Author: shawkins
Date: 2010-07-28 00:40:32 -0400 (Wed, 28 Jul 2010)
New Revision: 2382
Added:
trunk/engine/src/main/java/org/teiid/common/buffer/TupleBrowser.java
trunk/engine/src/main/java/org/teiid/query/tempdata/IndexCondition.java
Modified:
trunk/engine/src/main/java/org/teiid/common/buffer/STree.java
trunk/engine/src/main/java/org/teiid/query/metadata/TempCapabilitiesFinder.java
trunk/engine/src/main/java/org/teiid/query/sql/symbol/Constant.java
trunk/engine/src/main/java/org/teiid/query/tempdata/TempTable.java
trunk/engine/src/main/java/org/teiid/query/tempdata/TempTableStore.java
trunk/engine/src/main/java/org/teiid/query/validator/ValidationVisitor.java
trunk/engine/src/main/resources/org/teiid/query/i18n.properties
trunk/engine/src/test/java/org/teiid/query/processor/TestTempTables.java
trunk/engine/src/test/java/org/teiid/query/processor/xml/TestXMLPlanningEnhancements.java
trunk/engine/src/test/java/org/teiid/query/validator/TestValidator.java
Log:
TEIID-1167 adding support for predicate use of the index and validating that the primary
key must be comparable
Modified: trunk/engine/src/main/java/org/teiid/common/buffer/STree.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/common/buffer/STree.java 2010-07-27 23:06:31 UTC
(rev 2381)
+++ trunk/engine/src/main/java/org/teiid/common/buffer/STree.java 2010-07-28 04:40:32 UTC
(rev 2382)
@@ -49,7 +49,7 @@
private int mask = 1;
private int shift = 1;
- private SPage[] header = new SPage[] {new SPage(this, true)};
+ protected SPage[] header = new SPage[] {new SPage(this, true)};
protected BatchManager manager;
protected Comparator comparator;
protected int pageSize;
@@ -112,7 +112,7 @@
* @throws IOException
* @throws TeiidComponentException
*/
- private List find(List n, LinkedList<SearchResult> places) throws
TeiidComponentException {
+ List find(List n, LinkedList<SearchResult> places) throws TeiidComponentException
{
SPage x = null;
for (int i = header.length - 1; i >= 0; i--) {
if (x == null) {
@@ -313,10 +313,6 @@
return this.rowCount.get();
}
- public TupleBrowser browse(List lowerBound, List upperBound, boolean direction) {
- return new TupleBrowser(direction);
- }
-
public int truncate() {
int oldSize = rowCount.getAndSet(0);
for (int i = 0; i < header.length; i++) {
@@ -330,86 +326,6 @@
return oldSize;
}
- //TODO: support update/delete from the browser
- public class TupleBrowser {
-
- SPage page = header[0];
- int index;
- TupleBatch values;
- boolean updated;
- boolean direction;
-
- public TupleBrowser(boolean direction) {
- this.direction = direction;
- if (!direction) {
- while (page.prev != null) {
- page = page.prev;
- }
- }
- }
-
- public boolean matchedLower() {
- return false;
- }
-
- public boolean matchedUpper() {
- return false;
- }
-
- public List next() throws TeiidComponentException {
- for (;;) {
- if (values == null) {
- values = page.getValues();
- if (direction) {
- index = 0;
- } else {
- index = values.getTuples().size() - 1;
- }
- }
- if (index >= 0 && index < values.getTuples().size()) {
- List result = values.getTuples().get(index);
- index+=getOffset();
- return result;
- }
- if (updated) {
- page.setValues(values);
- }
- updated = false;
- values = null;
- if (direction) {
- page = page.next;
- } else {
- page = page.prev;
- }
- if (page == null) {
- return null;
- }
- }
- }
-
- private int getOffset() {
- return direction?1:-1;
- }
-
- /**
- * Perform an in-place update of the tuple just returned by the next method
- * WARNING - this must not change the key value
- * @param tuple
- * @throws TeiidComponentException
- */
- public void update(List tuple) throws TeiidComponentException {
- values.getTuples().set(index - getOffset(), tuple);
- updated = true;
- }
-
- /**
- * Notify the browser that the last value was deleted.
- */
- public void removed() {
- index-=getOffset();
- }
- }
-
@Override
public String toString() {
StringBuffer result = new StringBuffer();
Added: trunk/engine/src/main/java/org/teiid/common/buffer/TupleBrowser.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/common/buffer/TupleBrowser.java
(rev 0)
+++ trunk/engine/src/main/java/org/teiid/common/buffer/TupleBrowser.java 2010-07-28
04:40:32 UTC (rev 2382)
@@ -0,0 +1,208 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership. Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+package org.teiid.common.buffer;
+
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.teiid.common.buffer.SPage.SearchResult;
+import org.teiid.core.TeiidComponentException;
+
+/**
+ * Implements intelligent browsing over a {@link STree}
+ *
+ * TODO: when using other values we can be more efficient
+ * with paging.
+ */
+public class TupleBrowser {
+
+ private final STree tree;
+
+ private List<List<?>> otherValues;
+
+ private SPage page;
+ private int index;
+
+ private SPage bound;
+ private int boundIndex = -1;
+
+ private TupleBatch values;
+ private boolean updated;
+ private boolean direction;
+ private boolean range;
+
+ public TupleBrowser(STree sTree, List<?> lowerBound, List<?> upperBound,
List<List<?>> otherValues, boolean range, boolean direction) throws
TeiidComponentException {
+ this.tree = sTree;
+ this.direction = direction;
+ this.otherValues = otherValues;
+ this.range = range;
+
+ if (lowerBound != null) {
+ setPage(lowerBound);
+ } else {
+ page = sTree.header[0];
+ }
+
+ boolean valid = true;
+
+ if (upperBound != null) {
+ if (this.tree.comparator.compare(upperBound, lowerBound) < 0) {
+ valid = false;
+ }
+ LinkedList<SearchResult> places = new LinkedList<SearchResult>();
+ this.tree.find(upperBound, places);
+ SearchResult upper = places.getLast();
+ bound = upper.page;
+ boundIndex = upper.index;
+ if (boundIndex < 0) {
+ boundIndex = Math.min(upper.values.getTuples().size() - 1, -boundIndex -1);
+ }
+ if (!direction) {
+ values = upper.values;
+ }
+ } else if (range) {
+ //this is a range query
+ //TODO: this could also be signaled with an all null key
+ bound = tree.header[0];
+ while (bound.next != null) {
+ bound = bound.next;
+ }
+ } else {
+ bound = page;
+ boundIndex = index;
+ }
+
+ if (!direction) {
+ SPage swap = page;
+ page = bound;
+ bound = swap;
+ int upperIndex = boundIndex;
+ boundIndex = index;
+ index = upperIndex;
+ }
+
+ if (!valid) {
+ page = null;
+ }
+ }
+
+ private void setPage(List<?> lowerBound) throws TeiidComponentException {
+ if (values != null) {
+ int possibleIndex = Collections.binarySearch(values.getTuples(), lowerBound,
tree.comparator);
+ if (possibleIndex != -1 && possibleIndex != -values.getTuples().size() -1) {
+ index = possibleIndex;
+ if (possibleIndex < 0) {
+ index = -index -1;
+ }
+ return;
+ }
+ }
+ resetState();
+ LinkedList<SearchResult> places = new LinkedList<SearchResult>();
+ this.tree.find(lowerBound, places);
+
+ SearchResult sr = places.getLast();
+ page = sr.page;
+ index = sr.index;
+ if (index < 0) {
+ index = -index - 1;
+ }
+ values = sr.values;
+ }
+
+ public List<?> next() throws TeiidComponentException {
+ for (;;) {
+ if (page == null) {
+ return null;
+ }
+ if (values == null) {
+ values = page.getValues();
+ if (direction) {
+ index = 0;
+ } else {
+ index = values.getTuples().size() - 1;
+ }
+ }
+ if (index >= 0 && index < values.getTuples().size()) {
+ List<?> result = values.getTuples().get(index);
+ if (page == bound && index == boundIndex) {
+ resetState();
+ page = null; //terminate
+ } else if (otherValues != null && !range) {
+ if (!otherValues.isEmpty()) {
+ List newBound =
direction?otherValues.remove(0):otherValues.remove(otherValues.size() -1);
+ setPage(newBound);
+ } else {
+ otherValues = null;
+ if (page != bound) {
+ resetState();
+ }
+ page = bound;
+ index = boundIndex;
+ values = bound.values;
+ }
+ } else {
+ index+=getOffset();
+ }
+ return result;
+ }
+ resetState();
+ if (direction) {
+ page = page.next;
+ } else {
+ page = page.prev;
+ }
+ }
+ }
+
+ private void resetState() throws TeiidComponentException {
+ if (updated) {
+ page.setValues(values);
+ }
+ updated = false;
+ values = null;
+ }
+
+ private int getOffset() {
+ return direction?1:-1;
+ }
+
+ /**
+ * Perform an in-place update of the tuple just returned by the next method
+ * WARNING - this must not change the key value
+ * @param tuple
+ * @throws TeiidComponentException
+ */
+ public void update(List<?> tuple) throws TeiidComponentException {
+ values.getTuples().set(index - getOffset(), tuple);
+ updated = true;
+ }
+
+ /**
+ * Notify the browser that the last value was deleted.
+ */
+ public void removed() {
+ index-=getOffset();
+ }
+}
\ No newline at end of file
Property changes on: trunk/engine/src/main/java/org/teiid/common/buffer/TupleBrowser.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Modified: trunk/engine/src/main/java/org/teiid/query/metadata/TempCapabilitiesFinder.java
===================================================================
---
trunk/engine/src/main/java/org/teiid/query/metadata/TempCapabilitiesFinder.java 2010-07-27
23:06:31 UTC (rev 2381)
+++
trunk/engine/src/main/java/org/teiid/query/metadata/TempCapabilitiesFinder.java 2010-07-28
04:40:32 UTC (rev 2382)
@@ -45,6 +45,13 @@
tempCaps = new BasicSourceCapabilities();
tempCaps.setCapabilitySupport(Capability.BULK_UPDATE, true);
tempCaps.setCapabilitySupport(Capability.QUERY_ORDERBY, true);
+ tempCaps.setCapabilitySupport(Capability.CRITERIA_NOT, true);
+ tempCaps.setCapabilitySupport(Capability.CRITERIA_IN, true);
+ tempCaps.setCapabilitySupport(Capability.CRITERIA_COMPARE_EQ, true);
+ tempCaps.setCapabilitySupport(Capability.CRITERIA_COMPARE_ORDERED, true);
+ tempCaps.setCapabilitySupport(Capability.CRITERIA_ISNULL, true);
+ tempCaps.setCapabilitySupport(Capability.CRITERIA_LIKE, true);
+ tempCaps.setCapabilitySupport(Capability.CRITERIA_LIKE_ESCAPE, true);
}
return tempCaps;
}
Modified: trunk/engine/src/main/java/org/teiid/query/sql/symbol/Constant.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/symbol/Constant.java 2010-07-27
23:06:31 UTC (rev 2381)
+++ trunk/engine/src/main/java/org/teiid/query/sql/symbol/Constant.java 2010-07-28
04:40:32 UTC (rev 2382)
@@ -37,7 +37,7 @@
* value, but that is not true if the value is null. In that case, the type is unknown
* and is set to the null type until the type is resolved at a later point.
*/
-public class Constant implements Expression {
+public class Constant implements Expression, Comparable<Constant> {
private Object value;
private Class type;
@@ -181,5 +181,19 @@
public String toString() {
return SQLStringVisitor.getSQLString(this);
}
+
+ @Override
+ public int compareTo(Constant o) {
+ if (isNull()) {
+ if (o.isNull()) {
+ return 0;
+ }
+ return -1;
+ }
+ if (o.isNull()) {
+ return 1;
+ }
+ return ((Comparable)this.value).compareTo(o.getValue());
+ }
}
Added: trunk/engine/src/main/java/org/teiid/query/tempdata/IndexCondition.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/tempdata/IndexCondition.java
(rev 0)
+++ trunk/engine/src/main/java/org/teiid/query/tempdata/IndexCondition.java 2010-07-28
04:40:32 UTC (rev 2382)
@@ -0,0 +1,170 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * See the COPYRIGHT.txt file distributed with this work for information
+ * regarding copyright ownership. Some portions may be licensed
+ * to Red Hat, Inc. under one or more contributor license agreements.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301 USA.
+ */
+
+package org.teiid.query.tempdata;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.TreeSet;
+
+import org.teiid.query.sql.lang.CompareCriteria;
+import org.teiid.query.sql.lang.Criteria;
+import org.teiid.query.sql.lang.IsNullCriteria;
+import org.teiid.query.sql.lang.MatchCriteria;
+import org.teiid.query.sql.lang.SetCriteria;
+import org.teiid.query.sql.symbol.Constant;
+import org.teiid.query.sql.symbol.ElementSymbol;
+import org.teiid.query.sql.symbol.Expression;
+
+class IndexCondition {
+
+ static IndexCondition[] getIndexConditions(Criteria condition, List<ElementSymbol>
keyColumns) {
+ List<Criteria> crits = Criteria.separateCriteriaByAnd(condition);
+ IndexCondition[] conditions = new IndexCondition[keyColumns.size()];
+ for (int i = 0; i < conditions.length; i++) {
+ if (i > 0 && (conditions[i - 1].range || conditions[i -1].upper != null))
{
+ break; //don't yet support any other types of composite key lookups
+ }
+ conditions[i] = new IndexCondition();
+ ElementSymbol keyColumn = keyColumns.get(i);
+ for (Iterator<Criteria> critIter = crits.iterator(); critIter.hasNext();) {
+ Criteria criteria = critIter.next();
+ if (criteria instanceof CompareCriteria) {
+ CompareCriteria cc = (CompareCriteria)criteria;
+ if (cc.getOperator() == CompareCriteria.NE
+ || !(cc.getRightExpression() instanceof Constant) || (cc.getOperator() !=
CompareCriteria.EQ && i > 0)) {
+ critIter.remove();
+ continue;
+ }
+ if (!cc.getLeftExpression().equals(keyColumn)) {
+ continue;
+ }
+ conditions[i].addCondition((Constant)cc.getRightExpression(), cc.getOperator());
+ critIter.remove();
+ } else if (criteria instanceof IsNullCriteria) {
+ IsNullCriteria inc = (IsNullCriteria)criteria;
+ if (inc.isNegated() || !inc.getExpression().equals(keyColumn)) {
+ continue;
+ }
+ conditions[i].addCondition(new Constant(null), CompareCriteria.EQ);
+ critIter.remove();
+ } else {
+ if (i > 0) {
+ critIter.remove();
+ continue;
+ }
+ if (criteria instanceof MatchCriteria) {
+ MatchCriteria matchCriteria = (MatchCriteria)criteria;
+ if (matchCriteria.isNegated() ||
!matchCriteria.getLeftExpression().equals(keyColumn) ||
!(matchCriteria.getRightExpression() instanceof Constant)) {
+ continue;
+ }
+ Constant value = (Constant)matchCriteria.getRightExpression();
+ String pattern = (String)value.getValue();
+ boolean escaped = false;
+ StringBuilder prefix = new StringBuilder();
+ for (int j = 0; i < pattern.length(); j++) {
+ char character = pattern.charAt(j);
+
+ if (character == matchCriteria.getEscapeChar() && character !=
MatchCriteria.NULL_ESCAPE_CHAR) {
+ if (escaped) {
+ prefix.append(character);
+ escaped = false;
+ } else {
+ escaped = true;
+ }
+ } else if (character == MatchCriteria.WILDCARD_CHAR || character ==
MatchCriteria.MATCH_CHAR) {
+ break;
+ } else {
+ prefix.append(character);
+ }
+ }
+ if (prefix.length() > 0) {
+ conditions[i].addCondition(new Constant(prefix.toString()), CompareCriteria.GE);
+ }
+ } else if (criteria instanceof SetCriteria) {
+ SetCriteria setCriteria = (SetCriteria)criteria;
+ if (!setCriteria.getExpression().equals(keyColumn)) {
+ continue;
+ }
+ TreeSet<Constant> values = new TreeSet<Constant>();
+ for (Expression expr : (List<? extends Expression>)setCriteria.getValues())
{
+ if (!(expr instanceof Constant)) {
+ continue;
+ }
+ values.add((Constant)expr);
+ }
+ conditions[i].addSet(values);
+ }
+ }
+ }
+ }
+ return conditions;
+ }
+
+ Constant lower = null;
+ Constant upper = null;
+ boolean range = true;
+ TreeSet<Constant> otherValues = new TreeSet<Constant>();
+
+ void addCondition(Constant value, int comparisionMode) {
+ switch (comparisionMode) {
+ case CompareCriteria.EQ:
+ otherValues.clear();
+ lower = value;
+ upper = null;
+ range = false;
+ break;
+ case CompareCriteria.GE:
+ case CompareCriteria.GT:
+ if (lower == null) {
+ range = true;
+ lower = value;
+ }
+ break;
+ case CompareCriteria.LE:
+ case CompareCriteria.LT:
+ if (upper == null && range) {
+ upper = value;
+ }
+ break;
+ }
+ }
+
+ void addSet(TreeSet<Constant> values) {
+ if (!range && lower != null) {
+ return;
+ }
+ Iterator<Constant> iter = values.iterator();
+ Constant lowest = iter.next();
+ iter.remove();
+ lower = lowest;
+ range = false;
+ iter = values.descendingIterator();
+ if (iter.hasNext()) {
+ Constant highest = iter.next();
+ upper = highest;
+ iter.remove();
+ }
+ otherValues.addAll(values);
+ }
+
+}
\ No newline at end of file
Property changes on:
trunk/engine/src/main/java/org/teiid/query/tempdata/IndexCondition.java
___________________________________________________________________
Name: svn:mime-type
+ text/plain
Modified: trunk/engine/src/main/java/org/teiid/query/tempdata/TempTable.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/tempdata/TempTable.java 2010-07-27 23:06:31
UTC (rev 2381)
+++ trunk/engine/src/main/java/org/teiid/query/tempdata/TempTable.java 2010-07-28 04:40:32
UTC (rev 2382)
@@ -34,37 +34,93 @@
import org.teiid.common.buffer.BlockedException;
import org.teiid.common.buffer.BufferManager;
import org.teiid.common.buffer.STree;
+import org.teiid.common.buffer.TupleBrowser;
import org.teiid.common.buffer.TupleBuffer;
import org.teiid.common.buffer.TupleSource;
import org.teiid.common.buffer.BufferManager.TupleSourceType;
-import org.teiid.common.buffer.STree.TupleBrowser;
import org.teiid.core.TeiidComponentException;
import org.teiid.core.TeiidException;
import org.teiid.core.TeiidProcessingException;
import org.teiid.core.types.DataTypeManager;
import org.teiid.query.QueryPlugin;
import org.teiid.query.eval.Evaluator;
+import org.teiid.query.metadata.TempMetadataID;
import org.teiid.query.processor.CollectionTupleSource;
import org.teiid.query.processor.relational.RelationalNode;
import org.teiid.query.processor.relational.SortUtility;
import org.teiid.query.processor.relational.SortUtility.Mode;
-import org.teiid.query.sql.lang.Command;
import org.teiid.query.sql.lang.Criteria;
import org.teiid.query.sql.lang.OrderBy;
import org.teiid.query.sql.lang.OrderByItem;
import org.teiid.query.sql.lang.SetClauseList;
-import org.teiid.query.sql.symbol.AliasSymbol;
+import org.teiid.query.sql.symbol.Constant;
import org.teiid.query.sql.symbol.ElementSymbol;
import org.teiid.query.sql.symbol.Expression;
import org.teiid.query.sql.symbol.SingleElementSymbol;
/**
* A Teiid Temp Table
- * TODO: an update will not happen unless the tuplesource is accessed
- * TODO: better handling for blocked exceptions (should be rare)
+ * TODO: in this implementation blocked exceptions will not happen
+ * allowing for subquery evaluation though would cause pauses
*/
class TempTable {
+ private final class QueryTupleSource extends TupleBrowserTupleSource {
+ private final Evaluator eval;
+ private final List<SingleElementSymbol> projectedCols;
+ private final Criteria condition;
+ private final boolean project;
+ private final int[] indexes;
+
+ private QueryTupleSource(TupleBrowser browser, Map map,
+ List<SingleElementSymbol> projectedCols, Criteria condition) {
+ super(browser);
+ this.indexes = RelationalNode.getProjectionIndexes(map, projectedCols);
+ this.eval = new Evaluator(map, null, null);
+ this.projectedCols = projectedCols;
+ this.condition = condition;
+ this.project = shouldProject();
+ }
+
+ @Override
+ public List<?> nextTuple() throws TeiidComponentException,
+ TeiidProcessingException {
+ for (;;) {
+ List<?> next = super.nextTuple();
+ if (next == null) {
+ return null;
+ }
+ if (rowId != null) {
+ next = next.subList(1, next.size());
+ }
+ if (condition != null && !eval.evaluate(condition, next)) {
+ continue;
+ }
+ if (project) {
+ next = RelationalNode.projectTuple(indexes, next);
+ }
+ return next;
+ }
+ }
+
+ private boolean shouldProject() {
+ if (indexes.length == getColumns().size()) {
+ for (int i = 0; i < indexes.length; i++) {
+ if (indexes[i] != i) {
+ return true;
+ }
+ }
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public List<? extends Expression> getSchema() {
+ return projectedCols;
+ }
+ }
+
private class TupleBrowserTupleSource implements TupleSource {
private final TupleBrowser browser;
@@ -94,18 +150,17 @@
}
}
- private abstract class UpdateTupleSource implements TupleSource {
+ private abstract class UpdateProcessor {
private TupleSource ts;
protected final Map lookup;
protected final Evaluator eval;
private final Criteria crit;
protected int updateCount = 0;
- protected boolean done;
private List currentTuple;
protected TupleBuffer undoLog;
- UpdateTupleSource(Criteria crit, TupleSource ts) throws TeiidComponentException {
+ UpdateProcessor(Criteria crit, TupleSource ts) throws TeiidComponentException {
this.ts = ts;
this.lookup = RelationalNode.createLookupMap(columns);
this.eval = new Evaluator(lookup, null, null);
@@ -113,32 +168,21 @@
this.undoLog = bm.createTupleBuffer(columns, sessionID, TupleSourceType.PROCESSOR);
}
- void process() throws TeiidComponentException, TeiidProcessingException {
- //still have to worry about blocked exceptions...
- while (currentTuple != null || (currentTuple = ts.nextTuple()) != null) {
- if (crit == null || eval.evaluate(crit, currentTuple)) {
- tuplePassed(currentTuple);
- updateCount++;
- undoLog.addTuple(currentTuple);
+ int process() throws ExpressionEvaluationException, TeiidComponentException,
TeiidProcessingException {
+ boolean success = false;
+ try {
+ while (currentTuple != null || (currentTuple = ts.nextTuple()) != null) {
+ if (crit == null || eval.evaluate(crit, currentTuple)) {
+ tuplePassed(currentTuple);
+ updateCount++;
+ undoLog.addTuple(currentTuple);
+ }
+ currentTuple = null;
}
- currentTuple = null;
- }
- }
-
- @Override
- public List<?> nextTuple() throws TeiidComponentException,
- TeiidProcessingException {
- if (done) {
- return null;
- }
- try {
- process();
- done = true;
- } catch (BlockedException e) {
- //this is horrible...
- throw e;
+ success();
+ success = true;
} finally {
- if (!done) {
+ if (!success) {
TupleSource undoTs = undoLog.createIndexedTupleSource();
List<?> tuple = null;
try {
@@ -149,26 +193,19 @@
}
}
+ close();
}
- return Arrays.asList(updateCount);
+ return updateCount;
}
+
+ @SuppressWarnings("unused")
+ void success() throws TeiidComponentException, ExpressionEvaluationException,
TeiidProcessingException {}
protected abstract void tuplePassed(List tuple) throws BlockedException,
TeiidComponentException, TeiidProcessingException;
protected abstract void undo(List tuple) throws TeiidComponentException,
TeiidProcessingException;
- @Override
- public List<SingleElementSymbol> getSchema() {
- return Command.getUpdateCommandSymbol();
- }
-
- @Override
- public int available() {
- return 0;
- }
-
- @Override
- public void closeSource() {
+ public void close() {
ts.closeSource();
undoLog.remove();
}
@@ -180,8 +217,10 @@
private List<ElementSymbol> columns;
private BufferManager bm;
private String sessionID;
+ private TempMetadataID tid;
- TempTable(BufferManager bm, List<ElementSymbol> columns, int primaryKeyLength,
String sessionID) {
+ TempTable(TempMetadataID tid, BufferManager bm, List<ElementSymbol> columns, int
primaryKeyLength, String sessionID) {
+ this.tid = tid;
this.bm = bm;
if (primaryKeyLength == 0) {
ElementSymbol id = new ElementSymbol("rowId"); //$NON-NLS-1$
@@ -196,8 +235,9 @@
this.sessionID = sessionID;
}
- public TupleSource createTupleSource(List<SingleElementSymbol> cols, Criteria
condition, OrderBy orderBy) throws TeiidComponentException, TeiidProcessingException {
+ public TupleSource createTupleSource(final List<SingleElementSymbol>
projectedCols, final Criteria condition, OrderBy orderBy) throws TeiidComponentException,
TeiidProcessingException {
Map map = RelationalNode.createLookupMap(getColumns());
+
Boolean direction = null;
boolean orderByUsingIndex = false;
if (orderBy != null && rowId == null) {
@@ -239,39 +279,9 @@
if (!orderByUsingIndex) {
direction = OrderBy.ASC;
}
- TupleBrowser browser = createTupleBrower(null, direction);
- final int[] indexes = RelationalNode.getProjectionIndexes(map, cols);
- final ArrayList<SingleElementSymbol> projectedCols = new
ArrayList<SingleElementSymbol>(cols);
- for (SingleElementSymbol singleElementSymbol : projectedCols) {
- if (singleElementSymbol instanceof AliasSymbol) {
-
- }
- }
- final boolean project = shouldProject(indexes);
- TupleSource ts = new TupleBrowserTupleSource(browser) {
-
- @Override
- public List<?> nextTuple() throws TeiidComponentException,
- TeiidProcessingException {
- List<?> next = super.nextTuple();
- if (next == null) {
- return null;
- }
- if (rowId != null) {
- next = next.subList(1, next.size());
- }
- if (project) {
- next = RelationalNode.projectTuple(indexes, next);
- }
- return next;
- }
-
- @Override
- public List<? extends Expression> getSchema() {
- return projectedCols;
- }
- };
+ TupleBrowser browser = createTupleBrower(condition, direction);
+ TupleSource ts = new QueryTupleSource(browser, map, projectedCols, condition);
TupleBuffer tb = null;
if (!orderByUsingIndex && orderBy != null) {
@@ -289,22 +299,37 @@
return tb.createIndexedTupleSource(true);
}
- private boolean shouldProject(final int[] indexes) {
- if (indexes.length == getColumns().size()) {
- for (int i = 0; i < indexes.length; i++) {
- if (indexes[i] != i) {
- return true;
+ private TupleBrowser createTupleBrower(Criteria condition, boolean direction) throws
TeiidComponentException {
+ List lower = null;
+ List upper = null;
+ List<List<?>> otherValues = null;
+ boolean range = true;
+ if (condition != null && rowId == null) {
+ IndexCondition[] indexConditions = IndexCondition.getIndexConditions(condition,
columns.subList(0, tree.getKeyLength()));
+ if (indexConditions.length > 1 && indexConditions[indexConditions.length -
1] != null) {
+ lower = new ArrayList(indexConditions.length);
+ for (IndexCondition indexCondition : indexConditions) {
+ lower.add(indexCondition.lower.getValue());
}
+ range = false;
+ //TODO: support other composite key lookups
+ } else {
+ if (indexConditions[0].lower != null) {
+ lower = Arrays.asList(indexConditions[0].lower.getValue());
+ }
+ if (indexConditions[0].upper != null) {
+ upper = Arrays.asList(indexConditions[0].upper.getValue());
+ }
+ otherValues = new ArrayList<List<?>>();
+ for (Constant constant : indexConditions[0].otherValues) {
+ otherValues.add(Arrays.asList(constant.getValue()));
+ }
+ range = indexConditions[0].range;
}
- return false;
- }
- return true;
+ }
+ return new TupleBrowser(this.tree, lower, upper, otherValues, range, direction);
}
- private TupleBrowser createTupleBrower(List<Criteria> conditions, boolean
direction) {
- return tree.browse(null, null, direction);
- }
-
public int getRowCount() {
return tree.getRowCount();
}
@@ -324,8 +349,8 @@
return columns;
}
- public TupleSource insert(List<List<Object>> tuples) throws
TeiidComponentException {
- UpdateTupleSource uts = new UpdateTupleSource(null, new
CollectionTupleSource(tuples.iterator(), getColumns())) {
+ public TupleSource insert(List<List<Object>> tuples) throws
TeiidComponentException, ExpressionEvaluationException, TeiidProcessingException {
+ UpdateProcessor up = new UpdateProcessor(null, new
CollectionTupleSource(tuples.iterator(), getColumns())) {
protected void tuplePassed(List tuple)
throws BlockedException, TeiidComponentException, TeiidProcessingException {
@@ -341,16 +366,18 @@
}
};
- return uts;
+ int updateCount = up.process();
+ tid.setCardinality(tree.getRowCount());
+ return CollectionTupleSource.createUpdateCountTupleSource(updateCount);
}
- public TupleSource update(Criteria crit, final SetClauseList update) throws
TeiidComponentException {
+ public TupleSource update(Criteria crit, final SetClauseList update) throws
TeiidComponentException, ExpressionEvaluationException, TeiidProcessingException {
final boolean primaryKeyChangePossible = canChangePrimaryKey(update);
- final TupleBrowser browser = createTupleBrower(null, OrderBy.ASC);
- UpdateTupleSource uts = new UpdateTupleSource(crit, new
TupleBrowserTupleSource(browser)) {
+ final TupleBrowser browser = createTupleBrower(crit, OrderBy.ASC);
+ UpdateProcessor up = new UpdateProcessor(crit, new TupleBrowserTupleSource(browser)) {
protected TupleBuffer changeSet;
- protected TupleSource changeSetProcessor;
+ protected UpdateProcessor changeSetProcessor;
@Override
protected void tuplePassed(List tuple)
@@ -373,14 +400,21 @@
}
@Override
- void process() throws TeiidComponentException,
- TeiidProcessingException {
- super.process();
+ protected void undo(List tuple) throws TeiidComponentException,
TeiidProcessingException {
+ if (primaryKeyChangePossible) {
+ insertTuple(tuple);
+ } else {
+ updateTuple(tuple);
+ }
+ }
+
+ @Override
+ void success() throws TeiidComponentException, ExpressionEvaluationException,
TeiidProcessingException {
//existing tuples have been removed
//changeSet contains possible updates
if (primaryKeyChangePossible) {
if (changeSetProcessor == null) {
- changeSetProcessor = new UpdateTupleSource(null,
changeSet.createIndexedTupleSource(true)) {
+ changeSetProcessor = new UpdateProcessor(null,
changeSet.createIndexedTupleSource(true)) {
@Override
protected void tuplePassed(List tuple) throws BlockedException,
TeiidComponentException, TeiidProcessingException {
@@ -395,24 +429,15 @@
};
}
- changeSetProcessor.nextTuple(); //when this returns, we're up to date
+ changeSetProcessor.process(); //when this returns, we're up to date
}
}
@Override
- protected void undo(List tuple) throws TeiidComponentException,
TeiidProcessingException {
- if (primaryKeyChangePossible) {
- insertTuple(tuple);
- } else {
- updateTuple(tuple);
- }
- }
-
- @Override
- public void closeSource() {
- super.closeSource();
+ public void close() {
+ super.close();
if (changeSetProcessor != null) {
- changeSetProcessor.closeSource(); // causes a revert of the change set
+ changeSetProcessor.close(); // causes a revert of the change set
}
if (changeSet != null) {
changeSet.remove();
@@ -420,7 +445,8 @@
}
};
- return uts;
+ int updateCount = up.process();
+ return CollectionTupleSource.createUpdateCountTupleSource(updateCount);
}
private boolean canChangePrimaryKey(final SetClauseList update) {
@@ -434,9 +460,9 @@
return false;
}
- public TupleSource delete(Criteria crit) throws TeiidComponentException {
- final TupleBrowser browser = createTupleBrower(null, OrderBy.ASC);
- UpdateTupleSource uts = new UpdateTupleSource(crit, new
TupleBrowserTupleSource(browser)) {
+ public TupleSource delete(Criteria crit) throws TeiidComponentException,
ExpressionEvaluationException, TeiidProcessingException {
+ final TupleBrowser browser = createTupleBrower(crit, OrderBy.ASC);
+ UpdateProcessor up = new UpdateProcessor(crit, new TupleBrowserTupleSource(browser)) {
@Override
protected void tuplePassed(List tuple)
throws ExpressionEvaluationException,
@@ -450,7 +476,9 @@
insertTuple(tuple);
}
};
- return uts;
+ int updateCount = up.process();
+ tid.setCardinality(tree.getRowCount());
+ return CollectionTupleSource.createUpdateCountTupleSource(updateCount);
}
private void insertTuple(List<Object> list) throws TeiidComponentException,
TeiidProcessingException {
Modified: trunk/engine/src/main/java/org/teiid/query/tempdata/TempTableStore.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/tempdata/TempTableStore.java 2010-07-27
23:06:31 UTC (rev 2381)
+++ trunk/engine/src/main/java/org/teiid/query/tempdata/TempTableStore.java 2010-07-28
04:40:32 UTC (rev 2382)
@@ -95,7 +95,7 @@
columns.removeAll(primaryKey);
columns.addAll(0, primaryKey);
}
- TempTable tempTable = new TempTable(buffer, columns,
create.getPrimaryKey().size(), sessionID);
+ TempTable tempTable = new TempTable(id, buffer, columns,
create.getPrimaryKey().size(), sessionID);
groupToTupleSourceID.put(tempTableName, tempTable);
}
@@ -131,10 +131,7 @@
return element;
}
};
- PostOrderNavigator.doVisit(query.getSelect(), emv);
- if (query.getOrderBy() != null) {
- PostOrderNavigator.doVisit(query.getOrderBy(), emv);
- }
+ PostOrderNavigator.doVisit(query, emv);
return table.createTupleSource(command.getProjectedSymbols(),
query.getCriteria(), query.getOrderBy());
}
if (command instanceof ProcedureContainer) {
Modified: trunk/engine/src/main/java/org/teiid/query/validator/ValidationVisitor.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/validator/ValidationVisitor.java 2010-07-27
23:06:31 UTC (rev 2381)
+++ trunk/engine/src/main/java/org/teiid/query/validator/ValidationVisitor.java 2010-07-28
04:40:32 UTC (rev 2382)
@@ -57,6 +57,7 @@
import org.teiid.query.sql.lang.Command;
import org.teiid.query.sql.lang.CompareCriteria;
import org.teiid.query.sql.lang.CompoundCriteria;
+import org.teiid.query.sql.lang.Create;
import org.teiid.query.sql.lang.Criteria;
import org.teiid.query.sql.lang.Delete;
import org.teiid.query.sql.lang.DependentSetCriteria;
@@ -1061,6 +1062,13 @@
}
}
+ @Override
+ public void visit(Create obj) {
+ if (!obj.getPrimaryKey().isEmpty()) {
+ validateSortable(obj.getPrimaryKey());
+ }
+ }
+
/**
* @see org.teiid.query.sql.LanguageVisitor#visit(org.teiid.query.sql.lang.Drop)
*/
Modified: trunk/engine/src/main/resources/org/teiid/query/i18n.properties
===================================================================
--- trunk/engine/src/main/resources/org/teiid/query/i18n.properties 2010-07-27 23:06:31
UTC (rev 2381)
+++ trunk/engine/src/main/resources/org/teiid/query/i18n.properties 2010-07-28 04:40:32
UTC (rev 2382)
@@ -276,7 +276,7 @@
ERR.015.012.0023 = Unable to translate criteria on the update command against the virtual
group, the element {0} is mapped to an expression whose elements are not present on the
command in the procedure using the translated criteria.
ERR.015.012.0024 = The following data elements are not supported in the SELECT clause:
{0}.
ERR.015.012.0025 = Command must project at least one symbol
-ERR.015.012.0026 = Expressions of type OBJECT, CLOB, BLOB, or XML cannot be used in
SELECT DISTINCT, ORDER BY, GROUP BY, or non-all set queries: [{0}]
+ERR.015.012.0026 = Expressions of type OBJECT, CLOB, BLOB, or XML cannot be used in
SELECT DISTINCT, ORDER BY, GROUP BY, KEYS, or non-all set queries: [{0}]
ERR.015.012.0027 = Expressions of type OBJECT, CLOB, BLOB, or XML cannot be used in
comparison: {0}.
ValidationVisitor.expression_requires_name = Non-column expressions require a name in
XMLATTRIBUTES, XMLFOREST, or QUERYSTRING
ValidationVisitor.invalid_lookup_key=Expressions of type OBJECT, CLOB, BLOB, or XML
cannot be used as LOOKUP key columns: {0}.
Modified: trunk/engine/src/test/java/org/teiid/query/processor/TestTempTables.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/processor/TestTempTables.java 2010-07-27
23:06:31 UTC (rev 2381)
+++ trunk/engine/src/test/java/org/teiid/query/processor/TestTempTables.java 2010-07-28
04:40:32 UTC (rev 2382)
@@ -157,4 +157,35 @@
execute("select * from x order by e1", new List[]
{Arrays.asList("a", 3), Arrays.asList("b", 2)}); //$NON-NLS-1$
}
+ @Test public void testCompareEqualsWithIndex() throws Exception {
+ execute("create local temporary table x (e1 string, e2 integer, primary key
(e2))", new List[] {Arrays.asList(0)}); //$NON-NLS-1$
+ execute("insert into x (e2, e1) values (3, 'a')", new List[]
{Arrays.asList(1)}); //$NON-NLS-1$
+ execute("insert into x (e2, e1) values (2, 'b')", new List[]
{Arrays.asList(1)}); //$NON-NLS-1$
+ execute("select * from x where e2 = 3", new List[]
{Arrays.asList("a", 3)}); //$NON-NLS-1$
+ }
+
+ @Test public void testLikeWithIndex() throws Exception {
+ execute("create local temporary table x (e1 string, e2 integer, primary key
(e1))", new List[] {Arrays.asList(0)}); //$NON-NLS-1$
+ execute("insert into x (e2, e1) values (3, 'a')", new List[]
{Arrays.asList(1)}); //$NON-NLS-1$
+ execute("insert into x (e2, e1) values (2, 'b')", new List[]
{Arrays.asList(1)}); //$NON-NLS-1$
+ execute("select * from x where e1 like 'z%'", new List[0]);
//$NON-NLS-1$
+ }
+
+ @Test public void testIsNullWithIndex() throws Exception {
+ execute("create local temporary table x (e1 string, e2 integer, primary key
(e1))", new List[] {Arrays.asList(0)}); //$NON-NLS-1$
+ execute("insert into x (e2, e1) values (3, null)", new List[]
{Arrays.asList(1)}); //$NON-NLS-1$
+ execute("insert into x (e2, e1) values (2, 'b')", new List[]
{Arrays.asList(1)}); //$NON-NLS-1$
+ execute("select * from x where e1 is null", new List[] {Arrays.asList(null,
3)}); //$NON-NLS-1$
+ }
+
+ @Test public void testInWithIndex() throws Exception {
+ execute("create local temporary table x (e1 string, e2 integer, primary key
(e1))", new List[] {Arrays.asList(0)}); //$NON-NLS-1$
+ execute("insert into x (e2, e1) values (3, 'a')", new List[]
{Arrays.asList(1)}); //$NON-NLS-1$
+ execute("insert into x (e2, e1) values (2, 'b')", new List[]
{Arrays.asList(1)}); //$NON-NLS-1$
+ execute("insert into x (e2, e1) values (1, 'c')", new List[]
{Arrays.asList(1)}); //$NON-NLS-1$
+ execute("insert into x (e2, e1) values (0, 'd')", new List[]
{Arrays.asList(1)}); //$NON-NLS-1$
+ execute("insert into x (e2, e1) values (-1, 'e')", new List[]
{Arrays.asList(1)}); //$NON-NLS-1$
+ execute("select * from x where e1 in ('a', 'c',
'e')", new List[] {Arrays.asList("a", 3),
Arrays.asList("c", 1), Arrays.asList("e", -1)}); //$NON-NLS-1$
+ }
+
}
Modified:
trunk/engine/src/test/java/org/teiid/query/processor/xml/TestXMLPlanningEnhancements.java
===================================================================
---
trunk/engine/src/test/java/org/teiid/query/processor/xml/TestXMLPlanningEnhancements.java 2010-07-27
23:06:31 UTC (rev 2381)
+++
trunk/engine/src/test/java/org/teiid/query/processor/xml/TestXMLPlanningEnhancements.java 2010-07-28
04:40:32 UTC (rev 2382)
@@ -454,7 +454,7 @@
ExecSqlInstruction instr = (ExecSqlInstruction)list.get(2);
- ProcessorPlan plan = (ProcessorPlan)instr.info.getPlan();
+ ProcessorPlan plan = instr.info.getPlan();
TestOptimizer.checkNodeTypes(plan, new int[] {
2, // Access
@@ -468,7 +468,7 @@
0, // Null
0, // PlanExecution
1, // Project
- 1, // Select
+ 0, // Select
0, // Sort
0 // UnionAll
});
@@ -494,7 +494,7 @@
ExecSqlInstruction instr = (ExecSqlInstruction)list.get(2);
- ProcessorPlan plan = (ProcessorPlan)instr.info.getPlan();
+ ProcessorPlan plan = instr.info.getPlan();
TestOptimizer.checkNodeTypes(plan, new int[] {
2, // Access
0, // DependentAccess
@@ -507,7 +507,7 @@
0, // Null
0, // PlanExecution
1, // Project
- 1, // Select
+ 0, // Select
0, // Sort
0 // UnionAll
});
Modified: trunk/engine/src/test/java/org/teiid/query/validator/TestValidator.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/validator/TestValidator.java 2010-07-27
23:06:31 UTC (rev 2381)
+++ trunk/engine/src/test/java/org/teiid/query/validator/TestValidator.java 2010-07-28
04:40:32 UTC (rev 2382)
@@ -1879,6 +1879,12 @@
@Test public void testSelectIntoWithNull() {
helpValidate("SELECT null, null, null, null INTO pm1.g1 FROM pm1.g2",
new String[] {}, FakeMetadataFactory.example1Cached()); //$NON-NLS-1$
}
+
+ @Test public void testCreateWithNonSortablePrimaryKey() {
+ QueryMetadataInterface metadata = FakeMetadataFactory.example1Cached();
+ Command command = helpResolve("create local temporary table x (column1
string, column2 clob, primary key (column2))", metadata); //$NON-NLS-1$
+ helpRunValidator(command, new String[] {"column2"},
FakeMetadataFactory.example1Cached());
+ }
@Test public void testDropNonTemporary() {
QueryMetadataInterface metadata = FakeMetadataFactory.example1Cached();