All Downloads are FREE. Search and download functionalities are using the official Maven repository.

studio.raptor.sqlparser.fast.expression.Comparison Maven / Gradle / Ivy

/*
 * Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0,
 * and the EPL 1.0 (http://h2database.com/html/license.html).
 * Initial Developer: H2 Group
 */
package studio.raptor.sqlparser.fast.expression;

import studio.raptor.sqlparser.fast.message.ParseException;
import studio.raptor.sqlparser.fast.table.ColumnResolver;
import studio.raptor.sqlparser.fast.value.Value;

/**
 * Example comparison expressions are ID=1, NAME=NAME, NAME IS NULL.
 *
 * @author Thomas Mueller
 * @author Noel Grandin
 * @author Nicolas Fortin, Atelier SIG, IRSTV FR CNRS 24888
 */
public class Comparison extends Condition {

  /**
   * This is a flag meaning the comparison is null safe (meaning never returns
   * NULL even if one operand is NULL). Only EQUAL and NOT_EQUAL are supported
   * currently.
   */
  public static final int NULL_SAFE = 16;

  /**
   * The comparison type meaning = as in ID=1.
   */
  public static final int EQUAL = 0;

  /**
   * The comparison type meaning ID IS 1 (ID IS NOT DISTINCT FROM 1).
   */
  public static final int EQUAL_NULL_SAFE = EQUAL | NULL_SAFE;

  /**
   * The comparison type meaning >= as in ID>=1.
   */
  public static final int BIGGER_EQUAL = 1;

  /**
   * The comparison type meaning > as in ID>1.
   */
  public static final int BIGGER = 2;

  /**
   * The comparison type meaning <= as in ID<=1.
   */
  public static final int SMALLER_EQUAL = 3;

  /**
   * The comparison type meaning < as in ID<1.
   */
  public static final int SMALLER = 4;

  /**
   * The comparison type meaning <> as in ID<>1.
   */
  public static final int NOT_EQUAL = 5;

  /**
   * The comparison type meaning ID IS NOT 1 (ID IS DISTINCT FROM 1).
   */
  public static final int NOT_EQUAL_NULL_SAFE = NOT_EQUAL | NULL_SAFE;

  /**
   * The comparison type meaning IS NULL as in NAME IS NULL.
   */
  public static final int IS_NULL = 6;

  /**
   * The comparison type meaning IS NOT NULL as in NAME IS NOT NULL.
   */
  public static final int IS_NOT_NULL = 7;

  /**
   * This is a pseudo comparison type that is only used for index conditions.
   * It means the comparison will always yield FALSE. Example: 1=0.
   */
  public static final int FALSE = 8;

  /**
   * This is a pseudo comparison type that is only used for index conditions.
   * It means equals any value of a list. Example: IN(1, 2, 3).
   */
  public static final int IN_LIST = 9;

  /**
   * This is a pseudo comparison type that is only used for index conditions.
   * It means equals any value of a list. Example: IN(SELECT ...).
   */
  public static final int IN_QUERY = 10;

  /**
   * This is a comparison type that is only used for spatial index
   * conditions (operator "&&").
   */
  public static final int SPATIAL_INTERSECTS = 11;

  private int compareType;
  private Expression left;
  private Expression right;

  public Comparison(int compareType, Expression left,
      Expression right) {
    this.left = left;
    this.right = right;
    this.compareType = compareType;
  }

  @Override
  public Value getValue() {
    return null;
  }

  /**
   * Get the comparison operator string ("=", ">",...).
   *
   * @param compareType the compare type
   * @return the string
   */
  static String getCompareOperator(int compareType) {
    switch (compareType) {
      case EQUAL:
        return "=";
      case EQUAL_NULL_SAFE:
        return "IS";
      case BIGGER_EQUAL:
        return ">=";
      case BIGGER:
        return ">";
      case SMALLER_EQUAL:
        return "<=";
      case SMALLER:
        return "<";
      case NOT_EQUAL:
        return "<>";
      case NOT_EQUAL_NULL_SAFE:
        return "IS NOT";
      case SPATIAL_INTERSECTS:
        return "&&";
      default:
        throw ParseException.throwInternalError("compareType=" + compareType);
    }
  }

  /**
   * Compare two values, given the values are not NULL.
   *
   * @param l the first value
   * @param r the second value
   * @param compareType the compare type
   * @return true if the comparison indicated by the comparison type evaluates to true
   */
  static boolean compareNotNull(Value l, Value r,
      int compareType) {
    return false;
  }

  @Override
  public String getSQL() {
    String sql;
    switch (compareType) {
      case IS_NULL:
        sql = left.getSQL() + " IS NULL";
        break;
      case IS_NOT_NULL:
        sql = left.getSQL() + " IS NOT NULL";
        break;
      case SPATIAL_INTERSECTS:
        sql = "INTERSECTS(" + left.getSQL() + ", " + right.getSQL() + ")";
        break;
      default:
        sql = left.getSQL() + " " + getCompareOperator(compareType) +
            " " + right.getSQL();
    }
    return "(" + sql + ")";
  }

  @Override
  public Expression optimize() {
    /*left = left.optimize();
    if (right != null) {
      right = right.optimize();
      if (right instanceof ExpressionColumn) {
        if (left.isConstant() || left instanceof Parameter) {
          Expression temp = left;
          left = right;
          right = temp;
          compareType = getReversedCompareType(compareType);
        }
      }
      if (left instanceof ExpressionColumn) {
        if (right.isConstant()) {
          Value r = right.getValue();
          if (r == ValueNull.INSTANCE) {
            if ((compareType & NULL_SAFE) == 0) {
              return ValueExpression.getNull();
            }
          }
          int colType = left.getType();
          int constType = r.getType();
          int resType = Value.getHigherOrder(colType, constType);
          // If not, the column values will need to be promoted
          // to constant type, but vise versa, then let's do this here
          // once.
          if (constType != resType) {
            right = ValueExpression.get(r.convertTo(resType));
          }
        } else if (right instanceof Parameter) {
          ((Parameter) right).setColumn(
              ((ExpressionColumn) left).getColumn());
        }
      }
    }
    if (compareType == IS_NULL || compareType == IS_NOT_NULL) {
      if (left.isConstant()) {
        return ValueExpression.get(getValue());
      }
    } else {
      if (SysProperties.CHECK && (left == null || right == null)) {
        ParseException.throwInternalError(left + " " + right);
      }
      if (left == ValueExpression.getNull() ||
          right == ValueExpression.getNull()) {
        // TODO NULL handling: maybe issue a warning when comparing with
        // a NULL constants
        if ((compareType & NULL_SAFE) == 0) {
          return ValueExpression.getNull();
        }
      }
      if (left.isConstant() && right.isConstant()) {
        return ValueExpression.get(getValue());
      }
    }*/
    return this;
  }

  private int getReversedCompareType(int type) {
    switch (compareType) {
      case EQUAL:
      case EQUAL_NULL_SAFE:
      case NOT_EQUAL:
      case NOT_EQUAL_NULL_SAFE:
      case SPATIAL_INTERSECTS:
        return type;
      case BIGGER_EQUAL:
        return SMALLER_EQUAL;
      case BIGGER:
        return SMALLER;
      case SMALLER_EQUAL:
        return BIGGER_EQUAL;
      case SMALLER:
        return BIGGER;
      default:
        throw ParseException.throwInternalError("type=" + compareType);
    }
  }

  private int getNotCompareType() {
    switch (compareType) {
      case EQUAL:
        return NOT_EQUAL;
      case EQUAL_NULL_SAFE:
        return NOT_EQUAL_NULL_SAFE;
      case NOT_EQUAL:
        return EQUAL;
      case NOT_EQUAL_NULL_SAFE:
        return EQUAL_NULL_SAFE;
      case BIGGER_EQUAL:
        return SMALLER;
      case BIGGER:
        return SMALLER_EQUAL;
      case SMALLER_EQUAL:
        return BIGGER;
      case SMALLER:
        return BIGGER_EQUAL;
      case IS_NULL:
        return IS_NOT_NULL;
      case IS_NOT_NULL:
        return IS_NULL;
      default:
        throw ParseException.throwInternalError("type=" + compareType);
    }
  }

  @Override
  public void mapColumns(ColumnResolver resolver, int level) {
    left.mapColumns(resolver, level);
    if (right != null) {
      right.mapColumns(resolver, level);
    }
  }

  @Override
  public boolean isEverything(ExpressionVisitor visitor) {
    return left.isEverything(visitor) &&
        (right == null || right.isEverything(visitor));
  }

  /**
   * Get the other expression if this is an equals comparison and the other
   * expression matches.
   *
   * @param match the expression that should match
   * @return null if no match, the other expression if there is a match
   */
  Expression getIfEquals(Expression match) {
    if (compareType == EQUAL) {
      String sql = match.getSQL();
      if (left.getSQL().equals(sql)) {
        return right;
      } else if (right.getSQL().equals(sql)) {
        return left;
      }
    }
    return null;
  }

  /**
   * Get the left or the right sub-expression of this condition.
   *
   * @param getLeft true to get the left sub-expression, false to get the right sub-expression.
   * @return the sub-expression
   */
  public Expression getExpression(boolean getLeft) {
    return getLeft ? this.left : right;
  }

  @Override
  public int getType() {
    return 0;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy