Java Code Examples for org.apache.calcite.rex.RexCall#getKind()

The following examples show how to use org.apache.calcite.rex.RexCall#getKind() . You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
Source File: DateRangeRules.java    From Bats with Apache License 2.0 6 votes vote down vote up
@Override
public Object visitCall(RexCall call) {
    switch (call.getKind()) {
    case EXTRACT:
        final RexLiteral operand = (RexLiteral) call.getOperands().get(0);
        timeUnits.add((TimeUnitRange) operand.getValue());
        break;
    case FLOOR:
    case CEIL:
        // Check that the call to FLOOR/CEIL is on date-time
        if (call.getOperands().size() == 2) {
            opKinds.add(call.getKind());
        }
        break;
    }
    return super.visitCall(call);
}
 
Example 2
Source File: PredicateAnalyzer.java    From calcite with Apache License 2.0 6 votes vote down vote up
/**
 * If one operand in a binary operator is a DateTime type, but the other isn't,
 * we should not push down the predicate
 * @param call current node being evaluated
 */
private static void checkForIncompatibleDateTimeOperands(RexCall call) {
  RelDataType op1 = call.getOperands().get(0).getType();
  RelDataType op2 = call.getOperands().get(1).getType();
  if ((SqlTypeFamily.DATETIME.contains(op1) && !SqlTypeFamily.DATETIME.contains(op2))
         || (SqlTypeFamily.DATETIME.contains(op2) && !SqlTypeFamily.DATETIME.contains(op1))
         || (SqlTypeFamily.DATE.contains(op1) && !SqlTypeFamily.DATE.contains(op2))
         || (SqlTypeFamily.DATE.contains(op2) && !SqlTypeFamily.DATE.contains(op1))
         || (SqlTypeFamily.TIMESTAMP.contains(op1) && !SqlTypeFamily.TIMESTAMP.contains(op2))
         || (SqlTypeFamily.TIMESTAMP.contains(op2) && !SqlTypeFamily.TIMESTAMP.contains(op1))
         || (SqlTypeFamily.TIME.contains(op1) && !SqlTypeFamily.TIME.contains(op2))
         || (SqlTypeFamily.TIME.contains(op2) && !SqlTypeFamily.TIME.contains(op1))) {
    throw new PredicateAnalyzerException("Cannot handle " + call.getKind()
        + " expression for _id field, " + call);
  }
}
 
Example 3
Source File: IndexableExprMarker.java    From Bats with Apache License 2.0 6 votes vote down vote up
public boolean operandsAreIndexable(RexCall call) {
    SqlKind kind = call.getKind();
    boolean kindIsRight = (SqlKind.COMPARISON.contains(kind) || kind == SqlKind.LIKE || kind == SqlKind.SIMILAR);

    if (!kindIsRight) {
        return false;
    }

    int inputReference = 0;
    for (RexNode operand : call.getOperands()) {
        // if for this operator, there are two operands and more have inputRef, which means it is something like:
        // a.b = a.c, instead of a.b ='hello', so this cannot apply index
        if (containInputRef(operand)) {
            inputReference++;
            if (inputReference >= 2) {
                return false;
            }
        }
    }
    return true;
}
 
Example 4
Source File: PredicateAnalyzer.java    From dremio-oss with Apache License 2.0 6 votes vote down vote up
/**
 * If one operand in a binary operator is a DateTime type, but the other isn't, we should not push down the predicate
 * @param call
 */
public static void checkForIncompatibleDateTimeOperands(RexCall call) {
  RelDataType op1 = call.getOperands().get(0).getType();
  RelDataType op2 = call.getOperands().get(1).getType();
  if (
      (SqlTypeFamily.DATETIME.contains(op1) && !SqlTypeFamily.DATETIME.contains(op2)) ||
      (SqlTypeFamily.DATETIME.contains(op2) && !SqlTypeFamily.DATETIME.contains(op1)) ||
      (SqlTypeFamily.DATE.contains(op1) && !SqlTypeFamily.DATE.contains(op2)) ||
      (SqlTypeFamily.DATE.contains(op2) && !SqlTypeFamily.DATE.contains(op1)) ||
      (SqlTypeFamily.TIMESTAMP.contains(op1) && !SqlTypeFamily.TIMESTAMP.contains(op2)) ||
      (SqlTypeFamily.TIMESTAMP.contains(op2) && !SqlTypeFamily.TIMESTAMP.contains(op1)) ||
      (SqlTypeFamily.TIME.contains(op1) && !SqlTypeFamily.TIME.contains(op2)) ||
      (SqlTypeFamily.TIME.contains(op2) && !SqlTypeFamily.TIME.contains(op1)))
  {
    throw new PredicateAnalyzerException("Cannot handle " + call.getKind() + " expression for _id field, " + call);
  }
}
 
