1 package com.mapd.calcite.parser;
8 import org.apache.calcite.rel.type.RelDataType;
9 import org.apache.calcite.rel.type.RelDataTypeFactory;
10 import org.apache.calcite.rel.type.RelDataTypeFactoryImpl;
11 import org.apache.calcite.rel.type.RelDataTypeField;
12 import org.apache.calcite.rel.type.RelDataTypeFieldImpl;
13 import org.apache.calcite.sql.SqlBasicCall;
14 import org.apache.calcite.sql.SqlBinaryOperator;
15 import org.apache.calcite.sql.SqlCall;
16 import org.apache.calcite.sql.SqlCallBinding;
17 import org.apache.calcite.sql.SqlKind;
18 import org.apache.calcite.sql.SqlNode;
19 import org.apache.calcite.sql.SqlSelect;
20 import org.apache.calcite.sql.type.ArraySqlType;
21 import org.apache.calcite.sql.type.IntervalSqlType;
22 import org.apache.calcite.sql.type.SqlTypeName;
23 import org.apache.calcite.sql.type.SqlTypeUtil;
24 import org.apache.calcite.sql.validate.SqlValidator;
25 import org.apache.calcite.sql.validate.SqlValidatorScope;
26 import org.apache.calcite.sql.validate.implicit.TypeCoercionImpl;
28 import java.util.ArrayList;
29 import java.util.List;
33 super(typeFactory, validator);
44 final List<ExtArgumentType> paramTypes = udtf.getArgTypes();
45 SqlCall permutedCall = callBinding.permutedCall();
46 assert paramTypes != null;
48 for (
int i = 0; i < permutedCall.operandCount(); i++) {
49 SqlNode operand = permutedCall.operand(i);
53 if (operand.getKind() == SqlKind.DEFAULT) {
57 RelDataType actualRelType = validator.deriveType(callBinding.getScope(), operand);
58 RelDataType formalRelType = toRelDataType(paramTypes.get(i), factory);
60 if (actualRelType.getSqlTypeName() == SqlTypeName.CURSOR) {
61 SqlCall cursorCall = (SqlCall) operand;
63 cursorCall.operand(0), i, callBinding.getScope(), udtf);
64 if (cursorScore < 0) {
68 }
else if (actualRelType != formalRelType) {
69 if (SqlTypeUtil.isInterval(actualRelType)
70 && SqlTypeUtil.isInterval(formalRelType)) {
72 IntervalSqlType actualInterval = (IntervalSqlType) actualRelType;
73 IntervalSqlType formalInterval = (IntervalSqlType) formalRelType;
74 if (actualInterval.getIntervalQualifier().isYearMonth()
75 == formalInterval.getIntervalQualifier().isYearMonth()) {
82 if (widerType == null) {
84 }
else if (!SqlTypeUtil.isTimestamp(widerType)
85 && SqlTypeUtil.sameNamedType(formalRelType, actualRelType)) {
89 }
else if (actualRelType == widerType) {
91 }
else if (widerType != actualRelType) {
105 SqlValidatorScope scope,
109 String formalOperandName = udtf.getExtendedParamNames().
get(index);
110 List<ExtArgumentType> formalFieldTypes =
111 udtf.getCursorFieldTypes().
get(formalOperandName);
119 if (formalFieldTypes == null || formalFieldTypes.size() == 0) {
121 "Warning: UDTF has no CURSOR field subtype data. Proceeding assuming CURSOR typechecks.");
127 switch (cursorOperand.getKind()) {
129 SqlSelect selectNode = (SqlSelect) cursorOperand;
131 int iFormal = 0, iActual = 0;
132 for (; iActual < selectNode.getSelectList().size()
133 && iFormal < formalFieldTypes.size();
134 iActual++, iFormal++) {
135 SqlNode selectOperand = selectNode.getSelectList().
get(iActual);
137 RelDataType formalRelType = toRelDataType(extType, factory);
138 RelDataType actualRelType = factory.createTypeWithNullability(
139 validator.deriveType(scope, selectOperand),
true);
142 if (formalRelType.getSqlTypeName() == SqlTypeName.COLUMN_LIST) {
144 RelDataType formalSubtype = toRelDataType(colListSubtype, factory);
146 if (isArrayType(colListSubtype)
147 && actualRelType.getSqlTypeName() == SqlTypeName.ARRAY) {
148 ArraySqlType formalArrayType = (ArraySqlType) formalSubtype;
149 ArraySqlType actualArrayType = (ArraySqlType) actualRelType;
150 if (!SqlTypeUtil.sameNamedType(formalArrayType.getComponentType(),
151 actualArrayType.getComponentType())) {
159 if (!SqlTypeUtil.sameNamedType(actualRelType, formalSubtype)) {
160 if (widerType == null || widerType == actualRelType) {
167 int numFormalArgumentsLeft = (formalFieldTypes.size() - 1) - iFormal;
169 selectNode.getSelectList().size() - numFormalArgumentsLeft - iActual;
170 while (colListSize < maxColListSize) {
171 SqlNode curOperand = selectNode.getSelectList().
get(iActual + colListSize);
172 actualRelType = scope.getValidator().deriveType(scope, curOperand);
174 if (!SqlTypeUtil.sameNamedType(actualRelType, formalSubtype)) {
175 if (widerType == null
176 || !SqlTypeUtil.sameNamedType(widerType, formalSubtype)) {
179 }
else if (widerType != formalSubtype) {
195 iActual += colListSize - 1;
196 }
else if (actualRelType != formalRelType) {
197 if (widerType == null) {
200 }
else if (!SqlTypeUtil.isTimestamp(widerType)
201 && SqlTypeUtil.sameNamedType(formalRelType, actualRelType)) {
205 }
else if (actualRelType == widerType
206 || !SqlTypeUtil.sameNamedType(widerType, formalRelType)) {
222 if (iActual < selectNode.getSelectList().size()) {
228 System.out.println(
"Unsupported subquery kind in UDTF CURSOR input argument: "
229 + cursorOperand.getKind());
241 RelDataType type1, RelDataType type2,
boolean stringPromotion) {
242 RelDataType returnType = super.getWiderTypeForTwo(type1, type2, stringPromotion);
243 if (SqlTypeUtil.isTimestamp(type1) && SqlTypeUtil.isTimestamp(type2)) {
244 returnType = (type1.getPrecision() > type2.getPrecision()) ? type1 : type2;
245 }
else if ((SqlTypeUtil.isDouble(type1) || SqlTypeUtil.isDouble(type2))
246 && (SqlTypeUtil.isApproximateNumeric(type1)
247 && SqlTypeUtil.isApproximateNumeric(type2))) {
248 returnType = factory.createTypeWithNullability(
249 factory.createSqlType(SqlTypeName.DOUBLE),
true);
260 boolean coerced =
false;
261 final List<ExtArgumentType> paramTypes = udtf.getArgTypes();
262 SqlCall permutedCall = callBinding.permutedCall();
263 for (
int i = 0; i < permutedCall.operandCount(); i++) {
264 SqlNode operand = permutedCall.operand(i);
265 if (operand.getKind() == SqlKind.DEFAULT) {
271 RelDataType actualRelType = validator.deriveType(callBinding.getScope(), operand);
273 if (actualRelType.getSqlTypeName() == SqlTypeName.CURSOR) {
274 SqlCall cursorCall = (SqlCall) operand;
276 callBinding.getScope(), permutedCall, i, cursorCall.operand(0), udtf);
279 RelDataType formalRelType = toRelDataType(paramTypes.get(i), factory);
280 if (actualRelType != formalRelType) {
281 if (SqlTypeUtil.isInterval(actualRelType)
282 && SqlTypeUtil.isInterval(formalRelType)) {
283 IntervalSqlType actualInterval = (IntervalSqlType) actualRelType;
284 IntervalSqlType formalInterval = (IntervalSqlType) formalRelType;
285 if (actualInterval.getIntervalQualifier().isYearMonth()
286 == formalInterval.getIntervalQualifier().isYearMonth()) {
291 if (!SqlTypeUtil.isTimestamp(widerType)
292 && SqlTypeUtil.sameNamedType(formalRelType, actualRelType)) {
297 coerced = coerceOperandType(callBinding.getScope(), permutedCall, i, widerType)
307 SqlNode cursorOperand,
309 String formalOperandName = udtf.getExtendedParamNames().
get(index);
310 List<ExtArgumentType> formalFieldTypes =
311 udtf.getCursorFieldTypes().
get(formalOperandName);
312 if (formalFieldTypes == null || formalFieldTypes.size() == 0) {
316 switch (cursorOperand.getKind()) {
318 SqlSelect selectNode = (SqlSelect) cursorOperand;
319 int iFormal = 0, iActual = 0;
320 List<RelDataTypeField> newValidatedTypeList =
new ArrayList<>();
321 for (; iActual < selectNode.getSelectList().size()
322 && iFormal < formalFieldTypes.size();
323 iFormal++, iActual++) {
324 SqlNode selectOperand = selectNode.getSelectList().
get(iActual);
326 RelDataType formalRelType = toRelDataType(extType, factory);
327 RelDataType actualRelType = validator.deriveType(scope, selectOperand);
330 if (isColumnArrayType(extType) || isColumnListArrayType(extType)) {
336 if (formalRelType.getSqlTypeName() == SqlTypeName.COLUMN_LIST) {
338 RelDataType formalSubtype = toRelDataType(colListSubtype, factory);
342 int numFormalArgumentsLeft = (formalFieldTypes.size() - 1) - iFormal;
344 selectNode.getSelectList().size() - numFormalArgumentsLeft - iActual;
345 while (colListSize < maxColListSize) {
346 SqlNode curOperand = selectNode.getSelectList().
get(iActual + colListSize);
347 actualRelType = scope.getValidator().deriveType(scope, curOperand);
349 if (!SqlTypeUtil.sameNamedType(actualRelType, formalSubtype)) {
350 if (widerType == null) {
352 }
else if (actualRelType != widerType) {
353 coerceColumnType(scope,
354 selectNode.getSelectList(),
355 iActual + colListSize,
363 newValidatedTypeList, selectNode, iActual + colListSize);
366 iActual += colListSize - 1;
367 }
else if (actualRelType != formalRelType) {
368 if (!SqlTypeUtil.isTimestamp(widerType)
369 && SqlTypeUtil.sameNamedType(actualRelType, formalRelType)) {
373 if (widerType != actualRelType) {
374 coerceColumnType(scope, selectNode.getSelectList(), iActual, widerType);
385 RelDataType newCursorStructType = factory.createStructType(newValidatedTypeList);
386 RelDataType newCursorType = factory.createTypeWithNullability(newCursorStructType,
387 validator.getValidatedNodeType(selectNode).isNullable());
388 validator.setValidatedNodeType(selectNode, newCursorType);
404 SqlValidatorScope scope, SqlNode node, RelDataType toType) {
405 RelDataType fromType = validator.deriveType(scope, node);
408 if (fromType == null) {
413 if (fromType instanceof RelDataTypeFactoryImpl.JavaType
414 && toType.getSqlTypeName() == fromType.getSqlTypeName()) {
419 if (toType.getSqlTypeName() == SqlTypeName.ANY
420 || fromType.getSqlTypeName() == SqlTypeName.ANY) {
425 if (SqlTypeUtil.isCharacter(toType) && SqlTypeUtil.isCharacter(fromType)) {
430 if (SqlTypeUtil.equalSansNullability(factory, fromType, toType)) {
434 assert SqlTypeUtil.canCastFrom(toType, fromType,
true);
442 List<RelDataTypeField> typeList, SqlSelect selectNode,
int operandIndex) {
443 SqlNode operand = selectNode.getSelectList().
get(operandIndex);
444 RelDataType newType = validator.getValidatedNodeType(operand);
445 if (operand instanceof SqlCall) {
446 SqlCall asCall = (SqlCall) operand;
447 if (asCall.getOperator().getKind() == SqlKind.AS) {
448 newType = validator.getValidatedNodeType(asCall.operand(0));
451 RelDataTypeField oldTypeField =
452 validator.getValidatedNodeType(selectNode).getFieldList().get(operandIndex);
453 RelDataTypeField newTypeField =
new RelDataTypeFieldImpl(
454 oldTypeField.getName(), oldTypeField.getIndex(), newType);
455 typeList.add(newTypeField);
465 RelDataType targetType, RelDataType originalType,
boolean isCursorArgument) {
467 int baseScore = isCursorArgument ? 100 : 1;
468 switch (originalType.getSqlTypeName()) {
474 if (SqlTypeUtil.isApproximateNumeric(targetType)) {
482 return baseScore * multiplier;
498 SqlBasicCall binOp, RelDataType targetType, SqlValidatorScope scope) {
499 if (binOp.getKind() == SqlKind.AS) {
500 binOp = binOp.operand(0);
502 coerceOperandType(scope, binOp, 0, targetType);
503 coerceOperandType(scope, binOp, 1, targetType);
515 SqlNode op, RelDataType targetType, SqlValidatorScope scope) {
516 if (op instanceof SqlBasicCall) {
517 SqlBasicCall asCall = (SqlBasicCall) op;
518 if (asCall.getOperator().getKind() == SqlKind.AS) {
519 SqlNode op2 = asCall.operand(0);
520 if (op2 instanceof SqlBasicCall) {
521 asCall = (SqlBasicCall) op2;
526 if (asCall.getOperator() instanceof SqlBinaryOperator) {
527 SqlNode lhs = asCall.operand(0);
528 SqlNode rhs = asCall.operand(1);
529 RelDataType lhsType = validator.deriveType(scope, lhs);
530 RelDataType rhsType = validator.deriveType(scope, rhs);
533 if (lhsType != targetType && rhsType != targetType
534 && (lhs.getKind() == SqlKind.LITERAL
535 || 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)
List< ExtArgumentType > getArgTypes()
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)