#3772·mybatis-3

3.6 regression: variable created by <bind> inside <where>/<set>/<trim>/<foreach> is no longer visible after the closing tag

Author: harrisleeshCreated Sep 3, 2026Updated Sep 5, 2026

MyBatis version

master (c5e06b1, 3.6.x line). Works in 3.5.19.

Description

In 3.5.19, TrimSqlNode's filtered context and ForEachSqlNode's prefixed context delegated bind() to the parent context, so a <bind> evaluated inside <where>, <set>, <trim> or <foreach> remained visible after the closing tag. On the 3.6 line those inner contexts keep bindings local, so the variable silently disappears:

xml
<select id="selectBlog" resultType="Blog">
  SELECT * FROM BLOG
  <where>
    <bind name="orderColumn" value="3"/>
    ID = #{id}
  </where>
  ORDER BY ${orderColumn} <!-- empty on 3.6: variable lost after </where> -->
</select>

On master this renders ... ORDER BY (the binding is gone); on 3.5.19 it renders ... ORDER BY 3. The same happens with <bind> inside <foreach>.

I realize the 3.6 scoping of <foreach>'s item/index variables is deliberate (ForEachTest.shouldRemoveItemVariableInTheContext / shouldRemoveIndexVariableInTheContext), so this may be intended fallout — but losing explicit <bind> results looks unintentional, and it breaks statements that worked on 3.5.x.

If you agree this is a regression, I have a fix ready that propagates bind() from both inner contexts to their delegate while keeping item/index local-only (the existing 3.6 scoping tests still pass; full suite 2014 tests green) and will submit a PR.

Steps to reproduce

Failing test against master (passes on 3.5.19): build a DynamicSqlSource with a <where> containing a <bind> and reference the bound variable after the tag — the variable is absent from the final SQL.