Author: cbegin
Date: Sat May 9 16:35:37 2009
New Revision: 773245
URL: http://svn.apache.org/viewvc?rev=773245&view=rev
Log:
Added parser for dynamic SQL (not hooked in yet)
Modified:
ibatis/trunk/java/ibatis-3/TODO
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/parser/BaseParser.java
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/parser/SequentialMapperBuilder.java
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/parser/xml/XMLMapperConfigParser.java
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/parser/xml/XMLMapperParser.java
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/parser/xml/XMLStatementParser.java
ibatis/trunk/java/ibatis-3/version.properties
Modified: ibatis/trunk/java/ibatis-3/TODO
URL:
http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/TODO?rev=773245&r1=773244&r2=773245&view=diff
==============================================================================
--- ibatis/trunk/java/ibatis-3/TODO (original)
+++ ibatis/trunk/java/ibatis-3/TODO Sat May 9 16:35:37 2009
@@ -1,19 +1,10 @@
###################################
-# TODO List #
+# TO-DO List #
###################################
Required:
* Return selectKey or autogen key from session.insert()
-* Dynamic SQL XML Parser
- <where>
- <set>
- <prefix insert removeFirst>
- <foreach item index open close separator>
- <if test>
- <choose>
- <when test>
- <otherwise>
Nice to Have:
Modified:
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/parser/BaseParser.java
URL:
http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/parser/BaseParser.java?rev=773245&r1=773244&r2=773245&view=diff
==============================================================================
---
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/parser/BaseParser.java
(original)
+++
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/parser/BaseParser.java
Sat May 9 16:35:37 2009
@@ -3,7 +3,7 @@
import org.apache.ibatis.mapping.*;
import org.apache.ibatis.type.*;
-public class BaseParser {
+public abstract class BaseParser {
protected final Configuration configuration;
protected final TypeAliasRegistry typeAliasRegistry;
protected final TypeHandlerRegistry typeHandlerRegistry;
Modified:
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/parser/SequentialMapperBuilder.java
URL:
http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/parser/SequentialMapperBuilder.java?rev=773245&r1=773244&r2=773245&view=diff
==============================================================================
---
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/parser/SequentialMapperBuilder.java
(original)
+++
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/parser/SequentialMapperBuilder.java
Sat May 9 16:35:37 2009
@@ -227,16 +227,16 @@
configuration.addMappedStatement(statement);
}
- private <T> T valueOrDefault(T value, T defaultValue) {
- return value == null ? defaultValue : value;
- }
-
- private String applyNamespace(String base) {
+ public String applyNamespace(String base) {
if (base == null) return null;
if (base.contains(".")) return base;
return namespace + "." + base;
}
+ private <T> T valueOrDefault(T value, T defaultValue) {
+ return value == null ? defaultValue : value;
+ }
+
private void setStatementCache(
boolean isSelect,
boolean flushCache,
Modified:
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/parser/xml/XMLMapperConfigParser.java
URL:
http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/parser/xml/XMLMapperConfigParser.java?rev=773245&r1=773244&r2=773245&view=diff
==============================================================================
---
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/parser/xml/XMLMapperConfigParser.java
(original)
+++
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/parser/xml/XMLMapperConfigParser.java
Sat May 9 16:35:37 2009
@@ -18,8 +18,8 @@
private boolean parsed;
- protected Reader reader;
- protected NodeletParser parser;
+ private Reader reader;
+ private NodeletParser parser;
private String environment;
private Environment.Builder environmentBuilder;
Modified:
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/parser/xml/XMLMapperParser.java
URL:
http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/parser/xml/XMLMapperParser.java?rev=773245&r1=773244&r2=773245&view=diff
==============================================================================
---
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/parser/xml/XMLMapperParser.java
(original)
+++
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/parser/xml/XMLMapperParser.java
Sat May 9 16:35:37 2009
@@ -10,9 +10,11 @@
public class XMLMapperParser extends BaseParser {
- protected Reader reader;
- protected NodeletParser parser;
- protected SequentialMapperBuilder sequentialBuilder;
+ private Reader reader;
+ private NodeletParser parser;
+ private SequentialMapperBuilder sequentialBuilder;
+
+ private Map<String,NodeletContext> sqlFragments = new
HashMap<String,NodeletContext>();
public XMLMapperParser(Reader reader, Configuration configuration, String
resource, String namespace) {
this(reader, configuration, resource);
@@ -198,6 +200,14 @@
sequentialBuilder.resultMapEnd();
}
+ // <sql id="">
+ @Nodelet("/mapper/sql")
+ public void sqlElement(NodeletContext context) throws Exception {
+ String id = context.getStringAttribute("id");
+
+ sqlFragments.put(id, context);
+ }
+
// <select ...>
@Nodelet("/mapper/select")
public void selectElement(NodeletContext context) throws Exception {
@@ -222,8 +232,12 @@
buildStatementFromContext(context);
}
+ public NodeletContext getSqlFragment(String refid) {
+ return sqlFragments.get(refid);
+ }
+
private void buildStatementFromContext(NodeletContext context) {
- final XMLStatementParser statementParser = new
XMLStatementParser(configuration, sequentialBuilder);
+ final XMLStatementParser statementParser = new
XMLStatementParser(configuration, sequentialBuilder, this);
statementParser.parseStatementNode(context);
}
Modified:
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/parser/xml/XMLStatementParser.java
URL:
http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/parser/xml/XMLStatementParser.java?rev=773245&r1=773244&r2=773245&view=diff
==============================================================================
---
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/parser/xml/XMLStatementParser.java
(original)
+++
ibatis/trunk/java/ibatis-3/ibatis-3-core/src/main/java/org/apache/ibatis/parser/xml/XMLStatementParser.java
Sat May 9 16:35:37 2009
@@ -1,16 +1,32 @@
package org.apache.ibatis.parser.xml;
+import org.apache.ibatis.mapping.Configuration;
+import org.apache.ibatis.mapping.ResultSetType;
+import org.apache.ibatis.mapping.SqlSource;
+import org.apache.ibatis.mapping.StatementType;
+import org.apache.ibatis.parser.BaseParser;
+import org.apache.ibatis.parser.ParserException;
+import org.apache.ibatis.parser.SequentialMapperBuilder;
+import org.apache.ibatis.parser.SqlSourceParser;
+import org.apache.ibatis.parser.xml.dynamic.*;
import org.apache.ibatis.xml.NodeletContext;
-import org.apache.ibatis.mapping.*;
-import org.apache.ibatis.parser.*;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
public class XMLStatementParser extends BaseParser {
- protected SequentialMapperBuilder sequentialBuilder;
+ private SequentialMapperBuilder sequentialBuilder;
+ private XMLMapperParser xmlMapperParser;
- public XMLStatementParser(Configuration configuration,
SequentialMapperBuilder sequentialBuilder) {
+ public XMLStatementParser(Configuration configuration,
SequentialMapperBuilder sequentialBuilder, XMLMapperParser xmlMapperParser) {
super(configuration);
this.sequentialBuilder = sequentialBuilder;
+ this.xmlMapperParser = xmlMapperParser;
}
public void parseStatementNode(NodeletContext context) {
@@ -35,6 +51,159 @@
resultMap, resultTypeClass, resultSetTypeEnum, isSelect, flushCache,
useCache, statementType);
}
-
+
+ private List<SqlNode> parseDynamicTags(NodeletContext node) {
+ List<SqlNode> contents = new ArrayList<SqlNode>();
+ NodeList children = node.getNode().getChildNodes();
+ for (int i = 0; i < children.getLength(); i++) {
+ NodeletContext child = new NodeletContext(children.item(i),
configuration.getVariables());
+ String nodeName = child.getNode().getNodeName();
+ if (child.getNode().getNodeType() == Node.CDATA_SECTION_NODE
+ || child.getNode().getNodeType() == Node.TEXT_NODE) {
+ String data = child.getStringBody("");
+ contents.add(new TextSqlNode(data));
+ } else {
+ NodeHandler handler = nodeHandlers.get(nodeName);
+ if (handler == null) {
+ throw new ParserException("Unknown element <" + nodeName + "> in SQL
statement.");
+ }
+ handler.handleNode(child, contents);
+
+ }
+ }
+ return contents;
+ }
+
+ private Map<String, NodeHandler> nodeHandlers = new HashMap<String,
NodeHandler>() {
+ {
+ put("include", new IncludeNodeHandler());
+ put("prefix", new PrefixHandler());
+ put("where", new WhereHandler());
+ put("set", new SetHandler());
+ put("foreach", new ForEachHandler());
+ put("if", new IfHandler());
+ put("choose", new ChooseHandler());
+ put("when", new IfHandler());
+ put("otherwise", new OtherwiseHandler());
+ }
+ };
+
+ private interface NodeHandler {
+ void handleNode(NodeletContext nodeToHandle, List<SqlNode> targetContents);
+ }
+
+ private class IncludeNodeHandler implements NodeHandler {
+ public void handleNode(NodeletContext nodeToHandle, List<SqlNode>
targetContents) {
+ String refid = nodeToHandle.getStringAttribute("refid");
+ NodeletContext includeNode = xmlMapperParser.getSqlFragment(refid);
+ if (includeNode == null) {
+ String nsrefid = sequentialBuilder.applyNamespace(refid);
+ includeNode = xmlMapperParser.getSqlFragment(nsrefid);
+ if (includeNode == null) {
+ throw new RuntimeException("Could not find SQL statement to include
with refid '" + refid + "'");
+ }
+ }
+ MixedSqlNode mixedSqlNode = new MixedSqlNode(contents(includeNode));
+ targetContents.add(mixedSqlNode);
+ }
+
+ private List<SqlNode> contents(NodeletContext includeNode) {
+ return parseDynamicTags(includeNode);
+ }
+ }
+
+ private class PrefixHandler implements NodeHandler {
+ public void handleNode(NodeletContext nodeToHandle, List<SqlNode>
targetContents) {
+ List<SqlNode> contents = parseDynamicTags(nodeToHandle);
+ MixedSqlNode mixedSqlNode = new MixedSqlNode(contents);
+ String with = nodeToHandle.getStringAttribute("with");
+ String overrides = nodeToHandle.getStringAttribute("overrides");
+ PrefixSqlNode prefix = new PrefixSqlNode(mixedSqlNode, with, overrides);
+ targetContents.add(prefix);
+ }
+ }
+
+ private class WhereHandler implements NodeHandler {
+ public void handleNode(NodeletContext nodeToHandle, List<SqlNode>
targetContents) {
+ List<SqlNode> contents = parseDynamicTags(nodeToHandle);
+ MixedSqlNode mixedSqlNode = new MixedSqlNode(contents);
+ WhereSqlNode where = new WhereSqlNode(mixedSqlNode);
+ targetContents.add(where);
+ }
+ }
+
+ private class SetHandler implements NodeHandler {
+ public void handleNode(NodeletContext nodeToHandle, List<SqlNode>
targetContents) {
+ List<SqlNode> contents = parseDynamicTags(nodeToHandle);
+ MixedSqlNode mixedSqlNode = new MixedSqlNode(contents);
+ SetSqlNode set = new SetSqlNode(mixedSqlNode);
+ targetContents.add(set);
+ }
+ }
+
+ private class ForEachHandler implements NodeHandler {
+ public void handleNode(NodeletContext nodeToHandle, List<SqlNode>
targetContents) {
+ List<SqlNode> contents = parseDynamicTags(nodeToHandle);
+ MixedSqlNode mixedSqlNode = new MixedSqlNode(contents);
+ String collection = nodeToHandle.getStringAttribute("collection");
+ String item = nodeToHandle.getStringAttribute("item");
+ String index = nodeToHandle.getStringAttribute("index");
+ String open = nodeToHandle.getStringAttribute("open");
+ String close = nodeToHandle.getStringAttribute("close");
+ String separator = nodeToHandle.getStringAttribute("separator");
+ ForEachSqlNode forEachSqlNode = new ForEachSqlNode(mixedSqlNode,
collection, index, item, open, close, separator);
+ targetContents.add(forEachSqlNode);
+ }
+ }
+
+ private class IfHandler implements NodeHandler {
+ public void handleNode(NodeletContext nodeToHandle, List<SqlNode>
targetContents) {
+ List<SqlNode> contents = parseDynamicTags(nodeToHandle);
+ MixedSqlNode mixedSqlNode = new MixedSqlNode(contents);
+ String test = nodeToHandle.getStringAttribute("test");
+ IfSqlNode ifSqlNode = new IfSqlNode(mixedSqlNode, test);
+ targetContents.add(ifSqlNode);
+ }
+ }
+
+ private class OtherwiseHandler implements NodeHandler {
+ public void handleNode(NodeletContext nodeToHandle, List<SqlNode>
targetContents) {
+ List<SqlNode> contents = parseDynamicTags(nodeToHandle);
+ MixedSqlNode mixedSqlNode = new MixedSqlNode(contents);
+ targetContents.add(mixedSqlNode);
+ }
+ }
+
+ private class ChooseHandler implements NodeHandler {
+ public void handleNode(NodeletContext nodeToHandle, List<SqlNode>
targetContents) {
+ List whenSqlNodes = new ArrayList<SqlNode>();
+ List<SqlNode> otherwiseSqlNodes = new ArrayList<SqlNode>();
+ handleWhenOtherwiseNodes(nodeToHandle, whenSqlNodes, otherwiseSqlNodes);
+ SqlNode defaultSqlNode = getDefaultSqlNode(otherwiseSqlNodes);
+ ChooseSqlNode forEachSqlNode = new ChooseSqlNode((List<IfSqlNode>)
whenSqlNodes, defaultSqlNode);
+ targetContents.add(forEachSqlNode);
+ }
+ private void handleWhenOtherwiseNodes(NodeletContext chooseSqlNode, List
ifSqlNodes, List<SqlNode> defaultSqlNodes) {
+ List<NodeletContext> children = chooseSqlNode.getChildren();
+ for (NodeletContext child : children) {
+ String nodeName = child.getNode().getNodeName();
+ NodeHandler handler = nodeHandlers.get(nodeName);
+ if (handler instanceof IfHandler) {
+ handler.handleNode(child, ifSqlNodes);
+ } else if (handler instanceof OtherwiseHandler) {
+ handler.handleNode(child, defaultSqlNodes);
+ }
+ }
+ }
+ private SqlNode getDefaultSqlNode(List<SqlNode> defaultSqlNodes) {
+ SqlNode defaultSqlNode = null;
+ if (defaultSqlNodes.size() == 1) {
+ defaultSqlNode = defaultSqlNodes.get(0);
+ } else if (defaultSqlNodes.size() > 1) {
+ throw new ParserException("Too many default (otherwise) elements in
choose statement.");
+ }
+ return defaultSqlNode;
+ }
+ }
}
Modified: ibatis/trunk/java/ibatis-3/version.properties
URL:
http://svn.apache.org/viewvc/ibatis/trunk/java/ibatis-3/version.properties?rev=773245&r1=773244&r2=773245&view=diff
==============================================================================
--- ibatis/trunk/java/ibatis-3/version.properties (original)
+++ ibatis/trunk/java/ibatis-3/version.properties Sat May 9 16:35:37 2009
@@ -1,5 +1,5 @@
#Build version info
-#Sat Apr 11 01:46:47 MDT 2009
+#Tue May 05 17:36:19 MDT 2009
version=3.0.0
-buildDate=2009/04/11 01\:46
-buildNum=150
+buildDate=2009/05/05 17\:36
+buildNum=152