vvysotskyi commented on a change in pull request #1940: DRILL-7406: Update Calcite to 1.21.0 URL: https://github.com/apache/drill/pull/1940#discussion_r361661949
########## File path: exec/java-exec/src/main/java/org/apache/drill/exec/planner/sql/DrillConvertletTable.java ########## @@ -138,14 +105,209 @@ public SqlRexConvertlet get(SqlCall call) { ((SqlBasicCall) call).setOperator(wrapper); return sqlRexConvertlet; } - - if ((convertlet = map.get(call.getOperator())) != null) { + if ((convertlet = operatorToConvertletMap.get(call.getOperator())) != null) { return convertlet; } - return StandardConvertletTable.INSTANCE.get(call); } - private DrillConvertletTable() { + /** + * Custom convertlet to handle extract functions. Optiq rewrites + * extract functions as divide and modulo functions, based on the + * data type. We cannot do that in Drill since we don't know the data type + * till we start scanning. So we don't rewrite extract and treat it as + * a regular function. + */ + private SqlRexConvertlet extract() { + return (cx, call) -> { + final RexBuilder rexBuilder = cx.getRexBuilder(); + final List<SqlNode> operands = call.getOperandList(); + final List<RexNode> exprs = new LinkedList<>(); + + String timeUnit = ((SqlIntervalQualifier) operands.get(0)).timeUnitRange.toString(); + + RelDataTypeFactory typeFactory = cx.getTypeFactory(); + + //RelDataType nullableReturnType = + + for (SqlNode node : operands) { + exprs.add(cx.convertExpression(node)); + } + + final RelDataType returnType; + if (call.getOperator() == SqlStdOperatorTable.EXTRACT) { + // Legacy code: + // The return type is wrong! + // Legacy code choose SqlTypeName.BIGINT simply to avoid conflicting against Calcite's inference mechanism + // (, which chose BIGINT in validation phase already) + // Determine NULL-able using 2nd argument's Null-able. + returnType = typeFactory.createTypeWithNullability(typeFactory.createSqlType(SqlTypeName.BIGINT), exprs.get(1).getType().isNullable()); + } else { + // Determine NULL-able using 2nd argument's Null-able. + returnType = typeFactory.createTypeWithNullability( + typeFactory.createSqlType( + TypeInferenceUtils.getSqlTypeNameForTimeUnit(timeUnit)), + exprs.get(1).getType().isNullable()); + } + + return rexBuilder.makeCall(returnType, call.getOperator(), exprs); + }; + } + + /** + * SQRT needs it's own convertlet because calcite overrides it to POWER(x, 0.5) + * which is not suitable for Infinity value case + */ + private static SqlRexConvertlet sqrt() { + return (cx, call) -> { + RexNode operand = cx.convertExpression(call.operand(0)); + return cx.getRexBuilder().makeCall(SqlStdOperatorTable.SQRT, operand); + }; + } + + /** + * Rewrites COALESCE function into CASE WHEN IS NOT NULL operand1 THEN operand1... + * all Calcite interval representations correctly. + * Custom convertlet to avoid rewriting TIMESTAMP_DIFF by Calcite, + * since Drill does not support Reinterpret function and does not handle + */ + private static SqlRexConvertlet coalesce() { + return (cx, call) -> { + int operandsCount = call.operandCount(); + if (operandsCount == 1) { + return cx.convertExpression(call.operand(0)); + } else { + List<RexNode> caseOperands = new ArrayList<>(); + for (int i = 0; i < operandsCount - 1; i++) { + RexNode caseOperand = cx.convertExpression(call.operand(i)); + caseOperands.add(cx.getRexBuilder().makeCall( + SqlStdOperatorTable.IS_NOT_NULL, caseOperand)); + caseOperands.add(caseOperand); + } + caseOperands.add(cx.convertExpression(call.operand(operandsCount - 1))); + return cx.getRexBuilder().makeCall(SqlStdOperatorTable.CASE, caseOperands); + } + }; + } + + private static SqlRexConvertlet timestampDiff() { + return (cx, call) -> { + SqlLiteral unitLiteral = call.operand(0); + SqlIntervalQualifier qualifier = + new SqlIntervalQualifier(unitLiteral.symbolValue(TimeUnit.class), null, SqlParserPos.ZERO); + + List<RexNode> operands = Arrays.asList( + cx.convertExpression(qualifier), + cx.convertExpression(call.operand(1)), + cx.convertExpression(call.operand(2))); + + RelDataTypeFactory typeFactory = cx.getTypeFactory(); + + RelDataType returnType = typeFactory.createTypeWithNullability( + typeFactory.createSqlType(SqlTypeName.BIGINT), + cx.getValidator().getValidatedNodeType(call.operand(1)).isNullable() + || cx.getValidator().getValidatedNodeType(call.operand(2)).isNullable()); + + return cx.getRexBuilder().makeCall(returnType, + SqlStdOperatorTable.TIMESTAMP_DIFF, operands); + }; + } + + private static SqlRexConvertlet row() { + return (cx, call) -> { + List<RexNode> args = call.getOperandList().stream() + .map(cx::convertExpression) + .collect(Collectors.toList()); + return cx.getRexBuilder().makeCall(SqlStdOperatorTable.ROW, args); + }; + } + + private static SqlRexConvertlet avgVariance(Function<SqlNode, SqlNode> expandFunc) { + return (cx, call) -> cx.convertExpression(expandFunc.apply(call.operand(0))); + } + + private static SqlNode expandAvg(final SqlNode arg) { + final SqlParserPos pos = SqlParserPos.ZERO; Review comment: final ---------------------------------------------------------------- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. For queries about this service, please contact Infrastructure at: us...@infra.apache.org With regards, Apache Git Services