[teiid-commits] teiid SVN: r2371 - in trunk: build/kits/jboss-container and 29 other directories.

teiid-commits at lists.jboss.org teiid-commits at lists.jboss.org
Fri Jul 23 17:44:22 EDT 2010


Author: shawkins
Date: 2010-07-23 17:44:19 -0400 (Fri, 23 Jul 2010)
New Revision: 2371

Added:
   trunk/engine/src/main/java/org/teiid/common/buffer/SPage.java
   trunk/engine/src/main/java/org/teiid/common/buffer/STree.java
   trunk/engine/src/main/java/org/teiid/query/tempdata/TempTable.java
   trunk/engine/src/test/java/org/teiid/common/buffer/impl/TestSTree.java
Removed:
   trunk/engine/src/main/java/org/teiid/query/tempdata/TempTableStoreImpl.java
   trunk/engine/src/test/java/org/teiid/internal/
   trunk/runtime/src/test/java/com/metamatrix/dqp/
Modified:
   trunk/api/src/main/java/org/teiid/language/SQLConstants.java
   trunk/build/kits/jboss-container/teiid-releasenotes.html
   trunk/engine/src/main/java/org/teiid/common/buffer/BufferManager.java
   trunk/engine/src/main/java/org/teiid/common/buffer/TupleBatch.java
   trunk/engine/src/main/java/org/teiid/common/buffer/TupleBuffer.java
   trunk/engine/src/main/java/org/teiid/common/buffer/impl/BufferManagerImpl.java
   trunk/engine/src/main/java/org/teiid/common/buffer/impl/MemoryStorageManager.java
   trunk/engine/src/main/java/org/teiid/dqp/internal/process/CodeTableCache.java
   trunk/engine/src/main/java/org/teiid/dqp/internal/process/DQPCore.java
   trunk/engine/src/main/java/org/teiid/dqp/internal/process/DataTierManagerImpl.java
   trunk/engine/src/main/java/org/teiid/dqp/internal/process/RequestWorkItem.java
   trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/NewCalculateCostUtil.java
   trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePlanJoins.java
   trunk/engine/src/main/java/org/teiid/query/processor/CollectionTupleSource.java
   trunk/engine/src/main/java/org/teiid/query/processor/batch/BatchedUpdatePlan.java
   trunk/engine/src/main/java/org/teiid/query/processor/proc/ProcedurePlan.java
   trunk/engine/src/main/java/org/teiid/query/processor/relational/PlanExecutionNode.java
   trunk/engine/src/main/java/org/teiid/query/processor/relational/ProjectIntoNode.java
   trunk/engine/src/main/java/org/teiid/query/processor/relational/UnionAllNode.java
   trunk/engine/src/main/java/org/teiid/query/processor/xml/XMLPlan.java
   trunk/engine/src/main/java/org/teiid/query/resolver/command/TempTableResolver.java
   trunk/engine/src/main/java/org/teiid/query/resolver/util/ResolverVisitor.java
   trunk/engine/src/main/java/org/teiid/query/sql/lang/Create.java
   trunk/engine/src/main/java/org/teiid/query/sql/navigator/PreOrPostOrderNavigator.java
   trunk/engine/src/main/java/org/teiid/query/sql/visitor/SQLStringVisitor.java
   trunk/engine/src/main/java/org/teiid/query/tempdata/TempTableStore.java
   trunk/engine/src/main/javacc/org/teiid/query/parser/SQLParser.jj
   trunk/engine/src/main/resources/org/teiid/query/i18n.properties
   trunk/engine/src/test/java/org/teiid/dqp/internal/process/TestCodeTableCache.java
   trunk/engine/src/test/java/org/teiid/query/optimizer/TestOptionalJoins.java
   trunk/engine/src/test/java/org/teiid/query/parser/TestParser.java
   trunk/engine/src/test/java/org/teiid/query/processor/TestProcessor.java
   trunk/engine/src/test/java/org/teiid/query/processor/TestTempTables.java
   trunk/engine/src/test/java/org/teiid/query/processor/proc/TestProcedureProcessor.java
   trunk/engine/src/test/java/org/teiid/query/processor/relational/TestProjectIntoNode.java
   trunk/engine/src/test/java/org/teiid/query/resolver/TestResolver.java
   trunk/engine/src/test/java/org/teiid/query/sql/util/TestElementSymbolOptimizer.java
   trunk/engine/src/test/java/org/teiid/query/sql/visitor/TestSQLStringVisitor.java
Log:
TEIID-1167 initial support for temp tables with primary keys.  We're using a simplified tree structure as the index with everything hooked (or forced) into the existing buffer support.  search optimizations and other concerns have not been hooked up yet.

Modified: trunk/api/src/main/java/org/teiid/language/SQLConstants.java
===================================================================
--- trunk/api/src/main/java/org/teiid/language/SQLConstants.java	2010-07-23 20:47:35 UTC (rev 2370)
+++ trunk/api/src/main/java/org/teiid/language/SQLConstants.java	2010-07-23 21:44:19 UTC (rev 2371)
@@ -96,6 +96,8 @@
 		public static final String NULLS = "NULLS"; //$NON-NLS-1$
 		public static final String FIRST = "FIRST"; //$NON-NLS-1$
 		public static final String LAST = "LAST"; //$NON-NLS-1$
+		
+		public static final String KEY = "KEY"; //$NON-NLS-1$
 	}
 	
 	public interface Reserved {

Modified: trunk/build/kits/jboss-container/teiid-releasenotes.html
===================================================================
--- trunk/build/kits/jboss-container/teiid-releasenotes.html	2010-07-23 20:47:35 UTC (rev 2370)
+++ trunk/build/kits/jboss-container/teiid-releasenotes.html	2010-07-23 21:44:19 UTC (rev 2371)
@@ -120,6 +120,7 @@
 The following components have been updated:
 <h4>From 7.0</h4>
 <ul>
+	<li>Direct integration of JBossCache jars were removed.
 	<li>Netty was upgraded to 3.2.0	
 	<li>JDOM was removed.
 </ul>

Modified: trunk/engine/src/main/java/org/teiid/common/buffer/BufferManager.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/common/buffer/BufferManager.java	2010-07-23 20:47:35 UTC (rev 2370)
+++ trunk/engine/src/main/java/org/teiid/common/buffer/BufferManager.java	2010-07-23 21:44:19 UTC (rev 2371)
@@ -114,4 +114,6 @@
      */
     int getSchemaSize(List elements);
     
+    STree createSTree(final List elements, String groupName, TupleSourceType tupleSourceType, int keyLength);
+    
 }

Added: trunk/engine/src/main/java/org/teiid/common/buffer/SPage.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/common/buffer/SPage.java	                        (rev 0)
+++ trunk/engine/src/main/java/org/teiid/common/buffer/SPage.java	2010-07-23 21:44:19 UTC (rev 2371)
@@ -0,0 +1,143 @@
+/*
+ * 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.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.teiid.common.buffer.BatchManager.ManagedBatch;
+import org.teiid.core.TeiidComponentException;
+
+/**
+ * A linked list Page entry in the tree
+ */
+ at SuppressWarnings("unchecked")
+class SPage {
+	
+	static final int MIN_PERSISTENT_SIZE = 16;
+
+	static class SearchResult {
+		int index;
+		SPage page;
+		List values;
+		public SearchResult(int index, SPage page, List values) {
+			this.index = index;
+			this.page = page;
+			this.values = values;
+		}
+	}
+	
+	private static AtomicInteger counter = new AtomicInteger();
+
+	STree stree;
+	
+	protected SPage next; 
+	protected ManagedBatch managedBatch;
+	protected List values;
+	protected ArrayList<SPage> children;
+	
+	SPage(STree stree, boolean leaf) {
+		this.stree = stree;
+		this.values = new ArrayList<SPage>(stree.pageSize);
+		if (!leaf) {
+			children = new ArrayList<SPage>(stree.pageSize/4);
+		}
+	}
+	
+	static SearchResult search(SPage page, List k, SearchResult parent, List parentKey) throws TeiidComponentException {
+		SPage previous = null;
+		List previousValues = null;
+		for (;;) {
+			List values = page.getValues();
+			int index = Collections.binarySearch(values, k, page.stree.comparator);
+			int actual = - index - 1;
+			if (previous != null) {
+				if (actual == 0) {
+					if (values.isEmpty()) {
+						page.remove();
+						previous.next = page.next;
+					}
+					return new SearchResult(-previousValues.size() - 1, previous, previousValues);
+				}
+				if (parentKey != null) {
+					if (page.stree.comparator.compare(parentKey, values.get(0)) >= 0) {
+						//TODO: the entries after this point may also need moved forward
+						//TODO: this should be done as part of insert
+						parent.page.children.set(Math.max(0, -parent.index - 2), page);
+					} else {
+						//parentKey < page.keys.get(0)
+						//TODO: this circumvents the normal probabilistic process, but
+						//ensures there is an index entry.
+						page.stree.insert(page.stree.extractKey((List) values.get(0)), parent, page);
+						parent.index--;
+					}
+				}
+			}
+			if (actual != values.size() || page.next == null) {
+				return new SearchResult(index, page, values);
+			}
+			previous = page;
+			previousValues = values; 
+			page = page.next;
+		}
+	}
+	
+	protected void setValues(List values) throws TeiidComponentException {
+		if (managedBatch != null) {
+			managedBatch.remove();
+		}
+		if (values.size() < MIN_PERSISTENT_SIZE) {
+			this.values = values;
+			return;
+		} 
+		this.values = null;
+		TupleBatch batch = TupleBatch.directBatch(counter.getAndIncrement(), values);
+		if (children != null) {
+			batch.setDataTypes(stree.keytypes);
+		} else {
+			batch.setDataTypes(stree.types);
+		}
+		managedBatch = stree.manager.createManagedBatch(batch);
+	}
+	
+	protected void remove() {
+		if (managedBatch != null) {
+			managedBatch.remove();
+			managedBatch = null;
+		}
+	}
+
+	protected List getValues() throws TeiidComponentException {
+		if (values != null) {
+			return values;
+		}
+		if (managedBatch == null) {
+			return Collections.emptyList();
+		}
+		TupleBatch batch = managedBatch.getBatch(true, stree.types);
+		return batch.getTuples();
+	}
+
+}


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

Added: trunk/engine/src/main/java/org/teiid/common/buffer/STree.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/common/buffer/STree.java	                        (rev 0)
+++ trunk/engine/src/main/java/org/teiid/common/buffer/STree.java	2010-07-23 21:44:19 UTC (rev 2371)
@@ -0,0 +1,343 @@
+/*
+ * 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.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Random;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.teiid.common.buffer.SPage.SearchResult;
+import org.teiid.core.TeiidComponentException;
+
+ at SuppressWarnings("unchecked")
+
+/**
+ * Self balancing search tree using skip list like logic
+ * This has similar performance similar to a B+/-Tree 
+ * 
+ * TODO: reserve additional memory for delete/update operations
+ * TODO: double link to support desc key access
+ */
+public class STree {
+
+	private static final Random seedGenerator = new Random();
+
+	private int randomSeed;
+	private SPage[] header = new SPage[] {new SPage(this, true)};
+    protected BatchManager manager;
+    protected Comparator comparator;
+    protected int pageSize;
+    protected int keyLength;
+    protected String[] types;
+    protected String[] keytypes;
+    
+    private AtomicInteger rowCount = new AtomicInteger();
+	
+	public STree(BatchManager recman,
+            final Comparator comparator,
+            int pageSize,
+            int keyLength,
+            String[] types) {
+		randomSeed = seedGenerator.nextInt() | 0x00000100; // ensure nonzero
+		this.manager = recman;
+		this.comparator = comparator;
+		this.pageSize = Math.max(pageSize, SPage.MIN_PERSISTENT_SIZE);
+		this.keyLength = keyLength;
+		this.types = types;
+		this.keytypes = Arrays.copyOf(types, keyLength);
+	}
+
+	/**
+	 * Determine a new random level using an XOR rng.
+	 * 
+	 * This uses the simplest of the generators described in George
+     * Marsaglia's "Xorshift RNGs" paper.  This is not a high-quality
+     * generator but is acceptable here.
+	 * 
+	 * See also the JSR-166 working group ConcurrentSkipListMap implementation.
+	 * 
+	 * @return
+	 */
+    private int randomLevel() {
+        int x = randomSeed;
+        x ^= x << 13;
+        x ^= x >>> 17;
+        randomSeed = x ^= x << 5;
+        int level = 0;
+        int shift = 8;
+        while ((x & 0xff) == 0xff) { 
+        	++level;
+        	x >>>= shift;
+        }
+        return level;
+    }
+    
+	/**
+	 * Search each level to find the pointer to the next level
+	 * @param n
+	 * @param places
+	 * @return
+	 * @throws IOException
+	 * @throws TeiidComponentException 
+	 */
+	private List find(List n, List<SearchResult> places) throws TeiidComponentException {
+		SPage x = null;
+		List parentKey = null;
+		SearchResult parent = null;
+		for (int i = header.length - 1; i >= 0; i--) {
+			if (x == null) {
+				x = header[i];
+			}
+			SearchResult s = SPage.search(x, n, parent, parentKey);
+			if (places != null) {
+				places.add(s);
+			}
+			if ((s.index == -1 && s.page == header[i]) || s.values.isEmpty()) {
+				x = null;
+				continue; //start at the beginning of the next level
+			}
+			x = s.page;
+			int index = s.index;
+			boolean matched = true;
+			if (index < 0) {
+				matched = false;
+				index = Math.max(0, -index - 2);
+			}
+			if (i == 0) {
+				if (!matched) {
+					return null;
+				}
+				return (List) s.values.get(index);
+			}
+			parentKey = (List) s.values.get(index);
+			parent = s;
+			x = x.children.get(index);
+		}
+		return null;
+	}
+	
+	public List find(List k) throws TeiidComponentException {
+		return find(k, null);
+	}
+	
+	public List insert(List tuple, boolean replace) throws TeiidComponentException {
+		LinkedList<SearchResult> places = new LinkedList<SearchResult>();
+		List match = find(tuple, places);
+		if (match != null) {
+			if (!replace) {
+				return match;
+			}
+			SearchResult last = places.getLast();
+			SPage page = last.page;
+			last.values.set(last.index, tuple);
+			page.setValues(last.values);
+			return match;
+		}
+		List key = extractKey(tuple);
+		int level = randomLevel(); 
+		assert header.length == places.size();
+		if (level >= header.length) {
+			header = Arrays.copyOf(header, level + 1);
+		}
+		rowCount.addAndGet(1);
+		SPage page = null;
+		for (int i = 0; i <= level; i++) {
+			if (places.isEmpty()) {
+				SPage newHead = new SPage(this, false);
+				ArrayList newValues = new ArrayList();
+				newValues.add(key);
+				newHead.setValues(newValues);
+				newHead.children.add(page);
+				header[i] = newHead;
+				page = newHead;
+			} else {
+				SearchResult result = places.removeLast();
+				Object value = (i == 0 ? tuple : page);
+				page = insert(key, result, value);
+			}
+		}
+		return null;
+	}
+	
+	List extractKey(List tuple) {
+		return tuple.subList(0, keyLength);
+	}
+
+	SPage insert(List k, SearchResult result, Object value) throws TeiidComponentException {
+		SPage page = result.page;
+		int index = -result.index - 1;
+		if (result.values.size() == pageSize) {
+			boolean leaf = !(value instanceof SPage);
+			SPage nextPage = new SPage(this, leaf);
+			ArrayList nextValues = new ArrayList(result.values.subList(pageSize/2, pageSize));
+			result.values.subList(pageSize/2, pageSize).clear();
+			if (!leaf) {
+				nextPage.children.addAll(page.children.subList(pageSize/2, pageSize));
+				page.children.subList(pageSize/2, pageSize).clear();
+			}
+			nextPage.next = page.next;
+			page.next = nextPage;
+			boolean inNext = false;
+			if (index <= pageSize/2) {
+				setValue(index, k, value, result.values, page);
+			} else {
+				inNext = true;
+				setValue(index - pageSize/2, k, value, nextValues, nextPage);
+			}
+			nextPage.setValues(nextValues);
+			page.setValues(result.values);
+			if (inNext) {
+				page = nextPage;
+			}
+		} else {
+			setValue(index, k, value, result.values, page);
+			page.setValues(result.values);
+		}
+		return page;
+	}
+	
+	static void setValue(int index, List key, Object value, List values, SPage page) {
+		if (value instanceof SPage) {
+			values.add(index, key);
+			page.children.add(index, (SPage) value);
+		} else {
+			values.add(index, value);
+		}
+	}
+	
+	public List remove(List key) throws TeiidComponentException {
+		LinkedList<SearchResult> places = new LinkedList<SearchResult>();
+		List tuple = find(key, places);
+		if (tuple == null) {
+			return null;
+		}
+		rowCount.addAndGet(-1);
+		for (int i = header.length -1; i >=0; i--) {
+			SearchResult searchResult = places.remove();
+			if (searchResult.index < 0) {
+				continue;
+			}
+			boolean cleanup = false;
+			searchResult.values.remove(searchResult.index);
+			int size = searchResult.values.size();
+			if (size == 0) {
+				if (header[i] == searchResult.page && (i != 0 || header[i].next != null)) {
+					header[i].remove();
+					header[i] = header[i].next;
+					if (header[i] == null) {
+						//remove the layer
+						header = Arrays.copyOf(header, header.length - 1);
+					}
+				} else if (i == 0 && header.length > 1) {
+					cleanup = true;
+				}
+			} else if (searchResult.page.next != null && size < pageSize/4) {
+				List nextValues = searchResult.page.next.getValues();
+				SPage next = searchResult.page.next;
+				if (nextValues.size() + size < pageSize/2) {
+					searchResult.page.next = next.next;
+					searchResult.values.addAll(nextValues);
+					nextValues.clear();
+					next.remove();
+					//any references to toMerge are now invalid
+					//setting back to the header will self heal
+					//TODO: this can take advantage of a previous link
+					next.next = header[i];
+				}
+			}
+			searchResult.page.setValues(searchResult.values);
+			if (cleanup) {
+				find(key, null); //trigger cleanup
+			}
+		}
+		return tuple;
+	}
+	
+	public void remove() {
+		truncate();
+		this.manager.remove();
+	}
+
+	public int getRowCount() {
+		return this.rowCount.get();
+	}
+	
+	public TupleBrowser browse(List lowerBound, List upperBound, boolean direction) {
+		return new TupleBrowser();
+	}
+
+	public int truncate() {
+		int oldSize = rowCount.getAndSet(0);
+		for (int i = 0; i < header.length; i++) {
+			SPage page = header[i];
+			while (page != null) {
+				page.remove();
+				page = page.next;
+			}
+		}
+		header = new SPage[] {new SPage(this, true)};
+		return oldSize;
+	}
+	
+	//TODO: support update/delete from the browser
+	public class TupleBrowser {
+		
+		SPage page = header[0];
+		int index;
+		List values;
+		
+		public boolean matchedLower() {
+			return false;
+		}
+		
+		public boolean matchedUpper() {
+			return false;
+		}
+		
+		public List next() throws TeiidComponentException {
+			for (;;) {
+				if (values == null) {
+					values = page.getValues();
+				}
+				if (index < values.size()) {
+					return (List) values.get(index++);
+				}
+				index = 0;
+				page = page.next;
+				if (page == null) {
+					return null;
+				}
+			}
+		}
+	}
+	
+	public int getKeyLength() {
+		return keyLength;
+	}
+	
+}
\ No newline at end of file


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

Modified: trunk/engine/src/main/java/org/teiid/common/buffer/TupleBatch.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/common/buffer/TupleBatch.java	2010-07-23 20:47:35 UTC (rev 2370)
+++ trunk/engine/src/main/java/org/teiid/common/buffer/TupleBatch.java	2010-07-23 21:44:19 UTC (rev 2371)
@@ -26,6 +26,8 @@
 import java.io.IOException;
 import java.io.ObjectInput;
 import java.io.ObjectOutput;
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 
 import org.teiid.client.BatchSerializer;
@@ -45,7 +47,7 @@
 	private static final long serialVersionUID = 6304443387337336957L;
 	
 	private int rowOffset;    
-    private List[] tuples;
+    private List<List> tuples;
     
     // Optional state
     private boolean terminationFlag = false;
@@ -61,6 +63,13 @@
     public TupleBatch() {
     }
     
+    public static TupleBatch directBatch(int rowOffset, List<List> tuples) {
+    	TupleBatch result = new TupleBatch();
+    	result.rowOffset = rowOffset;
+    	result.tuples = tuples;
+    	return result;
+    }
+    
     /**
      * Constructor
      * @param beginRow indicates the row of the tuple source which is the
@@ -70,7 +79,7 @@
      */
     public TupleBatch(int beginRow, List[] tuples) {
         this.rowOffset = beginRow;
-        this.tuples = tuples;
+        this.tuples = Arrays.asList(tuples);
     }
 
     /**
@@ -82,7 +91,7 @@
      */
     public TupleBatch(int beginRow, List listOfTupleLists) {
         this.rowOffset = beginRow;
-        this.tuples = (List[]) listOfTupleLists.toArray(new List[listOfTupleLists.size()]);
+        this.tuples = new ArrayList(listOfTupleLists);
     }
 
     /**
@@ -100,7 +109,7 @@
      * @return the last row contained in this tuple batch
      */
     public int getEndRow() {
-        return rowOffset + tuples.length - 1;
+        return rowOffset + tuples.size() - 1;
     }
     
     /**
@@ -108,7 +117,7 @@
      * @return the number of rows contained in this tuple batch
      */
     public int getRowCount() {
-        return tuples.length;
+        return tuples.size();
     }
         
     /**
@@ -116,15 +125,19 @@
      * @return the tuple at the given index
      */
     public List getTuple(int rowIndex) {
-        return tuples[rowIndex-rowOffset];
+        return tuples.get(rowIndex-rowOffset);
     }
     
+    public List<List> getTuples() {
+		return tuples;
+	}
+    
     /**
      * Get all tuples 
      * @return All tuples
      */
     public List[] getAllTuples() { 
-        return tuples;    
+    	return tuples.toArray(new List[tuples.size()]);    
     }
 
     /**
@@ -164,21 +177,22 @@
         s.append("TupleBatch; beginning row="); //$NON-NLS-1$
         s.append(rowOffset);
         s.append(", number of rows="); //$NON-NLS-1$
-        s.append(tuples.length);
+        s.append(tuples.size());
         s.append(", lastBatch="); //$NON-NLS-1$
         s.append(this.terminationFlag);
         return s.toString();
     }
 
     public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
-        //rowOffset = in.readInt();
         terminationFlag = in.readBoolean();
-        tuples = BatchSerializer.readBatch(in, types);
+        tuples = new ArrayList<List>();
+        for (List tuple : BatchSerializer.readBatch(in, types)) {
+        	tuples.add(tuple);
+        }
     }
     public void writeExternal(ObjectOutput out) throws IOException {
-        //out.writeInt(rowOffset);
         out.writeBoolean(terminationFlag);
-        BatchSerializer.writeBatch(out, types, tuples);
+        BatchSerializer.writeBatch(out, types, getAllTuples());
     }
     
     public void setRowOffset(int rowOffset) {

Modified: trunk/engine/src/main/java/org/teiid/common/buffer/TupleBuffer.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/common/buffer/TupleBuffer.java	2010-07-23 20:47:35 UTC (rev 2370)
+++ trunk/engine/src/main/java/org/teiid/common/buffer/TupleBuffer.java	2010-07-23 21:44:19 UTC (rev 2371)
@@ -106,7 +106,7 @@
 	
 	public void addTuple(List<?> tuple) throws TeiidComponentException {
 		if (lobs) {
-			correctLobReferences(new List[] {tuple});
+			correctLobReferences(schema.size(), tuple);
 		}
 		this.rowCount++;
 		if (batchBuffer == null) {
@@ -126,12 +126,12 @@
 	public void addTupleBatch(TupleBatch batch, boolean save) throws TeiidComponentException {
 		setRowCount(batch.getBeginRow() - 1); 
 		if (save) {
-			for (List<?> tuple : batch.getAllTuples()) {
+			for (List<?> tuple : batch.getTuples()) {
 				addTuple(tuple);
 			}
 		} else {
 			//add the lob references only, since they may still be referenced later
-			correctLobReferences(batch.getAllTuples()); 
+			correctLobReferences(batch.getTuples()); 
 		}
 	}
 
@@ -210,7 +210,7 @@
 			BatchManager.ManagedBatch batch = entry.getValue();
 	    	result = batch.getBatch(!forwardOnly, types);
 	    	if (lobs && result.getDataTypes() == null) {
-		        correctLobReferences(result.getAllTuples());
+		        correctLobReferences(result.getTuples());
 	    	}
 	    	result.setDataTypes(types);
 	    	if (forwardOnly) {
@@ -277,42 +277,51 @@
      * @throws TeiidComponentException 
      */
     @SuppressWarnings("unchecked")
