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

studio.raptor.sqlparser.fast.expression.Operation 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.value.Value;
import studio.raptor.sqlparser.fast.value.ValueNull;
import studio.raptor.sqlparser.fast.value.ValueString;
import studio.raptor.sqlparser.fast.table.ColumnResolver;

/**
 * A mathematical expression, or string concatenation.
 */
public class Operation extends Expression {

  /**
   * This operation represents a string concatenation as in
   * 'Hello' || 'World'.
   */
  public static final int CONCAT = 0;

  /**
   * This operation represents an addition as in 1 + 2.
   */
  public static final int PLUS = 1;

  /**
   * This operation represents a subtraction as in 2 - 1.
   */
  public static final int MINUS = 2;

  /**
   * This operation represents a multiplication as in 2 * 3.
   */
  public static final int MULTIPLY = 3;

  /**
   * This operation represents a division as in 4 * 2.
   */
  public static final int DIVIDE = 4;

  /**
   * This operation represents a negation as in - ID.
   */
  public static final int NEGATE = 5;

  /**
   * This operation represents a modulus as in 5 % 2.
   */
  public static final int MODULUS = 6;

  private int opType;
  private Expression left, right;
  private int dataType;
  private boolean convertRight = true;

  public Operation(int opType, Expression left, Expression right) {
    this.opType = opType;
    this.left = left;
    this.right = right;
  }

  @Override
  public String getSQL() {
    String sql;
    if (opType == NEGATE) {
      // don't remove the space, otherwise it might end up some thing like
      // --1 which is a line remark
      sql = "- " + left.getSQL();
    } else {
      // don't remove the space, otherwise it might end up some thing like
      // --1 which is a line remark
      sql = left.getSQL() + " " + getOperationToken() + " " + right.getSQL();
    }
    return "(" + sql + ")";
  }

  private String getOperationToken() {
    switch (opType) {
      case NEGATE:
        return "-";
      case CONCAT:
        return "||";
      case PLUS:
        return "+";
      case MINUS:
        return "-";
      case MULTIPLY:
        return "*";
      case DIVIDE:
        return "/";
      case MODULUS:
        return "%";
      default:
        throw ParseException.throwInternalError("opType=" + opType);
    }
  }

  @Override
  public Value getValue() {
    Value l = left.getValue().convertTo(dataType);
    Value r;
    if (right == null) {
      r = null;
    } else {
      r = right.getValue();
      if (convertRight) {
        r = r.convertTo(dataType);
      }
    }
    switch (opType) {
      case NEGATE:
        return l == ValueNull.INSTANCE ? l : l.negate();
      case CONCAT: {
        String s1 = l.getString(), s2 = r.getString();
        StringBuilder buff = new StringBuilder(s1.length() + s2.length());
        buff.append(s1).append(s2);
        return ValueString.get(buff.toString());
      }
      case PLUS:
        if (l == ValueNull.INSTANCE || r == ValueNull.INSTANCE) {
          return ValueNull.INSTANCE;
        }
        return l.add(r);
      case MINUS:
        if (l == ValueNull.INSTANCE || r == ValueNull.INSTANCE) {
          return ValueNull.INSTANCE;
        }
        return l.subtract(r);
      case MULTIPLY:
        if (l == ValueNull.INSTANCE || r == ValueNull.INSTANCE) {
          return ValueNull.INSTANCE;
        }
        return l.multiply(r);
      case DIVIDE:
        if (l == ValueNull.INSTANCE || r == ValueNull.INSTANCE) {
          return ValueNull.INSTANCE;
        }
        return l.divide(r);
      case MODULUS:
        if (l == ValueNull.INSTANCE || r == ValueNull.INSTANCE) {
          return ValueNull.INSTANCE;
        }
        return l.modulus(r);
      default:
        throw ParseException.throwInternalError("type=" + opType);
    }
  }

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

  @Override
  public Expression optimize() {
    left = left.optimize();
    switch (opType) {
      case NEGATE:
        dataType = left.getType();
        if (dataType == Value.UNKNOWN) {
          dataType = Value.DECIMAL;
        }
        break;
      case CONCAT:
        right = right.optimize();
        dataType = Value.STRING;
        if (left.isConstant() && right.isConstant()) {
          return ValueExpression.get(getValue());
        }
        break;
      case PLUS:
      case MINUS:
      case MULTIPLY:
      case DIVIDE:

      default:
        ParseException.throwInternalError("type=" + opType);
    }
    if (left.isConstant() && (right == null || right.isConstant())) {
      return ValueExpression.get(getValue());
    }
    return this;
  }

  private void swap() {
    Expression temp = left;
    left = right;
    right = temp;
  }

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

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

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy