[teiid-commits] teiid SVN: r2185 - in trunk/engine/src: main/java/org/teiid/query/processor/relational and 8 other directories.

teiid-commits at lists.jboss.org teiid-commits at lists.jboss.org
Sun Jun 6 11:12:21 EDT 2010


Author: shawkins
Date: 2010-06-06 11:12:19 -0400 (Sun, 06 Jun 2010)
New Revision: 2185

Added:
   trunk/engine/src/test/java/org/teiid/query/xquery/saxon/
   trunk/engine/src/test/java/org/teiid/query/xquery/saxon/TestSaxonXQueryExpression.java
Modified:
   trunk/engine/src/main/java/org/teiid/query/optimizer/relational/PlanToProcessConverter.java
   trunk/engine/src/main/java/org/teiid/query/processor/relational/RelationalNode.java
   trunk/engine/src/main/java/org/teiid/query/processor/relational/SubqueryAwareRelationalNode.java
   trunk/engine/src/main/java/org/teiid/query/processor/relational/TextTableNode.java
   trunk/engine/src/main/java/org/teiid/query/processor/relational/XMLTableNode.java
   trunk/engine/src/main/java/org/teiid/query/rewriter/QueryRewriter.java
   trunk/engine/src/main/java/org/teiid/query/sql/lang/XMLTable.java
   trunk/engine/src/main/java/org/teiid/query/validator/ValidationVisitor.java
   trunk/engine/src/main/java/org/teiid/query/xquery/saxon/SaxonXQueryExpression.java
   trunk/engine/src/main/resources/org/teiid/query/i18n.properties
   trunk/engine/src/test/java/org/teiid/query/processor/TestSQLXMLProcessing.java
Log:
TEIID-1087 TEIID-171 refining xquery analysis based upon saxon path maps.  memory usage will be nearly as good as xom/nux, but there are far fewer restrictions on the row path expression.  

Modified: trunk/engine/src/main/java/org/teiid/query/optimizer/relational/PlanToProcessConverter.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/optimizer/relational/PlanToProcessConverter.java	2010-06-05 01:49:35 UTC (rev 2184)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/PlanToProcessConverter.java	2010-06-06 15:12:19 UTC (rev 2185)
@@ -22,9 +22,11 @@
 
 package org.teiid.query.optimizer.relational;
 
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 
 import org.teiid.api.exception.query.QueryMetadataException;
 import org.teiid.api.exception.query.QueryPlannerException;
@@ -69,6 +71,7 @@
 import org.teiid.query.processor.relational.SortNode;
 import org.teiid.query.processor.relational.TextTableNode;
 import org.teiid.query.processor.relational.UnionAllNode;
+import org.teiid.query.processor.relational.XMLTableNode;
 import org.teiid.query.processor.relational.JoinNode.JoinStrategyType;
 import org.teiid.query.processor.relational.MergeJoinStrategy.SortOption;
 import org.teiid.query.processor.relational.SortUtility.Mode;
@@ -83,6 +86,7 @@
 import org.teiid.query.sql.lang.TextTable;
 import org.teiid.query.sql.lang.XMLTable;
 import org.teiid.query.sql.lang.SetQuery.Operation;
+import org.teiid.query.sql.lang.XMLTable.XMLColumn;
 import org.teiid.query.sql.symbol.ElementSymbol;
 import org.teiid.query.sql.symbol.Expression;
 import org.teiid.query.sql.symbol.GroupSymbol;
@@ -369,15 +373,30 @@
 				}
 				Object source = node.getProperty(NodeConstants.Info.TABLE_FUNCTION);
 				if (source instanceof XMLTable) {
-					return null;
+					XMLTable xt = (XMLTable)source;
+					XMLTableNode xtn = new XMLTableNode(getID());
+					//we handle the projection filtering once here rather than repeating the
+					//path analysis on a per plan basis
+					Map elementMap = RelationalNode.createLookupMap(xt.getProjectedSymbols());
+			        List cols = (List) node.getProperty(NodeConstants.Info.OUTPUT_COLS);
+					int[] projectionIndexes = RelationalNode.getProjectionIndexes(elementMap, cols);
+					ArrayList<XMLColumn> filteredColumns = new ArrayList<XMLColumn>(projectionIndexes.length);
+					for (int col : projectionIndexes) {
+						filteredColumns.add(xt.getColumns().get(col));
+					}
+					xt.getXQueryExpression().useDocumentProjection(filteredColumns, analysisRecord);
+					xtn.setProjectedColumns(filteredColumns);
+					xtn.setTable(xt);
+					processNode = xtn;
+					break;
 				}
