/** * 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; }
/** 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)))); } }
/** * 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(); }