Return-Path: X-Original-To: apmail-db-derby-commits-archive@www.apache.org Delivered-To: apmail-db-derby-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id C6A7B10163 for ; Tue, 2 Jul 2013 16:49:28 +0000 (UTC) Received: (qmail 45685 invoked by uid 500); 2 Jul 2013 16:49:28 -0000 Delivered-To: apmail-db-derby-commits-archive@db.apache.org Received: (qmail 45666 invoked by uid 500); 2 Jul 2013 16:49:28 -0000 Mailing-List: contact derby-commits-help@db.apache.org; run by ezmlm Precedence: bulk list-help: list-unsubscribe: List-Post: Reply-To: "Derby Development" List-Id: Delivered-To: mailing list derby-commits@db.apache.org Received: (qmail 45659 invoked by uid 99); 2 Jul 2013 16:49:27 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 02 Jul 2013 16:49:27 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 02 Jul 2013 16:49:23 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id 4C914238890D; Tue, 2 Jul 2013 16:49:03 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1499012 [1/2] - in /db/derby/code/trunk/java: engine/org/apache/derby/iapi/sql/ engine/org/apache/derby/iapi/sql/compile/ engine/org/apache/derby/impl/sql/compile/ engine/org/apache/derby/impl/sql/execute/ engine/org/apache/derby/loc/ shar... Date: Tue, 02 Jul 2013 16:49:02 -0000 To: derby-commits@db.apache.org From: rhillegas@apache.org X-Mailer: svnmailer-1.0.9 Message-Id: <20130702164903.4C914238890D@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: rhillegas Date: Tue Jul 2 16:49:01 2013 New Revision: 1499012 URL: http://svn.apache.org/r1499012 Log: DERBY-6267: Add first rev of complete plan overrides; merged derby-6267-01-ae-compactSyntax.diff to head of trunk. Added: db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/compile/OptimizerPlan.java (with props) db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/NewOptimizerOverridesTest.java (with props) db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/resultSetReader.policy (with props) Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/StatementUtil.java db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/compile/OptimizerFactory.java db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/CurrentOfNode.java db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/DeleteNode.java db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/DistinctNode.java db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/GroupByNode.java db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/OptimizerFactoryImpl.java db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/OptimizerImpl.java db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ProjectRestrictNode.java db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/QueryTreeNode.java db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ResultSetNode.java db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/RowResultSetNode.java db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/SelectNode.java db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/SetOperatorNode.java db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/SingleChildResultSetNode.java db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/TableOperatorNode.java db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/XMLOptTrace.java db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/sqlgrammar.jj db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/BasicNoPutResultSetImpl.java db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/VTIResultSet.java db/derby/code/trunk/java/engine/org/apache/derby/loc/messages.xml db/derby/code/trunk/java/shared/org/apache/derby/shared/common/reference/SQLState.java db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/GeneratedColumnsHelper.java db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/_Suite.java Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/StatementUtil.java URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/StatementUtil.java?rev=1499012&r1=1499011&r2=1499012&view=diff ============================================================================== --- db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/StatementUtil.java (original) +++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/StatementUtil.java Tue Jul 2 16:49:01 2013 @@ -24,6 +24,10 @@ package org.apache.derby.iapi.sql; import org.apache.derby.iapi.error.StandardException; import org.apache.derby.iapi.services.i18n.MessageService; import org.apache.derby.iapi.reference.SQLState; +import org.apache.derby.iapi.sql.compile.CompilerContext; +import org.apache.derby.iapi.sql.dictionary.DataDictionary; +import org.apache.derby.iapi.sql.dictionary.SchemaDescriptor; +import org.apache.derby.iapi.sql.conn.LanguageConnectionContext; /** * Utilities for dealing with statements. @@ -66,4 +70,98 @@ public class StatementUtil "ENABLED", "DISABLED" }; + + /** + * Get the descriptor for the named schema. If the schemaName + * parameter is NULL, it gets the descriptor for the current + * compilation schema. + * + * @param schemaName The name of the schema we're interested in. + * If the name is NULL, get the descriptor for the current compilation schema. + * @param raiseError True to raise an error if the schema does not exist, + * false to return null if the schema does not exist. + * @return Valid SchemaDescriptor or null if raiseError is false and the + * schema does not exist. + * @throws StandardException Schema does not exist and raiseError is true. + */ + public static SchemaDescriptor getSchemaDescriptor + ( + String schemaName, + boolean raiseError, + DataDictionary dataDictionary, + LanguageConnectionContext lcc, + CompilerContext cc + ) + throws StandardException + { + /* + ** Check for a compilation context. Sometimes + ** there is a special compilation context in + ** place to recompile something that may have + ** been compiled against a different schema than + ** the current schema (e.g views): + ** + ** CREATE SCHEMA x + ** CREATE TABLE t + ** CREATE VIEW vt as SEELCT * FROM t + ** SET SCHEMA app + ** SELECT * FROM X.vt + ** + ** In the above view vt must be compiled against + ** the X schema. + */ + + + SchemaDescriptor sd = null; + boolean isCurrent = false; + boolean isCompilation = false; + if (schemaName == null) { + + sd = cc.getCompilationSchema(); + + if (sd == null) { + // Set the compilation schema to be the default, + // notes that this query has schema dependencies. + sd = lcc.getDefaultSchema(); + + isCurrent = true; + + cc.setCompilationSchema(sd); + } + else + { + isCompilation = true; + } + schemaName = sd.getSchemaName(); + } + + SchemaDescriptor sdCatalog = dataDictionary.getSchemaDescriptor(schemaName, + lcc.getTransactionCompile(), raiseError); + + if (isCurrent || isCompilation) { + //if we are dealing with a SESSION schema and it is not physically + //created yet, then it's uuid is going to be null. DERBY-1706 + //Without the getUUID null check below, following will give NPE + //set schema session; -- session schema has not been created yet + //create table t1(c11 int); + if (sdCatalog != null && sdCatalog.getUUID() != null) + { + // different UUID for default (current) schema than in catalog, + // so reset default schema. + if (!sdCatalog.getUUID().equals(sd.getUUID())) + { + if (isCurrent) { lcc.setDefaultSchema(sdCatalog); } + cc.setCompilationSchema(sdCatalog); + } + } + else + { + // this schema does not exist, so ensure its UUID is null. + sd.setUUID(null); + sdCatalog = sd; + } + } + return sdCatalog; + } + } Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/compile/OptimizerFactory.java URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/compile/OptimizerFactory.java?rev=1499012&r1=1499011&r2=1499012&view=diff ============================================================================== --- db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/compile/OptimizerFactory.java (original) +++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/compile/OptimizerFactory.java Tue Jul 2 16:49:01 2013 @@ -48,6 +48,7 @@ public interface OptimizerFactory { * @param requiredRowOrdering The required ordering of the rows to * come out of the optimized result set * @param numTablesInQuery The number of tables in the current query + * @param overridingPlan (Optional) A complete plan specified by optimizer overrides. Must have been bound already. * @param lcc The LanguageConnectionContext * * RESOLVE - We probably want to pass a subquery list, once we define a @@ -61,6 +62,7 @@ public interface OptimizerFactory { DataDictionary dDictionary, RequiredRowOrdering requiredRowOrdering, int numTablesInQuery, + OptimizerPlan overridingPlan, LanguageConnectionContext lcc) throws StandardException; Added: db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/compile/OptimizerPlan.java URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/compile/OptimizerPlan.java?rev=1499012&view=auto ============================================================================== --- db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/compile/OptimizerPlan.java (added) +++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/compile/OptimizerPlan.java Tue Jul 2 16:49:01 2013 @@ -0,0 +1,381 @@ +/* + + Derby - Class org.apache.derby.iapi.sql.compile.OptimizerPlan + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to you under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ + +package org.apache.derby.iapi.sql.compile; + +import org.apache.derby.catalog.AliasInfo; +import org.apache.derby.iapi.error.StandardException; +import org.apache.derby.iapi.reference.SQLState; +import org.apache.derby.iapi.sql.StatementUtil; +import org.apache.derby.iapi.sql.compile.CompilerContext; +import org.apache.derby.iapi.sql.conn.LanguageConnectionContext; +import org.apache.derby.iapi.sql.dictionary.AliasDescriptor; +import org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor; +import org.apache.derby.iapi.sql.dictionary.DataDictionary; +import org.apache.derby.iapi.sql.dictionary.SchemaDescriptor; +import org.apache.derby.iapi.sql.dictionary.UniqueTupleDescriptor; +import org.apache.derby.iapi.util.IdUtil; + +/** + *

