/**
   * Returns true if a type is a simple cast of another type. It is if the cast type is nullable and
   * the cast is one of the following:
   * <li>x TO x
   * <li>char(n) TO varchar(m)
   * <li>varchar(n) TO varchar(m)
   * <li>x not null TO x nullable
   *
   * @param origType original type passed into the cast operand
   * @param castType type the operand will be casted to
   * @return true if the cast is simple
   */
  private boolean isCastSimple(RelDataType origType, RelDataType castType) {
    SqlTypeName origTypeName = origType.getSqlTypeName();
    SqlTypeName castTypeName = castType.getSqlTypeName();

    if (!(castType.isNullable())) {
      return false;
    }

    Charset origCharset = origType.getCharset();
    Charset castCharset = castType.getCharset();
    if ((origCharset != null) || (castCharset != null)) {
      if ((origCharset == null) || (castCharset == null)) {
        return false;
      }
      if (!origCharset.equals(castCharset)) {
        return false;
      }
    }

    return ((origType == castType)
        || ((origTypeName == SqlTypeName.CHAR) && (castTypeName == SqlTypeName.VARCHAR))
        || ((origTypeName == SqlTypeName.VARCHAR) && (castTypeName == SqlTypeName.VARCHAR))
        || ((origTypeName == castTypeName)
            && (origType.getPrecision() == castType.getPrecision())
            && ((origTypeName != SqlTypeName.DECIMAL)
                || (origType.getScale() == castType.getScale()))
            && (!origType.isNullable() && castType.isNullable())));
  }
Example #2
0
 private SqlNode toSql(RelDataType type) {
   if (dialect.getDatabaseProduct() == SqlDialect.DatabaseProduct.MYSQL) {
     final SqlTypeName sqlTypeName = type.getSqlTypeName();
     switch (sqlTypeName) {
       case VARCHAR:
         // MySQL doesn't have a VARCHAR type, only CHAR.
         return new SqlDataTypeSpec(
             new SqlIdentifier("CHAR", POS), type.getPrecision(), -1, null, null, POS);
       case INTEGER:
         return new SqlDataTypeSpec(
             new SqlIdentifier("_UNSIGNED", POS), type.getPrecision(), -1, null, null, POS);
     }
   }
   if (type instanceof BasicSqlType) {
     return new SqlDataTypeSpec(
         new SqlIdentifier(type.getSqlTypeName().name(), POS),
         type.getPrecision(),
         type.getScale(),
         type.getCharset() != null && dialect.supportsCharSet()
             ? type.getCharset().name()
             : null,
         null,
         POS);
   }
   throw new AssertionError(type); // TODO: implement
 }
 /**
  * Gets the right hand expression as a valid value to be assigned to the left hand side. Usually
  * returns the original rhs. However, if the lhs is of a primitive type, and the rhs is an
  * explicit null, returns a primitive value instead.
  */
 private Expression rhsAsValue() {
   if (SqlTypeUtil.isJavaPrimitive(lhsType) && (rhsType.getSqlTypeName() == SqlTypeName.NULL)) {
     if (lhsType.getSqlTypeName() == SqlTypeName.BOOLEAN) {
       return Literal.constantFalse();
     } else {
       return Literal.constantZero();
     }
   }
   return rhsExp;
 }
