1 package com.mapd.calcite.parser;
7 import org.apache.calcite.rel.type.RelDataType;
8 import org.apache.calcite.rel.type.RelDataTypeFactory;
9 import org.apache.calcite.rel.type.RelDataTypeFactoryImpl;
10 import org.apache.calcite.rel.type.RelDataTypeField;
11 import org.apache.calcite.rel.type.RelDataTypeFieldImpl;
12 import org.apache.calcite.sql.SqlBasicCall;
13 import org.apache.calcite.sql.SqlBinaryOperator;
14 import org.apache.calcite.sql.SqlCall;
15 import org.apache.calcite.sql.SqlCallBinding;
16 import org.apache.calcite.sql.SqlKind;
17 import org.apache.calcite.sql.SqlNode;
18 import org.apache.calcite.sql.SqlSelect;
19 import org.apache.calcite.sql.type.ArraySqlType;
20 import org.apache.calcite.sql.type.IntervalSqlType;
21 import org.apache.calcite.sql.type.SqlTypeName;
22 import org.apache.calcite.sql.type.SqlTypeUtil;
23 import org.apache.calcite.sql.validate.SqlValidator;
24 import org.apache.calcite.sql.validate.SqlValidatorScope;
25 import org.apache.calcite.sql.validate.implicit.TypeCoercionImpl;
27 import java.util.ArrayList;
28 import java.util.List;
32 super(typeFactory, validator);
43 final List<ExtArgumentType> paramTypes = udtf.getArgTypes();
44 SqlCall permutedCall = callBinding.permutedCall();
45 assert paramTypes != null;
47 for (
int i = 0; i < permutedCall.operandCount(); i++) {
48 SqlNode operand = permutedCall.operand(i);
52 if (operand.getKind() == SqlKind.DEFAULT) {
56 RelDataType actualRelType = validator.deriveType(callBinding.getScope(), operand);
57 RelDataType formalRelType = toRelDataType(paramTypes.get(i), factory);
59 if (actualRelType.getSqlTypeName() == SqlTypeName.CURSOR) {
60 SqlCall cursorCall = (SqlCall) operand;
62 cursorCall.operand(0), i, callBinding.getScope(), udtf);
63 if (cursorScore < 0) {
67 }
else if (actualRelType != formalRelType) {
68 if (SqlTypeUtil.isInterval(actualRelType)
69 && SqlTypeUtil.isInterval(formalRelType)) {
71 IntervalSqlType actualInterval = (IntervalSqlType) actualRelType;
72 IntervalSqlType formalInterval = (IntervalSqlType) formalRelType;
73 if (actualInterval.getIntervalQualifier().isYearMonth()
74 == formalInterval.getIntervalQualifier().isYearMonth()) {
81 if (widerType == null) {
83 }
else if (!SqlTypeUtil.isTimestamp(widerType)
84 && SqlTypeUtil.sameNamedType(formalRelType, actualRelType)) {
88 }
else if (actualRelType == widerType) {
90 }
else if (widerType != actualRelType) {
104 SqlValidatorScope scope,
108 String formalOperandName = udtf.getExtendedParamNames().
get(index);
109 List<ExtArgumentType> formalFieldTypes =
110 udtf.getCursorFieldTypes().
get(formalOperandName);
112 if (formalFieldTypes == null || formalFieldTypes.size() == 0) {
114 "Warning: UDTF has no CURSOR field subtype data. Proceeding assuming CURSOR typechecks.");
120 switch (cursorOperand.getKind()) {
122 SqlSelect selectNode = (SqlSelect) cursorOperand;
124 int iFormal = 0, iActual = 0;
125 for (; iActual < selectNode.getSelectList().size()
126 && iFormal < formalFieldTypes.size();
127 iActual++, iFormal++) {
128 SqlNode selectOperand = selectNode.getSelectList().
get(iActual);
130 RelDataType formalRelType = toRelDataType(extType, factory);
131 RelDataType actualRelType = factory.createTypeWithNullability(
132 validator.deriveType(scope, selectOperand),
true);
135 if (formalRelType.getSqlTypeName() == SqlTypeName.COLUMN_LIST) {
137 RelDataType formalSubtype = toRelDataType(colListSubtype, factory);
139 if (isArrayType(colListSubtype)
140 && actualRelType.getSqlTypeName() == SqlTypeName.ARRAY) {
141 ArraySqlType formalArrayType = (ArraySqlType) formalSubtype;
142 ArraySqlType actualArrayType = (ArraySqlType) actualRelType;
143 if (!SqlTypeUtil.sameNamedType(formalArrayType.getComponentType(),
144 actualArrayType.getComponentType())) {
152 if (!SqlTypeUtil.sameNamedType(actualRelType, formalSubtype)) {
153 if (widerType == null || widerType == actualRelType) {
160 int numFormalArgumentsLeft = (formalFieldTypes.size() - 1) - iFormal;
162 selectNode.getSelectList().size() - numFormalArgumentsLeft - iActual;
163 while (colListSize < maxColListSize) {
164 SqlNode curOperand = selectNode.getSelectList().
get(iActual + colListSize);
165 actualRelType = scope.getValidator().deriveType(scope, curOperand);
167 if (!SqlTypeUtil.sameNamedType(actualRelType, formalSubtype)) {
168 if (widerType == null
169 || !SqlTypeUtil.sameNamedType(widerType, formalSubtype)) {
172 }
else if (widerType != formalSubtype) {
188 iActual += colListSize - 1;
189 }
else if (actualRelType != formalRelType) {
190 if (widerType == null) {
193 }
else if (!SqlTypeUtil.isTimestamp(widerType)
194 && SqlTypeUtil.sameNamedType(formalRelType, actualRelType)) {
198 }
else if (actualRelType == widerType
199 || !SqlTypeUtil.sameNamedType(widerType, formalRelType)) {
215 if (iActual < selectNode.getSelectList().size()) {
221 System.out.println(
"Unsupported subquery kind in UDTF CURSOR input argument: "
222 + cursorOperand.getKind());
234 RelDataType type1, RelDataType type2,
boolean stringPromotion) {
235 RelDataType returnType = super.getWiderTypeForTwo(type1, type2, stringPromotion);
236 if (SqlTypeUtil.isTimestamp(type1) && SqlTypeUtil.isTimestamp(type2)) {
237 returnType = (type1.getPrecision() > type2.getPrecision()) ? type1 : type2;
238 }
else if ((SqlTypeUtil.isDouble(type1) || SqlTypeUtil.isDouble(type2))
239 && (SqlTypeUtil.isApproximateNumeric(type1)
240 && SqlTypeUtil.isApproximateNumeric(type2))) {
241 returnType = factory.createTypeWithNullability(
242 factory.createSqlType(SqlTypeName.DOUBLE),
true);
253 boolean coerced =
false;
254 final List<ExtArgumentType> paramTypes = udtf.getArgTypes();
255 SqlCall permutedCall = callBinding.permutedCall();
256 for (
int i = 0; i < permutedCall.operandCount(); i++) {
257 SqlNode operand = permutedCall.operand(i);
258 if (operand.getKind() == SqlKind.DEFAULT) {
264 RelDataType actualRelType = validator.deriveType(callBinding.getScope(), operand);
266 if (actualRelType.getSqlTypeName() == SqlTypeName.CURSOR) {
267 SqlCall cursorCall = (SqlCall) operand;
269 callBinding.getScope(), permutedCall, i, cursorCall.operand(0), udtf);
272 RelDataType formalRelType = toRelDataType(paramTypes.get(i), factory);
273 if (actualRelType != formalRelType) {
274 if (SqlTypeUtil.isInterval(actualRelType)
275 && SqlTypeUtil.isInterval(formalRelType)) {
276 IntervalSqlType actualInterval = (IntervalSqlType) actualRelType;
277 IntervalSqlType formalInterval = (IntervalSqlType) formalRelType;
278 if (actualInterval.getIntervalQualifier().isYearMonth()
279 == formalInterval.getIntervalQualifier().isYearMonth()) {
284 if (!SqlTypeUtil.isTimestamp(widerType)
285 && SqlTypeUtil.sameNamedType(formalRelType, actualRelType)) {
290 coerced = coerceOperandType(callBinding.getScope(), permutedCall, i, widerType)
300 SqlNode cursorOperand,
302 String formalOperandName = udtf.getExtendedParamNames().
get(index);
303 List<ExtArgumentType> formalFieldTypes =
304 udtf.getCursorFieldTypes().
get(formalOperandName);
305 if (formalFieldTypes == null || formalFieldTypes.size() == 0) {
309 switch (cursorOperand.getKind()) {
311 SqlSelect selectNode = (SqlSelect) cursorOperand;
312 int iFormal = 0, iActual = 0;
313 List<RelDataTypeField> newValidatedTypeList =
new ArrayList<>();
314 for (; iActual < selectNode.getSelectList().size()
315 && iFormal < formalFieldTypes.size();
316 iFormal++, iActual++) {
317 SqlNode selectOperand = selectNode.getSelectList().
get(iActual);
319 RelDataType formalRelType = toRelDataType(extType, factory);
320 RelDataType actualRelType = validator.deriveType(scope, selectOperand);
323 if (isColumnArrayType(extType) || isColumnListArrayType(extType)) {
329 if (formalRelType.getSqlTypeName() == SqlTypeName.COLUMN_LIST) {
331 RelDataType formalSubtype = toRelDataType(colListSubtype, factory);
335 int numFormalArgumentsLeft = (formalFieldTypes.size() - 1) - iFormal;
337 selectNode.getSelectList().size() - numFormalArgumentsLeft - iActual;
338 while (colListSize < maxColListSize) {
339 SqlNode curOperand = selectNode.getSelectList().
get(iActual + colListSize);
340 actualRelType = scope.getValidator().deriveType(scope, curOperand);
342 if (!SqlTypeUtil.sameNamedType(actualRelType, formalSubtype)) {
343 if (widerType == null) {
345 }
else if (actualRelType != widerType) {
346 coerceColumnType(scope,
347 selectNode.getSelectList(),
348 iActual + colListSize,
356 newValidatedTypeList, selectNode, iActual + colListSize);
359 iActual += colListSize - 1;
360 }
else if (actualRelType != formalRelType) {
361 if (!SqlTypeUtil.isTimestamp(widerType)
362 && SqlTypeUtil.sameNamedType(actualRelType, formalRelType)) {
366 if (widerType != actualRelType) {
367 coerceColumnType(scope, selectNode.getSelectList(), iActual, widerType);
378 RelDataType newCursorStructType = factory.createStructType(newValidatedTypeList);
379 RelDataType newCursorType = factory.createTypeWithNullability(newCursorStructType,
380 validator.getValidatedNodeType(selectNode).isNullable());
381 validator.setValidatedNodeType(selectNode, newCursorType);
397 SqlValidatorScope scope, SqlNode node, RelDataType toType) {
398 RelDataType fromType = validator.deriveType(scope, node);
401 if (fromType == null) {
406 if (fromType instanceof RelDataTypeFactoryImpl.JavaType
407 && toType.getSqlTypeName() == fromType.getSqlTypeName()) {
412 if (toType.getSqlTypeName() == SqlTypeName.ANY
413 || fromType.getSqlTypeName() == SqlTypeName.ANY) {
418 if (SqlTypeUtil.isCharacter(toType) && SqlTypeUtil.isCharacter(fromType)) {
423 if (SqlTypeUtil.equalSansNullability(factory, fromType, toType)) {
427 assert SqlTypeUtil.canCastFrom(toType, fromType,
true);
435 List<RelDataTypeField> typeList, SqlSelect selectNode,
int operandIndex) {
436 SqlNode operand = selectNode.getSelectList().
get(operandIndex);
437 RelDataType newType = validator.getValidatedNodeType(operand);
438 if (operand instanceof SqlCall) {
439 SqlCall asCall = (SqlCall) operand;
440 if (asCall.getOperator().getKind() == SqlKind.AS) {
441 newType = validator.getValidatedNodeType(asCall.operand(0));
444 RelDataTypeField oldTypeField =
445 validator.getValidatedNodeType(selectNode).getFieldList().get(operandIndex);
446 RelDataTypeField newTypeField =
new RelDataTypeFieldImpl(
447 oldTypeField.getName(), oldTypeField.getIndex(), newType);
448 typeList.add(newTypeField);
458 RelDataType targetType, RelDataType originalType,
boolean isCursorArgument) {
460 int baseScore = isCursorArgument ? 100 : 1;
461 switch (originalType.getSqlTypeName()) {
467 if (SqlTypeUtil.isApproximateNumeric(targetType)) {
475 return baseScore * multiplier;
491 SqlBasicCall binOp, RelDataType targetType, SqlValidatorScope scope) {
492 if (binOp.getKind() == SqlKind.AS) {
493 binOp = binOp.operand(0);
495 coerceOperandType(scope, binOp, 0, targetType);
496 coerceOperandType(scope, binOp, 1, targetType);
508 SqlNode op, RelDataType targetType, SqlValidatorScope scope) {
509 if (op instanceof SqlBasicCall) {
510 SqlBasicCall asCall = (SqlBasicCall) op;
511 if (asCall.getOperator().getKind() == SqlKind.AS) {
512 SqlNode op2 = asCall.operand(0);
513 if (op2 instanceof SqlBasicCall) {
514 asCall = (SqlBasicCall) op2;
519 if (asCall.getOperator() instanceof SqlBinaryOperator) {
520 SqlNode lhs = asCall.operand(0);
521 SqlNode rhs = asCall.operand(1);
522 RelDataType lhsType = validator.deriveType(scope, lhs);
523 RelDataType rhsType = validator.deriveType(scope, rhs);
526 if (lhsType != targetType && rhsType != targetType
527 && (lhs.getKind() == SqlKind.LITERAL
528 || rhs.getKind() == SqlKind.LITERAL)) {
void updateValidatedType(List< RelDataTypeField > typeList, SqlSelect selectNode, int operandIndex)
boolean extTableFunctionTypeCoercion(SqlCallBinding callBinding, ExtTableFunction udtf)
boolean needToCast(SqlValidatorScope scope, SqlNode node, RelDataType toType)
boolean shouldCoerceBinOpOperand(SqlNode op, RelDataType targetType, SqlValidatorScope scope)
void coerceBinOpOperand(SqlBasicCall binOp, RelDataType targetType, SqlValidatorScope scope)
int getScoreForTypes(RelDataType targetType, RelDataType originalType, boolean isCursorArgument)
int calculateTypeCoercionScore(SqlCallBinding callBinding, ExtTableFunction udtf)
int calculateScoreForCursorOperand(SqlNode cursorOperand, int index, SqlValidatorScope scope, ExtTableFunction udtf)
void coerceCursorType(SqlValidatorScope scope, SqlCall call, int index, SqlNode cursorOperand, ExtTableFunction udtf)
HeavyDBTypeCoercion(RelDataTypeFactory typeFactory, SqlValidator validator)
RelDataType getWiderTypeForTwo(RelDataType type1, RelDataType type2, boolean stringPromotion)