@Override public LogicalExpression visitFunctionCall( FunctionCall call, FunctionImplementationRegistry registry) { List<LogicalExpression> args = Lists.newArrayList(); for (int i = 0; i < call.args.size(); ++i) { LogicalExpression newExpr = call.args.get(i).accept(this, registry); args.add(newExpr); } // replace with a new function call, since its argument could be changed. call = new FunctionCall(call.getDefinition(), args, call.getPosition()); // call function resolver, get the best match. FunctionResolver resolver = FunctionResolverFactory.getResolver(call); DrillFuncHolder matchedFuncHolder = resolver.getBestMatch(registry.getMethods().get(call.getDefinition().getName()), call); // new arg lists, possible with implicit cast inserted. List<LogicalExpression> argsWithCast = Lists.newArrayList(); if (matchedFuncHolder == null) { // TODO: found no matched funcholder. Raise exception here? return validateNewExpr(call); } else { // Compare parm type against arg type. Insert cast on top of arg, whenever necessary. for (int i = 0; i < call.args.size(); ++i) { MajorType parmType = matchedFuncHolder.getParmMajorType(i); // Case 1: If 1) the argument is NullExpression // 2) the parameter of matchedFuncHolder allows null input, or func's // null_handling is NULL_IF_NULL (means null and non-null are exchangable). // then replace NullExpression with a TypedNullConstant if (call.args.get(i).equals(NullExpression.INSTANCE) && (parmType.getMode().equals(DataMode.OPTIONAL) || matchedFuncHolder.getNullHandling() == NullHandling.NULL_IF_NULL)) { argsWithCast.add(new TypedNullConstant(parmType)); } else if (Types.softEquals( parmType, call.args.get(i).getMajorType(), matchedFuncHolder.getNullHandling() == NullHandling.NULL_IF_NULL)) { // Case 2: argument and parameter matches. Do nothing. argsWithCast.add(call.args.get(i)); } else { // Case 3: insert cast if param type is different from arg type. FunctionDefinition castFuncDef = CastFunctionDefs.getCastFuncDef(parmType.getMinorType()); List<LogicalExpression> castArgs = Lists.newArrayList(); castArgs.add(call.args.get(i)); // input_expr argsWithCast.add(new FunctionCall(castFuncDef, castArgs, ExpressionPosition.UNKNOWN)); } } } return validateNewExpr( new FunctionCall(call.getDefinition(), argsWithCast, call.getPosition())); }
public void resolveHash( DrillConfig config, LogicalExpression arg, TypeProtos.MajorType expectedArg, TypeProtos.MajorType expectedOut, TypeProtos.DataMode expectedBestInputMode, FunctionImplementationRegistry registry) throws JClassAlreadyExistsException, IOException { List<LogicalExpression> args = new ArrayList<>(); args.add(arg); String[] registeredNames = {"hash"}; FunctionCall call = new FunctionCall("hash", args, ExpressionPosition.UNKNOWN); FunctionResolver resolver = FunctionResolverFactory.getResolver(call); DrillFuncHolder matchedFuncHolder = registry.findDrillFunction(resolver, call); assertEquals(expectedBestInputMode, matchedFuncHolder.getParmMajorType(0).getMode()); }