📄 castnode.java
字号:
* * @exception StandardException Thrown on error */ public ValueNode remapColumnReferencesToExpressions() throws StandardException { castOperand = castOperand.remapColumnReferencesToExpressions(); return this; } /** * Return whether or not this expression tree represents a constant expression. * * @return Whether or not this expression tree represents a constant expression. */ public boolean isConstantExpression() { return castOperand.isConstantExpression(); } /** @see ValueNode#constantExpression */ public boolean constantExpression(PredicateList whereClause) { return castOperand.constantExpression(whereClause); } /** * By default unary operators don't accept ? parameters as operands. * This can be over-ridden for particular unary operators. * * @return Nothing * * @exception StandardException Always thrown to indicate a * ? parameter where it isn't allowed. */ void bindParameter() throws StandardException { ((ParameterNode) castOperand).setDescriptor(castTarget); } /** * Return an Object representing the bind time value of this * expression tree. If the expression tree does not evaluate to * a constant at bind time then we return null. * This is useful for bind time resolution of VTIs. * RESOLVE: What do we do for primitives? * * @return An Object representing the bind time value of this expression tree. * (null if not a bind time constant.) * * @exception StandardException Thrown on error */ Object getConstantValueAsObject() throws StandardException { Object sourceObject = castOperand.getConstantValueAsObject(); // RESOLVE - need to figure out how to handle casts if (sourceObject == null) { return null; } // Simple if source and destination are of same type if (sourceCTI.getCorrespondingJavaTypeName().equals( destCTI.getCorrespondingJavaTypeName())) { return sourceObject; } // RESOLVE - simply return null until we can figure out how to // do the cast return null; } /** * Do code generation for this unary operator. * * @param acb The ExpressionClassBuilder for the class we're generating * @param mb The method the code to place the code * * @return An expression to evaluate this operator * * @exception StandardException Thrown on error */ public void generateExpression(ExpressionClassBuilder acb, MethodBuilder mb) throws StandardException { castOperand.generateExpression(acb, mb); /* No need to generate code for null constants */ if (castOperand instanceof UntypedNullConstantNode) { return; } /* HACK ALERT. When casting a parameter, there * is not sourceCTI. Code generation requires one, * so we simply set it to be the same as the * destCTI. The user can still pass whatever * type they'd like in as a parameter. * They'll get an exception, as expected, if the * conversion cannot be performed. */ else if (castOperand.isParameterNode()) { sourceCTI = destCTI; } genDataValueConversion(acb, mb); } private void genDataValueConversion(ExpressionClassBuilder acb, MethodBuilder mb) throws StandardException { MethodBuilder acbConstructor = acb.getConstructor(); String resultTypeName = getTypeCompiler().interfaceName(); /* field = method call */ /* Allocate an object for re-use to hold the result of the operator */ LocalField field = acb.newFieldDeclaration(Modifier.PRIVATE, resultTypeName); /* ** Store the result of the method call in the field, so we can re-use ** the object. */ acb.generateNull(acbConstructor, getTypeCompiler(destCTI)); acbConstructor.setField(field); /* For most types generate targetDVD.setValue(sourceDVD); // optional for variable length types targetDVD.setWidth(); */ if (!sourceCTI.isNationalStringTypeId() && !sourceCTI.userType() && !destCTI.userType()) { mb.getField(field); // targetDVD reference for the setValue method call mb.swap(); mb.cast(ClassName.DataValueDescriptor); mb.callMethod(VMOpcode.INVOKEINTERFACE, ClassName.DataValueDescriptor, "setValue", "void", 1); mb.getField(field); /* ** If we are casting to a variable length datatype, we ** have to make sure we have set it to the correct ** length. */ if (destCTI.variableLength()) { boolean isNumber = destCTI.isNumericTypeId(); /* setWidth() is on VSDV - upcast since * decimal implements subinterface * of VSDV. */ mb.push(isNumber ? castTarget.getPrecision() : castTarget.getMaximumWidth()); mb.push(castTarget.getScale()); mb.push(!sourceCTI.variableLength() || isNumber); mb.callMethod(VMOpcode.INVOKEINTERFACE, ClassName.VariableSizeDataValue, "setWidth", ClassName.DataValueDescriptor, 3); /* setWidth returns DataValueDescriptor - we need * to cast result to actual subinterface getting returned. */ mb.cast(resultTypeName); } return; } /* ** If we are casting from a national string to a date, time, ** or timestamp, do a getDate(), getTime(), or getTimestamp() ** rather than a getObject(). This is because getObject() returns ** a String, and setValue() can't tell whether the String comes ** from a national or non-national character type, so it can't tell ** whether to use the database locale to do the conversion. */ String getMethod = "getObject"; String getType = "java.lang.Object"; String castType = sourceCTI.getCorrespondingJavaTypeName(); int argCount = 0; if (sourceCTI.isNationalStringTypeId()) { switch (destCTI.getJDBCTypeId()) { case Types.DATE: getMethod = "getDate"; getType = "java.sql.Date"; castType = getType; break; case Types.TIME: getMethod = "getTime"; getType = "java.sql.Time"; castType = getType; break; case Types.TIMESTAMP: getMethod = "getTimestamp"; getType = "java.sql.Timestamp"; castType = getType; break; } if (!getMethod.equals("getObject")) { mb.pushThis(); mb.callMethod(VMOpcode.INVOKEVIRTUAL, acb.getBaseClassName(), "getCalendar", "java.util.Calendar", 0); argCount++; } } /* ** generate: field.setValue((<type>) expr.getObject ) ** or field.setValue((<type>) expr.getDate ) ** or field.setValue((<type>) expr.getTime ) ** or field.setValue((<type>) expr.getTimestamp ) */ mb.callMethod(VMOpcode.INVOKEINTERFACE, ClassName.DataValueDescriptor, getMethod, getType, argCount); /* ** Cast to java.lang.Object if source or destination type ** is a java type because that's how the interface is defined. */ mb.cast(destCTI.userType() || sourceCTI.userType() ? "java.lang.Object" : castType); //castExpr mb.getField(field); // instance for the setValue/setObjectForCast method call mb.swap(); // push it before the value /* ** If we are casting a java type, then ** we generate: ** ** DataValueDescriptor.setObjectForCast(java.lang.Object castExpr, boolean instanceOfExpr, destinationClassName) ** where instanceOfExpr is "source instanceof destinationClass". ** ** otherwise: ** ** <specificDataValue>.setValue(<type>castExpr) */ if (sourceCTI.userType()) { String destinationType = getTypeId().getCorrespondingJavaTypeName(); // at this point method instance and cast result are on the stack // we duplicate the cast value in order to perform the instanceof check mb.dup(); mb.isInstanceOf(destinationType); mb.push(destinationType); mb.callMethod(VMOpcode.INVOKEINTERFACE, ClassName.DataValueDescriptor, "setObjectForCast", "void", 3); } else { String itype = ClassName.DataValueDescriptor; if (castType.startsWith("java.lang.")) { if (!castType.equals("java.lang.String") && !castType.equals("java.lang.Object")) itype = resultTypeName; } // System.out.println("type = " + castType); mb.callMethod(VMOpcode.INVOKEINTERFACE, itype, "setValue", "void", 1); // mb.endStatement(); } mb.getField(field); /* ** If we are casting to a variable length datatype, we ** have to make sure we have set it to the correct ** length. */ if (destCTI.variableLength()) { boolean isNumber = destCTI.isNumericTypeId(); /* setWidth() is on VSDV - upcast since * decimal implements subinterface * of VSDV. */ mb.push(isNumber ? castTarget.getPrecision() : castTarget.getMaximumWidth()); mb.push(castTarget.getScale()); mb.push(!sourceCTI.variableLength() || isNumber); mb.callMethod(VMOpcode.INVOKEINTERFACE, ClassName.VariableSizeDataValue, "setWidth", ClassName.DataValueDescriptor, 3); /* ** The last argument is true if we should ** throw error on truncation. We throw an ** error on all but Bits and Strings ** (everything with variable length that ** isn't a number -- all variable length ** except DECIMAL/NUMERIC). */ /* RESOLVE: ** NOTE: If the source is a parameter ** then the user can pass any type ** in as the parameter. We will not ** raise a truncation exception in ** this case, even if we would if the ** cast was directly on the value ** being passed in as a parameter. ** For example: ** cast(123 as char(1)) throws truncation ** exception ** cast(? as char(1)), user passes 123 ** no truncation exception ** We are considering this behavior to be ** an extension, at least for now. We may ** need to revisit this if there's a ** SQL-J compliance test with this. ** (The solution would be to add a method ** off of ParameterValueSet to get some ** info about the data type of the ** actual parameter and generate code for ** the 3rd parameter to setWidth() based ** on the execution time data type. */ /* setWidth returns DataValueDescriptor - we need * to cast result to actual subinterface getting returned. */ mb.cast(resultTypeName); } } /** * Accept a visitor, and call v.visit() * on child nodes as necessary. * * @param v the visitor * * @exception StandardException on error */ public Visitable accept(Visitor v) throws StandardException { Visitable returnNode = v.visit(this); if (v.skipChildren(this)) { return returnNode; } if (castOperand != null && !v.stopTraversal()) { castOperand = (ValueNode)castOperand.accept(v); } return returnNode; } /** set this to be a dataTypeScalarFunction * * @param b true to use function conversion rules */ public void setForDataTypeFunction(boolean b) { forDataTypeFunction = b; } /** is this a cast node for a data type scalar function? * @return true if this is a function, false for regular cast node * */ public boolean getForDataTypeFunction() { return forDataTypeFunction; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -