[teiid-commits] teiid SVN: r2382 - in trunk/engine/src: main/java/org/teiid/query/metadata and 7 other directories.

teiid-commits at lists.jboss.org teiid-commits at lists.jboss.org
Wed Jul 28 00:40:35 EDT 2010


Author: shawkins
Date: 2010-07-28 00:40:32 -0400 (Wed, 28 Jul 2010)
New Revision: 2382

Added:
   trunk/engine/src/main/java/org/teiid/common/buffer/TupleBrowser.java
   trunk/engine/src/main/java/org/teiid/query/tempdata/IndexCondition.java
Modified:
   trunk/engine/src/main/java/org/teiid/common/buffer/STree.java
   trunk/engine/src/main/java/org/teiid/query/metadata/TempCapabilitiesFinder.java
   trunk/engine/src/main/java/org/teiid/query/sql/symbol/Constant.java
   trunk/engine/src/main/java/org/teiid/query/tempdata/TempTable.java
   trunk/engine/src/main/java/org/teiid/query/tempdata/TempTableStore.java
   trunk/engine/src/main/java/org/teiid/query/validator/ValidationVisitor.java
   trunk/engine/src/main/resources/org/teiid/query/i18n.properties
   trunk/engine/src/test/java/org/teiid/query/processor/TestTempTables.java
   trunk/engine/src/test/java/org/teiid/query/processor/xml/TestXMLPlanningEnhancements.java
   trunk/engine/src/test/java/org/teiid/query/validator/TestValidator.java
Log:
TEIID-1167 adding support for predicate use of the index and validating that the primary key must be comparable

Modified: trunk/engine/src/main/java/org/teiid/common/buffer/STree.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/common/buffer/STree.java	2010-07-27 23:06:31 UTC (rev 2381)
+++ trunk/engine/src/main/java/org/teiid/common/buffer/STree.java	2010-07-28 04:40:32 UTC (rev 2382)
@@ -49,7 +49,7 @@
 	private int mask = 1;
 	private int shift = 1;
 	
-	private SPage[] header = new SPage[] {new SPage(this, true)};
+	protected SPage[] header = new SPage[] {new SPage(this, true)};
     protected BatchManager manager;
     protected Comparator comparator;
     protected int pageSize;
@@ -112,7 +112,7 @@
 	 * @throws IOException
 	 * @throws TeiidComponentException 
 	 */
