You are viewing a plain text version of this content. The canonical link for it is here.
Posted to derby-commits@db.apache.org by rh...@apache.org on 2007/07/10 20:40:41 UTC

svn commit: r555032 [1/2] - in /db/derby/code/trunk/java: engine/org/apache/derby/catalog/ engine/org/apache/derby/catalog/types/ engine/org/apache/derby/iapi/services/io/ engine/org/apache/derby/iapi/sql/dictionary/ engine/org/apache/derby/iapi/sql/ex...

Author: rhillegas
Date: Tue Jul 10 11:40:39 2007
New Revision: 555032

URL: http://svn.apache.org/viewvc?view=rev&rev=555032
Log:
DERBY-716: Commit first increment of VTI work, enabling DDL for table functions and their invocation in simple SELECTs.

Added:
    db/derby/code/trunk/java/engine/org/apache/derby/catalog/types/RowMultiSetImpl.java   (with props)
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/StringArrayVTI.java   (with props)
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/StringColumnVTI.java   (with props)
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/TableFunctionTest.java   (with props)
Modified:
    db/derby/code/trunk/java/engine/org/apache/derby/catalog/TypeDescriptor.java
    db/derby/code/trunk/java/engine/org/apache/derby/catalog/types/BaseTypeIdImpl.java
    db/derby/code/trunk/java/engine/org/apache/derby/catalog/types/RoutineAliasInfo.java
    db/derby/code/trunk/java/engine/org/apache/derby/catalog/types/TypeDescriptorImpl.java
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/services/io/RegisteredFormatIds.java
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/services/io/StoredFormatIds.java
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/AliasDescriptor.java
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/DataDictionary.java
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/execute/ResultSetFactory.java
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/DTSClassInfo.java
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/DataTypeDescriptor.java
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/TypeId.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/catalog/DataDictionaryImpl.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/FromVTI.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/MethodCallNode.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/NewInvocationNode.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ResultColumnList.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/StaticMethodCallNode.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/VTIDeferModPolicy.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/GenericResultSetFactory.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/storeless/org/apache/derby/impl/storeless/EmptyDictionary.java
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/SysDiagVTIMappingTest.java
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/_Suite.java
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/junit/BaseTestCase.java

Modified: db/derby/code/trunk/java/engine/org/apache/derby/catalog/TypeDescriptor.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/catalog/TypeDescriptor.java?view=diff&rev=555032&r1=555031&r2=555032
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/catalog/TypeDescriptor.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/catalog/TypeDescriptor.java Tue Jul 10 11:40:39 2007
@@ -203,5 +203,10 @@
 	 *  @return	the name of the collation being used in this type.
 	 */
 	public String getCollationName();
+
+	/**
+	 * Return true if this is a Row Multiset type
+	  */
+	public	boolean isRowMultiSet();
 }
 

Modified: db/derby/code/trunk/java/engine/org/apache/derby/catalog/types/BaseTypeIdImpl.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/catalog/types/BaseTypeIdImpl.java?view=diff&rev=555032&r1=555031&r2=555032
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/catalog/types/BaseTypeIdImpl.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/catalog/types/BaseTypeIdImpl.java Tue Jul 10 11:40:39 2007
@@ -195,7 +195,7 @@
     public String   toString()
     {
         return MessageService.getTextMessage(SQLState.TI_SQL_TYPE_NAME) +
-                ": " + SQLTypeName;
+                ": " + getSQLTypeName();
     }
 
     /**
@@ -205,7 +205,7 @@
     {
         if (that instanceof BaseTypeIdImpl)
         {
-            return this.SQLTypeName.equals(((BaseTypeIdImpl)that).getSQLTypeName());
+            return this.getSQLTypeName().equals(((BaseTypeIdImpl)that).getSQLTypeName());
         }
         else
         {
@@ -218,7 +218,7 @@
       */
     public int hashCode()
     {
-        return this.SQLTypeName.hashCode();
+        return this.getSQLTypeName().hashCode();
     }
 
     /**

Modified: db/derby/code/trunk/java/engine/org/apache/derby/catalog/types/RoutineAliasInfo.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/catalog/types/RoutineAliasInfo.java?view=diff&rev=555032&r1=555031&r2=555032
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/catalog/types/RoutineAliasInfo.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/catalog/types/RoutineAliasInfo.java Tue Jul 10 11:40:39 2007
@@ -52,6 +52,9 @@
 	/** PARAMETER STYLE JAVA */
 	public static final short PS_JAVA = 0;
 
+	/** PARAMETER STYLE DERBY_JDBC_RESULT_SET */
+	public static final short PS_DERBY_JDBC_RESULT_SET = PS_JAVA + 1;
+
 	private int parameterCount;
 
 	private TypeDescriptor[]	parameterTypes;
@@ -315,7 +318,12 @@
 			sb.append(" RETURNS " + returnType.getSQLstring());
 		}
 
-		sb.append(" LANGUAGE JAVA PARAMETER STYLE JAVA ");
+		sb.append(" LANGUAGE JAVA PARAMETER STYLE " );
+		switch( parameterStyle )
+		{
+		    case PS_JAVA:    sb.append( "JAVA " ); break;
+		    case PS_DERBY_JDBC_RESULT_SET:    sb.append( "DERBY_JDBC_RESULT_SET " ); break;
+		}
 		sb.append(RoutineAliasInfo.SQL_CONTROL[getSQLAllowed()]);
 		if ((returnType == null) &&
 			(dynamicResultSets != 0))

Added: db/derby/code/trunk/java/engine/org/apache/derby/catalog/types/RowMultiSetImpl.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/catalog/types/RowMultiSetImpl.java?view=auto&rev=555032
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/catalog/types/RowMultiSetImpl.java (added)
+++ db/derby/code/trunk/java/engine/org/apache/derby/catalog/types/RowMultiSetImpl.java Tue Jul 10 11:40:39 2007
@@ -0,0 +1,228 @@
+/*
+
+   Derby - Class org.apache.derby.catalog.types.RowMultiSetImpl
+
+   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.catalog.types;
+import org.apache.derby.iapi.services.sanity.SanityManager;
+import org.apache.derby.iapi.services.io.StoredFormatIds;
+import org.apache.derby.iapi.types.DataTypeDescriptor;
+import java.io.ObjectOutput;
+import java.io.ObjectInput;
+import java.io.IOException;
+import java.sql.Types;
+
+/**
+ * <p>
+ * Row data type as described in the 2003 SQL spec
+ * in part 2, section 4.8.
+ * </p>
+ */
+public class RowMultiSetImpl extends BaseTypeIdImpl
+{
+    /********************************************************
+    **
+    **      This class implements Formatable. That means that it
+    **      can write itself to and from a formatted stream. If
+    **      you add more fields to this class, make sure that you
+    **      also write/read them with the writeExternal()/readExternal()
+    **      methods.
+    **
+    **      If, inbetween releases, you add more fields to this class,
+    **      then you should bump the version number emitted by the 
+    **      getTypeFormatId() method.
+    **
+    ********************************************************/
+
+    ///////////////////////////////////////////////////////////////////////////////////
+    //
+    // CONSTANTS
+    //
+    ///////////////////////////////////////////////////////////////////////////////////
+
+    ///////////////////////////////////////////////////////////////////////////////////
+    //
+    // STATE
+    //
+    ///////////////////////////////////////////////////////////////////////////////////
+
+    private String[]                            _columnNames;
+    private DataTypeDescriptor[]    _types;
+
+    ///////////////////////////////////////////////////////////////////////////////////
+    //
+    // CONSTRUCTOR
+    //
+    ///////////////////////////////////////////////////////////////////////////////////
+
+    /**
+     * <p>
+     * 0-arg constructor for Formatable machinery.
+     * </p>
+     */
+    public RowMultiSetImpl()
+    {}
+    
+    /**
+     * <p>
+     * Construct from column names and their types.
+     * </p>
+     */
+    public RowMultiSetImpl( String[] columnNames, DataTypeDescriptor[] types )
+    {
+        _columnNames = columnNames;
+        _types = types;
+
+        if (
+            (columnNames == null ) ||
+            (types == null) ||
+            (columnNames.length != types.length )
+            )
+        {
+            throw new IllegalArgumentException( "Bad args: columnNames = " + columnNames + ". types = " + types );
+        }
+    }
+
+        
+    ///////////////////////////////////////////////////////////////////////////////////
+    //
+    // ACCESSORS
+    //
+    ///////////////////////////////////////////////////////////////////////////////////
+
+    /** Get the names of the columns in this row set */
+    public  String[]    getColumnNames()    { return _columnNames; }
+    
+    /** Get the types of the columns in this row set */
+    public  DataTypeDescriptor[]    getTypes() { return _types; }
+    
+    ///////////////////////////////////////////////////////////////////////////////////
+    //
+    // OVERRIDE BEHAVIOR IN BaseTypeIdImpl
+    //
+    ///////////////////////////////////////////////////////////////////////////////////
+
+    /**
+     * <p>
+     * Get the SQL name of this multi set.
+     * </p>
+     */
+    public  String  getSQLTypeName()
+    {
+        StringBuffer    buffer = new StringBuffer();
+        int                     count = _columnNames.length;
+
+        buffer.append( "ROW ( " );
+
+        for ( int i = 0; i < count; i++ )
+        {
+            if ( i > 0 ) { buffer.append( ", " ); }
+
+            buffer.append( _columnNames[ i ] );
+            buffer.append( ' ' );
+            buffer.append( _types[ i ].getSQLstring() );
+        }
+
+        buffer.append( " ) MULTISET" );
+
+        return buffer.toString();
+    }
+    
+    /**
+     * <p>
+     * Get the corresponding JDBC type.
+     * </p>
+     */
+    public  int getJDBCTypeId()
+    {
+        return Types.OTHER;
+    }
+    
+    /**
+     * Get the format id for the wrapper type id that corresponds to
+     * this type id. Should not be called.
+     */
+    public int wrapperTypeFormatId()
+    {
+        if (SanityManager.DEBUG)
+        {
+            SanityManager.THROWASSERT("RowMultiSetImpl.wrapperTypeFormatId() unexpectedly called. " );
+        }
+        
+        return -1;
+    }
+
+    ///////////////////////////////////////////////////////////////////////////////////
+    //
+    // Formatable BEHAVIOR
+    //
+    ///////////////////////////////////////////////////////////////////////////////////
+
+    /**
+     * <p>
+     * Get the id which indicates which class deserializes us.
+     * </p>
+     */
+    public  int getTypeFormatId()
+    {
+        return StoredFormatIds.ROW_MULTISET_TYPE_ID_IMPL;
+    }
+    
+    /**
+     * <p>
+     * Read ourself from a formatable stream.
+     * </p>
+     */
+    public  void readExternal( ObjectInput in )
+        throws IOException, ClassNotFoundException
+    {
+        int     count = in.readInt();
+
+        _columnNames = new String[ count ];
+        _types = new DataTypeDescriptor[ count ];
+
+        for ( int i = 0; i < count; i++ ) { _columnNames[ i ] = in.readUTF(); }
+        for ( int i = 0; i < count; i++ ) { _types[ i ] = (DataTypeDescriptor) in.readObject(); }
+    }
+
+    /**
+     * <p>
+     * Write ourself to a formatable stream.
+     * </p>
+     */
+    public  void writeExternal( ObjectOutput out )
+        throws IOException
+    {
+        int     count = _columnNames.length;
+
+        out.writeInt( count );
+
+        for ( int i = 0; i < count; i++ ) { out.writeUTF( _columnNames[ i ] ); }
+        for ( int i = 0; i < count; i++ ) { out.writeObject( _types[ i ] ); }
+    }
+
+    ///////////////////////////////////////////////////////////////////////////////////
+    //
+    // MINIONS
+    //
+    ///////////////////////////////////////////////////////////////////////////////////
+
+
+
+}

