This is an automated email from the ASF dual-hosted git repository.
mihaibudiu pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/calcite.git
The following commit(s) were added to refs/heads/main by this push:
new 437398834e [CALCITE-7719] Field access on an element of a ROW array
built by a sub-query raises IllegalArgumentException
437398834e is described below
commit 437398834e49c8086a64870427214fec428684fc
Author: Mihai Budiu <[email protected]>
AuthorDate: Thu Aug 13 21:58:48 2026 -0700
[CALCITE-7719] Field access on an element of a ROW array built by a
sub-query raises IllegalArgumentException
Signed-off-by: Mihai Budiu <[email protected]>
---
.../java/org/apache/calcite/rex/LogicVisitor.java | 28 ++++++++++++++++++++--
core/src/test/resources/sql/sub-query.iq | 13 ++++++++++
2 files changed, 39 insertions(+), 2 deletions(-)
diff --git a/core/src/main/java/org/apache/calcite/rex/LogicVisitor.java
b/core/src/main/java/org/apache/calcite/rex/LogicVisitor.java
index 68a0d0aa96..b18613b104 100644
--- a/core/src/main/java/org/apache/calcite/rex/LogicVisitor.java
+++ b/core/src/main/java/org/apache/calcite/rex/LogicVisitor.java
@@ -31,13 +31,20 @@
import static java.util.Objects.requireNonNull;
/**
- * Visitor pattern for traversing a tree of {@link RexNode} objects.
+ * Visitor that, given the {@link Logic} in force at the root of an
+ * expression, computes the Logic in force at every occurrence of a sought
+ * sub-expression {@code seek}. Results are collected in {@code
logicCollection}.
+ *
+ * <p>This value is meaningful only for expressions that evaluate to Boolean
values.
*/
public class LogicVisitor extends RexUnaryBiVisitor<@Nullable Logic> {
private final RexNode seek;
private final Collection<Logic> logicCollection;
- /** Creates a LogicVisitor. */
+ /** Creates a LogicVisitor.
+ *
+ * @param seek Expression whose occurrences to find
+ * @param logicCollection Receives the Logic in force for each occurrence of
{@code seek} */
private LogicVisitor(RexNode seek, Collection<Logic> logicCollection) {
super(true);
this.seek = seek;
@@ -51,6 +58,14 @@ private LogicVisitor(RexNode seek, Collection<Logic>
logicCollection) {
* answer) with the fewest possibilities (that is, we prefer one that
* returns [true as true, false as false, unknown as false] over one that
* distinguishes false from unknown).
+ *
+ * <p>If {@code seek} occurs multiple times, the result is
+ * a single Logic that is safe for every one of them. If the occurrences
+ * are evaluated under different Logic values, the result is
+ * {@link Logic#TRUE_FALSE_UNKNOWN}, which is safe for any occurrence.
+ *
+ * @throws IllegalArgumentException if {@code seek} does not occur in
+ * {@code nodes}
*/
public static Logic find(Logic logic, List<RexNode> nodes,
RexNode seek) {
@@ -74,6 +89,9 @@ public static Logic find(Logic logic, List<RexNode> nodes,
}
}
+ /** Appends to {@code logicList}, for each occurrence of {@code seek}
+ * within {@code node} in depth-first order, the Logic in force at that
+ * occurrence. */
public static void collect(RexNode node, RexNode seek, Logic logic,
List<Logic> logicList) {
node.accept(new LogicVisitor(seek, logicList), logic);
@@ -137,6 +155,12 @@ public static void collect(RexNode node, RexNode seek,
Logic logic,
@Override public @Nullable Logic visitFieldAccess(RexFieldAccess fieldAccess,
@Nullable Logic arg) {
+ // Not a Boolean value
+ Logic logic = requireNonNull(arg, "arg");
+ if (logic == Logic.TRUE) {
+ logic = Logic.TRUE_FALSE_UNKNOWN;
+ }
+ super.visitFieldAccess(fieldAccess, logic);
return end(fieldAccess, arg);
}
diff --git a/core/src/test/resources/sql/sub-query.iq
b/core/src/test/resources/sql/sub-query.iq
index 5d1bbb7386..08c5bcf6e4 100644
--- a/core/src/test/resources/sql/sub-query.iq
+++ b/core/src/test/resources/sql/sub-query.iq
@@ -10152,3 +10152,16 @@ ORDER BY emp.ename;
!ok
# End sub-query.iq
+
+# [CALCITE-7719] Field access on an element of a ROW array built by a
+# sub-query raises IllegalArgumentException.
+select t.a[1]."EXPR$0"."EXPR$1" as v
+from (select array(select ROW(ROW(1, 2), 3) from (values (0))) as a) as t;
++---+
+| V |
++---+
+| 2 |
++---+
+(1 row)
+
+!ok