Example 5
Source File: DateRangeRules.java    From calcite with Apache License 2.0 6 votes vote down vote up
@Override public Void visitCall(RexCall call) {
  switch (call.getKind()) {
  case EXTRACT:
    final RexLiteral operand = (RexLiteral) call.getOperands().get(0);
    timeUnits.add((TimeUnitRange) operand.getValue());
    break;
  case FLOOR:
  case CEIL:
    // Check that the call to FLOOR/CEIL is on date-time
    if (call.getOperands().size() == 2) {
      opKinds.add(call.getKind());
    }
    break;
  }
  return super.visitCall(call);
}
 
Example 6
Source File: RelOptUtil.java    From calcite with Apache License 2.0 5 votes vote down vote up
private static RexCall doCollapseExpandedIsNotDistinctFromCaseExpr(final RexCall call,
    final RexBuilder rexBuilder) {
  if (call.getKind() != SqlKind.CASE || call.getOperands().size() != 5) {
    return call;
  }

  final RexNode op0 = call.getOperands().get(0);
  final RexNode op1 = call.getOperands().get(1);
  final RexNode op2 = call.getOperands().get(2);
  final RexNode op3 = call.getOperands().get(3);
  final RexNode op4 = call.getOperands().get(4);

  if (!(op0 instanceof RexCall) || !(op1 instanceof RexCall) || !(op2 instanceof RexCall)
      || !(op3 instanceof RexCall) || !(op4 instanceof RexCall)) {
    return call;
  }

  RexCall ifCall = (RexCall) op0;
  RexCall thenCall = (RexCall) op1;
  RexCall elseIfCall = (RexCall) op2;
  RexCall elseIfThenCall = (RexCall) op3;
  RexCall elseCall = (RexCall) op4;

  if (ifCall.getKind() != SqlKind.IS_NULL
      || thenCall.getKind() != SqlKind.IS_NULL
      || elseIfCall.getKind() != SqlKind.IS_NULL
      || elseIfThenCall.getKind() != SqlKind.IS_NULL
      || elseCall.getKind() != SqlKind.EQUALS) {
    return call;
  }

  if (!ifCall.equals(elseIfThenCall)
      || !thenCall.equals(elseIfCall)) {
    return call;
  }

  return doCollapseExpandedIsNotDistinctFrom(rexBuilder, call, ifCall, elseIfCall, elseCall);
}
 
Example 7
Source File: RexUtil.java    From kylin-on-parquet-v2 with Apache License 2.0 5 votes vote down vote up
public static CompareTupleFilter.CompareResultType getCompareResultType(RexCall whenCall) {
    List<RexNode> operands = whenCall.getOperands();
    if (SqlKind.EQUALS == whenCall.getKind() && operands != null && operands.size() == 2) {
        if (operands.get(0).equals(operands.get(1))) {
            return CompareTupleFilter.CompareResultType.AlwaysTrue;
        }

        if (isConstant(operands.get(0)) && isConstant(operands.get(1))) {
            return CompareTupleFilter.CompareResultType.AlwaysFalse;
        }
    }
    return CompareTupleFilter.CompareResultType.Unknown;
}
 
Example 8
Source File: PredicateAnalyzer.java    From calcite with Apache License 2.0 5 votes vote down vote up
private QueryExpression postfix(RexCall call) {
  Preconditions.checkArgument(call.getKind() == SqlKind.IS_NULL
      || call.getKind() == SqlKind.IS_NOT_NULL);
  if (call.getOperands().size() != 1) {
    String message = String.format(Locale.ROOT, "Unsupported operator: [%s]", call);
    throw new PredicateAnalyzerException(message);
  }
  Expression a = call.getOperands().get(0).accept(this);
  // Elasticsearch does not want is null/is not null (exists query)
  // for _id and _index, although it supports for all other metadata column
  isColumn(a, call, ElasticsearchConstants.ID, true);
  isColumn(a, call, ElasticsearchConstants.INDEX, true);
  QueryExpression operand = QueryExpression.create((TerminalExpression) a);
  return call.getKind() == SqlKind.IS_NOT_NULL ? operand.exists() : operand.notExists();
}
 