Propchange: db/derby/code/trunk/java/engine/org/apache/derby/catalog/types/RowMultiSetImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: db/derby/code/trunk/java/engine/org/apache/derby/catalog/types/TypeDescriptorImpl.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/catalog/types/TypeDescriptorImpl.java?view=diff&rev=555032&r1=555031&r2=555032
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/catalog/types/TypeDescriptorImpl.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/catalog/types/TypeDescriptorImpl.java Tue Jul 10 11:40:39 2007
@@ -391,6 +391,14 @@
 		isNullable = nullable;
 	}
 
+	/**
+	* @see TypeDescriptor#isRowMultiSet
+	 */
+	public	boolean isRowMultiSet()
+	{
+		return false;
+	}
+
 	/** @see TypeDescriptor#getCollationType() */
 	public int	getCollationType()
 	{

Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/services/io/RegisteredFormatIds.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/services/io/RegisteredFormatIds.java?view=diff&rev=555032&r1=555031&r2=555032
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/services/io/RegisteredFormatIds.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/services/io/RegisteredFormatIds.java Tue Jul 10 11:40:39 2007
@@ -528,6 +528,8 @@
         /* 464 */   "org.apache.derby.iapi.types.SqlXmlUtil",        
 		/* 465 */   "org.apache.derby.impl.store.raw.data.CompressSpacePageOperation",
         /* 466 */   "org.apache.derby.impl.store.access.btree.index.B2I",
-        /* 467 */   "org.apache.derby.impl.store.access.heap.Heap"
+        /* 467 */   "org.apache.derby.impl.store.access.heap.Heap",
+        /* 468 */       "org.apache.derby.iapi.types.DTSClassInfo",
+        /* 469 */       "org.apache.derby.catalog.types.RowMultiSetImpl"
 };
 }

Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/services/io/StoredFormatIds.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/services/io/StoredFormatIds.java?view=diff&rev=555032&r1=555031&r2=555032
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/services/io/StoredFormatIds.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/services/io/StoredFormatIds.java Tue Jul 10 11:40:39 2007
@@ -879,6 +879,12 @@
     static public final int XML_TYPE_ID_IMPL =
             (MIN_ID_2 + 457);
 
+    public static final int ROW_MULTISET_CATALOG_ID = 
+            (MIN_ID_2 + 468);
+
+    public static final int ROW_MULTISET_TYPE_ID_IMPL = 
+            (MIN_ID_2 + 469);
+    
     /******************************************************************
     **
     **      Execution MODULE CLASSES
@@ -1873,7 +1879,7 @@
      * Make sure this is updated when a new module is added
      */
     public static final int MAX_ID_2 =
-            (MIN_ID_2 + 467);
+            (MIN_ID_2 + 469);
 
     // DO NOT USE 4 BYTE IDS ANYMORE
     static public final int MAX_ID_4 =

Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/AliasDescriptor.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/AliasDescriptor.java?view=diff&rev=555032&r1=555031&r2=555032
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/AliasDescriptor.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/AliasDescriptor.java Tue Jul 10 11:40:39 2007
@@ -25,11 +25,11 @@
 import org.apache.derby.iapi.sql.depend.DependencyManager;
 import org.apache.derby.iapi.sql.depend.Provider;
 import org.apache.derby.iapi.store.access.TransactionController;
-
 import org.apache.derby.iapi.error.StandardException;
 import org.apache.derby.iapi.services.sanity.SanityManager;
 
 import	org.apache.derby.catalog.AliasInfo;
+import org.apache.derby.catalog.types.RoutineAliasInfo;
 
 import org.apache.derby.catalog.UUID;
 
