private TPreparedExpression in(
     TPreparedExpression lhs, List<TPreparedExpression> rhs, InListCondition inList) {
   ComparisonCondition comparison = inList.getComparison();
   if (comparison == null) return TInExpression.prepare(lhs, rhs, queryContext);
   else
     return TInExpression.prepare(
         lhs, rhs, comparison.getRight().getType(), comparison.getKeyComparable(), queryContext);
 }
 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());
 }