Example #4
0
        /** @pre SqlTypeUtil.sameNamedType(argTypes[0], (argTypes[1])) */
        public RelDataType inferReturnType(SqlOperatorBinding opBinding) {
          final RelDataType argType0 = opBinding.getOperandType(0);
          final RelDataType argType1 = opBinding.getOperandType(1);
          if (!(SqlTypeUtil.inCharOrBinaryFamilies(argType0)
              && SqlTypeUtil.inCharOrBinaryFamilies(argType1))) {
            Util.pre(
                SqlTypeUtil.sameNamedType(argType0, argType1),
                "SqlTypeUtil.sameNamedType(argTypes[0], argTypes[1])");
          }
          SqlCollation pickedCollation = null;
          if (SqlTypeUtil.inCharFamily(argType0)) {
            if (!SqlTypeUtil.isCharTypeComparable(opBinding.collectOperandTypes().subList(0, 2))) {
              throw opBinding.newError(
                  RESOURCE.typeNotComparable(
                      argType0.getFullTypeString(), argType1.getFullTypeString()));
            }

            pickedCollation =
                SqlCollation.getCoercibilityDyadicOperator(
                    argType0.getCollation(), argType1.getCollation());
            assert null != pickedCollation;
          }

          // Determine whether result is variable-length
          SqlTypeName typeName = argType0.getSqlTypeName();
          if (SqlTypeUtil.isBoundedVariableWidth(argType1)) {
            typeName = argType1.getSqlTypeName();
          }

          RelDataType ret;
          ret =
              opBinding
                  .getTypeFactory()
                  .createSqlType(typeName, argType0.getPrecision() + argType1.getPrecision());
          if (null != pickedCollation) {
            RelDataType pickedType;
            if (argType0.getCollation().equals(pickedCollation)) {
              pickedType = argType0;
            } else if (argType1.getCollation().equals(pickedCollation)) {
              pickedType = argType1;
            } else {
              throw Util.newInternal("should never come here");
            }
            ret =
                opBinding
                    .getTypeFactory()
                    .createTypeWithCharsetAndCollation(
                        ret, pickedType.getCharset(), pickedType.getCollation());
          }
          return ret;
        }
 public int getFieldJdbcType(int fieldOrdinal) {
   RelDataType type = getFieldNamedType(fieldOrdinal);
   SqlTypeName typeName = type.getSqlTypeName();
   if (typeName == null) {
     return Types.OTHER;
   }
   return typeName.getJdbcOrdinal();
 }
    /**
     * Checks for overflow when assigning one primitive type to another. Non-primitive types check
     * for overflow during assignment.
     */
    private void checkOverflow() {
      String maxLiteral = null;
      String minLiteral = null;
      if (lhsType == null) {
        return;
      }

      // Assume that equivalent types can be assigned without overflow
      if (lhsType.getSqlTypeName() == rhsType.getSqlTypeName()) {
        return;
      }

      // Approximate numerics have a wider range than exact numerics
      if (SqlTypeUtil.isApproximateNumeric(lhsType) && SqlTypeUtil.isExactNumeric(rhsType)) {
        return;
      }

      // We can skip an error check if the left type is "larger"
      if (SqlTypeUtil.isIntType(lhsType)
          && SqlTypeUtil.isIntType(rhsType)
          && (SqlTypeUtil.maxValue(lhsType) >= SqlTypeUtil.maxValue(rhsType))) {
        return;
      }
      if (SqlTypeUtil.isExactNumeric(lhsType)) {
        String numClassName = SqlTypeUtil.getNumericJavaClassName(lhsType);
        minLiteral = numClassName + ".MIN_VALUE";
        maxLiteral = numClassName + ".MAX_VALUE";
      } else if (SqlTypeUtil.isApproximateNumeric(lhsType)) {
        String numClassName = SqlTypeUtil.getNumericJavaClassName(lhsType);
        maxLiteral = numClassName + ".MAX_VALUE";
        minLiteral = "-" + maxLiteral;
      }
      if (maxLiteral == null) {
        return;
      }
      Statement ifstmt =
          new IfStatement(
              new BinaryExpression(
                  new BinaryExpression(
                      rhsExp, BinaryExpression.LESS, new Literal(Literal.STRING, minLiteral)),
                  BinaryExpression.LOGICAL_OR,
                  new BinaryExpression(
                      rhsExp, BinaryExpression.GREATER, new Literal(Literal.STRING, maxLiteral))),
              getThrowStmtList());
      addStatement(ifstmt);
    }
 public RelDataType getFieldType(int fieldOrdinal) {
   RelDataType namedType = getFieldNamedType(fieldOrdinal);
   if (namedType.getSqlTypeName() == SqlTypeName.DISTINCT) {
     // for most metadata calls, report information about the
     // predefined type on which the distinct type is based
     return namedType.getFields()[0].getType();
   } else {
     return namedType;
   }
 }
 public int getFieldScale(int fieldOrdinal) {
   RelDataType type = getFieldType(fieldOrdinal);
   SqlTypeName typeName = type.getSqlTypeName();
   if (typeName == null) {
     return 0;
   }
   if (typeName.allowsPrecScale(true, true)) {
     return type.getScale();
   } else {
     return 0;
   }
 }
 private boolean requiresSpecializedCast() {
   if ((rhsType != null)
       && (SqlTypeUtil.isNumeric(rhsType) || (rhsType.getSqlTypeName() == SqlTypeName.BOOLEAN))
       && SqlTypeUtil.inCharOrBinaryFamilies(lhsType)
       && !SqlTypeUtil.isLob(lhsType)) {
     // Boolean or Numeric to String.
     // sometimes the Integer got slipped by.
     return true;
   } else {
     return false;
   }
 }
