From c9d5a6104c9b381bded6f6922bb36e74bee96f1e Mon Sep 17 00:00:00 2001 From: Robert Brunel Date: Tue, 12 May 2026 15:52:33 +0100 Subject: [PATCH 1/3] Allow more types of boolean expressions as top-level `WHERE`/`ON` predicates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extend `Expression.Utils.toUnderlyingPredicate()` to handle value types other than `BooleanValue`, in particular `ConstantObjectValue` and `NullValue`. Among other boolean expression types, this fixes a gap that prevented a `TRUE`, `FALSE`, or `NULL` literal from being used directly as a `WHERE` or `JOIN … ON` predicate. Testing: * `join-tests.yamsql` covers `WHERE {TRUE|FALSE|NULL}` and `JOIN … ON {TRUE|FALSE|NULL}`. * `boolean-ddl.yamsql` exercises the “for DDL” code path via `CREATE INDEX … WHERE {TRUE|FALSE|NULL}`. Resolves #4150. --- .../record/metadata/IndexPredicate.java | 3 +- .../predicates/ConstantPredicate.java | 13 + .../recordlayer/query/Expression.java | 48 +- .../src/test/java/YamlIntegrationTests.java | 5 + .../src/test/resources/boolean-ddl.yamsql | 43 ++ .../test/resources/join-tests.metrics.binpb | 575 +++++++++++------- .../test/resources/join-tests.metrics.yaml | 245 +++++--- .../src/test/resources/join-tests.yamsql | 48 ++ 8 files changed, 667 insertions(+), 313 deletions(-) create mode 100644 yaml-tests/src/test/resources/boolean-ddl.yamsql diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/metadata/IndexPredicate.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/metadata/IndexPredicate.java index 0205363b63..36d7699e5c 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/metadata/IndexPredicate.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/metadata/IndexPredicate.java @@ -424,8 +424,9 @@ public ConstantPredicate(@Nonnull final com.apple.foundationdb.record.query.plan this.value = ConstantValue.FALSE; } else if (predicate == com.apple.foundationdb.record.query.plan.cascades.predicates.ConstantPredicate.NULL) { this.value = ConstantValue.NULL; + } else { + throw new RecordCoreException("could not create a PoJo constant index predicate").addLogInfo(LogMessageKeys.VALUE, predicate); } - throw new RecordCoreException("could not create a PoJo constant index predicate").addLogInfo(LogMessageKeys.VALUE, predicate); } public ConstantPredicate(@Nonnull final RecordMetaDataProto.ConstantPredicate proto) { diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/ConstantPredicate.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/ConstantPredicate.java index 9b7c9386e5..280387c452 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/ConstantPredicate.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/ConstantPredicate.java @@ -66,6 +66,19 @@ public class ConstantPredicate extends AbstractQueryPredicate implements LeafQue @Nullable private final Boolean value; + /** + * Returns the {@link ConstantPredicate} singleton corresponding to the given boolean value. + * + * @return {@link #TRUE} for {@code true}, {@link #FALSE} for {@code false}, {@link #NULL} for {@code null} + */ + @Nonnull + public static ConstantPredicate of(@Nullable final Boolean value) { + if (value == null) { + return NULL; + } + return value ? TRUE : FALSE; + } + public ConstantPredicate(@Nonnull final PlanSerializationContext serializationContext, @Nonnull final PConstantPredicate constantPredicateProto) { super(serializationContext, Objects.requireNonNull(constantPredicateProto.getSuper())); diff --git a/fdb-relational-core/src/main/java/com/apple/foundationdb/relational/recordlayer/query/Expression.java b/fdb-relational-core/src/main/java/com/apple/foundationdb/relational/recordlayer/query/Expression.java index e91b5ed750..6f58d9558c 100644 --- a/fdb-relational-core/src/main/java/com/apple/foundationdb/relational/recordlayer/query/Expression.java +++ b/fdb-relational-core/src/main/java/com/apple/foundationdb/relational/recordlayer/query/Expression.java @@ -22,10 +22,15 @@ import com.apple.foundationdb.annotation.API; import com.apple.foundationdb.record.EvaluationContext; +import com.apple.foundationdb.record.query.expressions.Comparisons; import com.apple.foundationdb.record.query.plan.cascades.AliasMap; import com.apple.foundationdb.record.query.plan.cascades.Column; import com.apple.foundationdb.record.query.plan.cascades.CorrelationIdentifier; +import com.apple.foundationdb.record.query.plan.cascades.predicates.ConstantPredicate; import com.apple.foundationdb.record.query.plan.cascades.predicates.QueryPredicate; +import com.apple.foundationdb.record.query.plan.cascades.predicates.ValuePredicate; +import com.apple.foundationdb.record.query.plan.cascades.typing.Type; +import com.apple.foundationdb.record.query.plan.cascades.typing.TypeRepository; import com.apple.foundationdb.record.query.plan.cascades.values.AggregateValue; import com.apple.foundationdb.record.query.plan.cascades.values.AndOrValue; import com.apple.foundationdb.record.query.plan.cascades.values.ArithmeticValue; @@ -33,9 +38,11 @@ import com.apple.foundationdb.record.query.plan.cascades.values.ConstantObjectValue; import com.apple.foundationdb.record.query.plan.cascades.values.LiteralValue; import com.apple.foundationdb.record.query.plan.cascades.values.NotValue; +import com.apple.foundationdb.record.query.plan.cascades.values.NullValue; import com.apple.foundationdb.record.query.plan.cascades.values.RecordConstructorValue; import com.apple.foundationdb.record.query.plan.cascades.values.RelOpValue; import com.apple.foundationdb.record.query.plan.cascades.values.Value; +import com.apple.foundationdb.relational.api.exceptions.ErrorCode; import com.apple.foundationdb.relational.api.metadata.DataType; import com.apple.foundationdb.relational.recordlayer.metadata.DataTypeUtils; import com.apple.foundationdb.relational.util.Assert; @@ -351,18 +358,45 @@ private static Iterable filterUnderlying(@Nonnull final Expression expres .collect(ImmutableList.toImmutableList()); } + /** + * Converts a boolean-typed {@link Expression} into a {@link QueryPredicate} suitable for use as a + * {@code WHERE} or {@code ON} predicate. If the underlying value already implements {@link BooleanValue} + * (for example, an {@code AND}, {@code OR}, comparison, or {@code NOT} expression), it converts itself. + * Otherwise, the value may be a SQL {@code NULL} ({@link NullValue}), a {@code BOOLEAN}-typed literal, + * constant reference, parameter, or column. A {@code NullValue} folds to {@link ConstantPredicate#NULL}. + * A literal ({@link LiteralValue}) folds to the corresponding {@link ConstantPredicate}. Everything + * else is wrapped as a {@code ValuePredicate} performing a {@code «value» = TRUE} comparison. + */ @Nonnull public static QueryPredicate toUnderlyingPredicate(@Nonnull final Expression expression, @Nonnull final Set localAliases, boolean forDdl) { - final var value = Assert.castUnchecked(expression.getUnderlying(), BooleanValue.class); - final Optional result; - if (forDdl) { - result = value.toQueryPredicate(ParseHelpers.EMPTY_TYPE_REPOSITORY, localAliases); - } else { - result = value.toQueryPredicate(null, localAliases); + final Value value = expression.getUnderlying(); + + // A `BooleanValue` can convert itself into a `QueryPredicate`. + if (value instanceof final BooleanValue booleanValue) { + final TypeRepository typeRepository = forDdl ? ParseHelpers.EMPTY_TYPE_REPOSITORY : null; + final Optional result = booleanValue.toQueryPredicate(typeRepository, localAliases); + return Assert.optionalUnchecked(result); + } + + // Recognize `NullValue` as a null boolean `ConstantPredicate`. + if (value instanceof NullValue) { + return ConstantPredicate.NULL; } - return Assert.optionalUnchecked(result); + + // At this point the `value` is some other boolean expression that does not implement `BooleanValue`. + Assert.thatUnchecked(value.getResultType().getTypeCode() == Type.TypeCode.BOOLEAN, + ErrorCode.DATATYPE_MISMATCH, + () -> "expected boolean expression but got " + value.getResultType()); + + // Convert a plain boolean `LiteralValue` to `ConstantPredicate`. + if (value instanceof final LiteralValue literalValue) { + return ConstantPredicate.of((Boolean) literalValue.getLiteralValue()); + } + + // For other cases, lift the expression into a `ValuePredicate` performing a `«value» = TRUE` comparison. + return new ValuePredicate(value, new Comparisons.SimpleComparison(Comparisons.Type.EQUALS, true)); } } diff --git a/yaml-tests/src/test/java/YamlIntegrationTests.java b/yaml-tests/src/test/java/YamlIntegrationTests.java index 1b4042d060..3ddd1465b6 100644 --- a/yaml-tests/src/test/java/YamlIntegrationTests.java +++ b/yaml-tests/src/test/java/YamlIntegrationTests.java @@ -100,6 +100,11 @@ void booleanTypes(YamlTest.Runner runner) throws Exception { runner.runYamsql("boolean.yamsql"); } + @TestTemplate + void boolLiteralPredicate(YamlTest.Runner runner) throws Exception { + runner.runYamsql("boolean-ddl.yamsql"); + } + @TestTemplate void bytes(YamlTest.Runner runner) throws Exception { runner.runYamsql("bytes.yamsql"); diff --git a/yaml-tests/src/test/resources/boolean-ddl.yamsql b/yaml-tests/src/test/resources/boolean-ddl.yamsql new file mode 100644 index 0000000000..69dd92ca35 --- /dev/null +++ b/yaml-tests/src/test/resources/boolean-ddl.yamsql @@ -0,0 +1,43 @@ +# +# boolean-ddl.yamsql +# +# This source file is part of the FoundationDB open source project +# +# Copyright 2021-2026 Apple Inc. and the FoundationDB project authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +--- +options: + supported_version: !current_version +--- +# Exercise boolean constants (TRUE/FALSE/NULL) used as top-level WHERE predicates in `CREATE INDEX … AS` DDL statements. +# This covers the `forDdl == true` branch of `Expression.Utils.toUnderlyingPredicate()`. +schema_template: + CREATE TABLE T ("id" INTEGER, "col1" INTEGER, PRIMARY KEY ("id")) + CREATE INDEX idx_true AS SELECT "col1" FROM T WHERE TRUE ORDER BY "col1" + CREATE INDEX idx_false AS SELECT "col1" FROM T WHERE FALSE ORDER BY "col1" + CREATE INDEX idx_null AS SELECT "col1" FROM T WHERE NULL ORDER BY "col1" +--- +setup: + steps: + - query: INSERT INTO T VALUES (1, 100) +--- +test_block: + preset: single_repetition_ordered + tests: + - + # Just confirm the table is usable. + - query: SELECT "col1" FROM T ORDER BY "col1" + - result: [{col1: 100}] +... diff --git a/yaml-tests/src/test/resources/join-tests.metrics.binpb b/yaml-tests/src/test/resources/join-tests.metrics.binpb index d519a09d65..72ee229e9c 100644 --- a/yaml-tests/src/test/resources/join-tests.metrics.binpb +++ b/yaml-tests/src/test/resources/join-tests.metrics.binpb @@ -1,7 +1,7 @@ /  unnamed-2EXPLAIN select fname, lname from emp inner join project on emp_id = emp.id inner join dept on dept_id = dept.id and dept.name = 'Sales';. -ޤE (y0Ȟ8@+SCAN([IS DEPT]) | FILTER _.NAME EQUALS promote(@c29 AS STRING) | FLATMAP q0 -> { SCAN([IS PROJECT]) | FLATMAP q1 -> { SCAN([IS EMP]) | FILTER q1.EMP_ID EQUALS _.ID AND _.DEPT_ID EQUALS q0.ID AS q2 RETURN q2 } AS q2 RETURN (q2.FNAME AS FNAME, q2.LNAME AS LNAME) },digraph G { +P #(y08@+SCAN([IS DEPT]) | FILTER _.NAME EQUALS promote(@c29 AS STRING) | FLATMAP q0 -> { SCAN([IS PROJECT]) | FLATMAP q1 -> { SCAN([IS EMP]) | FILTER q1.EMP_ID EQUALS _.ID AND _.DEPT_ID EQUALS q0.ID AS q2 RETURN q2 } AS q2 RETURN (q2.FNAME AS FNAME, q2.LNAME AS LNAME) },digraph G { fontname=courier; rankdir=BT; splines=line; @@ -10,46 +10,46 @@ 3 [ label=<
Scan
comparisons: [IS DEPT]
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, STRING AS NAME)" ]; 4 [ label=<
Primary Storage
record types: [A, PROJECT, B, JUB, JA, JUA, JB, JUD, EMP, DEPT, JD]
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, STRING AS NAME)" ]; 5 [ label=<
Nested Loop Join
FLATMAP q2
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, STRING AS FNAME, STRING AS LNAME, LONG AS DEPT_ID)" ]; - 6 [ label=<
Predicate Filter
WHERE q6.EMP_ID EQUALS q2.ID AND q2.DEPT_ID EQUALS q10.ID
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, STRING AS FNAME, STRING AS LNAME, LONG AS DEPT_ID)" ]; - 7 [ label=<
Scan
comparisons: [IS PROJECT]
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, STRING AS NAME, STRING AS DSC, LONG AS EMP_ID)" ]; - 8 [ label=<
Scan
comparisons: [IS EMP]
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, STRING AS FNAME, STRING AS LNAME, LONG AS DEPT_ID)" ]; - 9 [ label=<
Primary Storage
record types: [A, PROJECT, B, JUB, JA, JUA, JB, JUD, EMP, DEPT, JD]
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, STRING AS NAME, STRING AS DSC, LONG AS EMP_ID)" ]; + 6 [ label=<
Scan
comparisons: [IS PROJECT]
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, STRING AS NAME, STRING AS DSC, LONG AS EMP_ID)" ]; + 7 [ label=<
Predicate Filter
WHERE q6.EMP_ID EQUALS q2.ID AND q2.DEPT_ID EQUALS q10.ID
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, STRING AS FNAME, STRING AS LNAME, LONG AS DEPT_ID)" ]; + 8 [ label=<
Primary Storage
record types: [A, PROJECT, B, JUB, JA, JUA, JB, JUD, EMP, DEPT, JD]
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, STRING AS NAME, STRING AS DSC, LONG AS EMP_ID)" ]; + 9 [ label=<
Scan
comparisons: [IS EMP]
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, STRING AS FNAME, STRING AS LNAME, LONG AS DEPT_ID)" ]; 10 [ label=<
Primary Storage
record types: [A, PROJECT, B, JUB, JA, JUA, JB, JUD, EMP, DEPT, JD]
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, STRING AS FNAME, STRING AS LNAME, LONG AS DEPT_ID)" ]; 3 -> 2 [ label=< q10> label="q10" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 3 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q10> label="q10" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 6 -> 5 [ label=< q2> label="q2" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 7 -> 5 [ label=< q6> label="q6" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 8 -> 6 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 9 -> 7 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 10 -> 8 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 6 -> 5 [ label=< q6> label="q6" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 7 -> 5 [ label=< q2> label="q2" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 8 -> 6 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 9 -> 7 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 10 -> 9 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 1 [ label=< q2> label="q2" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; { - 6 -> 1 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; + 7 -> 5 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; } { - 5 -> 1 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; + rank=same; + rankDir=LR; + 6 -> 7 [ color="red" style="invis" ]; } { 2 -> 1 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; } { - rank=same; - rankDir=LR; - 2 -> 5 [ color="red" style="invis" ]; + 7 -> 1 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; } { - 6 -> 5 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; + 5 -> 1 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; } { rank=same; rankDir=LR; - 7 -> 6 [ color="red" style="invis" ]; + 2 -> 5 [ color="red" style="invis" ]; } })  unnamed-2wEXPLAIN select dept.name, project.name from emp, dept, project where emp.dept_id = dept.id and project.emp_id = emp.id;( - @ (`08@ SCAN([IS PROJECT]) | FLATMAP q0 -> { SCAN([IS DEPT]) | FLATMAP q1 -> { SCAN([IS EMP]) | FILTER _.DEPT_ID EQUALS q1.ID AND q0.EMP_ID EQUALS _.ID AS q2 RETURN q1 } AS q1 RETURN (q1.NAME AS _0, q0.NAME AS _1) }&digraph G { + 7 (`08@ SCAN([IS PROJECT]) | FLATMAP q0 -> { SCAN([IS DEPT]) | FLATMAP q1 -> { SCAN([IS EMP]) | FILTER _.DEPT_ID EQUALS q1.ID AND q0.EMP_ID EQUALS _.ID AS q2 RETURN q1 } AS q1 RETURN (q1.NAME AS _0, q0.NAME AS _1) }&digraph G { fontname=courier; rankdir=BT; splines=line; @@ -89,10 +89,10 @@ rankDir=LR; 2 -> 4 [ color="red" style="invis" ]; } -}) +}*  - unnamed-2EXPLAIN select dept.name, project.name from emp inner join dept on emp.dept_id = dept.id inner join project on project.emp_id = emp.id;( - G (`08@ SCAN([IS PROJECT]) | FLATMAP q0 -> { SCAN([IS DEPT]) | FLATMAP q1 -> { SCAN([IS EMP]) | FILTER _.DEPT_ID EQUALS q1.ID AND q0.EMP_ID EQUALS _.ID AS q2 RETURN q1 } AS q1 RETURN (q1.NAME AS _0, q0.NAME AS _1) }&digraph G { + unnamed-2EXPLAIN select dept.name, project.name from emp inner join dept on emp.dept_id = dept.id inner join project on project.emp_id = emp.id;( + ȟ S(`08@ SCAN([IS PROJECT]) | FLATMAP q0 -> { SCAN([IS DEPT]) | FLATMAP q1 -> { SCAN([IS EMP]) | FILTER _.DEPT_ID EQUALS q1.ID AND q0.EMP_ID EQUALS _.ID AS q2 RETURN q1 } AS q1 RETURN (q1.NAME AS _0, q0.NAME AS _1) }&digraph G { fontname=courier; rankdir=BT; splines=line; @@ -100,42 +100,42 @@ 2 [ label=<
Scan
comparisons: [IS PROJECT]
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, STRING AS NAME, STRING AS DSC, LONG AS EMP_ID)" ]; 3 [ label=<
Primary Storage
record types: [A, PROJECT, B, JUB, JA, JUA, JB, JUD, EMP, DEPT, JD]
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, STRING AS NAME, STRING AS DSC, LONG AS EMP_ID)" ]; 4 [ label=<
Nested Loop Join
FLATMAP q6
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, STRING AS NAME)" ]; - 5 [ label=<
Predicate Filter
WHERE q2.DEPT_ID EQUALS q6.ID AND q10.EMP_ID EQUALS q2.ID
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, STRING AS FNAME, STRING AS LNAME, LONG AS DEPT_ID)" ]; - 6 [ label=<
Scan
comparisons: [IS DEPT]
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, STRING AS NAME)" ]; - 7 [ label=<
Scan
comparisons: [IS EMP]
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, STRING AS FNAME, STRING AS LNAME, LONG AS DEPT_ID)" ]; - 8 [ label=<
Primary Storage
record types: [A, PROJECT, B, JUB, JA, JUA, JB, JUD, EMP, DEPT, JD]
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, STRING AS NAME)" ]; + 5 [ label=<
Scan
comparisons: [IS DEPT]
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, STRING AS NAME)" ]; + 6 [ label=<
Predicate Filter
WHERE q2.DEPT_ID EQUALS q6.ID AND q10.EMP_ID EQUALS q2.ID
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, STRING AS FNAME, STRING AS LNAME, LONG AS DEPT_ID)" ]; + 7 [ label=<
Primary Storage
record types: [A, PROJECT, B, JUB, JA, JUA, JB, JUD, EMP, DEPT, JD]
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, STRING AS NAME)" ]; + 8 [ label=<
Scan
comparisons: [IS EMP]
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, STRING AS FNAME, STRING AS LNAME, LONG AS DEPT_ID)" ]; 9 [ label=<
Primary Storage
record types: [A, PROJECT, B, JUB, JA, JUA, JB, JUD, EMP, DEPT, JD]
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, STRING AS FNAME, STRING AS LNAME, LONG AS DEPT_ID)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q10> label="q10" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 5 -> 4 [ label=< q2> label="q2" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 6 -> 4 [ label=< q6> label="q6" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 7 -> 5 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 8 -> 6 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 9 -> 7 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 -> 4 [ label=< q6> label="q6" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 6 -> 4 [ label=< q2> label="q2" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 7 -> 5 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 8 -> 6 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 9 -> 8 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 1 [ label=< q6> label="q6" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; { - 5 -> 4 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; + 6 -> 1 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; } { - rank=same; - rankDir=LR; - 6 -> 5 [ color="red" style="invis" ]; + 4 -> 1 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; } { - 5 -> 1 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; + rank=same; + rankDir=LR; + 2 -> 4 [ color="red" style="invis" ]; } { - 4 -> 1 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; + 6 -> 4 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; } { rank=same; rankDir=LR; - 2 -> 4 [ color="red" style="invis" ]; + 5 -> 6 [ color="red" style="invis" ]; } }*  unnamed-2EXPLAIN select * from (select dept.name, project.name from emp, dept, project where emp.dept_id = dept.id and project.emp_id = emp.id) X;( - ѧ: (b0ڦ8@ SCAN([IS PROJECT]) | FLATMAP q0 -> { SCAN([IS DEPT]) | FLATMAP q1 -> { SCAN([IS EMP]) | FILTER _.DEPT_ID EQUALS q1.ID AND q0.EMP_ID EQUALS _.ID AS q2 RETURN q1 } AS q1 RETURN (q1.NAME AS _0, q0.NAME AS _1) }&digraph G { + 7 ذ(b08@ SCAN([IS PROJECT]) | FLATMAP q0 -> { SCAN([IS DEPT]) | FLATMAP q1 -> { SCAN([IS EMP]) | FILTER _.DEPT_ID EQUALS q1.ID AND q0.EMP_ID EQUALS _.ID AS q2 RETURN q1 } AS q1 RETURN (q1.NAME AS _0, q0.NAME AS _1) }&digraph G { fontname=courier; rankdir=BT; splines=line; @@ -157,28 +157,28 @@ 9 -> 8 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 1 [ label=< q6> label="q6" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; { - 6 -> 1 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; - } - { - 4 -> 1 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; + 6 -> 4 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; } { rank=same; rankDir=LR; - 2 -> 4 [ color="red" style="invis" ]; + 5 -> 6 [ color="red" style="invis" ]; } { - 6 -> 4 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; + 6 -> 1 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; + } + { + 4 -> 1 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; } { rank=same; rankDir=LR; - 5 -> 6 [ color="red" style="invis" ]; + 2 -> 4 [ color="red" style="invis" ]; } }*  unnamed-2EXPLAIN select (*) from (select dept.name, project.name from emp, dept, project where emp.dept_id = dept.id and project.emp_id = emp.id) X;) - ˮ3 (b08@ SCAN([IS DEPT]) | FLATMAP q0 -> { SCAN([IS PROJECT]) | FLATMAP q1 -> { SCAN([IS EMP]) | FILTER _.DEPT_ID EQUALS q0.ID AND q1.EMP_ID EQUALS _.ID AS q2 RETURN q1 } AS q1 RETURN ((q0.NAME AS _0, q1.NAME AS _1) AS _0) }'digraph G { + Ŝ0 (b08@ SCAN([IS DEPT]) | FLATMAP q0 -> { SCAN([IS PROJECT]) | FLATMAP q1 -> { SCAN([IS EMP]) | FILTER _.DEPT_ID EQUALS q0.ID AND q1.EMP_ID EQUALS _.ID AS q2 RETURN q1 } AS q1 RETURN ((q0.NAME AS _0, q1.NAME AS _1) AS _0) }'digraph G { fontname=courier; rankdir=BT; splines=line; @@ -200,28 +200,28 @@ 9 -> 8 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 1 [ label=< q10> label="q10" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; { - 6 -> 4 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; + 6 -> 1 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; } { - rank=same; - rankDir=LR; - 5 -> 6 [ color="red" style="invis" ]; + 4 -> 1 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; } { - 6 -> 1 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; + rank=same; + rankDir=LR; + 2 -> 4 [ color="red" style="invis" ]; } { - 4 -> 1 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; + 6 -> 4 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; } { rank=same; rankDir=LR; - 2 -> 4 [ color="red" style="invis" ]; + 5 -> 6 [ color="red" style="invis" ]; } }+  unnamed-2EXPLAIN select dept.name, project.name from project inner join emp on emp.id = project.emp_id inner join dept on emp.dept_id = dept.id;* - ꀞ1 ݴ(e08@SCAN([IS DEPT]) | FLATMAP q0 -> { SCAN([IS PROJECT]) | FLATMAP q1 -> { SCAN([IS EMP, EQUALS q1.EMP_ID]) | FILTER _.DEPT_ID EQUALS q0.ID AS q2 RETURN q1 } AS q1 RETURN (q0.NAME AS _0, q1.NAME AS _1) }(digraph G { + . (e0ͩ8@SCAN([IS DEPT]) | FLATMAP q0 -> { SCAN([IS PROJECT]) | FLATMAP q1 -> { SCAN([IS EMP, EQUALS q1.EMP_ID]) | FILTER _.DEPT_ID EQUALS q0.ID AS q2 RETURN q1 } AS q1 RETURN (q0.NAME AS _0, q1.NAME AS _1) }(digraph G { fontname=courier; rankdir=BT; splines=line; @@ -243,34 +243,34 @@ 9 -> 8 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 1 [ label=< q2> label="q2" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; { - 8 -> 4 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; + 8 -> 1 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; } { - 6 -> 4 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; + 6 -> 1 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; } { - rank=same; - rankDir=LR; - 5 -> 6 [ color="red" style="invis" ]; + 4 -> 1 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; } { - 8 -> 1 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; + rank=same; + rankDir=LR; + 2 -> 4 [ color="red" style="invis" ]; } { - 6 -> 1 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; + 8 -> 4 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; } { - 4 -> 1 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; + 6 -> 4 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; } { rank=same; rankDir=LR; - 2 -> 4 [ color="red" style="invis" ]; + 5 -> 6 [ color="red" style="invis" ]; } }/  unnamed-2EXPLAIN select dept.id, dept.name, project.name from emp, dept, project where emp.dept_id = dept.id and project.emp_id = emp.id and dept.id not in (1). -̽U ֗(j08@-SCAN([IS DEPT]) | FILTER NOT _.ID IN promote(@c40 AS ARRAY(LONG)) | FLATMAP q0 -> { SCAN([IS PROJECT]) | FLATMAP q1 -> { SCAN([IS EMP]) | FILTER _.DEPT_ID EQUALS q0.ID AND q1.EMP_ID EQUALS _.ID AS q2 RETURN q1 } AS q1 RETURN (q0.ID AS ID, q0.NAME AS _1, q1.NAME AS _2) },digraph G { +. (j0ߍ8@-SCAN([IS DEPT]) | FILTER NOT _.ID IN promote(@c40 AS ARRAY(LONG)) | FLATMAP q0 -> { SCAN([IS PROJECT]) | FLATMAP q1 -> { SCAN([IS EMP]) | FILTER _.DEPT_ID EQUALS q0.ID AND q1.EMP_ID EQUALS _.ID AS q2 RETURN q1 } AS q1 RETURN (q0.ID AS ID, q0.NAME AS _1, q1.NAME AS _2) },digraph G { fontname=courier; rankdir=BT; splines=line; @@ -294,31 +294,31 @@ 10 -> 9 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 1 [ label=< q10> label="q10" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; { - 7 -> 5 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; + 7 -> 1 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; } { - rank=same; - rankDir=LR; - 6 -> 7 [ color="red" style="invis" ]; + 5 -> 1 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; } { 2 -> 1 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; } { - 7 -> 1 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; + rank=same; + rankDir=LR; + 2 -> 5 [ color="red" style="invis" ]; } { - 5 -> 1 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; + 7 -> 5 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; } { rank=same; rankDir=LR; - 2 -> 5 [ color="red" style="invis" ]; + 6 -> 7 [ color="red" style="invis" ]; } }0  unnamed-2EXPLAIN select dept.id, dept.name, project.name from emp inner join dept on emp.dept_id = dept.id and dept.id not in (1) inner join project on project.emp_id = emp.id. -Ϛ5 (j0ۘ8@-SCAN([IS DEPT]) | FILTER NOT _.ID IN promote(@c31 AS ARRAY(LONG)) | FLATMAP q0 -> { SCAN([IS PROJECT]) | FLATMAP q1 -> { SCAN([IS EMP]) | FILTER _.DEPT_ID EQUALS q0.ID AND q1.EMP_ID EQUALS _.ID AS q2 RETURN q1 } AS q1 RETURN (q0.ID AS ID, q0.NAME AS _1, q1.NAME AS _2) },digraph G { +4 (j08@-SCAN([IS DEPT]) | FILTER NOT _.ID IN promote(@c31 AS ARRAY(LONG)) | FLATMAP q0 -> { SCAN([IS PROJECT]) | FLATMAP q1 -> { SCAN([IS EMP]) | FILTER _.DEPT_ID EQUALS q0.ID AND q1.EMP_ID EQUALS _.ID AS q2 RETURN q1 } AS q1 RETURN (q0.ID AS ID, q0.NAME AS _1, q1.NAME AS _2) },digraph G { fontname=courier; rankdir=BT; splines=line; @@ -342,31 +342,31 @@ 10 -> 9 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 1 [ label=< q10> label="q10" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; { - 2 -> 1 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; + 7 -> 5 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; } { - 7 -> 1 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; + rank=same; + rankDir=LR; + 6 -> 7 [ color="red" style="invis" ]; } { - 5 -> 1 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; + 2 -> 1 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; } { - rank=same; - rankDir=LR; - 2 -> 5 [ color="red" style="invis" ]; + 7 -> 1 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; } { - 7 -> 5 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; + 5 -> 1 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; } { rank=same; rankDir=LR; - 6 -> 7 [ color="red" style="invis" ]; + 2 -> 5 [ color="red" style="invis" ]; } }1  unnamed-2EXPLAIN select project.id, project.name from emp, dept, project where emp.dept_id = dept.id and project.emp_id = emp.id and dept.id not in (3) and project.id not in (3)/ -B (08@?SCAN([IS EMP]) | FLATMAP q0 -> { SCAN([IS PROJECT]) | FILTER NOT _.ID IN promote(@c36 AS ARRAY(LONG)) AND _.EMP_ID EQUALS q0.ID | FLATMAP q1 -> { SCAN([IS DEPT]) | FILTER NOT _.ID IN promote(@c36 AS ARRAY(LONG)) AND q0.DEPT_ID EQUALS _.ID AS q2 RETURN q1 } AS q1 RETURN (q1.ID AS ID, q1.NAME AS NAME) }-digraph G { +] +(08@?SCAN([IS EMP]) | FLATMAP q0 -> { SCAN([IS PROJECT]) | FILTER NOT _.ID IN promote(@c36 AS ARRAY(LONG)) AND _.EMP_ID EQUALS q0.ID | FLATMAP q1 -> { SCAN([IS DEPT]) | FILTER NOT _.ID IN promote(@c36 AS ARRAY(LONG)) AND q0.DEPT_ID EQUALS _.ID AS q2 RETURN q1 } AS q1 RETURN (q1.ID AS ID, q1.NAME AS NAME) }-digraph G { fontname=courier; rankdir=BT; splines=line; @@ -374,18 +374,18 @@ 2 [ label=<
Scan
comparisons: [IS EMP]
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, STRING AS FNAME, STRING AS LNAME, LONG AS DEPT_ID)" ]; 3 [ label=<
Primary Storage
record types: [A, PROJECT, B, JUB, JA, JUA, JB, JUD, EMP, DEPT, JD]
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, STRING AS FNAME, STRING AS LNAME, LONG AS DEPT_ID)" ]; 4 [ label=<
Nested Loop Join
FLATMAP q10
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, STRING AS NAME, STRING AS DSC, LONG AS EMP_ID)" ]; - 5 [ label=<
Predicate Filter
WHERE NOT q10.ID IN promote(@c36 AS ARRAY(LONG)) AND q10.EMP_ID EQUALS q2.ID
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, STRING AS NAME, STRING AS DSC, LONG AS EMP_ID)" ]; - 6 [ label=<
Predicate Filter
WHERE NOT q6.ID IN promote(@c36 AS ARRAY(LONG)) AND q2.DEPT_ID EQUALS q6.ID
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, STRING AS NAME)" ]; - 7 [ label=<
Scan
comparisons: [IS PROJECT]
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, STRING AS NAME, STRING AS DSC, LONG AS EMP_ID)" ]; - 8 [ label=<
Scan
comparisons: [IS DEPT]
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, STRING AS NAME)" ]; - 9 [ label=<
Primary Storage
record types: [A, PROJECT, B, JUB, JA, JUA, JB, JUD, EMP, DEPT, JD]
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, STRING AS NAME, STRING AS DSC, LONG AS EMP_ID)" ]; - 10 [ label=<
Primary Storage
record types: [A, PROJECT, B, JUB, JA, JUA, JB, JUD, EMP, DEPT, JD]
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, STRING AS NAME)" ]; + 5 [ label=<
Predicate Filter
WHERE NOT q6.ID IN promote(@c36 AS ARRAY(LONG)) AND q2.DEPT_ID EQUALS q6.ID
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, STRING AS NAME)" ]; + 6 [ label=<
Predicate Filter
WHERE NOT q10.ID IN promote(@c36 AS ARRAY(LONG)) AND q10.EMP_ID EQUALS q2.ID
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, STRING AS NAME, STRING AS DSC, LONG AS EMP_ID)" ]; + 7 [ label=<
Scan
comparisons: [IS DEPT]
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, STRING AS NAME)" ]; + 8 [ label=<
Scan
comparisons: [IS PROJECT]
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, STRING AS NAME, STRING AS DSC, LONG AS EMP_ID)" ]; + 9 [ label=<
Primary Storage
record types: [A, PROJECT, B, JUB, JA, JUA, JB, JUD, EMP, DEPT, JD]
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, STRING AS NAME)" ]; + 10 [ label=<
Primary Storage
record types: [A, PROJECT, B, JUB, JA, JUA, JB, JUD, EMP, DEPT, JD]
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, STRING AS NAME, STRING AS DSC, LONG AS EMP_ID)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q2> label="q2" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 5 -> 4 [ label=< q10> label="q10" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 6 -> 4 [ label=< q6> label="q6" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 7 -> 5 [ label=< q10> label="q10" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 8 -> 6 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 -> 4 [ label=< q6> label="q6" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 6 -> 4 [ label=< q10> label="q10" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 7 -> 5 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 8 -> 6 [ label=< q10> label="q10" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 9 -> 7 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 10 -> 8 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 1 [ label=< q10> label="q10" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; @@ -398,7 +398,7 @@ { rank=same; rankDir=LR; - 5 -> 6 [ color="red" style="invis" ]; + 6 -> 5 [ color="red" style="invis" ]; } { 5 -> 1 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; @@ -417,14 +417,14 @@ }3  unnamed-2EXPLAIN select dept.id, dept.name, project.name from emp, dept, project where emp.dept_id = dept.id and project.emp_id = emp.id and dept.id in (1, 2)1 -v՜5 \(0V8@[IN arrayDistinct(promote(@c39 AS ARRAY(LONG)))] | INJOIN q0 -> { SCAN([IS DEPT, EQUALS q0]) } | FLATMAP q1 -> { SCAN([IS PROJECT]) | FLATMAP q2 -> { SCAN([IS EMP]) | FILTER _.DEPT_ID EQUALS q1.ID AND q2.EMP_ID EQUALS _.ID AS q3 RETURN q2 } AS q2 RETURN (q1.ID AS ID, q1.NAME AS _1, q2.NAME AS _2) }/digraph G { +vڬ5 a(0R8@[IN arrayDistinct(promote(@c39 AS ARRAY(LONG)))] | INJOIN q0 -> { SCAN([IS DEPT, EQUALS q0]) } | FLATMAP q1 -> { SCAN([IS PROJECT]) | FLATMAP q2 -> { SCAN([IS EMP]) | FILTER _.DEPT_ID EQUALS q1.ID AND q2.EMP_ID EQUALS _.ID AS q3 RETURN q2 } AS q2 RETURN (q1.ID AS ID, q1.NAME AS _1, q2.NAME AS _2) }/digraph G { fontname=courier; rankdir=BT; splines=line; 1 [ label=<
Nested Loop Join
FLATMAP (q6.ID AS ID, q6.NAME AS _1, q10.NAME AS _2)
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, STRING AS _1, STRING AS _2)" ]; 2 [ label=<
Nested Loop Join
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(LONG AS ID, STRING AS NAME)" ]; - 3 [ label=<
Table Function
EXPLODE(arrayDistinct(promote(@c39 AS ARRAY(LONG))))
> color="black" shape="plain" style="filled" fillcolor="darkseagreen2" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, STRING AS NAME)" ]; - 4 [ label=<
Scan
comparisons: [IS DEPT, EQUALS q396]
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, STRING AS NAME)" ]; + 3 [ label=<
Scan
comparisons: [IS DEPT, EQUALS q396]
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, STRING AS NAME)" ]; + 4 [ label=<
Table Function
EXPLODE(arrayDistinct(promote(@c39 AS ARRAY(LONG))))
> color="black" shape="plain" style="filled" fillcolor="darkseagreen2" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, STRING AS NAME)" ]; 5 [ label=<
Primary Storage
record types: [A, PROJECT, B, JUB, JA, JUA, JB, JUD, EMP, DEPT, JD]
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, STRING AS NAME)" ]; 6 [ label=<
Nested Loop Join
FLATMAP q10
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, STRING AS NAME, STRING AS DSC, LONG AS EMP_ID)" ]; 7 [ label=<
Scan
comparisons: [IS PROJECT]
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, STRING AS NAME, STRING AS DSC, LONG AS EMP_ID)" ]; @@ -434,7 +434,7 @@ 11 [ label=<
Primary Storage
record types: [A, PROJECT, B, JUB, JA, JUA, JB, JUD, EMP, DEPT, JD]
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, STRING AS FNAME, STRING AS LNAME, LONG AS DEPT_ID)" ]; 3 -> 2 [ color="black" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 2 [ color="black" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 5 -> 4 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 -> 3 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 7 -> 6 [ label=< q10> label="q10" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 8 -> 6 [ label=< q2> label="q2" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; @@ -442,14 +442,6 @@ 10 -> 8 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 11 -> 10 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 1 [ label=< q10> label="q10" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - { - 8 -> 6 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; - } - { - rank=same; - rankDir=LR; - 7 -> 8 [ color="red" style="invis" ]; - } { 8 -> 1 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; } @@ -464,12 +456,20 @@ { rank=same; rankDir=LR; - 3 -> 4 [ color="red" style="invis" ]; + 4 -> 3 [ color="red" style="invis" ]; + } + { + 8 -> 6 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; + } + { + rank=same; + rankDir=LR; + 7 -> 8 [ color="red" style="invis" ]; } }" J unnamed-2=EXPLAIN select * from ja join jb using(c1) join jd using(c1);" - 5 ߣ(O08@SCAN([IS JD]) | FLATMAP q0 -> { SCAN([IS JB]) | FLATMAP q1 -> { SCAN([IS JA, EQUALS q1.C1]) AS q2 RETURN (q2 AS _0, q1 AS _1) } AS q3 RETURN (q3._0.C1 AS C1, q3._0.C2 AS C2, q3._1.C3 AS C3, q0.C4 AS C4) } digraph G { + J (O08@SCAN([IS JD]) | FLATMAP q0 -> { SCAN([IS JB]) | FLATMAP q1 -> { SCAN([IS JA, EQUALS q1.C1]) AS q2 RETURN (q2 AS _0, q1 AS _1) } AS q3 RETURN (q3._0.C1 AS C1, q3._0.C2 AS C2, q3._1.C3 AS C3, q0.C4 AS C4) } digraph G { fontname=courier; rankdir=BT; splines=line; @@ -488,23 +488,23 @@ J 7 -> 5 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 8 -> 6 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 1 [ label=< q53> label="q53" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - { - 6 -> 4 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; - } { rank=same; rankDir=LR; - 5 -> 6 [ color="red" style="invis" ]; + 2 -> 4 [ color="red" style="invis" ]; + } + { + 6 -> 4 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; } { rank=same; rankDir=LR; - 2 -> 4 [ color="red" style="invis" ]; + 5 -> 6 [ color="red" style="invis" ]; } }# b unnamed-2UEXPLAIN select jua.c5, jub.c5, jud.c5 from jua join jub using(c1) join jud using(c1);" - Q (O08@SCAN([IS JUD]) | FLATMAP q0 -> { SCAN([IS JUB]) | FLATMAP q1 -> { SCAN([IS JUA, EQUALS q1.C1]) AS q2 RETURN (q2 AS _0, q1 AS _1) } AS q3 RETURN (q3._0.C5 AS _0, q3._1.C5 AS _1, q0.C5 AS _2) }!digraph G { + * (O08@SCAN([IS JUD]) | FLATMAP q0 -> { SCAN([IS JUB]) | FLATMAP q1 -> { SCAN([IS JUA, EQUALS q1.C1]) AS q2 RETURN (q2 AS _0, q1 AS _1) } AS q3 RETURN (q3._0.C5 AS _0, q3._1.C5 AS _1, q0.C5 AS _2) }!digraph G { fontname=courier; rankdir=BT; splines=line; @@ -523,23 +523,23 @@ b 7 -> 5 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 8 -> 6 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 1 [ label=< q53> label="q53" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - { - 5 -> 4 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; - } { rank=same; rankDir=LR; - 6 -> 5 [ color="red" style="invis" ]; + 2 -> 4 [ color="red" style="invis" ]; + } + { + 5 -> 4 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; } { rank=same; rankDir=LR; - 2 -> 4 [ color="red" style="invis" ]; + 6 -> 5 [ color="red" style="invis" ]; } }& c unnamed-2VEXPLAIN select * from jua join (select * from jub join jud using(c1)) as X using (c1);% - ԁS (a0≍8@SCAN([IS JUD]) | FLATMAP q0 -> { SCAN([IS JUB, EQUALS q0.C1]) | FLATMAP q1 -> { SCAN([IS JUA, EQUALS q1.C1]) AS q2 RETURN (q2 AS _0, q1 AS _1) } AS q3 RETURN (q3._0.C1 AS C1, q3._0.C2 AS C2, q3._0.C5 AS _2, q3._1.C3 AS C3, q3._1.C5 AS _4, q0.C4 AS C4, q0.C5 AS _6) }"digraph G { + B 䮓(a08@SCAN([IS JUD]) | FLATMAP q0 -> { SCAN([IS JUB, EQUALS q0.C1]) | FLATMAP q1 -> { SCAN([IS JUA, EQUALS q1.C1]) AS q2 RETURN (q2 AS _0, q1 AS _1) } AS q3 RETURN (q3._0.C1 AS C1, q3._0.C2 AS C2, q3._0.C5 AS _2, q3._1.C3 AS C3, q3._1.C5 AS _4, q0.C4 AS C4, q0.C5 AS _6) }"digraph G { fontname=courier; rankdir=BT; splines=line; @@ -574,10 +574,146 @@ c rankDir=LR; 6 -> 5 [ color="red" style="invis" ]; } +} +N + unnamed-2AEXPLAIN select ja.c1, ja.c2, jb.c3 from ja inner join jb on true; +ƨX @(&082@dSCAN([IS JA]) | FLATMAP q0 -> { SCAN([IS JB]) AS q1 RETURN (q0.C1 AS C1, q0.C2 AS C2, q1.C3 AS C3) }digraph G { + fontname=courier; + rankdir=BT; + splines=line; + 1 [ label=<
Nested Loop Join
FLATMAP (q2.C1 AS C1, q2.C2 AS C2, q6.C3 AS C3)
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C1, LONG AS C2, LONG AS C3)" ]; + 2 [ label=<
Scan
comparisons: [IS JA]
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C1, LONG AS C2)" ]; + 3 [ label=<
Primary Storage
record types: [A, PROJECT, B, JUB, JA, JUA, JB, JUD, EMP, DEPT, JD]
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C1, LONG AS C2)" ]; + 4 [ label=<
Scan
comparisons: [IS JB]
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C1, LONG AS C3)" ]; + 5 [ label=<
Primary Storage
record types: [A, PROJECT, B, JUB, JA, JUA, JB, JUD, EMP, DEPT, JD]
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C1, LONG AS C3)" ]; + 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 2 -> 1 [ label=< q2> label="q2" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 -> 4 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 1 [ label=< q6> label="q6" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + { + rank=same; + rankDir=LR; + 2 -> 4 [ color="red" style="invis" ]; + } +} +G + unnamed-2:EXPLAIN select ja.c1, ja.c2, jb.c3 from ja, jb where true; + (&0׿82@dSCAN([IS JA]) | FLATMAP q0 -> { SCAN([IS JB]) AS q1 RETURN (q0.C1 AS C1, q0.C2 AS C2, q1.C3 AS C3) }digraph G { + fontname=courier; + rankdir=BT; + splines=line; + 1 [ label=<
Nested Loop Join
FLATMAP (q2.C1 AS C1, q2.C2 AS C2, q6.C3 AS C3)
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C1, LONG AS C2, LONG AS C3)" ]; + 2 [ label=<
Scan
comparisons: [IS JA]
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C1, LONG AS C2)" ]; + 3 [ label=<
Primary Storage
record types: [A, PROJECT, B, JUB, JA, JUA, JB, JUD, EMP, DEPT, JD]
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C1, LONG AS C2)" ]; + 4 [ label=<
Scan
comparisons: [IS JB]
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C1, LONG AS C3)" ]; + 5 [ label=<
Primary Storage
record types: [A, PROJECT, B, JUB, JA, JUA, JB, JUD, EMP, DEPT, JD]
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C1, LONG AS C3)" ]; + 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 2 -> 1 [ label=< q2> label="q2" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 -> 4 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 1 [ label=< q6> label="q6" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + { + rank=same; + rankDir=LR; + 2 -> 4 [ color="red" style="invis" ]; + } +} +O + unnamed-2BEXPLAIN select ja.c1, ja.c2, jb.c3 from ja inner join jb on false; +  (&0-86@sSCAN([IS JA]) | FLATMAP q0 -> { SCAN([IS JB]) | FILTER false AS q1 RETURN (q0.C1 AS C1, q0.C2 AS C2, q1.C3 AS C3) }digraph G { + fontname=courier; + rankdir=BT; + splines=line; + 1 [ label=<
Nested Loop Join
FLATMAP (q2.C1 AS C1, q2.C2 AS C2, q6.C3 AS C3)
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C1, LONG AS C2, LONG AS C3)" ]; + 2 [ label=<
Scan
comparisons: [IS JA]
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C1, LONG AS C2)" ]; + 3 [ label=<
Primary Storage
record types: [A, PROJECT, B, JUB, JA, JUA, JB, JUD, EMP, DEPT, JD]
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C1, LONG AS C2)" ]; + 4 [ label=<
Predicate Filter
WHERE false
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C1, LONG AS C3)" ]; + 5 [ label=<
Scan
comparisons: [IS JB]
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C1, LONG AS C3)" ]; + 6 [ label=<
Primary Storage
record types: [A, PROJECT, B, JUB, JA, JUA, JB, JUD, EMP, DEPT, JD]
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C1, LONG AS C3)" ]; + 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 2 -> 1 [ label=< q2> label="q2" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 -> 4 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 6 -> 5 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 1 [ label=< q6> label="q6" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + { + rank=same; + rankDir=LR; + 2 -> 4 [ color="red" style="invis" ]; + } +} +H + unnamed-2;EXPLAIN select ja.c1, ja.c2, jb.c3 from ja, jb where false; +ԧ ڡ(&0486@sSCAN([IS JA]) | FLATMAP q0 -> { SCAN([IS JB]) | FILTER false AS q1 RETURN (q0.C1 AS C1, q0.C2 AS C2, q1.C3 AS C3) }digraph G { + fontname=courier; + rankdir=BT; + splines=line; + 1 [ label=<
Nested Loop Join
FLATMAP (q2.C1 AS C1, q2.C2 AS C2, q6.C3 AS C3)
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C1, LONG AS C2, LONG AS C3)" ]; + 2 [ label=<
Scan
comparisons: [IS JA]
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C1, LONG AS C2)" ]; + 3 [ label=<
Primary Storage
record types: [A, PROJECT, B, JUB, JA, JUA, JB, JUD, EMP, DEPT, JD]
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C1, LONG AS C2)" ]; + 4 [ label=<
Predicate Filter
WHERE false
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C1, LONG AS C3)" ]; + 5 [ label=<
Scan
comparisons: [IS JB]
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C1, LONG AS C3)" ]; + 6 [ label=<
Primary Storage
record types: [A, PROJECT, B, JUB, JA, JUA, JB, JUD, EMP, DEPT, JD]
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C1, LONG AS C3)" ]; + 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 2 -> 1 [ label=< q2> label="q2" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 -> 4 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 6 -> 5 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 1 [ label=< q6> label="q6" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + { + rank=same; + rankDir=LR; + 2 -> 4 [ color="red" style="invis" ]; + } +} +_ + unnamed-2REXPLAIN select ja.c1, ja.c2, jb.c3 from ja inner join jb on cast(null as boolean); + + ($0 81@SCAN([IS JB]) | FILTER CAST(NULL AS BOOLEAN) EQUALS true | FLATMAP q0 -> { SCAN([IS JA]) AS q1 RETURN (q1.C1 AS C1, q1.C2 AS C2, q0.C3 AS C3) }digraph G { + fontname=courier; + rankdir=BT; + splines=line; + 1 [ label=<
Nested Loop Join
FLATMAP (q2.C1 AS C1, q2.C2 AS C2, q6.C3 AS C3)
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C1, LONG AS C2, LONG AS C3)" ]; + 2 [ label=<
Predicate Filter
WHERE CAST(NULL AS BOOLEAN) EQUALS true
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C1, LONG AS C3)" ]; + 3 [ label=<
Scan
comparisons: [IS JB]
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C1, LONG AS C3)" ]; + 4 [ label=<
Primary Storage
record types: [A, PROJECT, B, JUB, JA, JUA, JB, JUD, EMP, DEPT, JD]
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C1, LONG AS C3)" ]; + 5 [ label=<
Scan
comparisons: [IS JA]
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C1, LONG AS C2)" ]; + 6 [ label=<
Primary Storage
record types: [A, PROJECT, B, JUB, JA, JUA, JB, JUD, EMP, DEPT, JD]
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C1, LONG AS C2)" ]; + 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 2 -> 1 [ label=< q6> label="q6" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 6 -> 5 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 -> 1 [ label=< q2> label="q2" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + { + rank=same; + rankDir=LR; + 2 -> 5 [ color="red" style="invis" ]; + } +} +X + unnamed-2KEXPLAIN select ja.c1, ja.c2, jb.c3 from ja, jb where cast(null as boolean); + +($0P81@SCAN([IS JB]) | FILTER CAST(NULL AS BOOLEAN) EQUALS true | FLATMAP q0 -> { SCAN([IS JA]) AS q1 RETURN (q1.C1 AS C1, q1.C2 AS C2, q0.C3 AS C3) }digraph G { + fontname=courier; + rankdir=BT; + splines=line; + 1 [ label=<
Nested Loop Join
FLATMAP (q2.C1 AS C1, q2.C2 AS C2, q6.C3 AS C3)
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C1, LONG AS C2, LONG AS C3)" ]; + 2 [ label=<
Predicate Filter
WHERE CAST(NULL AS BOOLEAN) EQUALS true
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C1, LONG AS C3)" ]; + 3 [ label=<
Scan
comparisons: [IS JB]
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C1, LONG AS C3)" ]; + 4 [ label=<
Primary Storage
record types: [A, PROJECT, B, JUB, JA, JUA, JB, JUD, EMP, DEPT, JD]
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C1, LONG AS C3)" ]; + 5 [ label=<
Scan
comparisons: [IS JA]
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C1, LONG AS C2)" ]; + 6 [ label=<
Primary Storage
record types: [A, PROJECT, B, JUB, JA, JUA, JB, JUD, EMP, DEPT, JD]
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C1, LONG AS C2)" ]; + 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 2 -> 1 [ label=< q6> label="q6" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 6 -> 5 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 -> 1 [ label=< q2> label="q2" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + { + rank=same; + rankDir=LR; + 2 -> 5 [ color="red" style="invis" ]; + } }/  "three-way-joins-right-deep-plannerEXPLAIN select fname, lname from emp inner join project on emp_id = emp.id inner join dept on dept_id = dept.id and dept.name = 'Sales';. -# (M08@SCAN([IS DEPT]) | FILTER _.NAME EQUALS promote(@c29 AS STRING) | FLATMAP q0 -> { SCAN([IS PROJECT]) | FLATMAP q1 -> { SCAN([IS EMP]) | FILTER q1.EMP_ID EQUALS _.ID AND _.DEPT_ID EQUALS q0.ID AS q2 RETURN q2 } AS q2 RETURN (q2.FNAME AS FNAME, q2.LNAME AS LNAME) },digraph G { +0 ߲(M08@SCAN([IS DEPT]) | FILTER _.NAME EQUALS promote(@c29 AS STRING) | FLATMAP q0 -> { SCAN([IS PROJECT]) | FLATMAP q1 -> { SCAN([IS EMP]) | FILTER q1.EMP_ID EQUALS _.ID AND _.DEPT_ID EQUALS q0.ID AS q2 RETURN q2 } AS q2 RETURN (q2.FNAME AS FNAME, q2.LNAME AS LNAME) },digraph G { fontname=courier; rankdir=BT; splines=line; @@ -600,14 +736,6 @@ c 9 -> 7 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 10 -> 9 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 1 [ label=< q2> label="q2" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - { - 7 -> 5 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; - } - { - rank=same; - rankDir=LR; - 6 -> 7 [ color="red" style="invis" ]; - } { 2 -> 1 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; } @@ -622,10 +750,18 @@ c rankDir=LR; 2 -> 5 [ color="red" style="invis" ]; } + { + 7 -> 5 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; + } + { + rank=same; + rankDir=LR; + 6 -> 7 [ color="red" style="invis" ]; + } }*  "three-way-joins-right-deep-plannerwEXPLAIN select dept.name, project.name from emp, dept, project where emp.dept_id = dept.id and project.emp_id = emp.id;( -& (E0ݜ8r@SCAN([IS PROJECT]) | FLATMAP q0 -> { SCAN([IS DEPT]) | FLATMAP q1 -> { SCAN([IS EMP]) | FILTER _.DEPT_ID EQUALS q1.ID AND q0.EMP_ID EQUALS _.ID AS q2 RETURN q1 } AS q1 RETURN (q1.NAME AS _0, q0.NAME AS _1) }&digraph G { +) Ϻ(E08r@SCAN([IS PROJECT]) | FLATMAP q0 -> { SCAN([IS DEPT]) | FLATMAP q1 -> { SCAN([IS EMP]) | FILTER _.DEPT_ID EQUALS q1.ID AND q0.EMP_ID EQUALS _.ID AS q2 RETURN q1 } AS q1 RETURN (q1.NAME AS _0, q0.NAME AS _1) }&digraph G { fontname=courier; rankdir=BT; splines=line; @@ -647,28 +783,28 @@ c 9 -> 8 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 1 [ label=< q6> label="q6" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; { - 6 -> 4 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; + 6 -> 1 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; } { - rank=same; - rankDir=LR; - 5 -> 6 [ color="red" style="invis" ]; + 4 -> 1 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; } { - 6 -> 1 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; + rank=same; + rankDir=LR; + 2 -> 4 [ color="red" style="invis" ]; } { - 4 -> 1 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; + 6 -> 4 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; } { rank=same; rankDir=LR; - 2 -> 4 [ color="red" style="invis" ]; + 5 -> 6 [ color="red" style="invis" ]; } -}* +}*  -"three-way-joins-right-deep-plannerEXPLAIN select dept.name, project.name from emp inner join dept on emp.dept_id = dept.id inner join project on project.emp_id = emp.id;( -1 (E08r@SCAN([IS PROJECT]) | FLATMAP q0 -> { SCAN([IS DEPT]) | FLATMAP q1 -> { SCAN([IS EMP]) | FILTER _.DEPT_ID EQUALS q1.ID AND q0.EMP_ID EQUALS _.ID AS q2 RETURN q1 } AS q1 RETURN (q1.NAME AS _0, q0.NAME AS _1) }&digraph G { +"three-way-joins-right-deep-plannerEXPLAIN select dept.name, project.name from emp inner join dept on emp.dept_id = dept.id inner join project on project.emp_id = emp.id;( +  ‚(E0]8r@SCAN([IS PROJECT]) | FLATMAP q0 -> { SCAN([IS DEPT]) | FLATMAP q1 -> { SCAN([IS EMP]) | FILTER _.DEPT_ID EQUALS q1.ID AND q0.EMP_ID EQUALS _.ID AS q2 RETURN q1 } AS q1 RETURN (q1.NAME AS _0, q0.NAME AS _1) }&digraph G { fontname=courier; rankdir=BT; splines=line; @@ -690,28 +826,28 @@ c 9 -> 7 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 1 [ label=< q6> label="q6" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; { - 5 -> 4 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; + 5 -> 1 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; } { - rank=same; - rankDir=LR; - 6 -> 5 [ color="red" style="invis" ]; + 4 -> 1 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; } { - 5 -> 1 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; + rank=same; + rankDir=LR; + 2 -> 4 [ color="red" style="invis" ]; } { - 4 -> 1 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; + 5 -> 4 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; } { rank=same; rankDir=LR; - 2 -> 4 [ color="red" style="invis" ]; + 6 -> 5 [ color="red" style="invis" ]; } }*  "three-way-joins-right-deep-plannerEXPLAIN select * from (select dept.name, project.name from emp, dept, project where emp.dept_id = dept.id and project.emp_id = emp.id) X;( -( (G0Ɔ8v@SCAN([IS PROJECT]) | FLATMAP q0 -> { SCAN([IS DEPT]) | FLATMAP q1 -> { SCAN([IS EMP]) | FILTER _.DEPT_ID EQUALS q1.ID AND q0.EMP_ID EQUALS _.ID AS q2 RETURN q1 } AS q1 RETURN (q1.NAME AS _0, q0.NAME AS _1) }&digraph G { +' (G0ѕ8v@SCAN([IS PROJECT]) | FLATMAP q0 -> { SCAN([IS DEPT]) | FLATMAP q1 -> { SCAN([IS EMP]) | FILTER _.DEPT_ID EQUALS q1.ID AND q0.EMP_ID EQUALS _.ID AS q2 RETURN q1 } AS q1 RETURN (q1.NAME AS _0, q0.NAME AS _1) }&digraph G { fontname=courier; rankdir=BT; splines=line; @@ -751,10 +887,10 @@ c rankDir=LR; 2 -> 4 [ color="red" style="invis" ]; } -}* +}*  -"three-way-joins-right-deep-plannerEXPLAIN select (*) from (select dept.name, project.name from emp, dept, project where emp.dept_id = dept.id and project.emp_id = emp.id) X;) -) (G08v@SCAN([IS DEPT]) | FLATMAP q0 -> { SCAN([IS PROJECT]) | FLATMAP q1 -> { SCAN([IS EMP]) | FILTER _.DEPT_ID EQUALS q0.ID AND q1.EMP_ID EQUALS _.ID AS q2 RETURN q1 } AS q1 RETURN ((q0.NAME AS _0, q1.NAME AS _1) AS _0) }'digraph G { +"three-way-joins-right-deep-plannerEXPLAIN select (*) from (select dept.name, project.name from emp, dept, project where emp.dept_id = dept.id and project.emp_id = emp.id) X;) + (G0f8v@SCAN([IS DEPT]) | FLATMAP q0 -> { SCAN([IS PROJECT]) | FLATMAP q1 -> { SCAN([IS EMP]) | FILTER _.DEPT_ID EQUALS q0.ID AND q1.EMP_ID EQUALS _.ID AS q2 RETURN q1 } AS q1 RETURN ((q0.NAME AS _0, q1.NAME AS _1) AS _0) }'digraph G { fontname=courier; rankdir=BT; splines=line; @@ -762,42 +898,42 @@ c 2 [ label=<
Scan
comparisons: [IS DEPT]
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, STRING AS NAME)" ]; 3 [ label=<
Primary Storage
record types: [A, PROJECT, B, JUB, JA, JUA, JB, JUD, EMP, DEPT, JD]
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, STRING AS NAME)" ]; 4 [ label=<
Nested Loop Join
FLATMAP q10
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, STRING AS NAME, STRING AS DSC, LONG AS EMP_ID)" ]; - 5 [ label=<
Scan
comparisons: [IS PROJECT]
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, STRING AS NAME, STRING AS DSC, LONG AS EMP_ID)" ]; - 6 [ label=<
Predicate Filter
WHERE q2.DEPT_ID EQUALS q6.ID AND q10.EMP_ID EQUALS q2.ID
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, STRING AS FNAME, STRING AS LNAME, LONG AS DEPT_ID)" ]; - 7 [ label=<
Primary Storage
record types: [A, PROJECT, B, JUB, JA, JUA, JB, JUD, EMP, DEPT, JD]
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, STRING AS NAME, STRING AS DSC, LONG AS EMP_ID)" ]; - 8 [ label=<
Scan
comparisons: [IS EMP]
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, STRING AS FNAME, STRING AS LNAME, LONG AS DEPT_ID)" ]; + 5 [ label=<
Predicate Filter
WHERE q2.DEPT_ID EQUALS q6.ID AND q10.EMP_ID EQUALS q2.ID
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, STRING AS FNAME, STRING AS LNAME, LONG AS DEPT_ID)" ]; + 6 [ label=<
Scan
comparisons: [IS PROJECT]
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, STRING AS NAME, STRING AS DSC, LONG AS EMP_ID)" ]; + 7 [ label=<
Scan
comparisons: [IS EMP]
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, STRING AS FNAME, STRING AS LNAME, LONG AS DEPT_ID)" ]; + 8 [ label=<
Primary Storage
record types: [A, PROJECT, B, JUB, JA, JUA, JB, JUD, EMP, DEPT, JD]
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, STRING AS NAME, STRING AS DSC, LONG AS EMP_ID)" ]; 9 [ label=<
Primary Storage
record types: [A, PROJECT, B, JUB, JA, JUA, JB, JUD, EMP, DEPT, JD]
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS ID, STRING AS FNAME, STRING AS LNAME, LONG AS DEPT_ID)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 5 -> 4 [ label=< q10> label="q10" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 6 -> 4 [ label=< q2> label="q2" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 7 -> 5 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 8 -> 6 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 9 -> 8 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 -> 4 [ label=< q2> label="q2" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 6 -> 4 [ label=< q10> label="q10" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 7 -> 5 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 8 -> 6 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 9 -> 7 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 1 [ label=< q10> label="q10" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; { - 6 -> 1 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; - } - { - 4 -> 1 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; + 5 -> 4 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; } { rank=same; rankDir=LR; - 2 -> 4 [ color="red" style="invis" ]; + 6 -> 5 [ color="red" style="invis" ]; } { - 6 -> 4 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; + 5 -> 1 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; + } + { + 4 -> 1 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; } { rank=same; rankDir=LR; - 5 -> 6 [ color="red" style="invis" ]; + 2 -> 4 [ color="red" style="invis" ]; } },  "three-way-joins-right-deep-plannerEXPLAIN select dept.name, project.name from project inner join emp on emp.id = project.emp_id inner join dept on emp.dept_id = dept.id;* -䙏2 (I08{@SCAN([IS DEPT]) | FLATMAP q0 -> { SCAN([IS PROJECT]) | FLATMAP q1 -> { SCAN([IS EMP, EQUALS q1.EMP_ID]) | FILTER _.DEPT_ID EQUALS q0.ID AS q2 RETURN q1 } AS q1 RETURN (q0.NAME AS _0, q1.NAME AS _1) }(digraph G { +Ǖ+ (I08{@SCAN([IS DEPT]) | FLATMAP q0 -> { SCAN([IS PROJECT]) | FLATMAP q1 -> { SCAN([IS EMP, EQUALS q1.EMP_ID]) | FILTER _.DEPT_ID EQUALS q0.ID AS q2 RETURN q1 } AS q1 RETURN (q0.NAME AS _0, q1.NAME AS _1) }(digraph G { fontname=courier; rankdir=BT; splines=line; @@ -846,7 +982,7 @@ c }0  "three-way-joins-right-deep-plannerEXPLAIN select dept.id, dept.name, project.name from emp, dept, project where emp.dept_id = dept.id and project.emp_id = emp.id and dept.id not in (1). -ɐ$ (K0օ8@SCAN([IS DEPT]) | FILTER NOT _.ID IN promote(@c40 AS ARRAY(LONG)) | FLATMAP q0 -> { SCAN([IS PROJECT]) | FLATMAP q1 -> { SCAN([IS EMP]) | FILTER _.DEPT_ID EQUALS q0.ID AND q1.EMP_ID EQUALS _.ID AS q2 RETURN q1 } AS q1 RETURN (q0.ID AS ID, q0.NAME AS _1, q1.NAME AS _2) },digraph G { +2 ޫ(K0˼8@SCAN([IS DEPT]) | FILTER NOT _.ID IN promote(@c40 AS ARRAY(LONG)) | FLATMAP q0 -> { SCAN([IS PROJECT]) | FLATMAP q1 -> { SCAN([IS EMP]) | FILTER _.DEPT_ID EQUALS q0.ID AND q1.EMP_ID EQUALS _.ID AS q2 RETURN q1 } AS q1 RETURN (q0.ID AS ID, q0.NAME AS _1, q1.NAME AS _2) },digraph G { fontname=courier; rankdir=BT; splines=line; @@ -869,14 +1005,6 @@ c 9 -> 7 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 10 -> 9 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 1 [ label=< q10> label="q10" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - { - 7 -> 5 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; - } - { - rank=same; - rankDir=LR; - 6 -> 7 [ color="red" style="invis" ]; - } { 2 -> 1 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; } @@ -891,10 +1019,18 @@ c rankDir=LR; 2 -> 5 [ color="red" style="invis" ]; } + { + 7 -> 5 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; + } + { + rank=same; + rankDir=LR; + 6 -> 7 [ color="red" style="invis" ]; + } }0  "three-way-joins-right-deep-plannerEXPLAIN select dept.id, dept.name, project.name from emp inner join dept on emp.dept_id = dept.id and dept.id not in (1) inner join project on project.emp_id = emp.id. -) (K08@SCAN([IS DEPT]) | FILTER NOT _.ID IN promote(@c31 AS ARRAY(LONG)) | FLATMAP q0 -> { SCAN([IS PROJECT]) | FLATMAP q1 -> { SCAN([IS EMP]) | FILTER _.DEPT_ID EQUALS q0.ID AND q1.EMP_ID EQUALS _.ID AS q2 RETURN q1 } AS q1 RETURN (q0.ID AS ID, q0.NAME AS _1, q1.NAME AS _2) },digraph G { +3 (K08@SCAN([IS DEPT]) | FILTER NOT _.ID IN promote(@c31 AS ARRAY(LONG)) | FLATMAP q0 -> { SCAN([IS PROJECT]) | FLATMAP q1 -> { SCAN([IS EMP]) | FILTER _.DEPT_ID EQUALS q0.ID AND q1.EMP_ID EQUALS _.ID AS q2 RETURN q1 } AS q1 RETURN (q0.ID AS ID, q0.NAME AS _1, q1.NAME AS _2) },digraph G { fontname=courier; rankdir=BT; splines=line; @@ -918,31 +1054,32 @@ c 10 -> 9 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 5 -> 1 [ label=< q10> label="q10" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; { - 7 -> 1 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; + 7 -> 5 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; } { - 5 -> 1 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; + rank=same; + rankDir=LR; + 6 -> 7 [ color="red" style="invis" ]; } { - 2 -> 1 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; + 7 -> 1 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; } { - rank=same; - rankDir=LR; - 2 -> 5 [ color="red" style="invis" ]; + 5 -> 1 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; } { - 7 -> 5 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; + 2 -> 1 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; } { rank=same; rankDir=LR; - 6 -> 7 [ color="red" style="invis" ]; + 2 -> 5 [ color="red" style="invis" ]; } -}1 +}1  -"three-way-joins-right-deep-plannerEXPLAIN select project.id, project.name from emp, dept, project where emp.dept_id = dept.id and project.emp_id = emp.id and dept.id not in (3) and project.id not in (3)/ - ʞ. ۹(Q08@SCAN([IS EMP]) | FLATMAP q0 -> { SCAN([IS PROJECT]) | FILTER NOT _.ID IN promote(@c36 AS ARRAY(LONG)) AND _.EMP_ID EQUALS q0.ID | FLATMAP q1 -> { SCAN([IS DEPT]) | FILTER NOT _.ID IN promote(@c36 AS ARRAY(LONG)) AND q0.DEPT_ID EQUALS _.ID AS q2 RETURN q1 } AS q1 RETURN (q1.ID AS ID, q1.NAME AS NAME) }-digraph G { +"three-way-joins-right-deep-plannerEXPLAIN select project.id, project.name from emp, dept, project where emp.dept_id = dept.id and project.emp_id = emp.id and dept.id not in (3) and project.id not in (3)/ +  +(Q0˽}8@SCAN([IS EMP]) | FLATMAP q0 -> { SCAN([IS PROJECT]) | FILTER NOT _.ID IN promote(@c36 AS ARRAY(LONG)) AND _.EMP_ID EQUALS q0.ID | FLATMAP q1 -> { SCAN([IS DEPT]) | FILTER NOT _.ID IN promote(@c36 AS ARRAY(LONG)) AND q0.DEPT_ID EQUALS _.ID AS q2 RETURN q1 } AS q1 RETURN (q1.ID AS ID, q1.NAME AS NAME) }-digraph G { fontname=courier; rankdir=BT; splines=line; @@ -993,8 +1130,7 @@ c }3  "three-way-joins-right-deep-plannerEXPLAIN select dept.id, dept.name, project.name from emp, dept, project where emp.dept_id = dept.id and project.emp_id = emp.id and dept.id in (1, 2)1 -& 0(0 -8@f[IN arrayDistinct(promote(@c39 AS ARRAY(LONG)))] | INJOIN q0 -> { SCAN([IS DEPT, EQUALS q0]) } | FLATMAP q1 -> { SCAN([IS PROJECT]) | FLATMAP q2 -> { SCAN([IS EMP]) | FILTER _.DEPT_ID EQUALS q1.ID AND q2.EMP_ID EQUALS _.ID AS q3 RETURN q2 } AS q2 RETURN (q1.ID AS ID, q1.NAME AS _1, q2.NAME AS _2) }/digraph G { +& 8(08@f[IN arrayDistinct(promote(@c39 AS ARRAY(LONG)))] | INJOIN q0 -> { SCAN([IS DEPT, EQUALS q0]) } | FLATMAP q1 -> { SCAN([IS PROJECT]) | FLATMAP q2 -> { SCAN([IS EMP]) | FILTER _.DEPT_ID EQUALS q1.ID AND q2.EMP_ID EQUALS _.ID AS q3 RETURN q2 } AS q2 RETURN (q1.ID AS ID, q1.NAME AS _1, q2.NAME AS _2) }/digraph G { fontname=courier; rankdir=BT; splines=line; @@ -1019,6 +1155,14 @@ c 10 -> 8 [ label=< q2> label="q2" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 11 -> 10 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 6 -> 1 [ label=< q10> label="q10" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + { + 8 -> 6 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; + } + { + rank=same; + rankDir=LR; + 7 -> 8 [ color="red" style="invis" ]; + } { rank=same; rankDir=LR; @@ -1035,18 +1179,10 @@ c rankDir=LR; 2 -> 6 [ color="red" style="invis" ]; } - { - 8 -> 6 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; - } - { - rank=same; - rankDir=LR; - 7 -> 8 [ color="red" style="invis" ]; - } }# c "three-way-joins-right-deep-planner=EXPLAIN select * from ja join jb using(c1) join jd using(c1);" -4 (@08g@ SCAN([IS JD]) | FLATMAP q0 -> { SCAN([IS JB]) | FLATMAP q1 -> { SCAN([IS JA, EQUALS q1.C1]) AS q2 RETURN (q2 AS _0, q1 AS _1) } AS q3 RETURN (q3._0.C1 AS C1, q3._0.C2 AS C2, q3._1.C3 AS C3, q0.C4 AS C4) } digraph G { +/ Ğ (@0ի8g@ SCAN([IS JD]) | FLATMAP q0 -> { SCAN([IS JB]) | FLATMAP q1 -> { SCAN([IS JA, EQUALS q1.C1]) AS q2 RETURN (q2 AS _0, q1 AS _1) } AS q3 RETURN (q3._0.C1 AS C1, q3._0.C2 AS C2, q3._1.C3 AS C3, q0.C4 AS C4) } digraph G { fontname=courier; rankdir=BT; splines=line; @@ -1054,34 +1190,35 @@ c 2 [ label=<
Scan
comparisons: [IS JD]
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C1, LONG AS C4)" ]; 3 [ label=<
Primary Storage
record types: [A, PROJECT, B, JUB, JA, JUA, JB, JUD, EMP, DEPT, JD]
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C1, LONG AS C4)" ]; 4 [ label=<
Nested Loop Join
FLATMAP (q2 AS _0, q6 AS _1)
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C1, LONG AS C2 AS _0, LONG AS C1, LONG AS C3 AS _1)" ]; - 5 [ label=<
Scan
comparisons: [IS JA, EQUALS q6.C1]
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C1, LONG AS C2)" ]; - 6 [ label=<
Scan
comparisons: [IS JB]
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C1, LONG AS C3)" ]; - 7 [ label=<
Primary Storage
record types: [A, PROJECT, B, JUB, JA, JUA, JB, JUD, EMP, DEPT, JD]
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C1, LONG AS C2)" ]; - 8 [ label=<
Primary Storage
record types: [A, PROJECT, B, JUB, JA, JUA, JB, JUD, EMP, DEPT, JD]
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C1, LONG AS C3)" ]; + 5 [ label=<
Scan
comparisons: [IS JB]
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C1, LONG AS C3)" ]; + 6 [ label=<
Scan
comparisons: [IS JA, EQUALS q6.C1]
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C1, LONG AS C2)" ]; + 7 [ label=<
Primary Storage
record types: [A, PROJECT, B, JUB, JA, JUA, JB, JUD, EMP, DEPT, JD]
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C1, LONG AS C3)" ]; + 8 [ label=<
Primary Storage
record types: [A, PROJECT, B, JUB, JA, JUA, JB, JUD, EMP, DEPT, JD]
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C1, LONG AS C2)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q10> label="q10" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 5 -> 4 [ label=< q2> label="q2" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 6 -> 4 [ label=< q6> label="q6" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 -> 4 [ label=< q6> label="q6" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 6 -> 4 [ label=< q2> label="q2" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 7 -> 5 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 8 -> 6 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 1 [ label=< q47> label="q47" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; { - 5 -> 4 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; + 6 -> 4 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; } { rank=same; rankDir=LR; - 6 -> 5 [ color="red" style="invis" ]; + 5 -> 6 [ color="red" style="invis" ]; } { rank=same; rankDir=LR; 2 -> 4 [ color="red" style="invis" ]; } -}# +}# { -"three-way-joins-right-deep-plannerUEXPLAIN select jua.c5, jub.c5, jud.c5 from jua join jub using(c1) join jud using(c1);" -5 (@08g@ SCAN([IS JUD]) | FLATMAP q0 -> { SCAN([IS JUB]) | FLATMAP q1 -> { SCAN([IS JUA, EQUALS q1.C1]) AS q2 RETURN (q2 AS _0, q1 AS _1) } AS q3 RETURN (q3._0.C5 AS _0, q3._1.C5 AS _1, q0.C5 AS _2) }!digraph G { +"three-way-joins-right-deep-plannerUEXPLAIN select jua.c5, jub.c5, jud.c5 from jua join jub using(c1) join jud using(c1);" +灼 ߕ +(@0n8g@ SCAN([IS JUD]) | FLATMAP q0 -> { SCAN([IS JUB]) | FLATMAP q1 -> { SCAN([IS JUA, EQUALS q1.C1]) AS q2 RETURN (q2 AS _0, q1 AS _1) } AS q3 RETURN (q3._0.C5 AS _0, q3._1.C5 AS _1, q0.C5 AS _2) }!digraph G { fontname=courier; rankdir=BT; splines=line; @@ -1116,7 +1253,7 @@ c }& | "three-way-joins-right-deep-plannerVEXPLAIN select * from jua join (select * from jub join jud using(c1)) as X using (c1);% -A (N0݉8@ SCAN([IS JUD]) | FLATMAP q0 -> { SCAN([IS JUB, EQUALS q0.C1]) | FLATMAP q1 -> { SCAN([IS JUA, EQUALS q1.C1]) AS q2 RETURN (q2 AS _0, q1 AS _1) } AS q3 RETURN (q3._0.C1 AS C1, q3._0.C2 AS C2, q3._0.C5 AS _2, q3._1.C3 AS C3, q3._1.C5 AS _4, q0.C4 AS C4, q0.C5 AS _6) }"digraph G { +5 ͕(N0玖8@ SCAN([IS JUD]) | FLATMAP q0 -> { SCAN([IS JUB, EQUALS q0.C1]) | FLATMAP q1 -> { SCAN([IS JUA, EQUALS q1.C1]) AS q2 RETURN (q2 AS _0, q1 AS _1) } AS q3 RETURN (q3._0.C1 AS C1, q3._0.C2 AS C2, q3._0.C5 AS _2, q3._1.C3 AS C3, q3._1.C5 AS _4, q0.C4 AS C4, q0.C5 AS _6) }"digraph G { fontname=courier; rankdir=BT; splines=line; @@ -1124,27 +1261,27 @@ c 2 [ label=<
Scan
comparisons: [IS JUD]
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C1, LONG AS C4, LONG AS C5)" ]; 3 [ label=<
Primary Storage
record types: [A, PROJECT, B, JUB, JA, JUA, JB, JUD, EMP, DEPT, JD]
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C1, LONG AS C4, LONG AS C5)" ]; 4 [ label=<
Nested Loop Join
FLATMAP (q2 AS _0, q6 AS _1)
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C1, LONG AS C2, LONG AS C5 AS _0, LONG AS C1, LONG AS C3, LONG AS C5 AS _1)" ]; - 5 [ label=<
Scan
comparisons: [IS JUB, EQUALS q10.C1]
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C1, LONG AS C3, LONG AS C5)" ]; - 6 [ label=<
Scan
comparisons: [IS JUA, EQUALS q6.C1]
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C1, LONG AS C2, LONG AS C5)" ]; - 7 [ label=<
Primary Storage
record types: [A, PROJECT, B, JUB, JA, JUA, JB, JUD, EMP, DEPT, JD]
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C1, LONG AS C3, LONG AS C5)" ]; - 8 [ label=<
Primary Storage
record types: [A, PROJECT, B, JUB, JA, JUA, JB, JUD, EMP, DEPT, JD]
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C1, LONG AS C2, LONG AS C5)" ]; + 5 [ label=<
Scan
comparisons: [IS JUA, EQUALS q6.C1]
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C1, LONG AS C2, LONG AS C5)" ]; + 6 [ label=<
Scan
comparisons: [IS JUB, EQUALS q10.C1]
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C1, LONG AS C3, LONG AS C5)" ]; + 7 [ label=<
Primary Storage
record types: [A, PROJECT, B, JUB, JA, JUA, JB, JUD, EMP, DEPT, JD]
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C1, LONG AS C2, LONG AS C5)" ]; + 8 [ label=<
Primary Storage
record types: [A, PROJECT, B, JUB, JA, JUA, JB, JUD, EMP, DEPT, JD]
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS C1, LONG AS C3, LONG AS C5)" ]; 3 -> 2 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q10> label="q10" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 5 -> 4 [ label=< q6> label="q6" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 6 -> 4 [ label=< q2> label="q2" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 -> 4 [ label=< q2> label="q2" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 6 -> 4 [ label=< q6> label="q6" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 7 -> 5 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 8 -> 6 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 4 -> 1 [ label=< q51> label="q51" color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; { - 6 -> 4 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; + 5 -> 4 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; } { rank=same; rankDir=LR; - 5 -> 6 [ color="red" style="invis" ]; + 6 -> 5 [ color="red" style="invis" ]; } { - 5 -> 1 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; + 6 -> 1 [ color="blue" style="dotted" arrowhead="none" tailport="nw" headport="s" constraint="false" ]; } { rank=same; diff --git a/yaml-tests/src/test/resources/join-tests.metrics.yaml b/yaml-tests/src/test/resources/join-tests.metrics.yaml index 80083d0ea6..7e743a127f 100644 --- a/yaml-tests/src/test/resources/join-tests.metrics.yaml +++ b/yaml-tests/src/test/resources/join-tests.metrics.yaml @@ -7,9 +7,9 @@ unnamed-2: EQUALS _.ID AND _.DEPT_ID EQUALS q0.ID AS q2 RETURN q2 } AS q2 RETURN (q2.FNAME AS FNAME, q2.LNAME AS LNAME) } task_count: 2056 - task_total_time_ms: 146 + task_total_time_ms: 169 transform_count: 856 - transform_time_ms: 48 + transform_time_ms: 74 transform_yield_count: 121 insert_time_ms: 11 insert_new_count: 232 @@ -21,11 +21,11 @@ unnamed-2: { SCAN([IS EMP]) | FILTER _.DEPT_ID EQUALS q1.ID AND q0.EMP_ID EQUALS _.ID AS q2 RETURN q1 } AS q1 RETURN (q1.NAME AS _0, q0.NAME AS _1) } task_count: 1574 - task_total_time_ms: 136 + task_total_time_ms: 116 transform_count: 655 - transform_time_ms: 41 + transform_time_ms: 54 transform_yield_count: 96 - insert_time_ms: 6 + insert_time_ms: 10 insert_new_count: 172 insert_reused_count: 32 - query: EXPLAIN select dept.name, project.name from emp inner join dept on emp.dept_id @@ -35,11 +35,11 @@ unnamed-2: { SCAN([IS EMP]) | FILTER _.DEPT_ID EQUALS q1.ID AND q0.EMP_ID EQUALS _.ID AS q2 RETURN q1 } AS q1 RETURN (q1.NAME AS _0, q0.NAME AS _1) } task_count: 1574 - task_total_time_ms: 149 + task_total_time_ms: 334 transform_count: 655 - transform_time_ms: 46 + transform_time_ms: 174 transform_yield_count: 96 - insert_time_ms: 8 + insert_time_ms: 37 insert_new_count: 172 insert_reused_count: 32 - query: EXPLAIN select dept.name, project.name from emp inner join dept on emp.dept_id @@ -49,11 +49,11 @@ unnamed-2: { SCAN([IS EMP]) | FILTER _.DEPT_ID EQUALS q1.ID AND q0.EMP_ID EQUALS _.ID AS q2 RETURN q1 } AS q1 RETURN (q1.NAME AS _0, q0.NAME AS _1) } task_count: 1574 - task_total_time_ms: 149 + task_total_time_ms: 334 transform_count: 655 - transform_time_ms: 46 + transform_time_ms: 174 transform_yield_count: 96 - insert_time_ms: 8 + insert_time_ms: 37 insert_new_count: 172 insert_reused_count: 32 - query: EXPLAIN select * from (select dept.name, project.name from emp, dept, project @@ -63,9 +63,9 @@ unnamed-2: { SCAN([IS EMP]) | FILTER _.DEPT_ID EQUALS q1.ID AND q0.EMP_ID EQUALS _.ID AS q2 RETURN q1 } AS q1 RETURN (q1.NAME AS _0, q0.NAME AS _1) } task_count: 1604 - task_total_time_ms: 122 + task_total_time_ms: 116 transform_count: 659 - transform_time_ms: 39 + transform_time_ms: 53 transform_yield_count: 98 insert_time_ms: 6 insert_new_count: 176 @@ -77,11 +77,11 @@ unnamed-2: { SCAN([IS EMP]) | FILTER _.DEPT_ID EQUALS q0.ID AND q1.EMP_ID EQUALS _.ID AS q2 RETURN q1 } AS q1 RETURN ((q0.NAME AS _0, q1.NAME AS _1) AS _0) } task_count: 1604 - task_total_time_ms: 107 + task_total_time_ms: 101 transform_count: 659 - transform_time_ms: 28 + transform_time_ms: 40 transform_yield_count: 98 - insert_time_ms: 5 + insert_time_ms: 6 insert_new_count: 176 insert_reused_count: 32 - query: EXPLAIN select dept.name, project.name from project inner join emp on emp.id @@ -91,11 +91,11 @@ unnamed-2: { SCAN([IS EMP, EQUALS q1.EMP_ID]) | FILTER _.DEPT_ID EQUALS q0.ID AS q2 RETURN q1 } AS q1 RETURN (q0.NAME AS _0, q1.NAME AS _1) } task_count: 1617 - task_total_time_ms: 103 + task_total_time_ms: 97 transform_count: 657 - transform_time_ms: 32 + transform_time_ms: 33 transform_yield_count: 101 - insert_time_ms: 5 + insert_time_ms: 4 insert_new_count: 187 insert_reused_count: 27 - query: EXPLAIN select dept.id, dept.name, project.name from emp, dept, project @@ -107,11 +107,11 @@ unnamed-2: EQUALS q0.ID AND q1.EMP_ID EQUALS _.ID AS q2 RETURN q1 } AS q1 RETURN (q0.ID AS ID, q0.NAME AS _1, q1.NAME AS _2) } task_count: 1804 - task_total_time_ms: 179 + task_total_time_ms: 98 transform_count: 765 - transform_time_ms: 63 + transform_time_ms: 44 transform_yield_count: 106 - insert_time_ms: 10 + insert_time_ms: 8 insert_new_count: 198 insert_reused_count: 45 - query: EXPLAIN select dept.id, dept.name, project.name from emp inner join dept @@ -123,9 +123,9 @@ unnamed-2: EQUALS q0.ID AND q1.EMP_ID EQUALS _.ID AS q2 RETURN q1 } AS q1 RETURN (q0.ID AS ID, q0.NAME AS _1, q1.NAME AS _2) } task_count: 1804 - task_total_time_ms: 112 + task_total_time_ms: 109 transform_count: 765 - transform_time_ms: 40 + transform_time_ms: 41 transform_yield_count: 106 insert_time_ms: 6 insert_new_count: 198 @@ -140,11 +140,11 @@ unnamed-2: EQUALS _.ID AS q2 RETURN q1 } AS q1 RETURN (q1.ID AS ID, q1.NAME AS NAME) } task_count: 2320 - task_total_time_ms: 139 + task_total_time_ms: 196 transform_count: 996 - transform_time_ms: 38 + transform_time_ms: 90 transform_yield_count: 131 - insert_time_ms: 12 + insert_time_ms: 13 insert_new_count: 257 insert_reused_count: 63 - query: EXPLAIN select dept.id, dept.name, project.name from emp, dept, project @@ -156,11 +156,11 @@ unnamed-2: SCAN([IS EMP]) | FILTER _.DEPT_ID EQUALS q1.ID AND q2.EMP_ID EQUALS _.ID AS q3 RETURN q2 } AS q2 RETURN (q1.ID AS ID, q1.NAME AS _1, q2.NAME AS _2) }' task_count: 15228 - task_total_time_ms: 862 + task_total_time_ms: 785 transform_count: 6857 - transform_time_ms: 194 + transform_time_ms: 205 transform_yield_count: 817 - insert_time_ms: 181 + insert_time_ms: 172 insert_new_count: 2151 insert_reused_count: 425 - query: EXPLAIN select * from ja join jb using(c1) join jd using(c1); @@ -169,11 +169,11 @@ unnamed-2: JA, EQUALS q1.C1]) AS q2 RETURN (q2 AS _0, q1 AS _1) } AS q3 RETURN (q3._0.C1 AS C1, q3._0.C2 AS C2, q3._1.C3 AS C3, q0.C4 AS C4) } task_count: 1195 - task_total_time_ms: 113 + task_total_time_ms: 155 transform_count: 508 - transform_time_ms: 29 + transform_time_ms: 67 transform_yield_count: 79 - insert_time_ms: 3 + insert_time_ms: 7 insert_new_count: 133 insert_reused_count: 21 - query: EXPLAIN select jua.c5, jub.c5, jud.c5 from jua join jub using(c1) join @@ -183,11 +183,11 @@ unnamed-2: JUA, EQUALS q1.C1]) AS q2 RETURN (q2 AS _0, q1 AS _1) } AS q3 RETURN (q3._0.C5 AS _0, q3._1.C5 AS _1, q0.C5 AS _2) } task_count: 1195 - task_total_time_ms: 170 + task_total_time_ms: 89 transform_count: 507 - transform_time_ms: 58 + transform_time_ms: 28 transform_yield_count: 79 - insert_time_ms: 7 + insert_time_ms: 4 insert_new_count: 133 insert_reused_count: 21 - query: EXPLAIN select * from jua join (select * from jub join jud using(c1)) as @@ -198,95 +198,168 @@ unnamed-2: q3 RETURN (q3._0.C1 AS C1, q3._0.C2 AS C2, q3._0.C5 AS _2, q3._1.C3 AS C3, q3._1.C5 AS _4, q0.C4 AS C4, q0.C5 AS _6) } task_count: 1497 - task_total_time_ms: 174 + task_total_time_ms: 139 transform_count: 595 transform_time_ms: 54 transform_yield_count: 97 - insert_time_ms: 10 + insert_time_ms: 4 insert_new_count: 184 insert_reused_count: 26 +- query: EXPLAIN select ja.c1, ja.c2, jb.c3 from ja inner join jb on true; + ref: join-tests.yamsql:425 + explain: SCAN([IS JA]) | FLATMAP q0 -> { SCAN([IS JB]) AS q1 RETURN (q0.C1 AS + C1, q0.C2 AS C2, q1.C3 AS C3) } + task_count: 460 + task_total_time_ms: 185 + transform_count: 151 + transform_time_ms: 136 + transform_yield_count: 38 + insert_time_ms: 3 + insert_new_count: 50 + insert_reused_count: 6 +- query: EXPLAIN select ja.c1, ja.c2, jb.c3 from ja, jb where true; + ref: join-tests.yamsql:431 + explain: SCAN([IS JA]) | FLATMAP q0 -> { SCAN([IS JB]) AS q1 RETURN (q0.C1 AS + C1, q0.C2 AS C2, q1.C3 AS C3) } + task_count: 460 + task_total_time_ms: 17 + transform_count: 151 + transform_time_ms: 7 + transform_yield_count: 38 + insert_time_ms: 0 + insert_new_count: 50 + insert_reused_count: 6 +- query: EXPLAIN select ja.c1, ja.c2, jb.c3 from ja inner join jb on false; + ref: join-tests.yamsql:437 + explain: SCAN([IS JA]) | FLATMAP q0 -> { SCAN([IS JB]) | FILTER false AS q1 RETURN + (q0.C1 AS C1, q0.C2 AS C2, q1.C3 AS C3) } + task_count: 466 + task_total_time_ms: 27 + transform_count: 149 + transform_time_ms: 12 + transform_yield_count: 38 + insert_time_ms: 0 + insert_new_count: 54 + insert_reused_count: 6 +- query: EXPLAIN select ja.c1, ja.c2, jb.c3 from ja, jb where false; + ref: join-tests.yamsql:443 + explain: SCAN([IS JA]) | FLATMAP q0 -> { SCAN([IS JB]) | FILTER false AS q1 RETURN + (q0.C1 AS C1, q0.C2 AS C2, q1.C3 AS C3) } + task_count: 466 + task_total_time_ms: 29 + transform_count: 149 + transform_time_ms: 11 + transform_yield_count: 38 + insert_time_ms: 0 + insert_new_count: 54 + insert_reused_count: 6 +- query: EXPLAIN select ja.c1, ja.c2, jb.c3 from ja inner join jb on cast(null as + boolean); + ref: join-tests.yamsql:449 + explain: SCAN([IS JB]) | FILTER CAST(NULL AS BOOLEAN) EQUALS true | FLATMAP q0 + -> { SCAN([IS JA]) AS q1 RETURN (q1.C1 AS C1, q1.C2 AS C2, q0.C3 AS C3) } + task_count: 447 + task_total_time_ms: 21 + transform_count: 143 + transform_time_ms: 8 + transform_yield_count: 36 + insert_time_ms: 0 + insert_new_count: 49 + insert_reused_count: 6 +- query: EXPLAIN select ja.c1, ja.c2, jb.c3 from ja, jb where cast(null as boolean); + ref: join-tests.yamsql:455 + explain: SCAN([IS JB]) | FILTER CAST(NULL AS BOOLEAN) EQUALS true | FLATMAP q0 + -> { SCAN([IS JA]) AS q1 RETURN (q1.C1 AS C1, q1.C2 AS C2, q0.C3 AS C3) } + task_count: 447 + task_total_time_ms: 49 + transform_count: 143 + transform_time_ms: 21 + transform_yield_count: 36 + insert_time_ms: 1 + insert_new_count: 49 + insert_reused_count: 6 three-way-joins-right-deep-planner: - query: EXPLAIN select fname, lname from emp inner join project on emp_id = emp.id inner join dept on dept_id = dept.id and dept.name = 'Sales'; - ref: join-tests.yamsql:433 + ref: join-tests.yamsql:479 explain: SCAN([IS DEPT]) | FILTER _.NAME EQUALS promote(@c29 AS STRING) | FLATMAP q0 -> { SCAN([IS PROJECT]) | FLATMAP q1 -> { SCAN([IS EMP]) | FILTER q1.EMP_ID EQUALS _.ID AND _.DEPT_ID EQUALS q0.ID AS q2 RETURN q2 } AS q2 RETURN (q2.FNAME AS FNAME, q2.LNAME AS LNAME) } task_count: 1138 - task_total_time_ms: 73 + task_total_time_ms: 101 transform_count: 426 - transform_time_ms: 23 + transform_time_ms: 34 transform_yield_count: 77 - insert_time_ms: 2 + insert_time_ms: 4 insert_new_count: 133 insert_reused_count: 22 - query: EXPLAIN select dept.name, project.name from emp, dept, project where emp.dept_id = dept.id and project.emp_id = emp.id; - ref: join-tests.yamsql:438 + ref: join-tests.yamsql:484 explain: SCAN([IS PROJECT]) | FLATMAP q0 -> { SCAN([IS DEPT]) | FLATMAP q1 -> { SCAN([IS EMP]) | FILTER _.DEPT_ID EQUALS q1.ID AND q0.EMP_ID EQUALS _.ID AS q2 RETURN q1 } AS q1 RETURN (q1.NAME AS _0, q0.NAME AS _1) } task_count: 1008 - task_total_time_ms: 79 + task_total_time_ms: 87 transform_count: 380 - transform_time_ms: 30 + transform_time_ms: 36 transform_yield_count: 69 - insert_time_ms: 2 + insert_time_ms: 4 insert_new_count: 114 insert_reused_count: 20 - query: EXPLAIN select dept.name, project.name from emp inner join dept on emp.dept_id = dept.id inner join project on project.emp_id = emp.id; - ref: join-tests.yamsql:445 + ref: join-tests.yamsql:491 explain: SCAN([IS PROJECT]) | FLATMAP q0 -> { SCAN([IS DEPT]) | FLATMAP q1 -> { SCAN([IS EMP]) | FILTER _.DEPT_ID EQUALS q1.ID AND q0.EMP_ID EQUALS _.ID AS q2 RETURN q1 } AS q1 RETURN (q1.NAME AS _0, q0.NAME AS _1) } task_count: 1008 - task_total_time_ms: 104 + task_total_time_ms: 29 transform_count: 380 - transform_time_ms: 36 + transform_time_ms: 16 transform_yield_count: 69 - insert_time_ms: 3 + insert_time_ms: 1 insert_new_count: 114 insert_reused_count: 20 - query: EXPLAIN select * from (select dept.name, project.name from emp, dept, project where emp.dept_id = dept.id and project.emp_id = emp.id) X; - ref: join-tests.yamsql:452 + ref: join-tests.yamsql:498 explain: SCAN([IS PROJECT]) | FLATMAP q0 -> { SCAN([IS DEPT]) | FLATMAP q1 -> { SCAN([IS EMP]) | FILTER _.DEPT_ID EQUALS q1.ID AND q0.EMP_ID EQUALS _.ID AS q2 RETURN q1 } AS q1 RETURN (q1.NAME AS _0, q0.NAME AS _1) } task_count: 1038 - task_total_time_ms: 84 + task_total_time_ms: 83 transform_count: 384 - transform_time_ms: 36 + transform_time_ms: 28 transform_yield_count: 71 insert_time_ms: 2 insert_new_count: 118 insert_reused_count: 20 - query: EXPLAIN select (*) from (select dept.name, project.name from emp, dept, project where emp.dept_id = dept.id and project.emp_id = emp.id) X; - ref: join-tests.yamsql:459 + ref: join-tests.yamsql:505 explain: SCAN([IS DEPT]) | FLATMAP q0 -> { SCAN([IS PROJECT]) | FLATMAP q1 -> { SCAN([IS EMP]) | FILTER _.DEPT_ID EQUALS q0.ID AND q1.EMP_ID EQUALS _.ID AS q2 RETURN q1 } AS q1 RETURN ((q0.NAME AS _0, q1.NAME AS _1) AS _0) } task_count: 1038 - task_total_time_ms: 86 + task_total_time_ms: 59 transform_count: 384 - transform_time_ms: 28 + transform_time_ms: 15 transform_yield_count: 71 - insert_time_ms: 2 + insert_time_ms: 1 insert_new_count: 118 insert_reused_count: 20 - query: EXPLAIN select dept.name, project.name from project inner join emp on emp.id = project.emp_id inner join dept on emp.dept_id = dept.id; - ref: join-tests.yamsql:466 + ref: join-tests.yamsql:512 explain: SCAN([IS DEPT]) | FLATMAP q0 -> { SCAN([IS PROJECT]) | FLATMAP q1 -> { SCAN([IS EMP, EQUALS q1.EMP_ID]) | FILTER _.DEPT_ID EQUALS q0.ID AS q2 RETURN q1 } AS q1 RETURN (q0.NAME AS _0, q1.NAME AS _1) } task_count: 1041 - task_total_time_ms: 105 + task_total_time_ms: 90 transform_count: 381 - transform_time_ms: 28 + transform_time_ms: 33 transform_yield_count: 73 insert_time_ms: 3 insert_new_count: 123 @@ -294,31 +367,31 @@ three-way-joins-right-deep-planner: - query: EXPLAIN select dept.id, dept.name, project.name from emp, dept, project where emp.dept_id = dept.id and project.emp_id = emp.id and dept.id not in (1) - ref: join-tests.yamsql:473 + ref: join-tests.yamsql:519 explain: SCAN([IS DEPT]) | FILTER NOT _.ID IN promote(@c40 AS ARRAY(LONG)) | FLATMAP q0 -> { SCAN([IS PROJECT]) | FLATMAP q1 -> { SCAN([IS EMP]) | FILTER _.DEPT_ID EQUALS q0.ID AND q1.EMP_ID EQUALS _.ID AS q2 RETURN q1 } AS q1 RETURN (q0.ID AS ID, q0.NAME AS _1, q1.NAME AS _2) } task_count: 1116 - task_total_time_ms: 75 + task_total_time_ms: 104 transform_count: 422 - transform_time_ms: 25 + transform_time_ms: 35 transform_yield_count: 75 - insert_time_ms: 2 + insert_time_ms: 3 insert_new_count: 127 insert_reused_count: 22 - query: EXPLAIN select dept.id, dept.name, project.name from emp inner join dept on emp.dept_id = dept.id and dept.id not in (1) inner join project on project.emp_id = emp.id - ref: join-tests.yamsql:479 + ref: join-tests.yamsql:525 explain: SCAN([IS DEPT]) | FILTER NOT _.ID IN promote(@c31 AS ARRAY(LONG)) | FLATMAP q0 -> { SCAN([IS PROJECT]) | FLATMAP q1 -> { SCAN([IS EMP]) | FILTER _.DEPT_ID EQUALS q0.ID AND q1.EMP_ID EQUALS _.ID AS q2 RETURN q1 } AS q1 RETURN (q0.ID AS ID, q0.NAME AS _1, q1.NAME AS _2) } task_count: 1116 - task_total_time_ms: 86 + task_total_time_ms: 107 transform_count: 422 - transform_time_ms: 32 + transform_time_ms: 38 transform_yield_count: 75 insert_time_ms: 3 insert_new_count: 127 @@ -326,75 +399,75 @@ three-way-joins-right-deep-planner: - query: EXPLAIN select project.id, project.name from emp, dept, project where emp.dept_id = dept.id and project.emp_id = emp.id and dept.id not in (3) and project.id not in (3) - ref: join-tests.yamsql:485 + ref: join-tests.yamsql:531 explain: SCAN([IS EMP]) | FLATMAP q0 -> { SCAN([IS PROJECT]) | FILTER NOT _.ID IN promote(@c36 AS ARRAY(LONG)) AND _.EMP_ID EQUALS q0.ID | FLATMAP q1 -> { SCAN([IS DEPT]) | FILTER NOT _.ID IN promote(@c36 AS ARRAY(LONG)) AND q0.DEPT_ID EQUALS _.ID AS q2 RETURN q1 } AS q1 RETURN (q1.ID AS ID, q1.NAME AS NAME) } task_count: 1224 - task_total_time_ms: 96 + task_total_time_ms: 45 transform_count: 463 - transform_time_ms: 34 + transform_time_ms: 21 transform_yield_count: 81 - insert_time_ms: 3 + insert_time_ms: 2 insert_new_count: 140 insert_reused_count: 24 - query: EXPLAIN select dept.id, dept.name, project.name from emp, dept, project where emp.dept_id = dept.id and project.emp_id = emp.id and dept.id in (1, 2) - ref: join-tests.yamsql:490 + ref: join-tests.yamsql:536 explain: '[IN arrayDistinct(promote(@c39 AS ARRAY(LONG)))] | INJOIN q0 -> { SCAN([IS DEPT, EQUALS q0]) } | FLATMAP q1 -> { SCAN([IS PROJECT]) | FLATMAP q2 -> { SCAN([IS EMP]) | FILTER _.DEPT_ID EQUALS q1.ID AND q2.EMP_ID EQUALS _.ID AS q3 RETURN q2 } AS q2 RETURN (q1.ID AS ID, q1.NAME AS _1, q2.NAME AS _2) }' task_count: 4963 - task_total_time_ms: 377 + task_total_time_ms: 410 transform_count: 1903 - transform_time_ms: 100 + transform_time_ms: 118 transform_yield_count: 287 - insert_time_ms: 22 + insert_time_ms: 29 insert_new_count: 733 insert_reused_count: 102 - query: EXPLAIN select * from ja join jb using(c1) join jd using(c1); - ref: join-tests.yamsql:496 + ref: join-tests.yamsql:542 explain: SCAN([IS JD]) | FLATMAP q0 -> { SCAN([IS JB]) | FLATMAP q1 -> { SCAN([IS JA, EQUALS q1.C1]) AS q2 RETURN (q2 AS _0, q1 AS _1) } AS q3 RETURN (q3._0.C1 AS C1, q3._0.C2 AS C2, q3._1.C3 AS C3, q0.C4 AS C4) } task_count: 892 - task_total_time_ms: 110 + task_total_time_ms: 98 transform_count: 352 - transform_time_ms: 35 + transform_time_ms: 27 transform_yield_count: 64 insert_time_ms: 2 insert_new_count: 103 insert_reused_count: 12 - query: EXPLAIN select jua.c5, jub.c5, jud.c5 from jua join jub using(c1) join jud using(c1); - ref: join-tests.yamsql:501 + ref: join-tests.yamsql:547 explain: SCAN([IS JUD]) | FLATMAP q0 -> { SCAN([IS JUB]) | FLATMAP q1 -> { SCAN([IS JUA, EQUALS q1.C1]) AS q2 RETURN (q2 AS _0, q1 AS _1) } AS q3 RETURN (q3._0.C5 AS _0, q3._1.C5 AS _1, q0.C5 AS _2) } task_count: 892 - task_total_time_ms: 111 + task_total_time_ms: 65 transform_count: 351 - transform_time_ms: 39 + transform_time_ms: 21 transform_yield_count: 64 - insert_time_ms: 2 + insert_time_ms: 1 insert_new_count: 103 insert_reused_count: 12 - query: EXPLAIN select * from jua join (select * from jub join jud using(c1)) as X using (c1); - ref: join-tests.yamsql:506 + ref: join-tests.yamsql:552 explain: SCAN([IS JUD]) | FLATMAP q0 -> { SCAN([IS JUB, EQUALS q0.C1]) | FLATMAP q1 -> { SCAN([IS JUA, EQUALS q1.C1]) AS q2 RETURN (q2 AS _0, q1 AS _1) } AS q3 RETURN (q3._0.C1 AS C1, q3._0.C2 AS C2, q3._0.C5 AS _2, q3._1.C3 AS C3, q3._1.C5 AS _4, q0.C4 AS C4, q0.C5 AS _6) } task_count: 1094 - task_total_time_ms: 138 + task_total_time_ms: 112 transform_count: 387 - transform_time_ms: 43 + transform_time_ms: 39 transform_yield_count: 78 - insert_time_ms: 3 + insert_time_ms: 2 insert_new_count: 137 insert_reused_count: 13 diff --git a/yaml-tests/src/test/resources/join-tests.yamsql b/yaml-tests/src/test/resources/join-tests.yamsql index 8dbe88e7ff..386647bdc5 100644 --- a/yaml-tests/src/test/resources/join-tests.yamsql +++ b/yaml-tests/src/test/resources/join-tests.yamsql @@ -418,6 +418,54 @@ test_block: - query: select * from (select c11 as c1, c3 from (select c3 - 2 as c11, c3 from jub) as Z) as Y join (select c2 - 1 as c1, c5 from jua) as X using (c1); - supported_version: 4.10.4.0 - result: [{c1: 1, c3: 3, c5: 5}] + - + # inner join with ON TRUE: yields the cross product + - query: select ja.c1, ja.c2, jb.c3 from ja inner join jb on true; + - supported_version: !current_version + - explain: "SCAN([IS JA]) | FLATMAP q0 -> { SCAN([IS JB]) AS q1 RETURN (q0.C1 AS C1, q0.C2 AS C2, q1.C3 AS C3) }" + - result: [{c1: 1, c2: 2, c3: 3}] + - + # same cross product, but expressed using a comma-separated list and an explicit WHERE TRUE clause + - query: select ja.c1, ja.c2, jb.c3 from ja, jb where true; + - supported_version: !current_version + - explain: "SCAN([IS JA]) | FLATMAP q0 -> { SCAN([IS JB]) AS q1 RETURN (q0.C1 AS C1, q0.C2 AS C2, q1.C3 AS C3) }" + - result: [{c1: 1, c2: 2, c3: 3}] + - + # inner join with ON FALSE: yields an empty result + - query: select ja.c1, ja.c2, jb.c3 from ja inner join jb on false; + - supported_version: !current_version + - explain: "SCAN([IS JA]) | FLATMAP q0 -> { SCAN([IS JB]) | FILTER false AS q1 RETURN (q0.C1 AS C1, q0.C2 AS C2, q1.C3 AS C3) }" + - result: [] + - + # same join as above, but using an explicit WHERE FALSE clause + - query: select ja.c1, ja.c2, jb.c3 from ja, jb where false; + - supported_version: !current_version + - explain: "SCAN([IS JA]) | FLATMAP q0 -> { SCAN([IS JB]) | FILTER false AS q1 RETURN (q0.C1 AS C1, q0.C2 AS C2, q1.C3 AS C3) }" + - result: [] + - + # inner join with ON UNKNOWN: has the same effect as ON FALSE + - query: select ja.c1, ja.c2, jb.c3 from ja inner join jb on cast(null as boolean); + - supported_version: !current_version + - explain: "SCAN([IS JB]) | FILTER CAST(NULL AS BOOLEAN) EQUALS true | FLATMAP q0 -> { SCAN([IS JA]) AS q1 RETURN (q1.C1 AS C1, q1.C2 AS C2, q0.C3 AS C3) }" + - result: [] + - + # same join as above, but using an explicit WHERE NULL clause + - query: select ja.c1, ja.c2, jb.c3 from ja, jb where cast(null as boolean); + - supported_version: !current_version + - explain: "SCAN([IS JB]) | FILTER CAST(NULL AS BOOLEAN) EQUALS true | FLATMAP q0 -> { SCAN([IS JA]) AS q1 RETURN (q1.C1 AS C1, q1.C2 AS C2, q0.C3 AS C3) }" + - result: [] + - + # inner join with ON NULL: a plain NULL predicate is recognized as a null boolean and yields an empty result + - query: select ja.c1, ja.c2, jb.c3 from ja inner join jb on null; + - supported_version: !current_version + - explain: "SCAN([IS JA]) | FLATMAP q0 -> { SCAN([IS JB]) | FILTER null AS q1 RETURN (q0.C1 AS C1, q0.C2 AS C2, q1.C3 AS C3) }" + - result: [] + - + # same join as above, but using an explicit WHERE NULL clause + - query: select ja.c1, ja.c2, jb.c3 from ja, jb where null; + - supported_version: !current_version + - explain: "SCAN([IS JA]) | FLATMAP q0 -> { SCAN([IS JB]) | FILTER null AS q1 RETURN (q0.C1 AS C1, q0.C2 AS C2, q1.C3 AS C3) }" + - result: [] --- # All 3-way (or more) join queries from above, repeated with PLAN_RIGHT_DEEP enabled. test_block: From f47fb1d17ce6f23505ea3b465a3232ab899ca292 Mon Sep 17 00:00:00 2001 From: Scott Dugas Date: Wed, 20 May 2026 10:08:18 -0400 Subject: [PATCH 2/3] Add branch coverage to our PR coverage annotations The data was already gathered via JaCoCo so this just exposes it in the same way as the line coverage. branch coverage is omitted if the changed lines have no branches. --- build/coverage_annotations.py | 70 +++++++++++-- build/test_coverage_annotations.py | 151 ++++++++++++++++++++++++++++- 2 files changed, 209 insertions(+), 12 deletions(-) diff --git a/build/coverage_annotations.py b/build/coverage_annotations.py index 0ddda24ea9..6d5c888363 100644 --- a/build/coverage_annotations.py +++ b/build/coverage_annotations.py @@ -204,15 +204,67 @@ def compute_changed_lines_coverage(lines, changed_line_numbers): return covered_changed, executable_changed +def compute_file_branch_coverage(lines): + """ + Compute overall branch coverage for a file. + + Returns: + tuple of (covered_branches, total_branches) + """ + covered = sum(l.covered_branches for l in lines) + missed = sum(l.missed_branches for l in lines) + return covered, covered + missed + + +def compute_changed_lines_branch_coverage(lines, changed_line_numbers): + """ + Compute branch coverage for only the changed lines in a file. + + Returns: + tuple of (covered_branches, total_branches) + """ + line_map = {l.line_number: l for l in lines} + covered = 0 + total = 0 + + for line_num in changed_line_numbers: + line = line_map.get(line_num) + if line is not None: + covered += line.covered_branches + total += line.covered_branches + line.missed_branches + + return covered, total + + def format_percentage(covered, total): - """Format a coverage percentage string.""" + """Format a line coverage percentage string.""" if total == 0: return 'N/A (no executable lines)' pct = (covered / total) * 100 return f'{pct:.1f}% ({covered}/{total} lines)' -def format_file_annotation(repo_path, file_coverage, changed_coverage, first_changed_line): +def format_branch_percentage(covered, total): + """Format a branch coverage percentage string.""" + pct = (covered / total) * 100 + return f'{pct:.1f}% ({covered}/{total} branches)' + + +def format_combined_percentage(line_cov, branch_cov): + """ + Format combined line + branch coverage. Branch part is omitted when there + are no branches at all (keeps annotations tidy for files with no + conditional logic). + """ + parts = [format_percentage(*line_cov)] + if branch_cov[1] > 0: + parts.append(format_branch_percentage(*branch_cov)) + return ', '.join(parts) + + +def format_file_annotation(repo_path, file_line_coverage, changed_line_coverage, + file_branch_coverage, changed_branch_coverage, + first_changed_line): """ Format a single GitHub Actions annotation for a file's coverage summary. @@ -221,11 +273,8 @@ def format_file_annotation(repo_path, file_coverage, changed_coverage, first_cha Returns the annotation string, or None if there's nothing to report. """ - file_covered, file_total = file_coverage - changed_covered, changed_total = changed_coverage - - file_pct_str = format_percentage(file_covered, file_total) - changed_pct_str = format_percentage(changed_covered, changed_total) + file_pct_str = format_combined_percentage(file_line_coverage, file_branch_coverage) + changed_pct_str = format_combined_percentage(changed_line_coverage, changed_branch_coverage) annotation_line = max(1, first_changed_line - 1) message = f'File coverage: {file_pct_str} | Changed lines: {changed_pct_str}' @@ -260,10 +309,15 @@ def generate_annotations(coverage_data, diff_data, source_prefixes): file_coverage = compute_file_coverage(lines) changed_coverage = compute_changed_lines_coverage(lines, changed_line_numbers) + file_branch_coverage = compute_file_branch_coverage(lines) + changed_branch_coverage = compute_changed_lines_branch_coverage(lines, changed_line_numbers) first_changed_line = min(changed_line_numbers) annotation = format_file_annotation( - repo_path, file_coverage, changed_coverage, first_changed_line) + repo_path, + file_coverage, changed_coverage, + file_branch_coverage, changed_branch_coverage, + first_changed_line) if annotation: annotations.append(annotation) diff --git a/build/test_coverage_annotations.py b/build/test_coverage_annotations.py index 5ace1c765b..314b9e3c2f 100644 --- a/build/test_coverage_annotations.py +++ b/build/test_coverage_annotations.py @@ -30,8 +30,12 @@ sys.path.insert(0, os.path.dirname(__file__)) from coverage_annotations import ( LineCoverage, + compute_changed_lines_branch_coverage, compute_changed_lines_coverage, + compute_file_branch_coverage, compute_file_coverage, + format_branch_percentage, + format_combined_percentage, format_file_annotation, format_percentage, generate_annotations, @@ -343,11 +347,13 @@ def test_no_executable_lines(self): class TestFormatFileAnnotation(unittest.TestCase): """Tests for format_file_annotation()""" - def test_basic_annotation(self): + def test_basic_annotation_no_branches(self): result = format_file_annotation( 'module/src/main/java/com/example/Foo.java', (8, 10), (2, 3), + (0, 0), + (0, 0), first_changed_line=15, ) self.assertEqual( @@ -356,11 +362,43 @@ def test_basic_annotation(self): 'File coverage: 80.0% (8/10 lines) | Changed lines: 66.7% (2/3 lines)' ) + def test_annotation_with_branches(self): + result = format_file_annotation( + 'module/src/main/java/com/example/Foo.java', + (8, 10), + (2, 3), + (6, 10), + (1, 4), + first_changed_line=15, + ) + self.assertEqual( + result, + '::notice file=module/src/main/java/com/example/Foo.java,line=14::' + 'File coverage: 80.0% (8/10 lines), 60.0% (6/10 branches) | ' + 'Changed lines: 66.7% (2/3 lines), 25.0% (1/4 branches)' + ) + + def test_annotation_omits_branches_when_only_file_has_branches(self): + # File has branches, but changed lines don't touch any + result = format_file_annotation( + 'module/src/main/java/com/example/Foo.java', + (8, 10), + (2, 3), + (6, 10), + (0, 0), + first_changed_line=15, + ) + self.assertIn('80.0% (8/10 lines), 60.0% (6/10 branches)', result) + self.assertIn('Changed lines: 66.7% (2/3 lines)', result) + self.assertNotIn('0/0 branches', result) + def test_annotation_line_does_not_go_below_1(self): result = format_file_annotation( 'module/src/main/java/com/example/Foo.java', (8, 10), (2, 3), + (0, 0), + (0, 0), first_changed_line=1, ) self.assertIn('line=1', result) @@ -370,11 +408,101 @@ def test_no_executable_changed_lines(self): 'module/src/main/java/com/example/Foo.java', (8, 10), (0, 0), + (0, 0), + (0, 0), first_changed_line=5, ) self.assertIn('N/A (no executable lines)', result) +class TestComputeFileBranchCoverage(unittest.TestCase): + """Tests for compute_file_branch_coverage()""" + + def test_mixed_branches(self): + lines = [ + LineCoverage(10, 0, 3, 0, 0), # no branches + LineCoverage(15, 0, 5, 1, 3), # 3 covered, 1 missed + LineCoverage(20, 0, 1, 2, 2), # 2 covered, 2 missed + ] + covered, total = compute_file_branch_coverage(lines) + self.assertEqual(covered, 5) + self.assertEqual(total, 8) + + def test_no_branches(self): + lines = [ + LineCoverage(10, 0, 3, 0, 0), + LineCoverage(11, 0, 2, 0, 0), + ] + covered, total = compute_file_branch_coverage(lines) + self.assertEqual(covered, 0) + self.assertEqual(total, 0) + + def test_all_branches_covered(self): + lines = [LineCoverage(10, 0, 5, 0, 4)] + covered, total = compute_file_branch_coverage(lines) + self.assertEqual(covered, 4) + self.assertEqual(total, 4) + + def test_empty_file(self): + covered, total = compute_file_branch_coverage([]) + self.assertEqual(covered, 0) + self.assertEqual(total, 0) + + +class TestComputeChangedLinesBranchCoverage(unittest.TestCase): + """Tests for compute_changed_lines_branch_coverage()""" + + def test_changed_lines_with_branches(self): + lines = [ + LineCoverage(10, 0, 3, 0, 0), # no branches + LineCoverage(15, 0, 5, 1, 3), # 3 covered, 1 missed + LineCoverage(20, 0, 1, 2, 2), # 2 covered, 2 missed + ] + # Only line 15 is changed + covered, total = compute_changed_lines_branch_coverage(lines, {15}) + self.assertEqual(covered, 3) + self.assertEqual(total, 4) + + def test_changed_lines_without_branches(self): + lines = [LineCoverage(10, 0, 3, 0, 0)] + covered, total = compute_changed_lines_branch_coverage(lines, {10}) + self.assertEqual(covered, 0) + self.assertEqual(total, 0) + + def test_changed_line_not_in_coverage(self): + lines = [LineCoverage(10, 0, 3, 1, 1)] + # Line 5 is changed but has no coverage data (e.g., a comment) + covered, total = compute_changed_lines_branch_coverage(lines, {5}) + self.assertEqual(covered, 0) + self.assertEqual(total, 0) + + +class TestFormatCombinedPercentage(unittest.TestCase): + """Tests for format_combined_percentage()""" + + def test_with_branches(self): + result = format_combined_percentage((4, 8), (3, 5)) + self.assertEqual(result, '50.0% (4/8 lines), 60.0% (3/5 branches)') + + def test_without_branches(self): + result = format_combined_percentage((4, 8), (0, 0)) + self.assertEqual(result, '50.0% (4/8 lines)') + + def test_no_executable_lines(self): + result = format_combined_percentage((0, 0), (0, 0)) + self.assertEqual(result, 'N/A (no executable lines)') + + +class TestFormatBranchPercentage(unittest.TestCase): + """Tests for format_branch_percentage()""" + + def test_basic(self): + self.assertEqual(format_branch_percentage(3, 5), '60.0% (3/5 branches)') + + def test_full(self): + self.assertEqual(format_branch_percentage(4, 4), '100.0% (4/4 branches)') + + class TestGenerateAnnotations(unittest.TestCase): """Tests for generate_annotations()""" @@ -435,9 +563,24 @@ def test_annotation_contains_coverage_data(self): annotations = generate_annotations(self.coverage_data, diff_data, None) self.assertEqual(len(annotations), 1) # File has 8 executable lines, 4 covered -> 50% - self.assertIn('50.0%', annotations[0]) - # Changed lines 12, 13, 14 are all uncovered -> 0% - self.assertIn('0.0%', annotations[0]) + self.assertIn('50.0% (4/8 lines)', annotations[0]) + # File has 4 total branches (line 15: cb=3 mb=1), 3 covered -> 75% + self.assertIn('75.0% (3/4 branches)', annotations[0]) + # Changed lines 12, 13, 14 are all uncovered with no branches -> 0% lines, no branches + self.assertIn('0.0% (0/3 lines)', annotations[0]) + # Changed lines have no branches, so branches segment should be omitted from changed + self.assertNotIn('0/0 branches', annotations[0]) + + def test_annotation_with_branches_on_changed_line(self): + diff_data = { + # Line 15 has cb=3 mb=1 (partial branch coverage) + 'fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/FDBRecordStore.java': {15}, + } + annotations = generate_annotations(self.coverage_data, diff_data, None) + self.assertEqual(len(annotations), 1) + # Changed line 15: 1 covered line, 3/4 branches covered + self.assertIn('100.0% (1/1 lines)', annotations[0]) + self.assertIn('75.0% (3/4 branches)', annotations[0]) class TestEndToEnd(unittest.TestCase): From 5f1f273ced6e30af1a5f0678a535e96ea67bbd05 Mon Sep 17 00:00:00 2001 From: Scott Dugas Date: Thu, 21 May 2026 12:35:33 -0400 Subject: [PATCH 3/3] Use two lines for coverage annotation With the branch coverage it's a bit length and hard to read, use two lines. --- build/coverage_annotations.py | 2 +- build/test_coverage_annotations.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build/coverage_annotations.py b/build/coverage_annotations.py index 6d5c888363..15e6bd9ae6 100644 --- a/build/coverage_annotations.py +++ b/build/coverage_annotations.py @@ -277,7 +277,7 @@ def format_file_annotation(repo_path, file_line_coverage, changed_line_coverage, changed_pct_str = format_combined_percentage(changed_line_coverage, changed_branch_coverage) annotation_line = max(1, first_changed_line - 1) - message = f'File coverage: {file_pct_str} | Changed lines: {changed_pct_str}' + message = f'File coverage: {file_pct_str}%0AChanged lines: {changed_pct_str}' return f'::notice file={repo_path},line={annotation_line}::{message}' diff --git a/build/test_coverage_annotations.py b/build/test_coverage_annotations.py index 314b9e3c2f..c42afdbe73 100644 --- a/build/test_coverage_annotations.py +++ b/build/test_coverage_annotations.py @@ -359,7 +359,7 @@ def test_basic_annotation_no_branches(self): self.assertEqual( result, '::notice file=module/src/main/java/com/example/Foo.java,line=14::' - 'File coverage: 80.0% (8/10 lines) | Changed lines: 66.7% (2/3 lines)' + 'File coverage: 80.0% (8/10 lines)%0AChanged lines: 66.7% (2/3 lines)' ) def test_annotation_with_branches(self): @@ -374,7 +374,7 @@ def test_annotation_with_branches(self): self.assertEqual( result, '::notice file=module/src/main/java/com/example/Foo.java,line=14::' - 'File coverage: 80.0% (8/10 lines), 60.0% (6/10 branches) | ' + 'File coverage: 80.0% (8/10 lines), 60.0% (6/10 branches)%0A' 'Changed lines: 66.7% (2/3 lines), 25.0% (1/4 branches)' )