-				if (!(source instanceof TextTable)) {
-					return null;
+				if (source instanceof TextTable) {
+					TextTableNode ttn = new TextTableNode(getID());
+					ttn.setTable((TextTable)source);
+					processNode = ttn;
+					break;
 				}
-				TextTableNode ttn = new TextTableNode(getID());
-				ttn.setTable((TextTable)source);
-				processNode = ttn;
-				break;
+				return null;
     		case NodeConstants.Types.SET_OP:
                 Operation setOp = (Operation) node.getProperty(NodeConstants.Info.SET_OPERATION);
                 boolean useAll = ((Boolean) node.getProperty(NodeConstants.Info.USE_ALL)).booleanValue();

Modified: trunk/engine/src/main/java/org/teiid/query/processor/relational/RelationalNode.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/processor/relational/RelationalNode.java	2010-06-05 01:49:35 UTC (rev 2184)
+++ trunk/engine/src/main/java/org/teiid/query/processor/relational/RelationalNode.java	2010-06-06 15:12:19 UTC (rev 2185)
@@ -338,7 +338,7 @@
 	/**
 	 * Helper method for all the node that will filter the elements needed for the next node.
 	 */
-	protected int[] getProjectionIndexes(Map<SingleElementSymbol, Integer> tupleElements, List<SingleElementSymbol> projectElements) {
+	public static int[] getProjectionIndexes(Map<SingleElementSymbol, Integer> tupleElements, List<SingleElementSymbol> projectElements) {
 		int[] result = new int[projectElements.size()];
 
 		int i = 0;

Modified: trunk/engine/src/main/java/org/teiid/query/processor/relational/SubqueryAwareRelationalNode.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/processor/relational/SubqueryAwareRelationalNode.java	2010-06-05 01:49:35 UTC (rev 2184)
+++ trunk/engine/src/main/java/org/teiid/query/processor/relational/SubqueryAwareRelationalNode.java	2010-06-06 15:12:19 UTC (rev 2185)
@@ -22,9 +22,16 @@
 
 package org.teiid.query.processor.relational;
 
+import java.util.Collections;
 import java.util.Map;
 
+import org.teiid.api.exception.query.ExpressionEvaluationException;
+import org.teiid.common.buffer.BlockedException;
+import org.teiid.core.TeiidComponentException;
 import org.teiid.query.eval.Evaluator;
+import org.teiid.query.sql.lang.TableFunctionReference;
+import org.teiid.query.sql.symbol.ElementSymbol;
+import org.teiid.query.sql.symbol.Expression;
 
 public abstract class SubqueryAwareRelationalNode extends RelationalNode {
 
@@ -57,5 +64,14 @@
 			evaluator.close();
 		}
 	}
+	
+	protected void setReferenceValues(TableFunctionReference ref) throws ExpressionEvaluationException, BlockedException, TeiidComponentException {
+		if (ref.getCorrelatedReferences() == null) {
+			return;
+		}
+		for (Map.Entry<ElementSymbol, Expression> entry : ref.getCorrelatedReferences().asMap().entrySet()) {
+			getContext().getVariableContext().setValue(entry.getKey(), getEvaluator(Collections.emptyMap()).evaluate(entry.getValue(), null));
+		}
+	}
 
 }

Modified: trunk/engine/src/main/java/org/teiid/query/processor/relational/TextTableNode.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/processor/relational/TextTableNode.java	2010-06-05 01:49:35 UTC (rev 2184)
+++ trunk/engine/src/main/java/org/teiid/query/processor/relational/TextTableNode.java	2010-06-06 15:12:19 UTC (rev 2185)
@@ -43,6 +43,7 @@
 import org.teiid.core.types.TransformationException;
 import org.teiid.query.execution.QueryExecPlugin;
 import org.teiid.query.processor.ProcessorDataManager;
+import org.teiid.query.sql.lang.TableFunctionReference;
 import org.teiid.query.sql.lang.TextTable;
 import org.teiid.query.sql.lang.TextTable.TextColumn;
 import org.teiid.query.sql.symbol.ElementSymbol;
@@ -69,7 +70,6 @@
 	private char quote;
 	private char delimiter;
 	private int lineWidth;
-	private Map elementMap;
     private int[] projectionIndexes;
 	
     //per file state
@@ -85,7 +85,7 @@
 	public void initialize(CommandContext context, BufferManager bufferManager,
 			ProcessorDataManager dataMgr) {
 		super.initialize(context, bufferManager, dataMgr);
-		if (elementMap != null) {
+		if (projectionIndexes != null) {
 			return;
 		}
 		if (table.getSkip() != null) {
@@ -112,7 +112,7 @@
 				quote = table.getQuote();
 			}
 		}
-        this.elementMap = createLookupMap(table.getProjectedSymbols());
+        Map elementMap = createLookupMap(table.getProjectedSymbols());
         this.projectionIndexes = getProjectionIndexes(elementMap, getElements());
 	}
 	
@@ -215,11 +215,7 @@
 	private void initReader() throws ExpressionEvaluationException,
 			BlockedException, TeiidComponentException, TeiidProcessingException {
 		
-		if (table.getCorrelatedReferences() != null) { 
-			for (Map.Entry<ElementSymbol, Expression> entry : table.getCorrelatedReferences().asMap().entrySet()) {
-				getContext().getVariableContext().setValue(entry.getKey(), getEvaluator(Collections.emptyMap()).evaluate(entry.getValue(), null));
-			}
-		}
+		setReferenceValues(this.table);
 		ClobType file = (ClobType)getEvaluator(Collections.emptyMap()).evaluate(table.getFile(), null);
 		
 		if (file == null) {

Modified: trunk/engine/src/main/java/org/teiid/query/processor/relational/XMLTableNode.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/processor/relational/XMLTableNode.java	2010-06-05 01:49:35 UTC (rev 2184)
+++ trunk/engine/src/main/java/org/teiid/query/processor/relational/XMLTableNode.java	2010-06-06 15:12:19 UTC (rev 2185)
@@ -22,82 +22,198 @@
 
 package org.teiid.query.processor.relational;
 
-import java.util.Map;
+import java.io.IOException;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Properties;
 
-import net.sf.saxon.query.XQueryExpression;
-import nu.xom.Element;
-import nu.xom.Node;
-import nu.xom.NodeFactory;
-import nu.xom.Nodes;
-import nux.xom.pool.XQueryPool;
-import nux.xom.xquery.StreamingPathFilter;
-import nux.xom.xquery.StreamingTransform;
-import nux.xom.xquery.XQueryUtil;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.TransformerException;
 
+import net.sf.saxon.Configuration;
+import net.sf.saxon.om.Item;
+import net.sf.saxon.om.NodeInfo;
+import net.sf.saxon.om.SequenceIterator;
+import net.sf.saxon.query.QueryResult;
+import net.sf.saxon.sxpath.XPathDynamicContext;
+import net.sf.saxon.sxpath.XPathExpression;
+import net.sf.saxon.trans.XPathException;
+import net.sf.saxon.value.Value;
+
+import org.teiid.api.exception.query.ExpressionEvaluationException;
 import org.teiid.common.buffer.BlockedException;
-import org.teiid.common.buffer.BufferManager;
 import org.teiid.common.buffer.TupleBatch;
 import org.teiid.core.TeiidComponentException;
 import org.teiid.core.TeiidProcessingException;
-import org.teiid.query.processor.ProcessorDataManager;
+import org.teiid.core.types.DataTypeManager;
+import org.teiid.core.types.SQLXMLImpl;
+import org.teiid.core.types.Streamable;
+import org.teiid.core.types.TransformationException;
+import org.teiid.core.types.XMLTranslator;
+import org.teiid.core.types.XMLType;
+import org.teiid.core.types.XMLType.Type;
+import org.teiid.query.processor.xml.XMLUtil;
 import org.teiid.query.sql.lang.XMLTable;
-import org.teiid.query.util.CommandContext;
+import org.teiid.query.sql.lang.XMLTable.XMLColumn;
+import org.teiid.query.sql.symbol.DerivedColumn;
 
 /**
- * Handles xml processing.
+ * Handles xml table processing.
  */
 public class XMLTableNode extends SubqueryAwareRelationalNode {
 
+	private static final class QueryResultTranslator extends XMLTranslator {
+		private final SequenceIterator pathIter;
+		private final Configuration config;
+
+		private QueryResultTranslator(SequenceIterator pathIter, Configuration config) {
+			this.pathIter = pathIter;
+			this.config = config;
+		}
+
+		@Override
+		public void translate(Writer writer) throws TransformerException,
+				IOException {
+			Properties props = new Properties();
+		    props.setProperty(OutputKeys.METHOD, "xml"); //$NON-NLS-1$
+		    //props.setProperty(OutputKeys.INDENT, "yes"); //$NON-NLS-1$
+		    props.setProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); //$NON-NLS-1$
+			QueryResult.serializeSequence(pathIter, config, writer, props);
+		}
+	}
+
 	private XMLTable table;
+	private List<XMLColumn> projectedColumns;
 	
-	//initialized state
-	private Map elementMap;
-    private int[] projectionIndexes;
+	private SequenceIterator result;
+	private int rowCount = 0;
 	
-    //per file state
-	
 	public XMLTableNode(int nodeID) {
 		super(nodeID);
 	}
 	
 	@Override
-	public void initialize(CommandContext context, BufferManager bufferManager,
-			ProcessorDataManager dataMgr) {
-		super.initialize(context, bufferManager, dataMgr);
-		if (elementMap != null) {
-			return;
-		}
-        this.elementMap = createLookupMap(table.getProjectedSymbols());
-        this.projectionIndexes = getProjectionIndexes(elementMap, getElements());
-	}
-	
-	@Override
 	public void closeDirect() {
 		super.closeDirect();
 		reset();
 	}
 	
+	@Override
+	public void reset() {
+		super.reset();
+		if (this.result != null) {
+			result.close();
+			result = null;
+		}
+		rowCount = 0;
+	}
+	
 	public void setTable(XMLTable table) {
 		this.table = table;
 	}
-
+	
+	public void setProjectedColumns(List<XMLColumn> projectedColumns) {
+		this.projectedColumns = projectedColumns;
+	}
+	
 	@Override
 	public XMLTableNode clone() {
 		XMLTableNode clone = new XMLTableNode(getID());
 		this.copy(this, clone);
 		clone.setTable(table);
+		clone.setProjectedColumns(projectedColumns);
 		return clone;
 	}
 
 	@Override
 	protected TupleBatch nextBatchDirect() throws BlockedException,
 			TeiidComponentException, TeiidProcessingException {
-		return null;
+		
+		if (result == null) {
+			setReferenceValues(this.table);
+			HashMap<String, Object> parameters = new HashMap<String, Object>();
+			Object contextItem = null;
+			for (DerivedColumn passing : this.table.getPassing()) {
+				Object value = getEvaluator(Collections.emptyMap()).evaluate(passing.getExpression(), null);
+				if (passing.getAlias() == null) {
+					contextItem = value;
+				} else {
+					parameters.put(passing.getAlias(), value);
+				}
+			}
+			result = this.table.getXQueryExpression().evaluateXQuery(contextItem, parameters);
+		}
+		
+		while (!isBatchFull() && !isLastBatch()) {
+			try {
+				processRow();
+			} catch (XPathException e) {
+				e.printStackTrace();
+			}
+		}
+		return pullBatch();
 	}
-	
-	public static void main(String[] args) {
-		
 
+	private void processRow() throws XPathException,
+			ExpressionEvaluationException, BlockedException,
+			TeiidComponentException, TeiidProcessingException,
+			TransformationException {
+		Item item = result.next();
+		rowCount++;
+		if (item == null) {
+			terminateBatches();
+			return;
+		}
+		List<Object> tuple = new ArrayList<Object>(projectedColumns.size());
+		for (XMLColumn proColumn : projectedColumns) {
+			if (proColumn.isOrdinal()) {
+				tuple.add(rowCount);
+			} else {
+				XPathExpression path = proColumn.getPathExpression();
+				XPathDynamicContext dynamicContext = path.createDynamicContext(item);
+				SequenceIterator pathIter = path.iterate(dynamicContext);
+				Item colItem = pathIter.next();
+				if (colItem == null) {
+					if (proColumn.getDefaultExpression() != null) {
+						tuple.add(getEvaluator(Collections.emptyMap()).evaluate(proColumn.getDefaultExpression(), null));
+					} else {
+						tuple.add(null);
+					}
+					continue;
+				}
+				if (proColumn.getSymbol().getType() == DataTypeManager.DefaultDataClasses.XML) {
+					Item next = pathIter.next();
+					XMLType.Type type = Type.FRAGMENT;
+					if (next != null) {
+						if (next instanceof NodeInfo || colItem instanceof NodeInfo) {
+							type = Type.SIBLINGS;
+						} else {
+							type = Type.TEXT;
+						}
+					}
+					pathIter = pathIter.getAnother();
+					SQLXMLImpl xml = XMLUtil.saveToBufferManager(getBufferManager(), new QueryResultTranslator(pathIter, this.table.getXQueryExpression().getConfig()), Streamable.STREAMING_BATCH_SIZE_IN_BYTES);
+					XMLType value = new XMLType(xml);
+					value.setType(type);
+					tuple.add(value);
+					continue;
+				}
+				if (pathIter.next() != null) {
+					throw new TeiidProcessingException("Unexpected multi-valued result was returned for XML Column " + proColumn.getName() + ".  All path expressions should return at most a single result.");
+				}
+				Object value = Value.convertToJava(colItem);
+				if (value instanceof Item) {
+					value = ((Item)value).getStringValue();
+				}
+				value = DataTypeManager.convertToRuntimeType(value);
+				value = DataTypeManager.transformValue(value, proColumn.getSymbol().getType());
+				tuple.add(value);
+			}
+		}
+		addBatchRow(tuple);
 	}
-
+	
 }
\ No newline at end of file

Modified: trunk/engine/src/main/java/org/teiid/query/rewriter/QueryRewriter.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/rewriter/QueryRewriter.java	2010-06-05 01:49:35 UTC (rev 2184)
+++ trunk/engine/src/main/java/org/teiid/query/rewriter/QueryRewriter.java	2010-06-06 15:12:19 UTC (rev 2185)
@@ -47,8 +47,8 @@
 import org.teiid.api.exception.query.QueryResolverException;
 import org.teiid.api.exception.query.QueryValidatorException;
 import org.teiid.core.TeiidComponentException;
+import org.teiid.core.TeiidException;
 import org.teiid.core.TeiidProcessingException;
-import org.teiid.core.TeiidException;
 import org.teiid.core.TeiidRuntimeException;
 import org.teiid.core.types.DataTypeManager;
 import org.teiid.core.util.Assertion;
@@ -926,6 +926,8 @@
         	TextTable tt = (TextTable)clause;
         	tt.setFile(rewriteExpressionDirect(tt.getFile()));
         } else if (clause instanceof XMLTable) {
+        	XMLTable xt = (XMLTable)clause;
+        	xt.rewriteDefaultColumn();
         	rewriteExpressions(clause);
         }
         return clause;

Modified: trunk/engine/src/main/java/org/teiid/query/sql/lang/XMLTable.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/lang/XMLTable.java	2010-06-05 01:49:35 UTC (rev 2184)
+++ trunk/engine/src/main/java/org/teiid/query/sql/lang/XMLTable.java	2010-06-06 15:12:19 UTC (rev 2185)
@@ -105,7 +105,7 @@
     private XMLNamespaces namespaces;
     private String xquery;
     private List<DerivedColumn> passing = new ArrayList<DerivedColumn>();
-    private ElementSymbol defaultColumn;
+    private XMLColumn defaultColumn;
     
     private SaxonXQueryExpression xqueryExpression;
     
@@ -114,10 +114,14 @@
 	}
     
     public void compileXqueryExpression() throws TeiidProcessingException {
-    	this.xqueryExpression = new SaxonXQueryExpression(xquery, namespaces, passing, columns);
+    	List<XMLColumn> cols = this.columns;
+    	if (cols.isEmpty()) {
+    		cols = Arrays.asList(defaultColumn);
+    	}
+    	this.xqueryExpression = new SaxonXQueryExpression(xquery, namespaces, passing, cols);
     }
     
-    public SaxonXQueryExpression getXqueryExpression() {
+    public SaxonXQueryExpression getXQueryExpression() {
 		return xqueryExpression;
 	}
     
@@ -155,10 +159,9 @@
         	return super.getProjectedSymbols();
     	}
     	if (defaultColumn == null) {
-    		defaultColumn = new ElementSymbol("COLUMN_VALUE"); //$NON-NLS-1$
-    		defaultColumn.setType(DataTypeManager.DefaultDataClasses.XML);
+    		defaultColumn = new XMLColumn("OBJECT_VALUE", DataTypeManager.DefaultDataTypes.XML, ".", null); //$NON-NLS-1$ //$NON-NLS-2$
     	}
-    	return Arrays.asList(defaultColumn);
+    	return Arrays.asList(defaultColumn.getSymbol());
     }
     
 	@Override
