Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 26 additions & 2 deletions core/src/main/java/org/apache/calcite/rex/LogicVisitor.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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) {
Expand All @@ -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);
Expand Down Expand Up @@ -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);
}

Expand Down
13 changes: 13 additions & 0 deletions core/src/test/resources/sql/sub-query.iq
Original file line number Diff line number Diff line change
Expand Up @@ -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
Loading