Skip to content

Placeholders for prepared parameters are expanded too early #270

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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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