Example 9
Source File: PredicateAnalyzer.java    From dremio-oss with Apache License 2.0 5 votes vote down vote up
@Override
public Expression visitCall(RexCall call) {

  SqlSyntax syntax = call.getOperator().getSyntax();
  if (!supportedRexCall(call)) {
    throw new PredicateAnalyzerException(format("Unsupported call: [%s]", call));
  }

  switch (syntax) {
    case BINARY:
      return binary(call);
    case POSTFIX:
      return postfix(call);
    case SPECIAL:
      switch (call.getKind()) {
        case CAST:
          return cast(call);
        case LIKE:
          return binary(call);
        default:
          throw new PredicateAnalyzerException(format("Unsupported call: [%s]", call));
      }
    case FUNCTION:
      if (call.getOperator().getName().equalsIgnoreCase("CONTAINS")) {
        List<Expression> operands = Lists.newArrayList();
        for (RexNode node : call.getOperands()) {
          final Expression nodeExpr = node.accept(this);
          operands.add(nodeExpr);
        }
        String query = convertQueryString(operands.subList(0, operands.size() - 1), operands.get(operands.size() - 1));
        return QueryExpression.create(new NamedFieldExpression(null)).queryString(query);
      }
    default:
      throw new PredicateAnalyzerException(format("Unsupported syntax [%s] for call: [%s]", syntax, call));
  }
}
 
Example 10
Source File: TimeExtractionFunction.java    From calcite with Apache License 2.0 5 votes vote down vote up
/**
 * Returns whether the RexCall contains a valid extract unit that we can
 * serialize to Druid.
 *
 * @param rexNode Extract expression
 *
 * @return true if the extract unit is valid
 */

public static boolean isValidTimeExtract(RexNode rexNode) {
  final RexCall call = (RexCall) rexNode;
  if (call.getKind() != SqlKind.EXTRACT || call.getOperands().size() != 2) {
    return false;
  }
  final RexLiteral flag = (RexLiteral) call.operands.get(0);
  final TimeUnitRange timeUnit = (TimeUnitRange) flag.getValue();
  return timeUnit != null && VALID_TIME_EXTRACT.contains(timeUnit);
}
 
Example 11
Source File: PredicateAnalyzer.java    From dremio-oss with Apache License 2.0 5 votes vote down vote up
private QueryExpression andOr(RexCall call) {
  QueryExpression[] expressions = new QueryExpression[call.getOperands().size()];
  PredicateAnalyzerException firstError = null;
  boolean partial = false;
  for (int i = 0; i < call.getOperands().size(); i++) {
    try {
      Expression expr = call.getOperands().get(i).accept(this);
      if (expr instanceof NamedFieldExpression) {
        NamedFieldExpression namedFieldExpression = (NamedFieldExpression) expr;
        if (namedFieldExpression.getType().isBoolean()) {
          expressions[i] = QueryExpression.create((NamedFieldExpression) expr).isTrue();
        }
      } else {
        expressions[i] = (QueryExpression) call.getOperands().get(i).accept(this);
      }
      partial |= expressions[i].isPartial();
    } catch (PredicateAnalyzerException e) {
      if (firstError == null) {
        firstError = e;
      }
      partial = true;
    }
  }

  switch (call.getKind()) {
    case OR:
      if (partial) {
        if (firstError != null) {
          throw firstError;
        } else {
          throw new PredicateAnalyzerException(format("Unable to handle call: [%s]", call));
        }
      }
      return CompoundQueryExpression.or(expressions);
    case AND:
      return CompoundQueryExpression.and(partial, expressions);
    default:
      throw new PredicateAnalyzerException(format("Unable to handle call: [%s]", call));
  }
}
 