-	private List find(List n, LinkedList<SearchResult> places) throws TeiidComponentException {
+	List find(List n, LinkedList<SearchResult> places) throws TeiidComponentException {
 		SPage x = null;
 		for (int i = header.length - 1; i >= 0; i--) {
 			if (x == null) {
@@ -313,10 +313,6 @@
 		return this.rowCount.get();
 	}
 	
-	public TupleBrowser browse(List lowerBound, List upperBound, boolean direction) {
-		return new TupleBrowser(direction);
-	}
-
 	public int truncate() {
 		int oldSize = rowCount.getAndSet(0);
 		for (int i = 0; i < header.length; i++) {
@@ -330,86 +326,6 @@
 		return oldSize;
 	}
 	
-	//TODO: support update/delete from the browser
-	public class TupleBrowser {
-		
-		SPage page = header[0];
-		int index;
-		TupleBatch values;
-		boolean updated;
-		boolean direction;
-		
-		public TupleBrowser(boolean direction) {
-			this.direction = direction;
-			if (!direction) {
-				while (page.prev != null) {
-					page = page.prev;
-				}
-			}
-		}
-		
-		public boolean matchedLower() {
-			return false;
-		}
-		
-		public boolean matchedUpper() {
-			return false;
-		}
-		
-		public List next() throws TeiidComponentException {
-			for (;;) {
-				if (values == null) {
-					values = page.getValues();
-					if (direction) {
-						index = 0;
-					} else {
-						index = values.getTuples().size() - 1;
-					}
-				}
-				if (index >= 0 && index < values.getTuples().size()) {
-					List result = values.getTuples().get(index);
-					index+=getOffset();
-					return result;
-				}
-				if (updated) {
-					page.setValues(values);
-				}
-				updated = false;
-				values = null;
-				if (direction) {
-					page = page.next;
-				} else {
-					page = page.prev;
-				}
-				if (page == null) {
-					return null;
-				}
-			}
-		}
-		
-		private int getOffset() {
-			return direction?1:-1;
-		}
-		
-		/**
-		 * Perform an in-place update of the tuple just returned by the next method
-		 * WARNING - this must not change the key value
-		 * @param tuple
-		 * @throws TeiidComponentException
-		 */
-		public void update(List tuple) throws TeiidComponentException {
-			values.getTuples().set(index - getOffset(), tuple);
-			updated = true;
-		}
-		
-		/**
-		 * Notify the browser that the last value was deleted.
-		 */
-		public void removed() {
-			index-=getOffset();
-		}
-	}
-	
 	@Override
 	public String toString() {
 		StringBuffer result = new StringBuffer();

Added: trunk/engine/src/main/java/org/teiid/common/buffer/TupleBrowser.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/common/buffer/TupleBrowser.java	                        (rev 0)
+++ trunk/engine/src/main/java/org/teiid/common/buffer/TupleBrowser.java	2010-07-28 04:40:32 UTC (rev 2382)
@@ -0,0 +1,208 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership.  Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+package org.teiid.common.buffer;
+
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.teiid.common.buffer.SPage.SearchResult;
+import org.teiid.core.TeiidComponentException;
+
+/**
+ * Implements intelligent browsing over a {@link STree}
+ * 
+ * TODO: when using other values we can be more efficient 
+ * with paging.
+ */
+public class TupleBrowser {
+	
+	private final STree tree;
+	
+	private List<List<?>> otherValues;
+	
+	private SPage page;
+	private int index;
+	
+	private SPage bound;
+	private int boundIndex = -1;
+	
+	private TupleBatch values;
+	private boolean updated;
+	private boolean direction;
+	private boolean range;
+	
+	public TupleBrowser(STree sTree, List<?> lowerBound, List<?> upperBound, List<List<?>> otherValues, boolean range, boolean direction) throws TeiidComponentException {
+		this.tree = sTree;
+		this.direction = direction;
+		this.otherValues = otherValues;
+		this.range = range;
+		
+		if (lowerBound != null) {
+			setPage(lowerBound);
+		} else {
+			page = sTree.header[0];
+		}
+		
+		boolean valid = true;
+		
+		if (upperBound != null) {
+			if (this.tree.comparator.compare(upperBound, lowerBound) < 0) {
+				valid = false;
+			}
+			LinkedList<SearchResult> places = new LinkedList<SearchResult>();
+			this.tree.find(upperBound, places);
+			SearchResult upper = places.getLast();
+			bound = upper.page;
+			boundIndex = upper.index;
+			if (boundIndex < 0) {
+				boundIndex = Math.min(upper.values.getTuples().size() - 1, -boundIndex -1);
+			}
+			if (!direction) {
+				values = upper.values;
+			}
+		} else if (range) {
+			//this is a range query
+			//TODO: this could also be signaled with an all null key
+			bound = tree.header[0];
+			while (bound.next != null) {
+				bound = bound.next;
+			}
+		} else {
+			bound = page;
+			boundIndex = index;
+		}
+				
+		if (!direction) {
+			SPage swap = page;
+			page = bound;
+			bound = swap;
+			int upperIndex = boundIndex;
+			boundIndex = index;
+			index = upperIndex;
+		}
+		
+		if (!valid) {
+			page = null;
+		}
+	}
+
+	private void setPage(List<?> lowerBound) throws TeiidComponentException {
+		if (values != null) {
+			int possibleIndex = Collections.binarySearch(values.getTuples(), lowerBound, tree.comparator);
+			if (possibleIndex != -1 && possibleIndex != -values.getTuples().size() -1) {
+				index = possibleIndex;
+				if (possibleIndex < 0) {
+					index = -index -1;
+				}
+				return;
+			}
+		}
+		resetState();
+		LinkedList<SearchResult> places = new LinkedList<SearchResult>();
+		this.tree.find(lowerBound, places);
+		
+		SearchResult sr = places.getLast();
+		page = sr.page;
+		index = sr.index;
+		if (index < 0) {
+			index = -index - 1;
+		}
+		values = sr.values;
+	}
+	
+	public List<?> next() throws TeiidComponentException {
+		for (;;) {
+			if (page == null) {
+				return null;
+			}
+			if (values == null) {
+				values = page.getValues();
+				if (direction) {
+					index = 0;
+				} else {
+					index = values.getTuples().size() - 1;
+				}
+			}
+			if (index >= 0 && index < values.getTuples().size()) {
+				List<?> result = values.getTuples().get(index);
+				if (page == bound && index == boundIndex) {
+					resetState();
+					page = null; //terminate
+				} else if (otherValues != null && !range) {
+					if (!otherValues.isEmpty()) {
+						List newBound = direction?otherValues.remove(0):otherValues.remove(otherValues.size() -1);
+						setPage(newBound);
+					} else {
+						otherValues = null;
+						if (page != bound) {
+							resetState();
+						}
+						page = bound;
+						index = boundIndex;
+						values = bound.values;
+					}
+				} else {
+					index+=getOffset();
+				}
+				return result;
+			}
+			resetState();
+			if (direction) {
+				page = page.next;
+			} else {
+				page = page.prev;
+			}
+		}
+	}
+
+	private void resetState() throws TeiidComponentException {
+		if (updated) {
+			page.setValues(values);
+		}
+		updated = false;
+		values = null;
+	}
+	
+	private int getOffset() {
+		return direction?1:-1;
+	}
+	
+	/**
+	 * Perform an in-place update of the tuple just returned by the next method
+	 * WARNING - this must not change the key value
+	 * @param tuple
+	 * @throws TeiidComponentException
+	 */
+	public void update(List<?> tuple) throws TeiidComponentException {
+		values.getTuples().set(index - getOffset(), tuple);
+		updated = true;
+	}
+	
+	/**
+	 * Notify the browser that the last value was deleted.
+	 */
+	public void removed() {
+		index-=getOffset();
+	}
+}
\ No newline at end of file


Property changes on: trunk/engine/src/main/java/org/teiid/common/buffer/TupleBrowser.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain

Modified: trunk/engine/src/main/java/org/teiid/query/metadata/TempCapabilitiesFinder.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/metadata/TempCapabilitiesFinder.java	2010-07-27 23:06:31 UTC (rev 2381)
+++ trunk/engine/src/main/java/org/teiid/query/metadata/TempCapabilitiesFinder.java	2010-07-28 04:40:32 UTC (rev 2382)
@@ -45,6 +45,13 @@
 	    		tempCaps = new BasicSourceCapabilities();
 	    		tempCaps.setCapabilitySupport(Capability.BULK_UPDATE, true);
 	    		tempCaps.setCapabilitySupport(Capability.QUERY_ORDERBY, true);
+	    		tempCaps.setCapabilitySupport(Capability.CRITERIA_NOT, true);
+	    		tempCaps.setCapabilitySupport(Capability.CRITERIA_IN, true);
+	    		tempCaps.setCapabilitySupport(Capability.CRITERIA_COMPARE_EQ, true);
+	    		tempCaps.setCapabilitySupport(Capability.CRITERIA_COMPARE_ORDERED, true);
+	    		tempCaps.setCapabilitySupport(Capability.CRITERIA_ISNULL, true);
+	    		tempCaps.setCapabilitySupport(Capability.CRITERIA_LIKE, true);
+	    		tempCaps.setCapabilitySupport(Capability.CRITERIA_LIKE_ESCAPE, true);
     		}
     		return tempCaps;
     	}

Modified: trunk/engine/src/main/java/org/teiid/query/sql/symbol/Constant.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/symbol/Constant.java	2010-07-27 23:06:31 UTC (rev 2381)
+++ trunk/engine/src/main/java/org/teiid/query/sql/symbol/Constant.java	2010-07-28 04:40:32 UTC (rev 2382)
@@ -37,7 +37,7 @@
  * value, but that is not true if the value is null.  In that case, the type is unknown
  * and is set to the null type until the type is resolved at a later point.
  */
-public class Constant implements Expression {
+public class Constant implements Expression, Comparable<Constant> {
 
 	private Object value;
 	private Class type;
@@ -181,5 +181,19 @@
 	public String toString() {
 		return SQLStringVisitor.getSQLString(this);
 	}
+
+	@Override
+	public int compareTo(Constant o) {
+		if (isNull()) {
+			if (o.isNull()) {
+				return 0;
+			}
+			return -1;
+		}
+		if (o.isNull()) {
+			return 1;
+		}
+		return ((Comparable)this.value).compareTo(o.getValue());
+	}
 	
 }

Added: trunk/engine/src/main/java/org/teiid/query/tempdata/IndexCondition.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/tempdata/IndexCondition.java	                        (rev 0)
+++ trunk/engine/src/main/java/org/teiid/query/tempdata/IndexCondition.java	2010-07-28 04:40:32 UTC (rev 2382)
@@ -0,0 +1,170 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership.  Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+package org.teiid.query.tempdata;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.TreeSet;
+
+import org.teiid.query.sql.lang.CompareCriteria;
+import org.teiid.query.sql.lang.Criteria;
+import org.teiid.query.sql.lang.IsNullCriteria;
+import org.teiid.query.sql.lang.MatchCriteria;
+import org.teiid.query.sql.lang.SetCriteria;
+import org.teiid.query.sql.symbol.Constant;
+import org.teiid.query.sql.symbol.ElementSymbol;
+import org.teiid.query.sql.symbol.Expression;
+
+class IndexCondition {
+	
+	static IndexCondition[] getIndexConditions(Criteria condition, List<ElementSymbol> keyColumns) {
+		List<Criteria> crits = Criteria.separateCriteriaByAnd(condition);
+		IndexCondition[] conditions = new IndexCondition[keyColumns.size()];
+		for (int i = 0; i < conditions.length; i++) {
+			if (i > 0 && (conditions[i - 1].range || conditions[i -1].upper != null)) {
+				break; //don't yet support any other types of composite key lookups
+			}
+			conditions[i] = new IndexCondition();
+			ElementSymbol keyColumn = keyColumns.get(i);
+			for (Iterator<Criteria> critIter = crits.iterator(); critIter.hasNext();) {
+				Criteria criteria = critIter.next();
+				if (criteria instanceof CompareCriteria) {
+					CompareCriteria cc = (CompareCriteria)criteria;
+					if (cc.getOperator() == CompareCriteria.NE 
+							|| !(cc.getRightExpression() instanceof Constant) || (cc.getOperator() != CompareCriteria.EQ && i > 0)) {
+						critIter.remove();
+						continue;
+					}
+					if (!cc.getLeftExpression().equals(keyColumn)) {
+						continue;
+					}
+					conditions[i].addCondition((Constant)cc.getRightExpression(), cc.getOperator());
+					critIter.remove();
+				} else if (criteria instanceof IsNullCriteria) {
+					IsNullCriteria inc = (IsNullCriteria)criteria;
+					if (inc.isNegated() || !inc.getExpression().equals(keyColumn)) {
+						continue;
+					}
+					conditions[i].addCondition(new Constant(null), CompareCriteria.EQ);
+					critIter.remove();
+				} else {
+					if (i > 0) {
+						critIter.remove();
+						continue;
+					}
+					if (criteria instanceof MatchCriteria) {
+						MatchCriteria matchCriteria = (MatchCriteria)criteria;
+						if (matchCriteria.isNegated() || !matchCriteria.getLeftExpression().equals(keyColumn) || !(matchCriteria.getRightExpression() instanceof Constant)) {
+							continue;
+						}
+						Constant value = (Constant)matchCriteria.getRightExpression();
+						String pattern = (String)value.getValue();
+						boolean escaped = false;
+						StringBuilder prefix = new StringBuilder();
+						for (int j = 0; i < pattern.length(); j++) {
+				            char character = pattern.charAt(j);
+				            
+				            if (character == matchCriteria.getEscapeChar() && character != MatchCriteria.NULL_ESCAPE_CHAR) {
+				                if (escaped) {
+				                    prefix.append(character);
+				                    escaped = false;
+				                } else {
+				                    escaped = true;
+				                }
+				            } else if (character == MatchCriteria.WILDCARD_CHAR || character == MatchCriteria.MATCH_CHAR) {
+				            	break;
+				            } else {
+				            	prefix.append(character);
+				            }
+						}
+						if (prefix.length() > 0) {
+							conditions[i].addCondition(new Constant(prefix.toString()), CompareCriteria.GE);
+						}
+					} else if (criteria instanceof SetCriteria) {
+						SetCriteria setCriteria = (SetCriteria)criteria;
+						if (!setCriteria.getExpression().equals(keyColumn)) {
+							continue;
+						}
+						TreeSet<Constant> values = new TreeSet<Constant>();
+						for (Expression expr : (List<? extends Expression>)setCriteria.getValues()) {
+							if (!(expr instanceof Constant)) {
+								continue;
+							}
+							values.add((Constant)expr);
+						}
+						conditions[i].addSet(values);
+					}
+				}
+			}
+		}
+		return conditions;
+	}
+	
+	Constant lower = null;
+	Constant upper = null;
+	boolean range = true;
+	TreeSet<Constant> otherValues = new TreeSet<Constant>();
+	
+	void addCondition(Constant value, int comparisionMode) {
+		switch (comparisionMode) {
+		case CompareCriteria.EQ:
+			otherValues.clear();
+			lower = value;
+			upper = null;
+			range = false;
+			break;
+		case CompareCriteria.GE:
+		case CompareCriteria.GT:
+			if (lower == null) {
+				range = true;
+				lower = value;
+			} 
+			break;
+		case CompareCriteria.LE:
+		case CompareCriteria.LT:
+			if (upper == null && range) {
+				upper = value;
+			}
+			break;
+		}
+	}
+	
+	void addSet(TreeSet<Constant> values) {
+		if (!range && lower != null) {
+			return;
+		}
+		Iterator<Constant> iter = values.iterator();
+		Constant lowest = iter.next();
+		iter.remove();
+		lower = lowest;
+		range = false;
+		iter = values.descendingIterator();
+		if (iter.hasNext()) {
+			Constant highest = iter.next();
+			upper = highest;
+			iter.remove();
+		}
+		otherValues.addAll(values);
+	}
+	
+}
\ No newline at end of file


Property changes on: trunk/engine/src/main/java/org/teiid/query/tempdata/IndexCondition.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain

Modified: trunk/engine/src/main/java/org/teiid/query/tempdata/TempTable.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/tempdata/TempTable.java	2010-07-27 23:06:31 UTC (rev 2381)
+++ trunk/engine/src/main/java/org/teiid/query/tempdata/TempTable.java	2010-07-28 04:40:32 UTC (rev 2382)
@@ -34,37 +34,93 @@
 import org.teiid.common.buffer.BlockedException;
 import org.teiid.common.buffer.BufferManager;
 import org.teiid.common.buffer.STree;
+import org.teiid.common.buffer.TupleBrowser;
 import org.teiid.common.buffer.TupleBuffer;
 import org.teiid.common.buffer.TupleSource;
 import org.teiid.common.buffer.BufferManager.TupleSourceType;
-import org.teiid.common.buffer.STree.TupleBrowser;
 import org.teiid.core.TeiidComponentException;
 import org.teiid.core.TeiidException;
 import org.teiid.core.TeiidProcessingException;
 import org.teiid.core.types.DataTypeManager;
 import org.teiid.query.QueryPlugin;
 import org.teiid.query.eval.Evaluator;
+import org.teiid.query.metadata.TempMetadataID;
 import org.teiid.query.processor.CollectionTupleSource;
 import org.teiid.query.processor.relational.RelationalNode;
 import org.teiid.query.processor.relational.SortUtility;
 import org.teiid.query.processor.relational.SortUtility.Mode;
-import org.teiid.query.sql.lang.Command;
 import org.teiid.query.sql.lang.Criteria;
 import org.teiid.query.sql.lang.OrderBy;
 import org.teiid.query.sql.lang.OrderByItem;
 import org.teiid.query.sql.lang.SetClauseList;
-import org.teiid.query.sql.symbol.AliasSymbol;
+import org.teiid.query.sql.symbol.Constant;
 import org.teiid.query.sql.symbol.ElementSymbol;
 import org.teiid.query.sql.symbol.Expression;
 import org.teiid.query.sql.symbol.SingleElementSymbol;
 
 /**
  * A Teiid Temp Table
- * TODO: an update will not happen unless the tuplesource is accessed
- * TODO: better handling for blocked exceptions (should be rare)
+ * TODO: in this implementation blocked exceptions will not happen
+ *       allowing for subquery evaluation though would cause pauses
  */
 class TempTable {
 	
+	private final class QueryTupleSource extends TupleBrowserTupleSource {
+		private final Evaluator eval;
+		private final List<SingleElementSymbol> projectedCols;
+		private final Criteria condition;
+		private final boolean project;
+		private final int[] indexes;
+
+		private QueryTupleSource(TupleBrowser browser, Map map,
+				List<SingleElementSymbol> projectedCols, Criteria condition) {
+			super(browser);
+			this.indexes = RelationalNode.getProjectionIndexes(map, projectedCols);
+			this.eval = new Evaluator(map, null, null);
+			this.projectedCols = projectedCols;
+			this.condition = condition;
+			this.project = shouldProject();
+		}
+
+		@Override
+		public List<?> nextTuple() throws TeiidComponentException,
+				TeiidProcessingException {
+			for (;;) {
+				List<?> next = super.nextTuple();
+				if (next == null) {
+					return null;
+				}
+				if (rowId != null) {
+					next = next.subList(1, next.size());
+				}
+				if (condition != null && !eval.evaluate(condition, next)) {
+					continue;
+				}
+				if (project) {
+					next = RelationalNode.projectTuple(indexes, next);
+				}
+				return next;
+			}
+		}
+		
+		private boolean shouldProject() {
+			if (indexes.length == getColumns().size()) {
+				for (int i = 0; i < indexes.length; i++) {
+					if (indexes[i] != i) {
+						return true;
+					}
+				}
+				return false;
+			} 
+			return true;
+		}
+
+		@Override
+		public List<? extends Expression> getSchema() {
+			return projectedCols;
+		}
+	}
+
 	private class TupleBrowserTupleSource implements TupleSource {
 		private final TupleBrowser browser;
 
@@ -94,18 +150,17 @@
 		}
 	}
 
-	private abstract class UpdateTupleSource implements TupleSource {
+	private abstract class UpdateProcessor {
 		private TupleSource ts;
 		protected final Map lookup;
 		protected final Evaluator eval;
 		private final Criteria crit;
 		protected int updateCount = 0;
-		protected boolean done;
 		private List currentTuple;
 		
 		protected TupleBuffer undoLog;
 
-		UpdateTupleSource(Criteria crit, TupleSource ts) throws TeiidComponentException {
+		UpdateProcessor(Criteria crit, TupleSource ts) throws TeiidComponentException {
 			this.ts = ts;
 			this.lookup = RelationalNode.createLookupMap(columns);
 			this.eval = new Evaluator(lookup, null, null);
@@ -113,32 +168,21 @@
 			this.undoLog = bm.createTupleBuffer(columns, sessionID, TupleSourceType.PROCESSOR);
 		}
 		
-		void process() throws TeiidComponentException, TeiidProcessingException {
-			//still have to worry about blocked exceptions...
-			while (currentTuple != null || (currentTuple = ts.nextTuple()) != null) {
-				if (crit == null || eval.evaluate(crit, currentTuple)) {
-					tuplePassed(currentTuple);
-					updateCount++;
-					undoLog.addTuple(currentTuple);
+		int process() throws ExpressionEvaluationException, TeiidComponentException, TeiidProcessingException {
+			boolean success = false;
+			try {
+				while (currentTuple != null || (currentTuple = ts.nextTuple()) != null) {
+					if (crit == null || eval.evaluate(crit, currentTuple)) {
+						tuplePassed(currentTuple);
+						updateCount++;
+						undoLog.addTuple(currentTuple);
+					}
+					currentTuple = null;
 				}
-				currentTuple = null;
-			}
-		}
-		
-		@Override
-		public List<?> nextTuple() throws TeiidComponentException,
-				TeiidProcessingException {
-			if (done) {
-				return null;
-			}
-			try {
-				process();
-			    done = true;
-			} catch (BlockedException e) {
-				//this is horrible...
-				throw e; 
+				success();
+				success = true;
 			} finally {
-				if (!done) {
+				if (!success) {
 					TupleSource undoTs = undoLog.createIndexedTupleSource();
 					List<?> tuple = null;
 					try {
@@ -149,26 +193,19 @@
 						
 					}
 				}
+				close();
 			}
-			return Arrays.asList(updateCount);
+			return updateCount;
 		}
+		
+		@SuppressWarnings("unused")
+		void success() throws TeiidComponentException, ExpressionEvaluationException, TeiidProcessingException {}
 
 		protected abstract void tuplePassed(List tuple) throws BlockedException, TeiidComponentException, TeiidProcessingException;
 		
 		protected abstract void undo(List tuple) throws TeiidComponentException, TeiidProcessingException;
 		
-		@Override
-		public List<SingleElementSymbol> getSchema() {
-			return Command.getUpdateCommandSymbol();
-		}
-
-		@Override
-		public int available() {
-			return 0;
-		}
-		
-		@Override
-		public void closeSource() {
+		public void close() {
 			ts.closeSource();
 			undoLog.remove();
 		}
@@ -180,8 +217,10 @@
 	private List<ElementSymbol> columns;
 	private BufferManager bm;
 	private String sessionID;
+	private TempMetadataID tid;
 
-	TempTable(BufferManager bm, List<ElementSymbol> columns, int primaryKeyLength, String sessionID) {
+	TempTable(TempMetadataID tid, BufferManager bm, List<ElementSymbol> columns, int primaryKeyLength, String sessionID) {
+		this.tid = tid;
 		this.bm = bm;
 		if (primaryKeyLength == 0) {
             ElementSymbol id = new ElementSymbol("rowId"); //$NON-NLS-1$
@@ -196,8 +235,9 @@
 		this.sessionID = sessionID;
 	}
 
-	public TupleSource createTupleSource(List<SingleElementSymbol> cols, Criteria condition, OrderBy orderBy) throws TeiidComponentException, TeiidProcessingException {
+	public TupleSource createTupleSource(final List<SingleElementSymbol> projectedCols, final Criteria condition, OrderBy orderBy) throws TeiidComponentException, TeiidProcessingException {
 		Map map = RelationalNode.createLookupMap(getColumns());
+		
 		Boolean direction = null;
 		boolean orderByUsingIndex = false;
 		if (orderBy != null && rowId == null) {
@@ -239,39 +279,9 @@
 		if (!orderByUsingIndex) {
 			direction = OrderBy.ASC;
 		}
-		TupleBrowser browser = createTupleBrower(null, direction);
 		
-		final int[] indexes = RelationalNode.getProjectionIndexes(map, cols);
-		final ArrayList<SingleElementSymbol> projectedCols = new ArrayList<SingleElementSymbol>(cols);
-		for (SingleElementSymbol singleElementSymbol : projectedCols) {
-			if (singleElementSymbol instanceof AliasSymbol) {
-				
-			}
-		}
-		final boolean project = shouldProject(indexes);
-		TupleSource ts = new TupleBrowserTupleSource(browser) {
-			
-			@Override
-			public List<?> nextTuple() throws TeiidComponentException,
-					TeiidProcessingException {
-				List<?> next = super.nextTuple();
-				if (next == null) {
-					return null;
-				}
-				if (rowId != null) {
-					next = next.subList(1, next.size());
-				}
-				if (project) {
-					next = RelationalNode.projectTuple(indexes, next);
-				}
-				return next;
-			}
-			
-			@Override
-			public List<? extends Expression> getSchema() {
-				return projectedCols;
-			}
-		};
+		TupleBrowser browser = createTupleBrower(condition, direction);
+		TupleSource ts = new QueryTupleSource(browser, map, projectedCols, condition);
 
 		TupleBuffer tb = null;
 		if (!orderByUsingIndex && orderBy != null) {
@@ -289,22 +299,37 @@
 		return tb.createIndexedTupleSource(true);
 	}
 
-	private boolean shouldProject(final int[] indexes) {
-		if (indexes.length == getColumns().size()) {
-			for (int i = 0; i < indexes.length; i++) {
-				if (indexes[i] != i) {
-					return true;
+	private TupleBrowser createTupleBrower(Criteria condition, boolean direction) throws TeiidComponentException {
+		List lower = null;
+		List upper = null;
+		List<List<?>> otherValues = null;
+		boolean range = true;
+		if (condition != null && rowId == null) {
+			IndexCondition[] indexConditions = IndexCondition.getIndexConditions(condition, columns.subList(0, tree.getKeyLength()));
+			if (indexConditions.length > 1 && indexConditions[indexConditions.length - 1] != null) {
+				lower = new ArrayList(indexConditions.length);
+				for (IndexCondition indexCondition : indexConditions) {
+					lower.add(indexCondition.lower.getValue());
 				}
+				range = false;
+				//TODO: support other composite key lookups
+			} else {
+				if (indexConditions[0].lower != null) {
+					lower = Arrays.asList(indexConditions[0].lower.getValue());
+				}
+				if (indexConditions[0].upper != null) {
+					upper = Arrays.asList(indexConditions[0].upper.getValue());
+				}
+				otherValues = new ArrayList<List<?>>();
+				for (Constant constant : indexConditions[0].otherValues) {
+					otherValues.add(Arrays.asList(constant.getValue()));
+				}
+				range = indexConditions[0].range;
 			}
-			return false;
-		} 
-		return true;
+		}
+		return new TupleBrowser(this.tree, lower, upper, otherValues, range, direction);
 	}
 	
-	private TupleBrowser createTupleBrower(List<Criteria> conditions, boolean direction) {
-		return tree.browse(null, null, direction);
-	}
-	
 	public int getRowCount() {
 		return tree.getRowCount();
 	}
@@ -324,8 +349,8 @@
 		return columns;
 	}
 	
-	public TupleSource insert(List<List<Object>> tuples) throws TeiidComponentException {
-        UpdateTupleSource uts = new UpdateTupleSource(null, new CollectionTupleSource(tuples.iterator(), getColumns())) {
+	public TupleSource insert(List<List<Object>> tuples) throws TeiidComponentException, ExpressionEvaluationException, TeiidProcessingException {
+        UpdateProcessor up = new UpdateProcessor(null, new CollectionTupleSource(tuples.iterator(), getColumns())) {
         	
         	protected void tuplePassed(List tuple) 
         	throws BlockedException, TeiidComponentException, TeiidProcessingException {
@@ -341,16 +366,18 @@
         	}
         	
         };
-        return uts;
+        int updateCount = up.process();
+        tid.setCardinality(tree.getRowCount());
+        return CollectionTupleSource.createUpdateCountTupleSource(updateCount);
     }
 	
-	public TupleSource update(Criteria crit, final SetClauseList update) throws TeiidComponentException {
+	public TupleSource update(Criteria crit, final SetClauseList update) throws TeiidComponentException, ExpressionEvaluationException, TeiidProcessingException {
 		final boolean primaryKeyChangePossible = canChangePrimaryKey(update);
-		final TupleBrowser browser = createTupleBrower(null, OrderBy.ASC);
-		UpdateTupleSource uts = new UpdateTupleSource(crit, new TupleBrowserTupleSource(browser)) {
+		final TupleBrowser browser = createTupleBrower(crit, OrderBy.ASC);
+		UpdateProcessor up = new UpdateProcessor(crit, new TupleBrowserTupleSource(browser)) {
 			
 			protected TupleBuffer changeSet;
-			protected TupleSource changeSetProcessor;
+			protected UpdateProcessor changeSetProcessor;
 			
 			@Override
 			protected void tuplePassed(List tuple)
@@ -373,14 +400,21 @@
 			}
 			
 			@Override
-			void process() throws TeiidComponentException,
-					TeiidProcessingException {
-				super.process();
+			protected void undo(List tuple) throws TeiidComponentException, TeiidProcessingException {
+				if (primaryKeyChangePossible) {
+					insertTuple(tuple);
+				} else {
+					updateTuple(tuple);
+				}
+			}
+			
+			@Override
+			void success() throws TeiidComponentException, ExpressionEvaluationException, TeiidProcessingException {
 				//existing tuples have been removed
 				//changeSet contains possible updates
 				if (primaryKeyChangePossible) {
 					if (changeSetProcessor == null) {
-						changeSetProcessor = new UpdateTupleSource(null, changeSet.createIndexedTupleSource(true)) {
+						changeSetProcessor = new UpdateProcessor(null, changeSet.createIndexedTupleSource(true)) {
 							@Override
 							protected void tuplePassed(List tuple) throws BlockedException,
 									TeiidComponentException, TeiidProcessingException {
@@ -395,24 +429,15 @@
 							
 						};
 					}
-					changeSetProcessor.nextTuple(); //when this returns, we're up to date
+					changeSetProcessor.process(); //when this returns, we're up to date
 				}
 			}
 			
 			@Override
-			protected void undo(List tuple) throws TeiidComponentException, TeiidProcessingException {
-				if (primaryKeyChangePossible) {
-					insertTuple(tuple);
-				} else {
-					updateTuple(tuple);
-				}
-			}
-			
-			@Override
-			public void closeSource() {
-				super.closeSource();
+			public void close() {
+				super.close();
 				if (changeSetProcessor != null) {
-					changeSetProcessor.closeSource(); // causes a revert of the change set
+					changeSetProcessor.close(); // causes a revert of the change set
 				}
 				if (changeSet != null) {
 					changeSet.remove();
@@ -420,7 +445,8 @@
 			}
 			
 		};
-		return uts;
+		int updateCount = up.process();
+		return CollectionTupleSource.createUpdateCountTupleSource(updateCount);
 	}
 
 	private boolean canChangePrimaryKey(final SetClauseList update) {
@@ -434,9 +460,9 @@
 		return false;
 	}
 	
-	public TupleSource delete(Criteria crit) throws TeiidComponentException {
-		final TupleBrowser browser = createTupleBrower(null, OrderBy.ASC);
-		UpdateTupleSource uts = new UpdateTupleSource(crit, new TupleBrowserTupleSource(browser)) {
+	public TupleSource delete(Criteria crit) throws TeiidComponentException, ExpressionEvaluationException, TeiidProcessingException {
+		final TupleBrowser browser = createTupleBrower(crit, OrderBy.ASC);
+		UpdateProcessor up = new UpdateProcessor(crit, new TupleBrowserTupleSource(browser)) {
 			@Override
 			protected void tuplePassed(List tuple)
 					throws ExpressionEvaluationException,
@@ -450,7 +476,9 @@
 				insertTuple(tuple);
 			}
 		};
-		return uts;
+		int updateCount = up.process();
+		tid.setCardinality(tree.getRowCount());
+		return CollectionTupleSource.createUpdateCountTupleSource(updateCount);
 	}
 	
 	private void insertTuple(List<Object> list) throws TeiidComponentException, TeiidProcessingException {

Modified: trunk/engine/src/main/java/org/teiid/query/tempdata/TempTableStore.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/tempdata/TempTableStore.java	2010-07-27 23:06:31 UTC (rev 2381)
+++ trunk/engine/src/main/java/org/teiid/query/tempdata/TempTableStore.java	2010-07-28 04:40:32 UTC (rev 2382)
@@ -95,7 +95,7 @@
     		columns.removeAll(primaryKey);
     		columns.addAll(0, primaryKey);
     	}
-        TempTable tempTable = new TempTable(buffer, columns, create.getPrimaryKey().size(), sessionID);
+        TempTable tempTable = new TempTable(id, buffer, columns, create.getPrimaryKey().size(), sessionID);
         groupToTupleSourceID.put(tempTableName, tempTable);
     }
 
@@ -131,10 +131,7 @@
             		return element;
             	}
             };
-            PostOrderNavigator.doVisit(query.getSelect(), emv);
-            if (query.getOrderBy() != null) {
-            	PostOrderNavigator.doVisit(query.getOrderBy(), emv);
-            }
+            PostOrderNavigator.doVisit(query, emv);
             return table.createTupleSource(command.getProjectedSymbols(), query.getCriteria(), query.getOrderBy());
         }
         if (command instanceof ProcedureContainer) {

Modified: trunk/engine/src/main/java/org/teiid/query/validator/ValidationVisitor.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/validator/ValidationVisitor.java	2010-07-27 23:06:31 UTC (rev 2381)
+++ trunk/engine/src/main/java/org/teiid/query/validator/ValidationVisitor.java	2010-07-28 04:40:32 UTC (rev 2382)
@@ -57,6 +57,7 @@
 import org.teiid.query.sql.lang.Command;
 import org.teiid.query.sql.lang.CompareCriteria;
 import org.teiid.query.sql.lang.CompoundCriteria;
+import org.teiid.query.sql.lang.Create;
 import org.teiid.query.sql.lang.Criteria;
 import org.teiid.query.sql.lang.Delete;
 import org.teiid.query.sql.lang.DependentSetCriteria;
@@ -1061,6 +1062,13 @@
         }
     }
     
+    @Override
+    public void visit(Create obj) {
+    	if (!obj.getPrimaryKey().isEmpty()) {
+    		validateSortable(obj.getPrimaryKey());
+    	}
+    }
+    
     /** 
      * @see org.teiid.query.sql.LanguageVisitor#visit(org.teiid.query.sql.lang.Drop)
      */

Modified: trunk/engine/src/main/resources/org/teiid/query/i18n.properties
===================================================================
--- trunk/engine/src/main/resources/org/teiid/query/i18n.properties	2010-07-27 23:06:31 UTC (rev 2381)
+++ trunk/engine/src/main/resources/org/teiid/query/i18n.properties	2010-07-28 04:40:32 UTC (rev 2382)
@@ -276,7 +276,7 @@
 ERR.015.012.0023 = Unable to translate criteria on the update command against the virtual group, the element {0} is mapped to an expression whose elements are not present on the command in the procedure using the translated criteria.
 ERR.015.012.0024 = The following data elements are not supported in the SELECT clause: {0}.
 ERR.015.012.0025 = Command must project at least one symbol
-ERR.015.012.0026 = Expressions of type OBJECT, CLOB, BLOB, or XML cannot be used in SELECT DISTINCT, ORDER BY, GROUP BY, or non-all set queries: [{0}]
+ERR.015.012.0026 = Expressions of type OBJECT, CLOB, BLOB, or XML cannot be used in SELECT DISTINCT, ORDER BY, GROUP BY, KEYS, or non-all set queries: [{0}]
 ERR.015.012.0027 = Expressions of type OBJECT, CLOB, BLOB, or XML cannot be used in comparison: {0}.
 ValidationVisitor.expression_requires_name = Non-column expressions require a name in XMLATTRIBUTES, XMLFOREST, or QUERYSTRING
 ValidationVisitor.invalid_lookup_key=Expressions of type OBJECT, CLOB, BLOB, or XML cannot be used as LOOKUP key columns: {0}.

Modified: trunk/engine/src/test/java/org/teiid/query/processor/TestTempTables.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/processor/TestTempTables.java	2010-07-27 23:06:31 UTC (rev 2381)
+++ trunk/engine/src/test/java/org/teiid/query/processor/TestTempTables.java	2010-07-28 04:40:32 UTC (rev 2382)
@@ -157,4 +157,35 @@
 		execute("select * from x order by e1", new List[] {Arrays.asList("a", 3), Arrays.asList("b", 2)}); //$NON-NLS-1$
 	}
 	
+	@Test public void testCompareEqualsWithIndex() throws Exception {
+		execute("create local temporary table x (e1 string, e2 integer, primary key (e2))", new List[] {Arrays.asList(0)}); //$NON-NLS-1$
+		execute("insert into x (e2, e1) values (3, 'a')", new List[] {Arrays.asList(1)}); //$NON-NLS-1$
+		execute("insert into x (e2, e1) values (2, 'b')", new List[] {Arrays.asList(1)}); //$NON-NLS-1$
+		execute("select * from x where e2 = 3", new List[] {Arrays.asList("a", 3)}); //$NON-NLS-1$
+	}
+	
+	@Test public void testLikeWithIndex() throws Exception {
+		execute("create local temporary table x (e1 string, e2 integer, primary key (e1))", new List[] {Arrays.asList(0)}); //$NON-NLS-1$
+		execute("insert into x (e2, e1) values (3, 'a')", new List[] {Arrays.asList(1)}); //$NON-NLS-1$
+		execute("insert into x (e2, e1) values (2, 'b')", new List[] {Arrays.asList(1)}); //$NON-NLS-1$
+		execute("select * from x where e1 like 'z%'", new List[0]); //$NON-NLS-1$
+	}
+	
+	@Test public void testIsNullWithIndex() throws Exception {
+		execute("create local temporary table x (e1 string, e2 integer, primary key (e1))", new List[] {Arrays.asList(0)}); //$NON-NLS-1$
+		execute("insert into x (e2, e1) values (3, null)", new List[] {Arrays.asList(1)}); //$NON-NLS-1$
+		execute("insert into x (e2, e1) values (2, 'b')", new List[] {Arrays.asList(1)}); //$NON-NLS-1$
+		execute("select * from x where e1 is null", new List[] {Arrays.asList(null, 3)}); //$NON-NLS-1$
+	}
+	
+	@Test public void testInWithIndex() throws Exception {
+		execute("create local temporary table x (e1 string, e2 integer, primary key (e1))", new List[] {Arrays.asList(0)}); //$NON-NLS-1$
+		execute("insert into x (e2, e1) values (3, 'a')", new List[] {Arrays.asList(1)}); //$NON-NLS-1$
+		execute("insert into x (e2, e1) values (2, 'b')", new List[] {Arrays.asList(1)}); //$NON-NLS-1$
+		execute("insert into x (e2, e1) values (1, 'c')", new List[] {Arrays.asList(1)}); //$NON-NLS-1$
+		execute("insert into x (e2, e1) values (0, 'd')", new List[] {Arrays.asList(1)}); //$NON-NLS-1$
+		execute("insert into x (e2, e1) values (-1, 'e')", new List[] {Arrays.asList(1)}); //$NON-NLS-1$
+		execute("select * from x where e1 in ('a', 'c', 'e')", new List[] {Arrays.asList("a", 3), Arrays.asList("c", 1), Arrays.asList("e", -1)}); //$NON-NLS-1$
+	}
+	
 }

Modified: trunk/engine/src/test/java/org/teiid/query/processor/xml/TestXMLPlanningEnhancements.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/processor/xml/TestXMLPlanningEnhancements.java	2010-07-27 23:06:31 UTC (rev 2381)
+++ trunk/engine/src/test/java/org/teiid/query/processor/xml/TestXMLPlanningEnhancements.java	2010-07-28 04:40:32 UTC (rev 2382)
@@ -454,7 +454,7 @@
         
         ExecSqlInstruction instr = (ExecSqlInstruction)list.get(2);
         
-        ProcessorPlan plan = (ProcessorPlan)instr.info.getPlan();  
+        ProcessorPlan plan = instr.info.getPlan();  
         
         TestOptimizer.checkNodeTypes(plan, new int[] {
             2,      // Access
@@ -468,7 +468,7 @@
             0,      // Null
             0,      // PlanExecution
             1,      // Project
-            1,      // Select
+            0,      // Select
             0,      // Sort
             0       // UnionAll
         });        
@@ -494,7 +494,7 @@
         
         ExecSqlInstruction instr = (ExecSqlInstruction)list.get(2);
         
-        ProcessorPlan plan = (ProcessorPlan)instr.info.getPlan();        
+        ProcessorPlan plan = instr.info.getPlan();        
         TestOptimizer.checkNodeTypes(plan, new int[] {
             2,      // Access
             0,      // DependentAccess
@@ -507,7 +507,7 @@
             0,      // Null
             0,      // PlanExecution
             1,      // Project
-            1,      // Select
+            0,      // Select
             0,      // Sort
             0       // UnionAll
         });   

Modified: trunk/engine/src/test/java/org/teiid/query/validator/TestValidator.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/validator/TestValidator.java	2010-07-27 23:06:31 UTC (rev 2381)
+++ trunk/engine/src/test/java/org/teiid/query/validator/TestValidator.java	2010-07-28 04:40:32 UTC (rev 2382)
@@ -1879,6 +1879,12 @@
     @Test public void testSelectIntoWithNull() {
         helpValidate("SELECT null, null, null, null INTO pm1.g1 FROM pm1.g2", new String[] {}, FakeMetadataFactory.example1Cached()); //$NON-NLS-1$
     }
+    
+    @Test public void testCreateWithNonSortablePrimaryKey() {
+        QueryMetadataInterface metadata = FakeMetadataFactory.example1Cached();
+        Command command = helpResolve("create local temporary table x (column1 string, column2 clob, primary key (column2))", metadata); //$NON-NLS-1$
+        helpRunValidator(command, new String[] {"column2"}, FakeMetadataFactory.example1Cached()); 
+    }
         
     @Test public void testDropNonTemporary() {
         QueryMetadataInterface metadata = FakeMetadataFactory.example1Cached();



More information about the teiid-commits mailing list