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

studio.raptor.sqlparser.fast.expression.CompareLike 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 java.util.regex.Pattern;
import studio.raptor.sqlparser.fast.message.ParseException;
import studio.raptor.sqlparser.fast.value.Value;
import studio.raptor.sqlparser.fast.table.ColumnResolver;

/**
 * Pattern matching comparison expression: WHERE NAME LIKE ?
 */
public class CompareLike extends Condition {

  private static final int MATCH = 0, ONE = 1, ANY = 2;
  private final boolean regexp;
  private Expression left;
  private Expression right;
  private Expression escape;
  private boolean isInit;
  private char[] patternChars;
  private String patternString;
  /**
   * one of MATCH / ONE / ANY
   */
  private int[] patternTypes;
  private int patternLength;
  private Pattern patternRegexp;

  private boolean ignoreCase;
  private boolean fastCompare;
  private boolean invalidPattern;
  /**
   * indicates that we can shortcut the comparison and use startsWith
   */
  private boolean shortcutToStartsWith;
  /**
   * indicates that we can shortcut the comparison and use endsWith
   */
  private boolean shortcutToEndsWith;
  /**
   * indicates that we can shortcut the comparison and use contains
   */
  private boolean shortcutToContains;


  public CompareLike(
      Expression left, Expression right, Expression escape, boolean regexp) {
    this.regexp = regexp;
    this.left = left;
    this.right = right;
    this.escape = escape;
  }

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

  private static Character getEscapeChar(String s) {
    return s == null || s.length() == 0 ? null : s.charAt(0);
  }

  private static boolean containsIgnoreCase(String src, String what) {
    final int length = what.length();
    if (length == 0) {
      // Empty string is contained
      return true;
    }

    final char firstLo = Character.toLowerCase(what.charAt(0));
    final char firstUp = Character.toUpperCase(what.charAt(0));

    for (int i = src.length() - length; i >= 0; i--) {
      // Quick check before calling the more expensive regionMatches()
      final char ch = src.charAt(i);
      if (ch != firstLo && ch != firstUp) {
        continue;
      }
      if (src.regionMatches(true, i, what, 0, length)) {
        return true;
      }
    }

    return false;
  }

  @Override
  public String getSQL() {
    String sql;
    if (regexp) {
      sql = left.getSQL() + " REGEXP " + right.getSQL();
    } else {
      sql = left.getSQL() + " LIKE " + right.getSQL();
      if (escape != null) {
        sql += " ESCAPE " + escape.getSQL();
      }
    }
    return "(" + sql + ")";
  }

  @Override
  public Expression optimize() {
    return null;
  }

  private boolean compareAt(String s, int pi, int si, int sLen,
      char[] pattern, int[] types) {
    for (; pi < patternLength; pi++) {
      switch (types[pi]) {
        case MATCH:
          if ((si >= sLen) || !compare(pattern, s, pi, si++)) {
            return false;
          }
          break;
        case ONE:
          if (si++ >= sLen) {
            return false;
          }
          break;
        case ANY:
          if (++pi >= patternLength) {
            return true;
          }
          while (si < sLen) {
            if (compare(pattern, s, pi, si) &&
                compareAt(s, pi, si, sLen, pattern, types)) {
              return true;
            }
            si++;
          }
          return false;
        default:
          ParseException.throwInternalError("" + types[pi]);
      }
    }
    return si == sLen;
  }

  private boolean compare(char[] pattern, String s, int pi, int si) {
    return pattern[pi] == s.charAt(si);
  }

  /**
   * Test if the value matches the pattern.
   *
   * @param testPattern the pattern
   * @param value the value
   * @param escapeChar the escape character
   * @return true if the value matches
   */
  public boolean test(String testPattern, String value, char escapeChar) {
    initPattern(testPattern, escapeChar);
    if (invalidPattern) {
      return false;
    }
    return compareAt(value, 0, 0, value.length(), patternChars, patternTypes);
  }

  private void initPattern(String p, Character escapeChar) {

  }

  private boolean isFullMatch() {
    if (patternTypes == null) {
      return false;
    }
    for (int type : patternTypes) {
      if (type != MATCH) {
        return false;
      }
    }
    return true;
  }

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

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

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




© 2015 - 2024 Weber Informatics LLC | Privacy Policy