--- /dev/null
+/*\r
+\r
+ Derby - Class org.apache.derby.impl.sql.compile.BaseTypeCompiler\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.reference.SQLState;\r
+import org.apache.derby.iapi.services.loader.ClassFactory;\r
+\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+\r
+import org.apache.derby.iapi.error.StandardException;\r
+\r
+import org.apache.derby.iapi.sql.compile.TypeCompiler;\r
+\r
+import org.apache.derby.iapi.types.DataValueDescriptor;\r
+import org.apache.derby.iapi.types.DataValueFactory;\r
+import org.apache.derby.iapi.types.NumberDataValue;\r
+import org.apache.derby.iapi.types.SQLInteger;\r
+import org.apache.derby.iapi.types.TypeId;\r
+\r
+import org.apache.derby.iapi.types.DataTypeDescriptor;\r
+\r
+import org.apache.derby.iapi.services.compiler.LocalField;\r
+import org.apache.derby.iapi.services.compiler.MethodBuilder;\r
+\r
+import org.apache.derby.iapi.services.classfile.VMOpcode;\r
+\r
+/**\r
+ * This is the base implementation of TypeCompiler\r
+ *\r
+ */\r
+\r
+abstract class BaseTypeCompiler implements TypeCompiler\r
+{\r
+ private TypeId correspondingTypeId;\r
+\r
+ /**\r
+ * Get the method name for getting out the corresponding primitive\r
+ * Java type.\r
+ *\r
+ * @return String The method call name for getting the\r
+ * corresponding primitive Java type.\r
+ */\r
+ public String getPrimitiveMethodName()\r
+ {\r
+ if (SanityManager.DEBUG)\r
+ {\r
+ SanityManager.THROWASSERT("getPrimitiveMethodName not applicable for " +\r
+ getClass().toString());\r
+ }\r
+ return null;\r
+ }\r
+\r
+ /**\r
+ * @see TypeCompiler#resolveArithmeticOperation\r
+ *\r
+ * @exception StandardException Thrown on error\r
+ */\r
+ public DataTypeDescriptor\r
+ resolveArithmeticOperation(DataTypeDescriptor leftType,\r
+ DataTypeDescriptor rightType,\r
+ String operator)\r
+ throws StandardException\r
+ {\r
+ throw StandardException.newException(SQLState.LANG_BINARY_OPERATOR_NOT_SUPPORTED, \r
+ operator,\r
+ leftType.getTypeId().getSQLTypeName(),\r
+ rightType.getTypeId().getSQLTypeName()\r
+ );\r
+ }\r
+\r
+ /**\r
+ * The caller will have pushed a DataValueFactory and a null or a value\r
+ * of the correct type (interfaceName()). Thus upon entry the\r
+ * stack looks like on of:\r
+ * ...,dvf,ref\r
+ * ...,dvf,null\r
+ * \r
+ * This method then sets up to call the required method\r
+ * on DataValueFactory using the nullMethodName().\r
+ * The value left on the stack will be a DataValueDescriptor\r
+ * of the correct type:\r
+ * \r
+ * ...,dvd\r
+ * \r
+ * @see TypeCompiler#generateNull(MethodBuilder, int)\r
+ */\r
+ public void generateNull(MethodBuilder mb, int collationType)\r
+ {\r
+ int argCount;\r
+ if (pushCollationForDataValue(collationType))\r
+ {\r
+ mb.push(collationType);\r
+ argCount = 2;\r
+ }\r
+ else\r
+ argCount = 1;\r
+ \r
+ mb.callMethod(VMOpcode.INVOKEINTERFACE, (String) null,\r
+ nullMethodName(),\r
+ interfaceName(),\r
+ argCount);\r
+ }\r
+\r
+ \r
+ /**\r
+ * The caller will have pushed a DataValueFactory and value\r
+ * of that can be converted to the correct type, e.g. int\r
+ * for a SQL INTEGER.\r
+ * \r
+ * Thus upon entry the\r
+ * stack looks like:\r
+ * ...,dvf,value\r
+ * \r
+ * If field is not null then it is used as the holder\r
+ * of the generated DataValueDescriptor to avoid object\r
+ * creations on multiple passes through this code.\r
+ * The field may contain null or a valid value.\r
+ * \r
+ * This method then sets up to call the required method\r
+ * on DataValueFactory using the dataValueMethodName().\r
+ * The value left on the stack will be a DataValueDescriptor\r
+ * of the correct type:\r
+ * \r
+ * If the field contained a valid value then generated\r
+ * code will return that value rather than a newly created\r
+ * object. If field was not-null then the generated code\r
+ * will set the value of field to be the return from\r
+ * the DataValueFactory method call. Thus if the field\r
+ * was empty (set to null) when this code is executed it\r
+ * will contain the newly generated value, otherwise it\r
+ * will be reset to the same value.\r
+ * \r
+ * ...,dvd\r
+ * \r
+ * @see TypeCompiler#generateDataValue(MethodBuilder, int, LocalField)\r
+ */\r
+ public void generateDataValue(MethodBuilder mb, int collationType,\r
+ LocalField field)\r
+ {\r
+\r
+ \r
+ String interfaceName = interfaceName();\r
+\r
+ // push the second argument\r
+\r
+ /* If fieldName is null, then there is no\r
+ * reusable wrapper (null), else we\r
+ * reuse the field.\r
+ */\r
+ if (field == null)\r
+ {\r
+ mb.pushNull(interfaceName);\r
+ }\r
+ else\r
+ {\r
+ mb.getField(field);\r
+ }\r
+ \r
+ int argCount;\r
+ if (pushCollationForDataValue(collationType))\r
+ {\r
+ mb.push(collationType);\r
+ argCount = 3;\r
+ }\r
+ else\r
+ argCount = 2;\r
+\r
+ mb.callMethod(VMOpcode.INVOKEINTERFACE, (String) null,\r
+ dataValueMethodName(),\r
+ interfaceName,\r
+ argCount);\r
+\r
+ if (field != null)\r
+ {\r
+ /* Store the result of the method call in the field,\r
+ * so we can re-use the wrapper.\r
+ */\r
+ mb.putField(field);\r
+ }\r
+ }\r
+\r
+ /**\r
+ Return the method name to get a Derby DataValueDescriptor\r
+ object of the correct type set to SQL NULL. The method named will\r
+ be called with one argument: a holder object if pushCollationForDataValue()\r
+ returns false, otherwise two arguments, the second being the\r
+ collationType.\r
+ */\r
+ abstract String nullMethodName();\r
+\r
+ /**\r
+ Return the method name to get a Derby DataValueDescriptor\r
+ object of the correct type and set it to a specific value.\r
+ The method named will be called with two arguments, a value to set the\r
+ returned value to and a holder object if pushCollationForDataValue()\r
+ returns false. Otherwise three arguments, the third being the\r
+ collationType.\r
+ This implementation returns "getDataValue" to map\r
+ to the overloaded methods\r
+ DataValueFactory.getDataValue(type, dvd type)\r
+ */\r
+ String dataValueMethodName()\r
+ {\r
+ return "getDataValue";\r
+ }\r
+ \r
+ /**\r
+ * Return true if the collationType is to be passed\r
+ * to the methods generated by generateNull and\r
+ * generateDataValue.\r
+ * \r
+ * @param collationType Collation type of character values.\r
+ * @return true collationType will be pushed, false collationType will be ignored.\r
+ */\r
+ boolean pushCollationForDataValue(int collationType)\r
+ {\r
+ return false;\r
+ }\r
+\r
+ \r
+ /**\r
+ * Determine whether thisType is storable in otherType due to otherType\r
+ * being a user type.\r
+ *\r
+ * @param thisType The TypeId of the value to be stored\r
+ * @param otherType The TypeId of the value to be stored in\r
+ *\r
+ * @return true if thisType is storable in otherType\r
+ */\r
+ protected boolean userTypeStorable(TypeId thisType,\r
+ TypeId otherType,\r
+ ClassFactory cf)\r
+ {\r
+ /*\r
+ ** If the other type is user-defined, use the java types to determine\r
+ ** assignability.\r
+ */\r
+ if (otherType.userType())\r
+ {\r
+ return cf.getClassInspector().assignableTo(\r
+ thisType.getCorrespondingJavaTypeName(),\r
+ otherType.getCorrespondingJavaTypeName());\r
+ }\r
+\r
+ return false;\r
+ }\r
+ \r
+ /**\r
+ * Tell whether this numeric type can be converted to the given type.\r
+ *\r
+ * @param otherType The TypeId of the other type.\r
+ * @param forDataTypeFunction was this called from a scalarFunction like\r
+ * CHAR() or DOUBLE()\r
+ */\r
+ public boolean numberConvertible(TypeId otherType, \r
+ boolean forDataTypeFunction)\r
+ {\r
+\r
+ // Can't convert numbers to long types\r
+ if (otherType.isLongConcatableTypeId())\r
+ return false;\r
+\r
+ // Numbers can only be converted to other numbers, \r
+ // and CHAR, (not VARCHARS or LONGVARCHAR). \r
+ // Only with the CHAR() or VARCHAR()function can they be converted.\r
+ boolean retval =((otherType.isNumericTypeId()) ||\r
+ (otherType.isBooleanTypeId()) ||\r
+ (otherType.userType()));\r
+\r
+ // For CHAR Conversions, function can convert \r
+ // Floating types\r
+ if (forDataTypeFunction)\r
+ retval = retval || \r
+ (otherType.isFixedStringTypeId() &&\r
+ (getTypeId().isFloatingPointTypeId()));\r
+ \r
+ retval = retval ||\r
+ (otherType.isFixedStringTypeId() && \r
+ (!getTypeId().isFloatingPointTypeId()));\r
+ \r
+ return retval;\r
+\r
+ }\r
+\r
+ /**\r
+ * Tell whether this numeric type can be stored into from the given type.\r
+ *\r
+ * @param thisType The TypeId of this type\r
+ * @param otherType The TypeId of the other type.\r
+ * @param cf A ClassFactory\r
+ */\r
+\r
+ public boolean numberStorable(TypeId thisType,\r
+ TypeId otherType,\r
+ ClassFactory cf)\r
+ {\r
+ /*\r
+ ** Numbers can be stored into from other number types.\r
+ ** Also, user types with compatible classes can be stored into numbers.\r
+ */\r
+ if ((otherType.isNumericTypeId()) ||\r
+ (otherType.isBooleanTypeId()))\r
+ return true;\r
+\r
+ /*\r
+ ** If the other type is user-defined, use the java types to determine\r
+ ** assignability.\r
+ */\r
+ return userTypeStorable(thisType, otherType, cf);\r
+ }\r
+\r
+\r
+ /**\r
+ * Get the TypeId that corresponds to this TypeCompiler.\r
+ */\r
+ protected TypeId getTypeId()\r
+ {\r
+ return correspondingTypeId;\r
+ }\r
+\r
+ /**\r
+ * Get the TypeCompiler that corresponds to the given TypeId.\r
+ */\r
+ protected TypeCompiler getTypeCompiler(TypeId typeId)\r
+ {\r
+ return TypeCompilerFactoryImpl.staticGetTypeCompiler(typeId);\r
+ }\r
+\r
+ /**\r
+ * Set the TypeCompiler that corresponds to the given TypeId.\r
+ */\r
+ void setTypeId(TypeId typeId)\r
+ {\r
+ correspondingTypeId = typeId;\r
+ }\r
+\r
+ /**\r
+ * Get the StoredFormatId from the corresponding\r
+ * TypeId.\r
+ *\r
+ * @return The StoredFormatId from the corresponding\r
+ * TypeId.\r
+ */\r
+ protected int getStoredFormatIdFromTypeId()\r
+ {\r
+ return getTypeId().getTypeFormatId();\r
+ }\r
+\r
+ private static DataValueDescriptor gnn(DataValueFactory dvf)\r
+ {\r
+ return dvf.getNullInteger((NumberDataValue) null);\r
+ }\r
+ \r
+ private static DataValueDescriptor gnn2(DataValueFactory dvf)\r
+ {\r
+ return new SQLInteger();\r
+ }\r
+ \r
+\r
+}\r
+\r
+\r
+\r
+\r
+\r