-	private void correctLobReferences(List[] rows) throws TeiidComponentException {
+	private void correctLobReferences(List<List> rows) throws TeiidComponentException {
         int columns = schema.size();
         // walk through the results and find all the lobs
-        for (int row = 0; row < rows.length; row++) {
-            for (int col = 0; col < columns; col++) {                                                
-                Object anObj = rows[row].get(col);
-                
-                if (!(anObj instanceof Streamable<?>)) {
-                	continue;
-                }
-                Streamable lob = (Streamable)anObj;                  
-                String id = lob.getReferenceStreamId();
-            	if (id == null) {
-            		id = String.valueOf(LOB_ID.getAndIncrement());
-            		lob.setReferenceStreamId(id);
-            	}
-            	if (this.lobReferences == null) {
-            		this.lobReferences = new ConcurrentHashMap<String, Streamable<?>>();
-            	}
-            	this.lobReferences.put(id, lob);
-                if (lob.getReference() == null) {
-                	lob.setReference(getLobReference(lob.getReferenceStreamId()).getReference());
-                }
-            }
+        for (List list : rows) {
+            correctLobReferences(columns, list);
         }
     }
+
+	private void correctLobReferences(int columns, List list)
+			throws TeiidComponentException {
+		for (int col = 0; col < columns; col++) {                                                
+		    Object anObj = list.get(col);
+		    
+		    if (!(anObj instanceof Streamable<?>)) {
+		    	continue;
+		    }
+		    Streamable lob = (Streamable)anObj;                  
+		    String id = lob.getReferenceStreamId();
+			if (id == null) {
+				id = String.valueOf(LOB_ID.getAndIncrement());
+				lob.setReferenceStreamId(id);
+			}
+			if (this.lobReferences == null) {
+				this.lobReferences = new ConcurrentHashMap<String, Streamable<?>>();
+			}
+			this.lobReferences.put(id, lob);
+		    if (lob.getReference() == null) {
+		    	lob.setReference(getLobReference(lob.getReferenceStreamId()).getReference());
+		    }
+		}
+	}
     
     public void setForwardOnly(boolean forwardOnly) {
 		this.forwardOnly = forwardOnly;
 	}
     
+	public IndexedTupleSource createIndexedTupleSource() {
+		return createIndexedTupleSource(false);
+	}
+    
 	/**
 	 * Create a new iterator for this buffer
 	 * @return
 	 */
-	public IndexedTupleSource createIndexedTupleSource() {
+	public IndexedTupleSource createIndexedTupleSource(final boolean singleUse) {
 		return new AbstractTupleSource() {
 			
 			@Override
@@ -337,6 +346,14 @@
 			protected TupleBatch getBatch(int row) throws TeiidComponentException {
 				return TupleBuffer.this.getBatch(row);
 			}
+			
+			@Override
+			public void closeSource() {
+				super.closeSource();
+				if (singleUse) {
+					remove();
+				}
+			}
 		};
 	}
 	

Modified: trunk/engine/src/main/java/org/teiid/common/buffer/impl/BufferManagerImpl.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/common/buffer/impl/BufferManagerImpl.java	2010-07-23 20:47:35 UTC (rev 2370)
+++ trunk/engine/src/main/java/org/teiid/common/buffer/impl/BufferManagerImpl.java	2010-07-23 21:44:19 UTC (rev 2371)
@@ -30,21 +30,29 @@
 import java.io.OutputStream;
 import java.lang.ref.Reference;
 import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
 import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.TreeMap;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentSkipListMap;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReadWriteLock;
 import java.util.concurrent.locks.ReentrantLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
 
 import javax.xml.transform.Source;
 
 import org.teiid.common.buffer.BatchManager;
 import org.teiid.common.buffer.BufferManager;
 import org.teiid.common.buffer.FileStore;
+import org.teiid.common.buffer.STree;
 import org.teiid.common.buffer.StorageManager;
 import org.teiid.common.buffer.TupleBatch;
 import org.teiid.common.buffer.TupleBuffer;
@@ -62,6 +70,7 @@
 import org.teiid.logging.LogConstants;
 import org.teiid.logging.LogManager;
 import org.teiid.query.execution.QueryExecPlugin;
+import org.teiid.query.processor.relational.ListNestedSortComparator;
 import org.teiid.query.processor.xml.XMLUtil;
 
 
@@ -84,7 +93,87 @@
 public class BufferManagerImpl implements BufferManager, StorageManager {
 	
 	private static final int IO_BUFFER_SIZE = 1 << 14;
+	private static final int COMPACTION_THRESHOLD = 1 << 25; //start checking at 32 megs
 	
+	private final class BatchManagerImpl implements BatchManager {
+		private final String id;
+		private final int columnCount;
+		private volatile FileStore store;
+		private Map<Long, long[]> physicalMapping = new ConcurrentHashMap<Long, long[]>();
+		private Map<Long, String[]> types = new ConcurrentSkipListMap<Long, String[]>();
+		private ReadWriteLock compactionLock = new ReentrantReadWriteLock();
+		private AtomicLong unusedSpace = new AtomicLong();
+
+		private BatchManagerImpl(String newID, int columnCount) {
+			this.id = newID;
+			this.columnCount = columnCount;
+			this.store = createFileStore(id);
+			this.store.setCleanupReference(this);
+		}
+
+		@Override
+		public ManagedBatch createManagedBatch(TupleBatch batch)
+				throws TeiidComponentException {
+			ManagedBatchImpl mbi = new ManagedBatchImpl(batch, this);
+			mbi.addToCache(false);
+			persistBatchReferences();
+			return mbi;
+		}
+		
+		private boolean shouldCompact(long offset) {
+			return offset > COMPACTION_THRESHOLD && unusedSpace.get() * 4 > offset * 3;
+		}
+		
+		private long getOffset() throws TeiidComponentException {
+			long offset = store.getLength();
+			if (!shouldCompact(offset)) {
+				return offset;
+			}
+			try {
+				this.compactionLock.writeLock().lock();
+				offset = store.getLength();
+				//retest the condition to ensure that compaction is still needed
+				if (!shouldCompact(offset)) {
+					return offset;
+				}
+				FileStore newStore = createFileStore(id);
+				newStore.setCleanupReference(this);
+				byte[] buffer = new byte[IO_BUFFER_SIZE];
+				List<long[]> values = new ArrayList<long[]>(physicalMapping.values());
+				Collections.sort(values, new Comparator<long[]>() {
+					@Override
+					public int compare(long[] o1, long[] o2) {
+						return Long.signum(o1[0] - o2[0]);
+					}
+				});
+				for (long[] info : values) {
+					long oldOffset = info[0];
+					info[0] = newStore.getLength();
+					int size = (int)info[1];
+					while (size > 0) {
+						int toWrite = Math.min(IO_BUFFER_SIZE, size);
+						store.readFully(oldOffset, buffer, 0, toWrite);
+						newStore.write(buffer, 0, toWrite);
+						size -= toWrite;
+					}
+				}
+				store.remove();
+				store = newStore;
+				long oldOffset = offset;
+				offset = store.getLength();
+				LogManager.logTrace(LogConstants.CTX_BUFFER_MGR, "Compacted store", id, "pre-size", oldOffset, "post-size", offset); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+				return offset;
+			} finally {
+				this.compactionLock.writeLock().unlock();
+			}
+		}
+
+		@Override
+		public void remove() {
+			this.store.remove();
+		}
+	}
+
 	/**
 	 * Holder for active batches
 	 */
@@ -95,33 +184,26 @@
 		ManagedBatchImpl removeBatch(int row) {
 			ManagedBatchImpl result = batches.remove(row);
 			if (result != null) {
-				activeBatchColumnCount -= result.columnCount;
+				activeBatchColumnCount -= result.batchManager.columnCount;
 			}
 			return result;
 		}
 	}
 	
 	private final class ManagedBatchImpl implements ManagedBatch {
-		final private String id;
-		final private FileStore store;
-		
-		private long offset = -1;
 		private boolean persistent;
 		private volatile TupleBatch activeBatch;
 		private volatile Reference<TupleBatch> batchReference;
 		private int beginRow;
-		private int columnCount;
+		private BatchManagerImpl batchManager;
+		private long id;
 		
-		public ManagedBatchImpl(String id, FileStore store, TupleBatch batch) {
-            LogManager.logTrace(LogConstants.CTX_BUFFER_MGR, "Add batch to BufferManager", batchAdded.incrementAndGet()); //$NON-NLS-1$
-			this.id = id;
-			this.store = store;
+		public ManagedBatchImpl(TupleBatch batch, BatchManagerImpl manager) {
+			id = batchAdded.incrementAndGet();
+            LogManager.logTrace(LogConstants.CTX_BUFFER_MGR, "Add batch to BufferManager", id); //$NON-NLS-1$
 			this.activeBatch = batch;
 			this.beginRow = batch.getBeginRow();
-			List[] allTuples = batch.getAllTuples();
-			if (allTuples.length > 0) {
-				columnCount = allTuples[0].size();
-			}
+			this.batchManager = manager;
 		}
 
 		private void addToCache(boolean update) {
@@ -130,19 +212,19 @@
 				if (batch == null) {
 					return; //already removed
 				}
-				activeBatchColumnCount += columnCount;
+				activeBatchColumnCount += batchManager.columnCount;
 				TupleBufferInfo tbi = null;
 				if (update) {
-					tbi = activeBatches.remove(this.id);
+					tbi = activeBatches.remove(batchManager.id);
 				} else {
-					tbi = activeBatches.get(this.id);
+					tbi = activeBatches.get(batchManager.id);
 				}
 				if (tbi == null) {
 					tbi = new TupleBufferInfo();
 					update = true;
 				} 
 				if (update) {
-					activeBatches.put(this.id, tbi);
+					activeBatches.put(batchManager.id, tbi);
 				}
 				Assertion.isNull(tbi.batches.put(this.beginRow, this));
 			}
@@ -151,9 +233,9 @@
 		@Override
 		public TupleBatch getBatch(boolean cache, String[] types) throws TeiidComponentException {
 			long reads = readAttempts.incrementAndGet();
-			LogManager.logTrace(LogConstants.CTX_BUFFER_MGR, id, "getting batch", reads, "reference hits", referenceHit.get()); //$NON-NLS-1$ //$NON-NLS-2$
+			LogManager.logTrace(LogConstants.CTX_BUFFER_MGR, batchManager.id, "getting batch", reads, "reference hits", referenceHit.get()); //$NON-NLS-1$ //$NON-NLS-2$
 			synchronized (activeBatches) {
-				TupleBufferInfo tbi = activeBatches.remove(this.id);
+				TupleBufferInfo tbi = activeBatches.remove(batchManager.id);
 				if (tbi != null) { 
 					boolean put = true;
 					if (!cache) {
@@ -164,7 +246,7 @@
 					}
 					if (put) {
 						tbi.lastUsed = this.beginRow;
-						activeBatches.put(this.id, tbi);
+						activeBatches.put(batchManager.id, tbi);
 					}
 				}
 			}
@@ -188,9 +270,11 @@
 					}
 				}
 				long count = readCount.incrementAndGet();
-				LogManager.logTrace(LogConstants.CTX_BUFFER_MGR, id, beginRow, "reading batch from disk, total reads:", count); //$NON-NLS-1$
+				LogManager.logTrace(LogConstants.CTX_BUFFER_MGR, batchManager.id, id, "reading batch from disk, total reads:", count); //$NON-NLS-1$
 				try {
-		            ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(store.createInputStream(this.offset), IO_BUFFER_SIZE));
+					this.batchManager.compactionLock.readLock().lock();
+					long[] info = batchManager.physicalMapping.get(this.id);
+					ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(batchManager.store.createInputStream(info[0]), IO_BUFFER_SIZE));
 		            batch = new TupleBatch();
 		            batch.setDataTypes(types);
 		            batch.readExternal(ois);
@@ -202,28 +286,36 @@
 			        }
 					return batch;
 		        } catch(IOException e) {
-		        	throw new TeiidComponentException(e, QueryExecPlugin.Util.getString("FileStoreageManager.error_reading", id)); //$NON-NLS-1$
+		        	throw new TeiidComponentException(e, QueryExecPlugin.Util.getString("FileStoreageManager.error_reading", batchManager.id)); //$NON-NLS-1$
 		        } catch (ClassNotFoundException e) {
-		        	throw new TeiidComponentException(e, QueryExecPlugin.Util.getString("FileStoreageManager.error_reading", id)); //$NON-NLS-1$
+		        	throw new TeiidComponentException(e, QueryExecPlugin.Util.getString("FileStoreageManager.error_reading", batchManager.id)); //$NON-NLS-1$
+		        } finally {
+		        	this.batchManager.compactionLock.readLock().unlock();
 		        }
 			}
 		}
 
 		public synchronized void persist() throws TeiidComponentException {
+			boolean lockheld = false;
 			try {
 				TupleBatch batch = activeBatch;
 				if (batch != null) {
 					if (!persistent) {
 						long count = writeCount.incrementAndGet();
-						LogManager.logTrace(LogConstants.CTX_BUFFER_MGR, id, beginRow, "writing batch to disk, total writes: ", count); //$NON-NLS-1$
-						synchronized (store) {
-							offset = store.getLength();
-							OutputStream fsos = new BufferedOutputStream(store.createOutputStream(), IO_BUFFER_SIZE);
+						LogManager.logTrace(LogConstants.CTX_BUFFER_MGR, batchManager.id, id, "writing batch to disk, total writes: ", count); //$NON-NLS-1$
+						long offset = 0;
+						synchronized (batchManager.store) {
+							offset = batchManager.getOffset();
+							OutputStream fsos = new BufferedOutputStream(batchManager.store.createOutputStream(), IO_BUFFER_SIZE);
 				            ObjectOutputStream oos = new ObjectOutputStream(fsos);
 				            batch.writeExternal(oos);
 				            oos.close();
+				            long size = batchManager.store.getLength() - offset;
+				            long[] info = new long[] {offset, size};
+				            batchManager.physicalMapping.put(this.id, info);
+				            batchManager.types.put(this.id, batch.getDataTypes());
 						}
-						LogManager.logTrace(LogConstants.CTX_BUFFER_MGR, id, beginRow, "batch written starting at:", offset); //$NON-NLS-1$
+						LogManager.logTrace(LogConstants.CTX_BUFFER_MGR, batchManager.id, id, "batch written starting at:", offset); //$NON-NLS-1$
 					}
 					this.batchReference = new WeakReference<TupleBatch>(batch);
 				}
@@ -232,23 +324,32 @@
 			} finally {
 				persistent = true;
 				activeBatch = null;
+				if (lockheld) {
+					this.batchManager.compactionLock.writeLock().unlock();
+				}
 			}
 		}
 
 		public void remove() {
 			synchronized (activeBatches) {
-				TupleBufferInfo tbi = activeBatches.get(this.id);
-				if (tbi != null && tbi.removeBatch(this.beginRow) != null && tbi.batches.isEmpty()) {
-					activeBatches.remove(this.id);
+				TupleBufferInfo tbi = activeBatches.get(batchManager.id);
+				if (tbi != null && tbi.removeBatch(this.beginRow) != null) {
+					if (tbi.batches.isEmpty()) {
+						activeBatches.remove(batchManager.id);
+					}
 				}
 			}
+			long[] info = batchManager.physicalMapping.remove(id);
+			if (info != null) {
+				batchManager.unusedSpace.addAndGet(info[1]); 
+			}
 			activeBatch = null;
 			batchReference = null;
 		}
 		
 		@Override
 		public String toString() {
-			return "ManagedBatch " + id + " " + activeBatch; //$NON-NLS-1$ //$NON-NLS-2$
+			return "ManagedBatch " + batchManager.id + " " + activeBatch; //$NON-NLS-1$ //$NON-NLS-2$
 		}
 	}
 	
@@ -267,7 +368,7 @@
     
     private StorageManager diskMgr;
 
-    private AtomicLong currentTuple = new AtomicLong();
+    private AtomicLong tsId = new AtomicLong();
     private AtomicLong batchAdded = new AtomicLong();
     private AtomicLong readCount = new AtomicLong();
 	private AtomicLong writeCount = new AtomicLong();
@@ -342,37 +443,26 @@
     @Override
     public TupleBuffer createTupleBuffer(final List elements, String groupName,
     		TupleSourceType tupleSourceType) {
-    	final String newID = String.valueOf(this.currentTuple.getAndIncrement());
+    	final String newID = String.valueOf(this.tsId.getAndIncrement());
     	
-    	BatchManager batchManager = new BatchManager() {
-    		private FileStore store;
-
-    		@Override
-    		public ManagedBatch createManagedBatch(TupleBatch batch)
-    				throws TeiidComponentException {
-    			if (this.store == null) {
-    				this.store = createFileStore(newID);
-    				this.store.setCleanupReference(this);
-    			}
-    			ManagedBatchImpl mbi = new ManagedBatchImpl(newID, store, batch);
-    			mbi.addToCache(false);
-    			persistBatchReferences();
-    			return mbi;
-    		}
-
-    		@Override
-    		public void remove() {
-    			if (this.store != null) {
-    				this.store.remove();
-    				this.store = null;
-    			}
-    		}
-    	};
+    	BatchManager batchManager = new BatchManagerImpl(newID, elements.size());
         TupleBuffer tupleBuffer = new TupleBuffer(batchManager, newID, elements, getProcessorBatchSize());
         LogManager.logDetail(LogConstants.CTX_BUFFER_MGR, "Creating TupleBuffer:", newID, "of type ", tupleSourceType); //$NON-NLS-1$ //$NON-NLS-2$
         return tupleBuffer;
     }
     
+    public STree createSTree(final List elements, String groupName, TupleSourceType tupleSourceType, int keyLength) {
+    	final String newID = String.valueOf(this.tsId.getAndIncrement());
+    	
+    	BatchManager bm = new BatchManagerImpl(newID, elements.size());
+    	int[] compareIndexes = new int[keyLength];
+    	for (int i = 1; i < compareIndexes.length; i++) {
+			compareIndexes[i] = i;
+		}
+        LogManager.logDetail(LogConstants.CTX_BUFFER_MGR, "Creating STree:", newID, "of type ", tupleSourceType); //$NON-NLS-1$ //$NON-NLS-2$
+    	return new STree(bm, new ListNestedSortComparator(compareIndexes), getProcessorBatchSize(), keyLength, TupleBuffer.getTypeNames(elements));
+    }
+
     @Override
     public FileStore createFileStore(String name) {
         LogManager.logDetail(LogConstants.CTX_BUFFER_MGR, "Creating FileStore:", name); //$NON-NLS-1$ 

Modified: trunk/engine/src/main/java/org/teiid/common/buffer/impl/MemoryStorageManager.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/common/buffer/impl/MemoryStorageManager.java	2010-07-23 20:47:35 UTC (rev 2370)
+++ trunk/engine/src/main/java/org/teiid/common/buffer/impl/MemoryStorageManager.java	2010-07-23 21:44:19 UTC (rev 2371)
@@ -43,6 +43,7 @@
 			public void writeDirect(byte[] bytes, int offset, int length) throws TeiidComponentException {
 				if (getLength() + length > buffer.capacity()) {
 					ByteBuffer newBuffer = ByteBuffer.allocate(buffer.capacity() * 2 + length);
+					buffer.position(0);
 					newBuffer.put(buffer);
 					buffer = newBuffer;
 				}

Modified: trunk/engine/src/main/java/org/teiid/dqp/internal/process/CodeTableCache.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/dqp/internal/process/CodeTableCache.java	2010-07-23 20:47:35 UTC (rev 2370)
+++ trunk/engine/src/main/java/org/teiid/dqp/internal/process/CodeTableCache.java	2010-07-23 21:44:19 UTC (rev 2371)
@@ -138,7 +138,7 @@
      * @param results QueryResults of <List<List<keyValue, returnValue>>
      * @throws TeiidProcessingException 
      */
-    public synchronized void loadTable(CacheKey cacheKey, List[] records) throws TeiidProcessingException {
+    public synchronized void loadTable(CacheKey cacheKey, List<List> records) throws TeiidProcessingException {
 		// Lookup the existing data  
 		// Map of data: keyValue --> returnValue;
 		CodeTable table = codeTableCache.get(cacheKey);
@@ -148,7 +148,7 @@
 		
 		// Determine whether the results should be added to code table cache
     	// Depends on size of results and available memory and system parameters
-		int potentialSize = table.codeMap.size() + records.length;
+		int potentialSize = table.codeMap.size() + records.size();
     	if (potentialSize > maxCodeTableRecords) {
     		throw new TeiidProcessingException("ERR.018.005.0100", DQPPlugin.Util.getString("ERR.018.005.0100", "maxCodeTables")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$                  
     	}
@@ -158,9 +158,8 @@
     	}
 		
         // Add data: <List<List<keyValue, returnValue>> from results to the code table cache
-      	for ( int i = 0; i < records.length; i++ ) {
+    	for (List<Object> record : records) {
       		// each record or row
-      		List<Object> record = records[i];
       		Object keyValue = record.get(0);
       		Object returnValue = record.get(1);
       		Object existing = table.codeMap.put(keyValue, returnValue);

Modified: trunk/engine/src/main/java/org/teiid/dqp/internal/process/DQPCore.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/dqp/internal/process/DQPCore.java	2010-07-23 20:47:35 UTC (rev 2370)
+++ trunk/engine/src/main/java/org/teiid/dqp/internal/process/DQPCore.java	2010-07-23 21:44:19 UTC (rev 2371)
@@ -72,7 +72,7 @@
 import org.teiid.logging.MessageLevel;
 import org.teiid.logging.CommandLogMessage.Event;
 import org.teiid.query.processor.ProcessorDataManager;
-import org.teiid.query.tempdata.TempTableStoreImpl;
+import org.teiid.query.tempdata.TempTableStore;
 
 
 /**
@@ -144,9 +144,9 @@
 	
 	static class ClientState {
 		List<RequestID> requests;
-		TempTableStoreImpl tempTableStoreImpl;
+		TempTableStore tempTableStoreImpl;
 		
-		public ClientState(TempTableStoreImpl tableStoreImpl) {
+		public ClientState(TempTableStore tableStoreImpl) {
 			this.tempTableStoreImpl = tableStoreImpl;
 		}
 		
@@ -236,7 +236,7 @@
     	synchronized (clientState) {
     		ClientState state = clientState.get(key);
     		if (state == null && create) {
-    			state = new ClientState(new TempTableStoreImpl(bufferManager, key, null));
+    			state = new ClientState(new TempTableStore(bufferManager, key, null));
         		clientState.put(key, state);
     		}
     		return state;

Modified: trunk/engine/src/main/java/org/teiid/dqp/internal/process/DataTierManagerImpl.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/dqp/internal/process/DataTierManagerImpl.java	2010-07-23 20:47:35 UTC (rev 2370)
+++ trunk/engine/src/main/java/org/teiid/dqp/internal/process/DataTierManagerImpl.java	2010-07-23 21:44:19 UTC (rev 2371)
@@ -406,7 +406,7 @@
         	processor.setNonBlocking(true); //process lookup as fully blocking
             while (true) {
             	TupleBatch batch = processor.nextBatch();
-            	codeTableCache.loadTable(codeRequestId, batch.getAllTuples());	
+            	codeTableCache.loadTable(codeRequestId, batch.getTuples());	
             	if (batch.getTerminationFlag()) {
             		break;
             	}

Modified: trunk/engine/src/main/java/org/teiid/dqp/internal/process/RequestWorkItem.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/dqp/internal/process/RequestWorkItem.java	2010-07-23 20:47:35 UTC (rev 2370)
+++ trunk/engine/src/main/java/org/teiid/dqp/internal/process/RequestWorkItem.java	2010-07-23 21:44:19 UTC (rev 2371)
@@ -431,11 +431,8 @@
     			} else if (fromBuffer && isForwardOnly()) {
         			savedBatch = batch;
     			}
-        		int firstOffset = beginRow - batch.getBeginRow();
-                List[] memoryRows = batch.getAllTuples();
-                List[] rows = new List[count];
-                System.arraycopy(memoryRows, firstOffset, rows, 0, endRow - beginRow + 1);
-                batch = new TupleBatch(beginRow, rows);
+                List<List> memoryRows = batch.getTuples();
+                batch = new TupleBatch(beginRow, memoryRows.subList(beginRow - batch.getBeginRow(), endRow - batch.getBeginRow() + 1));
                 batch.setTerminationFlag(last);
     		} else if (!fromBuffer){
     			result = !isForwardOnly();

Modified: trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/NewCalculateCostUtil.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/NewCalculateCostUtil.java	2010-07-23 20:47:35 UTC (rev 2370)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/NewCalculateCostUtil.java	2010-07-23 21:44:19 UTC (rev 2371)
@@ -141,7 +141,11 @@
                 break;
 
             case NodeConstants.Types.GROUP:
-                estimateNodeCost(node, (List)node.getProperty(NodeConstants.Info.GROUP_COLS), metadata);
+            	if (!node.hasCollectionProperty(NodeConstants.Info.GROUP_COLS)) {
+            		setCardinalityEstimate(node, 1f);
+            	} else {
+            		estimateNodeCost(node, (List)node.getProperty(NodeConstants.Info.GROUP_COLS), metadata);
+            	}
                 break;
             case NodeConstants.Types.ACCESS:
             case NodeConstants.Types.SORT:
@@ -153,7 +157,7 @@
                 break;
             }
             case NodeConstants.Types.NULL:
-                setCardinalityEstimate(node, new Float(0));
+                setCardinalityEstimate(node, 0f);
                 break;
 
             case NodeConstants.Types.PROJECT:
@@ -164,7 +168,7 @@
                     PlanNode child = node.getFirstChild();
                     childCost = (Float)child.getProperty(NodeConstants.Info.EST_CARDINALITY);
                 } else {
-                    childCost = new Float(1);
+                    childCost = 1f;
                 }
                 setCardinalityEstimate(node, childCost);
                 break;

Modified: trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePlanJoins.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePlanJoins.java	2010-07-23 20:47:35 UTC (rev 2370)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePlanJoins.java	2010-07-23 21:44:19 UTC (rev 2371)
@@ -268,7 +268,7 @@
                      * If we failed to find direct criteria, but still have non-pushable or criteria to
                      * other groups we'll use additional checks
                      */
-                    if ((!hasJoinCriteria || (hasJoinCriteria && joinCriteriaNodes.isEmpty())) && !canPushCrossJoin(metadata, context, accessNode1, accessNode2)) {
+                    if ((!hasJoinCriteria || joinCriteriaNodes.isEmpty()) && !canPushCrossJoin(metadata, context, accessNode1, accessNode2)) {
                     	continue;
                     }                    
                     

Modified: trunk/engine/src/main/java/org/teiid/query/processor/CollectionTupleSource.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/processor/CollectionTupleSource.java	2010-07-23 20:47:35 UTC (rev 2370)
+++ trunk/engine/src/main/java/org/teiid/query/processor/CollectionTupleSource.java	2010-07-23 21:44:19 UTC (rev 2371)
@@ -35,7 +35,7 @@
 public class CollectionTupleSource implements TupleSource {
 	
 	private Iterator<? extends List<?>> tuples;
-	private List<SingleElementSymbol> schema;
+	private List<? extends SingleElementSymbol> schema;
 
 	public static CollectionTupleSource createUpdateCountTupleSource(int count) {
 		return new CollectionTupleSource(Arrays.asList(Arrays.asList(count)).iterator(), Command.getUpdateCommandSymbol());
@@ -46,7 +46,7 @@
 	}
 	
 	public CollectionTupleSource(Iterator<? extends List<?>> tuples,
-			List<SingleElementSymbol> schema) {
+			List<? extends SingleElementSymbol> schema) {
 		this.tuples = tuples;
 		this.schema = schema;
 	}
@@ -60,7 +60,7 @@
 	}
 	
 	@Override
-	public List<SingleElementSymbol> getSchema() {
+	public List<? extends SingleElementSymbol> getSchema() {
 		return schema;
 	}
 	

Modified: trunk/engine/src/main/java/org/teiid/query/processor/batch/BatchedUpdatePlan.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/processor/batch/BatchedUpdatePlan.java	2010-07-23 20:47:35 UTC (rev 2370)
+++ trunk/engine/src/main/java/org/teiid/query/processor/batch/BatchedUpdatePlan.java	2010-07-23 21:44:19 UTC (rev 2371)
@@ -145,9 +145,9 @@
             	openPlan();
             }
             // Execute nextBatch() on each plan in sequence
-            List[] currentBatch = updatePlans[planIndex].nextBatch().getAllTuples(); // Can throw BlockedException
-            for (int i = 0; i < currentBatch.length; i++, commandIndex++) {
-                updateCounts[commandIndex] = currentBatch[i];
+            List<List> currentBatch = updatePlans[planIndex].nextBatch().getTuples(); // Can throw BlockedException
+            for (int i = 0; i < currentBatch.size(); i++, commandIndex++) {
+                updateCounts[commandIndex] = currentBatch.get(i);
             }
             
             // since we are done with the plan explicitly close it.

Modified: trunk/engine/src/main/java/org/teiid/query/processor/proc/ProcedurePlan.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/processor/proc/ProcedurePlan.java	2010-07-23 20:47:35 UTC (rev 2370)
+++ trunk/engine/src/main/java/org/teiid/query/processor/proc/ProcedurePlan.java	2010-07-23 21:44:19 UTC (rev 2371)
@@ -65,7 +65,7 @@
 import org.teiid.query.sql.symbol.Reference;
 import org.teiid.query.sql.util.VariableContext;
 import org.teiid.query.tempdata.TempTableStore;
-import org.teiid.query.tempdata.TempTableStoreImpl;
+import org.teiid.query.tempdata.TempTableStore;
 import org.teiid.query.util.CommandContext;
 import org.teiid.query.util.ErrorMessageKeys;
 
@@ -205,7 +205,7 @@
 		            context.setValue(entry.getKey(), value);
 				}
     		}
-    		tempTableStore = new TempTableStoreImpl(bufferMgr, getContext().getConnectionID(), null);
+    		tempTableStore = new TempTableStore(bufferMgr, getContext().getConnectionID(), null);
             this.dataMgr = new TempTableDataManager(dataMgr, tempTableStore);
     	}
     	this.evaluatedParams = true;

Modified: trunk/engine/src/main/java/org/teiid/query/processor/relational/PlanExecutionNode.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/processor/relational/PlanExecutionNode.java	2010-07-23 20:47:35 UTC (rev 2370)
+++ trunk/engine/src/main/java/org/teiid/query/processor/relational/PlanExecutionNode.java	2010-07-23 21:44:19 UTC (rev 2371)
@@ -113,7 +113,7 @@
         
 		TupleBatch batch = plan.nextBatch();
        
-        for (List tuple : batch.getAllTuples()) {
+        for (List tuple : batch.getTuples()) {
             addBatchRow(tuple);
 		}
         

Modified: trunk/engine/src/main/java/org/teiid/query/processor/relational/ProjectIntoNode.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/processor/relational/ProjectIntoNode.java	2010-07-23 20:47:35 UTC (rev 2370)
+++ trunk/engine/src/main/java/org/teiid/query/processor/relational/ProjectIntoNode.java	2010-07-23 21:44:19 UTC (rev 2371)
@@ -116,7 +116,9 @@
                 currentBatch = getChildren()[0].nextBatch(); // can throw BlockedException
                 this.batchRow = currentBatch.getBeginRow();
                 
-                if(currentBatch.getRowCount() == 0 && !this.intoGroup.isImplicitTempGroupSymbol()) {
+                //normally we would want to skip a 0 sized batch, but it typically represents the terminal batch
+                //and for implicit temp tables we need to issue an empty insert
+                if(currentBatch.getRowCount() == 0 && (!this.intoGroup.isImplicitTempGroupSymbol() || !currentBatch.getTerminationFlag())) {
                     continue;
                 }
             } else if (currentBatch.getTerminationFlag() && this.batchRow > currentBatch.getEndRow()) {
@@ -131,10 +133,10 @@
                 List<Constant> parameters = new ArrayList<Constant>(intoElements.size());
                 for (int i = 0; i < intoElements.size(); i++) {
 					Constant value = new Constant(null, ((ElementSymbol)intoElements.get(i)).getType());
-					value.setMultiValued(new ArrayList<Object>(currentBatch.getAllTuples().length));
+					value.setMultiValued(new ArrayList<Object>(currentBatch.getTuples().size()));
                 	parameters.add(value);
 				}
-                for (List row : currentBatch.getAllTuples()) {
+                for (List row : currentBatch.getTuples()) {
                 	for (int i = 0; i < row.size(); i++) {
                 		((List<Object>)parameters.get(i).getValue()).add(row.get(i));
                 	}

Modified: trunk/engine/src/main/java/org/teiid/query/processor/relational/UnionAllNode.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/processor/relational/UnionAllNode.java	2010-07-23 20:47:35 UTC (rev 2370)
+++ trunk/engine/src/main/java/org/teiid/query/processor/relational/UnionAllNode.java	2010-07-23 21:44:19 UTC (rev 2371)
@@ -117,7 +117,7 @@
         TupleBatch outputBatch = null;
         if(batch != null) {
             // Rebuild the batch to reset the output row
-            outputBatch = new TupleBatch(outputRow, batch.getAllTuples());
+            outputBatch = new TupleBatch(outputRow, batch.getTuples());
                         
             // This is the last unioned batch if:
             // 1) This batch is a termination batch from the child

Modified: trunk/engine/src/main/java/org/teiid/query/processor/xml/XMLPlan.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/processor/xml/XMLPlan.java	2010-07-23 20:47:35 UTC (rev 2370)
+++ trunk/engine/src/main/java/org/teiid/query/processor/xml/XMLPlan.java	2010-07-23 21:44:19 UTC (rev 2371)
@@ -61,7 +61,7 @@
 import org.teiid.query.sql.symbol.ElementSymbol;
 import org.teiid.query.sql.symbol.GroupSymbol;
 import org.teiid.query.tempdata.TempTableStore;
-import org.teiid.query.tempdata.TempTableStoreImpl;
+import org.teiid.query.tempdata.TempTableStore;
 import org.teiid.query.util.CommandContext;
 import org.teiid.query.util.ErrorMessageKeys;
 import org.xml.sax.Attributes;
@@ -108,7 +108,7 @@
      */
     public void initialize(CommandContext context, ProcessorDataManager dataMgr, BufferManager bufferMgr) {
         setContext(context);
-        TempTableStore tempTableStore = new TempTableStoreImpl(bufferMgr, context.getConnectionID(), (TempTableStore)context.getTempTableStore());
+        TempTableStore tempTableStore = new TempTableStore(bufferMgr, context.getConnectionID(), (TempTableStore)context.getTempTableStore());
         //this.dataMgr = new StagingTableDataManager(new TempTableDataManager(dataMgr, tempTableStore), env);
         this.dataMgr = new TempTableDataManager(dataMgr, tempTableStore);
         this.bufferMgr = bufferMgr;

Modified: trunk/engine/src/main/java/org/teiid/query/resolver/command/TempTableResolver.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/resolver/command/TempTableResolver.java	2010-07-23 20:47:35 UTC (rev 2370)
+++ trunk/engine/src/main/java/org/teiid/query/resolver/command/TempTableResolver.java	2010-07-23 21:44:19 UTC (rev 2371)
@@ -80,7 +80,7 @@
             ResolverUtil.addTempTable(metadata, group, create.getColumns());
             
             ResolverUtil.resolveGroup(((Create)command).getTable(), metadata);
-            Set groups = new HashSet();
+            Set<GroupSymbol> groups = new HashSet<GroupSymbol>();
             groups.add(((Create)command).getTable());
             ResolverVisitor.resolveLanguageObject(command, groups, metadata);
         } else if(command.getType() == Command.TYPE_DROP) {

Modified: trunk/engine/src/main/java/org/teiid/query/resolver/util/ResolverVisitor.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/resolver/util/ResolverVisitor.java	2010-07-23 20:47:35 UTC (rev 2370)
+++ trunk/engine/src/main/java/org/teiid/query/resolver/util/ResolverVisitor.java	2010-07-23 21:44:19 UTC (rev 2371)
@@ -299,10 +299,14 @@
         try {
             resolveFunction(obj, this.metadata.getFunctionLibrary());
         } catch(QueryResolverException e) {
-        	if (unresolvedFunctions == null) {
-        		unresolvedFunctions = new LinkedHashMap<Function, QueryResolverException>();
+        	if (ErrorMessageKeys.RESOLVER_0036.equals(e.getCode()) || ErrorMessageKeys.RESOLVER_0035.equals(e.getCode())) {
+	        	if (unresolvedFunctions == null) {
+	        		unresolvedFunctions = new LinkedHashMap<Function, QueryResolverException>();
+	        	}
+	        	unresolvedFunctions.put(obj, e);
+        	} else {
+        		handleException(e);
         	}
-        	unresolvedFunctions.put(obj, e);
         } catch(TeiidComponentException e) {
             handleException(e);
         }

Modified: trunk/engine/src/main/java/org/teiid/query/sql/lang/Create.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/lang/Create.java	2010-07-23 20:47:35 UTC (rev 2370)
+++ trunk/engine/src/main/java/org/teiid/query/sql/lang/Create.java	2010-07-23 21:44:19 UTC (rev 2371)
@@ -27,6 +27,7 @@
 
 import org.teiid.core.util.EquivalenceUtil;
 import org.teiid.core.util.HashCodeUtil;
+import org.teiid.query.sql.LanguageObject;
 import org.teiid.query.sql.LanguageVisitor;
 import org.teiid.query.sql.symbol.ElementSymbol;
 import org.teiid.query.sql.symbol.GroupSymbol;
@@ -42,6 +43,8 @@
     
     private List<ElementSymbol> columns = new ArrayList<ElementSymbol>();
     
+    private List<ElementSymbol> primaryKey = new ArrayList<ElementSymbol>();
+    
     public GroupSymbol getTable() {
         return table;
     }
@@ -54,6 +57,10 @@
         return columns;
     }
     
+    public List<ElementSymbol> getPrimaryKey() {
+		return primaryKey;
+	}
+    
     /** 
      * @see org.teiid.query.sql.lang.Command#getType()
      * @since 5.5
@@ -70,7 +77,8 @@
         Create copy = new Create();      
         GroupSymbol copyTable = (GroupSymbol) table.clone();    
         copy.setTable(copyTable);
-        copy.setColumns(columns);
+        copy.setColumns(LanguageObject.Util.deepClone(columns, ElementSymbol.class));
+        copy.primaryKey = LanguageObject.Util.deepClone(primaryKey, ElementSymbol.class);
         copyMetadataState(copy);
         return copy;
     }
@@ -128,6 +136,7 @@
         Create other = (Create) obj;
         
         return EquivalenceUtil.areEqual(getTable(), other.getTable()) &&
-               EquivalenceUtil.areEqual(getColumns(), other.getColumns());
+               EquivalenceUtil.areEqual(getColumns(), other.getColumns()) &&
+               EquivalenceUtil.areEqual(getPrimaryKey(), other.getPrimaryKey());
     }
 }

Modified: trunk/engine/src/main/java/org/teiid/query/sql/navigator/PreOrPostOrderNavigator.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/navigator/PreOrPostOrderNavigator.java	2010-07-23 20:47:35 UTC (rev 2370)
+++ trunk/engine/src/main/java/org/teiid/query/sql/navigator/PreOrPostOrderNavigator.java	2010-07-23 21:44:19 UTC (rev 2371)
@@ -306,6 +306,7 @@
         preVisitVisitor(obj);
         visitNode(obj.getTable());
         visitNodes(obj.getColumns());
+        visitNodes(obj.getPrimaryKey());
         postVisitVisitor(obj);
     }
     public void visit(Drop obj) {

Modified: trunk/engine/src/main/java/org/teiid/query/sql/visitor/SQLStringVisitor.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/visitor/SQLStringVisitor.java	2010-07-23 20:47:35 UTC (rev 2370)
+++ trunk/engine/src/main/java/org/teiid/query/sql/visitor/SQLStringVisitor.java	2010-07-23 21:44:19 UTC (rev 2371)
@@ -442,14 +442,28 @@
         Iterator<ElementSymbol> iter = columns.iterator();
         while(iter.hasNext()) {
             ElementSymbol element = iter.next();
-            element.setDisplayMode(ElementSymbol.DisplayMode.SHORT_OUTPUT_NAME);
-            parts.add(registerNode(element));
+            outputShortName(element);
             parts.add(SPACE);
             parts.add(DataTypeManager.getDataTypeName(element.getType()));
             if(iter.hasNext()) {
                 parts.add(", "); //$NON-NLS-1$
             }
         }
+        if (!obj.getPrimaryKey().isEmpty()) {
+        	parts.add(", "); //$NON-NLS-1$
+        	parts.add(PRIMARY);
+        	parts.add(" "); //$NON-NLS-1$
+        	parts.add(NonReserved.KEY);
+        	parts.add(Tokens.LPAREN);
+        	iter = obj.getPrimaryKey().iterator();
+            while(iter.hasNext()) {
+            	outputShortName(iter.next());
+            	if (iter.hasNext()) {
+            		parts.add(", "); //$NON-NLS-1$
+            	}
+            }
+        	parts.add(Tokens.RPAREN);
+        }
         parts.add(")"); //$NON-NLS-1$
     }
     
@@ -746,8 +760,7 @@
             parts.add(SPACE);
             for (int i = 0; i < obj.getAsColumns().size(); i++) {
                 ElementSymbol symbol = (ElementSymbol)obj.getAsColumns().get(i);
-                symbol.setDisplayMode(ElementSymbol.DisplayMode.SHORT_OUTPUT_NAME);
-                parts.add(registerNode(symbol));
+                outputShortName(symbol);
                 parts.add(SPACE);
                 parts.add(DataTypeManager.getDataTypeName(symbol.getType()));
                 if (i < obj.getAsColumns().size() - 1) {
@@ -794,8 +807,7 @@
     
     public void visit(SetClause obj) {
         ElementSymbol symbol = obj.getSymbol();
-        symbol.setDisplayMode(ElementSymbol.DisplayMode.SHORT_OUTPUT_NAME);
-        parts.add(registerNode(symbol));
+        outputShortName(symbol);
         parts.add(" = "); //$NON-NLS-1$
         parts.add(registerNode(obj.getValue()));
     }
@@ -1187,19 +1199,20 @@
     }
 
     public void visit(ElementSymbol obj) {
+        if (obj.getDisplayMode().equals(ElementSymbol.DisplayMode.SHORT_OUTPUT_NAME)) {
+            outputShortName(obj);
+            return;
+        }
         String name = obj.getOutputName();
         if (obj.getDisplayMode().equals(ElementSymbol.DisplayMode.FULLY_QUALIFIED)) {
             name = obj.getName();
-        } else if (obj.getDisplayMode().equals(ElementSymbol.DisplayMode.SHORT_OUTPUT_NAME)) {
-            String shortName = SingleElementSymbol.getShortName(name);
-            //TODO: this is a hack - since we default to not supporting double quoted identifiers, we need to fully qualify reserved
-            if (!isReservedWord(shortName)) {
-                name = shortName;
-            }
         }
-        
         outputDisplayName(name);
     }
+    
+    private void outputShortName(ElementSymbol obj) {
+    	outputDisplayName(SingleElementSymbol.getShortName(obj.getOutputName()));
+    }
 
     private void outputDisplayName(String name) {
         String[] pathParts = name.split("\\."); //$NON-NLS-1$

Added: trunk/engine/src/main/java/org/teiid/query/tempdata/TempTable.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/tempdata/TempTable.java	                        (rev 0)
+++ trunk/engine/src/main/java/org/teiid/query/tempdata/TempTable.java	2010-07-23 21:44:19 UTC (rev 2371)
@@ -0,0 +1,349 @@
+/*
+ * 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.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.teiid.api.exception.query.ExpressionEvaluationException;
+import org.teiid.common.buffer.BlockedException;
+import org.teiid.common.buffer.BufferManager;
+import org.teiid.common.buffer.STree;
+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.processor.CollectionTupleSource;
+import org.teiid.query.processor.relational.RelationalNode;
+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.SetClauseList;
+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: non-pk updates/deletes through the browser 
+ */
+class TempTable {
+	
+	private abstract class UpdateTupleSource implements TupleSource {
+		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 {
+			this.ts = ts;
+			this.lookup = RelationalNode.createLookupMap(columns);
+			this.eval = new Evaluator(lookup, null, null);
+			this.crit = crit;
+			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);
+				}
+				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; 
+			} finally {
+				if (!done) {
+					TupleSource undoTs = undoLog.createIndexedTupleSource();
+					List<?> tuple = null;
+					try {
+						while ((tuple = undoTs.nextTuple()) != null) {
+							undo(tuple);
+						}
+					} catch (TeiidException e) {
+						
+					}
+				}
+			}
+			return Arrays.asList(updateCount);
+		}
+
+		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() {
+			ts.closeSource();
+			undoLog.remove();
+		}
+		
+	}
+	
+	private STree tree;
+	private AtomicInteger rowId;
+	private List<ElementSymbol> columns;
+	private BufferManager bm;
+	private String sessionID;
+
+	TempTable(BufferManager bm, List<ElementSymbol> columns, int primaryKeyLength, String sessionID) {
+		this.bm = bm;
+		if (primaryKeyLength == 0) {
+            ElementSymbol id = new ElementSymbol("rowId"); //$NON-NLS-1$
+    		id.setType(DataTypeManager.DefaultDataClasses.INTEGER);
+    		columns.add(0, id);
+    		//we start at max, since the default sort order is ascending
+    		rowId = new AtomicInteger(Integer.MAX_VALUE);
+        	tree = bm.createSTree(columns, sessionID, TupleSourceType.PROCESSOR, 1);
+        } else {
+        	tree = bm.createSTree(columns, sessionID, TupleSourceType.PROCESSOR, primaryKeyLength);
+        }
+		this.columns = columns;
+		this.sessionID = sessionID;
+	}
+
+	public TupleSource createTupleSource(List<Criteria> conditions, OrderBy orderBy) throws TeiidComponentException {
+		return createTupleSource(conditions, orderBy, true);
+	}
+	
+	private TupleSource createTupleSource(List<Criteria> conditions, OrderBy orderBy, boolean filterRowId) throws TeiidComponentException {
+		TupleBuffer tb = bm.createTupleBuffer(columns, sessionID, TupleSourceType.PROCESSOR);
+		TupleBrowser browser = tree.browse(null, null, OrderBy.ASC);
+		List next = null;
+		while ((next = browser.next()) != null) {
+			if (rowId != null && filterRowId) {
+				next = next.subList(1, next.size());
+			}
+			tb.addTuple(next);
+		}
+		tb.close();
+		return tb.createIndexedTupleSource(true);
+	}
+	
+	public int getRowCount() {
+		return tree.getRowCount();
+	}
+	
+	public int truncate() {
+		return tree.truncate();
+	}
+	
+	public void remove() {
+		tree.remove();
+	}
+	
+	public List<ElementSymbol> getColumns() {
+		if (rowId != null) {
+			return columns.subList(1, columns.size());
+		}
+		return columns;
+	}
+	
+	public TupleSource insert(List<List<Object>> tuples) throws TeiidComponentException {
+        UpdateTupleSource uts = new UpdateTupleSource(null, new CollectionTupleSource(tuples.iterator(), getColumns())) {
+        	
+        	protected void tuplePassed(List tuple) 
+        	throws BlockedException, TeiidComponentException, TeiidProcessingException {
+        		if (rowId != null) {
+        			tuple.add(0, rowId.getAndAdd(-1));
+        		}
+        		insertTuple(tuple);
+        	}
+        	
+        	@Override
+        	protected void undo(List tuple) throws TeiidComponentException {
+        		deleteTuple(tuple);
+        	}
+        	
+        };
+        return uts;
+    }
+		
+	public TupleSource update(Criteria crit, final SetClauseList update) throws TeiidComponentException {
+		final boolean primaryKeyChangePossible = canChangePrimaryKey(update);
+		
+		UpdateTupleSource uts = new UpdateTupleSource(crit, createTupleSource(null, null, false)) {
+			
+			protected TupleBuffer changeSet;
+			protected TupleSource changeSetProcessor;
+			
+			@Override
+			protected void tuplePassed(List tuple)
+					throws ExpressionEvaluationException,
+					BlockedException, TeiidComponentException {
+				List<Object> newTuple = new ArrayList<Object>(tuple);
+    			for (Map.Entry<ElementSymbol, Expression> entry : update.getClauseMap().entrySet()) {
+    				newTuple.set((Integer)lookup.get(entry.getKey()), eval.evaluate(entry.getValue(), tuple));
+    			}
+    			if (primaryKeyChangePossible) {
+    				deleteTuple(tuple);
+    				if (changeSet == null) {
+    					changeSet = bm.createTupleBuffer(columns, sessionID, TupleSourceType.PROCESSOR);
+    				}
+    				changeSet.addTuple(newTuple);
+    			} else {
+    				updateTuple(newTuple);
+    			}
+			}
+			
+			@Override
+			void process() throws TeiidComponentException,
+					TeiidProcessingException {
+				super.process();
+				//existing tuples have been removed
+				//changeSet contains possible updates
+				if (primaryKeyChangePossible) {
+					if (changeSetProcessor == null) {
+						changeSetProcessor = new UpdateTupleSource(null, changeSet.createIndexedTupleSource(true)) {
+							@Override
+							protected void tuplePassed(List tuple) throws BlockedException,
+									TeiidComponentException, TeiidProcessingException {
+								insertTuple(tuple);
+							}
+							
+							@Override
+							protected void undo(List tuple) throws TeiidComponentException,
+									TeiidProcessingException {
+								deleteTuple(tuple);
+							}
+							
+						};
+					}
+					changeSetProcessor.nextTuple(); //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();
+				if (changeSetProcessor != null) {
+					changeSetProcessor.closeSource(); // causes a revert of the change set
+				}
+				if (changeSet != null) {
+					changeSet.remove();
+				}
+			}
+			
+		};
+		return uts;
+	}
+
+	private boolean canChangePrimaryKey(final SetClauseList update) {
+		if (rowId == null) {
+			Set<ElementSymbol> affectedColumns = new HashSet<ElementSymbol>(update.getClauseMap().keySet());
+			affectedColumns.retainAll(columns.subList(0, tree.getKeyLength()));
+			if (!affectedColumns.isEmpty()) {
+				return true;
+			}
+		}
+		return false;
+	}
+	
+	public TupleSource delete(Criteria crit) throws TeiidComponentException {
+		UpdateTupleSource uts = new UpdateTupleSource(crit, createTupleSource(null, null, false)) {
+			@Override
+			protected void tuplePassed(List tuple)
+					throws ExpressionEvaluationException,
+					BlockedException, TeiidComponentException {
+				deleteTuple(tuple);
+			}
+			
+			@Override
+			protected void undo(List tuple) throws TeiidComponentException, TeiidProcessingException {
+				insertTuple(tuple);
+			}
+		};
+		return uts;
+	}
+	
+	private void insertTuple(List<Object> list) throws TeiidComponentException, TeiidProcessingException {
+		if (tree.insert(list, false) != null) {
+			throw new TeiidProcessingException(QueryPlugin.Util.getString("TempTable.duplicate_key")); //$NON-NLS-1$
+		}
+	}
+	
+	private void deleteTuple(List<?> tuple) throws TeiidComponentException {
+		if (tree.remove(tuple) == null) {
+			throw new AssertionError("Delete failed"); //$NON-NLS-1$
+		}
+	}
+	
+	private void updateTuple(List<?> tuple) throws TeiidComponentException {
+		if (tree.insert(tuple, true) == null) {
+			throw new AssertionError("Update failed"); //$NON-NLS-1$
+		}
+	}
+		
+}
\ No newline at end of file


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

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-23 20:47:35 UTC (rev 2370)
+++ trunk/engine/src/main/java/org/teiid/query/tempdata/TempTableStore.java	2010-07-23 21:44:19 UTC (rev 2371)
@@ -22,32 +22,238 @@
 
 package org.teiid.query.tempdata;
 
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
-import org.teiid.common.buffer.TupleBuffer;
+import org.teiid.api.exception.query.ExpressionEvaluationException;
+import org.teiid.api.exception.query.QueryProcessingException;
+import org.teiid.common.buffer.BlockedException;
+import org.teiid.common.buffer.BufferManager;
 import org.teiid.common.buffer.TupleSource;
 import org.teiid.core.TeiidComponentException;
 import org.teiid.core.TeiidProcessingException;
+import org.teiid.query.eval.Evaluator;
+import org.teiid.query.execution.QueryExecPlugin;
 import org.teiid.query.metadata.TempMetadataStore;
+import org.teiid.query.processor.CollectionTupleSource;
 import org.teiid.query.sql.lang.Command;
+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.Drop;
+import org.teiid.query.sql.lang.Insert;
+import org.teiid.query.sql.lang.ProcedureContainer;
+import org.teiid.query.sql.lang.Query;
+import org.teiid.query.sql.lang.Update;
+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.GroupSymbol;
 
-
 /** 
  * @since 5.5
  */
-public interface TempTableStore {
+public class TempTableStore {
+
+	private BufferManager buffer;
+    private TempMetadataStore tempMetadataStore = new TempMetadataStore();
+    private Map<String, TempTable> groupToTupleSourceID = new HashMap<String, TempTable>();
+    private String sessionID;
+    private TempTableStore parentTempTableStore;
     
-    void removeTempTables() throws TeiidComponentException;
-  
-    TempMetadataStore getMetadataStore();
+    public TempTableStore(BufferManager buffer, String sessionID, TempTableStore parentTempTableStore) {
+        this.buffer = buffer;
+        this.sessionID = sessionID;
+        this.parentTempTableStore = parentTempTableStore;
+    }
 
-    public TupleSource registerRequest(Command command)  throws TeiidComponentException, TeiidProcessingException;
+    void addTempTable(Create create, boolean removeExistingTable) throws QueryProcessingException{
+    	String tempTableName = create.getTable().getName().toUpperCase();
+        if(tempMetadataStore.getTempGroupID(tempTableName) != null) {
+            if(!removeExistingTable) {
+                throw new QueryProcessingException(QueryExecPlugin.Util.getString("TempTableStore.table_exist_error", tempTableName));//$NON-NLS-1$
+            }
+            removeTempTableByName(tempTableName);
+        }
+    	List<ElementSymbol> columns = create.getColumns();
+    	
+    	boolean hasKey = !create.getPrimaryKey().isEmpty();
+    	columns = new ArrayList<ElementSymbol>(create.getColumns());
+    	
+    	if (hasKey) {
+    		//reorder the columns to put the key in front
+    		List<ElementSymbol> primaryKey = create.getPrimaryKey();
+    		columns.removeAll(primaryKey);
+    		columns.addAll(0, primaryKey);
+    	} 
+        //add metadata
+        tempMetadataStore.addTempGroup(tempTableName, columns, false, true);
+        TempTable tempTable = new TempTable(buffer, columns, create.getPrimaryKey().size(), sessionID);
+        groupToTupleSourceID.put(tempTableName, tempTable);
+    }
+
+    public void removeTempTableByName(String tempTableName) {
+        tempMetadataStore.removeTempGroup(tempTableName);
+        TempTable table = this.groupToTupleSourceID.remove(tempTableName);
+        if(table != null) {
+            table.remove();
+        }      
+    }
     
-    public boolean hasTempTable(Command command);
+    public TempMetadataStore getMetadataStore() {
+        return tempMetadataStore;
+    }
+        
+    public TupleSource registerRequest(Command command) throws TeiidComponentException, TeiidProcessingException{
+        if (command instanceof Query) {
+            Query query = (Query)command;
+            GroupSymbol group = (GroupSymbol)query.getFrom().getGroups().get(0);
+            if (!group.isTempGroupSymbol()) {
+            	return null;
+            }
+            TempTable table = getTempTable(group.getNonCorrelationName().toUpperCase(), command);
+            return table.createTupleSource(Criteria.separateCriteriaByAnd(query.getCriteria()), query.getOrderBy());
+        }
+        if (command instanceof ProcedureContainer) {
+        	GroupSymbol group = ((ProcedureContainer)command).getGroup();
+        	if (!group.isTempGroupSymbol()) {
+        		return null;
+        	}
+        	final String groupKey = group.getNonCorrelationName().toUpperCase();
+            final TempTable table = getTempTable(groupKey, command);
+        	if (command instanceof Insert) {
+        		List<List<Object>> tuples = getBulkRows((Insert)command, table.getColumns());
+        		if (tuples.isEmpty()) {
+        			return CollectionTupleSource.createUpdateCountTupleSource(0);
+        		}
+        		return table.insert(tuples);
+        	}
+        	if (command instanceof Update) {
+        		final Update update = (Update)command;
+        		final Criteria crit = update.getCriteria();
+        		return table.update(crit, update.getChangeList());
+        	}
+        	if (command instanceof Delete) {
+        		final Delete delete = (Delete)command;
+        		final Criteria crit = delete.getCriteria();
+        		if (crit == null) {
+        			//because we are non-transactional, just use a truncate
+        			int rows = table.truncate();
+                    return CollectionTupleSource.createUpdateCountTupleSource(rows);
+        		}
+        		return table.delete(crit);
+        	}
+        }
+    	if (command instanceof Create) {
+    		Create create = (Create)command;
+    		addTempTable(create, false);
+            return CollectionTupleSource.createUpdateCountTupleSource(0);	
+    	}
+    	if (command instanceof Drop) {
+    		String tempTableName = ((Drop)command).getTable().getName().toUpperCase();
+            removeTempTableByName(tempTableName);
+            return CollectionTupleSource.createUpdateCountTupleSource(0);
+    	}
+        return null;
+    }
     
-    public Set getAllTempTables();
+    public void removeTempTables() {
+        for (String name : new ArrayList<String>( groupToTupleSourceID.keySet() )) {
+            removeTempTableByName(name);
+        }
+    }
     
-    public void removeTempTableByName(String tempTableName) throws TeiidComponentException;
+    private TempTable getTempTable(String tempTableID, Command command) throws QueryProcessingException{
+    	TempTable tsID = groupToTupleSourceID.get(tempTableID);
+        if(tsID != null) {
+            return tsID;
+        }
+        if(this.parentTempTableStore != null){
+    		tsID = this.parentTempTableStore.groupToTupleSourceID.get(tempTableID);
+    	    if(tsID != null) {
+    	        return tsID;
+    	    }
+        }
+        //allow implicit temp group definition
+        List<ElementSymbol> columns = null;
+        if (command instanceof Insert) {
+            Insert insert = (Insert)command;
+            GroupSymbol group = insert.getGroup();
+            if(group.isImplicitTempGroupSymbol()) {
+                columns = insert.getVariables();
+            }
+        }
+        if (columns == null) {
+        	throw new QueryProcessingException(QueryExecPlugin.Util.getString("TempTableStore.table_doesnt_exist_error", tempTableID)); //$NON-NLS-1$
+        }
+        Create create = new Create();
+        create.setTable(new GroupSymbol(tempTableID));
+        create.setColumns(columns);
+        addTempTable(create, true);       
+        return groupToTupleSourceID.get(tempTableID);
+    }
+
+	public static List<List<Object>> getBulkRows(Insert insert, List<ElementSymbol> elements) throws ExpressionEvaluationException, BlockedException, TeiidComponentException {
+		int bulkRowCount = 1;
+		if (insert.isBulk()) {
+			Constant c = (Constant)insert.getValues().get(0);
+			bulkRowCount = ((List<?>)c.getValue()).size();
+		}
+		
+		List<List<Object>> tuples = new ArrayList<List<Object>>(bulkRowCount);
+		
+		for (int row = 0; row < bulkRowCount; row++) {
+			List<Object> currentRow = new ArrayList<Object>(insert.getValues().size());
+			for (ElementSymbol symbol : elements) {
+                int index = insert.getVariables().indexOf(symbol);
+                Object value = null;
+                if (index != -1) {
+                	if (insert.isBulk()) {
+	                	Constant multiValue = (Constant)insert.getValues().get(index);
+	    		    	value = ((List<?>)multiValue.getValue()).get(row);
+                	} else {
+                		Expression expr = (Expression)insert.getValues().get(index);
+                        value = Evaluator.evaluate(expr);
+                	}
+                }
+                currentRow.add(value);
+            }
+		    tuples.add(currentRow);
+		}
+		return tuples;
+	}
     
-    public TupleBuffer getTupleSourceID(String tempTableName);
+    public boolean hasTempTable(Command command){
+        switch (command.getType()) {
+            case Command.TYPE_INSERT:
+            {
+                Insert insert = (Insert)command;
+                GroupSymbol group = insert.getGroup();
+                return group.isTempGroupSymbol();
+            }
+            case Command.TYPE_QUERY:
+            {
+                if(command instanceof Query) {
+                    Query query = (Query)command;
+                    GroupSymbol group = (GroupSymbol)query.getFrom().getGroups().get(0);
+                    return group.isTempGroupSymbol(); 
+                }
+                break;
+            }
+            case Command.TYPE_CREATE:
+                return true;
+            case Command.TYPE_DROP:
+                return true;
+        }
+        return false;
+    }
+    
+    public Set<String> getAllTempTables() {
+        return new HashSet<String>(this.groupToTupleSourceID.keySet());
+    }
+    
 }

Deleted: trunk/engine/src/main/java/org/teiid/query/tempdata/TempTableStoreImpl.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/tempdata/TempTableStoreImpl.java	2010-07-23 20:47:35 UTC (rev 2370)
+++ trunk/engine/src/main/java/org/teiid/query/tempdata/TempTableStoreImpl.java	2010-07-23 21:44:19 UTC (rev 2371)
@@ -1,373 +0,0 @@
-/*
- * 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.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import org.teiid.api.exception.query.ExpressionEvaluationException;
-import org.teiid.api.exception.query.QueryMetadataException;
-import org.teiid.api.exception.query.QueryProcessingException;
-import org.teiid.common.buffer.BlockedException;
-import org.teiid.common.buffer.BufferManager;
-import org.teiid.common.buffer.TupleBuffer;
-import org.teiid.common.buffer.TupleSource;
-import org.teiid.common.buffer.BufferManager.TupleSourceType;
-import org.teiid.core.TeiidComponentException;
-import org.teiid.core.TeiidProcessingException;
-import org.teiid.query.eval.Evaluator;
-import org.teiid.query.execution.QueryExecPlugin;
-import org.teiid.query.metadata.TempMetadataAdapter;
-import org.teiid.query.metadata.TempMetadataStore;
-import org.teiid.query.processor.CollectionTupleSource;
-import org.teiid.query.processor.relational.RelationalNode;
-import org.teiid.query.resolver.util.ResolverUtil;
-import org.teiid.query.sql.lang.Command;
-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.Drop;
-import org.teiid.query.sql.lang.Insert;
-import org.teiid.query.sql.lang.ProcedureContainer;
-import org.teiid.query.sql.lang.Query;
-import org.teiid.query.sql.lang.Update;
-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.GroupSymbol;
-import org.teiid.query.sql.symbol.SingleElementSymbol;
-
-
-/** 
- * @since 5.5
- */
-public class TempTableStoreImpl implements TempTableStore {
-	
-    private abstract class UpdateTupleSource implements TupleSource {
-		private final String groupKey;
-		private final TupleBuffer oldBuffer;
-		private final TupleSource ts;
-		protected final Map lookup;
-		private final TupleBuffer newBuffer;
-		protected final Evaluator eval;
-		private final Criteria crit;
-		protected int updateCount = 0;
-		private boolean done;
-		private List<?> currentTuple;
-
-		private UpdateTupleSource(String groupKey, TupleBuffer tsId, Criteria crit) throws TeiidComponentException {
-			this.groupKey = groupKey;
-			this.oldBuffer = tsId;
-			this.ts = tsId.createIndexedTupleSource();
-    		List columns = tsId.getSchema();
-			this.lookup = RelationalNode.createLookupMap(columns);
-			this.newBuffer = buffer.createTupleBuffer(columns, sessionID, TupleSourceType.PROCESSOR);
-			this.eval = new Evaluator(lookup, null, null);
-			this.crit = crit;
-		}
-
-		@Override
-		public List<?> nextTuple() throws TeiidComponentException,
-				TeiidProcessingException {
-			if (done) {
-				return null;
-			}
-			
-			//still have to worry about blocked exceptions...
-			while (currentTuple != null || (currentTuple = ts.nextTuple()) != null) {
-				if (eval.evaluate(crit, currentTuple)) {
-					tuplePassed(currentTuple);
-				} else {
-					tupleFailed(currentTuple);
-				}
-				currentTuple = null;
-			}
-			newBuffer.close();
-			groupToTupleSourceID.put(groupKey, newBuffer);
-	        oldBuffer.remove();
-		    done = true;
-			return Arrays.asList(updateCount);
-		}
-		
-		protected void addTuple(List<?> tuple) throws TeiidComponentException {
-			newBuffer.addTuple(tuple);
-		}
-
-		protected abstract void tuplePassed(List<?> tuple) throws ExpressionEvaluationException, BlockedException, TeiidComponentException;
-		
-		protected abstract void tupleFailed(List<?> tuple) throws TeiidComponentException;
-
-		@Override
-		public List<SingleElementSymbol> getSchema() {
-			return Command.getUpdateCommandSymbol();
-		}
-
-		@Override
-		public void closeSource() {
-			
-		}
-		
-		@Override
-		public int available() {
-			return 0;
-		}
-	}
-
-	private BufferManager buffer;
-    private TempMetadataStore tempMetadataStore = new TempMetadataStore();
-    private Map<String, TupleBuffer> groupToTupleSourceID = new HashMap<String, TupleBuffer>();
-    private String sessionID;
-    private TempTableStore parentTempTableStore;
-    
-    public TempTableStoreImpl(BufferManager buffer, String sessionID, TempTableStore parentTempTableStore) {
-        this.buffer = buffer;
-        this.sessionID = sessionID;
-        this.parentTempTableStore = parentTempTableStore;
-    }
-
-    public void addTempTable(String tempTableName, List columns, boolean removeExistingTable) throws TeiidComponentException, QueryProcessingException{        
-        if(tempMetadataStore.getTempGroupID(tempTableName) != null) {
-            if(!removeExistingTable) {
-                throw new QueryProcessingException(QueryExecPlugin.Util.getString("TempTableStore.table_exist_error", tempTableName));//$NON-NLS-1$
-            }
-            removeTempTableByName(tempTableName);
-        }
-        
-        //add metadata
-        tempMetadataStore.addTempGroup(tempTableName, columns, false, true);
-        //create tuple source
-        TupleBuffer tupleBuffer = buffer.createTupleBuffer(columns, sessionID, TupleSourceType.PROCESSOR);
-        tupleBuffer.setFinal(true); //final, but not closed so that we can append on insert
-        groupToTupleSourceID.put(tempTableName, tupleBuffer);
-    }
-
-    public void removeTempTableByName(String tempTableName) throws TeiidComponentException {
-        tempMetadataStore.removeTempGroup(tempTableName);
-        TupleBuffer tsId = this.groupToTupleSourceID.remove(tempTableName);
-        if(tsId != null) {
-            tsId.remove();
-        }      
-    }
-    
-    public TempMetadataStore getMetadataStore() {
-        return tempMetadataStore;
-    }
-        
-    public TupleSource registerRequest(Command command) throws TeiidComponentException, ExpressionEvaluationException, QueryProcessingException{
-        if (command instanceof Query) {
-            Query query = (Query)command;
-            GroupSymbol group = (GroupSymbol)query.getFrom().getGroups().get(0);
-            if (!group.isTempGroupSymbol()) {
-            	return null;
-            }
-            TupleBuffer tsId = getTupleSourceID(group.getNonCorrelationName().toUpperCase(), command);
-            return tsId.createIndexedTupleSource();
-        }
-        if (command instanceof ProcedureContainer) {
-        	GroupSymbol group = ((ProcedureContainer)command).getGroup();
-        	if (!group.isTempGroupSymbol()) {
-        		return null;
-        	}
-        	final String groupKey = group.getNonCorrelationName().toUpperCase();
-            final TupleBuffer tsId = getTupleSourceID(groupKey, command);
-        	if (command instanceof Insert) {
-        		return addTuple((Insert)command, tsId);
-        	}
-        	if (command instanceof Update) {
-        		final Update update = (Update)command;
-        		final Criteria crit = update.getCriteria();
-        		return new UpdateTupleSource(groupKey, tsId, crit) {
-        			@Override
-        			protected void tuplePassed(List<?> tuple)
-        					throws ExpressionEvaluationException,
-        					BlockedException, TeiidComponentException {
-        				List<Object> newTuple = new ArrayList<Object>(tuple);
-	        			for (Map.Entry<ElementSymbol, Expression> entry : update.getChangeList().getClauseMap().entrySet()) {
-	        				newTuple.set((Integer)lookup.get(entry.getKey()), eval.evaluate(entry.getValue(), tuple));
-	        			}
-	        			updateCount++;
-	        			addTuple(newTuple);
-        			}
-        			
-        			protected void tupleFailed(java.util.List<?> tuple) throws TeiidComponentException {
-        				addTuple(tuple);
-        			}
-        		};
-        	}
-        	if (command instanceof Delete) {
-        		final Delete delete = (Delete)command;
-        		final Criteria crit = delete.getCriteria();
-        		if (crit == null) {
-        			int rows = tsId.getRowCount();
-                    addTempTable(groupKey, tsId.getSchema(), true);
-                    return CollectionTupleSource.createUpdateCountTupleSource(rows);
-        		}
-        		return new UpdateTupleSource(groupKey, tsId, crit) {
-        			@Override
-        			protected void tuplePassed(List<?> tuple)
-        					throws ExpressionEvaluationException,
-        					BlockedException, TeiidComponentException {
-        				updateCount++;
-        			}
-        			
-        			protected void tupleFailed(java.util.List<?> tuple) throws TeiidComponentException {
-        				addTuple(tuple);
-        			}
-        		};
-        	}
-        }
-    	if (command instanceof Create) {
-    		addTempTable(((Create)command).getTable().getName().toUpperCase(), ((Create)command).getColumns(), false);
-            return CollectionTupleSource.createUpdateCountTupleSource(0);	
-    	}
-    	if (command instanceof Drop) {
-    		String tempTableName = ((Drop)command).getTable().getName().toUpperCase();
-            removeTempTableByName(tempTableName);
-            return CollectionTupleSource.createUpdateCountTupleSource(0);
-    	}
-        return null;
-    }
-    
-    public void removeTempTables() throws TeiidComponentException{
-        for (String name : new ArrayList<String>( groupToTupleSourceID.keySet() )) {
-            removeTempTableByName(name);
-        }
-    }
-    
-    private TupleBuffer getTupleSourceID(String tempTableID, Command command) throws TeiidComponentException, QueryProcessingException{
-        TupleBuffer tsID = groupToTupleSourceID.get(tempTableID);
-        if(tsID != null) {
-            return tsID;
-        }
-        if(this.parentTempTableStore != null){
-    		tsID = this.parentTempTableStore.getTupleSourceID(tempTableID);
-    	    if(tsID != null) {
-    	        return tsID;
-    	    }
-        }
-        //allow implicit temp group definition
-        List columns = null;
-        if (command instanceof Insert) {
-            Insert insert = (Insert)command;
-            GroupSymbol group = insert.getGroup();
-            if(group.isImplicitTempGroupSymbol()) {
-                columns = insert.getVariables();
-            }
-        }
-        if (columns == null) {
-        	throw new QueryProcessingException(QueryExecPlugin.Util.getString("TempTableStore.table_doesnt_exist_error", tempTableID)); //$NON-NLS-1$
-        }
-        addTempTable(tempTableID, columns, true);       
-        return groupToTupleSourceID.get(tempTableID);
-    }
-    
-    private TupleSource addTuple(Insert insert, TupleBuffer tsId) throws TeiidComponentException, ExpressionEvaluationException {
-        GroupSymbol group = insert.getGroup();
-        int tuplesAdded = 0;
-        try {
-            List<ElementSymbol> elements = ResolverUtil.resolveElementsInGroup(group, new TempMetadataAdapter(null, tempMetadataStore));
-            
-            List<List<Object>> tuples = getBulkRows(insert, elements);
-            
-            for (List<Object> list : tuples) {
-				tsId.addTuple(list);
-			}
-            //TODO: this leads to fragmented batches, which may require recreating the table
-            tsId.saveBatch();
-            
-            tuplesAdded = tuples.size();
-        } catch (QueryMetadataException err) {
-            throw new TeiidComponentException(err);
-        }        
-        
-        return CollectionTupleSource.createUpdateCountTupleSource(tuplesAdded);
-    }
-
-	public static List<List<Object>> getBulkRows(Insert insert, List<ElementSymbol> elements) throws ExpressionEvaluationException, BlockedException, TeiidComponentException {
-		int bulkRowCount = 1;
-		if (insert.isBulk()) {
-			Constant c = (Constant)insert.getValues().get(0);
-			bulkRowCount = ((List<?>)c.getValue()).size();
-		}
-		
-		List<List<Object>> tuples = new ArrayList<List<Object>>(bulkRowCount);
-		
-		for (int row = 0; row < bulkRowCount; row++) {
-			List<Object> currentRow = new ArrayList<Object>(insert.getValues().size());
-			for (ElementSymbol symbol : elements) {
-                int index = insert.getVariables().indexOf(symbol);
-                Object value = null;
-                if (index != -1) {
-                	if (insert.isBulk()) {
-	                	Constant multiValue = (Constant)insert.getValues().get(index);
-	    		    	value = ((List<?>)multiValue.getValue()).get(row);
-                	} else {
-                		Expression expr = (Expression)insert.getValues().get(index);
-                        value = Evaluator.evaluate(expr);
-                	}
-                }
-                currentRow.add(value);
-            }
-		    tuples.add(currentRow);
-		}
-		return tuples;
-	}
-    
-    public boolean hasTempTable(Command command){
-        switch (command.getType()) {
-            case Command.TYPE_INSERT:
-            {
-                Insert insert = (Insert)command;
-                GroupSymbol group = insert.getGroup();
-                return group.isTempGroupSymbol();
-            }
-            case Command.TYPE_QUERY:
-            {
-                if(command instanceof Query) {
-                    Query query = (Query)command;
-                    GroupSymbol group = (GroupSymbol)query.getFrom().getGroups().get(0);
-                    return group.isTempGroupSymbol(); 
-                }
-                break;
-            }
-            case Command.TYPE_CREATE:
-                return true;
-            case Command.TYPE_DROP:
-                return true;
-        }
-        return false;
-    }
-    
-    public Set<String> getAllTempTables() {
-        return new HashSet<String>(this.groupToTupleSourceID.keySet());
-    }
-    
-    public TupleBuffer getTupleSourceID(String tempTableName) {
-    	return groupToTupleSourceID.get(tempTableName.toUpperCase());
-    } 
-}

Modified: trunk/engine/src/main/javacc/org/teiid/query/parser/SQLParser.jj
===================================================================
--- trunk/engine/src/main/javacc/org/teiid/query/parser/SQLParser.jj	2010-07-23 20:47:35 UTC (rev 2370)
+++ trunk/engine/src/main/javacc/org/teiid/query/parser/SQLParser.jj	2010-07-23 21:44:19 UTC (rev 2371)
@@ -500,6 +500,7 @@
 	Create create = new Create();
 	String table = null;
 	List columns = null;
+	String pkId = null;
 }
 {
 	<CREATE> <LOCAL> <TEMPORARY> <TABLE> 
@@ -512,6 +513,18 @@
 	{
 		create.setColumns(columns);
 	}
+	[<COMMA> <PRIMARY> nonReserved("KEY") <LPAREN>
+	  pkId = id()
+	  {
+	    create.getPrimaryKey().add(new ElementSymbol(validateElementName(pkId)));
+	  }
+	  (<COMMA> pkId = id()
+	   {
+	     create.getPrimaryKey().add(new ElementSymbol(validateElementName(pkId)));
+	   }
+	  )*
+	 <RPAREN>	
+	]
 	<RPAREN>
 	{
 		return create;
@@ -1087,7 +1100,7 @@
 	    symbol.setType(DataTypeManager.getDataTypeClass(type.getValue().toString()));
 		elements.add(symbol);
 	 }
-	 (<COMMA>
+	 (LOOKAHEAD(2) <COMMA>
 		element = id()
 		type = dataType()
 		{

Modified: trunk/engine/src/main/resources/org/teiid/query/i18n.properties
===================================================================
--- trunk/engine/src/main/resources/org/teiid/query/i18n.properties	2010-07-23 20:47:35 UTC (rev 2370)
+++ trunk/engine/src/main/resources/org/teiid/query/i18n.properties	2010-07-23 21:44:19 UTC (rev 2371)
@@ -945,4 +945,6 @@
 WorkerPool.New_thread=Created worker thread "{0}".
 WorkerPool.uncaughtException=Uncaught exception processing work
 
-XMLSystemFunctions.invalid_namespaces=Invalid namespaces supplied for XPath expression - ''{0}''
\ No newline at end of file
+XMLSystemFunctions.invalid_namespaces=Invalid namespaces supplied for XPath expression - ''{0}''
+
+TempTable.duplicate_key=Duplicate key
\ No newline at end of file

Added: trunk/engine/src/test/java/org/teiid/common/buffer/impl/TestSTree.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/common/buffer/impl/TestSTree.java	                        (rev 0)
+++ trunk/engine/src/test/java/org/teiid/common/buffer/impl/TestSTree.java	2010-07-23 21:44:19 UTC (rev 2371)
@@ -0,0 +1,62 @@
+/*
+ * 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.impl;
+
+import static org.junit.Assert.*;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.Test;
+import org.teiid.common.buffer.BufferManager;
+import org.teiid.common.buffer.BufferManagerFactory;
+import org.teiid.common.buffer.STree;
+import org.teiid.common.buffer.BufferManager.TupleSourceType;
+import org.teiid.core.TeiidComponentException;
+import org.teiid.query.sql.symbol.ElementSymbol;
+
+public class TestSTree {
+	
+	@Test public void testRemoveAll() throws TeiidComponentException, IOException {
+		BufferManager bm = BufferManagerFactory.getStandaloneBufferManager();
+		ElementSymbol e1 = new ElementSymbol("x");
+		e1.setType(Integer.class);
+		ElementSymbol e2 = new ElementSymbol("y");
+		e2.setType(String.class);
+		List elements = Arrays.asList(e1, e2);
+		STree map = bm.createSTree(elements, "1", TupleSourceType.PROCESSOR, 1);
+		
+		for (int i = 20000; i > 0; i--) {
+			map.insert(Arrays.asList(i, String.valueOf(i)), true);
+		}
+		
+		for (int i = 20000; i > 0; i--) {
+			map.remove(Arrays.asList(i));
+		}
+		
+		assertEquals(0, map.getRowCount());
+		assertNull(map.insert(Arrays.asList(1, String.valueOf(1)), true));
+	}
+
+}


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

Modified: trunk/engine/src/test/java/org/teiid/dqp/internal/process/TestCodeTableCache.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/dqp/internal/process/TestCodeTableCache.java	2010-07-23 20:47:35 UTC (rev 2370)
+++ trunk/engine/src/test/java/org/teiid/dqp/internal/process/TestCodeTableCache.java	2010-07-23 21:44:19 UTC (rev 2371)
@@ -69,7 +69,7 @@
 		//   r2--> 'Germany', 'GM'
 		
 		try {
-			ctc.loadTable(nodeId, results);
+			ctc.loadTable(nodeId, Arrays.asList(results));
 		} catch (TeiidProcessingException e) {
 			throw new RuntimeException(e);
 		}
@@ -90,7 +90,7 @@
 		//   r2--> 'Germany', 'GM'
 		
 		try {
-			ctc.loadTable(nodeId, results);
+			ctc.loadTable(nodeId, Arrays.asList(results));
 		} catch (TeiidProcessingException e) {
 			throw new RuntimeException(e);
 		}
@@ -203,7 +203,7 @@
         }; 
 		
 		try {
-			ctc.loadTable(nodeId, results);
+			ctc.loadTable(nodeId, Arrays.asList(results));
 			fail("expected exception"); //$NON-NLS-1$
 		} catch (TeiidProcessingException e) {
 			assertEquals("Duplicate code table 'table' key 'value' value '1'", e.getMessage()); //$NON-NLS-1$
@@ -221,7 +221,7 @@
         }; 
 		
 		try {
-			ctc.loadTable(nodeId, results);
+			ctc.loadTable(nodeId, Arrays.asList(results));
 			fail("expected exception"); //$NON-NLS-1$
 		} catch (TeiidProcessingException e) {
 			assertEquals("Error Code:ERR.018.005.0100 Message:Unable to load code table for because result sizes exceeds the allowed parameter - maxCodeTableRecords.", e.getMessage()); //$NON-NLS-1$
@@ -239,7 +239,7 @@
         }; 
 		
 		try {
-			ctc.loadTable(nodeId, results);
+			ctc.loadTable(nodeId, Arrays.asList(results));
 			fail("expected exception"); //$NON-NLS-1$
 		} catch (TeiidProcessingException e) {
 			assertEquals("Error Code:ERR.018.005.0100 Message:Unable to load code table for because result sizes exceeds the allowed parameter - maxCodeTables.", e.getMessage()); //$NON-NLS-1$

Modified: trunk/engine/src/test/java/org/teiid/query/optimizer/TestOptionalJoins.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/optimizer/TestOptionalJoins.java	2010-07-23 20:47:35 UTC (rev 2370)
+++ trunk/engine/src/test/java/org/teiid/query/optimizer/TestOptionalJoins.java	2010-07-23 21:44:19 UTC (rev 2371)
@@ -304,7 +304,7 @@
             0,      // Null
             0,      // PlanExecution
             3,      // Project
-            0,      // Select
+            1,      // Select
             0,      // Sort
             0       // UnionAll
         });    

Modified: trunk/engine/src/test/java/org/teiid/query/parser/TestParser.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/parser/TestParser.java	2010-07-23 20:47:35 UTC (rev 2370)
+++ trunk/engine/src/test/java/org/teiid/query/parser/TestParser.java	2010-07-23 21:44:19 UTC (rev 2371)
@@ -6569,6 +6569,21 @@
         helpException("Create local TEMPORARY table tempTable (c1.x boolean, c2 byte)" ,"Parsing error: Invalid simple identifier format: [c1.x]"); //$NON-NLS-1$ //$NON-NLS-2$ 
     }
     
+    @Test public void testCreateTempTableWithPrimaryKey() {
+        Create create = new Create();
+        create.setTable(new GroupSymbol("tempTable")); //$NON-NLS-1$
+        List columns = new ArrayList();
+        ElementSymbol column = new ElementSymbol("c1");//$NON-NLS-1$
+        column.setType(DataTypeManager.DefaultDataClasses.BOOLEAN);
+        columns.add(column);
+        column = new ElementSymbol("c2");//$NON-NLS-1$
+        column.setType(DataTypeManager.DefaultDataClasses.BYTE);
+        columns.add(column);
+        create.setColumns(columns);
+        create.getPrimaryKey().add(column);
+        helpTest("Create local TEMPORARY table tempTable(c1 boolean, c2 byte, primary key (c2))", "CREATE LOCAL TEMPORARY TABLE tempTable (c1 boolean, c2 byte, PRIMARY KEY(c2))", create); //$NON-NLS-1$ //$NON-NLS-2$
+    }
+    
     @Test public void testDropTable() {
         Drop drop = new Drop();
         drop.setTable(new GroupSymbol("tempTable")); //$NON-NLS-1$

Modified: trunk/engine/src/test/java/org/teiid/query/processor/TestProcessor.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/processor/TestProcessor.java	2010-07-23 20:47:35 UTC (rev 2370)
+++ trunk/engine/src/test/java/org/teiid/query/processor/TestProcessor.java	2010-07-23 21:44:19 UTC (rev 2371)
@@ -297,8 +297,8 @@
 		props.setProperty("soap_host", "my.host.com"); //$NON-NLS-1$ //$NON-NLS-2$
 		props.setProperty("soap_port", "12345"); //$NON-NLS-1$ //$NON-NLS-2$
 		CommandContext context = new CommandContext("0", "test", "user", null, "myvdb", 1, props, DEBUG, false); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
-        context.setProcessorBatchSize(2000);
-        context.setConnectorBatchSize(2000);
+        context.setProcessorBatchSize(BufferManager.DEFAULT_PROCESSOR_BATCH_SIZE);
+        context.setConnectorBatchSize(BufferManager.DEFAULT_CONNECTOR_BATCH_SIZE);
         context.setBufferManager(BufferManagerFactory.getStandaloneBufferManager());
         context.setProcessDebug(DEBUG);
 		return context;

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-23 20:47:35 UTC (rev 2370)
+++ trunk/engine/src/test/java/org/teiid/query/processor/TestTempTables.java	2010-07-23 21:44:19 UTC (rev 2371)
@@ -28,10 +28,9 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.teiid.common.buffer.BufferManagerFactory;
-import org.teiid.core.TeiidComponentException;
+import org.teiid.core.TeiidProcessingException;
 import org.teiid.query.metadata.TempMetadataAdapter;
-import org.teiid.query.processor.TempTableDataManager;
-import org.teiid.query.tempdata.TempTableStoreImpl;
+import org.teiid.query.tempdata.TempTableStore;
 import org.teiid.query.unittest.FakeMetadataFactory;
 
 
@@ -44,8 +43,8 @@
 		TestProcessor.doProcess(TestProcessor.helpGetPlan(sql, metadata), dataManager, expectedResults, TestProcessor.createCommandContext());
 	}
 
-	@Before public void setUp() throws TeiidComponentException {
-		TempTableStoreImpl tempStore = new TempTableStoreImpl(BufferManagerFactory.getStandaloneBufferManager(), "1", null); //$NON-NLS-1$
+	@Before public void setUp() {
+		TempTableStore tempStore = new TempTableStore(BufferManagerFactory.getStandaloneBufferManager(), "1", null); //$NON-NLS-1$
 		metadata = new TempMetadataAdapter(FakeMetadataFactory.example1Cached(), tempStore.getMetadataStore());
 		FakeDataManager fdm = new FakeDataManager();
 	    TestProcessor.sampleData1(fdm);
@@ -90,5 +89,37 @@
 		execute("delete from x", new List[] {Arrays.asList(6)}); //$NON-NLS-1$
 		execute("select e1 from x order by e1", new List[] {}); //$NON-NLS-1$
 	}
-
+	
+	@Test(expected=TeiidProcessingException.class) public void testDuplicatePrimaryKey() 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 (1, 'one')", new List[] {Arrays.asList(1)}); //$NON-NLS-1$
+		execute("insert into x (e2, e1) values (1, 'one')", new List[] {Arrays.asList(1)}); //$NON-NLS-1$
+	}
+	
+	@Test public void testAtomicUpdate() 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 (1, 'one')", new List[] {Arrays.asList(1)}); //$NON-NLS-1$
+		execute("insert into x (e2, e1) values (2, 'one')", new List[] {Arrays.asList(1)}); //$NON-NLS-1$
+		try {
+			execute("update x set e2 = 3", new List[] {Arrays.asList(1)}); //$NON-NLS-1$
+		} catch (TeiidProcessingException e) {
+			//should be a duplicate key
+		}
+		//should revert back to original
+		execute("select count(*) from x", new List[] {Arrays.asList(2)}); //$NON-NLS-1$
+	}
+	
+	@Test public void testAtomicDelete() 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 (1, 'one')", new List[] {Arrays.asList(1)}); //$NON-NLS-1$
+		execute("insert into x (e2, e1) values (2, 'one')", new List[] {Arrays.asList(1)}); //$NON-NLS-1$
+		try {
+			execute("delete from x where 1/(e2 - 2) <> 4", new List[] {Arrays.asList(1)}); //$NON-NLS-1$
+		} catch (TeiidProcessingException e) {
+			//should be a duplicate key
+		}
+		//should revert back to original
+		execute("select count(*) from x", new List[] {Arrays.asList(2)}); //$NON-NLS-1$
+	}
+	
 }

Modified: trunk/engine/src/test/java/org/teiid/query/processor/proc/TestProcedureProcessor.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/processor/proc/TestProcedureProcessor.java	2010-07-23 20:47:35 UTC (rev 2370)
+++ trunk/engine/src/test/java/org/teiid/query/processor/proc/TestProcedureProcessor.java	2010-07-23 21:44:19 UTC (rev 2371)
@@ -64,7 +64,7 @@
 import org.teiid.query.validator.ValidatorFailure;
 import org.teiid.query.validator.ValidatorReport;
 
-
+ at SuppressWarnings("unchecked")
 public class TestProcedureProcessor {
 	
     public static ProcessorPlan getProcedurePlan(String userQuery, FakeMetadataFacade metadata) throws Exception {
@@ -111,25 +111,25 @@
     	}
     }
 
-    private void helpTestProcessFailure(boolean optimistic, ProcessorPlan procPlan, 
-                                 FakeDataManager dataMgr, String failMessage) throws Exception {
+    private void helpTestProcessFailure(ProcessorPlan procPlan, FakeDataManager dataMgr, 
+                                 String failMessage) throws Exception {
         try {
-            helpTestProcess(optimistic, procPlan, new List[] {}, dataMgr, true);
+            helpTestProcess(procPlan, new List[] {}, dataMgr, true);
         } catch(TeiidException ex) {
             assertEquals(failMessage, ex.getMessage());
         }
     }
     
     public static void helpTestProcess(ProcessorPlan procPlan, List[] expectedResults, ProcessorDataManager dataMgr) throws Exception {
-        helpTestProcess(false, procPlan, expectedResults, dataMgr, false);
+        helpTestProcess(procPlan, expectedResults, dataMgr, false);
     }
     
     private void helpTestProcess(ProcessorPlan procPlan, int expectedRows, FakeDataManager dataMgr) throws Exception {
         helpTestProcess(procPlan, expectedRows, null, false, dataMgr, null);
     }
     
-    static void helpTestProcess(boolean optimistic, ProcessorPlan procPlan, List[] expectedResults, 
-    		ProcessorDataManager dataMgr, boolean shouldFail) throws Exception {
+    static void helpTestProcess(ProcessorPlan procPlan, List[] expectedResults, ProcessorDataManager dataMgr, 
+    		boolean shouldFail) throws Exception {
         helpTestProcess(procPlan, 0, expectedResults, shouldFail, dataMgr, null);
     }
 
@@ -451,7 +451,7 @@
 
 		ProcessorPlan plan = getProcedurePlan(userUpdateStr, metadata);
 									 
-        helpTestProcessFailure(false, plan, dataMgr, "Error Code:ERR.015.006.0058 Message:Unable to evaluate (SELECT pm1.g1.e2 FROM pm1.g1): Error Code:ERR.015.006.0058 Message:The command of this scalar subquery returned more than one value: SELECT pm1.g1.e2 FROM pm1.g1"); //$NON-NLS-1$ 
+        helpTestProcessFailure(plan, dataMgr, "Error Code:ERR.015.006.0058 Message:Unable to evaluate (SELECT pm1.g1.e2 FROM pm1.g1): Error Code:ERR.015.006.0058 Message:The command of this scalar subquery returned more than one value: SELECT pm1.g1.e2 FROM pm1.g1"); //$NON-NLS-1$ 
     }
 
     // error statement
@@ -488,7 +488,7 @@
 
         ProcessorPlan plan = getProcedurePlan(userUpdateStr, metadata);
                                      
-        helpTestProcessFailure(false, plan, dataMgr, ErrorInstruction.ERROR_PREFIX + "5MY ERROR"); //$NON-NLS-1$ 
+        helpTestProcessFailure(plan, dataMgr, ErrorInstruction.ERROR_PREFIX + "5MY ERROR"); //$NON-NLS-1$ 
     }
 
     private void helpTestErrorStatment(String errorValue, String expected) throws Exception {
@@ -508,7 +508,7 @@
 
 		ProcessorPlan plan = getProcedurePlan(userUpdateStr, metadata);
 									 
-        helpTestProcessFailure(false, plan, dataMgr, ErrorInstruction.ERROR_PREFIX + expected); 
+        helpTestProcessFailure(plan, dataMgr, ErrorInstruction.ERROR_PREFIX + expected); 
     }
     
 	/** test if statement's if block with lookup in if condition */
@@ -1502,8 +1502,7 @@
 
         ProcessorPlan plan = getProcedurePlan(userUpdateStr, metadata);
 
-        helpTestProcessFailure(false,
-                               plan,
+        helpTestProcessFailure(plan,
                                dataMgr,
                                "Couldn't execute the dynamic SQL command \"EXECUTE STRING 'EXEC pm1.sq2(''First'')' AS e1 string, e2 integer\" with the SQL statement \"'EXEC pm1.sq2(''First'')'\" due to: There is a recursive invocation of group 'PM1.SQ2'. Please correct the SQL."); //$NON-NLS-1$
     }
@@ -1535,7 +1534,7 @@
 
         ProcessorPlan plan = getProcedurePlan(userUpdateStr, metadata);
     	
-        helpTestProcessFailure(false, plan, dataMgr, "Couldn't execute the dynamic SQL command \"EXECUTE STRING 'EXEC pm1.sq1(''First'')' AS e1 string, e2 integer\" with the SQL statement \"'EXEC pm1.sq1(''First'')'\" due to: The dynamic sql string contains an incorrect number of elements."); //$NON-NLS-1$
+        helpTestProcessFailure(plan, dataMgr, "Couldn't execute the dynamic SQL command \"EXECUTE STRING 'EXEC pm1.sq1(''First'')' AS e1 string, e2 integer\" with the SQL statement \"'EXEC pm1.sq1(''First'')'\" due to: The dynamic sql string contains an incorrect number of elements."); //$NON-NLS-1$
      }
     
     @Test public void testDynamicCommandPositional() throws Exception {
@@ -1587,7 +1586,7 @@
 
         ProcessorPlan plan = getProcedurePlan(userUpdateStr, metadata);
     	
-        helpTestProcessFailure(false, plan, dataMgr, "Couldn't execute the dynamic SQL command \"EXECUTE STRING 'select e1 from pm1.g1'\" with the SQL statement \"'select e1 from pm1.g1'\" due to: The datatype 'string' for element 'E1' in the dynamic SQL cannot be implicitly converted to 'integer'."); //$NON-NLS-1$
+        helpTestProcessFailure(plan, dataMgr, "Couldn't execute the dynamic SQL command \"EXECUTE STRING 'select e1 from pm1.g1'\" with the SQL statement \"'select e1 from pm1.g1'\" due to: The datatype 'string' for element 'E1' in the dynamic SQL cannot be implicitly converted to 'integer'."); //$NON-NLS-1$
      }
      
     @Test public void testDynamicCommandWithTwoDynamicStatements() throws Exception {
@@ -1877,7 +1876,7 @@
 
         ProcessorPlan plan = getProcedurePlan(userUpdateStr, metadata);
         
-        helpTestProcessFailure(false, plan, dataMgr, "Temporary table \"T1\" already exists."); //$NON-NLS-1$
+        helpTestProcessFailure(plan, dataMgr, "Temporary table \"T1\" already exists."); //$NON-NLS-1$
     }
     
     /**

Modified: trunk/engine/src/test/java/org/teiid/query/processor/relational/TestProjectIntoNode.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/processor/relational/TestProjectIntoNode.java	2010-07-23 20:47:35 UTC (rev 2370)
+++ trunk/engine/src/test/java/org/teiid/query/processor/relational/TestProjectIntoNode.java	2010-07-23 21:44:19 UTC (rev 2371)
@@ -42,7 +42,7 @@
 import org.teiid.query.sql.symbol.Constant;
 import org.teiid.query.sql.symbol.ElementSymbol;
 import org.teiid.query.sql.symbol.GroupSymbol;
-import org.teiid.query.tempdata.TempTableStoreImpl;
+import org.teiid.query.tempdata.TempTableStore;
 import org.teiid.query.util.CommandContext;
 
 import junit.framework.TestCase;
@@ -140,7 +140,7 @@
             if (command instanceof Insert) {
             	Insert insert = (Insert)command;
             	if (insert.isBulk()) {
-                    List batch = TempTableStoreImpl.getBulkRows(insert, insert.getVariables());
+                    List batch = TempTableStore.getBulkRows(insert, insert.getVariables());
                     batchSize = batch.size();
                     assertEquals("Unexpected batch on call " + callCount, expectedBatchSize, batchSize); //$NON-NLS-1$
                     

Modified: trunk/engine/src/test/java/org/teiid/query/resolver/TestResolver.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/resolver/TestResolver.java	2010-07-23 20:47:35 UTC (rev 2370)
+++ trunk/engine/src/test/java/org/teiid/query/resolver/TestResolver.java	2010-07-23 21:44:19 UTC (rev 2371)
@@ -38,6 +38,7 @@
 import java.util.Map;
 
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.teiid.api.exception.query.QueryMetadataException;
 import org.teiid.api.exception.query.QueryResolverException;
@@ -94,8 +95,9 @@
 import org.teiid.query.unittest.FakeMetadataObject;
 import org.teiid.query.unittest.FakeMetadataStore;
 import org.teiid.query.unittest.TimestampUtil;
+import org.teiid.query.util.ErrorMessageKeys;
 
-
+ at SuppressWarnings("nls")
 public class TestResolver {
 
 	private FakeMetadataFacade metadata;
@@ -2400,6 +2402,16 @@
         helpResolveException(sql, "Cannot create temporary table \"pm1.g1\". Local temporary tables must be created with unqualified names."); //$NON-NLS-1$
     }
 
+    @Test public void testCreatePk() {
+        String sql = "CREATE LOCAL TEMPORARY TABLE foo (column1 string, column2 integer, primary key (column1, column2))"; //$NON-NLS-1$
+        helpResolve(sql);
+    }
+    
+    @Test public void testCreateUnknownPk() {
+        String sql = "CREATE LOCAL TEMPORARY TABLE foo (column1 string, primary key (column2))"; //$NON-NLS-1$
+        helpResolveException(sql, "Element \"column2\" is not defined by any relevant group."); //$NON-NLS-1$
+    }
+
     @Test public void testCreateAlreadyExists() {
         String sql = "CREATE LOCAL TEMPORARY TABLE g1 (column1 string)"; //$NON-NLS-1$
         helpResolveException(sql, "Cannot create temporary table \"g1\". A table with the same name already exists."); //$NON-NLS-1$
@@ -2863,6 +2875,21 @@
     @Test public void testSecondPassFunctionResolving() {
     	helpResolve("SELECT pm1.g1.e1 FROM pm1.g1 where lower(?) = e1 "); //$NON-NLS-1$
     }
+    
+    @Test public void testSecondPassFunctionResolving1() {
+    	try {
+    		helpResolve("SELECT pm1.g1.e1 FROM pm1.g1 where 1/(e1 - 2) <> 4 "); //$NON-NLS-1$
+    		fail("expected exception");
+    	} catch (RuntimeException e) {
+    		QueryResolverException qre = (QueryResolverException)e.getCause();
+    		assertEquals(ErrorMessageKeys.RESOLVER_0040, qre.getCode());
+    	}
+    }
+    
+    @Ignore("currently not supported - we get type hints from the criteria not from the possible signatures")
+    @Test public void testSecondPassFunctionResolving2() {
+    	helpResolve("SELECT pm1.g1.e1 FROM pm1.g1 where (lower(?) || 1) = e1 "); //$NON-NLS-1$
+    }
 
     /**
      * Test <code>QueryResolver</code>'s ability to resolve a query that 

Modified: trunk/engine/src/test/java/org/teiid/query/sql/util/TestElementSymbolOptimizer.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/sql/util/TestElementSymbolOptimizer.java	2010-07-23 20:47:35 UTC (rev 2370)
+++ trunk/engine/src/test/java/org/teiid/query/sql/util/TestElementSymbolOptimizer.java	2010-07-23 21:44:19 UTC (rev 2371)
@@ -183,7 +183,7 @@
         
         helpTestOptimize("EXEC pm1.sq2(pm1.sq3.in)",  //$NON-NLS-1$
                             FakeMetadataFactory.example1Cached(),  
-                            "EXEC pm1.sq2(pm1.sq3.\"in\")", //$NON-NLS-1$
+                            "EXEC pm1.sq2(\"in\")", //$NON-NLS-1$
                             externalMetadata);         
     }
 

Modified: trunk/engine/src/test/java/org/teiid/query/sql/visitor/TestSQLStringVisitor.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/sql/visitor/TestSQLStringVisitor.java	2010-07-23 20:47:35 UTC (rev 2370)
+++ trunk/engine/src/test/java/org/teiid/query/sql/visitor/TestSQLStringVisitor.java	2010-07-23 21:44:19 UTC (rev 2371)
@@ -1127,7 +1127,7 @@
     public void testElementSymbol5() {
     	ElementSymbol es = new ElementSymbol("m.g.select", false); //$NON-NLS-1$
     	es.setGroupSymbol(new GroupSymbol("m.g")); //$NON-NLS-1$
-    	helpTest(es, "m.g.\"select\"");     //$NON-NLS-1$
+    	helpTest(es, "\"select\"");     //$NON-NLS-1$
     }
 
     public void testExpressionSymbol1() {



More information about the teiid-commits mailing list