Example 12
Source File: MongoRules.java    From calcite with Apache License 2.0 4 votes vote down vote up
@Override public String visitCall(RexCall call) {
  String name = isItem(call);
  if (name != null) {
    return "'$" + name + "'";
  }
  final List<String> strings = visitList(call.operands);
  if (call.getKind() == SqlKind.CAST) {
    return strings.get(0);
  }
  String stdOperator = MONGO_OPERATORS.get(call.getOperator());
  if (stdOperator != null) {
    return "{" + stdOperator + ": [" + Util.commaList(strings) + "]}";
  }
  if (call.getOperator() == SqlStdOperatorTable.ITEM) {
    final RexNode op1 = call.operands.get(1);
    if (op1 instanceof RexLiteral
        && op1.getType().getSqlTypeName() == SqlTypeName.INTEGER) {
      if (!Bug.CALCITE_194_FIXED) {
        return "'" + stripQuotes(strings.get(0)) + "["
            + ((RexLiteral) op1).getValue2() + "]'";
      }
      return strings.get(0) + "[" + strings.get(1) + "]";
    }
  }
  if (call.getOperator() == SqlStdOperatorTable.CASE) {
    StringBuilder sb = new StringBuilder();
    StringBuilder finish = new StringBuilder();
    // case(a, b, c)  -> $cond:[a, b, c]
    // case(a, b, c, d) -> $cond:[a, b, $cond:[c, d, null]]
    // case(a, b, c, d, e) -> $cond:[a, b, $cond:[c, d, e]]
    for (int i = 0; i < strings.size(); i += 2) {
      sb.append("{$cond:[");
      finish.append("]}");

      sb.append(strings.get(i));
      sb.append(',');
      sb.append(strings.get(i + 1));
      sb.append(',');
      if (i == strings.size() - 3) {
        sb.append(strings.get(i + 2));
        break;
      }
      if (i == strings.size() - 2) {
        sb.append("null");
        break;
      }
    }
    sb.append(finish);
    return sb.toString();
  }
  throw new IllegalArgumentException("Translation of " + call.toString()
      + " is not supported by MongoProject");
}
 
Example 13
Source File: PredicateAnalyzer.java    From calcite with Apache License 2.0 4 votes vote down vote up
/**
 * Process a call which is a binary operation, transforming into an equivalent
 * query expression. Note that the incoming call may be either a simple binary
 * expression, such as {@code foo > 5}, or it may be several simple expressions connected
 * by {@code AND} or {@code OR} operators, such as {@code foo > 5 AND bar = 'abc' AND 'rot' < 1}
 *
 * @param call existing call
 * @return evaluated expression
 */
private QueryExpression binary(RexCall call) {

  // if AND/OR, do special handling
  if (call.getKind() == SqlKind.AND || call.getKind() == SqlKind.OR) {
    return andOr(call);
  }

  checkForIncompatibleDateTimeOperands(call);

  Preconditions.checkState(call.getOperands().size() == 2);
  final Expression a = call.getOperands().get(0).accept(this);
  final Expression b = call.getOperands().get(1).accept(this);

  final SwapResult pair = swap(a, b);
  final boolean swapped = pair.isSwapped();

  // For _id and _index columns, only equals/not_equals work!
  if (isColumn(pair.getKey(), call, ElasticsearchConstants.ID, false)
      || isColumn(pair.getKey(), call, ElasticsearchConstants.INDEX, false)
      || isColumn(pair.getKey(), call, ElasticsearchConstants.UID, false)) {
    switch (call.getKind()) {
    case EQUALS:
    case NOT_EQUALS:
      break;
    default:
      throw new PredicateAnalyzerException(
          "Cannot handle " + call.getKind() + " expression for _id field, " + call);
    }
  }

  switch (call.getKind()) {
  case CONTAINS:
    return QueryExpression.create(pair.getKey()).contains(pair.getValue());
  case LIKE:
    throw new UnsupportedOperationException("LIKE not yet supported");
  case EQUALS:
    return QueryExpression.create(pair.getKey()).equals(pair.getValue());
  case NOT_EQUALS:
    return QueryExpression.create(pair.getKey()).notEquals(pair.getValue());
  case GREATER_THAN:
    if (swapped) {
      return QueryExpression.create(pair.getKey()).lt(pair.getValue());
    }
    return QueryExpression.create(pair.getKey()).gt(pair.getValue());
  case GREATER_THAN_OR_EQUAL:
    if (swapped) {
      return QueryExpression.create(pair.getKey()).lte(pair.getValue());
    }
    return QueryExpression.create(pair.getKey()).gte(pair.getValue());
  case LESS_THAN:
    if (swapped) {
      return QueryExpression.create(pair.getKey()).gt(pair.getValue());
    }
    return QueryExpression.create(pair.getKey()).lt(pair.getValue());
  case LESS_THAN_OR_EQUAL:
    if (swapped) {
      return QueryExpression.create(pair.getKey()).gte(pair.getValue());
    }
    return QueryExpression.create(pair.getKey()).lte(pair.getValue());
  default:
    break;
  }
  String message = String.format(Locale.ROOT, "Unable to handle call: [%s]", call);
  throw new PredicateAnalyzerException(message);
}
 