@@ -194,5 +197,12 @@
 		XMLTable other = (XMLTable)obj;
 		return this.columns.equals(other.columns);
 	}
+
+	public void rewriteDefaultColumn() {
+		if (this.columns.isEmpty() && defaultColumn != null) {
+			this.columns.add(defaultColumn);
+			defaultColumn = null;
+		}
+	}
 	
 }

Modified: trunk/engine/src/main/java/org/teiid/query/validator/ValidationVisitor.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/validator/ValidationVisitor.java	2010-06-05 01:49:35 UTC (rev 2184)
+++ trunk/engine/src/main/java/org/teiid/query/validator/ValidationVisitor.java	2010-06-06 15:12:19 UTC (rev 2185)
@@ -1162,8 +1162,7 @@
     	for (DerivedColumn dc : obj.getPassing()) {
     		if (dc.getAlias() == null) {
     			Class<?> type = dc.getExpression().getType();
-    			if (type != DataTypeManager.DefaultDataClasses.STRING &&
-    				type != DataTypeManager.DefaultDataClasses.XML &&
+    			if (type != DataTypeManager.DefaultDataClasses.XML &&
     				type != DataTypeManager.DefaultDataClasses.CLOB) {
     				handleValidationError(QueryPlugin.Util.getString("ValidationVisitor.context_item_type"), obj); //$NON-NLS-1$
     			}
@@ -1176,6 +1175,9 @@
     			handleValidationError(QueryPlugin.Util.getString("ValidationVisitor.duplicate_passing", dc.getAlias()), obj); //$NON-NLS-1$
         	}
 		}
+    	if (obj.getXQueryExpression().usesContextItem() && !context) {
+			handleValidationError(QueryPlugin.Util.getString("ValidationVisitor.context_required"), obj); //$NON-NLS-1$    		
+    	}
     	boolean hasOrdinal = false;
     	for (XMLColumn xc : obj.getColumns()) {
 			if (!xc.isOrdinal()) {

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	2010-06-05 01:49:35 UTC (rev 2184)
+++ trunk/engine/src/main/java/org/teiid/query/xquery/saxon/SaxonXQueryExpression.java	2010-06-06 15:12:19 UTC (rev 2185)
@@ -22,15 +22,14 @@
 
 package org.teiid.query.xquery.saxon;
 
-import java.io.StringReader;
 import java.sql.Clob;
 import java.sql.SQLException;
 import java.sql.SQLXML;
 import java.util.Arrays;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import java.util.Properties;
 
 import javax.xml.transform.ErrorListener;
 import javax.xml.transform.Source;
@@ -41,8 +40,10 @@
 import net.sf.saxon.Configuration;
 import net.sf.saxon.event.ProxyReceiver;
 import net.sf.saxon.expr.AxisExpression;
+import net.sf.saxon.expr.ContextItemExpression;
 import net.sf.saxon.expr.Expression;
 import net.sf.saxon.expr.PathMap;
+import net.sf.saxon.expr.RootExpression;
 import net.sf.saxon.expr.PathMap.PathMapArc;
 import net.sf.saxon.expr.PathMap.PathMapNode;
 import net.sf.saxon.expr.PathMap.PathMapNodeSet;
@@ -54,9 +55,7 @@
 import net.sf.saxon.pattern.AnyNodeTest;
 import net.sf.saxon.pattern.NodeKindTest;
 import net.sf.saxon.query.DynamicQueryContext;
-import net.sf.saxon.query.QueryResult;
 import net.sf.saxon.query.StaticQueryContext;
-import net.sf.saxon.query.XQueryExpression;
 import net.sf.saxon.sxpath.IndependentContext;
 import net.sf.saxon.sxpath.XPathEvaluator;
 import net.sf.saxon.sxpath.XPathExpression;
@@ -72,16 +71,15 @@
 import org.teiid.core.types.ClobType;
 import org.teiid.core.types.DataTypeManager;
 import org.teiid.core.types.XMLType;
-import org.teiid.logging.LogConstants;
-import org.teiid.logging.LogManager;
-import org.teiid.logging.MessageLevel;
 import org.teiid.query.QueryPlugin;
+import org.teiid.query.analysis.AnalysisRecord;
 import org.teiid.query.sql.lang.XMLTable;
 import org.teiid.query.sql.lang.XMLTable.XMLColumn;
 import org.teiid.query.sql.symbol.DerivedColumn;
 import org.teiid.query.sql.symbol.XMLNamespaces;
 import org.teiid.query.sql.symbol.XMLNamespaces.NamespaceItem;
 
+ at SuppressWarnings("serial")
 public class SaxonXQueryExpression {
 	
 	private static final Expression DUMMY_EXPRESSION = new Expression() {
@@ -148,10 +146,8 @@
         		}
 			}
         }
-    	boolean hasContext = false;
         for (DerivedColumn derivedColumn : passing) {
         	if (derivedColumn.getAlias() == null) {
-        		hasContext = true; //skip the context item
         		continue;
         	}
         	try {
@@ -159,92 +155,156 @@
 			} catch (XPathException e) {
 				throw new TeiidRuntimeException(e, "Could not define global variable"); //$NON-NLS-1$ 
 			}
-        	ic.declareVariable("", derivedColumn.getAlias()); //$NON-NLS-1$
 		}
         
-        XPathEvaluator eval = new XPathEvaluator(config);
-    	eval.setStaticContext(ic);
-    	
-    	processColumns(columns, eval);	    	
+    	processColumns(columns, ic);	    	
     
         try {
 			this.xQuery = context.compileQuery(xQueryString);
 		} catch (XPathException e) {
 			throw new QueryResolverException(e, QueryPlugin.Util.getString("SaxonXQueryExpression.compile_failed")); //$NON-NLS-1$
 		}
-        if (hasContext) {
-        	useDocumentProjection(columns);
-        } else {
-	    	LogManager.logDetail(LogConstants.CTX_QUERY_PLANNER, "Document projection will not be used, since no context item exists or there are unknown dependencies"); //$NON-NLS-1$
-        }
     }
-
-	private void useDocumentProjection(List<XMLTable.XMLColumn> columns) {
-		XQueryExpression toAnalyze = this.xQuery;
-		
-		PathMap map = new PathMap(DUMMY_EXPRESSION);
-		PathMapNodeSet set = toAnalyze.getExpression().addToPathMap(map, null);
-		
-		boolean complexEndState = false;
-		if (set != null) {  
+    
+    public boolean usesContextItem() {
+    	return this.xQuery.usesContextItem();
+    }
+    
+	public void useDocumentProjection(List<XMLTable.XMLColumn> columns, AnalysisRecord record) {
+		PathMap map = this.xQuery.getPathMap();
+		PathMapRoot parentRoot;
+		try {
+			parentRoot = map.getContextRoot();
+		} catch (IllegalStateException e) {
+			if (record.recordDebug()) {
+				record.println("Document projection will not be used, since multiple context item exist."); //$NON-NLS-1$
+			}
+			return;
+		}
+		if (parentRoot == null) {
+			//TODO: this seems like we could omit the context item altogether
+			//this.xQuery.usesContextItem() should also be false
+			if (record.recordDebug()) {
+				record.println("Document projection will not be used, since no context item reference was found in the XQuery"); //$NON-NLS-1$
+			}
+			return;			
+		}
+		HashSet<PathMapNode> finalNodes = new HashSet<PathMapNode>();
+		getReturnableNodes(parentRoot, finalNodes);
+				
+		if (!finalNodes.isEmpty()) {  
 			if (columns != null && !columns.isEmpty()) {
-				if (set.size() != 1) {
-					complexEndState = true;
-				} else {
-					for (XMLColumn xmlColumn : columns) {
-						if (xmlColumn.isOrdinal()) {
-							continue;
-						}
-				    	Expression internalExpression = xmlColumn.getPathExpression().getInternalExpression();
-				    	PathMap subMap = new PathMap(internalExpression);
-				    	PathMapRoot root = subMap.getContextRoot();
-				    	if (root == null) {
-				    		continue;
-				    	}
-				    	PathMapNodeSet finalNodes = internalExpression.addToPathMap(map, set);
-				    	if (finalNodes != null) {
-				    		for (Iterator iter = finalNodes.iterator(); iter.hasNext(); ) {
-				                PathMapNode subNode = (PathMapNode)iter.next();
-						    	if (xmlColumn.getSymbol().getType() == DataTypeManager.DefaultDataClasses.XML) {
-						    		subNode.createArc(new AxisExpression(Axis.DESCENDANT_OR_SELF, AnyNodeTest.getInstance()));
-						    		subNode.setReturnable(true);
-						    	} else {
-						    		//this may not always be needed, but it doesn't harm anything
-						    		subNode.createArc(new AxisExpression(Axis.CHILD, NodeKindTest.TEXT));
-						    		subNode.setAtomized();
-						    	}
-				            }
-				    	}
+				if (finalNodes.size() != 1) {
+					if (record.recordDebug()) {
+						record.println("Document projection will not be used, since multiple return items exist"); //$NON-NLS-1$
 					}
+					return;	
+				} 
+				parentRoot = projectColumns(parentRoot, columns, finalNodes.iterator().next(), record);
+				if (parentRoot == null) {
+					return;
 				}
 			} else {
-				for (Iterator iter = set.iterator(); iter.hasNext(); ) {
+				for (Iterator iter = finalNodes.iterator(); iter.hasNext(); ) {
 	                PathMapNode subNode = (PathMapNode)iter.next();
 	                subNode.createArc(new AxisExpression(Axis.DESCENDANT_OR_SELF, AnyNodeTest.getInstance()));
-	                subNode.setReturnable(true);
 	            }
 			}
 		} 
-		//PathMap map = toAnalyze.getPathMap();
-		contextRoot = map.getContextRoot();
-		if (contextRoot == null || complexEndState || contextRoot.hasUnknownDependencies()) {
-	    	LogManager.logDetail(LogConstants.CTX_QUERY_PLANNER, "Document projection will not be used, since no context item exists or there are unknown dependencies"); //$NON-NLS-1$
-			contextRoot = null;
-		} else if (LogManager.isMessageToBeRecorded(LogConstants.CTX_QUERY_PLANNER, MessageLevel.DETAIL)) {
-	    	StringBuilder sb = new StringBuilder();
+		if (parentRoot.hasUnknownDependencies()) {
+			if (record.recordDebug()) {
+				record.println("Document projection will not be used since there are unknown dependencies (most likely a user defined function)."); //$NON-NLS-1$
+			}
+	    	return;
+		}
+		contextRoot = parentRoot;
+		if (record.recordDebug()) {
+			StringBuilder sb = new StringBuilder();
 	    	showArcs(sb, contextRoot, 0);
-	    	LogManager.logDetail(LogConstants.CTX_QUERY_PLANNER, "Using path filtering for XQuery context item: \n" + sb.toString()); //$NON-NLS-1$
+	    	record.println("Using path filtering for XQuery context item: \n" + sb.toString()); //$NON-NLS-1$
 		}
-/*		StringBuilder sb = new StringBuilder();
-    	showArcs(sb, contextRoot, 0);
-    	System.out.println(sb);
-*/	}
+	}
 
-	private void processColumns(List<XMLTable.XMLColumn> columns, XPathEvaluator eval)
+	private PathMapRoot projectColumns(PathMapRoot parentRoot, List<XMLTable.XMLColumn> columns, PathMapNode finalNode, AnalysisRecord record) {
+		for (XMLColumn xmlColumn : columns) {
+			if (xmlColumn.isOrdinal()) {
+				continue;
+			}
+	    	Expression internalExpression = xmlColumn.getPathExpression().getInternalExpression();
+	    	PathMap subMap = new PathMap(internalExpression);
+	    	PathMapRoot subContextRoot = null;
+	    	for (PathMapRoot root : subMap.getPathMapRoots()) {
+				if (root.getRootExpression() instanceof ContextItemExpression || root.getRootExpression() instanceof RootExpression) {
+					if (subContextRoot != null) {
+						if (record.recordDebug()) {
+							record.println("Document projection will not be used, since multiple context item exist in column path " + xmlColumn.getPath()); //$NON-NLS-1$
+						}
+						return null;
+					}
+					subContextRoot = root;
+				}
+			}
+	    	if (subContextRoot == null) {
+	    		//special case for handling '.', which the pathmap logic doesn't consider as a root
+	    		if (internalExpression instanceof ContextItemExpression) {
+	    			addReturnedArcs(xmlColumn, finalNode);
+	    		}
+	    		continue;
+	    	}
+	    	for (PathMapArc arc : subContextRoot.getArcs()) {
+				finalNode.createArc(arc.getStep(), arc.getTarget());
+			}
+	    	HashSet<PathMapNode> subFinalNodes = new HashSet<PathMapNode>();
+			getReturnableNodes(subContextRoot, subFinalNodes);
+	    	for (Iterator iter = subFinalNodes.iterator(); iter.hasNext(); ) {
+	            PathMapNode subNode = (PathMapNode)iter.next();
+		    	addReturnedArcs(xmlColumn, subNode);
+	        }
+		}
+		//Workaround to rerun the reduction algorithm - by making a copy of the old version
+		PathMap newMap = new PathMap(DUMMY_EXPRESSION);
+		PathMapRoot newRoot = newMap.makeNewRoot(parentRoot.getRootExpression());
+		if (parentRoot.isAtomized()) {
+			newRoot.setAtomized();
+		}
+		if (parentRoot.isReturnable()) {
+			newRoot.setReturnable(true);
+		}
+		if (parentRoot.hasUnknownDependencies()) {
+			newRoot.setHasUnknownDependencies();
+		}
+		for (PathMapArc arc : parentRoot.getArcs()) {
+			newRoot.createArc(arc.getStep(), arc.getTarget());
+		}
+		return newMap.reduceToDownwardsAxes(newRoot);
+	}
+
+	private void addReturnedArcs(XMLColumn xmlColumn, PathMapNode subNode) {
+		if (xmlColumn.getSymbol().getType() == DataTypeManager.DefaultDataClasses.XML) {
+			subNode.createArc(new AxisExpression(Axis.DESCENDANT_OR_SELF, AnyNodeTest.getInstance()));
+		} else {
+			//this may not always be needed, but it doesn't harm anything
+			subNode.createArc(new AxisExpression(Axis.CHILD, NodeKindTest.TEXT));
+			subNode.setAtomized();
+		}
+	}
+
+	private void getReturnableNodes(PathMapNode node, HashSet<PathMapNode> finalNodes) {
+		if (node.isReturnable()) {
+			finalNodes.add(node);
+		}
+		for (PathMapArc arc : node.getArcs()) {
+			getReturnableNodes(arc.getTarget(), finalNodes);
+		}
+	}
+
+	private void processColumns(List<XMLTable.XMLColumn> columns, IndependentContext ic)
 			throws TeiidProcessingException {
 		if (columns == null) {
 			return;
 		}
+        XPathEvaluator eval = new XPathEvaluator(config);
+    	eval.setStaticContext(ic);
 		for (XMLColumn xmlColumn : columns) {
         	if (xmlColumn.isOrdinal()) {
         		continue;
@@ -254,7 +314,7 @@
         		path = xmlColumn.getName();
         	}
         	path = path.trim();
-        	if (path.startsWith("/") && !path.startsWith("//")) {
+        	if (path.startsWith("/") && !path.startsWith("//")) { //$NON-NLS-1$ //$NON-NLS-2$
         		path = path.substring(1);
         	}
 	    	XPathExpression exp;
@@ -275,9 +335,6 @@
 	    	if (value instanceof XMLType) {
 				return ((SQLXML)value).getSource(null);
 	    	}
-	    	if (value instanceof String) {
-	    		return new StreamSource(new StringReader((String)value));
-	    	}
 	    	if (value instanceof ClobType) {
 	    		return new StreamSource(((Clob)value).getCharacterStream());
 	    	}
@@ -292,12 +349,8 @@
         
         for (Map.Entry<String, Object> entry : parameterValues.entrySet()) {
             Object value = entry.getValue();
-            if(value instanceof SQLXML) {                    
-                try {
-                    value = ((SQLXML)value).getSource(null);
-                } catch (SQLException e) {
-                    throw new TeiidProcessingException(e);
-                }
+            if(value instanceof SQLXML || value instanceof Clob) {                    
+            	value = convertToSource(value);
             }
             dynamicContext.setParameter(entry.getKey(), value);                
 		}
@@ -320,9 +373,7 @@
 	        dynamicContext.setContextItem(doc);
         }
         try {
-            //return this.xQuery.iterator(dynamicContext);
-        	QueryResult.serializeSequence(xQuery.iterator(dynamicContext), config, System.out, new Properties());
-        	return null;
+        	return xQuery.iterator(dynamicContext);
         } catch (TransformerException e) {
         	throw new TeiidProcessingException(e, QueryPlugin.Util.getString("SaxonXQueryExpression.bad_xquery")); //$NON-NLS-1$
         }       

Modified: trunk/engine/src/main/resources/org/teiid/query/i18n.properties
===================================================================
--- trunk/engine/src/main/resources/org/teiid/query/i18n.properties	2010-06-05 01:49:35 UTC (rev 2184)
+++ trunk/engine/src/main/resources/org/teiid/query/i18n.properties	2010-06-06 15:12:19 UTC (rev 2185)
@@ -892,7 +892,7 @@
 ValidationVisitor.text_table_newline=Text table DELIMITER, QUOTE, and ESCAPE characters cannot be the new line character.
 ValidationVisitor.xml_namespaces=At most only one NO DEFAULT or DEFAULT namespace may be specified.
 ValidationVisitor.xml_namespaces_reserved=At most only one NO DEFAULT or DEFAULT namespace may be specified.
-ValidationVisitor.context_item_type=XMLTABLE or XMLQUERY PASSING context item must be a character type (XML, STRING, CLOB).
+ValidationVisitor.context_item_type=XMLTABLE or XMLQUERY PASSING context item must be an XML or CLOB value.
 ValidationVisitor.passing_requires_name=XMLTABLE or XMLQUERY PASSING clause can only contain at most 1 unnamed item.
 ValidationVisitor.duplicate_passing=XMLTABLE or XMLQUERY PASSING clause duplicate item name "{0}".
 ValidationVisitor.one_ordinal=Only one FOR ORDINALITY column is allowed for an XMLTABLE.

Modified: trunk/engine/src/test/java/org/teiid/query/processor/TestSQLXMLProcessing.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/processor/TestSQLXMLProcessing.java	2010-06-05 01:49:35 UTC (rev 2184)
+++ trunk/engine/src/test/java/org/teiid/query/processor/TestSQLXMLProcessing.java	2010-06-06 15:12:19 UTC (rev 2185)
@@ -29,16 +29,15 @@
 
 import org.junit.Ignore;
 import org.junit.Test;
-import org.teiid.query.processor.ProcessorPlan;
 import org.teiid.query.unittest.FakeMetadataFactory;
 
- at SuppressWarnings("nls")
+ at SuppressWarnings({"nls", "unchecked"})
 public class TestSQLXMLProcessing {
 	
 	@Test public void testXmlElementTextContent() throws Exception {
 		String sql = "SELECT xmlelement(foo, '<bar>', convert('<bar1/>', xml))"; //$NON-NLS-1$
         
-        List[] expected = new List[] {
+        List<?>[] expected = new List<?>[] {
         		Arrays.asList("<foo>&lt;bar&gt;<bar1/></foo>"),
         };    
     
@@ -57,7 +56,7 @@
 	@Test public void testXmlElementTextContent1() throws Exception {
 		String sql = "SELECT xmlelement(foo, '<bar>', convert('<?xml version=\"1.0\" encoding=\"UTF-8\"?><bar1/>', xml))"; //$NON-NLS-1$
         
-        List[] expected = new List[] {
+        List<?>[] expected = new List<?>[] {
         		Arrays.asList("<foo>&lt;bar&gt;<bar1></bar1></foo>"),
         };    
     
@@ -72,7 +71,7 @@
     @Test public void testXmlElement() {
         String sql = "SELECT xmlelement(e1, e2) from pm1.g1 order by e1, e2"; //$NON-NLS-1$
         
-        List[] expected = new List[] {
+        List<?>[] expected = new List<?>[] {
         		Arrays.asList("<e1>1</e1>"),
         		Arrays.asList("<e1>0</e1>"),
         		Arrays.asList("<e1>0</e1>"),
@@ -92,7 +91,7 @@
     @Test public void testXmlElementWithConcat() {
         String sql = "SELECT xmlelement(e1, e2, xmlconcat(xmlelement(x), xmlelement(y, e3))) from pm1.g1 order by e1, e2"; //$NON-NLS-1$
         
-        List[] expected = new List[] {
+        List<?>[] expected = new List<?>[] {
         		Arrays.asList("<e1>1<x></x><y>false</y></e1>"),
         		Arrays.asList("<e1>0<x></x><y>false</y></e1>"),
         		Arrays.asList("<e1>0<x></x><y>false</y></e1>"),
@@ -112,7 +111,7 @@
     @Test public void testXmlElementWithForest() {
         String sql = "SELECT xmlelement(x, xmlforest(e1, e2, '1' as val)) from pm1.g1 order by e1, e2 limit 2"; //$NON-NLS-1$
         
-        List[] expected = new List[] {
+        List<?>[] expected = new List<?>[] {
         		Arrays.asList("<x><e2>1</e2><val>1</val></x>"), //note e1 is not present, because it's null
         		Arrays.asList("<x><e1>a</e1><e2>0</e2><val>1</val></x>"),
         };    
@@ -128,7 +127,7 @@
     @Test public void testXmlElementWithAttributes() {
         String sql = "SELECT xmlelement(x, xmlattributes(e1, e2, '1' as val)) from pm1.g1 order by e1, e2 limit 2"; //$NON-NLS-1$
         
-        List[] expected = new List[] {
+        List<?>[] expected = new List<?>[] {
         		Arrays.asList("<x e2=\"1\" val=\"1\"></x>"), //note e1 is not present, because it's null
         		Arrays.asList("<x e1=\"a\" e2=\"0\" val=\"1\"></x>"),
         };    
@@ -144,7 +143,7 @@
     @Test public void testXmlElementWithPi() {
         String sql = "SELECT xmlelement(x, xmlpi(name e1, '  1'))"; //$NON-NLS-1$
         
-        List[] expected = new List[] {
+        List<?>[] expected = new List<?>[] {
         		Arrays.asList("<x><?e1 1?></x>"),
         };    
     
@@ -159,7 +158,7 @@
     @Test public void testXmlElementWithNamespaces() {
         String sql = "SELECT xmlelement(x, xmlnamespaces(no default, 'http://foo' as x, 'http://foo1' as y), xmlattributes(e1), e2) from pm1.g1 order by e1, e2 limit 2"; //$NON-NLS-1$
         
-        List[] expected = new List[] {
+        List<?>[] expected = new List<?>[] {
         		Arrays.asList("<x xmlns=\"\" xmlns:x=\"http://foo\" xmlns:y=\"http://foo1\">1</x>"), //note e1 is not present, because it's null
         		Arrays.asList("<x xmlns=\"\" xmlns:x=\"http://foo\" xmlns:y=\"http://foo1\" e1=\"a\">0</x>"),
         };    
@@ -175,7 +174,7 @@
     @Test public void testXmlAgg() {
         String sql = "SELECT xmlelement(parent, xmlAgg(xmlelement(x, xmlattributes(e1, e2)))) from pm1.g1"; //$NON-NLS-1$
         
-        List[] expected = new List[] {
+        List<?>[] expected = new List<?>[] {
         		Arrays.asList("<parent><x e1=\"a\" e2=\"0\"></x><x e2=\"1\"></x><x e1=\"a\" e2=\"3\"></x><x e1=\"c\" e2=\"1\"></x><x e1=\"b\" e2=\"2\"></x><x e1=\"a\" e2=\"0\"></x></parent>"), 
         };    
     
@@ -190,7 +189,7 @@
     @Test public void testXmlAggOrderBy() {
         String sql = "SELECT xmlelement(parent, xmlAgg(xmlelement(x, xmlattributes(e1, e2)) order by e2)) from pm1.g1"; //$NON-NLS-1$
         
-        List[] expected = new List[] {
+        List<?>[] expected = new List<?>[] {
         		Arrays.asList("<parent><x e1=\"a\" e2=\"0\"></x><x e1=\"a\" e2=\"0\"></x><x e2=\"1\"></x><x e1=\"c\" e2=\"1\"></x><x e1=\"b\" e2=\"2\"></x><x e1=\"a\" e2=\"3\"></x></parent>"), 
         };    
     
@@ -205,7 +204,7 @@
     @Test public void testXmlSerialize() {
     	String sql = "SELECT xmlserialize(document xmlelement(parent) as string)"; //$NON-NLS-1$
         
-        List[] expected = new List[] {
+        List<?>[] expected = new List<?>[] {
         		Arrays.asList("<parent></parent>"), 
         };    
     
@@ -217,12 +216,12 @@
         helpProcess(plan, dataManager, expected);
     }
     
-    @Ignore
     @Test public void testXmlTable() {
-        String sql = "select * from xmltable('/a/b' passing '<a><b>first</b><b x='attr'>second</b>' columns x string, val string path '/b')"; //$NON-NLS-1$
+        String sql = "select * from xmltable('/a/b' passing convert('<a><b>first</b><b x=\"attr\">second</b></a>', xml) columns x string path '@x', val string path '/.') as x"; //$NON-NLS-1$
         
-        List[] expected = new List[] {
-        		Arrays.asList("<parent><x e1=\"a\" e2=\"0\"></x><x e1=\"a\" e2=\"0\"></x><x e2=\"1\"></x><x e1=\"c\" e2=\"1\"></x><x e1=\"b\" e2=\"2\"></x><x e1=\"a\" e2=\"3\"></x></parent>"), 
+        List<?>[] expected = new List<?>[] {
+        		Arrays.asList(null, "first"),
+        		Arrays.asList("attr", "second"),
         };    
     
         FakeDataManager dataManager = new FakeDataManager();
@@ -232,5 +231,83 @@
         
         helpProcess(plan, dataManager, expected);
     }
+    
+	@Test public void testXmlTableDefaultAndParent() {
+        String sql = "select * from xmltable('/a/b' passing convert('<a y=\"rev\"><b>first</b><b x=\"1\">second</b></a>', xml) columns x integer path '@x' default -1, val string path '../@y') as x"; //$NON-NLS-1$
+        
+        List<?>[] expected = new List<?>[] {
+        		Arrays.asList(-1, "rev"),
+        		Arrays.asList(1, "rev"),
+        };    
+    
+        FakeDataManager dataManager = new FakeDataManager();
+        sampleData1(dataManager);
+        
+        ProcessorPlan plan = helpGetPlan(helpParse(sql), FakeMetadataFactory.example1Cached());
+        
+        helpProcess(plan, dataManager, expected);
+    }
+    
+    @Test public void testXmlTableReturnXml() {
+        String sql = "select * from xmltable('/a/b' passing convert('<a><b>first</b><b x=\"1\">second</b></a>', xml) columns val xml path '.') as x"; //$NON-NLS-1$
+        
+        List<?>[] expected = new List<?>[] {
+        		Arrays.asList("<b>first</b>"),
+        		Arrays.asList("<b x=\"1\">second</b>"),
+        };    
+    
+        FakeDataManager dataManager = new FakeDataManager();
+        sampleData1(dataManager);
+        
+        ProcessorPlan plan = helpGetPlan(helpParse(sql), FakeMetadataFactory.example1Cached());
+        
+        helpProcess(plan, dataManager, expected);
+    }
+    
+    @Test public void testXmlTableNoColumns() {
+        String sql = "select * from xmltable('/a' passing convert('<a><b>first</b><b x=\"1\">second</b></a>', xml)) as x"; //$NON-NLS-1$
+        
+        List<?>[] expected = new List<?>[] {
+        		Arrays.asList("<a><b>first</b><b x=\"1\">second</b></a>"),
+        };    
+    
+        FakeDataManager dataManager = new FakeDataManager();
+        sampleData1(dataManager);
+        
+        ProcessorPlan plan = helpGetPlan(helpParse(sql), FakeMetadataFactory.example1Cached());
+        
+        helpProcess(plan, dataManager, expected);
+    }
+    
+    @Test public void testXmlTablePassing() {
+        String sql = "select * from xmltable('<root>{for $x in $a/a/b return <c>{$x}</c>}</root>' passing convert('<a><b>first</b><b x=\"1\">second</b></a>', xml) as a columns x xml path 'c[1]/b') as x"; //$NON-NLS-1$
+        
+        List<?>[] expected = new List<?>[] {
+        		Arrays.asList("<b>first</b>"),
+        };    
+    
+        FakeDataManager dataManager = new FakeDataManager();
+        sampleData1(dataManager);
+        
+        ProcessorPlan plan = helpGetPlan(helpParse(sql), FakeMetadataFactory.example1Cached());
+        
+        helpProcess(plan, dataManager, expected);
+    }
+    
+    @Ignore
+    @Test public void testXmlTableForOrdinality() {
+        String sql = "select * from xmltable('/a/b' passing convert('<a><b><c>1</c></b><b>1</b><b><c>1</c></b><b>1</b></a>', xml) as a columns x for ordinality, c integer path '.') as x"; //$NON-NLS-1$
+        
+        List<?>[] expected = new List<?>[] {
+        		Arrays.asList("<b>first</b>"),
+        };    
+    
+        FakeDataManager dataManager = new FakeDataManager();
+        sampleData1(dataManager);
+        
+        ProcessorPlan plan = helpGetPlan(helpParse(sql), FakeMetadataFactory.example1Cached());
+        
+        helpProcess(plan, dataManager, expected);
+    }
 
 }

Added: trunk/engine/src/test/java/org/teiid/query/xquery/saxon/TestSaxonXQueryExpression.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/xquery/saxon/TestSaxonXQueryExpression.java	                        (rev 0)
+++ trunk/engine/src/test/java/org/teiid/query/xquery/saxon/TestSaxonXQueryExpression.java	2010-06-06 15:12:19 UTC (rev 2185)
@@ -0,0 +1,66 @@
+package org.teiid.query.xquery.saxon;
+
+import java.util.Arrays;
+import java.util.HashMap;
+
+import net.sf.saxon.om.SequenceIterator;
+
+import org.junit.Ignore;
+import org.teiid.core.types.SQLXMLImpl;
+import org.teiid.core.types.XMLType;
+import org.teiid.query.sql.lang.XMLTable;
+import org.teiid.query.sql.symbol.DerivedColumn;
+import org.teiid.query.sql.symbol.ElementSymbol;
+import org.teiid.query.sql.symbol.XMLNamespaces;
+
+ at Ignore
+public class TestSaxonXQueryExpression {
+
+    public static void main(String[] args) throws Exception {
+    	String xquery = 
+        "/Catalogs/Catalog/Items"; //$NON-NLS-1$   
+    	
+    	String inputdoc = 
+            "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +  //$NON-NLS-1$
+            "<Catalogs xmlns=\"foo\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n" + //$NON-NLS-1$
+            "   <Catalog>\n" +  //$NON-NLS-1$
+            "      <Items>\n" +  //$NON-NLS-1$
+            "         <Item ItemID=\"001\" x=\"1\">\n" +  //$NON-NLS-1$
+            "            <Name>Lamp</Name>\n" +  //$NON-NLS-1$
+            "            <Quantity>5</Quantity>\n" +  //$NON-NLS-1$
+            "         </Item>\n" +  //$NON-NLS-1$
+            "         <Item ItemID=\"002\">\n" +  //$NON-NLS-1$
+            "            <Name>Screwdriver</Name>\n" +  //$NON-NLS-1$
+            "            <Quantity>100</Quantity>\n" +  //$NON-NLS-1$
+            "         </Item>\n" +  //$NON-NLS-1$
+            "         <Item ItemID=\"003\">\n" +  //$NON-NLS-1$
+            "            <Name>Goat</Name>\n" +  //$NON-NLS-1$
+            "            <Quantity>4</Quantity>\n" +  //$NON-NLS-1$
+            "         </Item>\n" +  //$NON-NLS-1$
+            "      </Items>\n" +  //$NON-NLS-1$
+            "   </Catalog>\n" +  //$NON-NLS-1$
+            "</Catalogs>"; //$NON-NLS-1$
+    	
+/*    	Configuration config = new Configuration();
+    	XPathExpression exp = new XPathEvaluator(config).createExpression("text()");
+    	Expression expr = exp.getInternalExpression();
+    	PathMap map = new PathMap(expr);
+    	map.diagnosticDump(System.out);
+    	PathMapRoot root = map.getContextRoot();
+    	StringBuilder sb = new StringBuilder();
+    	SaxonXQueryExpression.showArcs(sb, root.getArcs(), 0);
+    	System.out.println(sb);
+    	Source s = config.buildDocument(new StreamSource(new StringReader("<a Name='foo'><b><c Name='bar'>hello<d>world</d></c></b></a>")));
+    	Object o = new XPathEvaluator(config).createExpression("//c").evaluateSingle(s);
+    	XPathDynamicContext dc = exp.createDynamicContext((Item)o);
+    	System.out.println(exp.evaluateSingle(dc).getStringValue());
+*/    	
+    	XMLNamespaces namespaces = new XMLNamespaces(Arrays.asList(new XMLNamespaces.NamespaceItem("foo", null)));
+		SaxonXQueryExpression se = new SaxonXQueryExpression(xquery, namespaces, Arrays.asList(new DerivedColumn(null, new ElementSymbol("x"))), Arrays.asList(new XMLTable.XMLColumn("y", "string", "/elem", null), new XMLTable.XMLColumn("x", "string", "../@attr", null)));
+		HashMap<String, Object> values = new HashMap<String, Object>();
+		values.put("y", new SQLXMLImpl(inputdoc));
+		SequenceIterator iter = se.evaluateXQuery(new XMLType(new SQLXMLImpl(inputdoc)), values);
+	}
+
+	
+}


Property changes on: trunk/engine/src/test/java/org/teiid/query/xquery/saxon/TestSaxonXQueryExpression.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain



More information about the teiid-commits mailing list