PaulJackson123 commented on code in PR #3495:
URL: https://github.com/apache/calcite/pull/3495#discussion_r1406903023


##########
core/src/main/java/org/apache/calcite/rel/metadata/RelMdColumnUniqueness.java:
##########
@@ -526,12 +525,78 @@ private static ImmutableBitSet 
decorateWithConstantColumnsFromPredicates(
       ImmutableBitSet checkingColumns, RelNode rel, RelMetadataQuery mq) {
     final RelOptPredicateList predicates = mq.getPulledUpPredicates(rel);
     if (!RelOptPredicateList.isEmpty(predicates)) {
-      ImmutableBitSet invariantIndexes = predicates.getInvariantColumnSet();
-      if (!invariantIndexes.isEmpty()) {
-        return checkingColumns.union(ImmutableBitSet.of(invariantIndexes));
+      ImmutableBitSet constantIndexes = getConstantColumnSet(predicates);
+      if (!constantIndexes.isEmpty()) {
+        return checkingColumns.union(ImmutableBitSet.of(constantIndexes));
       }
     }
-    // If no invariant columns deduced, return the original "checkingColumns".
+    // If no constant columns deduced, return the original "checkingColumns".
     return checkingColumns;
   }
+
+  /**
+   * Return the set of columns that are set to a constant literal or a scalar 
query (as
+   * in a correlated subquery). Examples of constants are {@code x} in the 
following:
+   * <pre>SELECT x FROM table WHERE x = 5</pre>
+   * and
+   * <pre>SELECT x, y FROM table WHERE x = (SELECT MAX(x) FROM table)</pre>
+   * <p/>
+   * NOTE: Subqueries that reference correlating variables are not considered 
constant:
+   * <pre>SELECT x, y FROM table A WHERE x = (SELECT MAX(x) FROM table B WHERE 
A.y = B.y)</pre>
+   */
+  static ImmutableBitSet getConstantColumnSet(RelOptPredicateList 
relOptPredicateList) {
+    ImmutableBitSet.Builder builder = ImmutableBitSet.builder();
+    relOptPredicateList.constantMap.keySet()
+        .stream()
+        .filter(RexInputRef.class::isInstance)
+        .map(RexInputRef.class::cast)
+        .map(RexSlot::getIndex)
+        .forEach(builder::set);
+
+    relOptPredicateList.pulledUpPredicates.forEach(rex -> {
+      if (rex.getKind() == SqlKind.EQUALS
+          || rex.getKind() == SqlKind.IS_NOT_DISTINCT_FROM) {
+        List<RexNode> ops = ((RexCall) rex).getOperands();
+        RexNode op0 = ops.get(0);
+        RexNode op1 = ops.get(1);
+        addInputRefIfOtherConstant(builder, op0, op1);
+        addInputRefIfOtherConstant(builder, op1, op0);
+      }
+    });
+
+    return builder.build();
+  }
+
+  private static void addInputRefIfOtherConstant(ImmutableBitSet.Builder 
builder, RexNode inputRef,
+      RexNode other) {
+    if (inputRef instanceof RexInputRef
+        && (other.getKind() == SqlKind.LITERAL || 
isConstantScalarQuery(other))) {
+      builder.set(((RexInputRef) inputRef).getIndex());
+    }
+  }
+
+  /**
+   * Returns whether the supplied {@link RexNode} is a constant scalar 
subquery - one that does not
+   * reference any correlating variables.
+   */
+  private static boolean isConstantScalarQuery(RexNode rexNode) {
+    if (rexNode.getKind() == SqlKind.SCALAR_QUERY) {
+      MutableBoolean hasCorrelatedVars = new MutableBoolean(false);
+      ((RexSubQuery) rexNode).rel.accept(new RelShuttleImpl() {
+        @Override public RelNode visit(final LogicalFilter filter) {
+          filter.getCondition().accept(new RexShuttle() {
+            @Override public RexNode visitFieldAccess(final RexFieldAccess 
fieldAccess) {
+              if (fieldAccess.getReferenceExpr().getKind() == 
SqlKind.CORREL_VARIABLE) {
+                hasCorrelatedVars.setTrue();
+              }
+              return super.visitFieldAccess(fieldAccess);
+            }
+          });
+          return super.visit(filter);
+        }

Review Comment:
   This change was made to account to the fact that scalar subqueries are not 
constant when they have correlating variables. Not sure this is the best way to 
detect correlating variables. Also, only checking filters here - not sure what 
to do about Calc or others.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to