/**
   * 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())));
  }
    /**
     * Casts the rhs to an {@link AssignableValue} using that interface's standard assignment
     * method. i.e.
     *
     * <pre>
     * [AssignableValueType] lhs;
     * lhs.[assignMethod](rhs);
     * </pre>
     *
     * or perhaps a type-specific cast:
     *
     * <pre>
     * [AssignableValueType] lhs;
     * lhs.[castMethod](rhs, lhs.getPrecision());
     * </pre>
     *
     * <p>Code is also generated to pad and truncate values which need special handling, such as
     * date and time types. Plus good old null handling.
     */
    private Expression castToAssignableValue() {
      ensureLhs();

      if (requiresSpecializedCast() && rhsType.isNullable()) {
        assert (lhsType.isNullable());

        // propagate null value; normally, we can rely on
        // assignFrom to do it for us, but for specialized casts,
        // we can't
        Expression nullTest =
            new MethodCall(rhsExp, NullableValue.NULL_IND_ACCESSOR_NAME, new ExpressionList());
        addStatement(
            new ExpressionStatement(
                new MethodCall(
                    lhsExp, NullableValue.NULL_IND_MUTATOR_NAME, new ExpressionList(nullTest))));
        StatementList ifStmtList = new StatementList();
        addStatement(new IfStatement(not(nullTest), ifStmtList));
        borrowStmtList(ifStmtList);
        try {
          return castToAssignableValueImpl();
        } finally {
          returnStmtList(ifStmtList);
        }
      } else {
        return castToAssignableValueImpl();
      }
    }
 /** 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))));
   }
 }
Esempio n. 4
0
 /**
  * Replaces the operands of a call. The new operands' types must match the old operands' types.
  */
 public static RexCall replaceOperands(RexCall call, RexNode[] operands) {
   if (call.operands == operands) {
     return call;
   }
   for (int i = 0; i < operands.length; i++) {
     RelDataType oldType = call.operands[i].getType();
     RelDataType newType = operands[i].getType();
     if (!oldType.isNullable() && newType.isNullable()) {
       throw Util.newInternal("invalid nullability");
     }
     assert (oldType.toString().equals(newType.toString()));
   }
   return new RexCall(call.getType(), call.getOperator(), operands);
 }
    /**
     * Implements a cast from any Java primitive to a nullable Java primitive as a simple
     * assignment. i.e.
     *
     * <pre>
     * [NullablePrimitiveType] lhs;
     * lhs.[nullIndicator] = ...;
     * if (! lhs.[nullIndicator]) {
     *     // check overflow ...
     *     // round ...
     *     lhs.[value] = ...;
     * }
     * </pre>
     */
    private Expression castPrimitiveToNullablePrimitive() {
      ensureLhs();
      boolean nullableSource = rhsType.isNullable();
      Expression rhsIsNull;
      if (nullableSource) {
        rhsIsNull = getNullIndicator(rhsExp);
        rhsExp = getValue(rhsType, rhsExp);
      } else {
        rhsIsNull = Literal.constantFalse();
      }

      addStatement(assign(getNullIndicator(lhsExp), rhsIsNull));
      StatementList setValueBlock = new StatementList();
      StatementList oldList = borrowStmtList(setValueBlock);
      try {
        checkOverflow();
        roundAsNeeded();
        addStatement(assign(getValue(lhsType, lhsExp), new CastExpression(getLhsClass(), rhsExp)));
      } finally {
        returnStmtList(oldList);
      }
      if (nullableSource) {
        addStatement(new IfStatement(not(getNullIndicator(lhsExp)), setValueBlock));
      } else {
        addStatementList(setValueBlock);
      }
      return lhsExp;
    }
    /**
     * 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();
    }
Esempio n. 7
0
 public RelDataType inferReturnType(SqlOperatorBinding opBinding) {
   RelDataType type1 = opBinding.getOperandType(0);
   if (SqlTypeUtil.isDecimal(type1)) {
     if (type1.getScale() == 0) {
       return type1;
     } else {
       int p = type1.getPrecision();
       RelDataType ret;
       ret = opBinding.getTypeFactory().createSqlType(SqlTypeName.DECIMAL, p, 0);
       if (type1.isNullable()) {
         ret = opBinding.getTypeFactory().createTypeWithNullability(ret, true);
       }
       return ret;
     }
   }
   return null;
 }
    private void reduceCasts(RexCall outerCast) {
      RexNode[] operands = outerCast.getOperands();
      if (operands.length != 1) {
        return;
      }
      RelDataType outerCastType = outerCast.getType();
      RelDataType operandType = operands[0].getType();
      if (operandType.equals(outerCastType)) {
        removableCasts.add(outerCast);
        return;
      }

      // See if the reduction
      // CAST((CAST x AS type) AS type NOT NULL)
      // -> CAST(x AS type NOT NULL)
      // applies.  TODO jvs 15-Dec-2008:  consider
      // similar cases for precision changes.
      if (!(operands[0] instanceof RexCall)) {
        return;
      }
      RexCall innerCast = (RexCall) operands[0];
      if (innerCast.getOperator() != SqlStdOperatorTable.castFunc) {
        return;
      }
      if (innerCast.getOperands().length != 1) {
        return;
      }
      RelDataTypeFactory typeFactory = preparingStmt.getFarragoTypeFactory();
      RelDataType outerTypeNullable = typeFactory.createTypeWithNullability(outerCastType, true);
      RelDataType innerTypeNullable = typeFactory.createTypeWithNullability(operandType, true);
      if (outerTypeNullable != innerTypeNullable) {
        return;
      }
      if (operandType.isNullable()) {
        removableCasts.add(innerCast);
      }
    }
Esempio n. 9
0
 public int isFieldNullable(int fieldOrdinal) {
   RelDataType type = getFieldType(fieldOrdinal);
   return type.isNullable() ? ResultSetMetaData.columnNullable : ResultSetMetaData.columnNoNulls;
 }
  // implement FarragoMedDataServer
  public FarragoMedColumnSet newColumnSet(
      String[] localName,
      Properties tableProps,
      FarragoTypeFactory typeFactory,
      RelDataType rowType,
      Map<String, Properties> columnPropMap)
      throws SQLException {
    if (rowType == null) {
      rowType = createMockRowType(typeFactory);
    }

    assert (rowType.getFieldList().size() == 1);
    RelDataType type = rowType.getFields()[0].getType();
    assert (!type.isNullable());
    assert (typeFactory.getClassForPrimitive(type) != null);

    // TODO jvs 5-Aug-2005:  clean up usage of server properties
    // as defaults

    long nRows = -1;
    String rowCountSql = tableProps.getProperty(PROP_ROW_COUNT_SQL);
    if (rowCountSql != null) {
      // Attempt to issue a loopback query into Farrago to
      // get the number of rows to produce.
      DataSource loopbackDataSource = getLoopbackDataSource();
      Connection connection = null;
      if (loopbackDataSource != null) {
        try {
          connection = loopbackDataSource.getConnection();
          Statement stmt = connection.createStatement();
          ResultSet resultSet = stmt.executeQuery(rowCountSql);
          if (resultSet.next()) {
            nRows = resultSet.getLong(1);
          }
        } finally {
          // It's OK not to clean up stmt and resultSet;
          // connection.close() will do that for us.
          if (connection != null) {
            connection.close();
          }
        }
      }
    }

    if (nRows == -1) {
      nRows =
          getLongProperty(
              tableProps, PROP_ROW_COUNT, getLongProperty(getProperties(), PROP_ROW_COUNT, 10));
    }

    String executorImpl =
        tableProps.getProperty(
            PROP_EXECUTOR_IMPL, getProperties().getProperty(PROP_EXECUTOR_IMPL, PROPVAL_JAVA));
    assert (executorImpl.equals(PROPVAL_JAVA) || executorImpl.equals(PROPVAL_FENNEL));

    String udxSpecificName = tableProps.getProperty(PROP_UDX_SPECIFIC_NAME);

    if (udxSpecificName != null) {
      assert (executorImpl.equals(PROPVAL_JAVA));
    }

    checkNameMatch(getForeignSchemaName(), tableProps.getProperty(PROP_SCHEMA_NAME));

    checkNameMatch(getForeignTableName(), tableProps.getProperty(PROP_TABLE_NAME));

    return new MedMockColumnSet(this, localName, rowType, nRows, executorImpl, udxSpecificName);
  }
    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;
    }