XMLSqlSource.java
/*
* Copyright 2004-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.ibatis.sqlmap.engine.builder.xml;
import com.ibatis.common.xml.NodeletUtils;
import com.ibatis.sqlmap.engine.config.SqlSource;
import com.ibatis.sqlmap.engine.mapping.parameter.InlineParameterMapParser;
import com.ibatis.sqlmap.engine.mapping.sql.Sql;
import com.ibatis.sqlmap.engine.mapping.sql.SqlText;
import com.ibatis.sqlmap.engine.mapping.sql.dynamic.DynamicSql;
import com.ibatis.sqlmap.engine.mapping.sql.dynamic.elements.*;
import com.ibatis.sqlmap.engine.mapping.sql.raw.RawSql;
import java.util.Properties;
import org.w3c.dom.CharacterData;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* The Class XMLSqlSource.
*/
public class XMLSqlSource implements SqlSource {
/** The Constant PARAM_PARSER. */
private static final InlineParameterMapParser PARAM_PARSER = new InlineParameterMapParser();
/** The state. */
private XmlParserState state;
/** The parent node. */
private Node parentNode;
/**
* Instantiates a new XML sql source.
*
* @param config
* the config
* @param parentNode
* the parent node
*/
public XMLSqlSource(XmlParserState config, Node parentNode) {
this.state = config;
this.parentNode = parentNode;
}
public Sql getSql() {
state.getConfig().getErrorContext().setActivity("processing an SQL statement");
boolean isDynamic = false;
StringBuilder sqlBuffer = new StringBuilder();
DynamicSql dynamic = new DynamicSql(state.getConfig().getClient().getDelegate());
isDynamic = parseDynamicTags(parentNode, dynamic, sqlBuffer, isDynamic, false);
String sqlStatement = sqlBuffer.toString();
if (isDynamic) {
return dynamic;
} else {
return new RawSql(sqlStatement);
}
}
/**
* Parses the dynamic tags.
*
* @param node
* the node
* @param dynamic
* the dynamic
* @param sqlBuffer
* the sql buffer
* @param isDynamic
* the is dynamic
* @param postParseRequired
* the post parse required
*
* @return true, if successful
*/
private boolean parseDynamicTags(Node node, DynamicParent dynamic, StringBuilder sqlBuffer, boolean isDynamic,
boolean postParseRequired) {
state.getConfig().getErrorContext().setActivity("parsing dynamic SQL tags");
NodeList children = node.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node child = children.item(i);
String nodeName = child.getNodeName();
if (child.getNodeType() == Node.CDATA_SECTION_NODE || child.getNodeType() == Node.TEXT_NODE) {
String data = ((CharacterData) child).getData();
data = NodeletUtils.parsePropertyTokens(data, state.getGlobalProps());
SqlText sqlText;
if (postParseRequired) {
sqlText = new SqlText();
sqlText.setPostParseRequired(postParseRequired);
sqlText.setText(data);
} else {
sqlText = PARAM_PARSER
.parseInlineParameterMap(state.getConfig().getClient().getDelegate().getTypeHandlerFactory(), data, null);
sqlText.setPostParseRequired(postParseRequired);
}
dynamic.addChild(sqlText);
sqlBuffer.append(data);
} else if ("include".equals(nodeName)) {
Properties attributes = NodeletUtils.parseAttributes(child, state.getGlobalProps());
String refid = (String) attributes.get("refid");
Node includeNode = (Node) state.getSqlIncludes().get(refid);
if (includeNode == null) {
String nsrefid = state.applyNamespace(refid);
includeNode = (Node) state.getSqlIncludes().get(nsrefid);
if (includeNode == null) {
throw new RuntimeException("Could not find SQL statement to include with refid '" + refid + "'");
}
}
isDynamic = parseDynamicTags(includeNode, dynamic, sqlBuffer, isDynamic, false);
} else {
state.getConfig().getErrorContext().setMoreInfo("Check the dynamic tags.");
SqlTagHandler handler = SqlTagHandlerFactory.getSqlTagHandler(nodeName);
if (handler != null) {
isDynamic = true;
SqlTag tag = new SqlTag();
tag.setName(nodeName);
tag.setHandler(handler);
Properties attributes = NodeletUtils.parseAttributes(child, state.getGlobalProps());
tag.setPrependAttr(attributes.getProperty("prepend"));
tag.setPropertyAttr(attributes.getProperty("property"));
tag.setRemoveFirstPrepend(attributes.getProperty("removeFirstPrepend"));
tag.setOpenAttr(attributes.getProperty("open"));
tag.setCloseAttr(attributes.getProperty("close"));
tag.setComparePropertyAttr(attributes.getProperty("compareProperty"));
tag.setCompareValueAttr(attributes.getProperty("compareValue"));
tag.setConjunctionAttr(attributes.getProperty("conjunction"));
// an iterate ancestor requires a post parse
if (dynamic instanceof SqlTag) {
SqlTag parentSqlTag = (SqlTag) dynamic;
if (parentSqlTag.isPostParseRequired() || tag.getHandler() instanceof IterateTagHandler) {
tag.setPostParseRequired(true);
}
} else if (dynamic instanceof DynamicSql) {
if (tag.getHandler() instanceof IterateTagHandler) {
tag.setPostParseRequired(true);
}
}
dynamic.addChild(tag);
if (child.hasChildNodes()) {
isDynamic = parseDynamicTags(child, tag, sqlBuffer, isDynamic, tag.isPostParseRequired());
}
}
}
}
state.getConfig().getErrorContext().setMoreInfo(null);
return isDynamic;
}
}