Example 14
Source File: PredicateAnalyzer.java    From calcite with Apache License 2.0 4 votes vote down vote up
private boolean supportedRexCall(RexCall call) {
  final SqlSyntax syntax = call.getOperator().getSyntax();
  switch (syntax) {
  case BINARY:
    switch (call.getKind()) {
    case CONTAINS:
    case AND:
    case OR:
    case LIKE:
    case EQUALS:
    case NOT_EQUALS:
    case GREATER_THAN:
    case GREATER_THAN_OR_EQUAL:
    case LESS_THAN:
    case LESS_THAN_OR_EQUAL:
      return true;
    default:
      return false;
    }
  case SPECIAL:
    switch (call.getKind()) {
    case CAST:
    case LIKE:
    case ITEM:
    case OTHER_FUNCTION:
      return true;
    case CASE:
    case SIMILAR:
    default:
      return false;
    }
  case FUNCTION:
    return true;
  case POSTFIX:
    switch (call.getKind()) {
    case IS_NOT_NULL:
    case IS_NULL:
      return true;
    }
  case PREFIX: // NOT()
    switch (call.getKind()) {
    case NOT:
      return true;
    }
  // fall through
  case FUNCTION_ID:
  case FUNCTION_STAR:
  default:
    return false;
  }
}
 
Example 15
Source File: RexImpTable.java    From calcite with Apache License 2.0 4 votes vote down vote up
@Override Expression implementSafe(final RexToLixTranslator translator,
    final RexCall call, final List<Expression> argValueList) {
  final RexNode operand0 = call.getOperands().get(0);
  Expression trop0 = argValueList.get(0);
  final SqlTypeName typeName1 =
      call.getOperands().get(1).getType().getSqlTypeName();
  Expression trop1 = argValueList.get(1);
  final SqlTypeName typeName = call.getType().getSqlTypeName();
  switch (operand0.getType().getSqlTypeName()) {
  case DATE:
    switch (typeName) {
    case TIMESTAMP:
      trop0 = Expressions.convert_(
          Expressions.multiply(trop0,
              Expressions.constant(DateTimeUtils.MILLIS_PER_DAY)),
          long.class);
      break;
    default:
      switch (typeName1) {
      case INTERVAL_DAY:
      case INTERVAL_DAY_HOUR:
      case INTERVAL_DAY_MINUTE:
      case INTERVAL_DAY_SECOND:
      case INTERVAL_HOUR:
      case INTERVAL_HOUR_MINUTE:
      case INTERVAL_HOUR_SECOND:
      case INTERVAL_MINUTE:
      case INTERVAL_MINUTE_SECOND:
      case INTERVAL_SECOND:
        trop1 = Expressions.convert_(
            Expressions.divide(trop1,
                Expressions.constant(DateTimeUtils.MILLIS_PER_DAY)),
            int.class);
      }
    }
    break;
  case TIME:
    trop1 = Expressions.convert_(trop1, int.class);
    break;
  }
  switch (typeName1) {
  case INTERVAL_YEAR:
  case INTERVAL_YEAR_MONTH:
  case INTERVAL_MONTH:
    switch (call.getKind()) {
    case MINUS:
      trop1 = Expressions.negate(trop1);
    }
    switch (typeName) {
    case TIME:
      return Expressions.convert_(trop0, long.class);
    default:
      final BuiltInMethod method =
          operand0.getType().getSqlTypeName() == SqlTypeName.TIMESTAMP
              ? BuiltInMethod.ADD_MONTHS
              : BuiltInMethod.ADD_MONTHS_INT;
      return Expressions.call(method.method, trop0, trop1);
    }

  case INTERVAL_DAY:
  case INTERVAL_DAY_HOUR:
  case INTERVAL_DAY_MINUTE:
  case INTERVAL_DAY_SECOND:
  case INTERVAL_HOUR:
  case INTERVAL_HOUR_MINUTE:
  case INTERVAL_HOUR_SECOND:
  case INTERVAL_MINUTE:
  case INTERVAL_MINUTE_SECOND:
  case INTERVAL_SECOND:
    switch (call.getKind()) {
    case MINUS:
      return normalize(typeName, Expressions.subtract(trop0, trop1));
    default:
      return normalize(typeName, Expressions.add(trop0, trop1));
    }

  default:
    switch (call.getKind()) {
    case MINUS:
      switch (typeName) {
      case INTERVAL_YEAR:
      case INTERVAL_YEAR_MONTH:
      case INTERVAL_MONTH:
        return Expressions.call(BuiltInMethod.SUBTRACT_MONTHS.method,
            trop0, trop1);
      }
      TimeUnit fromUnit =
          typeName1 == SqlTypeName.DATE ? TimeUnit.DAY : TimeUnit.MILLISECOND;
      TimeUnit toUnit = TimeUnit.MILLISECOND;
      return multiplyDivide(
          Expressions.convert_(Expressions.subtract(trop0, trop1),
              (Class) long.class),
          fromUnit.multiplier, toUnit.multiplier);
    default:
      throw new AssertionError(call);
    }
  }
}
 
