teiid SVN: r2997 - in branches/7.1.x/engine/src/main: resources/org/teiid/query and 1 other directory.
by teiid-commits@lists.jboss.org
Author: shawkins
Date: 2011-03-16 23:43:53 -0400 (Wed, 16 Mar 2011)
New Revision: 2997
Modified:
branches/7.1.x/engine/src/main/java/org/teiid/dqp/internal/process/DQPCore.java
branches/7.1.x/engine/src/main/resources/org/teiid/query/i18n.properties
Log:
TEIID-1505 ensuring that maxActivePlans is picked up from the config
Modified: branches/7.1.x/engine/src/main/java/org/teiid/dqp/internal/process/DQPCore.java
===================================================================
--- branches/7.1.x/engine/src/main/java/org/teiid/dqp/internal/process/DQPCore.java 2011-03-17 03:33:13 UTC (rev 2996)
+++ branches/7.1.x/engine/src/main/java/org/teiid/dqp/internal/process/DQPCore.java 2011-03-17 03:43:53 UTC (rev 2997)
@@ -703,7 +703,13 @@
this.processWorkerPool = new ThreadReuseExecutor(DQPConfiguration.PROCESS_PLAN_QUEUE_NAME, config.getMaxThreads());
+ this.maxActivePlans = config.getMaxActivePlans();
+ if (this.maxActivePlans > config.getMaxThreads()) {
+ LogManager.logWarning(LogConstants.CTX_DQP, QueryPlugin.Util.getString("DQPCore.invalid_max_active_plan", this.maxActivePlans, config.getMaxThreads())); //$NON-NLS-1$
+ this.maxActivePlans = config.getMaxThreads();
+ }
+
if (cacheFactory.isReplicated()) {
matTables = new SessionAwareCache<CachedResults>(this.cacheFactory, SessionAwareCache.Type.RESULTSET, new CacheConfiguration(Policy.EXPIRATION, -1, -1, "MaterilizationTables")); //$NON-NLS-1$
matTables.setBufferManager(this.bufferManager);
Modified: branches/7.1.x/engine/src/main/resources/org/teiid/query/i18n.properties
===================================================================
--- branches/7.1.x/engine/src/main/resources/org/teiid/query/i18n.properties 2011-03-17 03:33:13 UTC (rev 2996)
+++ branches/7.1.x/engine/src/main/resources/org/teiid/query/i18n.properties 2011-03-17 03:43:53 UTC (rev 2997)
@@ -814,6 +814,7 @@
DQPCore.The_request_has_been_closed.=The request {0} has been closed.
DQPCore.The_atomic_request_has_been_cancelled=The atomic request {0} has been canceled.
DQPCore.failed_to_cancel=Failed to Cancel request, as request already finished processing
+DQPCore.invalid_max_active_plan=The maxActivePlan {0} setting should never be greater than the max processing threads {1}.
ProcessWorker.failed_rollback=Failed to properly rollback autowrap transaction properly
ProcessWorker.error=Unexpected exception for request {0}
13 years, 10 months
teiid SVN: r2996 - in branches/7.1.x: runtime/src/main/java/org/teiid/deployers and 2 other directories.
by teiid-commits@lists.jboss.org
Author: rareddy
Date: 2011-03-16 23:33:13 -0400 (Wed, 16 Mar 2011)
New Revision: 2996
Modified:
branches/7.1.x/build/kits/jboss-container/deploy/teiid/teiid-jboss-beans.xml
branches/7.1.x/runtime/src/main/java/org/teiid/deployers/PgCatalogMetadataStore.java
branches/7.1.x/runtime/src/main/java/org/teiid/odbc/ODBCServerRemoteImpl.java
branches/7.1.x/runtime/src/main/java/org/teiid/transport/PgBackendProtocol.java
branches/7.1.x/runtime/src/main/java/org/teiid/transport/SSLAwareChannelHandler.java
branches/7.1.x/runtime/src/main/java/org/teiid/transport/SocketListener.java
Log:
TEIID-1506: Adding fix ODBC data types for bigint and bigdecimal and byte. Also added the ODBC thread sizing fix.
Modified: branches/7.1.x/build/kits/jboss-container/deploy/teiid/teiid-jboss-beans.xml
===================================================================
--- branches/7.1.x/build/kits/jboss-container/deploy/teiid/teiid-jboss-beans.xml 2011-03-16 21:22:50 UTC (rev 2995)
+++ branches/7.1.x/build/kits/jboss-container/deploy/teiid/teiid-jboss-beans.xml 2011-03-17 03:33:13 UTC (rev 2996)
@@ -27,7 +27,8 @@
<!--
The number of batch columns to allow in memory (default 16384).
This value should be set lower or higher depending on the available memory to Teiid in the VM.
- 16384 is considered a good default for a dedicated 32-bit VM running Teiid with a 1 gig heap.
+ 16384 is considered a good default for a dedicated 32-bit VM running Teiid with a 1 gig heap.
+ See the admin guide for more.
-->
<property name="maxReserveBatchColumns">16384</property>
<!--
@@ -116,8 +117,10 @@
<property name="enabled">true</property>
<property name="bindAddress">${jboss.bind.address}</property>
<property name="portNumber">31000</property>
- <!-- Max number of threads dedicated to initial request processing (default 15) -->
- <property name="maxSocketThreads">15</property>
+ <!-- Max number of threads dedicated to initial request processing.
+ Zero indicates the system default of max available processors. (default 0)
+ Setting this value above the max available processors is not recommended. -->
+ <property name="maxSocketThreads">0</property>
<!-- SO_RCVBUF size, 0 indicates that system default should be used (default 0) -->
<property name="inputBufferSize">0</property>
<!-- SO_SNDBUF size, 0 indicates that system default should be used (default 0) -->
@@ -151,7 +154,8 @@
<property name="enabled">true</property>
<property name="bindAddress">${jboss.bind.address}</property>
<property name="portNumber">31443</property>
- <!-- Max number of threads dedicated to Admin and initial request processing (default 4) -->
+ <!-- Max number of threads dedicated to Admin request processing.
+ Zero indicates the system default of max available processors. (default 4) -->
<property name="maxSocketThreads">4</property>
<!-- SO_RCVBUF size, 0 indicates that system default should be used (default 0) -->
<property name="inputBufferSize">0</property>
@@ -186,7 +190,10 @@
<property name="enabled">true</property>
<property name="bindAddress">${jboss.bind.address}</property>
<property name="portNumber">35432</property>
- <!-- Max number of threads dedicated to initial request processing (default 15) -->
+ <!-- Max number of threads dedicated to ODBC request processing.
+ Zero indicates the system default of max available processors. (default 15)
+ ODBC queries are currently blocking on IO operations, so this value
+ should be set the expected number of concurrent ODBC queries -->
<property name="maxSocketThreads">15</property>
<!-- SO_RCVBUF size, 0 indicates that system default should be used (default 0) -->
<property name="inputBufferSize">0</property>
Modified: branches/7.1.x/runtime/src/main/java/org/teiid/deployers/PgCatalogMetadataStore.java
===================================================================
--- branches/7.1.x/runtime/src/main/java/org/teiid/deployers/PgCatalogMetadataStore.java 2011-03-16 21:22:50 UTC (rev 2995)
+++ branches/7.1.x/runtime/src/main/java/org/teiid/deployers/PgCatalogMetadataStore.java 2011-03-17 03:33:13 UTC (rev 2996)
@@ -145,7 +145,7 @@
"st.oid as attrelid, " + //$NON-NLS-1$
"t1.Name as attname, " + //$NON-NLS-1$
"pt.oid as atttypid," + //$NON-NLS-1$
- "convert(t1.Length, short) as attlen, " + //$NON-NLS-1$
+ "pt.typlen as attlen, " + //$NON-NLS-1$
"convert(t1.Position, short) as attnum, " + //$NON-NLS-1$
"t1.Length as atttypmod, " + //$NON-NLS-1$
"false as attnotnull, " + //$NON-NLS-1$
@@ -153,7 +153,13 @@
"false as atthasdef " + //$NON-NLS-1$
"FROM SYS.Columns as t1 LEFT OUTER JOIN " + //$NON-NLS-1$
"SYS.Tables st ON (st.Name = t1.TableName AND st.SchemaName = t1.SchemaName) LEFT OUTER JOIN " + //$NON-NLS-1$
- "pg_catalog.pg_type pt ON (CASE WHEN (t1.DataType = 'clob' OR t1.DataType = 'blob') THEN 'lo' ELSE t1.DataType END = pt.typname)"; //$NON-NLS-1$
+ "pg_catalog.pg_type pt ON (CASE " +//$NON-NLS-1$
+ "WHEN (t1.DataType = 'clob' OR t1.DataType = 'blob') THEN 'lo' " +//$NON-NLS-1$
+ "WHEN (t1.DataType = 'byte' ) THEN 'short' " + //$NON-NLS-1$
+ "WHEN (t1.DataType = 'time' ) THEN 'datetime' " + //$NON-NLS-1$
+ "WHEN (t1.DataType = 'biginteger' ) THEN 'decimal' " + //$NON-NLS-1$
+ "WHEN (t1.DataType = 'bigdecimal' ) THEN 'decimal' " + //$NON-NLS-1$
+ "ELSE t1.DataType END = pt.typname)"; //$NON-NLS-1$
t.setSelectTransformation(transformation);
t.setMaterialized(true);
return t;
Modified: branches/7.1.x/runtime/src/main/java/org/teiid/odbc/ODBCServerRemoteImpl.java
===================================================================
--- branches/7.1.x/runtime/src/main/java/org/teiid/odbc/ODBCServerRemoteImpl.java 2011-03-16 21:22:50 UTC (rev 2995)
+++ branches/7.1.x/runtime/src/main/java/org/teiid/odbc/ODBCServerRemoteImpl.java 2011-03-17 03:33:13 UTC (rev 2996)
@@ -53,7 +53,7 @@
private static Pattern pkPattern = Pattern.compile("select ta.attname, ia.attnum, ic.relname, n.nspname, tc.relname " +//$NON-NLS-1$
"from pg_catalog.pg_attribute ta, pg_catalog.pg_attribute ia, pg_catalog.pg_class tc, pg_catalog.pg_index i, " +//$NON-NLS-1$
- "pg_catalog.pg_namespace n, pg_catalog.pg_class ic where tc.relname = E'(\\w+)' AND n.nspname = E'(\\w+)'.*" );//$NON-NLS-1$
+ "pg_catalog.pg_namespace n, pg_catalog.pg_class ic where tc.relname = E?'(\\w+)' AND n.nspname = E?'(\\w+)'.*" );//$NON-NLS-1$
private static Pattern pkKeyPattern = Pattern.compile("select ta.attname, ia.attnum, ic.relname, n.nspname, NULL .*"); //$NON-NLS-1$
@@ -101,9 +101,9 @@
"\\s+pg_catalog.pg_namespace n" + //$NON-NLS-1$
"\\s+where contype = 'f' " + //$NON-NLS-1$
"\\s+and conrelid = c.oid" + //$NON-NLS-1$
- "\\s+and relname = E'(\\w+)'" + //$NON-NLS-1$
+ "\\s+and relname = E?'(\\w+)'" + //$NON-NLS-1$
"\\s+and n.oid = c.relnamespace" + //$NON-NLS-1$
- "\\s+and n.nspname = E'(\\w+)'" + //$NON-NLS-1$
+ "\\s+and n.nspname = E?'(\\w+)'" + //$NON-NLS-1$
"\\s+\\) ref" + //$NON-NLS-1$
"\\s+inner join pg_catalog.pg_class c1" + //$NON-NLS-1$
"\\s+on c1.oid = ref.conrelid\\)" + //$NON-NLS-1$
@@ -128,8 +128,8 @@
"nspname, p.oid, atttypid, attname, proargnames, proargmodes, proallargtypes from ((pg_catalog.pg_namespace n inner join " + //$NON-NLS-1$
"pg_catalog.pg_proc p on p.pronamespace = n.oid) inner join pg_type t on t.oid = p.prorettype) left outer join " + //$NON-NLS-1$
"pg_attribute a on a.attrelid = t.typrelid and attnum > 0 and not attisdropped " + //$NON-NLS-1$
- "where has_function_privilege(p.oid, 'EXECUTE') and nspname like E'(\\w+)' " + //$NON-NLS-1$
- "and proname like E'(\\w+)' " + //$NON-NLS-1$
+ "where has_function_privilege(p.oid, 'EXECUTE') and nspname like E?'(\\w+)' " + //$NON-NLS-1$
+ "and proname like E?'(\\w+)' " + //$NON-NLS-1$
"order by nspname, proname, p.oid, attnum"); //$NON-NLS-1$
Modified: branches/7.1.x/runtime/src/main/java/org/teiid/transport/PgBackendProtocol.java
===================================================================
--- branches/7.1.x/runtime/src/main/java/org/teiid/transport/PgBackendProtocol.java 2011-03-16 21:22:50 UTC (rev 2995)
+++ branches/7.1.x/runtime/src/main/java/org/teiid/transport/PgBackendProtocol.java 2011-03-17 03:33:13 UTC (rev 2996)
@@ -547,6 +547,7 @@
private static int convertType(final int type) {
switch (type) {
+ case Types.BIT:
case Types.BOOLEAN:
return PG_TYPE_BOOL;
case Types.VARCHAR:
@@ -555,14 +556,17 @@
return PG_TYPE_TEXT;
case Types.CHAR:
return PG_TYPE_BPCHAR;
+ case Types.TINYINT:
case Types.SMALLINT:
- return PG_TYPE_INT2;
+ return PG_TYPE_INT2;
case Types.INTEGER:
return PG_TYPE_INT4;
case Types.BIGINT:
return PG_TYPE_INT8;
+ case Types.NUMERIC:
case Types.DECIMAL:
return PG_TYPE_NUMERIC;
+ case Types.FLOAT:
case Types.REAL:
return PG_TYPE_FLOAT4;
case Types.DOUBLE:
@@ -573,12 +577,16 @@
return PG_TYPE_DATE;
case Types.TIMESTAMP:
return PG_TYPE_TIMESTAMP_NO_TMZONE;
+ case Types.BINARY:
case Types.VARBINARY:
+ case Types.LONGVARBINARY:
return PG_TYPE_BYTEA;
case Types.BLOB:
return PG_TYPE_OID;
case Types.ARRAY:
return PG_TYPE_TEXTARRAY;
+ case Types.LONGVARCHAR:
+ return PG_TYPE_TEXT;
default:
return PG_TYPE_UNKNOWN;
}
Modified: branches/7.1.x/runtime/src/main/java/org/teiid/transport/SSLAwareChannelHandler.java
===================================================================
--- branches/7.1.x/runtime/src/main/java/org/teiid/transport/SSLAwareChannelHandler.java 2011-03-16 21:22:50 UTC (rev 2995)
+++ branches/7.1.x/runtime/src/main/java/org/teiid/transport/SSLAwareChannelHandler.java 2011-03-17 03:33:13 UTC (rev 2996)
@@ -173,7 +173,7 @@
maxChannels = Math.max(maxChannels, this.listeners.size());
SslHandler sslHandler = ctx.getPipeline().get(SslHandler.class);
if (sslHandler != null) {
- sslHandler.handshake(e.getChannel()).addListener(new ChannelFutureListener() {
+ sslHandler.handshake().addListener(new ChannelFutureListener() {
public void operationComplete(ChannelFuture arg0)
throws Exception {
onConnection(e.getChannel());
Modified: branches/7.1.x/runtime/src/main/java/org/teiid/transport/SocketListener.java
===================================================================
--- branches/7.1.x/runtime/src/main/java/org/teiid/transport/SocketListener.java 2011-03-16 21:22:50 UTC (rev 2995)
+++ branches/7.1.x/runtime/src/main/java/org/teiid/transport/SocketListener.java 2011-03-17 03:33:13 UTC (rev 2996)
@@ -77,8 +77,12 @@
if (LogManager.isMessageToBeRecorded(LogConstants.CTX_TRANSPORT, MessageLevel.DETAIL)) {
LogManager.logDetail(LogConstants.CTX_TRANSPORT, "server = " + bindAddress + "binding to port:" + port); //$NON-NLS-1$ //$NON-NLS-2$
}
+
+ if (maxWorkers == 0) {
+ maxWorkers = Runtime.getRuntime().availableProcessors();
+ }
- ChannelFactory factory = new NioServerSocketChannelFactory(this.nettyPool, this.nettyPool, Math.min(Runtime.getRuntime().availableProcessors(), maxWorkers));
+ ChannelFactory factory = new NioServerSocketChannelFactory(this.nettyPool, this.nettyPool, maxWorkers);
ServerBootstrap bootstrap = new ServerBootstrap(factory);
this.channelHandler = createChannelPipelineFactory(config, storageManager);
13 years, 10 months
teiid SVN: r2995 - in trunk: engine/src/main/java/org/teiid/query/optimizer/relational/rules and 5 other directories.
by teiid-commits@lists.jboss.org
Author: shawkins
Date: 2011-03-16 17:22:50 -0400 (Wed, 16 Mar 2011)
New Revision: 2995
Modified:
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/RelationalPlanner.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/RuleChooseDependent.java
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePlanJoins.java
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushAggregates.java
trunk/engine/src/main/java/org/teiid/query/resolver/util/ResolverUtil.java
trunk/engine/src/main/java/org/teiid/query/sql/lang/DependentSetCriteria.java
trunk/engine/src/test/java/org/teiid/query/optimizer/TestAggregatePushdown.java
trunk/engine/src/test/java/org/teiid/query/processor/TestVirtualDepJoin.java
trunk/test-integration/common/src/test/java/org/teiid/dqp/internal/process/TestCrossSourceStarJoin.java
Log:
TEIID-1510 updating push aggregates to use costing information in making staged aggregate decisions.
Modified: trunk/engine/src/main/java/org/teiid/query/optimizer/relational/RelationalPlanner.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/optimizer/relational/RelationalPlanner.java 2011-03-16 14:56:38 UTC (rev 2994)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/RelationalPlanner.java 2011-03-16 21:22:50 UTC (rev 2995)
@@ -399,13 +399,13 @@
if (hints.hasRelationalProc) {
rules.push(RuleConstants.PLAN_PROCEDURES);
}
- if(hints.hasJoin) {
- rules.push(RuleConstants.CHOOSE_DEPENDENT);
- }
if(hints.hasAggregates) {
rules.push(RuleConstants.PUSH_AGGREGATES);
}
if(hints.hasJoin) {
+ rules.push(RuleConstants.CHOOSE_DEPENDENT);
+ }
+ if(hints.hasJoin) {
rules.push(RuleConstants.CHOOSE_JOIN_STRATEGY);
rules.push(RuleConstants.RAISE_ACCESS);
//after planning the joins, let the criteria be pushed back into place
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-16 14:56:38 UTC (rev 2994)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/NewCalculateCostUtil.java 2011-03-16 21:22:50 UTC (rev 2995)
@@ -93,7 +93,7 @@
private final static float readTime = .001f; //TODO: should come from the connector
private final static float procNewRequestTime = 1; //TODO: should come from the connector
- private enum Stat {
+ enum Stat {
NDV,
NNV
}
@@ -305,7 +305,7 @@
throws QueryMetadataException, TeiidComponentException {
PlanNode projectNode = NodeEditor.findNodePreOrder(node, NodeConstants.Types.PROJECT);
if (projectNode != null) {
- cost = getDistinctEstimate(projectNode, (List)projectNode.getProperty(NodeConstants.Info.PROJECT_COLS), metadata, cost);
+ cost = getNDVEstimate(node.getParent(), metadata, cost, (List)projectNode.getProperty(NodeConstants.Info.PROJECT_COLS), false);
}
return cost;
}
@@ -452,10 +452,12 @@
newStats[Stat.NDV.ordinal()] = stats[Stat.NDV.ordinal()];
} else if (stats[Stat.NDV.ordinal()] != UNKNOWN_VALUE) {
newStats[Stat.NDV.ordinal()] = stats[Stat.NDV.ordinal()]*Math.min(1, cardinality/origCardinality);
+ newStats[Stat.NDV.ordinal()] = Math.max(1, newStats[Stat.NDV.ordinal()]);
}
if (stats[Stat.NNV.ordinal()] != UNKNOWN_VALUE) {
//TODO: this is an under estimate for the inner side of outer joins
newStats[Stat.NNV.ordinal()] = stats[Stat.NNV.ordinal()]*Math.min(1, cardinality/origCardinality);
+ newStats[Stat.NNV.ordinal()] = Math.max(1, newStats[Stat.NNV.ordinal()]);
}
}
}
@@ -537,9 +539,11 @@
if (groupCardinality != UNKNOWN_VALUE && groupCardinality > cardinality) {
if (ndv != UNKNOWN_VALUE) {
ndv *= cardinality / Math.max(1, groupCardinality);
+ ndv = Math.max(ndv, 1);
}
if (nnv != UNKNOWN_VALUE) {
nnv *= cardinality / Math.max(1, groupCardinality);
+ nnv = Math.max(nnv, 1);
}
}
}
@@ -598,50 +602,38 @@
return;
}
- Float newCost = getDistinctEstimate(node, expressions, metadata, childCost);
- setCardinalityEstimate(node, newCost, true, metadata);
+ float cardinality = getNDVEstimate(node, metadata, childCost, expressions, false);
+ setCardinalityEstimate(node, cardinality, true, metadata);
}
- private static Float getDistinctEstimate(PlanNode node,
- List elements,
- QueryMetadataInterface metadata,
- float childCost) throws QueryMetadataException,
- TeiidComponentException {
- if(elements == null) {
- return new Float(childCost);
- }
- HashSet<ElementSymbol> elems = new HashSet<ElementSymbol>();
- ElementCollectorVisitor.getElements(elements, elems);
- if (usesKey(elements, metadata)) {
- return new Float(childCost);
- }
- float ndvCost = getStat(Stat.NDV, elems, node, childCost, metadata);
- if(ndvCost == UNKNOWN_VALUE) {
- ndvCost = childCost;
- }
-
- Float newCost = new Float(Math.min(childCost, ndvCost));
- return newCost;
- }
-
- private static float getStat(Stat stat, Collection<? extends Expression> elems, PlanNode node,
+ static float getStat(Stat stat, Collection<? extends Expression> elems, PlanNode node,
float cardinality, QueryMetadataInterface metadata) throws QueryMetadataException, TeiidComponentException {
float result = 0;
+ int branch = 0;
+ boolean branchFound = false;
for (Expression expression : elems) {
ColStats colStats = null;
if (node.getChildCount() == 0) {
colStats = createColStats(node, metadata, cardinality);
} else {
- for (PlanNode child : node.getChildren()) {
+ for (int i = branch; i < node.getChildCount(); i++) {
+ PlanNode child = node.getChildren().get(i);
colStats = (ColStats) child.getProperty(Info.EST_COL_STATS);
if (colStats == null) {
continue;
}
float[] stats = colStats.get(expression);
if (stats != null) {
+ if (node.getType() == NodeConstants.Types.SET_OP) {
+ branch = i;
+ branchFound = true;
+ }
break;
}
colStats = null;
+ if (branchFound) {
+ break;
+ }
}
}
if (colStats == null) {
@@ -879,6 +871,17 @@
}
isNegatedPredicateCriteria = isNullCriteria.isNegated();
+ } else if (predicateCriteria instanceof DependentSetCriteria) {
+ DependentSetCriteria dsc = (DependentSetCriteria)predicateCriteria;
+
+ if (unknownChildCost) {
+ return UNKNOWN_VALUE;
+ }
+ if (dsc.getNdv() == UNKNOWN_VALUE) {
+ return childCost / 3;
+ }
+
+ cost = childCost * dsc.getNdv() / ndv;
}
if (cost == UNKNOWN_VALUE) {
@@ -1005,6 +1008,7 @@
}
static boolean usesKey(PlanNode planNode, Collection<? extends SingleElementSymbol> allElements, QueryMetadataInterface metadata) throws QueryMetadataException, TeiidComponentException {
+ //TODO: key preserved joins should be marked
return NodeEditor.findAllNodes(planNode, NodeConstants.Types.SOURCE, NodeConstants.Types.JOIN | NodeConstants.Types.SET_OP).size() == 1
&& usesKey(allElements, metadata);
}
@@ -1132,15 +1136,7 @@
for (int i = 0; i < independentExpressions.size(); i++) {
Expression indExpr = (Expression)independentExpressions.get(i);
Collection<ElementSymbol> indElements = ElementCollectorVisitor.getElements(indExpr, true);
- float indSymbolNDV = getStat(Stat.NDV, indElements, independentNode, independentCardinality, metadata);
- boolean usesIndKey = usesKey(dependentNode, indElements, metadata);
- if (indSymbolNDV == UNKNOWN_VALUE) {
- if (!usesIndKey) {
- indSymbolNDV = Math.max(1, independentCardinality/2);
- } else {
- indSymbolNDV = independentCardinality;
- }
- }
+ float indSymbolNDV = getNDVEstimate(independentNode, metadata, independentCardinality, indElements, true);
Expression depExpr = (Expression)dependentExpressions.get(i);
LinkedList<PlanNode> critNodes = new LinkedList<PlanNode>();
@@ -1237,11 +1233,7 @@
indCardinalityOrig = computeCostForTree(indOrigNode, metadata);
indSymbolOrigNDV = getStat(Stat.NDV, indElements, indOrigNode, indCardinalityOrig, metadata);
if (indSymbolOrigNDV == UNKNOWN_VALUE) {
- if (!usesIndKey) {
- indSymbolOrigNDV = Math.max(1, indCardinalityOrig / 3);
- } else {
- indSymbolOrigNDV = indCardinalityOrig;
- }
+ indSymbolOrigNDV = indCardinalityOrig * indSymbolNDV / independentCardinality;
}
}
depSymbolNDV = Math.max((float)Math.pow(depTargetCardinality, .75), Math.min(indSymbolOrigNDV, depTargetCardinality));
@@ -1274,5 +1266,26 @@
return null;
}
+
+ static float getNDVEstimate(PlanNode indNode,
+ QueryMetadataInterface metadata, float cardinality,
+ Collection<? extends SingleElementSymbol> elems, boolean useCardinalityIfUnknown) throws QueryMetadataException,
+ TeiidComponentException {
+ if (elems == null || elems.isEmpty()) {
+ return cardinality;
+ }
+ float ndv = getStat(Stat.NDV, elems, indNode, cardinality, metadata);
+ if (ndv == UNKNOWN_VALUE) {
+ if (cardinality == UNKNOWN_VALUE) {
+ return UNKNOWN_VALUE;
+ }
+ if (usesKey(indNode, elems, metadata)) {
+ ndv = cardinality;
+ } else if (useCardinalityIfUnknown) {
+ ndv = cardinality/2;
+ }
+ }
+ return Math.max(1, ndv);
+ }
}
Modified: trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleChooseDependent.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleChooseDependent.java 2011-03-16 14:56:38 UTC (rev 2994)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleChooseDependent.java 2011-03-16 21:22:50 UTC (rev 2995)
@@ -23,6 +23,7 @@
package org.teiid.query.optimizer.relational.rules;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
@@ -42,8 +43,10 @@
import org.teiid.query.optimizer.relational.plantree.PlanNode;
import org.teiid.query.sql.lang.DependentSetCriteria;
import org.teiid.query.sql.lang.JoinType;
+import org.teiid.query.sql.symbol.ElementSymbol;
import org.teiid.query.sql.symbol.Expression;
import org.teiid.query.sql.util.SymbolMap;
+import org.teiid.query.sql.visitor.ElementCollectorVisitor;
import org.teiid.query.util.CommandContext;
@@ -82,7 +85,7 @@
PlanNode chosenNode = chooseDepWithoutCosting(sourceNode, bothCandidates?siblingNode:null, analysisRecord);
if(chosenNode != null) {
- pushCriteria |= markDependent(chosenNode, joinNode);
+ pushCriteria |= markDependent(chosenNode, joinNode, metadata);
continue;
}
@@ -97,16 +100,16 @@
}
if (useDepJoin) {
- pushCriteria |= markDependent(dependentNode, joinNode);
+ pushCriteria |= markDependent(dependentNode, joinNode, metadata);
} else {
float sourceCost = NewCalculateCostUtil.computeCostForTree(sourceNode, metadata);
float siblingCost = NewCalculateCostUtil.computeCostForTree(siblingNode, metadata);
if (bothCandidates && sourceCost != NewCalculateCostUtil.UNKNOWN_VALUE && sourceCost < RuleChooseDependent.DEFAULT_INDEPENDENT_CARDINALITY
&& (sourceCost < siblingCost || siblingCost == NewCalculateCostUtil.UNKNOWN_VALUE)) {
- pushCriteria |= markDependent(siblingNode, joinNode);
+ pushCriteria |= markDependent(siblingNode, joinNode, metadata);
} else if (siblingCost != NewCalculateCostUtil.UNKNOWN_VALUE && siblingCost < RuleChooseDependent.DEFAULT_INDEPENDENT_CARDINALITY) {
- pushCriteria |= markDependent(sourceNode, joinNode);
+ pushCriteria |= markDependent(sourceNode, joinNode, metadata);
}
}
}
@@ -257,8 +260,10 @@
/**
* Mark the specified access node to be made dependent
* @param sourceNode Node to make dependent
+ * @throws TeiidComponentException
+ * @throws QueryMetadataException
*/
- boolean markDependent(PlanNode sourceNode, PlanNode joinNode) {
+ boolean markDependent(PlanNode sourceNode, PlanNode joinNode, QueryMetadataInterface metadata) throws QueryMetadataException, TeiidComponentException {
boolean isLeft = joinNode.getFirstChild() == sourceNode;
@@ -274,12 +279,11 @@
// Create DependentValueSource and set on the independent side as this will feed the values
joinNode.setProperty(NodeConstants.Info.DEPENDENT_VALUE_SOURCE, id);
- List crits = getDependentCriteriaNodes(id, independentExpressions, dependentExpressions);
+ List<PlanNode> crits = getDependentCriteriaNodes(id, independentExpressions, dependentExpressions, isLeft?joinNode.getLastChild():joinNode.getFirstChild(), metadata);
PlanNode newRoot = sourceNode;
- for (Iterator i = crits.iterator(); i.hasNext();) {
- PlanNode crit = (PlanNode)i.next();
+ for (PlanNode crit : crits) {
newRoot.addAsParent(crit);
newRoot = crit;
}
@@ -294,20 +298,27 @@
* @param independentExpressions
* @param dependentExpressions
* @return
+ * @throws TeiidComponentException
+ * @throws QueryMetadataException
* @since 4.3
*/
- private List getDependentCriteriaNodes(String id, List independentExpressions,
- List dependentExpressions) {
+ private List<PlanNode> getDependentCriteriaNodes(String id, List independentExpressions,
+ List dependentExpressions, PlanNode indNode, QueryMetadataInterface metadata) throws QueryMetadataException, TeiidComponentException {
- List result = new LinkedList();
+ List<PlanNode> result = new LinkedList<PlanNode>();
Iterator depIter = dependentExpressions.iterator();
Iterator indepIter = independentExpressions.iterator();
+ float cardinality = NewCalculateCostUtil.computeCostForTree(indNode, metadata);
+
while(depIter.hasNext()) {
Expression depExpr = (Expression) depIter.next();
Expression indepExpr = (Expression) indepIter.next();
DependentSetCriteria crit = new DependentSetCriteria(SymbolMap.getExpression(depExpr), id);
+ Collection<ElementSymbol> elems = ElementCollectorVisitor.getElements(indepExpr, true);
+ float ndv = NewCalculateCostUtil.getNDVEstimate(indNode, metadata, cardinality, elems, true);
+ crit.setNdv(ndv);
crit.setValueExpression(indepExpr);
PlanNode selectNode = RelationalPlanner.createSelectNode(crit, false);
Modified: trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePlanJoins.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePlanJoins.java 2011-03-16 14:56:38 UTC (rev 2994)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePlanJoins.java 2011-03-16 21:22:50 UTC (rev 2995)
@@ -237,7 +237,7 @@
* Ideally we should be a little smarter in case 2
* - pushing down a same source cross join can be done if we know that a dependent join will be performed
*/
- //boolean hasJoinCriteria = false;
+ boolean hasJoinCriteria = false;
LinkedList<Criteria> joinCriteria = new LinkedList<Criteria>();
Object modelId = RuleRaiseAccess.getModelIDFromAccess(accessNode1, metadata);
SupportedJoinCriteria sjc = CapabilitiesUtil.getSupportedJoinCriteria(modelId, metadata, capFinder);
@@ -250,27 +250,23 @@
if (sources.contains(accessNode1)) {
if (sources.contains(accessNode2) && sources.size() == 2) {
- //hasJoinCriteria = true;
Criteria crit = (Criteria)critNode.getProperty(NodeConstants.Info.SELECT_CRITERIA);
if (RuleRaiseAccess.isSupportedJoinCriteria(sjc, crit, modelId, metadata, capFinder, null)) {
joinCriteriaNodes.add(critNode);
joinCriteria.add(crit);
}
} else if (!accessNodes.containsAll(sources)) {
- //hasJoinCriteria = true;
+ hasJoinCriteria = true;
}
} else if (sources.contains(accessNode2) && !accessNodes.containsAll(sources)) {
- //hasJoinCriteria = true;
+ hasJoinCriteria = true;
}
}
/*
* If we failed to find direct criteria, a cross join may still be acceptable
*/
- if (joinCriteriaNodes.isEmpty() && !canPushCrossJoin(metadata, context, accessNode1, accessNode2)) {
- //if (hasJoinCriteria) {
- //a cross join would still be a good idea given that a dependent join can be used
- //}
+ if (joinCriteriaNodes.isEmpty() && (hasJoinCriteria || !canPushCrossJoin(metadata, context, accessNode1, accessNode2))) {
continue;
}
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-16 14:56:38 UTC (rev 2994)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushAggregates.java 2011-03-16 21:22:50 UTC (rev 2995)
@@ -558,12 +558,12 @@
collectSymbolsFromOtherAggregates(allAggregates, aggregates, planNode, stagedGroupingSymbols);
- //if the grouping expressions are unique then there's no point in staging the aggregate
- if (NewCalculateCostUtil.usesKey(planNode, stagedGroupingSymbols, metadata)) {
- continue;
- }
-
- //TODO: we should be doing another cost check here - especially if the aggregate cannot be pushed.
+ //perform a costing check, if there's not a significant reduction, then don't stage
+ float cardinality = NewCalculateCostUtil.computeCostForTree(planNode, metadata);
+ float ndv = NewCalculateCostUtil.getNDVEstimate(planNode, metadata, cardinality, stagedGroupingSymbols, false);
+ if (ndv != NewCalculateCostUtil.UNKNOWN_VALUE && cardinality / ndv < 4) {
+ continue;
+ }
if (aggregates != null) {
stageAggregates(groupNode, metadata, stagedGroupingSymbols, aggregates);
Modified: trunk/engine/src/main/java/org/teiid/query/resolver/util/ResolverUtil.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/resolver/util/ResolverUtil.java 2011-03-16 14:56:38 UTC (rev 2994)
+++ trunk/engine/src/main/java/org/teiid/query/resolver/util/ResolverUtil.java 2011-03-16 21:22:50 UTC (rev 2995)
@@ -774,11 +774,11 @@
}
String exprTypeName = DataTypeManager.getDataTypeName(exprType);
- Collection projectedSymbols = crit.getCommand().getProjectedSymbols();
+ Collection<SingleElementSymbol> projectedSymbols = crit.getCommand().getProjectedSymbols();
if (projectedSymbols.size() != 1){
throw new QueryResolverException("ERR.015.008.0032", QueryPlugin.Util.getString("ERR.015.008.0032", crit.getCommand())); //$NON-NLS-1$ //$NON-NLS-2$
}
- Class subqueryType = ((Expression)projectedSymbols.iterator().next()).getType();
+ Class<?> subqueryType = projectedSymbols.iterator().next().getType();
String subqueryTypeName = DataTypeManager.getDataTypeName(subqueryType);
Expression result = null;
try {
Modified: trunk/engine/src/main/java/org/teiid/query/sql/lang/DependentSetCriteria.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/lang/DependentSetCriteria.java 2011-03-16 14:56:38 UTC (rev 2994)
+++ trunk/engine/src/main/java/org/teiid/query/sql/lang/DependentSetCriteria.java 2011-03-16 21:22:50 UTC (rev 2995)
@@ -43,6 +43,10 @@
*/
private Expression valueExpression;
private String id;
+ /**
+ * The estimated number of distinct values for the value Expression
+ */
+ private float ndv;
/**
* Construct with the left expression
@@ -56,6 +60,14 @@
public String getContextSymbol() {
return id;
}
+
+ public float getNdv() {
+ return ndv;
+ }
+
+ public void setNdv(float ndv) {
+ this.ndv = ndv;
+ }
/**
* Get the independent value expression
@@ -131,6 +143,7 @@
criteriaCopy.setValueExpression((Expression) getValueExpression().clone());
}
criteriaCopy.id = this.id;
+ criteriaCopy.ndv = this.ndv;
return criteriaCopy;
}
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-16 14:56:38 UTC (rev 2994)
+++ trunk/engine/src/test/java/org/teiid/query/optimizer/TestAggregatePushdown.java 2011-03-16 21:22:50 UTC (rev 2995)
@@ -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 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$
+ "SELECT g_0.CITY, g_0.REGION FROM oraclemodel.GEOGRAPHY AS g_0 WHERE g_0.REGION IN ('BORDEAUX', 'POLINESIA')"}, //$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 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$
+ "SELECT g_0.CITY, g_0.REGION FROM oraclemodel.GEOGRAPHY AS g_0 WHERE g_0.REGION IN ('BORDEAUX', 'POLINESIA')"}, //$NON-NLS-1$
ComparisonMode.EXACT_COMMAND_STRING );
checkNodeTypes(plan, new int[] {
Modified: trunk/engine/src/test/java/org/teiid/query/processor/TestVirtualDepJoin.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/processor/TestVirtualDepJoin.java 2011-03-16 14:56:38 UTC (rev 2994)
+++ trunk/engine/src/test/java/org/teiid/query/processor/TestVirtualDepJoin.java 2011-03-16 21:22:50 UTC (rev 2995)
@@ -374,7 +374,7 @@
0, // DependentSelect
0, // DependentProject
0, // DupRemove
- 3, // Grouping
+ 2, // Grouping
0, // NestedLoopJoinStrategy
1, // MergeJoinStrategy
0, // Null
@@ -710,7 +710,7 @@
0, // DependentSelect
0, // DependentProject
0, // DupRemove
- 3, // Grouping
+ 2, // Grouping
0, // NestedLoopJoinStrategy
1, // MergeJoinStrategy
0, // Null
Modified: trunk/test-integration/common/src/test/java/org/teiid/dqp/internal/process/TestCrossSourceStarJoin.java
===================================================================
--- trunk/test-integration/common/src/test/java/org/teiid/dqp/internal/process/TestCrossSourceStarJoin.java 2011-03-16 14:56:38 UTC (rev 2994)
+++ trunk/test-integration/common/src/test/java/org/teiid/dqp/internal/process/TestCrossSourceStarJoin.java 2011-03-16 21:22:50 UTC (rev 2995)
@@ -67,7 +67,7 @@
new String[] { "PRODUCT", "CURRENCY", "BOOK", "AMOUNT"}, //$NON-NLS-1$
new String[] { DataTypeManager.DefaultDataTypes.STRING, DataTypeManager.DefaultDataTypes.INTEGER, DataTypeManager.DefaultDataTypes.STRING, DataTypeManager.DefaultDataTypes.BIG_DECIMAL});
- f_cols.get(0).setDistinctValues(200);
+ f_cols.get(0).setDistinctValues(400);
f_cols.get(1).setDistinctValues(228);
f_cols.get(2).setDistinctValues(141496);
createKey(KeyRecord.Type.Index, "idx_p", f, f_cols.subList(0, 1));
@@ -79,6 +79,8 @@
new String[] { DataTypeManager.DefaultDataTypes.STRING, DataTypeManager.DefaultDataTypes.STRING});
createKey(KeyRecord.Type.Primary, "pk", b, b_cols.subList(0, 1));
+ b_cols.get(1).setDistinctValues(70000);
+
//createKey(KeyRecord.Type.Unique, "uk", b, b_cols.subList(1, 2));
List<Column> c_cols = createElements(c,
@@ -102,10 +104,19 @@
TestOptimizer.helpPlan(sql, metadata, new String[] {
"SELECT g_0.CurrencyCode AS c_0 FROM sybase.s2 AS g_0 WHERE g_0.Name = 'abc' ORDER BY c_0",
- "SELECT g_0.BOOKID FROM sybase.s1 AS g_0 WHERE g_0.Name = 'xyz'",
+ "SELECT g_0.BOOKID AS c_0 FROM sybase.s1 AS g_0 WHERE g_0.Name = 'xyz' ORDER BY c_0",
"SELECT g_0.PRODUCTID AS c_0, g_0.Description AS c_1 FROM sybase.s3 AS g_0 ORDER BY c_0",
- "SELECT g_0.CURRENCY AS c_0, g_0.PRODUCT AS c_1, g_0.BOOK AS c_2, SUM(g_0.AMOUNT) AS c_3 FROM oracle.o1 AS g_0 WHERE (g_0.CURRENCY IN (<dependent values>)) AND (g_0.PRODUCT IN (<dependent values>)) AND (g_0.BOOK IN (<dependent values>)) GROUP BY g_0.CURRENCY, g_0.PRODUCT, g_0.BOOK ORDER BY c_0 NULLS FIRST"
+ "SELECT g_0.BOOK AS c_0, g_0.CURRENCY AS c_1, g_0.PRODUCT AS c_2, SUM(g_0.AMOUNT) AS c_3 FROM oracle.o1 AS g_0 WHERE (g_0.BOOK IN (<dependent values>)) AND (g_0.CURRENCY IN (<dependent values>)) AND (g_0.PRODUCT IN (<dependent values>)) GROUP BY g_0.BOOK, g_0.CURRENCY, g_0.PRODUCT ORDER BY c_0 NULLS FIRST"
}, finder, ComparisonMode.EXACT_COMMAND_STRING);
+
+ //test that aggregate will not be staged
+ f.setCardinality(527696);
+ TestOptimizer.helpPlan(sql, metadata, new String[] {
+ "SELECT g_0.CurrencyCode AS c_0 FROM sybase.s2 AS g_0 WHERE g_0.Name = 'abc' ORDER BY c_0",
+ "SELECT g_0.BOOKID AS c_0 FROM sybase.s1 AS g_0 WHERE g_0.Name = 'xyz' ORDER BY c_0",
+ "SELECT g_0.PRODUCTID AS c_0, g_0.Description AS c_1 FROM sybase.s3 AS g_0 ORDER BY c_0",
+ "SELECT g_0.BOOK AS c_0, g_0.CURRENCY AS c_1, g_0.PRODUCT AS c_2, g_0.AMOUNT AS c_3 FROM oracle.o1 AS g_0 WHERE (g_0.BOOK IN (<dependent values>)) AND (g_0.CURRENCY IN (<dependent values>)) AND (g_0.PRODUCT IN (<dependent values>)) ORDER BY c_0 NULLS FIRST"
+ }, finder, ComparisonMode.EXACT_COMMAND_STRING);
}
}
13 years, 10 months
teiid SVN: r2994 - trunk/common-core/src/test/resources.
by teiid-commits@lists.jboss.org
Author: shawkins
Date: 2011-03-16 10:56:38 -0400 (Wed, 16 Mar 2011)
New Revision: 2994
Removed:
trunk/common-core/src/test/resources/testEmptiedZipFile.zip
trunk/common-core/src/test/resources/testEmptyZipFile.zip
trunk/common-core/src/test/resources/testZipFile.zip
Log:
removing unused test files
Deleted: trunk/common-core/src/test/resources/testEmptiedZipFile.zip
===================================================================
(Binary files differ)
Deleted: trunk/common-core/src/test/resources/testEmptyZipFile.zip
===================================================================
Deleted: trunk/common-core/src/test/resources/testZipFile.zip
===================================================================
(Binary files differ)
13 years, 10 months
teiid SVN: r2993 - in trunk: common-core/src/main/java/org/teiid/core/types and 1 other directories.
by teiid-commits@lists.jboss.org
Author: shawkins
Date: 2011-03-16 10:38:29 -0400 (Wed, 16 Mar 2011)
New Revision: 2993
Modified:
trunk/client/src/main/java/org/teiid/jdbc/ResultSetImpl.java
trunk/common-core/src/main/java/org/teiid/core/types/Streamable.java
trunk/test-integration/common/src/test/java/org/teiid/jdbc/TestQueryPlans.java
Log:
TEIID-1512 fixing the show plan results
Modified: trunk/client/src/main/java/org/teiid/jdbc/ResultSetImpl.java
===================================================================
--- trunk/client/src/main/java/org/teiid/jdbc/ResultSetImpl.java 2011-03-16 01:43:50 UTC (rev 2992)
+++ trunk/client/src/main/java/org/teiid/jdbc/ResultSetImpl.java 2011-03-16 14:38:29 UTC (rev 2993)
@@ -291,12 +291,10 @@
currentValue = cursorRow.get(column-1);
if (currentValue instanceof Streamable<?>) {
- if (Boolean.getBoolean(Streamable.FORCE_STREAMING)) {
- Object reference = ((Streamable<?>)currentValue).getReference();
- if (reference != null) {
- currentValue = reference;
- return currentValue;
- }
+ Object reference = ((Streamable<?>)currentValue).getReference();
+ if (reference != null) {
+ currentValue = reference;
+ return currentValue;
}
if(currentValue instanceof ClobType){
currentValue = new ClobImpl(createInputStreamFactory((ClobType)currentValue), ((ClobType)currentValue).getLength());
Modified: trunk/common-core/src/main/java/org/teiid/core/types/Streamable.java
===================================================================
--- trunk/common-core/src/main/java/org/teiid/core/types/Streamable.java 2011-03-16 01:43:50 UTC (rev 2992)
+++ trunk/common-core/src/main/java/org/teiid/core/types/Streamable.java 2011-03-16 14:38:29 UTC (rev 2993)
@@ -48,7 +48,6 @@
public static final String ENCODING = "UTF-8"; //$NON-NLS-1$
public static final Charset CHARSET = Charset.forName(ENCODING);
- public static final String FORCE_STREAMING = "FORCE_STREAMING"; //$NON-NLS-1$
public static final int STREAMING_BATCH_SIZE_IN_BYTES = 102400; // 100K
private String referenceStreamId = String.valueOf(counter.getAndIncrement());
Modified: trunk/test-integration/common/src/test/java/org/teiid/jdbc/TestQueryPlans.java
===================================================================
--- trunk/test-integration/common/src/test/java/org/teiid/jdbc/TestQueryPlans.java 2011-03-16 01:43:50 UTC (rev 2992)
+++ trunk/test-integration/common/src/test/java/org/teiid/jdbc/TestQueryPlans.java 2011-03-16 14:38:29 UTC (rev 2993)
@@ -71,6 +71,7 @@
rs = s.executeQuery("show plan");
assertTrue(rs.next());
assertEquals(rs.getMetaData().getColumnType(1), Types.CLOB);
+ assertTrue(rs.getString(1).startsWith("ProjectNode"));
SQLXML plan = rs.getSQLXML(2);
assertTrue(plan.getString().startsWith("<?xml"));
assertNull(rs.getObject("DEBUG_LOG"));
13 years, 10 months
teiid SVN: r2992 - trunk/engine/src/main/java/org/teiid/dqp/internal/process.
by teiid-commits@lists.jboss.org
Author: shawkins
Date: 2011-03-15 21:43:50 -0400 (Tue, 15 Mar 2011)
New Revision: 2992
Modified:
trunk/engine/src/main/java/org/teiid/dqp/internal/process/DataTierTupleSource.java
trunk/engine/src/main/java/org/teiid/dqp/internal/process/RequestWorkItem.java
Log:
TEIID-1474 refining the implementation so that morework is not called until after the workitem is done. otherwise there is a race condition which could result in hung requests
Modified: trunk/engine/src/main/java/org/teiid/dqp/internal/process/DataTierTupleSource.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/dqp/internal/process/DataTierTupleSource.java 2011-03-16 01:26:46 UTC (rev 2991)
+++ trunk/engine/src/main/java/org/teiid/dqp/internal/process/DataTierTupleSource.java 2011-03-16 01:43:50 UTC (rev 2992)
@@ -51,6 +51,7 @@
import org.teiid.core.util.Assertion;
import org.teiid.core.util.ObjectConverterUtil;
import org.teiid.dqp.internal.datamgr.ConnectorWork;
+import org.teiid.dqp.internal.process.DQPCore.CompletionListener;
import org.teiid.dqp.internal.process.DQPCore.FutureWork;
import org.teiid.dqp.message.AtomicRequestMessage;
import org.teiid.dqp.message.AtomicResultsMessage;
@@ -69,7 +70,7 @@
* In the multi-threaded case we'd like to not even
* notify the parent plan and just schedule the next poll.
*/
-public class DataTierTupleSource implements TupleSource {
+public class DataTierTupleSource implements TupleSource, CompletionListener<AtomicResultsMessage> {
// Construction state
private final AtomicRequestMessage aqr;
@@ -129,7 +130,7 @@
public AtomicResultsMessage call() throws Exception {
return getResults();
}
- }, 100);
+ }, this, 100);
}
private List correctTypes(List row) throws TransformationException {
@@ -282,27 +283,16 @@
throws BlockedException, TeiidComponentException,
TranslatorException {
AtomicResultsMessage results = null;
- try {
- if (cancelAsynch) {
- return null;
- }
- running = true;
- if (!executed) {
- results = cwi.execute();
- executed = true;
- } else {
- results = cwi.more();
- }
- } finally {
- if (!cancelAsynch) {
- workItem.moreWork();
- }
- canAsynchClose = false;
- if (closed.get()) {
- cwi.close();
- }
- running = false;
+ if (cancelAsynch) {
+ return null;
}
+ running = true;
+ if (!executed) {
+ results = cwi.execute();
+ executed = true;
+ } else {
+ results = cwi.more();
+ }
return results;
}
@@ -402,5 +392,17 @@
public boolean isTransactional() {
return this.aqr.isTransactional();
}
+
+ @Override
+ public void onCompletion(FutureWork<AtomicResultsMessage> future) {
+ if (!cancelAsynch) {
+ workItem.moreWork();
+ }
+ canAsynchClose = false;
+ if (closed.get()) {
+ cwi.close();
+ }
+ running = false;
+ }
}
Modified: trunk/engine/src/main/java/org/teiid/dqp/internal/process/RequestWorkItem.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/dqp/internal/process/RequestWorkItem.java 2011-03-16 01:26:46 UTC (rev 2991)
+++ trunk/engine/src/main/java/org/teiid/dqp/internal/process/RequestWorkItem.java 2011-03-16 01:43:50 UTC (rev 2992)
@@ -47,6 +47,7 @@
import org.teiid.core.TeiidException;
import org.teiid.core.TeiidProcessingException;
import org.teiid.core.types.DataTypeManager;
+import org.teiid.dqp.internal.process.DQPCore.CompletionListener;
import org.teiid.dqp.internal.process.DQPCore.FutureWork;
import org.teiid.dqp.internal.process.SessionAwareCache.CacheID;
import org.teiid.dqp.internal.process.ThreadReuseExecutor.PrioritizedRunnable;
@@ -807,10 +808,11 @@
return work;
}
- <T> FutureWork<T> addWork(Callable<T> callable, int priority) {
+ <T> FutureWork<T> addWork(Callable<T> callable, CompletionListener<T> listener, int priority) {
FutureWork<T> work = new FutureWork<T>(callable, priority);
WorkWrapper<T> wl = new WorkWrapper<T>(work);
work.addCompletionListener(wl);
+ work.addCompletionListener(listener);
synchronized (queue) {
if (totalThreads < dqpCore.getUserRequestSourceConcurrency()) {
dqpCore.addWork(work);
13 years, 10 months
teiid SVN: r2991 - in trunk: engine/src/main/java/org/teiid/query/optimizer/relational and 12 other directories.
by teiid-commits@lists.jboss.org
Author: shawkins
Date: 2011-03-15 21:26:46 -0400 (Tue, 15 Mar 2011)
New Revision: 2991
Added:
trunk/test-integration/common/src/test/java/org/teiid/dqp/internal/process/TestCrossSourceStarJoin.java
Modified:
trunk/build/kits/jboss-container/teiid-releasenotes.html
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/RelationalPlanner.java
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/plantree/NodeConstants.java
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/plantree/PlanNode.java
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/JoinRegion.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/RuleChooseDependent.java
trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleImplementJoinStrategy.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/RulePlanJoins.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/RulePushSelectCriteria.java
trunk/engine/src/main/java/org/teiid/query/processor/relational/RelationalNode.java
trunk/engine/src/main/java/org/teiid/query/rewriter/QueryRewriter.java
trunk/engine/src/main/java/org/teiid/query/sql/lang/DependentSetCriteria.java
trunk/engine/src/test/java/org/teiid/dqp/internal/process/TestDQPCore.java
trunk/engine/src/test/java/org/teiid/query/optimizer/TestAggregatePushdown.java
trunk/engine/src/test/java/org/teiid/query/optimizer/TestDependentJoins.java
trunk/engine/src/test/java/org/teiid/query/optimizer/TestOptimizer.java
trunk/engine/src/test/java/org/teiid/query/optimizer/TestPartitionedJoinPlanning.java
trunk/engine/src/test/java/org/teiid/query/optimizer/relational/rules/TestRuleChooseDependent.java
trunk/engine/src/test/java/org/teiid/query/processor/TestVirtualDepJoin.java
trunk/engine/src/test/java/org/teiid/query/processor/xml/TestXMLPlanningEnhancements.java
trunk/engine/src/test/java/org/teiid/query/unittest/RealMetadataFactory.java
trunk/test-integration/common/src/test/java/org/teiid/dqp/internal/process/TestTPCR.java
Log:
TEIID-1508 TEIID-239 considering dependent joins earlier in planning and enhancing the costing logic
Modified: trunk/build/kits/jboss-container/teiid-releasenotes.html
===================================================================
--- trunk/build/kits/jboss-container/teiid-releasenotes.html 2011-03-11 17:39:21 UTC (rev 2990)
+++ trunk/build/kits/jboss-container/teiid-releasenotes.html 2011-03-16 01:26:46 UTC (rev 2991)
@@ -40,6 +40,7 @@
<LI><B>Optional Join Enhancements</B> - the optional join hint no longer requires the use of ANSI joins and can will not remove optional bridging tables that are used by two other tables that are required.
<LI><B>InterSystems Cache</B> - InterSystems Cache database translator is now available to use as supported source under Teiid.
<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.
</UL>
<h2><a name="Compatibility">Compatibility Issues</a></h2>
Modified: trunk/engine/src/main/java/org/teiid/query/optimizer/relational/RelationalPlanner.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/optimizer/relational/RelationalPlanner.java 2011-03-11 17:39:21 UTC (rev 2990)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/RelationalPlanner.java 2011-03-16 01:26:46 UTC (rev 2991)
@@ -389,10 +389,10 @@
rules.push(RuleConstants.IMPLEMENT_JOIN_STRATEGY);
}
+ rules.push(RuleConstants.CALCULATE_COST);
+
rules.push(RuleConstants.ASSIGN_OUTPUT_ELEMENTS);
- rules.push(RuleConstants.CALCULATE_COST);
-
if (hints.hasLimit) {
rules.push(RuleConstants.PUSH_LIMIT);
}
Modified: trunk/engine/src/main/java/org/teiid/query/optimizer/relational/plantree/NodeConstants.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/optimizer/relational/plantree/NodeConstants.java 2011-03-11 17:39:21 UTC (rev 2990)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/plantree/NodeConstants.java 2011-03-16 01:26:46 UTC (rev 2991)
@@ -139,6 +139,7 @@
EST_DEP_JOIN_COST, // Float value that represents the estimated cost of a dependent join (the join strategy for this could be Nested Loop or Merge)
EST_JOIN_COST, // Float value that represents the estimated cost of a merge join (the join strategy for this could be Nested Loop or Merge)
EST_CARDINALITY, // Float represents the estimated cardinality (amount of rows) produced by this node
+ EST_COL_STATS,
EST_SELECTIVITY, // Float that represents the selectivity of a criteria node
// Tuple limit and offset
Modified: trunk/engine/src/main/java/org/teiid/query/optimizer/relational/plantree/PlanNode.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/optimizer/relational/plantree/PlanNode.java 2011-03-11 17:39:21 UTC (rev 2990)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/plantree/PlanNode.java 2011-03-16 01:26:46 UTC (rev 2991)
@@ -170,11 +170,11 @@
return nodeProperties.get(propertyID);
}
- public void setProperty(NodeConstants.Info propertyID, Object value) {
+ public Object setProperty(NodeConstants.Info propertyID, Object value) {
if(nodeProperties == null) {
nodeProperties = new HashMap<NodeConstants.Info, Object>();
}
- nodeProperties.put(propertyID, value);
+ return nodeProperties.put(propertyID, value);
}
public Object removeProperty(Object propertyID) {
Modified: trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/JoinRegion.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/JoinRegion.java 2011-03-11 17:39:21 UTC (rev 2990)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/JoinRegion.java 2011-03-16 01:26:46 UTC (rev 2991)
@@ -23,6 +23,7 @@
package org.teiid.query.optimizer.relational.rules;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
@@ -34,12 +35,15 @@
import java.util.Set;
import org.teiid.api.exception.query.QueryMetadataException;
+import org.teiid.api.exception.query.QueryPlannerException;
import org.teiid.core.TeiidComponentException;
import org.teiid.metadata.FunctionMethod.PushDown;
import org.teiid.query.metadata.QueryMetadataInterface;
+import org.teiid.query.optimizer.capabilities.CapabilitiesFinder;
import org.teiid.query.optimizer.relational.RelationalPlanner;
import org.teiid.query.optimizer.relational.plantree.NodeConstants;
import org.teiid.query.optimizer.relational.plantree.PlanNode;
+import org.teiid.query.optimizer.relational.plantree.NodeConstants.Info;
import org.teiid.query.resolver.util.AccessPattern;
import org.teiid.query.sql.lang.CompareCriteria;
import org.teiid.query.sql.lang.CompoundCriteria;
@@ -51,6 +55,7 @@
import org.teiid.query.sql.visitor.ElementCollectorVisitor;
import org.teiid.query.sql.visitor.FunctionCollectorVisitor;
import org.teiid.query.sql.visitor.GroupsUsedByElementsVisitor;
+import org.teiid.query.util.CommandContext;
/**
@@ -87,6 +92,8 @@
private Map<ElementSymbol, Set<Collection<GroupSymbol>>> dependentCriteriaElements;
private Map<PlanNode, Set<PlanNode>> critieriaToSourceMap;
+ private HashMap<List<Object>, Float> depCache;
+
public PlanNode getJoinRoot() {
return joinRoot;
}
@@ -224,7 +231,7 @@
}
this.joinRoot = root;
}
-
+
/**
* Will provide an estimate of cost by summing the estimated tuples flowing through
* each intermediate join.
@@ -234,8 +241,9 @@
* @return
* @throws TeiidComponentException
* @throws QueryMetadataException
+ * @throws QueryPlannerException
*/
- public double scoreRegion(Object[] joinOrder, QueryMetadataInterface metadata) throws QueryMetadataException, TeiidComponentException {
+ public double scoreRegion(Object[] joinOrder, int startIndex, QueryMetadataInterface metadata, CapabilitiesFinder capFinder, CommandContext context) throws QueryMetadataException, TeiidComponentException, QueryPlannerException {
List<Map.Entry<PlanNode, PlanNode>> joinSourceEntries = new ArrayList<Map.Entry<PlanNode, PlanNode>>(joinSourceNodes.entrySet());
double totalIntermediatCost = 0;
double cost = 1;
@@ -249,19 +257,25 @@
Map.Entry<PlanNode, PlanNode> entry = joinSourceEntries.get(source.intValue());
PlanNode joinSourceRoot = entry.getValue();
- //check to make sure that this group ordering satisfies the access patterns
- if (!this.unsatisfiedAccessPatterns.isEmpty() || this.containsNestedTable) {
- PlanNode joinSource = entry.getKey();
-
- Collection<GroupSymbol> requiredGroups = (Collection<GroupSymbol>)joinSource.getProperty(NodeConstants.Info.REQUIRED_ACCESS_PATTERN_GROUPS);
-
- if (requiredGroups != null && !groups.containsAll(requiredGroups)) {
- return Double.MAX_VALUE;
- }
- }
+ if (startIndex == 0) {
+ //check to make sure that this group ordering satisfies the access patterns
+ if (!this.unsatisfiedAccessPatterns.isEmpty() || this.containsNestedTable) {
+ PlanNode joinSource = entry.getKey();
+
+ Collection<GroupSymbol> requiredGroups = (Collection<GroupSymbol>)joinSource.getProperty(NodeConstants.Info.REQUIRED_ACCESS_PATTERN_GROUPS);
+
+ if (requiredGroups != null && !groups.containsAll(requiredGroups)) {
+ return Double.MAX_VALUE;
+ }
+ }
+ }
groups.addAll(joinSourceRoot.getGroups());
+ if (startIndex > 0) {
+ continue;
+ }
+
float sourceCost = ((Float)joinSourceRoot.getProperty(NodeConstants.Info.EST_CARDINALITY)).floatValue();
List<PlanNode> applicableCriteria = null;
@@ -280,7 +294,7 @@
sourceCost = (float)cost;
criteria.removeAll(applicableCriteria);
applicableCriteria = null;
- if (NewCalculateCostUtil.usesKey(cc, metadata)) {
+ if (NewCalculateCostUtil.usesKey(cc, metadata) || (i == 1 && joinSourceRoot.hasBooleanProperty(Info.MAKE_DEP) && !joinSourceRoot.hasBooleanProperty(Info.MAKE_NOT_DEP))) {
sourceCost = Math.min(UNKNOWN_TUPLE_EST, sourceCost * Math.min(NewCalculateCostUtil.UNKNOWN_JOIN_SCALING, sourceCost));
} else {
sourceCost = Math.min(UNKNOWN_TUPLE_EST, sourceCost * Math.min(NewCalculateCostUtil.UNKNOWN_JOIN_SCALING * 2, sourceCost));
@@ -288,6 +302,25 @@
}
} else if (Double.isInfinite(sourceCost) || Double.isNaN(sourceCost)) {
return Double.MAX_VALUE;
+ } else if (i == 1 && applicableCriteria != null && !applicableCriteria.isEmpty()) {
+ List<Object> key = Arrays.asList(joinOrder[0], joinOrder[1]);
+ Float depJoinCost = null;
+ if (depCache != null && depCache.containsKey(key)) {
+ depJoinCost = depCache.get(key);
+ } else {
+ Integer indIndex = (Integer)joinOrder[0];
+ Map.Entry<PlanNode, PlanNode> indEntry = joinSourceEntries.get(indIndex.intValue());
+ PlanNode possibleInd = indEntry.getValue();
+
+ depJoinCost = getDepJoinCost(metadata, capFinder, context, possibleInd, applicableCriteria, joinSourceRoot);
+ if (depCache == null) {
+ depCache = new HashMap<List<Object>, Float>();
+ }
+ depCache.put(key, depJoinCost);
+ }
+ if (depJoinCost != null) {
+ sourceCost = depJoinCost;
+ }
}
cost *= sourceCost;
@@ -306,6 +339,34 @@
return totalIntermediatCost;
}
+
+ private Float getDepJoinCost(QueryMetadataInterface metadata,
+ CapabilitiesFinder capFinder, CommandContext context,
+ PlanNode indNode, List<PlanNode> applicableCriteria,
+ PlanNode depNode) throws QueryMetadataException,
+ TeiidComponentException, QueryPlannerException {
+ if (depNode.hasBooleanProperty(Info.MAKE_NOT_DEP)) {
+ return null;
+ }
+
+ float indCost = indNode.getCardinality();
+
+ if (indCost == NewCalculateCostUtil.UNKNOWN_VALUE) {
+ return null;
+ }
+
+ List<Criteria> crits = new ArrayList<Criteria>(applicableCriteria.size());
+ for (PlanNode planNode : applicableCriteria) {
+ crits.add((Criteria) planNode.getProperty(NodeConstants.Info.SELECT_CRITERIA));
+ }
+ List<Expression> leftExpressions = new LinkedList<Expression>();
+ List<Expression> rightExpressions = new LinkedList<Expression>();
+ RuleChooseJoinStrategy.separateCriteria(indNode.getGroups(), depNode.getGroups(), leftExpressions, rightExpressions, crits, new LinkedList<Criteria>());
+ if (leftExpressions.isEmpty()) {
+ return null;
+ }
+ return NewCalculateCostUtil.computeCostForDepJoin(indNode, depNode, leftExpressions, rightExpressions, metadata, capFinder, context);
+ }
/**
* Returns true if every element in an unsatisfied access pattern can be satisfied by the current join criteria
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-11 17:39:21 UTC (rev 2990)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/NewCalculateCostUtil.java 2011-03-16 01:26:46 UTC (rev 2991)
@@ -31,11 +31,15 @@
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.Map.Entry;
import org.teiid.api.exception.query.QueryMetadataException;
+import org.teiid.api.exception.query.QueryPlannerException;
import org.teiid.common.buffer.BufferManager;
import org.teiid.core.TeiidComponentException;
import org.teiid.core.types.DataTypeManager;
@@ -43,16 +47,18 @@
import org.teiid.logging.LogManager;
import org.teiid.query.QueryPlugin;
import org.teiid.query.metadata.QueryMetadataInterface;
-import org.teiid.query.metadata.SupportConstants;
import org.teiid.query.optimizer.capabilities.CapabilitiesFinder;
+import org.teiid.query.optimizer.relational.RelationalPlanner;
import org.teiid.query.optimizer.relational.plantree.NodeConstants;
import org.teiid.query.optimizer.relational.plantree.NodeEditor;
import org.teiid.query.optimizer.relational.plantree.PlanNode;
-import org.teiid.query.processor.relational.JoinNode.JoinStrategyType;
+import org.teiid.query.optimizer.relational.plantree.NodeConstants.Info;
+import org.teiid.query.resolver.util.ResolverUtil;
import org.teiid.query.sql.lang.AbstractSetCriteria;
import org.teiid.query.sql.lang.CompareCriteria;
import org.teiid.query.sql.lang.CompoundCriteria;
import org.teiid.query.sql.lang.Criteria;
+import org.teiid.query.sql.lang.DependentSetCriteria;
import org.teiid.query.sql.lang.IsNullCriteria;
import org.teiid.query.sql.lang.JoinType;
import org.teiid.query.sql.lang.MatchCriteria;
@@ -61,12 +67,14 @@
import org.teiid.query.sql.lang.SetCriteria;
import org.teiid.query.sql.lang.SetQuery;
import org.teiid.query.sql.lang.SubquerySetCriteria;
+import org.teiid.query.sql.lang.SetQuery.Operation;
import org.teiid.query.sql.symbol.Constant;
import org.teiid.query.sql.symbol.ElementSymbol;
import org.teiid.query.sql.symbol.Expression;
import org.teiid.query.sql.symbol.GroupSymbol;
import org.teiid.query.sql.symbol.SingleElementSymbol;
import org.teiid.query.sql.util.SymbolMap;
+import org.teiid.query.sql.visitor.AggregateSymbolCollectorVisitor;
import org.teiid.query.sql.visitor.ElementCollectorVisitor;
import org.teiid.query.sql.visitor.EvaluatableVisitor;
import org.teiid.query.sql.visitor.GroupsUsedByElementsVisitor;
@@ -81,11 +89,41 @@
public static final float UNKNOWN_VALUE = -1;
// the following variables are used to hold cost estimates (roughly in milliseconds)
- private final static float compareTime = .05f; //TODO: a better estimate would be based upon the number of conjuncts
+ private final static float compareTime = .0001f; //TODO: a better estimate would be based upon the number of conjuncts
private final static float readTime = .001f; //TODO: should come from the connector
- private final static float procNewRequestTime = 100; //TODO: should come from the connector
- private final static float procMoreRequestTime = 15; //TODO: should come from the connector
+ private final static float procNewRequestTime = 1; //TODO: should come from the connector
+ private enum Stat {
+ NDV,
+ NNV
+ }
+
+ @SuppressWarnings("serial")
+ private static class ColStats extends LinkedHashMap<Expression, float[]> {
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append('{');
+
+ int j = 0;
+ for (Iterator<Entry<Expression, float[]>> i = this.entrySet().iterator(); i.hasNext();) {
+ Entry<Expression, float[]> e = i.next();
+ sb.append(e.getKey());
+ sb.append('=');
+ sb.append(Arrays.toString(e.getValue()));
+ j++;
+ if (i.hasNext()) {
+ sb.append(", "); //$NON-NLS-1$
+ if (j > 3) {
+ sb.append("..."); //$NON-NLS-1$
+ break;
+ }
+ }
+ }
+ return sb.append('}').toString();
+ }
+ }
+
/**
* Calculate cost of a node and all children, recursively from the bottom up.
* @param node
@@ -97,22 +135,24 @@
static float computeCostForTree(PlanNode node, QueryMetadataInterface metadata)
throws QueryMetadataException, TeiidComponentException {
- Float cost = (Float) node.getProperty(NodeConstants.Info.EST_CARDINALITY);
+ updateCardinality(node, metadata);
+
+ return node.getCardinality();
+ }
+
+ static boolean updateCardinality(PlanNode node, QueryMetadataInterface metadata) throws QueryMetadataException, TeiidComponentException {
+ Float cost = (Float) node.getProperty(NodeConstants.Info.EST_CARDINALITY);
// check if already computed
- if(cost == null) {
- for (PlanNode child : node.getChildren()) {
- computeCostForTree(child, metadata);
- }
+ boolean updated = false;
+ for (PlanNode child : node.getChildren()) {
+ updated |= updateCardinality(child, metadata);
+ }
+ if(cost == null || updated) {
computeNodeCost(node, metadata);
- cost = (Float) node.getProperty(NodeConstants.Info.EST_CARDINALITY);
+ return true;
}
-
- if(cost != null) {
- return cost.floatValue();
- }
-
- return UNKNOWN_VALUE;
+ return false;
}
/**
@@ -144,7 +184,7 @@
case NodeConstants.Types.GROUP:
if (!node.hasCollectionProperty(NodeConstants.Info.GROUP_COLS)) {
- setCardinalityEstimate(node, 1f);
+ setCardinalityEstimate(node, 1f, true, metadata);
} else {
estimateNodeCost(node, (List)node.getProperty(NodeConstants.Info.GROUP_COLS), metadata);
}
@@ -155,11 +195,11 @@
//Simply record the cost of the only child
PlanNode child = node.getFirstChild();
Float childCost = (Float)child.getProperty(NodeConstants.Info.EST_CARDINALITY);
- setCardinalityEstimate(node, childCost);
+ setCardinalityEstimate(node, childCost, true, metadata);
break;
}
case NodeConstants.Types.NULL:
- setCardinalityEstimate(node, 0f);
+ setCardinalityEstimate(node, 0f, true, metadata);
break;
case NodeConstants.Types.PROJECT:
@@ -172,7 +212,7 @@
} else {
childCost = 1f;
}
- setCardinalityEstimate(node, childCost);
+ setCardinalityEstimate(node, childCost, true, metadata);
break;
}
case NodeConstants.Types.SET_OP:
@@ -202,7 +242,7 @@
cost = new Float(limitCost);
}
}
- setCardinalityEstimate(node, cost);
+ setCardinalityEstimate(node, cost, true, metadata);
break;
}
}
@@ -223,6 +263,13 @@
rightCost = getDistinctEstimate(node.getLastChild(), metadata, rightCost);
}
+ cost = getCombinedSetEstimate(op, leftCost, rightCost, !node.hasBooleanProperty(NodeConstants.Info.USE_ALL));
+
+ setCardinalityEstimate(node, new Float(cost), true, metadata);
+ }
+
+ private static float getCombinedSetEstimate(SetQuery.Operation op, float leftCost, float rightCost, boolean distinct) {
+ float cost;
cost = leftCost;
switch (op) {
@@ -242,7 +289,7 @@
break;
default: //union
if (leftCost != UNKNOWN_VALUE && rightCost != UNKNOWN_VALUE) {
- if (!node.hasBooleanProperty(NodeConstants.Info.USE_ALL)) {
+ if (distinct) {
cost = Math.max(leftCost, rightCost) + .5f * Math.min(leftCost, rightCost);
} else {
cost = rightCost + leftCost;
@@ -250,8 +297,7 @@
}
break;
}
-
- setCardinalityEstimate(node, new Float(cost));
+ return cost;
}
private static float getDistinctEstimate(PlanNode node,
@@ -264,11 +310,17 @@
return cost;
}
- private static void setCardinalityEstimate(PlanNode node, Float bestEstimate) {
+ private static void setCardinalityEstimate(PlanNode node, Float bestEstimate, boolean setColEstimates, QueryMetadataInterface metadata) throws QueryMetadataException, TeiidComponentException {
if (bestEstimate == null){
bestEstimate = Float.valueOf(UNKNOWN_VALUE);
}
- node.setProperty(NodeConstants.Info.EST_CARDINALITY, bestEstimate);
+ Float lastEstimate = (Float)node.setProperty(NodeConstants.Info.EST_CARDINALITY, bestEstimate);
+ if (node.getParent() != null && (lastEstimate == null || !lastEstimate.equals(bestEstimate))) {
+ node.getParent().setProperty(Info.EST_CARDINALITY, null);
+ }
+ if (setColEstimates) {
+ setColStatEstimates(node, bestEstimate, metadata);
+ }
}
/**
@@ -286,7 +338,7 @@
float childCost2 = child2.getCardinality();
if (childCost1 == UNKNOWN_VALUE || childCost2 == UNKNOWN_VALUE) {
- setCardinalityEstimate(node, null);
+ setCardinalityEstimate(node, null, true, metadata);
return;
}
@@ -303,19 +355,17 @@
}
Float cost = null;
- if (JoinType.JOIN_CROSS.equals(joinType)){
- cost = new Float(baseCost);
+ if (JoinType.JOIN_CROSS.equals(joinType) || JoinType.JOIN_INNER.equals(joinType)){
+ cost = baseCost;
} else if (JoinType.JOIN_FULL_OUTER.equals(joinType)) {
- cost = new Float(Math.max((childCost1+childCost2),baseCost));
+ cost = Math.max((childCost1+childCost2),baseCost);
} else if (JoinType.JOIN_LEFT_OUTER.equals(joinType)) {
- cost = new Float(Math.max(childCost1,baseCost));
- } else if (JoinType.JOIN_RIGHT_OUTER.equals(joinType)) {
- cost = new Float(Math.max(childCost2,baseCost));
- } else if (JoinType.JOIN_INNER.equals(joinType)) {
- cost = new Float(baseCost);
+ cost = Math.max(childCost1,baseCost);
+ } else if (JoinType.JOIN_SEMI.equals(joinType) || JoinType.JOIN_ANTI_SEMI.equals(joinType)) {
+ cost = Math.min(childCost1, baseCost);
}
- setCardinalityEstimate(node, cost);
+ setCardinalityEstimate(node, cost, true, metadata);
}
/**
@@ -332,8 +382,87 @@
//Get list of conjuncts
Criteria selectCriteria = (Criteria)node.getProperty(NodeConstants.Info.SELECT_CRITERIA);
float newCost = recursiveEstimateCostOfCriteria(childCost, node, selectCriteria, metadata);
- setCardinalityEstimate(node, new Float(newCost));
+ setCardinalityEstimate(node, newCost, true, metadata);
}
+
+ private static void setColStatEstimates(PlanNode node, float cardinality, QueryMetadataInterface metadata) throws QueryMetadataException, TeiidComponentException {
+ if (cardinality == UNKNOWN_VALUE) {
+ return;
+ }
+ ColStats colStats = null;
+ ColStats colStatsOther = null;
+ float childCardinality = UNKNOWN_VALUE;
+ if (node.getChildCount() > 0) {
+ childCardinality = node.getFirstChild().getCardinality();
+ colStats = (ColStats) node.getFirstChild().getProperty(Info.EST_COL_STATS);
+ }
+ float otherChildCardinality = UNKNOWN_VALUE;
+ List<? extends Expression> outputColsOther = null;
+ if (node.getChildCount() > 1) {
+ otherChildCardinality = node.getLastChild().getCardinality();
+ colStatsOther = (ColStats) node.getLastChild().getProperty(Info.EST_COL_STATS);
+ outputColsOther = getOutputCols(node.getLastChild(), metadata);
+ }
+ SetQuery.Operation setOp = (Operation) node.getProperty(Info.SET_OPERATION);
+ List<? extends Expression> outputCols = getOutputCols(node, metadata);
+ ColStats newColStats = new ColStats();
+ for (int i = 0; i < outputCols.size(); i++) {
+ Expression expr = outputCols.get(i);
+ float[] newStats = new float[2];
+ Arrays.fill(newStats, UNKNOWN_VALUE);
+ if (childCardinality == UNKNOWN_VALUE || (setOp != null && (colStats == null || colStatsOther == null))) {
+ //base case - cannot determine, just assume unique rows
+ newStats[Stat.NDV.ordinal()] = cardinality;
+ newStats[Stat.NNV.ordinal()] = 0;
+ } else if (setOp != null) {
+ //set op
+ float[] stats = colStats.get(expr);
+ float[] statsOther = colStatsOther.get(outputColsOther.get(i));
+ newStats[Stat.NDV.ordinal()] = getCombinedSetEstimate(setOp, stats[Stat.NDV.ordinal()], statsOther[Stat.NDV.ordinal()], true);
+ newStats[Stat.NNV.ordinal()] = getCombinedSetEstimate(setOp, stats[Stat.NNV.ordinal()], statsOther[Stat.NNV.ordinal()], !node.hasBooleanProperty(NodeConstants.Info.USE_ALL));
+ } else {
+ //all other cases - join is the only multi-node case here
+ float[] stats = null;
+ float origCardinality = childCardinality;
+ if (colStats != null) {
+ stats = colStats.get(expr);
+ }
+ if (stats == null && colStatsOther != null) {
+ origCardinality = otherChildCardinality;
+ stats = colStatsOther.get(expr);
+ }
+ if (stats == null) {
+ if (node.getType() == NodeConstants.Types.PROJECT) {
+ Collection<SingleElementSymbol> elems = new HashSet<SingleElementSymbol>();
+ AggregateSymbolCollectorVisitor.getAggregates(expr, elems, elems);
+ newStats[Stat.NDV.ordinal()] = getStat(Stat.NDV, elems, node, childCardinality, metadata);
+ newStats[Stat.NNV.ordinal()] = getStat(Stat.NNV, elems, node, childCardinality, metadata);
+ } else {
+ //TODO: use a better estimate for new aggs
+ if (node.hasProperty(Info.GROUP_COLS)) {
+ newStats[Stat.NDV.ordinal()] = cardinality / 3;
+ } else {
+ newStats[Stat.NDV.ordinal()] = cardinality;
+ }
+ newStats[Stat.NNV.ordinal()] = UNKNOWN_VALUE;
+ }
+ } else {
+ if (node.getType() == NodeConstants.Types.DUP_REMOVE || node.getType() == NodeConstants.Types.GROUP) {
+ //don't scale down
+ newStats[Stat.NDV.ordinal()] = stats[Stat.NDV.ordinal()];
+ } else if (stats[Stat.NDV.ordinal()] != UNKNOWN_VALUE) {
+ newStats[Stat.NDV.ordinal()] = stats[Stat.NDV.ordinal()]*Math.min(1, cardinality/origCardinality);
+ }
+ if (stats[Stat.NNV.ordinal()] != UNKNOWN_VALUE) {
+ //TODO: this is an under estimate for the inner side of outer joins
+ newStats[Stat.NNV.ordinal()] = stats[Stat.NNV.ordinal()]*Math.min(1, cardinality/origCardinality);
+ }
+ }
+ }
+ newColStats.put(expr, newStats);
+ }
+ node.setProperty(Info.EST_COL_STATS, newColStats);
+ }
/**
* For a source node, the cost is basically the cardinality of the source
@@ -353,6 +482,26 @@
if (references == null) {
PlanNode child = node.getFirstChild();
cost = child.getCardinality();
+ SymbolMap symbolMap = (SymbolMap)node.getProperty(NodeConstants.Info.SYMBOL_MAP);
+ if (symbolMap != null) {
+ ColStats colStats = (ColStats) child.getProperty(Info.EST_COL_STATS);
+ if (colStats != null) {
+ List<? extends Expression> outputCols = getOutputCols(node, metadata);
+ ColStats newColStats = new ColStats();
+ for (Expression expr : outputCols) {
+ if (!(expr instanceof ElementSymbol)) {
+ continue;
+ }
+ ElementSymbol es = (ElementSymbol)expr;
+ Expression ex = symbolMap.getMappedExpression(es);
+ newColStats.put(es, colStats.get(ex));
+ }
+ node.setProperty(Info.EST_COL_STATS, newColStats);
+ } else {
+ colStats = createColStats(node, metadata, cost);
+ node.setProperty(Info.EST_COL_STATS, colStats);
+ }
+ }
}
}else {
GroupSymbol group = node.getGroups().iterator().next();
@@ -361,10 +510,74 @@
cardinality = UNKNOWN_VALUE;
}
cost = cardinality;
+ if (!node.hasProperty(Info.ATOMIC_REQUEST)) {
+ ColStats colStats = createColStats(node, metadata, cost);
+ node.setProperty(Info.EST_COL_STATS, colStats);
+ }
}
- setCardinalityEstimate(node, new Float(cost));
- }
+ setCardinalityEstimate(node, new Float(cost), false, metadata);
+ }
+
+ private static ColStats createColStats(PlanNode node,
+ QueryMetadataInterface metadata, float cardinality)
+ throws QueryMetadataException, TeiidComponentException {
+ ColStats colStats = new ColStats();
+ List<? extends Expression> outputCols = getOutputCols(node, metadata);
+ for (Expression expr : outputCols) {
+ if (!(expr instanceof ElementSymbol)) {
+ continue;
+ }
+ ElementSymbol es = (ElementSymbol)expr;
+ float[] vals = new float[2];
+ float ndv = metadata.getDistinctValues(es.getMetadataID());
+ float nnv = metadata.getNullValues(es.getMetadataID());
+ if (cardinality != UNKNOWN_VALUE) {
+ int groupCardinality = metadata.getCardinality(es.getGroupSymbol().getMetadataID());
+ if (groupCardinality != UNKNOWN_VALUE && groupCardinality > cardinality) {
+ if (ndv != UNKNOWN_VALUE) {
+ ndv *= cardinality / Math.max(1, groupCardinality);
+ }
+ if (nnv != UNKNOWN_VALUE) {
+ nnv *= cardinality / Math.max(1, groupCardinality);
+ }
+ }
+ }
+ vals[Stat.NDV.ordinal()] = ndv;
+ vals[Stat.NNV.ordinal()] = nnv;
+ colStats.put(es, vals);
+ }
+ return colStats;
+ }
+
+ private static List<? extends Expression> getOutputCols(PlanNode node,
+ QueryMetadataInterface metadata) throws QueryMetadataException,
+ TeiidComponentException {
+ List<Expression> outputCols =(List<Expression>)node.getProperty(Info.OUTPUT_COLS);
+ if (outputCols != null) {
+ return outputCols;
+ }
+ PlanNode projectNode = NodeEditor.findNodePreOrder(node,
+ NodeConstants.Types.PROJECT | NodeConstants.Types.GROUP
+ | NodeConstants.Types.SOURCE | NodeConstants.Types.JOIN
+ | NodeConstants.Types.NULL);
+ if (projectNode != null) {
+ node = projectNode;
+ }
+
+ if (node.getType() == NodeConstants.Types.PROJECT) {
+ return (List<? extends Expression>) node.getProperty(NodeConstants.Info.PROJECT_COLS);
+ } else if (node.getType() == NodeConstants.Types.GROUP) {
+ LinkedList<Expression> result = new LinkedList<Expression>(RulePushAggregates.collectAggregates(node));
+ result.addAll((Collection<? extends Expression>) node.getProperty(Info.GROUP_COLS));
+ return result;
+ }
+ LinkedList<ElementSymbol> elements = new LinkedList<ElementSymbol>();
+ for (GroupSymbol group : node.getGroups()) {
+ elements.addAll(ResolverUtil.resolveElementsInGroup(group, metadata));
+ }
+ return elements;
+ }
/**
* For a Group or Dup Removal node, the cost is basically the smaller of the largest NDV of the
@@ -381,12 +594,12 @@
float childCost = child.getCardinality();
if(childCost == UNKNOWN_VALUE) {
- setCardinalityEstimate(node, null);
+ setCardinalityEstimate(node, null, true, metadata);
return;
}
Float newCost = getDistinctEstimate(node, expressions, metadata, childCost);
- setCardinalityEstimate(node, newCost);
+ setCardinalityEstimate(node, newCost, true, metadata);
}
private static Float getDistinctEstimate(PlanNode node,
@@ -402,7 +615,7 @@
if (usesKey(elements, metadata)) {
return new Float(childCost);
}
- float ndvCost = getNDV(elems, node, childCost, metadata);
+ float ndvCost = getStat(Stat.NDV, elems, node, childCost, metadata);
if(ndvCost == UNKNOWN_VALUE) {
ndvCost = childCost;
}
@@ -411,7 +624,39 @@
return newCost;
}
- static float recursiveEstimateCostOfCriteria(float childCost, PlanNode currentNode, Criteria crit, QueryMetadataInterface metadata)
+ private static float getStat(Stat stat, Collection<? extends Expression> elems, PlanNode node,
+ float cardinality, QueryMetadataInterface metadata) throws QueryMetadataException, TeiidComponentException {
+ float result = 0;
+ for (Expression expression : elems) {
+ ColStats colStats = null;
+ if (node.getChildCount() == 0) {
+ colStats = createColStats(node, metadata, cardinality);
+ } else {
+ for (PlanNode child : node.getChildren()) {
+ colStats = (ColStats) child.getProperty(Info.EST_COL_STATS);
+ if (colStats == null) {
+ continue;
+ }
+ float[] stats = colStats.get(expression);
+ if (stats != null) {
+ break;
+ }
+ colStats = null;
+ }
+ }
+ if (colStats == null) {
+ return UNKNOWN_VALUE;
+ }
+ float[] stats = colStats.get(expression);
+ if (stats == null || stats[stat.ordinal()] == UNKNOWN_VALUE) {
+ return UNKNOWN_VALUE;
+ }
+ result = Math.max(result, stats[stat.ordinal()]);
+ }
+ return result;
+ }
+
+ static float recursiveEstimateCostOfCriteria(float childCost, PlanNode currentNode, Criteria crit, QueryMetadataInterface metadata)
throws QueryMetadataException, TeiidComponentException {
float cost = childCost;
@@ -552,7 +797,7 @@
boolean multiGroup = groups.size() > 1;
float cost = childCost;
- float ndv = getNDV(elements, currentNode, childCost, metadata);
+ float ndv = getStat(Stat.NDV, elements, currentNode, childCost, metadata);
boolean unknownChildCost = childCost == UNKNOWN_VALUE;
boolean usesKey = usesKey(elements, metadata);
@@ -623,7 +868,7 @@
} else if(predicateCriteria instanceof IsNullCriteria) {
IsNullCriteria isNullCriteria = (IsNullCriteria)predicateCriteria;
- float nnv = getNNV(elements, currentNode, childCost, metadata);
+ float nnv = getStat(Stat.NNV, elements, currentNode, childCost, metadata);
if (nnv == UNKNOWN_VALUE) {
if (unknownChildCost) {
return UNKNOWN_VALUE;
@@ -684,7 +929,7 @@
return childCost/3;
}
ElementSymbol element = (ElementSymbol)compCrit.getLeftExpression();
- Class dataType = compCrit.getRightExpression().getType();
+ Class<?> dataType = compCrit.getRightExpression().getType();
String max = (String)metadata.getMaximumValue(element.getMetadataID());
String min = (String)metadata.getMinimumValue(element.getMetadataID());
@@ -777,10 +1022,10 @@
*/
public static boolean usesKey(Collection<? extends SingleElementSymbol> allElements, QueryMetadataInterface metadata)
throws QueryMetadataException, TeiidComponentException {
- return usesKey(allElements, null, metadata);
+ return usesKey(allElements, null, metadata, true);
}
- public static boolean usesKey(Collection<? extends SingleElementSymbol> allElements, Set<GroupSymbol> groups, QueryMetadataInterface metadata)
+ public static boolean usesKey(Collection<? extends SingleElementSymbol> allElements, Set<GroupSymbol> groups, QueryMetadataInterface metadata, boolean unique)
throws QueryMetadataException, TeiidComponentException {
if(allElements == null || allElements.size() == 0) {
@@ -813,7 +1058,13 @@
List<Object> elements = entry.getValue();
// Look up keys
- Collection keys = metadata.getUniqueKeysInGroup(group.getMetadataID());
+ Collection keys = null;
+ if (unique) {
+ keys = metadata.getUniqueKeysInGroup(group.getMetadataID());
+ } else {
+ keys = metadata.getIndexesInGroup(group.getMetadataID());
+ }
+
if(keys != null && keys.size() > 0) {
// For each key, get key elements
Iterator keyIter = keys.iterator();
@@ -828,126 +1079,8 @@
}
return false;
- }
+ }
- /**
- * Get the scaled max ndv for a set of elements.
- *
- * NOTE: this is not a good approximation over unions, joins, grouping, etc.
- */
- private static float getNDV(Collection<ElementSymbol> elements, PlanNode current, float cardinality, QueryMetadataInterface metadata)
- throws QueryMetadataException, TeiidComponentException {
- float result = UNKNOWN_VALUE;
-
- for (ElementSymbol elementSymbol : elements) {
- Object elemID = elementSymbol.getMetadataID();
- float ndv = metadata.getDistinctValues(elemID);
- if (ndv == UNKNOWN_VALUE) {
- if (metadata.isVirtualGroup(elementSymbol.getGroupSymbol().getMetadataID()) && !metadata.isProcedure(elementSymbol.getGroupSymbol().getMetadataID())) {
- PlanNode sourceNode = FrameUtil.findOriginatingNode(current, new HashSet<GroupSymbol>(Arrays.asList(elementSymbol.getGroupSymbol())));
- if (sourceNode != null) {
- SymbolMap symbolMap = (SymbolMap)sourceNode.getProperty(NodeConstants.Info.SYMBOL_MAP);
- //symbolMap will be null for table functions
- if (symbolMap != null) {
- Expression expr = symbolMap.getMappedExpression(elementSymbol);
- ndv = getNDV(ElementCollectorVisitor.getElements(expr, true), sourceNode.getFirstChild(), cardinality, metadata);
- }
- }
- }
- } else if (cardinality != UNKNOWN_VALUE) {
- int groupCardinality = metadata.getCardinality(elementSymbol.getGroupSymbol().getMetadataID());
- if (groupCardinality != UNKNOWN_VALUE && groupCardinality > cardinality) {
- ndv *= cardinality / Math.max(1, groupCardinality);
- }
- }
- result = Math.max(result, ndv);
- }
- return result;
- }
-
- /**
- * Get the scaled max nnv for a set of elements.
- *
- * NOTE: assumes that the expression does not allow nulls
- */
- private static float getNNV(Collection<ElementSymbol> elements, PlanNode current, float cardinality, QueryMetadataInterface metadata)
- throws QueryMetadataException, TeiidComponentException {
- float result = 0;
- for (ElementSymbol elementSymbol : elements) {
- Object elemID = elementSymbol.getMetadataID();
- float nnv = metadata.getNullValues(elemID);
- if (nnv == UNKNOWN_VALUE) {
- if (!metadata.elementSupports(elemID, SupportConstants.Element.NULL)
- && !metadata.elementSupports(elemID, SupportConstants.Element.NULL_UNKNOWN)) {
- nnv = 0;
- } else if (metadata.isVirtualGroup(elementSymbol.getGroupSymbol().getMetadataID()) && !metadata.isProcedure(elementSymbol.getGroupSymbol().getMetadataID())) {
- PlanNode sourceNode = FrameUtil.findOriginatingNode(current, new HashSet<GroupSymbol>(Arrays.asList(elementSymbol.getGroupSymbol())));
- if (sourceNode != null) {
- SymbolMap symbolMap = (SymbolMap)sourceNode.getProperty(NodeConstants.Info.SYMBOL_MAP);
- Expression expr = symbolMap.getMappedExpression(elementSymbol);
- nnv = getNNV(ElementCollectorVisitor.getElements(expr, true), sourceNode.getFirstChild(), cardinality, metadata);
- }
- }
- if (nnv == UNKNOWN_VALUE) {
- return UNKNOWN_VALUE;
- }
- } else if (cardinality != UNKNOWN_VALUE) {
- int groupCardinality = metadata.getCardinality(elementSymbol.getGroupSymbol().getMetadataID());
- if (groupCardinality != UNKNOWN_VALUE) {
- nnv *= cardinality / Math.max(1, groupCardinality);
- }
- }
- result = Math.max(result, nnv);
- }
- return result;
- }
-
- /**
- * Computes the cost of a Merge Join
- */
- public static float computeCostForJoin(PlanNode leftChildNode, PlanNode rightChildNode, JoinStrategyType joinStrategy, QueryMetadataInterface metadata, CommandContext context)
- throws TeiidComponentException, QueryMetadataException {
-
- float leftChildCardinality = computeCostForTree(leftChildNode, metadata);
- float rightChildCardinality = computeCostForTree(rightChildNode, metadata);
-
- boolean merge = JoinStrategyType.MERGE.equals(joinStrategy);
-
- // If either cardinality is unknown, we return unknown
- if(leftChildCardinality == UNKNOWN_VALUE || rightChildCardinality == UNKNOWN_VALUE) {
- return UNKNOWN_VALUE;
- }
-
- float numberComparisons = merge?(leftChildCardinality + rightChildCardinality):(leftChildCardinality * rightChildCardinality);
-
- float connectorBatchSize = BufferManager.DEFAULT_CONNECTOR_BATCH_SIZE;
- if(context != null) {
- connectorBatchSize = context.getConnectorBatchSize();
- }
-
- float totalReadTime = (leftChildCardinality + rightChildCardinality) * readTime;
- float totalCompareTime = numberComparisons * compareTime;
- float totalProcMoreRequestLeftTime = (float)Math.floor(leftChildCardinality/connectorBatchSize)*procMoreRequestTime;
- float totalProcMoreRequestRightTime = (float)Math.floor(rightChildCardinality/connectorBatchSize)*procMoreRequestTime;
-
- float cost = (totalReadTime+
- totalCompareTime+
- totalProcMoreRequestLeftTime+
- totalProcMoreRequestRightTime);
-
- if (merge) {
- cost += (leftChildCardinality*safeLog(leftChildCardinality) + rightChildCardinality*safeLog(rightChildCardinality)) * readTime;
- }
-
- if (isPhysicalSource(rightChildNode)) {
- cost += procNewRequestTime;
- }
- if (isPhysicalSource(leftChildNode)) {
- cost += procNewRequestTime;
- }
- return cost;
- }
-
private static float safeLog(float x) {
return (float)Math.max(1, Math.log(x));
}
@@ -958,10 +1091,11 @@
* The worst possible cost will arise from a high independent ndv (many dependent sets) and a low dependent ndv (possibly many matches per set)
*
* This logic uses the same assumption as criteria in that ndv is used as a divisor of cardinality.
+ * @throws QueryPlannerException
*
*/
- public static float computeCostForDepJoin(PlanNode joinNode, boolean leftIndependent, JoinStrategyType joinStrategy, QueryMetadataInterface metadata, CapabilitiesFinder capFinder, CommandContext context)
- throws TeiidComponentException, QueryMetadataException {
+ public static Float computeCostForDepJoin(PlanNode joinNode, boolean leftIndependent, QueryMetadataInterface metadata, CapabilitiesFinder capFinder, CommandContext context)
+ throws TeiidComponentException, QueryMetadataException, QueryPlannerException {
PlanNode independentNode = leftIndependent?joinNode.getFirstChild():joinNode.getLastChild();
PlanNode dependentNode = leftIndependent?joinNode.getLastChild():joinNode.getFirstChild();
@@ -969,139 +1103,176 @@
List independentExpressions = (List)(leftIndependent?joinNode.getProperty(NodeConstants.Info.LEFT_EXPRESSIONS):joinNode.getProperty(NodeConstants.Info.RIGHT_EXPRESSIONS));
List dependentExpressions = (List)(leftIndependent?joinNode.getProperty(NodeConstants.Info.RIGHT_EXPRESSIONS):joinNode.getProperty(NodeConstants.Info.LEFT_EXPRESSIONS));
- // compute the cost for both trees, if we don't come up with a valid cost for both we have to return unknown
+ return computeCostForDepJoin(independentNode, dependentNode,
+ independentExpressions, dependentExpressions, metadata,
+ capFinder, context);
+ }
+
+ public static Float computeCostForDepJoin(PlanNode independentNode,
+ PlanNode dependentNode, List independentExpressions,
+ List dependentExpressions, QueryMetadataInterface metadata,
+ CapabilitiesFinder capFinder, CommandContext context)
+ throws QueryMetadataException, TeiidComponentException, QueryPlannerException {
+
float independentCardinality = computeCostForTree(independentNode, metadata);
float dependentCardinality = computeCostForTree(dependentNode, metadata);
- float indSymbolNDV = getNDV(independentNode, independentExpressions, metadata, independentCardinality, true);
- float depSymbolNDV = getNDV(dependentNode, dependentExpressions, metadata, dependentCardinality, false);
+ if (independentCardinality == UNKNOWN_VALUE || dependentCardinality == UNKNOWN_VALUE) {
+ return null;
+ }
- //If either cardinality is unknown, we return unknown
- if(indSymbolNDV == UNKNOWN_VALUE || depSymbolNDV == UNKNOWN_VALUE || independentCardinality == UNKNOWN_VALUE || dependentCardinality == UNKNOWN_VALUE) {
- return UNKNOWN_VALUE;
- }
-
- float connectorBatchSize = BufferManager.DEFAULT_CONNECTOR_BATCH_SIZE;
float processorBatchSize = BufferManager.DEFAULT_PROCESSOR_BATCH_SIZE;
if(context != null) {
- connectorBatchSize = context.getConnectorBatchSize();
processorBatchSize = context.getProcessorBatchSize();
}
+
+ RulePushSelectCriteria rpsc = new RulePushSelectCriteria();
+ rpsc.setCreatedNodes(new LinkedList<PlanNode>());
- float setCriteriaBatchSize = indSymbolNDV;
+ for (int i = 0; i < independentExpressions.size(); i++) {
+ Expression indExpr = (Expression)independentExpressions.get(i);
+ Collection<ElementSymbol> indElements = ElementCollectorVisitor.getElements(indExpr, true);
+ float indSymbolNDV = getStat(Stat.NDV, indElements, independentNode, independentCardinality, metadata);
+ boolean usesIndKey = usesKey(dependentNode, indElements, metadata);
+ if (indSymbolNDV == UNKNOWN_VALUE) {
+ if (!usesIndKey) {
+ indSymbolNDV = Math.max(1, independentCardinality/2);
+ } else {
+ indSymbolNDV = independentCardinality;
+ }
+ }
+ Expression depExpr = (Expression)dependentExpressions.get(i);
+
+ LinkedList<PlanNode> critNodes = new LinkedList<PlanNode>();
+ LinkedList<PlanNode> initialTargets = new LinkedList<PlanNode>();
+
+ LinkedList<Expression> depExpressions = new LinkedList<Expression>();
+ LinkedList<PlanNode> targets = new LinkedList<PlanNode>();
+ critNodes.add(RelationalPlanner.createSelectNode(new DependentSetCriteria(depExpr, null), false));
+ initialTargets.add(dependentNode);
+ while (!critNodes.isEmpty()) {
+ PlanNode critNode = critNodes.remove();
+ PlanNode initial = initialTargets.remove();
+ if (critNode.getGroups().isEmpty()) {
+ //TODO: we need to project constants up through a plan to avoid this case
+ continue;
+ }
+ PlanNode sourceNode = FrameUtil.findOriginatingNode(initial, critNode.getGroups());
+ PlanNode target = sourceNode;
+ if (initial != sourceNode) {
+ target = rpsc.examinePath(initial, sourceNode, metadata, capFinder);
+ }
+ if (target != sourceNode || (sourceNode.getType() == NodeConstants.Types.SOURCE && sourceNode.getChildCount() == 0)) {
+ targets.add(target);
+ DependentSetCriteria dsc = (DependentSetCriteria)critNode.getProperty(Info.SELECT_CRITERIA);
+ depExpressions.add(dsc.getExpression());
+ continue;
+ }
+ if (sourceNode.getType() == NodeConstants.Types.SOURCE) {
+ PlanNode child = sourceNode.getFirstChild();
+ child = FrameUtil.findOriginatingNode(child, child.getGroups());
+ if (child != null && child.getType() == NodeConstants.Types.SET_OP) {
+ targets.add(target);
+ DependentSetCriteria dsc = (DependentSetCriteria)critNode.getProperty(Info.SELECT_CRITERIA);
+ depExpressions.add(dsc.getExpression());
+ //TODO: we need better handling for set op situations
+ continue;
+ }
+ if (!rpsc.pushAcrossFrame(sourceNode, critNode, metadata)) {
+ targets.add(target);
+ DependentSetCriteria dsc = (DependentSetCriteria)critNode.getProperty(Info.SELECT_CRITERIA);
+ depExpressions.add(dsc.getExpression());
+ }
+ List<PlanNode> createdNodes = rpsc.getCreatedNodes();
+ for (PlanNode planNode : createdNodes) {
+ critNodes.add(planNode);
+ initialTargets.add(planNode.getFirstChild());
+ NodeEditor.removeChildNode(planNode.getParent(), planNode);
+ }
+ rpsc.getCreatedNodes().clear();
+ }
+ //the source must be a null or project node, which we don't care about
+ }
+
+ Iterator<Expression> exprIter = depExpressions.iterator();
+ for (Iterator<PlanNode> targetIter = targets.iterator(); targetIter.hasNext();) {
+ PlanNode target = targetIter.next();
+ Expression targerDepExpr = exprIter.next();
+ PlanNode accessNode = NodeEditor.findParent(target, NodeConstants.Types.ACCESS);
+
+ float setCriteriaBatchSize = indSymbolNDV;
+
+ if (accessNode != null) {
+ setCriteriaBatchSize = CapabilitiesUtil.getMaxInCriteriaSize(RuleRaiseAccess.getModelIDFromAccess(accessNode, metadata), metadata, capFinder);
+ if (setCriteriaBatchSize < 1) {
+ setCriteriaBatchSize = indSymbolNDV;
+ }
+ } else if (indSymbolNDV > processorBatchSize) {
+ //don't bother making a virtual join dependent if they are likely to be large
+ //TODO: what operations are performed between origNode and dependentNode
+ //TODO: we should be using a tree structure rather than just a value iterator
+ continue;
+ }
+ if (target.hasBooleanProperty(Info.MAKE_NOT_DEP)) {
+ continue;
+ }
+ Collection<ElementSymbol> depElems = ElementCollectorVisitor.getElements(targerDepExpr, true);
+ while (target.getParent().getType() == NodeConstants.Types.SELECT) {
+ target = target.getParent();
+ }
+ float depTargetCardinality = computeCostForTree(target, metadata);
+ if (depTargetCardinality == UNKNOWN_VALUE) {
+ continue;
+ }
+ float depSymbolNDV = getStat(Stat.NDV, depElems, target, depTargetCardinality, metadata);
+ boolean usesKey = usesKey(dependentNode, depElems, metadata);
+ if (depSymbolNDV == UNKNOWN_VALUE) {
+ if (!usesKey) {
+ //make an educated guess that this is a fk
+ float indSymbolOrigNDV = indSymbolNDV;
+ float indCardinalityOrig = independentCardinality;
+ //TODO: we should probably dig deeper than this
+ PlanNode indOrigNode = FrameUtil.findOriginatingNode(independentNode, GroupsUsedByElementsVisitor.getGroups(indElements));
+ if (indOrigNode != null) {
+ indCardinalityOrig = computeCostForTree(indOrigNode, metadata);
+ indSymbolOrigNDV = getStat(Stat.NDV, indElements, indOrigNode, indCardinalityOrig, metadata);
+ if (indSymbolOrigNDV == UNKNOWN_VALUE) {
+ if (!usesIndKey) {
+ indSymbolOrigNDV = Math.max(1, indCardinalityOrig / 3);
+ } else {
+ indSymbolOrigNDV = indCardinalityOrig;
+ }
+ }
+ }
+ depSymbolNDV = Math.max((float)Math.pow(depTargetCardinality, .75), Math.min(indSymbolOrigNDV, depTargetCardinality));
+ } else {
+ depSymbolNDV = depTargetCardinality;
+ }
+ }
+ boolean usesIndex = accessNode != null && usesKey;
+ if (!usesKey && accessNode != null && target.getType() == NodeConstants.Types.SOURCE && target.getChildCount() == 0) {
+ usesIndex = usesKey(depElems, target.getGroups(), metadata, false);
+ }
+ float dependentAccessCardinality = Math.min(depTargetCardinality, depTargetCardinality * indSymbolNDV / depSymbolNDV);
+ float scaledCardinality = Math.min(dependentCardinality, dependentCardinality * indSymbolNDV / depSymbolNDV);
+ float numberComparisons = (usesIndex?safeLog(depTargetCardinality):depTargetCardinality) * (usesIndex?indSymbolNDV:safeLog(indSymbolNDV));
+ float newDependentQueries = accessNode == null?0:(float)Math.ceil(indSymbolNDV / setCriteriaBatchSize);
+
+ float relativeCost = newDependentQueries*procNewRequestTime;
+ float relativeComparisonCost = (numberComparisons - safeLog(scaledCardinality) /*no longer needed by the join*/
+ /*sort cost reduction, however it's always true if its on the source and using an index
+ TODO: there are other cost reductions, which we could get by checking the other parent nodes */
+ + (scaledCardinality*safeLog(scaledCardinality) - dependentCardinality*safeLog(dependentCardinality)))
+ * compareTime;
+ float relativeReadCost = (dependentAccessCardinality - depTargetCardinality)*readTime; //cardinality reductions
+
+ if (relativeCost + relativeComparisonCost + relativeReadCost < 0) {
+ return scaledCardinality;
+ }
+ }
+ }
- PlanNode node = FrameUtil.findJoinSourceNode(dependentNode);
-
- while (node != null && node.getType() != NodeConstants.Types.ACCESS) {
- if (node.getType() == NodeConstants.Types.JOIN || node.getType() == NodeConstants.Types.SET_OP) {
- node = null;
- break;
- }
- node = node.getFirstChild();
- }
-
- if (node != null) {
- setCriteriaBatchSize = CapabilitiesUtil.getMaxInCriteriaSize(RuleRaiseAccess.getModelIDFromAccess(node, metadata), metadata, capFinder);
- if (setCriteriaBatchSize < 1) {
- setCriteriaBatchSize = indSymbolNDV;
- }
- } else {
- //don't bother making a virtual join dependent if they are likely to be large
- if (indSymbolNDV > Math.min(processorBatchSize, setCriteriaBatchSize)) {
- return UNKNOWN_VALUE;
- }
- }
-
- independentNode.setProperty(NodeConstants.Info.EST_SET_SIZE, new Float(indSymbolNDV));
-
- //for non-partitioned joins the cardinality of the dependentaccess should never be greater than the dependent cardinality
- //TODO: when partitioned joins are implemented, this logic will need updated
- float dependentAccessCardinality = Math.min(dependentCardinality, dependentCardinality * indSymbolNDV / depSymbolNDV);
-
- boolean merge = false;
- if (JoinStrategyType.MERGE.equals(joinStrategy)) {
- merge = true;
- } else if (!JoinStrategyType.NESTED_LOOP.equals(joinStrategy)) {
- return UNKNOWN_VALUE;
- }
-
- dependentNode.setProperty(NodeConstants.Info.EST_DEP_CARDINALITY, new Float(dependentAccessCardinality));
-
- float numberComparisons = merge?(independentCardinality + dependentAccessCardinality):(independentCardinality * dependentAccessCardinality);
-
- //account for sorting
- float totalLoadDataTime = independentCardinality * safeLog(independentCardinality) * readTime;
- if (merge) {
- totalLoadDataTime += dependentAccessCardinality * safeLog(dependentAccessCardinality) * readTime;
- }
-
- //the independentCardinality is doubled to account for the dependent setup time, which re-reads the independent values
- float totalReadTime = (2*independentCardinality + dependentAccessCardinality) * readTime;
- float totalCompareTime = numberComparisons * compareTime;
- float totalProcMoreRequestLeftTime = (float)Math.floor(independentCardinality / connectorBatchSize) * procMoreRequestTime;
- float newDependentQueries = (float)Math.ceil(indSymbolNDV / setCriteriaBatchSize);
- float totalProcMoreRequestRightTime = Math.max(dependentAccessCardinality / connectorBatchSize - newDependentQueries, 0) * procMoreRequestTime;
-
- float cost = (totalLoadDataTime +
- totalReadTime+
- totalCompareTime+
- totalProcMoreRequestLeftTime+
- totalProcMoreRequestRightTime);
-
- if (isPhysicalSource(independentNode)) {
- cost += procNewRequestTime; //independent query latency
- }
- /*estimate for dependent query latencies
- *NOTE: the initial latency estimate can be made significantly larger for queries against large dependent sets,
- *which is consistent with observed behavior in which criteria-less queries outperform those with in criteria
- *with 1000 entries.
- */
- if (isPhysicalSource(dependentNode)) {
- cost += newDependentQueries * (procNewRequestTime *
- Math.max(safeLog(dependentCardinality) - 10, 1) *
- Math.max(safeLog(Math.min(dependentCardinality, Math.min(setCriteriaBatchSize, indSymbolNDV))) - 2, 1)
- );
- }
-
- return cost;
- }
+ return null;
+ }
- private static boolean isPhysicalSource(PlanNode node) {
- node = FrameUtil.findJoinSourceNode(node);
- if (node != null) {
- return node.getType() == NodeConstants.Types.ACCESS;
- }
- return false;
- }
-
- private static float getNDV(PlanNode node,
- List expressions,
- QueryMetadataInterface metadata,
- float nodeCardinality, boolean independent) throws QueryMetadataException,
- TeiidComponentException {
- float result = UNKNOWN_VALUE;
- for(Iterator iter = expressions.iterator(); iter.hasNext();) {
- Expression expr = (Expression)iter.next();
- Collection<ElementSymbol> symbols = ElementCollectorVisitor.getElements(expr, true);
-
- float currentSymbolNDV = getNDV(symbols, node, nodeCardinality, metadata);
-
- if(currentSymbolNDV == UNKNOWN_VALUE) {
- if (usesKey(symbols, metadata)) {
- return nodeCardinality;
- }
- if (independent) {
- currentSymbolNDV = nodeCardinality / 2;
- } else {
- currentSymbolNDV = nodeCardinality / 4;
- }
- }
-
- if(result == UNKNOWN_VALUE || currentSymbolNDV > result) {
- result = currentSymbolNDV;
- }
- }
- return Math.max(1, Math.min(nodeCardinality, result));
- }
-
}
Modified: trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleChooseDependent.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleChooseDependent.java 2011-03-11 17:39:21 UTC (rev 2990)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleChooseDependent.java 2011-03-16 01:26:46 UTC (rev 2991)
@@ -40,7 +40,6 @@
import org.teiid.query.optimizer.relational.plantree.NodeConstants;
import org.teiid.query.optimizer.relational.plantree.NodeEditor;
import org.teiid.query.optimizer.relational.plantree.PlanNode;
-import org.teiid.query.processor.relational.JoinNode.JoinStrategyType;
import org.teiid.query.sql.lang.DependentSetCriteria;
import org.teiid.query.sql.lang.JoinType;
import org.teiid.query.sql.symbol.Expression;
@@ -81,29 +80,24 @@
boolean bothCandidates = entry.leftCandidate&&entry.rightCandidate;
- JoinStrategyType joinStrategy = (JoinStrategyType)joinNode.getProperty(NodeConstants.Info.JOIN_STRATEGY);
-
PlanNode chosenNode = chooseDepWithoutCosting(sourceNode, bothCandidates?siblingNode:null, analysisRecord);
if(chosenNode != null) {
pushCriteria |= markDependent(chosenNode, joinNode);
continue;
}
- float depJoinCost = NewCalculateCostUtil.computeCostForDepJoin(joinNode, !entry.leftCandidate, joinStrategy, metadata, capFinder, context);
+ boolean useDepJoin = NewCalculateCostUtil.computeCostForDepJoin(joinNode, !entry.leftCandidate, metadata, capFinder, context) != null;
PlanNode dependentNode = sourceNode;
- PlanNode independentNode = siblingNode;
- if (bothCandidates) {
- float siblingDepJoinCost = NewCalculateCostUtil.computeCostForDepJoin(joinNode, true, joinStrategy, metadata, capFinder, context);
- if (siblingDepJoinCost != NewCalculateCostUtil.UNKNOWN_VALUE && (siblingDepJoinCost < depJoinCost || depJoinCost == NewCalculateCostUtil.UNKNOWN_VALUE)) {
+ if (bothCandidates && !useDepJoin) {
+ useDepJoin = NewCalculateCostUtil.computeCostForDepJoin(joinNode, true, metadata, capFinder, context) != null;
+ if (useDepJoin) {
dependentNode = siblingNode;
- depJoinCost = siblingDepJoinCost;
- independentNode = sourceNode;
}
}
- if (depJoinCost != NewCalculateCostUtil.UNKNOWN_VALUE) {
- pushCriteria |= decideForAgainstDependentJoin(depJoinCost, independentNode, dependentNode, joinNode, metadata, context);
+ if (useDepJoin) {
+ pushCriteria |= markDependent(dependentNode, joinNode);
} else {
float sourceCost = NewCalculateCostUtil.computeCostForTree(sourceNode, metadata);
float siblingCost = NewCalculateCostUtil.computeCostForTree(siblingNode, metadata);
@@ -126,20 +120,6 @@
return plan;
}
- boolean decideForAgainstDependentJoin(float depJoinCost, PlanNode independentNode, PlanNode dependentNode, PlanNode joinNode, QueryMetadataInterface metadata, CommandContext context)
- throws QueryMetadataException, TeiidComponentException {
- JoinStrategyType joinStrategy = (JoinStrategyType)joinNode.getProperty(NodeConstants.Info.JOIN_STRATEGY);
- joinNode.setProperty(NodeConstants.Info.EST_DEP_JOIN_COST, new Float(depJoinCost));
-
- float joinCost = NewCalculateCostUtil.computeCostForJoin(independentNode, dependentNode, joinStrategy, metadata, context);
- joinNode.setProperty(NodeConstants.Info.EST_JOIN_COST, new Float(joinCost));
- if(depJoinCost < joinCost) {
- return markDependent(dependentNode, joinNode);
- }
-
- return false;
- }
-
/**
* Walk the tree pre-order, finding all access nodes that are candidates and
* adding them to the matches list.
Modified: trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleImplementJoinStrategy.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleImplementJoinStrategy.java 2011-03-11 17:39:21 UTC (rev 2990)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleImplementJoinStrategy.java 2011-03-16 01:26:46 UTC (rev 2991)
@@ -104,8 +104,8 @@
if (leftCost != NewCalculateCostUtil.UNKNOWN_VALUE && rightCost != NewCalculateCostUtil.UNKNOWN_VALUE
&& (leftCost > context.getProcessorBatchSize() || rightCost > context.getProcessorBatchSize())) {
//we use a larger constant here to ensure that we don't unwisely prevent pushdown
- pushLeft = leftCost < context.getProcessorBatchSize() || leftCost / rightCost < 16;
- pushRight = rightCost < context.getProcessorBatchSize() || rightCost / leftCost < 16 || joinNode.getProperty(NodeConstants.Info.DEPENDENT_VALUE_SOURCE) != null;
+ pushLeft = leftCost < context.getProcessorBatchSize() || leftCost / rightCost < 8;
+ pushRight = rightCost < context.getProcessorBatchSize() || rightCost / leftCost < 8 || joinNode.getProperty(NodeConstants.Info.DEPENDENT_VALUE_SOURCE) != null;
}
}
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-11 17:39:21 UTC (rev 2990)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RuleMergeCriteria.java 2011-03-16 01:26:46 UTC (rev 2991)
@@ -354,16 +354,6 @@
if (crit instanceof SubqueryCompareCriteria) {
SubqueryCompareCriteria scc = (SubqueryCompareCriteria)crit;
- /*if (scc.getCommand().getCorrelatedReferences() == null) {
- RelationalPlan originalPlan = (RelationalPlan)scc.getCommand().getProcessorPlan();
- Number originalCardinality = originalPlan.getRootNode().getEstimateNodeCardinality();
- if (originalCardinality.floatValue() != NewCalculateCostUtil.UNKNOWN_VALUE
- && originalCardinality.floatValue() < this.context.getProcessorBatchSize()) {
- //this is small enough that it will effectively be a hash join
- return current;
- }
- }*/
-
if (scc.getPredicateQuantifier() != SubqueryCompareCriteria.SOME
//TODO: could add an inline view if not a query
|| !(scc.getCommand() instanceof Query)) {
@@ -570,7 +560,7 @@
}
HashSet<GroupSymbol> keyPreservingGroups = new HashSet<GroupSymbol>();
ResolverUtil.findKeyPreserved(query, keyPreservingGroups, metadata);
- return NewCalculateCostUtil.usesKey(expressions, keyPreservingGroups, metadata);
+ return NewCalculateCostUtil.usesKey(expressions, keyPreservingGroups, metadata, true);
}
private boolean hasCorrelatedReferences(LanguageObject object, SymbolMap correlatedReferences) {
Modified: trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePlanJoins.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePlanJoins.java 2011-03-11 17:39:21 UTC (rev 2990)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePlanJoins.java 2011-03-16 01:26:46 UTC (rev 2991)
@@ -169,7 +169,7 @@
joinRegion.initializeCostingInformation(metadata);
- Object[] bestOrder = findBestJoinOrder(joinRegion, metadata);
+ Object[] bestOrder = findBestJoinOrder(joinRegion, metadata, capabilitiesFinder, context);
//if no best order was found, just stick with how the user entered the query
if (bestOrder == null) {
@@ -522,8 +522,9 @@
* @param region
* @param metadata
* @return
+ * @throws QueryPlannerException
*/
- Object[] findBestJoinOrder(JoinRegion region, QueryMetadataInterface metadata) throws QueryMetadataException, TeiidComponentException {
+ Object[] findBestJoinOrder(JoinRegion region, QueryMetadataInterface metadata, CapabilitiesFinder capFinder, CommandContext context) throws QueryMetadataException, TeiidComponentException, QueryPlannerException {
int regionCount = region.getJoinSourceNodes().size();
List<Integer> orderList = new ArrayList<Integer>(regionCount);
@@ -549,7 +550,7 @@
while(permIter.hasNext()) {
Object[] order = (Object[]) permIter.next();
- double score = region.scoreRegion(order, metadata);
+ double score = region.scoreRegion(order, 0, metadata, capFinder, context);
if(score < bestSubScore) {
bestSubScore = score;
bestSubOrder = order;
@@ -568,7 +569,6 @@
//remove the joins that have already been placed
for(int i=0; i<bestSubOrder.length; i++) {
- orderList.remove(bestSubOrder[i]);
result[i] = (Integer)bestSubOrder[i];
}
@@ -578,12 +578,12 @@
List bestOrder = null;
for (int i = 0; i < orderList.size(); i++) {
- Integer index = (Integer)orderList.get(i);
+ Integer index = orderList.get(i);
List order = new ArrayList(Arrays.asList(bestSubOrder));
order.add(index);
- double partialScore = region.scoreRegion(order.toArray(), metadata);
+ double partialScore = region.scoreRegion(order.toArray(), bestSubOrder.length, metadata, capFinder, context);
if (partialScore < bestPartialScore) {
bestPartialScore = partialScore;
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-11 17:39:21 UTC (rev 2990)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushAggregates.java 2011-03-16 01:26:46 UTC (rev 2991)
@@ -45,6 +45,7 @@
import org.teiid.query.function.FunctionLibrary;
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.capabilities.CapabilitiesFinder;
import org.teiid.query.optimizer.capabilities.SourceCapabilities.Capability;
@@ -251,6 +252,7 @@
ElementSymbol virtualElement = new ElementSymbol(virtualElementName);
virtualElement.setGroupSymbol(virtualGroup);
virtualElement.setType(symbol.getType());
+ virtualElement.setMetadataID(new TempMetadataID(virtualElementName, symbol.getType()));
updatedVirturalElement.add(virtualElement);
}
SymbolMap newParentMap = SymbolMap.createSymbolMap(updatedVirturalElement, projectedViewSymbols);
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-11 17:39:21 UTC (rev 2990)
+++ trunk/engine/src/main/java/org/teiid/query/optimizer/relational/rules/RulePushSelectCriteria.java 2011-03-16 01:26:46 UTC (rev 2991)
@@ -60,6 +60,16 @@
public final class RulePushSelectCriteria implements OptimizerRule {
+
+ private List<PlanNode> createdNodes;
+
+ public List<PlanNode> getCreatedNodes() {
+ return createdNodes;
+ }
+
+ public void setCreatedNodes(List<PlanNode> createdNodes) {
+ this.createdNodes = createdNodes;
+ }
/**
* Execute the rule as described in the class comments.
@@ -286,8 +296,9 @@
if (!RuleRaiseAccess.canRaiseOverSelect(currentNode, metadata, capFinder, critNode, null)) {
return currentNode;
}
-
- satisfyAccessPatterns(critNode, currentNode);
+ if (this.createdNodes == null) {
+ satisfyAccessPatterns(critNode, currentNode);
+ }
if (critNode.hasBooleanProperty(NodeConstants.Info.IS_DEPENDENT_SET)
&& CapabilitiesUtil.getMaxInCriteriaSize(RuleRaiseAccess.getModelIDFromAccess(currentNode, metadata), metadata, capFinder) > 0) {
@@ -302,7 +313,7 @@
}
} else if(currentNode.getType() == NodeConstants.Types.JOIN) {
//pushing below a join is not necessary under an access node
- if (NodeEditor.findParent(currentNode, NodeConstants.Types.ACCESS) != null) {
+ if (this.createdNodes == null && NodeEditor.findParent(currentNode, NodeConstants.Types.ACCESS) != null) {
return currentNode;
}
@@ -477,6 +488,9 @@
if(critNode.hasBooleanProperty(NodeConstants.Info.IS_DEPENDENT_SET)) {
copyNode.setProperty(NodeConstants.Info.IS_DEPENDENT_SET, Boolean.TRUE);
}
+ if (createdNodes != null) {
+ createdNodes.add(copyNode);
+ }
return copyNode;
}
Modified: trunk/engine/src/main/java/org/teiid/query/processor/relational/RelationalNode.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/processor/relational/RelationalNode.java 2011-03-11 17:39:21 UTC (rev 2990)
+++ trunk/engine/src/main/java/org/teiid/query/processor/relational/RelationalNode.java 2011-03-16 01:26:46 UTC (rev 2991)
@@ -421,7 +421,7 @@
for (int row = batch.getBeginRow(); row <= batch.getEndRow(); row++) {
str.append("\t").append(row).append(": ").append(batch.getTuple(row)).append("\n"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
- LogManager.logDetail(org.teiid.logging.LogConstants.CTX_DQP, str.toString());
+ LogManager.logTrace(org.teiid.logging.LogConstants.CTX_DQP, str.toString());
}
// =========================================================================
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-11 17:39:21 UTC (rev 2990)
+++ trunk/engine/src/main/java/org/teiid/query/rewriter/QueryRewriter.java 2011-03-16 01:26:46 UTC (rev 2991)
@@ -703,7 +703,7 @@
continue;
}
ResolverUtil.findKeyPreserved(query, keyPreservingGroups, metadata);
- if (!NewCalculateCostUtil.usesKey(plannedResult.leftExpressions, keyPreservingGroups, metadata)) {
+ if (!NewCalculateCostUtil.usesKey(plannedResult.leftExpressions, keyPreservingGroups, metadata, true)) {
continue;
}
crits.remove();
Modified: trunk/engine/src/main/java/org/teiid/query/sql/lang/DependentSetCriteria.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/query/sql/lang/DependentSetCriteria.java 2011-03-11 17:39:21 UTC (rev 2990)
+++ trunk/engine/src/main/java/org/teiid/query/sql/lang/DependentSetCriteria.java 2011-03-16 01:26:46 UTC (rev 2991)
@@ -127,7 +127,9 @@
}
DependentSetCriteria criteriaCopy = new DependentSetCriteria(copy, id);
- criteriaCopy.setValueExpression((Expression) getValueExpression().clone());
+ if (this.valueExpression != null) {
+ criteriaCopy.setValueExpression((Expression) getValueExpression().clone());
+ }
criteriaCopy.id = this.id;
return criteriaCopy;
}
Modified: trunk/engine/src/test/java/org/teiid/dqp/internal/process/TestDQPCore.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/dqp/internal/process/TestDQPCore.java 2011-03-11 17:39:21 UTC (rev 2990)
+++ trunk/engine/src/test/java/org/teiid/dqp/internal/process/TestDQPCore.java 2011-03-16 01:26:46 UTC (rev 2991)
@@ -332,7 +332,7 @@
Future<ResultsMessage> message = core.executeRequest(reqMsg.getExecutionId(), reqMsg);
assertNotNull(core.getClientState(String.valueOf(sessionid), false));
- ResultsMessage results = message.get(500000, TimeUnit.MILLISECONDS);
+ ResultsMessage results = message.get(5000, TimeUnit.MILLISECONDS);
core.terminateSession(String.valueOf(sessionid));
assertNull(core.getClientState(String.valueOf(sessionid), false));
if (results.getException() != null) {
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-11 17:39:21 UTC (rev 2990)
+++ trunk/engine/src/test/java/org/teiid/query/optimizer/TestAggregatePushdown.java 2011-03-16 01:26:46 UTC (rev 2991)
@@ -629,9 +629,9 @@
ProcessorPlan plan = helpPlan(sql,
metadata,
null, capFinder,
- new String[] {"SELECT g_0.\"MONTH\", g_0.\"YEAR\" FROM msModel.\"TIME\" AS g_0 WHERE g_0.\"YEAR\" = '1999'", //$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, c_1", //$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$
+ 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 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[] {
@@ -641,8 +641,8 @@
0, // DependentProject
0, // DupRemove
1, // Grouping
- 1, // NestedLoopJoinStrategy
- 1, // MergeJoinStrategy
+ 0, // NestedLoopJoinStrategy
+ 2, // MergeJoinStrategy
0, // Null
0, // PlanExecution
1, // Project
@@ -677,9 +677,9 @@
ProcessorPlan plan = helpPlan(sql,
metadata,
null, capFinder,
- new String[] {"SELECT g_0.\"MONTH\", g_0.\"YEAR\" FROM msModel.\"TIME\" AS g_0 WHERE g_0.\"YEAR\" = '1999'", //$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, c_1", //$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$
+ 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 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[] {
@@ -689,8 +689,8 @@
0, // DependentProject
0, // DupRemove
1, // Grouping
- 1, // NestedLoopJoinStrategy
- 1, // MergeJoinStrategy
+ 0, // NestedLoopJoinStrategy
+ 2, // MergeJoinStrategy
0, // Null
0, // PlanExecution
1, // Project
Modified: trunk/engine/src/test/java/org/teiid/query/optimizer/TestDependentJoins.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/optimizer/TestDependentJoins.java 2011-03-11 17:39:21 UTC (rev 2990)
+++ trunk/engine/src/test/java/org/teiid/query/optimizer/TestDependentJoins.java 2011-03-16 01:26:46 UTC (rev 2991)
@@ -26,7 +26,6 @@
import java.util.Collection;
import java.util.HashSet;
-import java.util.Iterator;
import java.util.Set;
import org.junit.Test;
@@ -59,11 +58,11 @@
}
// Collect all the group names (uppercase) for all the dependent groups in the plan
- Set depGroups = new HashSet();
- getDependentGroups(((RelationalPlan)plan).getRootNode(), depGroups);
+ Set<String> depGroups = new HashSet<String>();
+ getDependentGroups(((RelationalPlan)plan).getRootNode(), depGroups, true);
// Check that all the expected groups exist in depGroups
- Set expectedGroups = new HashSet();
+ Set<String> expectedGroups = new HashSet<String>();
for(int i=0; i<groups.length; i++) {
expectedGroups.add(groups[i].toUpperCase());
}
@@ -71,15 +70,20 @@
assertEquals("Expected groups were not made dependent", expectedGroups, depGroups); //$NON-NLS-1$
}
- static void getDependentGroups(RelationalNode node, Set depGroups) {
- if(node instanceof DependentAccessNode) {
- DependentAccessNode accessNode = (DependentAccessNode)node;
+ static void getDependentGroups(RelationalNode node, Set<String> depGroups, boolean depdenent) {
+ if(node instanceof AccessNode) {
+ if (node instanceof DependentAccessNode) {
+ if (!depdenent) {
+ return;
+ }
+ } else if (depdenent) {
+ return;
+ }
+ AccessNode accessNode = (AccessNode)node;
Command depCommand = accessNode.getCommand();
- Collection groupSymbols = GroupCollectorVisitor.getGroups(depCommand, true);
- Iterator groupIter = groupSymbols.iterator();
- while(groupIter.hasNext()) {
- GroupSymbol group = (GroupSymbol) groupIter.next();
- depGroups.add(group.getName().toUpperCase());
+ Collection<GroupSymbol> groupSymbols = GroupCollectorVisitor.getGroups(depCommand, true);
+ for (GroupSymbol groupSymbol : groupSymbols) {
+ depGroups.add(groupSymbol.getName().toUpperCase());
}
}
@@ -87,7 +91,7 @@
RelationalNode[] children = node.getChildren();
for(int i=0; i<children.length; i++) {
if(children[i] != null) {
- getDependentGroups(node.getChildren()[i], depGroups);
+ getDependentGroups(node.getChildren()[i], depGroups, depdenent);
}
}
}
@@ -98,11 +102,11 @@
}
// Collect all the group names (uppercase) for all the dependent groups in the plan
- Set notDepGroups = new HashSet();
- getNotDependentGroups(((RelationalPlan)plan).getRootNode(), notDepGroups);
+ Set<String> notDepGroups = new HashSet<String>();
+ getDependentGroups(((RelationalPlan)plan).getRootNode(), notDepGroups, false);
// Check that all the expected groups exist in depGroups
- Set expectedGroups = new HashSet();
+ Set<String> expectedGroups = new HashSet<String>();
for(int i=0; i<groups.length; i++) {
expectedGroups.add(groups[i].toUpperCase());
}
@@ -110,27 +114,6 @@
assertEquals("Expected groups were made dependent", expectedGroups, notDepGroups); //$NON-NLS-1$
}
- private void getNotDependentGroups(RelationalNode node, Set notDepGroups) {
- if(node instanceof AccessNode && !(node instanceof DependentAccessNode)) {
- AccessNode accessNode = (AccessNode)node;
- Command depCommand = accessNode.getCommand();
- Collection groupSymbols = GroupCollectorVisitor.getGroups(depCommand, true);
- Iterator groupIter = groupSymbols.iterator();
- while(groupIter.hasNext()) {
- GroupSymbol group = (GroupSymbol) groupIter.next();
- notDepGroups.add(group.getName().toUpperCase());
- }
- }
-
- // Recurse through children
- RelationalNode[] children = node.getChildren();
- for(int i=0; i<children.length; i++) {
- if(children[i] != null) {
- getNotDependentGroups(node.getChildren()[i], notDepGroups);
- }
- }
- }
-
@Test public void testOptionMakeDep1() throws Exception {
FakeCapabilitiesFinder capFinder = new FakeCapabilitiesFinder();
@@ -823,10 +806,13 @@
capFinder.addCapabilities("BQT2", caps); //$NON-NLS-1$
TransformationMetadata metadata = FakeMetadataFactory.exampleBQT();
- FakeMetadataFactory.setCardinality("bqt1.smalla", 3000, metadata); //$NON-NLS-1$
+ FakeMetadataFactory.setCardinality("bqt1.smalla", 1000, metadata); //$NON-NLS-1$
FakeMetadataFactory.setCardinality("bqt2.smalla", 10000, metadata); //$NON-NLS-1$
Column fmo = (Column)metadata.getElementID("bqt1.smalla.intnum");
fmo.setDistinctValues(1000);
+ Column floatnum = (Column)metadata.getElementID("bqt1.smalla.floatnum");
+ floatnum.setDistinctValues(800);
+
ProcessorPlan plan = TestOptimizer.helpPlan(
"SELECT max(a.stringkey) from bqt1.smalla a, bqt2.smalla a2, bqt1.smalla a1 where a.intnum = a2.intnum and a1.stringnum = a2.stringnum and a.floatnum = a1.floatnum", //$NON-NLS-1$
metadata,
@@ -852,5 +838,5 @@
});
}
-
+
}
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-11 17:39:21 UTC (rev 2990)
+++ trunk/engine/src/test/java/org/teiid/query/optimizer/TestOptimizer.java 2011-03-16 01:26:46 UTC (rev 2991)
@@ -3287,7 +3287,7 @@
0, // Null
0, // PlanExecution
1, // Project
- 1, // Select
+ 0, // Select
0, // Sort
0 // UnionAll
});
Modified: trunk/engine/src/test/java/org/teiid/query/optimizer/TestPartitionedJoinPlanning.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/optimizer/TestPartitionedJoinPlanning.java 2011-03-11 17:39:21 UTC (rev 2990)
+++ trunk/engine/src/test/java/org/teiid/query/optimizer/TestPartitionedJoinPlanning.java 2011-03-16 01:26:46 UTC (rev 2991)
@@ -53,7 +53,7 @@
FakeMetadataFacade metadata = FakeMetadataFactory.example1();
FakeMetadataObject g1 = metadata.getStore().findObject("pm1.g1", FakeMetadataObject.GROUP); //$NON-NLS-1$
- g1.putProperty(FakeMetadataObject.Props.CARDINALITY, BufferManager.DEFAULT_PROCESSOR_BATCH_SIZE);
+ g1.putProperty(FakeMetadataObject.Props.CARDINALITY, BufferManager.DEFAULT_PROCESSOR_BATCH_SIZE * 2);
FakeMetadataObject g2 = metadata.getStore().findObject("pm1.g2", FakeMetadataObject.GROUP); //$NON-NLS-1$
g2.putProperty(FakeMetadataObject.Props.CARDINALITY, BufferManager.DEFAULT_PROCESSOR_BATCH_SIZE * 16);
Modified: trunk/engine/src/test/java/org/teiid/query/optimizer/relational/rules/TestRuleChooseDependent.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/optimizer/relational/rules/TestRuleChooseDependent.java 2011-03-11 17:39:21 UTC (rev 2990)
+++ trunk/engine/src/test/java/org/teiid/query/optimizer/relational/rules/TestRuleChooseDependent.java 2011-03-16 01:26:46 UTC (rev 2991)
@@ -22,6 +22,8 @@
package org.teiid.query.optimizer.relational.rules;
+import static org.junit.Assert.*;
+
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -30,6 +32,7 @@
import java.util.LinkedList;
import java.util.List;
+import org.junit.Test;
import org.teiid.api.exception.query.QueryMetadataException;
import org.teiid.api.exception.query.QueryPlannerException;
import org.teiid.core.TeiidComponentException;
@@ -40,10 +43,6 @@
import org.teiid.query.optimizer.relational.plantree.NodeConstants;
import org.teiid.query.optimizer.relational.plantree.NodeFactory;
import org.teiid.query.optimizer.relational.plantree.PlanNode;
-import org.teiid.query.optimizer.relational.rules.FrameUtil;
-import org.teiid.query.optimizer.relational.rules.RuleChooseDependent;
-import org.teiid.query.optimizer.relational.rules.RuleChooseJoinStrategy;
-import org.teiid.query.optimizer.relational.rules.RulePlaceAccess;
import org.teiid.query.processor.relational.JoinNode.JoinStrategyType;
import org.teiid.query.rewriter.QueryRewriter;
import org.teiid.query.sql.lang.CompareCriteria;
@@ -65,11 +64,8 @@
import org.teiid.query.unittest.FakeMetadataObject;
import org.teiid.query.util.CommandContext;
-import junit.framework.TestCase;
+public class TestRuleChooseDependent {
-
-public class TestRuleChooseDependent extends TestCase {
-
/* Make Left Side Dependent */
private static final int LEFT_SIDE = 1;
/* Make Right Side Dependent */
@@ -79,12 +75,6 @@
private FakeMetadataFacade metadata = FakeMetadataFactory.example1Cached();
- // ################################## FRAMEWORK ################################
-
- public TestRuleChooseDependent(String name) {
- super(name);
- }
-
// ################################## TEST HELPERS ################################
public PlanNode createAccessNode(Collection groupSymbols) {
@@ -413,7 +403,7 @@
// ################################## ACTUAL TESTS ################################
- public void testValidJoin1() {
+ @Test public void testValidJoin1() {
PlanNode accessNode = NodeFactory.getNewNode(NodeConstants.Types.ACCESS);
accessNode.addGroup(getPhysicalGroup(1));
@@ -424,7 +414,7 @@
helpTestValidJoin(joinNode, accessNode, false);
}
- public void testValidJoin2() {
+ @Test public void testValidJoin2() {
PlanNode accessNode = NodeFactory.getNewNode(NodeConstants.Types.ACCESS);
accessNode.addGroup(getPhysicalGroup(1));
@@ -436,7 +426,7 @@
helpTestValidJoin(joinNode, accessNode, false);
}
- public void testValidJoin3() {
+ @Test public void testValidJoin3() {
PlanNode accessNode1 = NodeFactory.getNewNode(NodeConstants.Types.ACCESS);
PlanNode accessNode2 = NodeFactory.getNewNode(NodeConstants.Types.ACCESS);
accessNode1.addGroup(getPhysicalGroup(1));
@@ -453,7 +443,7 @@
helpTestValidJoin(joinNode, accessNode1, true);
}
- public void testValidJoin4() {
+ @Test public void testValidJoin4() {
PlanNode accessNode1 = NodeFactory.getNewNode(NodeConstants.Types.ACCESS);
PlanNode accessNode2 = NodeFactory.getNewNode(NodeConstants.Types.ACCESS);
@@ -468,7 +458,7 @@
helpTestValidJoin(joinNode, accessNode2, false);
}
- public void testValidJoin5() {
+ @Test public void testValidJoin5() {
PlanNode accessNode1 = NodeFactory.getNewNode(NodeConstants.Types.ACCESS);
PlanNode accessNode2 = NodeFactory.getNewNode(NodeConstants.Types.ACCESS);
@@ -483,7 +473,7 @@
helpTestValidJoin(joinNode, accessNode1, false);
}
- public void testValidJoin6() {
+ @Test public void testValidJoin6() {
PlanNode accessNode1 = NodeFactory.getNewNode(NodeConstants.Types.ACCESS);
PlanNode accessNode2 = NodeFactory.getNewNode(NodeConstants.Types.ACCESS);
accessNode1.addGroup(getPhysicalGroup(1));
@@ -504,7 +494,7 @@
* Tests that heuristics will take a primary key in the atomic criteria into account when
* making a dependent join.
*/
- public void testChooseKey() throws Exception {
+ @Test public void testChooseKey() throws Exception {
//override default metadata
this.metadata = FakeMetadataFactory.example4();
@@ -529,7 +519,7 @@
/**
* Neither side should be chosen since the left side lacks cardinality information and the right is not strong
*/
- public void testChooseKey2() throws Exception {
+ @Test public void testChooseKey2() throws Exception {
//override default metadata
this.metadata = FakeMetadataFactory.example4();
@@ -583,7 +573,7 @@
* Tests that heuristics will take cardinality of a group into account when
* making a dependent join.
*/
- public void testCardinality() throws Exception {
+ @Test public void testCardinality() throws Exception {
//override default metadata
this.metadata = FakeMetadataFactory.example4();
@@ -614,7 +604,7 @@
* making a dependent join, and that this information supercedes a key
* in the atomic criteria.
*/
- public void testCardinalityAndKey() throws Exception {
+ @Test public void testCardinalityAndKey() throws Exception {
//override default metadata
this.metadata = FakeMetadataFactory.example4();
@@ -640,7 +630,7 @@
helpTestChooseSiblingAndMarkDependent(group2, atomicCrit2, group1, atomicCrit1, crits, expected);
}
- public void testCardinalityAndKeyNestedLoop() throws Exception {
+ @Test public void testCardinalityAndKeyNestedLoop() throws Exception {
//override default metadata
this.metadata = FakeMetadataFactory.example4();
@@ -666,7 +656,7 @@
helpTestChooseSiblingAndMarkDependent(group2, atomicCrit2, group1, atomicCrit1, crits, expected);
}
- public void testRejectDependentJoin() throws Exception {
+ @Test public void testRejectDependentJoin() throws Exception {
//override default metadata
this.metadata = FakeMetadataFactory.example4();
@@ -692,7 +682,7 @@
* Tests that join side with larger cardinality will still have a lower
* cost computed because it has a criteria including a primary key
*/
- public void testCardinalityWithKeyCrit() throws Exception {
+ @Test public void testCardinalityWithKeyCrit() throws Exception {
//override default metadata
this.metadata = FakeMetadataFactory.example4();
@@ -720,7 +710,7 @@
* Tests that join side with larger cardinality will still have a lower
* cost computed because it has a criteria including a primary key
*/
- public void testCardinalityWithKeyCompoundCritAND() throws Exception {
+ @Test public void testCardinalityWithKeyCompoundCritAND() throws Exception {
//override default metadata
this.metadata = FakeMetadataFactory.example4();
@@ -752,7 +742,7 @@
* cost computed because it has a criteria including a primary key.
* Defect 8445
*/
- public void testCardinalityWithKeyCompoundCritOR() throws Exception {
+ @Test public void testCardinalityWithKeyCompoundCritOR() throws Exception {
//override default metadata
this.metadata = FakeMetadataFactory.example4();
@@ -782,7 +772,7 @@
/**
* Tests SetCriteria against a key column in the atomic criteria
*/
- public void testCardinalityWithKeySetCrit() throws Exception {
+ @Test public void testCardinalityWithKeySetCrit() throws Exception {
//override default metadata
this.metadata = FakeMetadataFactory.example4();
@@ -813,7 +803,7 @@
/**
* Tests SetCriteria in the atomic criteria
*/
- public void testCardinalityWithKeyMatchCrit() throws Exception {
+ @Test public void testCardinalityWithKeyMatchCrit() throws Exception {
//override default metadata
this.metadata = FakeMetadataFactory.example4();
@@ -840,7 +830,7 @@
/**
* Tests SetCriteria in the atomic criteria
*/
- public void testCardinalityWithKeyIsNullCrit() throws Exception {
+ @Test public void testCardinalityWithKeyIsNullCrit() throws Exception {
//override default metadata
this.metadata = FakeMetadataFactory.example4();
@@ -867,7 +857,7 @@
/**
* Tests NotCriteria in the atomic criteria
*/
- public void testCardinalityWithKeyNotCrit() throws Exception {
+ @Test public void testCardinalityWithKeyNotCrit() throws Exception {
//override default metadata
this.metadata = FakeMetadataFactory.example4();
@@ -896,7 +886,7 @@
* Tests that join side with larger cardinality will still have a lower
* cost computed because it has a criteria including a primary key
*/
- public void testCardinalityWithKeyComplexCrit() throws Exception {
+ @Test public void testCardinalityWithKeyComplexCrit() throws Exception {
//override default metadata
this.metadata = FakeMetadataFactory.example4();
@@ -925,7 +915,7 @@
helpTestChooseSiblingAndMarkDependent(group2, atomicCrit2, group1, atomicCrit1, crits, expected);
}
- public void testCardinalityWithKeyComplexCrit2() throws Exception {
+ @Test public void testCardinalityWithKeyComplexCrit2() throws Exception {
//override default metadata
this.metadata = FakeMetadataFactory.example4();
@@ -955,7 +945,7 @@
helpTestChooseSiblingAndMarkDependent(group2, atomicCrit2, group1, atomicCrit1, crits, expected);
}
- public void testCardinalityWithKeyComplexCrit3() throws Exception {
+ @Test public void testCardinalityWithKeyComplexCrit3() throws Exception {
//override default metadata
this.metadata = FakeMetadataFactory.example4();
@@ -989,7 +979,7 @@
* Tests that join side with larger cardinality and non-key criteria
* will be made dependent
*/
- public void testCardinalityWithNonKeyCrit() throws Exception {
+ @Test public void testCardinalityWithNonKeyCrit() throws Exception {
//override default metadata
this.metadata = FakeMetadataFactory.example4();
@@ -1018,7 +1008,7 @@
* Tests that join side with larger cardinality will still have a lower
* cost computed because it has a criteria including a primary key
*/
- public void testCardinalityWithCriteriaAndJoin() throws Exception {
+ @Test public void testCardinalityWithCriteriaAndJoin() throws Exception {
//override default metadata
this.metadata = FakeMetadataFactory.example4();
@@ -1069,7 +1059,7 @@
expected, 1000, 1);
}
- public void testCardinalityWithAtomicCrossJoin() throws Exception {
+ @Test public void testCardinalityWithAtomicCrossJoin() throws Exception {
//override default metadata
this.metadata = FakeMetadataFactory.example4();
@@ -1098,7 +1088,7 @@
//atomic Join criteria 2
List atomicJoinCrits2 = Collections.EMPTY_LIST; //INDICATES CROSS JOIN
- int expected = RIGHT_SIDE;
+ int expected = NEITHER_SIDE;
helpTestChooseSiblingAndMarkDependent(
group1,
@@ -1115,7 +1105,7 @@
expected, 1000, 1E5);
}
- public void testCardinalityWithAtomicCrossJoin2() throws Exception {
+ @Test public void testCardinalityWithAtomicCrossJoin2() throws Exception {
//override default metadata
this.metadata = FakeMetadataFactory.example4();
Modified: trunk/engine/src/test/java/org/teiid/query/processor/TestVirtualDepJoin.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/processor/TestVirtualDepJoin.java 2011-03-11 17:39:21 UTC (rev 2990)
+++ trunk/engine/src/test/java/org/teiid/query/processor/TestVirtualDepJoin.java 2011-03-16 01:26:46 UTC (rev 2991)
@@ -247,6 +247,7 @@
Command command = TestProcessor.helpParse(sql);
FakeCapabilitiesFinder finder = new FakeCapabilitiesFinder();
BasicSourceCapabilities caps = TestOptimizer.getTypicalCapabilities();
+ caps.setCapabilitySupport(Capability.QUERY_ORDERBY, false);
caps.setCapabilitySupport(Capability.QUERY_FROM_JOIN_INNER, false);
caps.setCapabilitySupport(Capability.CRITERIA_IN, setPushdown);
finder.addCapabilities("US", caps); //$NON-NLS-1$
@@ -255,8 +256,8 @@
ProcessorPlan plan = TestProcessor.helpGetPlan(command, exampleVirtualDepJoin(), finder, context);
// Check plan contents
- int selectCount = !setPushdown ? 2 : 0;
- int accessCount = setPushdown ? 2 : 4;
+ int selectCount = !setPushdown ? 3 : 0;
+ int accessCount = setPushdown ? 1 : 4;
int depAccessCount = 4 - accessCount;
TestOptimizer.checkNodeTypes(plan, new int[] {
accessCount, // Access
Modified: trunk/engine/src/test/java/org/teiid/query/processor/xml/TestXMLPlanningEnhancements.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/processor/xml/TestXMLPlanningEnhancements.java 2011-03-11 17:39:21 UTC (rev 2990)
+++ trunk/engine/src/test/java/org/teiid/query/processor/xml/TestXMLPlanningEnhancements.java 2011-03-16 01:26:46 UTC (rev 2991)
@@ -484,7 +484,7 @@
// supply the costing information for OrdersC
orders.putProperty(FakeMetadataObject.Props.CARDINALITY, BufferManager.DEFAULT_PROCESSOR_BATCH_SIZE - 1);
- suppliers.putProperty(FakeMetadataObject.Props.CARDINALITY, RuleChooseDependent.DEFAULT_INDEPENDENT_CARDINALITY);
+ suppliers.putProperty(FakeMetadataObject.Props.CARDINALITY, RuleChooseDependent.DEFAULT_INDEPENDENT_CARDINALITY - 1);
String expectedDoc = TestXMLProcessor.readFile("TestXMLProcessor-FullSuppliers.xml"); //$NON-NLS-1$
Modified: trunk/engine/src/test/java/org/teiid/query/unittest/RealMetadataFactory.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/unittest/RealMetadataFactory.java 2011-03-11 17:39:21 UTC (rev 2990)
+++ trunk/engine/src/test/java/org/teiid/query/unittest/RealMetadataFactory.java 2011-03-16 01:26:46 UTC (rev 2991)
@@ -464,6 +464,9 @@
case Index:
group.getIndexes().add(key);
break;
+ case Unique:
+ group.getUniqueKeys().add(key);
+ break;
default:
throw new AssertionError("TODO");
}
Added: trunk/test-integration/common/src/test/java/org/teiid/dqp/internal/process/TestCrossSourceStarJoin.java
===================================================================
--- trunk/test-integration/common/src/test/java/org/teiid/dqp/internal/process/TestCrossSourceStarJoin.java (rev 0)
+++ trunk/test-integration/common/src/test/java/org/teiid/dqp/internal/process/TestCrossSourceStarJoin.java 2011-03-16 01:26:46 UTC (rev 2991)
@@ -0,0 +1,111 @@
+/*
+ * 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.dqp.internal.process;
+
+import static org.teiid.query.unittest.RealMetadataFactory.*;
+
+import java.util.List;
+
+import org.junit.Test;
+import org.teiid.core.types.DataTypeManager;
+import org.teiid.dqp.internal.datamgr.CapabilitiesConverter;
+import org.teiid.metadata.Column;
+import org.teiid.metadata.KeyRecord;
+import org.teiid.metadata.MetadataStore;
+import org.teiid.metadata.Schema;
+import org.teiid.metadata.Table;
+import org.teiid.query.metadata.TransformationMetadata;
+import org.teiid.query.optimizer.TestOptimizer;
+import org.teiid.query.optimizer.TestOptimizer.ComparisonMode;
+import org.teiid.query.optimizer.capabilities.FakeCapabilitiesFinder;
+import org.teiid.query.unittest.RealMetadataFactory;
+import org.teiid.translator.jdbc.oracle.OracleExecutionFactory;
+import org.teiid.translator.jdbc.sybase.SybaseExecutionFactory;
+
+@SuppressWarnings("nls")
+public class TestCrossSourceStarJoin {
+
+ @Test public void testCrossSourceStartJoin() throws Exception {
+ String sql = "select p.Description, sum(AMOUNT) from s3 p, s2 c, s1 b, o1 f " +
+ "where p.PRODUCTID = f.PRODUCT and c.CurrencyCode = f.CURRENCY and b.BOOKID = f.BOOK and b.Name = 'xyz' and c.Name = 'abc' Group by p.Description";
+
+ MetadataStore metadataStore = new MetadataStore();
+
+ Schema oracle = createPhysicalModel("oracle", metadataStore); //$NON-NLS-1$
+ Schema sybase = createPhysicalModel("sybase", metadataStore); //$NON-NLS-1$
+
+ // Create physical groups
+ Table f = createPhysicalGroup("o1", oracle); //$NON-NLS-1$
+ f.setCardinality(5276965);
+ Table b = createPhysicalGroup("s1", sybase); //$NON-NLS-1$
+ b.setCardinality(141496);
+ Table c = createPhysicalGroup("s2", sybase); //$NON-NLS-1$
+ c.setCardinality(228);
+ Table p = createPhysicalGroup("s3", sybase); //$NON-NLS-1$
+ p.setCardinality(200);
+
+ List<Column> f_cols = createElements(f,
+ new String[] { "PRODUCT", "CURRENCY", "BOOK", "AMOUNT"}, //$NON-NLS-1$
+ new String[] { DataTypeManager.DefaultDataTypes.STRING, DataTypeManager.DefaultDataTypes.INTEGER, DataTypeManager.DefaultDataTypes.STRING, DataTypeManager.DefaultDataTypes.BIG_DECIMAL});
+
+ f_cols.get(0).setDistinctValues(200);
+ f_cols.get(1).setDistinctValues(228);
+ f_cols.get(2).setDistinctValues(141496);
+ createKey(KeyRecord.Type.Index, "idx_p", f, f_cols.subList(0, 1));
+ createKey(KeyRecord.Type.Index, "idx_c", f, f_cols.subList(1, 2));
+ createKey(KeyRecord.Type.Index, "idx_b", f, f_cols.subList(2, 3));
+
+ List<Column> b_cols = createElements(b,
+ new String[] { "BOOKID", "Name"}, //$NON-NLS-1$
+ new String[] { DataTypeManager.DefaultDataTypes.STRING, DataTypeManager.DefaultDataTypes.STRING});
+
+ createKey(KeyRecord.Type.Primary, "pk", b, b_cols.subList(0, 1));
+ //createKey(KeyRecord.Type.Unique, "uk", b, b_cols.subList(1, 2));
+
+ List<Column> c_cols = createElements(c,
+ new String[] { "Name", "CurrencyCode"}, //$NON-NLS-1$
+ new String[] { DataTypeManager.DefaultDataTypes.STRING, DataTypeManager.DefaultDataTypes.INTEGER});
+
+ createKey(KeyRecord.Type.Primary, "pk", c, c_cols.subList(1, 2));
+ //createKey(KeyRecord.Type.Unique, "uk", c, c_cols.subList(0, 1));
+
+ List<Column> p_cols = createElements(p,
+ new String[] { "PRODUCTID", "Description"}, //$NON-NLS-1$
+ new String[] { DataTypeManager.DefaultDataTypes.STRING, DataTypeManager.DefaultDataTypes.STRING});
+
+ createKey(KeyRecord.Type.Primary, "pk", p, p_cols.subList(0, 1));
+
+ FakeCapabilitiesFinder finder = new FakeCapabilitiesFinder();
+ finder.addCapabilities("oracle", CapabilitiesConverter.convertCapabilities(new OracleExecutionFactory())); //$NON-NLS-1$
+ finder.addCapabilities("sybase", CapabilitiesConverter.convertCapabilities(new SybaseExecutionFactory())); //$NON-NLS-1$
+
+ TransformationMetadata metadata = RealMetadataFactory.createTransformationMetadata(metadataStore, "star");
+
+ TestOptimizer.helpPlan(sql, metadata, new String[] {
+ "SELECT g_0.CurrencyCode AS c_0 FROM sybase.s2 AS g_0 WHERE g_0.Name = 'abc' ORDER BY c_0",
+ "SELECT g_0.BOOKID FROM sybase.s1 AS g_0 WHERE g_0.Name = 'xyz'",
+ "SELECT g_0.PRODUCTID AS c_0, g_0.Description AS c_1 FROM sybase.s3 AS g_0 ORDER BY c_0",
+ "SELECT g_0.CURRENCY AS c_0, g_0.PRODUCT AS c_1, g_0.BOOK AS c_2, SUM(g_0.AMOUNT) AS c_3 FROM oracle.o1 AS g_0 WHERE (g_0.CURRENCY IN (<dependent values>)) AND (g_0.PRODUCT IN (<dependent values>)) AND (g_0.BOOK IN (<dependent values>)) GROUP BY g_0.CURRENCY, g_0.PRODUCT, g_0.BOOK ORDER BY c_0 NULLS FIRST"
+ }, finder, ComparisonMode.EXACT_COMMAND_STRING);
+ }
+
+}
Property changes on: trunk/test-integration/common/src/test/java/org/teiid/dqp/internal/process/TestCrossSourceStarJoin.java
___________________________________________________________________
Added: svn:mime-type
+ text/plain
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-11 17:39:21 UTC (rev 2990)
+++ trunk/test-integration/common/src/test/java/org/teiid/dqp/internal/process/TestTPCR.java 2011-03-16 01:26:46 UTC (rev 2991)
@@ -127,7 +127,7 @@
List[] sqlServerExpected =
new List[] { Arrays.asList(new Object[] { new Integer(5), new Integer(12), new Long(5) } ),
Arrays.asList(new Object[] { new Integer(5), new Integer(13), new Long(5) } )};
- dataMgr.addData("SELECT g_0.O_CUSTKEY AS c_0, g_0.O_ORDERKEY AS c_1, g_0.O_CUSTKEY AS c_2 FROM TPCR_SQLS.ORDERS AS g_0 WHERE g_0.O_ORDERDATE < {ts'1992-01-02 00:00:00.0'} ORDER BY c_2", //$NON-NLS-1$
+ dataMgr.addData("SELECT g_0.O_CUSTKEY AS c_0, g_0.O_ORDERKEY AS c_1, g_0.O_CUSTKEY AS c_2 FROM TPCR_SQLS.ORDERS AS g_0 WHERE (g_0.O_ORDERDATE < {ts'1992-01-02 00:00:00.0'}) AND (g_0.O_CUSTKEY IN (5, 6)) ORDER BY c_2", //$NON-NLS-1$
sqlServerExpected);
List[] expected =
@@ -167,7 +167,7 @@
List[] sqlServerExpected =
new List[] { Arrays.asList(new Object[] { new Integer(5), new Integer(12), new Long(5) } ),
Arrays.asList(new Object[] { new Integer(5), new Integer(13), new Long(5) } )};
- dataMgr.addData("SELECT g_0.O_CUSTKEY AS c_0, g_0.O_ORDERKEY AS c_1, g_0.O_CUSTKEY AS c_2 FROM TPCR_SQLS.ORDERS AS g_0 WHERE g_0.O_ORDERDATE < {ts'1992-01-02 00:00:00.0'} ORDER BY c_2", //$NON-NLS-1$
+ dataMgr.addData("SELECT g_0.O_CUSTKEY AS c_0, g_0.O_ORDERKEY AS c_1, g_0.O_CUSTKEY AS c_2 FROM TPCR_SQLS.ORDERS AS g_0 WHERE (g_0.O_ORDERDATE < {ts'1992-01-02 00:00:00.0'}) AND (g_0.O_CUSTKEY IN (5, 6)) ORDER BY c_2", //$NON-NLS-1$
sqlServerExpected);
List[] expected =
13 years, 10 months
teiid SVN: r2990 - in trunk: build/kits/jboss-container/deploy/teiid and 8 other directories.
by teiid-commits@lists.jboss.org
Author: shawkins
Date: 2011-03-11 12:39:21 -0500 (Fri, 11 Mar 2011)
New Revision: 2990
Modified:
trunk/build/kits/jboss-container/deploy/teiid/teiid-jboss-beans.xml
trunk/build/kits/jboss-container/teiid-releasenotes.html
trunk/documentation/admin-guide/src/main/docbook/en-US/content/performance.xml
trunk/engine/src/main/java/org/teiid/dqp/internal/process/DQPConfiguration.java
trunk/engine/src/main/java/org/teiid/dqp/internal/process/DQPCore.java
trunk/engine/src/main/java/org/teiid/dqp/internal/process/DataTierManagerImpl.java
trunk/engine/src/main/java/org/teiid/dqp/internal/process/DataTierTupleSource.java
trunk/engine/src/main/java/org/teiid/dqp/internal/process/RequestWorkItem.java
trunk/engine/src/main/java/org/teiid/dqp/internal/process/ThreadReuseExecutor.java
trunk/engine/src/main/java/org/teiid/dqp/internal/process/TransactionServerImpl.java
trunk/engine/src/main/java/org/teiid/dqp/message/AtomicRequestMessage.java
trunk/engine/src/main/java/org/teiid/query/eval/Evaluator.java
trunk/engine/src/main/resources/org/teiid/query/i18n.properties
trunk/engine/src/test/java/org/teiid/common/queue/TestThreadReuseExecutor.java
trunk/engine/src/test/java/org/teiid/dqp/internal/process/TestDQPCore.java
trunk/engine/src/test/java/org/teiid/dqp/service/AutoGenDataService.java
Log:
TEIID-1474 TEIID-1505 adding a limit to the number of concurrent source requests and ensuring that maxactiveplans is read from the config.
Modified: trunk/build/kits/jboss-container/deploy/teiid/teiid-jboss-beans.xml
===================================================================
--- trunk/build/kits/jboss-container/deploy/teiid/teiid-jboss-beans.xml 2011-03-11 05:26:32 UTC (rev 2989)
+++ trunk/build/kits/jboss-container/deploy/teiid/teiid-jboss-beans.xml 2011-03-11 17:39:21 UTC (rev 2990)
@@ -92,6 +92,11 @@
<property name="maxThreads">64</property>
<!-- Max active plans (default 20). Increase this value on highly concurrent systems - but ensure that the underlying pools can handle the increased load without timeouts. -->
<property name="maxActivePlans">20</property>
+ <!-- Max source query concurrency per user request (default 0).
+ 0 indicates use the default calculated value based on max active plans and max threads - approximately 2*(max threads)/(max active plans).
+ 1 forces serial execution in the processing thread, just as is done for a transactional request.
+ Any number greater than 1 limits the maximum number of concurrently executing source requests accordingly. -->
+ <property name="userRequestSourceConcurrency">0</property>
<!-- Query processor time slice, in milliseconds. (default 2000) -->
<property name="timeSliceInMilli">2000</property>
<!-- Maximum allowed fetch size, set via JDBC. User requested value ignored above this value. (default 20480) -->
Modified: trunk/build/kits/jboss-container/teiid-releasenotes.html
===================================================================
--- trunk/build/kits/jboss-container/teiid-releasenotes.html 2011-03-11 05:26:32 UTC (rev 2989)
+++ trunk/build/kits/jboss-container/teiid-releasenotes.html 2011-03-11 17:39:21 UTC (rev 2990)
@@ -37,7 +37,9 @@
</UL>
<LI><B>ARRAYTABLE</B> - the ARRAYTABLE table function was added to simplify array value extraction into a tabular format.
<LI><B>Ingres</B> - Ingres database translator is now available to use as supported source under Teiid.
+ <LI><B>Optional Join Enhancements</B> - the optional join hint no longer requires the use of ANSI joins and can will not remove optional bridging tables that are used by two other tables that are required.
<LI><B>InterSystems Cache</B> - InterSystems Cache database translator is now available to use as supported source under Teiid.
+ <LI><B>userRequestSourceConcurrency</B> - was added to control the number of concurrent source queries allowed for each user request.
</UL>
<h2><a name="Compatibility">Compatibility Issues</a></h2>
@@ -103,6 +105,11 @@
See the <a href="teiid-docs/teiid_admin_guide.pdf">Admin Guide</a> for more on configuration and installation.
+<h4>from 7.3</h4>
+<ul>
+ <LI>SocketConfiguration.maxSocketThreads will interpret a setting of 0 to mean use the system default of max available processors.
+</ul>
+
<h4>from 7.2</h4>
<ul>
<LI>Temporary tables can now be restricted by data roles. Use the data-role attribute allow-create-temporary-tables to explicitly enable or disable the usage of temporary tables.
Modified: trunk/documentation/admin-guide/src/main/docbook/en-US/content/performance.xml
===================================================================
--- trunk/documentation/admin-guide/src/main/docbook/en-US/content/performance.xml 2011-03-11 05:26:32 UTC (rev 2989)
+++ trunk/documentation/admin-guide/src/main/docbook/en-US/content/performance.xml 2011-03-11 17:39:21 UTC (rev 2990)
@@ -62,13 +62,21 @@
They handle NIO non-blocking IO operations as well as directly servicing any operation that can run without blocking.</para>
<para>For longer running operations, the socket threads queue with work the query engine.
The query engine has two settings that determine its thread utilization.
+
<code>maxThreads</code> sets the total number of threads available for query engine work (processing plans, transaction control operations, processing source queries, etc.).
You should consider increasing the maximum threads on systems with a large number of available processors and/or when it's common to issue non-transactional queries with that
issue a large number of concurrent source requests.
+
<code>maxActivePlans</code>, which should always be smaller than maxThreads, sets the number of the maxThreads
that should be used for user query processing. Increasing the maxActivePlans should be considered for workloads with a high number of long
running queries and/or systems with a large number of available processors. If memory issues arise from increasing the max threads and the
- max active plans, then consider decreasing the processor/connector batch sizes to limit the base number of memory rows consumed by each plan.</para>
+ max active plans, then consider decreasing the processor/connector batch sizes to limit the base number of memory rows consumed by each plan.
+
+ <code>userRequestSourceConcurrency</code>, which should always be smaller than maxThreads, sets the number of concurrently executing source queries per user request.
+ Setting this value to 1 forces serial execution of all source queries by the processing thread. The default value is computed based upon 2*maxThreads/maxActivePlans.
+ Using the respective default values, this means that each user request would be allowed 6 concurrently executing source queries. If the default calculated value is
+ not applicable to your workload, for example if you have queries that generate more concurrent long running source queries, you should adjust this value.
+ </para>
</section>
<section>
<title>Cache Tuning</title>
Modified: trunk/engine/src/main/java/org/teiid/dqp/internal/process/DQPConfiguration.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/dqp/internal/process/DQPConfiguration.java 2011-03-11 05:26:32 UTC (rev 2989)
+++ trunk/engine/src/main/java/org/teiid/dqp/internal/process/DQPConfiguration.java 2011-03-11 17:39:21 UTC (rev 2990)
@@ -38,6 +38,7 @@
public static final int DEFAULT_MAX_PROCESS_WORKERS = 64;
public static final int DEFAULT_MAX_SOURCE_ROWS = -1;
public static final int DEFAULT_MAX_ACTIVE_PLANS = 20;
+ public static final int DEFAULT_USER_REQUEST_SOURCE_CONCURRENCY = 0;
private int maxThreads = DEFAULT_MAX_PROCESS_WORKERS;
private int timeSliceInMilli = DEFAULT_PROCESSOR_TIMESLICE;
@@ -52,6 +53,7 @@
private int maxActivePlans = DEFAULT_MAX_ACTIVE_PLANS;
private CacheConfiguration resultsetCacheConfig;
private int maxODBCLobSizeAllowed = 5*1024*1024; // 5 MB
+ private int userRequestSourceConcurrency = DEFAULT_USER_REQUEST_SOURCE_CONCURRENCY;
@ManagementProperty(description="Max active plans (default 20). Increase this value, and max threads, on highly concurrent systems - but ensure that the underlying pools can handle the increased load without timeouts.")
public int getMaxActivePlans() {
@@ -62,6 +64,18 @@
this.maxActivePlans = maxActivePlans;
}
+ @ManagementProperty(description="Max source query concurrency per user request (default 0). " +
+ "0 indicates use the default calculated value based on max active plans and max threads - approximately 2*(max threads)/(max active plans). " +
+ "1 forces serial execution in the processing thread, just as is done for a transactional request. " +
+ "Any number greater than 1 limits the maximum number of concurrently executing source requests accordingly.")
+ public int getUserRequestSourceConcurrency() {
+ return userRequestSourceConcurrency;
+ }
+
+ public void setUserRequestSourceConcurrency(int userRequestSourceConcurrency) {
+ this.userRequestSourceConcurrency = userRequestSourceConcurrency;
+ }
+
@ManagementProperty(description="Process pool maximum thread count. (default 64)")
public int getMaxThreads() {
return maxThreads;
Modified: trunk/engine/src/main/java/org/teiid/dqp/internal/process/DQPCore.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/dqp/internal/process/DQPCore.java 2011-03-11 05:26:32 UTC (rev 2989)
+++ trunk/engine/src/main/java/org/teiid/dqp/internal/process/DQPCore.java 2011-03-11 17:39:21 UTC (rev 2990)
@@ -30,11 +30,10 @@
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
import javax.resource.spi.work.Work;
-import javax.resource.spi.work.WorkEvent;
-import javax.resource.spi.work.WorkListener;
import javax.transaction.xa.Xid;
import org.teiid.adminapi.Admin;
@@ -83,72 +82,58 @@
*/
public class DQPCore implements DQP {
- //TODO: replace with FutureTask
- public final static class FutureWork<T> implements Work, WorkListener, PrioritizedRunnable {
- private final Callable<T> toCall;
- private ResultsFuture<T> result = new ResultsFuture<T>();
- private ResultsReceiver<T> receiver = result.getResultsReceiver();
+ public interface CompletionListener<T> {
+ void onCompletion(FutureWork<T> future);
+ }
+
+ public final static class FutureWork<T> extends FutureTask<T> implements PrioritizedRunnable, Work {
private int priority;
private long creationTime = System.currentTimeMillis();
private DQPWorkContext workContext = DQPWorkContext.getWorkContext();
+ private List<CompletionListener<T>> completionListeners = new LinkedList<CompletionListener<T>>();
- public FutureWork(Callable<T> processor, int priority) {
- this.toCall = processor;
+ public FutureWork(final Callable<T> processor, int priority) {
+ super(processor);
this.priority = priority;
}
- public ResultsFuture<T> getResult() {
- return result;
+ public FutureWork(final Runnable processor, T result, int priority) {
+ super(processor, result);
+ this.priority = priority;
}
@Override
- public void run() {
- try {
- receiver.receiveResults(toCall.call());
- } catch (Throwable t) {
- receiver.exceptionOccurred(t);
- }
+ public int getPriority() {
+ return priority;
}
-
+
@Override
- public void release() {
-
+ public long getCreationTime() {
+ return creationTime;
}
@Override
- public void workAccepted(WorkEvent arg0) {
-
+ public DQPWorkContext getDqpWorkContext() {
+ return workContext;
}
@Override
- public void workCompleted(WorkEvent arg0) {
+ public void release() {
}
- @Override
- public void workRejected(WorkEvent arg0) {
- receiver.exceptionOccurred(arg0.getException());
+ void addCompletionListener(CompletionListener<T> completionListener) {
+ this.completionListeners.add(completionListener);
}
@Override
- public void workStarted(WorkEvent arg0) {
-
+ protected void done() {
+ for (CompletionListener<T> listener : this.completionListeners) {
+ listener.onCompletion(this);
+ }
+ completionListeners.clear();
}
-
- @Override
- public int getPriority() {
- return priority;
- }
- @Override
- public long getCreationTime() {
- return creationTime;
- }
-
- @Override
- public DQPWorkContext getDqpWorkContext() {
- return workContext;
- }
}
static class ClientState {
@@ -200,6 +185,7 @@
private int maxActivePlans = DQPConfiguration.DEFAULT_MAX_ACTIVE_PLANS;
private int currentlyActivePlans;
+ private int userRequestSourceConcurrency;
private LinkedList<RequestWorkItem> waitingPlans = new LinkedList<RequestWorkItem>();
private CacheFactory cacheFactory;
@@ -690,9 +676,19 @@
prepPlanCache = new SessionAwareCache<PreparedPlan>(this.cacheFactory, SessionAwareCache.Type.PREPAREDPLAN, new CacheConfiguration(Policy.LRU, 60*60*8, config.getPreparedPlanCacheMaxCount(), "PreparedCache")); //$NON-NLS-1$
prepPlanCache.setBufferManager(this.bufferManager);
-
this.processWorkerPool = new ThreadReuseExecutor(DQPConfiguration.PROCESS_PLAN_QUEUE_NAME, config.getMaxThreads());
+ this.maxActivePlans = config.getMaxActivePlans();
+ if (this.maxActivePlans > config.getMaxThreads()) {
+ LogManager.logWarning(LogConstants.CTX_DQP, QueryPlugin.Util.getString("DQPCore.invalid_max_active_plan", this.maxActivePlans, config.getMaxThreads())); //$NON-NLS-1$
+ this.maxActivePlans = config.getMaxThreads();
+ }
+
+ this.userRequestSourceConcurrency = config.getUserRequestSourceConcurrency();
+ if (this.userRequestSourceConcurrency < 1) {
+ this.userRequestSourceConcurrency = Math.min(config.getMaxThreads(), 2*config.getMaxThreads()/this.maxActivePlans);
+ }
+
if (cacheFactory.isReplicated()) {
matTables = new SessionAwareCache<CachedResults>(this.cacheFactory, SessionAwareCache.Type.RESULTSET, new CacheConfiguration(Policy.EXPIRATION, -1, -1, "MaterilizationTables")); //$NON-NLS-1$
matTables.setBufferManager(this.bufferManager);
@@ -786,10 +782,23 @@
return addWork(processor, 10);
}
- <T> ResultsFuture<T> addWork(Callable<T> processor, int priority) {
- FutureWork<T> work = new FutureWork<T>(processor, priority);
+ <T> ResultsFuture<T> addWork(final Callable<T> processor, int priority) {
+ final ResultsFuture<T> result = new ResultsFuture<T>();
+ final ResultsReceiver<T> receiver = result.getResultsReceiver();
+ Runnable r = new Runnable() {
+
+ @Override
+ public void run() {
+ try {
+ receiver.receiveResults(processor.call());
+ } catch (Throwable t) {
+ receiver.exceptionOccurred(t);
+ }
+ }
+ };
+ FutureWork<T> work = new FutureWork<T>(r, null, priority);
this.addWork(work);
- return work.getResult();
+ return result;
}
// global txn
@@ -852,4 +861,16 @@
this.cacheFactory = factory;
}
+ public int getUserRequestSourceConcurrency() {
+ return userRequestSourceConcurrency;
+ }
+
+ void setUserRequestSourceConcurrency(int userRequestSourceConcurrency) {
+ this.userRequestSourceConcurrency = userRequestSourceConcurrency;
+ }
+
+ public int getMaxActivePlans() {
+ return maxActivePlans;
+ }
+
}
\ No newline at end of file
Modified: trunk/engine/src/main/java/org/teiid/dqp/internal/process/DataTierManagerImpl.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/dqp/internal/process/DataTierManagerImpl.java 2011-03-11 05:26:32 UTC (rev 2989)
+++ trunk/engine/src/main/java/org/teiid/dqp/internal/process/DataTierManagerImpl.java 2011-03-11 17:39:21 UTC (rev 2990)
@@ -30,13 +30,11 @@
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
-import java.util.concurrent.Callable;
import org.teiid.adminapi.impl.ModelMetaData;
import org.teiid.adminapi.impl.VDBMetaData;
import org.teiid.api.exception.query.QueryMetadataException;
import org.teiid.client.RequestMessage;
-import org.teiid.client.util.ResultsFuture;
import org.teiid.common.buffer.BlockedException;
import org.teiid.common.buffer.BufferManager;
import org.teiid.common.buffer.TupleSource;
@@ -360,6 +358,7 @@
aqr.setMaxResultRows(requestMgr.getMaxSourceRows());
aqr.setExceptionOnMaxRows(requestMgr.isExceptionOnMaxSourceRows());
aqr.setPartialResults(request.supportsPartialResults());
+ aqr.setSerial(requestMgr.getUserRequestSourceConcurrency() == 1);
if (nodeID >= 0) {
aqr.setTransactionContext(workItem.getTransactionContext());
}
@@ -389,14 +388,6 @@
throw new UnsupportedOperationException();
}
- <T> ResultsFuture<T> addWork(Callable<T> callable, int priority) {
- return requestMgr.addWork(callable, priority);
- }
-
- void scheduleWork(Runnable r, int priority, long delay) {
- requestMgr.scheduleWork(r, priority, delay);
- }
-
BufferManager getBufferManager() {
return bufferService.getBufferManager();
}
Modified: trunk/engine/src/main/java/org/teiid/dqp/internal/process/DataTierTupleSource.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/dqp/internal/process/DataTierTupleSource.java 2011-03-11 05:26:32 UTC (rev 2989)
+++ trunk/engine/src/main/java/org/teiid/dqp/internal/process/DataTierTupleSource.java 2011-03-11 17:39:21 UTC (rev 2990)
@@ -27,12 +27,12 @@
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
+import java.util.concurrent.atomic.AtomicBoolean;
import javax.activation.DataSource;
import javax.xml.transform.Source;
import org.teiid.client.SourceWarning;
-import org.teiid.client.util.ResultsFuture;
import org.teiid.common.buffer.BlockedException;
import org.teiid.common.buffer.FileStore;
import org.teiid.common.buffer.TupleSource;
@@ -51,6 +51,7 @@
import org.teiid.core.util.Assertion;
import org.teiid.core.util.ObjectConverterUtil;
import org.teiid.dqp.internal.datamgr.ConnectorWork;
+import org.teiid.dqp.internal.process.DQPCore.FutureWork;
import org.teiid.dqp.message.AtomicRequestMessage;
import org.teiid.dqp.message.AtomicResultsMessage;
import org.teiid.query.processor.xml.XMLUtil;
@@ -86,13 +87,15 @@
private int index;
private int rowsProcessed;
private AtomicResultsMessage arm;
- private boolean closed;
+ private AtomicBoolean closed = new AtomicBoolean();
+ private volatile boolean canAsynchClose;
private volatile boolean canceled;
+ private volatile boolean cancelAsynch;
private boolean executed;
private volatile boolean done;
private boolean explicitClose;
- private volatile ResultsFuture<AtomicResultsMessage> futureResult;
+ private volatile FutureWork<AtomicResultsMessage> futureResult;
private volatile boolean running;
public DataTierTupleSource(AtomicRequestMessage aqr, RequestWorkItem workItem, ConnectorWork cwi, DataTierManagerImpl dtm, int limit) {
@@ -114,23 +117,19 @@
Assertion.isNull(workItem.getConnectorRequest(aqr.getAtomicRequestID()));
workItem.addConnectorRequest(aqr.getAtomicRequestID(), this);
- if (!aqr.isTransactional()) {
+ if (!aqr.isSerial()) {
addWork();
}
}
private void addWork() {
- futureResult = dtm.addWork(new Callable<AtomicResultsMessage>() {
+ this.canAsynchClose = true;
+ futureResult = workItem.addWork(new Callable<AtomicResultsMessage>() {
@Override
public AtomicResultsMessage call() throws Exception {
return getResults();
}
}, 100);
- futureResult.addCompletionListener(new ResultsFuture.CompletionListener<AtomicResultsMessage>() {
- public void onCompletion(ResultsFuture<AtomicResultsMessage> future) {
- workItem.moreWork();
- }
- });
}
private List correctTypes(List row) throws TransformationException {
@@ -208,7 +207,7 @@
if (arm == null) {
AtomicResultsMessage results = null;
try {
- if (futureResult != null || !aqr.isTransactional()) {
+ if (futureResult != null || !aqr.isSerial()) {
results = asynchGet();
} else {
results = getResults();
@@ -216,7 +215,7 @@
} catch (TranslatorException e) {
results = exceptionOccurred(e, true);
} catch (DataNotAvailableException e) {
- dtm.scheduleWork(new Runnable() {
+ workItem.scheduleWork(new Runnable() {
@Override
public void run() {
workItem.moreWork();
@@ -250,7 +249,7 @@
if (!futureResult.isDone()) {
throw BlockedException.INSTANCE;
}
- ResultsFuture<AtomicResultsMessage> currentResults = futureResult;
+ FutureWork<AtomicResultsMessage> currentResults = futureResult;
futureResult = null;
AtomicResultsMessage results = null;
try {
@@ -284,6 +283,9 @@
TranslatorException {
AtomicResultsMessage results = null;
try {
+ if (cancelAsynch) {
+ return null;
+ }
running = true;
if (!executed) {
results = cwi.execute();
@@ -292,13 +294,20 @@
results = cwi.more();
}
} finally {
+ if (!cancelAsynch) {
+ workItem.moreWork();
+ }
+ canAsynchClose = false;
+ if (closed.get()) {
+ cwi.close();
+ }
running = false;
}
return results;
}
public boolean isQueued() {
- ResultsFuture<AtomicResultsMessage> future = futureResult;
+ FutureWork<AtomicResultsMessage> future = futureResult;
return !running && future != null && !future.isDone();
}
@@ -311,32 +320,20 @@
}
public void fullyCloseSource() {
- if (!closed) {
- if (cwi != null) {
- workItem.closeAtomicRequest(this.aqr.getAtomicRequestID());
- if (!aqr.isTransactional()) {
- if (futureResult != null && !futureResult.isDone()) {
- futureResult.addCompletionListener(new ResultsFuture.CompletionListener<AtomicResultsMessage>() {
- @Override
- public void onCompletion(
- ResultsFuture<AtomicResultsMessage> future) {
- cwi.close(); // there is a small chance that this will be done in the processing thread
- }
- });
- } else {
- dtm.addWork(new Callable<Void>() {
- @Override
- public Void call() throws Exception {
- cwi.close();
- return null;
- }
- }, 0);
- }
- } else {
- this.cwi.close();
- }
- }
- closed = true;
+ cancelAsynch = true;
+ if (closed.compareAndSet(false, true)) {
+ workItem.closeAtomicRequest(this.aqr.getAtomicRequestID());
+ if (aqr.isSerial()) {
+ this.cwi.close();
+ } else if (!canAsynchClose) {
+ workItem.addHighPriorityWork(new Callable<Void>() {
+ @Override
+ public Void call() throws Exception {
+ cwi.close();
+ return null;
+ }
+ });
+ }
}
}
@@ -346,15 +343,14 @@
public void cancelRequest() {
this.canceled = true;
- if (this.cwi != null) {
- this.cwi.cancel();
- }
+ this.cwi.cancel();
}
/**
* @see TupleSource#closeSource()
*/
public void closeSource() {
+ cancelAsynch = true;
if (!explicitClose) {
fullyCloseSource();
}
Modified: trunk/engine/src/main/java/org/teiid/dqp/internal/process/RequestWorkItem.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/dqp/internal/process/RequestWorkItem.java 2011-03-11 05:26:32 UTC (rev 2989)
+++ trunk/engine/src/main/java/org/teiid/dqp/internal/process/RequestWorkItem.java 2011-03-11 17:39:21 UTC (rev 2990)
@@ -28,6 +28,7 @@
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import org.teiid.client.RequestMessage;
@@ -46,6 +47,7 @@
import org.teiid.core.TeiidException;
import org.teiid.core.TeiidProcessingException;
import org.teiid.core.types.DataTypeManager;
+import org.teiid.dqp.internal.process.DQPCore.FutureWork;
import org.teiid.dqp.internal.process.SessionAwareCache.CacheID;
import org.teiid.dqp.internal.process.ThreadReuseExecutor.PrioritizedRunnable;
import org.teiid.dqp.message.AtomicRequestID;
@@ -71,12 +73,45 @@
public class RequestWorkItem extends AbstractWorkItem implements PrioritizedRunnable {
+ private final class WorkWrapper<T> implements
+ DQPCore.CompletionListener<T> {
+
+ boolean submitted;
+ FutureWork<T> work;
+
+ public WorkWrapper(FutureWork<T> work) {
+ this.work = work;
+ }
+
+ @Override
+ public void onCompletion(FutureWork<T> future) {
+ WorkWrapper<?> nextWork = null;
+ synchronized (queue) {
+ if (!submitted) {
+ return;
+ }
+ nextWork = queue.pollFirst();
+ if (nextWork == null) {
+ totalThreads--;
+ } else {
+ nextWork.submitted = true;
+ }
+ }
+ if (nextWork != null) {
+ dqpCore.addWork(nextWork.work);
+ }
+ }
+ }
+
private enum ProcessingState {NEW, PROCESSING, CLOSE}
private ProcessingState state = ProcessingState.NEW;
private enum TransactionState {NONE, ACTIVE, DONE}
private TransactionState transactionState = TransactionState.NONE;
+ private int totalThreads;
+ private LinkedList<WorkWrapper<?>> queue = new LinkedList<WorkWrapper<?>>();
+
/*
* Obtained at construction time
*/
@@ -764,6 +799,33 @@
@Override
public long getCreationTime() {
return processingTimestamp;
+ }
+
+ <T> FutureWork<T> addHighPriorityWork(Callable<T> callable) {
+ FutureWork<T> work = new FutureWork<T>(callable, PrioritizedRunnable.NO_WAIT_PRIORITY);
+ dqpCore.addWork(work);
+ return work;
}
+
+ <T> FutureWork<T> addWork(Callable<T> callable, int priority) {
+ FutureWork<T> work = new FutureWork<T>(callable, priority);
+ WorkWrapper<T> wl = new WorkWrapper<T>(work);
+ work.addCompletionListener(wl);
+ synchronized (queue) {
+ if (totalThreads < dqpCore.getUserRequestSourceConcurrency()) {
+ dqpCore.addWork(work);
+ totalThreads++;
+ wl.submitted = true;
+ } else {
+ queue.add(wl);
+ LogManager.logDetail(LogConstants.CTX_DQP, this.requestID, " reached max source concurrency of ", dqpCore.getUserRequestSourceConcurrency()); //$NON-NLS-1$
+ }
+ }
+ return work;
+ }
+
+ void scheduleWork(Runnable r, int priority, long delay) {
+ dqpCore.scheduleWork(r, priority, delay);
+ }
}
\ No newline at end of file
Modified: trunk/engine/src/main/java/org/teiid/dqp/internal/process/ThreadReuseExecutor.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/dqp/internal/process/ThreadReuseExecutor.java 2011-03-11 05:26:32 UTC (rev 2989)
+++ trunk/engine/src/main/java/org/teiid/dqp/internal/process/ThreadReuseExecutor.java 2011-03-11 17:39:21 UTC (rev 2990)
@@ -74,6 +74,8 @@
public interface PrioritizedRunnable extends Runnable {
+ final static int NO_WAIT_PRIORITY = 0;
+
int getPriority();
long getCreationTime();
Modified: trunk/engine/src/main/java/org/teiid/dqp/internal/process/TransactionServerImpl.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/dqp/internal/process/TransactionServerImpl.java 2011-03-11 05:26:32 UTC (rev 2989)
+++ trunk/engine/src/main/java/org/teiid/dqp/internal/process/TransactionServerImpl.java 2011-03-11 17:39:21 UTC (rev 2990)
@@ -248,7 +248,7 @@
}
}, 0);
workManager.doWork(work, WorkManager.INDEFINITE, tc, null);
- tc.setTransaction(work.getResult().get());
+ tc.setTransaction(work.get());
}
} catch (NotSupportedException e) {
throw new XATransactionException(e, XAException.XAER_INVAL);
Modified: trunk/engine/src/main/java/org/teiid/dqp/message/AtomicRequestMessage.java
===================================================================
--- trunk/engine/src/main/java/org/teiid/dqp/message/AtomicRequestMessage.java 2011-03-11 05:26:32 UTC (rev 2989)
+++ trunk/engine/src/main/java/org/teiid/dqp/message/AtomicRequestMessage.java 2011-03-11 17:39:21 UTC (rev 2990)
@@ -81,6 +81,8 @@
private boolean exceptionOnMaxRows;
private int maxRows;
+ private boolean serial;
+
private DQPWorkContext workContext;
public AtomicRequestMessage() {
@@ -137,6 +139,14 @@
public void setTransactionContext(TransactionContext context) {
txnContext = context;
}
+
+ public boolean isSerial() {
+ return serial || isTransactional();
+ }
+
+ public void setSerial(boolean serial) {
+ this.serial = serial;
+ }
public boolean isTransactional(){
return this.txnContext != null && this.txnContext.getTransactionType() != Scope.NONE;
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-11 05:26:32 UTC (rev 2989)
+++ trunk/engine/src/main/java/org/teiid/query/eval/Evaluator.java 2011-03-11 17:39:21 UTC (rev 2990)
@@ -569,17 +569,7 @@
}
} else { // value is null
-
- switch(criteria.getPredicateQuantifier()) {
- case SubqueryCompareCriteria.ALL:
- // null counts as unknown; one unknown means the whole thing is unknown
- return null;
- case SubqueryCompareCriteria.SOME:
- result = null;
- break;
- default:
- throw new ExpressionEvaluationException("ERR.015.006.0057", QueryPlugin.Util.getString("ERR.015.006.0057", criteria.getPredicateQuantifier())); //$NON-NLS-1$ //$NON-NLS-2$
- }
+ result = null;
}
Modified: trunk/engine/src/main/resources/org/teiid/query/i18n.properties
===================================================================
--- trunk/engine/src/main/resources/org/teiid/query/i18n.properties 2011-03-11 05:26:32 UTC (rev 2989)
+++ trunk/engine/src/main/resources/org/teiid/query/i18n.properties 2011-03-11 17:39:21 UTC (rev 2990)
@@ -839,6 +839,7 @@
DQPCore.The_request_has_been_closed.=The request {0} has been closed.
DQPCore.The_atomic_request_has_been_cancelled=The atomic request {0} has been canceled.
DQPCore.failed_to_cancel=Failed to Cancel request, as request already finished processing
+DQPCore.invalid_max_active_plan=The maxActivePlan {0} setting should never be greater than the max processing threads {1}.
ProcessWorker.failed_rollback=Failed to properly rollback autowrap transaction properly
ProcessWorker.error=Unexpected exception for request {0}
Modified: trunk/engine/src/test/java/org/teiid/common/queue/TestThreadReuseExecutor.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/common/queue/TestThreadReuseExecutor.java 2011-03-11 05:26:32 UTC (rev 2989)
+++ trunk/engine/src/test/java/org/teiid/common/queue/TestThreadReuseExecutor.java 2011-03-11 17:39:21 UTC (rev 2990)
@@ -215,10 +215,10 @@
synchronized (pool) {
pool.notifyAll();
}
- work1.getResult().get();
- work2.getResult().get();
- work3.getResult().get();
- work4.getResult().get();
+ work1.get();
+ work2.get();
+ work3.get();
+ work4.get();
assertEquals(Integer.valueOf(3), order.remove());
assertEquals(Integer.valueOf(2), order.remove());
assertEquals(Integer.valueOf(4), order.remove());
Modified: trunk/engine/src/test/java/org/teiid/dqp/internal/process/TestDQPCore.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/dqp/internal/process/TestDQPCore.java 2011-03-11 05:26:32 UTC (rev 2989)
+++ trunk/engine/src/test/java/org/teiid/dqp/internal/process/TestDQPCore.java 2011-03-11 17:39:21 UTC (rev 2990)
@@ -49,7 +49,7 @@
import org.teiid.query.optimizer.capabilities.SourceCapabilities.Capability;
import org.teiid.query.unittest.FakeMetadataFactory;
-
+@SuppressWarnings("nls")
public class TestDQPCore {
private DQPCore core;
@@ -70,7 +70,10 @@
core.setCacheFactory(new DefaultCacheFactory());
core.setTransactionService(new FakeTransactionService());
- core.start(new DQPConfiguration());
+ DQPConfiguration config = new DQPConfiguration();
+ config.setMaxActivePlans(1);
+ config.setUserRequestSourceConcurrency(2);
+ core.start(config);
}
@After public void tearDown() throws Exception {
@@ -86,6 +89,11 @@
msg.setExecutionId(100);
return msg;
}
+
+ @Test public void testConfigurationSets() {
+ assertEquals(1, core.getMaxActivePlans());
+ assertEquals(2, core.getUserRequestSourceConcurrency());
+ }
@Test public void testRequest1() throws Exception {
helpExecute("SELECT IntKey FROM BQT1.SmallA", "a"); //$NON-NLS-1$ //$NON-NLS-2$
@@ -272,6 +280,35 @@
assertEquals(100, item.resultsBuffer.getRowCount());
}
+ @Test public void testSourceConcurrency() throws Exception {
+ //setup default of 2
+ agds.setSleep(100);
+ StringBuffer sql = new StringBuffer();
+ int branches = 20;
+ for (int i = 0; i < branches; i++) {
+ if (i > 0) {
+ sql.append(" union all ");
+ }
+ sql.append("select intkey || " + i + " from bqt1.smalla");
+ }
+ sql.append(" limit 2");
+ helpExecute(sql.toString(), "a");
+ //there's isn't a hard guarantee that only two requests will get started
+ assertTrue(agds.getExecuteCount().get() <= 6);
+
+ //20 concurrent
+ core.setUserRequestSourceConcurrency(20);
+ agds.getExecuteCount().set(0);
+ helpExecute(sql.toString(), "a");
+ assertEquals(20, agds.getExecuteCount().get());
+
+ //serial
+ core.setUserRequestSourceConcurrency(1);
+ agds.getExecuteCount().set(0);
+ helpExecute(sql.toString(), "a");
+ assertEquals(1, agds.getExecuteCount().get());
+ }
+
public void helpTestVisibilityFails(String sql) throws Exception {
RequestMessage reqMsg = exampleRequestMessage(sql);
reqMsg.setTxnAutoWrapMode(RequestMessage.TXN_WRAP_OFF);
@@ -295,7 +332,7 @@
Future<ResultsMessage> message = core.executeRequest(reqMsg.getExecutionId(), reqMsg);
assertNotNull(core.getClientState(String.valueOf(sessionid), false));
- ResultsMessage results = message.get(5000, TimeUnit.MILLISECONDS);
+ ResultsMessage results = message.get(500000, TimeUnit.MILLISECONDS);
core.terminateSession(String.valueOf(sessionid));
assertNull(core.getClientState(String.valueOf(sessionid), false));
if (results.getException() != null) {
Modified: trunk/engine/src/test/java/org/teiid/dqp/service/AutoGenDataService.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/dqp/service/AutoGenDataService.java 2011-03-11 05:26:32 UTC (rev 2989)
+++ trunk/engine/src/test/java/org/teiid/dqp/service/AutoGenDataService.java 2011-03-11 17:39:21 UTC (rev 2990)
@@ -27,6 +27,7 @@
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
import org.teiid.core.TeiidComponentException;
import org.teiid.core.types.DataTypeManager;
@@ -53,12 +54,20 @@
private SourceCapabilities caps;
public boolean throwExceptionOnExecute;
public int dataNotAvailable = -1;
+ public int sleep;
+ private final AtomicInteger executeCount = new AtomicInteger();
+ private final AtomicInteger closeCount = new AtomicInteger();
+
public AutoGenDataService() {
super("FakeConnector","FakeConnector"); //$NON-NLS-1$ //$NON-NLS-2$
caps = TestOptimizer.getTypicalCapabilities();
}
+ public void setSleep(int sleep) {
+ this.sleep = sleep;
+ }
+
public void setCaps(SourceCapabilities caps) {
this.caps = caps;
}
@@ -88,6 +97,14 @@
@Override
public AtomicResultsMessage execute() throws TranslatorException {
+ executeCount.incrementAndGet();
+ if (sleep > 0) {
+ try {
+ Thread.sleep(sleep);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
if (throwExceptionOnExecute) {
throw new TranslatorException("Connector Exception"); //$NON-NLS-1$
}
@@ -101,7 +118,7 @@
@Override
public void close() {
-
+ closeCount.incrementAndGet();
}
@Override
@@ -112,6 +129,14 @@
};
}
+ public AtomicInteger getExecuteCount() {
+ return executeCount;
+ }
+
+ public AtomicInteger getCloseCount() {
+ return closeCount;
+ }
+
private List[] createResults(List symbols) {
List[] rows = new List[this.rows];
13 years, 10 months
teiid SVN: r2989 - trunk/documentation/caching-guide/src/main/docbook/en-US/content.
by teiid-commits@lists.jboss.org
Author: rareddy
Date: 2011-03-11 00:26:32 -0500 (Fri, 11 Mar 2011)
New Revision: 2989
Modified:
trunk/documentation/caching-guide/src/main/docbook/en-US/content/codetable.xml
trunk/documentation/caching-guide/src/main/docbook/en-US/content/matviews.xml
Log:
Few doc corrections from PaulN.
Modified: trunk/documentation/caching-guide/src/main/docbook/en-US/content/codetable.xml
===================================================================
--- trunk/documentation/caching-guide/src/main/docbook/en-US/content/codetable.xml 2011-03-10 15:53:30 UTC (rev 2988)
+++ trunk/documentation/caching-guide/src/main/docbook/en-US/content/codetable.xml 2011-03-11 05:26:32 UTC (rev 2989)
@@ -51,7 +51,7 @@
<itemizedlist>
<title>Reasons to use a materialized view:</title>
<listitem>
- <para>More control of the possible return columns. Code tables will create a mat view for each key/value pair. If there are multiple return columns it would be better to have a single materialized view.</para>
+ <para>More control of the possible return columns. Code tables will create a materialized view for each key/value pair. If there are multiple return columns it would be better to have a single materialized view.</para>
</listitem>
<listitem>
<para>Proper materialized views have built-in system procedure/table support.</para>
@@ -75,7 +75,7 @@
<para>Designate the appropriate column(s) as the primary key.</para>
</listitem>
<listitem>
- <para>Set the materailized property to true.</para>
+ <para>Set the materialized property to true.</para>
</listitem>
<listitem>
<para>Add a cache hint to the transformation query. To mimic the behavior of the implicit internal materialized view created by the lookup function, use the <link linkend="cache-hint">cache hint</link> <code>/*+ cache(pref_mem) */</code> to indicate that the table data pages should prefer to remain in memory.</para>
@@ -83,4 +83,4 @@
</orderedlist>
<para>Just as with the lookup function, the materialized view table will be created on first use and reused subsequently. See the <link linkend="matviews">Materialized View Chapter</link> for more on materialized views.</para>
</section>
-</chapter>
\ No newline at end of file
+</chapter>
Modified: trunk/documentation/caching-guide/src/main/docbook/en-US/content/matviews.xml
===================================================================
--- trunk/documentation/caching-guide/src/main/docbook/en-US/content/matviews.xml 2011-03-10 15:53:30 UTC (rev 2988)
+++ trunk/documentation/caching-guide/src/main/docbook/en-US/content/matviews.xml 2011-03-11 05:26:32 UTC (rev 2989)
@@ -60,7 +60,7 @@
Constraints or other database features cannot be added to internal materialization tables.</para>
</listitem>
<listitem><para>The data volume is large. Internal materialization (and temp tables in general) have memory overhead for each page.
- A rough guideline is that there can be 100 million rows in all materializated tables across all VDBs for every gigabyte of heap.</para>
+ A rough guideline is that there can be 100 million rows in all materialized tables across all VDBs for every gigabyte of heap.</para>
</listitem>
</itemizedlist>
</para>
@@ -73,7 +73,7 @@
<para>External materialized views cache their data in an external database
system. External materialized views give the administrator full control over the loading and refresh strategies.</para>
<para>Since the actual physical cache for materialized views is
- maintained external to the Teiid system, there is no pre-defined
+ maintained external to the Teiid system, there is no predefined
policy for clearing and managing the cache. These policies will be
defined and enforced by administrators of the Teiid system.
</para>
@@ -102,7 +102,7 @@
<para>Internal materialization creates Teiid temporary tables to hold the materialized table. While these tables are not fully durable, they perform
well in most circumstances and the data is present at each Teiid instance which removes the single point of failure and network overhead of an external database.
Internal materialization also provides more built-in facilities for refreshing and monitoring.</para>
- <para>The cache hint, when used in the context of an internal materialized view transformation query, provides the ability to fine tune the materializated table.
+ <para>The cache hint, when used in the context of an internal materialized view transformation query, provides the ability to fine tune the materialized table.
The pref_mem option also applies to internal materialized views. Internal table index pages already have a memory preference, so the perf_mem option indicates that the data pages should prefer memory as well.</para>
<section>
<title>Loading And Refreshing</title>
@@ -110,7 +110,7 @@
All other queries against the materialized view will block until the load completes.
In some situations administrators may wish to better control when the cache is loaded with a call to <code>SYSADMIN.refreshMatView</code>. The initial load may itself trigger the initial load
of dependent materialized views. After the initial load user queries against the materialized view table will only block if it is in an invalid state.
- The valid state may also be controled through the <code>SYSADMIN.refreshMatView</code> procedure.
+ The valid state may also be controlled through the <code>SYSADMIN.refreshMatView</code> procedure.
<example>
<title>Invalidating Refresh</title>
<programlisting>CALL SYSADMIN.refreshMatView(viewname=>'schema.matview', invalidate=>true)</programlisting>
@@ -149,9 +149,9 @@
To be updatable the materialized view must have a single column primary key. Composite keys are not yet supported by <code>SYSADMIN.refreshMatViewRow</code>.
<example>
<title>Updatable Transformation Query</title>
- <para>Transofrmation Query: <programlisting>/*+ cache(updatable) */ select t.col, t1.col from t, t1 where t.id = t1.id</programlisting></para>
+ <para>Transformation Query: <programlisting>/*+ cache(updatable) */ select t.col, t1.col from t, t1 where t.id = t1.id</programlisting></para>
<para>Update SQL: <programlisting>CALL SYSADMIN.updateMatViewRow(viewname=>'schema.matview', key=>5)</programlisting></para>
- <para>Given that the schema.matview defines an interger column col as it's primary key, the update will check the live source(s) for the row values.</para>
+ <para>Given that the schema.matview defines an integer column col as its primary key, the update will check the live source(s) for the row values.</para>
</example>
The update query will not use dependent materialized view tables, so care should be taken to ensure that getting a single
row from this transformation query performs well. See the Reference Guide for information on controlling dependent joins, which may be applicable to increasing the performance of retrieving a single row.
@@ -169,10 +169,10 @@
These indexes are created as non-unique even for unique constraints since the materialized table is not intended as an enforcement point for data integrity
and when updatable the table may not be consistent with underlying values and thus unable to satisfy constraints. The primary key (if it exists) of the view will automatically be part of the covered columns for the index.</para>
<para>The secondary indexes are always created as trees - bitmap or hash indexes are not supported. Teiid's metadata for indexes is currently limited.
- We are not currently able to capture additional information, such as specifying the evluated expressions, sort direction, additional columns to cover, etc. You may workaround some of these limitations though.
+ We are not currently able to capture additional information, such as specifying the evaluated expressions, sort direction, additional columns to cover, etc. You may workaround some of these limitations though.
<itemizedlist>
- <listitem><para>If a function based index is needed, consider adding another column to the view that projects the funciton expression, then place an index on that new column.
- Queries to the view will need to be modified as appropiate though to make use of the new column/index.</para></listitem>
+ <listitem><para>If a function based index is needed, consider adding another column to the view that projects the function expression, then place an index on that new column.
+ Queries to the view will need to be modified as appropriate though to make use of the new column/index.</para></listitem>
<listitem><para>If additional covered columns are needed, they may simply be added to the index columns. This however is only applicable to comparable types.
Adding additional columns will increase the amount of space used by the index, but may allow
its usage to result in higher performance when only the covered columns are used and the main table is not consulted.</para></listitem>
@@ -184,10 +184,10 @@
<para>Each member in a cluster maintains its own copy of each materialized table and associated indexes.
With cache clustering enabled, an additional snapshot copy of the table is maintained for loading by other members.
An attempt is made to ensure each member receives the same full refresh events as the others.
- Full consistency for updatable materialized views however is not guarenteed.
+ Full consistency for updatable materialized views however is not guaranteed.
Periodic full refreshes of updatable materialized view tables helps ensure consistency among members.
<note><para>Loads of materialized tables are not coordinated across the cluster. It is possible for the same ttl expiration to trigger a load at each member.</para></note>
- In many clustered scenarios using external materialization is advantagious to fully control the loading of the tables and to have materialized data that is durable.
+ In many clustered scenarios using external materialization is advantageous to fully control the loading of the tables and to have materialized data that is durable.
</para>
</section>
</section>
13 years, 10 months
teiid SVN: r2988 - in trunk: engine/src/test/java/org/teiid/query/unittest and 1 other directory.
by teiid-commits@lists.jboss.org
Author: shawkins
Date: 2011-03-10 10:53:30 -0500 (Thu, 10 Mar 2011)
New Revision: 2988
Modified:
trunk/connectors/translator-jdbc/src/main/java/org/teiid/translator/jdbc/JDBCMetdataProcessor.java
trunk/engine/src/test/java/org/teiid/query/unittest/FakeMetadataFactory.java
Log:
TEIID-1478 adding a set of the length as well
Modified: trunk/connectors/translator-jdbc/src/main/java/org/teiid/translator/jdbc/JDBCMetdataProcessor.java
===================================================================
--- trunk/connectors/translator-jdbc/src/main/java/org/teiid/translator/jdbc/JDBCMetdataProcessor.java 2011-03-09 22:28:50 UTC (rev 2987)
+++ trunk/connectors/translator-jdbc/src/main/java/org/teiid/translator/jdbc/JDBCMetdataProcessor.java 2011-03-10 15:53:30 UTC (rev 2988)
@@ -238,12 +238,13 @@
String columnName = columns.getString(4);
int type = columns.getInt(5);
String typeName = columns.getString(6);
- int columnLength = columns.getInt(7);
- String runtimeType = getRuntimeType(type, typeName, columnLength);
+ int columnSize = columns.getInt(7);
+ String runtimeType = getRuntimeType(type, typeName, columnSize);
//note that the resultset is already ordered by position, so we can rely on just adding columns in order
Column column = metadataFactory.addColumn(columnName, runtimeType, tableInfo.table);
column.setNameInSource(quoteName(columnName));
- column.setPrecision(columnLength);
+ column.setPrecision(columnSize);
+ column.setLength(columnSize);
column.setNativeType(typeName);
column.setRadix(columns.getInt(10));
column.setNullType(NullType.values()[columns.getShort(11)]);
@@ -264,7 +265,7 @@
}
} else { //SQLServer quotes bit values
String trimedDefault = defaultValue.trim();
- if (defaultValue.startsWith("(") && defaultValue.endsWith(")")) {
+ if (defaultValue.startsWith("(") && defaultValue.endsWith(")")) { //$NON-NLS-1$ //$NON-NLS-2$
trimedDefault = defaultValue.substring(1, defaultValue.length() - 1);
}
column.setDefaultValue(trimedDefault);
Modified: trunk/engine/src/test/java/org/teiid/query/unittest/FakeMetadataFactory.java
===================================================================
--- trunk/engine/src/test/java/org/teiid/query/unittest/FakeMetadataFactory.java 2011-03-09 22:28:50 UTC (rev 2987)
+++ trunk/engine/src/test/java/org/teiid/query/unittest/FakeMetadataFactory.java 2011-03-10 15:53:30 UTC (rev 2988)
@@ -164,7 +164,7 @@
model.setModelType(Model.Type.PHYSICAL);
}
else {
- model.setModelType(Model.Type.PHYSICAL);
+ model.setModelType(Model.Type.VIRTUAL);
}
model.setVisible(true);
model.setSupportsMultiSourceBindings(false);
13 years, 10 months