@@ -330,6 +330,19 @@
     public boolean isPersistent()
     {
         return !getSchemaUUID().toString().equals(SchemaDescriptor.SYSFUN_SCHEMA_UUID);
+    }
+   
+    /**
+     * Report whether this descriptor describes a Table Function.
+     *
+     */
+    public boolean isTableFunction()
+    {
+        if ( getAliasType() != AliasInfo.ALIAS_TYPE_FUNCTION_AS_CHAR ) { return false; }
+
+        RoutineAliasInfo    rai = (RoutineAliasInfo) getAliasInfo();
+
+        return rai.getReturnType().isRowMultiSet();
     }
    
     /**

Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/DataDictionary.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/DataDictionary.java?view=diff&rev=555032&r1=555031&r2=555032
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/DataDictionary.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/DataDictionary.java Tue Jul 10 11:40:39 2007
@@ -1759,6 +1759,21 @@
 		throws StandardException;
 
 	/**
+	 * Return the Java class to use for a builtin VTI to which the received
+	 * table descriptor maps.
+	 *
+	 *
+	 * @param td Table descriptor used for the VTI look-up.
+	 * @param asTableFunction If false then treat td's descriptor name as a
+	 *  VTI "table name"; if true, treat the descriptor name as a VTI "table
+	 *  function name".
+	 * @return Java class name of builtin VTI to which "td" maps, or null if no mapping
+	 *  is found.
+	 */
+	public String getBuiltinVTIClass(TableDescriptor td, boolean asTableFunction)
+		throws StandardException;
+
+	/**
 	 * Adds a descriptor to a system catalog identified by the catalogNumber. 
 	 *
 	 * @param tuple			   descriptor to insert.

Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/execute/ResultSetFactory.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/execute/ResultSetFactory.java?view=diff&rev=555032&r1=555031&r2=555032
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/execute/ResultSetFactory.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/execute/ResultSetFactory.java Tue Jul 10 11:40:39 2007
@@ -641,6 +641,7 @@
 		@param optimizerEstimatedRowCount	Estimated total # of rows by
 											optimizer
 		@param optimizerEstimatedCost		Estimated total cost by optimizer
+		@param isDerbyStyleTableFunction    True if this is a Derby-style table function
 		@return the row as a result set.
 		@exception StandardException thrown when unable to create the
 			result set
@@ -656,7 +657,9 @@
 									 boolean isTarget,
 									 int scanIsolationLevel,
 									 double optimizerEstimatedRowCount,
-									 double optimizerEstimatedCost)
+									 double optimizerEstimatedCost,
+									 boolean isDerbyStyleTableFunction
+                                          )
 		 throws StandardException;
 
 	/**

Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/DTSClassInfo.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/DTSClassInfo.java?view=diff&rev=555032&r1=555031&r2=555032
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/DTSClassInfo.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/DTSClassInfo.java Tue Jul 10 11:40:39 2007
@@ -64,6 +64,7 @@
                 case StoredFormatIds.CLOB_TYPE_ID:
                 case StoredFormatIds.NCLOB_TYPE_ID:
                 case StoredFormatIds.XML_TYPE_ID:
+                case StoredFormatIds.ROW_MULTISET_CATALOG_ID:
                         return new TypeId(fmtId);
                 default:
                         return null;

Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/DataTypeDescriptor.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/DataTypeDescriptor.java?view=diff&rev=555032&r1=555031&r2=555032
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/DataTypeDescriptor.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/DataTypeDescriptor.java Tue Jul 10 11:40:39 2007
@@ -28,6 +28,8 @@
 import java.text.RuleBasedCollator;
 
 import org.apache.derby.catalog.TypeDescriptor;
+import org.apache.derby.catalog.types.BaseTypeIdImpl;
+import org.apache.derby.catalog.types.RowMultiSetImpl;
 import org.apache.derby.catalog.types.TypeDescriptorImpl;
 import org.apache.derby.iapi.error.StandardException;
 import org.apache.derby.iapi.reference.SQLState;
@@ -252,6 +254,26 @@
 											maximumWidth);
 	}
     
+	/**
+	 * Get a DataTypeServices that corresponds to a SQL Row Multiset
+	 *
+	 * @param columnNames   Names of the columns in the Row Muliset
+	 * @param types                 Types of the columns in the Row Muliset
+	 *
+	 * @return	A new DataTypeDescriptor describing the SQL Row Multiset
+	 */
+	public static DataTypeDescriptor getRowMultiSet
+	(
+		String[]	                        columnNames,
+		DataTypeDescriptor[]	types
+	)
+	{
+		RowMultiSetImpl       rms = new RowMultiSetImpl( columnNames, types );
+		TypeId              typeID = new TypeId( StoredFormatIds.ROW_MULTISET_CATALOG_ID, rms );
+
+		return new DataTypeDescriptor( typeID, true);
+	}
+
 	/*
 	** Instance fields & methods
 	*/
