diff --git a/src/main/java/org/apache/ibatis/builder/xml/XMLIncludeTransformer.java b/src/main/java/org/apache/ibatis/builder/xml/XMLIncludeTransformer.java old mode 100644 new mode 100755 index 110fbe5a18c..cea66ae5fbd --- a/src/main/java/org/apache/ibatis/builder/xml/XMLIncludeTransformer.java +++ b/src/main/java/org/apache/ibatis/builder/xml/XMLIncludeTransformer.java @@ -15,6 +15,7 @@ */ package org.apache.ibatis.builder.xml; +import org.apache.ibatis.builder.BuilderException; import org.apache.ibatis.builder.IncompleteElementException; import org.apache.ibatis.builder.MapperBuilderAssistant; import org.apache.ibatis.parsing.PropertyParser; @@ -23,6 +24,8 @@ import org.w3c.dom.Node; import org.w3c.dom.NodeList; +import java.util.Properties; + /** * @author Frank D. Martinez [mnesarco] */ @@ -37,9 +40,39 @@ public XMLIncludeTransformer(Configuration configuration, MapperBuilderAssistant } public void applyIncludes(Node source) { + Properties variablesContext = new Properties(); + Properties configurationVariables = configuration.getVariables(); + if (configurationVariables != null) { + variablesContext.putAll(configurationVariables); + } + applyIncludes(source, variablesContext); + } + + /** + * Recursively apply includes through all SQL fragments. + * @param source Include node in DOM tree + * @param variablesContext Current context for static variables with values + */ + private void applyIncludes(Node source, final Properties variablesContext) { if (source.getNodeName().equals("include")) { - Node toInclude = findSqlFragment(getStringAttribute(source, "refid")); - applyIncludes(toInclude); + // new full context for included SQL - contains inherited context and new variables from current include node + Properties fullContext; + + String refid = getStringAttribute(source, "refid"); + // replace variables in include refid value + refid = PropertyParser.parse(refid, variablesContext); + Node toInclude = findSqlFragment(refid); + Properties newVariablesContext = getVariablesContext(source, variablesContext); + if (!newVariablesContext.isEmpty()) { + // merge contexts + fullContext = new Properties(); + fullContext.putAll(variablesContext); + fullContext.putAll(newVariablesContext); + } else { + // no new context - use inherited fully + fullContext = variablesContext; + } + applyIncludes(toInclude, fullContext); if (toInclude.getOwnerDocument() != source.getOwnerDocument()) { toInclude = source.getOwnerDocument().importNode(toInclude, true); } @@ -51,13 +84,18 @@ public void applyIncludes(Node source) { } else if (source.getNodeType() == Node.ELEMENT_NODE) { NodeList children = source.getChildNodes(); for (int i=0; i - + diff --git a/src/site/xdoc/sqlmap-xml.xml b/src/site/xdoc/sqlmap-xml.xml old mode 100644 new mode 100755 index 194c64213d6..be67e12e1b2 --- a/src/site/xdoc/sqlmap-xml.xml +++ b/src/site/xdoc/sqlmap-xml.xml @@ -485,19 +485,44 @@ ps.setInt(1,id);]]>

This element can be used to define a reusable fragment of SQL code that can be - included in other statements. For example: + included in other statements. It can be statically (during load phase) parametrized. Different property values can + vary in include instances. For example:

- id,username,password ]]> + ${alias}.id,${alias}.username,${alias}.password ]]>

The SQL fragment can then be included in another statement, for example:

- select - from some_table - where id = #{id} + select + , + + from some_table t1 + cross join some_table t2 +]]> + +

+ Property value can be also used in include refid attribute or property values inside include clause, for example: +

+ + + ${prefix}Table + + + + from + + + +]]>
diff --git a/src/test/java/org/apache/ibatis/builder/PostMapper.xml b/src/test/java/org/apache/ibatis/builder/PostMapper.xml old mode 100644 new mode 100755 index 5185de15176..131823797f7 --- a/src/test/java/org/apache/ibatis/builder/PostMapper.xml +++ b/src/test/java/org/apache/ibatis/builder/PostMapper.xml @@ -85,7 +85,7 @@ - blog_id = #{blog_id} + ${prefix}_id = #{blog_id} - + + + field1, field2, field3 - from + from + + + +