private TPreparedExpression assembleFunction(
      ExpressionNode functionNode,
      String functionName,
      List<ExpressionNode> argumentNodes,
      ColumnExpressionContext columnContext,
      SubqueryOperatorAssembler subqueryAssembler) {

    List<TPreparedExpression> arguments =
        assembleExpressions(argumentNodes, columnContext, subqueryAssembler);
    TValidatedScalar overload;
    SparseArray<Object> preptimeValues = null;
    if (functionNode instanceof FunctionExpression) {
      FunctionExpression fexpr = (FunctionExpression) functionNode;
      overload = fexpr.getResolved();
      preptimeValues = fexpr.getPreptimeValues();
    } else if (functionNode instanceof BooleanOperationExpression) {
      List<TPreptimeValue> inputPreptimeValues = new ArrayList<>(argumentNodes.size());
      for (ExpressionNode argument : argumentNodes) {
        inputPreptimeValues.add(argument.getPreptimeValue());
      }

      OverloadResolver<TValidatedScalar> scalarsResolver = registryService.getScalarsResolver();
      OverloadResult<TValidatedScalar> overloadResult =
          scalarsResolver.get(functionName, inputPreptimeValues);
      overload = overloadResult.getOverload();
    } else if (functionNode instanceof IfElseExpression) {
      overload = ifElseValidated;
    } else {
      throw new AssertionError(functionNode);
    }
    TInstance resultInstance = functionNode.getType();
    return new TPreparedFunction(overload, resultInstance, arguments, preptimeValues);
  }
 public TPreparedExpression assembleExpression(
     ExpressionNode node,
     ColumnExpressionContext columnContext,
     SubqueryOperatorAssembler subqueryAssembler) {
   TPreparedExpression possiblyLiteral = tryLiteral(node);
   if (possiblyLiteral != null) return possiblyLiteral;
   if (node instanceof ConstantExpression) return literal(((ConstantExpression) node));
   else if (node instanceof ColumnExpression)
     return assembleColumnExpression((ColumnExpression) node, columnContext);
   else if (node instanceof ParameterExpression) return variable((ParameterExpression) node);
   else if (node instanceof BooleanOperationExpression) {
     BooleanOperationExpression bexpr = (BooleanOperationExpression) node;
     return assembleFunction(
         bexpr,
         bexpr.getOperation().getFunctionName(),
         Arrays.<ExpressionNode>asList(bexpr.getLeft(), bexpr.getRight()),
         columnContext,
         subqueryAssembler);
   } else if (node instanceof CastExpression)
     return assembleCastExpression((CastExpression) node, columnContext, subqueryAssembler);
   else if (node instanceof ComparisonCondition) {
     ComparisonCondition cond = (ComparisonCondition) node;
     TPreparedExpression left =
         assembleExpression(cond.getLeft(), columnContext, subqueryAssembler);
     TPreparedExpression right =
         assembleExpression(cond.getRight(), columnContext, subqueryAssembler);
     // never use a collator if we have a KeyComparable
     AkCollator collator = (cond.getKeyComparable() == null) ? collator(cond, left, right) : null;
     if (collator != null) return collate(left, cond.getOperation(), right, collator);
     else return compare(left, cond, right);
   } else if (node instanceof FunctionExpression) {
     FunctionExpression funcNode = (FunctionExpression) node;
     return assembleFunction(
         funcNode,
         funcNode.getFunction(),
         funcNode.getOperands(),
         columnContext,
         subqueryAssembler);
   } else if (node instanceof IfElseExpression) {
     IfElseExpression ifElse = (IfElseExpression) node;
     return assembleFunction(
         ifElse,
         "if",
         Arrays.asList(
             ifElse.getTestCondition(), ifElse.getThenExpression(), ifElse.getElseExpression()),
         columnContext,
         subqueryAssembler);
   } else if (node instanceof InListCondition) {
     InListCondition inList = (InListCondition) node;
     TPreparedExpression lhs =
         assembleExpression(inList.getOperand(), columnContext, subqueryAssembler);
     List<TPreparedExpression> rhs =
         assembleExpressions(inList.getExpressions(), columnContext, subqueryAssembler);
     return in(lhs, rhs, inList);
   } else if (node instanceof RoutineExpression) {
     RoutineExpression routineNode = (RoutineExpression) node;
     return assembleRoutine(
         routineNode,
         routineNode.getRoutine(),
         routineNode.getOperands(),
         columnContext,
         subqueryAssembler);
   } else if (node instanceof SubqueryExpression)
     return subqueryAssembler.assembleSubqueryExpression((SubqueryExpression) node);
   else if (node instanceof AggregateFunctionExpression)
     throw new UnsupportedSQLException("Aggregate used as regular function", node.getSQLsource());
   else if (node instanceof ColumnDefaultExpression)
     return assembleColumnDefault(((ColumnDefaultExpression) node).getColumn(), null);
   else if (node instanceof IsNullIndexKey) return new TNullExpression(node.getType());
   else throw new UnsupportedSQLException("Unknown expression", node.getSQLsource());
 }