Skip to content

Commit 351e029

Browse files
committed
Related to #129.
Make sure that RAW language generates the same SQL than the XML language.
1 parent 5396486 commit 351e029

File tree

4 files changed

+68
-42
lines changed

4 files changed

+68
-42
lines changed

src/main/java/org/apache/ibatis/builder/xml/XMLStatementBuilder.java

+21-12
Original file line numberDiff line numberDiff line change
@@ -82,14 +82,9 @@ public void parseStatementNode() {
8282
XMLIncludeTransformer includeParser = new XMLIncludeTransformer(configuration, builderAssistant);
8383
includeParser.applyIncludes(context.getNode());
8484

85-
// Parse selectKey after includes,
86-
// in case if IncompleteElementException (issue #291)
87-
List<XNode> selectKeyNodes = context.evalNodes("selectKey");
88-
if (configuration.getDatabaseId() != null) {
89-
parseSelectKeyNodes(id, selectKeyNodes, parameterTypeClass, langDriver, configuration.getDatabaseId());
90-
}
91-
parseSelectKeyNodes(id, selectKeyNodes, parameterTypeClass, langDriver, null);
92-
85+
// Parse selectKey after includes and remove them.
86+
processSelectKeyNodes(id, parameterTypeClass, langDriver);
87+
9388
// Parse the SQL (pre: <selectKey> and <include> were parsed and removed)
9489
SqlSource sqlSource = langDriver.createSqlSource(configuration, context, parameterTypeClass);
9590
String resultSets = context.getStringAttribute("resultSets");
@@ -111,8 +106,17 @@ public void parseStatementNode() {
111106
resultSetTypeEnum, flushCache, useCache, resultOrdered,
112107
keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);
113108
}
114-
115-
public void parseSelectKeyNodes(String parentId, List<XNode> list, Class<?> parameterTypeClass, LanguageDriver langDriver, String skRequiredDatabaseId) {
109+
110+
private void processSelectKeyNodes(String id, Class<?> parameterTypeClass, LanguageDriver langDriver) {
111+
List<XNode> selectKeyNodes = context.evalNodes("selectKey");
112+
if (configuration.getDatabaseId() != null) {
113+
parseSelectKeyNodes(id, selectKeyNodes, parameterTypeClass, langDriver, configuration.getDatabaseId());
114+
}
115+
parseSelectKeyNodes(id, selectKeyNodes, parameterTypeClass, langDriver, null);
116+
removeSelectKeyNodes(selectKeyNodes);
117+
}
118+
119+
private void parseSelectKeyNodes(String parentId, List<XNode> list, Class<?> parameterTypeClass, LanguageDriver langDriver, String skRequiredDatabaseId) {
116120
for (XNode nodeToHandle : list) {
117121
String id = parentId + SelectKeyGenerator.SELECT_KEY_SUFFIX;
118122
String databaseId = nodeToHandle.getStringAttribute("databaseId");
@@ -122,7 +126,7 @@ public void parseSelectKeyNodes(String parentId, List<XNode> list, Class<?> para
122126
}
123127
}
124128

125-
public void parseSelectKeyNode(String id, XNode nodeToHandle, Class<?> parameterTypeClass, LanguageDriver langDriver, String databaseId) {
129+
private void parseSelectKeyNode(String id, XNode nodeToHandle, Class<?> parameterTypeClass, LanguageDriver langDriver, String databaseId) {
126130
String resultType = nodeToHandle.getStringAttribute("resultType");
127131
Class<?> resultTypeClass = resolveClass(resultType);
128132
StatementType statementType = StatementType.valueOf(nodeToHandle.getStringAttribute("statementType", StatementType.PREPARED.toString()));
@@ -152,7 +156,12 @@ public void parseSelectKeyNode(String id, XNode nodeToHandle, Class<?> parameter
152156

153157
MappedStatement keyStatement = configuration.getMappedStatement(id, false);
154158
configuration.addKeyGenerator(id, new SelectKeyGenerator(keyStatement, executeBefore));
155-
nodeToHandle.getParent().getNode().removeChild(nodeToHandle.getNode());
159+
}
160+
161+
private void removeSelectKeyNodes(List<XNode> selectKeyNodes) {
162+
for (XNode nodeToHandle : selectKeyNodes) {
163+
nodeToHandle.getParent().getNode().removeChild(nodeToHandle.getNode());
164+
}
156165
}
157166

158167
private boolean databaseIdMatchesCurrent(String id, String databaseId, String requiredDatabaseId) {

src/main/java/org/apache/ibatis/scripting/defaults/RawLanguageDriver.java

+34-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2013 MyBatis.org.
2+
* Copyright 2012-2014 MyBatis.org.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -15,26 +15,58 @@
1515
*/
1616
package org.apache.ibatis.scripting.defaults;
1717

18+
import java.util.ArrayList;
19+
import java.util.List;
20+
21+
import org.apache.ibatis.builder.BuilderException;
1822
import org.apache.ibatis.executor.parameter.ParameterHandler;
1923
import org.apache.ibatis.mapping.BoundSql;
2024
import org.apache.ibatis.mapping.MappedStatement;
2125
import org.apache.ibatis.mapping.SqlSource;
2226
import org.apache.ibatis.parsing.XNode;
2327
import org.apache.ibatis.scripting.LanguageDriver;
28+
import org.apache.ibatis.scripting.xmltags.MixedSqlNode;
29+
import org.apache.ibatis.scripting.xmltags.SqlNode;
30+
import org.apache.ibatis.scripting.xmltags.StaticTextSqlNode;
2431
import org.apache.ibatis.session.Configuration;
32+
import org.w3c.dom.Node;
33+
import org.w3c.dom.NodeList;
2534

35+
/**
36+
* As of 3.2.4 the default XML language is able to identify static statements
37+
* and create a {@link RawSqlSource}. So there is no need to use RAW unless you
38+
* want to make sure that there is not any dynamic tag for any reason.
39+
*
40+
* @since 3.2.0
41+
*/
2642
public class RawLanguageDriver implements LanguageDriver {
2743

2844
public ParameterHandler createParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
2945
return new DefaultParameterHandler(mappedStatement, parameterObject, boundSql);
3046
}
3147

3248
public SqlSource createSqlSource(Configuration configuration, XNode script, Class<?> parameterType) {
33-
return new RawSqlSource(configuration, script, parameterType);
49+
return new RawSqlSource(configuration, parseXML(script), parameterType);
3450
}
3551

3652
public SqlSource createSqlSource(Configuration configuration, String script, Class<?> parameterType) {
3753
return new RawSqlSource(configuration, script, parameterType);
3854
}
3955

56+
private static SqlNode parseXML(XNode script) {
57+
List<SqlNode> contents = new ArrayList<SqlNode>();
58+
NodeList children = script.getNode().getChildNodes();
59+
for (int i = 0; i < children.getLength(); i++) {
60+
XNode child = script.newXNode(children.item(i));
61+
String nodeName = child.getNode().getNodeName();
62+
if (child.getNode().getNodeType() == Node.CDATA_SECTION_NODE || child.getNode().getNodeType() == Node.TEXT_NODE) {
63+
String data = child.getStringBody("");
64+
contents.add(new StaticTextSqlNode(data));
65+
} else if (child.getNode().getNodeType() == Node.ELEMENT_NODE) {
66+
throw new BuilderException("Found an invalid element <" + nodeName + "> for RAW language.");
67+
}
68+
}
69+
return new MixedSqlNode(contents);
70+
}
71+
4072
}

src/main/java/org/apache/ibatis/scripting/defaults/RawSqlSource.java

+10-24
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2013 MyBatis.org.
2+
* Copyright 2012-2014 MyBatis.org.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -20,50 +20,36 @@
2020
import org.apache.ibatis.builder.SqlSourceBuilder;
2121
import org.apache.ibatis.mapping.BoundSql;
2222
import org.apache.ibatis.mapping.SqlSource;
23-
import org.apache.ibatis.parsing.XNode;
2423
import org.apache.ibatis.scripting.xmltags.DynamicContext;
24+
import org.apache.ibatis.scripting.xmltags.DynamicSqlSource;
2525
import org.apache.ibatis.scripting.xmltags.SqlNode;
2626
import org.apache.ibatis.session.Configuration;
27-
import org.w3c.dom.Node;
28-
import org.w3c.dom.NodeList;
2927

28+
/**
29+
* Static SqlSource. It is faster than {link {@link DynamicSqlSource} because mappings are
30+
* calculated during startup.
31+
*
32+
* @since 3.2.0
33+
*/
3034
public class RawSqlSource implements SqlSource {
3135

3236
private final SqlSource sqlSource;
33-
37+
3438
public RawSqlSource(Configuration configuration, SqlNode rootSqlNode, Class<?> parameterType) {
3539
this(configuration, getSql(configuration, rootSqlNode), parameterType);
3640
}
3741

38-
public RawSqlSource(Configuration configuration, XNode script, Class<?> parameterType) {
39-
this(configuration, getStringFromXNode(script), parameterType);
40-
}
41-
4242
public RawSqlSource(Configuration configuration, String sql, Class<?> parameterType) {
4343
SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration);
4444
Class<?> clazz = parameterType == null ? Object.class : parameterType;
4545
sqlSource = sqlSourceParser.parse(sql, clazz, new HashMap<String, Object>());
4646
}
47-
47+
4848
private static String getSql(Configuration configuration, SqlNode rootSqlNode) {
4949
DynamicContext context = new DynamicContext(configuration, null);
5050
rootSqlNode.apply(context);
5151
return context.getSql();
5252
}
53-
54-
private static String getStringFromXNode(XNode script) {
55-
StringBuilder contents = new StringBuilder();
56-
NodeList children = script.getNode().getChildNodes();
57-
for (int i = 0; i < children.getLength(); i++) {
58-
XNode child = script.newXNode(children.item(i));
59-
if (child.getNode().getNodeType() == Node.CDATA_SECTION_NODE || child.getNode().getNodeType() == Node.TEXT_NODE) {
60-
String data = child.getStringBody("");
61-
contents.append(data);
62-
contents.append(" "); // issue #128
63-
}
64-
}
65-
return contents.toString();
66-
}
6753

6854
public BoundSql getBoundSql(Object parameterObject) {
6955
return sqlSource.getBoundSql(parameterObject);

src/main/java/org/apache/ibatis/scripting/xmltags/XMLScriptBuilder.java

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2009-2013 the original author or authors.
2+
* Copyright 2009-2014 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -76,8 +76,7 @@ private List<SqlNode> parseDynamicTags(XNode node) {
7676
for (int i = 0; i < children.getLength(); i++) {
7777
XNode child = node.newXNode(children.item(i));
7878
String nodeName = child.getNode().getNodeName();
79-
if (child.getNode().getNodeType() == Node.CDATA_SECTION_NODE
80-
|| child.getNode().getNodeType() == Node.TEXT_NODE) {
79+
if (child.getNode().getNodeType() == Node.CDATA_SECTION_NODE || child.getNode().getNodeType() == Node.TEXT_NODE) {
8180
String data = child.getStringBody("");
8281
TextSqlNode textSqlNode = new TextSqlNode(data);
8382
if (textSqlNode.isDynamic()) {
@@ -86,7 +85,7 @@ private List<SqlNode> parseDynamicTags(XNode node) {
8685
} else {
8786
contents.add(new StaticTextSqlNode(data));
8887
}
89-
} else if (child.getNode().getNodeType() == Node.ELEMENT_NODE && !"selectKey".equals(nodeName)) { // issue #628
88+
} else if (child.getNode().getNodeType() == Node.ELEMENT_NODE) { // issue #628
9089
NodeHandler handler = nodeHandlers.get(nodeName);
9190
if (handler == null) {
9291
throw new BuilderException("Unknown element <" + nodeName + "> in SQL statement.");

0 commit comments

Comments
 (0)