/** Gets an expression for the current date */ private Expression getCurrentDate() { // unfortunately, we hard code the method name here return translator.convertVariable( translator.getTypeFactory().createSqlType(SqlTypeName.DATE), "getContextVariable_CURRENT_DATE", new ExpressionList()); }
/** * Adds the statement to the statement list if it is not null. Otherwise, adds the statement to * the translator list. * * @param stmt the statement to be added */ private void addStatement(Statement stmt) { if (stmtList == null) { translator.addStatement(stmt); } else { stmtList.add(stmt); } }
/** * Implement the cast expression. * * <p>TODO: check for overflow * * @return the rhs expression casted as the lhs type */ public Expression implement() { // Check for invalid null assignment. Code generated afterwards // can assume null will never be assigned to a not null value. checkNotNull(); // Check for an explicit rhs null value. Code generated // afterwards need never check for an explicit null. if (rhsType.getSqlTypeName() == SqlTypeName.NULL) { if (lhsType.isNullable()) { return castFromNull(); } else { // NOTE jvs 27-Jan-2005: this code will never actually // be executed do to previous checkNotNull test, but // it still has to compile! return rhsAsValue(); } } // Case when left hand side is a nullable primitive if (translator.isNullablePrimitive(lhsType)) { if (SqlTypeUtil.isJavaPrimitive(rhsType) && (!rhsType.isNullable() || translator.isNullablePrimitive(rhsType))) { return castPrimitiveToNullablePrimitive(); } return castToAssignableValue(); } // Case when left hand side is a not nullable primitive if (SqlTypeUtil.isJavaPrimitive(lhsType)) { return castToNotNullPrimitive(); } // Case when left hand side is a structure if (lhsType.isStruct()) { assert (rhsType.isStruct()); // TODO jvs 27-May-2004: relax this assert and deal with // conversions, null checks, etc. assert (lhsType.equals(rhsType)); return getDirectAssignment(); } // Default is to treat non-primitives as AssignableValue return castToAssignableValue(); }
/** Gets the OJ class for a RelDataType */ private OJClass getClass(RelDataType type) { // TODO: is this code any better? // OJUtil.typeToOJClass( // rhsType, // translator.getFarragoTypeFactory()); FarragoTypeFactory factory = translator.getFarragoTypeFactory(); return OJClass.forClass(factory.getClassForPrimitive(type)); }
/** * Gets the right hand expression as a simple Java value. If the rhs is a more complex * expression, then creates a scratch variable and assigns the right hand expression to it. Then * returns the scratch variable. */ private Expression rhsAsJava() { if (!RelDataTypeFactoryImpl.isJavaType(rhsType)) { Variable variable = translator.createScratchVariable(rhsType); addStatement( new ExpressionStatement( new AssignmentExpression(variable, AssignmentExpression.EQUALS, rhsExp))); return variable; } return rhsExp; }
/** Generates code to throw an exception when a NULL value is casted to a NOT NULL type */ private void checkNotNull() { if (!lhsType.isNullable() && rhsType.isNullable()) { rhsExp = rhsAsJava(); addStatement( new ExpressionStatement( new MethodCall( translator.getRelImplementor().getConnectionVariable(), "checkNotNull", new ExpressionList(Literal.makeLiteral(targetName), rhsExp)))); } }
/** * Generates code to round an expression according to the Farrago convention. The Farrago * convention is to round away from zero. Rounding is performed with the following algorithm. * * <pre> * in = rhs; * if (value < 0) { * in = -in; * out = Math.round(in); * out = -out; * } else { * out = Math.round(in); * } * </pre> * * <p>PRECONDITION: rhsExp must be an unwrapped (not null) Java primitive * * <p>TODO: account for overflow in both unary minus and round. */ private Expression roundAway() { // Get the primitive part of right hand side RelDataType inType = translator.getTypeFactory().createTypeWithNullability(rhsType, false); // TODO: is there any preference between stack and instance var? OJClass inClass = getClass(inType); Variable inTemp = translator.getRelImplementor().newVariable(); translator.addStatement(declareStackVar(inClass, inTemp, rhsExp)); OJClass outClass = getLhsClass(); Variable outTemp = translator.getRelImplementor().newVariable(); translator.addStatement(declareStackVar(outClass, outTemp, null)); boolean isLong = translator.getFarragoTypeFactory().getClassForPrimitive(lhsType) == long.class; addStatement( new IfStatement( new BinaryExpression(inTemp, BinaryExpression.LESS, Literal.constantZero()), new StatementList( assign(inTemp, minus(inClass, inTemp)), assign(outTemp, round(lhsClass, inTemp, isLong)), assign(outTemp, minus(outClass, outTemp))), new StatementList(assign(outTemp, round(lhsClass, inTemp, isLong))))); return outTemp; }
/** Creates a field access, as in expr.[value] */ private Expression getValue(RelDataType type, Expression expr) { FarragoTypeFactory factory = (FarragoTypeFactory) translator.getTypeFactory(); return factory.getValueAccessExpression(type, expr); }
/** Creates a left hand side variable if one was not provided. */ private void ensureLhs() { if (lhsExp == null) { lhsExp = translator.createScratchVariable(lhsType); } }
/** * Casts the rhs to a non nullable primitive value. Non nullable primitive values only have a * single value field. */ private Expression castToNotNullPrimitive() { // If the left and the right types are the same, perform a // trivial cast. if (lhsType == rhsType) { return getDirectAssignment(); } // Retrieve the value of the right side if it is a nullable // primitive or a Datetime or an Interval type. // TODO: is Decimal a nullable primitive? if (translator.isNullablePrimitive(rhsType) || SqlTypeUtil.isDatetime(rhsType) || SqlTypeUtil.isInterval(rhsType)) { rhsExp = getValue(rhsType, rhsExp); } // Get the name of the numeric class such as Byte, Short, etc. String numClassName = SqlTypeUtil.getNumericJavaClassName(lhsType); OJClass lhsClass = getLhsClass(); // When casting from a string (or binary) to a number, trim the // value and perform the cast by calling a class-specific parsing // function. if ((numClassName != null) && SqlTypeUtil.inCharOrBinaryFamilies(rhsType) && !SqlTypeUtil.isLob(rhsType)) { // TODO: toString will cause too much garbage collection. rhsExp = new MethodCall(rhsExp, "toString", new ExpressionList()); rhsExp = new MethodCall(rhsExp, "trim", new ExpressionList()); String methodName = "parse" + numClassName; if (lhsType.getSqlTypeName() == SqlTypeName.INTEGER) { methodName = "parseInt"; } rhsExp = new MethodCall( new Literal(Literal.STRING, numClassName), methodName, new ExpressionList(rhsExp)); Variable outTemp = translator.getRelImplementor().newVariable(); translator.addStatement( new VariableDeclaration( TypeName.forOJClass(lhsClass), new VariableDeclarator(outTemp.toString(), rhsExp))); rhsExp = outTemp; // Note: this check for overflow should only be required // when the string conversion does not perform a check. checkOverflow(); } else if ((lhsType.getSqlTypeName() == SqlTypeName.BOOLEAN) && SqlTypeUtil.inCharOrBinaryFamilies(rhsType) && !SqlTypeUtil.isLob(rhsType)) { // Casting from string to boolean relies on the runtime type. // Note: string is trimmed by conversion method. // TODO: toString will cause too much garbage collection. Expression str = new MethodCall(rhsExp, "toString", new ExpressionList()); rhsExp = new MethodCall( OJClass.forClass(NullablePrimitive.NullableBoolean.class), "convertString", new ExpressionList(str)); } else { // In general, check for overflow checkOverflow(); } roundAsNeeded(); rhsExp = new CastExpression(lhsClass, rhsExp); return getDirectAssignment(); }
/** * Implements a cast from NULL. Creates a scratch variable if one was not provided and assigns * NULL to it. */ private Expression castFromNull() { ensureLhs(); addStatement(translator.createSetNullStatement(lhsExp, true)); return lhsExp; }