[teiid-commits] teiid SVN: r4223 - in trunk: engine/src/main/java/org/teiid/query/eval and 4 other directories.

teiid-commits at lists.jboss.org teiid-commits at lists.jboss.org
Thu Jul 5 16:35:50 EDT 2012


Author: shawkins
Date: 2012-07-05 16:35:48 -0400 (Thu, 05 Jul 2012)
New Revision: 4223

Added:
   trunk/engine/src/main/java/org/teiid/query/xquery/saxon/AbstractXMLStreamReader.java
   trunk/engine/src/main/java/org/teiid/query/xquery/saxon/XMLEventStreamReader.java
Modified:
   trunk/build/kits/jboss-as7/docs/teiid/teiid-releasenotes.html
   trunk/engine/src/main/java/org/teiid/query/eval/Evaluator.java
   trunk/engine/src/main/java/org/teiid/query/function/source/SystemSource.java
   trunk/engine/src/main/java/org/teiid/query/function/source/XMLSystemFunctions.java
   trunk/engine/src/main/java/org/teiid/query/xquery/saxon/PathMapFilter.java
   trunk/engine/src/main/java/org/teiid/query/xquery/saxon/SaxonXQueryExpression.java
   trunk/engine/src/main/java/org/teiid/query/xquery/saxon/XQueryEvaluator.java
   trunk/engine/src/test/java/org/teiid/query/function/source/TestXMLSystemFunctions.java
   trunk/engine/src/test/java/org/teiid/query/processor/TestSQLXMLProcessing.java
Log:
TEIID-2092 allowing for streaming json processing

Modified: trunk/build/kits/jboss-as7/docs/teiid/teiid-releasenotes.html
===================================================================
--- trunk/build/kits/jboss-as7/docs/teiid/teiid-releasenotes.html	2012-07-05 15:43:21 UTC (rev 4222)
+++ trunk/build/kits/jboss-as7/docs/teiid/teiid-releasenotes.html	2012-07-05 20:35:48 UTC (rev 4223)
@@ -28,6 +28,7 @@
 <UL>
   <li><B>VDB Reuse</B> a vdb.xml can now declare imported vdbs to reuse metadata.
   <LI><B>Comparable Object</B> - the system property org.teiid.comparableObject can be set to use OBJECT values in comparison/sorting/grouping operations.  It is expected that the object values correctly implement Comparable.compareTo.
+  <LI><B>Admin Metadata</B> - you can now retrieve metadata in DDL from the admin api via the getSchema method.
 </UL>
 
 <h2><a name="Compatibility">Compatibility Issues</a></h2>
@@ -48,6 +49,7 @@
   <li>VDB.Status now has three states - LOADING, ACTIVE, REMOVED.  To check for validity use the isValid method, rather than checking for the VALID state.
   <li>The standalone and cli configuration files specify a setting for the teiid subsystem policy-decider-module.  If a module is not specified, then data roles will not be checked.
   <li>local connections specifying a VDB version will wait for their VDB to finish loading before allowing a connection.
+  <li>jsonToXml document elements will contain xsi:type attribute values of decimal and boolean respectively for number and boolean json values to allow for differentiation from string values.
 <ul>
 
 <h4>from 7.x</h4>

Modified: trunk/engine/src/main/java/org/teiid/query/eval/Evaluator.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/eval/Evaluator.java	2012-07-05 15:43:21 UTC (rev 4222)
+++ trunk/engine/src/main/java/org/teiid/query/eval/Evaluator.java	2012-07-05 20:35:48 UTC (rev 4223)
@@ -77,6 +77,7 @@
 import org.teiid.query.xquery.saxon.XQueryEvaluator;
 import org.teiid.query.xquery.saxon.SaxonXQueryExpression.Result;
 import org.teiid.query.xquery.saxon.SaxonXQueryExpression.RowProcessor;
+import org.teiid.translator.SourceSystemFunctions;
 import org.teiid.translator.WSConnection.Util;
 
 public class Evaluator {
@@ -872,7 +873,7 @@
 			TeiidComponentException {
 		Object contextItem = null;
 		for (DerivedColumn passing : cols) {
-			Object value = this.evaluate(passing.getExpression(), tuple);
+			Object value = evaluateParameter(tuple, passing);
 			if (passing.getAlias() == null) {
 				contextItem = value;
 			} else {
@@ -882,6 +883,39 @@
 		return contextItem;
 	}
 
+	private Object evaluateParameter(List<?> tuple, DerivedColumn passing)
+			throws ExpressionEvaluationException, BlockedException,
+			TeiidComponentException {
+		if (passing.getExpression() instanceof Function) {
+			Function f = (Function)passing.getExpression();
+			//narrow optimization of json based documents to allow for lower overhead streaming
+			if (f.getFunctionDescriptor().getName().equalsIgnoreCase(SourceSystemFunctions.JSONTOXML)) {
+				String rootName = (String)this.evaluate(f.getArg(0), tuple);
+				Object lob = this.evaluate(f.getArg(1), tuple);
+				if (rootName == null || lob == null) {
+					return null;
+				}
+				try {
+					if (lob instanceof Blob) {
+						return XMLSystemFunctions.jsonToXml(context, rootName, (Blob)lob, true);
+					}
+					return XMLSystemFunctions.jsonToXml(context, rootName, (Clob)lob, true);
+				} catch (IOException e) {
+					throw new FunctionExecutionException(QueryPlugin.Event.TEIID30384, e, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30384, f.getFunctionDescriptor().getName()));
+				} catch (SQLException e) {
+					throw new FunctionExecutionException(QueryPlugin.Event.TEIID30384, e, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30384, f.getFunctionDescriptor().getName()));
+				} catch (TeiidProcessingException e) {
+					throw new FunctionExecutionException(QueryPlugin.Event.TEIID30384, e, QueryPlugin.Util.gs(QueryPlugin.Event.TEIID30384, f.getFunctionDescriptor().getName()));
+				}
+			}
+		} else if (passing.getExpression() instanceof XMLParse) {
+			XMLParse xmlParse = (XMLParse)passing.getExpression();
+			xmlParse.setWellFormed(true);
+		}
+		Object value = this.evaluate(passing.getExpression(), tuple);
+		return value;
+	}
+
 	private Evaluator.NameValuePair<Object>[] getNameValuePairs(List<?> tuple, List<DerivedColumn> args, boolean xmlNames)
 			throws ExpressionEvaluationException, BlockedException, TeiidComponentException {
 		Evaluator.NameValuePair<Object>[] nameValuePairs = new Evaluator.NameValuePair[args.size()];

Modified: trunk/engine/src/main/java/org/teiid/query/function/source/SystemSource.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/function/source/SystemSource.java	2012-07-05 15:43:21 UTC (rev 4222)
+++ trunk/engine/src/main/java/org/teiid/query/function/source/SystemSource.java	2012-07-05 20:35:48 UTC (rev 4223)
@@ -974,6 +974,12 @@
                     new FunctionParameter("document", DataTypeManager.DefaultDataTypes.CLOB, QueryPlugin.Util.getString("SystemSource.xpath_param1")), //$NON-NLS-1$ //$NON-NLS-2$
                     new FunctionParameter("xpath", DataTypeManager.DefaultDataTypes.STRING, QueryPlugin.Util.getString("SystemSource.xpath_param2"))}, //$NON-NLS-1$ //$NON-NLS-2$ 
                 new FunctionParameter("result", DataTypeManager.DefaultDataTypes.STRING, QueryPlugin.Util.getString("SystemSource.xpathvalue_result")) ) );       //$NON-NLS-1$ //$NON-NLS-2$
