use of com.hazelcast.jet.sql.impl.validate.HazelcastCallBinding in project hazelcast by hazelcast.
the class HazelcastSqlOperandMetadata method checkOperandTypes.
@Override
public final boolean checkOperandTypes(SqlCallBinding callBinding, boolean throwOnFailure) {
HazelcastCallBinding binding = prepareBinding(callBinding, operandTypeInference);
boolean checkResult;
if (ValidationUtil.hasAssignment(binding.getCall())) {
OperandChecker[] checkers = parameters.stream().map(HazelcastTableFunctionParameter::checker).toArray(OperandChecker[]::new);
checkResult = new NamedOperandCheckerProgram(checkers).check(binding, throwOnFailure);
} else {
OperandChecker[] checkers = parameters.stream().limit(binding.getOperandCount()).map(HazelcastTableFunctionParameter::checker).toArray(OperandChecker[]::new);
checkResult = new OperandCheckerProgram(checkers).check(binding, throwOnFailure);
}
return checkResult && checkOperandTypes(binding, throwOnFailure);
}
use of com.hazelcast.jet.sql.impl.validate.HazelcastCallBinding in project hazelcast by hazelcast.
the class BinaryOperatorOperandTypeInference method inferOperandTypes.
@Override
public void inferOperandTypes(SqlCallBinding binding, RelDataType returnType, RelDataType[] operandTypes) {
assert operandTypes.length == 2;
assert binding.getOperandCount() == 2;
boolean hasParameters = HazelcastTypeUtils.hasParameters(binding);
int knownTypeOperandIndex = -1;
RelDataType knownType = null;
for (int i = 0; i < binding.getOperandCount(); i++) {
operandTypes[i] = binding.getOperandType(i);
if (!operandTypes[i].equals(binding.getValidator().getUnknownType())) {
if (hasParameters && toHazelcastType(operandTypes[i]).getTypeFamily().isNumericInteger()) {
// If we are here, the operands are a parameter and a numeric expression.
// We widen the type of the numeric expression to BIGINT, so that an expression `1 > ?` is resolved to
// `(BIGINT)1 > (BIGINT)?` rather than `(TINYINT)1 > (TINYINT)?`
RelDataType newOperandType = createType(binding.getTypeFactory(), SqlTypeName.BIGINT, operandTypes[i].isNullable());
operandTypes[i] = newOperandType;
}
if (knownType == null || knownType.getSqlTypeName() == SqlTypeName.NULL) {
knownType = operandTypes[i];
knownTypeOperandIndex = i;
}
}
}
// since we cannot deduce the return type
if (knownType == null || knownType.getSqlTypeName() == SqlTypeName.NULL && hasParameters) {
throw new HazelcastCallBinding(binding).newValidationSignatureError();
}
if (SqlTypeName.INTERVAL_TYPES.contains(knownType.getSqlTypeName()) && operandTypes[1 - knownTypeOperandIndex].getSqlTypeName() == SqlTypeName.NULL) {
// If there is an interval on the one side and NULL on the other, assume that the other side is a TIMESTAMP,
// because this is the only viable overload.
operandTypes[1 - knownTypeOperandIndex] = createType(binding.getTypeFactory(), SqlTypeName.TIMESTAMP, true);
} else {
operandTypes[1 - knownTypeOperandIndex] = knownType;
}
}
use of com.hazelcast.jet.sql.impl.validate.HazelcastCallBinding in project hazelcast by hazelcast.
the class ComparisonOperatorOperandTypeInference method inferOperandTypes.
@Override
public void inferOperandTypes(SqlCallBinding binding, RelDataType returnType, RelDataType[] operandTypes) {
assert operandTypes.length == 2;
assert binding.getOperandCount() == 2;
boolean hasParameters = HazelcastTypeUtils.hasParameters(binding);
int knownTypeOperandIndex = -1;
RelDataType knownType = null;
for (int i = 0; i < binding.getOperandCount(); i++) {
operandTypes[i] = binding.getOperandType(i);
if (!operandTypes[i].equals(binding.getValidator().getUnknownType())) {
if (knownType == null || knownType.getSqlTypeName() == SqlTypeName.NULL) {
knownType = operandTypes[i];
knownTypeOperandIndex = i;
}
}
}
// since we cannot deduce the return type
if (knownType == null || knownType.getSqlTypeName() == SqlTypeName.NULL && hasParameters) {
throw new HazelcastCallBinding(binding).newValidationSignatureError();
}
if (SqlTypeName.INTERVAL_TYPES.contains(knownType.getSqlTypeName()) && operandTypes[1 - knownTypeOperandIndex].getSqlTypeName() == SqlTypeName.NULL) {
// If there is an interval on the one side and NULL on the other, assume that the other side is a TIMESTAMP,
// because this is the only viable overload.
operandTypes[1 - knownTypeOperandIndex] = createType(binding.getTypeFactory(), SqlTypeName.TIMESTAMP, true);
} else {
operandTypes[1 - knownTypeOperandIndex] = knownType;
}
}
use of com.hazelcast.jet.sql.impl.validate.HazelcastCallBinding in project hazelcast by hazelcast.
the class HazelcastInOperator method deriveType.
@Override
public RelDataType deriveType(SqlValidator validator, SqlValidatorScope scope, SqlCall call) {
final List<SqlNode> operands = call.getOperandList();
assert operands.size() == 2;
final SqlNode left = operands.get(0);
final SqlNode right = operands.get(1);
final RelDataTypeFactory typeFactory = validator.getTypeFactory();
RelDataType leftType = validator.deriveType(scope, left);
RelDataType rightType;
// Derive type for RHS.
if (right instanceof SqlNodeList) {
// Handle the 'IN (expr, ...)' form.
List<RelDataType> rightTypeList = new ArrayList<>();
SqlNodeList nodeList = (SqlNodeList) right;
for (SqlNode node : nodeList) {
if (node instanceof SqlLiteral) {
SqlLiteral lit = (SqlLiteral) node;
// We are not supporting raw NULL literals within IN right-hand side list.
if (lit.getValue() == null) {
throw validator.newValidationError(right, HZRESOURCE.noRawNullsAllowed());
}
}
RelDataType nodeType = validator.deriveType(scope, node);
rightTypeList.add(nodeType);
}
rightType = typeFactory.leastRestrictive(rightTypeList);
// Same rules as the VALUES operator (per SQL:2003 Part 2 Section 8.4, <in predicate>).
if (null == rightType && validator.config().typeCoercionEnabled()) {
// Do implicit type cast if it is allowed to.
rightType = validator.getTypeCoercion().getWiderTypeFor(rightTypeList, false);
}
if (null == rightType) {
throw validator.newValidationError(right, RESOURCE.incompatibleTypesInList());
}
// Record the RHS type for use by SqlToRelConverter.
validator.setValidatedNodeType(nodeList, rightType);
} else {
// We do not support sub-querying for IN operator.
throw validator.newValidationError(call, HZRESOURCE.noSubQueryAllowed());
}
HazelcastCallBinding hazelcastCallBinding = prepareBinding(new SqlCallBinding(validator, scope, call));
// Coerce type first.
if (hazelcastCallBinding.isTypeCoercionEnabled()) {
boolean coerced = hazelcastCallBinding.getValidator().getTypeCoercion().inOperationCoercion(hazelcastCallBinding);
if (coerced) {
// Update the node data type if we coerced any type.
leftType = validator.deriveType(scope, call.operand(0));
rightType = validator.deriveType(scope, call.operand(1));
}
}
// Now check that the left expression is compatible with the
// type of the list. Same strategy as the '=' operator.
// Normalize the types on both sides to be row types
// for the purposes of compatibility-checking.
RelDataType leftRowType = SqlTypeUtil.promoteToRowType(typeFactory, leftType, null);
RelDataType rightRowType = SqlTypeUtil.promoteToRowType(typeFactory, rightType, null);
final ComparableOperandTypeChecker checker = (ComparableOperandTypeChecker) OperandTypes.COMPARABLE_UNORDERED_COMPARABLE_UNORDERED;
if (!checker.checkOperandTypes(new ExplicitOperatorBinding(hazelcastCallBinding, ImmutableList.of(leftRowType, rightRowType)), hazelcastCallBinding)) {
throw validator.newValidationError(call, RESOURCE.incompatibleValueType(SqlStdOperatorTable.IN.getName()));
}
return typeFactory.createTypeWithNullability(typeFactory.createSqlType(SqlTypeName.BOOLEAN), anyNullable(leftRowType.getFieldList()) || anyNullable(rightRowType.getFieldList()));
}
use of com.hazelcast.jet.sql.impl.validate.HazelcastCallBinding in project hazelcast by hazelcast.
the class HazelcastOperandTypeCheckerAware method prepareBinding.
default HazelcastCallBinding prepareBinding(SqlCallBinding binding, SqlOperandTypeInference operandTypeInference) {
HazelcastSqlValidator validator = (HazelcastSqlValidator) binding.getValidator();
boolean resolveOperands = false;
for (int i = 0; i < binding.getOperandCount(); i++) {
RelDataType operandType = binding.getOperandType(i);
if (operandType.getSqlTypeName() == SqlTypeName.NULL) {
resolveOperands = true;
break;
}
}
if (resolveOperands) {
RelDataType unknownType = binding.getValidator().getUnknownType();
RelDataType[] operandTypes = new RelDataType[binding.getOperandCount()];
Arrays.fill(operandTypes, unknownType);
operandTypeInference.inferOperandTypes(binding, binding.getValidator().getUnknownType(), operandTypes);
for (int i = 0; i < binding.getOperandCount(); i++) {
validator.setValidatedNodeType(binding.getCall().operand(i), operandTypes[i]);
}
}
// Provide custom binding
return new HazelcastCallBinding(binding);
}
Aggregations