--- /dev/null
+/*\r
+\r
+ Derby - Class org.apache.derby.impl.sql.compile.VirtualColumnNode\r
+\r
+ Licensed to the Apache Software Foundation (ASF) under one or more\r
+ contributor license agreements. See the NOTICE file distributed with\r
+ this work for additional information regarding copyright ownership.\r
+ The ASF licenses this file to you under the Apache License, Version 2.0\r
+ (the "License"); you may not use this file except in compliance with\r
+ the License. You may obtain a copy of the License at\r
+\r
+ http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+ Unless required by applicable law or agreed to in writing, software\r
+ distributed under the License is distributed on an "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ See the License for the specific language governing permissions and\r
+ limitations under the License.\r
+\r
+ */\r
+\r
+package org.apache.derby.impl.sql.compile;\r
+\r
+import org.apache.derby.iapi.services.compiler.MethodBuilder;\r
+\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+\r
+import org.apache.derby.iapi.types.DataTypeDescriptor;\r
+import org.apache.derby.iapi.error.StandardException;\r
+\r
+import org.apache.derby.impl.sql.compile.ExpressionClassBuilder;\r
+\r
+/**\r
+ * A VirtualColumnNode represents a virtual column reference to a column in\r
+ * a row returned by an underlying ResultSetNode. The underlying column could\r
+ * be in a base table, view (which could expand into a complex\r
+ * expression), subquery in the FROM clause, temp table, expression result, etc. \r
+ * By the time we get to code generation, all VirtualColumnNodes should stand only \r
+ * for references to columns in a base table within a FromBaseTable.\r
+ *\r
+ */\r
+\r
+public class VirtualColumnNode extends ValueNode\r
+{\r
+ /* A VirtualColumnNode contains a pointer to the immediate child result\r
+ * that is materializing the virtual column and the ResultColumn\r
+ * that represents that materialization.\r
+ */\r
+ private ResultSetNode sourceResultSet;\r
+ private ResultColumn sourceColumn;\r
+\r
+ /* columnId is redundant since a ResultColumn also has one, but\r
+ * we need it here for generate()\r
+ */\r
+ int columnId;\r
+\r
+ boolean correlated = false;\r
+\r
+\r
+ /**\r
+ * Initializer for a VirtualColumnNode.\r
+ *\r
+ * @param sourceResultSet The ResultSetNode where the value is originating\r
+ * @param sourceColumn The ResultColumn where the value is originating\r
+ * @param columnId The columnId within the current Row\r
+ */\r
+\r
+ public void init(\r
+ Object sourceResultSet,\r
+ Object sourceColumn,\r
+ Object columnId) throws StandardException\r
+ {\r
+ ResultColumn source = (ResultColumn) sourceColumn;\r
+\r
+ this.sourceResultSet = (ResultSetNode) sourceResultSet;\r
+ this.sourceColumn = source;\r
+ this.columnId = ((Integer) columnId).intValue();\r
+ setType(source.getTypeServices());\r
+ }\r
+\r
+\r
+ /**\r
+ * Prints the sub-nodes of this object. See QueryTreeNode.java for\r
+ * how tree printing is supposed to work.\r
+ *\r
+ * @param depth The depth of this node in the tree\r
+ */\r
+\r
+ public void printSubNodes(int depth)\r
+ {\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ super.printSubNodes(depth);\r
+\r
+ printLabel(depth, "sourceColumn: ");\r
+ sourceColumn.treePrint(depth + 1);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Return the ResultSetNode that is the source of this VirtualColumnNode.\r
+ *\r
+ * @return ResultSetNode \r
+ */\r
+ public ResultSetNode getSourceResultSet()\r
+ {\r
+ return sourceResultSet;\r
+ }\r
+\r
+ /**\r
+ * Return the ResultColumn that is the source of this VirtualColumnNode.\r
+ *\r
+ * @return ResultSetNode \r
+ */\r
+ public ResultColumn getSourceColumn()\r
+ {\r
+ return sourceColumn;\r
+ }\r
+\r
+ /**\r
+ * Get the name of the table the ResultColumn is in, if any. This will be null\r
+ * if the user did not supply a name (for example, select a from t).\r
+ * The method will return B for this example, select b.a from t as b\r
+ * The method will return T for this example, select t.a from t\r
+ *\r
+ * @return A String containing the name of the table the Column\r
+ * is in. If the column is not in a table (i.e. is a\r
+ * derived column), it returns NULL.\r
+ */\r
+ public String getTableName()\r
+ {\r
+ return sourceColumn.getTableName();\r
+ }\r
+\r
+ /**\r
+ * Get the name of the schema the ResultColumn's table is in, if any.\r
+ * The return value will be null if the user did not supply a schema name\r
+ * (for example, select t.a from t).\r
+ * Another example for null return value (for example, select b.a from t as b).\r
+ * But for following query select app.t.a from t, this will return APP\r
+ *\r
+ * @return A String containing the name of the schema for the Column's table.\r
+ * If the column is not in a schema (i.e. derived column), it returns NULL.\r
+ */\r
+ public String getSchemaName() throws StandardException\r
+ {\r
+ return sourceColumn.getSchemaName();\r
+ }\r
+\r
+ /**\r
+ * Return whether or not the ResultColumn is wirtable by a positioned update.\r
+ *\r
+ * @return TRUE, if the column is a base column of a table and is \r
+ * writable by a positioned update.\r
+ */\r
+ public boolean updatableByCursor()\r
+ {\r
+ return sourceColumn.updatableByCursor();\r
+ }\r
+\r
+ /**\r
+ * Return the ResultColumn that is the source of this VirtualColumnNode.\r
+ *\r
+ * @return ResultSetNode \r
+ */\r
+ public ResultColumn getSourceResultColumn()\r
+ {\r
+ return sourceColumn;\r
+ }\r
+\r
+ /**\r
+ * Mark this VCN as a reference to a correlated column.\r
+ * (It's source resultSet is an outer ResultSet.\r
+ */\r
+ void setCorrelated()\r
+ {\r
+ correlated = true;\r
+ }\r
+\r
+ /**\r
+ * Return whether or not this VCN is a correlated reference.\r
+ * \r
+ * @return Whether or not this VCN is a correlated reference.\r
+ */\r
+ boolean getCorrelated()\r
+ {\r
+ return correlated;\r
+ }\r
+\r
+ /**\r
+ * Return whether or not this expression tree is cloneable.\r
+ *\r
+ * @return boolean Whether or not this expression tree is cloneable.\r
+ */\r
+ public boolean isCloneable()\r
+ {\r
+ return true;\r
+ }\r
+\r
+ /**\r
+ * ColumnNode's are against the current row in the system.\r
+ * This lets us generate\r
+ * a faster get that simply returns the column from the\r
+ * current row, rather than getting the value out and\r
+ * returning that, only to have the caller (in the situations\r
+ * needed) stuffing it back into a new column holder object.\r
+ * We will assume the general generate() path is for getting\r
+ * the value out, and use generateColumn() when we want to\r
+ * keep the column wrapped.\r
+ *\r
+ * @exception StandardException Thrown on error\r
+ */\r
+ public void generateExpression(ExpressionClassBuilder acb,\r
+ MethodBuilder mb)\r
+ throws StandardException\r
+ {\r
+ int sourceResultSetNumber = sourceColumn.getResultSetNumber();\r
+\r
+ /* If the source is marked as redundant, then continue down\r
+ * the RC/VirtualColumnNode chain.\r
+ */\r
+ if (sourceColumn.isRedundant())\r
+ {\r
+ sourceColumn.getExpression().generateExpression(acb, mb);\r
+ return;\r
+ }\r
+\r
+ if (SanityManager.DEBUG)\r
+ SanityManager.ASSERT(sourceResultSetNumber >= 0,\r
+ "sourceResultSetNumber expected to be >= 0 for virtual column "+sourceColumn.getName());\r
+\r
+ /* The ColumnReference is from an immediately underlying ResultSet.\r
+ * The Row for that ResultSet is Activation.row[sourceResultSetNumber], \r
+ * where sourceResultSetNumber is the resultSetNumber for that ResultSet.\r
+ *\r
+ * The generated java is the expression:\r
+ * (<Datatype interface>) this.row[sourceResultSetNumber].\r
+ * getColumn(#columnId);\r
+ * where <Datatype interface> is the appropriate interface for the\r
+ * column from the Datatype protocol.\r
+ */\r
+ acb.pushColumnReference(mb, \r
+ sourceResultSetNumber,\r
+ sourceColumn.getVirtualColumnId());\r
+\r
+ mb.cast(sourceColumn.getTypeCompiler().interfaceName());\r
+ }\r
+\r
+ /**\r
+ * Return the variant type for the underlying expression.\r
+ * The variant type can be:\r
+ * VARIANT - variant within a scan\r
+ * (method calls and non-static field access)\r
+ * SCAN_INVARIANT - invariant within a scan\r
+ * (column references from outer tables)\r
+ * QUERY_INVARIANT - invariant within the life of a query\r
+ * (constant expressions)\r
+ *\r
+ * @return The variant type for the underlying expression.\r
+ * @exception StandardException thrown on error\r
+ */\r
+ protected int getOrderableVariantType() throws StandardException\r
+ {\r
+ /*\r
+ ** Delegate to the source column\r
+ */\r
+ return sourceColumn.getOrderableVariantType();\r
+ }\r
+\r
+ /**\r
+ * Get the DataTypeServices from this Node.\r
+ *\r
+ * @return The DataTypeServices from this Node. This\r
+ * may be null if the node isn't bound yet.\r
+ */\r
+ public DataTypeDescriptor getTypeServices() throws StandardException\r
+ {\r
+ DataTypeDescriptor dtd = super.getTypeServices();\r
+ if( dtd == null && sourceColumn != null)\r
+ {\r
+ dtd = sourceColumn.getTypeServices();\r
+ if( dtd != null)\r
+ setType( dtd);\r
+ }\r
+ return dtd;\r
+ } // end of getTypeServices\r
+ \r
+ protected boolean isEquivalent(ValueNode o) throws StandardException\r
+ {\r
+ if (isSameNodeType(o)) {\r
+ VirtualColumnNode other = (VirtualColumnNode)o;\r
+ return sourceColumn.isEquivalent(other.sourceColumn);\r
+ }\r
+ return false;\r
+ }\r
+}\r