Example #10
0
 public String getFieldTypeName(int fieldOrdinal) {
   RelDataType type = getFieldNamedType(fieldOrdinal);
   SqlTypeName typeName = type.getSqlTypeName();
   if (typeName == null) {
     return type.toString();
   }
   switch (typeName) {
     case STRUCTURED:
     case DISTINCT:
       return type.getSqlIdentifier().toString();
     case INTERVAL_DAY_TIME:
     case INTERVAL_YEAR_MONTH:
       return type.toString();
   }
   return typeName.name();
 }
    /**
     * 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();
    }
Example #12
0
 private SqlOperator toOp(SqlIdentifier name, Function function) {
   List<RelDataType> argTypes = new ArrayList<RelDataType>();
   List<SqlTypeFamily> typeFamilies = new ArrayList<SqlTypeFamily>();
   for (FunctionParameter o : function.getParameters()) {
     final RelDataType type = o.getType(typeFactory);
     argTypes.add(type);
     typeFamilies.add(Util.first(type.getSqlTypeName().getFamily(), SqlTypeFamily.ANY));
   }
   final RelDataType returnType;
   if (function instanceof ScalarFunction) {
     return new SqlUserDefinedFunction(
         name,
         ReturnTypes.explicit(Schemas.proto((ScalarFunction) function)),
         InferTypes.explicit(argTypes),
         OperandTypes.family(typeFamilies),
         toSql(argTypes),
         function);
   } else if (function instanceof AggregateFunction) {
     returnType = ((AggregateFunction) function).getReturnType(typeFactory);
     return new SqlUserDefinedAggFunction(
         name,
         ReturnTypes.explicit(returnType),
         InferTypes.explicit(argTypes),
         OperandTypes.family(typeFamilies),
         (AggregateFunction) function);
   } else if (function instanceof TableMacro) {
     return new SqlUserDefinedTableMacro(
         name,
         ReturnTypes.CURSOR,
         InferTypes.explicit(argTypes),
         OperandTypes.family(typeFamilies),
         (TableMacro) function);
   } else if (function instanceof TableFunction) {
     return new SqlUserDefinedTableFunction(
         name,
         ReturnTypes.CURSOR,
         InferTypes.explicit(argTypes),
         OperandTypes.family(typeFamilies),
         toSql(argTypes),
         (TableFunction) function);
   } else {
     throw new AssertionError("unknown function type " + function);
   }
 }
Example #13
0
  /**
   * Determines whether a {@link RexCall} requires decimal expansion. It usually requires expansion
   * if it has decimal operands.
   *
   * <p>Exceptions to this rule are:
   *
   * <ul>
   *   <li>isNull doesn't require expansion
   *   <li>It's okay to cast decimals to and from char types
   *   <li>It's okay to cast nulls as decimals
   *   <li>Casts require expansion if their return type is decimal
   *   <li>Reinterpret casts can handle a decimal operand
   * </ul>
   *
   * @param expr expression possibly in need of expansion
   * @param recurse whether to check nested calls
   * @return whether the expression requires expansion
   */
  public static boolean requiresDecimalExpansion(RexNode expr, boolean recurse) {
    if (!(expr instanceof RexCall)) {
      return false;
    }
    RexCall call = (RexCall) expr;

    boolean localCheck = true;
    switch (call.getKind()) {
      case Reinterpret:
      case IsNull:
        localCheck = false;
        break;
      case Cast:
        RelDataType lhsType = call.getType();
        RelDataType rhsType = call.operands[0].getType();
        if (rhsType.getSqlTypeName() == SqlTypeName.NULL) {
          return false;
        }
        if (SqlTypeUtil.inCharFamily(lhsType) || SqlTypeUtil.inCharFamily(rhsType)) {
          localCheck = false;
        } else if (SqlTypeUtil.isDecimal(lhsType) && (lhsType != rhsType)) {
          return true;
        }
        break;
      default:
        localCheck = call.getOperator().requiresDecimalExpansion();
    }

    if (localCheck) {
      if (SqlTypeUtil.isDecimal(call.getType())) {
        // NOTE jvs 27-Mar-2007: Depending on the type factory, the
        // result of a division may be decimal, even though both inputs
        // are integer.
        return true;
      }
      for (int i = 0; i < call.operands.length; i++) {
        if (SqlTypeUtil.isDecimal(call.operands[i].getType())) {
          return true;
        }
      }
    }
    return (recurse && requiresDecimalExpansion(call.operands, recurse));
  }
  // implement FarragoOJRexImplementor
  public Expression implementFarrago(
      FarragoRexToOJTranslator translator, RexCall call, Expression[] operands) {
    RelDataType lhsType = call.getType();
    RelDataType rhsType = call.operands[0].getType();
    Expression rhsExp = operands[0];

    SqlTypeName lhsTypeName = lhsType.getSqlTypeName();
    if ((lhsTypeName == SqlTypeName.CURSOR) || (lhsTypeName == SqlTypeName.COLUMN_LIST)) {
      // Conversion should already have been taken care of outside.
      return rhsExp;
    }

    // NOTE jvs 19-Nov-2008:  In some cases (e.g. FRG-273) a cast
    // may be illegal at the SQL level, but allowable as part of
    // implementation, so don't try to enforce
    // SqlTypeUtil.canCastFrom here.  Anything which was supposed
    // to have been prevented should already have been caught
    // by the validator.

    CastHelper helper =
        new CastHelper(translator, null, call.toString(), lhsType, rhsType, null, rhsExp);

    return helper.implement();
  }
