public RelDataType inferReturnType(SqlOperatorBinding opBinding) { RelDataType type1 = opBinding.getOperandType(0); RelDataType type2 = opBinding.getOperandType(1); if (SqlTypeUtil.isExactNumeric(type1) && SqlTypeUtil.isExactNumeric(type2)) { if (SqlTypeUtil.isDecimal(type1) || SqlTypeUtil.isDecimal(type2)) { int p1 = type1.getPrecision(); int p2 = type2.getPrecision(); int s1 = type1.getScale(); int s2 = type2.getScale(); int scale = Math.max(s1, s2); assert scale <= SqlTypeName.MAX_NUMERIC_SCALE; int precision = Math.max(p1 - s1, p2 - s2) + scale + 1; precision = Math.min(precision, SqlTypeName.MAX_NUMERIC_PRECISION); assert precision > 0; RelDataType ret; ret = opBinding.getTypeFactory().createSqlType(SqlTypeName.DECIMAL, precision, scale); return ret; } } return null; }
private RelDataType[] collectOperandTypes( SqlValidator validator, SqlValidatorScope scope, SqlCall call) { RelDataType[] argTypes = SqlTypeUtil.deriveAndCollectTypes(validator, scope, call.operands); RelDataType[] newArgTypes = { argTypes[VALUE_OPERAND], argTypes[LOWER_OPERAND], argTypes[UPPER_OPERAND] }; return newArgTypes; }
/** * 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)); }
/** @return true if all tuples match rowType; otherwise, assert on mismatch */ private boolean assertRowType() { for (List<RexLiteral> tuple : tuples) { assert tuple.size() == rowType.getFieldCount(); for (Pair<RexLiteral, RelDataTypeField> pair : Pair.zip(tuple, rowType.getFieldList())) { RexLiteral literal = pair.left; RelDataType fieldType = pair.right.getType(); // TODO jvs 19-Feb-2006: strengthen this a bit. For example, // overflow, rounding, and padding/truncation must already have // been dealt with. if (!RexLiteral.isNullLiteral(literal)) { assert (SqlTypeUtil.canAssignFrom(fieldType, literal.getType())); } } } return true; }
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; }
/** @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 static void checkCharsetAndCollateConsistentIfCharType(RelDataType type) { // (every charset must have a default collation) if (SqlTypeUtil.inCharFamily(type)) { Charset strCharset = type.getCharset(); Charset colCharset = type.getCollation().getCharset(); assert null != strCharset; assert null != colCharset; if (!strCharset.equals(colCharset)) { if (false) { // todo: enable this checking when we have a charset to // collation mapping throw new Error( type.toString() + " was found to have charset '" + strCharset.name() + "' and a mismatched collation charset '" + colCharset.name() + "'"); } } } }