+ * High level description of a plan for consideration by the Optimizer. + * This is used to specify a complete plan via optimizer overrides. A + * plan is a tree whose interior nodes are join operators and whose + * leaves are row sources (conglomerates or tableFunctions). + *

+ */ +public abstract class OptimizerPlan +{ + //////////////////////////////////////////////////////////////////////// + // + // CONSTANTS + // + //////////////////////////////////////////////////////////////////////// + + //////////////////////////////////////////////////////////////////////// + // + // FACTORY METHODS + // + //////////////////////////////////////////////////////////////////////// + + /** + *

+ * Make a RowSource corresponding to the given tuple descriptor. + *

+ */ + public static RowSource makeRowSource( UniqueTupleDescriptor utd, DataDictionary dd ) + throws StandardException + { + if ( utd == null ) { return null; } + else if ( utd instanceof ConglomerateDescriptor ) + { + return new ConglomerateRS( (ConglomerateDescriptor) utd, dd ); + } + else if ( utd instanceof AliasDescriptor ) + { + return new TableFunctionRS( (AliasDescriptor) utd ); + } + else { return null; } + } + + //////////////////////////////////////////////////////////////////////// + // + // ABSTRACT BEHAVIOR + // + //////////////////////////////////////////////////////////////////////// + + /** + *

+ * Bind the conglomerate and table function names in this plan. + *

+ * + * @param dataDictionary DataDictionary to bind against. + * @param fromListSize If > 0, then this is the top node in the plan and fromListSize should be the number of leaf nodes + */ + public abstract void bind + ( + DataDictionary dataDictionary, + LanguageConnectionContext lcc, + CompilerContext cc, + int fromListSize + ) + throws StandardException; + + /** + *

+ * Return true if this the schema and RowSource names have been resolved. + *

+ */ + public abstract boolean isBound(); + + /** + *

+ * Count the number of leaf nodes under (and including) this node. + *

+ */ + public abstract int countLeafNodes(); + + /** + *

+ * Get the leftmost leaf node in this plan. + *

+ */ + public abstract RowSource leftmostLeaf(); + + /** + *

+ * Return true if this plan is a (left) leading prefix of the other plan. + *

+ */ + public abstract boolean isLeftPrefixOf( OptimizerPlan that ); + + //////////////////////////////////////////////////////////////////////// + // + // INNER CLASSES + // + //////////////////////////////////////////////////////////////////////// + + public static final class Join extends OptimizerPlan + { + final JoinStrategy strategy; + final OptimizerPlan leftChild; + final OptimizerPlan rightChild; + private boolean _isBound; + private int _leafNodeCount = 0; + + public Join + ( + JoinStrategy strategy, + OptimizerPlan leftChild, + OptimizerPlan rightChild + ) + { + this.strategy = strategy; + this.leftChild = leftChild; + this.rightChild = rightChild; + } + + public void bind + ( + DataDictionary dataDictionary, + LanguageConnectionContext lcc, + CompilerContext cc, + int fromListSize + ) + throws StandardException + { + if ( fromListSize > 0 ) + { + int leafNodeCount = countLeafNodes(); + if ( fromListSize != leafNodeCount ) + { + throw StandardException.newException + ( SQLState.LANG_BAD_ROW_SOURCE_COUNT, leafNodeCount, fromListSize ); + } + } + + // only left-deep trees allowed at this time + if ( !( rightChild instanceof RowSource ) ) + { + throw StandardException.newException( SQLState.LANG_NOT_LEFT_DEEP ); + } + + leftChild.bind( dataDictionary, lcc, cc, (leftChild instanceof RowSource) ? 1 : -1 ); + rightChild.bind( dataDictionary, lcc, cc, (rightChild instanceof RowSource) ? 1 : -1 ); + + _isBound = true; + } + + public boolean isBound() { return _isBound; } + + public int countLeafNodes() + { + if ( _leafNodeCount <= 0 ) { _leafNodeCount = leftChild.countLeafNodes() + rightChild.countLeafNodes(); } + return _leafNodeCount; + } + + public RowSource leftmostLeaf() { return leftChild.leftmostLeaf(); } + + public boolean isLeftPrefixOf( OptimizerPlan other ) + { + if ( !(other instanceof Join) ) { return false; } + + Join that = (Join) other; + + int thisLeafCount = this.countLeafNodes(); + int thatLeafCount = that.countLeafNodes(); + + if ( thisLeafCount > thatLeafCount ) { return false; } + else if ( thisLeafCount < thatLeafCount ) { return isLeftPrefixOf( that.leftChild ); } + else { return this.equals( that ); } + } + + public String toString() + { + return + "( " + + leftChild.toString() + + " " + strategy.getOperatorSymbol() + " " + + rightChild.toString() + + " )"; + } + + public boolean equals( Object other ) + { + if ( other == null ) { return false; } + if ( !(other instanceof Join) ) { return false; } + + Join that = (Join) other; + + if ( !this.strategy.getOperatorSymbol().equals( that.strategy.getOperatorSymbol() ) ) { return false; } + + return this.leftChild.equals( that.leftChild) && this.rightChild.equals( that.rightChild ); + } + } + + public abstract static class RowSource extends OptimizerPlan + { + protected String _schemaName; + protected String _rowSourceName; + protected SchemaDescriptor _schema; + protected D _descriptor; + + public RowSource( String schemaName, String rowSourceName ) + { + _schemaName = schemaName; + _rowSourceName = rowSourceName; + } + protected RowSource() {} + + /** Get the UniqueTupleDescriptor bound to this RowSource */ + public D getDescriptor() { return _descriptor; } + + public void bind + ( + DataDictionary dataDictionary, + LanguageConnectionContext lcc, + CompilerContext cc, + int fromListSize + ) + throws StandardException + { + if ( fromListSize != 1 ) + { + throw StandardException.newException + ( SQLState.LANG_BAD_ROW_SOURCE_COUNT, 1, fromListSize ); + } + + // bind the schema name + if ( _schema == null ) + { + _schema = StatementUtil.getSchemaDescriptor( _schemaName, true, dataDictionary, lcc, cc ); + _schemaName = _schema.getSchemaName(); + } + } + + public boolean isBound() { return (_descriptor != null); } + + public int countLeafNodes() { return 1; } + + public RowSource leftmostLeaf() { return this; } + + public boolean isLeftPrefixOf( OptimizerPlan that ) + { + return this.equals( that.leftmostLeaf() ); + } + + public String toString() + { + return IdUtil.mkQualifiedName( _schemaName, _rowSourceName ); + } + + public boolean equals( Object other ) + { + if ( other == null ) { return false; } + if ( other.getClass() != this.getClass() ) { return false; } + + RowSource that = (RowSource) other; + + if ( !( this.isBound() && that.isBound() ) ) { return false; } + + return this._schemaName.equals( that._schemaName ) && this._rowSourceName.equals( that._rowSourceName ); + } + } + + public static final class ConglomerateRS extends RowSource + { + public ConglomerateRS( String schemaName, String rowSourceName ) { super( schemaName, rowSourceName ); } + + public ConglomerateRS( ConglomerateDescriptor cd, DataDictionary dataDictionary ) + throws StandardException + { + _descriptor = cd; + _schema = dataDictionary.getSchemaDescriptor( cd.getSchemaID(), null ); + _schemaName = _schema.getSchemaName(); + _rowSourceName = cd.getConglomerateName(); + } + + public void bind + ( + DataDictionary dataDictionary, + LanguageConnectionContext lcc, + CompilerContext cc, + int fromListSize + ) + throws StandardException + { + super.bind( dataDictionary, lcc, cc, fromListSize ); + + if ( _descriptor == null ) + { + _descriptor = dataDictionary.getConglomerateDescriptor( _rowSourceName, _schema, false ); + } + if ( _descriptor == null ) + { + throw StandardException.newException + ( SQLState.LANG_INDEX_NOT_FOUND, _schemaName + "." + _rowSourceName ); + } + } + } + + public static final class TableFunctionRS extends RowSource + { + public TableFunctionRS( String schemaName, String rowSourceName ) { super( schemaName, rowSourceName ); } + + public TableFunctionRS( AliasDescriptor ad ) + { + _descriptor = ad; + _schemaName = ad.getSchemaName(); + _rowSourceName = ad.getName(); + } + + public void bind + ( + DataDictionary dataDictionary, + LanguageConnectionContext lcc, + CompilerContext cc, + int fromListSize + ) + throws StandardException + { + super.bind( dataDictionary, lcc, cc, fromListSize ); + + if ( _descriptor == null ) + { + _descriptor = dataDictionary.getAliasDescriptor + ( _schema.getUUID().toString(), _rowSourceName, AliasInfo.ALIAS_NAME_SPACE_FUNCTION_AS_CHAR ); + } + if ( _descriptor == null ) + { + throw StandardException.newException + ( + SQLState.LANG_OBJECT_NOT_FOUND, + AliasDescriptor.getAliasType( AliasInfo.ALIAS_TYPE_FUNCTION_AS_CHAR ), + _schemaName + "." + _rowSourceName + ); + } + } + + public String toString() { return super.toString() + "()"; } + + } + +} Propchange: db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/compile/OptimizerPlan.java ------------------------------------------------------------------------------ svn:eol-style = native Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/CurrentOfNode.java URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/CurrentOfNode.java?rev=1499012&r1=1499011&r2=1499012&view=diff ============================================================================== --- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/CurrentOfNode.java (original) +++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/CurrentOfNode.java Tue Jul 2 16:49:01 2013 @@ -400,7 +400,8 @@ public final class CurrentOfNode extends getContextManager()), predicateList, dataDictionary, - (RequiredRowOrdering) null); + (RequiredRowOrdering) null, + null ); /* Assume there is no cost associated with fetching the current row */ bestCostEstimate = opt.newCostEstimate(); Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/DeleteNode.java URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/DeleteNode.java?rev=1499012&r1=1499011&r2=1499012&view=diff ============================================================================== --- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/DeleteNode.java (original) +++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/DeleteNode.java Tue Jul 2 16:49:01 2013 @@ -758,6 +758,7 @@ class DeleteNode extends DMLModStatement null, /* GROUP BY list */ null, /* having clause */ null, /* windows */ + null, /* optimizer override plan */ getContextManager()); return new DeleteNode(tableName, rs, getContextManager()); @@ -801,6 +802,7 @@ class DeleteNode extends DMLModStatement null, /* GROUP BY list */ null, /* having clause */ null, /* windows */ + null, /* optimizer override plan */ getContextManager()); return new UpdateNode(tableName, sn, getContextManager()); Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/DistinctNode.java URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/DistinctNode.java?rev=1499012&r1=1499011&r2=1499012&view=diff ============================================================================== --- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/DistinctNode.java (original) +++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/DistinctNode.java Tue Jul 2 16:49:01 2013 @@ -221,7 +221,8 @@ class DistinctNode extends SingleChildRe getContextManager()), predicates, dataDictionary, - (RequiredRowOrdering) null); + (RequiredRowOrdering) null, + null ); // RESOLVE: NEED TO FACTOR IN COST OF SORTING AND FIGURE OUT HOW // MANY ROWS HAVE BEEN ELIMINATED. Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/GroupByNode.java URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/GroupByNode.java?rev=1499012&r1=1499011&r2=1499012&view=diff ============================================================================== --- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/GroupByNode.java (original) +++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/GroupByNode.java Tue Jul 2 16:49:01 2013 @@ -943,7 +943,8 @@ class GroupByNode extends SingleChildRes getContextManager()), predicates, dataDictionary, - (RequiredRowOrdering) null); + (RequiredRowOrdering) null, + null ); // RESOLVE: NEED TO FACTOR IN COST OF SORTING AND FIGURE OUT HOW // MANY ROWS HAVE BEEN ELIMINATED. Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/OptimizerFactoryImpl.java URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/OptimizerFactoryImpl.java?rev=1499012&r1=1499011&r2=1499012&view=diff ============================================================================== --- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/OptimizerFactoryImpl.java (original) +++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/OptimizerFactoryImpl.java Tue Jul 2 16:49:01 2013 @@ -31,6 +31,7 @@ import org.apache.derby.iapi.sql.compile import org.apache.derby.iapi.sql.compile.OptimizablePredicateList; import org.apache.derby.iapi.sql.compile.Optimizer; import org.apache.derby.iapi.sql.compile.OptimizerFactory; +import org.apache.derby.iapi.sql.compile.OptimizerPlan; import org.apache.derby.iapi.sql.compile.RequiredRowOrdering; import org.apache.derby.iapi.sql.conn.LanguageConnectionContext; import org.apache.derby.iapi.sql.dictionary.DataDictionary; @@ -141,6 +142,7 @@ public class OptimizerFactoryImpl DataDictionary dDictionary, RequiredRowOrdering requiredRowOrdering, int numTablesInQuery, + OptimizerPlan overridingPlan, LanguageConnectionContext lcc) throws StandardException { @@ -166,6 +168,7 @@ public class OptimizerFactoryImpl dDictionary, requiredRowOrdering, numTablesInQuery, + overridingPlan, lcc); } @@ -199,6 +202,7 @@ public class OptimizerFactoryImpl DataDictionary dDictionary, RequiredRowOrdering requiredRowOrdering, int numTablesInQuery, + OptimizerPlan overridingPlan, LanguageConnectionContext lcc) throws StandardException { @@ -215,6 +219,7 @@ public class OptimizerFactoryImpl lcc.getLockEscalationThreshold(), requiredRowOrdering, numTablesInQuery, + overridingPlan, lcc); } Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/OptimizerImpl.java URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/OptimizerImpl.java?rev=1499012&r1=1499011&r2=1499012&view=diff ============================================================================== --- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/OptimizerImpl.java (original) +++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/OptimizerImpl.java Tue Jul 2 16:49:01 2013 @@ -36,12 +36,14 @@ import org.apache.derby.iapi.sql.compile import org.apache.derby.iapi.sql.compile.OptimizablePredicate; import org.apache.derby.iapi.sql.compile.OptimizablePredicateList; import org.apache.derby.iapi.sql.compile.Optimizer; +import org.apache.derby.iapi.sql.compile.OptimizerPlan; import org.apache.derby.iapi.sql.compile.RequiredRowOrdering; import org.apache.derby.iapi.sql.compile.RowOrdering; import org.apache.derby.iapi.sql.conn.LanguageConnectionContext; import org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor; import org.apache.derby.iapi.sql.dictionary.DataDictionary; import org.apache.derby.iapi.sql.dictionary.TableDescriptor; +import org.apache.derby.iapi.sql.dictionary.UniqueTupleDescriptor; import org.apache.derby.iapi.util.JBitSet; import org.apache.derby.iapi.util.StringUtil; @@ -74,6 +76,8 @@ class OptimizerImpl implements Optimizer */ private JBitSet assignedTableMap; private OptimizableList optimizableList; + private OptimizerPlan overridingPlan; + private OptimizerPlan currentPlan; private OptimizablePredicateList predicateList; private JBitSet nonCorrelatedTableMap; @@ -196,6 +200,7 @@ class OptimizerImpl implements Optimizer int tableLockThreshold, RequiredRowOrdering requiredRowOrdering, int numTablesInQuery, + OptimizerPlan overridingPlan, LanguageConnectionContext lcc ) throws StandardException { @@ -233,6 +238,7 @@ class OptimizerImpl implements Optimizer bestJoinOrder = new int[numOptimizables]; joinPosition = -1; this.optimizableList = optimizableList; + this.overridingPlan = overridingPlan; this.predicateList = predicateList; this.dDictionary = dDictionary; this.ruleBasedOptimization = ruleBasedOptimization; @@ -271,6 +277,15 @@ class OptimizerImpl implements Optimizer // Optimization started if (tracingIsOn()) { tracer().traceStart( timeOptimizationStarted, hashCode(), optimizableList ); } + + // make sure that optimizer overrides are bound and left-deep + if ( overridingPlan != null ) + { + if ( !overridingPlan.isBound() ) + { + throw StandardException.newException( SQLState.LANG_UNRESOLVED_ROW_SOURCE ); + } + } } /** @@ -1540,10 +1555,52 @@ class OptimizerImpl implements Optimizer // RESOLVE: Should we step through the different join strategies here? - /* Returns true until all access paths are exhausted */ - retval = curOpt.nextAccessPath(this, - (OptimizablePredicateList) null, - currentRowOrdering); + while ( true ) + { + /* Returns true until all access paths are exhausted */ + retval = curOpt.nextAccessPath(this, (OptimizablePredicateList) null, currentRowOrdering); + + // if the user didn't specify an explicit plan, we're ok + if ( overridingPlan == null ) { break; } + if ( !retval ) { break; } + + // if we've already found the right access path for this location in + // the join order, then we move on to the next position + if ( currentPlan != null ) + { + if ( currentPlan.countLeafNodes() == (joinPosition+1) ) + { + retval = false; + break; + } + } + + // at this point, figure out if the plan so far is a prefix of the desired plan + OptimizerPlan candidate = OptimizerPlan.makeRowSource( getTupleDescriptor( curOpt ), dDictionary ); + if ( candidate == null ) + { + retval = false; + break; + } + if ( currentPlan != null ) + { + candidate = new OptimizerPlan.Join + ( + curOpt.getCurrentAccessPath().getJoinStrategy(), + currentPlan, + candidate + ); + } + + if ( candidate.isLeftPrefixOf( overridingPlan ) ) + { + currentPlan = candidate; + break; + } + + // well, that decoration didn't match up with the user-specified plan. + // try again + } // If the previous path that we considered for curOpt was _not_ the best // path for this round, then we need to revert back to whatever the @@ -1794,6 +1851,34 @@ class OptimizerImpl implements Optimizer return retval; } + /** + * Get the unique tuple descriptor of the current access path for an Optimizable. + */ + private UniqueTupleDescriptor getTupleDescriptor( Optimizable optimizable ) + throws StandardException + { + if ( isTableFunction( optimizable ) ) + { + ProjectRestrictNode prn = (ProjectRestrictNode) optimizable; + return ((StaticMethodCallNode) ((FromVTI) prn.getChildResult()).getMethodCall() ).ad; + } + else + { + return optimizable.getCurrentAccessPath().getConglomerateDescriptor(); + } + } + + /** Return true if the optimizable is a table function */ + static boolean isTableFunction( Optimizable optimizable ) + { + if ( !( optimizable instanceof ProjectRestrictNode ) ) { return false; } + + ResultSetNode rsn = ((ProjectRestrictNode) optimizable).getChildResult(); + if ( !( rsn instanceof FromVTI ) ) { return false; } + + return ( ((FromVTI) rsn).getMethodCall() instanceof StaticMethodCallNode ); + } + /** * Is the cost of this join order lower than the best one we've * found so far? If so, remember it. Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ProjectRestrictNode.java URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ProjectRestrictNode.java?rev=1499012&r1=1499011&r2=1499012&view=diff ============================================================================== --- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ProjectRestrictNode.java (original) +++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ProjectRestrictNode.java Tue Jul 2 16:49:01 2013 @@ -1218,7 +1218,8 @@ class ProjectRestrictNode extends Single getContextManager()), predicates, dataDictionary, - (RequiredRowOrdering) null); + (RequiredRowOrdering) null, + null ); // RESOLVE: SHOULD FACTOR IN THE NON-OPTIMIZABLE PREDICATES THAT // WERE NOT PUSHED DOWN Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/QueryTreeNode.java URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/QueryTreeNode.java?rev=1499012&r1=1499011&r2=1499012&view=diff ============================================================================== --- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/QueryTreeNode.java (original) +++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/QueryTreeNode.java Tue Jul 2 16:49:01 2013 @@ -39,6 +39,7 @@ import org.apache.derby.iapi.services.lo import org.apache.derby.iapi.services.loader.ClassInspector; import org.apache.derby.iapi.services.sanity.SanityManager; import org.apache.derby.iapi.sql.StatementType; +import org.apache.derby.iapi.sql.StatementUtil; import org.apache.derby.iapi.sql.compile.C_NodeTypes; import org.apache.derby.iapi.sql.compile.CompilerContext; import org.apache.derby.iapi.sql.compile.OptimizerFactory; @@ -1062,77 +1063,14 @@ public abstract class QueryTreeNode impl final SchemaDescriptor getSchemaDescriptor(String schemaName, boolean raiseError) throws StandardException { - /* - ** Check for a compilation context. Sometimes - ** there is a special compilation context in - ** place to recompile something that may have - ** been compiled against a different schema than - ** the current schema (e.g views): - ** - ** CREATE SCHEMA x - ** CREATE TABLE t - ** CREATE VIEW vt as SEELCT * FROM t - ** SET SCHEMA app - ** SELECT * FROM X.vt - ** - ** In the above view vt must be compiled against - ** the X schema. - */ - - - SchemaDescriptor sd = null; - boolean isCurrent = false; - boolean isCompilation = false; - if (schemaName == null) { - - CompilerContext cc = getCompilerContext(); - sd = cc.getCompilationSchema(); - - if (sd == null) { - // Set the compilation schema to be the default, - // notes that this query has schema dependencies. - sd = getLanguageConnectionContext().getDefaultSchema(); - - isCurrent = true; - - cc.setCompilationSchema(sd); - } - else - { - isCompilation = true; - } - schemaName = sd.getSchemaName(); - } - - DataDictionary dataDictionary = getDataDictionary(); - SchemaDescriptor sdCatalog = dataDictionary.getSchemaDescriptor(schemaName, - getLanguageConnectionContext().getTransactionCompile(), raiseError); - - if (isCurrent || isCompilation) { - //if we are dealing with a SESSION schema and it is not physically - //created yet, then it's uuid is going to be null. DERBY-1706 - //Without the getUUID null check below, following will give NPE - //set schema session; -- session schema has not been created yet - //create table t1(c11 int); - if (sdCatalog != null && sdCatalog.getUUID() != null) - { - // different UUID for default (current) schema than in catalog, - // so reset default schema. - if (!sdCatalog.getUUID().equals(sd.getUUID())) - { - if (isCurrent) - getLanguageConnectionContext().setDefaultSchema(sdCatalog); - getCompilerContext().setCompilationSchema(sdCatalog); - } - } - else - { - // this schema does not exist, so ensure its UUID is null. - sd.setUUID(null); - sdCatalog = sd; - } - } - return sdCatalog; + return StatementUtil.getSchemaDescriptor + ( + schemaName, + raiseError, + getDataDictionary(), + getLanguageConnectionContext(), + getCompilerContext() + ); } /** Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ResultSetNode.java URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ResultSetNode.java?rev=1499012&r1=1499011&r2=1499012&view=diff ============================================================================== --- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ResultSetNode.java (original) +++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ResultSetNode.java Tue Jul 2 16:49:01 2013 @@ -38,6 +38,7 @@ import org.apache.derby.iapi.sql.compile import org.apache.derby.iapi.sql.compile.OptimizablePredicateList; import org.apache.derby.iapi.sql.compile.Optimizer; import org.apache.derby.iapi.sql.compile.OptimizerFactory; +import org.apache.derby.iapi.sql.compile.OptimizerPlan; import org.apache.derby.iapi.sql.compile.Parser; import org.apache.derby.iapi.sql.compile.RequiredRowOrdering; import org.apache.derby.iapi.sql.compile.Visitable; @@ -1483,7 +1484,8 @@ public abstract class ResultSetNode exte OptimizableList optList, OptimizablePredicateList predList, DataDictionary dataDictionary, - RequiredRowOrdering requiredRowOrdering) + RequiredRowOrdering requiredRowOrdering, + OptimizerPlan overridingPlan) throws StandardException { if (optimizer == null) @@ -1497,6 +1499,7 @@ public abstract class ResultSetNode exte dataDictionary, requiredRowOrdering, getCompilerContext().getNumTables(), + overridingPlan, getLanguageConnectionContext()); } Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/RowResultSetNode.java URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/RowResultSetNode.java?rev=1499012&r1=1499011&r2=1499012&view=diff ============================================================================== --- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/RowResultSetNode.java (original) +++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/RowResultSetNode.java Tue Jul 2 16:49:01 2013 @@ -630,7 +630,8 @@ class RowResultSetNode extends FromTable getContextManager()), predicateList, dataDictionary, - (RequiredRowOrdering) null); + (RequiredRowOrdering) null, + null ); costEstimate = opt.newCostEstimate(); Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/SelectNode.java URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/SelectNode.java?rev=1499012&r1=1499011&r2=1499012&view=diff ============================================================================== --- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/SelectNode.java (original) +++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/SelectNode.java Tue Jul 2 16:49:01 2013 @@ -34,6 +34,7 @@ import org.apache.derby.iapi.sql.compile import org.apache.derby.iapi.sql.compile.CompilerContext; import org.apache.derby.iapi.sql.compile.CostEstimate; import org.apache.derby.iapi.sql.compile.Optimizer; +import org.apache.derby.iapi.sql.compile.OptimizerPlan; import org.apache.derby.iapi.sql.compile.Visitor; import org.apache.derby.iapi.sql.conn.Authorizer; import org.apache.derby.iapi.sql.dictionary.DataDictionary; @@ -87,6 +88,9 @@ class SelectNode extends ResultSetNode */ WindowList windows; + /** Full plan for this SELECT as specified in an optimizer override */ + OptimizerPlan overridingPlan; + /** * List of window function calls (e.g. ROW_NUMBER, AVG(i), DENSE_RANK). */ @@ -142,6 +146,7 @@ class SelectNode extends ResultSetNode GroupByList groupByList, ValueNode havingClause, WindowList windowDefinitionList, + OptimizerPlan overridingPlan, ContextManager cm) throws StandardException { super(cm); setNodeType(C_NodeTypes.SELECT_NODE); @@ -168,6 +173,8 @@ class SelectNode extends ResultSetNode // used in window functions in ORDER BY. this.windows = windowDefinitionList; + this.overridingPlan = overridingPlan; + bindTargetListOnly = false; this.originalWhereClauseHadSubqueries = false; @@ -516,6 +523,13 @@ class SelectNode extends ResultSetNode { fromListParam.removeElementAt(0); } + + // if an explicit join plan is requested, bind it + if ( overridingPlan != null ) + { + overridingPlan.bind( dataDictionary, getLanguageConnectionContext(), getCompilerContext(), fromList.size() ); + } + return this; } @@ -1976,7 +1990,8 @@ class SelectNode extends ResultSetNode opt = getOptimizer(fromList, wherePredicates, dataDictionary, - orderByLists[0]); // use first one + orderByLists[0], // use first one + overridingPlan); opt.setOuterRows(outerRows); /* Optimize this SelectNode */ Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/SetOperatorNode.java URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/SetOperatorNode.java?rev=1499012&r1=1499011&r2=1499012&view=diff ============================================================================== --- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/SetOperatorNode.java (original) +++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/SetOperatorNode.java Tue Jul 2 16:49:01 2013 @@ -1111,6 +1111,7 @@ abstract class SetOperatorNode extends T null, // GROUP BY list null, // having clause null, /* window list */ + null, /* optimizer override plan */ getContextManager()); /* And finally, transform the "*" in the new SELECT node Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/SingleChildResultSetNode.java URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/SingleChildResultSetNode.java?rev=1499012&r1=1499011&r2=1499012&view=diff ============================================================================== --- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/SingleChildResultSetNode.java (original) +++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/SingleChildResultSetNode.java Tue Jul 2 16:49:01 2013 @@ -407,7 +407,8 @@ abstract class SingleChildResultSetNode getContextManager()), predicates, dataDictionary, - (RequiredRowOrdering) null); + (RequiredRowOrdering) null, + null ); costEstimate = opt.newCostEstimate(); costEstimate.setCost(childResult.getCostEstimate().getEstimatedCost(), Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/TableOperatorNode.java URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/TableOperatorNode.java?rev=1499012&r1=1499011&r2=1499012&view=diff ============================================================================== --- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/TableOperatorNode.java (original) +++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/TableOperatorNode.java Tue Jul 2 16:49:01 2013 @@ -694,7 +694,8 @@ abstract class TableOperatorNode extends getContextManager()), predicateList, dataDictionary, - (RequiredRowOrdering) null); + (RequiredRowOrdering) null, + null ); costEstimate = opt.newCostEstimate(); @@ -863,6 +864,7 @@ abstract class TableOperatorNode extends getDataDictionary(), (RequiredRowOrdering) null, getCompilerContext().getNumTables(), + null, lcc); optimizer.prepForNextRound(); Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/XMLOptTrace.java URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/XMLOptTrace.java?rev=1499012&r1=1499011&r2=1499012&view=diff ============================================================================== --- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/XMLOptTrace.java (original) +++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/XMLOptTrace.java Tue Jul 2 16:49:01 2013 @@ -499,7 +499,7 @@ class XMLOptTrace implements OptTrace ((FromBaseTable) prn.getChildResult()).getTableDescriptor(); return makeTableName( td.getSchemaName(), td.getName(), cm ); } - else if ( isTableFunction( optimizable ) ) + else if ( OptimizerImpl.isTableFunction( optimizable ) ) { ProjectRestrictNode prn = (ProjectRestrictNode) optimizable; AliasDescriptor ad = @@ -546,17 +546,6 @@ class XMLOptTrace implements OptTrace return ( rsn instanceof FromTable ); } - /** Return true if the optimizable is a table function */ - private boolean isTableFunction( Optimizable optimizable ) - { - if ( !( optimizable instanceof ProjectRestrictNode ) ) { return false; } - - ResultSetNode rsn = ((ProjectRestrictNode) optimizable).getChildResult(); - if ( !( rsn instanceof FromVTI ) ) { return false; } - - return ( ((FromVTI) rsn).getMethodCall() instanceof StaticMethodCallNode ); - } - /** Make a TableName */ private TableName makeTableName( String schemaName, String unqualifiedName, ContextManager cm ) @@ -743,7 +732,7 @@ class XMLOptTrace implements OptTrace return IdUtil.mkQualifiedName( schemaName, conglomerateName ); } - boolean isTableFunction = isTableFunction( optimizable ); + boolean isTableFunction = OptimizerImpl.isTableFunction( optimizable ); StringBuilder buffer = new StringBuilder(); buffer.append( getOptimizableName( optimizable ).getFullSQLName() ); if ( isTableFunction ) { buffer.append( TABLE_FUNCTION_FLAG ); } Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/sqlgrammar.jj URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/sqlgrammar.jj?rev=1499012&r1=1499011&r2=1499012&view=diff ============================================================================== --- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/sqlgrammar.jj (original) +++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/sqlgrammar.jj Tue Jul 2 16:49:01 2013 @@ -58,7 +58,9 @@ import org.apache.derby.iapi.services.sa import org.apache.derby.iapi.sql.StatementType; import org.apache.derby.iapi.sql.compile.C_NodeTypes; import org.apache.derby.iapi.sql.compile.CompilerContext; +import org.apache.derby.iapi.sql.compile.JoinStrategy; import org.apache.derby.iapi.sql.compile.OptimizerFactory; +import org.apache.derby.iapi.sql.compile.OptimizerPlan; import org.apache.derby.iapi.sql.compile.TypeCompiler; import org.apache.derby.iapi.sql.conn.Authorizer; import org.apache.derby.iapi.sql.conn.LanguageConnectionContext; @@ -719,6 +721,7 @@ public class SQLParser null, /* GROUP BY list */ null, /* having clause */ null, /* window list */ + null, /* optimizer plan override */ getContextManager()); StatementNode retval = @@ -751,6 +754,7 @@ public class SQLParser null, /* GROUP BY list */ null, /* having clause */ null, /* window list */ + null, /* optimizer plan override */ getContextManager()); StatementNode retval = @@ -2393,6 +2397,7 @@ TOKEN [IGNORE_CASE] : | | | +| } /* @@ -2523,6 +2528,7 @@ TOKEN : | | | +| | | | @@ -8747,6 +8753,7 @@ tableExpression(ResultColumnList selectL ValueNode havingClause = null; Token whereToken; WindowList windows = null; + OptimizerPlan optimizerOverridePlan = null; } { fromList = fromClause() @@ -8754,6 +8761,7 @@ tableExpression(ResultColumnList selectL [ groupByList = groupByClause() ] [ havingClause = havingClause() ] [ windows = windowClause() ] + [ optimizerOverridePlan = optimizerOverridePlan() ] { // fix for HAVING without GROUP BY, makes sure we get one @@ -8774,6 +8782,7 @@ tableExpression(ResultColumnList selectL groupByList, havingClause, windows, + optimizerOverridePlan, getContextManager()); return selectNode; @@ -9785,6 +9794,104 @@ windowDefinition(WindowList wl) throws S } } +/* + * optimizerOverridePlan + */ +OptimizerPlan +optimizerOverridePlan() throws StandardException : +{ + OptimizerPlan optimizerOverridePlan; +} +{ + optimizerOverridePlan = optimizerPlan() + { + return optimizerOverridePlan; + } +} + +/* + * optimizerPlan + */ +OptimizerPlan +optimizerPlan() throws StandardException : +{ + OptimizerPlan plan; +} +{ + LOOKAHEAD ( { getToken(1).kind == LEFT_PAREN } ) + plan = optimizerJoin() + { + return plan; + } +| + plan = optimizerRowSource() + { + return plan; + } +} + +/* + * optimizerJoin + */ +OptimizerPlan +optimizerJoin() throws StandardException : +{ + JoinStrategy strategy; + OptimizerPlan leftPlan; + OptimizerPlan rightPlan; +} +{ + + leftPlan = optimizerPlan() strategy = joinStrategy() rightPlan = optimizerPlan() + + { + return new OptimizerPlan.Join( strategy, leftPlan, rightPlan ); + } +} + +/* + * joinStrategy + */ +JoinStrategy +joinStrategy() throws StandardException : +{ +} +{ + + { + return new NestedLoopJoinStrategy(); + } +| + + { + return new HashJoinStrategy(); + } +} + +/* + * optimizerRowSource + */ +OptimizerPlan +optimizerRowSource() throws StandardException : +{ + TableName sourceName = null; + Token leftParenToken = null; +} +{ + sourceName = qualifiedName( Limits.MAX_IDENTIFIER_LENGTH ) + [ leftParenToken = ] + { + if ( leftParenToken != null ) + { + return new OptimizerPlan.TableFunctionRS( sourceName.getSchemaName(), sourceName.getTableName() ); + } + else + { + return new OptimizerPlan.ConglomerateRS( sourceName.getSchemaName(), sourceName.getTableName() ); + } + } +} + StatementNode schemaDefinition() throws StandardException : { Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/BasicNoPutResultSetImpl.java URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/BasicNoPutResultSetImpl.java?rev=1499012&r1=1499011&r2=1499012&view=diff ============================================================================== --- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/BasicNoPutResultSetImpl.java (original) +++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/BasicNoPutResultSetImpl.java Tue Jul 2 16:49:01 2013 @@ -22,6 +22,8 @@ package org.apache.derby.impl.sql.execute; import java.lang.reflect.Field; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.sql.SQLWarning; import java.sql.Timestamp; import java.util.Arrays; @@ -1107,12 +1109,21 @@ implements NoPutResultSet * Find all fields of type ResultSet. *

*/ - private static void findResultSetFields( ArrayList fieldList, Class klass ) + private static void findResultSetFields( ArrayList fieldList, final Class klass ) throws Exception { if ( klass == null ) { return; } - Field[] fields = klass.getDeclaredFields(); + Field[] fields = AccessController.doPrivileged + ( + new PrivilegedAction() + { + public Field[] run() + { + return klass.getDeclaredFields(); + } + } + ); for ( Field field : fields ) { Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/VTIResultSet.java URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/VTIResultSet.java?rev=1499012&r1=1499011&r2=1499012&view=diff ============================================================================== --- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/VTIResultSet.java (original) +++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/VTIResultSet.java Tue Jul 2 16:49:01 2013 @@ -62,7 +62,7 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.sql.SQLWarning; import java.sql.ResultSetMetaData; - +import org.w3c.dom.Element; /** */ @@ -833,4 +833,11 @@ class VTIResultSet extends NoPutResultSe vsdv.setWidth( dtd.getPrecision(), dtd.getScale(), false ); } + public Element toXML( Element parentNode, String tag ) throws Exception + { + Element myNode = super.toXML( parentNode, tag ); + myNode.setAttribute( "javaClassName", javaClassName ); + + return myNode; + } } Modified: db/derby/code/trunk/java/engine/org/apache/derby/loc/messages.xml URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/loc/messages.xml?rev=1499012&r1=1499011&r2=1499012&view=diff ============================================================================== --- db/derby/code/trunk/java/engine/org/apache/derby/loc/messages.xml (original) +++ db/derby/code/trunk/java/engine/org/apache/derby/loc/messages.xml Tue Jul 2 16:49:01 2013 @@ -2587,7 +2587,7 @@ Guide. 42Y69 - No valid execution plan was found for this statement. This may have one of two causes: either you specified a hash join strategy when hash join is not allowed (no optimizable equijoin) or you are attempting to join two external virtual tables, each of which references the other, and so the statement cannot be evaluated. + No valid execution plan was found for this statement. This may have many causes: 1) you specified a hash join strategy when hash join is not allowed (no optimizable equijoin), 2) you are attempting to join two external virtual tables, each of which references the other, and so the statement cannot be evaluated, 3) you have specified a plan shape which the optimizer would never consider. @@ -3048,6 +3048,23 @@ Guide. A varargs procedure may not return result sets. + + 42ZCC + Bad optimizer override. There are {0} row sources in the plan but there should be {1}. + rowSourceCountInPlan + actualRowSourceCount + + + + 42ZCD + Bad optimizer override. The plan is not a left-deep tree. + + + + 42ZCE + Bad optimizer override. Row sources have not been resolved. + + Modified: db/derby/code/trunk/java/shared/org/apache/derby/shared/common/reference/SQLState.java URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/shared/org/apache/derby/shared/common/reference/SQLState.java?rev=1499012&r1=1499011&r2=1499012&view=diff ============================================================================== --- db/derby/code/trunk/java/shared/org/apache/derby/shared/common/reference/SQLState.java (original) +++ db/derby/code/trunk/java/shared/org/apache/derby/shared/common/reference/SQLState.java Tue Jul 2 16:49:01 2013 @@ -1139,7 +1139,12 @@ public interface SQLState { String LANG_VARARGS_PARAMETER_STYLE = "42ZC9"; String LANG_DERBY_PARAMETER_STYLE = "42ZCA"; String LANG_VARARGS_RETURN_RESULT_SETS = "42ZCB"; - + + // bad optimizer overrides + String LANG_BAD_ROW_SOURCE_COUNT = "42ZCC"; + String LANG_NOT_LEFT_DEEP = "42ZCD"; + String LANG_UNRESOLVED_ROW_SOURCE = "42ZCE"; + //following 3 matches the DB2 sql states String LANG_DECLARED_GLOBAL_TEMP_TABLE_ONLY_IN_SESSION_SCHEMA = "428EK"; String LANG_NOT_ALLOWED_FOR_DECLARED_GLOBAL_TEMP_TABLE = "42995"; Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/GeneratedColumnsHelper.java URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/GeneratedColumnsHelper.java?rev=1499012&r1=1499011&r2=1499012&view=diff ============================================================================== --- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/GeneratedColumnsHelper.java (original) +++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/GeneratedColumnsHelper.java Tue Jul 2 16:49:01 2013 @@ -68,6 +68,7 @@ public class GeneratedColumnsHelper exte protected static final String FOREIGN_KEY_VIOLATION = "23503"; protected static final String ILLEGAL_DUPLICATE = "23505"; protected static final String SYNTAX_ERROR = "42X01"; + protected static final String LEXICAL_ERROR = "42X02"; protected static final String COLUMN_OUT_OF_SCOPE = "42X04"; protected static final String OPERATION_FORBIDDEN = "X0Y25"; Added: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/NewOptimizerOverridesTest.java URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/NewOptimizerOverridesTest.java?rev=1499012&view=auto ============================================================================== --- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/NewOptimizerOverridesTest.java (added) +++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/NewOptimizerOverridesTest.java Tue Jul 2 16:49:01 2013 @@ -0,0 +1,473 @@ +/* + + Derby - Class org.apache.derbyTesting.functionTests.tests.lang.NewOptimizerOverridesTest + + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to you under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ + +package org.apache.derbyTesting.functionTests.tests.lang; + +import java.io.StringWriter; +import java.sql.CallableStatement; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import junit.framework.Test; +import junit.framework.TestSuite; +import org.apache.derbyTesting.junit.Decorator; +import org.apache.derbyTesting.junit.SecurityManagerSetup; +import org.apache.derbyTesting.junit.TestConfiguration; +import org.apache.derbyTesting.junit.JDBC; + +import org.apache.derby.iapi.services.context.ContextManager; +import org.apache.derby.iapi.sql.conn.LanguageConnectionContext; +import org.apache.derby.impl.jdbc.EmbedConnection; +import org.apache.derby.iapi.sql.Activation; + +/** + *

+ * Test the complete plan overrides added by DERBY-6267. + *

+ */ +public class NewOptimizerOverridesTest extends GeneratedColumnsHelper +{ + /////////////////////////////////////////////////////////////////////////////////// + // + // CONSTANTS + // + /////////////////////////////////////////////////////////////////////////////////// + + private static final String WRONG_ROW_SOURCE_COUNT = "42ZCC"; + private static final String NOT_LEFT_DEEP = "42ZCD"; + private static final String MISSING_INDEX = "42X65"; + private static final String MISSING_FUNCTION = "42X94"; + private static final String MISSING_SCHEMA = "42Y07"; + private static final String UNSUPPORTED_PLAN_SHAPE = "42Y69"; + + /////////////////////////////////////////////////////////////////////////////////// + // + // STATE + // + /////////////////////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////////////////////// + // + // CONSTRUCTOR + // + /////////////////////////////////////////////////////////////////////////////////// + + + /** + * Create a new instance. + */ + + public NewOptimizerOverridesTest(String name) + { + super(name); + } + + /////////////////////////////////////////////////////////////////////////////////// + // + // JUnit BEHAVIOR + // + /////////////////////////////////////////////////////////////////////////////////// + + + /** + * Construct top level suite in this JUnit test + */ + public static Test suite() + { + TestSuite suite = new TestSuite( "NewOptimizerOverridesTest" ); + + suite.addTest( TestConfiguration.embeddedSuite( NewOptimizerOverridesTest.class ) ); + + // use a policy file which allows the xml-based plan reader to access fields in the ResultSet graph + return new SecurityManagerSetup + ( + suite, + "org/apache/derbyTesting/functionTests/tests/lang/resultSetReader.policy" + ); + } + + protected void setUp() + throws Exception + { + super.setUp(); + + Connection conn = getConnection(); + + if ( !routineExists( conn, "INTEGERLIST" ) ) + { + goodStatement + ( + conn, + "create function integerList()\n" + + "returns table( a int, b int, c int, d int )\n" + + "language java parameter style derby_jdbc_result_set no sql\n" + + "external name 'org.apache.derbyTesting.functionTests.tests.lang.RestrictedVTITest.integerList'\n" + ); + } + + if ( !tableExists( conn, "V" ) ) + { + goodStatement + ( + conn, + "create view v as select tablename from sys.systables" + ); + } + } + + /////////////////////////////////////////////////////////////////////////////////// + // + // TESTS + // + /////////////////////////////////////////////////////////////////////////////////// + + /** + *

+ * Basic syntax. + *

+ */ + public void test_01_basicSyntax() throws Exception + { + Connection conn = getConnection(); + + // these statements, without optimizer overrides, should run fine + goodStatement + ( conn, + "select tablename from v, sys.syscolumns\n" + + "where tablename = columnname\n" + ); + goodStatement + ( conn, + "select columnname from sys.syscolumns, table( integerList() ) i\n" + + "where columnnumber = -i.a\n" + ); + goodStatement + ( conn, + "select tablename\n" + + "from sys.systables t, sys.syscolumns c, sys.sysaliases a\n" + + "where tablename = columnname and columnname = alias\n" + ); + + // properly stated plan + goodStatement + ( conn, + "select columnname from sys.syscolumns, table( integerList() ) i\n" + + "where columnnumber = -i.a\n" + + "--derbyplan ( app.integerList() # sys.syscolumns_heap )\n" + ); + + // wrong number of row sources in the plan + expectCompilationError + ( WRONG_ROW_SOURCE_COUNT, + "select tablename from v, sys.syscolumns\n" + + "where tablename = columnname\n" + + "--derbyplan A\n" + ); + expectCompilationError + ( WRONG_ROW_SOURCE_COUNT, + "select tablename from v, sys.syscolumns\n" + + "where tablename = columnname\n" + + "--derbyplan A.B\n" + ); + expectCompilationError + ( WRONG_ROW_SOURCE_COUNT, + "select tablename from v, sys.syscolumns\n" + + "where tablename = columnname\n" + + "--derbyplan ( ( A.B # C.D ) * E )\n" + ); + + // unknown conglomerates + expectCompilationError + ( MISSING_INDEX, + "select tablename from v, sys.syscolumns\n" + + "where tablename = columnname\n" + + "--derbyplan ( A * C )\n" + ); + + // unknown function + expectCompilationError + ( MISSING_FUNCTION, + "select tablename from v, sys.syscolumns\n" + + "where tablename = columnname\n" + + "--derbyplan ( A() * C )\n" + ); + + // unknown schema + expectCompilationError + ( MISSING_SCHEMA, + "select tablename from v, sys.syscolumns\n" + + "where tablename = columnname\n" + + "--derbyplan ( A.B * C )\n" + ); + expectCompilationError + ( MISSING_SCHEMA, + "select tablename from v, sys.syscolumns\n" + + "where tablename = columnname\n" + + "--derbyplan ( A.B # C.D )\n" + ); + + // plan is not left deep + expectCompilationError + ( NOT_LEFT_DEEP, + "select tablename\n" + + "from sys.systables t, sys.syscolumns c, sys.sysaliases a\n" + + "where tablename = columnname and columnname = alias\n" + + "--derbyplan ( A.B # ( C.D * E ) )\n" + ); + + // syntax errors + expectCompilationError + ( SYNTAX_ERROR, + "select tablename\n" + + "from sys.systables t, sys.syscolumns c, sys.sysaliases a\n" + + "where tablename = columnname and columnname = alias\n" + + "--derbyplan blah blah blah ( ( A.B # C.D ) * E )\n" + ); + + // bad join operator + expectCompilationError + ( LEXICAL_ERROR, + "select tablename\n" + + "from sys.systables t, sys.syscolumns c, sys.sysaliases a\n" + + "where tablename = columnname and columnname = alias\n" + + "--derbyplan ( ( A.B # C.D ) $ E )\n" + ); + } + + /** + *

+ * Verify that plan shapes can be overridden for simple selects. + *

+ */ + public void test_02_simpleSelects() throws Exception + { + Connection conn = getConnection(); + String select; + + // + // 2 RowSource plan. + // + select = + "select columnname from sys.syscolumns, table( integerList() ) i\n" + + "where columnnumber = -i.a\n"; + + // by itself without an optimizer override. the table function is in the outer slot. + assertPlanShape + ( + conn, select, + "( org.apache.derbyTesting.functionTests.tests.lang.RestrictedVTITest # SYSCOLUMNS )" + ); + + // with an override which places the table function on the inner slot + assertPlanShape + ( + conn, select + "\n--derbyplan ( sys.syscolumns_heap * app.integerList() )\n", + "( SYSCOLUMNS * org.apache.derbyTesting.functionTests.tests.lang.RestrictedVTITest )" + ); + + // hashjoin strategy not allowed for this query + expectCompilationError + ( UNSUPPORTED_PLAN_SHAPE, + select + "\n--derbyplan ( sys.syscolumns_heap # app.integerList() )" + ); + + // + // 4 RowSource plan. + // + select = + "select tablename from sys.systables t, sys.syscolumns c, sys.sysaliases a, sys.syssequences s\n" + + "where t.tablename = c.columnname and c.columnname = a.alias and a.alias = s.sequencename\n"; + + // with an override the join order is syssequences, syscolumns, sysaliases, systables + assertPlanShape + ( + conn, select + "--derbyplan ( ((SYS.SYSSEQUENCES_INDEX2 # SYS.SYSCOLUMNS_HEAP) # SYS.SYSALIASES_INDEX1) # SYS.SYSTABLES_INDEX1 )\n", + "( ( ( SYSSEQUENCES_INDEX2 # SYSCOLUMNS ) # SYSALIASES_INDEX1 ) # SYSTABLES_INDEX1 )" + ); + + // missing a RowSource for SYSALIASES + expectCompilationError + ( UNSUPPORTED_PLAN_SHAPE, + select + "\n--derbyplan ( ((SYS.SYSSEQUENCES_INDEX2 # SYS.SYSCOLUMNS_HEAP) # SYS.SYSCOLUMNS_HEAP) # SYS.SYSTABLES_INDEX1 )" + ); + + } + + /////////////////////////////////////////////////////////////////////////////////// + // + // MINIONS + // + /////////////////////////////////////////////////////////////////////////////////// + + /** Return true if the SQL routine exists */ + private boolean routineExists( Connection conn, String functionName ) throws Exception + { + PreparedStatement ps = chattyPrepare( conn, "select count (*) from sys.sysaliases where alias = ?" ); + ps.setString( 1, functionName ); + + ResultSet rs = ps.executeQuery(); + rs.next(); + + boolean retval = rs.getInt( 1 ) > 0 ? true : false; + + rs.close(); + ps.close(); + + return retval; + } + + /** Return true if the table exists */ + private boolean tableExists( Connection conn, String tableName ) throws Exception + { + PreparedStatement ps = chattyPrepare( conn, "select count (*) from sys.systables where tablename = ?" ); + ps.setString( 1, tableName ); + + ResultSet rs = ps.executeQuery(); + rs.next(); + + boolean retval = rs.getInt( 1 ) > 0 ? true : false; + + rs.close(); + ps.close(); + + return retval; + } + + /** Assert that a query produces the expected plan shape */ + static void assertPlanShape( Connection conn, String query, String expectedPlanShape ) + throws Exception + { + ResultSet rs = conn.prepareStatement( query ).executeQuery(); + String actualPlanShape = summarize( getLastQueryPlan( conn, rs ) ); + rs.close(); + + println( "Expected plan shape = " + expectedPlanShape ); + println( "Actual plan shape = " + actualPlanShape ); + + assertEquals( expectedPlanShape, actualPlanShape ); + } + + /** Get an xml-based picture of the plan chosen for the last query. The query is identified by its JDBC ResultSet */ + static Document getLastQueryPlan( Connection conn, ResultSet rs ) throws Exception + { + ContextManager contextManager = ((EmbedConnection) conn).getContextManager(); + LanguageConnectionContext lcc = (LanguageConnectionContext) contextManager.getContext( "LanguageConnectionContext" ); + org.apache.derby.iapi.sql.ResultSet derbyRS = lcc.getLastActivation().getResultSet(); + + Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); + Element root = doc.createElement( "planTrace" ); + doc.appendChild( root ); + + derbyRS.toXML( root, "top" ); + + return doc; + } + + public static String summarize( Document doc ) throws Exception + { + StringBuilder buffer = new StringBuilder(); + Element root = getFirstElement( doc.getDocumentElement(), "top" );; + + summarize( buffer, root ); + + return buffer.toString(); + } + + private static void summarize( StringBuilder buffer, Element element ) throws Exception + { + String type = element.getAttribute( "type" ); + + if ( "HashJoinResultSet".equals( type ) ) { summarizeJoin( buffer, element, "#" ); } + else if ( "NestedLoopJoinResultSet".equals( type ) ) { summarizeJoin( buffer, element, "*" ); } + else if ( "ProjectRestrictResultSet".equals( type ) ) { summarize( buffer, getFirstElement( element, "source" ) ); } + else + { + String indexName = element.getAttribute( "indexName" ); + String tableName = element.getAttribute( "tableName" ); + String javaClassName = element.getAttribute( "javaClassName" ); + + if ( indexName.length() != 0 ) { buffer.append( indexName ); } + else if ( tableName.length() != 0 ) { buffer.append( tableName ); } + else if ( javaClassName.length() != 0 ) { buffer.append( javaClassName ); } + else { buffer.append( type ); } + } + } + + private static void summarizeJoin( StringBuilder buffer, Element element, String joinSymbol ) + throws Exception + { + buffer.append( "( " ); + summarize( buffer, getFirstElement( element, "leftResultSet" ) ); + buffer.append( " " + joinSymbol + " " ); + summarize( buffer, getFirstElement( element, "rightResultSet" ) ); + buffer.append( " )" ); + } + + /** Get first element by the give tag name */ + private static Element getFirstElement( Element parent, String tag ) throws Exception + { + NodeList list = parent.getChildNodes(); + + for ( int i = 0; i < list.getLength(); i++ ) + { + Node child = list.item( i ); + if ( tag.equals( child.getNodeName() ) ) { return (Element) child; } + } + + return null; + } + + /** Print a document to a string. Not actually used. Useful for debugging this test. */ + static String printDocument( Document doc ) throws Exception + { + TransformerFactory transformerFactory = TransformerFactory.newInstance(); + Transformer transformer = transformerFactory.newTransformer(); + DOMSource source = new DOMSource( doc ); + StringWriter sw = new StringWriter(); + StreamResult result = new StreamResult( sw ); + + // pretty-print + transformer.setOutputProperty( OutputKeys.OMIT_XML_DECLARATION, "no" ); + transformer.setOutputProperty( OutputKeys.METHOD, "xml" ); + transformer.setOutputProperty( OutputKeys.INDENT, "yes" ); + transformer.setOutputProperty( OutputKeys.ENCODING, "UTF-8" ); + transformer.setOutputProperty( "{http://xml.apache.org/xslt}indent-amount", "4" ); + + transformer.transform( source, result ); + + return sw.toString(); + } + +} Propchange: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/NewOptimizerOverridesTest.java ------------------------------------------------------------------------------ svn:eol-style = native Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/_Suite.java URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/_Suite.java?rev=1499012&r1=1499011&r2=1499012&view=diff ============================================================================== --- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/_Suite.java (original) +++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/_Suite.java Tue Jul 2 16:49:01 2013 @@ -237,6 +237,7 @@ public class _Suite extends BaseTestCase suite.addTest(TruncateTableAndOnlineBackupTest.suite()); suite.addTest(QueryPlanTest.suite()); suite.addTest(Derby6131.suite()); + suite.addTest(NewOptimizerOverridesTest.suite()); return suite; } }