Example 16
Source File: PredicateAnalyzer.java    From dremio-oss with Apache License 2.0 4 votes vote down vote up
/**
 * Process a call which is a binary operation, transforming into an equivalent
 * query expression. Note that the incoming call may be either a simple binary
 * expression, such as 'foo > 5', or it may be several simple expressions connected
 * by 'AND' or 'OR' operators, such as 'foo > 5 AND bar = 'abc' AND 'rot' < 1'.
 */
private QueryExpression binary(RexCall call) {

  // if AND/OR, do special handling
  if (call.getKind() == SqlKind.AND || call.getKind() == SqlKind.OR) {
    return andOr(call);
  }

  checkForIncompatibleDateTimeOperands(call);

  Preconditions.checkState(call.getOperands().size() == 2);
  final Expression a = call.getOperands().get(0).accept(this);
  final Expression b = call.getOperands().get(1).accept(this);

  final SwapResult pair = swap(a, b);
  final boolean swapped = pair.isSwapped();

  // For _id and _index columns, only equals/not_equals work!
  if (isColumn(pair.getKey(), call, ElasticsearchConstants.ID, false)
    || isColumn(pair.getKey(), call, ElasticsearchConstants.INDEX, false)
    || isColumn(pair.getKey(), call, ElasticsearchConstants.UID, false)) {
    switch (call.getKind()) {
      case EQUALS:
      case NOT_EQUALS:
        break;
      default:
        throw new PredicateAnalyzerException("Cannot handle " + call.getKind() + " expression for _id field, " + call);
    }
  }

 // Fields cannot be queried without being indexed
  final NamedFieldExpression fieldExpression = (NamedFieldExpression) pair.getKey();
  if (fieldExpression.getAnnotation() != null && fieldExpression.getAnnotation().isNotIndexed()) {
    throw new PredicateAnalyzerException("Cannot handle " + call.getKind() + " expression because indexing is disabled, " + call);
  }

  // Analyzed text fields and normalized keyword fields cannot be pushed down unless allowed in settings
  if (!config.isAllowPushdownOnNormalizedOrAnalyzedFields() &&
      fieldExpression.getAnnotation() != null && fieldExpression.getType().isText() &&
      (fieldExpression.getAnnotation().isAnalyzed() || fieldExpression.getAnnotation().isNormalized())) {
    throw new PredicateAnalyzerException(
        "Cannot handle " + call.getKind() + " expression because text or keyword field is analyzed or normalized, " + call);
  }

  switch (call.getKind()) {
    case LIKE:
      // LIKE/regexp cannot handle metadata columns
      isMeta(pair.getKey(), call, true);
      String sqlRegex = RegexpUtil.sqlToRegexLike(pair.getValue().stringValue());
      RexLiteral sqlRegexLiteral = rexBuilder.makeLiteral(sqlRegex);
      LiteralExpression sqlRegexExpression = new LiteralExpression(sqlRegexLiteral);
      SqlLikeOperator likeOperator = (SqlLikeOperator) call.getOperator();
      if (likeOperator.isNegated()) {
        return QueryExpression.create(pair.getKey()).notLike(sqlRegexExpression);
      } else {
        return QueryExpression.create(pair.getKey()).like(sqlRegexExpression);
      }
    case EQUALS:
      return QueryExpression.create(pair.getKey()).equals(pair.getValue());
    case NOT_EQUALS:
      return QueryExpression.create(pair.getKey()).notEquals(pair.getValue());
    case GREATER_THAN:
      if (swapped) {
        return QueryExpression.create(pair.getKey()).lt(pair.getValue());
      }
      return QueryExpression.create(pair.getKey()).gt(pair.getValue());
    case GREATER_THAN_OR_EQUAL:
      if (swapped) {
        return QueryExpression.create(pair.getKey()).lte(pair.getValue());
      }
      return QueryExpression.create(pair.getKey()).gte(pair.getValue());
    case LESS_THAN:
      if (swapped) {
        return QueryExpression.create(pair.getKey()).gt(pair.getValue());
      }
      return QueryExpression.create(pair.getKey()).lt(pair.getValue());
    case LESS_THAN_OR_EQUAL:
      if (swapped) {
        return QueryExpression.create(pair.getKey()).gte(pair.getValue());
      }
      return QueryExpression.create(pair.getKey()).lte(pair.getValue());
    default:
      break;
  }
  throw new PredicateAnalyzerException(format("Unable to handle call: [%s]", call));
}
 
Example 17
Source File: PredicateAnalyzer.java    From dremio-oss with Apache License 2.0 4 votes vote down vote up
private boolean supportedRexCall(RexCall call) {
  final SqlSyntax syntax = call.getOperator().getSyntax();
  switch (syntax) {
    case BINARY:
      switch (call.getKind()) {
        case AND:
        case OR:
        case LIKE:
        case EQUALS:
        case NOT_EQUALS:
        case GREATER_THAN:
        case GREATER_THAN_OR_EQUAL:
        case LESS_THAN:
        case LESS_THAN_OR_EQUAL:
          return true;
        default:
          return false;
      }
    case SPECIAL:
      switch (call.getKind()) {
        case CAST:
        case LIKE:
        case OTHER_FUNCTION:
          return true;
        case CASE:
        case SIMILAR:
        default:
          return false;
      }
    case FUNCTION:
      return true;
    case POSTFIX:
      switch (call.getKind()) {
        case IS_NOT_NULL:
        case IS_NULL:
          return true;
        default: // fall through
      }
    case FUNCTION_ID:
    case FUNCTION_STAR:
    case PREFIX: // NOT()
    default:
      return false;
  }
}
 
Example 18
Source File: RelOptUtil.java    From Bats with Apache License 2.0 4 votes vote down vote up
/**
 * Helper method for
 * {@link #splitJoinCondition(RexBuilder, int, RexNode, List, List, List, List)} and
 * {@link #splitJoinCondition(List, List, RexNode, List, List, List, List)}.
 *
 * <p>If the given expr <code>call</code> is an expanded version of
 * IS NOT DISTINCT FROM function call, collapse it and return a
 * IS NOT DISTINCT FROM function call.
 *
 * <p>For example: {@code t1.key IS NOT DISTINCT FROM t2.key}
 * can rewritten in expanded form as
 * {@code t1.key = t2.key OR (t1.key IS NULL AND t2.key IS NULL)}.
 *
 * @param call       Function expression to try collapsing.
 * @param rexBuilder {@link RexBuilder} instance to create new {@link RexCall} instances.
 * @return If the given function is an expanded IS NOT DISTINCT FROM function call,
 *         return a IS NOT DISTINCT FROM function call. Otherwise return the input
 *         function call as it is.
 */
private static RexCall collapseExpandedIsNotDistinctFromExpr(final RexCall call, final RexBuilder rexBuilder) {
    if (call.getKind() != SqlKind.OR || call.getOperands().size() != 2) {
        return call;
    }

    final RexNode op0 = call.getOperands().get(0);
    final RexNode op1 = call.getOperands().get(1);

    if (!(op0 instanceof RexCall) || !(op1 instanceof RexCall)) {
        return call;
    }

    RexCall opEqCall = (RexCall) op0;
    RexCall opNullEqCall = (RexCall) op1;

    if (opEqCall.getKind() == SqlKind.AND && opNullEqCall.getKind() == SqlKind.EQUALS) {
        RexCall temp = opEqCall;
        opEqCall = opNullEqCall;
        opNullEqCall = temp;
    }

    if (opNullEqCall.getKind() != SqlKind.AND || opNullEqCall.getOperands().size() != 2
            || opEqCall.getKind() != SqlKind.EQUALS) {
        return call;
    }

    final RexNode op10 = opNullEqCall.getOperands().get(0);
    final RexNode op11 = opNullEqCall.getOperands().get(1);
    if (op10.getKind() != SqlKind.IS_NULL || op11.getKind() != SqlKind.IS_NULL) {
        return call;
    }
    final RexNode isNullInput0 = ((RexCall) op10).getOperands().get(0);
    final RexNode isNullInput1 = ((RexCall) op11).getOperands().get(0);

    final String isNullInput0Digest = isNullInput0.toString();
    final String isNullInput1Digest = isNullInput1.toString();
    final String equalsInput0Digest = opEqCall.getOperands().get(0).toString();
    final String equalsInput1Digest = opEqCall.getOperands().get(1).toString();

    if ((isNullInput0Digest.equals(equalsInput0Digest) && isNullInput1Digest.equals(equalsInput1Digest))
            || (isNullInput1Digest.equals(equalsInput0Digest) && isNullInput0Digest.equals(equalsInput1Digest))) {
        return (RexCall) rexBuilder.makeCall(SqlStdOperatorTable.IS_NOT_DISTINCT_FROM,
                ImmutableList.of(isNullInput0, isNullInput1));
    }

    return call;
}
 