+
+        functions.add(new FunctionMethod(SourceSystemFunctions.XPATHVALUE, QueryPlugin.Util.getString("SystemSource.xpathvalue_description"), XML, XML_FUNCTION_CLASS, "xpathValue", //$NON-NLS-1$ //$NON-NLS-2$ 
+                new FunctionParameter[] { 
+                    new FunctionParameter("document", DataTypeManager.DefaultDataTypes.BLOB, QueryPlugin.Util.getString("SystemSource.xpath_param1")), //$NON-NLS-1$ //$NON-NLS-2$
+                    new FunctionParameter("xpath", DataTypeManager.DefaultDataTypes.STRING, QueryPlugin.Util.getString("SystemSource.xpath_param2"))}, //$NON-NLS-1$ //$NON-NLS-2$ 
+                new FunctionParameter("result", DataTypeManager.DefaultDataTypes.STRING, QueryPlugin.Util.getString("SystemSource.xpathvalue_result")) ) );       //$NON-NLS-1$ //$NON-NLS-2$
         
         functions.add(new FunctionMethod(SourceSystemFunctions.XPATHVALUE, QueryPlugin.Util.getString("SystemSource.xpathvalue_description"), XML, XML_FUNCTION_CLASS, "xpathValue", //$NON-NLS-1$ //$NON-NLS-2$ 
                                          new FunctionParameter[] { 

Modified: trunk/engine/src/main/java/org/teiid/query/function/source/XMLSystemFunctions.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/function/source/XMLSystemFunctions.java	2012-07-05 15:43:21 UTC (rev 4222)
+++ trunk/engine/src/main/java/org/teiid/query/function/source/XMLSystemFunctions.java	2012-07-05 20:35:48 UTC (rev 4223)
@@ -47,18 +47,19 @@
 import javax.xml.namespace.QName;
 import javax.xml.stream.EventFilter;
 import javax.xml.stream.FactoryConfigurationError;
+import javax.xml.stream.Location;
 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.XMLStreamWriter;
 import javax.xml.stream.events.XMLEvent;
 import javax.xml.transform.Source;
 import javax.xml.transform.Transformer;
 import javax.xml.transform.TransformerException;
 import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.stax.StAXSource;
 import javax.xml.transform.stream.StreamResult;
 import javax.xml.transform.stream.StreamSource;
 import javax.xml.xpath.XPathExpressionException;
@@ -83,6 +84,7 @@
 import org.teiid.common.buffer.FileStoreInputStreamFactory;
 import org.teiid.core.TeiidComponentException;
 import org.teiid.core.TeiidProcessingException;
+import org.teiid.core.TeiidRuntimeException;
 import org.teiid.core.types.ClobImpl;
 import org.teiid.core.types.ClobType;
 import org.teiid.core.types.SQLXMLImpl;
@@ -90,6 +92,7 @@
 import org.teiid.core.types.XMLTranslator;
 import org.teiid.core.types.XMLType;
 import org.teiid.core.types.XMLType.Type;
+import org.teiid.jdbc.TeiidSQLException;
 import org.teiid.query.QueryPlugin;
 import org.teiid.query.eval.Evaluator;
 import org.teiid.query.function.CharsetUtils;
@@ -110,50 +113,54 @@
 	private static final Charset UTF_16LE = Charset.forName("UTF-16LE"); //$NON-NLS-1$
 	private static final Charset UTF_8 = Charset.forName("UTF-8"); //$NON-NLS-1$
 
-	//TODO: this could be done fully streaming without holding the intermediate xml output
 	private static final class JsonToXmlContentHandler implements
-			ContentHandler {
-		private final XMLStreamWriter streamWriter;
+			ContentHandler, XMLEventReader {
+		private Reader reader;
+		private JSONParser parser;
+		private XMLEventFactory eventFactory;
+
+		private LinkedList<String> nameStack = new LinkedList<String>();
+		private LinkedList<XMLEvent> eventStack = new LinkedList<XMLEvent>();
+		
 		private boolean rootArray;
-		private LinkedList<String> nameStack = new LinkedList<String>();
+		private boolean end;
+		private boolean declaredNs;
 
 		private JsonToXmlContentHandler(String rootName,
-				XMLStreamWriter streamWriter) {
-			this.streamWriter = streamWriter;
-			this.nameStack.push(rootName);
+				Reader reader, JSONParser parser, XMLEventFactory eventFactory) {
+			this.nameStack.push(escapeName(rootName, true));
+			this.reader = reader;
+			this.eventFactory = eventFactory;
+			this.parser = parser;
 		}
 
 		@Override
 		public boolean startObjectEntry(String key)
 				throws org.json.simple.parser.ParseException, IOException {
-			this.nameStack.push(key);
-			return true;
+			this.nameStack.push(escapeName(key, true));
+			return false;
 		}
 
 		@Override
 		public boolean startObject() throws org.json.simple.parser.ParseException,
 				IOException {
 			start();
-			return true;
+			return false;
 		}
 
-		private void start()
-				throws IOException {
-			try {
-				streamWriter.writeStartElement(escapeName(this.nameStack.peek(), true));
-			} catch (XMLStreamException e) {
-				throw new IOException(e);
+		private void start() {
+			eventStack.add(eventFactory.createStartElement("", "", nameStack.peek())); //$NON-NLS-1$ //$NON-NLS-2$ 
+			if (!declaredNs) {
+				eventStack.add(eventFactory.createNamespace("xsi", XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI)); //$NON-NLS-1$
+				declaredNs = true;
 			}
 		}
 
 		@Override
 		public void startJSON() throws org.json.simple.parser.ParseException,
 				IOException {
-			try {
-				streamWriter.writeStartDocument();
-			} catch (XMLStreamException e) {
-				throw new IOException(e);
-			}
+			//specify the defaults, since different providers emit/omit differently
+			eventStack.add(eventFactory.createStartDocument("UTF-8", "1.0")); //$NON-NLS-1$ //$NON-NLS-2$
 		}
 
 		@Override
@@ -163,58 +170,55 @@
 				this.rootArray = true;
 				start();
 			}
-			return true;
+			return false;
 		}
 
 		@Override
 		public boolean primitive(Object value)
 				throws org.json.simple.parser.ParseException, IOException {
 			start();
-			try {
-				if (value != null) {
-					streamWriter.writeCharacters(value.toString());
-				} else {
-					streamWriter.writeNamespace("xsi", XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI); //$NON-NLS-1$
-					streamWriter.writeAttribute("xsi", XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, "nil", "true"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+			if (value != null) {
+				String type = "decimal"; //$NON-NLS-1$
+				if (value instanceof String) {
+					type = null;
+				} else if (value instanceof Boolean) {
+					type = "boolean"; //$NON-NLS-1$
 				}
-			} catch (XMLStreamException e) {
-				throw new IOException(e);
+				if (type != null) {
+					//we need to differentiate boolean/decimal entries from their string counter parts
+					eventStack.add(eventFactory.createAttribute("xsi", XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, "type", type)); //$NON-NLS-1$ //$NON-NLS-2$
+				}
+				eventStack.add(eventFactory.createCharacters(value.toString()));
+			} else {
+				eventStack.add(eventFactory.createAttribute("xsi", XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, "nil", "true")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
 			}
 			end();
-			return true;
+			return true; //return true, otherwise we don't get the endObjectEntry
 		}
 
-		private void end()
-				throws IOException {
-			try {
-				streamWriter.writeEndElement();
-			} catch (XMLStreamException e) {
-				throw new IOException(e);
-			}
+		private void end() {
+			eventStack.add(eventFactory.createEndElement("", "", nameStack.peek())); //$NON-NLS-1$ //$NON-NLS-2$ 
 		}
 
 		@Override
 		public boolean endObjectEntry()
 				throws org.json.simple.parser.ParseException, IOException {
 			this.nameStack.pop();
-			return true;
+			return false;
 		}
 
 		@Override
 		public boolean endObject() throws org.json.simple.parser.ParseException,
 				IOException {
 			end();
-			return true;
+			return false;
 		}
 
 		@Override
 		public void endJSON() throws org.json.simple.parser.ParseException,
 				IOException {
-			try {
-				streamWriter.writeEndDocument();
-			} catch (XMLStreamException e) {
-				throw new IOException(e);
-			}
+			this.eventStack.add(eventFactory.createEndDocument());
+			end = true;
 		}
 
 		@Override
@@ -223,8 +227,76 @@
 			if (this.nameStack.size() == 1 && rootArray) {
 				end();
 			}
-			return true;
+			return false;
 		}
+
+		@Override
+		public void close() throws XMLStreamException {
+			try {
+				//this is explicitly against the javadoc, but
+				//it's our only chance to close the reader
+				this.reader.close();
+			} catch (IOException e) {
+			}
+		}
+
+		@Override
+		public String getElementText() throws XMLStreamException {
+			throw new UnsupportedOperationException();
+		}
+
+		@Override
+		public Object getProperty(String name) throws IllegalArgumentException {
+			return null;
+		}
+
+		@Override
+		public boolean hasNext() {
+			return !eventStack.isEmpty() || !end;
+		}
+
+		@Override
+		public XMLEvent nextEvent() throws XMLStreamException {
+			while (eventStack.isEmpty() && !end) {
+				try {
+					parser.parse(reader, this, true);
+				} catch (IOException e) {
+					throw new XMLStreamException(e);
+				} catch (ParseException e) {
+					throw new XMLStreamException(e);
+				}
+			}
+			return eventStack.remove();
+		}
+
+		@Override
+		public XMLEvent nextTag() throws XMLStreamException {
+			throw new UnsupportedOperationException();
+		}
+
+		@Override
+		public XMLEvent peek() throws XMLStreamException {
+			if (hasNext()) {
+				XMLEvent next = next();
+				this.eventStack.push(next);
+				return next;
+			}
+			return null;
+		}
+
+		@Override
+		public XMLEvent next() {
+			try {
+				return nextEvent();
+			} catch (XMLStreamException e) {
+				throw new TeiidRuntimeException(e);
+			}
+		}
+
+		@Override
+		public void remove() {
+			throw new UnsupportedOperationException();			
+		}
 	}
 	
 	private static ThreadLocal<TransformerFactory> threadLocalTransformerFactory = new ThreadLocal<TransformerFactory>() {
@@ -239,8 +311,13 @@
 	};
 	static ThreadLocal<XMLEventFactory> threadLocalEventtFactory = new ThreadLocal<XMLEventFactory>() {
 		protected XMLEventFactory initialValue() {
-			return XMLEventFactory.newInstance();
+			return XMLEventFactory.newFactory();
 		}
+		public XMLEventFactory get() {
+			XMLEventFactory eventFactory = super.get();
+			eventFactory.setLocation(null);
+			return eventFactory;
+		}
 	};
 	private static final String P_OUTPUT_VALIDATE_STRUCTURE = "com.ctc.wstx.outputValidateStructure"; //$NON-NLS-1$
 	static XMLOutputFactory newXmlOutputFactory() throws FactoryConfigurationError {
@@ -436,7 +513,7 @@
 				fs.remove();
 				 throw new TeiidProcessingException(QueryPlugin.Event.TEIID30437, e);
 			}
-			eventFactory = XMLEventFactory.newInstance();
+			eventFactory = threadLocalEventtFactory.get();
 		}
 		
 		public void addValue(Object object) throws TeiidProcessingException {
@@ -712,6 +789,10 @@
 	}
 
     public static SQLXML jsonToXml(CommandContext context, final String rootName, final Blob json) throws TeiidComponentException, TeiidProcessingException, SQLException, IOException {
+    	return jsonToXml(context, rootName, json, false);
+    }
+    
+    public static SQLXML jsonToXml(CommandContext context, final String rootName, final Blob json, boolean stream) throws TeiidComponentException, TeiidProcessingException, SQLException, IOException {
 		InputStream is = json.getBinaryStream();
 		PushbackInputStream pStream = new PushbackInputStream(is, 4);
 		byte[] encoding = new byte[3];
@@ -734,33 +815,81 @@
 			}
 		}
 		Reader r = new InputStreamReader(pStream, charset);
-		return jsonToXml(context, rootName, r);
+		return jsonToXml(context, rootName, r, stream);
     }
-	
+    
     public static SQLXML jsonToXml(CommandContext context, final String rootName, final Clob json) throws TeiidComponentException, TeiidProcessingException, SQLException {
-		return jsonToXml(context, rootName, json.getCharacterStream());
+    	return jsonToXml(context, rootName, json, false);
     }
-
+    
+    public static SQLXML jsonToXml(CommandContext context, final String rootName, final Clob json, boolean stream) throws TeiidComponentException, TeiidProcessingException, SQLException {
+		return jsonToXml(context, rootName, json.getCharacterStream(), stream);
+    }
+    
 	private static SQLXML jsonToXml(CommandContext context,
-			final String rootName, final Reader r) throws TeiidComponentException,
+			final String rootName, final Reader r, boolean stream) throws TeiidComponentException,
 			TeiidProcessingException {
+    	JSONParser parser = new JSONParser();
+    	final JsonToXmlContentHandler reader = new JsonToXmlContentHandler(rootName, r, parser, threadLocalEventtFactory.get());
+
+		if (stream) {
+			//jre 1.7 event logic does not set a dummy location and throws an NPE in StAXSource, so we explicitly set a location
+			reader.eventFactory.setLocation(new Location() {
+				
+				@Override
+				public String getSystemId() {
+					return null;
+				}
+				
+				@Override
+				public String getPublicId() {
+					return null;
+				}
+				
+				@Override
+				public int getLineNumber() {
+					return -1;
+				}
+				
+				@Override
+				public int getColumnNumber() {
+					return -1;
+				}
+				
+				@Override
+				public int getCharacterOffset() {
+					return -1;
+				}
+			});
+			return new SQLXMLImpl() {
+				@SuppressWarnings("unchecked")
+				public <T extends Source> T getSource(Class<T> sourceClass) throws SQLException {
+					if (sourceClass == null || sourceClass == StAXSource.class) {
+						StAXSource source;
+						try {
+							source = new StAXSource(reader);
+						} catch (XMLStreamException e) {
+							throw TeiidSQLException.create(e);
+						}
+						return (T) source;
+					}
+					throw new AssertionError("unsupported source type"); //$NON-NLS-1$
+				}
+			};
+		}
 		XMLType result = new XMLType(XMLSystemFunctions.saveToBufferManager(context.getBufferManager(), new XMLTranslator() {
 			
 			@Override
 			public void translate(Writer writer) throws TransformerException,
 					IOException {
 		    	try {
-			    	JSONParser parser = new JSONParser();
 					XMLOutputFactory factory = getOutputFactory();
-					final XMLStreamWriter streamWriter = factory.createXMLStreamWriter(writer);
-			    	
-					parser.parse(r, new JsonToXmlContentHandler(escapeName(rootName, true), streamWriter));
-		    		
+					final XMLEventWriter streamWriter = factory.createXMLEventWriter(writer);
+
+			    	streamWriter.add(reader);
 					streamWriter.flush(); //woodstox needs a flush rather than a close
 				} catch (XMLStreamException e) {
 					throw new TransformerException(e);
-				} catch (ParseException e) {
-					throw new TransformerException(e);
 				} finally {
 		    		try {
 	    				r.close();

Added: trunk/engine/src/main/java/org/teiid/query/xquery/saxon/AbstractXMLStreamReader.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/xquery/saxon/AbstractXMLStreamReader.java	                        (rev 0)
+++ trunk/engine/src/main/java/org/teiid/query/xquery/saxon/AbstractXMLStreamReader.java	2012-07-05 20:35:48 UTC (rev 4223)
@@ -0,0 +1,180 @@
+/*
+ * Copyright 2002-2009 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
+ *
+ *      http://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 org.teiid.query.xquery.saxon;
+
+import javax.xml.namespace.QName;
+import javax.xml.stream.XMLStreamConstants;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+
+/**
+ * Abstract base class for <code>XMLStreamReader</code>s.
+ *
+ * @author Arjen Poutsma
+ * @since 3.0
+ */
+abstract class AbstractXMLStreamReader implements XMLStreamReader {
+
+	public String getElementText() throws XMLStreamException {
+		if (getEventType() != XMLStreamConstants.START_ELEMENT) {
+			throw new XMLStreamException("parser must be on START_ELEMENT to read next text", getLocation());
+		}
+		int eventType = next();
+		StringBuilder builder = new StringBuilder();
+		while (eventType != XMLStreamConstants.END_ELEMENT) {
+			if (eventType == XMLStreamConstants.CHARACTERS || eventType == XMLStreamConstants.CDATA ||
+					eventType == XMLStreamConstants.SPACE || eventType == XMLStreamConstants.ENTITY_REFERENCE) {
+				builder.append(getText());
+			}
+			else if (eventType == XMLStreamConstants.PROCESSING_INSTRUCTION ||
+					eventType == XMLStreamConstants.COMMENT) {
+				// skipping
+			}
+			else if (eventType == XMLStreamConstants.END_DOCUMENT) {
+				throw new XMLStreamException("unexpected end of document when reading element text content",
+						getLocation());
+			}
+			else if (eventType == XMLStreamConstants.START_ELEMENT) {
+				throw new XMLStreamException("element text content may not contain START_ELEMENT", getLocation());
+			}
+			else {
+				throw new XMLStreamException("Unexpected event type " + eventType, getLocation());
+			}
+			eventType = next();
+		}
+		return builder.toString();
+	}
+
+	public String getAttributeLocalName(int index) {
+		return getAttributeName(index).getLocalPart();
+	}
+
+	public String getAttributeNamespace(int index) {
+		return getAttributeName(index).getNamespaceURI();
+	}
+
+	public String getAttributePrefix(int index) {
+		return getAttributeName(index).getPrefix();
+	}
+
+	public String getNamespaceURI() {
+		int eventType = getEventType();
+		if (eventType == XMLStreamConstants.START_ELEMENT || eventType == XMLStreamConstants.END_ELEMENT) {
+			return getName().getNamespaceURI();
+		}
+		else {
+			throw new IllegalStateException("parser must be on START_ELEMENT or END_ELEMENT state");
+		}
+	}
+
+	public String getNamespaceURI(String prefix) {
+		return getNamespaceContext().getNamespaceURI(prefix);
+	}
+
+	public boolean hasText() {
+		int eventType = getEventType();
+		return eventType == XMLStreamConstants.SPACE || eventType == XMLStreamConstants.CHARACTERS ||
+				eventType == XMLStreamConstants.COMMENT || eventType == XMLStreamConstants.CDATA ||
+				eventType == XMLStreamConstants.ENTITY_REFERENCE;
+	}
+
+	public String getPrefix() {
+		int eventType = getEventType();
+		if (eventType == XMLStreamConstants.START_ELEMENT || eventType == XMLStreamConstants.END_ELEMENT) {
+			return getName().getPrefix();
+		}
+		else {
+			throw new IllegalStateException("parser must be on START_ELEMENT or END_ELEMENT state");
+		}
+	}
+
+	public boolean hasName() {
+		int eventType = getEventType();
+		return eventType == XMLStreamConstants.START_ELEMENT || eventType == XMLStreamConstants.END_ELEMENT;
+	}
+
+	public boolean isWhiteSpace() {
+		return getEventType() == XMLStreamConstants.SPACE;
+	}
+
+	public boolean isStartElement() {
+		return getEventType() == XMLStreamConstants.START_ELEMENT;
+	}
+
+	public boolean isEndElement() {
+		return getEventType() == XMLStreamConstants.END_ELEMENT;
+	}
+
+	public boolean isCharacters() {
+		return getEventType() == XMLStreamConstants.CHARACTERS;
+	}
+
+	public int nextTag() throws XMLStreamException {
+		int eventType = next();
+		while (eventType == XMLStreamConstants.CHARACTERS && isWhiteSpace() ||
+				eventType == XMLStreamConstants.CDATA && isWhiteSpace() || eventType == XMLStreamConstants.SPACE ||
+				eventType == XMLStreamConstants.PROCESSING_INSTRUCTION || eventType == XMLStreamConstants.COMMENT) {
+			eventType = next();
+		}
+		if (eventType != XMLStreamConstants.START_ELEMENT && eventType != XMLStreamConstants.END_ELEMENT) {
+			throw new XMLStreamException("expected start or end tag", getLocation());
+		}
+		return eventType;
+	}
+
+	public void require(int expectedType, String namespaceURI, String localName) throws XMLStreamException {
+		int eventType = getEventType();
+		if (eventType != expectedType) {
+			throw new XMLStreamException("Expected [" + expectedType + "] but read [" + eventType + "]");
+		}
+	}
+
+	public String getAttributeValue(String namespaceURI, String localName) {
+		for (int i = 0; i < getAttributeCount(); i++) {
+			QName name = getAttributeName(i);
+			if (name.getLocalPart().equals(localName) &&
+					(namespaceURI == null || name.getNamespaceURI().equals(namespaceURI))) {
+				return getAttributeValue(i);
+			}
+		}
+		return null;
+	}
+
+	public boolean hasNext() throws XMLStreamException {
+		return getEventType() != END_DOCUMENT;
+	}
+
+	public String getLocalName() {
+		return getName().getLocalPart();
+	}
+
+	public char[] getTextCharacters() {
+		return getText().toCharArray();
+	}
+
+	public int getTextCharacters(int sourceStart, char[] target, int targetStart, int length)
+			throws XMLStreamException {
+		char[] source = getTextCharacters();
+		length = Math.min(length, source.length);
+		System.arraycopy(source, sourceStart, target, targetStart, length);
+		return length;
+	}
+
+	public int getTextLength() {
+		return getText().length();
+	}
+}


Property changes on: trunk/engine/src/main/java/org/teiid/query/xquery/saxon/AbstractXMLStreamReader.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Modified: trunk/engine/src/main/java/org/teiid/query/xquery/saxon/PathMapFilter.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/xquery/saxon/PathMapFilter.java	2012-07-05 15:43:21 UTC (rev 4222)
+++ trunk/engine/src/main/java/org/teiid/query/xquery/saxon/PathMapFilter.java	2012-07-05 20:35:48 UTC (rev 4223)
@@ -86,7 +86,7 @@
 		}
 	}
 
-	
+	private boolean closed;
 	private LinkedList<MatchContext> matchContext = new LinkedList<MatchContext>();
 	
 	public PathMapFilter(PathMapRoot root) {
@@ -192,5 +192,13 @@
 			super.startContent();
 		}
 	}
+	
+	@Override
+	public void close() throws XPathException {
+		if (!closed) {
+			super.close();
+			closed = true;
+		}
+	}
 
 }
\ No newline at end of file

Modified: trunk/engine/src/main/java/org/teiid/query/xquery/saxon/SaxonXQueryExpression.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/xquery/saxon/SaxonXQueryExpression.java	2012-07-05 15:43:21 UTC (rev 4222)
+++ trunk/engine/src/main/java/org/teiid/query/xquery/saxon/SaxonXQueryExpression.java	2012-07-05 20:35:48 UTC (rev 4223)
@@ -33,10 +33,12 @@
 import java.util.Map;
 import java.util.Properties;
 
+import javax.xml.stream.XMLStreamException;
 import javax.xml.transform.ErrorListener;
 import javax.xml.transform.OutputKeys;
 import javax.xml.transform.Source;
 import javax.xml.transform.TransformerException;
+import javax.xml.transform.stax.StAXSource;
 
 import net.sf.saxon.Configuration;
 import net.sf.saxon.expr.AxisExpression;
@@ -115,6 +117,20 @@
 		public void close() {
 			for (Source source : sources) {
 				Util.closeSource(source);
+				if (source instanceof StAXSource) {
+					StAXSource ss = (StAXSource)source;
+					if (ss.getXMLEventReader() != null) {
+						try {
+							ss.getXMLEventReader().close();
+						} catch (XMLStreamException e) {
+						}
+					} else {
+						try {
+							ss.getXMLStreamReader().close();
+						} catch (XMLStreamException e) {
+						}
+					}
+				}
 			}
 			if (iter != null) {
 				iter.close();

Added: trunk/engine/src/main/java/org/teiid/query/xquery/saxon/XMLEventStreamReader.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/xquery/saxon/XMLEventStreamReader.java	                        (rev 0)
+++ trunk/engine/src/main/java/org/teiid/query/xquery/saxon/XMLEventStreamReader.java	2012-07-05 20:35:48 UTC (rev 4223)
@@ -0,0 +1,256 @@
+/*
+ * Copyright 2002-2010 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
+ *
+ *      http://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 org.teiid.query.xquery.saxon;
+
+import java.util.Iterator;
+
+import javax.xml.namespace.NamespaceContext;
+import javax.xml.namespace.QName;
+import javax.xml.stream.Location;
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.events.Attribute;
+import javax.xml.stream.events.Namespace;
+import javax.xml.stream.events.ProcessingInstruction;
+import javax.xml.stream.events.StartDocument;
+import javax.xml.stream.events.XMLEvent;
+
+/**
+ * Implementation of the {@link javax.xml.stream.XMLStreamReader} interface that wraps a {@link XMLEventReader}. Useful,
+ * because the StAX {@link javax.xml.stream.XMLInputFactory} allows one to create a event reader from a stream reader,
+ * but not vice-versa.
+ *
+ * @author Arjen Poutsma
+ * @since 3.0
+ * @see StaxUtils#createEventStreamReader(javax.xml.stream.XMLEventReader)
+ */
+class XMLEventStreamReader extends AbstractXMLStreamReader {
+
+	private XMLEvent event;
+
+	private final XMLEventReader eventReader;
+
+	XMLEventStreamReader(XMLEventReader eventReader) throws XMLStreamException {
+		this.eventReader = eventReader;
+		event = eventReader.nextEvent();
+	}
+
+	public boolean isStandalone() {
+		if (event.isStartDocument()) {
+			return ((StartDocument) event).isStandalone();
+		}
+		else {
+			throw new IllegalStateException();
+		}
+	}
+
+	public String getVersion() {
+		if (event.isStartDocument()) {
+			return ((StartDocument) event).getVersion();
+		}
+		else {
+			return null;
+		}
+	}
+
+	public int getTextStart() {
+		return 0;
+	}
+
+	public String getText() {
+		if (event.isCharacters()) {
+			return event.asCharacters().getData();
+		}
+		else {
+			throw new IllegalStateException();
+		}
+	}
+
+	public String getPITarget() {
+		if (event.isProcessingInstruction()) {
+			return ((ProcessingInstruction) event).getTarget();
+		}
+		else {
+			throw new IllegalStateException();
+		}
+	}
+
+	public String getPIData() {
+		if (event.isProcessingInstruction()) {
+			return ((ProcessingInstruction) event).getData();
+		}
+		else {
+			throw new IllegalStateException();
+		}
+	}
+
+	public int getNamespaceCount() {
+		Iterator namespaces;
+		if (event.isStartElement()) {
+			namespaces = event.asStartElement().getNamespaces();
+		}
+		else if (event.isEndElement()) {
+			namespaces = event.asEndElement().getNamespaces();
+		}
+		else {
+			throw new IllegalStateException();
+		}
+		return countIterator(namespaces);
+	}
+
+	public NamespaceContext getNamespaceContext() {
+		if (event.isStartElement()) {
+			return event.asStartElement().getNamespaceContext();
+		}
+		else {
+			throw new IllegalStateException();
+		}
+	}
+
+	public QName getName() {
+		if (event.isStartElement()) {
+			return event.asStartElement().getName();
+		}
+		else if (event.isEndElement()) {
+			return event.asEndElement().getName();
+		}
+		else {
+			throw new IllegalStateException();
+		}
+	}
+
+	public Location getLocation() {
+		return event.getLocation();
+	}
+
+	public int getEventType() {
+		return event.getEventType();
+	}
+
+	public String getEncoding() {
+		return null;
+	}
+
+	public String getCharacterEncodingScheme() {
+		return null;
+	}
+
+	public int getAttributeCount() {
+		if (!event.isStartElement()) {
+			throw new IllegalStateException();
+		}
+		Iterator attributes = event.asStartElement().getAttributes();
+		return countIterator(attributes);
+	}
+
+	public void close() throws XMLStreamException {
+		eventReader.close();
+	}
+
+	public QName getAttributeName(int index) {
+		return getAttribute(index).getName();
+	}
+
+	public String getAttributeType(int index) {
+		return getAttribute(index).getDTDType();
+	}
+
+	public String getAttributeValue(int index) {
+		return getAttribute(index).getValue();
+	}
+
+	public String getNamespacePrefix(int index) {
+		return getNamespace(index).getPrefix();
+	}
+
+	public String getNamespaceURI(int index) {
+		return getNamespace(index).getNamespaceURI();
+	}
+
+	public Object getProperty(String name) throws IllegalArgumentException {
+		return eventReader.getProperty(name);
+	}
+
+	public boolean isAttributeSpecified(int index) {
+		return getAttribute(index).isSpecified();
+	}
+
+	public int next() throws XMLStreamException {
+		event = eventReader.nextEvent();
+		return event.getEventType();
+	}
+
+	public boolean standaloneSet() {
+		if (event.isStartDocument()) {
+			return ((StartDocument) event).standaloneSet();
+		}
+		else {
+			throw new IllegalStateException();
+		}
+	}
+
+	private int countIterator(Iterator iterator) {
+		int count = 0;
+		while (iterator.hasNext()) {
+			iterator.next();
+			count++;
+		}
+		return count;
+	}
+
+	private Attribute getAttribute(int index) {
+		if (!event.isStartElement()) {
+			throw new IllegalStateException();
+		}
+		int count = 0;
+		Iterator attributes = event.asStartElement().getAttributes();
+		while (attributes.hasNext()) {
+			Attribute attribute = (Attribute) attributes.next();
+			if (count == index) {
+				return attribute;
+			}
+			else {
+				count++;
+			}
+		}
+		throw new IllegalArgumentException();
+	}
+
+	private Namespace getNamespace(int index) {
+		Iterator namespaces;
+		if (event.isStartElement()) {
+			namespaces = event.asStartElement().getNamespaces();
+		}
+		else if (event.isEndElement()) {
+			namespaces = event.asEndElement().getNamespaces();
+		}
+		else {
+			throw new IllegalStateException();
+		}
+		int count = 0;
+		while (namespaces.hasNext()) {
+			Namespace namespace = (Namespace) namespaces.next();
+			if (count == index) {
+				return namespace;
+			}
+			else {
+				count++;
+			}
+		}
+		throw new IllegalArgumentException();
+	}
+}


Property changes on: trunk/engine/src/main/java/org/teiid/query/xquery/saxon/XMLEventStreamReader.java
___________________________________________________________________
Added: svn:mime-type
   + text/plain

Modified: trunk/engine/src/main/java/org/teiid/query/xquery/saxon/XQueryEvaluator.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/xquery/saxon/XQueryEvaluator.java	2012-07-05 15:43:21 UTC (rev 4222)
+++ trunk/engine/src/main/java/org/teiid/query/xquery/saxon/XQueryEvaluator.java	2012-07-05 20:35:48 UTC (rev 4223)
@@ -27,12 +27,16 @@
 import java.sql.SQLXML;
 import java.util.Map;
 
+import javax.xml.stream.XMLStreamException;
 import javax.xml.transform.Source;
 import javax.xml.transform.TransformerException;
+import javax.xml.transform.stax.StAXSource;
 
 import net.sf.saxon.AugmentedSource;
 import net.sf.saxon.Configuration;
 import net.sf.saxon.event.ProxyReceiver;
+import net.sf.saxon.evpull.PullEventSource;
+import net.sf.saxon.evpull.StaxToEventBridge;
 import net.sf.saxon.om.DocumentInfo;
 import net.sf.saxon.om.NodeInfo;
 import net.sf.saxon.query.DynamicQueryContext;
@@ -83,6 +87,7 @@
 		            if(value instanceof SQLXML) {                    
 		            	value = XMLSystemFunctions.convertToSource(value);
 		            	result.sources.add((Source)value);
+		            	value = wrapStax((Source)value, xquery.getConfig());
 		            } else if (value instanceof java.util.Date) {
 		            	value = XMLSystemFunctions.convertToAtomicValue(value);
 		            }
@@ -94,6 +99,7 @@
 	        if (context != null) {
 	        	Source source = XMLSystemFunctions.convertToSource(context);
 	        	result.sources.add(source);
+	        	source = wrapStax(source, xquery.getConfig());
 	            if (xquery.contextRoot != null) {
 	            	//create our own filter as this logic is not provided in the free saxon
 	                ProxyReceiver filter = new PathMapFilter(xquery.contextRoot);
@@ -158,6 +164,27 @@
 	    }
 	}
 
+	private static Source wrapStax(Source value, Configuration config) throws TeiidProcessingException {
+		if (value instanceof StAXSource) {
+			//saxon doesn't like staxsources
+			StaxToEventBridge sb = new StaxToEventBridge();
+			sb.setPipelineConfiguration(config.makePipelineConfiguration());
+			StAXSource staxSource = (StAXSource)value;
+			if (staxSource.getXMLEventReader() != null) {
+				try {
+					sb.setXMLStreamReader(new XMLEventStreamReader(staxSource.getXMLEventReader()));
+				} catch (XMLStreamException e) {
+					//should not happen as the StAXSource already peeked
+					throw new TeiidProcessingException(e);
+				}
+			} else {
+				sb.setXMLStreamReader(staxSource.getXMLStreamReader());
+			}
+			value = new PullEventSource(sb);
+		}
+		return value;
+	}
+
 	/**
 	 * Converts a xom node into something readable by Saxon
 	 * @param node

Modified: trunk/engine/src/test/java/org/teiid/query/function/source/TestXMLSystemFunctions.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/function/source/TestXMLSystemFunctions.java	2012-07-05 15:43:21 UTC (rev 4222)
+++ trunk/engine/src/test/java/org/teiid/query/function/source/TestXMLSystemFunctions.java	2012-07-05 20:35:48 UTC (rev 4223)
@@ -194,7 +194,7 @@
 	
 	@Test public void testJsonToXml() throws Exception {
 		String json = "[0,{\"1\":{\"2\":{\"3\":{\"4\":[5,{\"6\":7}]}}}}]";
-		String expected = "<?xml version=\"1.0\" ?><Array><Array>0</Array><Array><_u0031_><_u0032_><_u0033_><_u0034_>5</_u0034_><_u0034_><_u0036_>7</_u0036_></_u0034_></_u0033_></_u0032_></_u0031_></Array></Array>";
+		String expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><Array xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"><Array xsi:type=\"decimal\">0</Array><Array><_u0031_><_u0032_><_u0033_><_u0034_ xsi:type=\"decimal\">5</_u0034_><_u0034_><_u0036_ xsi:type=\"decimal\">7</_u0036_></_u0034_></_u0033_></_u0032_></_u0031_></Array></Array>";
 		helpTestJson(json, "Array", expected);
 	}
 
@@ -214,25 +214,25 @@
 	@Test public void testJsonToXml1() throws Exception {
 		String json = "{ \"firstName\": \"John\", \"lastName\": \"Smith\", \"age\": 25, \"address\": { \"streetAddress\": \"21 2nd Street\", \"city\": \"New York\", \"state\": \"NY\", "+
 		         "\"postalCode\": \"10021\" }, \"phoneNumber\": [ { \"type\": \"home\", \"number\": \"212 555-1234\" }, { \"type\": \"fax\", \"number\": \"646 555-4567\" } ] }"; 
-		String expected = "<?xml version=\"1.0\" ?><Person><firstName>John</firstName><lastName>Smith</lastName><age>25</age><address><streetAddress>21 2nd Street</streetAddress><city>New York</city><state>NY</state><postalCode>10021</postalCode></address><phoneNumber><type>home</type><number>212 555-1234</number></phoneNumber><phoneNumber><type>fax</type><number>646 555-4567</number></phoneNumber></Person>";
+		String expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><Person xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"><firstName>John</firstName><lastName>Smith</lastName><age xsi:type=\"decimal\">25</age><address><streetAddress>21 2nd Street</streetAddress><city>New York</city><state>NY</state><postalCode>10021</postalCode></address><phoneNumber><type>home</type><number>212 555-1234</number></phoneNumber><phoneNumber><type>fax</type><number>646 555-4567</number></phoneNumber></Person>";
 		helpTestJson(json, "Person", expected);
 	}
 	
 	@Test public void testJsonToXml2() throws Exception {
 		String json = "{ \"firstName\": null }"; 
-		String expected = "<?xml version=\"1.0\" ?><Person><firstName xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:nil=\"true\"></firstName></Person>";
+		String expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><Person xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"><firstName xsi:nil=\"true\"></firstName></Person>";
 		helpTestJson(json, "Person", expected);
 	}
 	
 	@Test public void testJsonToXml3() throws Exception {
 		String json = "{ \"kids\":[{ \"firstName\" : \"George\" }, { \"firstName\" : \"Jerry\" }]}"; 
-		String expected = "<?xml version=\"1.0\" ?><Person><kids><firstName>George</firstName></kids><kids><firstName>Jerry</firstName></kids></Person>";
+		String expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><Person xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"><kids><firstName>George</firstName></kids><kids><firstName>Jerry</firstName></kids></Person>";
 		helpTestJson(json, "Person", expected);
 	}
 	
 	@Test public void testJsonToXml4() throws Exception {
 		String json = "{ \"kids\":[{ \"firstName\" : \"George\" }, { \"firstName\" : \"Jerry\" }]}"; 
-		String expected = "<?xml version=\"1.0\" ?><Person><kids><firstName>George</firstName></kids><kids><firstName>Jerry</firstName></kids></Person>";
+		String expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><Person xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"><kids><firstName>George</firstName></kids><kids><firstName>Jerry</firstName></kids></Person>";
 		helpTestJson(json, "Person", expected);
 	}
 
@@ -242,7 +242,7 @@
 	 */
 	@Test public void testJsonToXml5() throws Exception {
 		String json = "[[],{\"x\": 1},[]]"; 
-		String expected = "<?xml version=\"1.0\" ?><Person><Person></Person><Person><x>1</x></Person><Person></Person></Person>";
+		String expected = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><Person xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"><Person></Person><Person><x xsi:type=\"decimal\">1</x></Person><Person></Person></Person>";
 		helpTestJson(json, "Person", expected);
 	}
 	

Modified: trunk/engine/src/test/java/org/teiid/query/processor/TestSQLXMLProcessing.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/processor/TestSQLXMLProcessing.java	2012-07-05 15:43:21 UTC (rev 4222)
+++ trunk/engine/src/test/java/org/teiid/query/processor/TestSQLXMLProcessing.java	2012-07-05 20:35:48 UTC (rev 4223)
@@ -27,6 +27,7 @@
 import java.io.FileInputStream;
 import java.io.InputStreamReader;
 import java.nio.charset.Charset;
+import java.sql.Blob;
 import java.sql.Timestamp;
 import java.util.Arrays;
 import java.util.List;
@@ -515,4 +516,18 @@
         process(sql, expected);
     }
     
+	@Test public void testJsonStreamingXmlTable() throws Exception {
+		String sql = "select * from xmltable('/Person/phoneNumber' passing jsontoxml('Person', cast(? as blob)) columns x string path 'type', y string path 'number') as x"; //$NON-NLS-1$
+
+		List<?>[] expected = new List<?>[] {
+        		Arrays.asList("home", "212 555-1234"),
+        		Arrays.asList("fax", "646 555-4567"),
+        };    
+    
+		Blob b = BlobType.createBlob(("{ \"firstName\": \"John\", \"lastName\": \"Smith\", \"age\": 25, \"address\": { \"streetAddress\": \"21 2nd Street\", \"city\": \"New York\", \"state\": \"NY\", "+
+        "\"postalCode\": \"10021\" }, \"phoneNumber\": [ { \"type\": \"home\", \"number\": \"212 555-1234\" }, { \"type\": \"fax\", \"number\": \"646 555-4567\" } ] }").getBytes(Charset.forName("UTF-8")));
+		
+		processPreparedStatement(sql, expected, dataManager, new DefaultCapabilitiesFinder(), RealMetadataFactory.example1Cached(), Arrays.asList(b));
+	}
+    
 }



More information about the teiid-commits mailing list