@@ -928,6 +950,14 @@
 	public int	getCollationDerivation()
 	{
 		return typeDescriptor.getCollationDerivation();
+	}
+
+	/**
+	* @see TypeDescriptor#isRowMultiSet
+	 */
+	public	boolean isRowMultiSet()
+	{
+		return getTypeId().isRowMultiSetTypeId();
 	}
 
     /**

Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/TypeId.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/TypeId.java?view=diff&rev=555032&r1=555031&r2=555032
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/TypeId.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/TypeId.java Tue Jul 10 11:40:39 2007
@@ -1204,6 +1204,17 @@
                return (formatId == StoredFormatIds.XML_TYPE_ID);
         }
 
+        /** 
+         *Is this a ROW MULTISET?
+         * @return true if this is XML
+         */
+        public boolean isRowMultiSetTypeId()
+        {
+               return (formatId == StoredFormatIds.ROW_MULTISET_CATALOG_ID);
+        }
+
+
+	
         /**
          * Tell whether this type is orderable, that is, can participate
          * in comparisons.

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/catalog/DataDictionaryImpl.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/catalog/DataDictionaryImpl.java?view=diff&rev=555032&r1=555031&r2=555032
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/catalog/DataDictionaryImpl.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/catalog/DataDictionaryImpl.java Tue Jul 10 11:40:39 2007
@@ -11233,43 +11233,59 @@
 	public String getVTIClass(TableDescriptor td, boolean asTableFunction)
 		throws StandardException
 	{
+		if (SchemaDescriptor.STD_SYSTEM_DIAG_SCHEMA_NAME.equals(
+			td.getSchemaName()))
+		{ return getBuiltinVTIClass( td, asTableFunction ); }
+		else // see if it's a user-defined table function
+		{
+		    String                          schemaName = td.getSchemaName();
+		    String                          functionName = td.getDescriptorName();
+		    SchemaDescriptor     sd = getSchemaDescriptor( td.getSchemaName(), null, true );
+
+		    if ( sd != null )
+		    {
+		        AliasDescriptor         ad = getAliasDescriptor( sd.getUUID().toString(), functionName, AliasInfo.ALIAS_TYPE_FUNCTION_AS_CHAR );
+
+		        if ( (ad != null) && ad.isTableFunction() ) { return ad.getJavaClassName(); }
+
+		        throw StandardException.newException
+		        ( SQLState.LANG_NOT_TABLE_FUNCTION, schemaName, functionName );
+		    }
+		}
+		
+		return null;
+	}
+
+	/**
+	 * @see DataDictionary#getBuiltinVTIClass(TableDescriptor, boolean)
+	 */
+	public String getBuiltinVTIClass(TableDescriptor td, boolean asTableFunction)
+		throws StandardException
+	{
 		if (SanityManager.DEBUG)
 		{
 			if (td.getTableType() != TableDescriptor.VTI_TYPE)
 				SanityManager.THROWASSERT("getVTIClass: Invalid table type " + td);
 		}
 		
-		/* For now we only recognize VTI table (or table function) names
-		 * that are in the "SYSCS_DIAG" schema; for anything else just
-		 * return null.  Note that if no schema was specified then the
+		/* First check to see if this is a system VTI. Note that if no schema was specified then the
 		 * call to "td.getSchemaName()" will return the current schema.
 		 */
-		if (!SchemaDescriptor.STD_SYSTEM_DIAG_SCHEMA_NAME.equals(
+		if (SchemaDescriptor.STD_SYSTEM_DIAG_SCHEMA_NAME.equals(
 			td.getSchemaName()))
 		{
-			return null;
+		    String [][] vtiMappings = asTableFunction
+		        ? DIAG_VTI_TABLE_FUNCTION_CLASSES
+		        : DIAG_VTI_TABLE_CLASSES;
+
+		    for (int i = 0; i < vtiMappings.length; i++)
+		    {
+		        String[] entry = vtiMappings[i];
+		        if (entry[0].equals(td.getDescriptorName()))
+		            return entry[1];	
+		    }	
 		}
-
-		String [][] vtiMappings = asTableFunction
-			? DIAG_VTI_TABLE_FUNCTION_CLASSES
-			: DIAG_VTI_TABLE_CLASSES;
-
-		for (int i = 0; i < vtiMappings.length; i++)
-		{
-			String[] entry = vtiMappings[i];
-			if (entry[0].equals(td.getDescriptorName()))
-				return entry[1];	
-		}	
 		
 		return null;
 	}
 }
-
-
-
-
-
-
-
-
-

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/FromVTI.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/FromVTI.java?view=diff&rev=555032&r1=555031&r2=555032
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/FromVTI.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/FromVTI.java Tue Jul 10 11:40:39 2007
@@ -51,6 +51,7 @@
 import org.apache.derby.iapi.sql.dictionary.ColumnDescriptorList;
 import org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor;
 import org.apache.derby.iapi.sql.dictionary.TableDescriptor;
+import org.apache.derby.iapi.types.DataTypeDescriptor;
 
 import org.apache.derby.iapi.reference.ClassName;
 import org.apache.derby.iapi.reference.JDBC20Translation;
@@ -58,7 +59,10 @@
 
 import org.apache.derby.iapi.sql.Activation;
 
+import org.apache.derby.catalog.TypeDescriptor;
 import org.apache.derby.catalog.UUID;
+import org.apache.derby.catalog.types.RoutineAliasInfo;
+import org.apache.derby.catalog.types.RowMultiSetImpl;
 
 import org.apache.derby.vti.DeferModification;
 import org.apache.derby.vti.VTICosting;
@@ -97,13 +101,14 @@
 
 	JBitSet				correlationMap;
 	JBitSet				dependencyMap;
-	NewInvocationNode	newInvocation;
+	MethodCallNode	methodCall;
 	TableName			exposedName;
 	SubqueryList subqueryList;
 	boolean				implementsVTICosting;
 	boolean				optimized;
 	boolean				materializable;
 	boolean				isTarget;
+	boolean				isDerbyStyleTableFunction;
 	ResultSet			rs;
 
 	private	FormatableHashtable	compileTimeConstants;
@@ -147,7 +152,7 @@
     private int resultSetType = ResultSet.TYPE_FORWARD_ONLY;
 
     /**
-	 * @param newInvocation		The constructor for the VTI
+	 * @param invocation		The constructor or static method for the VTI
 	 * @param correlationName	The correlation name
 	 * @param derivedRCL		The derived column list
 	 * @param tableProperties	Properties list associated with the table
@@ -155,13 +160,13 @@
 	 * @exception StandardException		Thrown on error
 	 */
 	public void init(
-					Object newInvocation,
+					Object invocation,
 					Object correlationName,
 					Object derivedRCL,
 					Object tableProperties)
 		throws StandardException
 	{
-        init( newInvocation,
+        init( invocation,
               correlationName,
               derivedRCL,
               tableProperties,
@@ -169,7 +174,7 @@
 	}
 
     /**
-	 * @param newInvocation		The constructor for the VTI
+	 * @param invocation		The constructor or static method for the VTI
 	 * @param correlationName	The correlation name
 	 * @param derivedRCL		The derived column list
 	 * @param tableProperties	Properties list associated with the table
@@ -178,7 +183,7 @@
 	 * @exception StandardException		Thrown on error
 	 */
 	public void init(
-					Object newInvocation,
+					Object invocation,
 					Object correlationName,
 					Object derivedRCL,
 					Object tableProperties,
@@ -186,7 +191,9 @@
 		throws StandardException
 	{
 		super.init(correlationName, tableProperties);
-		this.newInvocation = (NewInvocationNode) newInvocation;
+
+		this.methodCall = (MethodCallNode) invocation;
+
 		resultColumns = (ResultColumnList) derivedRCL;
 		subqueryList = (SubqueryList) getNodeFactory().getNode(
 											C_NodeTypes.SUBQUERY_LIST,
@@ -408,10 +415,10 @@
 		if (SanityManager.DEBUG) {
 			super.printSubNodes(depth);
 
-			if (newInvocation != null)
+			if (methodCall != null)
 			{
-				printLabel(depth, "newInvocation: ");
-				newInvocation.treePrint(depth + 1);
+				printLabel(depth, "methodCall: ");
+				methodCall.treePrint(depth + 1);
 			}
 
 			if (exposedName != null)
@@ -429,13 +436,19 @@
 	}
 
 	/** 
-	 * Return the new invocation from this node.
-	 *
-	 * @return ResultSetNode	The new invocation from this node.
+	 * Return true if this VTI is a constructor. Otherwise, it is a static method.
 	 */
-	public NewInvocationNode getNewInvocation()
+	public boolean  isConstructor()
 	{
-		return newInvocation;
+		return ( methodCall instanceof NewInvocationNode );
+	}
+
+	/** 
+	 * Return the constructor or static method invoked from this node
+	 */
+	public MethodCallNode getMethodCall()
+	{
+		return methodCall;
 	}
 
 	/**
@@ -496,7 +509,7 @@
      */
     String getVTIName()
     {
-        return newInvocation.getJavaClassName();
+        return methodCall.getJavaClassName();
     } // end of getVTIName
 
 	/**
@@ -521,54 +534,59 @@
 		 * parameters.
 		 */
 
-		/* Bind the constructor - does basic error checking.
+		/* Bind the constructor or static method - does basic error checking.
 		 * Correlated subqueries are not allowed as parameters to
 		 * a VTI, so pass an empty FromList.
 		 */
 		Vector aggregateVector = new Vector();
-		newInvocation.bindExpression(fromListParam,
+		methodCall.bindExpression(fromListParam,
 									 subqueryList,
 									 aggregateVector);
 
-		/* We have a valid constructor.  Does class implement the correct interface? 
+		/* If we have a valid constructor, does class implement the correct interface? 
 		 * If version2 is true, then it must implement PreparedStatement, otherwise
 		 * it can implement either PreparedStatement or ResultSet.  (We check for
 		 * PreparedStatement first.)
 		 */
 
-		if (!newInvocation.assignableTo("java.sql.PreparedStatement"))
+		if ( isConstructor() )
 		{
+		    NewInvocationNode   constructor = (NewInvocationNode) methodCall;
+                
+		    if (!constructor.assignableTo("java.sql.PreparedStatement"))
+		    {
 			if (version2)
 			{
 				throw StandardException.newException(SQLState.LANG_DOES_NOT_IMPLEMENT, 
 										getVTIName(),
 										"java.sql.PreparedStatement");
 			}
-			else if (! newInvocation.assignableTo("java.sql.ResultSet"))
+			else if (! constructor.assignableTo("java.sql.ResultSet"))
 			{
 				throw StandardException.newException(SQLState.LANG_DOES_NOT_IMPLEMENT, 
 										getVTIName(),
 										"java.sql.ResultSet");
 			}
-		}
-		else
-		{
-			version2 = true;
-		}
+		    }
+		    else
+		    {
+			    version2 = true;
+		    }
         
-		/* If this is a version 2 VTI */
-		if (version2)
-		{
+		    /* If this is a version 2 VTI */
+		    if (version2)
+		    {
 			// Does it support predicates
-			implementsPushable = newInvocation.assignableTo("org.apache.derby.vti.IQualifyable");
+			implementsPushable = constructor.assignableTo("org.apache.derby.vti.IQualifyable");
+		    }
+		    // Remember whether or not the VTI implements the VTICosting interface
+		    implementsVTICosting = constructor.assignableTo(ClassName.VTICosting);
 		}
 
-		// Remember whether or not the VTI implements the VTICosting interface
-		implementsVTICosting = newInvocation.assignableTo(ClassName.VTICosting);
 
 
 		// Is the parameter list to the constructor valid for a VTI?
-		methodParms = newInvocation.getMethodParms();
+		methodParms = methodCall.getMethodParms();
 
 		/* Build the RCL for this VTI.  We instantiate an object in order
 		 * to get the ResultSetMetaData.
@@ -578,7 +596,7 @@
 		 * the compiler context.
 		 */
 		UUID triggerTableId;
-		if ((triggerTableId = getSpecialTriggerVTITableName(lcc, newInvocation.getJavaClassName())) != null)	
+		if ((isConstructor()) && ((triggerTableId = getSpecialTriggerVTITableName(lcc, methodCall.getJavaClassName())) != null)  )
 		{
 			TableDescriptor td = getDataDictionary().getTableDescriptor(triggerTableId);
 			resultColumns = genResultColList(td);
@@ -591,32 +609,49 @@
 		}
 		else
 		{	
-			ResultSetMetaData rsmd = getResultSetMetaData();
-	
-			/* Wouldn't it be nice if we knew that the class/object would never
-			 * return a null ResultSetMetaData.
-			 */
-			if (rsmd == null)
+			resultColumns = (ResultColumnList) getNodeFactory().getNode(
+												C_NodeTypes.RESULT_COLUMN_LIST,
+												getContextManager());
+
+			// if this is a Derby-style Table Function, then build the result
+			// column list from the RowMultiSetImpl return datatype
+			RoutineAliasInfo    routineInfo = methodCall.getRoutineInfo();
+
+			if (
+			     (routineInfo !=null) &&
+			     routineInfo.getReturnType().isRowMultiSet() &&
+			     (routineInfo.getParameterStyle() == RoutineAliasInfo.PS_DERBY_JDBC_RESULT_SET)
+			    )			{
+			    isDerbyStyleTableFunction = true;
+			    createResultColumnsForTableFunction( routineInfo.getReturnType() );
+			}
+			else
 			{
+            
+			    ResultSetMetaData rsmd = getResultSetMetaData();
+	
+			    /* Wouldn't it be nice if we knew that the class/object would never
+			     * return a null ResultSetMetaData.
+			     */
+			    if (rsmd == null)
+			    {
 				throw StandardException.newException(SQLState.LANG_NULL_RESULT_SET_META_DATA, 
 											getVTIName());
-			}
+			    }
 	
-			// Remember how many columns VTI returns for partial row calculation
-			try
-			{
+			    // Remember how many columns VTI returns for partial row calculation
+			    try
+			    {
 				numVTICols = rsmd.getColumnCount();
-			}
-			catch (SQLException sqle)
-			{
+			    }
+			    catch (SQLException sqle)
+			    {
 				numVTICols = 0;
-			}
+			    }
 
-			resultColumns = (ResultColumnList) getNodeFactory().getNode(
-												C_NodeTypes.RESULT_COLUMN_LIST,
-												getContextManager());
-			resultColumns.createListFromResultSetMetaData(rsmd, exposedName, 
-														  newInvocation.getJavaClassName());
+			    resultColumns.createListFromResultSetMetaData(rsmd, exposedName, 
+														  getVTIName() );
+			}
 		}
 		numVTICols = resultColumns.size();
 	
@@ -705,7 +740,8 @@
     private Object getNewInstance()
         throws StandardException
     {
-		Class[]  paramTypeClasses = newInvocation.getMethodParameterClasses();
+		NewInvocationNode   constructor = (NewInvocationNode) methodCall;
+		Class[]  paramTypeClasses = constructor.getMethodParameterClasses();
 		Object[] paramObjects = null;
 
 		if (paramTypeClasses != null)
@@ -781,10 +817,10 @@
         try
         {
             ClassInspector classInspector = getClassFactory().getClassInspector();
-            String javaClassName = newInvocation.getJavaClassName();
-            Constructor constructor = classInspector.getClass(javaClassName).getConstructor(paramTypeClasses);
+            String javaClassName = methodCall.getJavaClassName();
+            Constructor constr = classInspector.getClass(javaClassName).getConstructor(paramTypeClasses);
 
-            return constructor.newInstance(paramObjects);
+            return constr.newInstance(paramObjects);
         }
 		catch(Throwable t)
 		{
@@ -846,7 +882,7 @@
 		 * then the VTI is a candidate for materialization at execution time
 		 * if it is the inner table of a join or in a subquery.
 		 */
-		materializable = newInvocation.areParametersQueryInvariant();
+		materializable = methodCall.areParametersQueryInvariant();
 
 		/* NOTE: We need to rebind any ColumnReferences that are parameters and are
 		 * from other VTIs that appear after this one in the FROM list.
@@ -887,7 +923,7 @@
 		throws StandardException
 	{
 		CollectNodesVisitor getCRs = new CollectNodesVisitor(nodeClass);
-		newInvocation.accept(getCRs);
+		methodCall.accept(getCRs);
 		return getCRs.getList();
 	}
 
@@ -1025,7 +1061,7 @@
 									FromList fromList)
 								throws StandardException
 	{
-		newInvocation.preprocess(
+		methodCall.preprocess(
 								numTables,
 								(FromList) getNodeFactory().getNode(
 									C_NodeTypes.FROM_LIST,
@@ -1040,7 +1076,7 @@
 		/* Generate the referenced table map */
 		referencedTableMap = new JBitSet(numTables);
 		referencedTableMap.set(tableNumber);
-		newInvocation.categorize(referencedTableMap, false);
+		methodCall.categorize(referencedTableMap, false);
 
 		// Create the dependency map
 		dependencyMap = new JBitSet(numTables);
@@ -1054,7 +1090,7 @@
 
 		// Get a JBitSet of the outer tables represented in the parameter list
 		correlationMap = new JBitSet(numTables);
-		newInvocation.getCorrelationTables(correlationMap);
+		methodCall.getCorrelationTables(correlationMap);
 
 		return genProjectRestrict(numTables);
 	}
@@ -1168,7 +1204,7 @@
 		 * join row since the join row hasn't been filled in yet.
 		 */
 		RemapCRsVisitor rcrv = new RemapCRsVisitor(true);
-		newInvocation.accept(rcrv);
+		methodCall.accept(rcrv);
 
 		/* Get the next ResultSet #, so that we can number this ResultSetNode, its
 		 * ResultColumnList and ResultSet.
@@ -1239,7 +1275,7 @@
 		generateConstructor(acb, mb, reuseablePs); // arg 4
 
 		// Pass in the class name
-		mb.push(newInvocation.getJavaClassName()); // arg 5
+		mb.push(methodCall.getJavaClassName()); // arg 5
 
 		if (restrictionList != null) {
 			restrictionList.generateQualifiers(acb, mb, this, true);
@@ -1269,7 +1305,10 @@
 		// estimated cost
 		mb.push(costEstimate.getEstimatedCost());
 
-		return 14;
+		// Whether or not this is a Derby-style Table Function
+		mb.push(isDerbyStyleTableFunction);
+
+		return 15;
 	}
 
 	private void generateConstructor(ActivationClassBuilder acb,
@@ -1296,7 +1335,7 @@
 			userExprFun.conditionalIfNull();
 		}
 
-		newInvocation.generateExpression(acb, userExprFun);
+		methodCall.generateExpression(acb, userExprFun);
         userExprFun.upCast(vtiType);
 
 		if (reuseablePs) {
@@ -1314,7 +1353,7 @@
 
 
 
-		// newInvocation knows it is returning its value;
+		// methodCall knows it is returning its value;
 
 		/* generates:
 		 *    return <newInvocation.generate(acb)>;
@@ -1365,7 +1404,7 @@
 	public boolean referencesTarget(String name, boolean baseTable)
 		throws StandardException
 	{
-		return (! baseTable) && name.equals(newInvocation.getJavaClassName());
+		return (! baseTable) && name.equals(methodCall.getJavaClassName());
 	}
 
 	/**
@@ -1388,7 +1427,7 @@
 
 		if (!v.stopTraversal())
 		{
-			newInvocation = (NewInvocationNode) newInvocation.accept(v);
+			methodCall = (MethodCallNode) methodCall.accept(v);
 		}
 
 		return returnNode;
@@ -1539,4 +1578,24 @@
 
 		return compileTimeConstants.get(key);
 	}
+
+    /**
+     * Add result columns for a Derby-style Table Function
+     */
+    private void    createResultColumnsForTableFunction
+        (TypeDescriptor td)
+        throws StandardException
+    {
+        DataTypeDescriptor      returnType = (DataTypeDescriptor) td;
+        RowMultiSetImpl         rmsi = (RowMultiSetImpl) returnType.getTypeId().getBaseTypeId();
+        String[]                        columnNames = rmsi.getColumnNames();
+        DataTypeDescriptor[]    types = rmsi.getTypes();
+        int                                     count = columnNames.length;
+        
+        for ( int i = 0; i < count; i++ )
+        {
+            resultColumns.addColumn( exposedName, columnNames[ i ], types[ i ] );
+        }
+
+    }
 }

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/MethodCallNode.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/MethodCallNode.java?view=diff&rev=555032&r1=555031&r2=555032
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/MethodCallNode.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/MethodCallNode.java Tue Jul 10 11:40:39 2007
@@ -58,6 +58,7 @@
 import java.lang.reflect.Modifier;
 import java.lang.reflect.Member;
 
+import java.util.Enumeration;
 import java.util.StringTokenizer;
 import java.util.Vector;
 
@@ -139,6 +140,14 @@
         return javaClassName;
     }
 
+    /**
+     * Get the details on the invoked routines.
+     */
+    public RoutineAliasInfo getRoutineInfo()
+    {
+        return routineInfo;
+    }
+
 	/**
 	 * Add the parameter list
 	 *
@@ -176,6 +185,61 @@
 	}
 
 	/**
+	  *	Get the resolved Classes of our parameters
+	  *
+	  *	@return	the Classes of our parameters
+	  */
+	public	Class[]	getMethodParameterClasses() 
+	{ 
+		ClassInspector ci = getClassFactory().getClassInspector();
+
+		Class[]	parmTypeClasses = new Class[methodParms.length];
+		for (int i = 0; i < methodParms.length; i++)
+		{
+			String className = methodParameterTypes[i];
+			try
+			{
+				parmTypeClasses[i] = ci.getClass(className);
+			}
+			catch (ClassNotFoundException cnfe)
+			{
+				/* We should never get this exception since we verified 
+				 * that the classes existed at bind time.  Just return null.
+				 */
+				if (SanityManager.DEBUG)
+				{
+					SanityManager.THROWASSERT("Unexpected exception", cnfe);
+				}
+				return null;
+			}
+		}
+
+		return parmTypeClasses;
+	}
+
+	/**
+	 * Build a JBitSet of all of the tables that we are
+	 * correlated with.
+	 *
+	 * @param correlationMap	The JBitSet of the tables that we are correlated with.
+	 */
+	void getCorrelationTables(JBitSet correlationMap)
+		throws StandardException
+	{
+		CollectNodesVisitor getCRs = new CollectNodesVisitor(ColumnReference.class);
+		super.accept(getCRs);
+		Vector colRefs = getCRs.getList();
+		for (Enumeration e = colRefs.elements(); e.hasMoreElements(); )
+		{
+			ColumnReference ref = (ColumnReference)e.nextElement();
+			if (ref.getCorrelated())
+			{
+				correlationMap.set(ref.getTableNumber());
+			}
+		}
+	}
+
+	/**
 	 * Prints the sub-nodes of this object.  See QueryTreeNode.java for
 	 * how tree printing is supposed to work.
 	 *
@@ -705,25 +769,35 @@
 
 				
 				TypeId returnTypeId = TypeId.getBuiltInTypeId(returnType.getJDBCTypeId());
-				switch (returnType.getJDBCTypeId()) {
-				case java.sql.Types.SMALLINT:
-				case java.sql.Types.INTEGER:
-				case java.sql.Types.BIGINT:
-				case java.sql.Types.REAL:
-				case java.sql.Types.DOUBLE:
-					TypeCompiler tc = getTypeCompiler(returnTypeId);
-					requiredType = tc.getCorrespondingPrimitiveTypeName();
-					if (!routineInfo.calledOnNullInput() && routineInfo.getParameterCount() != 0)
-					{
-						promoteName = returnTypeId.getCorrespondingJavaTypeName();
-					}
 
-					break;
-				default:
-					requiredType = returnTypeId.getCorrespondingJavaTypeName();
-					break;
+				if (
+				    returnType.isRowMultiSet() &&
+				    ( routineInfo.getParameterStyle() == RoutineAliasInfo.PS_DERBY_JDBC_RESULT_SET )
+				)
+				{
+				    requiredType = "java.sql.ResultSet";
+				}
+				else
+				{
+				    switch (returnType.getJDBCTypeId()) {
+				    case java.sql.Types.SMALLINT:
+				    case java.sql.Types.INTEGER:
+				    case java.sql.Types.BIGINT:
+				    case java.sql.Types.REAL:
+				    case java.sql.Types.DOUBLE:
+				    	TypeCompiler tc = getTypeCompiler(returnTypeId);
+				    	requiredType = tc.getCorrespondingPrimitiveTypeName();
+				    	if (!routineInfo.calledOnNullInput() && routineInfo.getParameterCount() != 0)
+				    	{
+				    		promoteName = returnTypeId.getCorrespondingJavaTypeName();
+				    	}
+
+				    	break;
+				    default:
+				    	requiredType = returnTypeId.getCorrespondingJavaTypeName();
+				    	break;
+				    }
 				}
-
 			}
 
 			if (!requiredType.equals(typeName))

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/NewInvocationNode.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/NewInvocationNode.java?view=diff&rev=555032&r1=555031&r2=555032
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/NewInvocationNode.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/NewInvocationNode.java Tue Jul 10 11:40:39 2007
@@ -63,6 +63,8 @@
 
 	private boolean delimitedIdentifier;
 
+	private boolean isBuiltinVTI = false;
+
 	/**
 	 * Initializer for a NewInvocationNode. Parameters are:
 	 *
@@ -161,6 +163,9 @@
 		this.javaClassName = getDataDictionary().getVTIClass(
 			td, isTableFunctionVTI);
 
+		this.isBuiltinVTI =
+		    ( getDataDictionary().getBuiltinVTIClass( td, isTableFunctionVTI) != null);
+
 		/* If javaClassName is still null at this point then we
 		 * could not find the target class for the received table
 		 * (or table function) name.  So throw the appropriate
@@ -190,6 +195,11 @@
 	}
 
 	/**
+	 * Report whether this node represents a builtin VTI.
+	 */
+	public  boolean isBuiltinVTI()  { return isBuiltinVTI; }
+
+	/**
 	 * Mark this node as only needing to
 	 * to a single instantiation.  (We can
 	 * reuse the object after newing it.)
@@ -200,39 +210,6 @@
 	}
 
 	/**
-	  *	Get the resolved Classes of our parameters
-	  *
-	  *	@return	the Classes of our parameters
-	  */
-	public	Class[]	getMethodParameterClasses() 
-	{ 
-		ClassInspector ci = getClassFactory().getClassInspector();
-
-		Class[]	parmTypeClasses = new Class[methodParms.length];
-		for (int i = 0; i < methodParms.length; i++)
-		{
-			String className = methodParameterTypes[i];
-			try
-			{
-				parmTypeClasses[i] = ci.getClass(className);
-			}
-			catch (ClassNotFoundException cnfe)
-			{
-				/* We should never get this exception since we verified 
-				 * that the classes existed at bind time.  Just return null.
-				 */
-				if (SanityManager.DEBUG)
-				{
-					SanityManager.THROWASSERT("Unexpected exception", cnfe);
-				}
-				return null;
-			}
-		}
-
-		return parmTypeClasses;
-	}
-
-	/**
 	 * Bind this expression.  This means binding the sub-expressions,
 	 * as well as figuring out what the return type is for this expression.
 	 *
@@ -378,28 +355,6 @@
 		pushable = pushable && super.categorize(referencedTabs, simplePredsOnly);
 
 		return pushable;
-	}
-
-	/**
-	 * Build a JBitSet of all of the tables that we are
-	 * correlated with.
-	 *
-	 * @param correlationMap	The JBitSet of the tables that we are correlated with.
-	 */
-	void getCorrelationTables(JBitSet correlationMap)
-		throws StandardException
-	{
-		CollectNodesVisitor getCRs = new CollectNodesVisitor(ColumnReference.class);
-		super.accept(getCRs);
-		Vector colRefs = getCRs.getList();
-		for (Enumeration e = colRefs.elements(); e.hasMoreElements(); )
-		{
-			ColumnReference ref = (ColumnReference)e.nextElement();
-			if (ref.getCorrelated())
-			{
-				correlationMap.set(ref.getTableNumber());
-			}
-		}
 	}
 
 	/**

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ResultColumnList.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ResultColumnList.java?view=diff&rev=555032&r1=555031&r2=555032
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ResultColumnList.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ResultColumnList.java Tue Jul 10 11:40:39 2007
@@ -836,7 +836,7 @@
 			{
 				throw StandardException.newException(SQLState.LANG_COLUMN_NOT_FOUND_IN_TABLE, 
 													 rc.getName(), 
-													 targetVTI.getNewInvocation().getJavaClassName());
+													 targetVTI.getMethodCall().getJavaClassName());
 			}
 
 			/* We have a match.  We need to create a dummy ColumnDescriptor
@@ -3286,19 +3286,7 @@
 											scale, 
 											nullableResult, 
 											maxWidth);
-				ValueNode bcn = (ValueNode) getNodeFactory().getNode(
-											C_NodeTypes.BASE_COLUMN_NODE,
-											rsmd.getColumnName(index),
-									  		tableName,
-											dts,
-											getContextManager());
-				ResultColumn rc = (ResultColumn) getNodeFactory().getNode(
-										C_NodeTypes.RESULT_COLUMN,
-										rsmd.getColumnName(index),
-										bcn,
-										getContextManager());
-				rc.setType(dts);
-				addResultColumn(rc);
+				addColumn( tableName, rsmd.getColumnName(index), dts );
 			}
 		}
 		catch (Throwable t)
@@ -3314,6 +3302,28 @@
 		}
 	}
 
+    /** 
+     * Add a column to the list given a tablename, columnname, and datatype.
+     *
+     */
+    public void addColumn( TableName tableName, String columnName, DataTypeDescriptor dts )
+        throws StandardException
+    {
+        ValueNode bcn = (ValueNode) getNodeFactory().getNode(
+                                                             C_NodeTypes.BASE_COLUMN_NODE,
+                                                             columnName,
+                                                             tableName,
+                                                             dts,
+                                                             getContextManager());
+        ResultColumn rc = (ResultColumn) getNodeFactory().getNode(
+                                                                  C_NodeTypes.RESULT_COLUMN,
+                                                                  columnName,
+                                                                  bcn,
+                                                                  getContextManager());
+        rc.setType(dts);
+        addResultColumn(rc);
+    }
+    
 	/**
 	 * Add an RC to the end of the list for the RID from an index.
 	 * NOTE: RC.expression is a CurrentRowLocationNode.  This was previously only used

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/StaticMethodCallNode.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/StaticMethodCallNode.java?view=diff&rev=555032&r1=555031&r2=555032
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/StaticMethodCallNode.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/StaticMethodCallNode.java Tue Jul 10 11:40:39 2007
@@ -263,7 +263,7 @@
 				optimizeDomainValueConversion();
 			
 			TypeDescriptor returnType = routineInfo.getReturnType();
-			if (returnType != null)
+			if (returnType != null && !returnType.isRowMultiSet())
 			{
 				TypeId returnTypeId = TypeId.getBuiltInTypeId(returnType.getJDBCTypeId());
 

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/VTIDeferModPolicy.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/VTIDeferModPolicy.java?view=diff&rev=555032&r1=555031&r2=555032
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/VTIDeferModPolicy.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/VTIDeferModPolicy.java Tue Jul 10 11:40:39 2007
@@ -70,7 +70,7 @@
             deferralControl = targetVTI.getDeferralControl();
             if( deferralControl == null)
             {
-                String VTIClassName = targetVTI.getNewInvocation().getJavaClassName();
+                String VTIClassName = targetVTI.getMethodCall().getJavaClassName();
                 deferralControl = new DefaultVTIModDeferPolicy( VTIClassName,
                                                                 ResultSet.TYPE_SCROLL_SENSITIVE == resultSetType);
             }
@@ -182,7 +182,7 @@
                     {
                         FromVTI fromVTI = (FromVTI) fromTable;
                         if( deferralControl.subselectRequiresDefer( statementType,
-                                                                    fromVTI.getNewInvocation().getJavaClassName()))
+                                                                    fromVTI.getMethodCall().getJavaClassName()))
                             deferred = true;
                     }
                 }

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?view=diff&rev=555032&r1=555031&r2=555032
==============================================================================
--- 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 10 11:40:39 2007
@@ -2256,6 +2256,7 @@
 |   <CS: "cs">
 |	<CURSORS: "cursors">
 |	<DB2SQL: "db2sql">
+|	<DERBY_JDBC_RESULT_SET: "derby_jdbc_result_set">
 |       <DIRTY: "dirty">
 |	<DOCUMENT: "document">
 |	<EACH: "each">
@@ -7436,9 +7437,12 @@
 JavaToSQLValueNode
 vtiTableConstruct() throws StandardException :
 {
-    QueryTreeNode newNode = null;
+    NewInvocationNode newNode = null;
+    QueryTreeNode invocationNode = null;
     Vector parameterList = new Vector();
     TableName vtiTableName = null;
+    TableDescriptor td;
+    MethodCallNode	methodNode;
 }
 {
     <TABLE> <LEFT_PAREN>
@@ -7446,19 +7450,35 @@
         methodCallParameterList(parameterList)
     <RIGHT_PAREN>
     {
-		/* The fact that we pass a NULL table descriptor to the
-		 * following call is an indication that we are mapping to a
-		 * VTI table function (i.e. one that accepts arguments).
-		 * Since we have the table name we do not need to pass in a
-		 * TableDescriptor--we'll just create one from the table
-		 * name. See NewInvocationNode for more.
-		 */
-        newNode = nodeFactory.getNode(C_NodeTypes.NEW_INVOCATION_NODE,
-                    vtiTableName,  // TableName
-                    null,          // TableDescriptor
-                    parameterList, 
-                    lastTokenDelimitedIdentifier,
-                    getContextManager());
+        /* The fact that we pass a NULL table descriptor to the
+        * following call is an indication that we are mapping to a
+        * VTI table function (i.e. one that accepts arguments).
+        * Since we have the table name we do not need to pass in a
+        * TableDescriptor--we'll just create one from the table
+        * name. See NewInvocationNode for more.
+        */
+        newNode = (NewInvocationNode) nodeFactory.getNode
+        (
+            C_NodeTypes.NEW_INVOCATION_NODE,
+            vtiTableName,  // TableName
+            null,          // TableDescriptor
+            parameterList, 
+            lastTokenDelimitedIdentifier,
+            getContextManager());
+
+        if ( newNode.isBuiltinVTI() ) { invocationNode = newNode; }
+        else
+        {
+            methodNode = (MethodCallNode) nodeFactory.getNode(
+                C_NodeTypes.STATIC_METHOD_CALL_NODE,
+                vtiTableName,
+                null,
+                getContextManager());
+            methodNode.addParms(parameterList);
+
+            invocationNode = methodNode;
+        }
+
 
         /*
         ** Assume this is being returned to the SQL domain.  If it turns
@@ -7467,7 +7487,7 @@
         */
         return (JavaToSQLValueNode) nodeFactory.getNode(
                     C_NodeTypes.JAVA_TO_SQL_VALUE_NODE,
-                    newNode,
+                    invocationNode,
                     getContextManager());
     }
 }
@@ -7526,7 +7546,6 @@
 	routineName = qualifiedName(Limits.MAX_IDENTIFIER_LENGTH)
 		methodCallParameterList(parameterList)
 	{
-
 		methodNode = (MethodCallNode) nodeFactory.getNode(
 								C_NodeTypes.STATIC_METHOD_CALL_NODE,
 								routineName,
@@ -9800,7 +9819,7 @@
 {
 		<PROCEDURE> procedureName = qualifiedName(Limits.MAX_IDENTIFIER_LENGTH)
 		procedureElements[0] = procedureParameterList()
-		( routineElement(true, procedureElements) ) +
+		( routineElement(true, false, procedureElements) ) +
 		{
 		    checkRequiredRoutineClause(JAVA_ROUTINE_CLAUSES, procedureElements);
 
@@ -9813,7 +9832,7 @@
 		}
 }
 
-void routineElement(boolean isProcedure, Object[] routineElements) throws StandardException :
+void routineElement(boolean isProcedure, boolean isTableFunction, Object[] routineElements) throws StandardException :
 {
 	int drs;
 	int clausePosition = -1;
@@ -9835,7 +9854,7 @@
 	|
 		<EXTERNAL> <NAME> clauseValue = string() { clausePosition = 4; }
 	|
-		<PARAMETER> <STYLE> clauseValue = parameterStyle() { clausePosition = 5; }
+		<PARAMETER> <STYLE> clauseValue = parameterStyle( isTableFunction ) { clausePosition = 5; }
 
 	|	<NO> <SQL>				{ clauseValue = ReuseFactory.getShort(RoutineAliasInfo.NO_SQL); clausePosition = 6; }
 	|	<CONTAINS> <SQL>		{ clauseValue = ReuseFactory.getShort(RoutineAliasInfo.CONTAINS_SQL); clausePosition = 6; }
@@ -9885,12 +9904,26 @@
 	}
 }
 
-Short parameterStyle() :
+Short parameterStyle( boolean isTableFunction ) throws StandardException :
 {
 }
 {
-	  <JAVA>               { return ReuseFactory.getShort(RoutineAliasInfo.PS_JAVA); }
-	}
+	  <JAVA>
+	  {
+	      if ( isTableFunction )
+	      { throw StandardException.newException( SQLState.LANG_MUST_BE_DJRS ); }
+
+	      return ReuseFactory.getShort(RoutineAliasInfo.PS_JAVA);
+	  }
+|
+	  <DERBY_JDBC_RESULT_SET>
+	  {
+	      if ( !isTableFunction )
+	      { throw StandardException.newException( SQLState.LANG_NO_DJRS ); }
+
+	      return ReuseFactory.getShort(RoutineAliasInfo.PS_DERBY_JDBC_RESULT_SET);
+	  }
+}
 
 Object[]
 procedureParameterList() throws StandardException :
@@ -9969,14 +10002,16 @@
 functionDefinition() throws StandardException :
 {
 	TableName functionName;
+	DataTypeDescriptor  returnType;
 	Object[] functionElements = new Object[9];
 }
 {
 		<FUNCTION> functionName = qualifiedName(Limits.MAX_IDENTIFIER_LENGTH)
 		functionElements[0] = functionParameterList()
-		<RETURNS> functionElements[8] = dataTypeCommon() 
-		( routineElement(false, functionElements) ) +
+		<RETURNS> returnType = functionReturnDataType() 
+		( routineElement(false, returnType.getTypeId().isRowMultiSetTypeId(), functionElements) ) +
 		{
+		    functionElements[8] = returnType;
 		    checkRequiredRoutineClause(JAVA_ROUTINE_CLAUSES, functionElements);
 		    
 			return getCreateAliasNode(
@@ -10029,6 +10064,91 @@
 	}
 }
 
+/*
+ * <A NAME="functionReturnDataType">functionReturnDataType</A>
+ */
+DataTypeDescriptor
+functionReturnDataType() throws StandardException :
+{
+    DataTypeDescriptor	typeDescriptor;
+}
+{
+    (
+        typeDescriptor = dataTypeCommon()
+         |
+        typeDescriptor = functionTableType()
+    )
+    {
+        return typeDescriptor;
+    }
+}
+
+/*
+ * <A NAME="functionTableType">functionTableType</A>
+ */
+DataTypeDescriptor
+functionTableType() throws StandardException :
+{
+	DataTypeDescriptor      typeDescriptor;
+	ArrayList                       names = new ArrayList();
+	ArrayList                         types = new ArrayList();
+	String[]                          nameArray;
+	DataTypeDescriptor[]        typeArray;
+	int                                     columnCount;
+}
+{
+	<TABLE>
+	<LEFT_PAREN>
+	    functionTableReturnColumn( names, types )
+	    ( <COMMA> functionTableReturnColumn( names, types ) ) *
+	<RIGHT_PAREN>
+	{
+		columnCount = names.size();
+		nameArray = new String[ columnCount ];
+		names.toArray( nameArray );
+		typeArray = new DataTypeDescriptor[ columnCount ];
+		types.toArray( typeArray );
+
+		//
+		// We do not allow XML as a column datatype because
+		// Derby does not yet support the streaming JDBC4
+		// interfaces to XML values.
+		//
+		for ( int i = 0; i < columnCount; i++ )
+		{
+		    if ( typeArray[ i ].getTypeId().isXMLTypeId() )
+		    { throw StandardException.newException( SQLState.LANG_XML_NOT_ALLOWED_DJRS ); }
+		}
+
+		typeDescriptor = DataTypeDescriptor.getRowMultiSet( nameArray, typeArray );
+
+		return typeDescriptor;
+	}
+}
+
+/*
+ * <A NAME="functionTableReturnColumn">functionTableReturnColumn</A>
+ */
+void
+functionTableReturnColumn
+(
+    ArrayList names,
+    ArrayList types
+)
+throws StandardException :
+{
+	String                          name;
+	DataTypeDescriptor	typeDescriptor;
+}
+{
+	name = identifier( Limits.MAX_IDENTIFIER_LENGTH, true )
+	typeDescriptor = dataTypeDDL()
+	{
+		names.add( name );
+		types.add( typeDescriptor );
+	}
+}
+
 StatementNode
 viewDefinition(Token beginToken) throws StandardException :
 {
@@ -12961,6 +13081,7 @@
 	|	tok = <DYNAMIC>
     |   tok = <DATABASE>
 	|	tok = <DB2SQL>
+	|	tok = <DERBY_JDBC_RESULT_SET>
 	|	tok = <DOCUMENT>
 	|	tok = <EACH>
 	|	tok = <EMPTY>

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/GenericResultSetFactory.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/GenericResultSetFactory.java?view=diff&rev=555032&r1=555031&r2=555032
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/GenericResultSetFactory.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/GenericResultSetFactory.java Tue Jul 10 11:40:39 2007
@@ -443,7 +443,9 @@
 									 boolean isTarget,
 									 int scanIsolationLevel,
 									 double optimizerEstimatedRowCount,
-									 double optimizerEstimatedCost)
+									 double optimizerEstimatedCost,
+									 boolean isDerbyStyleTableFunction
+                                          )
 		throws StandardException
 	{
 		return new VTIResultSet(activation, row, resultSetNumber, 
@@ -456,7 +458,9 @@
 								isTarget,
 								scanIsolationLevel,
 							    optimizerEstimatedRowCount,
-								optimizerEstimatedCost);
+								optimizerEstimatedCost,
+								isDerbyStyleTableFunction
+                                );
 	}
 
 	/**

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?view=diff&rev=555032&r1=555031&r2=555032
==============================================================================
--- 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 10 11:40:39 2007
@@ -92,6 +92,8 @@
 
 	private boolean[] runtimeNullableColumn;
 
+	private boolean isDerbyStyleTableFunction;
+
 	/**
 		Specified isolation level of SELECT (scan). If not set or
 		not application, it will be set to ExecutionContext.UNSPECIFIED_ISOLATION_LEVEL
@@ -111,7 +113,9 @@
 				 boolean isTarget,
 				 int scanIsolationLevel,
 			     double optimizerEstimatedRowCount,
-				 double optimizerEstimatedCost) 
+				 double optimizerEstimatedCost,
+				 boolean isDerbyStyleTableFunction
+                 ) 
 		throws StandardException
 	{
 		super(activation, resultSetNumber, 
@@ -124,6 +128,7 @@
 		this.isTarget = isTarget;
 		this.pushedQualifiers = pushedQualifiers;
 		this.scanIsolationLevel = scanIsolationLevel;
+		this.isDerbyStyleTableFunction = isDerbyStyleTableFunction;
 
 		if (erdNumber != -1)
 		{
@@ -218,10 +223,22 @@
 		openTime += getElapsedMillis(beginTime);
 	}
 
-	private boolean[] setNullableColumnList() throws SQLException {
+	private boolean[] setNullableColumnList() throws SQLException, StandardException {
 
 		if (runtimeNullableColumn != null)
 			return runtimeNullableColumn;
+
+		// Derby-style table functions return SQL rows which don't have not-null
+		// constraints bound to them
+		if ( isDerbyStyleTableFunction )
+		{
+		    int         count = getAllocatedRow().nColumns() + 1;
+            
+		    runtimeNullableColumn = new boolean[ count ];
+		    for ( int i = 0; i < count; i++ )   { runtimeNullableColumn[ i ] = true; }
+            
+		    return runtimeNullableColumn;
+		}
 
 		if (userVTI == null)
 			return null;

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?view=diff&rev=555032&r1=555031&r2=555032
==============================================================================
--- 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 10 11:40:39 2007
@@ -2484,6 +2484,28 @@
                 <arg>type</arg>
             </msg>
 
+            <msg>
+                <name>42ZB1</name>
+                <text>Parameter style DERBY_JDBC_RESULT_SET is only allowed for table functions.</text>
+            </msg>
+
+            <msg>
+                <name>42ZB2</name>
+                <text>Table functions can only have parameter style DERBY_JDBC_RESULT_SET.</text>
+            </msg>
+
+            <msg>
+                <name>42ZB3</name>
+                <text>XML is not allowed as the datatype of a column returned by a table function.</text>
+            </msg>
+
+            <msg>
+                <name>42ZB4</name>
+                <text>'{0}'.{1}' does not identify a table function.</text>
+                <arg>schemaName</arg>
+                <arg>functionName</arg>
+            </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?view=diff&rev=555032&r1=555031&r2=555032
==============================================================================
--- 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 10 11:40:39 2007
@@ -1049,6 +1049,11 @@
     String LANG_LIKE_COLLATION_MISMATCH                               = "42ZA2";
     String LANG_CAN_NOT_CREATE_TABLE                               = "42ZA3";
 
+    String LANG_NO_DJRS                                                 = "42ZB1";
+    String LANG_MUST_BE_DJRS                                        = "42ZB2";
+    String LANG_XML_NOT_ALLOWED_DJRS                    = "42ZB3";
+    String LANG_NOT_TABLE_FUNCTION                    = "42ZB4";
+
 	//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/storeless/org/apache/derby/impl/storeless/EmptyDictionary.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/storeless/org/apache/derby/impl/storeless/EmptyDictionary.java?view=diff&rev=555032&r1=555031&r2=555032
==============================================================================
--- db/derby/code/trunk/java/storeless/org/apache/derby/impl/storeless/EmptyDictionary.java (original)
+++ db/derby/code/trunk/java/storeless/org/apache/derby/impl/storeless/EmptyDictionary.java Tue Jul 10 11:40:39 2007
@@ -735,4 +735,9 @@
         // TODO Auto-generated method stub
         return null;
     }
+
+    public String getBuiltinVTIClass(TableDescriptor td, boolean asTableFunction) throws StandardException {
+        // TODO Auto-generated method stub
+        return null;
+    }
 }

Added: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/StringArrayVTI.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/StringArrayVTI.java?view=auto&rev=555032
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/StringArrayVTI.java (added)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/StringArrayVTI.java Tue Jul 10 11:40:39 2007
@@ -0,0 +1,110 @@
+/*
+
+Derby - Class org.apache.derbyTesting.functionTests.tests.lang.StringArrayVTI
+
+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.sql.*;
+
+/**
+ * <p>
+ * This is a concrete VTI which is prepopulated with rows which are just
+ * arrays of string columns.
+ * </p>
+ */
+public    class   StringArrayVTI  extends StringColumnVTI
+{
+    ///////////////////////////////////////////////////////////////////////////////////
+    //
+    // CONSTANTS
+    //
+    ///////////////////////////////////////////////////////////////////////////////////
+
+    ///////////////////////////////////////////////////////////////////////////////////
+    //
+    // INNER CLASSES
+    //
+    ///////////////////////////////////////////////////////////////////////////////////
+
+    ///////////////////////////////////////////////////////////////////////////////////
+    //
+    // STATE
+    //
+    ///////////////////////////////////////////////////////////////////////////////////
+
+    private int             _rowIdx = -1;
+    private String[][]  _rows;
+    
+    ///////////////////////////////////////////////////////////////////////////////////
+    //
+    // CONSTRUCTORS
+    //
+    ///////////////////////////////////////////////////////////////////////////////////
+
+    public  StringArrayVTI( String[] columnNames, String[][] rows )
+    {
+        super( columnNames );
+
+        _rows = rows;
+    }
+    
+    ///////////////////////////////////////////////////////////////////////////////////
+    //
+    // ABSTRACT StringColumn BEHAVIOR
+    //
+    ///////////////////////////////////////////////////////////////////////////////////
+
+    protected String  getRawColumn( int columnNumber ) throws SQLException
+    {
+        try {
+            return  _rows[ _rowIdx ][ columnNumber - 1 ];
+        } catch (Throwable t) { throw new SQLException( t.getMessage() ); }
+    }
+
+    ///////////////////////////////////////////////////////////////////////////////////
+    //
+    // ResultSet BEHAVIOR
+    //
+    ///////////////////////////////////////////////////////////////////////////////////
+
+    public  boolean next() throws SQLException
+    {
+        if ( (++_rowIdx) >= _rows.length ) { return false; }
+        else { return true; }
+    }
+
+    public  void close() throws SQLException
+    {}
+
+    public  ResultSetMetaData   getMetaData() throws SQLException
+    {
+        throw new SQLException( "Not implemented." );
+    }
+    
+    ///////////////////////////////////////////////////////////////////////////////////
+    //
+    // MINIONS
+    //
+    ///////////////////////////////////////////////////////////////////////////////////
+
+
+
+}
+

Propchange: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/StringArrayVTI.java
------------------------------------------------------------------------------
    svn:eol-style = native