--- /dev/null
+/*\r
+\r
+ Derby - Class org.apache.derby.impl.sql.compile.JavaToSQLValueNode\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.sql.dictionary.DataDictionary;\r
+import org.apache.derby.iapi.types.DataTypeDescriptor;\r
+import org.apache.derby.iapi.types.StringDataValue;\r
+import org.apache.derby.iapi.types.TypeId;\r
+import org.apache.derby.iapi.sql.compile.TypeCompiler;\r
+import org.apache.derby.iapi.reference.SQLState;\r
+\r
+import org.apache.derby.iapi.services.compiler.MethodBuilder;\r
+import org.apache.derby.iapi.services.compiler.LocalField;\r
+\r
+import org.apache.derby.iapi.error.StandardException;\r
+\r
+import org.apache.derby.impl.sql.compile.ExpressionClassBuilder;\r
+\r
+import org.apache.derby.iapi.sql.compile.Visitable;\r
+import org.apache.derby.iapi.sql.compile.Visitor;\r
+\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+\r
+import java.lang.reflect.Modifier;\r
+\r
+import org.apache.derby.iapi.util.JBitSet;\r
+\r
+import java.util.Vector;\r
+\r
+/**\r
+ * This node type converts a value from the Java domain to the SQL domain.\r
+ */\r
+\r
+public class JavaToSQLValueNode extends ValueNode\r
+{\r
+ JavaValueNode javaNode;\r
+\r
+ /**\r
+ * Initializer for a JavaToSQLValueNode\r
+ *\r
+ * @param value The Java value to convert to the SQL domain\r
+ */\r
+ public void init(Object value)\r
+ {\r
+ this.javaNode = (JavaValueNode) value;\r
+ }\r
+\r
+ /**\r
+ * Preprocess an expression tree. We do a number of transformations\r
+ * here (including subqueries, IN lists, LIKE and BETWEEN) plus\r
+ * subquery flattening.\r
+ * NOTE: This is done before the outer ResultSetNode is preprocessed.\r
+ *\r
+ * @param numTables Number of tables in the DML Statement\r
+ * @param outerFromList FromList from outer query block\r
+ * @param outerSubqueryList SubqueryList from outer query block\r
+ * @param outerPredicateList PredicateList from outer query block\r
+ *\r
+ * @return The modified expression\r
+ *\r
+ * @exception StandardException Thrown on error\r
+ */\r
+ public ValueNode preprocess(int numTables,\r
+ FromList outerFromList,\r
+ SubqueryList outerSubqueryList,\r
+ PredicateList outerPredicateList) \r
+ throws StandardException\r
+ {\r
+ javaNode.preprocess(numTables,\r
+ outerFromList, outerSubqueryList,\r
+ outerPredicateList);\r
+\r
+ return this;\r
+ }\r
+\r
+ /**\r
+ * Do code generation for this conversion of a value from the Java to\r
+ * the SQL domain.\r
+ *\r
+ * @param acb The ExpressionClassBuilder for the class we're generating\r
+ * @param mb the method the expression will go into\r
+ *\r
+ * @exception StandardException Thrown on error\r
+ */\r
+\r
+ public void generateExpression(ExpressionClassBuilder acb,\r
+ MethodBuilder mb)\r
+ throws StandardException\r
+ {\r
+ TypeId resultType;\r
+ String resultTypeName;\r
+\r
+ /*\r
+ ** Tell the Java node that it's value is being returned to the\r
+ ** SQL domain. This way, it knows whether the checking for a null\r
+ ** receiver is to be done at the Java level or the SQL level.\r
+ */\r
+ javaNode.returnValueToSQLDomain();\r
+\r
+ /* Generate the receiver, if any. */\r
+ boolean hasReceiver = javaNode.generateReceiver(acb, mb);\r
+\r
+ /*\r
+ ** If the java expression has a receiver, we want to check whether\r
+ ** it's null before evaluating the whole expression (to avoid\r
+ ** a NullPointerException.\r
+ */\r
+ if (hasReceiver)\r
+ {\r
+ /*\r
+ ** There is a receiver. Generate a null SQL value to return\r
+ ** in case the receiver is null. First, create a field to hold\r
+ ** the null SQL value.\r
+ */\r
+ String nullValueClass = getTypeCompiler().interfaceName();\r
+ LocalField nullValueField =\r
+ acb.newFieldDeclaration(Modifier.PRIVATE, nullValueClass);\r
+ /*\r
+ ** There is a receiver. Generate the following to test\r
+ ** for null:\r
+ **\r
+ ** (receiverExpression == null) ? \r
+ */\r
+\r
+ mb.conditionalIfNull();\r
+ mb.getField(nullValueField);\r
+ acb.generateNullWithExpress(mb, getTypeCompiler(), \r
+ getTypeServices().getCollationType());\r
+\r
+\r
+ /*\r
+ ** We have now generated the expression to test, and the\r
+ ** "true" side of the ?: operator. Finish the "true" side\r
+ ** so we can generate the "false" side.\r
+ */\r
+ mb.startElseCode();\r
+ }\r
+ \r
+ resultType = getTypeId();\r
+ TypeCompiler tc = getTypeCompiler();\r
+\r
+ resultTypeName = tc.interfaceName();\r
+\r
+ /* Allocate an object for re-use to hold the result of the conversion */\r
+ LocalField field = acb.newFieldDeclaration(Modifier.PRIVATE, resultTypeName);\r
+\r
+ /* Generate the expression for the Java value under us */\r
+ javaNode.generateExpression(acb, mb);\r
+\r
+ /* Generate the SQL value, which is always nullable */\r
+ acb.generateDataValue(mb, tc, \r
+ getTypeServices().getCollationType(), field);\r
+\r
+ /*\r
+ ** If there was a receiver, the return value will be the result\r
+ ** of the ?: operator.\r
+ */\r
+ if (hasReceiver)\r
+ {\r
+ mb.completeConditional();\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Prints the sub-nodes of this object. See QueryTreeNode 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, "javaNode: ");\r
+ javaNode.treePrint(depth + 1);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * Get the JavaValueNode that lives under this JavaToSQLValueNode.\r
+ *\r
+ * @return The JavaValueNode that lives under this node.\r
+ */\r
+\r
+ public JavaValueNode getJavaValueNode()\r
+ {\r
+ return javaNode;\r
+ }\r
+\r
+ /** \r
+ * @see QueryTreeNode#disablePrivilegeCollection\r
+ */\r
+ public void disablePrivilegeCollection()\r
+ {\r
+ super.disablePrivilegeCollection();\r
+ if (javaNode != null)\r
+ javaNode.disablePrivilegeCollection();\r
+ }\r
+\r
+ /**\r
+ * Bind this expression. This means binding the sub-expressions,\r
+ * as well as figuring out what the return type is for this expression.\r
+ *\r
+ * @param fromList The FROM list for the query this\r
+ * expression is in, for binding columns.\r
+ * @param subqueryList The subquery list being built as we find\r
+ * SubqueryNodes\r
+ * @param aggregateVector The aggregate vector being built as we find AggregateNodes\r
+ *\r
+ * @return The new top of the expression tree.\r
+ *\r
+ * @exception StandardException Thrown on error\r
+ */\r
+\r
+ public ValueNode bindExpression(FromList fromList, SubqueryList subqueryList,\r
+ Vector aggregateVector) \r
+ throws StandardException\r
+ {\r
+ // method invocations are not allowed in ADD TABLE clauses.\r
+ // And neither are field references. \r
+ javaNode.checkReliability(this);\r
+\r
+ /* Bind the expression under us */\r
+ javaNode = javaNode.bindExpression(fromList, subqueryList, aggregateVector);\r
+\r
+ DataTypeDescriptor dts = DataTypeDescriptor.getSQLDataTypeDescriptor(javaNode.getJavaTypeName());\r
+ if (dts == null)\r
+ {\r
+ throw StandardException.newException(SQLState.LANG_NO_CORRESPONDING_S_Q_L_TYPE, \r
+ javaNode.getJavaTypeName());\r
+ }\r
+ // For functions returning string types we should set the collation to match the \r
+ // java method's schema DERBY-2972. This is propogated from \r
+ // RoutineAliasInfo to javaNode.\r
+ if (dts.getTypeId().isStringTypeId()){ \r
+ dts.setCollationType(javaNode.getCollationType());\r
+ dts.setCollationDerivation(StringDataValue.COLLATION_DERIVATION_IMPLICIT);\r
+ }\r
+ setType(dts);\r
+ \r
+ return this;\r
+ }\r
+\r
+ /**\r
+ * Remap all ColumnReferences in this tree to be clones of the\r
+ * underlying expression.\r
+ *\r
+ * @return ValueNode The remapped expression tree.\r
+ *\r
+ * @exception StandardException Thrown on error\r
+ */\r
+ public ValueNode remapColumnReferencesToExpressions()\r
+ throws StandardException\r
+ {\r
+ javaNode = javaNode.remapColumnReferencesToExpressions();\r
+ return this;\r
+ }\r
+\r
+ /**\r
+ * Categorize this predicate. Initially, this means\r
+ * building a bit map of the referenced tables for each predicate.\r
+ * If the source of this ColumnReference (at the next underlying level) \r
+ * is not a ColumnReference or a VirtualColumnNode then this predicate\r
+ * will not be pushed down.\r
+ *\r
+ * For example, in:\r
+ * select * from (select 1 from s) a (x) where x = 1\r
+ * we will not push down x = 1.\r
+ * NOTE: It would be easy to handle the case of a constant, but if the\r
+ * inner SELECT returns an arbitrary expression, then we would have to copy\r
+ * that tree into the pushed predicate, and that tree could contain\r
+ * subqueries and method calls.\r
+ *\r
+ * @param referencedTabs JBitSet with bit map of referenced FromTables\r
+ * @param simplePredsOnly Whether or not to consider method\r
+ * calls, field references and conditional nodes\r
+ * when building bit map\r
+ *\r
+ * @return boolean Whether or not source.expression is a ColumnReference\r
+ * or a VirtualColumnNode.\r
+ *\r
+ * @exception StandardException Thrown on error\r
+ */\r
+ public boolean categorize(JBitSet referencedTabs, boolean simplePredsOnly)\r
+ throws StandardException\r
+ {\r
+ return javaNode.categorize(referencedTabs, simplePredsOnly);\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
+ return javaNode.getOrderableVariantType();\r
+ }\r
+\r
+ /**\r
+ * Accept a visitor, and call v.visit()\r
+ * on child nodes as necessary. \r
+ * \r
+ * @param v the visitor\r
+ *\r
+ * @exception StandardException on error\r
+ */\r
+ public Visitable accept(Visitor v) \r
+ throws StandardException\r
+ {\r
+ Visitable returnNode = v.visit(this);\r
+ \r
+ if (v.skipChildren(this))\r
+ {\r
+ return returnNode;\r
+ }\r
+\r
+ if (javaNode != null && !v.stopTraversal())\r
+ {\r
+ javaNode = (JavaValueNode)javaNode.accept(v);\r
+ }\r
+ \r
+ return returnNode;\r
+ }\r
+ \r
+ /**\r
+ * {@inheritDoc}\r
+ */\r
+ protected boolean isEquivalent(ValueNode o)\r
+ {\r
+ // anything in the java domain is not equiavlent.\r
+ return false;\r
+ }\r
+}\r