Author: shawkins
Date: 2010-05-04 15:00:28 -0400 (Tue, 04 May 2010)
New Revision: 2097
Modified:
trunk/connector-api/src/main/java/org/teiid/connector/api/SourceSystemFunctions.java
trunk/documentation/reference/src/main/docbook/en-US/content/scalar_functions.xml
trunk/engine/src/main/java/com/metamatrix/query/function/source/SystemSource.java
trunk/engine/src/main/java/com/metamatrix/query/function/source/XMLSystemFunctions.java
trunk/engine/src/main/java/com/metamatrix/query/optimizer/relational/rules/RuleAssignOutputElements.java
trunk/engine/src/main/javacc/com/metamatrix/query/parser/SQLParser.jj
trunk/engine/src/main/resources/com/metamatrix/query/i18n.properties
trunk/engine/src/test/java/com/metamatrix/query/function/TestFunctionLibrary.java
trunk/engine/src/test/java/com/metamatrix/query/processor/TestProcessor.java
Log:
TEIID-171 adding support for the xmlelement function
Modified:
trunk/connector-api/src/main/java/org/teiid/connector/api/SourceSystemFunctions.java
===================================================================
---
trunk/connector-api/src/main/java/org/teiid/connector/api/SourceSystemFunctions.java 2010-05-04
14:06:31 UTC (rev 2096)
+++
trunk/connector-api/src/main/java/org/teiid/connector/api/SourceSystemFunctions.java 2010-05-04
19:00:28 UTC (rev 2097)
@@ -137,5 +137,6 @@
//xml
public static final String XPATHVALUE = "xpathvalue"; //$NON-NLS-1$
public static final String XSLTRANSFORM = "xsltransform"; //$NON-NLS-1$
+ public static final String XMLELEMENT = "xmlelement"; //$NON-NLS-1$
}
Modified:
trunk/documentation/reference/src/main/docbook/en-US/content/scalar_functions.xml
===================================================================
---
trunk/documentation/reference/src/main/docbook/en-US/content/scalar_functions.xml 2010-05-04
14:06:31 UTC (rev 2096)
+++
trunk/documentation/reference/src/main/docbook/en-US/content/scalar_functions.xml 2010-05-04
19:00:28 UTC (rev 2097)
@@ -1957,6 +1957,23 @@
</para>
</entry>
</row>
+ <row>
+ <entry>
+ <para><code>XMLELEMENT(name [,
content]*)</code></para>
+ </entry>
+ <entry>
+ <para>Returns an XML element with the given name and conent. If the
content value is of a type other than xml,
+ it will be escaped when added to the parent element. Null content values
are ignored.
+ Whitespace in XML or the string values of the content is preserved, but no
whitespace is added between content values.</para>
+ <para>Example: with an xml_value of <doc/>,
<code>xmlelement('myelement', 1, '<2/>',
xml_value)</code>
+ Returns:
<code><myelement>1&lt;2/&gt;<doc/>></code>
+ </para>
+ </entry>
+ <entry>
+ <para>Name in {string}. Content can be any type. Return value is
xml.
+ </para>
+ </entry>
+ </row>
</tbody>
</tgroup>
</informaltable>
Modified:
trunk/engine/src/main/java/com/metamatrix/query/function/source/SystemSource.java
===================================================================
---
trunk/engine/src/main/java/com/metamatrix/query/function/source/SystemSource.java 2010-05-04
14:06:31 UTC (rev 2096)
+++
trunk/engine/src/main/java/com/metamatrix/query/function/source/SystemSource.java 2010-05-04
19:00:28 UTC (rev 2097)
@@ -168,6 +168,7 @@
// xml functions
addXpathFunction();
addXslTransformFunction();
+ addXmlElement();
addSecurityFunctions();
@@ -904,6 +905,14 @@
new FunctionParameter("result",
DataTypeManager.DefaultDataTypes.CLOB,
QueryPlugin.Util.getString("SystemSource.xsltransform_result")) ) );
//$NON-NLS-1$ //$NON-NLS-2$
}
+ private void addXmlElement() {
+ functions.add(new FunctionMethod(SourceSystemFunctions.XMLELEMENT,
QueryPlugin.Util.getString("SystemSource.xsltransform_description"), XML,
XML_FUNCTION_CLASS, "xmlElement", //$NON-NLS-1$ //$NON-NLS-2$
+ new FunctionParameter[] {
+ new FunctionParameter("name",
DataTypeManager.DefaultDataTypes.STRING,
QueryPlugin.Util.getString("SystemSource.xmlelement_param1")), //$NON-NLS-1$
//$NON-NLS-2$
+ new FunctionParameter("value",
DataTypeManager.DefaultDataTypes.OBJECT,
QueryPlugin.Util.getString("SystemSource.xmlelement_param2"), true)},
//$NON-NLS-1$ //$NON-NLS-2$
+ new FunctionParameter("result",
DataTypeManager.DefaultDataTypes.XML,
QueryPlugin.Util.getString("SystemSource.xmlement_result")) ) );
//$NON-NLS-1$ //$NON-NLS-2$
+ }
+
private void addTimeZoneFunctions() {
functions.add(new FunctionMethod(SourceSystemFunctions.MODIFYTIMEZONE,
QueryPlugin.Util.getString("SystemSource.modifyTimeZone_description"), DATETIME,
FUNCTION_CLASS, "modifyTimeZone", //$NON-NLS-1$ //$NON-NLS-2$
new FunctionParameter[] {
Modified:
trunk/engine/src/main/java/com/metamatrix/query/function/source/XMLSystemFunctions.java
===================================================================
---
trunk/engine/src/main/java/com/metamatrix/query/function/source/XMLSystemFunctions.java 2010-05-04
14:06:31 UTC (rev 2096)
+++
trunk/engine/src/main/java/com/metamatrix/query/function/source/XMLSystemFunctions.java 2010-05-04
19:00:28 UTC (rev 2097)
@@ -29,6 +29,14 @@
import java.sql.SQLException;
import java.sql.SQLXML;
+import javax.xml.stream.EventFilter;
+import javax.xml.stream.XMLEventFactory;
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.XMLEventWriter;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLOutputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.events.XMLEvent;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
@@ -38,10 +46,12 @@
import net.sf.saxon.trans.XPathException;
+import com.metamatrix.api.exception.MetaMatrixComponentException;
import com.metamatrix.api.exception.query.FunctionExecutionException;
import com.metamatrix.common.types.ClobType;
import com.metamatrix.common.types.DataTypeManager;
import com.metamatrix.common.types.Streamable;
+import com.metamatrix.common.types.TransformationException;
import com.metamatrix.common.types.XMLTranslator;
import com.metamatrix.common.types.XMLType;
import com.metamatrix.internal.core.xml.XPathHelper;
@@ -49,9 +59,6 @@
import com.metamatrix.query.processor.xml.XMLUtil;
import com.metamatrix.query.util.CommandContext;
-
-
-
/**
* This class contains scalar system functions supporting for XML manipulation.
*
@@ -60,10 +67,6 @@
public class XMLSystemFunctions {
public static Object xpathValue(Object document, Object xpathStr) throws
FunctionExecutionException {
- if(document == null || xpathStr == null) {
- return null;
- }
-
Reader stream = null;
if (document instanceof SQLXML) {
@@ -93,6 +96,7 @@
Reader reader = xmlResults.getCharacterStream();
final Source xmlSource = new StreamSource(reader);
try {
+ //this creates a non-validated sqlxml - it may not be valid xml/root-less xml
SQLXML result = XMLUtil.saveToBufferManager(context.getBufferManager(), new
XMLTranslator() {
@Override
@@ -115,5 +119,67 @@
}
}
}
-
+
+ /**
+ * Basic support for xmlelement. Attributes are not yet supported.
+ * @param context
+ * @param name
+ * @param contents
+ * @return
+ * @throws MetaMatrixComponentException
+ */
+ public static XMLType xmlElement(CommandContext context, final String name, final
Object... contents) throws MetaMatrixComponentException {
+ return new XMLType(XMLUtil.saveToBufferManager(context.getBufferManager(), new
XMLTranslator() {
+
+ @Override
+ public void translate(Writer writer) throws TransformerException,
+ IOException {
+ try {
+ XMLOutputFactory factory = XMLOutputFactory.newInstance();
+ XMLEventWriter eventWriter = factory.createXMLEventWriter(writer);
+ XMLEventFactory eventFactory = XMLEventFactory.newInstance();
+ eventWriter.add(eventFactory.createStartElement("", null, name));
//$NON-NLS-1$
+ for (Object object : contents) {
+ if (object == null) {
+ continue;
+ }
+ if (object instanceof XMLType) {
+ Reader r = null;
+ try {
+ r = ((XMLType)object).getCharacterStream();
+ XMLInputFactory inputFactory = XMLInputFactory.newInstance();
+ XMLEventReader xmlEventReader =
inputFactory.createFilteredReader(inputFactory.createXMLEventReader(r), new EventFilter()
{
+
+ @Override
+ public boolean accept(XMLEvent event) {
+ return !event.isStartDocument() && !event.isEndDocument();
+ }
+ });
+ eventWriter.add(xmlEventReader);
+ } catch (SQLException e) {
+ throw new IOException(e);
+ } finally {
+ if (r != null) {
+ r.close();
+ }
+ }
+ } else {
+ try {
+ String result = DataTypeManager.transformValue(object,
DataTypeManager.DefaultDataClasses.STRING);
+ eventWriter.add(eventFactory.createCharacters(result));
+ } catch (TransformationException e) {
+ throw new TransformerException(e);
+ }
+ }
+ }
+ eventWriter.add(eventFactory.createEndElement("", null, name));
//$NON-NLS-1$
+ } catch (XMLStreamException e) {
+ throw new TransformerException(e);
+ } finally {
+
+ }
+ }
+ }, context.getStreamingBatchSize()));
+ }
+
}
Modified:
trunk/engine/src/main/java/com/metamatrix/query/optimizer/relational/rules/RuleAssignOutputElements.java
===================================================================
---
trunk/engine/src/main/java/com/metamatrix/query/optimizer/relational/rules/RuleAssignOutputElements.java 2010-05-04
14:06:31 UTC (rev 2096)
+++
trunk/engine/src/main/java/com/metamatrix/query/optimizer/relational/rules/RuleAssignOutputElements.java 2010-05-04
19:00:28 UTC (rev 2097)
@@ -194,12 +194,15 @@
break;
}
default: {
- GroupSymbol intoGroup =
(GroupSymbol)root.getProperty(NodeConstants.Info.INTO_GROUP);
- if (intoGroup != null) { //if this is a project into, treat the nodes under
the source as a new plan root
- PlanNode intoRoot = NodeEditor.findNodePreOrder(root,
NodeConstants.Types.SOURCE);
- execute(intoRoot.getFirstChild(), metadata, capFinder, rules,
analysisRecord, context);
- return;
- }
+ if (root.getType() == NodeConstants.Types.PROJECT) {
+ GroupSymbol intoGroup =
(GroupSymbol)root.getProperty(NodeConstants.Info.INTO_GROUP);
+ if (intoGroup != null) { //if this is a project into, treat the nodes under
the source as a new plan root
+ PlanNode intoRoot = NodeEditor.findNodePreOrder(root,
NodeConstants.Types.SOURCE);
+ execute(intoRoot.getFirstChild(), metadata, capFinder, rules,
analysisRecord, context);
+ return;
+ }
+ root.setProperty(NodeConstants.Info.PROJECT_COLS, outputElements);
+ }
List<SingleElementSymbol> requiredInput =
collectRequiredInputSymbols(root);
Modified: trunk/engine/src/main/javacc/com/metamatrix/query/parser/SQLParser.jj
===================================================================
--- trunk/engine/src/main/javacc/com/metamatrix/query/parser/SQLParser.jj 2010-05-04
14:06:31 UTC (rev 2096)
+++ trunk/engine/src/main/javacc/com/metamatrix/query/parser/SQLParser.jj 2010-05-04
19:00:28 UTC (rev 2097)
@@ -2904,7 +2904,7 @@
(
(funcToken = <LEFT> | funcToken = <RIGHT> | funcToken = <CHAR> |
funcToken = <USER>
| funcToken = <YEAR> | funcToken = <MONTH> | funcToken
= <HOUR>
- | funcToken = <MINUTE> | funcToken = <SECOND>)
+ | funcToken = <MINUTE> | funcToken = <SECOND> |
funcToken = <XMLELEMENT>)
<LPAREN>
[
expression = expression(info)
Modified: trunk/engine/src/main/resources/com/metamatrix/query/i18n.properties
===================================================================
--- trunk/engine/src/main/resources/com/metamatrix/query/i18n.properties 2010-05-04
14:06:31 UTC (rev 2096)
+++ trunk/engine/src/main/resources/com/metamatrix/query/i18n.properties 2010-05-04
19:00:28 UTC (rev 2097)
@@ -771,6 +771,10 @@
SystemSource.xsltransform_param1=Source document
SystemSource.xsltransform_param2=XSL stylesheet
SystemSource.xsltransform_result=Clob result
+SystemSource.xmlelement_description=Create an XML element.
+SystemSource.xmlelement_param1=Element name
+SystemSource.xmlelement_param2=Element contents
+SystemSource.xmlelement_result=XML result
SystemSource.modifyTimeZone_description=Modify the time zone of this timestamp by adding
or subtracting time
SystemSource.modifyTimeZone_param1=Timestamp
SystemSource.modifyTimeZone_param2=Starting time zone
Modified:
trunk/engine/src/test/java/com/metamatrix/query/function/TestFunctionLibrary.java
===================================================================
---
trunk/engine/src/test/java/com/metamatrix/query/function/TestFunctionLibrary.java 2010-05-04
14:06:31 UTC (rev 2096)
+++
trunk/engine/src/test/java/com/metamatrix/query/function/TestFunctionLibrary.java 2010-05-04
19:00:28 UTC (rev 2097)
@@ -1339,5 +1339,15 @@
String xml = ObjectConverterUtil.convertToString(result.getCharacterStream());
assertEquals("<?xml version=\"1.0\"
encoding=\"UTF-8\"?><Catalogs
xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"><...
ItemID=\"001\"><Name>Lamp</Name></Item></Items></Catalog></Catalogs>",
xml);
}
-
+
+ @Test public void testInvokeXmlElement() throws Exception {
+ CommandContext c = new CommandContext();
+ c.setBufferManager(BufferManagerFactory.getStandaloneBufferManager());
+ XMLType result = (XMLType)helpInvokeMethod("xmlelement", new Class[]
{DataTypeManager.DefaultDataClasses.STRING, DataTypeManager.DefaultDataClasses.OBJECT,
DataTypeManager.DefaultDataClasses.OBJECT},
+ new Object[] {"foo", "<bar>", new XMLType(new
SQLXMLImpl("<?xml version=\"1.0\"
encoding=\"UTF-8\"?><Catalogs
xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"><...
ItemID=\"001\"><Name>Lamp</Name><Quantity>5</Quantity></Item></Items></Catalog></Catalogs>"))},
c);
+
+ String xml = ObjectConverterUtil.convertToString(result.getCharacterStream());
+ assertEquals("<foo><bar><Catalogs
xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"><...
ItemID=\"001\"><Name>Lamp</Name><Quantity>5</Quantity></Item></Items></Catalog></Catalogs></foo>",
xml);
+ }
+
}
Modified: trunk/engine/src/test/java/com/metamatrix/query/processor/TestProcessor.java
===================================================================
---
trunk/engine/src/test/java/com/metamatrix/query/processor/TestProcessor.java 2010-05-04
14:06:31 UTC (rev 2096)
+++
trunk/engine/src/test/java/com/metamatrix/query/processor/TestProcessor.java 2010-05-04
19:00:28 UTC (rev 2097)
@@ -302,6 +302,7 @@
CommandContext context = new CommandContext("0", "test",
"user", null, "myvdb", 1, props, DEBUG, false); //$NON-NLS-1$
//$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
context.setProcessorBatchSize(2000);
context.setConnectorBatchSize(2000);
+ context.setBufferManager(BufferManagerFactory.getStandaloneBufferManager());
return context;
}
@@ -7482,6 +7483,25 @@
helpProcess(plan, dataManager, expected);
}
-
+ @Test public void testXmlElement() {
+ String sql = "SELECT xmlelement(e1, e2) from pm1.g1 order by e1, e2";
//$NON-NLS-1$
+
+ List[] expected = new List[] {
+ Arrays.asList(new String[] {null}),
+ Arrays.asList("<a>0</a>"),
+ Arrays.asList("<a>0</a>"),
+ Arrays.asList("<a>3</a>"),
+ Arrays.asList("<b>2</b>"),
+ Arrays.asList("<c>1</c>"),
+ };
+
+ FakeDataManager dataManager = new FakeDataManager();
+ sampleData1(dataManager);
+
+ ProcessorPlan plan = helpGetPlan(helpParse(sql),
FakeMetadataFactory.example1Cached());
+
+ helpProcess(plan, dataManager, expected);
+ }
+
private static final boolean DEBUG = false;
}