@Override protected String visitQuantifiedComparisonExpression(QuantifiedComparisonExpression node, Void context) { return new StringBuilder() .append("(") .append(process(node.getValue(), context)) .append(' ') .append(node.getOperator().getValue()) .append(' ') .append(node.getQuantifier().toString()) .append(' ') .append(process(node.getSubquery(), context)) .append(")") .toString(); }
private Multimap<Symbol, Symbol> extractCorrelatedSymbolsMapping(List<Expression> correlatedConjuncts) { // TODO: handle coercions and non-direct column references ImmutableMultimap.Builder<Symbol, Symbol> mapping = ImmutableMultimap.builder(); for (Expression conjunct : correlatedConjuncts) { if (!(conjunct instanceof ComparisonExpression)) { continue; } ComparisonExpression comparison = (ComparisonExpression) conjunct; if (!(comparison.getLeft() instanceof SymbolReference && comparison.getRight() instanceof SymbolReference && comparison.getOperator().equals(EQUAL))) { continue; } Symbol left = Symbol.from(comparison.getLeft()); Symbol right = Symbol.from(comparison.getRight()); if (correlation.contains(left) && !correlation.contains(right)) { mapping.put(left, right); } if (correlation.contains(right) && !correlation.contains(left)) { mapping.put(right, left); } } return mapping.build(); }
leftComparisonExpressions.add(secondExpression); rightComparisonExpressions.add(firstExpression); joinConditionComparisonOperators.add(comparisonOperator.flip());
leftComparisonExpressions.add(secondExpression); rightComparisonExpressions.add(firstExpression); joinConditionComparisonOperators.add(comparisonOperator.flip());
format("Unexpected quantified comparison: '%s %s'", quantifiedComparison.getOperator().getValue(), quantifiedComparison.getQuantifier()));
format("Unexpected quantified comparison: '%s %s'", quantifiedComparison.getOperator().getValue(), quantifiedComparison.getQuantifier()));
@VisibleForTesting public static final class ExtractSpatialLeftJoin implements Rule<JoinNode> { private static final Pattern<JoinNode> PATTERN = join().matching(node -> node.getCriteria().isEmpty() && node.getFilter().isPresent() && node.getType() == LEFT); private final Metadata metadata; private final SplitManager splitManager; private final PageSourceManager pageSourceManager; private final SqlParser sqlParser; public ExtractSpatialLeftJoin(Metadata metadata, SplitManager splitManager, PageSourceManager pageSourceManager, SqlParser sqlParser) { this.metadata = requireNonNull(metadata, "metadata is null"); this.splitManager = requireNonNull(splitManager, "splitManager is null"); this.pageSourceManager = requireNonNull(pageSourceManager, "pageSourceManager is null"); this.sqlParser = requireNonNull(sqlParser, "sqlParser is null"); } @Override public boolean isEnabled(Session session) { return isSpatialJoinEnabled(session); } @Override public Pattern<JoinNode> getPattern() { return PATTERN; }
@VisibleForTesting public static final class ExtractSpatialLeftJoin implements Rule<JoinNode> { private static final Pattern<JoinNode> PATTERN = join().matching(node -> node.getCriteria().isEmpty() && node.getFilter().isPresent() && node.getType() == LEFT); private final Metadata metadata; private final SplitManager splitManager; private final PageSourceManager pageSourceManager; public ExtractSpatialLeftJoin(Metadata metadata, SplitManager splitManager, PageSourceManager pageSourceManager) { this.metadata = requireNonNull(metadata, "metadata is null"); this.splitManager = requireNonNull(splitManager, "splitManager is null"); this.pageSourceManager = requireNonNull(pageSourceManager, "pageSourceManager is null"); } @Override public boolean isEnabled(Session session) { return isSpatialJoinEnabled(session); } @Override public Pattern<JoinNode> getPattern() { return PATTERN; } @Override
comparisonOperator = comparison.getOperator().flip(); value = new NullableValue(leftType, left);
comparisonOperator = comparison.getOperator().flip(); value = new NullableValue(leftType, left);
@Override protected Object visitComparisonExpression(ComparisonExpression node, Object context) { ComparisonExpression.Operator operator = node.getOperator(); Object left = process(node.getLeft(), context); if (left == null && operator != ComparisonExpression.Operator.IS_DISTINCT_FROM) { return null; } Object right = process(node.getRight(), context); if (operator == ComparisonExpression.Operator.IS_DISTINCT_FROM) { if (left == null && right == null) { return false; } else if (left == null || right == null) { return true; } } else if (right == null) { return null; } if (hasUnresolvedValue(left, right)) { return new ComparisonExpression(operator, toExpression(left, type(node.getLeft())), toExpression(right, type(node.getRight()))); } return invokeOperator(OperatorType.valueOf(operator.name()), types(node.getLeft(), node.getRight()), ImmutableList.of(left, right)); }
@Override protected Object visitComparisonExpression(ComparisonExpression node, Object context) { ComparisonExpression.Operator operator = node.getOperator(); Object left = process(node.getLeft(), context); if (left == null && operator != ComparisonExpression.Operator.IS_DISTINCT_FROM) { return null; } Object right = process(node.getRight(), context); if (operator == ComparisonExpression.Operator.IS_DISTINCT_FROM) { if (left == null && right == null) { return false; } else if (left == null || right == null) { return true; } } else if (right == null) { return null; } if (hasUnresolvedValue(left, right)) { return new ComparisonExpression(operator, toExpression(left, type(node.getLeft())), toExpression(right, type(node.getRight()))); } return invokeOperator(OperatorType.valueOf(operator.name()), types(node.getLeft(), node.getRight()), ImmutableList.of(left, right)); }
private Multimap<Symbol, Symbol> extractCorrelatedSymbolsMapping(List<Expression> correlatedConjuncts) { // TODO: handle coercions and non-direct column references ImmutableMultimap.Builder<Symbol, Symbol> mapping = ImmutableMultimap.builder(); for (Expression conjunct : correlatedConjuncts) { if (!(conjunct instanceof ComparisonExpression)) { continue; } ComparisonExpression comparison = (ComparisonExpression) conjunct; if (!(comparison.getLeft() instanceof SymbolReference && comparison.getRight() instanceof SymbolReference && comparison.getOperator().equals(EQUAL))) { continue; } Symbol left = Symbol.from(comparison.getLeft()); Symbol right = Symbol.from(comparison.getRight()); if (correlation.contains(left) && !correlation.contains(right)) { mapping.put(left, right); } if (correlation.contains(right) && !correlation.contains(left)) { mapping.put(right, left); } } return mapping.build(); }
@Override public Expression rewriteNotExpression(NotExpression node, Void context, ExpressionTreeRewriter<Void> treeRewriter) { if (node.getValue() instanceof LogicalBinaryExpression) { LogicalBinaryExpression child = (LogicalBinaryExpression) node.getValue(); List<Expression> predicates = extractPredicates(child); List<Expression> negatedPredicates = predicates.stream().map(predicate -> treeRewriter.rewrite((Expression) new NotExpression(predicate), context)).collect(toImmutableList()); return combinePredicates(child.getOperator().flip(), negatedPredicates); } else if (node.getValue() instanceof ComparisonExpression && ((ComparisonExpression) node.getValue()).getOperator() != IS_DISTINCT_FROM) { ComparisonExpression child = (ComparisonExpression) node.getValue(); return new ComparisonExpression(child.getOperator().negate(), treeRewriter.rewrite(child.getLeft(), context), treeRewriter.rewrite(child.getRight(), context)); } else if (node.getValue() instanceof NotExpression) { NotExpression child = (NotExpression) node.getValue(); return treeRewriter.rewrite(child.getValue(), context); } return new NotExpression(treeRewriter.rewrite(node.getValue(), context)); } }
@Override public Expression rewriteNotExpression(NotExpression node, Void context, ExpressionTreeRewriter<Void> treeRewriter) { if (node.getValue() instanceof LogicalBinaryExpression) { LogicalBinaryExpression child = (LogicalBinaryExpression) node.getValue(); List<Expression> predicates = extractPredicates(child); List<Expression> negatedPredicates = predicates.stream().map(predicate -> treeRewriter.rewrite((Expression) new NotExpression(predicate), context)).collect(toImmutableList()); return combinePredicates(child.getOperator().flip(), negatedPredicates); } else if (node.getValue() instanceof ComparisonExpression && ((ComparisonExpression) node.getValue()).getOperator() != IS_DISTINCT_FROM) { ComparisonExpression child = (ComparisonExpression) node.getValue(); return new ComparisonExpression(child.getOperator().negate(), treeRewriter.rewrite(child.getLeft(), context), treeRewriter.rewrite(child.getRight(), context)); } else if (node.getValue() instanceof NotExpression) { NotExpression child = (NotExpression) node.getValue(); return treeRewriter.rewrite(child.getValue(), context); } return new NotExpression(treeRewriter.rewrite(node.getValue(), context)); } }
@Override protected String visitQuantifiedComparisonExpression(QuantifiedComparisonExpression node, Void context) { return new StringBuilder() .append("(") .append(process(node.getValue(), context)) .append(' ') .append(node.getOperator().getValue()) .append(' ') .append(node.getQuantifier().toString()) .append(' ') .append(process(node.getSubquery(), context)) .append(")") .toString(); }
@Test public void testComparisonExpressionWithNulls() { for (ComparisonExpression.Operator operator : ComparisonExpression.Operator.values()) { if (operator == ComparisonExpression.Operator.IS_DISTINCT_FROM) { // IS DISTINCT FROM has different NULL semantics continue; } assertFilter(format("NULL %s NULL", operator.getValue()), false); assertFilter(format("42 %s NULL", operator.getValue()), false); assertFilter(format("NULL %s 42", operator.getValue()), false); assertFilter(format("11.1 %s NULL", operator.getValue()), false); assertFilter(format("NULL %s 11.1", operator.getValue()), false); } }
@Test public void testComparisonExpressionWithNulls() { for (ComparisonExpression.Operator operator : ComparisonExpression.Operator.values()) { if (operator == ComparisonExpression.Operator.IS_DISTINCT_FROM) { // IS DISTINCT FROM has different NULL semantics continue; } assertFilter(format("NULL %s NULL", operator.getValue()), false); assertFilter(format("42 %s NULL", operator.getValue()), false); assertFilter(format("NULL %s 42", operator.getValue()), false); assertFilter(format("11.1 %s NULL", operator.getValue()), false); assertFilter(format("NULL %s 11.1", operator.getValue()), false); } }