Skip to content

Placeholders for prepared parameters are expanded too early #270

@sbernatsky

Description

@sbernatsky

I have a mapper which passes prepared parameters into velocity macro. And this fails for at least two cases:

  • When parameters in macro are used in different order than they are defined in the macro;
  • When parameters are used more than one time in macro.

Most probably is is due to the changes in velocity from version 2.0 where they changed when arguments are evaluated (https://velocity.apache.org/engine/2.4.1/upgrading.html#vtl-changes_3):

Velocimacro arguments are now evaluated only once (instead of each time they were referenced inside the macro body as was the case for v1.7) and passed by value (or more precisely as reference after evaluation).

Using parameters in other order than they are defined

Mapper:

<select id="selectFromMacroParamsOrder" resultType="org.mybatis.scripting.velocity.use.Name">
  #macro(select_values $firstName, $lastName)
    SELECT firstName, lastName FROM (VALUES ($lastName, $firstName)) as tmp (lastName, firstName)
  #end
  #select_values(@{firstName}, @{lastName})
</select>

Test:

  @Test
  public void testSelectFromMacroWithParametersOrdering() {
    try (SqlSession sqlSession = sqlSessionFactory.openSession()) {

      Name fred = new Name();
      fred.setFirstName("Fred");
      fred.setLastName("Flinstone");

      List<Name> answers = sqlSession.selectList("org.mybatis.scripting.velocity.use.selectFromMacroParamsOrder", fred);
      assertEquals(1, answers.size());
      assertEquals(answers.get(0).getFirstName(), fred.getFirstName());
      assertEquals(answers.get(0).getLastName(), fred.getLastName());
    }
  }

MyBatis mapper logs:

[main] DEBUG org.mybatis.scripting.velocity.use.selectFromMacroParamsOrder - ==>  Preparing: SELECT firstName, lastName FROM (VALUES (?, ?)) as tmp (lastName, firstName)
[main] DEBUG org.mybatis.scripting.velocity.use.selectFromMacroParamsOrder - ==> Parameters: Fred(String), Flinstone(String)
[main] DEBUG org.mybatis.scripting.velocity.use.selectFromMacroParamsOrder - <==      Total: 1

Using parameters more than once in macro

Mapper:

<select id="selectFromMacroMultipleTimes" resultType="java.lang.String">
  #macro(select_multiple $value)
    SELECT * FROM (VALUES ($value), ($value)) as tmp (v)
  #end
  #select_multiple(@{value})
</select>

Test:

  @Test
  public void testSelectFromMacroMultipleTimes() {
    try (SqlSession sqlSession = sqlSessionFactory.openSession()) {

      List<String> answers = sqlSession.selectList("org.mybatis.scripting.velocity.use.selectFromMacroMultipleTimes", "A");
      assertEquals(2, answers.size());
      assertEquals(answers.get(0), "A");
      assertEquals(answers.get(1), "A");
    }
  }

MyBatis mapper logs:

[main] DEBUG org.mybatis.scripting.velocity.use.selectFromMacroMultipleTimes - ==>  Preparing: SELECT * FROM (VALUES (?), (?)) as tmp (v)
[main] DEBUG org.mybatis.scripting.velocity.use.selectFromMacroMultipleTimes - ==> Parameters: A(String)

Probably the ParameterMappingCollector should return some 'proxy' from org.mybatis.scripting.velocity.ParameterMappingCollector.g(int) method, which would add parameter mapping on toString call.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions