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;
}
}