--- /dev/null
+/*\r
+\r
+ Derby - Class org.apache.derby.impl.sql.compile.JavaValueNode\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.compile.CompilerContext;\r
+\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+\r
+import org.apache.derby.iapi.services.context.ContextManager;\r
+\r
+import org.apache.derby.iapi.types.DataTypeDescriptor;\r
+\r
+import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;\r
+\r
+import org.apache.derby.iapi.types.TypeId;\r
+\r
+import org.apache.derby.iapi.sql.dictionary.DataDictionary;\r
+import org.apache.derby.iapi.error.StandardException;\r
+import org.apache.derby.iapi.services.i18n.MessageService;\r
+import org.apache.derby.impl.sql.compile.ExpressionClassBuilder;\r
+import org.apache.derby.impl.sql.compile.ActivationClassBuilder;\r
+\r
+import org.apache.derby.iapi.types.JSQLType;\r
+\r
+import org.apache.derby.iapi.services.compiler.LocalField;\r
+import org.apache.derby.iapi.services.compiler.MethodBuilder;\r
+\r
+\r
+import org.apache.derby.iapi.services.loader.ClassInspector;\r
+\r
+import org.apache.derby.iapi.store.access.Qualifier;\r
+\r
+import org.apache.derby.iapi.util.JBitSet;\r
+\r
+import org.apache.derby.iapi.reference.SQLState;\r
+\r
+import java.lang.reflect.Modifier;\r
+\r
+import java.util.Vector;\r
+\r
+/**\r
+ * This abstract node class represents a data value in the Java domain.\r
+ */\r
+\r
+abstract class JavaValueNode extends QueryTreeNode\r
+{\r
+ private boolean mustCastToPrimitive;\r
+\r
+ protected boolean forCallStatement;\r
+ private boolean valueReturnedToSQLDomain;\r
+ private boolean returnValueDiscarded;\r
+\r
+ protected JSQLType jsqlType;\r
+\r
+ /* Name of field holding receiver value, if any */\r
+ private LocalField receiverField;\r
+\r
+ // * Collation type of schema where method is defined. \r
+ private int collationType;\r
+\r
+ public boolean isPrimitiveType() throws StandardException\r
+ {\r
+ JSQLType myType = getJSQLType();\r
+ \r
+ if ( myType == null ) { return false; }\r
+ else { return ( myType.getCategory() == JSQLType.JAVA_PRIMITIVE ); }\r
+ }\r
+\r
+ public String getJavaTypeName() throws StandardException\r
+ {\r
+ JSQLType myType = getJSQLType();\r
+\r
+ if ( myType == null ) { return ""; }\r
+\r
+ switch( myType.getCategory() )\r
+ {\r
+ case JSQLType.JAVA_CLASS: return myType.getJavaClassName();\r
+\r
+ case JSQLType.JAVA_PRIMITIVE: return JSQLType.primitiveNames[ myType.getPrimitiveKind() ];\r
+\r
+ default:\r
+\r
+ if (SanityManager.DEBUG)\r
+ { SanityManager.THROWASSERT( "Inappropriate JSQLType: " + myType ); }\r
+ }\r
+\r
+ return "";\r
+ }\r
+\r
+ public void setJavaTypeName(String javaTypeName)\r
+ {\r
+ jsqlType = new JSQLType( javaTypeName );\r
+ }\r
+\r
+ public String getPrimitiveTypeName()\r
+ throws StandardException\r
+ {\r
+ JSQLType myType = getJSQLType();\r
+\r
+ if ( myType == null ) { return ""; }\r
+\r
+ switch( myType.getCategory() )\r
+ {\r
+ case JSQLType.JAVA_PRIMITIVE: return JSQLType.primitiveNames[ myType.getPrimitiveKind() ];\r
+\r
+ default:\r
+\r
+ if (SanityManager.DEBUG)\r
+ { SanityManager.THROWASSERT( "Inappropriate JSQLType: " + myType ); }\r
+ }\r
+\r
+ return "";\r
+ }\r
+\r
+ /**\r
+ * Toggles whether the code generator should add a cast to extract a primitive\r
+ * value from an object.\r
+ *\r
+ * @param booleanValue true if we want the code generator to add a cast\r
+ * false otherwise\r
+ */\r
+ public void castToPrimitive(boolean booleanValue)\r
+ {\r
+ mustCastToPrimitive = booleanValue;\r
+ }\r
+\r
+ /**\r
+ * Reports whether the code generator should add a cast to extract a primitive\r
+ * value from an object.\r
+ *\r
+ * @return true if we want the code generator to add a cast\r
+ * false otherwise\r
+ */\r
+ public boolean mustCastToPrimitive() { return mustCastToPrimitive; }\r
+\r
+ /**\r
+ * Get the JSQLType that corresponds to this node. Could be a SQLTYPE,\r
+ * a Java primitive, or a Java class.\r
+ *\r
+ * @return the corresponding JSQLType\r
+ *\r
+ */\r
+ public JSQLType getJSQLType() throws StandardException\r
+ { return jsqlType; }\r
+\r
+\r
+ /**\r
+ * Map a JSQLType to a compilation type id.\r
+ *\r
+ * @param jsqlType the universal type to map\r
+ *\r
+ * @return the corresponding compilation type id\r
+ *\r
+ */\r
+ public TypeId mapToTypeID( JSQLType jsqlType )\r
+ {\r
+ DataTypeDescriptor dts = jsqlType.getSQLType();\r
+\r
+ if ( dts == null ) { return null; }\r
+\r
+ return dts.getTypeId();\r
+ }\r
+\r
+ /**\r
+ * Mark this node as being for a CALL Statement.\r
+ * (void methods are only okay for CALL Statements)\r
+ */\r
+ public void markForCallStatement()\r
+ {\r
+ forCallStatement = true;\r
+ }\r
+\r
+ /**\r
+ * @see ValueNode#remapColumnReferencesToExpressions\r
+ *\r
+ * @exception StandardException Thrown on error\r
+ */\r
+ abstract public JavaValueNode remapColumnReferencesToExpressions()\r
+ throws StandardException;\r
+\r
+ /**\r
+ * @see ValueNode#categorize\r
+ *\r
+ * @exception StandardException Thrown on error\r
+ */\r
+ abstract public boolean categorize(JBitSet referencedTabs, boolean simplePredsOnly)\r
+ throws StandardException;\r
+\r
+ /**\r
+ * @see ValueNode#bindExpression\r
+ *\r
+ * @return the new node, usually this\r
+ *\r
+ * @exception StandardException Thrown on error\r
+ */\r
+ abstract JavaValueNode bindExpression(FromList fromList, SubqueryList subqueryList,\r
+ Vector aggregateVector) \r
+ throws StandardException;\r
+ /**\r
+ * @see ValueNode#preprocess\r
+ *\r
+ * @exception StandardException Thrown on error\r
+ */\r
+ abstract public void preprocess(int numTables,\r
+ FromList outerFromList,\r
+ SubqueryList outerSubqueryList,\r
+ PredicateList outerPredicateList)\r
+ throws StandardException;\r
+\r
+ /** @see ValueNode#getConstantValueAsObject \r
+ *\r
+ * @exception StandardException Thrown on error\r
+ */\r
+ Object getConstantValueAsObject()\r
+ throws StandardException\r
+ {\r
+ return null;\r
+ }\r
+\r
+ /**\r
+ * Do the code generation for this node. Call the more general\r
+ * routine that generates expressions.\r
+ *\r
+ * @param acb The ActivationClassBuilder for the class being built\r
+ * @param mb the method the expression will go into\r
+ *\r
+ * @exception StandardException Thrown on error\r
+ */\r
+\r
+ protected final void generate(ActivationClassBuilder acb,\r
+ MethodBuilder mb)\r
+ throws StandardException\r
+ {\r
+ generateExpression( acb, mb );\r
+ }\r
+\r
+ /**\r
+ * Generate the expression that evaluates to the receiver. This is\r
+ * for the case where a java expression is being returned to the SQL\r
+ * domain, and we need to check whether the receiver is null (if so,\r
+ * the SQL value should be set to null, and this Java expression\r
+ * not evaluated). Instance method calls and field references have\r
+ * receivers, while class method calls and calls to constructors do\r
+ * not. If this Java expression does not have a receiver, this method\r
+ * returns null.\r
+ *\r
+ * The implementation of this method should only generate the receiver\r
+ * once and cache it in a field. This is because there will be two\r
+ * references to the receiver, and we want to evaluate it only once.\r
+ *\r
+ *\r
+ * @param acb The ExpressionClassBuilder for the class being built\r
+ * @param mb the method the expression will go into\r
+ *\r
+ * @return True if has compiled receiver.\r
+ *\r
+ * @exception StandardException Thrown on error\r
+ */\r
+ protected boolean generateReceiver(ExpressionClassBuilder acb,\r
+ MethodBuilder mb)\r
+ throws StandardException\r
+ {\r
+ return false;\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
+ */\r
+ protected int getOrderableVariantType() throws StandardException\r
+ {\r
+ // The default is VARIANT\r
+ return Qualifier.VARIANT;\r
+ //return Qualifier.SCAN_INVARIANT;\r
+ }\r
+\r
+ /**\r
+ * General logic shared by Core compilation and by the Replication Filter\r
+ * compiler. Every child of ValueNode must implement one of these methods.\r
+ *\r
+ * @param acb The ExpressionClassBuilder for the class being built\r
+ * @param mb the method the expression will go into\r
+ *\r
+ * @exception StandardException Thrown on error\r
+ */\r
+\r
+ protected abstract void generateExpression(\r
+ ExpressionClassBuilder acb,\r
+ MethodBuilder mb)\r
+ throws StandardException;\r
+\r
+ /**\r
+ * Generate the expression that evaluates to the receiver. This is\r
+ * for the case where a java expression is being returned to the SQL\r
+ * domain, and we need to check whether the receiver is null (if so,\r
+ * the SQL value should be set to null, and this Java expression\r
+ * not evaluated). Instance method calls and field references have\r
+ * receivers, while class method calls and calls to constructors do\r
+ * not. If this Java expression does not have a receiver, this method\r
+ * returns null.\r
+ *\r
+ * This also covers the case where a java expression is being returned\r
+ * to the Java domain. In this case, we need to check whether the\r
+ * receiver is null only if the value returned by the Java expression\r
+ * is an object (not a primitive type). We don't want to generate the\r
+ * expression here if we are returning a primitive type to the Java\r
+ * domain, because there's no point in checking whether the receiver\r
+ * is null in this case (we can't make the expression return a null\r
+ * value).\r
+ *\r
+ * Only generate the receiver once and cache it in a field. This is\r
+ * because there will be two references to the receiver, and we want\r
+ * to evaluate it only once.\r
+ *\r
+ *\r
+ * @param acb The ActivationClassBuilder for the class being built\r
+ * @param mb the method the expression will go into\r
+ * @param receiver The query tree form of the receiver expression\r
+ *\r
+ * @return The compiled receiver, if any.\r
+ *\r
+ * @exception StandardException Thrown on error\r
+ */\r
+ protected final boolean generateReceiver(ExpressionClassBuilder acb,\r
+ MethodBuilder mb,\r
+ JavaValueNode receiver)\r
+ throws StandardException\r
+ {\r
+ ClassInspector classInspector = getClassFactory().getClassInspector();\r
+\r
+ /*\r
+ ** Don't generate the expression now if it returns a primitive\r
+ ** type to the Java domain.\r
+ */\r
+ if ( (! valueReturnedToSQLDomain()) &&\r
+ classInspector.primitiveType(getJavaTypeName()))\r
+ {\r
+ return false;\r
+ }\r
+\r
+ /*\r
+ ** Generate the following:\r
+ **\r
+ ** <receiver class> <field name>;\r
+ ** <field name> = <receiver>;\r
+ **\r
+ ** for non-static calls.\r
+ */\r
+\r
+ String receiverClassName = receiver.getJavaTypeName();\r
+ receiverField =\r
+ acb.newFieldDeclaration(Modifier.PRIVATE, receiverClassName);\r
+\r
+ receiver.generateExpression(acb, mb);\r
+ mb.putField(receiverField);\r
+ return true;\r
+ }\r
+\r
+ /**\r
+ * Get an expression that has the value of the receiver. If a field\r
+ * holding the receiver value was already generated, use that. If not,\r
+ * generate the receiver value.\r
+ *\r
+ * @param acb The ExpressionClassBuilder for the class we're generating\r
+ * @param mb the method the expression will go into\r
+ * @param receiver The query tree form of the receiver expression\r
+ *\r
+ *\r
+ * @exception StandardException Thrown on error\r
+ */\r
+ protected final void getReceiverExpression(ExpressionClassBuilder acb,\r
+ MethodBuilder mb,\r
+ JavaValueNode receiver)\r
+ throws StandardException\r
+ {\r
+ if (receiverField != null)\r
+ {\r
+ mb.getField(receiverField);\r
+ }\r
+ else\r
+ {\r
+ receiver.generateExpression(acb, mb);\r
+ }\r
+ }\r
+\r
+ /** Inform this node that it returns its value to the SQL domain */\r
+ protected void returnValueToSQLDomain()\r
+ {\r
+ valueReturnedToSQLDomain = true;\r
+ }\r
+\r
+ /** Tell whether this node returns its value to the SQL domain */\r
+ protected boolean valueReturnedToSQLDomain()\r
+ {\r
+ return valueReturnedToSQLDomain;\r
+ }\r
+\r
+ /** Tell this node that nothing is done with the returned value */\r
+ protected void markReturnValueDiscarded()\r
+ {\r
+ returnValueDiscarded = true;\r
+ }\r
+\r
+ /** Tell whether the return value from this node is discarded */\r
+ protected boolean returnValueDiscarded()\r
+ {\r
+ return returnValueDiscarded;\r
+ }\r
+\r
+ /**\r
+ Check the reliability type of this java value.\r
+\r
+ @exception StandardException Thrown on error\r
+\r
+ @see org.apache.derby.iapi.sql.compile.CompilerContext\r
+ */\r
+ public void checkReliability(ValueNode sqlNode) throws StandardException {\r
+ sqlNode.checkReliability( \r
+ CompilerContext.FUNCTION_CALL_ILLEGAL,\r
+ SQLState.LANG_JAVA_METHOD_CALL_OR_FIELD_REF\r
+ );\r
+ }\r
+\r
+ /**\r
+ * @return collationType as set by setCollationType\r
+ */\r
+ public int getCollationType() {\r
+ return collationType;\r
+ }\r
+ \r
+ /**\r
+ * Set the collation type.\r
+ * This will be used to determine the collation type for \r
+ * the SQLToJavaValueNode.\r
+ * \r
+ * @param type one of <code>StringDataValue.COLLATION_TYPE_UCS_BASIC </code> or\r
+ * <code>StringDataValue.COLLATION_TYPE_TERRITORY_BASED </code> \r
+ */\r
+ public void setCollationType(int type) {\r
+ collationType = type;\r
+ }\r
+ \r
+ \r
+}\r