db-derby-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From rhille...@apache.org
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 GMT
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;
+
+/**
+ * <p>
+ * 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).
+ * </p>
+ */
+public abstract class OptimizerPlan
+{
+    ////////////////////////////////////////////////////////////////////////
+    //
+    //	CONSTANTS
+    //
+    ////////////////////////////////////////////////////////////////////////
+
+    ////////////////////////////////////////////////////////////////////////
+    //
+    //	FACTORY METHODS
+    //
+    ////////////////////////////////////////////////////////////////////////
+
+    /**
+     * <p>
+     * Make a RowSource corresponding to the given tuple descriptor.
+     * </p>
+     */
+    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
+    //
+    ////////////////////////////////////////////////////////////////////////
+
+    /**
+     * <p>
+     * Bind the conglomerate and table function names in this plan.
+     * </p>
+     *
+     * @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;
+
+    /**
+     * <p>
+     * Return true if this the schema and RowSource names have been resolved.
+     * </p>
+     */
+    public abstract boolean isBound();
+
+    /**
+     * <p>
+     * Count the number of leaf nodes under (and including) this node.
+     * </p>
+     */
+    public abstract    int countLeafNodes();
+    
+    /**
+     * <p>
+     * Get the leftmost leaf node in this plan.
+     * </p>
+     */
+    public abstract    RowSource    leftmostLeaf();
+    
+    /**
+     * <p>
+     * Return true if this plan is a (left) leading prefix of the other plan.
+     * </p>
+     */
+    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<D extends UniqueTupleDescriptor>   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<ConglomerateDescriptor>
+    {
+        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<AliasDescriptor>
+    {
+        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] :
 |	<UNCOMMITTED: "uncommitted">
 |	<USAGE: "usage">
 |	<WHEN: "when">
+|	<DERBYPLAN: "--derbyplan">
 }
 
 /*
@@ -2523,6 +2528,7 @@ TOKEN :
 |	<LEFT_PAREN: "(">
 |	<RIGHT_PAREN: ")">
 |	<ASTERISK: "*">
+|	<HASH: "#">
 |	<PLUS_SIGN: "+">
 |	<COMMA: ",">
 |	<MINUS_SIGN: "-">
@@ -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
 	}
 }
 
+/*
+ * <A NAME="optimizerOverridePlan">optimizerOverridePlan</A>
+ */
+OptimizerPlan
+optimizerOverridePlan() throws StandardException :
+{
+    OptimizerPlan       optimizerOverridePlan;
+}
+{
+    <DERBYPLAN> optimizerOverridePlan = optimizerPlan()
+	{
+        return  optimizerOverridePlan;
+	}
+}
+
+/*
+ * <A NAME="optimizerPlan">optimizerPlan</A>
+ */
+OptimizerPlan
+optimizerPlan() throws StandardException :
+{
+    OptimizerPlan       plan;
+}
+{
+	LOOKAHEAD ( { getToken(1).kind == LEFT_PAREN } )
+    plan = optimizerJoin()
+	{
+        return  plan;
+	}
+|
+    plan = optimizerRowSource()
+	{
+        return plan;
+	}
+}
+
+/*
+ * <A NAME="optimizerJoin">optimizerJoin</A>
+ */
+OptimizerPlan
+optimizerJoin() throws StandardException :
+{
+    JoinStrategy        strategy;
+    OptimizerPlan       leftPlan;
+    OptimizerPlan       rightPlan;
+}
+{
+    <LEFT_PAREN>
+        leftPlan = optimizerPlan() strategy = joinStrategy() rightPlan = optimizerPlan()
+    <RIGHT_PAREN>
+	{
+        return new OptimizerPlan.Join( strategy, leftPlan, rightPlan );
+	}
+}
+
+/*
+ * <A NAME="joinStrategy">joinStrategy</A>
+ */
+JoinStrategy
+joinStrategy() throws StandardException :
+{
+}
+{
+    <ASTERISK>
+	{
+        return new NestedLoopJoinStrategy();
+	}
+|
+    <HASH>
+	{
+        return new HashJoinStrategy();
+	}
+}
+
+/*
+ * <A NAME="optimizerRowSource">optimizerRowSource</A>
+ */
+OptimizerPlan
+optimizerRowSource() throws StandardException :
+{
+    TableName       sourceName = null;
+	Token	           leftParenToken = null;
+}
+{
+    sourceName = qualifiedName( Limits.MAX_IDENTIFIER_LENGTH )
+    [ leftParenToken = <LEFT_PAREN> <RIGHT_PAREN> ]
+	{
+        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.
      * </p>
      */
-    private static  void    findResultSetFields( ArrayList<Field> fieldList, Class<?> klass )
+    private static  void    findResultSetFields( ArrayList<Field> fieldList, final Class<?> klass )
         throws Exception
     {
         if ( klass == null ) { return; }
         
-        Field[] fields = klass.getDeclaredFields();
+        Field[] fields = AccessController.doPrivileged
+            (
+             new PrivilegedAction<Field[]>()
+             {
+                 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.
 
             <msg>
                 <name>42Y69</name>
-                <text>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.  </text>
+                <text>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.</text>
             </msg>
 
             <msg>
@@ -3048,6 +3048,23 @@ Guide.
                 <text>A varargs procedure may not return result sets.</text>
             </msg>
 
+            <msg>
+                <name>42ZCC</name>
+                <text>Bad optimizer override. There are {0} row sources in the plan but there should be {1}.</text>
+                <arg>rowSourceCountInPlan</arg>
+                <arg>actualRowSourceCount</arg>
+            </msg>
+
+            <msg>
+                <name>42ZCD</name>
+                <text>Bad optimizer override. The plan is not a left-deep tree.</text>
+            </msg>
+
+            <msg>
+                <name>42ZCE</name>
+                <text>Bad optimizer override. Row sources have not been resolved.</text>
+            </msg>
+
         </family>
 
 

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;
+
+/**
+ * <p>
+ * Test the complete plan overrides added by DERBY-6267.
+ * </p>
+ */
+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
+    //
+    ///////////////////////////////////////////////////////////////////////////////////
+
+    /**
+     * <p>
+     * Basic syntax.
+     * </p>
+     */
+    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"
+              );
+    }
+    
+    /**
+     * <p>
+     * Verify that plan shapes can be overridden for simple selects.
+     * </p>
+     */
+    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;
 	}
 }



Mime
View raw message