/** * Tell whether this numeric type can be stored into from the given type. * * @param thisType The TypeId of this type * @param otherType The TypeId of the other type. * @param cf A ClassFactory */ public boolean numberStorable(TypeId thisType, TypeId otherType, ClassFactory cf) { /* ** Numbers can be stored into from other number types. ** Also, user types with compatible classes can be stored into numbers. */ if ((otherType.isNumericTypeId()) || (otherType.isBooleanTypeId())) return true; /* ** If the other type is user-defined, use the java types to determine ** assignability. */ return userTypeStorable(thisType, otherType, cf); }
/** * Determine whether thisType is storable in otherType due to otherType being a user type. * * @param thisType The TypeId of the value to be stored * @param otherType The TypeId of the value to be stored in * @return true if thisType is storable in otherType */ protected boolean userTypeStorable(TypeId thisType, TypeId otherType, ClassFactory cf) { /* ** If the other type is user-defined, use the java types to determine ** assignability. */ if (otherType.userType()) { return cf.getClassInspector() .assignableTo( thisType.getCorrespondingJavaTypeName(), otherType.getCorrespondingJavaTypeName()); } return false; }
/** * Tell whether this numeric type can be converted to the given type. * * @param otherType The TypeId of the other type. * @param forDataTypeFunction was this called from a scalarFunction like CHAR() or DOUBLE() */ public boolean numberConvertible(TypeId otherType, boolean forDataTypeFunction) { // Can't convert numbers to long types if (otherType.isLongConcatableTypeId()) return false; // Numbers can only be converted to other numbers, // and CHAR, (not VARCHARS or LONGVARCHAR). // Only with the CHAR() or VARCHAR()function can they be converted. boolean retval = ((otherType.isNumericTypeId()) || (otherType.isBooleanTypeId()) || (otherType.userType())); // For CHAR Conversions, function can convert // Floating types if (forDataTypeFunction) retval = retval || (otherType.isFixedStringTypeId() && (getTypeId().isFloatingPointTypeId())); retval = retval || (otherType.isFixedStringTypeId() && (!getTypeId().isFloatingPointTypeId())); return retval; }
/** * Tell whether this type (numeric) is compatible with the given type. * * @param otherType The TypeId of the other type. */ public boolean compatible(TypeId otherType) { // Numbers can only be compatible with other numbers. return (otherType.isNumericTypeId()); }
/** * @see TypeCompiler#resolveArithmeticOperation * @exception StandardException Thrown on error */ public DataTypeDescriptor resolveArithmeticOperation( DataTypeDescriptor leftType, DataTypeDescriptor rightType, String operator) throws StandardException { NumericTypeCompiler higherTC; DataTypeDescriptor higherType; boolean nullable; int precision, scale, maximumWidth; /* ** Check the right type to be sure it's a number. By convention, ** we call this method off the TypeId of the left operand, so if ** we get here, we know the left operand is a number. */ if (SanityManager.DEBUG) SanityManager.ASSERT( leftType.getTypeId().isNumericTypeId(), "The left type is supposed to be a number because we're resolving an arithmetic operator"); TypeId leftTypeId = leftType.getTypeId(); TypeId rightTypeId = rightType.getTypeId(); boolean supported = true; if (!(rightTypeId.isNumericTypeId())) { supported = false; } if (TypeCompiler.MOD_OP.equals(operator)) { switch (leftTypeId.getJDBCTypeId()) { case java.sql.Types.TINYINT: case java.sql.Types.SMALLINT: case java.sql.Types.INTEGER: case java.sql.Types.BIGINT: break; default: supported = false; break; } switch (rightTypeId.getJDBCTypeId()) { case java.sql.Types.TINYINT: case java.sql.Types.SMALLINT: case java.sql.Types.INTEGER: case java.sql.Types.BIGINT: break; default: supported = false; break; } } if (!supported) { throw StandardException.newException( SQLState.LANG_BINARY_OPERATOR_NOT_SUPPORTED, operator, leftType.getTypeId().getSQLTypeName(), rightType.getTypeId().getSQLTypeName()); } /* ** Take left as the higher precedence if equal */ if (rightTypeId.typePrecedence() > leftTypeId.typePrecedence()) { higherType = rightType; higherTC = (NumericTypeCompiler) getTypeCompiler(rightTypeId); } else { higherType = leftType; higherTC = (NumericTypeCompiler) getTypeCompiler(leftTypeId); } /* The calculation of precision and scale should be based upon * the type with higher precedence, which is going to be the result * type, this is also to be consistent with maximumWidth. Beetle 3906. */ precision = higherTC.getPrecision(operator, leftType, rightType); scale = higherTC.getScale(operator, leftType, rightType); if (higherType.getTypeId().isDecimalTypeId()) { maximumWidth = (scale > 0) ? precision + 3 : precision + 1; /* ** Be careful not to overflow */ if (maximumWidth < precision) { maximumWidth = Integer.MAX_VALUE; } } else { maximumWidth = higherType.getMaximumWidth(); } /* The result is nullable if either side is nullable */ nullable = leftType.isNullable() || rightType.isNullable(); /* ** The higher type does not have the right nullability. Create a ** new DataTypeDescriptor that has the correct type and nullability. ** ** It's OK to call the implementation of the DataTypeDescriptorFactory ** here, because we're in the same package. */ return new DataTypeDescriptor(higherType.getTypeId(), precision, scale, nullable, maximumWidth); }