Example #15
0
  <T> PrepareResult<T> prepare_(
      Context context, String sql, Queryable<T> queryable, Type elementType) {
    final JavaTypeFactory typeFactory = context.getTypeFactory();
    OptiqCatalogReader catalogReader = new OptiqCatalogReader(context.getRootSchema(), typeFactory);
    final OptiqPreparingStmt preparingStmt =
        new OptiqPreparingStmt(catalogReader, typeFactory, context.getRootSchema());
    preparingStmt.setResultCallingConvention(CallingConvention.ENUMERABLE);

    final RelDataType x;
    final PreparedResult preparedResult;
    if (sql != null) {
      assert queryable == null;
      SqlParser parser = new SqlParser(sql);
      SqlNode sqlNode;
      try {
        sqlNode = parser.parseQuery();
      } catch (SqlParseException e) {
        throw new RuntimeException("parse failed", e);
      }
      final Schema rootSchema = context.getRootSchema();
      SqlValidator validator =
          new SqlValidatorImpl(
              new ChainedSqlOperatorTable(
                  Arrays.<SqlOperatorTable>asList(
                      SqlStdOperatorTable.instance(),
                      new MySqlOperatorTable(rootSchema, typeFactory))),
              catalogReader,
              typeFactory,
              SqlConformance.Default) {};
      preparedResult = preparingStmt.prepareSql(sqlNode, Object.class, validator, true);
      x = validator.getValidatedNodeType(sqlNode);
    } else {
      assert queryable != null;
      x = context.getTypeFactory().createType(elementType);
      preparedResult = preparingStmt.prepareQueryable(queryable, x);
    }

    // TODO: parameters
    final List<Parameter> parameters = Collections.emptyList();
    // TODO: column meta data
    final List<ColumnMetaData> columns = new ArrayList<ColumnMetaData>();
    RelDataType jdbcType = makeStruct(typeFactory, x);
    for (RelDataTypeField field : jdbcType.getFields()) {
      RelDataType type = field.getType();
      SqlTypeName sqlTypeName = type.getSqlTypeName();
      columns.add(
          new ColumnMetaData(
              columns.size(),
              false,
              true,
              false,
              false,
              type.isNullable() ? 1 : 0,
              true,
              0,
              field.getName(),
              field.getName(),
              null,
              sqlTypeName.allowsPrec() && false ? type.getPrecision() : -1,
              sqlTypeName.allowsScale() ? type.getScale() : -1,
              null,
              null,
              sqlTypeName.getJdbcOrdinal(),
              sqlTypeName.getName(),
              true,
              false,
              false,
              null));
    }
    return new PrepareResult<T>(sql, parameters, columns, (Enumerable<T>) preparedResult.execute());
  }
    private Expression castToAssignableValueImpl() {
      if (requiresSpecializedCast()) {
        if (rhsType.isNullable() && (!SqlTypeUtil.isDecimal(rhsType))) {
          rhsExp = getValue(rhsType, rhsExp);
        }
        addStatement(
            new ExpressionStatement(
                new MethodCall(
                    lhsExp,
                    "cast",
                    new ExpressionList(rhsExp, Literal.makeLiteral(lhsType.getPrecision())))));
      } else {
        // Set current_date for casting time to timestamp. If
        // rhsType is null then we may have to be ready for anything.
        // But it will be null even for current_timestamp, so the
        // condition below seems a bit excessive.
        if ((lhsType.getSqlTypeName() == SqlTypeName.TIMESTAMP)
            && ((rhsType == null) || (rhsType.getSqlTypeName() == SqlTypeName.TIME))) {
          addStatement(
              new ExpressionStatement(
                  new MethodCall(lhsExp, "setCurrentDate", new ExpressionList(getCurrentDate()))));
        }
        addStatement(
            new ExpressionStatement(
                new MethodCall(
                    lhsExp, AssignableValue.ASSIGNMENT_METHOD_NAME, new ExpressionList(rhsExp))));
      }

      // Trim precision of datetime values.
      //
      if (((lhsType.getSqlTypeName() == SqlTypeName.TIMESTAMP)
          || (lhsType.getSqlTypeName() == SqlTypeName.TIME))) {
        if ((rhsType != null)
            // FIXME: JavaType(java.sql.Time) and
            // JavaType(java.sql.Timestamp) say they support precision
            // but do not.
            && !rhsType.toString().startsWith("JavaType(")
            && rhsType.getSqlTypeName().allowsPrec()
            && (lhsType.getPrecision() < rhsType.getPrecision())) {
          int lhsPrecision = lhsType.getPrecision();
          if (lhsPrecision == -1) {
            lhsPrecision = 0;
          }
          addStatement(
              new ExpressionStatement(
                  new MethodCall(
                      lhsExp,
                      SqlDateTimeWithoutTZ.ADJUST_PRECISION_METHOD_NAME,
                      new ExpressionList(Literal.makeLiteral(lhsPrecision)))));
        }
      }

      boolean mayNeedPadOrTruncate = false;
      if (SqlTypeUtil.inCharOrBinaryFamilies(lhsType) && !SqlTypeUtil.isLob(lhsType)) {
        mayNeedPadOrTruncate = true;
      }
      if (mayNeedPadOrTruncate) {
        // check overflow if it is datetime.
        // TODO: should check it at the run time.
        // so, it should be in the
        // cast(SqlDateTimeWithTZ, int precision);
        if ((rhsType != null) && (rhsType.getSqlTypeName() != null)) {
          SqlTypeName typeName = rhsType.getSqlTypeName();
          int precision = 0;
          switch (typeName) {
            case DATE:
              precision = 10;
              break;
            case TIME:
              precision = 8;
              break;
            case TIMESTAMP:
              precision = 19;
              break;
          }
          if ((precision != 0) && (precision > lhsType.getPrecision())) {
            addStatement(
                new IfStatement(
                    new BinaryExpression(
                        Literal.makeLiteral(precision),
                        BinaryExpression.GREATER,
                        Literal.makeLiteral(lhsType.getPrecision())),
                    getThrowStmtList()));
          }
        }
        if ((rhsType != null)
            && (rhsType.getFamily() == lhsType.getFamily())
            && !SqlTypeUtil.isLob(rhsType)) {
          // we may be able to skip pad/truncate based on
          // known facts about source and target precisions
          if (SqlTypeUtil.isBoundedVariableWidth(lhsType)) {
            if (lhsType.getPrecision() >= rhsType.getPrecision()) {
              // target precision is greater than source
              // precision, so truncation is impossible
              // and we can skip adjustment
              return lhsExp;
            }
          } else {
            if ((lhsType.getPrecision() == rhsType.getPrecision())
                && !SqlTypeUtil.isBoundedVariableWidth(rhsType)) {
              // source and target are both fixed-width, and
              // precisions are the same, so there's no adjustment
              // needed
              return lhsExp;
            }
          }
        }

        // determine target precision
        Expression precisionExp = Literal.makeLiteral(lhsType.getPrecision());

        // need to pad only for fixed width
        Expression needPadExp = Literal.makeLiteral(!SqlTypeUtil.isBoundedVariableWidth(lhsType));

        // pad character is 0 for binary, space for character
        Expression padByteExp;
        if (!SqlTypeUtil.inCharFamily(lhsType)) {
          padByteExp = new CastExpression(OJSystem.BYTE, Literal.makeLiteral(0));
        } else {
          padByteExp = new CastExpression(OJSystem.BYTE, Literal.makeLiteral(' '));
        }

        // generate the call to do the job
        addStatement(
            new ExpressionStatement(
                new MethodCall(
                    lhsExp,
                    BytePointer.ENFORCE_PRECISION_METHOD_NAME,
                    new ExpressionList(precisionExp, needPadExp, padByteExp))));
      }

      return lhsExp;
    }
    /**
     * 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();
    }
Example #18
0
 /** Converts an expression from {@link RexNode} to {@link SqlNode} format. */
 SqlNode toSql(RexProgram program, RexNode rex) {
   if (rex instanceof RexLocalRef) {
     final int index = ((RexLocalRef) rex).getIndex();
     return toSql(program, program.getExprList().get(index));
   } else if (rex instanceof RexInputRef) {
     return field(((RexInputRef) rex).getIndex());
   } else if (rex instanceof RexLiteral) {
     final RexLiteral literal = (RexLiteral) rex;
     switch (literal.getTypeName().getFamily()) {
       case CHARACTER:
         return SqlLiteral.createCharString((String) literal.getValue2(), POS);
       case NUMERIC:
       case EXACT_NUMERIC:
         return SqlLiteral.createExactNumeric(literal.getValue().toString(), POS);
       case APPROXIMATE_NUMERIC:
         return SqlLiteral.createApproxNumeric(literal.getValue().toString(), POS);
       case BOOLEAN:
         return SqlLiteral.createBoolean((Boolean) literal.getValue(), POS);
       case DATE:
         return SqlLiteral.createDate((Calendar) literal.getValue(), POS);
       case TIME:
         return SqlLiteral.createTime(
             (Calendar) literal.getValue(), literal.getType().getPrecision(), POS);
       case TIMESTAMP:
         return SqlLiteral.createTimestamp(
             (Calendar) literal.getValue(), literal.getType().getPrecision(), POS);
       case ANY:
         switch (literal.getTypeName()) {
           case NULL:
             return SqlLiteral.createNull(POS);
             // fall through
         }
       default:
         throw new AssertionError(literal + ": " + literal.getTypeName());
     }
   } else if (rex instanceof RexCall) {
     final RexCall call = (RexCall) rex;
     final SqlOperator op = call.getOperator();
     final List<SqlNode> nodeList = toSql(program, call.getOperands());
     if (op == SqlStdOperatorTable.CAST) {
       RelDataType type = call.getType();
       if (type.getSqlTypeName() == SqlTypeName.VARCHAR
           && dialect.getDatabaseProduct() == SqlDialect.DatabaseProduct.MYSQL) {
         // MySQL doesn't have a VARCHAR type, only CHAR.
         nodeList.add(
             new SqlDataTypeSpec(
                 new SqlIdentifier("CHAR", POS), type.getPrecision(), -1, null, null, POS));
       } else {
         nodeList.add(toSql(type));
       }
     }
     if (op == SqlStdOperatorTable.CASE) {
       final SqlNode valueNode;
       final List<SqlNode> whenList = Expressions.list();
       final List<SqlNode> thenList = Expressions.list();
       final SqlNode elseNode;
       if (nodeList.size() % 2 == 0) {
         // switched:
         //   "case x when v1 then t1 when v2 then t2 ... else e end"
         valueNode = nodeList.get(0);
         for (int i = 1; i < nodeList.size() - 1; i += 2) {
           whenList.add(nodeList.get(i));
           thenList.add(nodeList.get(i + 1));
         }
       } else {
         // other: "case when w1 then t1 when w2 then t2 ... else e end"
         valueNode = null;
         for (int i = 0; i < nodeList.size() - 1; i += 2) {
           whenList.add(nodeList.get(i));
           thenList.add(nodeList.get(i + 1));
         }
       }
       elseNode = nodeList.get(nodeList.size() - 1);
       return op.createCall(
           POS,
           valueNode,
           new SqlNodeList(whenList, POS),
           new SqlNodeList(thenList, POS),
           elseNode);
     }
     if (op instanceof SqlBinaryOperator && nodeList.size() > 2) {
       // In RexNode trees, OR and AND have any number of children;
       // SqlCall requires exactly 2. So, convert to a left-deep binary tree.
       return createLeftCall(op, nodeList);
     }
     return op.createCall(new SqlNodeList(nodeList, POS));
   } else {
     throw new AssertionError(rex);
   }
 }