teiid SVN: r3012 - in trunk: common-core/src/main/java/org/teiid/core/types/basic and 5 other directories.
by teiid-commits@lists.jboss.org
Author: shawkins
Date: 2011-03-20 11:06:45 -0400 (Sun, 20 Mar 2011)
New Revision: 3012
Modified:
trunk/common-core/src/main/java/org/teiid/core/types/DataTypeManager.java
trunk/common-core/src/main/java/org/teiid/core/types/basic/BigIntegerToBigDecimalTransform.java
trunk/common-core/src/main/java/org/teiid/core/types/basic/FloatingNumberToBigDecimalTransform.java
trunk/common-core/src/main/java/org/teiid/core/types/basic/StringToBigDecimalTransform.java
trunk/engine/src/main/java/org/teiid/query/processor/relational/DependentValueSource.java
trunk/engine/src/main/java/org/teiid/query/rewriter/QueryRewriter.java
trunk/engine/src/main/java/org/teiid/query/sql/symbol/Constant.java
trunk/engine/src/test/java/org/teiid/query/function/TestFunction.java
trunk/test-integration/common/src/test/java/org/teiid/dqp/internal/process/TestTPCR.java
Log:
TEIID-1497 backing out teiidbigdecimal for a more targeted fix
Modified: trunk/common-core/src/main/java/org/teiid/core/types/DataTypeManager.java
===================================================================
--- trunk/common-core/src/main/java/org/teiid/core/types/DataTypeManager.java 2011-03-20 13:39:50 UTC (rev 3011)
+++ trunk/common-core/src/main/java/org/teiid/core/types/DataTypeManager.java 2011-03-20 15:06:45 UTC (rev 3012)
@@ -173,7 +173,7 @@
public static final Class<BigInteger> BIG_INTEGER = BigInteger.class;
public static final Class<Float> FLOAT = Float.class;
public static final Class<Double> DOUBLE = Double.class;
- public static final Class<? extends BigDecimal> BIG_DECIMAL = TeiidBigDecimal.class;
+ public static final Class<BigDecimal> BIG_DECIMAL = BigDecimal.class;
public static final Class<java.sql.Date> DATE = java.sql.Date.class;
public static final Class<Time> TIME = Time.class;
public static final Class<Timestamp> TIMESTAMP = Timestamp.class;
@@ -736,12 +736,6 @@
return new Timestamp(value.getTime());
}
});
- addSourceTransform(BigDecimal.class, new SourceTransform<BigDecimal, TeiidBigDecimal>() {
- @Override
- public TeiidBigDecimal transform(BigDecimal value) {
- return new TeiidBigDecimal(value);
- }
- });
}
public static Object convertToRuntimeType(Object value) {
Modified: trunk/common-core/src/main/java/org/teiid/core/types/basic/BigIntegerToBigDecimalTransform.java
===================================================================
--- trunk/common-core/src/main/java/org/teiid/core/types/basic/BigIntegerToBigDecimalTransform.java 2011-03-20 13:39:50 UTC (rev 3011)
+++ trunk/common-core/src/main/java/org/teiid/core/types/basic/BigIntegerToBigDecimalTransform.java 2011-03-20 15:06:45 UTC (rev 3012)
@@ -22,9 +22,9 @@
package org.teiid.core.types.basic;
+import java.math.BigDecimal;
import java.math.BigInteger;
-import org.teiid.core.types.TeiidBigDecimal;
import org.teiid.core.types.Transform;
import org.teiid.core.types.TransformationException;
import org.teiid.core.types.DataTypeManager.DefaultDataClasses;
@@ -41,7 +41,7 @@
* the transformation fails
*/
public Object transformDirect(Object value) throws TransformationException {
- return new TeiidBigDecimal((BigInteger) value, 0);
+ return new BigDecimal((BigInteger) value, 0);
}
/**
Modified: trunk/common-core/src/main/java/org/teiid/core/types/basic/FloatingNumberToBigDecimalTransform.java
===================================================================
--- trunk/common-core/src/main/java/org/teiid/core/types/basic/FloatingNumberToBigDecimalTransform.java 2011-03-20 13:39:50 UTC (rev 3011)
+++ trunk/common-core/src/main/java/org/teiid/core/types/basic/FloatingNumberToBigDecimalTransform.java 2011-03-20 15:06:45 UTC (rev 3012)
@@ -25,7 +25,6 @@
import java.math.BigDecimal;
import org.teiid.core.types.DataTypeManager;
-import org.teiid.core.types.TeiidBigDecimal;
import org.teiid.core.types.Transform;
import org.teiid.core.types.TransformationException;
@@ -49,7 +48,7 @@
public Object transformDirect(Object value) throws TransformationException {
BigDecimal result = BigDecimal.valueOf(((Number)value).doubleValue());
result = result.setScale(Math.max(result.scale(), (value instanceof Double ? 16 : 8) - result.precision()));
- return new TeiidBigDecimal(result);
+ return result;
}
/**
Modified: trunk/common-core/src/main/java/org/teiid/core/types/basic/StringToBigDecimalTransform.java
===================================================================
--- trunk/common-core/src/main/java/org/teiid/core/types/basic/StringToBigDecimalTransform.java 2011-03-20 13:39:50 UTC (rev 3011)
+++ trunk/common-core/src/main/java/org/teiid/core/types/basic/StringToBigDecimalTransform.java 2011-03-20 15:06:45 UTC (rev 3012)
@@ -22,8 +22,9 @@
package org.teiid.core.types.basic;
+import java.math.BigDecimal;
+
import org.teiid.core.CorePlugin;
-import org.teiid.core.types.TeiidBigDecimal;
import org.teiid.core.types.Transform;
import org.teiid.core.types.TransformationException;
import org.teiid.core.types.DataTypeManager.DefaultDataClasses;
@@ -41,7 +42,7 @@
*/
public Object transformDirect(Object value) throws TransformationException {
try {
- return new TeiidBigDecimal(((String)value).trim());
+ return new BigDecimal(((String)value).trim());
} catch(NumberFormatException e) {
throw new TransformationException("ERR.003.029.0014", CorePlugin.Util.getString("ERR.003.029.0014", value)); //$NON-NLS-1$ //$NON-NLS-2$
}
Modified: trunk/engine/src/main/java/org/teiid/query/processor/relational/DependentValueSource.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/processor/relational/DependentValueSource.java 2011-03-20 13:39:50 UTC (rev 3011)
+++ trunk/engine/src/main/java/org/teiid/query/processor/relational/DependentValueSource.java 2011-03-20 15:06:45 UTC (rev 3012)
@@ -26,13 +26,16 @@
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
+import java.util.TreeSet;
import org.teiid.common.buffer.IndexedTupleSource;
import org.teiid.common.buffer.TupleBuffer;
import org.teiid.core.TeiidComponentException;
import org.teiid.core.TeiidProcessingException;
+import org.teiid.core.types.DataTypeManager;
import org.teiid.core.util.Assertion;
import org.teiid.query.sql.symbol.Expression;
+import org.teiid.query.sql.symbol.SingleElementSymbol;
import org.teiid.query.sql.util.ValueIterator;
import org.teiid.query.sql.util.ValueIteratorSource;
@@ -83,7 +86,11 @@
index = buffer.getSchema().indexOf(valueExpression);
}
Assertion.assertTrue(index != -1);
- result = new HashSet<Object>();
+ if (((SingleElementSymbol)buffer.getSchema().get(index)).getType() == DataTypeManager.DefaultDataClasses.BIG_DECIMAL) {
+ result = new TreeSet<Object>();
+ } else {
+ result = new HashSet<Object>();
+ }
while (its.hasNext()) {
Object value = its.nextTuple().get(index);
if (value != null) {
Modified: trunk/engine/src/main/java/org/teiid/query/rewriter/QueryRewriter.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/rewriter/QueryRewriter.java 2011-03-20 13:39:50 UTC (rev 3011)
+++ trunk/engine/src/main/java/org/teiid/query/rewriter/QueryRewriter.java 2011-03-20 15:06:45 UTC (rev 3012)
@@ -2235,7 +2235,6 @@
criteria.setValues(newVals);
if (allConstants) {
criteria.setAllConstants(true);
- criteria.setValues(new LinkedHashSet(newVals));
}
if (size == 0) {
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 2011-03-20 13:39:50 UTC (rev 3011)
+++ trunk/engine/src/main/java/org/teiid/query/sql/symbol/Constant.java 2011-03-20 15:06:45 UTC (rev 3012)
@@ -22,6 +22,7 @@
package org.teiid.query.sql.symbol;
+import java.math.BigDecimal;
import java.util.List;
import org.teiid.core.types.DataTypeManager;
@@ -153,6 +154,16 @@
if(! other.getType().equals(this.getType())) {
return false;
}
+
+ if (this.value instanceof BigDecimal) {
+ if (this.value == other.value) {
+ return true;
+ }
+ if (!(other.value instanceof BigDecimal)) {
+ return false;
+ }
+ return ((BigDecimal)this.value).compareTo((BigDecimal)other.value) == 0;
+ }
return multiValued == other.multiValued && other.getValue().equals(this.getValue());
}
@@ -163,6 +174,14 @@
*/
public int hashCode() {
if(this.value != null) {
+ if (this.value instanceof BigDecimal) {
+ BigDecimal bd = (BigDecimal)this.value;
+ int xsign = bd.signum();
+ if (xsign == 0)
+ return 0;
+ bd = bd.stripTrailingZeros();
+ return bd.hashCode();
+ }
return this.value.hashCode();
}
return 0;
Modified: trunk/engine/src/test/java/org/teiid/query/function/TestFunction.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/function/TestFunction.java 2011-03-20 13:39:50 UTC (rev 3011)
+++ trunk/engine/src/test/java/org/teiid/query/function/TestFunction.java 2011-03-20 15:06:45 UTC (rev 3012)
@@ -34,7 +34,6 @@
import org.junit.Test;
import org.teiid.api.exception.query.FunctionExecutionException;
-import org.teiid.core.types.TeiidBigDecimal;
import org.teiid.language.SQLConstants.NonReserved;
import org.teiid.query.sql.symbol.Constant;
import org.teiid.query.unittest.TimestampUtil;
@@ -471,7 +470,7 @@
}
@Test public void testConvertBigDecimalBigInteger() throws Exception {
- helpConvert(new TeiidBigDecimal("1.0"), "biginteger", new BigInteger("1")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ helpConvert(new BigDecimal("1.0"), "biginteger", new BigInteger("1")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
@Test public void testConvertDoubleLong() throws Exception {
Modified: trunk/test-integration/common/src/test/java/org/teiid/dqp/internal/process/TestTPCR.java
===================================================================
--- trunk/test-integration/common/src/test/java/org/teiid/dqp/internal/process/TestTPCR.java 2011-03-20 13:39:50 UTC (rev 3011)
+++ trunk/test-integration/common/src/test/java/org/teiid/dqp/internal/process/TestTPCR.java 2011-03-20 15:06:45 UTC (rev 3012)
@@ -191,7 +191,7 @@
ProcessorPlan plan = TestOptimizer.helpPlan("SELECT custsale.cntrycode, COUNT(*) AS numcust, SUM(c_acctbal) AS totacctbal FROM (SELECT left(C_PHONE, 2) AS cntrycode, CUSTOMER.C_ACCTBAL FROM CUSTOMER WHERE (left(C_PHONE, 2) IN ('13','31','23','29','30','18','17')) AND (CUSTOMER.C_ACCTBAL > (SELECT AVG(CUSTOMER.C_ACCTBAL) FROM CUSTOMER WHERE (CUSTOMER.C_ACCTBAL > 0.0) AND (left(C_PHONE, 2) IN ('13','31','23','29','30','18','17')))) AND (NOT (EXISTS (SELECT * FROM ORDERS WHERE O_CUSTKEY = C_CUSTKEY)))) AS custsale GROUP BY custsale.cntrycode ORDER BY custsale.cntrycode", //$NON-NLS-1$
METADATA, null, finder,
- new String[] {"SELECT v_0.c_0, COUNT(*) AS c_1, SUM(v_0.c_1) AS c_2 FROM (SELECT left(g_0.C_PHONE, 2) AS c_0, g_0.C_ACCTBAL AS c_1 FROM TPCR_Oracle_9i.CUSTOMER AS g_0 WHERE (left(g_0.C_PHONE, 2) IN ('13', '17', '18', '23', '29', '30', '31')) AND (g_0.C_ACCTBAL > (SELECT AVG(g_1.C_ACCTBAL) FROM TPCR_Oracle_9i.CUSTOMER AS g_1 WHERE (g_1.C_ACCTBAL > 0E-15) AND (left(g_1.C_PHONE, 2) IN ('13', '17', '18', '23', '29', '30', '31')))) AND (NOT EXISTS (SELECT 1 FROM TPCR_Oracle_9i.ORDERS AS g_2 WHERE g_2.O_CUSTKEY = g_0.C_CUSTKEY))) AS v_0 GROUP BY v_0.c_0 ORDER BY c_0 NULLS FIRST"}, ComparisonMode.EXACT_COMMAND_STRING); //$NON-NLS-1$
+ new String[] {"SELECT v_0.c_0, COUNT(*) AS c_1, SUM(v_0.c_1) AS c_2 FROM (SELECT left(g_0.C_PHONE, 2) AS c_0, g_0.C_ACCTBAL AS c_1 FROM TPCR_Oracle_9i.CUSTOMER AS g_0 WHERE (left(g_0.C_PHONE, 2) IN ('13', '31', '23', '29', '30', '18', '17')) AND (g_0.C_ACCTBAL > (SELECT AVG(g_1.C_ACCTBAL) FROM TPCR_Oracle_9i.CUSTOMER AS g_1 WHERE (g_1.C_ACCTBAL > 0E-15) AND (left(g_1.C_PHONE, 2) IN ('13', '31', '23', '29', '30', '18', '17')))) AND (NOT EXISTS (SELECT 1 FROM TPCR_Oracle_9i.ORDERS AS g_2 WHERE g_2.O_CUSTKEY = g_0.C_CUSTKEY))) AS v_0 GROUP BY v_0.c_0 ORDER BY c_0 NULLS FIRST"}, ComparisonMode.EXACT_COMMAND_STRING); //$NON-NLS-1$
TestOptimizer.checkNodeTypes(plan, TestOptimizer.FULL_PUSHDOWN);
}
13 years, 9 months
teiid SVN: r3011 - in trunk: build/kits/jboss-container and 17 other directories.
by teiid-commits@lists.jboss.org
Author: shawkins
Date: 2011-03-20 09:39:50 -0400 (Sun, 20 Mar 2011)
New Revision: 3011
Added:
trunk/common-core/src/main/java/org/teiid/core/types/TeiidBigDecimal.java
Modified:
trunk/api/src/main/java/org/teiid/translator/TypeFacility.java
trunk/build/kits/jboss-container/teiid-releasenotes.html
trunk/common-core/src/main/java/org/teiid/core/types/DataTypeManager.java
trunk/common-core/src/main/java/org/teiid/core/types/basic/BigDecimalToBigIntegerTransform.java
trunk/common-core/src/main/java/org/teiid/core/types/basic/BigIntegerToBigDecimalTransform.java
trunk/common-core/src/main/java/org/teiid/core/types/basic/FloatingNumberToBigDecimalTransform.java
trunk/common-core/src/main/java/org/teiid/core/types/basic/StringToBigDecimalTransform.java
trunk/documentation/admin-guide/src/main/docbook/en-US/content/appendix-c.xml
trunk/documentation/reference/src/main/docbook/en-US/content/federated_planning.xml
trunk/documentation/reference/src/main/docbook/en-US/content/sql_support.xml
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/PartitionAnalyzer.java
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleMergeCriteria.java
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushSelectCriteria.java
trunk/engine/src/main/java/org/teiid/query/parser/SQLParserUtil.java
trunk/engine/src/main/java/org/teiid/query/processor/relational/DependentValueSource.java
trunk/engine/src/main/java/org/teiid/query/rewriter/QueryRewriter.java
trunk/engine/src/main/java/org/teiid/query/sql/lang/ExistsCriteria.java
trunk/engine/src/main/java/org/teiid/query/sql/lang/SetCriteria.java
trunk/engine/src/main/java/org/teiid/query/sql/lang/SubquerySetCriteria.java
trunk/engine/src/main/java/org/teiid/query/sql/visitor/EvaluatableVisitor.java
trunk/engine/src/main/java/org/teiid/query/sql/visitor/SQLStringVisitor.java
trunk/engine/src/main/java/org/teiid/query/tempdata/IndexInfo.java
trunk/engine/src/main/javacc/org/teiid/query/parser/SQLParser.jj
trunk/engine/src/test/java/org/teiid/query/function/TestFunction.java
trunk/engine/src/test/java/org/teiid/query/function/TestFunctionLibrary.java
trunk/engine/src/test/java/org/teiid/query/optimizer/TestSubqueryPushdown.java
trunk/engine/src/test/java/org/teiid/query/parser/TestOptionsAndHints.java
trunk/engine/src/test/java/org/teiid/query/parser/TestParser.java
trunk/engine/src/test/java/org/teiid/query/rewriter/TestQueryRewriter.java
Log:
TEIID-1497 adding the no_unnest hint and a system property to control the default subquery unnesting. also adding a better runtime type for bigdecimal.
Modified: trunk/api/src/main/java/org/teiid/translator/TypeFacility.java
===================================================================
--- trunk/api/src/main/java/org/teiid/translator/TypeFacility.java 2011-03-19 14:32:44 UTC (rev 3010)
+++ trunk/api/src/main/java/org/teiid/translator/TypeFacility.java 2011-03-20 13:39:50 UTC (rev 3011)
@@ -53,7 +53,7 @@
public static final Class<BigInteger> BIG_INTEGER = DataTypeManager.DefaultDataClasses.BIG_INTEGER;
public static final Class<Float> FLOAT = DataTypeManager.DefaultDataClasses.FLOAT;
public static final Class<Double> DOUBLE = DataTypeManager.DefaultDataClasses.DOUBLE;
- public static final Class<BigDecimal> BIG_DECIMAL = DataTypeManager.DefaultDataClasses.BIG_DECIMAL;
+ public static final Class<? extends BigDecimal> BIG_DECIMAL = DataTypeManager.DefaultDataClasses.BIG_DECIMAL;
public static final Class<java.sql.Date> DATE = DataTypeManager.DefaultDataClasses.DATE;
public static final Class<Time> TIME = DataTypeManager.DefaultDataClasses.TIME;
public static final Class<Timestamp> TIMESTAMP = DataTypeManager.DefaultDataClasses.TIMESTAMP;
Modified: trunk/build/kits/jboss-container/teiid-releasenotes.html
===================================================================
--- trunk/build/kits/jboss-container/teiid-releasenotes.html 2011-03-19 14:32:44 UTC (rev 3010)
+++ trunk/build/kits/jboss-container/teiid-releasenotes.html 2011-03-20 13:39:50 UTC (rev 3011)
@@ -42,6 +42,7 @@
<LI><B>userRequestSourceConcurrency</B> - was added to control the number of concurrent source queries allowed for each user request.
<LI><B>Dependent Join Improvements</B> - dependent join analysis and costing in general was improved to consider dependent joins earlier in planning.
<LI><B>Memory Management Improvements</B> - maxReserveBatchColumns and maxProcessingBatchesColumns will be default be determined automatically and will more reliably prevent memory issues. See the admin guide for more.
+ <LI><B>Subquery optimization control</B> - added the MJ and NO_UNNEST hints and the org.teiid.subqueryUnnestDefault system property to control the optimization of subqueries to traditional joins or to a merge join implemenation of a semijoin or antijoin.
</UL>
<h2><a name="Compatibility">Compatibility Issues</a></h2>
@@ -153,6 +154,7 @@
<h2><a name="Other">Other Issues</a></h2>
<ul>
+ <li>TEIID-1170 - correlated subqueries are not allowed in UPDATEs or DELETEs against internal Teiid tables (internal materialized views or temporary tables).
<li>TEIID-1281 - Negative start indexing is not supported by DB2 and Derby databases. Usage of the Teiid SUBSTRING against these sources should not use negative start values.
<li>TEIID-1008 - Most versions of Oracle and MySQL do not support deeply nested correlated references. There is currently no workaround for this issue.
<li>For compatibility with the 7.0 release if a stored procedure parameter list begins with identifier=, then it will be parsed as a named parameter invocation even if the intent was to use a comparison predicate
Modified: trunk/common-core/src/main/java/org/teiid/core/types/DataTypeManager.java
===================================================================
--- trunk/common-core/src/main/java/org/teiid/core/types/DataTypeManager.java 2011-03-19 14:32:44 UTC (rev 3010)
+++ trunk/common-core/src/main/java/org/teiid/core/types/DataTypeManager.java 2011-03-20 13:39:50 UTC (rev 3011)
@@ -173,7 +173,7 @@
public static final Class<BigInteger> BIG_INTEGER = BigInteger.class;
public static final Class<Float> FLOAT = Float.class;
public static final Class<Double> DOUBLE = Double.class;
- public static final Class<BigDecimal> BIG_DECIMAL = BigDecimal.class;
+ public static final Class<? extends BigDecimal> BIG_DECIMAL = TeiidBigDecimal.class;
public static final Class<java.sql.Date> DATE = java.sql.Date.class;
public static final Class<Time> TIME = Time.class;
public static final Class<Timestamp> TIMESTAMP = Timestamp.class;
@@ -201,14 +201,14 @@
}
/** Base data type names and classes, Type name --> Type class */
- private static Map<String, Class> dataTypeNames = new LinkedHashMap<String, Class>(128);
+ private static Map<String, Class<?>> dataTypeNames = new LinkedHashMap<String, Class<?>>(128);
/** Base data type names and classes, Type class --> Type name */
- private static Map<Class, String> dataTypeClasses = new LinkedHashMap<Class, String>(128);
+ private static Map<Class<?>, String> dataTypeClasses = new LinkedHashMap<Class<?>, String>(128);
private static Set<String> DATA_TYPE_NAMES;
- private static Set<Class> DATA_TYPE_CLASSES = Collections.unmodifiableSet(dataTypeClasses.keySet());
+ private static Set<Class<?>> DATA_TYPE_CLASSES = Collections.unmodifiableSet(dataTypeClasses.keySet());
private static Map<Class<?>, SourceTransform> sourceConverters = new HashMap<Class<?>, SourceTransform>();
@@ -251,7 +251,7 @@
return DATA_TYPE_NAMES;
}
- public static Set<Class> getAllDataTypeClasses() {
+ public static Set<Class<?>> getAllDataTypeClasses() {
return DATA_TYPE_CLASSES;
}
@@ -736,6 +736,12 @@
return new Timestamp(value.getTime());
}
});
+ addSourceTransform(BigDecimal.class, new SourceTransform<BigDecimal, TeiidBigDecimal>() {
+ @Override
+ public TeiidBigDecimal transform(BigDecimal value) {
+ return new TeiidBigDecimal(value);
+ }
+ });
}
public static Object convertToRuntimeType(Object value) {
Added: trunk/common-core/src/main/java/org/teiid/core/types/TeiidBigDecimal.java
===================================================================
--- trunk/common-core/src/main/java/org/teiid/core/types/TeiidBigDecimal.java (rev 0)
+++ trunk/common-core/src/main/java/org/teiid/core/types/TeiidBigDecimal.java 2011-03-20 13:39:50 UTC (rev 3011)
@@ -0,0 +1,68 @@
+/*
+ * 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.core.types;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+/**
+ * Same as a regular BigDecimal, but changes the implementation of hashCode and equals
+ * so that the same numerical value regardless of scale will be equal
+ */
+public class TeiidBigDecimal extends BigDecimal {
+
+ private static final long serialVersionUID = -5796515987947436480L;
+
+ public TeiidBigDecimal(BigInteger unscaled, int scale) {
+ super(unscaled, scale);
+ }
+
+ public TeiidBigDecimal(BigDecimal bigDecimal) {
+ this(bigDecimal.unscaledValue(), bigDecimal.scale());
+ }
+
+ public TeiidBigDecimal(String val) {
+ super(val);
+ }
+
+ @Override
+ public int hashCode() {
+ int xsign = this.signum();
+ if (xsign == 0)
+ return 0;
+ BigDecimal bd = this.stripTrailingZeros();
+ return bd.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object x) {
+ if (x == this) {
+ return true;
+ }
+ if (!(x instanceof BigDecimal)) {
+ return false;
+ }
+ return this.compareTo((BigDecimal)x) == 0;
+ }
+
+}
Property changes on: trunk/common-core/src/main/java/org/teiid/core/types/TeiidBigDecimal.java
___________________________________________________________________
Added: svn:mime-type
+ text/plain
Modified: trunk/common-core/src/main/java/org/teiid/core/types/basic/BigDecimalToBigIntegerTransform.java
===================================================================
--- trunk/common-core/src/main/java/org/teiid/core/types/basic/BigDecimalToBigIntegerTransform.java 2011-03-19 14:32:44 UTC (rev 3010)
+++ trunk/common-core/src/main/java/org/teiid/core/types/basic/BigDecimalToBigIntegerTransform.java 2011-03-20 13:39:50 UTC (rev 3011)
@@ -23,10 +23,10 @@
package org.teiid.core.types.basic;
import java.math.BigDecimal;
-import java.math.BigInteger;
import org.teiid.core.types.Transform;
import org.teiid.core.types.TransformationException;
+import org.teiid.core.types.DataTypeManager.DefaultDataClasses;
public class BigDecimalToBigIntegerTransform extends Transform {
@@ -47,16 +47,16 @@
* Type of the incoming value.
* @return Source type
*/
- public Class getSourceType() {
- return BigDecimal.class;
+ public Class<?> getSourceType() {
+ return DefaultDataClasses.BIG_DECIMAL;
}
/**
* Type of the outgoing value.
* @return Target type
*/
- public Class getTargetType() {
- return BigInteger.class;
+ public Class<?> getTargetType() {
+ return DefaultDataClasses.BIG_INTEGER;
}
public boolean isExplicit() {
Modified: trunk/common-core/src/main/java/org/teiid/core/types/basic/BigIntegerToBigDecimalTransform.java
===================================================================
--- trunk/common-core/src/main/java/org/teiid/core/types/basic/BigIntegerToBigDecimalTransform.java 2011-03-19 14:32:44 UTC (rev 3010)
+++ trunk/common-core/src/main/java/org/teiid/core/types/basic/BigIntegerToBigDecimalTransform.java 2011-03-20 13:39:50 UTC (rev 3011)
@@ -22,11 +22,12 @@
package org.teiid.core.types.basic;
-import java.math.BigDecimal;
import java.math.BigInteger;
+import org.teiid.core.types.TeiidBigDecimal;
import org.teiid.core.types.Transform;
import org.teiid.core.types.TransformationException;
+import org.teiid.core.types.DataTypeManager.DefaultDataClasses;
public class BigIntegerToBigDecimalTransform extends Transform {
@@ -40,23 +41,23 @@
* the transformation fails
*/
public Object transformDirect(Object value) throws TransformationException {
- return new BigDecimal((BigInteger) value);
+ return new TeiidBigDecimal((BigInteger) value, 0);
}
/**
* Type of the incoming value.
* @return Source type
*/
- public Class getSourceType() {
- return BigInteger.class;
+ public Class<?> getSourceType() {
+ return DefaultDataClasses.BIG_INTEGER;
}
/**
* Type of the outgoing value.
* @return Target type
*/
- public Class getTargetType() {
- return BigDecimal.class;
+ public Class<?> getTargetType() {
+ return DefaultDataClasses.BIG_DECIMAL;
}
}
Modified: trunk/common-core/src/main/java/org/teiid/core/types/basic/FloatingNumberToBigDecimalTransform.java
===================================================================
--- trunk/common-core/src/main/java/org/teiid/core/types/basic/FloatingNumberToBigDecimalTransform.java 2011-03-19 14:32:44 UTC (rev 3010)
+++ trunk/common-core/src/main/java/org/teiid/core/types/basic/FloatingNumberToBigDecimalTransform.java 2011-03-20 13:39:50 UTC (rev 3011)
@@ -25,6 +25,7 @@
import java.math.BigDecimal;
import org.teiid.core.types.DataTypeManager;
+import org.teiid.core.types.TeiidBigDecimal;
import org.teiid.core.types.Transform;
import org.teiid.core.types.TransformationException;
@@ -48,7 +49,7 @@
public Object transformDirect(Object value) throws TransformationException {
BigDecimal result = BigDecimal.valueOf(((Number)value).doubleValue());
result = result.setScale(Math.max(result.scale(), (value instanceof Double ? 16 : 8) - result.precision()));
- return result;
+ return new TeiidBigDecimal(result);
}
/**
Modified: trunk/common-core/src/main/java/org/teiid/core/types/basic/StringToBigDecimalTransform.java
===================================================================
--- trunk/common-core/src/main/java/org/teiid/core/types/basic/StringToBigDecimalTransform.java 2011-03-19 14:32:44 UTC (rev 3010)
+++ trunk/common-core/src/main/java/org/teiid/core/types/basic/StringToBigDecimalTransform.java 2011-03-20 13:39:50 UTC (rev 3011)
@@ -22,11 +22,11 @@
package org.teiid.core.types.basic;
-import java.math.BigDecimal;
-
import org.teiid.core.CorePlugin;
+import org.teiid.core.types.TeiidBigDecimal;
import org.teiid.core.types.Transform;
import org.teiid.core.types.TransformationException;
+import org.teiid.core.types.DataTypeManager.DefaultDataClasses;
public class StringToBigDecimalTransform extends Transform {
@@ -41,7 +41,7 @@
*/
public Object transformDirect(Object value) throws TransformationException {
try {
- return new BigDecimal(((String)value).trim());
+ return new TeiidBigDecimal(((String)value).trim());
} catch(NumberFormatException e) {
throw new TransformationException("ERR.003.029.0014", CorePlugin.Util.getString("ERR.003.029.0014", value)); //$NON-NLS-1$ //$NON-NLS-2$
}
@@ -51,16 +51,16 @@
* Type of the incoming value.
* @return Source type
*/
- public Class getSourceType() {
- return String.class;
+ public Class<?> getSourceType() {
+ return DefaultDataClasses.STRING;
}
/**
* Type of the outgoing value.
* @return Target type
*/
- public Class getTargetType() {
- return BigDecimal.class;
+ public Class<?> getTargetType() {
+ return DefaultDataClasses.BIG_DECIMAL;
}
@Override
Modified: trunk/documentation/admin-guide/src/main/docbook/en-US/content/appendix-c.xml
===================================================================
--- trunk/documentation/admin-guide/src/main/docbook/en-US/content/appendix-c.xml 2011-03-19 14:32:44 UTC (rev 3010)
+++ trunk/documentation/admin-guide/src/main/docbook/en-US/content/appendix-c.xml 2011-03-20 13:39:50 UTC (rev 3011)
@@ -24,5 +24,11 @@
expected by the SQL specification.
</para>
</listitem>
+ <listitem id="subquery_unnest">
+ <para><emphasis>org.teiid.subqueryUnnestDefault</emphasis> - defaults to false.
+ Set to true to aggressively unnest subquery IN and EXISTS predicates. If possible the predicate will be unnested to a traditional join and will be eligible for dependent join planning.
+ If a traditional join is not possible (such as with NOT IN) a merge join version of the semijoin or antijoin will be considered by upon the costing information available.
+ </para>
+ </listitem>
</itemizedlist>
</appendix>
\ No newline at end of file
Modified: trunk/documentation/reference/src/main/docbook/en-US/content/federated_planning.xml
===================================================================
--- trunk/documentation/reference/src/main/docbook/en-US/content/federated_planning.xml 2011-03-19 14:32:44 UTC (rev 3010)
+++ trunk/documentation/reference/src/main/docbook/en-US/content/federated_planning.xml 2011-03-20 13:39:50 UTC (rev 3011)
@@ -262,7 +262,7 @@
</para>
</tip>
<warning><para>
- A simple SELECT COUNT(*) ... against a view where all join tables are marked as optional will not return a meaningful result.
+ A simple "SELECT COUNT(*) FROM VIEW" against a view where all join tables are marked as optional will not return a meaningful result.
</para>
</warning>
</section>
@@ -305,11 +305,60 @@
<listitem>
<para>Parallelizing of source access during execution.</para>
</listitem>
+ <listitem>
+ <para><xref linkend="subquery_optimization"/></para>
+ </listitem>
</itemizedlist>
</para>
</section>
</section>
- <section>
+ <section id="subquery_optimization">
+ <title>Subquery optimization</title>
+ <itemizedlist>
+ <listitem>
+ <para>EXISTS subqueries are typically rewrite to "SELECT 1 FROM ..." to prevent unnecessary evaluation of SELECT expressions.</para>
+ </listitem>
+ <listitem>
+ <para>Quantified compare SOME subqueries are always turned into an equivalent IN prediate or comparison against an aggregate value. e.g. col > SOME (select col1 from table) would become col > (select min(col1) from table)</para>
+ </listitem>
+ <listitem>
+ <para>Uncorrelated EXISTs and scalar subquery that are not pushed to the source can be preevaluated prior to source command formation.</para>
+ </listitem>
+ <listitem>
+ <para>Correlated subqueries used in DETELEs or UPDATEs that are not pushed as part of the corresponding DELETE/UPDATE will cause Teiid to perform row-by-row compensating processing.
+ This will only happen if the affected table has a primary key. If it does not, then an exception will be thrown.</para>
+ </listitem>
+ <listitem>
+ <para>WHERE or HAVING clause IN and EXISTs predicates can take the MJ (merge join) or NO_UNNEST (no unnest) hints appearing just before the subquery.
+ The MJ hint directs the optimizer to use a traditional, semijoin, or antisemijoin merge join if possible.
+ The NO_UNNEST hint, which supercedes the MJ hint, will direct the optimizer to leave the subquery in place.
+ <example>
+ <title>Merge Join Hint Usage</title>
+ <programlisting language="SQL">SELECT col1 from tbl where col2 IN /*+ MJ */ (SELECT col1 FROM tbl2)</programlisting>
+ </example>
+ <example>
+ <title>No Unnest Hint Usage</title>
+ <programlisting language="SQL">SELECT col1 from tbl where col2 IN /*+ NO_UNNEST */ (SELECT col1 FROM tbl2)</programlisting>
+ </example>
+ </para>
+ </listitem>
+ <listitem>
+ <para>The system property <link linkend="subquery_unnest">org.teiid.subqueryUnnestDefault</link> controls whether the optimizer will by default unnest subqueries.
+ The default is false. If true, then most non-negated WHERE or HAVING clause non-negated EXISTS or IN subquery predicates can be converted to a traditional merge join or as antijoin or semijoin variants.</para>
+ </listitem>
+ <listitem>
+ <para>WHERE clause EXISTs and IN predicates that can be rewriten to a traditional join with the semantics of the semi-join can preserved
+ if the system property <link linkend="subquery_unnest">org.teiid.subqueryUnnestDefault</link> is set to true or the subquery has a MJ hint.</para>
+ </listitem>
+ <listitem>
+ <para>EXISTs and scalar subqueries that are not pushed down, and not converted to merge joins, are implicitly limited to 1 and 2 result rows respectively.</para>
+ </listitem>
+ <listitem>
+ <para>Conversion of subquery predicates to nested loop joins is not yet available.</para>
+ </listitem>
+ </itemizedlist>
+ </section>
+ <section>
<title>Federated Failure Modes</title>
<section>
<title>Partial Results</title>
Modified: trunk/documentation/reference/src/main/docbook/en-US/content/sql_support.xml
===================================================================
--- trunk/documentation/reference/src/main/docbook/en-US/content/sql_support.xml 2011-03-19 14:32:44 UTC (rev 3010)
+++ trunk/documentation/reference/src/main/docbook/en-US/content/sql_support.xml 2011-03-20 13:39:50 UTC (rev 3011)
@@ -800,6 +800,7 @@
<listitem><para>FROM <link linkend="texttable">TEXTTABLE...</link></para></listitem>
<listitem><para>FROM <link linkend="xmltable">XMLTABLE...</link></para></listitem>
<listitem><para>FROM <link linkend="arraytable">ARRAYTABLE...</link></para></listitem>
+ <listitem><para>FROM <link linkend="from_subquery">(SELECT ...</link></para></listitem>
</itemizedlist>
<note>
<title>DEP Hints</title>
@@ -1256,47 +1257,34 @@
</para>
</listitem>
</itemizedlist>
- <itemizedlist>
- <para>Supported subquery locations:
- </para>
- <listitem>
- <para><link linkend="from_subquery">Subqueries in the FROM clause</link></para>
- </listitem>
- <listitem>
- <para><link linkend="where_subquery">Subqueries in the WHERE/HAVING Clauses</link></para>
- </listitem>
- <listitem>
- <para>Subqueries may be used in any expression or CASE CRITERIA in the SELECT clasue.</para>
- </listitem>
- </itemizedlist>
<section id="from_subquery">
<title>Inline views</title>
- <para> Subqueries in the FROM clause of the outer query (also known as
+ <para>Subqueries in the FROM clause of the outer query (also known as
"inline views") can return any number of rows and columns. This type
- of subquery must always be given an alias.</para>
+ of subquery must always be given an alias. An inline view is nearly identical to a traditional view. See also <xref linkend="with_clause"/>.</para>
<example>
<title>Example Subquery in FROM Clause (Inline View)</title>
- <programlisting>SELECT a FROM (SELECT Y.b, Y.c FROM Y WHERE Y.d = ‘3’) AS X WHERE a = X.c AND b = X.b</programlisting>
+ <programlisting language="SQL">SELECT a FROM (SELECT Y.b, Y.c FROM Y WHERE Y.d = ‘3’) AS X WHERE a = X.c AND b = X.b</programlisting>
</example>
</section>
- <section id="where_subquery">
- <title>Subqueries in the WHERE and HAVING clauses</title>
- <para>Subqueries supported in the criteria of the outer query include subqueries in an IN clause, subqueries using the ANY/SOME or ALL predicate quantifier, and subqueries using the EXISTS predicate. </para>
+ <section id="other_subqueries">
+ <title>Subqueries can appear anywhere where an expression or criteria is expected.</title>
+ <para>Subqueries are supported in quantified criteria, the EXISTS predicate, the IN predicate, and as <xref linkend="scalar_subqueries"/>.</para>
<example>
<title>Example Subquery in WHERE Using EXISTS</title>
<programlisting>SELECT a FROM X WHERE EXISTS (SELECT 1 FROM Y WHERE c=X.a)</programlisting>
</example>
- <note><para>EXISTS subqueries should typically follow the convention "SELECT 1 FROM ..." to prevent unnecessary evaluation of select expressions.</para></note>
- <para>
- The following usages of subqueries must each select only one column, but can return any number of rows.
- </para>
<example>
- <title>Example Subqueries in WHERE Clause</title>
- <programlisting>SELECT a FROM X WHERE a IN (SELECT b FROM Y WHERE c=3)
-SELECT a FROM X WHERE a >= ANY (SELECT b FROM Y WHERE c=3)
+ <title>Example Quantified Comparison Subqueries</title>
+ <programlisting language="SQL">SELECT a FROM X WHERE a >= ANY (SELECT b FROM Y WHERE c=3)
SELECT a FROM X WHERE a < SOME (SELECT b FROM Y WHERE c=4)
SELECT a FROM X WHERE a = ALL (SELECT b FROM Y WHERE c=2)</programlisting>
</example>
+ <example>
+ <title>Example IN Subquery</title>
+ <programlisting language="SQL">SELECT a FROM X WHERE a IN (SELECT b FROM Y WHERE c=3)</programlisting>
+ </example>
+ <para>See also <xref linkend="subquery_optimization"/>.</para>
</section>
</section>
</chapter>
\ No newline at end of file
Modified: trunk/engine/src/main/java/org/teiid/query/optimizer/relational/PartitionAnalyzer.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/optimizer/relational/PartitionAnalyzer.java 2011-03-19 14:32:44 UTC (rev 3010)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/PartitionAnalyzer.java 2011-03-20 13:39:50 UTC (rev 3011)
@@ -27,13 +27,13 @@
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
-import java.util.TreeSet;
import org.teiid.core.types.DataTypeManager;
import org.teiid.query.sql.lang.CompareCriteria;
@@ -124,9 +124,9 @@
continue;
}
if (cc.getLeftExpression() instanceof Constant) {
- inMap.put(cc.getRightExpression(), new TreeSet<Constant>(Arrays.asList((Constant)cc.getLeftExpression())));
+ inMap.put(cc.getRightExpression(), new HashSet<Constant>(Arrays.asList((Constant)cc.getLeftExpression())));
} else if (cc.getRightExpression() instanceof Constant) {
- inMap.put(cc.getLeftExpression(), new TreeSet<Constant>(Arrays.asList((Constant)cc.getRightExpression())));
+ inMap.put(cc.getLeftExpression(), new HashSet<Constant>(Arrays.asList((Constant)cc.getRightExpression())));
}
continue;
}
@@ -134,7 +134,7 @@
continue;
}
SetCriteria sc = (SetCriteria)criteria;
- TreeSet<Constant> values = new TreeSet<Constant>();
+ HashSet<Constant> values = new HashSet<Constant>();
boolean allConstants = true;
for (Expression exp : (Collection<Expression>)sc.getValues()) {
if (exp instanceof Constant) {
Modified: trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleMergeCriteria.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleMergeCriteria.java 2011-03-19 14:32:44 UTC (rev 3010)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleMergeCriteria.java 2011-03-20 13:39:50 UTC (rev 3011)
@@ -86,6 +86,9 @@
public final class RuleMergeCriteria implements OptimizerRule {
+ public static final String UNNEST_DEFAULT = "org.teiid.subqueryUnnestDefault"; //$NON-NLS-1$
+ private final boolean UNNEST = Boolean.getBoolean(UNNEST_DEFAULT);
+
/**
* Used to replace correlated references
*/
@@ -104,6 +107,11 @@
Reference r = (Reference)element;
Expression ex = refs.getMappedExpression(r.getExpression());
if (ex != null) {
+ if (ex instanceof ElementSymbol) {
+ ElementSymbol es = (ElementSymbol) ex.clone();
+ es.setIsExternalReference(false);
+ ex = es;
+ }
replacedAny = true;
return ex;
}
@@ -122,6 +130,7 @@
public Criteria additionalCritieria;
public Class<?> type;
public boolean mergeJoin;
+ public boolean madeDistinct;
}
private IDGenerator idGenerator;
@@ -348,11 +357,20 @@
if (crit instanceof SubquerySetCriteria) {
//convert to the quantified form
SubquerySetCriteria ssc = (SubquerySetCriteria)crit;
+ if (ssc.getSubqueryHint().isNoUnnest()) {
+ return result;
+ }
result.not ^= ssc.isNegated();
result.type = crit.getClass();
- result.mergeJoin = ssc.isMergeJoin();
+ result.mergeJoin = ssc.getSubqueryHint().isMergeJoin();
+ if (!UNNEST && !result.mergeJoin) {
+ return result;
+ }
crit = new SubqueryCompareCriteria(ssc.getExpression(), ssc.getCommand(), SubqueryCompareCriteria.EQ, SubqueryCompareCriteria.SOME);
} else if (crit instanceof CompareCriteria) {
+ if (!UNNEST) {
+ return result;
+ }
//convert to the quantified form
CompareCriteria cc = (CompareCriteria)crit;
if (cc.getRightExpression() instanceof ScalarSubquery) {
@@ -369,7 +387,7 @@
}
if (crit instanceof SubqueryCompareCriteria) {
SubqueryCompareCriteria scc = (SubqueryCompareCriteria)crit;
-
+
if (scc.getPredicateQuantifier() != SubqueryCompareCriteria.SOME
//TODO: could add an inline view if not a query
|| !(scc.getCommand() instanceof Query)) {
@@ -390,6 +408,9 @@
}
if (crit instanceof ExistsCriteria) {
ExistsCriteria exists = (ExistsCriteria)crit;
+ if (exists.getSubqueryHint().isNoUnnest()) {
+ return result;
+ }
if (!(exists.getCommand() instanceof Query)) {
return result;
}
@@ -397,7 +418,10 @@
result.not = exists.isNegated();
//the correlations can only be in where (if no group by or aggregates) or having
result.query = (Query)exists.getCommand();
- result.mergeJoin = exists.isMergeJoin();
+ result.mergeJoin = exists.getSubqueryHint().isMergeJoin();
+ if (!UNNEST && !result.mergeJoin) {
+ return result;
+ }
}
return result;
}
@@ -495,6 +519,7 @@
return false;
}
plannedResult.query.getSelect().setDistinct(true);
+ plannedResult.madeDistinct = true;
}
if (addGroupBy) {
Modified: trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushSelectCriteria.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushSelectCriteria.java 2011-03-19 14:32:44 UTC (rev 3010)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushSelectCriteria.java 2011-03-20 13:39:50 UTC (rev 3011)
@@ -33,7 +33,6 @@
import org.teiid.api.exception.query.QueryMetadataException;
import org.teiid.api.exception.query.QueryPlannerException;
import org.teiid.core.TeiidComponentException;
-import org.teiid.core.util.Assertion;
import org.teiid.query.QueryPlugin;
import org.teiid.query.analysis.AnalysisRecord;
import org.teiid.query.metadata.QueryMetadataInterface;
@@ -391,8 +390,6 @@
boolean moveNodeAcrossFrame(PlanNode critNode, PlanNode sourceNode, QueryMetadataInterface metadata)
throws QueryPlannerException {
- Assertion.isNotNull(critNode.getParent());
-
// Check that sourceNode has a child to push across
if(sourceNode.getChildCount() == 0) {
return false;
Modified: trunk/engine/src/main/java/org/teiid/query/parser/SQLParserUtil.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/parser/SQLParserUtil.java 2011-03-19 14:32:44 UTC (rev 3010)
+++ trunk/engine/src/main/java/org/teiid/query/parser/SQLParserUtil.java 2011-03-20 13:39:50 UTC (rev 3011)
@@ -38,8 +38,8 @@
import org.teiid.query.sql.lang.Option;
import org.teiid.query.sql.lang.QueryCommand;
import org.teiid.query.sql.lang.SetQuery;
+import org.teiid.query.sql.lang.ExistsCriteria.SubqueryHint;
import org.teiid.query.sql.proc.CriteriaSelector;
-import org.teiid.query.sql.visitor.SQLStringVisitor;
public class SQLParserUtil {
@@ -167,14 +167,17 @@
}
}
- boolean isMergeJoin(Token t) {
+ SubqueryHint getSubqueryHint(Token t) {
+ SubqueryHint hint = new SubqueryHint();
String[] parts = getComment(t).split("\\s"); //$NON-NLS-1$
for (int i = 0; i < parts.length; i++) {
- if (parts[i].equalsIgnoreCase(SQLStringVisitor.MJ)) {
- return true;
- }
+ if (parts[i].equalsIgnoreCase(SubqueryHint.MJ)) {
+ hint.setMergeJoin(true);
+ } else if (parts[i].equalsIgnoreCase(SubqueryHint.NOUNNEST)) {
+ hint.setNoUnnest(true);
+ }
}
- return false;
+ return hint;
}
String getComment(Token t) {
Modified: trunk/engine/src/main/java/org/teiid/query/processor/relational/DependentValueSource.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/processor/relational/DependentValueSource.java 2011-03-19 14:32:44 UTC (rev 3010)
+++ trunk/engine/src/main/java/org/teiid/query/processor/relational/DependentValueSource.java 2011-03-20 13:39:50 UTC (rev 3011)
@@ -26,16 +26,13 @@
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
-import java.util.TreeSet;
import org.teiid.common.buffer.IndexedTupleSource;
import org.teiid.common.buffer.TupleBuffer;
import org.teiid.core.TeiidComponentException;
import org.teiid.core.TeiidProcessingException;
-import org.teiid.core.types.DataTypeManager;
import org.teiid.core.util.Assertion;
import org.teiid.query.sql.symbol.Expression;
-import org.teiid.query.sql.symbol.SingleElementSymbol;
import org.teiid.query.sql.util.ValueIterator;
import org.teiid.query.sql.util.ValueIteratorSource;
@@ -86,11 +83,7 @@
index = buffer.getSchema().indexOf(valueExpression);
}
Assertion.assertTrue(index != -1);
- if (((SingleElementSymbol)buffer.getSchema().get(index)).getType() == DataTypeManager.DefaultDataClasses.BIG_DECIMAL) {
- result = new TreeSet<Object>();
- } else {
- result = new HashSet<Object>();
- }
+ result = new HashSet<Object>();
while (its.hasNext()) {
Object value = its.nextTuple().get(index);
if (value != null) {
Modified: trunk/engine/src/main/java/org/teiid/query/rewriter/QueryRewriter.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/rewriter/QueryRewriter.java 2011-03-19 14:32:44 UTC (rev 3010)
+++ trunk/engine/src/main/java/org/teiid/query/rewriter/QueryRewriter.java 2011-03-20 13:39:50 UTC (rev 3011)
@@ -40,7 +40,6 @@
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
-import java.util.TreeSet;
import org.teiid.api.exception.query.ExpressionEvaluationException;
import org.teiid.api.exception.query.FunctionExecutionException;
@@ -161,6 +160,7 @@
import org.teiid.query.sql.visitor.EvaluatableVisitor;
import org.teiid.query.sql.visitor.ExpressionMappingVisitor;
import org.teiid.query.sql.visitor.FunctionCollectorVisitor;
+import org.teiid.query.sql.visitor.ValueIteratorProviderCollectorVisitor;
import org.teiid.query.sql.visitor.EvaluatableVisitor.EvaluationLevel;
import org.teiid.query.util.CommandContext;
import org.teiid.query.validator.UpdateValidator.UpdateInfo;
@@ -632,7 +632,7 @@
}
}
- if (from != null) {
+ if (from != null && !query.getIsXML()) {
writeSubqueriesAsJoins(query);
}
@@ -707,9 +707,10 @@
//check for key preservation
HashSet<GroupSymbol> keyPreservingGroups = new HashSet<GroupSymbol>();
ResolverUtil.findKeyPreserved(query, keyPreservingGroups, metadata);
- if (!NewCalculateCostUtil.usesKey(plannedResult.leftExpressions, keyPreservingGroups, metadata, true)) {
- //if not key perserved then the semi-join will not remain in tact
- continue;
+ if (NewCalculateCostUtil.usesKey(plannedResult.leftExpressions, keyPreservingGroups, metadata, true) && plannedResult.madeDistinct) {
+ //if key perserved then the semi-join will remain in-tact without make the other query distinct
+ plannedResult.madeDistinct = false;
+ plannedResult.query.getSelect().setDistinct(false);
}
}
crits.remove();
@@ -1156,18 +1157,18 @@
if (exists.shouldEvaluate() && processing) {
return getCriteria(evaluator.evaluate(exists, null));
}
- if (exists.getCommand().getProcessorPlan() == null && exists.getCommand() instanceof Query) {
- Query query = (Query)exists.getCommand();
- if ((query.getLimit() == null || query.getOrderBy() == null) && query.getProjectedSymbols().size() > 1) {
- query.getSelect().clearSymbols();
- query.getSelect().addSymbol(new ExpressionSymbol("x", new Constant(1))); //$NON-NLS-1$
- }
- }
rewriteSubqueryContainer((SubqueryContainer)criteria, true);
if (!RelationalNodeUtil.shouldExecute(exists.getCommand(), false, true)) {
return exists.isNegated()?TRUE_CRITERIA:FALSE_CRITERIA;
}
if (exists.getCommand().getProcessorPlan() == null) {
+ if (exists.getCommand() instanceof Query) {
+ Query query = (Query)exists.getCommand();
+ if ((query.getLimit() == null || query.getOrderBy() == null) && query.getSelect().getProjectedSymbols().size() > 1) {
+ query.getSelect().clearSymbols();
+ query.getSelect().addSymbol(new ExpressionSymbol("x", new Constant(1))); //$NON-NLS-1$
+ }
+ }
addImplicitLimit(exists, 1);
}
} else if (criteria instanceof SubquerySetCriteria) {
@@ -1338,7 +1339,7 @@
} else {
newCrits.remove(crit);
CompareCriteria other = (CompareCriteria)crit;
- SetCriteria sc = new SetCriteria(cc.getLeftExpression(), new TreeSet<Expression>());
+ SetCriteria sc = new SetCriteria(cc.getLeftExpression(), new LinkedHashSet<Expression>());
sc.setAllConstants(true);
sc.getValues().add(cc.getRightExpression());
sc.getValues().add(other.getRightExpression());
@@ -2234,7 +2235,7 @@
criteria.setValues(newVals);
if (allConstants) {
criteria.setAllConstants(true);
- criteria.setValues(new TreeSet(newVals));
+ criteria.setValues(new LinkedHashSet(newVals));
}
if (size == 0) {
Modified: trunk/engine/src/main/java/org/teiid/query/sql/lang/ExistsCriteria.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/lang/ExistsCriteria.java 2011-03-19 14:32:44 UTC (rev 3010)
+++ trunk/engine/src/main/java/org/teiid/query/sql/lang/ExistsCriteria.java 2011-03-20 13:39:50 UTC (rev 3011)
@@ -40,13 +40,57 @@
public class ExistsCriteria extends PredicateCriteria
implements SubqueryContainer<QueryCommand>, ContextReference, Negatable {
+ public static class SubqueryHint {
+ public static String MJ = "MJ"; //$NON-NLS-1$
+ public static String NOUNNEST = "NO_UNNEST"; //$NON-NLS-1$
+
+ private boolean mergeJoin;
+ private boolean noUnnest;
+
+ public void setMergeJoin(boolean semiJoin) {
+ this.mergeJoin = semiJoin;
+ }
+
+ public boolean isMergeJoin() {
+ return mergeJoin;
+ }
+
+ public void setNoUnnest(boolean noUnnest) {
+ this.noUnnest = noUnnest;
+ }
+
+ public boolean isNoUnnest() {
+ return noUnnest;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!(obj instanceof SubqueryHint)) {
+ return false;
+ }
+ SubqueryHint other = (SubqueryHint) obj;
+ return mergeJoin == other.mergeJoin && noUnnest == other.noUnnest;
+ }
+
+ public SubqueryHint clone() {
+ SubqueryHint clone = new SubqueryHint();
+ clone.mergeJoin = this.mergeJoin;
+ clone.noUnnest = this.noUnnest;
+ return clone;
+ }
+
+ }
+
private static AtomicInteger ID = new AtomicInteger();
private QueryCommand command;
private String id = "$ec/id" + ID.getAndIncrement(); //$NON-NLS-1$
private boolean shouldEvaluate;
- private boolean mergeJoin;
private boolean negated;
+ private SubqueryHint subqueryHint = new SubqueryHint();
/**
* Default constructor
@@ -55,14 +99,6 @@
super();
}
- public void setMergeJoin(boolean semiJoin) {
- this.mergeJoin = semiJoin;
- }
-
- public boolean isMergeJoin() {
- return mergeJoin;
- }
-
public ExistsCriteria(QueryCommand subqueryCommand){
this.command = subqueryCommand;
}
@@ -127,9 +163,17 @@
return EquivalenceUtil.areEqual(getCommand(), other.getCommand()) &&
this.negated == other.negated &&
- this.mergeJoin == other.mergeJoin;
+ this.subqueryHint.equals(other.subqueryHint);
}
-
+
+ public SubqueryHint getSubqueryHint() {
+ return subqueryHint;
+ }
+
+ public void setSubqueryHint(SubqueryHint subqueryHint) {
+ this.subqueryHint = subqueryHint;
+ }
+
/**
* Deep copy of object. The values Iterator of this object
* will not be cloned - it will be null in the new object
@@ -139,7 +183,7 @@
*/
public Object clone() {
ExistsCriteria ec = new ExistsCriteria((QueryCommand) this.command.clone());
- ec.setMergeJoin(this.mergeJoin);
+ ec.subqueryHint = this.subqueryHint.clone();
ec.setNegated(this.negated);
return ec;
}
Modified: trunk/engine/src/main/java/org/teiid/query/sql/lang/SetCriteria.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/lang/SetCriteria.java 2011-03-19 14:32:44 UTC (rev 3010)
+++ trunk/engine/src/main/java/org/teiid/query/sql/lang/SetCriteria.java 2011-03-20 13:39:50 UTC (rev 3011)
@@ -24,7 +24,7 @@
import java.util.ArrayList;
import java.util.Collection;
-import java.util.TreeSet;
+import java.util.LinkedHashSet;
import org.teiid.core.util.EquivalenceUtil;
import org.teiid.core.util.HashCodeUtil;
@@ -152,7 +152,7 @@
Collection copyValues = null;
if (isAllConstants()) {
- copyValues = new TreeSet(values);
+ copyValues = new LinkedHashSet(values);
} else {
copyValues = LanguageObject.Util.deepClone(new ArrayList(values), Expression.class);
}
Modified: trunk/engine/src/main/java/org/teiid/query/sql/lang/SubquerySetCriteria.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/lang/SubquerySetCriteria.java 2011-03-19 14:32:44 UTC (rev 3010)
+++ trunk/engine/src/main/java/org/teiid/query/sql/lang/SubquerySetCriteria.java 2011-03-20 13:39:50 UTC (rev 3011)
@@ -27,6 +27,7 @@
import org.teiid.core.util.EquivalenceUtil;
import org.teiid.core.util.HashCodeUtil;
import org.teiid.query.sql.LanguageVisitor;
+import org.teiid.query.sql.lang.ExistsCriteria.SubqueryHint;
import org.teiid.query.sql.symbol.ContextReference;
import org.teiid.query.sql.symbol.Expression;
@@ -41,8 +42,8 @@
private static AtomicInteger ID = new AtomicInteger();
private QueryCommand command;
+ private SubqueryHint subqueryHint = new SubqueryHint();
private String id = "$ssc/id" + ID.getAndIncrement(); //$NON-NLS-1$
- private boolean mergeJoin;
/**
* Constructor for SubquerySetCriteria.
@@ -56,12 +57,12 @@
setCommand(subCommand);
}
- public boolean isMergeJoin() {
- return mergeJoin;
+ public SubqueryHint getSubqueryHint() {
+ return subqueryHint;
}
- public void setMergeJoin(boolean semiJoin) {
- this.mergeJoin = semiJoin;
+ public void setSubqueryHint(SubqueryHint subqueryHint) {
+ this.subqueryHint = subqueryHint;
}
@Override
@@ -127,7 +128,7 @@
return this.isNegated() == sc.isNegated() &&
EquivalenceUtil.areEqual(getExpression(), sc.getExpression()) &&
EquivalenceUtil.areEqual(getCommand(), sc.getCommand()) &&
- this.mergeJoin == sc.mergeJoin;
+ this.subqueryHint.equals(sc.getSubqueryHint());
}
/**
@@ -149,7 +150,7 @@
SubquerySetCriteria criteriaCopy = new SubquerySetCriteria(copy, copyCommand);
criteriaCopy.setNegated(isNegated());
- criteriaCopy.mergeJoin = this.mergeJoin;
+ criteriaCopy.subqueryHint = this.subqueryHint.clone();
return criteriaCopy;
}
Modified: trunk/engine/src/main/java/org/teiid/query/sql/visitor/EvaluatableVisitor.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/visitor/EvaluatableVisitor.java 2011-03-19 14:32:44 UTC (rev 3010)
+++ trunk/engine/src/main/java/org/teiid/query/sql/visitor/EvaluatableVisitor.java 2011-03-20 13:39:50 UTC (rev 3011)
@@ -27,8 +27,8 @@
import java.util.TreeSet;
+import org.teiid.metadata.FunctionMethod.Determinism;
import org.teiid.metadata.FunctionMethod.PushDown;
-import org.teiid.metadata.FunctionMethod.Determinism;
import org.teiid.query.function.FunctionLibrary;
import org.teiid.query.metadata.TempMetadataID;
import org.teiid.query.sql.LanguageObject;
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 2011-03-19 14:32:44 UTC (rev 3010)
+++ trunk/engine/src/main/java/org/teiid/query/sql/visitor/SQLStringVisitor.java 2011-03-20 13:39:50 UTC (rev 3011)
@@ -84,6 +84,7 @@
import org.teiid.query.sql.lang.Update;
import org.teiid.query.sql.lang.WithQueryCommand;
import org.teiid.query.sql.lang.XMLTable;
+import org.teiid.query.sql.lang.ExistsCriteria.SubqueryHint;
import org.teiid.query.sql.lang.TableFunctionReference.ProjectedColumn;
import org.teiid.query.sql.lang.TextTable.TextColumn;
import org.teiid.query.sql.lang.XMLTable.XMLColumn;
@@ -144,10 +145,8 @@
private static final String BEGIN_HINT = "/*+"; //$NON-NLS-1$
private static final String END_HINT = "*/"; //$NON-NLS-1$
private static final char ID_ESCAPE_CHAR = '\"';
- public static String MJ = "MJ"; //$NON-NLS-1$
+ protected StringBuilder parts = new StringBuilder();
- protected StringBuilder parts = new StringBuilder();
-
/**
* Helper to quickly get the parser string for an object using the visitor.
*
@@ -1067,14 +1066,7 @@
append(SPACE);
}
append(IN);
- if (obj.isMergeJoin()) {
- append(SPACE);
- append(BEGIN_HINT);
- append(SPACE);
- append(MJ);
- append(SPACE);
- append(END_HINT);
- }
+ addSubqueryHint(obj.getSubqueryHint());
append(" ("); //$NON-NLS-1$
visitNode(obj.getCommand());
append(")"); //$NON-NLS-1$
@@ -1560,17 +1552,28 @@
append(SPACE);
}
append(EXISTS);
- if (obj.isMergeJoin()) {
+ addSubqueryHint(obj.getSubqueryHint());
+ append(" ("); //$NON-NLS-1$
+ visitNode(obj.getCommand());
+ append(")"); //$NON-NLS-1$
+ }
+
+ public void addSubqueryHint(SubqueryHint hint) {
+ if (hint.isNoUnnest()) {
+ append(SPACE);
+ append(BEGIN_HINT);
append(SPACE);
+ append(SubqueryHint.NOUNNEST);
+ append(SPACE);
+ append(END_HINT);
+ } else if (hint.isMergeJoin()) {
+ append(SPACE);
append(BEGIN_HINT);
append(SPACE);
- append(MJ);
+ append(SubqueryHint.MJ);
append(SPACE);
append(END_HINT);
}
- append(" ("); //$NON-NLS-1$
- visitNode(obj.getCommand());
- append(")"); //$NON-NLS-1$
}
public void visit( SubqueryCompareCriteria obj ) {
Modified: trunk/engine/src/main/java/org/teiid/query/tempdata/IndexInfo.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/tempdata/IndexInfo.java 2011-03-19 14:32:44 UTC (rev 3010)
+++ trunk/engine/src/main/java/org/teiid/query/tempdata/IndexInfo.java 2011-03-20 13:39:50 UTC (rev 3011)
@@ -23,11 +23,11 @@
package org.teiid.query.tempdata;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
-import java.util.TreeSet;
import org.teiid.common.buffer.TupleBrowser;
import org.teiid.common.buffer.TupleSource;
@@ -151,7 +151,7 @@
if (!setCriteria.getExpression().equals(keyColumn) || !setCriteria.isAllConstants()) {
continue;
}
- TreeSet<Constant> values = (TreeSet<Constant>) setCriteria.getValues();
+ Collection<Constant> values = (Collection<Constant>) setCriteria.getValues();
this.addSet(i, values);
}
}
@@ -197,7 +197,7 @@
}
}
- void addSet(int i, TreeSet<Constant> values) {
+ void addSet(int i, Collection<Constant> values) {
if (!valueSet.isEmpty()) {
return;
}
Modified: trunk/engine/src/main/javacc/org/teiid/query/parser/SQLParser.jj
===================================================================
--- trunk/engine/src/main/javacc/org/teiid/query/parser/SQLParser.jj 2011-03-19 14:32:44 UTC (rev 3010)
+++ trunk/engine/src/main/javacc/org/teiid/query/parser/SQLParser.jj 2011-03-20 13:39:50 UTC (rev 3011)
@@ -2707,7 +2707,7 @@
)
<RPAREN>
{
- return new Object[] {subquery, isMergeJoin(lparen)};
+ return new Object[] {subquery, getSubqueryHint(lparen)};
}
}
@@ -2877,7 +2877,7 @@
{
if (command != null) {
SubquerySetCriteria ssc = new SubquerySetCriteria(expression, (QueryCommand)command[0]);
- ssc.setMergeJoin((Boolean)command[1]);
+ ssc.setSubqueryHint((ExistsCriteria.SubqueryHint)command[1]);
criteria = ssc;
} else {
criteria = new SetCriteria(expression, setList);
@@ -2902,7 +2902,7 @@
{
ExistsCriteria existsCrit = new ExistsCriteria((QueryCommand)subquery[0]);
- existsCrit.setMergeJoin((Boolean)subquery[1]);
+ existsCrit.setSubqueryHint((ExistsCriteria.SubqueryHint)subquery[1]);
return existsCrit;
}
}
Modified: trunk/engine/src/test/java/org/teiid/query/function/TestFunction.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/function/TestFunction.java 2011-03-19 14:32:44 UTC (rev 3010)
+++ trunk/engine/src/test/java/org/teiid/query/function/TestFunction.java 2011-03-20 13:39:50 UTC (rev 3011)
@@ -34,8 +34,8 @@
import org.junit.Test;
import org.teiid.api.exception.query.FunctionExecutionException;
+import org.teiid.core.types.TeiidBigDecimal;
import org.teiid.language.SQLConstants.NonReserved;
-import org.teiid.query.function.FunctionMethods;
import org.teiid.query.sql.symbol.Constant;
import org.teiid.query.unittest.TimestampUtil;
import org.teiid.query.util.CommandContext;
@@ -471,7 +471,7 @@
}
@Test public void testConvertBigDecimalBigInteger() throws Exception {
- helpConvert(new BigDecimal("1.0"), "biginteger", new BigInteger("1")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ helpConvert(new TeiidBigDecimal("1.0"), "biginteger", new BigInteger("1")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
@Test public void testConvertDoubleLong() throws Exception {
Modified: trunk/engine/src/test/java/org/teiid/query/function/TestFunctionLibrary.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/function/TestFunctionLibrary.java 2011-03-19 14:32:44 UTC (rev 3010)
+++ trunk/engine/src/test/java/org/teiid/query/function/TestFunctionLibrary.java 2011-03-20 13:39:50 UTC (rev 3011)
@@ -68,7 +68,7 @@
private static final Class<String> T_STRING = DataTypeManager.DefaultDataClasses.STRING;
private static final Class<Integer> T_INTEGER = DataTypeManager.DefaultDataClasses.INTEGER;
private static final Class<BigInteger> T_BIG_INTEGER = DataTypeManager.DefaultDataClasses.BIG_INTEGER;
- private static final Class<BigDecimal> T_BIG_DECIMAL = DataTypeManager.DefaultDataClasses.BIG_DECIMAL;
+ private static final Class<? extends BigDecimal> T_BIG_DECIMAL = DataTypeManager.DefaultDataClasses.BIG_DECIMAL;
private static final Class<Long> T_LONG = DataTypeManager.DefaultDataClasses.LONG;
private static final Class<Float> T_FLOAT = DataTypeManager.DefaultDataClasses.FLOAT;
private static final Class<Double> T_DOUBLE = DataTypeManager.DefaultDataClasses.DOUBLE;
Modified: trunk/engine/src/test/java/org/teiid/query/optimizer/TestSubqueryPushdown.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/optimizer/TestSubqueryPushdown.java 2011-03-19 14:32:44 UTC (rev 3010)
+++ trunk/engine/src/test/java/org/teiid/query/optimizer/TestSubqueryPushdown.java 2011-03-20 13:39:50 UTC (rev 3011)
@@ -24,7 +24,7 @@
import static org.teiid.query.optimizer.TestOptimizer.*;
-import org.junit.Ignore;
+import org.junit.After;
import org.junit.Test;
import org.teiid.core.TeiidComponentException;
import org.teiid.core.TeiidProcessingException;
@@ -35,6 +35,7 @@
import org.teiid.query.optimizer.capabilities.DefaultCapabilitiesFinder;
import org.teiid.query.optimizer.capabilities.FakeCapabilitiesFinder;
import org.teiid.query.optimizer.capabilities.SourceCapabilities.Capability;
+import org.teiid.query.optimizer.relational.rules.RuleMergeCriteria;
import org.teiid.query.processor.ProcessorPlan;
import org.teiid.query.rewriter.TestQueryRewriter;
import org.teiid.query.unittest.FakeMetadataFacade;
@@ -395,18 +396,18 @@
ProcessorPlan plan = helpPlan("Select e1 from pm1.g1 where e1 in (select max(e1) FROM pm1.g2)", FakeMetadataFactory.example1Cached(), //$NON-NLS-1$
null, capFinder,
- new String[] { "SELECT e1 AS c_0 FROM pm1.g1 ORDER BY c_0" }, SHOULD_SUCCEED); //$NON-NLS-1$
+ new String[] { "SELECT e1 FROM pm1.g1" }, SHOULD_SUCCEED); //$NON-NLS-1$
checkNodeTypes(plan, new int[] {
1, // Access
0, // DependentAccess
- 0, // DependentSelect
+ 1, // DependentSelect
0, // DependentProject
0, // DupRemove
0, // Grouping
0, // NestedLoopJoinStrategy
- 1, // MergeJoinStrategy
+ 0, // MergeJoinStrategy
0, // Null
- 1, // PlanExecution
+ 0, // PlanExecution
1, // Project
0, // Select
0, // Sort
@@ -779,11 +780,11 @@
}
@Test public void testSubqueryRewriteToJoin1() throws Exception {
- TestQueryRewriter.helpTestRewriteCommand("Select e1 from pm3.g1 where pm3.g1.e1 in (select pm1.g1.e1 as x FROM pm1.g1)", "SELECT e1 FROM pm3.g1, (SELECT pm1.g1.e1 AS x FROM pm1.g1) AS X__1 WHERE pm3.g1.e1 = X__1.x", FakeMetadataFactory.example4());
+ TestQueryRewriter.helpTestRewriteCommand("Select e1 from pm3.g1 where pm3.g1.e1 in /*+ mj */ (select pm1.g1.e1 as x FROM pm1.g1)", "SELECT e1 FROM pm3.g1, (SELECT pm1.g1.e1 AS x FROM pm1.g1) AS X__1 WHERE pm3.g1.e1 = X__1.x", FakeMetadataFactory.example4());
}
@Test public void testSubqueryRewriteToJoin2() throws Exception {
- TestQueryRewriter.helpTestRewriteCommand("Select e1 from pm3.g1 where pm3.g1.e1 in (select pm1.g1.e1 || 1 FROM pm1.g1)", "SELECT e1 FROM pm3.g1, (SELECT DISTINCT concat(pm1.g1.e1, '1') AS EXPR FROM pm1.g1) AS X__1 WHERE pm3.g1.e1 = X__1.EXPR", FakeMetadataFactory.example4());
+ TestQueryRewriter.helpTestRewriteCommand("Select e1 from pm3.g1 where pm3.g1.e1 in /*+ mj */ (select pm1.g1.e1 || 1 FROM pm1.g1)", "SELECT e1 FROM pm3.g1, (SELECT concat(pm1.g1.e1, '1') AS EXPR FROM pm1.g1) AS X__1 WHERE pm3.g1.e1 = X__1.EXPR", FakeMetadataFactory.example4());
}
/**
@@ -794,10 +795,16 @@
}
@Test public void testSubqueryRewriteToJoinWithOtherCriteria() throws Exception {
- TestQueryRewriter.helpTestRewriteCommand("Select e1 from pm3.g1 where pm3.g1.e1 in (select pm1.g1.e1 FROM pm1.g1 where e2 < pm3.g1.e2)", "SELECT e1 FROM pm3.g1, (SELECT pm1.g1.e1, e2 FROM pm1.g1) AS X__1 WHERE (X__1.e2 < pm3.g1.e2) AND (pm3.g1.e1 = X__1.e1)", FakeMetadataFactory.example4());
+ TestQueryRewriter.helpTestRewriteCommand("Select e1 from pm3.g1 where pm3.g1.e1 in /*+ mj */ (select pm1.g1.e1 FROM pm1.g1 where e2 < pm3.g1.e2)", "SELECT e1 FROM pm3.g1, (SELECT pm1.g1.e1, e2 FROM pm1.g1) AS X__1 WHERE (X__1.e2 < pm3.g1.e2) AND (pm3.g1.e1 = X__1.e1)", FakeMetadataFactory.example4());
}
+
+ @Test public void testDontRewriteToJoinWithOtherCriteria() throws Exception {
+ System.setProperty(RuleMergeCriteria.UNNEST_DEFAULT, Boolean.TRUE.toString());
+ TestQueryRewriter.helpTestRewriteCommand("Select e1 from pm3.g1 where pm3.g1.e1 in /*+ NO_UNNEST */ (select pm1.g1.e1 FROM pm1.g1 where e2 < pm3.g1.e2)", "SELECT e1 FROM pm3.g1 WHERE pm3.g1.e1 IN /*+ NO_UNNEST */ (SELECT pm1.g1.e1 FROM pm1.g1 WHERE e2 < pm3.g1.e2)", FakeMetadataFactory.example4());
+ }
@Test public void testSubqueryRewriteToJoinWithAggregate() throws Exception {
+ System.setProperty(RuleMergeCriteria.UNNEST_DEFAULT, Boolean.TRUE.toString());
TestQueryRewriter.helpTestRewriteCommand("Select e1 from pm3.g1 where pm3.g1.e2 < (select max(e2) FROM pm1.g1 where pm3.g1.e1 = e1)", "SELECT e1 FROM pm3.g1, (SELECT MAX(e2) AS MAX, e1 FROM pm1.g1 GROUP BY e1) AS X__1 WHERE (pm3.g1.e2 < X__1.MAX) AND (pm3.g1.e1 = X__1.e1)", FakeMetadataFactory.example4());
}
@@ -810,6 +817,7 @@
}
@Test public void testSubqueryRewriteToJoinWithAggregate2() throws Exception {
+ System.setProperty(RuleMergeCriteria.UNNEST_DEFAULT, Boolean.TRUE.toString());
TestQueryRewriter.helpTestRewriteCommand("Select e1 from pm3.g1 where pm3.g1.e2 < (select max(e2) FROM pm1.g1 WHERE pm3.g1.e1 = e1 HAVING min(e3) < pm3.g1.e3)", "SELECT e1 FROM pm3.g1, (SELECT MAX(e2) AS MAX, e1, MIN(e3) AS MIN FROM pm1.g1 GROUP BY e1) AS X__1 WHERE (X__1.MIN < pm3.g1.e3) AND (pm3.g1.e2 < X__1.MAX) AND (pm3.g1.e1 = X__1.e1)", FakeMetadataFactory.example4());
}
@@ -830,14 +838,15 @@
}
@Test public void testSubqueryExpressionJoin() throws Exception {
+ System.setProperty(RuleMergeCriteria.UNNEST_DEFAULT, Boolean.TRUE.toString());
TestQueryRewriter.helpTestRewriteCommand("Select e1 from pm3.g1 where pm3.g1.e2 < (Select max(e2) from pm2.g2 where e1 = pm3.g1.e1 having convert(min(e2), string) > pm3.g1.e1)", "SELECT e1 FROM pm3.g1, (SELECT MAX(e2) AS MAX, e1, MIN(e2) AS MIN FROM pm2.g2 GROUP BY e1) AS X__1 WHERE (convert(X__1.MIN, string) > pm3.g1.e1) AND (pm3.g1.e2 < X__1.MAX) AND (pm3.g1.e1 = X__1.e1)", FakeMetadataFactory.example4());
}
/**
- * Must be handled as a semi-join
+ * Must be handled as a semi-join, rather than a regular join
*/
@Test public void testSemiJoin() {
- ProcessorPlan plan = helpPlan("Select e1 from pm2.g2 where e2 in (select count(e2) FROM pm1.g2 group by e1 having e1 < pm2.g2.e3)", FakeMetadataFactory.example4(), //$NON-NLS-1$
+ ProcessorPlan plan = helpPlan("Select e1 from pm2.g2 where e2 in /*+ mj */ (select count(e2) FROM pm1.g2 group by e1 having e1 < pm2.g2.e3)", FakeMetadataFactory.example4(), //$NON-NLS-1$
new String[] { "SELECT g_0.e2 AS c_0, g_0.e3 AS c_1, g_0.e1 AS c_2 FROM pm2.g2 AS g_0 ORDER BY c_0" }); //$NON-NLS-1$
checkNodeTypes(plan, new int[] {
1, // Access
@@ -854,14 +863,15 @@
0, // Select
0, // Sort
0 // UnionAll
- });
+ });
+ checkJoinCounts(plan, 1, 0);
}
/**
- * This will not plan as a semi-join since the cost seems too high
+ * This will not plan as a anti semi-join since the cost seems too high
*/
- @Test public void testNonSemiJoinExistsCosting() {
- ProcessorPlan plan = helpPlan("Select e1 from pm1.g2 as o where exists (select 1 from pm3.g1 where e1 = o.e1 having o.e2 = count(e2))", FakeMetadataFactory.example4(), //$NON-NLS-1$
+ @Test public void testNoAntiSemiJoinExistsCosting() {
+ ProcessorPlan plan = helpPlan("Select e1 from pm1.g2 as o where not exists (select 1 from pm3.g1 where e1 = o.e1 having o.e2 = count(e2))", FakeMetadataFactory.example4(), //$NON-NLS-1$
new String[] { "SELECT g_0.e1, g_0.e2 FROM pm1.g2 AS g_0" }); //$NON-NLS-1$
checkNodeTypes(plan, new int[] {
1, // Access
@@ -885,7 +895,7 @@
* Same as above, but the source is much larger, so a semi-join is favorable
*/
@Test public void testSemiJoinExistsCosting() {
- ProcessorPlan plan = helpPlan("Select e1 from pm2.g2 as o where exists (select 1 from pm3.g1 where e1 = o.e1 having o.e2 = count(e2))", FakeMetadataFactory.example4(), //$NON-NLS-1$
+ ProcessorPlan plan = helpPlan("Select e1 from pm2.g2 as o where not exists (select 1 from pm3.g1 where e1 = o.e1 having o.e2 = count(e2))", FakeMetadataFactory.example4(), //$NON-NLS-1$
new String[] { "SELECT g_0.e1 AS c_0, g_0.e2 AS c_1 FROM pm2.g2 AS g_0 ORDER BY c_0, c_1" }); //$NON-NLS-1$
checkNodeTypes(plan, new int[] {
1, // Access
@@ -903,7 +913,7 @@
0, // Sort
0 // UnionAll
});
- checkJoinCounts(plan, 1, 0);
+ checkJoinCounts(plan, 0, 1);
}
@Test public void testAntiSemiJoinExistsHint() {
@@ -928,8 +938,12 @@
checkJoinCounts(plan, 0, 1);
}
- @Test public void testSemiJoinInHint() {
- ProcessorPlan plan = helpPlan("Select e1 from pm1.g2 as o where e2 IN /*+ MJ */ (select count(e2) from pm3.g1 where e1 = o.e1)", FakeMetadataFactory.example4(), //$NON-NLS-1$
+ @After public void tearDown() {
+ System.setProperty(RuleMergeCriteria.UNNEST_DEFAULT, Boolean.FALSE.toString());
+ }
+
+ @Test public void testAntiSemiJoinInHint() {
+ ProcessorPlan plan = helpPlan("Select e1 from pm1.g2 as o where e2 NOT IN /*+ MJ */ (select count(e2) from pm3.g1 where e1 = o.e1)", FakeMetadataFactory.example4(), //$NON-NLS-1$
new String[] { "SELECT g_0.e2 AS c_0, g_0.e1 AS c_1 FROM pm1.g2 AS g_0 ORDER BY c_1, c_0" }); //$NON-NLS-1$
checkNodeTypes(plan, new int[] {
1, // Access
@@ -947,7 +961,7 @@
0, // Sort
0 // UnionAll
});
- checkJoinCounts(plan, 1, 0);
+ checkJoinCounts(plan, 0, 1);
}
void checkJoinCounts(ProcessorPlan plan, int semi, int antiSemi) {
@@ -987,7 +1001,7 @@
}
@Test public void testInvalidGeneratedSemijoinQuery1() throws Exception {
- TestQueryRewriter.helpTestRewriteCommand("Select e1 from pm3.g1 where pm3.g1.e2 = (Select max(e2) from pm2.g2 where e1 = pm3.g1.e1)", "SELECT e1 FROM pm3.g1, (SELECT MAX(e2) AS MAX, e1 FROM pm2.g2 GROUP BY e1) AS X__1 WHERE (pm3.g1.e1 = X__1.e1) AND (pm3.g1.e2 = X__1.MAX)", FakeMetadataFactory.example4());
+ TestQueryRewriter.helpTestRewriteCommand("Select e1 from pm3.g1 where pm3.g1.e2 IN /*+ mj */ (Select max(e2) from pm2.g2 where e1 = pm3.g1.e1)", "SELECT e1 FROM pm3.g1, (SELECT MAX(e2) AS MAX, e1 FROM pm2.g2 GROUP BY e1) AS X__1 WHERE (pm3.g1.e1 = X__1.e1) AND (pm3.g1.e2 = X__1.MAX)", FakeMetadataFactory.example4());
}
@Test public void testCompareSubquery2() throws Exception {
@@ -996,19 +1010,18 @@
checkNodeTypes(plan, FULL_PUSHDOWN);
}
- @Ignore
@Test public void testUncorrelatedSet() {
- ProcessorPlan plan = helpPlan("Select e1 from pm1.g1 where e1 in (select e1 FROM pm2.g1)", FakeMetadataFactory.example1Cached(), //$NON-NLS-1$
- new String[] { "SELECT e1, pm1.g1.e2 FROM pm1.g1" }); //$NON-NLS-1$
+ ProcessorPlan plan = helpPlan("Select e1 from pm1.g1 where e1 in /*+ mj */ (select e1 FROM pm2.g1)", FakeMetadataFactory.example1Cached(), //$NON-NLS-1$
+ new String[] { "SELECT DISTINCT g_0.e1 FROM pm2.g1 AS g_0", "SELECT g_0.e1 AS c_0 FROM pm1.g1 AS g_0 ORDER BY c_0" }); //$NON-NLS-1$
checkNodeTypes(plan, new int[] {
- 1, // Access
+ 2, // Access
0, // DependentAccess
- 1, // DependentSelect
+ 0, // DependentSelect
0, // DependentProject
0, // DupRemove
0, // Grouping
0, // NestedLoopJoinStrategy
- 0, // MergeJoinStrategy
+ 1, // MergeJoinStrategy
0, // Null
0, // PlanExecution
1, // Project
@@ -1016,6 +1029,7 @@
0, // Sort
0 // UnionAll
});
+ checkJoinCounts(plan, 0, 0);
}
}
Modified: trunk/engine/src/test/java/org/teiid/query/parser/TestOptionsAndHints.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/parser/TestOptionsAndHints.java 2011-03-19 14:32:44 UTC (rev 3010)
+++ trunk/engine/src/test/java/org/teiid/query/parser/TestOptionsAndHints.java 2011-03-20 13:39:50 UTC (rev 3011)
@@ -1144,13 +1144,13 @@
TestParser.helpTest(sql, "/*+ cache */ ? = EXEC proc()", sp); //$NON-NLS-1$
}
- @Test public void testSemiJoinHint() {
+ @Test public void testMergeJoinHint() {
String sql = "SELECT e1 FROM m.g2 WHERE EXISTS /*+ MJ */ (SELECT e1 FROM m.g1)"; //$NON-NLS-1$
Query q = TestParser.exampleExists(true);
TestParser.helpTest(sql, "SELECT e1 FROM m.g2 WHERE EXISTS /*+ MJ */ (SELECT e1 FROM m.g1)", q); //$NON-NLS-1$
}
- @Test public void testSemiJoinHint1() {
+ @Test public void testMergeJoinHint1() {
String sql = "SELECT a FROM db.g WHERE b IN /*+ MJ */ (SELECT a FROM db.g WHERE a2 = 5)"; //$NON-NLS-1$
Query q = TestParser.exampleIn(true);
TestParser.helpTest(sql, "SELECT a FROM db.g WHERE b IN /*+ MJ */ (SELECT a FROM db.g WHERE a2 = 5)", q); //$NON-NLS-1$
Modified: trunk/engine/src/test/java/org/teiid/query/parser/TestParser.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/parser/TestParser.java 2011-03-19 14:32:44 UTC (rev 3010)
+++ trunk/engine/src/test/java/org/teiid/query/parser/TestParser.java 2011-03-20 13:39:50 UTC (rev 3011)
@@ -4980,7 +4980,7 @@
query.setFrom(from);
query.setCriteria(criteria);
SubquerySetCriteria subCrit = new SubquerySetCriteria(expr, query);
- subCrit.setMergeJoin(semiJoin);
+ subCrit.getSubqueryHint().setMergeJoin(semiJoin);
Query outer = new Query();
outer.setSelect(select);
outer.setFrom(from);
@@ -5735,7 +5735,7 @@
From f2 = new From();
f2.addGroup(new GroupSymbol("m.g2")); //$NON-NLS-1$
ExistsCriteria existsCrit = new ExistsCriteria(q1);
- existsCrit.setMergeJoin(semiJoin);
+ existsCrit.getSubqueryHint().setMergeJoin(semiJoin);
Query q2 = new Query();
q2.setSelect(s2);
q2.setFrom(f2);
Modified: trunk/engine/src/test/java/org/teiid/query/rewriter/TestQueryRewriter.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/rewriter/TestQueryRewriter.java 2011-03-19 14:32:44 UTC (rev 3010)
+++ trunk/engine/src/test/java/org/teiid/query/rewriter/TestQueryRewriter.java 2011-03-20 13:39:50 UTC (rev 3011)
@@ -1061,7 +1061,7 @@
String rewritProc = "CREATE PROCEDURE\n"; //$NON-NLS-1$
rewritProc = rewritProc + "BEGIN\n"; //$NON-NLS-1$
rewritProc = rewritProc + "DECLARE String var1;\n"; //$NON-NLS-1$
- rewritProc = rewritProc + "IF(var1 IN ('x', 'y'))\n"; //$NON-NLS-1$
+ rewritProc = rewritProc + "IF(var1 IN ('y', 'x'))\n"; //$NON-NLS-1$
rewritProc = rewritProc + "BEGIN\n"; //$NON-NLS-1$
rewritProc = rewritProc + "SELECT pm1.g1.e2, null, FALSE, TRUE FROM pm1.g1;\n"; //$NON-NLS-1$
rewritProc = rewritProc + "END\n"; //$NON-NLS-1$
@@ -1250,7 +1250,7 @@
String rewritProc = "CREATE PROCEDURE\n"; //$NON-NLS-1$
rewritProc = rewritProc + "BEGIN\n"; //$NON-NLS-1$
rewritProc = rewritProc + "DECLARE integer var1;\n"; //$NON-NLS-1$
- rewritProc = rewritProc + "UPDATE pm1.g1 SET e1 = 'x' WHERE CONCAT(e1, 'm') IN ('1', '2');\n"; //$NON-NLS-1$
+ rewritProc = rewritProc + "UPDATE pm1.g1 SET e1 = 'x' WHERE CONCAT(e1, 'm') IN ('2', '1');\n"; //$NON-NLS-1$
rewritProc = rewritProc + "END"; //$NON-NLS-1$
String procReturned = this.getRewritenProcedure(procedure, userQuery,
13 years, 9 months
teiid SVN: r3010 - in trunk/engine/src: main/java/org/teiid/query/processor/relational and 4 other directories.
by teiid-commits@lists.jboss.org
Author: shawkins
Date: 2011-03-19 10:32:44 -0400 (Sat, 19 Mar 2011)
New Revision: 3010
Modified:
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/CriteriaCapabilityValidatorVisitor.java
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleMergeVirtual.java
trunk/engine/src/main/java/org/teiid/query/processor/relational/SubqueryAwareEvaluator.java
trunk/engine/src/main/java/org/teiid/query/rewriter/QueryRewriter.java
trunk/engine/src/main/java/org/teiid/query/sql/util/VariableContext.java
trunk/engine/src/main/java/org/teiid/query/sql/visitor/FunctionCollectorVisitor.java
trunk/engine/src/test/java/org/teiid/query/processor/TestProcessor.java
Log:
TEIID-1497 adding determinism checks and cleaning up correlation logic
Modified: trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/CriteriaCapabilityValidatorVisitor.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/CriteriaCapabilityValidatorVisitor.java 2011-03-19 01:18:44 UTC (rev 3009)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/CriteriaCapabilityValidatorVisitor.java 2011-03-19 14:32:44 UTC (rev 3010)
@@ -76,6 +76,7 @@
import org.teiid.query.sql.symbol.XMLSerialize;
import org.teiid.query.sql.util.SymbolMap;
import org.teiid.query.sql.visitor.EvaluatableVisitor;
+import org.teiid.query.sql.visitor.FunctionCollectorVisitor;
import org.teiid.query.sql.visitor.GroupCollectorVisitor;
@@ -386,7 +387,7 @@
try {
if(!this.caps.supportsCapability(Capability.QUERY_SUBQUERIES_SCALAR)
|| validateSubqueryPushdown(obj, modelID, metadata, capFinder, analysisRecord) == null) {
- if (obj.getCommand().getCorrelatedReferences() == null) {
+ if (obj.getCommand().getCorrelatedReferences() == null && !FunctionCollectorVisitor.isNonDeterministic(obj.getCommand())) {
obj.setShouldEvaluate(true);
} else {
markInvalid(obj.getCommand(), !this.caps.supportsCapability(Capability.QUERY_SUBQUERIES_SCALAR)?
Modified: trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleMergeVirtual.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleMergeVirtual.java 2011-03-19 01:18:44 UTC (rev 3009)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleMergeVirtual.java 2011-03-19 14:32:44 UTC (rev 3010)
@@ -32,7 +32,6 @@
import org.teiid.api.exception.query.QueryMetadataException;
import org.teiid.api.exception.query.QueryPlannerException;
import org.teiid.core.TeiidComponentException;
-import org.teiid.metadata.FunctionMethod.Determinism;
import org.teiid.query.analysis.AnalysisRecord;
import org.teiid.query.metadata.QueryMetadataInterface;
import org.teiid.query.optimizer.capabilities.CapabilitiesFinder;
@@ -47,7 +46,6 @@
import org.teiid.query.sql.lang.OrderByItem;
import org.teiid.query.sql.symbol.ElementSymbol;
import org.teiid.query.sql.symbol.Expression;
-import org.teiid.query.sql.symbol.Function;
import org.teiid.query.sql.symbol.GroupSymbol;
import org.teiid.query.sql.symbol.SingleElementSymbol;
import org.teiid.query.sql.util.SymbolMap;
@@ -355,11 +353,8 @@
return false;
}
// TEIID-16: We do not want to merge a non-deterministic scalar function
- Collection<Function> functions = FunctionCollectorVisitor.getFunctions(symbol, true, true);
- for (Function function : functions) {
- if ( function.getFunctionDescriptor().getDeterministic() == Determinism.NONDETERMINISTIC) {
- return false;
- }
+ if (FunctionCollectorVisitor.isNonDeterministic(symbol)) {
+ return false;
}
}
Modified: trunk/engine/src/main/java/org/teiid/query/processor/relational/SubqueryAwareEvaluator.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/processor/relational/SubqueryAwareEvaluator.java 2011-03-19 01:18:44 UTC (rev 3009)
+++ trunk/engine/src/main/java/org/teiid/query/processor/relational/SubqueryAwareEvaluator.java 2011-03-19 14:32:44 UTC (rev 3010)
@@ -30,6 +30,7 @@
import org.teiid.common.buffer.BufferManager;
import org.teiid.core.TeiidComponentException;
import org.teiid.core.TeiidProcessingException;
+import org.teiid.core.types.DataTypeManager;
import org.teiid.query.eval.Evaluator;
import org.teiid.query.processor.BatchCollector;
import org.teiid.query.processor.ProcessorDataManager;
@@ -39,8 +40,11 @@
import org.teiid.query.sql.symbol.ContextReference;
import org.teiid.query.sql.symbol.ElementSymbol;
import org.teiid.query.sql.symbol.Expression;
+import org.teiid.query.sql.symbol.ScalarSubquery;
+import org.teiid.query.sql.util.SymbolMap;
import org.teiid.query.sql.util.ValueIterator;
import org.teiid.query.sql.util.VariableContext;
+import org.teiid.query.sql.visitor.FunctionCollectorVisitor;
import org.teiid.query.util.CommandContext;
@@ -54,8 +58,10 @@
QueryProcessor processor;
BatchCollector collector;
boolean done;
- List<?> tuple;
ProcessorPlan plan;
+ boolean nonDeterministic;
+ List<Object> refValues;
+ boolean comparable = true;
void close() {
if (processor == null) {
@@ -73,13 +79,13 @@
//processing state
private Map<String, SubqueryState> subqueries = new HashMap<String, SubqueryState>();
-
+
public SubqueryAwareEvaluator(Map elements, ProcessorDataManager dataMgr,
CommandContext context, BufferManager manager) {
super(elements, dataMgr, context);
this.manager = manager;
}
-
+
public void reset() {
for (SubqueryState subQueryState : subqueries.values()) {
subQueryState.plan.reset();
@@ -102,26 +108,48 @@
if (state == null) {
state = new SubqueryState();
state.plan = container.getCommand().getProcessorPlan().clone();
+ if (container instanceof ScalarSubquery) {
+ state.nonDeterministic = FunctionCollectorVisitor.isNonDeterministic(container.getCommand());
+ }
+ if (container.getCommand().getCorrelatedReferences() != null) {
+ for (ElementSymbol es : container.getCommand().getCorrelatedReferences().getKeys()) {
+ if (DataTypeManager.isNonComparable(DataTypeManager.getDataTypeName(es.getType()))) {
+ state.comparable = false;
+ break;
+ }
+ }
+ }
this.subqueries.put(key, state);
}
- if ((tuple == null && state.tuple != null) || (tuple != null && !tuple.equals(state.tuple))) {
- if (container.getCommand().getCorrelatedReferences() != null) {
- state.close();
+ SymbolMap correlatedRefs = container.getCommand().getCorrelatedReferences();
+ VariableContext currentContext = null;
+ boolean shouldClose = state.done && state.nonDeterministic;
+ if (correlatedRefs != null) {
+ currentContext = new VariableContext();
+ for (Map.Entry<ElementSymbol, Expression> entry : container.getCommand().getCorrelatedReferences().asMap().entrySet()) {
+ currentContext.setValue(entry.getKey(), evaluate(entry.getValue(), tuple));
}
- state.tuple = tuple;
+ List<Object> refValues = currentContext.getLocalValues();
+ if (!refValues.equals(state.refValues)) {
+ state.refValues = refValues;
+ shouldClose = true;
+ }
}
+ if (shouldClose) {
+ //if (state.done && state.comparable) {
+ //cache
+ //} else {
+ state.close();
+ //}
+ }
if (!state.done) {
if (state.processor == null) {
CommandContext subContext = context.clone();
state.plan.reset();
state.processor = new QueryProcessor(state.plan, subContext, manager, this.dataMgr);
- if (container.getCommand().getCorrelatedReferences() != null) {
- VariableContext currentContext = new VariableContext();
- for (Map.Entry<ElementSymbol, Expression> entry : container.getCommand().getCorrelatedReferences().asMap().entrySet()) {
- currentContext.setValue(entry.getKey(), evaluate(entry.getValue(), tuple));
- }
- state.processor.getContext().pushVariableContext(currentContext);
- }
+ if (currentContext != null) {
+ state.processor.getContext().pushVariableContext(currentContext);
+ }
state.collector = state.processor.createBatchCollector();
}
state.done = true;
Modified: trunk/engine/src/main/java/org/teiid/query/rewriter/QueryRewriter.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/rewriter/QueryRewriter.java 2011-03-19 01:18:44 UTC (rev 3009)
+++ trunk/engine/src/main/java/org/teiid/query/rewriter/QueryRewriter.java 2011-03-19 14:32:44 UTC (rev 3010)
@@ -55,7 +55,6 @@
import org.teiid.core.util.Assertion;
import org.teiid.core.util.TimestampWithTimezone;
import org.teiid.language.SQLConstants.NonReserved;
-import org.teiid.metadata.FunctionMethod.Determinism;
import org.teiid.query.QueryPlugin;
import org.teiid.query.eval.Evaluator;
import org.teiid.query.function.FunctionDescriptor;
@@ -162,7 +161,6 @@
import org.teiid.query.sql.visitor.EvaluatableVisitor;
import org.teiid.query.sql.visitor.ExpressionMappingVisitor;
import org.teiid.query.sql.visitor.FunctionCollectorVisitor;
-import org.teiid.query.sql.visitor.ValueIteratorProviderCollectorVisitor;
import org.teiid.query.sql.visitor.EvaluatableVisitor.EvaluationLevel;
import org.teiid.query.util.CommandContext;
import org.teiid.query.validator.UpdateValidator.UpdateInfo;
@@ -750,11 +748,8 @@
} else if (query.getSelect().isDistinct()) {
for (SingleElementSymbol projectSymbol : query.getSelect().getProjectedSymbols()) {
Expression ex = SymbolMap.getExpression(projectSymbol);
- Collection<Function> functions = FunctionCollectorVisitor.getFunctions(ex, true, false);
- for (Function function : functions) {
- if ( function.getFunctionDescriptor().getDeterministic() == Determinism.NONDETERMINISTIC) {
- return true;
- }
+ if (FunctionCollectorVisitor.isNonDeterministic(ex)) {
+ return true;
}
if (!ValueIteratorProviderCollectorVisitor.getValueIteratorProviders(ex).isEmpty()) {
return true;
Modified: trunk/engine/src/main/java/org/teiid/query/sql/util/VariableContext.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/util/VariableContext.java 2011-03-19 01:18:44 UTC (rev 3009)
+++ trunk/engine/src/main/java/org/teiid/query/sql/util/VariableContext.java 2011-03-19 14:32:44 UTC (rev 3010)
@@ -22,7 +22,9 @@
package org.teiid.query.sql.util;
-import java.util.HashMap;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
import java.util.Map;
import org.teiid.core.TeiidComponentException;
@@ -33,7 +35,7 @@
public class VariableContext {
// map between variables and their values
- private Map variableMap = new HashMap();
+ private Map variableMap = new LinkedHashMap();
// reference to the parent variable context
private VariableContext parentContext;
@@ -48,7 +50,6 @@
public VariableContext(boolean delegateSets) {
this.delegateSets = delegateSets;
- this.variableMap = new HashMap();
}
public void setGlobalValue(String variable, Object value) {
@@ -185,4 +186,8 @@
this.variableMap.putAll(other.variableMap);
}
+ public List<Object> getLocalValues() {
+ return new ArrayList<Object>(this.variableMap.values());
+ }
+
}
Modified: trunk/engine/src/main/java/org/teiid/query/sql/visitor/FunctionCollectorVisitor.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/visitor/FunctionCollectorVisitor.java 2011-03-19 01:18:44 UTC (rev 3009)
+++ trunk/engine/src/main/java/org/teiid/query/sql/visitor/FunctionCollectorVisitor.java 2011-03-19 14:32:44 UTC (rev 3010)
@@ -26,6 +26,7 @@
import java.util.Collection;
import java.util.HashSet;
+import org.teiid.metadata.FunctionMethod.Determinism;
import org.teiid.query.QueryPlugin;
import org.teiid.query.sql.LanguageObject;
import org.teiid.query.sql.LanguageVisitor;
@@ -141,4 +142,15 @@
getFunctions(obj, functions, deep);
return functions;
}
+
+ public static boolean isNonDeterministic(LanguageObject ex) {
+ Collection<Function> functions = FunctionCollectorVisitor.getFunctions(ex, true, false);
+ for (Function function : functions) {
+ if ( function.getFunctionDescriptor().getDeterministic() == Determinism.NONDETERMINISTIC) {
+ return true;
+ }
+ }
+ return false;
+ }
+
}
Modified: trunk/engine/src/test/java/org/teiid/query/processor/TestProcessor.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/processor/TestProcessor.java 2011-03-19 01:18:44 UTC (rev 3009)
+++ trunk/engine/src/test/java/org/teiid/query/processor/TestProcessor.java 2011-03-19 14:32:44 UTC (rev 3010)
@@ -7540,6 +7540,30 @@
helpProcess(plan, hdm, expected);
}
+ @Test public void testNonDeterministicScalarSubquery() throws Exception {
+ FakeCapabilitiesFinder capFinder = new FakeCapabilitiesFinder();
+ FakeMetadataFacade metadata = FakeMetadataFactory.example1Cached();
+
+ BasicSourceCapabilities caps = getTypicalCapabilities();
+ caps.setCapabilitySupport(Capability.QUERY_SUBQUERIES_SCALAR, false);
+ caps.setCapabilitySupport(Capability.QUERY_AGGREGATES, true);
+ caps.setCapabilitySupport(Capability.QUERY_AGGREGATES_MAX, true);
+ capFinder.addCapabilities("pm1", caps); //$NON-NLS-1$
+
+ ProcessorPlan plan = helpPlan("select count(distinct x) from (select (select uuid()) as x from pm1.g1) as v", metadata, //$NON-NLS-1
+ null, capFinder,
+ new String[] { "SELECT 1 FROM pm1.g1 AS g_0" }, ComparisonMode.EXACT_COMMAND_STRING); //$NON-NLS-1$
+
+ HardcodedDataManager hdm = new HardcodedDataManager();
+ hdm.addData("SELECT 1 FROM pm1.g1 AS g_0", new List[] {Arrays.asList(1), Arrays.asList(1)});
+ hdm.setBlockOnce(true);
+ List[] expected = new List[] {
+ Arrays.asList(2),
+ };
+
+ helpProcess(plan, hdm, expected);
+ }
+
@Test public void testUncorrelatedScalarSubqueryPushdown1() throws Exception {
FakeCapabilitiesFinder capFinder = new FakeCapabilitiesFinder();
FakeMetadataFacade metadata = FakeMetadataFactory.example1Cached();
13 years, 9 months
teiid SVN: r3009 - in trunk: common-core/src/test/java/org/teiid/core/util and 7 other directories.
by teiid-commits@lists.jboss.org
Author: shawkins
Date: 2011-03-18 21:18:44 -0400 (Fri, 18 Mar 2011)
New Revision: 3009
Modified:
trunk/common-core/src/main/java/org/teiid/core/util/ReflectionHelper.java
trunk/common-core/src/test/java/org/teiid/core/util/TestReflectionHelper.java
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushAggregates.java
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleRemoveOptionalJoins.java
trunk/engine/src/main/java/org/teiid/query/resolver/QueryResolver.java
trunk/engine/src/main/java/org/teiid/query/rewriter/QueryRewriter.java
trunk/engine/src/main/java/org/teiid/query/sql/lang/Select.java
trunk/engine/src/main/java/org/teiid/query/sql/symbol/AggregateSymbol.java
trunk/engine/src/main/java/org/teiid/query/sql/visitor/AggregateSymbolCollectorVisitor.java
trunk/engine/src/main/java/org/teiid/query/sql/visitor/ExpressionMappingVisitor.java
trunk/engine/src/test/java/org/teiid/query/optimizer/TestSubqueryPushdown.java
Log:
TEIID-1497 expanding the checks performed in the rewriter to allow more conversions to joins
Modified: trunk/common-core/src/main/java/org/teiid/core/util/ReflectionHelper.java
===================================================================
--- trunk/common-core/src/main/java/org/teiid/core/util/ReflectionHelper.java 2011-03-18 18:50:32 UTC (rev 3008)
+++ trunk/common-core/src/main/java/org/teiid/core/util/ReflectionHelper.java 2011-03-19 01:18:44 UTC (rev 3009)
@@ -40,8 +40,8 @@
public class ReflectionHelper {
- private Class targetClass;
- private Map methodMap = null; // used for the brute-force method finder
+ private Class<?> targetClass;
+ private Map<String, LinkedList<Method>> methodMap = null; // used for the brute-force method finder
/**
* Construct a ReflectionHelper instance that cache's some information about
@@ -50,7 +50,7 @@
* @param targetClass the target class
* @throws IllegalArgumentException if the target class is null
*/
- public ReflectionHelper( Class targetClass ) {
+ public ReflectionHelper( Class<?> targetClass ) {
if ( targetClass == null ) {
throw new IllegalArgumentException(CorePlugin.Util.getString("ReflectionHelper.errorConstructing")); //$NON-NLS-1$
}
@@ -79,10 +79,10 @@
return findBestMethodWithSignature(methodName, Collections.EMPTY_LIST);
}
int size = arguments.length;
- List argumentClasses = new ArrayList(size);
+ List<Class<?>> argumentClasses = new ArrayList<Class<?>>(size);
for (int i=0; i!=size; ++i) {
if ( arguments[i] != null ) {
- Class clazz = arguments[i].getClass();
+ Class<?> clazz = arguments[i].getClass();
argumentClasses.add( clazz );
} else {
argumentClasses.add(null);
@@ -122,7 +122,7 @@
* @throws NoSuchMethodException if a matching method is not found.
* @throws SecurityException if access to the information is denied.
*/
- public Method findBestMethodWithSignature( String methodName, List argumentsClasses ) throws NoSuchMethodException, SecurityException {
+ public Method findBestMethodWithSignature( String methodName, List<Class<?>> argumentsClasses ) throws NoSuchMethodException, SecurityException {
// Attempt to find the method
Method result = null;
Class[] classArgs = new Class[argumentsClasses.size()];
@@ -141,7 +141,7 @@
// ---------------------------------------------------------------------------------------------
// Then try to find a method with the argument classes converted to a primitive, if possible ...
// ---------------------------------------------------------------------------------------------
- List argumentsClassList = convertArgumentClassesToPrimitives(argumentsClasses);
+ List<Class<?>> argumentsClassList = convertArgumentClassesToPrimitives(argumentsClasses);
argumentsClassList.toArray(classArgs);
try {
result = this.targetClass.getMethod(methodName,classArgs); // this may throw an exception if not found
@@ -156,20 +156,20 @@
// the arguments). There is no canned algorithm in Java to do this, so we have to brute-force it.
// ---------------------------------------------------------------------------------------------
if ( this.methodMap == null ) {
- this.methodMap = new HashMap();
+ this.methodMap = new HashMap<String, LinkedList<Method>>();
Method[] methods = this.targetClass.getMethods();
for ( int i=0; i!=methods.length; ++i ) {
Method method = methods[i];
- LinkedList methodsWithSameName = (LinkedList) this.methodMap.get(method.getName());
+ LinkedList<Method> methodsWithSameName = this.methodMap.get(method.getName());
if ( methodsWithSameName == null ) {
- methodsWithSameName = new LinkedList();
+ methodsWithSameName = new LinkedList<Method>();
this.methodMap.put(method.getName(),methodsWithSameName);
}
methodsWithSameName.addFirst(method); // add lower methods first
}
}
- LinkedList<Method> methodsWithSameName = (LinkedList) this.methodMap.get(methodName);
+ LinkedList<Method> methodsWithSameName = this.methodMap.get(methodName);
if ( methodsWithSameName == null ) {
throw new NoSuchMethodException(methodName);
}
@@ -180,8 +180,8 @@
}
boolean allMatch = true; // assume all args match
for ( int i=0; i<args.length && allMatch == true; ++i ) {
- Class primitiveClazz = (Class) argumentsClassList.get(i);
- Class objectClazz = (Class) argumentsClasses.get(i);
+ Class<?> primitiveClazz = argumentsClassList.get(i);
+ Class<?> objectClazz = argumentsClasses.get(i);
if ( objectClazz != null ) {
// Check for possible matches with (converted) primitive types
// as well as the original Object type
@@ -216,11 +216,9 @@
* @return the list of Class instances in which any classes that could be represented
* by primitives (e.g., Boolean) were replaced with the primitive classes (e.g., Boolean.TYPE).
*/
- private static List convertArgumentClassesToPrimitives( List arguments ) {
- List result = new ArrayList(arguments.size());
- Iterator iter = arguments.iterator();
- while ( iter.hasNext() ) {
- Class clazz = (Class) iter.next();
+ private static List<Class<?>> convertArgumentClassesToPrimitives( List<Class<?>> arguments ) {
+ List<Class<?>> result = new ArrayList<Class<?>>(arguments.size());
+ for (Class<?> clazz : arguments) {
if ( clazz == Boolean.class ) clazz = Boolean.TYPE;
else if ( clazz == Character.class ) clazz = Character.TYPE;
else if ( clazz == Byte.class ) clazz = Byte.TYPE;
@@ -244,8 +242,8 @@
* @return Class is the instance of the class
* @throws ClassNotFoundException
*/
- private static final Class loadClass(final String className, final ClassLoader classLoader) throws ClassNotFoundException {
- Class cls = null;
+ private static final Class<?> loadClass(final String className, final ClassLoader classLoader) throws ClassNotFoundException {
+ Class<?> cls = null;
if ( classLoader == null ) {
cls = Class.forName(className.trim());
} else {
@@ -290,9 +288,9 @@
public static final Object create(String className, Object[] ctorObjs, Class<?>[] argTypes,
final ClassLoader classLoader) throws TeiidException {
try {
- final Class cls = loadClass(className,classLoader);
+ final Class<?> cls = loadClass(className,classLoader);
- Constructor ctor = cls.getDeclaredConstructor(argTypes);
+ Constructor<?> ctor = cls.getDeclaredConstructor(argTypes);
return ctor.newInstance(ctorObjs);
Modified: trunk/common-core/src/test/java/org/teiid/core/util/TestReflectionHelper.java
===================================================================
--- trunk/common-core/src/test/java/org/teiid/core/util/TestReflectionHelper.java 2011-03-18 18:50:32 UTC (rev 3008)
+++ trunk/common-core/src/test/java/org/teiid/core/util/TestReflectionHelper.java 2011-03-19 01:18:44 UTC (rev 3009)
@@ -22,28 +22,21 @@
package org.teiid.core.util;
+import static org.junit.Assert.*;
+
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
-import org.teiid.core.util.ReflectionHelper;
+import org.junit.Test;
-import junit.framework.TestCase;
-
/**
* TestReflectionHelper
*/
-public class TestReflectionHelper extends TestCase {
+@SuppressWarnings("unchecked")
+public class TestReflectionHelper {
- /**
- * Constructor for TestReflectionHelper.
- * @param name
- */
- public TestReflectionHelper(String name) {
- super(name);
- }
-
// =========================================================================
// H E L P E R M E T H O D S
// =========================================================================
@@ -68,7 +61,7 @@
// T E S T C A S E S
// =========================================================================
- public void testConstructorWithNullTargetClass() {
+ @Test public void testConstructorWithNullTargetClass() {
try {
new ReflectionHelper(null);
fail("Should have caught null target class passed to constructor"); //$NON-NLS-1$
@@ -77,7 +70,7 @@
}
}
- public void testConstructorWithValidTargetClass() {
+ @Test public void testConstructorWithValidTargetClass() {
final ReflectionHelper helper = new ReflectionHelper(String.class);
assertNotNull(helper);
}
@@ -85,7 +78,7 @@
// ===============================================================================================
// Test overloaded methods
// ===============================================================================================
- public void testFindBestMethodWithSignature_String() throws Exception {
+ @Test public void testFindBestMethodWithSignature_String() throws Exception {
ReflectionHelper helper = new ReflectionHelper(FakeInterface.class);
Class[] signatureSought = new Class[] {String.class};
Method theMethod = helper.findBestMethodWithSignature("method", signatureSought ); //$NON-NLS-1$
@@ -98,7 +91,7 @@
helpAssertSameMethodSignature("Found wrong method signature", signatureExpected, signatureFound); //$NON-NLS-1$
}
- public void testFindBestMethodWithSignature_Serializable() throws Exception {
+ @Test public void testFindBestMethodWithSignature_Serializable() throws Exception {
ReflectionHelper helper = new ReflectionHelper(FakeInterface.class);
Class[] signatureSought = new Class[] {Serializable.class};
Method theMethod = helper.findBestMethodWithSignature("method", signatureSought ); //$NON-NLS-1$
@@ -111,7 +104,7 @@
helpAssertSameMethodSignature("Found wrong method signature", signatureExpected, signatureFound); //$NON-NLS-1$
}
- public void testFindBestMethodWithSignature_Object() throws Exception {
+ @Test public void testFindBestMethodWithSignature_Object() throws Exception {
ReflectionHelper helper = new ReflectionHelper(FakeInterface.class);
Class[] signatureSought = new Class[] {NullPointerException.class};
try {
@@ -122,7 +115,7 @@
}
}
- public void testFindBestMethodWithSignature_StringArray() throws Exception {
+ @Test public void testFindBestMethodWithSignature_StringArray() throws Exception {
ReflectionHelper helper = new ReflectionHelper(FakeInterface.class);
Class[] signatureSought = new Class[] {String[].class};
Method theMethod = helper.findBestMethodWithSignature("method", signatureSought ); //$NON-NLS-1$
@@ -135,7 +128,7 @@
helpAssertSameMethodSignature("Found wrong method signature", signatureExpected, signatureFound); //$NON-NLS-1$
}
- public void testFindBestMethodWithSignature_Integer() throws Exception {
+ @Test public void testFindBestMethodWithSignature_Integer() throws Exception {
ReflectionHelper helper = new ReflectionHelper(FakeInterface.class);
Class[] signatureSought = new Class[] {Integer.class};
Method theMethod = helper.findBestMethodWithSignature("method", signatureSought ); //$NON-NLS-1$
@@ -148,7 +141,7 @@
helpAssertSameMethodSignature("Found wrong method signature", signatureExpected, signatureFound); //$NON-NLS-1$
}
- public void testFindBestMethodWithSignature_long() throws Exception {
+ @Test public void testFindBestMethodWithSignature_long() throws Exception {
ReflectionHelper helper = new ReflectionHelper(FakeInterface.class);
Class[] signatureSought = new Class[] {Long.TYPE};
Method theMethod = helper.findBestMethodWithSignature("method", signatureSought ); //$NON-NLS-1$
@@ -161,7 +154,7 @@
helpAssertSameMethodSignature("Found wrong method signature", signatureExpected, signatureFound); //$NON-NLS-1$
}
- public void testFindBestMethodWithSignature_2ArgSerializableAndNumber() throws Exception {
+ @Test public void testFindBestMethodWithSignature_2ArgSerializableAndNumber() throws Exception {
ReflectionHelper helper = new ReflectionHelper(FakeInterface.class);
Class[] signatureSought = new Class[] {Integer.class, Integer.class};
Method theMethod = helper.findBestMethodWithSignature("method", signatureSought ); //$NON-NLS-1$
@@ -177,7 +170,7 @@
// ===============================================================================================
// Test explicit method names
// ===============================================================================================
- public void testFindBestMethodWithSignature_StringAndMethodName() throws Exception {
+ @Test public void testFindBestMethodWithSignature_StringAndMethodName() throws Exception {
ReflectionHelper helper = new ReflectionHelper(FakeInterface.class);
Class[] signatureSought = new Class[] {String.class};
Method theMethod = helper.findBestMethodWithSignature("methodString", signatureSought ); //$NON-NLS-1$
@@ -190,7 +183,7 @@
helpAssertSameMethodSignature("Found wrong method signature", signatureExpected, signatureFound); //$NON-NLS-1$
}
- public void testFindBestMethodWithSignature_ObjectAndMethodName() throws Exception {
+ @Test public void testFindBestMethodWithSignature_ObjectAndMethodName() throws Exception {
ReflectionHelper helper = new ReflectionHelper(FakeInterface.class);
Class[] signatureSought = new Class[] {NullPointerException.class};
Method theMethod = helper.findBestMethodWithSignature("methodObject", signatureSought ); //$NON-NLS-1$
@@ -203,7 +196,7 @@
helpAssertSameMethodSignature("Found wrong method signature", signatureExpected, signatureFound); //$NON-NLS-1$
}
- public void testFindBestMethodWithSignature_SerializableAndMethodName() throws Exception {
+ @Test public void testFindBestMethodWithSignature_SerializableAndMethodName() throws Exception {
ReflectionHelper helper = new ReflectionHelper(FakeInterface.class);
Class[] signatureSought = new Class[] {NullPointerException.class};
Method theMethod = helper.findBestMethodWithSignature("methodSerializable", signatureSought ); //$NON-NLS-1$
@@ -216,7 +209,7 @@
helpAssertSameMethodSignature("Found wrong method signature", signatureExpected, signatureFound); //$NON-NLS-1$
}
- public void testFindBestMethodWithSignature_ObjectSerializableAndMethodName() throws Exception {
+ @Test public void testFindBestMethodWithSignature_ObjectSerializableAndMethodName() throws Exception {
ReflectionHelper helper = new ReflectionHelper(FakeInterface.class);
Class[] signatureSought = new Class[] {NullPointerException.class};
Method theMethod = helper.findBestMethodWithSignature("methodSerializable", signatureSought ); //$NON-NLS-1$
@@ -229,7 +222,7 @@
helpAssertSameMethodSignature("Found wrong method signature", signatureExpected, signatureFound); //$NON-NLS-1$
}
- public void testFindBestMethodWithSignature_IntegerSerializableAndMethodName() throws Exception {
+ @Test public void testFindBestMethodWithSignature_IntegerSerializableAndMethodName() throws Exception {
ReflectionHelper helper = new ReflectionHelper(FakeInterface.class);
Class[] signatureSought = new Class[] {Integer.class};
Method theMethod = helper.findBestMethodWithSignature("methodSerializable", signatureSought ); //$NON-NLS-1$
@@ -242,7 +235,7 @@
helpAssertSameMethodSignature("Found wrong method signature", signatureExpected, signatureFound); //$NON-NLS-1$
}
- public void testFindBestMethodWithSignature_StringArrayAndMethodName() throws Exception {
+ @Test public void testFindBestMethodWithSignature_StringArrayAndMethodName() throws Exception {
ReflectionHelper helper = new ReflectionHelper(FakeInterface.class);
Class[] signatureSought = new Class[] {String[].class};
Method theMethod = helper.findBestMethodWithSignature("methodStringArray", signatureSought ); //$NON-NLS-1$
@@ -255,7 +248,7 @@
helpAssertSameMethodSignature("Found wrong method signature", signatureExpected, signatureFound); //$NON-NLS-1$
}
- public void testFindBestMethodWithSignature_ListAndMethodName() throws Exception {
+ @Test public void testFindBestMethodWithSignature_ListAndMethodName() throws Exception {
ReflectionHelper helper = new ReflectionHelper(FakeInterface.class);
Class[] signatureSought = new Class[] {ArrayList.class};
Method theMethod = helper.findBestMethodWithSignature("methodList", signatureSought ); //$NON-NLS-1$
@@ -268,7 +261,7 @@
helpAssertSameMethodSignature("Found wrong method signature", signatureExpected, signatureFound); //$NON-NLS-1$
}
- public void testFindBestMethodWithSignature_IntegerAndMethodName() throws Exception {
+ @Test public void testFindBestMethodWithSignature_IntegerAndMethodName() throws Exception {
ReflectionHelper helper = new ReflectionHelper(FakeInterface.class);
Class[] signatureSought = new Class[] {Integer.class};
Method theMethod = helper.findBestMethodWithSignature("methodInteger", signatureSought ); //$NON-NLS-1$
@@ -281,7 +274,7 @@
helpAssertSameMethodSignature("Found wrong method signature", signatureExpected, signatureFound); //$NON-NLS-1$
}
- public void testFindBestMethodWithSignature_IntegerObjectAndMethodName() throws Exception {
+ @Test public void testFindBestMethodWithSignature_IntegerObjectAndMethodName() throws Exception {
ReflectionHelper helper = new ReflectionHelper(FakeInterface.class);
Class[] signatureSought = new Class[] {Integer.class};
Method theMethod = helper.findBestMethodWithSignature("methodObject", signatureSought ); //$NON-NLS-1$
@@ -294,7 +287,7 @@
helpAssertSameMethodSignature("Found wrong method signature", signatureExpected, signatureFound); //$NON-NLS-1$
}
- public void testFindBestMethodWithSignature_LongObjectAndMethodName() throws Exception {
+ @Test public void testFindBestMethodWithSignature_LongObjectAndMethodName() throws Exception {
ReflectionHelper helper = new ReflectionHelper(FakeInterface.class);
Class[] signatureSought = new Class[] {Long.class};
Method theMethod = helper.findBestMethodWithSignature("methodObject", signatureSought ); //$NON-NLS-1$
@@ -307,7 +300,7 @@
helpAssertSameMethodSignature("Found wrong method signature", signatureExpected, signatureFound); //$NON-NLS-1$
}
- public void testFindBestMethodWithSignature_longAndMethodName() throws Exception {
+ @Test public void testFindBestMethodWithSignature_longAndMethodName() throws Exception {
ReflectionHelper helper = new ReflectionHelper(FakeInterface.class);
Class[] signatureSought = new Class[] {Long.TYPE};
Method theMethod = helper.findBestMethodWithSignature("method_long", signatureSought ); //$NON-NLS-1$
@@ -323,7 +316,7 @@
// ===============================================================================================
// Test 2-arg methods
// ===============================================================================================
- public void testFindBestMethodWithSignature_2ArgIntegerObjectAndMethodName() throws Exception {
+ @Test public void testFindBestMethodWithSignature_2ArgIntegerObjectAndMethodName() throws Exception {
ReflectionHelper helper = new ReflectionHelper(FakeInterface.class);
Class[] signatureSought = new Class[] {Integer.class, Integer.class};
Method theMethod = helper.findBestMethodWithSignature("twoArgMethod_Object_Object", signatureSought ); //$NON-NLS-1$
@@ -336,7 +329,7 @@
helpAssertSameMethodSignature("Found wrong method signature", signatureExpected, signatureFound); //$NON-NLS-1$
}
- public void testFindBestMethodWithSignature_2ArgLongObjectAndMethodName() throws Exception {
+ @Test public void testFindBestMethodWithSignature_2ArgLongObjectAndMethodName() throws Exception {
ReflectionHelper helper = new ReflectionHelper(FakeInterface.class);
Class[] signatureSought = new Class[] {Long.class, Long.class};
Method theMethod = helper.findBestMethodWithSignature("twoArgMethod_Object_Object", signatureSought ); //$NON-NLS-1$
@@ -349,7 +342,7 @@
helpAssertSameMethodSignature("Found wrong method signature", signatureExpected, signatureFound); //$NON-NLS-1$
}
- public void testFindBestMethodWithSignature_2ArgSerializableNumberAndMethodName() throws Exception {
+ @Test public void testFindBestMethodWithSignature_2ArgSerializableNumberAndMethodName() throws Exception {
ReflectionHelper helper = new ReflectionHelper(FakeInterface.class);
Class[] signatureSought = new Class[] {Long.class, Long.class};
Method theMethod = helper.findBestMethodWithSignature("twoArgMethod_Serializable_Number", signatureSought ); //$NON-NLS-1$
@@ -365,7 +358,7 @@
// ===============================================================================================
// Test overridden methods
// ===============================================================================================
- public void testFindBestMethodWithSignature_SubInterface_2ArgSerializableAndNumber() throws Exception {
+ @Test public void testFindBestMethodWithSignature_SubInterface_2ArgSerializableAndNumber() throws Exception {
ReflectionHelper helper = new ReflectionHelper(FakeSubInterface.class);
Class[] signatureSought = new Class[] {Serializable.class, Number.class};
Method theMethod = helper.findBestMethodWithSignature("method", signatureSought ); //$NON-NLS-1$
@@ -378,7 +371,7 @@
helpAssertSameMethodSignature("Found wrong method signature", signatureExpected, signatureFound); //$NON-NLS-1$
}
- public void testFindBestMethodWithSignature_SubInterface_2ArgSerializableAndLong() throws Exception {
+ @Test public void testFindBestMethodWithSignature_SubInterface_2ArgSerializableAndLong() throws Exception {
ReflectionHelper helper = new ReflectionHelper(FakeSubInterface.class);
Class[] signatureSought = new Class[] {Serializable.class, Long.class};
Method theMethod = helper.findBestMethodWithSignature("method", signatureSought ); //$NON-NLS-1$
@@ -390,12 +383,12 @@
assertEquals("Wrong class", theMethod.getDeclaringClass().getName(), FakeSubInterface.class.getName()); //$NON-NLS-1$
helpAssertSameMethodSignature("Found wrong method signature", signatureExpected, signatureFound); //$NON-NLS-1$
}
-
+
/**
* Test base interface
*/
public interface FakeInterface {
-
+
void method(String arg);
void method(Serializable arg);
void method(Object arg);
Modified: trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushAggregates.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushAggregates.java 2011-03-18 18:50:32 UTC (rev 3008)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushAggregates.java 2011-03-19 01:18:44 UTC (rev 3009)
@@ -186,7 +186,7 @@
Map<ElementSymbol, List<Set<Constant>>> partitionInfo = (Map<ElementSymbol, List<Set<Constant>>>)child.getProperty(Info.PARTITION_INFO);
//check to see if any aggregate is dependent upon cardinality
- boolean cardinalityDependent = RuleRemoveOptionalJoins.areAggregatesCardinalityDependent(aggregates);
+ boolean cardinalityDependent = AggregateSymbol.areAggregatesCardinalityDependent(aggregates);
LinkedList<PlanNode> unionChildren = new LinkedList<PlanNode>();
findUnionChildren(unionChildren, cardinalityDependent, setOp);
@@ -747,7 +747,7 @@
if (originatingNode.getParent() == groupNode) {
//anything logically applied after the join and is
//dependent upon the cardinality prevents us from optimizing.
- if (aggs && RuleRemoveOptionalJoins.isCardinalityDependent((AggregateSymbol)aggregateSymbol)) {
+ if (aggs && ((AggregateSymbol)aggregateSymbol).isCardinalityDependent()) {
return null;
}
continue;
Modified: trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleRemoveOptionalJoins.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleRemoveOptionalJoins.java 2011-03-18 18:50:32 UTC (rev 3008)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleRemoveOptionalJoins.java 2011-03-19 01:18:44 UTC (rev 3009)
@@ -226,7 +226,7 @@
}
case NodeConstants.Types.GROUP: {
Set<AggregateSymbol> aggs = RulePushAggregates.collectAggregates(parent);
- return areAggregatesCardinalityDependent(aggs);
+ return AggregateSymbol.areAggregatesCardinalityDependent(aggs);
}
case NodeConstants.Types.TUPLE_LIMIT: {
if (!(parent.getProperty(NodeConstants.Info.MAX_TUPLE_LIMIT) instanceof Constant)
@@ -245,33 +245,7 @@
return true;
}
- static boolean areAggregatesCardinalityDependent(Set<AggregateSymbol> aggs) {
- for (AggregateSymbol aggregateSymbol : aggs) {
- if (isCardinalityDependent(aggregateSymbol)) {
- return true;
- }
- }
- return false;
- }
-
- static boolean isCardinalityDependent(AggregateSymbol aggregateSymbol) {
- if (aggregateSymbol.isDistinct()) {
- return false;
- }
- switch (aggregateSymbol.getAggregateFunction()) {
- case COUNT:
- case AVG:
- case STDDEV_POP:
- case STDDEV_SAMP:
- case VAR_POP:
- case VAR_SAMP:
- case SUM:
- return true;
- }
- return false;
- }
-
- public String toString() {
+ public String toString() {
return "RuleRemoveOptionalJoins"; //$NON-NLS-1$
}
Modified: trunk/engine/src/main/java/org/teiid/query/resolver/QueryResolver.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/resolver/QueryResolver.java 2011-03-18 18:50:32 UTC (rev 3008)
+++ trunk/engine/src/main/java/org/teiid/query/resolver/QueryResolver.java 2011-03-19 01:18:44 UTC (rev 3009)
@@ -222,7 +222,6 @@
TempMetadataStore result = resolveCommand(currentCommand, metadata, false);
if (replaceBindings && symbolMap != null && !symbolMap.isEmpty()) {
ExpressionMappingVisitor emv = new ExpressionMappingVisitor(symbolMap);
- emv.setClone(true);
DeepPostOrderNavigator.doVisit(currentCommand, emv);
}
return result;
Modified: trunk/engine/src/main/java/org/teiid/query/rewriter/QueryRewriter.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/rewriter/QueryRewriter.java 2011-03-18 18:50:32 UTC (rev 3008)
+++ trunk/engine/src/main/java/org/teiid/query/rewriter/QueryRewriter.java 2011-03-19 01:18:44 UTC (rev 3009)
@@ -55,6 +55,7 @@
import org.teiid.core.util.Assertion;
import org.teiid.core.util.TimestampWithTimezone;
import org.teiid.language.SQLConstants.NonReserved;
+import org.teiid.metadata.FunctionMethod.Determinism;
import org.teiid.query.QueryPlugin;
import org.teiid.query.eval.Evaluator;
import org.teiid.query.function.FunctionDescriptor;
@@ -62,6 +63,7 @@
import org.teiid.query.function.FunctionMethods;
import org.teiid.query.metadata.QueryMetadataInterface;
import org.teiid.query.metadata.TempMetadataAdapter;
+import org.teiid.query.metadata.TempMetadataID;
import org.teiid.query.metadata.TempMetadataStore;
import org.teiid.query.optimizer.relational.rules.NewCalculateCostUtil;
import org.teiid.query.optimizer.relational.rules.RuleMergeCriteria;
@@ -159,6 +161,8 @@
import org.teiid.query.sql.visitor.ElementCollectorVisitor;
import org.teiid.query.sql.visitor.EvaluatableVisitor;
import org.teiid.query.sql.visitor.ExpressionMappingVisitor;
+import org.teiid.query.sql.visitor.FunctionCollectorVisitor;
+import org.teiid.query.sql.visitor.ValueIteratorProviderCollectorVisitor;
import org.teiid.query.sql.visitor.EvaluatableVisitor.EvaluationLevel;
import org.teiid.query.util.CommandContext;
import org.teiid.query.validator.UpdateValidator.UpdateInfo;
@@ -685,6 +689,8 @@
continue;
}
if (plannedResult.query.getCorrelatedReferences() == null) {
+ //create the correlated refs if they exist
+ //there is a little bit of a design problem here that null usually means no refs.
ArrayList<Reference> correlatedReferences = new ArrayList<Reference>();
CorrelatedReferenceCollectorVisitor.collectReferences(plannedResult.query, groups, correlatedReferences);
if (!correlatedReferences.isEmpty()) {
@@ -695,26 +701,30 @@
plannedResult.query.setCorrelatedReferences(map);
}
}
- if (!rmc.planQuery(groups, true, plannedResult)) {
+ boolean requiresDistinct = requiresDistinctRows(query);
+ if (!rmc.planQuery(groups, requiresDistinct, plannedResult)) {
continue;
}
- HashSet<GroupSymbol> keyPreservingGroups = new HashSet<GroupSymbol>();
- if (query.getFrom().getClauses().size() > 1) {
- continue;
+ if (requiresDistinct) {
+ //check for key preservation
+ HashSet<GroupSymbol> keyPreservingGroups = new HashSet<GroupSymbol>();
+ ResolverUtil.findKeyPreserved(query, keyPreservingGroups, metadata);
+ if (!NewCalculateCostUtil.usesKey(plannedResult.leftExpressions, keyPreservingGroups, metadata, true)) {
+ //if not key perserved then the semi-join will not remain in tact
+ continue;
+ }
}
- ResolverUtil.findKeyPreserved(query, keyPreservingGroups, metadata);
- if (!NewCalculateCostUtil.usesKey(plannedResult.leftExpressions, keyPreservingGroups, metadata, true)) {
- continue;
- }
crits.remove();
GroupSymbol viewName = RulePlaceAccess.recontextSymbol(new GroupSymbol("X"), names); //$NON-NLS-1$
+ viewName.setName(viewName.getCanonicalName());
+ viewName.setDefinition(null);
Query q = createInlineViewQuery(viewName, plannedResult.query, metadata, plannedResult.query.getSelect().getProjectedSymbols());
- Iterator iter = q.getSelect().getProjectedSymbols().iterator();
+ Iterator<SingleElementSymbol> iter = q.getSelect().getProjectedSymbols().iterator();
HashMap<Expression, SingleElementSymbol> expressionMap = new HashMap<Expression, SingleElementSymbol>();
- for (SingleElementSymbol symbol : (List<SingleElementSymbol>)plannedResult.query.getSelect().getProjectedSymbols()) {
- expressionMap.put(SymbolMap.getExpression(symbol), (SingleElementSymbol)iter.next());
+ for (SingleElementSymbol symbol : plannedResult.query.getSelect().getProjectedSymbols()) {
+ expressionMap.put(SymbolMap.getExpression(symbol), iter.next());
}
for (int i = 0; i < plannedResult.leftExpressions.size(); i++) {
plannedResult.nonEquiJoinCriteria.add(new CompareCriteria(SymbolMap.getExpression((Expression)plannedResult.leftExpressions.get(i)), CompareCriteria.EQ, (Expression)plannedResult.rightExpressions.get(i)));
@@ -729,6 +739,32 @@
query.setCriteria(Criteria.combineCriteria(query.getCriteria(), Criteria.combineCriteria(current)));
}
+ private boolean requiresDistinctRows(Query query) {
+ Set<AggregateSymbol> aggs = new HashSet<AggregateSymbol>();
+ aggs.addAll(AggregateSymbolCollectorVisitor.getAggregates(query.getSelect(), false));
+ aggs.addAll(AggregateSymbolCollectorVisitor.getAggregates(query.getHaving(), false));
+ if (!aggs.isEmpty() || query.getGroupBy() != null) {
+ if (!AggregateSymbol.areAggregatesCardinalityDependent(aggs)) {
+ return false;
+ }
+ } else if (query.getSelect().isDistinct()) {
+ for (SingleElementSymbol projectSymbol : query.getSelect().getProjectedSymbols()) {
+ Expression ex = SymbolMap.getExpression(projectSymbol);
+ Collection<Function> functions = FunctionCollectorVisitor.getFunctions(ex, true, false);
+ for (Function function : functions) {
+ if ( function.getFunctionDescriptor().getDeterministic() == Determinism.NONDETERMINISTIC) {
+ return true;
+ }
+ }
+ if (!ValueIteratorProviderCollectorVisitor.getValueIteratorProviders(ex).isEmpty()) {
+ return true;
+ }
+ }
+ return false;
+ }
+ return true;
+ }
+
/**
* Converts a group by with expressions into a group by with only element symbols and an inline view
* @param query
@@ -792,10 +828,10 @@
} catch (TeiidException err) {
throw new TeiidRuntimeException(err);
}
- Iterator iter = outerQuery.getSelect().getProjectedSymbols().iterator();
+ Iterator<SingleElementSymbol> iter = outerQuery.getSelect().getProjectedSymbols().iterator();
HashMap<Expression, SingleElementSymbol> expressionMap = new HashMap<Expression, SingleElementSymbol>();
- for (SingleElementSymbol symbol : (List<SingleElementSymbol>)query.getSelect().getProjectedSymbols()) {
- expressionMap.put(SymbolMap.getExpression(symbol), (SingleElementSymbol)iter.next());
+ for (SingleElementSymbol symbol : query.getSelect().getProjectedSymbols()) {
+ expressionMap.put(SymbolMap.getExpression(symbol), iter.next());
}
ExpressionMappingVisitor.mapExpressions(groupBy, expressionMap);
outerQuery.setGroupBy(groupBy);
@@ -819,7 +855,7 @@
return false;
}
HashSet<Expression> selectExpressions = new HashSet<Expression>();
- for (SingleElementSymbol selectExpr : (List<SingleElementSymbol>)query.getSelect().getProjectedSymbols()) {
+ for (SingleElementSymbol selectExpr : query.getSelect().getProjectedSymbols()) {
selectExpressions.add(SymbolMap.getExpression(selectExpr));
}
for (SingleElementSymbol groupByExpr : (List<SingleElementSymbol>)groupBy.getSymbols()) {
@@ -873,7 +909,7 @@
return queryCommand;
}
Select select = queryCommand.getProjectedQuery().getSelect();
- final List projectedSymbols = select.getProjectedSymbols();
+ final List<SingleElementSymbol> projectedSymbols = select.getProjectedSymbols();
LinkedList<OrderByItem> unrelatedItems = new LinkedList<OrderByItem>();
@@ -904,10 +940,10 @@
try {
top = createInlineViewQuery(new GroupSymbol("X"), query, metadata, select.getProjectedSymbols()); //$NON-NLS-1$
- Iterator iter = top.getSelect().getProjectedSymbols().iterator();
+ Iterator<SingleElementSymbol> iter = top.getSelect().getProjectedSymbols().iterator();
HashMap<Expression, SingleElementSymbol> expressionMap = new HashMap<Expression, SingleElementSymbol>();
- for (SingleElementSymbol symbol : (List<SingleElementSymbol>)select.getProjectedSymbols()) {
- SingleElementSymbol ses = (SingleElementSymbol)iter.next();
+ for (SingleElementSymbol symbol : select.getProjectedSymbols()) {
+ SingleElementSymbol ses = iter.next();
expressionMap.put(SymbolMap.getExpression(symbol), ses);
expressionMap.put(new ElementSymbol(symbol.getName()), ses);
}
@@ -2739,8 +2775,8 @@
Query firstProject = ((QueryCommand)nested).getProjectedQuery();
makeSelectUnique(firstProject.getSelect(), false);
}
- store.addTempGroup(inlineGroup.getName(), nested.getProjectedSymbols());
- inlineGroup.setMetadataID(store.getTempGroupID(inlineGroup.getName()));
+ TempMetadataID gid = store.addTempGroup(inlineGroup.getName(), nested.getProjectedSymbols());
+ inlineGroup.setMetadataID(gid);
List<Class<?>> actualTypes = new ArrayList<Class<?>>(nested.getProjectedSymbols().size());
for (SingleElementSymbol ses : actualSymbols) {
Modified: trunk/engine/src/main/java/org/teiid/query/sql/lang/Select.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/lang/Select.java 2011-03-18 18:50:32 UTC (rev 3008)
+++ trunk/engine/src/main/java/org/teiid/query/sql/lang/Select.java 2011-03-19 01:18:44 UTC (rev 3009)
@@ -22,12 +22,22 @@
package org.teiid.query.sql.lang;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
import org.teiid.core.util.EquivalenceUtil;
import org.teiid.core.util.HashCodeUtil;
-import org.teiid.query.sql.*;
-import org.teiid.query.sql.symbol.*;
+import org.teiid.query.sql.LanguageObject;
+import org.teiid.query.sql.LanguageVisitor;
+import org.teiid.query.sql.symbol.AllInGroupSymbol;
+import org.teiid.query.sql.symbol.AllSymbol;
+import org.teiid.query.sql.symbol.ElementSymbol;
+import org.teiid.query.sql.symbol.GroupSymbol;
+import org.teiid.query.sql.symbol.MultipleElementSymbol;
+import org.teiid.query.sql.symbol.SelectSymbol;
+import org.teiid.query.sql.symbol.SingleElementSymbol;
import org.teiid.query.sql.visitor.SQLStringVisitor;
@@ -200,15 +210,15 @@
* single column.
* @return Ordered list of SingleElementSymbol
*/
- public List getProjectedSymbols() {
- ArrayList projectedSymbols = new ArrayList();
+ public List<SingleElementSymbol> getProjectedSymbols() {
+ ArrayList<SingleElementSymbol> projectedSymbols = new ArrayList<SingleElementSymbol>();
Iterator iter = symbols.iterator();
while(iter.hasNext()) {
SelectSymbol symbol = (SelectSymbol) iter.next();
if(symbol instanceof SingleElementSymbol) {
- projectedSymbols.add(symbol);
+ projectedSymbols.add((SingleElementSymbol)symbol);
} else {
- List multiSymbols = ((MultipleElementSymbol)symbol).getElementSymbols();
+ List<ElementSymbol> multiSymbols = ((MultipleElementSymbol)symbol).getElementSymbols();
if(multiSymbols != null) {
projectedSymbols.addAll(multiSymbols);
}
Modified: trunk/engine/src/main/java/org/teiid/query/sql/symbol/AggregateSymbol.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/symbol/AggregateSymbol.java 2011-03-18 18:50:32 UTC (rev 3008)
+++ trunk/engine/src/main/java/org/teiid/query/sql/symbol/AggregateSymbol.java 2011-03-19 01:18:44 UTC (rev 3009)
@@ -22,6 +22,7 @@
package org.teiid.query.sql.symbol;
+import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
@@ -244,5 +245,31 @@
&& EquivalenceUtil.areEqual(this.getExpression(), other.getExpression())
&& EquivalenceUtil.areEqual(this.getOrderBy(), other.getOrderBy());
}
+
+ public boolean isCardinalityDependent() {
+ if (isDistinct()) {
+ return false;
+ }
+ switch (getAggregateFunction()) {
+ case COUNT:
+ case AVG:
+ case STDDEV_POP:
+ case STDDEV_SAMP:
+ case VAR_POP:
+ case VAR_SAMP:
+ case SUM:
+ return true;
+ }
+ return false;
+ }
+ public static boolean areAggregatesCardinalityDependent(Collection<AggregateSymbol> aggs) {
+ for (AggregateSymbol aggregateSymbol : aggs) {
+ if (aggregateSymbol.isCardinalityDependent()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
}
Modified: trunk/engine/src/main/java/org/teiid/query/sql/visitor/AggregateSymbolCollectorVisitor.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/visitor/AggregateSymbolCollectorVisitor.java 2011-03-18 18:50:32 UTC (rev 3008)
+++ trunk/engine/src/main/java/org/teiid/query/sql/visitor/AggregateSymbolCollectorVisitor.java 2011-03-19 01:18:44 UTC (rev 3009)
@@ -24,6 +24,7 @@
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.HashSet;
import org.teiid.query.sql.LanguageObject;
@@ -98,6 +99,9 @@
}
public static final Collection<AggregateSymbol> getAggregates(LanguageObject obj, boolean removeDuplicates) {
+ if (obj == null) {
+ return Collections.emptyList();
+ }
Collection<AggregateSymbol> aggregates = null;
if (removeDuplicates) {
aggregates = new HashSet<AggregateSymbol>();
Modified: trunk/engine/src/main/java/org/teiid/query/sql/visitor/ExpressionMappingVisitor.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/visitor/ExpressionMappingVisitor.java 2011-03-18 18:50:32 UTC (rev 3008)
+++ trunk/engine/src/main/java/org/teiid/query/sql/visitor/ExpressionMappingVisitor.java 2011-03-19 01:18:44 UTC (rev 3009)
@@ -77,7 +77,7 @@
public class ExpressionMappingVisitor extends LanguageVisitor {
private Map symbolMap;
- private boolean clone;
+ private boolean clone = true;
/**
* Constructor for ExpressionMappingVisitor.
Modified: trunk/engine/src/test/java/org/teiid/query/optimizer/TestSubqueryPushdown.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/optimizer/TestSubqueryPushdown.java 2011-03-18 18:50:32 UTC (rev 3008)
+++ trunk/engine/src/test/java/org/teiid/query/optimizer/TestSubqueryPushdown.java 2011-03-19 01:18:44 UTC (rev 3009)
@@ -754,8 +754,26 @@
ProcessorPlan plan = helpPlan("Select e1, (select e1 FROM pm2.g1 where e1 = 'x') from pm1.g1", FakeMetadataFactory.example1Cached(), //$NON-NLS-1$
new String[] { "SELECT g_0.e1, (SELECT g_0.e1 FROM pm2.g1 AS g_0 WHERE g_0.e1 = 'x') FROM pm1.g1 AS g_0" }, ComparisonMode.EXACT_COMMAND_STRING); //$NON-NLS-1$
checkNodeTypes(plan, FULL_PUSHDOWN);
- }
+ }
+ @Test public void testSubqueryRewriteToJoinDistinct() throws Exception {
+ TestQueryRewriter.helpTestRewriteCommand("Select distinct e1 from pm1.g1 as x where exists (select pm1.g1.e1 FROM pm1.g1 where e1 = x.e1)", "SELECT DISTINCT e1 FROM pm1.g1 AS x, (SELECT pm1.g1.e1 FROM pm1.g1) AS X__1 WHERE x.e1 = X__1.e1", FakeMetadataFactory.example1Cached());
+ }
+
+ /**
+ * Agg does not depend on cardinality
+ */
+ @Test public void testSubqueryRewriteToJoinGroupBy() throws Exception {
+ TestQueryRewriter.helpTestRewriteCommand("Select max(e1) from pm1.g1 as x where exists (select pm1.g1.e1 FROM pm1.g1 where e1 = x.e1) group by e2", "SELECT MAX(e1) FROM pm1.g1 AS x, (SELECT pm1.g1.e1 FROM pm1.g1) AS X__1 WHERE x.e1 = X__1.e1 GROUP BY e2", FakeMetadataFactory.example1Cached());
+ }
+
+ /**
+ * Agg does depend on cardinality
+ */
+ @Test public void testSubqueryRewriteToJoinGroupBy1() throws Exception {
+ TestQueryRewriter.helpTestRewriteCommand("Select avg(e1) from pm1.g1 as x where exists (select pm1.g1.e1 FROM pm1.g1 where e1 = x.e1) group by e2", "SELECT AVG(e1) FROM pm1.g1 AS x WHERE EXISTS (SELECT pm1.g1.e1 FROM pm1.g1 WHERE e1 = x.e1 LIMIT 1) GROUP BY e2", FakeMetadataFactory.example1Cached());
+ }
+
@Test public void testSubqueryRewriteToJoin() throws Exception {
TestQueryRewriter.helpTestRewriteCommand("Select e1 from pm3.g1 where exists (select pm1.g1.e1 FROM pm1.g1 where e1 = pm3.g1.e1)", "SELECT e1 FROM pm3.g1, (SELECT pm1.g1.e1 FROM pm1.g1) AS X__1 WHERE pm3.g1.e1 = X__1.e1", FakeMetadataFactory.example4());
}
13 years, 9 months
teiid SVN: r3008 - in trunk: engine/src/main/java/org/teiid/query/eval and 11 other directories.
by teiid-commits@lists.jboss.org
Author: shawkins
Date: 2011-03-18 14:50:32 -0400 (Fri, 18 Mar 2011)
New Revision: 3008
Modified:
trunk/engine/src/main/java/org/teiid/dqp/internal/datamgr/LanguageBridgeFactory.java
trunk/engine/src/main/java/org/teiid/query/eval/Evaluator.java
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/CriteriaCapabilityValidatorVisitor.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/RuleMergeCriteria.java
trunk/engine/src/main/java/org/teiid/query/parser/SQLParserUtil.java
trunk/engine/src/main/java/org/teiid/query/rewriter/QueryRewriter.java
trunk/engine/src/main/java/org/teiid/query/sql/lang/ExistsCriteria.java
trunk/engine/src/main/java/org/teiid/query/sql/lang/JoinType.java
trunk/engine/src/main/java/org/teiid/query/sql/lang/SubquerySetCriteria.java
trunk/engine/src/main/java/org/teiid/query/sql/visitor/SQLStringVisitor.java
trunk/engine/src/main/java/org/teiid/query/validator/AggregateValidationVisitor.java
trunk/engine/src/main/javacc/org/teiid/query/parser/SQLParser.jj
trunk/engine/src/test/java/org/teiid/dqp/internal/datamgr/TestExistsCriteriaImpl.java
trunk/engine/src/test/java/org/teiid/query/optimizer/TestAggregatePushdown.java
trunk/engine/src/test/java/org/teiid/query/optimizer/TestOptimizer.java
trunk/engine/src/test/java/org/teiid/query/optimizer/TestSubqueryPushdown.java
trunk/engine/src/test/java/org/teiid/query/parser/TestOptionsAndHints.java
trunk/engine/src/test/java/org/teiid/query/parser/TestParser.java
trunk/test-integration/common/src/test/java/org/teiid/dqp/internal/process/TestTPCR.java
Log:
TEIID-1497 adding a merge join hint to in/exists subqueries
Modified: trunk/engine/src/main/java/org/teiid/dqp/internal/datamgr/LanguageBridgeFactory.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/dqp/internal/datamgr/LanguageBridgeFactory.java 2011-03-18 15:30:08 UTC (rev 3007)
+++ trunk/engine/src/main/java/org/teiid/dqp/internal/datamgr/LanguageBridgeFactory.java 2011-03-18 18:50:32 UTC (rev 3008)
@@ -349,8 +349,12 @@
return result;
}
- Exists translate(ExistsCriteria criteria) {
- return new Exists(translate(criteria.getCommand()));
+ Condition translate(ExistsCriteria criteria) {
+ Exists exists = new Exists(translate(criteria.getCommand()));
+ if (criteria.isNegated()) {
+ return new Not(exists);
+ }
+ return exists;
}
IsNull translate(IsNullCriteria criteria) {
Modified: trunk/engine/src/main/java/org/teiid/query/eval/Evaluator.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/eval/Evaluator.java 2011-03-18 15:30:08 UTC (rev 3007)
+++ trunk/engine/src/main/java/org/teiid/query/eval/Evaluator.java 2011-03-18 18:50:32 UTC (rev 3008)
@@ -588,9 +588,9 @@
throw new ExpressionEvaluationException(e, e.getMessage());
}
if(valueIter.hasNext()) {
- return true;
+ return !criteria.isNegated();
}
- return false;
+ return criteria.isNegated();
}
public Object evaluate(Expression expression, List<?> tuple)
Modified: trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/CriteriaCapabilityValidatorVisitor.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/CriteriaCapabilityValidatorVisitor.java 2011-03-18 15:30:08 UTC (rev 3007)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/CriteriaCapabilityValidatorVisitor.java 2011-03-18 18:50:32 UTC (rev 3008)
@@ -327,6 +327,11 @@
return;
}
+ if (crit.isNegated() && !this.caps.supportsCapability(Capability.CRITERIA_NOT)) {
+ markInvalid(crit, "Negation is not supported by source"); //$NON-NLS-1$
+ return;
+ }
+
try {
if (validateSubqueryPushdown(crit, modelID, metadata, capFinder, analysisRecord) == null) {
if (crit.getCommand().getCorrelatedReferences() == null) {
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 2011-03-18 15:30:08 UTC (rev 3007)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/NewCalculateCostUtil.java 2011-03-18 18:50:32 UTC (rev 3008)
@@ -602,7 +602,7 @@
return;
}
- float cardinality = getNDVEstimate(node, metadata, childCost, expressions, false);
+ float cardinality = getNDVEstimate(node, metadata, childCost, expressions, true);
setCardinalityEstimate(node, cardinality, true, metadata);
}
@@ -1283,6 +1283,8 @@
ndv = cardinality;
} else if (useCardinalityIfUnknown) {
ndv = cardinality/2;
+ } else {
+ return UNKNOWN_VALUE;
}
}
return Math.max(1, ndv);
Modified: trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleMergeCriteria.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleMergeCriteria.java 2011-03-18 15:30:08 UTC (rev 3007)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleMergeCriteria.java 2011-03-18 18:50:32 UTC (rev 3008)
@@ -33,6 +33,8 @@
import org.teiid.api.exception.query.QueryMetadataException;
import org.teiid.api.exception.query.QueryPlannerException;
+import org.teiid.client.plan.Annotation;
+import org.teiid.client.plan.Annotation.Priority;
import org.teiid.core.TeiidComponentException;
import org.teiid.core.id.IDGenerator;
import org.teiid.query.analysis.AnalysisRecord;
@@ -119,6 +121,7 @@
public List<Criteria> nonEquiJoinCriteria = new LinkedList<Criteria>();
public Criteria additionalCritieria;
public Class<?> type;
+ public boolean mergeJoin;
}
private IDGenerator idGenerator;
@@ -143,7 +146,7 @@
// Find strings of criteria and merge them, removing duplicates
List<PlanNode> criteriaChains = new ArrayList<PlanNode>();
- findCriteriaChains(plan, criteriaChains);
+ findCriteriaChains(plan, criteriaChains, analysisRecord);
// Merge chains
for (PlanNode critNode : criteriaChains) {
@@ -158,7 +161,7 @@
* @param node Root node to search
* @param foundNodes Roots of criteria chains
*/
- void findCriteriaChains(PlanNode root, List<PlanNode> foundNodes)
+ void findCriteriaChains(PlanNode root, List<PlanNode> foundNodes, AnalysisRecord analysisRecord)
throws QueryPlannerException, TeiidComponentException {
PlanNode recurseRoot = root;
@@ -167,7 +170,7 @@
// Walk to end of the chain and change recurse root
while(recurseRoot.getType() == NodeConstants.Types.SELECT) {
// Look for opportunities to replace with a semi-join
- recurseRoot = planSemiJoin(recurseRoot, root);
+ recurseRoot = planMergeJoin(recurseRoot, root, analysisRecord);
if (root.getChildCount() == 0) {
root = recurseRoot.getFirstChild();
if (root.getType() != NodeConstants.Types.SELECT) {
@@ -186,7 +189,7 @@
if (recurseRoot.getType() != NodeConstants.Types.ACCESS) {
for (PlanNode child : recurseRoot.getChildren()) {
- findCriteriaChains(child, foundNodes);
+ findCriteriaChains(child, foundNodes, analysisRecord);
}
}
}
@@ -242,24 +245,24 @@
*
* TODO: it would be good to have a hint to force
*/
- private PlanNode planSemiJoin(PlanNode current, PlanNode root) throws QueryMetadataException,
+ private PlanNode planMergeJoin(PlanNode current, PlanNode root, AnalysisRecord analysisRecord) throws QueryMetadataException,
TeiidComponentException {
- float sourceCost = NewCalculateCostUtil.computeCostForTree(current, metadata);
- if (sourceCost != NewCalculateCostUtil.UNKNOWN_VALUE
- && sourceCost < RuleChooseDependent.DEFAULT_INDEPENDENT_CARDINALITY) {
- //TODO: see if a dependent join applies
- return current;
- }
+ float sourceCost = NewCalculateCostUtil.computeCostForTree(current.getFirstChild(), metadata);
Criteria crit = (Criteria)current.getProperty(NodeConstants.Info.SELECT_CRITERIA);
PlannedResult plannedResult = findSubquery(crit);
if (plannedResult.query == null) {
return current;
}
+ if (sourceCost != NewCalculateCostUtil.UNKNOWN_VALUE
+ && sourceCost < RuleChooseDependent.DEFAULT_INDEPENDENT_CARDINALITY && !plannedResult.mergeJoin) {
+ //TODO: see if a dependent join applies the other direction
+ return current;
+ }
RelationalPlan originalPlan = (RelationalPlan)plannedResult.query.getProcessorPlan();
Number originalCardinality = originalPlan.getRootNode().getEstimateNodeCardinality();
- if (originalCardinality.floatValue() == NewCalculateCostUtil.UNKNOWN_VALUE) {
+ if (!plannedResult.mergeJoin && originalCardinality.floatValue() == NewCalculateCostUtil.UNKNOWN_VALUE) {
//TODO: this check isn't really accurate - exists and scalarsubqueries will always have cardinality 2/1
//if it's currently unknown, removing criteria won't make it any better
return current;
@@ -268,6 +271,9 @@
Collection<GroupSymbol> leftGroups = FrameUtil.findJoinSourceNode(current).getGroups();
if (!planQuery(leftGroups, false, plannedResult)) {
+ if (plannedResult.mergeJoin && analysisRecord != null && analysisRecord.recordAnnotations()) {
+ this.analysisRecord.addAnnotation(new Annotation(Annotation.HINTS, "could not plan as a merge join: " + crit, "ignoring hint", Priority.MEDIUM)); //$NON-NLS-1$ //$NON-NLS-2$
+ }
return current;
}
@@ -283,18 +289,26 @@
List<SingleElementSymbol> projectedSymbols = LanguageObject.Util.deepClone(plannedResult.query.getProjectedSymbols(), SingleElementSymbol.class);
//NOTE: we could tap into the relationalplanner at a lower level to get this in a plan node form,
//the major benefit would be to reuse the dependent join planning logic if possible.
+ if (analysisRecord != null && analysisRecord.recordDebug()) {
+ analysisRecord.println("Attempting to plan " + crit + " as a mege join"); //$NON-NLS-1$ //$NON-NLS-2$
+ }
RelationalPlan subPlan = (RelationalPlan)QueryOptimizer.optimizePlan(plannedResult.query, metadata, idGenerator, capFinder, analysisRecord, context);
- Number planCardinality = subPlan.getRootNode().getEstimateNodeCardinality();
+ Number planCardinality = subPlan.getRootNode().getEstimateNodeCardinality();
- if (planCardinality.floatValue() == NewCalculateCostUtil.UNKNOWN_VALUE
- || planCardinality.floatValue() > 10000000
- || (sourceCost == NewCalculateCostUtil.UNKNOWN_VALUE && planCardinality.floatValue() > 1000)
- || (sourceCost != NewCalculateCostUtil.UNKNOWN_VALUE && sourceCost * originalCardinality.floatValue() < planCardinality.floatValue() / (100 * Math.log(Math.max(4, sourceCost))))) {
- //bail-out if both are unknown or the new plan is too large
- return current;
- }
+ if (!plannedResult.mergeJoin) {
+ //if we don't have a specific hint, then use costing
+ if (planCardinality.floatValue() == NewCalculateCostUtil.UNKNOWN_VALUE
+ || planCardinality.floatValue() > 10000000
+ || (sourceCost == NewCalculateCostUtil.UNKNOWN_VALUE && planCardinality.floatValue() > 1000)
+ || (sourceCost != NewCalculateCostUtil.UNKNOWN_VALUE && sourceCost * originalCardinality.floatValue() < planCardinality.floatValue() / (100 * Math.log(Math.max(4, sourceCost))))) {
+ //bail-out if both are unknown or the new plan is too large
+ if (analysisRecord != null && analysisRecord.recordDebug()) {
+ analysisRecord.println("Failed to use mege join, as the cost was not favorable. Use the MJ hint to force."); //$NON-NLS-1$
+ }
+ return current;
+ }
+ }
- //TODO: don't allow if too large
PlanNode semiJoin = NodeFactory.getNewNode(NodeConstants.Types.JOIN);
semiJoin.addGroups(current.getGroups());
semiJoin.setProperty(NodeConstants.Info.JOIN_STRATEGY, JoinStrategyType.MERGE);
@@ -336,6 +350,7 @@
SubquerySetCriteria ssc = (SubquerySetCriteria)crit;
result.not ^= ssc.isNegated();
result.type = crit.getClass();
+ result.mergeJoin = ssc.isMergeJoin();
crit = new SubqueryCompareCriteria(ssc.getExpression(), ssc.getCommand(), SubqueryCompareCriteria.EQ, SubqueryCompareCriteria.SOME);
} else if (crit instanceof CompareCriteria) {
//convert to the quantified form
@@ -343,6 +358,7 @@
if (cc.getRightExpression() instanceof ScalarSubquery) {
ScalarSubquery ss = (ScalarSubquery)cc.getRightExpression();
result.type = ss.getClass();
+ //we can only use a semi-join if we know that 1 row will be present
if (ss.getCommand() instanceof Query) {
Query query = (Query)ss.getCommand();
if (query.getGroupBy() == null && query.hasAggregates()) {
@@ -378,8 +394,10 @@
return result;
}
result.type = crit.getClass();
+ result.not = exists.isNegated();
//the correlations can only be in where (if no group by or aggregates) or having
result.query = (Query)exists.getCommand();
+ result.mergeJoin = exists.isMergeJoin();
}
return result;
}
@@ -466,8 +484,6 @@
}
if (plannedResult.leftExpressions.isEmpty()) {
- //there's no equi-join
- //TODO: if there are correlations a "cross" join may still be preferable
return false;
}
Modified: trunk/engine/src/main/java/org/teiid/query/parser/SQLParserUtil.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/parser/SQLParserUtil.java 2011-03-18 15:30:08 UTC (rev 3007)
+++ trunk/engine/src/main/java/org/teiid/query/parser/SQLParserUtil.java 2011-03-18 18:50:32 UTC (rev 3008)
@@ -39,6 +39,7 @@
import org.teiid.query.sql.lang.QueryCommand;
import org.teiid.query.sql.lang.SetQuery;
import org.teiid.query.sql.proc.CriteriaSelector;
+import org.teiid.query.sql.visitor.SQLStringVisitor;
public class SQLParserUtil {
@@ -165,8 +166,18 @@
}
}
}
-
- private String getComment(Token t) {
+
+ boolean isMergeJoin(Token t) {
+ String[] parts = getComment(t).split("\\s"); //$NON-NLS-1$
+ for (int i = 0; i < parts.length; i++) {
+ if (parts[i].equalsIgnoreCase(SQLStringVisitor.MJ)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ String getComment(Token t) {
Token optToken = t.specialToken;
if (optToken == null) {
return ""; //$NON-NLS-1$
Modified: trunk/engine/src/main/java/org/teiid/query/rewriter/QueryRewriter.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/rewriter/QueryRewriter.java 2011-03-18 15:30:08 UTC (rev 3007)
+++ trunk/engine/src/main/java/org/teiid/query/rewriter/QueryRewriter.java 2011-03-18 18:50:32 UTC (rev 3008)
@@ -1134,7 +1134,7 @@
}
rewriteSubqueryContainer((SubqueryContainer)criteria, true);
if (!RelationalNodeUtil.shouldExecute(exists.getCommand(), false, true)) {
- return FALSE_CRITERIA;
+ return exists.isNegated()?TRUE_CRITERIA:FALSE_CRITERIA;
}
if (exists.getCommand().getProcessorPlan() == null) {
addImplicitLimit(exists, 1);
Modified: trunk/engine/src/main/java/org/teiid/query/sql/lang/ExistsCriteria.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/lang/ExistsCriteria.java 2011-03-18 15:30:08 UTC (rev 3007)
+++ trunk/engine/src/main/java/org/teiid/query/sql/lang/ExistsCriteria.java 2011-03-18 18:50:32 UTC (rev 3008)
@@ -27,6 +27,7 @@
import org.teiid.core.util.EquivalenceUtil;
import org.teiid.core.util.HashCodeUtil;
import org.teiid.query.sql.LanguageVisitor;
+import org.teiid.query.sql.lang.PredicateCriteria.Negatable;
import org.teiid.query.sql.symbol.ContextReference;
import org.teiid.query.sql.symbol.Expression;
@@ -37,13 +38,15 @@
* "EXISTS (Select EmployeeID FROM Employees WHERE EmployeeName = 'Smith')".
*/
public class ExistsCriteria extends PredicateCriteria
-implements SubqueryContainer<QueryCommand>, ContextReference {
+implements SubqueryContainer<QueryCommand>, ContextReference, Negatable {
private static AtomicInteger ID = new AtomicInteger();
private QueryCommand command;
private String id = "$ec/id" + ID.getAndIncrement(); //$NON-NLS-1$
private boolean shouldEvaluate;
+ private boolean mergeJoin;
+ private boolean negated;
/**
* Default constructor
@@ -51,6 +54,14 @@
public ExistsCriteria() {
super();
}
+
+ public void setMergeJoin(boolean semiJoin) {
+ this.mergeJoin = semiJoin;
+ }
+
+ public boolean isMergeJoin() {
+ return mergeJoin;
+ }
public ExistsCriteria(QueryCommand subqueryCommand){
this.command = subqueryCommand;
@@ -104,7 +115,6 @@
* @return True if equal
*/
public boolean equals(Object obj) {
- // Use super.equals() to check obvious stuff and variable
if(obj == this) {
return true;
}
@@ -112,8 +122,12 @@
if(!(obj instanceof ExistsCriteria)) {
return false;
}
+
+ ExistsCriteria other = (ExistsCriteria)obj;
- return EquivalenceUtil.areEqual(getCommand(), ((ExistsCriteria)obj).getCommand());
+ return EquivalenceUtil.areEqual(getCommand(), other.getCommand()) &&
+ this.negated == other.negated &&
+ this.mergeJoin == other.mergeJoin;
}
/**
@@ -124,6 +138,22 @@
* @see java.lang.Object#clone()
*/
public Object clone() {
- return new ExistsCriteria((QueryCommand) this.command.clone());
+ ExistsCriteria ec = new ExistsCriteria((QueryCommand) this.command.clone());
+ ec.setMergeJoin(this.mergeJoin);
+ ec.setNegated(this.negated);
+ return ec;
}
+
+ public boolean isNegated() {
+ return negated;
+ }
+
+ public void setNegated(boolean negated) {
+ this.negated = negated;
+ }
+
+ @Override
+ public void negate() {
+ this.negated = !this.negated;
+ }
}
Modified: trunk/engine/src/main/java/org/teiid/query/sql/lang/JoinType.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/lang/JoinType.java 2011-03-18 15:30:08 UTC (rev 3007)
+++ trunk/engine/src/main/java/org/teiid/query/sql/lang/JoinType.java 2011-03-18 18:50:32 UTC (rev 3008)
@@ -22,7 +22,8 @@
package org.teiid.query.sql.lang;
-import org.teiid.query.sql.*;
+import org.teiid.query.sql.LanguageObject;
+import org.teiid.query.sql.LanguageVisitor;
import org.teiid.query.sql.visitor.SQLStringVisitor;
/**
@@ -102,10 +103,6 @@
return outer;
}
- public boolean isSemi() {
- return this.equals(JOIN_ANTI_SEMI) || this.equals(JOIN_SEMI);
- }
-
/**
* Override Object.equals() to compare objects
* @param other Other object
Modified: trunk/engine/src/main/java/org/teiid/query/sql/lang/SubquerySetCriteria.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/lang/SubquerySetCriteria.java 2011-03-18 15:30:08 UTC (rev 3007)
+++ trunk/engine/src/main/java/org/teiid/query/sql/lang/SubquerySetCriteria.java 2011-03-18 18:50:32 UTC (rev 3008)
@@ -42,6 +42,7 @@
private QueryCommand command;
private String id = "$ssc/id" + ID.getAndIncrement(); //$NON-NLS-1$
+ private boolean mergeJoin;
/**
* Constructor for SubquerySetCriteria.
@@ -55,6 +56,14 @@
setCommand(subCommand);
}
+ public boolean isMergeJoin() {
+ return mergeJoin;
+ }
+
+ public void setMergeJoin(boolean semiJoin) {
+ this.mergeJoin = semiJoin;
+ }
+
@Override
public String getContextSymbol() {
return id;
@@ -114,12 +123,11 @@
}
SubquerySetCriteria sc = (SubquerySetCriteria)obj;
- if (isNegated() ^ sc.isNegated()) {
- return false;
- }
- return EquivalenceUtil.areEqual(getExpression(), sc.getExpression()) &&
- EquivalenceUtil.areEqual(getCommand(), sc.getCommand());
+ return this.isNegated() == sc.isNegated() &&
+ EquivalenceUtil.areEqual(getExpression(), sc.getExpression()) &&
+ EquivalenceUtil.areEqual(getCommand(), sc.getCommand()) &&
+ this.mergeJoin == sc.mergeJoin;
}
/**
@@ -128,7 +136,7 @@
* (see #setValueIterator setValueIterator}).
* @return Deep copy of object
*/
- public Object clone() {
+ public SubquerySetCriteria clone() {
Expression copy = null;
if(getExpression() != null) {
copy = (Expression) getExpression().clone();
@@ -141,6 +149,7 @@
SubquerySetCriteria criteriaCopy = new SubquerySetCriteria(copy, copyCommand);
criteriaCopy.setNegated(isNegated());
+ criteriaCopy.mergeJoin = this.mergeJoin;
return criteriaCopy;
}
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 2011-03-18 15:30:08 UTC (rev 3007)
+++ trunk/engine/src/main/java/org/teiid/query/sql/visitor/SQLStringVisitor.java 2011-03-18 18:50:32 UTC (rev 3008)
@@ -144,6 +144,7 @@
private static final String BEGIN_HINT = "/*+"; //$NON-NLS-1$
private static final String END_HINT = "*/"; //$NON-NLS-1$
private static final char ID_ESCAPE_CHAR = '\"';
+ public static String MJ = "MJ"; //$NON-NLS-1$
protected StringBuilder parts = new StringBuilder();
@@ -1066,6 +1067,14 @@
append(SPACE);
}
append(IN);
+ if (obj.isMergeJoin()) {
+ append(SPACE);
+ append(BEGIN_HINT);
+ append(SPACE);
+ append(MJ);
+ append(SPACE);
+ append(END_HINT);
+ }
append(" ("); //$NON-NLS-1$
visitNode(obj.getCommand());
append(")"); //$NON-NLS-1$
@@ -1546,8 +1555,19 @@
}
public void visit( ExistsCriteria obj ) {
- // operator and beginning of list
+ if (obj.isNegated()) {
+ append(NOT);
+ append(SPACE);
+ }
append(EXISTS);
+ if (obj.isMergeJoin()) {
+ append(SPACE);
+ append(BEGIN_HINT);
+ append(SPACE);
+ append(MJ);
+ append(SPACE);
+ append(END_HINT);
+ }
append(" ("); //$NON-NLS-1$
visitNode(obj.getCommand());
append(")"); //$NON-NLS-1$
Modified: trunk/engine/src/main/java/org/teiid/query/validator/AggregateValidationVisitor.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/validator/AggregateValidationVisitor.java 2011-03-18 15:30:08 UTC (rev 3007)
+++ trunk/engine/src/main/java/org/teiid/query/validator/AggregateValidationVisitor.java 2011-03-18 18:50:32 UTC (rev 3008)
@@ -119,11 +119,11 @@
}
if(groupExpressions == null) {
- if (symbol instanceof ElementSymbol) {
+ if (symbol instanceof ElementSymbol && !((ElementSymbol)symbol).isExternalReference()) {
handleValidationError(QueryPlugin.Util.getString("ERR.015.012.0037", symbol), symbol); //$NON-NLS-1$
}
} else if(! groupExpressions.contains(symbol)) {
- if (symbol instanceof ElementSymbol) {
+ if (symbol instanceof ElementSymbol && !((ElementSymbol)symbol).isExternalReference()) {
handleValidationError(QueryPlugin.Util.getString("ERR.015.012.0038", symbol), symbol); //$NON-NLS-1$
}
} else {
Modified: trunk/engine/src/main/javacc/org/teiid/query/parser/SQLParser.jj
===================================================================
--- trunk/engine/src/main/javacc/org/teiid/query/parser/SQLParser.jj 2011-03-18 15:30:08 UTC (rev 3007)
+++ trunk/engine/src/main/javacc/org/teiid/query/parser/SQLParser.jj 2011-03-18 18:50:32 UTC (rev 3008)
@@ -2680,11 +2680,23 @@
QueryCommand subquery(ParseInfo info) :
{
+ Object[] result = null;
+}
+{
+ result = subqueryAndHint(info)
+ {
+ return (QueryCommand)result[0];
+ }
+}
+
+Object[] subqueryAndHint(ParseInfo info) :
+{
QueryCommand subquery = null;
StoredProcedure proc = null;
+ Token lparen = null;
}
{
- <LPAREN>
+ lparen = <LPAREN>
( subquery = queryExpression(info) |
(
proc = storedProcedure(info, new StoredProcedure()) //deprecated
@@ -2695,7 +2707,7 @@
)
<RPAREN>
{
- return subquery;
+ return new Object[] {subquery, isMergeJoin(lparen)};
}
}
@@ -2838,7 +2850,7 @@
{
Expression value = null;
List setList = new ArrayList();
- QueryCommand command = null;
+ Object[] command = null;
boolean negated = false;
AbstractSetCriteria criteria = null;
}
@@ -2846,7 +2858,7 @@
[<NOT> {negated = true;}]
<IN>
(
- LOOKAHEAD(subquery(info)) (command = subquery(info)) |
+ LOOKAHEAD(subquery(info)) (command = subqueryAndHint(info)) |
(
<LPAREN>
value = commonValueExpression(info)
@@ -2862,14 +2874,11 @@
<RPAREN>
)
)
-
-
{
- if(setList.size() == 1 && setList.get(0) instanceof ScalarSubquery) {
- ScalarSubquery subqueryExpr = (ScalarSubquery) setList.get(0);
- criteria = new SubquerySetCriteria(expression, subqueryExpr.getCommand());
- } else if (command != null) {
- criteria = new SubquerySetCriteria(expression, command);
+ if (command != null) {
+ SubquerySetCriteria ssc = new SubquerySetCriteria(expression, (QueryCommand)command[0]);
+ ssc.setMergeJoin((Boolean)command[1]);
+ criteria = ssc;
} else {
criteria = new SetCriteria(expression, setList);
}
@@ -2885,15 +2894,15 @@
*/
ExistsCriteria existsCriteria(ParseInfo info) :
{
- ExistsCriteria existsCrit = null;
- QueryCommand subquery = null;
+ Object[] subquery = null;
}
{
<EXISTS>
- subquery = subquery(info)
+ subquery = subqueryAndHint(info)
{
- existsCrit = new ExistsCriteria(subquery);
+ ExistsCriteria existsCrit = new ExistsCriteria((QueryCommand)subquery[0]);
+ existsCrit.setMergeJoin((Boolean)subquery[1]);
return existsCrit;
}
}
Modified: trunk/engine/src/test/java/org/teiid/dqp/internal/datamgr/TestExistsCriteriaImpl.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/dqp/internal/datamgr/TestExistsCriteriaImpl.java 2011-03-18 15:30:08 UTC (rev 3007)
+++ trunk/engine/src/test/java/org/teiid/dqp/internal/datamgr/TestExistsCriteriaImpl.java 2011-03-18 18:50:32 UTC (rev 3008)
@@ -23,12 +23,12 @@
package org.teiid.dqp.internal.datamgr;
+import junit.framework.TestCase;
+
import org.teiid.language.Exists;
+import org.teiid.language.Not;
import org.teiid.query.sql.lang.ExistsCriteria;
-
-import junit.framework.TestCase;
-
/**
*/
public class TestExistsCriteriaImpl extends TestCase {
@@ -41,17 +41,22 @@
super(name);
}
- public static ExistsCriteria helpExample() {
+ public static ExistsCriteria helpExample(boolean negated) {
ExistsCriteria crit = new ExistsCriteria(TestQueryImpl.helpExample(true));
+ crit.setNegated(negated);
return crit;
}
public static Exists example() throws Exception {
- return (Exists)TstLanguageBridgeFactory.factory.translate(helpExample());
+ return (Exists)TstLanguageBridgeFactory.factory.translate(helpExample(false));
}
public void testGetQuery() throws Exception {
assertNotNull(example().getSubquery());
}
+ public void testNegated() throws Exception {
+ assertTrue(TstLanguageBridgeFactory.factory.translate(helpExample(true)) instanceof Not);
+ }
+
}
Modified: trunk/engine/src/test/java/org/teiid/query/optimizer/TestAggregatePushdown.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/optimizer/TestAggregatePushdown.java 2011-03-18 15:30:08 UTC (rev 3007)
+++ trunk/engine/src/test/java/org/teiid/query/optimizer/TestAggregatePushdown.java 2011-03-18 18:50:32 UTC (rev 3008)
@@ -631,7 +631,7 @@
null, capFinder,
new String[] {"SELECT g_0.\"MONTH\" AS c_0, g_0.\"YEAR\" AS c_1 FROM msModel.\"TIME\" AS g_0 WHERE g_0.\"YEAR\" = '1999' ORDER BY c_0", //$NON-NLS-1$
"SELECT g_0.\"MONTH\" AS c_0, g_0.CITY AS c_1, SUM(g_0.SALES) AS c_2 FROM db2model.SALES AS g_0 WHERE (g_0.\"MONTH\" IN (<dependent values>)) AND (g_0.CITY IN (<dependent values>)) GROUP BY g_0.\"MONTH\", g_0.CITY ORDER BY c_0", //$NON-NLS-1$
- "SELECT g_0.CITY, g_0.REGION FROM oraclemodel.GEOGRAPHY AS g_0 WHERE g_0.REGION IN ('BORDEAUX', 'POLINESIA')"}, //$NON-NLS-1$
+ "SELECT g_0.CITY AS c_0, g_0.REGION AS c_1 FROM oraclemodel.GEOGRAPHY AS g_0 WHERE g_0.REGION IN ('BORDEAUX', 'POLINESIA') ORDER BY c_0"}, //$NON-NLS-1$
ComparisonMode.EXACT_COMMAND_STRING );
checkNodeTypes(plan, new int[] {
@@ -679,7 +679,7 @@
null, capFinder,
new String[] {"SELECT g_0.\"MONTH\" AS c_0, g_0.\"YEAR\" AS c_1 FROM msModel.\"TIME\" AS g_0 WHERE g_0.\"YEAR\" = '1999' ORDER BY c_0", //$NON-NLS-1$
"SELECT g_0.\"MONTH\" AS c_0, g_0.CITY AS c_1, SUM(g_0.SALES) AS c_2 FROM db2model.SALES AS g_0 WHERE (g_0.\"MONTH\" IN (<dependent values>)) AND (g_0.CITY IN (<dependent values>)) GROUP BY g_0.\"MONTH\", g_0.CITY ORDER BY c_0", //$NON-NLS-1$
- "SELECT g_0.CITY, g_0.REGION FROM oraclemodel.GEOGRAPHY AS g_0 WHERE g_0.REGION IN ('BORDEAUX', 'POLINESIA')"}, //$NON-NLS-1$
+ "SELECT g_0.CITY AS c_0, g_0.REGION AS c_1 FROM oraclemodel.GEOGRAPHY AS g_0 WHERE g_0.REGION IN ('BORDEAUX', 'POLINESIA') ORDER BY c_0"}, //$NON-NLS-1$
ComparisonMode.EXACT_COMMAND_STRING );
checkNodeTypes(plan, new int[] {
Modified: trunk/engine/src/test/java/org/teiid/query/optimizer/TestOptimizer.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/optimizer/TestOptimizer.java 2011-03-18 15:30:08 UTC (rev 3007)
+++ trunk/engine/src/test/java/org/teiid/query/optimizer/TestOptimizer.java 2011-03-18 18:50:32 UTC (rev 3008)
@@ -77,6 +77,7 @@
import org.teiid.query.resolver.TestResolver;
import org.teiid.query.rewriter.QueryRewriter;
import org.teiid.query.sql.lang.Command;
+import org.teiid.query.sql.lang.JoinType;
import org.teiid.query.sql.symbol.GroupSymbol;
import org.teiid.query.sql.visitor.GroupCollectorVisitor;
import org.teiid.query.sql.visitor.ValueIteratorProviderCollectorVisitor;
@@ -95,6 +96,7 @@
public interface DependentJoin {}
public interface DependentSelectNode {}
public interface SemiJoin {}
+ public interface AntiSemiJoin {}
public interface DependentProjectNode {}
public interface DupRemoveNode {}
public interface DupRemoveSortNode {}
@@ -385,9 +387,11 @@
Class<?> nodeType = relationalNode.getClass();
if(nodeType.equals(JoinNode.class)) {
JoinStrategy strategy = ((JoinNode)relationalNode).getJoinStrategy();
- if (((JoinNode)relationalNode).getJoinType().isSemi()) {
+ if (((JoinNode)relationalNode).getJoinType().equals(JoinType.JOIN_SEMI)) {
updateCounts(SemiJoin.class, counts, types);
- }
+ } else if (((JoinNode)relationalNode).getJoinType().equals(JoinType.JOIN_ANTI_SEMI)) {
+ updateCounts(AntiSemiJoin.class, counts, types);
+ }
if (strategy instanceof NestedLoopJoinStrategy) {
updateCounts(NestedLoopJoinStrategy.class, counts, types);
} else if (strategy instanceof MergeJoinStrategy) {
Modified: trunk/engine/src/test/java/org/teiid/query/optimizer/TestSubqueryPushdown.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/optimizer/TestSubqueryPushdown.java 2011-03-18 15:30:08 UTC (rev 3007)
+++ trunk/engine/src/test/java/org/teiid/query/optimizer/TestSubqueryPushdown.java 2011-03-18 18:50:32 UTC (rev 3008)
@@ -24,10 +24,13 @@
import static org.teiid.query.optimizer.TestOptimizer.*;
+import org.junit.Ignore;
import org.junit.Test;
import org.teiid.core.TeiidComponentException;
import org.teiid.core.TeiidProcessingException;
+import org.teiid.query.optimizer.TestOptimizer.AntiSemiJoin;
import org.teiid.query.optimizer.TestOptimizer.ComparisonMode;
+import org.teiid.query.optimizer.TestOptimizer.SemiJoin;
import org.teiid.query.optimizer.capabilities.BasicSourceCapabilities;
import org.teiid.query.optimizer.capabilities.DefaultCapabilitiesFinder;
import org.teiid.query.optimizer.capabilities.FakeCapabilitiesFinder;
@@ -836,6 +839,103 @@
});
}
+ /**
+ * This will not plan as a semi-join since the cost seems too high
+ */
+ @Test public void testNonSemiJoinExistsCosting() {
+ ProcessorPlan plan = helpPlan("Select e1 from pm1.g2 as o where exists (select 1 from pm3.g1 where e1 = o.e1 having o.e2 = count(e2))", FakeMetadataFactory.example4(), //$NON-NLS-1$
+ new String[] { "SELECT g_0.e1, g_0.e2 FROM pm1.g2 AS g_0" }); //$NON-NLS-1$
+ checkNodeTypes(plan, new int[] {
+ 1, // Access
+ 0, // DependentAccess
+ 1, // DependentSelect
+ 0, // DependentProject
+ 0, // DupRemove
+ 0, // Grouping
+ 0, // NestedLoopJoinStrategy
+ 0, // MergeJoinStrategy
+ 0, // Null
+ 0, // PlanExecution
+ 1, // Project
+ 0, // Select
+ 0, // Sort
+ 0 // UnionAll
+ });
+ }
+
+ /**
+ * Same as above, but the source is much larger, so a semi-join is favorable
+ */
+ @Test public void testSemiJoinExistsCosting() {
+ ProcessorPlan plan = helpPlan("Select e1 from pm2.g2 as o where exists (select 1 from pm3.g1 where e1 = o.e1 having o.e2 = count(e2))", FakeMetadataFactory.example4(), //$NON-NLS-1$
+ new String[] { "SELECT g_0.e1 AS c_0, g_0.e2 AS c_1 FROM pm2.g2 AS g_0 ORDER BY c_0, c_1" }); //$NON-NLS-1$
+ checkNodeTypes(plan, new int[] {
+ 1, // Access
+ 0, // DependentAccess
+ 0, // DependentSelect
+ 0, // DependentProject
+ 0, // DupRemove
+ 0, // Grouping
+ 0, // NestedLoopJoinStrategy
+ 1, // MergeJoinStrategy
+ 0, // Null
+ 1, // PlanExecution
+ 1, // Project
+ 0, // Select
+ 0, // Sort
+ 0 // UnionAll
+ });
+ checkJoinCounts(plan, 1, 0);
+ }
+
+ @Test public void testAntiSemiJoinExistsHint() {
+ ProcessorPlan plan = helpPlan("Select e1 from pm1.g2 as o where not exists /*+ MJ */ (select 1 from pm3.g1 where e1 = o.e1 having o.e2 = count(e2))", FakeMetadataFactory.example4(), //$NON-NLS-1$
+ new String[] { "SELECT g_0.e1 AS c_0, g_0.e2 AS c_1 FROM pm1.g2 AS g_0 ORDER BY c_0, c_1" }); //$NON-NLS-1$
+ checkNodeTypes(plan, new int[] {
+ 1, // Access
+ 0, // DependentAccess
+ 0, // DependentSelect
+ 0, // DependentProject
+ 0, // DupRemove
+ 0, // Grouping
+ 0, // NestedLoopJoinStrategy
+ 1, // MergeJoinStrategy
+ 0, // Null
+ 1, // PlanExecution
+ 1, // Project
+ 0, // Select
+ 0, // Sort
+ 0 // UnionAll
+ });
+ checkJoinCounts(plan, 0, 1);
+ }
+
+ @Test public void testSemiJoinInHint() {
+ ProcessorPlan plan = helpPlan("Select e1 from pm1.g2 as o where e2 IN /*+ MJ */ (select count(e2) from pm3.g1 where e1 = o.e1)", FakeMetadataFactory.example4(), //$NON-NLS-1$
+ new String[] { "SELECT g_0.e2 AS c_0, g_0.e1 AS c_1 FROM pm1.g2 AS g_0 ORDER BY c_1, c_0" }); //$NON-NLS-1$
+ checkNodeTypes(plan, new int[] {
+ 1, // Access
+ 0, // DependentAccess
+ 0, // DependentSelect
+ 0, // DependentProject
+ 0, // DupRemove
+ 0, // Grouping
+ 0, // NestedLoopJoinStrategy
+ 1, // MergeJoinStrategy
+ 0, // Null
+ 1, // PlanExecution
+ 1, // Project
+ 0, // Select
+ 0, // Sort
+ 0 // UnionAll
+ });
+ checkJoinCounts(plan, 1, 0);
+ }
+
+ void checkJoinCounts(ProcessorPlan plan, int semi, int antiSemi) {
+ checkNodeTypes(plan, new int[] {semi, antiSemi}, new Class[] {SemiJoin.class, AntiSemiJoin.class});
+ }
+
@Test public void testNonSemiJoin() throws Exception {
ProcessorPlan plan = helpPlan("Select x from xmltable('/a/b' passing convert('<a/>', xml) columns x integer path '@x') as t where x = (select count(e2) FROM pm1.g2)", FakeMetadataFactory.example4(), //$NON-NLS-1$
new String[] {}, ComparisonMode.EXACT_COMMAND_STRING); //$NON-NLS-1$
@@ -877,4 +977,27 @@
new String[] { "SELECT g_0.e1 FROM pm1.g1 AS g_0 WHERE g_0.e1 <= (SELECT MAX(X.e1) FROM (SELECT e1 FROM pm2.g1) AS X)" }, ComparisonMode.EXACT_COMMAND_STRING); //$NON-NLS-1$
checkNodeTypes(plan, FULL_PUSHDOWN);
}
+
+ @Ignore
+ @Test public void testUncorrelatedSet() {
+ ProcessorPlan plan = helpPlan("Select e1 from pm1.g1 where e1 in (select e1 FROM pm2.g1)", FakeMetadataFactory.example1Cached(), //$NON-NLS-1$
+ new String[] { "SELECT e1, pm1.g1.e2 FROM pm1.g1" }); //$NON-NLS-1$
+ checkNodeTypes(plan, new int[] {
+ 1, // Access
+ 0, // DependentAccess
+ 1, // DependentSelect
+ 0, // DependentProject
+ 0, // DupRemove
+ 0, // Grouping
+ 0, // NestedLoopJoinStrategy
+ 0, // MergeJoinStrategy
+ 0, // Null
+ 0, // PlanExecution
+ 1, // Project
+ 0, // Select
+ 0, // Sort
+ 0 // UnionAll
+ });
+ }
+
}
Modified: trunk/engine/src/test/java/org/teiid/query/parser/TestOptionsAndHints.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/parser/TestOptionsAndHints.java 2011-03-18 15:30:08 UTC (rev 3007)
+++ trunk/engine/src/test/java/org/teiid/query/parser/TestOptionsAndHints.java 2011-03-18 18:50:32 UTC (rev 3008)
@@ -22,7 +22,7 @@
package org.teiid.query.parser;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.*;
import java.util.ArrayList;
import java.util.Arrays;
@@ -1144,4 +1144,16 @@
TestParser.helpTest(sql, "/*+ cache */ ? = EXEC proc()", sp); //$NON-NLS-1$
}
+ @Test public void testSemiJoinHint() {
+ String sql = "SELECT e1 FROM m.g2 WHERE EXISTS /*+ MJ */ (SELECT e1 FROM m.g1)"; //$NON-NLS-1$
+ Query q = TestParser.exampleExists(true);
+ TestParser.helpTest(sql, "SELECT e1 FROM m.g2 WHERE EXISTS /*+ MJ */ (SELECT e1 FROM m.g1)", q); //$NON-NLS-1$
+ }
+
+ @Test public void testSemiJoinHint1() {
+ String sql = "SELECT a FROM db.g WHERE b IN /*+ MJ */ (SELECT a FROM db.g WHERE a2 = 5)"; //$NON-NLS-1$
+ Query q = TestParser.exampleIn(true);
+ TestParser.helpTest(sql, "SELECT a FROM db.g WHERE b IN /*+ MJ */ (SELECT a FROM db.g WHERE a2 = 5)", q); //$NON-NLS-1$
+ }
+
}
Modified: trunk/engine/src/test/java/org/teiid/query/parser/TestParser.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/parser/TestParser.java 2011-03-18 15:30:08 UTC (rev 3007)
+++ trunk/engine/src/test/java/org/teiid/query/parser/TestParser.java 2011-03-18 18:50:32 UTC (rev 3008)
@@ -4955,7 +4955,15 @@
@Test public void testSubquerySetCriteria0() {
//test wrap up command with subquerySetCriteria
- GroupSymbol g = new GroupSymbol("db.g"); //$NON-NLS-1$
+ Query outer = exampleIn(false);
+
+ helpTest("SELECT a FROM db.g WHERE b IN (SELECT a FROM db.g WHERE a2 = 5)", //$NON-NLS-1$
+ "SELECT a FROM db.g WHERE b IN (SELECT a FROM db.g WHERE a2 = 5)", //$NON-NLS-1$
+ outer);
+ }
+
+ static Query exampleIn(boolean semiJoin) {
+ GroupSymbol g = new GroupSymbol("db.g"); //$NON-NLS-1$
From from = new From();
from.addGroup(g);
@@ -4972,16 +4980,13 @@
query.setFrom(from);
query.setCriteria(criteria);
SubquerySetCriteria subCrit = new SubquerySetCriteria(expr, query);
-
+ subCrit.setMergeJoin(semiJoin);
Query outer = new Query();
outer.setSelect(select);
outer.setFrom(from);
outer.setCriteria(subCrit);
-
- helpTest("SELECT a FROM db.g WHERE b IN (SELECT a FROM db.g WHERE a2 = 5)", //$NON-NLS-1$
- "SELECT a FROM db.g WHERE b IN (SELECT a FROM db.g WHERE a2 = 5)", //$NON-NLS-1$
- outer);
- }
+ return outer;
+ }
@Test public void testSubquerySetCriteria1() {
@@ -5710,7 +5715,14 @@
@Test public void testExistsPredicateCriteria(){
- Select s1 = new Select();
+ Query q2 = exampleExists(false);
+
+ helpTest("SELECT e1 FROM m.g2 WHERE Exists (SELECT e1 FROM m.g1)", //$NON-NLS-1$
+ "SELECT e1 FROM m.g2 WHERE EXISTS (SELECT e1 FROM m.g1)", //$NON-NLS-1$
+ q2);
+ }
+ static Query exampleExists(boolean semiJoin) {
+ Select s1 = new Select();
s1.addSymbol(new ElementSymbol("e1")); //$NON-NLS-1$
From f1 = new From();
f1.addGroup(new GroupSymbol("m.g1")); //$NON-NLS-1$
@@ -5722,16 +5734,14 @@
s2.addSymbol(new ElementSymbol("e1")); //$NON-NLS-1$
From f2 = new From();
f2.addGroup(new GroupSymbol("m.g2")); //$NON-NLS-1$
- Criteria existsCrit = new ExistsCriteria(q1);
+ ExistsCriteria existsCrit = new ExistsCriteria(q1);
+ existsCrit.setMergeJoin(semiJoin);
Query q2 = new Query();
q2.setSelect(s2);
q2.setFrom(f2);
q2.setCriteria(existsCrit);
-
- helpTest("SELECT e1 FROM m.g2 WHERE Exists (SELECT e1 FROM m.g1)", //$NON-NLS-1$
- "SELECT e1 FROM m.g2 WHERE EXISTS (SELECT e1 FROM m.g1)", //$NON-NLS-1$
- q2);
- }
+ return q2;
+ }
@Test public void testAnyQuantifierSubqueryComparePredicate(){
Modified: trunk/test-integration/common/src/test/java/org/teiid/dqp/internal/process/TestTPCR.java
===================================================================
--- trunk/test-integration/common/src/test/java/org/teiid/dqp/internal/process/TestTPCR.java 2011-03-18 15:30:08 UTC (rev 3007)
+++ trunk/test-integration/common/src/test/java/org/teiid/dqp/internal/process/TestTPCR.java 2011-03-18 18:50:32 UTC (rev 3008)
@@ -191,7 +191,7 @@
ProcessorPlan plan = TestOptimizer.helpPlan("SELECT custsale.cntrycode, COUNT(*) AS numcust, SUM(c_acctbal) AS totacctbal FROM (SELECT left(C_PHONE, 2) AS cntrycode, CUSTOMER.C_ACCTBAL FROM CUSTOMER WHERE (left(C_PHONE, 2) IN ('13','31','23','29','30','18','17')) AND (CUSTOMER.C_ACCTBAL > (SELECT AVG(CUSTOMER.C_ACCTBAL) FROM CUSTOMER WHERE (CUSTOMER.C_ACCTBAL > 0.0) AND (left(C_PHONE, 2) IN ('13','31','23','29','30','18','17')))) AND (NOT (EXISTS (SELECT * FROM ORDERS WHERE O_CUSTKEY = C_CUSTKEY)))) AS custsale GROUP BY custsale.cntrycode ORDER BY custsale.cntrycode", //$NON-NLS-1$
METADATA, null, finder,
- new String[] {"SELECT v_0.c_0, COUNT(*) AS c_1, SUM(v_0.c_1) AS c_2 FROM (SELECT left(g_0.C_PHONE, 2) AS c_0, g_0.C_ACCTBAL AS c_1 FROM TPCR_Oracle_9i.CUSTOMER AS g_0 WHERE (left(g_0.C_PHONE, 2) IN ('13', '17', '18', '23', '29', '30', '31')) AND (g_0.C_ACCTBAL > (SELECT AVG(g_1.C_ACCTBAL) FROM TPCR_Oracle_9i.CUSTOMER AS g_1 WHERE (g_1.C_ACCTBAL > 0E-15) AND (left(g_1.C_PHONE, 2) IN ('13', '17', '18', '23', '29', '30', '31')))) AND (NOT (EXISTS (SELECT 1 FROM TPCR_Oracle_9i.ORDERS AS g_2 WHERE g_2.O_CUSTKEY = g_0.C_CUSTKEY)))) AS v_0 GROUP BY v_0.c_0 ORDER BY c_0 NULLS FIRST"}, ComparisonMode.EXACT_COMMAND_STRING); //$NON-NLS-1$
+ new String[] {"SELECT v_0.c_0, COUNT(*) AS c_1, SUM(v_0.c_1) AS c_2 FROM (SELECT left(g_0.C_PHONE, 2) AS c_0, g_0.C_ACCTBAL AS c_1 FROM TPCR_Oracle_9i.CUSTOMER AS g_0 WHERE (left(g_0.C_PHONE, 2) IN ('13', '17', '18', '23', '29', '30', '31')) AND (g_0.C_ACCTBAL > (SELECT AVG(g_1.C_ACCTBAL) FROM TPCR_Oracle_9i.CUSTOMER AS g_1 WHERE (g_1.C_ACCTBAL > 0E-15) AND (left(g_1.C_PHONE, 2) IN ('13', '17', '18', '23', '29', '30', '31')))) AND (NOT EXISTS (SELECT 1 FROM TPCR_Oracle_9i.ORDERS AS g_2 WHERE g_2.O_CUSTKEY = g_0.C_CUSTKEY))) AS v_0 GROUP BY v_0.c_0 ORDER BY c_0 NULLS FIRST"}, ComparisonMode.EXACT_COMMAND_STRING); //$NON-NLS-1$
TestOptimizer.checkNodeTypes(plan, TestOptimizer.FULL_PUSHDOWN);
}
13 years, 9 months
teiid SVN: r3007 - trunk/engine/src/test/java/org/teiid/query/processor/xml.
by teiid-commits@lists.jboss.org
Author: shawkins
Date: 2011-03-18 11:30:08 -0400 (Fri, 18 Mar 2011)
New Revision: 3007
Modified:
trunk/engine/src/test/java/org/teiid/query/processor/xml/TestXMLProcessor.java
Log:
TEIID-114 test of correlated xml procedure
Modified: trunk/engine/src/test/java/org/teiid/query/processor/xml/TestXMLProcessor.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/processor/xml/TestXMLProcessor.java 2011-03-18 14:45:33 UTC (rev 3006)
+++ trunk/engine/src/test/java/org/teiid/query/processor/xml/TestXMLProcessor.java 2011-03-18 15:30:08 UTC (rev 3007)
@@ -544,10 +544,11 @@
List normDocE3 = FakeMetadataFactory.createElements(normDoc3, new String[] { "Catalogs", "Catalogs.Catalog", "Catalogs.Catalog.items", "Catalogs.Catalog.items.item", "Catalogs.Catalog.items.item.@ItemID", "Catalogs.Catalog.items.item.Name", "Catalogs.Catalog.items.item.Quantity", "Catalogs.Catalog.items.DiscontinuedItem", "Catalogs.Catalog.items.DiscontinuedItem.@ItemID", "Catalogs.Catalog.items.DiscontinuedItem.Name", "Catalogs.Catalog.items.DiscontinuedItem.Quantity", "Catalogs.Catalog.items.StatusUnknown", "Catalogs.Catalog.items.StatusUnknown.@ItemID", "Catalogs.Catalog.items.StatusUnknown.Name", "Catalogs.Catalog.items.StatusUnknown.Quantity", "Catalogs.Catalog.items.Shouldn't see", "Catalogs.Catalog.items.Shouldn't see 2" }, //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ //$NON-NLS-11$ //$NON-NLS-12$ //$NON-NLS-13$ //$NON-NLS-14$ //$NON-NLS-15$ //$NON-NLS-16$ //$NON-N!
LS-17$
new String[] { DataTypeManager.DefaultDataTypes.STRING, DataTypeManager.DefaultDataTypes.STRING, DataTypeManager.DefaultDataTypes.STRING, DataTypeManager.DefaultDataTypes.STRING, DataTypeManager.DefaultDataTypes.STRING, DataTypeManager.DefaultDataTypes.STRING, DataTypeManager.DefaultDataTypes.INTEGER, DataTypeManager.DefaultDataTypes.STRING, DataTypeManager.DefaultDataTypes.STRING, DataTypeManager.DefaultDataTypes.STRING, DataTypeManager.DefaultDataTypes.INTEGER, DataTypeManager.DefaultDataTypes.STRING, DataTypeManager.DefaultDataTypes.STRING, DataTypeManager.DefaultDataTypes.STRING, DataTypeManager.DefaultDataTypes.INTEGER, DataTypeManager.DefaultDataTypes.STRING, DataTypeManager.DefaultDataTypes.STRING });
- QueryNode vspqn1 = new QueryNode("vsp1", "CREATE VIRTUAL PROCEDURE BEGIN insert into #temp select * from stock.items; SELECT * FROM xmltest.doc1 where Item.Quantity < (select avg(itemquantity) from #temp); END"); //$NON-NLS-1$ //$NON-NLS-2$
+ QueryNode vspqn1 = new QueryNode("vsp1", "CREATE VIRTUAL PROCEDURE BEGIN insert into #temp select * from stock.items where itemquantity < param; SELECT * FROM xmltest.doc1 where Item.Quantity < (select avg(itemquantity) from #temp); END"); //$NON-NLS-1$ //$NON-NLS-2$
FakeMetadataObject vsprs1 = FakeMetadataFactory.createResultSet("pm1.vsprs1", xmltest, new String[] { "xml" }, new String[] { DataTypeManager.DefaultDataTypes.XML }); //$NON-NLS-1$ //$NON-NLS-2$
- FakeMetadataObject vspp1 = FakeMetadataFactory.createParameter("ret", 1, ParameterInfo.RESULT_SET, DataTypeManager.DefaultDataTypes.XML, vsprs1); //$NON-NLS-1$
- FakeMetadataObject vsp1 = FakeMetadataFactory.createVirtualProcedure("xmltest.vsp1", xmltest, Arrays.asList(new FakeMetadataObject[] { vspp1 }), vspqn1); //$NON-NLS-1$
+ FakeMetadataObject vspp1 = FakeMetadataFactory.createParameter("param", 1, ParameterInfo.IN, DataTypeManager.DefaultDataTypes.INTEGER, vsprs1); //$NON-NLS-1$
+ FakeMetadataObject vspp2 = FakeMetadataFactory.createParameter("ret", 2, ParameterInfo.RESULT_SET, DataTypeManager.DefaultDataTypes.XML, vsprs1); //$NON-NLS-1$
+ FakeMetadataObject vsp1 = FakeMetadataFactory.createVirtualProcedure("xmltest.vsp1", xmltest, Arrays.asList(vspp1, vspp2 ), vspqn1); //$NON-NLS-1$
// Add all objects to the store
store.addObject(stock);
@@ -11758,9 +11759,50 @@
" </Items>\r\n" + //$NON-NLS-1$
" </Catalog>\r\n" + //$NON-NLS-1$
"</Catalogs>\r\n\r\n"; //$NON-NLS-1$
- helpTestProcess("call xmltest.vsp1()", expectedDoc, metadata, dataMgr); //$NON-NLS-1$
+ helpTestProcess("call xmltest.vsp1(1000)", expectedDoc, metadata, dataMgr); //$NON-NLS-1$
}
+ @Test public void testProcedureAndXML1() throws Exception {
+ FakeMetadataFacade metadata = exampleMetadataCached();
+ FakeDataManager dataMgr = exampleDataManager(metadata);
+ String expectedDoc1 =
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n" + //$NON-NLS-1$
+ "<Catalogs xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\r\n" + //$NON-NLS-1$
+ " <Catalog>\r\n" + //$NON-NLS-1$
+ " <Items/>\r\n" + //$NON-NLS-1$
+ " </Catalog>\r\n" + //$NON-NLS-1$
+ "</Catalogs>\r\n\r\n"; //$NON-NLS-1$
+ String expectedDoc2 =
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n" + //$NON-NLS-1$
+ "<Catalogs xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\r\n" + //$NON-NLS-1$
+ " <Catalog>\r\n" + //$NON-NLS-1$
+ " <Items>\r\n" + //$NON-NLS-1$
+ " <Item ItemID=\"003\">\r\n" + //$NON-NLS-1$
+ " <Name>Goat</Name>\r\n" + //$NON-NLS-1$
+ " <Quantity>4</Quantity>\r\n" + //$NON-NLS-1$
+ " </Item>\r\n" + //$NON-NLS-1$
+ " </Items>\r\n" + //$NON-NLS-1$
+ " </Catalog>\r\n" + //$NON-NLS-1$
+ "</Catalogs>\r\n\r\n"; //$NON-NLS-1$
+ String expectedDoc3 =
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n" + //$NON-NLS-1$
+ "<Catalogs xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\r\n" + //$NON-NLS-1$
+ " <Catalog>\r\n" + //$NON-NLS-1$
+ " <Items>\r\n" + //$NON-NLS-1$
+ " <Item ItemID=\"001\">\r\n" + //$NON-NLS-1$
+ " <Name>Lamp</Name>\r\n" + //$NON-NLS-1$
+ " <Quantity>5</Quantity>\r\n" + //$NON-NLS-1$
+ " </Item>\r\n" + //$NON-NLS-1$
+ " <Item ItemID=\"003\">\r\n" + //$NON-NLS-1$
+ " <Name>Goat</Name>\r\n" + //$NON-NLS-1$
+ " <Quantity>4</Quantity>\r\n" + //$NON-NLS-1$
+ " </Item>\r\n" + //$NON-NLS-1$
+ " </Items>\r\n" + //$NON-NLS-1$
+ " </Catalog>\r\n" + //$NON-NLS-1$
+ "</Catalogs>\r\n\r\n"; //$NON-NLS-1$
+ helpTestProcess("select (call xmltest.vsp1(y)) from texttable(unescape('1\n100\n1000') COLUMNS y integer) as x", metadata, dataMgr, null, new DefaultCapabilitiesFinder(), expectedDoc1, expectedDoc2, expectedDoc3); //$NON-NLS-1$
+ }
+
/**
* When a element with source node is specied, it can be unbouned or bounded. In the case
* of bounded, but result set is returning more results then it should fail.
13 years, 9 months