Author: jolee
Date: 2012-06-19 10:13:44 -0400 (Tue, 19 Jun 2012)
New Revision: 4187
Modified:
branches/7.4.x/engine/src/main/java/org/teiid/query/processor/relational/DependentCriteriaProcessor.java
branches/7.4.x/engine/src/test/java/org/teiid/query/processor/TestDependentJoins.java
Log:
TEIID-2074: NPE with multi-column dependent join
Modified:
branches/7.4.x/engine/src/main/java/org/teiid/query/processor/relational/DependentCriteriaProcessor.java
===================================================================
---
branches/7.4.x/engine/src/main/java/org/teiid/query/processor/relational/DependentCriteriaProcessor.java 2012-06-19
02:20:38 UTC (rev 4186)
+++
branches/7.4.x/engine/src/main/java/org/teiid/query/processor/relational/DependentCriteriaProcessor.java 2012-06-19
14:13:44 UTC (rev 4187)
@@ -27,17 +27,21 @@
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.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
import org.teiid.api.exception.query.ExpressionEvaluationException;
import org.teiid.common.buffer.BlockedException;
import org.teiid.core.TeiidComponentException;
import org.teiid.core.TeiidProcessingException;
+import org.teiid.core.types.DataTypeManager;
import org.teiid.logging.LogConstants;
import org.teiid.logging.LogManager;
import org.teiid.query.QueryPlugin;
@@ -108,22 +112,47 @@
}
for (SetState setState : dependentSetStates) {
setState.valueIterator =
dvs.getValueIterator(setState.valueExpression);
- if (setState.maxNdv > 0 && setState.maxNdv <
dvs.getTupleBuffer().getRowCount()) {
- ValueIterator vi = dvs.getValueIterator(setState.valueExpression);
- Comparable last = null;
- int distinctCount = 0;
- while (vi.hasNext()) {
- Comparable next = (Comparable) vi.next();
- if (last == null || next.compareTo(last) != 0) {
- distinctCount++;
+ int distinctCount = dvs.getTupleBuffer().getRowCount();
+ if (setState.maxNdv <= 0 || setState.maxNdv >= distinctCount)
{
+ continue;
+ }
+ if (dvs.getTupleBuffer().getSchema().size() > 1) {
+ distinctCount = 0;
+ ValueIterator vi = dvs.getValueIterator(setState.valueExpression);
+ if
(dvs.getTupleBuffer().getSchema().indexOf(setState.valueExpression) == 0) {
+ Object last = null;
+ while (vi.hasNext()) {
+ Object next = vi.next();
+ if (next != null && (last == null ||
((Comparable)next).compareTo(last) != 0)) {
+ distinctCount++;
+ }
+ last = next;
}
- last = next;
+ } else {
+ //secondary attributes are not in sorted order, so we use an
approximate count
+ Set<Object> set = new TreeSet<Object>();
+ int maxSize = Math.min(10000, dvs.getTupleBuffer().getRowCount());
+ List<Object> buffer = Arrays.asList(new Object[maxSize]);
+ int i = 0;
+ while (vi.hasNext()) {
+ Object next = vi.next();
+ if (next == null) {
+ continue;
+ }
+ if (set.add(next)) {
+ distinctCount++;
+ }
+ Object old = buffer.set(i++%maxSize, next);
+ if (set.size() > maxSize) {
+ set.remove(old);
+ }
+ }
}
- if (!setState.overMax && distinctCount > setState.maxNdv)
{
- LogManager.logWarning(LogConstants.CTX_DQP,
QueryPlugin.Util.getString("DependentCriteriaProcessor.dep_join_backoff",
valueSource, setState.valueExpression, setState.maxNdv)); //$NON-NLS-1$
- setState.overMax = true;
- }
- }
+ }
+ if (!setState.overMax && distinctCount > setState.maxNdv) {
+ LogManager.logWarning(LogConstants.CTX_DQP,
QueryPlugin.Util.getString("DependentCriteriaProcessor.dep_join_backoff",
valueSource, setState.valueExpression, setState.maxNdv)); //$NON-NLS-1$
+ setState.overMax = true;
+ }
}
}
}
Modified:
branches/7.4.x/engine/src/test/java/org/teiid/query/processor/TestDependentJoins.java
===================================================================
---
branches/7.4.x/engine/src/test/java/org/teiid/query/processor/TestDependentJoins.java 2012-06-19
02:20:38 UTC (rev 4186)
+++
branches/7.4.x/engine/src/test/java/org/teiid/query/processor/TestDependentJoins.java 2012-06-19
14:13:44 UTC (rev 4187)
@@ -571,6 +571,7 @@
metadata,
"pm1.g1", new List[] {
Arrays.asList(new Object[] { "a", new Integer(0), Boolean.FALSE,
new Double(2.0) }), //$NON-NLS-1$
+ Arrays.asList(new Object[] { "q", null, Boolean.FALSE, new
Double(0.0) }), //$NON-NLS-1$
Arrays.asList(new Object[] { "b", new Integer(1), Boolean.TRUE,
null }), //$NON-NLS-1$
Arrays.asList(new Object[] { "c", new Integer(2), Boolean.FALSE,
new Double(0.0) }), //$NON-NLS-1$
} );
@@ -578,7 +579,7 @@
dataMgr.registerTuples(
metadata,
"pm6.g1", new List[] {
- Arrays.asList(new Object[] { "b", new Integer(0) }), //$NON-NLS-1$
+ Arrays.asList(new Object[] { "b", 1 }), //$NON-NLS-1$
Arrays.asList(new Object[] { "d", new Integer(3) }), //$NON-NLS-1$
Arrays.asList(new Object[] { "e", new Integer(1) }), //$NON-NLS-1$
} );
@@ -837,7 +838,7 @@
FakeDataManager dataManager = helpTestBackoff(true);
//note that the dependent join was not actually performed
- assertEquals(new HashSet<String>(Arrays.asList("SELECT pm1.g1.e1 FROM
pm1.g1", "SELECT pm6.g1.e1 FROM pm6.g1 ORDER BY pm6.g1.e1")),
+ assertEquals(new HashSet<String>(Arrays.asList("SELECT pm6.g1.e1,
pm6.g1.e2 FROM pm6.g1 ORDER BY pm6.g1.e1, pm6.g1.e2", "SELECT pm1.g1.e1,
pm1.g1.e2 FROM pm1.g1")),
new HashSet<String>(dataManager.getQueries()));
}
@@ -852,7 +853,7 @@
QueryMetadataException, TeiidComponentException,
TeiidProcessingException {
// Create query
- String sql = "SELECT pm1.g1.e1 FROM pm1.g1, pm6.g1 WHERE
pm1.g1.e1=pm6.g1.e1"; //$NON-NLS-1$
+ String sql = "SELECT pm1.g1.e1 FROM pm1.g1, pm6.g1 WHERE pm1.g1.e1=pm6.g1.e1
and pm1.g1.e2=pm6.g1.e2"; //$NON-NLS-1$
// Construct data manager with data
FakeDataManager dataManager = new FakeDataManager();
@@ -863,10 +864,12 @@
RealMetadataFactory.setCardinality("pm1.g1", 1, fakeMetadata);
if (setNdv) {
fakeMetadata.getElementID("pm1.g1.e1").setDistinctValues(1);
+ fakeMetadata.getElementID("pm1.g1.e2").setDistinctValues(1);
}
RealMetadataFactory.setCardinality("pm6.g1", 1000, fakeMetadata);
if (setNdv) {
fakeMetadata.getElementID("pm6.g1.e1").setDistinctValues(1000);
+ fakeMetadata.getElementID("pm6.g1.e2").setDistinctValues(1000);
}
// Plan query
FakeCapabilitiesFinder capFinder = new FakeCapabilitiesFinder();
@@ -886,8 +889,8 @@
new String("b")})}; //$NON-NLS-1$
ProcessorPlan plan = TestOptimizer.helpPlan(sql, fakeMetadata, new String[] {
- "SELECT pm6.g1.e1 FROM pm6.g1 WHERE pm6.g1.e1 IN (<dependent
values>) ORDER BY pm6.g1.e1",
- "SELECT pm1.g1.e1 FROM pm1.g1"
+ "SELECT pm6.g1.e1, pm6.g1.e2 FROM pm6.g1 WHERE (pm6.g1.e1 IN
(<dependent values>)) AND (pm6.g1.e2 IN (<dependent values>)) ORDER BY
pm6.g1.e1, pm6.g1.e2",
+ "SELECT pm1.g1.e1, pm1.g1.e2 FROM pm1.g1"
}, capFinder, ComparisonMode.EXACT_COMMAND_STRING);
// Run query