public static SqlExpr substitute(SqlExpr expr, Factory1<SqlExpr> postTraversalTransformer) {

    if (expr == null) {
      System.out.println("Null expr");
    }

    assert expr != null : "Expr must not be null";
    assert expr.getType() != null : "Type of exprs must not be null";

    SqlExpr result;
    switch (expr.getType()) {
      case Constant:
        {
          // result = expr;
          result = postTraversalTransformer.create(expr);
          break;
        }
      case Function:
        {
          SqlExprFunction fn = expr.asFunction();

          List<SqlExpr> args = fn.getArgs();

          assert !Iterables.contains(args, null) : "Null argument in expr: " + fn;

          List<SqlExpr> newArgs = substitute(args, postTraversalTransformer);
          SqlExpr tmp = fn.copy(newArgs);

          result = postTraversalTransformer.create(tmp);
          break;
        }
      case Variable:
        {
          // S_ColumnRef columnRef = (S_ColumnRef)expr;
          // SqlExprVar var = expr.asVariable();
          // String name = var.getVarName();

          result = postTraversalTransformer.create(expr); // map.get(name);

          /*
          if(substitute != null) {
          	result = substitute;
          } else {
          	result = expr;
          }
          )*/
          // columnRef.ge

          // The datatype of the substituted expression must be an equal-or-sub-type of the current
          // one.
          // result = null;
          // if(true) { throw new RuntimeException("todo"); }
          break;
        }
      default:
        {
          throw new RuntimeException("Should not happen");
        }
    }

    return result;
  }