Example 19
Source File: RelOptUtil.java    From Bats with Apache License 2.0 4 votes vote down vote up
private static void splitJoinCondition(final RexBuilder rexBuilder, final int leftFieldCount, RexNode condition,
        List<Integer> leftKeys, List<Integer> rightKeys, List<Boolean> filterNulls, List<RexNode> nonEquiList) {
    if (condition instanceof RexCall) {
        RexCall call = (RexCall) condition;
        SqlKind kind = call.getKind();
        if (kind == SqlKind.AND) {
            for (RexNode operand : call.getOperands()) {
                splitJoinCondition(rexBuilder, leftFieldCount, operand, leftKeys, rightKeys, filterNulls,
                        nonEquiList);
            }
            return;
        }

        if (filterNulls != null) {
            call = collapseExpandedIsNotDistinctFromExpr(call, rexBuilder);
            kind = call.getKind();
        }

        // "=" and "IS NOT DISTINCT FROM" are the same except for how they
        // treat nulls.
        if (kind == SqlKind.EQUALS || (filterNulls != null && kind == SqlKind.IS_NOT_DISTINCT_FROM)) {
            final List<RexNode> operands = call.getOperands();
            if ((operands.get(0) instanceof RexInputRef) && (operands.get(1) instanceof RexInputRef)) {
                RexInputRef op0 = (RexInputRef) operands.get(0);
                RexInputRef op1 = (RexInputRef) operands.get(1);

                RexInputRef leftField;
                RexInputRef rightField;
                if ((op0.getIndex() < leftFieldCount) && (op1.getIndex() >= leftFieldCount)) {
                    // Arguments were of form 'op0 = op1'
                    leftField = op0;
                    rightField = op1;
                } else if ((op1.getIndex() < leftFieldCount) && (op0.getIndex() >= leftFieldCount)) {
                    // Arguments were of form 'op1 = op0'
                    leftField = op1;
                    rightField = op0;
                } else {
                    nonEquiList.add(condition);
                    return;
                }

                leftKeys.add(leftField.getIndex());
                rightKeys.add(rightField.getIndex() - leftFieldCount);
                if (filterNulls != null) {
                    filterNulls.add(kind == SqlKind.EQUALS);
                }
                return;
            }
            // Arguments were not field references, one from each side, so
            // we fail. Fall through.
        }
    }

    // Add this condition to the list of non-equi-join conditions.
    if (!condition.isAlwaysTrue()) {
        nonEquiList.add(condition);
    }
}
 
Example 20
Source File: RelOptUtil.java    From calcite with Apache License 2.0 3 votes vote down vote up
/**
 * Collapses an expanded version of {@code IS NOT DISTINCT FROM} expression.
 *
 * <p>Helper method for
 * {@link #splitJoinCondition(RexBuilder, int, RexNode, List, List, List, List)}
 * and
 * {@link #splitJoinCondition(List, List, RexNode, List, List, List, List)}.
 *
 * <p>If the given expr <code>call</code> is an expanded version of
 * {@code IS NOT DISTINCT FROM} function call, collapses it and return a
 * {@code IS NOT DISTINCT FROM} function call.
 *
 * <p>For example: {@code t1.key IS NOT DISTINCT FROM t2.key}
 * can rewritten in expanded form as
 * {@code t1.key = t2.key OR (t1.key IS NULL AND t2.key IS NULL)}.
 *
 * @param call       Function expression to try collapsing
 * @param rexBuilder {@link RexBuilder} instance to create new {@link RexCall} instances.
 * @return If the given function is an expanded IS NOT DISTINCT FROM function call,
 *         return a IS NOT DISTINCT FROM function call. Otherwise return the input
 *         function call as it is.
 */
public static RexCall collapseExpandedIsNotDistinctFromExpr(final RexCall call,
    final RexBuilder rexBuilder) {
  switch (call.getKind()) {
  case OR:
    return doCollapseExpandedIsNotDistinctFromOrExpr(call, rexBuilder);

  case CASE:
    return doCollapseExpandedIsNotDistinctFromCaseExpr(call, rexBuilder);

  default:
    return call;
  }
}