package com.chenyang.druid.sql.ast.expr;

import com.chenyang.druid.DbType;
import com.chenyang.druid.sql.SQLUtils;
import com.chenyang.druid.sql.ast.SQLDataType;
import com.chenyang.druid.sql.ast.SQLDataTypeImpl;
import com.chenyang.druid.sql.ast.SQLDbTypedObject;
import com.chenyang.druid.sql.ast.SQLExpr;
import com.chenyang.druid.sql.ast.SQLExprComparor;
import com.chenyang.druid.sql.ast.SQLExprImpl;
import com.chenyang.druid.sql.ast.SQLName;
import com.chenyang.druid.sql.ast.SQLObject;
import com.chenyang.druid.sql.ast.SQLReplaceable;
import com.chenyang.druid.sql.visitor.ParameterizedVisitor;
import com.chenyang.druid.sql.visitor.SQLASTVisitor;
import com.chenyang.druid.sql.visitor.VisitorFeature;
import com.chenyang.druid.util.FnvHash;
import com.chenyang.druid.util.Utils;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class SQLBinaryOpExpr extends SQLExprImpl implements SQLReplaceable, Serializable, SQLDbTypedObject, Comparable<SQLBinaryOpExpr> {
   private static final long serialVersionUID = 1L;
   protected SQLExpr left;
   protected SQLExpr right;
   protected SQLBinaryOperator operator;
   protected DbType dbType;
   private boolean bracket = false;
   protected transient List<SQLObject> mergedList;

   public SQLBinaryOpExpr() {
   }

   public SQLBinaryOpExpr(DbType dbType) {
      this.dbType = dbType;
   }

   public SQLBinaryOpExpr(SQLExpr left, SQLBinaryOperator operator, SQLExpr right) {
      if (left != null) {
         left.setParent(this);
      }

      if (right != null) {
         right.setParent(this);
      }

      this.left = left;
      this.right = right;
      this.operator = operator;
      if (this.dbType == null && left instanceof SQLBinaryOpExpr) {
         this.dbType = ((SQLBinaryOpExpr)left).dbType;
      }

      if (this.dbType == null && right instanceof SQLBinaryOpExpr) {
         this.dbType = ((SQLBinaryOpExpr)right).dbType;
      }

   }

   public SQLBinaryOpExpr(SQLExpr left, SQLBinaryOperator operator, SQLExpr right, DbType dbType) {
      if (left != null) {
         left.setParent(this);
      }

      if (right != null) {
         right.setParent(this);
      }

      this.left = left;
      this.right = right;
      this.operator = operator;
      if (dbType == null && left instanceof SQLBinaryOpExpr) {
         dbType = ((SQLBinaryOpExpr)left).dbType;
      }

      if (dbType == null && right instanceof SQLBinaryOpExpr) {
         dbType = ((SQLBinaryOpExpr)right).dbType;
      }

      this.dbType = dbType;
   }

   public SQLBinaryOpExpr(SQLExpr left, SQLExpr right, SQLBinaryOperator operator) {
      if (left != null) {
         left.setParent(this);
      }

      if (right != null) {
         right.setParent(this);
      }

      this.left = left;
      this.right = right;
      this.operator = operator;
   }

   public DbType getDbType() {
      return this.dbType;
   }

   public void setDbType(DbType dbType) {
      this.dbType = dbType;
   }

   public SQLExpr getLeft() {
      return this.left;
   }

   public void setLeft(SQLExpr left) {
      if (left != null) {
         left.setParent(this);
      }

      this.left = left;
   }

   public SQLExpr getRight() {
      return this.right;
   }

   public void setRight(SQLExpr right) {
      if (right != null) {
         right.setParent(this);
      }

      this.right = right;
   }

   public SQLBinaryOperator getOperator() {
      return this.operator;
   }

   public void setOperator(SQLBinaryOperator operator) {
      this.operator = operator;
   }

   public boolean isBracket() {
      return this.bracket;
   }

   public void setBracket(boolean bracket) {
      this.bracket = bracket;
   }

   protected void accept0(SQLASTVisitor visitor) {
      if (visitor.visit(this)) {
         if (this.left != null) {
            this.left.accept(visitor);
         }

         if (this.right != null) {
            this.right.accept(visitor);
         }
      }

      visitor.endVisit(this);
   }

   public List getChildren() {
      return Arrays.asList(this.left, this.right);
   }

   public int hashCode() {
      int prime = 31;
      int result = 1;
      result = 31 * result + (this.left == null ? 0 : this.left.hashCode());
      result = 31 * result + (this.operator == null ? 0 : this.operator.hashCode());
      result = 31 * result + (this.right == null ? 0 : this.right.hashCode());
      return result;
   }

   public boolean equals(Object obj) {
      if (this == obj) {
         return true;
      } else if (obj == null) {
         return false;
      } else if (!(obj instanceof SQLBinaryOpExpr)) {
         return false;
      } else {
         SQLBinaryOpExpr other = (SQLBinaryOpExpr)obj;
         return this.operator == other.operator && SQLExprUtils.equals(this.left, other.left) && SQLExprUtils.equals(this.right, other.right);
      }
   }

   public boolean equals(SQLBinaryOpExpr other) {
      return this.operator == other.operator && SQLExprUtils.equals(this.left, other.left) && SQLExprUtils.equals(this.right, other.right);
   }

   public boolean equalsIgoreOrder(SQLBinaryOpExpr other) {
      if (this == other) {
         return true;
      } else if (other == null) {
         return false;
      } else if (this.operator != other.operator) {
         return false;
      } else {
         return Utils.equals(this.left, other.left) && Utils.equals(this.right, other.right) || Utils.equals(this.left, other.right) && Utils.equals(this.right, other.left);
      }
   }

   public SQLBinaryOpExpr clone() {
      SQLBinaryOpExpr x = new SQLBinaryOpExpr();
      if (this.left != null) {
         x.setLeft(this.left.clone());
      }

      if (this.right != null) {
         x.setRight(this.right.clone());
      }

      x.operator = this.operator;
      x.dbType = this.dbType;
      x.bracket = this.bracket;
      if (this.hint != null) {
         x.hint = this.hint.clone();
      }

      return x;
   }

   public String toString() {
      return SQLUtils.toSQLString(this, (DbType)this.getDbType());
   }

   public static SQLExpr combine(List<? extends SQLExpr> items, SQLBinaryOperator op) {
      if (items != null && op != null) {
         int size = items.size();
         if (size == 0) {
            return null;
         } else if (size == 1) {
            return (SQLExpr)items.get(0);
         } else {
            SQLBinaryOpExpr expr = new SQLBinaryOpExpr((SQLExpr)items.get(0), op, (SQLExpr)items.get(1));

            for(int i = 2; i < size; ++i) {
               SQLExpr item = (SQLExpr)items.get(i);
               expr = new SQLBinaryOpExpr(expr, op, item);
            }

            return expr;
         }
      } else {
         return null;
      }
   }

   public static List<SQLExpr> split(SQLBinaryOpExpr x) {
      return split(x, x.getOperator());
   }

   public static List<SQLExpr> split(SQLExpr x, SQLBinaryOperator op) {
      if (x instanceof SQLBinaryOpExprGroup) {
         SQLBinaryOpExprGroup group = (SQLBinaryOpExprGroup)x;
         if (group.getOperator() == op) {
            return new ArrayList(group.getItems());
         }
      } else if (x instanceof SQLBinaryOpExpr) {
         return split((SQLBinaryOpExpr)x, op);
      }

      List<SQLExpr> list = new ArrayList(1);
      list.add(x);
      return list;
   }

   public static List<SQLExpr> split(SQLBinaryOpExpr x, SQLBinaryOperator op) {
      if (x.getOperator() != op) {
         List<SQLExpr> groupList = new ArrayList(1);
         groupList.add(x);
         return groupList;
      } else {
         List<SQLExpr> groupList = new ArrayList();
         split(groupList, x, op);
         return groupList;
      }
   }

   public static void split(List<SQLExpr> outList, SQLExpr expr, SQLBinaryOperator op) {
      if (expr != null) {
         if (!(expr instanceof SQLBinaryOpExpr)) {
            outList.add(expr);
         } else {
            SQLBinaryOpExpr binaryExpr = (SQLBinaryOpExpr)expr;
            if (binaryExpr.getOperator() != op) {
               outList.add(binaryExpr);
            } else {
               List<SQLExpr> rightList = new ArrayList();
               rightList.add(binaryExpr.getRight());
               SQLExpr left = binaryExpr.getLeft();

               while(true) {
                  if (left instanceof SQLBinaryOpExpr) {
                     SQLBinaryOpExpr leftBinary = (SQLBinaryOpExpr)left;
                     if (leftBinary.operator == op) {
                        left = leftBinary.getLeft();
                        rightList.add(leftBinary.getRight());
                        continue;
                     }

                     outList.add(leftBinary);
                     break;
                  }

                  outList.add(left);
                  break;
               }

               for(int i = rightList.size() - 1; i >= 0; --i) {
                  SQLExpr right = (SQLExpr)rightList.get(i);
                  if (right instanceof SQLBinaryOpExpr) {
                     SQLBinaryOpExpr binaryRight = (SQLBinaryOpExpr)right;
                     if (binaryRight.operator == op) {
                        SQLExpr rightLeft = binaryRight.getLeft();
                        if (rightLeft instanceof SQLBinaryOpExpr) {
                           SQLBinaryOpExpr rightLeftBinary = (SQLBinaryOpExpr)rightLeft;
                           if (rightLeftBinary.operator == op) {
                              split(outList, rightLeftBinary, op);
                           } else {
                              outList.add(rightLeftBinary);
                           }
                        } else {
                           outList.add(rightLeft);
                        }

                        rightLeft = binaryRight.getRight();
                        if (rightLeft instanceof SQLBinaryOpExpr) {
                           SQLBinaryOpExpr rightRightBinary = (SQLBinaryOpExpr)rightLeft;
                           if (rightRightBinary.operator == op) {
                              split(outList, rightRightBinary, op);
                           } else {
                              outList.add(rightRightBinary);
                           }
                        } else {
                           outList.add(rightLeft);
                        }
                     } else {
                        outList.add(binaryRight);
                     }
                  } else {
                     outList.add(right);
                  }
               }

            }
         }
      }
   }

   public static SQLExpr and(SQLExpr a, SQLExpr b) {
      if (a == null) {
         return b;
      } else if (b == null) {
         return a;
      } else {
         if (a instanceof SQLBinaryOpExprGroup) {
            SQLBinaryOpExprGroup group = (SQLBinaryOpExprGroup)a;
            if (group.getOperator() == SQLBinaryOperator.BooleanAnd) {
               group.add(b);
               return group;
            }

            if (group.getOperator() == SQLBinaryOperator.BooleanOr && group.getItems().size() == 1) {
               a = ((SQLExpr)group.getItems().get(0)).clone();
            }
         }

         if (b instanceof SQLBinaryOpExpr) {
            SQLBinaryOpExpr bb = (SQLBinaryOpExpr)b;
            if (bb.operator == SQLBinaryOperator.BooleanAnd) {
               return and(and(a, bb.left), bb.right);
            }
         } else if (b instanceof SQLBinaryOpExprGroup) {
            SQLBinaryOpExprGroup group = (SQLBinaryOpExprGroup)b;
            if (group.getOperator() == SQLBinaryOperator.BooleanOr && group.getItems().size() == 1) {
               b = ((SQLExpr)group.getItems().get(0)).clone();
            }
         }

         if (a instanceof SQLBinaryOpExpr && b instanceof SQLBinaryOpExprGroup && ((SQLBinaryOpExprGroup)b).getOperator() == SQLBinaryOperator.BooleanAnd) {
            SQLBinaryOpExprGroup group = (SQLBinaryOpExprGroup)b;
            group.add(0, a);
            return group;
         } else {
            return new SQLBinaryOpExpr(a, SQLBinaryOperator.BooleanAnd, b);
         }
      }
   }

   public static SQLExpr and(SQLExpr a, SQLExpr b, SQLExpr c) {
      return and(and(a, b), c);
   }

   public static SQLExpr or(SQLExpr a, SQLExpr b) {
      if (a == null) {
         return b;
      } else if (b == null) {
         return a;
      } else {
         if (a instanceof SQLBinaryOpExprGroup) {
            SQLBinaryOpExprGroup group = (SQLBinaryOpExprGroup)a;
            if (group.getOperator() == SQLBinaryOperator.BooleanOr) {
               group.add(b);
               return group;
            }
         }

         if (b instanceof SQLBinaryOpExpr) {
            SQLBinaryOpExpr bb = (SQLBinaryOpExpr)b;
            if (bb.operator == SQLBinaryOperator.BooleanOr) {
               return or(or(a, bb.left), bb.right);
            }
         }

         return new SQLBinaryOpExpr(a, SQLBinaryOperator.BooleanOr, b);
      }
   }

   public static SQLExpr or(List<? extends SQLExpr> list) {
      if (list.size() == 0) {
         return null;
      } else {
         SQLExpr first = (SQLExpr)list.get(0);

         for(int i = 1; i < list.size(); ++i) {
            first = or(first, (SQLExpr)list.get(i));
         }

         return first;
      }
   }

   public static SQLExpr andIfNotExists(SQLExpr a, SQLExpr b) {
      if (a == null) {
         return b;
      } else if (b == null) {
         return a;
      } else {
         List<SQLExpr> groupListA = new ArrayList();
         List<SQLExpr> groupListB = new ArrayList();
         split(groupListA, a, SQLBinaryOperator.BooleanAnd);
         split(groupListB, b, SQLBinaryOperator.BooleanAnd);

         for(SQLExpr itemB : groupListB) {
            boolean exist = false;

            for(SQLExpr itemA : groupListA) {
               if (itemA.equals(itemB)) {
                  exist = true;
               } else if (itemA instanceof SQLBinaryOpExpr && itemB instanceof SQLBinaryOpExpr && ((SQLBinaryOpExpr)itemA).equalsIgoreOrder((SQLBinaryOpExpr)itemB)) {
                  exist = true;
               }
            }

            if (!exist) {
               groupListA.add(itemB);
            }
         }

         return combine(groupListA, SQLBinaryOperator.BooleanAnd);
      }
   }

   public static SQLBinaryOpExpr isNotNull(SQLExpr expr) {
      return new SQLBinaryOpExpr(expr, SQLBinaryOperator.IsNot, new SQLNullExpr());
   }

   public static SQLBinaryOpExpr isNull(SQLExpr expr) {
      return new SQLBinaryOpExpr(expr, SQLBinaryOperator.Is, new SQLNullExpr());
   }

   public boolean replace(SQLExpr expr, SQLExpr target) {
      SQLObject parent = this.getParent();
      if (this.left == expr) {
         if (target == null) {
            return parent instanceof SQLReplaceable ? ((SQLReplaceable)parent).replace(this, this.right) : false;
         } else {
            this.setLeft(target);
            return true;
         }
      } else if (this.right == expr) {
         if (target == null) {
            return parent instanceof SQLReplaceable ? ((SQLReplaceable)parent).replace(this, this.left) : false;
         } else {
            this.setRight(target);
            return true;
         }
      } else {
         if (this.left instanceof SQLBinaryOpExpr) {
            SQLBinaryOperator operator = ((SQLBinaryOpExpr)this.left).getOperator();
            if (operator == SQLBinaryOperator.BooleanAnd && ((SQLBinaryOpExpr)this.left).replace(expr, target)) {
               return true;
            }
         }

         return false;
      }
   }

   public SQLExpr other(SQLExpr x) {
      if (x == this.left) {
         return this.right;
      } else {
         return x == this.right ? this.left : null;
      }
   }

   public boolean contains(SQLExpr item) {
      if (item instanceof SQLBinaryOpExpr) {
         if (this.equalsIgoreOrder((SQLBinaryOpExpr)item)) {
            return true;
         } else {
            return this.left.equals(item) || this.right.equals(item);
         }
      } else {
         return false;
      }
   }

   public SQLDataType computeDataType() {
      if (this.operator == null) {
         return null;
      } else if (this.operator.isRelational()) {
         return SQLBooleanExpr.DATA_TYPE;
      } else {
         SQLDataType leftDataType = null;
         SQLDataType rightDataType = null;
         if (this.left != null) {
            leftDataType = this.left.computeDataType();
         }

         if (this.right != null) {
            rightDataType = this.right.computeDataType();
         }

         switch (this.operator) {
            case Concat:
               if (leftDataType != null) {
                  return leftDataType;
               } else {
                  if (rightDataType != null) {
                     return rightDataType;
                  }

                  return SQLCharExpr.DATA_TYPE;
               }
            case BooleanXor:
            case Modulus:
            case Mod:
            case DIV:
            case Divide:
               if (leftDataType != null) {
                  return leftDataType;
               } else {
                  if (rightDataType != null) {
                     return rightDataType;
                  }

                  return null;
               }
            case Subtract:
            case Add:
            case Multiply:
               if (leftDataType == null) {
                  return null;
               } else {
                  if (rightDataType != null) {
                     if (leftDataType.nameHashCode64() == FnvHash.Constants.BIGINT && rightDataType.nameHashCode64() == FnvHash.Constants.NUMBER) {
                        return rightDataType;
                     }

                     if (leftDataType.isInt() && rightDataType.nameHashCode64() == FnvHash.Constants.INTERVAL) {
                        return rightDataType;
                     }

                     if ((leftDataType.nameHashCode64() == FnvHash.Constants.DATE || leftDataType.nameHashCode64() == FnvHash.Constants.DATETIME || leftDataType.nameHashCode64() == FnvHash.Constants.TIMESTAMP) && (rightDataType.nameHashCode64() == FnvHash.Constants.DATE || rightDataType.nameHashCode64() == FnvHash.Constants.DATETIME || rightDataType.nameHashCode64() == FnvHash.Constants.TIMESTAMP)) {
                        return new SQLDataTypeImpl("BIGING");
                     }
                  }

                  return leftDataType;
               }
            default:
               return null;
         }
      }
   }

   public boolean conditionContainsTable(String alias) {
      if (this.left != null && this.right != null) {
         if (this.left instanceof SQLPropertyExpr) {
            if (((SQLPropertyExpr)this.left).matchOwner(alias)) {
               return true;
            }
         } else if (this.left instanceof SQLBinaryOpExpr && ((SQLBinaryOpExpr)this.left).conditionContainsTable(alias)) {
            return true;
         }

         if (this.right instanceof SQLPropertyExpr) {
            if (((SQLPropertyExpr)this.right).matchOwner(alias)) {
               return true;
            }
         } else if (this.right instanceof SQLBinaryOpExpr) {
            return ((SQLBinaryOpExpr)this.right).conditionContainsTable(alias);
         }

         return false;
      } else {
         return false;
      }
   }

   public boolean conditionContainsColumn(String column) {
      if (this.left != null && this.right != null) {
         if (this.left instanceof SQLIdentifierExpr) {
            if (((SQLIdentifierExpr)this.left).nameEquals(column)) {
               return true;
            }
         } else if (this.right instanceof SQLIdentifierExpr && ((SQLIdentifierExpr)this.right).nameEquals(column)) {
            return true;
         }

         return false;
      } else {
         return false;
      }
   }

   public static SQLBinaryOpExpr merge(ParameterizedVisitor v, SQLBinaryOpExpr x) {
      SQLObject parent = x.parent;

      while(x.right instanceof SQLBinaryOpExpr) {
         SQLBinaryOpExpr rightBinary = (SQLBinaryOpExpr)x.right;
         if (x.left instanceof SQLBinaryOpExpr) {
            SQLBinaryOpExpr leftBinaryExpr = (SQLBinaryOpExpr)x.left;
            if (SQLExprUtils.equals(leftBinaryExpr.right, rightBinary)) {
               x = leftBinaryExpr;
               v.incrementReplaceCunt();
               continue;
            }
         }

         SQLExpr mergedRight = merge(v, rightBinary);
         if (mergedRight != x.right) {
            x = new SQLBinaryOpExpr(x.left, x.operator, mergedRight);
            v.incrementReplaceCunt();
         }

         x.setParent(parent);
         break;
      }

      if (x.left instanceof SQLBinaryOpExpr) {
         SQLExpr mergedLeft = merge(v, (SQLBinaryOpExpr)x.left);
         if (mergedLeft != x.left) {
            SQLBinaryOpExpr tmp = new SQLBinaryOpExpr(mergedLeft, x.operator, x.right);
            tmp.setParent(parent);
            x = tmp;
            v.incrementReplaceCunt();
         }
      }

      if (x.operator == SQLBinaryOperator.BooleanOr && !v.isEnabled(VisitorFeature.OutputParameterizedQuesUnMergeInList) && x.left instanceof SQLBinaryOpExpr && x.right instanceof SQLBinaryOpExpr) {
         SQLBinaryOpExpr leftBinary = (SQLBinaryOpExpr)x.left;
         SQLBinaryOpExpr rightBinary = (SQLBinaryOpExpr)x.right;
         if (mergeEqual(leftBinary, rightBinary)) {
            v.incrementReplaceCunt();
            leftBinary.setParent(x.parent);
            leftBinary.addMergedItem(rightBinary);
            return leftBinary;
         }

         if (SQLExprUtils.isLiteralExpr(leftBinary.left) && leftBinary.operator == SQLBinaryOperator.BooleanOr && mergeEqual(leftBinary.right, x.right)) {
            v.incrementReplaceCunt();
            leftBinary.addMergedItem(rightBinary);
            return leftBinary;
         }
      }

      return x;
   }

   private void addMergedItem(SQLBinaryOpExpr item) {
      if (this.mergedList == null) {
         this.mergedList = new ArrayList();
      }

      this.mergedList.add(item);
   }

   public List<SQLObject> getMergedList() {
      return this.mergedList;
   }

   private static boolean mergeEqual(SQLExpr a, SQLExpr b) {
      if (!(a instanceof SQLBinaryOpExpr)) {
         return false;
      } else if (!(b instanceof SQLBinaryOpExpr)) {
         return false;
      } else {
         SQLBinaryOpExpr binaryA = (SQLBinaryOpExpr)a;
         SQLBinaryOpExpr binaryB = (SQLBinaryOpExpr)b;
         if (binaryA.operator != SQLBinaryOperator.Equality) {
            return false;
         } else if (binaryB.operator != SQLBinaryOperator.Equality) {
            return false;
         } else if (!(binaryA.right instanceof SQLLiteralExpr) && !(binaryA.right instanceof SQLVariantRefExpr)) {
            return false;
         } else {
            return !(binaryB.right instanceof SQLLiteralExpr) && !(binaryB.right instanceof SQLVariantRefExpr) ? false : binaryA.left.equals(binaryB.left);
         }
      }
   }

   public static boolean isOr(SQLExpr x) {
      return x instanceof SQLBinaryOpExpr && ((SQLBinaryOpExpr)x).getOperator() == SQLBinaryOperator.BooleanOr;
   }

   public static boolean isAnd(SQLExpr x) {
      return x instanceof SQLBinaryOpExpr && ((SQLBinaryOpExpr)x).getOperator() == SQLBinaryOperator.BooleanAnd;
   }

   public boolean isLeftNameAndRightLiteral() {
      return this.left instanceof SQLName && this.right instanceof SQLLiteralExpr;
   }

   public boolean isLeftFunctionAndRightLiteral() {
      return this.left instanceof SQLMethodInvokeExpr && this.right instanceof SQLLiteralExpr;
   }

   public boolean isNameAndLiteral() {
      return this.left instanceof SQLLiteralExpr && this.right instanceof SQLName || this.left instanceof SQLName && this.right instanceof SQLLiteralExpr;
   }

   public boolean isBothName() {
      return this.left instanceof SQLName && this.right instanceof SQLName;
   }

   public int compareTo(SQLBinaryOpExpr o) {
      int leftResult = SQLExprComparor.compareTo(this.left, o.left);
      if (leftResult != 0) {
         return leftResult;
      } else {
         int opResult = this.operator.compareTo(o.operator);
         if (opResult != 0) {
            return opResult;
         } else {
            int rightResult = SQLExprComparor.compareTo(this.right, o.right);
            return rightResult != 0 ? rightResult : 0;
         }
      }
   }

   public boolean isLeftLiteralAndRightName() {
      return this.right instanceof SQLName && this.left instanceof SQLLiteralExpr;
   }

   public static SQLBinaryOpExpr conditionEq(String column, String value) {
      return new SQLBinaryOpExpr(SQLUtils.toSQLExpr(column), SQLBinaryOperator.Equality, new SQLCharExpr(value));
   }

   public static SQLBinaryOpExpr conditionEq(String column, int value) {
      return new SQLBinaryOpExpr(SQLUtils.toSQLExpr(column), SQLBinaryOperator.Equality, new SQLIntegerExpr(value));
   }

   public static SQLBinaryOpExpr conditionLike(String column, String value) {
      return new SQLBinaryOpExpr(SQLUtils.toSQLExpr(column), SQLBinaryOperator.Like, new SQLCharExpr(value));
   }

   public static SQLBinaryOpExpr conditionLike(String column, SQLExpr value) {
      return new SQLBinaryOpExpr(SQLUtils.toSQLExpr(column), SQLBinaryOperator.Like, value);
   }

   public static SQLBinaryOpExpr eq(SQLExpr a, SQLExpr b) {
      return new SQLBinaryOpExpr(a, SQLBinaryOperator.Equality, b);
   }
}
