From abf60b77a9422019d5dd1cdf4ed94b62c86b7e17 Mon Sep 17 00:00:00 2001 From: Pengpeng Lu Date: Thu, 15 May 2025 23:29:23 -0700 Subject: [PATCH 01/16] not distinct from --- .../record/query/expressions/Comparisons.java | 19 ++++ .../cascades/predicates/RangeConstraints.java | 1 + .../plan/cascades/values/RelOpValue.java | 86 +++++++++++++++++++ .../src/main/antlr/RelationalLexer.g4 | 2 + .../src/main/antlr/RelationalParser.g4 | 1 + .../functions/SqlFunctionCatalogImpl.java | 3 + .../recordlayer/query/StandardQueryTests.java | 73 ++++++++++++++++ 7 files changed, 185 insertions(+) diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/expressions/Comparisons.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/expressions/Comparisons.java index 6b30c1f32b..a6452e65a3 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/expressions/Comparisons.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/expressions/Comparisons.java @@ -261,6 +261,22 @@ private static Boolean compareEquals(Object value, Object comparand) { } } + @Nullable + @SpotBugsSuppressWarnings("NP_BOOLEAN_RETURN_NULL") + private static Boolean compareNotDistinctFrom(Object value, Object comparand) { + if (value == null && comparand == null) { + return true; + } else if (value == null || comparand == null) { + return false; + } else { + if (value instanceof Message) { + return MessageHelpers.compareMessageEquals(value, comparand); + } else { + return toClassWithRealEquals(value).equals(toClassWithRealEquals(comparand)); + } + } + } + @Nullable @SpotBugsSuppressWarnings("NP_BOOLEAN_RETURN_NULL") private static Boolean compareStartsWith(@Nullable Object value, @Nullable Object comparand) { @@ -623,6 +639,7 @@ public enum Type { STARTS_WITH, NOT_NULL(false, true), IS_NULL(true, true), + NOT_DISTINCT_FROM(false), IN, TEXT_CONTAINS_ALL(true), TEXT_CONTAINS_ALL_WITHIN(true), @@ -722,6 +739,8 @@ public static Boolean evalComparison(@Nonnull Type type, @Nullable Object value, return null; } return !compareEquals(value, comparand); + case NOT_DISTINCT_FROM: + return compareNotDistinctFrom(value, comparand); case LESS_THAN: return compare(value, comparand) < 0; case LESS_THAN_OR_EQUALS: diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/RangeConstraints.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/RangeConstraints.java index f8b978d410..996f3ace89 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/RangeConstraints.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/RangeConstraints.java @@ -729,6 +729,7 @@ private boolean canBeUsedInScanPrefix(@Nonnull final Comparisons.Comparison comp case STARTS_WITH: case NOT_NULL: case IS_NULL: + case NOT_DISTINCT_FROM: return true; case TEXT_CONTAINS_ALL: case TEXT_CONTAINS_ALL_WITHIN: diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/RelOpValue.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/RelOpValue.java index 2e0f41bd2d..5df2099c67 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/RelOpValue.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/RelOpValue.java @@ -184,6 +184,9 @@ private static Optional promoteOperandsAndCreatePredicate(@Nulla @Nonnull Value leftChild, @Nonnull Value rightChild, @Nonnull final Comparisons.Type comparisonType) { + if (leftChild.getResultType().getTypeCode() == Type.TypeCode.NULL && rightChild.getResultType().getTypeCode() == Type.TypeCode.NULL && comparisonType == Comparisons.Type.NOT_DISTINCT_FROM) { + return Optional.of(ConstantPredicate.TRUE); + } // maximumType may return null, but only for non-primitive types which is not possible here final var maxtype = Verify.verifyNotNull(Type.maximumType(leftChild.getResultType(), rightChild.getResultType())); @@ -255,6 +258,7 @@ private static Comparisons.Type swapBinaryComparisonOperator(@Nonnull Comparison switch (type) { case EQUALS: case NOT_EQUALS: + case NOT_DISTINCT_FROM: return type; case LESS_THAN: return Comparisons.Type.GREATER_THAN; @@ -290,6 +294,13 @@ private static Value encapsulate(@Nonnull final String functionName, } else { final Typed arg1 = arguments.get(1); final Type res1 = arg1.getResultType(); + if (functionName.equals("notDistinctFrom")) { + if (res0.getTypeCode() == Type.TypeCode.NULL && res1.getTypeCode() != Type.TypeCode.NULL) { + return encapsulate("isNull", Comparisons.Type.IS_NULL, List.of(arg1)); + } else if (res1.getTypeCode() == Type.TypeCode.NULL && res0.getTypeCode() != Type.TypeCode.NULL) { + return encapsulate("isNull", Comparisons.Type.IS_NULL, List.of(arg0)); + } + } SemanticException.check(res1.isPrimitive() || res1.isEnum() || res1.isUuid(), SemanticException.ErrorCode.COMPARAND_TO_COMPARISON_IS_OF_COMPLEX_TYPE); final BinaryPhysicalOperator physicalOperator = @@ -451,6 +462,21 @@ private static Value encapsulate(@Nonnull BuiltInFunction builtInFunction } } + /** + * The {@code notDistinctFrom} function. + */ + @AutoService(BuiltInFunction.class) + public static class NotDistinctFromFn extends BuiltInFunction { + public NotDistinctFromFn() { + super("notDistinctFrom", + List.of(new Type.Any(), new Type.Any()), NotDistinctFromFn::encapsulate); + } + + private static Value encapsulate(@Nonnull BuiltInFunction builtInFunction, @Nonnull final List arguments) { + return RelOpValue.encapsulate(builtInFunction.getFunctionName(), Comparisons.Type.NOT_DISTINCT_FROM, arguments); + } + } + private enum BinaryPhysicalOperator { // TODO think about equality epsilon for floating-point types. EQ_BU(Comparisons.Type.EQUALS, Type.TypeCode.BOOLEAN, Type.TypeCode.UNKNOWN, (l, r) -> null), @@ -763,6 +789,66 @@ private enum BinaryPhysicalOperator { GTE_SID(Comparisons.Type.GREATER_THAN_OR_EQUALS, Type.TypeCode.STRING, Type.TypeCode.UUID, (l, r) -> Comparisons.evalComparison(Comparisons.Type.GREATER_THAN_OR_EQUALS, PromoteValue.PhysicalOperator.stringToUuidValue((String) l), r)), GTE_UID(Comparisons.Type.GREATER_THAN_OR_EQUALS, Type.TypeCode.UNKNOWN, Type.TypeCode.UUID, (l, r) -> null), GTE_IDU(Comparisons.Type.GREATER_THAN_OR_EQUALS, Type.TypeCode.UUID, Type.TypeCode.UNKNOWN, (l, r) -> null), + + NOT_DISTINCT_FROM_BU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.BOOLEAN, Type.TypeCode.UNKNOWN, (l, r) -> null), + NOT_DISTINCT_FROM_BB(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.BOOLEAN, Type.TypeCode.BOOLEAN, (l, r) -> (boolean)l == (boolean)r), + NOT_DISTINCT_FROM_IU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.INT, Type.TypeCode.UNKNOWN, (l, r) -> null), + NOT_DISTINCT_FROM_II(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.INT, Type.TypeCode.INT, (l, r) -> (int)l == (int)r), + NOT_DISTINCT_FROM_IL(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.INT, Type.TypeCode.LONG, (l, r) -> (int)l == (long)r), + NOT_DISTINCT_FROM_IF(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.INT, Type.TypeCode.FLOAT, (l, r) -> (int)l == (float)r), + NOT_DISTINCT_FROM_ID(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.INT, Type.TypeCode.DOUBLE, (l, r) -> (int)l == (double)r), + NOT_DISTINCT_FROM_LU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.LONG, Type.TypeCode.UNKNOWN, (l, r) -> null), + NOT_DISTINCT_FROM_LI(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.LONG, Type.TypeCode.INT, (l, r) -> (long)l == (int)r), + NOT_DISTINCT_FROM_LL(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.LONG, Type.TypeCode.LONG, (l, r) -> (long)l == (long)r), + NOT_DISTINCT_FROM_LF(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.LONG, Type.TypeCode.FLOAT, (l, r) -> (long)l == (float)r), + NOT_DISTINCT_FROM_LD(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.LONG, Type.TypeCode.DOUBLE, (l, r) -> (long)l == (double)r), + NOT_DISTINCT_FROM_FU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.FLOAT, Type.TypeCode.UNKNOWN, (l, r) -> null), + NOT_DISTINCT_FROM_FI(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.FLOAT, Type.TypeCode.INT, (l, r) -> (float)l == (int)r), + NOT_DISTINCT_FROM_FL(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.FLOAT, Type.TypeCode.LONG, (l, r) -> (float)l == (long)r), + NOT_DISTINCT_FROM_FF(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.FLOAT, Type.TypeCode.FLOAT, (l, r) -> (float)l == (float)r), + NOT_DISTINCT_FROM_FD(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.FLOAT, Type.TypeCode.DOUBLE, (l, r) -> (float)l == (double)r), + NOT_DISTINCT_FROM_DU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.DOUBLE, Type.TypeCode.UNKNOWN, (l, r) -> null), + NOT_DISTINCT_FROM_DI(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.DOUBLE, Type.TypeCode.INT, (l, r) -> (double)l == (int)r), + NOT_DISTINCT_FROM_DL(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.DOUBLE, Type.TypeCode.LONG, (l, r) -> (double)l == (long)r), + NOT_DISTINCT_FROM_DF(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.DOUBLE, Type.TypeCode.FLOAT, (l, r) -> (double)l == (float)r), + NOT_DISTINCT_FROM_DD(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.DOUBLE, Type.TypeCode.DOUBLE, (l, r) -> (double)l == (double)r), + NOT_DISTINCT_FROM_SU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.STRING, Type.TypeCode.UNKNOWN, (l, r) -> null), + NOT_DISTINCT_FROM_SS(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.STRING, Type.TypeCode.STRING, Object::equals), // TODO: locale-aware comparison + NOT_DISTINCT_FROM_UU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.UNKNOWN, (l, r) -> null), + NOT_DISTINCT_FROM_UB(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.BOOLEAN, (l, r) -> null), + NOT_DISTINCT_FROM_UI(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.INT, (l, r) -> null), + NOT_DISTINCT_FROM_UL(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.LONG, (l, r) -> null), + NOT_DISTINCT_FROM_UF(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.FLOAT, (l, r) -> null), + NOT_DISTINCT_FROM_UD(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.DOUBLE, (l, r) -> null), + NOT_DISTINCT_FROM_US(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.STRING, (l, r) -> null), + NOT_DISTINCT_FROM_UV(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.VERSION, (l, r) -> null), + NOT_DISTINCT_FROM_VU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.VERSION, Type.TypeCode.UNKNOWN, (l, r) -> null), + NOT_DISTINCT_FROM_VV(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.VERSION, Type.TypeCode.VERSION, Object::equals), + + NOT_DISTINCT_FROM_BYU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.BYTES, Type.TypeCode.UNKNOWN, (l, r) -> null), + NOT_DISTINCT_FROM_BYBY(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.BYTES, Type.TypeCode.BYTES, (l, r) -> Comparisons.evalComparison(Comparisons.Type.NOT_DISTINCT_FROM, l, r)), + NOT_DISTINCT_FROM_UBY(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.BYTES, (l, r) -> null), + + NOT_DISTINCT_FROM_EE(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.ENUM, Type.TypeCode.ENUM, (l, r) -> Comparisons.evalComparison(Comparisons.Type.NOT_DISTINCT_FROM, l, r)), + NOT_DISTINCT_FROM_ES(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.ENUM, Type.TypeCode.STRING, (l, r) -> { + final var otherValue = PromoteValue.PhysicalOperator.stringToEnumValue(((Descriptors.EnumValueDescriptor) l).getType(), (String) r); + return Comparisons.evalComparison(Comparisons.Type.NOT_DISTINCT_FROM, l, otherValue); + }), + NOT_DISTINCT_FROM_SE(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.STRING, Type.TypeCode.ENUM, (l, r) -> { + final var otherValue = PromoteValue.PhysicalOperator.stringToEnumValue(((Descriptors.EnumValueDescriptor) r).getType(), (String) l); + return Comparisons.evalComparison(Comparisons.Type.NOT_DISTINCT_FROM, otherValue, r); + }), + NOT_DISTINCT_FROM_EU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.ENUM, Type.TypeCode.UNKNOWN, (l, r) -> null), + NOT_DISTINCT_FROM_UE(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.ENUM, (l, r) -> null), + + NOT_DISTINCT_FROM_IDID(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UUID, Type.TypeCode.UUID, (l, r) -> Comparisons.evalComparison(Comparisons.Type.NOT_DISTINCT_FROM, l, r)), + NOT_DISTINCT_FROM_IDS(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UUID, Type.TypeCode.STRING, (l, r) -> Comparisons.evalComparison(Comparisons.Type.NOT_DISTINCT_FROM, l, PromoteValue.PhysicalOperator.stringToUuidValue((String) r))), + NOT_DISTINCT_FROM_SID(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.STRING, Type.TypeCode.UUID, (l, r) -> Comparisons.evalComparison(Comparisons.Type.NOT_DISTINCT_FROM, PromoteValue.PhysicalOperator.stringToUuidValue((String) l), r)), + NOT_DISTINCT_FROM_UID(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.UUID, (l, r) -> null), + NOT_DISTINCT_FROM_IDU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UUID, Type.TypeCode.UNKNOWN, (l, r) -> null), + + NOT_DISTINCT_FROM_NN(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.NULL, (l, r) -> true), + ; // We can pass down UUID or String till here. diff --git a/fdb-relational-core/src/main/antlr/RelationalLexer.g4 b/fdb-relational-core/src/main/antlr/RelationalLexer.g4 index 8d49e2d193..3464611236 100644 --- a/fdb-relational-core/src/main/antlr/RelationalLexer.g4 +++ b/fdb-relational-core/src/main/antlr/RelationalLexer.g4 @@ -127,6 +127,8 @@ INSERT: 'INSERT'; INTERVAL: 'INTERVAL'; INTO: 'INTO'; IS: 'IS'; +IS_DISTINCT_FROM: 'IS DISTINCT FROM'; +IS_NOT_DISTINCT_FROM: 'IS NOT DISTINCT FROM'; ITERATE: 'ITERATE'; JOIN: 'JOIN'; KEY: 'KEY'; diff --git a/fdb-relational-core/src/main/antlr/RelationalParser.g4 b/fdb-relational-core/src/main/antlr/RelationalParser.g4 index 85a9435fdd..292f9377c1 100644 --- a/fdb-relational-core/src/main/antlr/RelationalParser.g4 +++ b/fdb-relational-core/src/main/antlr/RelationalParser.g4 @@ -1163,6 +1163,7 @@ unaryOperator comparisonOperator : '=' | '>' | '<' | '<' '=' | '>' '=' | '<' '>' | '!' '=' // | '<' '=' '>' // no support for null-safe equality + | IS_DISTINCT_FROM | IS_NOT_DISTINCT_FROM ; logicalOperator diff --git a/fdb-relational-core/src/main/java/com/apple/foundationdb/relational/recordlayer/query/functions/SqlFunctionCatalogImpl.java b/fdb-relational-core/src/main/java/com/apple/foundationdb/relational/recordlayer/query/functions/SqlFunctionCatalogImpl.java index c2badb4fae..9063d4799c 100644 --- a/fdb-relational-core/src/main/java/com/apple/foundationdb/relational/recordlayer/query/functions/SqlFunctionCatalogImpl.java +++ b/fdb-relational-core/src/main/java/com/apple/foundationdb/relational/recordlayer/query/functions/SqlFunctionCatalogImpl.java @@ -77,6 +77,8 @@ public CatalogedFunction lookupFunction(@Nonnull final String name, @Nonnull fin private Optional lookupBuiltInFunction(@Nonnull final String name, @Nonnull final Expressions expressions) { final var functionValidator = builtInSynonyms.get(name.toLowerCase(Locale.ROOT)); + System.out.println("builtInSynonyms:" + builtInSynonyms.keySet()); + System.out.println("name lowercase:" + name.toLowerCase(Locale.ROOT) + "name in builtInSynonyms keyset:" + builtInSynonyms.keySet().contains(name.toLowerCase(Locale.ROOT))); if (functionValidator == null) { return Optional.empty(); } @@ -145,6 +147,7 @@ private static ImmutableMap BuiltInFunctionCatalog.resolve("coalesce", argumentsCount)) .put("is null", argumentsCount -> BuiltInFunctionCatalog.resolve("isNull", argumentsCount)) .put("is not null", argumentsCount -> BuiltInFunctionCatalog.resolve("notNull", argumentsCount)) + .put("is not distinct from", argumentsCount -> BuiltInFunctionCatalog.resolve("notDistinctFrom", argumentsCount)) .put("range", argumentsCount -> BuiltInFunctionCatalog.resolve("range", argumentsCount)) .put("__pattern_for_like", argumentsCount -> BuiltInFunctionCatalog.resolve("patternForLike", argumentsCount)) .put("__internal_array", argumentsCount -> BuiltInFunctionCatalog.resolve("array", argumentsCount)) diff --git a/fdb-relational-core/src/test/java/com/apple/foundationdb/relational/recordlayer/query/StandardQueryTests.java b/fdb-relational-core/src/test/java/com/apple/foundationdb/relational/recordlayer/query/StandardQueryTests.java index 61000544f7..f4a99ecb0c 100644 --- a/fdb-relational-core/src/test/java/com/apple/foundationdb/relational/recordlayer/query/StandardQueryTests.java +++ b/fdb-relational-core/src/test/java/com/apple/foundationdb/relational/recordlayer/query/StandardQueryTests.java @@ -881,6 +881,79 @@ void aliasingTableToResolveAmbiguityWorks() throws Exception { } } + @Test + void testNotDistinctFrom() throws Exception { + final String schema = "CREATE TYPE AS STRUCT contact_detail(phone_number string, address string) " + + "CREATE TABLE student(id bigint, name string, contact contact_detail, score bigint, primary key(id))"; + try (var ddl = Ddl.builder().database(URI.create("/TEST/QT")).relationalExtension(relationalExtension).schemaTemplate(schema).build()) { + try (var statement = ddl.setSchemaAndGetConnection().createStatement()) { + final var row1 = EmbeddedRelationalStruct.newBuilder() + .addLong("ID", 1L) + .addString("NAME", "Alice") + .addLong("SCORE", 100) + .build(); + final var row2 = EmbeddedRelationalStruct.newBuilder() + .addLong("ID", 2L) + .addString("NAME", "Bob") + .build(); + Assertions.assertEquals(1, statement.executeInsert("STUDENT", row1), "Incorrect insertion count"); + Assertions.assertEquals(1, statement.executeInsert("STUDENT", row2), "Incorrect insertion count"); + + Assertions.assertTrue(statement.execute("SELECT * from STUDENT f WHERE score is not distinct from null"), "Did not return a result set from a select statement!"); + try (final RelationalResultSet resultSet = statement.getResultSet()) { + ResultSetAssert.assertThat(resultSet) + .hasNextRow() + .hasColumn("NAME", "Bob") + .hasNoNextRow(); + } + + Assertions.assertTrue(statement.execute("SELECT * from STUDENT f WHERE score is not distinct from 100"), "Did not return a result set from a select statement!"); + try (final RelationalResultSet resultSet = statement.getResultSet()) { + ResultSetAssert.assertThat(resultSet) + .hasNextRow() + .hasColumn("NAME", "Alice") + .hasNoNextRow(); + } + + Assertions.assertTrue(statement.execute("SELECT * from STUDENT f WHERE null is not distinct from score"), "Did not return a result set from a select statement!"); + try (final RelationalResultSet resultSet = statement.getResultSet()) { + ResultSetAssert.assertThat(resultSet) + .hasNextRow() + .hasColumn("NAME", "Bob") + .hasNoNextRow(); + } + + Assertions.assertTrue(statement.execute("SELECT * from STUDENT f WHERE 100 is not distinct from score"), "Did not return a result set from a select statement!"); + try (final RelationalResultSet resultSet = statement.getResultSet()) { + ResultSetAssert.assertThat(resultSet) + .hasNextRow() + .hasColumn("NAME", "Alice") + .hasNoNextRow(); + } + + Assertions.assertTrue(statement.execute("SELECT * from STUDENT f WHERE 100 is not distinct from 100"), "Did not return a result set from a select statement!"); + try (final RelationalResultSet resultSet = statement.getResultSet()) { + ResultSetAssert.assertThat(resultSet) + .hasNextRow() + .hasColumn("NAME", "Alice") + .hasNextRow() + .hasColumn("NAME", "Bob") + .hasNoNextRow(); + } + + Assertions.assertTrue(statement.execute("SELECT * from STUDENT f WHERE null is not distinct from null"), "Did not return a result set from a select statement!"); + try (final RelationalResultSet resultSet = statement.getResultSet()) { + ResultSetAssert.assertThat(resultSet) + .hasNextRow() + .hasColumn("NAME", "Alice") + .hasNextRow() + .hasColumn("NAME", "Bob") + .hasNoNextRow(); + } + } + } + } + @Test void testBitmap() throws Exception { final String query = "SELECT BITMAP_CONSTRUCT_AGG(BITMAP_BIT_POSITION(uid)) as bitmap, category, BITMAP_BUCKET_OFFSET(uid) as offset FROM T1\n" + From fc8bbde071eddf17168993b20b38bfb9f1f61481 Mon Sep 17 00:00:00 2001 From: Pengpeng Lu Date: Fri, 16 May 2025 11:53:34 -0700 Subject: [PATCH 02/16] is distinct from --- .../record/query/expressions/Comparisons.java | 55 ++++---- .../cascades/predicates/RangeConstraints.java | 1 + .../plan/cascades/values/RelOpValue.java | 128 ++++++++++++++---- .../src/main/proto/record_query_plan.proto | 98 ++++++++++++++ .../functions/SqlFunctionCatalogImpl.java | 3 +- .../recordlayer/query/StandardQueryTests.java | 65 +++++++++ 6 files changed, 299 insertions(+), 51 deletions(-) diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/expressions/Comparisons.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/expressions/Comparisons.java index a6452e65a3..4b0e382c44 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/expressions/Comparisons.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/expressions/Comparisons.java @@ -234,30 +234,15 @@ public static Object toClassWithRealEquals(@Nullable Object obj) { @SuppressWarnings("unchecked") public static int compare(@Nullable Object fieldValue, @Nullable Object comparand) { - if (fieldValue == null) { - if (comparand == null) { - return 0; - } else { - return -1; - } - } else if (comparand == null) { - return 1; - } else { - return toComparable(fieldValue).compareTo(toComparable(comparand)); - } + return toComparable(fieldValue).compareTo(toComparable(comparand)); } - @Nullable @SpotBugsSuppressWarnings("NP_BOOLEAN_RETURN_NULL") - private static Boolean compareEquals(Object value, Object comparand) { - if (value == null || comparand == null) { - return null; + private static boolean compareEquals(@Nonnull Object value, @Nonnull Object comparand) { + if (value instanceof Message) { + return MessageHelpers.compareMessageEquals(value, comparand); } else { - if (value instanceof Message) { - return MessageHelpers.compareMessageEquals(value, comparand); - } else { - return toClassWithRealEquals(value).equals(toClassWithRealEquals(comparand)); - } + return toClassWithRealEquals(value).equals(toClassWithRealEquals(comparand)); } } @@ -301,6 +286,9 @@ private static Boolean compareStartsWith(@Nullable Object value, @Nullable Objec @Nullable @SpotBugsSuppressWarnings("NP_BOOLEAN_RETURN_NULL") private static Boolean compareLike(@Nullable Object value, @Nullable Object pattern) { + if (value == null) { + return null; + } if (!(value instanceof String)) { throw new RecordCoreException("Illegal comparand value type: " + value); } @@ -639,7 +627,6 @@ public enum Type { STARTS_WITH, NOT_NULL(false, true), IS_NULL(true, true), - NOT_DISTINCT_FROM(false), IN, TEXT_CONTAINS_ALL(true), TEXT_CONTAINS_ALL_WITHIN(true), @@ -651,7 +638,9 @@ public enum Type { @API(API.Status.EXPERIMENTAL) SORT(false), @API(API.Status.EXPERIMENTAL) - LIKE; + LIKE, + IS_DISTINCT_FROM(true), + NOT_DISTINCT_FROM(false); @Nonnull private static final Supplier> protoEnumBiMapSupplier = @@ -724,30 +713,44 @@ public static Type invertComparisonType(@Nonnull final Comparisons.Type type) { @Nullable @SpotBugsSuppressWarnings("NP_BOOLEAN_RETURN_NULL") public static Boolean evalComparison(@Nonnull Type type, @Nullable Object value, @Nullable Object comparand) { - if (value == null) { - return null; - } switch (type) { case STARTS_WITH: return compareStartsWith(value, comparand); case IN: return compareIn(value, comparand); case EQUALS: + if (value == null || comparand == null) { + return null; + } return compareEquals(value, comparand); case NOT_EQUALS: - if (comparand == null) { + if (value == null || comparand == null) { return null; } return !compareEquals(value, comparand); + case IS_DISTINCT_FROM: + return !compareNotDistinctFrom(value, comparand); case NOT_DISTINCT_FROM: return compareNotDistinctFrom(value, comparand); case LESS_THAN: + if (value == null || comparand == null) { + return null; + } return compare(value, comparand) < 0; case LESS_THAN_OR_EQUALS: + if (value == null || comparand == null) { + return null; + } return compare(value, comparand) <= 0; case GREATER_THAN: + if (value == null || comparand == null) { + return null; + } return compare(value, comparand) > 0; case GREATER_THAN_OR_EQUALS: + if (value == null || comparand == null) { + return null; + } return compare(value, comparand) >= 0; case LIKE: return compareLike(value, comparand); diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/RangeConstraints.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/RangeConstraints.java index 996f3ace89..48ab55977b 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/RangeConstraints.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/predicates/RangeConstraints.java @@ -730,6 +730,7 @@ private boolean canBeUsedInScanPrefix(@Nonnull final Comparisons.Comparison comp case NOT_NULL: case IS_NULL: case NOT_DISTINCT_FROM: + case IS_DISTINCT_FROM: return true; case TEXT_CONTAINS_ALL: case TEXT_CONTAINS_ALL_WITHIN: diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/RelOpValue.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/RelOpValue.java index 5df2099c67..8b032dda78 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/RelOpValue.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/RelOpValue.java @@ -184,8 +184,12 @@ private static Optional promoteOperandsAndCreatePredicate(@Nulla @Nonnull Value leftChild, @Nonnull Value rightChild, @Nonnull final Comparisons.Type comparisonType) { - if (leftChild.getResultType().getTypeCode() == Type.TypeCode.NULL && rightChild.getResultType().getTypeCode() == Type.TypeCode.NULL && comparisonType == Comparisons.Type.NOT_DISTINCT_FROM) { - return Optional.of(ConstantPredicate.TRUE); + if (leftChild.getResultType().getTypeCode() == Type.TypeCode.NULL && rightChild.getResultType().getTypeCode() == Type.TypeCode.NULL) { + if (comparisonType == Comparisons.Type.NOT_DISTINCT_FROM) { + return Optional.of(ConstantPredicate.TRUE); + } else if (comparisonType == Comparisons.Type.IS_DISTINCT_FROM) { + return Optional.of(ConstantPredicate.FALSE); + } } // maximumType may return null, but only for non-primitive types which is not possible here final var maxtype = Verify.verifyNotNull(Type.maximumType(leftChild.getResultType(), rightChild.getResultType())); @@ -259,6 +263,7 @@ private static Comparisons.Type swapBinaryComparisonOperator(@Nonnull Comparison case EQUALS: case NOT_EQUALS: case NOT_DISTINCT_FROM: + case IS_DISTINCT_FROM: return type; case LESS_THAN: return Comparisons.Type.GREATER_THAN; @@ -294,6 +299,13 @@ private static Value encapsulate(@Nonnull final String functionName, } else { final Typed arg1 = arguments.get(1); final Type res1 = arg1.getResultType(); + if (functionName.equals("isDistinctFrom")) { + if (res0.getTypeCode() == Type.TypeCode.NULL && res1.getTypeCode() != Type.TypeCode.NULL) { + return encapsulate("notNull", Comparisons.Type.NOT_NULL, List.of(arg1)); + } else if (res1.getTypeCode() == Type.TypeCode.NULL && res0.getTypeCode() != Type.TypeCode.NULL) { + return encapsulate("notNull", Comparisons.Type.NOT_NULL, List.of(arg0)); + } + } if (functionName.equals("notDistinctFrom")) { if (res0.getTypeCode() == Type.TypeCode.NULL && res1.getTypeCode() != Type.TypeCode.NULL) { return encapsulate("isNull", Comparisons.Type.IS_NULL, List.of(arg1)); @@ -462,6 +474,21 @@ private static Value encapsulate(@Nonnull BuiltInFunction builtInFunction } } + /** + * The {@code isDistinctFrom} function. + */ + @AutoService(BuiltInFunction.class) + public static class IsDistinctFromFn extends BuiltInFunction { + public IsDistinctFromFn() { + super("isDistinctFrom", + List.of(new Type.Any(), new Type.Any()), IsDistinctFromFn::encapsulate); + } + + private static Value encapsulate(@Nonnull BuiltInFunction builtInFunction, @Nonnull final List arguments) { + return RelOpValue.encapsulate(builtInFunction.getFunctionName(), Comparisons.Type.IS_DISTINCT_FROM, arguments); + } + } + /** * The {@code notDistinctFrom} function. */ @@ -790,44 +817,99 @@ private enum BinaryPhysicalOperator { GTE_UID(Comparisons.Type.GREATER_THAN_OR_EQUALS, Type.TypeCode.UNKNOWN, Type.TypeCode.UUID, (l, r) -> null), GTE_IDU(Comparisons.Type.GREATER_THAN_OR_EQUALS, Type.TypeCode.UUID, Type.TypeCode.UNKNOWN, (l, r) -> null), - NOT_DISTINCT_FROM_BU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.BOOLEAN, Type.TypeCode.UNKNOWN, (l, r) -> null), + IS_DISTINCT_FROM_BU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.BOOLEAN, Type.TypeCode.UNKNOWN, (l, r) -> true), + IS_DISTINCT_FROM_BB(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.BOOLEAN, Type.TypeCode.BOOLEAN, (l, r) -> (boolean)l != (boolean)r), + IS_DISTINCT_FROM_IU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.INT, Type.TypeCode.UNKNOWN, (l, r) -> true), + IS_DISTINCT_FROM_II(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.INT, Type.TypeCode.INT, (l, r) -> (int)l != (int)r), + IS_DISTINCT_FROM_IL(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.INT, Type.TypeCode.LONG, (l, r) -> (int)l != (long)r), + IS_DISTINCT_FROM_IF(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.INT, Type.TypeCode.FLOAT, (l, r) -> (int)l != (float)r), + IS_DISTINCT_FROM_ID(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.INT, Type.TypeCode.DOUBLE, (l, r) -> (int)l != (double)r), + IS_DISTINCT_FROM_LU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.LONG, Type.TypeCode.UNKNOWN, (l, r) -> true), + IS_DISTINCT_FROM_LI(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.LONG, Type.TypeCode.INT, (l, r) -> (long)l != (int)r), + IS_DISTINCT_FROM_LL(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.LONG, Type.TypeCode.LONG, (l, r) -> (long)l != (long)r), + IS_DISTINCT_FROM_LF(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.LONG, Type.TypeCode.FLOAT, (l, r) -> (long)l != (float)r), + IS_DISTINCT_FROM_LD(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.LONG, Type.TypeCode.DOUBLE, (l, r) -> (long)l != (double)r), + IS_DISTINCT_FROM_FU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.FLOAT, Type.TypeCode.UNKNOWN, (l, r) -> true), + IS_DISTINCT_FROM_FI(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.FLOAT, Type.TypeCode.INT, (l, r) -> (float)l != (int)r), + IS_DISTINCT_FROM_FL(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.FLOAT, Type.TypeCode.LONG, (l, r) -> (float)l != (long)r), + IS_DISTINCT_FROM_FF(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.FLOAT, Type.TypeCode.FLOAT, (l, r) -> (float)l != (float)r), + IS_DISTINCT_FROM_FD(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.FLOAT, Type.TypeCode.DOUBLE, (l, r) -> (float)l != (double)r), + IS_DISTINCT_FROM_DU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.DOUBLE, Type.TypeCode.UNKNOWN, (l, r) -> true), + IS_DISTINCT_FROM_DI(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.DOUBLE, Type.TypeCode.INT, (l, r) -> (double)l != (int)r), + IS_DISTINCT_FROM_DL(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.DOUBLE, Type.TypeCode.LONG, (l, r) -> (double)l != (long)r), + IS_DISTINCT_FROM_DF(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.DOUBLE, Type.TypeCode.FLOAT, (l, r) -> (double)l != (float)r), + IS_DISTINCT_FROM_DD(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.DOUBLE, Type.TypeCode.DOUBLE, (l, r) -> (double)l != (double)r), + IS_DISTINCT_FROM_SU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.STRING, Type.TypeCode.UNKNOWN, (l, r) -> true), + IS_DISTINCT_FROM_SS(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.STRING, Type.TypeCode.STRING, (l, r) -> !l.equals(r)), // TODO: locale-aware comparison + IS_DISTINCT_FROM_UU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.UNKNOWN, (l, r) -> false), + IS_DISTINCT_FROM_UB(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.BOOLEAN, (l, r) -> true), + IS_DISTINCT_FROM_UI(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.INT, (l, r) -> true), + IS_DISTINCT_FROM_UL(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.LONG, (l, r) -> true), + IS_DISTINCT_FROM_UF(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.FLOAT, (l, r) -> true), + IS_DISTINCT_FROM_UD(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.DOUBLE, (l, r) -> true), + IS_DISTINCT_FROM_US(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.STRING, (l, r) -> true), + IS_DISTINCT_FROM_UV(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.VERSION, (l, r) -> true), + IS_DISTINCT_FROM_VU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.VERSION, Type.TypeCode.UNKNOWN, (l, r) -> null), + IS_DISTINCT_FROM_VV(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.VERSION, Type.TypeCode.VERSION, (l, r) -> !l.equals(r)), + IS_DISTINCT_FROM_BYU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.BYTES, Type.TypeCode.UNKNOWN, (l, r) -> null), + IS_DISTINCT_FROM_BYBY(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.BYTES, Type.TypeCode.BYTES, (l, r) -> Comparisons.evalComparison(Comparisons.Type.IS_DISTINCT_FROM, l, r)), + IS_DISTINCT_FROM_UBY(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.BYTES, (l, r) -> true), + IS_DISTINCT_FROM_EE(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.ENUM, Type.TypeCode.ENUM, (l, r) -> Comparisons.evalComparison(Comparisons.Type.IS_DISTINCT_FROM, l, r)), + IS_DISTINCT_FROM_ES(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.ENUM, Type.TypeCode.STRING, (l, r) -> { + final var otherValue = PromoteValue.PhysicalOperator.stringToEnumValue(((Descriptors.EnumValueDescriptor) l).getType(), (String) r); + return Comparisons.evalComparison(Comparisons.Type.IS_DISTINCT_FROM, l, otherValue); + }), + IS_DISTINCT_FROM_SE(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.STRING, Type.TypeCode.ENUM, (l, r) -> { + final var otherValue = PromoteValue.PhysicalOperator.stringToEnumValue(((Descriptors.EnumValueDescriptor) r).getType(), (String) l); + return Comparisons.evalComparison(Comparisons.Type.EQUALS, otherValue, r); + }), + IS_DISTINCT_FROM_EU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.ENUM, Type.TypeCode.UNKNOWN, (l, r) -> true), + IS_DISTINCT_FROM_UE(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.ENUM, (l, r) -> true), + IS_DISTINCT_FROM_IDID(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.UUID, Type.TypeCode.UUID, (l, r) -> Comparisons.evalComparison(Comparisons.Type.IS_DISTINCT_FROM, l, r)), + IS_DISTINCT_FROM_IDS(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.UUID, Type.TypeCode.STRING, (l, r) -> Comparisons.evalComparison(Comparisons.Type.IS_DISTINCT_FROM, l, PromoteValue.PhysicalOperator.stringToUuidValue((String) r))), + IS_DISTINCT_FROM_SID(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.STRING, Type.TypeCode.UUID, (l, r) -> Comparisons.evalComparison(Comparisons.Type.IS_DISTINCT_FROM, PromoteValue.PhysicalOperator.stringToUuidValue((String) l), r)), + IS_DISTINCT_FROM_UID(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.UUID, (l, r) -> true), + IS_DISTINCT_FROM_IDU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.UUID, Type.TypeCode.UNKNOWN, (l, r) -> true), + IS_DISTINCT_FROM_NN(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.NULL, (l, r) -> false), + + NOT_DISTINCT_FROM_BU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.BOOLEAN, Type.TypeCode.UNKNOWN, (l, r) -> false), NOT_DISTINCT_FROM_BB(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.BOOLEAN, Type.TypeCode.BOOLEAN, (l, r) -> (boolean)l == (boolean)r), - NOT_DISTINCT_FROM_IU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.INT, Type.TypeCode.UNKNOWN, (l, r) -> null), + NOT_DISTINCT_FROM_IU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.INT, Type.TypeCode.UNKNOWN, (l, r) -> false), NOT_DISTINCT_FROM_II(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.INT, Type.TypeCode.INT, (l, r) -> (int)l == (int)r), NOT_DISTINCT_FROM_IL(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.INT, Type.TypeCode.LONG, (l, r) -> (int)l == (long)r), NOT_DISTINCT_FROM_IF(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.INT, Type.TypeCode.FLOAT, (l, r) -> (int)l == (float)r), NOT_DISTINCT_FROM_ID(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.INT, Type.TypeCode.DOUBLE, (l, r) -> (int)l == (double)r), - NOT_DISTINCT_FROM_LU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.LONG, Type.TypeCode.UNKNOWN, (l, r) -> null), + NOT_DISTINCT_FROM_LU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.LONG, Type.TypeCode.UNKNOWN, (l, r) -> false), NOT_DISTINCT_FROM_LI(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.LONG, Type.TypeCode.INT, (l, r) -> (long)l == (int)r), NOT_DISTINCT_FROM_LL(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.LONG, Type.TypeCode.LONG, (l, r) -> (long)l == (long)r), NOT_DISTINCT_FROM_LF(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.LONG, Type.TypeCode.FLOAT, (l, r) -> (long)l == (float)r), NOT_DISTINCT_FROM_LD(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.LONG, Type.TypeCode.DOUBLE, (l, r) -> (long)l == (double)r), - NOT_DISTINCT_FROM_FU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.FLOAT, Type.TypeCode.UNKNOWN, (l, r) -> null), + NOT_DISTINCT_FROM_FU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.FLOAT, Type.TypeCode.UNKNOWN, (l, r) -> false), NOT_DISTINCT_FROM_FI(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.FLOAT, Type.TypeCode.INT, (l, r) -> (float)l == (int)r), NOT_DISTINCT_FROM_FL(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.FLOAT, Type.TypeCode.LONG, (l, r) -> (float)l == (long)r), NOT_DISTINCT_FROM_FF(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.FLOAT, Type.TypeCode.FLOAT, (l, r) -> (float)l == (float)r), NOT_DISTINCT_FROM_FD(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.FLOAT, Type.TypeCode.DOUBLE, (l, r) -> (float)l == (double)r), - NOT_DISTINCT_FROM_DU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.DOUBLE, Type.TypeCode.UNKNOWN, (l, r) -> null), + NOT_DISTINCT_FROM_DU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.DOUBLE, Type.TypeCode.UNKNOWN, (l, r) -> false), NOT_DISTINCT_FROM_DI(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.DOUBLE, Type.TypeCode.INT, (l, r) -> (double)l == (int)r), NOT_DISTINCT_FROM_DL(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.DOUBLE, Type.TypeCode.LONG, (l, r) -> (double)l == (long)r), NOT_DISTINCT_FROM_DF(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.DOUBLE, Type.TypeCode.FLOAT, (l, r) -> (double)l == (float)r), NOT_DISTINCT_FROM_DD(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.DOUBLE, Type.TypeCode.DOUBLE, (l, r) -> (double)l == (double)r), - NOT_DISTINCT_FROM_SU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.STRING, Type.TypeCode.UNKNOWN, (l, r) -> null), + NOT_DISTINCT_FROM_SU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.STRING, Type.TypeCode.UNKNOWN, (l, r) -> false), NOT_DISTINCT_FROM_SS(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.STRING, Type.TypeCode.STRING, Object::equals), // TODO: locale-aware comparison - NOT_DISTINCT_FROM_UU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.UNKNOWN, (l, r) -> null), - NOT_DISTINCT_FROM_UB(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.BOOLEAN, (l, r) -> null), - NOT_DISTINCT_FROM_UI(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.INT, (l, r) -> null), - NOT_DISTINCT_FROM_UL(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.LONG, (l, r) -> null), - NOT_DISTINCT_FROM_UF(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.FLOAT, (l, r) -> null), - NOT_DISTINCT_FROM_UD(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.DOUBLE, (l, r) -> null), - NOT_DISTINCT_FROM_US(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.STRING, (l, r) -> null), - NOT_DISTINCT_FROM_UV(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.VERSION, (l, r) -> null), - NOT_DISTINCT_FROM_VU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.VERSION, Type.TypeCode.UNKNOWN, (l, r) -> null), + NOT_DISTINCT_FROM_UU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.UNKNOWN, (l, r) -> true), + NOT_DISTINCT_FROM_UB(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.BOOLEAN, (l, r) -> false), + NOT_DISTINCT_FROM_UI(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.INT, (l, r) -> false), + NOT_DISTINCT_FROM_UL(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.LONG, (l, r) -> false), + NOT_DISTINCT_FROM_UF(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.FLOAT, (l, r) -> false), + NOT_DISTINCT_FROM_UD(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.DOUBLE, (l, r) -> false), + NOT_DISTINCT_FROM_US(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.STRING, (l, r) -> false), + NOT_DISTINCT_FROM_UV(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.VERSION, (l, r) -> false), + NOT_DISTINCT_FROM_VU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.VERSION, Type.TypeCode.UNKNOWN, (l, r) -> false), NOT_DISTINCT_FROM_VV(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.VERSION, Type.TypeCode.VERSION, Object::equals), - NOT_DISTINCT_FROM_BYU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.BYTES, Type.TypeCode.UNKNOWN, (l, r) -> null), + NOT_DISTINCT_FROM_BYU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.BYTES, Type.TypeCode.UNKNOWN, (l, r) -> false), NOT_DISTINCT_FROM_BYBY(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.BYTES, Type.TypeCode.BYTES, (l, r) -> Comparisons.evalComparison(Comparisons.Type.NOT_DISTINCT_FROM, l, r)), - NOT_DISTINCT_FROM_UBY(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.BYTES, (l, r) -> null), + NOT_DISTINCT_FROM_UBY(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.BYTES, (l, r) -> false), NOT_DISTINCT_FROM_EE(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.ENUM, Type.TypeCode.ENUM, (l, r) -> Comparisons.evalComparison(Comparisons.Type.NOT_DISTINCT_FROM, l, r)), NOT_DISTINCT_FROM_ES(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.ENUM, Type.TypeCode.STRING, (l, r) -> { @@ -838,14 +920,14 @@ private enum BinaryPhysicalOperator { final var otherValue = PromoteValue.PhysicalOperator.stringToEnumValue(((Descriptors.EnumValueDescriptor) r).getType(), (String) l); return Comparisons.evalComparison(Comparisons.Type.NOT_DISTINCT_FROM, otherValue, r); }), - NOT_DISTINCT_FROM_EU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.ENUM, Type.TypeCode.UNKNOWN, (l, r) -> null), - NOT_DISTINCT_FROM_UE(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.ENUM, (l, r) -> null), + NOT_DISTINCT_FROM_EU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.ENUM, Type.TypeCode.UNKNOWN, (l, r) -> false), + NOT_DISTINCT_FROM_UE(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.ENUM, (l, r) -> false), NOT_DISTINCT_FROM_IDID(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UUID, Type.TypeCode.UUID, (l, r) -> Comparisons.evalComparison(Comparisons.Type.NOT_DISTINCT_FROM, l, r)), NOT_DISTINCT_FROM_IDS(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UUID, Type.TypeCode.STRING, (l, r) -> Comparisons.evalComparison(Comparisons.Type.NOT_DISTINCT_FROM, l, PromoteValue.PhysicalOperator.stringToUuidValue((String) r))), NOT_DISTINCT_FROM_SID(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.STRING, Type.TypeCode.UUID, (l, r) -> Comparisons.evalComparison(Comparisons.Type.NOT_DISTINCT_FROM, PromoteValue.PhysicalOperator.stringToUuidValue((String) l), r)), - NOT_DISTINCT_FROM_UID(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.UUID, (l, r) -> null), - NOT_DISTINCT_FROM_IDU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UUID, Type.TypeCode.UNKNOWN, (l, r) -> null), + NOT_DISTINCT_FROM_UID(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.UUID, (l, r) -> false), + NOT_DISTINCT_FROM_IDU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UUID, Type.TypeCode.UNKNOWN, (l, r) -> false), NOT_DISTINCT_FROM_NN(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.NULL, (l, r) -> true), diff --git a/fdb-record-layer-core/src/main/proto/record_query_plan.proto b/fdb-record-layer-core/src/main/proto/record_query_plan.proto index 33bcf47d8c..86f779fce7 100644 --- a/fdb-record-layer-core/src/main/proto/record_query_plan.proto +++ b/fdb-record-layer-core/src/main/proto/record_query_plan.proto @@ -918,6 +918,102 @@ message PBinaryRelOpValue { GTE_SID = 268; GTE_UID = 269; GTE_IDU = 270; + IS_DISTINCT_FROM_BU = 271; + IS_DISTINCT_FROM_BB = 272; + IS_DISTINCT_FROM_IU = 273; + IS_DISTINCT_FROM_II = 274; + IS_DISTINCT_FROM_IL = 275; + IS_DISTINCT_FROM_IF = 276; + IS_DISTINCT_FROM_ID = 277; + IS_DISTINCT_FROM_LU = 278; + IS_DISTINCT_FROM_LI = 279; + IS_DISTINCT_FROM_LL = 280; + IS_DISTINCT_FROM_LF = 281; + IS_DISTINCT_FROM_LD = 282; + IS_DISTINCT_FROM_FU = 283; + IS_DISTINCT_FROM_FI = 284; + IS_DISTINCT_FROM_FL = 285; + IS_DISTINCT_FROM_FF = 286; + IS_DISTINCT_FROM_FD = 287; + IS_DISTINCT_FROM_DU = 288; + IS_DISTINCT_FROM_DI = 289; + IS_DISTINCT_FROM_DL = 290; + IS_DISTINCT_FROM_DF = 291; + IS_DISTINCT_FROM_DD = 292; + IS_DISTINCT_FROM_SU = 293; + IS_DISTINCT_FROM_SS = 294; + IS_DISTINCT_FROM_UU = 295; + IS_DISTINCT_FROM_UB = 296; + IS_DISTINCT_FROM_UI = 297; + IS_DISTINCT_FROM_UL = 298; + IS_DISTINCT_FROM_UF = 299; + IS_DISTINCT_FROM_UD = 300; + IS_DISTINCT_FROM_US = 301; + IS_DISTINCT_FROM_UV = 302; + IS_DISTINCT_FROM_VU = 303; + IS_DISTINCT_FROM_VV = 304; + IS_DISTINCT_FROM_BYU = 305; + IS_DISTINCT_FROM_BYBY = 306; + IS_DISTINCT_FROM_UBY = 307; + IS_DISTINCT_FROM_EE = 308; + IS_DISTINCT_FROM_ES = 309; + IS_DISTINCT_FROM_SE = 310; + IS_DISTINCT_FROM_EU = 311; + IS_DISTINCT_FROM_UE = 312; + IS_DISTINCT_FROM_IDID = 313; + IS_DISTINCT_FROM_IDS = 314; + IS_DISTINCT_FROM_SID = 315; + IS_DISTINCT_FROM_UID = 316; + IS_DISTINCT_FROM_IDU = 317; + IS_DISTINCT_FROM_NN = 318; + NOT_DISTINCT_FROM_BU = 319; + NOT_DISTINCT_FROM_BB = 320; + NOT_DISTINCT_FROM_IU = 321; + NOT_DISTINCT_FROM_II = 322; + NOT_DISTINCT_FROM_IL = 323; + NOT_DISTINCT_FROM_IF = 324; + NOT_DISTINCT_FROM_ID = 325; + NOT_DISTINCT_FROM_LU = 326; + NOT_DISTINCT_FROM_LI = 327; + NOT_DISTINCT_FROM_LL = 328; + NOT_DISTINCT_FROM_LF = 329; + NOT_DISTINCT_FROM_LD = 330; + NOT_DISTINCT_FROM_FU = 331; + NOT_DISTINCT_FROM_FI = 332; + NOT_DISTINCT_FROM_FL = 333; + NOT_DISTINCT_FROM_FF = 334; + NOT_DISTINCT_FROM_FD = 335; + NOT_DISTINCT_FROM_DU = 336; + NOT_DISTINCT_FROM_DI = 337; + NOT_DISTINCT_FROM_DL = 338; + NOT_DISTINCT_FROM_DF = 339; + NOT_DISTINCT_FROM_DD = 340; + NOT_DISTINCT_FROM_SU = 341; + NOT_DISTINCT_FROM_SS = 342; + NOT_DISTINCT_FROM_UU = 343; + NOT_DISTINCT_FROM_UB = 344; + NOT_DISTINCT_FROM_UI = 345; + NOT_DISTINCT_FROM_UL = 346; + NOT_DISTINCT_FROM_UF = 347; + NOT_DISTINCT_FROM_UD = 348; + NOT_DISTINCT_FROM_US = 349; + NOT_DISTINCT_FROM_UV = 350; + NOT_DISTINCT_FROM_VU = 351; + NOT_DISTINCT_FROM_VV = 352; + NOT_DISTINCT_FROM_BYU = 353; + NOT_DISTINCT_FROM_BYBY = 354; + NOT_DISTINCT_FROM_UBY = 355; + NOT_DISTINCT_FROM_EE = 356; + NOT_DISTINCT_FROM_ES = 357; + NOT_DISTINCT_FROM_SE = 358; + NOT_DISTINCT_FROM_EU = 359; + NOT_DISTINCT_FROM_UE = 360; + NOT_DISTINCT_FROM_IDID = 361; + NOT_DISTINCT_FROM_IDS = 362; + NOT_DISTINCT_FROM_SID = 363; + NOT_DISTINCT_FROM_UID = 364; + NOT_DISTINCT_FROM_IDU = 365; + NOT_DISTINCT_FROM_NN = 366; } optional PRelOpValue super = 1; optional PBinaryPhysicalOperator operator = 2; @@ -1042,6 +1138,8 @@ message PComparison { TEXT_CONTAINS_ANY_PREFIX = 17; SORT = 18; LIKE = 19; + IS_DISTINCT_FROM = 20; + NOT_DISTINCT_FROM = 21; } extensions 5000 to max; diff --git a/fdb-relational-core/src/main/java/com/apple/foundationdb/relational/recordlayer/query/functions/SqlFunctionCatalogImpl.java b/fdb-relational-core/src/main/java/com/apple/foundationdb/relational/recordlayer/query/functions/SqlFunctionCatalogImpl.java index 9063d4799c..6bfa3ecd09 100644 --- a/fdb-relational-core/src/main/java/com/apple/foundationdb/relational/recordlayer/query/functions/SqlFunctionCatalogImpl.java +++ b/fdb-relational-core/src/main/java/com/apple/foundationdb/relational/recordlayer/query/functions/SqlFunctionCatalogImpl.java @@ -77,8 +77,6 @@ public CatalogedFunction lookupFunction(@Nonnull final String name, @Nonnull fin private Optional lookupBuiltInFunction(@Nonnull final String name, @Nonnull final Expressions expressions) { final var functionValidator = builtInSynonyms.get(name.toLowerCase(Locale.ROOT)); - System.out.println("builtInSynonyms:" + builtInSynonyms.keySet()); - System.out.println("name lowercase:" + name.toLowerCase(Locale.ROOT) + "name in builtInSynonyms keyset:" + builtInSynonyms.keySet().contains(name.toLowerCase(Locale.ROOT))); if (functionValidator == null) { return Optional.empty(); } @@ -147,6 +145,7 @@ private static ImmutableMap BuiltInFunctionCatalog.resolve("coalesce", argumentsCount)) .put("is null", argumentsCount -> BuiltInFunctionCatalog.resolve("isNull", argumentsCount)) .put("is not null", argumentsCount -> BuiltInFunctionCatalog.resolve("notNull", argumentsCount)) + .put("is distinct from", argumentsCount -> BuiltInFunctionCatalog.resolve("isDistinctFrom", argumentsCount)) .put("is not distinct from", argumentsCount -> BuiltInFunctionCatalog.resolve("notDistinctFrom", argumentsCount)) .put("range", argumentsCount -> BuiltInFunctionCatalog.resolve("range", argumentsCount)) .put("__pattern_for_like", argumentsCount -> BuiltInFunctionCatalog.resolve("patternForLike", argumentsCount)) diff --git a/fdb-relational-core/src/test/java/com/apple/foundationdb/relational/recordlayer/query/StandardQueryTests.java b/fdb-relational-core/src/test/java/com/apple/foundationdb/relational/recordlayer/query/StandardQueryTests.java index f4a99ecb0c..bc878792b0 100644 --- a/fdb-relational-core/src/test/java/com/apple/foundationdb/relational/recordlayer/query/StandardQueryTests.java +++ b/fdb-relational-core/src/test/java/com/apple/foundationdb/relational/recordlayer/query/StandardQueryTests.java @@ -881,6 +881,71 @@ void aliasingTableToResolveAmbiguityWorks() throws Exception { } } + @Test + void testDistinctFrom() throws Exception { + final String schema = "CREATE TYPE AS STRUCT contact_detail(phone_number string, address string) " + + "CREATE TABLE student(id bigint, name string, contact contact_detail, score bigint, primary key(id))"; + try (var ddl = Ddl.builder().database(URI.create("/TEST/QT")).relationalExtension(relationalExtension).schemaTemplate(schema).build()) { + try (var statement = ddl.setSchemaAndGetConnection().createStatement()) { + final var row1 = EmbeddedRelationalStruct.newBuilder() + .addLong("ID", 1L) + .addString("NAME", "Alice") + .addLong("SCORE", 100) + .build(); + final var row2 = EmbeddedRelationalStruct.newBuilder() + .addLong("ID", 2L) + .addString("NAME", "Bob") + .build(); + Assertions.assertEquals(1, statement.executeInsert("STUDENT", row1), "Incorrect insertion count"); + Assertions.assertEquals(1, statement.executeInsert("STUDENT", row2), "Incorrect insertion count"); + + Assertions.assertTrue(statement.execute("SELECT * from STUDENT WHERE score is distinct from null"), "Did not return a result set from a select statement!"); + try (final RelationalResultSet resultSet = statement.getResultSet()) { + ResultSetAssert.assertThat(resultSet) + .hasNextRow() + .hasColumn("NAME", "Alice") + .hasNoNextRow(); + } + + Assertions.assertTrue(statement.execute("SELECT * from STUDENT WHERE score is distinct from 100"), "Did not return a result set from a select statement!"); + try (final RelationalResultSet resultSet = statement.getResultSet()) { + ResultSetAssert.assertThat(resultSet) + .hasNextRow() + .hasColumn("NAME", "Bob") + .hasNoNextRow(); + } + + Assertions.assertTrue(statement.execute("SELECT * from STUDENT f WHERE null is distinct from score"), "Did not return a result set from a select statement!"); + try (final RelationalResultSet resultSet = statement.getResultSet()) { + ResultSetAssert.assertThat(resultSet) + .hasNextRow() + .hasColumn("NAME", "Alice") + .hasNoNextRow(); + } + + Assertions.assertTrue(statement.execute("SELECT * from STUDENT f WHERE 100 is distinct from score"), "Did not return a result set from a select statement!"); + try (final RelationalResultSet resultSet = statement.getResultSet()) { + ResultSetAssert.assertThat(resultSet) + .hasNextRow() + .hasColumn("NAME", "Bob") + .hasNoNextRow(); + } + + Assertions.assertTrue(statement.execute("SELECT * from STUDENT f WHERE 100 is distinct from 100"), "Did not return a result set from a select statement!"); + try (final RelationalResultSet resultSet = statement.getResultSet()) { + ResultSetAssert.assertThat(resultSet) + .hasNoNextRow(); + } + + Assertions.assertTrue(statement.execute("SELECT * from STUDENT f WHERE null is distinct from null"), "Did not return a result set from a select statement!"); + try (final RelationalResultSet resultSet = statement.getResultSet()) { + ResultSetAssert.assertThat(resultSet) + .hasNoNextRow(); + } + } + } + } + @Test void testNotDistinctFrom() throws Exception { final String schema = "CREATE TYPE AS STRUCT contact_detail(phone_number string, address string) " + From bdedab971c96b3feb0a0e70951f6c4211a034afb Mon Sep 17 00:00:00 2001 From: Pengpeng Lu Date: Tue, 20 May 2025 11:43:06 -0700 Subject: [PATCH 03/16] fix test --- .../foundationdb/record/query/expressions/Comparisons.java | 3 +-- .../record/query/expressions/QueryExpressionTest.java | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/expressions/Comparisons.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/expressions/Comparisons.java index 4b0e382c44..ad76c585e7 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/expressions/Comparisons.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/expressions/Comparisons.java @@ -246,9 +246,8 @@ private static boolean compareEquals(@Nonnull Object value, @Nonnull Object comp } } - @Nullable @SpotBugsSuppressWarnings("NP_BOOLEAN_RETURN_NULL") - private static Boolean compareNotDistinctFrom(Object value, Object comparand) { + private static boolean compareNotDistinctFrom(Object value, Object comparand) { if (value == null && comparand == null) { return true; } else if (value == null || comparand == null) { diff --git a/fdb-record-layer-core/src/test/java/com/apple/foundationdb/record/query/expressions/QueryExpressionTest.java b/fdb-record-layer-core/src/test/java/com/apple/foundationdb/record/query/expressions/QueryExpressionTest.java index 899d9489a6..1b922a3a74 100644 --- a/fdb-record-layer-core/src/test/java/com/apple/foundationdb/record/query/expressions/QueryExpressionTest.java +++ b/fdb-record-layer-core/src/test/java/com/apple/foundationdb/record/query/expressions/QueryExpressionTest.java @@ -417,7 +417,7 @@ protected void testParameterComparison(String name, String field, Object val1, C final Bindings bindings = Bindings.newBuilder() .set("fooParam", val2) .build(); - if (val1 != null && val2 != null && (type == Comparisons.Type.IN && !(val2 instanceof List) || type.name().startsWith("TEXT_"))) { + if (val1 != null && val2 != null && (type == Comparisons.Type.IN && !(val2 instanceof List)) || type.name().startsWith("TEXT_")) { assertThrows(name, RecordCoreException.class, () -> evaluate(qc, bindings, rec)); } else { From 360d2386b32d941675a9634e2f68c9238b2c0073 Mon Sep 17 00:00:00 2001 From: Pengpeng Lu Date: Tue, 20 May 2025 12:26:13 -0700 Subject: [PATCH 04/16] pmd --- .../record/query/plan/cascades/values/RelOpValue.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/RelOpValue.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/RelOpValue.java index 8b032dda78..eebb3b7ac6 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/RelOpValue.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/RelOpValue.java @@ -299,14 +299,14 @@ private static Value encapsulate(@Nonnull final String functionName, } else { final Typed arg1 = arguments.get(1); final Type res1 = arg1.getResultType(); - if (functionName.equals("isDistinctFrom")) { + if ("isDistinctFrom".equals(functionName)) { if (res0.getTypeCode() == Type.TypeCode.NULL && res1.getTypeCode() != Type.TypeCode.NULL) { return encapsulate("notNull", Comparisons.Type.NOT_NULL, List.of(arg1)); } else if (res1.getTypeCode() == Type.TypeCode.NULL && res0.getTypeCode() != Type.TypeCode.NULL) { return encapsulate("notNull", Comparisons.Type.NOT_NULL, List.of(arg0)); } } - if (functionName.equals("notDistinctFrom")) { + if ("notDistinctFrom".equals(functionName)) { if (res0.getTypeCode() == Type.TypeCode.NULL && res1.getTypeCode() != Type.TypeCode.NULL) { return encapsulate("isNull", Comparisons.Type.IS_NULL, List.of(arg1)); } else if (res1.getTypeCode() == Type.TypeCode.NULL && res0.getTypeCode() != Type.TypeCode.NULL) { From db1f740e8b75faedb27d7fccfe2349bcc011b2cd Mon Sep 17 00:00:00 2001 From: Pengpeng Lu Date: Wed, 21 May 2025 11:17:32 -0700 Subject: [PATCH 05/16] add index matching test --- .../recordlayer/query/StandardQueryTests.java | 77 +++++++++++++++++-- 1 file changed, 71 insertions(+), 6 deletions(-) diff --git a/fdb-relational-core/src/test/java/com/apple/foundationdb/relational/recordlayer/query/StandardQueryTests.java b/fdb-relational-core/src/test/java/com/apple/foundationdb/relational/recordlayer/query/StandardQueryTests.java index bc878792b0..a04f2cac93 100644 --- a/fdb-relational-core/src/test/java/com/apple/foundationdb/relational/recordlayer/query/StandardQueryTests.java +++ b/fdb-relational-core/src/test/java/com/apple/foundationdb/relational/recordlayer/query/StandardQueryTests.java @@ -964,7 +964,7 @@ void testNotDistinctFrom() throws Exception { Assertions.assertEquals(1, statement.executeInsert("STUDENT", row1), "Incorrect insertion count"); Assertions.assertEquals(1, statement.executeInsert("STUDENT", row2), "Incorrect insertion count"); - Assertions.assertTrue(statement.execute("SELECT * from STUDENT f WHERE score is not distinct from null"), "Did not return a result set from a select statement!"); + Assertions.assertTrue(statement.execute("SELECT * from STUDENT WHERE score is not distinct from null"), "Did not return a result set from a select statement!"); try (final RelationalResultSet resultSet = statement.getResultSet()) { ResultSetAssert.assertThat(resultSet) .hasNextRow() @@ -972,7 +972,7 @@ void testNotDistinctFrom() throws Exception { .hasNoNextRow(); } - Assertions.assertTrue(statement.execute("SELECT * from STUDENT f WHERE score is not distinct from 100"), "Did not return a result set from a select statement!"); + Assertions.assertTrue(statement.execute("SELECT * from STUDENT WHERE score is not distinct from 100"), "Did not return a result set from a select statement!"); try (final RelationalResultSet resultSet = statement.getResultSet()) { ResultSetAssert.assertThat(resultSet) .hasNextRow() @@ -980,7 +980,7 @@ void testNotDistinctFrom() throws Exception { .hasNoNextRow(); } - Assertions.assertTrue(statement.execute("SELECT * from STUDENT f WHERE null is not distinct from score"), "Did not return a result set from a select statement!"); + Assertions.assertTrue(statement.execute("SELECT * from STUDENT WHERE null is not distinct from score"), "Did not return a result set from a select statement!"); try (final RelationalResultSet resultSet = statement.getResultSet()) { ResultSetAssert.assertThat(resultSet) .hasNextRow() @@ -988,7 +988,7 @@ void testNotDistinctFrom() throws Exception { .hasNoNextRow(); } - Assertions.assertTrue(statement.execute("SELECT * from STUDENT f WHERE 100 is not distinct from score"), "Did not return a result set from a select statement!"); + Assertions.assertTrue(statement.execute("SELECT * from STUDENT WHERE 100 is not distinct from score"), "Did not return a result set from a select statement!"); try (final RelationalResultSet resultSet = statement.getResultSet()) { ResultSetAssert.assertThat(resultSet) .hasNextRow() @@ -996,7 +996,7 @@ void testNotDistinctFrom() throws Exception { .hasNoNextRow(); } - Assertions.assertTrue(statement.execute("SELECT * from STUDENT f WHERE 100 is not distinct from 100"), "Did not return a result set from a select statement!"); + Assertions.assertTrue(statement.execute("SELECT * from STUDENT WHERE 100 is not distinct from 100"), "Did not return a result set from a select statement!"); try (final RelationalResultSet resultSet = statement.getResultSet()) { ResultSetAssert.assertThat(resultSet) .hasNextRow() @@ -1006,7 +1006,7 @@ void testNotDistinctFrom() throws Exception { .hasNoNextRow(); } - Assertions.assertTrue(statement.execute("SELECT * from STUDENT f WHERE null is not distinct from null"), "Did not return a result set from a select statement!"); + Assertions.assertTrue(statement.execute("SELECT * from STUDENT WHERE null is not distinct from null"), "Did not return a result set from a select statement!"); try (final RelationalResultSet resultSet = statement.getResultSet()) { ResultSetAssert.assertThat(resultSet) .hasNextRow() @@ -1019,6 +1019,71 @@ void testNotDistinctFrom() throws Exception { } } + @Test + void testExplainDistinctFrom() throws Exception { + final String schemaTemplate = "CREATE TYPE AS STRUCT contact_detail(phone_number string, address string) " + + "CREATE TABLE STUDENT(id bigint, name string, contact contact_detail, score bigint, primary key(id)) " + + "CREATE index score_idx as select score from STUDENT"; + try (var ddl = Ddl.builder().database(URI.create("/TEST/QT")).relationalExtension(relationalExtension).schemaTemplate(schemaTemplate).build()) { + try (var statement = ddl.setSchemaAndGetConnection().createStatement()) { + try (final RelationalResultSet resultSet = statement.executeQuery("EXPLAIN SELECT name FROM STUDENT where score is distinct from null")) { + resultSet.next(); + String plan = resultSet.getString(1); + assertThat(plan).matches("ISCAN\\(SCORE_IDX \\(\\[null\\],>\\) \\| MAP \\(_\\.NAME AS NAME\\)"); + } + } + try (var statement = ddl.setSchemaAndGetConnection().createStatement()) { + try (final RelationalResultSet resultSet = statement.executeQuery("EXPLAIN SELECT name FROM STUDENT where score is distinct from 100")) { + resultSet.next(); + String plan = resultSet.getString(1); + assertThat(plan).matches("COVERING\\(SCORE_IDX <,> -> \\[ID: KEY\\[.*], SCORE: KEY\\[.*]\\]\\) \\| FILTER _\\.SCORE IS_DISTINCT_FROM promote\\(@.* AS LONG\\) \\| FETCH \\| MAP \\(_\\.NAME AS NAME\\)"); + } + } + try (var statement = ddl.setSchemaAndGetConnection().createStatement()) { + try (final RelationalResultSet resultSet = statement.executeQuery("EXPLAIN SELECT name FROM STUDENT where null is distinct from score")) { + resultSet.next(); + String plan = resultSet.getString(1); + assertThat(plan).matches("ISCAN\\(SCORE_IDX \\(\\[null\\],>\\) \\| MAP \\(_\\.NAME AS NAME\\)"); + } + } + try (var statement = ddl.setSchemaAndGetConnection().createStatement()) { + try (final RelationalResultSet resultSet = statement.executeQuery("EXPLAIN SELECT name FROM STUDENT where 100 is distinct from score")) { + resultSet.next(); + String plan = resultSet.getString(1); + assertThat(plan).matches("COVERING\\(SCORE_IDX <,> -> \\[ID: KEY\\[.*], SCORE: KEY\\[.*]\\]\\) \\| FILTER _\\.SCORE IS_DISTINCT_FROM promote\\(@.* AS LONG\\) \\| FETCH \\| MAP \\(_\\.NAME AS NAME\\)"); + } + } + try (var statement = ddl.setSchemaAndGetConnection().createStatement()) { + try (final RelationalResultSet resultSet = statement.executeQuery("EXPLAIN SELECT name FROM STUDENT where score is not distinct from null")) { + resultSet.next(); + String plan = resultSet.getString(1); + assertThat(plan).matches("ISCAN\\(SCORE_IDX \\[\\[null\\],\\[null\\]\\]\\) \\| MAP \\(_\\.NAME AS NAME\\)"); + } + } + try (var statement = ddl.setSchemaAndGetConnection().createStatement()) { + try (final RelationalResultSet resultSet = statement.executeQuery("EXPLAIN SELECT name FROM STUDENT where score is not distinct from 100")) { + resultSet.next(); + String plan = resultSet.getString(1); + assertThat(plan).matches("COVERING\\(SCORE_IDX <,> -> \\[ID: KEY\\[.*], SCORE: KEY\\[.*]\\]\\) \\| FILTER _\\.SCORE NOT_DISTINCT_FROM promote\\(@.* AS LONG\\) \\| FETCH \\| MAP \\(_\\.NAME AS NAME\\)"); + } + } + try (var statement = ddl.setSchemaAndGetConnection().createStatement()) { + try (final RelationalResultSet resultSet = statement.executeQuery("EXPLAIN SELECT name FROM STUDENT where null is not distinct from score")) { + resultSet.next(); + String plan = resultSet.getString(1); + assertThat(plan).matches("ISCAN\\(SCORE_IDX \\[\\[null\\],\\[null\\]\\]\\) \\| MAP \\(_\\.NAME AS NAME\\)"); + } + } + try (var statement = ddl.setSchemaAndGetConnection().createStatement()) { + try (final RelationalResultSet resultSet = statement.executeQuery("EXPLAIN SELECT name FROM STUDENT where 100 is not distinct from score")) { + resultSet.next(); + String plan = resultSet.getString(1); + assertThat(plan).matches("COVERING\\(SCORE_IDX <,> -> \\[ID: KEY\\[.*], SCORE: KEY\\[.*]\\]\\) \\| FILTER _\\.SCORE NOT_DISTINCT_FROM promote\\(@.* AS LONG\\) \\| FETCH \\| MAP \\(_\\.NAME AS NAME\\)"); + } + } + } + } + @Test void testBitmap() throws Exception { final String query = "SELECT BITMAP_CONSTRUCT_AGG(BITMAP_BIT_POSITION(uid)) as bitmap, category, BITMAP_BUCKET_OFFSET(uid) as offset FROM T1\n" + From 7c0b2837aa567e601a7f76d7f8ab8bb2b0c2b836 Mon Sep 17 00:00:00 2001 From: Pengpeng Lu Date: Mon, 2 Jun 2025 17:07:18 -0700 Subject: [PATCH 06/16] parser --- .../plan/cascades/values/RelOpValue.java | 228 +++++++++--------- .../src/main/antlr/RelationalLexer.g4 | 2 - .../src/main/antlr/RelationalParser.g4 | 2 +- .../functions/SqlFunctionCatalogImpl.java | 4 +- .../src/test/java/YamlIntegrationTests.java | 5 + .../resources/distinct-from.metrics.binpb | 167 +++++++++++++ .../test/resources/distinct-from.metrics.yaml | 130 ++++++++++ .../src/test/resources/distinct-from.yamsql | 101 ++++++++ 8 files changed, 521 insertions(+), 118 deletions(-) create mode 100644 yaml-tests/src/test/resources/distinct-from.metrics.binpb create mode 100644 yaml-tests/src/test/resources/distinct-from.metrics.yaml create mode 100644 yaml-tests/src/test/resources/distinct-from.yamsql diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/RelOpValue.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/RelOpValue.java index 0351f76daf..9e6b9b7a9e 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/RelOpValue.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/RelOpValue.java @@ -817,119 +817,6 @@ private enum BinaryPhysicalOperator { GTE_UID(Comparisons.Type.GREATER_THAN_OR_EQUALS, Type.TypeCode.UNKNOWN, Type.TypeCode.UUID, (l, r) -> null), GTE_IDU(Comparisons.Type.GREATER_THAN_OR_EQUALS, Type.TypeCode.UUID, Type.TypeCode.UNKNOWN, (l, r) -> null), - IS_DISTINCT_FROM_BU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.BOOLEAN, Type.TypeCode.UNKNOWN, (l, r) -> true), - IS_DISTINCT_FROM_BB(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.BOOLEAN, Type.TypeCode.BOOLEAN, (l, r) -> (boolean)l != (boolean)r), - IS_DISTINCT_FROM_IU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.INT, Type.TypeCode.UNKNOWN, (l, r) -> true), - IS_DISTINCT_FROM_II(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.INT, Type.TypeCode.INT, (l, r) -> (int)l != (int)r), - IS_DISTINCT_FROM_IL(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.INT, Type.TypeCode.LONG, (l, r) -> (int)l != (long)r), - IS_DISTINCT_FROM_IF(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.INT, Type.TypeCode.FLOAT, (l, r) -> (int)l != (float)r), - IS_DISTINCT_FROM_ID(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.INT, Type.TypeCode.DOUBLE, (l, r) -> (int)l != (double)r), - IS_DISTINCT_FROM_LU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.LONG, Type.TypeCode.UNKNOWN, (l, r) -> true), - IS_DISTINCT_FROM_LI(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.LONG, Type.TypeCode.INT, (l, r) -> (long)l != (int)r), - IS_DISTINCT_FROM_LL(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.LONG, Type.TypeCode.LONG, (l, r) -> (long)l != (long)r), - IS_DISTINCT_FROM_LF(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.LONG, Type.TypeCode.FLOAT, (l, r) -> (long)l != (float)r), - IS_DISTINCT_FROM_LD(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.LONG, Type.TypeCode.DOUBLE, (l, r) -> (long)l != (double)r), - IS_DISTINCT_FROM_FU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.FLOAT, Type.TypeCode.UNKNOWN, (l, r) -> true), - IS_DISTINCT_FROM_FI(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.FLOAT, Type.TypeCode.INT, (l, r) -> (float)l != (int)r), - IS_DISTINCT_FROM_FL(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.FLOAT, Type.TypeCode.LONG, (l, r) -> (float)l != (long)r), - IS_DISTINCT_FROM_FF(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.FLOAT, Type.TypeCode.FLOAT, (l, r) -> (float)l != (float)r), - IS_DISTINCT_FROM_FD(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.FLOAT, Type.TypeCode.DOUBLE, (l, r) -> (float)l != (double)r), - IS_DISTINCT_FROM_DU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.DOUBLE, Type.TypeCode.UNKNOWN, (l, r) -> true), - IS_DISTINCT_FROM_DI(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.DOUBLE, Type.TypeCode.INT, (l, r) -> (double)l != (int)r), - IS_DISTINCT_FROM_DL(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.DOUBLE, Type.TypeCode.LONG, (l, r) -> (double)l != (long)r), - IS_DISTINCT_FROM_DF(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.DOUBLE, Type.TypeCode.FLOAT, (l, r) -> (double)l != (float)r), - IS_DISTINCT_FROM_DD(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.DOUBLE, Type.TypeCode.DOUBLE, (l, r) -> (double)l != (double)r), - IS_DISTINCT_FROM_SU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.STRING, Type.TypeCode.UNKNOWN, (l, r) -> true), - IS_DISTINCT_FROM_SS(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.STRING, Type.TypeCode.STRING, (l, r) -> !l.equals(r)), // TODO: locale-aware comparison - IS_DISTINCT_FROM_UU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.UNKNOWN, (l, r) -> false), - IS_DISTINCT_FROM_UB(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.BOOLEAN, (l, r) -> true), - IS_DISTINCT_FROM_UI(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.INT, (l, r) -> true), - IS_DISTINCT_FROM_UL(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.LONG, (l, r) -> true), - IS_DISTINCT_FROM_UF(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.FLOAT, (l, r) -> true), - IS_DISTINCT_FROM_UD(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.DOUBLE, (l, r) -> true), - IS_DISTINCT_FROM_US(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.STRING, (l, r) -> true), - IS_DISTINCT_FROM_UV(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.VERSION, (l, r) -> true), - IS_DISTINCT_FROM_VU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.VERSION, Type.TypeCode.UNKNOWN, (l, r) -> null), - IS_DISTINCT_FROM_VV(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.VERSION, Type.TypeCode.VERSION, (l, r) -> !l.equals(r)), - IS_DISTINCT_FROM_BYU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.BYTES, Type.TypeCode.UNKNOWN, (l, r) -> null), - IS_DISTINCT_FROM_BYBY(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.BYTES, Type.TypeCode.BYTES, (l, r) -> Comparisons.evalComparison(Comparisons.Type.IS_DISTINCT_FROM, l, r)), - IS_DISTINCT_FROM_UBY(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.BYTES, (l, r) -> true), - IS_DISTINCT_FROM_EE(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.ENUM, Type.TypeCode.ENUM, (l, r) -> Comparisons.evalComparison(Comparisons.Type.IS_DISTINCT_FROM, l, r)), - IS_DISTINCT_FROM_ES(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.ENUM, Type.TypeCode.STRING, (l, r) -> { - final var otherValue = PromoteValue.PhysicalOperator.stringToEnumValue(((Descriptors.EnumValueDescriptor) l).getType(), (String) r); - return Comparisons.evalComparison(Comparisons.Type.IS_DISTINCT_FROM, l, otherValue); - }), - IS_DISTINCT_FROM_SE(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.STRING, Type.TypeCode.ENUM, (l, r) -> { - final var otherValue = PromoteValue.PhysicalOperator.stringToEnumValue(((Descriptors.EnumValueDescriptor) r).getType(), (String) l); - return Comparisons.evalComparison(Comparisons.Type.EQUALS, otherValue, r); - }), - IS_DISTINCT_FROM_EU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.ENUM, Type.TypeCode.UNKNOWN, (l, r) -> true), - IS_DISTINCT_FROM_UE(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.ENUM, (l, r) -> true), - IS_DISTINCT_FROM_IDID(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.UUID, Type.TypeCode.UUID, (l, r) -> Comparisons.evalComparison(Comparisons.Type.IS_DISTINCT_FROM, l, r)), - IS_DISTINCT_FROM_IDS(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.UUID, Type.TypeCode.STRING, (l, r) -> Comparisons.evalComparison(Comparisons.Type.IS_DISTINCT_FROM, l, PromoteValue.PhysicalOperator.stringToUuidValue((String) r))), - IS_DISTINCT_FROM_SID(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.STRING, Type.TypeCode.UUID, (l, r) -> Comparisons.evalComparison(Comparisons.Type.IS_DISTINCT_FROM, PromoteValue.PhysicalOperator.stringToUuidValue((String) l), r)), - IS_DISTINCT_FROM_UID(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.UUID, (l, r) -> true), - IS_DISTINCT_FROM_IDU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.UUID, Type.TypeCode.UNKNOWN, (l, r) -> true), - IS_DISTINCT_FROM_NN(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.NULL, (l, r) -> false), - - NOT_DISTINCT_FROM_BU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.BOOLEAN, Type.TypeCode.UNKNOWN, (l, r) -> false), - NOT_DISTINCT_FROM_BB(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.BOOLEAN, Type.TypeCode.BOOLEAN, (l, r) -> (boolean)l == (boolean)r), - NOT_DISTINCT_FROM_IU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.INT, Type.TypeCode.UNKNOWN, (l, r) -> false), - NOT_DISTINCT_FROM_II(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.INT, Type.TypeCode.INT, (l, r) -> (int)l == (int)r), - NOT_DISTINCT_FROM_IL(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.INT, Type.TypeCode.LONG, (l, r) -> (int)l == (long)r), - NOT_DISTINCT_FROM_IF(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.INT, Type.TypeCode.FLOAT, (l, r) -> (int)l == (float)r), - NOT_DISTINCT_FROM_ID(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.INT, Type.TypeCode.DOUBLE, (l, r) -> (int)l == (double)r), - NOT_DISTINCT_FROM_LU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.LONG, Type.TypeCode.UNKNOWN, (l, r) -> false), - NOT_DISTINCT_FROM_LI(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.LONG, Type.TypeCode.INT, (l, r) -> (long)l == (int)r), - NOT_DISTINCT_FROM_LL(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.LONG, Type.TypeCode.LONG, (l, r) -> (long)l == (long)r), - NOT_DISTINCT_FROM_LF(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.LONG, Type.TypeCode.FLOAT, (l, r) -> (long)l == (float)r), - NOT_DISTINCT_FROM_LD(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.LONG, Type.TypeCode.DOUBLE, (l, r) -> (long)l == (double)r), - NOT_DISTINCT_FROM_FU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.FLOAT, Type.TypeCode.UNKNOWN, (l, r) -> false), - NOT_DISTINCT_FROM_FI(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.FLOAT, Type.TypeCode.INT, (l, r) -> (float)l == (int)r), - NOT_DISTINCT_FROM_FL(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.FLOAT, Type.TypeCode.LONG, (l, r) -> (float)l == (long)r), - NOT_DISTINCT_FROM_FF(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.FLOAT, Type.TypeCode.FLOAT, (l, r) -> (float)l == (float)r), - NOT_DISTINCT_FROM_FD(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.FLOAT, Type.TypeCode.DOUBLE, (l, r) -> (float)l == (double)r), - NOT_DISTINCT_FROM_DU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.DOUBLE, Type.TypeCode.UNKNOWN, (l, r) -> false), - NOT_DISTINCT_FROM_DI(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.DOUBLE, Type.TypeCode.INT, (l, r) -> (double)l == (int)r), - NOT_DISTINCT_FROM_DL(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.DOUBLE, Type.TypeCode.LONG, (l, r) -> (double)l == (long)r), - NOT_DISTINCT_FROM_DF(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.DOUBLE, Type.TypeCode.FLOAT, (l, r) -> (double)l == (float)r), - NOT_DISTINCT_FROM_DD(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.DOUBLE, Type.TypeCode.DOUBLE, (l, r) -> (double)l == (double)r), - NOT_DISTINCT_FROM_SU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.STRING, Type.TypeCode.UNKNOWN, (l, r) -> false), - NOT_DISTINCT_FROM_SS(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.STRING, Type.TypeCode.STRING, Object::equals), // TODO: locale-aware comparison - NOT_DISTINCT_FROM_UU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.UNKNOWN, (l, r) -> true), - NOT_DISTINCT_FROM_UB(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.BOOLEAN, (l, r) -> false), - NOT_DISTINCT_FROM_UI(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.INT, (l, r) -> false), - NOT_DISTINCT_FROM_UL(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.LONG, (l, r) -> false), - NOT_DISTINCT_FROM_UF(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.FLOAT, (l, r) -> false), - NOT_DISTINCT_FROM_UD(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.DOUBLE, (l, r) -> false), - NOT_DISTINCT_FROM_US(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.STRING, (l, r) -> false), - NOT_DISTINCT_FROM_UV(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.VERSION, (l, r) -> false), - NOT_DISTINCT_FROM_VU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.VERSION, Type.TypeCode.UNKNOWN, (l, r) -> false), - NOT_DISTINCT_FROM_VV(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.VERSION, Type.TypeCode.VERSION, Object::equals), - - NOT_DISTINCT_FROM_BYU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.BYTES, Type.TypeCode.UNKNOWN, (l, r) -> false), - NOT_DISTINCT_FROM_BYBY(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.BYTES, Type.TypeCode.BYTES, (l, r) -> Comparisons.evalComparison(Comparisons.Type.NOT_DISTINCT_FROM, l, r)), - NOT_DISTINCT_FROM_UBY(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.BYTES, (l, r) -> false), - - NOT_DISTINCT_FROM_EE(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.ENUM, Type.TypeCode.ENUM, (l, r) -> Comparisons.evalComparison(Comparisons.Type.NOT_DISTINCT_FROM, l, r)), - NOT_DISTINCT_FROM_ES(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.ENUM, Type.TypeCode.STRING, (l, r) -> { - final var otherValue = PromoteValue.PhysicalOperator.stringToEnumValue(((Descriptors.EnumValueDescriptor) l).getType(), (String) r); - return Comparisons.evalComparison(Comparisons.Type.NOT_DISTINCT_FROM, l, otherValue); - }), - NOT_DISTINCT_FROM_SE(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.STRING, Type.TypeCode.ENUM, (l, r) -> { - final var otherValue = PromoteValue.PhysicalOperator.stringToEnumValue(((Descriptors.EnumValueDescriptor) r).getType(), (String) l); - return Comparisons.evalComparison(Comparisons.Type.NOT_DISTINCT_FROM, otherValue, r); - }), - NOT_DISTINCT_FROM_EU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.ENUM, Type.TypeCode.UNKNOWN, (l, r) -> false), - NOT_DISTINCT_FROM_UE(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.ENUM, (l, r) -> false), - - NOT_DISTINCT_FROM_IDID(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UUID, Type.TypeCode.UUID, (l, r) -> Comparisons.evalComparison(Comparisons.Type.NOT_DISTINCT_FROM, l, r)), - NOT_DISTINCT_FROM_IDS(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UUID, Type.TypeCode.STRING, (l, r) -> Comparisons.evalComparison(Comparisons.Type.NOT_DISTINCT_FROM, l, PromoteValue.PhysicalOperator.stringToUuidValue((String) r))), - NOT_DISTINCT_FROM_SID(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.STRING, Type.TypeCode.UUID, (l, r) -> Comparisons.evalComparison(Comparisons.Type.NOT_DISTINCT_FROM, PromoteValue.PhysicalOperator.stringToUuidValue((String) l), r)), - NOT_DISTINCT_FROM_UID(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.UUID, (l, r) -> false), - NOT_DISTINCT_FROM_IDU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UUID, Type.TypeCode.UNKNOWN, (l, r) -> false), - - NOT_DISTINCT_FROM_NN(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.NULL, (l, r) -> true), EQ_BN(Comparisons.Type.EQUALS, Type.TypeCode.BOOLEAN, Type.TypeCode.NULL, (l, r) -> null), EQ_IN(Comparisons.Type.EQUALS, Type.TypeCode.INT, Type.TypeCode.NULL, (l, r) -> null), @@ -1061,6 +948,121 @@ private enum BinaryPhysicalOperator { GT_IDN(Comparisons.Type.GREATER_THAN, Type.TypeCode.UUID, Type.TypeCode.NULL, (l, r) -> null), GTE_NID(Comparisons.Type.GREATER_THAN_OR_EQUALS, Type.TypeCode.NULL, Type.TypeCode.UUID, (l, r) -> null), GTE_IDN(Comparisons.Type.GREATER_THAN_OR_EQUALS, Type.TypeCode.UUID, Type.TypeCode.NULL, (l, r) -> null), + + IS_DISTINCT_FROM_BU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.BOOLEAN, Type.TypeCode.UNKNOWN, (l, r) -> true), + IS_DISTINCT_FROM_BB(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.BOOLEAN, Type.TypeCode.BOOLEAN, (l, r) -> (boolean)l != (boolean)r), + IS_DISTINCT_FROM_IU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.INT, Type.TypeCode.UNKNOWN, (l, r) -> true), + IS_DISTINCT_FROM_II(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.INT, Type.TypeCode.INT, (l, r) -> (int)l != (int)r), + IS_DISTINCT_FROM_IL(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.INT, Type.TypeCode.LONG, (l, r) -> (int)l != (long)r), + IS_DISTINCT_FROM_IF(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.INT, Type.TypeCode.FLOAT, (l, r) -> (int)l != (float)r), + IS_DISTINCT_FROM_ID(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.INT, Type.TypeCode.DOUBLE, (l, r) -> (int)l != (double)r), + IS_DISTINCT_FROM_LU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.LONG, Type.TypeCode.UNKNOWN, (l, r) -> true), + IS_DISTINCT_FROM_LI(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.LONG, Type.TypeCode.INT, (l, r) -> (long)l != (int)r), + IS_DISTINCT_FROM_LL(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.LONG, Type.TypeCode.LONG, (l, r) -> (long)l != (long)r), + IS_DISTINCT_FROM_LF(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.LONG, Type.TypeCode.FLOAT, (l, r) -> (long)l != (float)r), + IS_DISTINCT_FROM_LD(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.LONG, Type.TypeCode.DOUBLE, (l, r) -> (long)l != (double)r), + IS_DISTINCT_FROM_FU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.FLOAT, Type.TypeCode.UNKNOWN, (l, r) -> true), + IS_DISTINCT_FROM_FI(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.FLOAT, Type.TypeCode.INT, (l, r) -> (float)l != (int)r), + IS_DISTINCT_FROM_FL(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.FLOAT, Type.TypeCode.LONG, (l, r) -> (float)l != (long)r), + IS_DISTINCT_FROM_FF(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.FLOAT, Type.TypeCode.FLOAT, (l, r) -> (float)l != (float)r), + IS_DISTINCT_FROM_FD(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.FLOAT, Type.TypeCode.DOUBLE, (l, r) -> (float)l != (double)r), + IS_DISTINCT_FROM_DU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.DOUBLE, Type.TypeCode.UNKNOWN, (l, r) -> true), + IS_DISTINCT_FROM_DI(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.DOUBLE, Type.TypeCode.INT, (l, r) -> (double)l != (int)r), + IS_DISTINCT_FROM_DL(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.DOUBLE, Type.TypeCode.LONG, (l, r) -> (double)l != (long)r), + IS_DISTINCT_FROM_DF(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.DOUBLE, Type.TypeCode.FLOAT, (l, r) -> (double)l != (float)r), + IS_DISTINCT_FROM_DD(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.DOUBLE, Type.TypeCode.DOUBLE, (l, r) -> (double)l != (double)r), + IS_DISTINCT_FROM_SU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.STRING, Type.TypeCode.UNKNOWN, (l, r) -> true), + IS_DISTINCT_FROM_SS(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.STRING, Type.TypeCode.STRING, (l, r) -> !l.equals(r)), // TODO: locale-aware comparison + IS_DISTINCT_FROM_UU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.UNKNOWN, (l, r) -> false), + IS_DISTINCT_FROM_UB(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.BOOLEAN, (l, r) -> true), + IS_DISTINCT_FROM_UI(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.INT, (l, r) -> true), + IS_DISTINCT_FROM_UL(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.LONG, (l, r) -> true), + IS_DISTINCT_FROM_UF(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.FLOAT, (l, r) -> true), + IS_DISTINCT_FROM_UD(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.DOUBLE, (l, r) -> true), + IS_DISTINCT_FROM_US(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.STRING, (l, r) -> true), + IS_DISTINCT_FROM_UV(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.VERSION, (l, r) -> true), + IS_DISTINCT_FROM_VU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.VERSION, Type.TypeCode.UNKNOWN, (l, r) -> null), + IS_DISTINCT_FROM_VV(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.VERSION, Type.TypeCode.VERSION, (l, r) -> !l.equals(r)), + IS_DISTINCT_FROM_BYU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.BYTES, Type.TypeCode.UNKNOWN, (l, r) -> null), + IS_DISTINCT_FROM_BYBY(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.BYTES, Type.TypeCode.BYTES, (l, r) -> Comparisons.evalComparison(Comparisons.Type.IS_DISTINCT_FROM, l, r)), + IS_DISTINCT_FROM_UBY(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.BYTES, (l, r) -> true), + IS_DISTINCT_FROM_EE(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.ENUM, Type.TypeCode.ENUM, (l, r) -> Comparisons.evalComparison(Comparisons.Type.IS_DISTINCT_FROM, l, r)), + IS_DISTINCT_FROM_ES(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.ENUM, Type.TypeCode.STRING, (l, r) -> { + final var otherValue = PromoteValue.PhysicalOperator.stringToEnumValue(((Descriptors.EnumValueDescriptor) l).getType(), (String) r); + return Comparisons.evalComparison(Comparisons.Type.IS_DISTINCT_FROM, l, otherValue); + }), + IS_DISTINCT_FROM_SE(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.STRING, Type.TypeCode.ENUM, (l, r) -> { + final var otherValue = PromoteValue.PhysicalOperator.stringToEnumValue(((Descriptors.EnumValueDescriptor) r).getType(), (String) l); + return Comparisons.evalComparison(Comparisons.Type.EQUALS, otherValue, r); + }), + IS_DISTINCT_FROM_EU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.ENUM, Type.TypeCode.UNKNOWN, (l, r) -> true), + IS_DISTINCT_FROM_UE(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.ENUM, (l, r) -> true), + IS_DISTINCT_FROM_IDID(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.UUID, Type.TypeCode.UUID, (l, r) -> Comparisons.evalComparison(Comparisons.Type.IS_DISTINCT_FROM, l, r)), + IS_DISTINCT_FROM_IDS(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.UUID, Type.TypeCode.STRING, (l, r) -> Comparisons.evalComparison(Comparisons.Type.IS_DISTINCT_FROM, l, PromoteValue.PhysicalOperator.stringToUuidValue((String) r))), + IS_DISTINCT_FROM_SID(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.STRING, Type.TypeCode.UUID, (l, r) -> Comparisons.evalComparison(Comparisons.Type.IS_DISTINCT_FROM, PromoteValue.PhysicalOperator.stringToUuidValue((String) l), r)), + IS_DISTINCT_FROM_UID(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.UUID, (l, r) -> true), + IS_DISTINCT_FROM_IDU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.UUID, Type.TypeCode.UNKNOWN, (l, r) -> true), + IS_DISTINCT_FROM_NN(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.NULL, (l, r) -> false), + + NOT_DISTINCT_FROM_BU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.BOOLEAN, Type.TypeCode.UNKNOWN, (l, r) -> false), + NOT_DISTINCT_FROM_BB(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.BOOLEAN, Type.TypeCode.BOOLEAN, (l, r) -> (boolean)l == (boolean)r), + NOT_DISTINCT_FROM_IU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.INT, Type.TypeCode.UNKNOWN, (l, r) -> false), + NOT_DISTINCT_FROM_II(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.INT, Type.TypeCode.INT, (l, r) -> (int)l == (int)r), + NOT_DISTINCT_FROM_IL(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.INT, Type.TypeCode.LONG, (l, r) -> (int)l == (long)r), + NOT_DISTINCT_FROM_IF(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.INT, Type.TypeCode.FLOAT, (l, r) -> (int)l == (float)r), + NOT_DISTINCT_FROM_ID(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.INT, Type.TypeCode.DOUBLE, (l, r) -> (int)l == (double)r), + NOT_DISTINCT_FROM_LU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.LONG, Type.TypeCode.UNKNOWN, (l, r) -> false), + NOT_DISTINCT_FROM_LI(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.LONG, Type.TypeCode.INT, (l, r) -> (long)l == (int)r), + NOT_DISTINCT_FROM_LL(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.LONG, Type.TypeCode.LONG, (l, r) -> (long)l == (long)r), + NOT_DISTINCT_FROM_LF(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.LONG, Type.TypeCode.FLOAT, (l, r) -> (long)l == (float)r), + NOT_DISTINCT_FROM_LD(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.LONG, Type.TypeCode.DOUBLE, (l, r) -> (long)l == (double)r), + NOT_DISTINCT_FROM_FU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.FLOAT, Type.TypeCode.UNKNOWN, (l, r) -> false), + NOT_DISTINCT_FROM_FI(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.FLOAT, Type.TypeCode.INT, (l, r) -> (float)l == (int)r), + NOT_DISTINCT_FROM_FL(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.FLOAT, Type.TypeCode.LONG, (l, r) -> (float)l == (long)r), + NOT_DISTINCT_FROM_FF(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.FLOAT, Type.TypeCode.FLOAT, (l, r) -> (float)l == (float)r), + NOT_DISTINCT_FROM_FD(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.FLOAT, Type.TypeCode.DOUBLE, (l, r) -> (float)l == (double)r), + NOT_DISTINCT_FROM_DU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.DOUBLE, Type.TypeCode.UNKNOWN, (l, r) -> false), + NOT_DISTINCT_FROM_DI(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.DOUBLE, Type.TypeCode.INT, (l, r) -> (double)l == (int)r), + NOT_DISTINCT_FROM_DL(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.DOUBLE, Type.TypeCode.LONG, (l, r) -> (double)l == (long)r), + NOT_DISTINCT_FROM_DF(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.DOUBLE, Type.TypeCode.FLOAT, (l, r) -> (double)l == (float)r), + NOT_DISTINCT_FROM_DD(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.DOUBLE, Type.TypeCode.DOUBLE, (l, r) -> (double)l == (double)r), + NOT_DISTINCT_FROM_SU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.STRING, Type.TypeCode.UNKNOWN, (l, r) -> false), + NOT_DISTINCT_FROM_SS(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.STRING, Type.TypeCode.STRING, Object::equals), // TODO: locale-aware comparison + NOT_DISTINCT_FROM_UU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.UNKNOWN, (l, r) -> true), + NOT_DISTINCT_FROM_UB(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.BOOLEAN, (l, r) -> false), + NOT_DISTINCT_FROM_UI(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.INT, (l, r) -> false), + NOT_DISTINCT_FROM_UL(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.LONG, (l, r) -> false), + NOT_DISTINCT_FROM_UF(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.FLOAT, (l, r) -> false), + NOT_DISTINCT_FROM_UD(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.DOUBLE, (l, r) -> false), + NOT_DISTINCT_FROM_US(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.STRING, (l, r) -> false), + NOT_DISTINCT_FROM_UV(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.VERSION, (l, r) -> false), + NOT_DISTINCT_FROM_VU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.VERSION, Type.TypeCode.UNKNOWN, (l, r) -> false), + NOT_DISTINCT_FROM_VV(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.VERSION, Type.TypeCode.VERSION, Object::equals), + + NOT_DISTINCT_FROM_BYU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.BYTES, Type.TypeCode.UNKNOWN, (l, r) -> false), + NOT_DISTINCT_FROM_BYBY(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.BYTES, Type.TypeCode.BYTES, (l, r) -> Comparisons.evalComparison(Comparisons.Type.NOT_DISTINCT_FROM, l, r)), + NOT_DISTINCT_FROM_UBY(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.BYTES, (l, r) -> false), + + NOT_DISTINCT_FROM_EE(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.ENUM, Type.TypeCode.ENUM, (l, r) -> Comparisons.evalComparison(Comparisons.Type.NOT_DISTINCT_FROM, l, r)), + NOT_DISTINCT_FROM_ES(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.ENUM, Type.TypeCode.STRING, (l, r) -> { + final var otherValue = PromoteValue.PhysicalOperator.stringToEnumValue(((Descriptors.EnumValueDescriptor) l).getType(), (String) r); + return Comparisons.evalComparison(Comparisons.Type.NOT_DISTINCT_FROM, l, otherValue); + }), + NOT_DISTINCT_FROM_SE(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.STRING, Type.TypeCode.ENUM, (l, r) -> { + final var otherValue = PromoteValue.PhysicalOperator.stringToEnumValue(((Descriptors.EnumValueDescriptor) r).getType(), (String) l); + return Comparisons.evalComparison(Comparisons.Type.NOT_DISTINCT_FROM, otherValue, r); + }), + NOT_DISTINCT_FROM_EU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.ENUM, Type.TypeCode.UNKNOWN, (l, r) -> false), + NOT_DISTINCT_FROM_UE(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.ENUM, (l, r) -> false), + + NOT_DISTINCT_FROM_IDID(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UUID, Type.TypeCode.UUID, (l, r) -> Comparisons.evalComparison(Comparisons.Type.NOT_DISTINCT_FROM, l, r)), + NOT_DISTINCT_FROM_IDS(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UUID, Type.TypeCode.STRING, (l, r) -> Comparisons.evalComparison(Comparisons.Type.NOT_DISTINCT_FROM, l, PromoteValue.PhysicalOperator.stringToUuidValue((String) r))), + NOT_DISTINCT_FROM_SID(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.STRING, Type.TypeCode.UUID, (l, r) -> Comparisons.evalComparison(Comparisons.Type.NOT_DISTINCT_FROM, PromoteValue.PhysicalOperator.stringToUuidValue((String) l), r)), + NOT_DISTINCT_FROM_UID(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.UUID, (l, r) -> false), + NOT_DISTINCT_FROM_IDU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UUID, Type.TypeCode.UNKNOWN, (l, r) -> false), + + NOT_DISTINCT_FROM_NN(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.NULL, (l, r) -> true), + ; // We can pass down UUID or String till here. diff --git a/fdb-relational-core/src/main/antlr/RelationalLexer.g4 b/fdb-relational-core/src/main/antlr/RelationalLexer.g4 index 3464611236..8d49e2d193 100644 --- a/fdb-relational-core/src/main/antlr/RelationalLexer.g4 +++ b/fdb-relational-core/src/main/antlr/RelationalLexer.g4 @@ -127,8 +127,6 @@ INSERT: 'INSERT'; INTERVAL: 'INTERVAL'; INTO: 'INTO'; IS: 'IS'; -IS_DISTINCT_FROM: 'IS DISTINCT FROM'; -IS_NOT_DISTINCT_FROM: 'IS NOT DISTINCT FROM'; ITERATE: 'ITERATE'; JOIN: 'JOIN'; KEY: 'KEY'; diff --git a/fdb-relational-core/src/main/antlr/RelationalParser.g4 b/fdb-relational-core/src/main/antlr/RelationalParser.g4 index e8cf29c7b2..879fa3f3e4 100644 --- a/fdb-relational-core/src/main/antlr/RelationalParser.g4 +++ b/fdb-relational-core/src/main/antlr/RelationalParser.g4 @@ -1164,7 +1164,7 @@ unaryOperator comparisonOperator : '=' | '>' | '<' | '<' '=' | '>' '=' | '<' '>' | '!' '=' // | '<' '=' '>' // no support for null-safe equality - | IS_DISTINCT_FROM | IS_NOT_DISTINCT_FROM + | IS NOT? DISTINCT FROM ; logicalOperator diff --git a/fdb-relational-core/src/main/java/com/apple/foundationdb/relational/recordlayer/query/functions/SqlFunctionCatalogImpl.java b/fdb-relational-core/src/main/java/com/apple/foundationdb/relational/recordlayer/query/functions/SqlFunctionCatalogImpl.java index 79082137b1..9c7ec3d668 100644 --- a/fdb-relational-core/src/main/java/com/apple/foundationdb/relational/recordlayer/query/functions/SqlFunctionCatalogImpl.java +++ b/fdb-relational-core/src/main/java/com/apple/foundationdb/relational/recordlayer/query/functions/SqlFunctionCatalogImpl.java @@ -145,8 +145,8 @@ private static ImmutableMap BuiltInFunctionCatalog.resolve("coalesce", argumentsCount)) .put("is null", argumentsCount -> BuiltInFunctionCatalog.resolve("isNull", argumentsCount)) .put("is not null", argumentsCount -> BuiltInFunctionCatalog.resolve("notNull", argumentsCount)) - .put("is distinct from", argumentsCount -> BuiltInFunctionCatalog.resolve("isDistinctFrom", argumentsCount)) - .put("is not distinct from", argumentsCount -> BuiltInFunctionCatalog.resolve("notDistinctFrom", argumentsCount)) + .put("isdistinctfrom", argumentsCount -> BuiltInFunctionCatalog.resolve("isDistinctFrom", argumentsCount)) + .put("isnotdistinctfrom", argumentsCount -> BuiltInFunctionCatalog.resolve("notDistinctFrom", argumentsCount)) .put("range", argumentsCount -> BuiltInFunctionCatalog.resolve("range", argumentsCount)) .put("__pattern_for_like", argumentsCount -> BuiltInFunctionCatalog.resolve("patternForLike", argumentsCount)) .put("__internal_array", argumentsCount -> BuiltInFunctionCatalog.resolve("array", argumentsCount)) diff --git a/yaml-tests/src/test/java/YamlIntegrationTests.java b/yaml-tests/src/test/java/YamlIntegrationTests.java index 3c008556e0..0c81cbcdb2 100644 --- a/yaml-tests/src/test/java/YamlIntegrationTests.java +++ b/yaml-tests/src/test/java/YamlIntegrationTests.java @@ -194,6 +194,11 @@ void like(YamlTest.Runner runner) throws Exception { runner.runYamsql("like.yamsql"); } + @TestTemplate + void distinctFrom(YamlTest.Runner runner) throws Exception { + runner.runYamsql("distinct-from.yamsql"); + } + @TestTemplate void functions(YamlTest.Runner runner) throws Exception { runner.runYamsql("functions.yamsql"); diff --git a/yaml-tests/src/test/resources/distinct-from.metrics.binpb b/yaml-tests/src/test/resources/distinct-from.metrics.binpb new file mode 100644 index 0000000000..f0bd098956 --- /dev/null +++ b/yaml-tests/src/test/resources/distinct-from.metrics.binpb @@ -0,0 +1,167 @@ +£ +U +distinct-from-tests>EXPLAIN select * from t1 WHERE col2 is distinct from nullÉ +œ¬ƒüc¶ þÇ?(70ÆÙ€8E@ ISCAN(I2 ([null],>)”digraph G { + fontname=courier; + rankdir=BT; + splines=polyline; + 1 [ label=<
Index Scan
range: ((null), ∞>
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 2 [ label=<
Index
I2
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 2 -> 1 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; +}Š +N +distinct-from-tests7EXPLAIN select * from t1 WHERE col1 is DISTINCT from 10· +«•Öî¶ ýÜã(50øþè8J@ lCOVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER _.COL1 IS_DISTINCT_FROM promote(@c10 AS INT) | FETCH© digraph G { + fontname=courier; + rankdir=BT; + splines=polyline; + 1 [ label=<
Fetch Records
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(INT AS ID, )" ]; + 2 [ label=<
Predicate Filter
WHERE q61.COL1 IS_DISTINCT_FROM promote(@c10 AS INT)
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 3 [ label=<
Covering Index Scan
range: <-∞, ∞>
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 4 [ label=<
Index
I1
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 3 -> 2 [ label=< q61> label="q61" 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=< q63> label="q63" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; +}ž +P +distinct-from-tests9EXPLAIN select * from t1 WHERE null is distinct from col2É +œìÏ„d¶  »ô?(70ºÊ‹8E@ ISCAN(I2 ([null],>)”digraph G { + fontname=courier; + rankdir=BT; + splines=polyline; + 1 [ label=<
Index Scan
range: ((null), ∞>
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 2 [ label=<
Index
I2
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 2 -> 1 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; +}ˆ +N +distinct-from-tests7EXPLAIN select * from t1 WHERE 10 is distinct from col1µ +«ÕÎͶ µö(50º¥ì8J@ kCOVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER _.COL1 IS_DISTINCT_FROM promote(@c6 AS INT) | FETCH¨ digraph G { + fontname=courier; + rankdir=BT; + splines=polyline; + 1 [ label=<
Fetch Records
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(INT AS ID, )" ]; + 2 [ label=<
Predicate Filter
WHERE q61.COL1 IS_DISTINCT_FROM promote(@c6 AS INT)
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 3 [ label=<
Covering Index Scan
range: <-∞, ∞>
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 4 [ label=<
Index
I1
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 3 -> 2 [ label=< q61> label="q61" 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=< q63> label="q63" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; +}¼ +P +distinct-from-tests9EXPLAIN select * from t1 WHERE null is distinct from nullç +ÑÌŒ“cÀ ããã>(80¡þ•8Q@ +ECOVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER false | FETCH€ digraph G { + fontname=courier; + rankdir=BT; + splines=polyline; + 1 [ label=<
Fetch Records
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(INT AS ID, )" ]; + 2 [ label=<
Predicate Filter
WHERE false
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 3 [ label=<
Covering Index Scan
range: <-∞, ∞>
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 4 [ label=<
Index
I1
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 3 -> 2 [ label=< q64> label="q64" 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=< q66> label="q66" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; +}Þ +L +distinct-from-tests5EXPLAIN select * from t1 WHERE 10 is distinct from 10 +ÑÆ£‹cÀ É¢´@(80Í‚¡8Q@ +XCOVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER @c6 IS_DISTINCT_FROM @c6 | FETCH“ digraph G { + fontname=courier; + rankdir=BT; + splines=polyline; + 1 [ label=<
Fetch Records
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(INT AS ID, )" ]; + 2 [ label=<
Predicate Filter
WHERE @c6 IS_DISTINCT_FROM @c6
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 3 [ label=<
Covering Index Scan
range: <-∞, ∞>
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 4 [ label=<
Index
I1
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 3 -> 2 [ label=< q64> label="q64" 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=< q66> label="q66" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; +}± +] +not-distinct-from-testsBEXPLAIN select * from t1 WHERE col2 is not distinct from nullÏ +œê§ñµ ðÆ´(70¢çÞ8E@ ISCAN(I2 [[null],[null]])”digraph G { + fontname=courier; + rankdir=BT; + splines=polyline; + 1 [ label=<
Index Scan
range: [(null), (null)]
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 2 [ label=<
Index
I2
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 2 -> 1 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; +}” +V +not-distinct-from-tests;EXPLAIN select * from t1 WHERE col1 is not distinct from 20¹ +«¬ñƒ· á‹ö(50ߎë8J@ mCOVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER _.COL1 NOT_DISTINCT_FROM promote(@c11 AS INT) | FETCHª digraph G { + fontname=courier; + rankdir=BT; + splines=polyline; + 1 [ label=<
Fetch Records
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(INT AS ID, )" ]; + 2 [ label=<
Predicate Filter
WHERE q61.COL1 NOT_DISTINCT_FROM promote(@c11 AS INT)
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 3 [ label=<
Covering Index Scan
range: <-∞, ∞>
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 4 [ label=<
Index
I1
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 3 -> 2 [ label=< q61> label="q61" 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=< q63> label="q63" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; +}¬ +X +not-distinct-from-tests=EXPLAIN select * from t1 WHERE null is not distinct from col2Ï +œõ뤵 ‹å˜(70õ¿æ8E@ ISCAN(I2 [[null],[null]])”digraph G { + fontname=courier; + rankdir=BT; + splines=polyline; + 1 [ label=<
Index Scan
range: [(null), (null)]
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 2 [ label=<
Index
I2
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 2 -> 1 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; +}’ +V +not-distinct-from-tests;EXPLAIN select * from t1 WHERE 20 is not distinct from col1· +«̰… · ¯è³(50…¨8J@ lCOVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER _.COL1 NOT_DISTINCT_FROM promote(@c6 AS INT) | FETCH© digraph G { + fontname=courier; + rankdir=BT; + splines=polyline; + 1 [ label=<
Fetch Records
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(INT AS ID, )" ]; + 2 [ label=<
Predicate Filter
WHERE q61.COL1 NOT_DISTINCT_FROM promote(@c6 AS INT)
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 3 [ label=<
Covering Index Scan
range: <-∞, ∞>
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 4 [ label=<
Index
I1
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 3 -> 2 [ label=< q61> label="q61" 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=< q63> label="q63" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; +}Œ +_ +not-distinct-from-testsDEXPLAIN select count(*) from t1 WHERE null is not distinct from null¨ +Ó¾¥ÈÌ ¡Ìæ (<0þ¼Æ8`@ƒISCAN(I2 <,>) | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)‚digraph G { + fontname=courier; + rankdir=BT; + splines=polyline; + 1 [ label=<
Value Computation
MAP (coalesce_long(q6._0._0, promote(0l AS LONG)) AS _0)
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; + 2 [ label=<
Value Computation
$q6 OR NULL
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 3 [ label=<
Streaming Aggregate
COLLECT (count_star(*) AS _0)
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 4 [ label=<
Value Computation
MAP (q2 AS _0)
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, AS _0)" ]; + 5 [ label=<
Index Scan
range: <-∞, ∞>
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 6 [ label=<
Index
I2
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q88> label="q88" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 -> 4 [ label=< q2> label="q2" 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" ]; + 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; +}Ø +[ +not-distinct-from-tests@EXPLAIN select count(*) from t1 WHERE 10 is not distinct from 10ø +Ý®„«Ü £žÓ (>0¯Íé8v@ÏCOVERING(I2 <,> -> [COL2: KEY[0], ID: KEY[2]]) | FILTER @c9 NOT_DISTINCT_FROM @c9 | FETCH | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)†digraph G { + fontname=courier; + rankdir=BT; + splines=polyline; + 1 [ label=<
Value Computation
MAP (coalesce_long(q6._0._0, promote(0l AS LONG)) AS _0)
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; + 2 [ label=<
Value Computation
$q6 OR NULL
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 3 [ label=<
Streaming Aggregate
COLLECT (count_star(*) AS _0)
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 4 [ label=<
Value Computation
MAP (q67 AS _0)
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, AS _0)" ]; + 5 [ label=<
Fetch Records
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(INT AS ID, )" ]; + 6 [ label=<
Predicate Filter
WHERE @c9 NOT_DISTINCT_FROM @c9
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 7 [ label=<
Covering Index Scan
range: <-∞, ∞>
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 8 [ label=<
Index
I2
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q113> label="q113" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 -> 4 [ label=< q67> label="q67" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 6 -> 5 [ label=< q74> label="q74" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 7 -> 6 [ label=< q72> label="q72" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 8 -> 7 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; +} \ No newline at end of file diff --git a/yaml-tests/src/test/resources/distinct-from.metrics.yaml b/yaml-tests/src/test/resources/distinct-from.metrics.yaml new file mode 100644 index 0000000000..d2ab107cff --- /dev/null +++ b/yaml-tests/src/test/resources/distinct-from.metrics.yaml @@ -0,0 +1,130 @@ +distinct-from-tests: +- query: EXPLAIN select * from t1 WHERE col2 is distinct from null + explain: ISCAN(I2 ([null],>) + task_count: 668 + task_total_time_ms: 209 + transform_count: 182 + transform_time_ms: 132 + transform_yield_count: 55 + insert_time_ms: 12 + insert_new_count: 69 + insert_reused_count: 9 +- query: EXPLAIN select * from t1 WHERE col1 is DISTINCT from 10 + explain: 'COVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER _.COL1 IS_DISTINCT_FROM + promote(@c10 AS INT) | FETCH' + task_count: 683 + task_total_time_ms: 41 + transform_count: 182 + transform_time_ms: 14 + transform_yield_count: 53 + insert_time_ms: 3 + insert_new_count: 74 + insert_reused_count: 9 +- query: EXPLAIN select * from t1 WHERE null is distinct from col2 + explain: ISCAN(I2 ([null],>) + task_count: 668 + task_total_time_ms: 209 + transform_count: 182 + transform_time_ms: 134 + transform_yield_count: 55 + insert_time_ms: 12 + insert_new_count: 69 + insert_reused_count: 9 +- query: EXPLAIN select * from t1 WHERE 10 is distinct from col1 + explain: 'COVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER _.COL1 IS_DISTINCT_FROM + promote(@c6 AS INT) | FETCH' + task_count: 683 + task_total_time_ms: 39 + transform_count: 182 + transform_time_ms: 14 + transform_yield_count: 53 + insert_time_ms: 3 + insert_new_count: 74 + insert_reused_count: 9 +- query: EXPLAIN select * from t1 WHERE null is distinct from null + explain: 'COVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER false | FETCH' + task_count: 721 + task_total_time_ms: 207 + transform_count: 192 + transform_time_ms: 131 + transform_yield_count: 56 + insert_time_ms: 15 + insert_new_count: 81 + insert_reused_count: 10 +- query: EXPLAIN select * from t1 WHERE 10 is distinct from 10 + explain: 'COVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER @c6 IS_DISTINCT_FROM + @c6 | FETCH' + task_count: 721 + task_total_time_ms: 207 + transform_count: 192 + transform_time_ms: 135 + transform_yield_count: 56 + insert_time_ms: 13 + insert_new_count: 81 + insert_reused_count: 10 +not-distinct-from-tests: +- query: EXPLAIN select * from t1 WHERE col2 is not distinct from null + explain: ISCAN(I2 [[null],[null]]) + task_count: 668 + task_total_time_ms: 47 + transform_count: 181 + transform_time_ms: 17 + transform_yield_count: 55 + insert_time_ms: 3 + insert_new_count: 69 + insert_reused_count: 9 +- query: EXPLAIN select * from t1 WHERE col1 is not distinct from 20 + explain: 'COVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER _.COL1 NOT_DISTINCT_FROM + promote(@c11 AS INT) | FETCH' + task_count: 683 + task_total_time_ms: 48 + transform_count: 183 + transform_time_ms: 18 + transform_yield_count: 53 + insert_time_ms: 3 + insert_new_count: 74 + insert_reused_count: 9 +- query: EXPLAIN select * from t1 WHERE null is not distinct from col2 + explain: ISCAN(I2 [[null],[null]]) + task_count: 668 + task_total_time_ms: 46 + transform_count: 181 + transform_time_ms: 17 + transform_yield_count: 55 + insert_time_ms: 3 + insert_new_count: 69 + insert_reused_count: 9 +- query: EXPLAIN select * from t1 WHERE 20 is not distinct from col1 + explain: 'COVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER _.COL1 NOT_DISTINCT_FROM + promote(@c6 AS INT) | FETCH' + task_count: 683 + task_total_time_ms: 27 + transform_count: 183 + transform_time_ms: 11 + transform_yield_count: 53 + insert_time_ms: 2 + insert_new_count: 74 + insert_reused_count: 9 +- query: EXPLAIN select count(*) from t1 WHERE null is not distinct from null + explain: ISCAN(I2 <,>) | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY + NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0) + task_count: 723 + task_total_time_ms: 57 + transform_count: 204 + transform_time_ms: 26 + transform_yield_count: 60 + insert_time_ms: 3 + insert_new_count: 96 + insert_reused_count: 8 +- query: EXPLAIN select count(*) from t1 WHERE 10 is not distinct from 10 + explain: 'COVERING(I2 <,> -> [COL2: KEY[0], ID: KEY[2]]) | FILTER @c9 NOT_DISTINCT_FROM + @c9 | FETCH | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | + MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)' + task_count: 861 + task_total_time_ms: 59 + transform_count: 220 + transform_time_ms: 24 + transform_yield_count: 62 + insert_time_ms: 3 + insert_new_count: 118 + insert_reused_count: 6 diff --git a/yaml-tests/src/test/resources/distinct-from.yamsql b/yaml-tests/src/test/resources/distinct-from.yamsql new file mode 100644 index 0000000000..a042d07481 --- /dev/null +++ b/yaml-tests/src/test/resources/distinct-from.yamsql @@ -0,0 +1,101 @@ +# +# distinct-from.yamsql +# +# This source file is part of the FoundationDB open source project +# +# Copyright 2021-2024 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 +--- +schema_template: + create table t1(id integer, col1 integer, col2 integer, primary key(id)) + create index i1 as select col1 from t1 + create index cnt as select count(*) from t1 + create index i2 as select col2 from t1 +--- +setup: + steps: + - query: INSERT INTO T1 + VALUES (1, 10, 1), + (2, 10, null), + (3, 10, 3), + (4, 10, null), + (5, 10, 5), + (6, 20, null), + (7, 20, null), + (8, 20, null), + (9, 20, 9), + (10, 20, 10) +--- +test_block: + name: distinct-from-tests + tests: + - + - query: select * from t1 WHERE col2 is distinct from null + - explain: "ISCAN(I2 ([null],>)" + - result: [{ID: 1, 10, 1}, {ID: 3, 10, 3}, {ID: 5, 10, 5}, {ID: 9, 20, 9}, {ID: 10, 20, 10}] + - + - query: select * from t1 WHERE col1 is DISTINCT from 10 + - explain: "COVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER _.COL1 IS_DISTINCT_FROM promote(@c10 AS INT) | FETCH" + - result: [{ID: 6, 20, !null }, {ID: 7, 20, !null }, {ID: 8, 20, !null }, {ID: 9, 20, 9}, {ID: 10, 20, 10}] + - + - query: select * from t1 WHERE null is distinct from col2 + - explain: "ISCAN(I2 ([null],>)" + - result: [{ID: 1, 10, 1}, {ID: 3, 10, 3}, {ID: 5, 10, 5}, {ID: 9, 20, 9}, {ID: 10, 20, 10}] + - + - query: select * from t1 WHERE 10 is distinct from col1 + - explain: "COVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER _.COL1 IS_DISTINCT_FROM promote(@c6 AS INT) | FETCH" + - result: [{ID: 6, 20, !null }, {ID: 7, 20, !null }, {ID: 8, 20, !null }, {ID: 9, 20, 9}, {ID: 10, 20, 10}] + - + - query: select * from t1 WHERE null is distinct from null + - explain: "COVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER false | FETCH" + - result: [] + - + - query: select * from t1 WHERE 10 is distinct from 10 + - explain: "COVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER @c6 IS_DISTINCT_FROM @c6 | FETCH" + - result: [] + +--- +test_block: + name: not-distinct-from-tests + tests: + - + - query: select * from t1 WHERE col2 is not distinct from null + - explain: "ISCAN(I2 [[null],[null]])" + - result: [{ID: 2, 10, !null }, {ID: 4, 10, !null }, {ID: 6, 20, !null }, {ID: 7, 20, !null }, {ID: 8, 20, !null }] + - + - query: select * from t1 WHERE col1 is not distinct from 20 + - explain: "COVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER _.COL1 NOT_DISTINCT_FROM promote(@c11 AS INT) | FETCH" + - result: [{ID: 6, 20, !null }, {ID: 7, 20, !null }, {ID: 8, 20, !null }, {ID: 9, 20, 9}, {ID: 10, 20, 10}] + - + - query: select * from t1 WHERE null is not distinct from col2 + - explain: "ISCAN(I2 [[null],[null]])" + - result: [{ID: 2, 10, !null }, {ID: 4, 10, !null }, {ID: 6, 20, !null }, {ID: 7, 20, !null }, {ID: 8, 20, !null }] + - + - query: select * from t1 WHERE 20 is not distinct from col1 + - explain: "COVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER _.COL1 NOT_DISTINCT_FROM promote(@c6 AS INT) | FETCH" + - result: [{ID: 6, 20, !null }, {ID: 7, 20, !null }, {ID: 8, 20, !null }, {ID: 9, 20, 9}, {ID: 10, 20, 10}] + - + - query: select count(*) from t1 WHERE null is not distinct from null + - explain: "ISCAN(I2 <,>) | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)" + - result: [{10}] + - + - query: select count(*) from t1 WHERE 10 is not distinct from 10 + - explain: "COVERING(I2 <,> -> [COL2: KEY[0], ID: KEY[2]]) | FILTER @c9 NOT_DISTINCT_FROM @c9 | FETCH | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)" + - result: [{10}] +... From 6e540c1b81244ad57cb9ff24a57322ba4d3ca413 Mon Sep 17 00:00:00 2001 From: Pengpeng Lu Date: Mon, 2 Jun 2025 17:08:21 -0700 Subject: [PATCH 07/16] remove standard test --- .../recordlayer/query/StandardQueryTests.java | 205 +----------------- 1 file changed, 1 insertion(+), 204 deletions(-) diff --git a/fdb-relational-core/src/test/java/com/apple/foundationdb/relational/recordlayer/query/StandardQueryTests.java b/fdb-relational-core/src/test/java/com/apple/foundationdb/relational/recordlayer/query/StandardQueryTests.java index a04f2cac93..6d2a964b37 100644 --- a/fdb-relational-core/src/test/java/com/apple/foundationdb/relational/recordlayer/query/StandardQueryTests.java +++ b/fdb-relational-core/src/test/java/com/apple/foundationdb/relational/recordlayer/query/StandardQueryTests.java @@ -880,210 +880,7 @@ void aliasingTableToResolveAmbiguityWorks() throws Exception { } } } - - @Test - void testDistinctFrom() throws Exception { - final String schema = "CREATE TYPE AS STRUCT contact_detail(phone_number string, address string) " + - "CREATE TABLE student(id bigint, name string, contact contact_detail, score bigint, primary key(id))"; - try (var ddl = Ddl.builder().database(URI.create("/TEST/QT")).relationalExtension(relationalExtension).schemaTemplate(schema).build()) { - try (var statement = ddl.setSchemaAndGetConnection().createStatement()) { - final var row1 = EmbeddedRelationalStruct.newBuilder() - .addLong("ID", 1L) - .addString("NAME", "Alice") - .addLong("SCORE", 100) - .build(); - final var row2 = EmbeddedRelationalStruct.newBuilder() - .addLong("ID", 2L) - .addString("NAME", "Bob") - .build(); - Assertions.assertEquals(1, statement.executeInsert("STUDENT", row1), "Incorrect insertion count"); - Assertions.assertEquals(1, statement.executeInsert("STUDENT", row2), "Incorrect insertion count"); - - Assertions.assertTrue(statement.execute("SELECT * from STUDENT WHERE score is distinct from null"), "Did not return a result set from a select statement!"); - try (final RelationalResultSet resultSet = statement.getResultSet()) { - ResultSetAssert.assertThat(resultSet) - .hasNextRow() - .hasColumn("NAME", "Alice") - .hasNoNextRow(); - } - - Assertions.assertTrue(statement.execute("SELECT * from STUDENT WHERE score is distinct from 100"), "Did not return a result set from a select statement!"); - try (final RelationalResultSet resultSet = statement.getResultSet()) { - ResultSetAssert.assertThat(resultSet) - .hasNextRow() - .hasColumn("NAME", "Bob") - .hasNoNextRow(); - } - - Assertions.assertTrue(statement.execute("SELECT * from STUDENT f WHERE null is distinct from score"), "Did not return a result set from a select statement!"); - try (final RelationalResultSet resultSet = statement.getResultSet()) { - ResultSetAssert.assertThat(resultSet) - .hasNextRow() - .hasColumn("NAME", "Alice") - .hasNoNextRow(); - } - - Assertions.assertTrue(statement.execute("SELECT * from STUDENT f WHERE 100 is distinct from score"), "Did not return a result set from a select statement!"); - try (final RelationalResultSet resultSet = statement.getResultSet()) { - ResultSetAssert.assertThat(resultSet) - .hasNextRow() - .hasColumn("NAME", "Bob") - .hasNoNextRow(); - } - - Assertions.assertTrue(statement.execute("SELECT * from STUDENT f WHERE 100 is distinct from 100"), "Did not return a result set from a select statement!"); - try (final RelationalResultSet resultSet = statement.getResultSet()) { - ResultSetAssert.assertThat(resultSet) - .hasNoNextRow(); - } - - Assertions.assertTrue(statement.execute("SELECT * from STUDENT f WHERE null is distinct from null"), "Did not return a result set from a select statement!"); - try (final RelationalResultSet resultSet = statement.getResultSet()) { - ResultSetAssert.assertThat(resultSet) - .hasNoNextRow(); - } - } - } - } - - @Test - void testNotDistinctFrom() throws Exception { - final String schema = "CREATE TYPE AS STRUCT contact_detail(phone_number string, address string) " + - "CREATE TABLE student(id bigint, name string, contact contact_detail, score bigint, primary key(id))"; - try (var ddl = Ddl.builder().database(URI.create("/TEST/QT")).relationalExtension(relationalExtension).schemaTemplate(schema).build()) { - try (var statement = ddl.setSchemaAndGetConnection().createStatement()) { - final var row1 = EmbeddedRelationalStruct.newBuilder() - .addLong("ID", 1L) - .addString("NAME", "Alice") - .addLong("SCORE", 100) - .build(); - final var row2 = EmbeddedRelationalStruct.newBuilder() - .addLong("ID", 2L) - .addString("NAME", "Bob") - .build(); - Assertions.assertEquals(1, statement.executeInsert("STUDENT", row1), "Incorrect insertion count"); - Assertions.assertEquals(1, statement.executeInsert("STUDENT", row2), "Incorrect insertion count"); - - Assertions.assertTrue(statement.execute("SELECT * from STUDENT WHERE score is not distinct from null"), "Did not return a result set from a select statement!"); - try (final RelationalResultSet resultSet = statement.getResultSet()) { - ResultSetAssert.assertThat(resultSet) - .hasNextRow() - .hasColumn("NAME", "Bob") - .hasNoNextRow(); - } - - Assertions.assertTrue(statement.execute("SELECT * from STUDENT WHERE score is not distinct from 100"), "Did not return a result set from a select statement!"); - try (final RelationalResultSet resultSet = statement.getResultSet()) { - ResultSetAssert.assertThat(resultSet) - .hasNextRow() - .hasColumn("NAME", "Alice") - .hasNoNextRow(); - } - - Assertions.assertTrue(statement.execute("SELECT * from STUDENT WHERE null is not distinct from score"), "Did not return a result set from a select statement!"); - try (final RelationalResultSet resultSet = statement.getResultSet()) { - ResultSetAssert.assertThat(resultSet) - .hasNextRow() - .hasColumn("NAME", "Bob") - .hasNoNextRow(); - } - - Assertions.assertTrue(statement.execute("SELECT * from STUDENT WHERE 100 is not distinct from score"), "Did not return a result set from a select statement!"); - try (final RelationalResultSet resultSet = statement.getResultSet()) { - ResultSetAssert.assertThat(resultSet) - .hasNextRow() - .hasColumn("NAME", "Alice") - .hasNoNextRow(); - } - - Assertions.assertTrue(statement.execute("SELECT * from STUDENT WHERE 100 is not distinct from 100"), "Did not return a result set from a select statement!"); - try (final RelationalResultSet resultSet = statement.getResultSet()) { - ResultSetAssert.assertThat(resultSet) - .hasNextRow() - .hasColumn("NAME", "Alice") - .hasNextRow() - .hasColumn("NAME", "Bob") - .hasNoNextRow(); - } - - Assertions.assertTrue(statement.execute("SELECT * from STUDENT WHERE null is not distinct from null"), "Did not return a result set from a select statement!"); - try (final RelationalResultSet resultSet = statement.getResultSet()) { - ResultSetAssert.assertThat(resultSet) - .hasNextRow() - .hasColumn("NAME", "Alice") - .hasNextRow() - .hasColumn("NAME", "Bob") - .hasNoNextRow(); - } - } - } - } - - @Test - void testExplainDistinctFrom() throws Exception { - final String schemaTemplate = "CREATE TYPE AS STRUCT contact_detail(phone_number string, address string) " + - "CREATE TABLE STUDENT(id bigint, name string, contact contact_detail, score bigint, primary key(id)) " + - "CREATE index score_idx as select score from STUDENT"; - try (var ddl = Ddl.builder().database(URI.create("/TEST/QT")).relationalExtension(relationalExtension).schemaTemplate(schemaTemplate).build()) { - try (var statement = ddl.setSchemaAndGetConnection().createStatement()) { - try (final RelationalResultSet resultSet = statement.executeQuery("EXPLAIN SELECT name FROM STUDENT where score is distinct from null")) { - resultSet.next(); - String plan = resultSet.getString(1); - assertThat(plan).matches("ISCAN\\(SCORE_IDX \\(\\[null\\],>\\) \\| MAP \\(_\\.NAME AS NAME\\)"); - } - } - try (var statement = ddl.setSchemaAndGetConnection().createStatement()) { - try (final RelationalResultSet resultSet = statement.executeQuery("EXPLAIN SELECT name FROM STUDENT where score is distinct from 100")) { - resultSet.next(); - String plan = resultSet.getString(1); - assertThat(plan).matches("COVERING\\(SCORE_IDX <,> -> \\[ID: KEY\\[.*], SCORE: KEY\\[.*]\\]\\) \\| FILTER _\\.SCORE IS_DISTINCT_FROM promote\\(@.* AS LONG\\) \\| FETCH \\| MAP \\(_\\.NAME AS NAME\\)"); - } - } - try (var statement = ddl.setSchemaAndGetConnection().createStatement()) { - try (final RelationalResultSet resultSet = statement.executeQuery("EXPLAIN SELECT name FROM STUDENT where null is distinct from score")) { - resultSet.next(); - String plan = resultSet.getString(1); - assertThat(plan).matches("ISCAN\\(SCORE_IDX \\(\\[null\\],>\\) \\| MAP \\(_\\.NAME AS NAME\\)"); - } - } - try (var statement = ddl.setSchemaAndGetConnection().createStatement()) { - try (final RelationalResultSet resultSet = statement.executeQuery("EXPLAIN SELECT name FROM STUDENT where 100 is distinct from score")) { - resultSet.next(); - String plan = resultSet.getString(1); - assertThat(plan).matches("COVERING\\(SCORE_IDX <,> -> \\[ID: KEY\\[.*], SCORE: KEY\\[.*]\\]\\) \\| FILTER _\\.SCORE IS_DISTINCT_FROM promote\\(@.* AS LONG\\) \\| FETCH \\| MAP \\(_\\.NAME AS NAME\\)"); - } - } - try (var statement = ddl.setSchemaAndGetConnection().createStatement()) { - try (final RelationalResultSet resultSet = statement.executeQuery("EXPLAIN SELECT name FROM STUDENT where score is not distinct from null")) { - resultSet.next(); - String plan = resultSet.getString(1); - assertThat(plan).matches("ISCAN\\(SCORE_IDX \\[\\[null\\],\\[null\\]\\]\\) \\| MAP \\(_\\.NAME AS NAME\\)"); - } - } - try (var statement = ddl.setSchemaAndGetConnection().createStatement()) { - try (final RelationalResultSet resultSet = statement.executeQuery("EXPLAIN SELECT name FROM STUDENT where score is not distinct from 100")) { - resultSet.next(); - String plan = resultSet.getString(1); - assertThat(plan).matches("COVERING\\(SCORE_IDX <,> -> \\[ID: KEY\\[.*], SCORE: KEY\\[.*]\\]\\) \\| FILTER _\\.SCORE NOT_DISTINCT_FROM promote\\(@.* AS LONG\\) \\| FETCH \\| MAP \\(_\\.NAME AS NAME\\)"); - } - } - try (var statement = ddl.setSchemaAndGetConnection().createStatement()) { - try (final RelationalResultSet resultSet = statement.executeQuery("EXPLAIN SELECT name FROM STUDENT where null is not distinct from score")) { - resultSet.next(); - String plan = resultSet.getString(1); - assertThat(plan).matches("ISCAN\\(SCORE_IDX \\[\\[null\\],\\[null\\]\\]\\) \\| MAP \\(_\\.NAME AS NAME\\)"); - } - } - try (var statement = ddl.setSchemaAndGetConnection().createStatement()) { - try (final RelationalResultSet resultSet = statement.executeQuery("EXPLAIN SELECT name FROM STUDENT where 100 is not distinct from score")) { - resultSet.next(); - String plan = resultSet.getString(1); - assertThat(plan).matches("COVERING\\(SCORE_IDX <,> -> \\[ID: KEY\\[.*], SCORE: KEY\\[.*]\\]\\) \\| FILTER _\\.SCORE NOT_DISTINCT_FROM promote\\(@.* AS LONG\\) \\| FETCH \\| MAP \\(_\\.NAME AS NAME\\)"); - } - } - } - } - + @Test void testBitmap() throws Exception { final String query = "SELECT BITMAP_CONSTRUCT_AGG(BITMAP_BIT_POSITION(uid)) as bitmap, category, BITMAP_BUCKET_OFFSET(uid) as offset FROM T1\n" + From 3c537c152aa90de0b528777b88905fd6c444653f Mon Sep 17 00:00:00 2001 From: Pengpeng Lu Date: Mon, 2 Jun 2025 17:50:33 -0700 Subject: [PATCH 08/16] remove --- .../relational/recordlayer/query/StandardQueryTests.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fdb-relational-core/src/test/java/com/apple/foundationdb/relational/recordlayer/query/StandardQueryTests.java b/fdb-relational-core/src/test/java/com/apple/foundationdb/relational/recordlayer/query/StandardQueryTests.java index 6d2a964b37..61000544f7 100644 --- a/fdb-relational-core/src/test/java/com/apple/foundationdb/relational/recordlayer/query/StandardQueryTests.java +++ b/fdb-relational-core/src/test/java/com/apple/foundationdb/relational/recordlayer/query/StandardQueryTests.java @@ -880,7 +880,7 @@ void aliasingTableToResolveAmbiguityWorks() throws Exception { } } } - + @Test void testBitmap() throws Exception { final String query = "SELECT BITMAP_CONSTRUCT_AGG(BITMAP_BIT_POSITION(uid)) as bitmap, category, BITMAP_BUCKET_OFFSET(uid) as offset FROM T1\n" + From 1daf2499f7dae9d22f9a4478a5448417edb54cb1 Mon Sep 17 00:00:00 2001 From: Pengpeng Lu Date: Thu, 24 Jul 2025 11:38:56 -0700 Subject: [PATCH 09/16] save --- .../plan/cascades/values/RelOpValue.java | 94 +++++----- .../src/main/proto/record_query_plan.proto | 143 ++++++++-------- .../src/test/java/YamlIntegrationTests.java | 1 + .../resources/distinct-from.metrics.binpb | 162 +----------------- .../test/resources/distinct-from.metrics.yaml | 125 +------------- .../src/test/resources/distinct-from.yamsql | 51 +----- 6 files changed, 131 insertions(+), 445 deletions(-) diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/RelOpValue.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/RelOpValue.java index 9e6b9b7a9e..9042c74338 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/RelOpValue.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/RelOpValue.java @@ -184,6 +184,7 @@ private static Optional promoteOperandsAndCreatePredicate(@Nulla @Nonnull Value leftChild, @Nonnull Value rightChild, @Nonnull final Comparisons.Type comparisonType) { +/* if (leftChild.getResultType().getTypeCode() == Type.TypeCode.NULL && rightChild.getResultType().getTypeCode() == Type.TypeCode.NULL) { if (comparisonType == Comparisons.Type.NOT_DISTINCT_FROM) { return Optional.of(ConstantPredicate.TRUE); @@ -191,6 +192,11 @@ private static Optional promoteOperandsAndCreatePredicate(@Nulla return Optional.of(ConstantPredicate.FALSE); } } + + */ + + + // maximumType may return null, but only for non-primitive types which is not possible here final var maxtype = Verify.verifyNotNull(Type.maximumType(leftChild.getResultType(), rightChild.getResultType())); @@ -299,6 +305,8 @@ private static Value encapsulate(@Nonnull final String functionName, } else { final Typed arg1 = arguments.get(1); final Type res1 = arg1.getResultType(); + + /* if ("isDistinctFrom".equals(functionName)) { if (res0.getTypeCode() == Type.TypeCode.NULL && res1.getTypeCode() != Type.TypeCode.NULL) { return encapsulate("notNull", Comparisons.Type.NOT_NULL, List.of(arg1)); @@ -313,11 +321,15 @@ private static Value encapsulate(@Nonnull final String functionName, return encapsulate("isNull", Comparisons.Type.IS_NULL, List.of(arg0)); } } + + */ + SemanticException.check(res1.isPrimitive() || res1.isEnum() || res1.isUuid(), SemanticException.ErrorCode.COMPARAND_TO_COMPARISON_IS_OF_COMPLEX_TYPE); final BinaryPhysicalOperator physicalOperator = getBinaryOperatorMap().get(new BinaryComparisonSignature(comparisonType, res0.getTypeCode(), res1.getTypeCode())); + System.out.println("comparisonType:" + comparisonType + " res0:" + res0.getTypeCode() + " res1:" + res1.getTypeCode()); Verify.verifyNotNull(physicalOperator, "unable to encapsulate comparison operation due to type mismatch(es)"); return new BinaryRelOpValue(functionName, @@ -949,43 +961,42 @@ private enum BinaryPhysicalOperator { GTE_NID(Comparisons.Type.GREATER_THAN_OR_EQUALS, Type.TypeCode.NULL, Type.TypeCode.UUID, (l, r) -> null), GTE_IDN(Comparisons.Type.GREATER_THAN_OR_EQUALS, Type.TypeCode.UUID, Type.TypeCode.NULL, (l, r) -> null), - IS_DISTINCT_FROM_BU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.BOOLEAN, Type.TypeCode.UNKNOWN, (l, r) -> true), + IS_DISTINCT_FROM_BU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.BOOLEAN, Type.TypeCode.NULL, (l, r) -> Objects.nonNull(l)), IS_DISTINCT_FROM_BB(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.BOOLEAN, Type.TypeCode.BOOLEAN, (l, r) -> (boolean)l != (boolean)r), - IS_DISTINCT_FROM_IU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.INT, Type.TypeCode.UNKNOWN, (l, r) -> true), + IS_DISTINCT_FROM_IU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.INT, Type.TypeCode.NULL, (l, r) -> Objects.nonNull(l)), IS_DISTINCT_FROM_II(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.INT, Type.TypeCode.INT, (l, r) -> (int)l != (int)r), IS_DISTINCT_FROM_IL(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.INT, Type.TypeCode.LONG, (l, r) -> (int)l != (long)r), IS_DISTINCT_FROM_IF(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.INT, Type.TypeCode.FLOAT, (l, r) -> (int)l != (float)r), IS_DISTINCT_FROM_ID(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.INT, Type.TypeCode.DOUBLE, (l, r) -> (int)l != (double)r), - IS_DISTINCT_FROM_LU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.LONG, Type.TypeCode.UNKNOWN, (l, r) -> true), + IS_DISTINCT_FROM_LU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.LONG, Type.TypeCode.NULL, (l, r) -> Objects.nonNull(l)), IS_DISTINCT_FROM_LI(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.LONG, Type.TypeCode.INT, (l, r) -> (long)l != (int)r), IS_DISTINCT_FROM_LL(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.LONG, Type.TypeCode.LONG, (l, r) -> (long)l != (long)r), IS_DISTINCT_FROM_LF(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.LONG, Type.TypeCode.FLOAT, (l, r) -> (long)l != (float)r), IS_DISTINCT_FROM_LD(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.LONG, Type.TypeCode.DOUBLE, (l, r) -> (long)l != (double)r), - IS_DISTINCT_FROM_FU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.FLOAT, Type.TypeCode.UNKNOWN, (l, r) -> true), + IS_DISTINCT_FROM_FU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.FLOAT, Type.TypeCode.NULL, (l, r) -> Objects.nonNull(l)), IS_DISTINCT_FROM_FI(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.FLOAT, Type.TypeCode.INT, (l, r) -> (float)l != (int)r), IS_DISTINCT_FROM_FL(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.FLOAT, Type.TypeCode.LONG, (l, r) -> (float)l != (long)r), IS_DISTINCT_FROM_FF(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.FLOAT, Type.TypeCode.FLOAT, (l, r) -> (float)l != (float)r), IS_DISTINCT_FROM_FD(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.FLOAT, Type.TypeCode.DOUBLE, (l, r) -> (float)l != (double)r), - IS_DISTINCT_FROM_DU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.DOUBLE, Type.TypeCode.UNKNOWN, (l, r) -> true), + IS_DISTINCT_FROM_DU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.DOUBLE, Type.TypeCode.NULL, (l, r) -> Objects.nonNull(l)), IS_DISTINCT_FROM_DI(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.DOUBLE, Type.TypeCode.INT, (l, r) -> (double)l != (int)r), IS_DISTINCT_FROM_DL(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.DOUBLE, Type.TypeCode.LONG, (l, r) -> (double)l != (long)r), IS_DISTINCT_FROM_DF(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.DOUBLE, Type.TypeCode.FLOAT, (l, r) -> (double)l != (float)r), IS_DISTINCT_FROM_DD(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.DOUBLE, Type.TypeCode.DOUBLE, (l, r) -> (double)l != (double)r), - IS_DISTINCT_FROM_SU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.STRING, Type.TypeCode.UNKNOWN, (l, r) -> true), + IS_DISTINCT_FROM_SU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.STRING, Type.TypeCode.NULL, (l, r) -> Objects.nonNull(l)), IS_DISTINCT_FROM_SS(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.STRING, Type.TypeCode.STRING, (l, r) -> !l.equals(r)), // TODO: locale-aware comparison - IS_DISTINCT_FROM_UU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.UNKNOWN, (l, r) -> false), - IS_DISTINCT_FROM_UB(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.BOOLEAN, (l, r) -> true), - IS_DISTINCT_FROM_UI(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.INT, (l, r) -> true), - IS_DISTINCT_FROM_UL(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.LONG, (l, r) -> true), - IS_DISTINCT_FROM_UF(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.FLOAT, (l, r) -> true), - IS_DISTINCT_FROM_UD(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.DOUBLE, (l, r) -> true), - IS_DISTINCT_FROM_US(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.STRING, (l, r) -> true), - IS_DISTINCT_FROM_UV(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.VERSION, (l, r) -> true), - IS_DISTINCT_FROM_VU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.VERSION, Type.TypeCode.UNKNOWN, (l, r) -> null), + IS_DISTINCT_FROM_UB(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.BOOLEAN, (l, r) -> Objects.nonNull(r)), + IS_DISTINCT_FROM_UI(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.INT, (l, r) -> Objects.nonNull(r)), + IS_DISTINCT_FROM_UL(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.LONG, (l, r) -> Objects.nonNull(r)), + IS_DISTINCT_FROM_UF(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.FLOAT, (l, r) -> Objects.nonNull(r)), + IS_DISTINCT_FROM_UD(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.DOUBLE, (l, r) -> Objects.nonNull(r)), + IS_DISTINCT_FROM_US(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.STRING, (l, r) -> Objects.nonNull(r)), + IS_DISTINCT_FROM_UV(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.VERSION, (l, r) -> Objects.nonNull(r)), + IS_DISTINCT_FROM_VU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.VERSION, Type.TypeCode.NULL, (l, r) -> null), IS_DISTINCT_FROM_VV(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.VERSION, Type.TypeCode.VERSION, (l, r) -> !l.equals(r)), - IS_DISTINCT_FROM_BYU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.BYTES, Type.TypeCode.UNKNOWN, (l, r) -> null), + IS_DISTINCT_FROM_BYU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.BYTES, Type.TypeCode.NULL, (l, r) -> Objects.nonNull(l)), IS_DISTINCT_FROM_BYBY(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.BYTES, Type.TypeCode.BYTES, (l, r) -> Comparisons.evalComparison(Comparisons.Type.IS_DISTINCT_FROM, l, r)), - IS_DISTINCT_FROM_UBY(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.BYTES, (l, r) -> true), + IS_DISTINCT_FROM_UBY(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.BYTES, (l, r) -> Objects.nonNull(r)), IS_DISTINCT_FROM_EE(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.ENUM, Type.TypeCode.ENUM, (l, r) -> Comparisons.evalComparison(Comparisons.Type.IS_DISTINCT_FROM, l, r)), IS_DISTINCT_FROM_ES(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.ENUM, Type.TypeCode.STRING, (l, r) -> { final var otherValue = PromoteValue.PhysicalOperator.stringToEnumValue(((Descriptors.EnumValueDescriptor) l).getType(), (String) r); @@ -995,53 +1006,52 @@ private enum BinaryPhysicalOperator { final var otherValue = PromoteValue.PhysicalOperator.stringToEnumValue(((Descriptors.EnumValueDescriptor) r).getType(), (String) l); return Comparisons.evalComparison(Comparisons.Type.EQUALS, otherValue, r); }), - IS_DISTINCT_FROM_EU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.ENUM, Type.TypeCode.UNKNOWN, (l, r) -> true), - IS_DISTINCT_FROM_UE(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.ENUM, (l, r) -> true), + IS_DISTINCT_FROM_EU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.ENUM, Type.TypeCode.NULL, (l, r) -> Objects.nonNull(l)), + IS_DISTINCT_FROM_UE(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.ENUM, (l, r) -> Objects.nonNull(r)), IS_DISTINCT_FROM_IDID(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.UUID, Type.TypeCode.UUID, (l, r) -> Comparisons.evalComparison(Comparisons.Type.IS_DISTINCT_FROM, l, r)), IS_DISTINCT_FROM_IDS(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.UUID, Type.TypeCode.STRING, (l, r) -> Comparisons.evalComparison(Comparisons.Type.IS_DISTINCT_FROM, l, PromoteValue.PhysicalOperator.stringToUuidValue((String) r))), IS_DISTINCT_FROM_SID(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.STRING, Type.TypeCode.UUID, (l, r) -> Comparisons.evalComparison(Comparisons.Type.IS_DISTINCT_FROM, PromoteValue.PhysicalOperator.stringToUuidValue((String) l), r)), - IS_DISTINCT_FROM_UID(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.UUID, (l, r) -> true), - IS_DISTINCT_FROM_IDU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.UUID, Type.TypeCode.UNKNOWN, (l, r) -> true), + IS_DISTINCT_FROM_UID(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.UUID, (l, r) -> Objects.nonNull(r)), + IS_DISTINCT_FROM_IDU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.UUID, Type.TypeCode.NULL, (l, r) -> Objects.nonNull(l)), IS_DISTINCT_FROM_NN(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.NULL, (l, r) -> false), - NOT_DISTINCT_FROM_BU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.BOOLEAN, Type.TypeCode.UNKNOWN, (l, r) -> false), + NOT_DISTINCT_FROM_BU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.BOOLEAN, Type.TypeCode.NULL, (l, r) -> Objects.isNull(l)), NOT_DISTINCT_FROM_BB(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.BOOLEAN, Type.TypeCode.BOOLEAN, (l, r) -> (boolean)l == (boolean)r), - NOT_DISTINCT_FROM_IU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.INT, Type.TypeCode.UNKNOWN, (l, r) -> false), + NOT_DISTINCT_FROM_IU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.INT, Type.TypeCode.NULL, (l, r) -> Objects.isNull(l)), NOT_DISTINCT_FROM_II(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.INT, Type.TypeCode.INT, (l, r) -> (int)l == (int)r), NOT_DISTINCT_FROM_IL(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.INT, Type.TypeCode.LONG, (l, r) -> (int)l == (long)r), NOT_DISTINCT_FROM_IF(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.INT, Type.TypeCode.FLOAT, (l, r) -> (int)l == (float)r), NOT_DISTINCT_FROM_ID(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.INT, Type.TypeCode.DOUBLE, (l, r) -> (int)l == (double)r), - NOT_DISTINCT_FROM_LU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.LONG, Type.TypeCode.UNKNOWN, (l, r) -> false), + NOT_DISTINCT_FROM_LU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.LONG, Type.TypeCode.NULL, (l, r) -> Objects.isNull(l)), NOT_DISTINCT_FROM_LI(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.LONG, Type.TypeCode.INT, (l, r) -> (long)l == (int)r), NOT_DISTINCT_FROM_LL(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.LONG, Type.TypeCode.LONG, (l, r) -> (long)l == (long)r), NOT_DISTINCT_FROM_LF(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.LONG, Type.TypeCode.FLOAT, (l, r) -> (long)l == (float)r), NOT_DISTINCT_FROM_LD(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.LONG, Type.TypeCode.DOUBLE, (l, r) -> (long)l == (double)r), - NOT_DISTINCT_FROM_FU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.FLOAT, Type.TypeCode.UNKNOWN, (l, r) -> false), + NOT_DISTINCT_FROM_FU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.FLOAT, Type.TypeCode.NULL, (l, r) -> Objects.isNull(l)), NOT_DISTINCT_FROM_FI(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.FLOAT, Type.TypeCode.INT, (l, r) -> (float)l == (int)r), NOT_DISTINCT_FROM_FL(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.FLOAT, Type.TypeCode.LONG, (l, r) -> (float)l == (long)r), NOT_DISTINCT_FROM_FF(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.FLOAT, Type.TypeCode.FLOAT, (l, r) -> (float)l == (float)r), NOT_DISTINCT_FROM_FD(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.FLOAT, Type.TypeCode.DOUBLE, (l, r) -> (float)l == (double)r), - NOT_DISTINCT_FROM_DU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.DOUBLE, Type.TypeCode.UNKNOWN, (l, r) -> false), + NOT_DISTINCT_FROM_DU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.DOUBLE, Type.TypeCode.NULL, (l, r) -> Objects.isNull(l)), NOT_DISTINCT_FROM_DI(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.DOUBLE, Type.TypeCode.INT, (l, r) -> (double)l == (int)r), NOT_DISTINCT_FROM_DL(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.DOUBLE, Type.TypeCode.LONG, (l, r) -> (double)l == (long)r), NOT_DISTINCT_FROM_DF(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.DOUBLE, Type.TypeCode.FLOAT, (l, r) -> (double)l == (float)r), NOT_DISTINCT_FROM_DD(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.DOUBLE, Type.TypeCode.DOUBLE, (l, r) -> (double)l == (double)r), - NOT_DISTINCT_FROM_SU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.STRING, Type.TypeCode.UNKNOWN, (l, r) -> false), + NOT_DISTINCT_FROM_SU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.STRING, Type.TypeCode.NULL, (l, r) -> Objects.isNull(l)), NOT_DISTINCT_FROM_SS(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.STRING, Type.TypeCode.STRING, Object::equals), // TODO: locale-aware comparison - NOT_DISTINCT_FROM_UU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.UNKNOWN, (l, r) -> true), - NOT_DISTINCT_FROM_UB(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.BOOLEAN, (l, r) -> false), - NOT_DISTINCT_FROM_UI(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.INT, (l, r) -> false), - NOT_DISTINCT_FROM_UL(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.LONG, (l, r) -> false), - NOT_DISTINCT_FROM_UF(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.FLOAT, (l, r) -> false), - NOT_DISTINCT_FROM_UD(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.DOUBLE, (l, r) -> false), - NOT_DISTINCT_FROM_US(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.STRING, (l, r) -> false), - NOT_DISTINCT_FROM_UV(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.VERSION, (l, r) -> false), - NOT_DISTINCT_FROM_VU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.VERSION, Type.TypeCode.UNKNOWN, (l, r) -> false), + NOT_DISTINCT_FROM_UB(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.BOOLEAN, (l, r) -> Objects.isNull(r)), + NOT_DISTINCT_FROM_UI(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.INT, (l, r) -> Objects.isNull(r)), + NOT_DISTINCT_FROM_UL(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.LONG, (l, r) -> Objects.isNull(r)), + NOT_DISTINCT_FROM_UF(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.FLOAT, (l, r) -> Objects.isNull(r)), + NOT_DISTINCT_FROM_UD(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.DOUBLE, (l, r) -> Objects.isNull(r)), + NOT_DISTINCT_FROM_US(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.STRING, (l, r) -> Objects.isNull(r)), + NOT_DISTINCT_FROM_UV(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.VERSION, (l, r) -> Objects.isNull(r)), + NOT_DISTINCT_FROM_VU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.VERSION, Type.TypeCode.NULL, (l, r) -> Objects.isNull(r)), NOT_DISTINCT_FROM_VV(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.VERSION, Type.TypeCode.VERSION, Object::equals), - NOT_DISTINCT_FROM_BYU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.BYTES, Type.TypeCode.UNKNOWN, (l, r) -> false), + NOT_DISTINCT_FROM_BYU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.BYTES, Type.TypeCode.NULL, (l, r) -> Objects.isNull(l)), NOT_DISTINCT_FROM_BYBY(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.BYTES, Type.TypeCode.BYTES, (l, r) -> Comparisons.evalComparison(Comparisons.Type.NOT_DISTINCT_FROM, l, r)), - NOT_DISTINCT_FROM_UBY(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.BYTES, (l, r) -> false), + NOT_DISTINCT_FROM_UBY(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.BYTES, (l, r) -> Objects.isNull(r)), NOT_DISTINCT_FROM_EE(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.ENUM, Type.TypeCode.ENUM, (l, r) -> Comparisons.evalComparison(Comparisons.Type.NOT_DISTINCT_FROM, l, r)), NOT_DISTINCT_FROM_ES(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.ENUM, Type.TypeCode.STRING, (l, r) -> { @@ -1052,14 +1062,14 @@ private enum BinaryPhysicalOperator { final var otherValue = PromoteValue.PhysicalOperator.stringToEnumValue(((Descriptors.EnumValueDescriptor) r).getType(), (String) l); return Comparisons.evalComparison(Comparisons.Type.NOT_DISTINCT_FROM, otherValue, r); }), - NOT_DISTINCT_FROM_EU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.ENUM, Type.TypeCode.UNKNOWN, (l, r) -> false), - NOT_DISTINCT_FROM_UE(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.ENUM, (l, r) -> false), + NOT_DISTINCT_FROM_EU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.ENUM, Type.TypeCode.NULL, (l, r) -> Objects.isNull(l)), + NOT_DISTINCT_FROM_UE(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.ENUM, (l, r) -> Objects.isNull(r)), NOT_DISTINCT_FROM_IDID(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UUID, Type.TypeCode.UUID, (l, r) -> Comparisons.evalComparison(Comparisons.Type.NOT_DISTINCT_FROM, l, r)), NOT_DISTINCT_FROM_IDS(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UUID, Type.TypeCode.STRING, (l, r) -> Comparisons.evalComparison(Comparisons.Type.NOT_DISTINCT_FROM, l, PromoteValue.PhysicalOperator.stringToUuidValue((String) r))), NOT_DISTINCT_FROM_SID(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.STRING, Type.TypeCode.UUID, (l, r) -> Comparisons.evalComparison(Comparisons.Type.NOT_DISTINCT_FROM, PromoteValue.PhysicalOperator.stringToUuidValue((String) l), r)), - NOT_DISTINCT_FROM_UID(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UNKNOWN, Type.TypeCode.UUID, (l, r) -> false), - NOT_DISTINCT_FROM_IDU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UUID, Type.TypeCode.UNKNOWN, (l, r) -> false), + NOT_DISTINCT_FROM_UID(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.UUID, (l, r) -> Objects.isNull(r)), + NOT_DISTINCT_FROM_IDU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UUID, Type.TypeCode.NULL, (l, r) -> Objects.isNull(l)), NOT_DISTINCT_FROM_NN(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.NULL, (l, r) -> true), diff --git a/fdb-record-layer-core/src/main/proto/record_query_plan.proto b/fdb-record-layer-core/src/main/proto/record_query_plan.proto index 6b790bc323..694d7ce112 100644 --- a/fdb-record-layer-core/src/main/proto/record_query_plan.proto +++ b/fdb-record-layer-core/src/main/proto/record_query_plan.proto @@ -1072,78 +1072,77 @@ message PBinaryRelOpValue { IS_DISTINCT_FROM_DD = 422; IS_DISTINCT_FROM_SU = 423; IS_DISTINCT_FROM_SS = 424; - IS_DISTINCT_FROM_UU = 425; - IS_DISTINCT_FROM_UB = 426; - IS_DISTINCT_FROM_UI = 427; - IS_DISTINCT_FROM_UL = 428; - IS_DISTINCT_FROM_UF = 429; - IS_DISTINCT_FROM_UD = 430; - IS_DISTINCT_FROM_US = 431; - IS_DISTINCT_FROM_UV = 432; - IS_DISTINCT_FROM_VU = 433; - IS_DISTINCT_FROM_VV = 434; - IS_DISTINCT_FROM_BYU = 435; - IS_DISTINCT_FROM_BYBY = 436; - IS_DISTINCT_FROM_UBY = 437; - IS_DISTINCT_FROM_EE = 438; - IS_DISTINCT_FROM_ES = 439; - IS_DISTINCT_FROM_SE = 440; - IS_DISTINCT_FROM_EU = 441; - IS_DISTINCT_FROM_UE = 442; - IS_DISTINCT_FROM_IDID = 443; - IS_DISTINCT_FROM_IDS = 444; - IS_DISTINCT_FROM_SID = 445; - IS_DISTINCT_FROM_UID = 446; - IS_DISTINCT_FROM_IDU = 447; - IS_DISTINCT_FROM_NN = 448; - NOT_DISTINCT_FROM_BU = 449; - NOT_DISTINCT_FROM_BB = 450; - NOT_DISTINCT_FROM_IU = 451; - NOT_DISTINCT_FROM_II = 452; - NOT_DISTINCT_FROM_IL = 453; - NOT_DISTINCT_FROM_IF = 454; - NOT_DISTINCT_FROM_ID = 455; - NOT_DISTINCT_FROM_LU = 456; - NOT_DISTINCT_FROM_LI = 457; - NOT_DISTINCT_FROM_LL = 458; - NOT_DISTINCT_FROM_LF = 459; - NOT_DISTINCT_FROM_LD = 460; - NOT_DISTINCT_FROM_FU = 461; - NOT_DISTINCT_FROM_FI = 462; - NOT_DISTINCT_FROM_FL = 463; - NOT_DISTINCT_FROM_FF = 464; - NOT_DISTINCT_FROM_FD = 465; - NOT_DISTINCT_FROM_DU = 466; - NOT_DISTINCT_FROM_DI = 467; - NOT_DISTINCT_FROM_DL = 468; - NOT_DISTINCT_FROM_DF = 469; - NOT_DISTINCT_FROM_DD = 470; - NOT_DISTINCT_FROM_SU = 471; - NOT_DISTINCT_FROM_SS = 472; - NOT_DISTINCT_FROM_UU = 473; - NOT_DISTINCT_FROM_UB = 474; - NOT_DISTINCT_FROM_UI = 475; - NOT_DISTINCT_FROM_UL = 476; - NOT_DISTINCT_FROM_UF = 477; - NOT_DISTINCT_FROM_UD = 478; - NOT_DISTINCT_FROM_US = 479; - NOT_DISTINCT_FROM_UV = 480; - NOT_DISTINCT_FROM_VU = 481; - NOT_DISTINCT_FROM_VV = 482; - NOT_DISTINCT_FROM_BYU = 483; - NOT_DISTINCT_FROM_BYBY = 484; - NOT_DISTINCT_FROM_UBY = 485; - NOT_DISTINCT_FROM_EE = 486; - NOT_DISTINCT_FROM_ES = 487; - NOT_DISTINCT_FROM_SE = 488; - NOT_DISTINCT_FROM_EU = 489; - NOT_DISTINCT_FROM_UE = 490; - NOT_DISTINCT_FROM_IDID = 491; - NOT_DISTINCT_FROM_IDS = 492; - NOT_DISTINCT_FROM_SID = 493; - NOT_DISTINCT_FROM_UID = 494; - NOT_DISTINCT_FROM_IDU = 495; - NOT_DISTINCT_FROM_NN = 496; + IS_DISTINCT_FROM_UB = 425; + IS_DISTINCT_FROM_UI = 426; + IS_DISTINCT_FROM_UL = 427; + IS_DISTINCT_FROM_UF = 428; + IS_DISTINCT_FROM_UD = 429; + IS_DISTINCT_FROM_US = 430; + IS_DISTINCT_FROM_UV = 431; + IS_DISTINCT_FROM_VU = 432; + IS_DISTINCT_FROM_VV = 433; + IS_DISTINCT_FROM_BYU = 434; + IS_DISTINCT_FROM_BYBY = 435; + IS_DISTINCT_FROM_UBY = 436; + IS_DISTINCT_FROM_EE = 437; + IS_DISTINCT_FROM_ES = 438; + IS_DISTINCT_FROM_SE = 439; + IS_DISTINCT_FROM_EU = 440; + IS_DISTINCT_FROM_UE = 441; + IS_DISTINCT_FROM_IDID = 442; + IS_DISTINCT_FROM_IDS = 443; + IS_DISTINCT_FROM_SID = 444; + IS_DISTINCT_FROM_UID = 445; + IS_DISTINCT_FROM_IDU = 446; + IS_DISTINCT_FROM_NN = 447; + NOT_DISTINCT_FROM_BU = 448; + NOT_DISTINCT_FROM_BB = 449; + NOT_DISTINCT_FROM_IU = 450; + NOT_DISTINCT_FROM_II = 451; + NOT_DISTINCT_FROM_IL = 452; + NOT_DISTINCT_FROM_IF = 453; + NOT_DISTINCT_FROM_ID = 454; + NOT_DISTINCT_FROM_LU = 455; + NOT_DISTINCT_FROM_LI = 456; + NOT_DISTINCT_FROM_LL = 457; + NOT_DISTINCT_FROM_LF = 458; + NOT_DISTINCT_FROM_LD = 459; + NOT_DISTINCT_FROM_FU = 460; + NOT_DISTINCT_FROM_FI = 461; + NOT_DISTINCT_FROM_FL = 462; + NOT_DISTINCT_FROM_FF = 463; + NOT_DISTINCT_FROM_FD = 464; + NOT_DISTINCT_FROM_DU = 465; + NOT_DISTINCT_FROM_DI = 466; + NOT_DISTINCT_FROM_DL = 467; + NOT_DISTINCT_FROM_DF = 468; + NOT_DISTINCT_FROM_DD = 469; + NOT_DISTINCT_FROM_SU = 470; + NOT_DISTINCT_FROM_SS = 471; + + NOT_DISTINCT_FROM_UB = 472; + NOT_DISTINCT_FROM_UI = 473; + NOT_DISTINCT_FROM_UL = 474; + NOT_DISTINCT_FROM_UF = 475; + NOT_DISTINCT_FROM_UD = 476; + NOT_DISTINCT_FROM_US = 477; + NOT_DISTINCT_FROM_UV = 478; + NOT_DISTINCT_FROM_VU = 479; + NOT_DISTINCT_FROM_VV = 480; + NOT_DISTINCT_FROM_BYU = 481; + NOT_DISTINCT_FROM_BYBY = 482; + NOT_DISTINCT_FROM_UBY = 483; + NOT_DISTINCT_FROM_EE = 484; + NOT_DISTINCT_FROM_ES = 485; + NOT_DISTINCT_FROM_SE = 486; + NOT_DISTINCT_FROM_EU = 487; + NOT_DISTINCT_FROM_UE = 488; + NOT_DISTINCT_FROM_IDID = 489; + NOT_DISTINCT_FROM_IDS = 490; + NOT_DISTINCT_FROM_SID = 491; + NOT_DISTINCT_FROM_UID = 492; + NOT_DISTINCT_FROM_IDU = 493; + NOT_DISTINCT_FROM_NN = 494; } optional PRelOpValue super = 1; optional PBinaryPhysicalOperator operator = 2; diff --git a/yaml-tests/src/test/java/YamlIntegrationTests.java b/yaml-tests/src/test/java/YamlIntegrationTests.java index 0c81cbcdb2..e345d8b484 100644 --- a/yaml-tests/src/test/java/YamlIntegrationTests.java +++ b/yaml-tests/src/test/java/YamlIntegrationTests.java @@ -195,6 +195,7 @@ void like(YamlTest.Runner runner) throws Exception { } @TestTemplate + @MaintainYamlTestConfig(YamlTestConfigFilters.CORRECT_EXPLAIN_AND_METRICS) void distinctFrom(YamlTest.Runner runner) throws Exception { runner.runYamsql("distinct-from.yamsql"); } diff --git a/yaml-tests/src/test/resources/distinct-from.metrics.binpb b/yaml-tests/src/test/resources/distinct-from.metrics.binpb index f0bd098956..d36b1acdc7 100644 --- a/yaml-tests/src/test/resources/distinct-from.metrics.binpb +++ b/yaml-tests/src/test/resources/distinct-from.metrics.binpb @@ -1,167 +1,11 @@ -£ -U -distinct-from-tests>EXPLAIN select * from t1 WHERE col2 is distinct from nullÉ -œ¬ƒüc¶ þÇ?(70ÆÙ€8E@ ISCAN(I2 ([null],>)”digraph G { - fontname=courier; - rankdir=BT; - splines=polyline; - 1 [ label=<
Index Scan
range: ((null), ∞>
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; - 2 [ label=<
Index
I2
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; - 2 -> 1 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -}Š -N -distinct-from-tests7EXPLAIN select * from t1 WHERE col1 is DISTINCT from 10· -«•Öî¶ ýÜã(50øþè8J@ lCOVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER _.COL1 IS_DISTINCT_FROM promote(@c10 AS INT) | FETCH© digraph G { - fontname=courier; - rankdir=BT; - splines=polyline; - 1 [ label=<
Fetch Records
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(INT AS ID, )" ]; - 2 [ label=<
Predicate Filter
WHERE q61.COL1 IS_DISTINCT_FROM promote(@c10 AS INT)
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; - 3 [ label=<
Covering Index Scan
range: <-∞, ∞>
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; - 4 [ label=<
Index
I1
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; - 3 -> 2 [ label=< q61> label="q61" 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=< q63> label="q63" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -}ž +ž P -distinct-from-tests9EXPLAIN select * from t1 WHERE null is distinct from col2É -œìÏ„d¶  »ô?(70ºÊ‹8E@ ISCAN(I2 ([null],>)”digraph G { +distinct-from-tests9EXPLAIN select * from t1 WHERE col2 is distinct from nullÉ +œß»§_¶ ð¨Ÿ:(70ñ¿’8E@ ISCAN(I2 ([null],>)”digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
Index Scan
range: ((null), ∞>
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; 2 [ label=<
Index
I2
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; 2 -> 1 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -}ˆ -N -distinct-from-tests7EXPLAIN select * from t1 WHERE 10 is distinct from col1µ -«ÕÎͶ µö(50º¥ì8J@ kCOVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER _.COL1 IS_DISTINCT_FROM promote(@c6 AS INT) | FETCH¨ digraph G { - fontname=courier; - rankdir=BT; - splines=polyline; - 1 [ label=<
Fetch Records
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(INT AS ID, )" ]; - 2 [ label=<
Predicate Filter
WHERE q61.COL1 IS_DISTINCT_FROM promote(@c6 AS INT)
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; - 3 [ label=<
Covering Index Scan
range: <-∞, ∞>
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; - 4 [ label=<
Index
I1
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; - 3 -> 2 [ label=< q61> label="q61" 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=< q63> label="q63" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -}¼ -P -distinct-from-tests9EXPLAIN select * from t1 WHERE null is distinct from nullç -ÑÌŒ“cÀ ããã>(80¡þ•8Q@ -ECOVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER false | FETCH€ digraph G { - fontname=courier; - rankdir=BT; - splines=polyline; - 1 [ label=<
Fetch Records
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(INT AS ID, )" ]; - 2 [ label=<
Predicate Filter
WHERE false
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; - 3 [ label=<
Covering Index Scan
range: <-∞, ∞>
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; - 4 [ label=<
Index
I1
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; - 3 -> 2 [ label=< q64> label="q64" 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=< q66> label="q66" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -}Þ -L -distinct-from-tests5EXPLAIN select * from t1 WHERE 10 is distinct from 10 -ÑÆ£‹cÀ É¢´@(80Í‚¡8Q@ -XCOVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER @c6 IS_DISTINCT_FROM @c6 | FETCH“ digraph G { - fontname=courier; - rankdir=BT; - splines=polyline; - 1 [ label=<
Fetch Records
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(INT AS ID, )" ]; - 2 [ label=<
Predicate Filter
WHERE @c6 IS_DISTINCT_FROM @c6
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; - 3 [ label=<
Covering Index Scan
range: <-∞, ∞>
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; - 4 [ label=<
Index
I1
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; - 3 -> 2 [ label=< q64> label="q64" 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=< q66> label="q66" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -}± -] -not-distinct-from-testsBEXPLAIN select * from t1 WHERE col2 is not distinct from nullÏ -œê§ñµ ðÆ´(70¢çÞ8E@ ISCAN(I2 [[null],[null]])”digraph G { - fontname=courier; - rankdir=BT; - splines=polyline; - 1 [ label=<
Index Scan
range: [(null), (null)]
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; - 2 [ label=<
Index
I2
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; - 2 -> 1 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -}” -V -not-distinct-from-tests;EXPLAIN select * from t1 WHERE col1 is not distinct from 20¹ -«¬ñƒ· á‹ö(50ߎë8J@ mCOVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER _.COL1 NOT_DISTINCT_FROM promote(@c11 AS INT) | FETCHª digraph G { - fontname=courier; - rankdir=BT; - splines=polyline; - 1 [ label=<
Fetch Records
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(INT AS ID, )" ]; - 2 [ label=<
Predicate Filter
WHERE q61.COL1 NOT_DISTINCT_FROM promote(@c11 AS INT)
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; - 3 [ label=<
Covering Index Scan
range: <-∞, ∞>
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; - 4 [ label=<
Index
I1
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; - 3 -> 2 [ label=< q61> label="q61" 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=< q63> label="q63" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -}¬ -X -not-distinct-from-tests=EXPLAIN select * from t1 WHERE null is not distinct from col2Ï -œõ뤵 ‹å˜(70õ¿æ8E@ ISCAN(I2 [[null],[null]])”digraph G { - fontname=courier; - rankdir=BT; - splines=polyline; - 1 [ label=<
Index Scan
range: [(null), (null)]
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; - 2 [ label=<
Index
I2
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; - 2 -> 1 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -}’ -V -not-distinct-from-tests;EXPLAIN select * from t1 WHERE 20 is not distinct from col1· -«̰… · ¯è³(50…¨8J@ lCOVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER _.COL1 NOT_DISTINCT_FROM promote(@c6 AS INT) | FETCH© digraph G { - fontname=courier; - rankdir=BT; - splines=polyline; - 1 [ label=<
Fetch Records
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(INT AS ID, )" ]; - 2 [ label=<
Predicate Filter
WHERE q61.COL1 NOT_DISTINCT_FROM promote(@c6 AS INT)
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; - 3 [ label=<
Covering Index Scan
range: <-∞, ∞>
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; - 4 [ label=<
Index
I1
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; - 3 -> 2 [ label=< q61> label="q61" 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=< q63> label="q63" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -}Œ -_ -not-distinct-from-testsDEXPLAIN select count(*) from t1 WHERE null is not distinct from null¨ -Ó¾¥ÈÌ ¡Ìæ (<0þ¼Æ8`@ƒISCAN(I2 <,>) | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)‚digraph G { - fontname=courier; - rankdir=BT; - splines=polyline; - 1 [ label=<
Value Computation
MAP (coalesce_long(q6._0._0, promote(0l AS LONG)) AS _0)
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; - 2 [ label=<
Value Computation
$q6 OR NULL
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 3 [ label=<
Streaming Aggregate
COLLECT (count_star(*) AS _0)
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
Value Computation
MAP (q2 AS _0)
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, AS _0)" ]; - 5 [ label=<
Index Scan
range: <-∞, ∞>
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; - 6 [ label=<
Index
I2
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; - 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q88> label="q88" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 5 -> 4 [ label=< q2> label="q2" 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" ]; - 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -}Ø -[ -not-distinct-from-tests@EXPLAIN select count(*) from t1 WHERE 10 is not distinct from 10ø -Ý®„«Ü £žÓ (>0¯Íé8v@ÏCOVERING(I2 <,> -> [COL2: KEY[0], ID: KEY[2]]) | FILTER @c9 NOT_DISTINCT_FROM @c9 | FETCH | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)†digraph G { - fontname=courier; - rankdir=BT; - splines=polyline; - 1 [ label=<
Value Computation
MAP (coalesce_long(q6._0._0, promote(0l AS LONG)) AS _0)
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; - 2 [ label=<
Value Computation
$q6 OR NULL
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 3 [ label=<
Streaming Aggregate
COLLECT (count_star(*) AS _0)
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
Value Computation
MAP (q67 AS _0)
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, AS _0)" ]; - 5 [ label=<
Fetch Records
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(INT AS ID, )" ]; - 6 [ label=<
Predicate Filter
WHERE @c9 NOT_DISTINCT_FROM @c9
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; - 7 [ label=<
Covering Index Scan
range: <-∞, ∞>
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; - 8 [ label=<
Index
I2
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; - 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q113> label="q113" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 5 -> 4 [ label=< q67> label="q67" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 6 -> 5 [ label=< q74> label="q74" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 7 -> 6 [ label=< q72> label="q72" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 8 -> 7 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; } \ No newline at end of file diff --git a/yaml-tests/src/test/resources/distinct-from.metrics.yaml b/yaml-tests/src/test/resources/distinct-from.metrics.yaml index d2ab107cff..e0adcb3637 100644 --- a/yaml-tests/src/test/resources/distinct-from.metrics.yaml +++ b/yaml-tests/src/test/resources/distinct-from.metrics.yaml @@ -1,130 +1,11 @@ distinct-from-tests: -- query: EXPLAIN select * from t1 WHERE col2 is distinct from null +- query: EXPLAIN select * from t1 WHERE col2 is distinct from null explain: ISCAN(I2 ([null],>) task_count: 668 - task_total_time_ms: 209 + task_total_time_ms: 199 transform_count: 182 - transform_time_ms: 132 + transform_time_ms: 122 transform_yield_count: 55 insert_time_ms: 12 insert_new_count: 69 insert_reused_count: 9 -- query: EXPLAIN select * from t1 WHERE col1 is DISTINCT from 10 - explain: 'COVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER _.COL1 IS_DISTINCT_FROM - promote(@c10 AS INT) | FETCH' - task_count: 683 - task_total_time_ms: 41 - transform_count: 182 - transform_time_ms: 14 - transform_yield_count: 53 - insert_time_ms: 3 - insert_new_count: 74 - insert_reused_count: 9 -- query: EXPLAIN select * from t1 WHERE null is distinct from col2 - explain: ISCAN(I2 ([null],>) - task_count: 668 - task_total_time_ms: 209 - transform_count: 182 - transform_time_ms: 134 - transform_yield_count: 55 - insert_time_ms: 12 - insert_new_count: 69 - insert_reused_count: 9 -- query: EXPLAIN select * from t1 WHERE 10 is distinct from col1 - explain: 'COVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER _.COL1 IS_DISTINCT_FROM - promote(@c6 AS INT) | FETCH' - task_count: 683 - task_total_time_ms: 39 - transform_count: 182 - transform_time_ms: 14 - transform_yield_count: 53 - insert_time_ms: 3 - insert_new_count: 74 - insert_reused_count: 9 -- query: EXPLAIN select * from t1 WHERE null is distinct from null - explain: 'COVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER false | FETCH' - task_count: 721 - task_total_time_ms: 207 - transform_count: 192 - transform_time_ms: 131 - transform_yield_count: 56 - insert_time_ms: 15 - insert_new_count: 81 - insert_reused_count: 10 -- query: EXPLAIN select * from t1 WHERE 10 is distinct from 10 - explain: 'COVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER @c6 IS_DISTINCT_FROM - @c6 | FETCH' - task_count: 721 - task_total_time_ms: 207 - transform_count: 192 - transform_time_ms: 135 - transform_yield_count: 56 - insert_time_ms: 13 - insert_new_count: 81 - insert_reused_count: 10 -not-distinct-from-tests: -- query: EXPLAIN select * from t1 WHERE col2 is not distinct from null - explain: ISCAN(I2 [[null],[null]]) - task_count: 668 - task_total_time_ms: 47 - transform_count: 181 - transform_time_ms: 17 - transform_yield_count: 55 - insert_time_ms: 3 - insert_new_count: 69 - insert_reused_count: 9 -- query: EXPLAIN select * from t1 WHERE col1 is not distinct from 20 - explain: 'COVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER _.COL1 NOT_DISTINCT_FROM - promote(@c11 AS INT) | FETCH' - task_count: 683 - task_total_time_ms: 48 - transform_count: 183 - transform_time_ms: 18 - transform_yield_count: 53 - insert_time_ms: 3 - insert_new_count: 74 - insert_reused_count: 9 -- query: EXPLAIN select * from t1 WHERE null is not distinct from col2 - explain: ISCAN(I2 [[null],[null]]) - task_count: 668 - task_total_time_ms: 46 - transform_count: 181 - transform_time_ms: 17 - transform_yield_count: 55 - insert_time_ms: 3 - insert_new_count: 69 - insert_reused_count: 9 -- query: EXPLAIN select * from t1 WHERE 20 is not distinct from col1 - explain: 'COVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER _.COL1 NOT_DISTINCT_FROM - promote(@c6 AS INT) | FETCH' - task_count: 683 - task_total_time_ms: 27 - transform_count: 183 - transform_time_ms: 11 - transform_yield_count: 53 - insert_time_ms: 2 - insert_new_count: 74 - insert_reused_count: 9 -- query: EXPLAIN select count(*) from t1 WHERE null is not distinct from null - explain: ISCAN(I2 <,>) | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY - NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0) - task_count: 723 - task_total_time_ms: 57 - transform_count: 204 - transform_time_ms: 26 - transform_yield_count: 60 - insert_time_ms: 3 - insert_new_count: 96 - insert_reused_count: 8 -- query: EXPLAIN select count(*) from t1 WHERE 10 is not distinct from 10 - explain: 'COVERING(I2 <,> -> [COL2: KEY[0], ID: KEY[2]]) | FILTER @c9 NOT_DISTINCT_FROM - @c9 | FETCH | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | - MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)' - task_count: 861 - task_total_time_ms: 59 - transform_count: 220 - transform_time_ms: 24 - transform_yield_count: 62 - insert_time_ms: 3 - insert_new_count: 118 - insert_reused_count: 6 diff --git a/yaml-tests/src/test/resources/distinct-from.yamsql b/yaml-tests/src/test/resources/distinct-from.yamsql index a042d07481..d2deb8a1fe 100644 --- a/yaml-tests/src/test/resources/distinct-from.yamsql +++ b/yaml-tests/src/test/resources/distinct-from.yamsql @@ -46,56 +46,7 @@ test_block: name: distinct-from-tests tests: - - - query: select * from t1 WHERE col2 is distinct from null + - query: select * from t1 WHERE col2 is distinct from null - explain: "ISCAN(I2 ([null],>)" - result: [{ID: 1, 10, 1}, {ID: 3, 10, 3}, {ID: 5, 10, 5}, {ID: 9, 20, 9}, {ID: 10, 20, 10}] - - - - query: select * from t1 WHERE col1 is DISTINCT from 10 - - explain: "COVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER _.COL1 IS_DISTINCT_FROM promote(@c10 AS INT) | FETCH" - - result: [{ID: 6, 20, !null }, {ID: 7, 20, !null }, {ID: 8, 20, !null }, {ID: 9, 20, 9}, {ID: 10, 20, 10}] - - - - query: select * from t1 WHERE null is distinct from col2 - - explain: "ISCAN(I2 ([null],>)" - - result: [{ID: 1, 10, 1}, {ID: 3, 10, 3}, {ID: 5, 10, 5}, {ID: 9, 20, 9}, {ID: 10, 20, 10}] - - - - query: select * from t1 WHERE 10 is distinct from col1 - - explain: "COVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER _.COL1 IS_DISTINCT_FROM promote(@c6 AS INT) | FETCH" - - result: [{ID: 6, 20, !null }, {ID: 7, 20, !null }, {ID: 8, 20, !null }, {ID: 9, 20, 9}, {ID: 10, 20, 10}] - - - - query: select * from t1 WHERE null is distinct from null - - explain: "COVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER false | FETCH" - - result: [] - - - - query: select * from t1 WHERE 10 is distinct from 10 - - explain: "COVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER @c6 IS_DISTINCT_FROM @c6 | FETCH" - - result: [] - ---- -test_block: - name: not-distinct-from-tests - tests: - - - - query: select * from t1 WHERE col2 is not distinct from null - - explain: "ISCAN(I2 [[null],[null]])" - - result: [{ID: 2, 10, !null }, {ID: 4, 10, !null }, {ID: 6, 20, !null }, {ID: 7, 20, !null }, {ID: 8, 20, !null }] - - - - query: select * from t1 WHERE col1 is not distinct from 20 - - explain: "COVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER _.COL1 NOT_DISTINCT_FROM promote(@c11 AS INT) | FETCH" - - result: [{ID: 6, 20, !null }, {ID: 7, 20, !null }, {ID: 8, 20, !null }, {ID: 9, 20, 9}, {ID: 10, 20, 10}] - - - - query: select * from t1 WHERE null is not distinct from col2 - - explain: "ISCAN(I2 [[null],[null]])" - - result: [{ID: 2, 10, !null }, {ID: 4, 10, !null }, {ID: 6, 20, !null }, {ID: 7, 20, !null }, {ID: 8, 20, !null }] - - - - query: select * from t1 WHERE 20 is not distinct from col1 - - explain: "COVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER _.COL1 NOT_DISTINCT_FROM promote(@c6 AS INT) | FETCH" - - result: [{ID: 6, 20, !null }, {ID: 7, 20, !null }, {ID: 8, 20, !null }, {ID: 9, 20, 9}, {ID: 10, 20, 10}] - - - - query: select count(*) from t1 WHERE null is not distinct from null - - explain: "ISCAN(I2 <,>) | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)" - - result: [{10}] - - - - query: select count(*) from t1 WHERE 10 is not distinct from 10 - - explain: "COVERING(I2 <,> -> [COL2: KEY[0], ID: KEY[2]]) | FILTER @c9 NOT_DISTINCT_FROM @c9 | FETCH | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)" - - result: [{10}] ... From b93b544b0921960f72cd88931c224db5f8dd90d2 Mon Sep 17 00:00:00 2001 From: Pengpeng Lu Date: Thu, 24 Jul 2025 12:21:31 -0700 Subject: [PATCH 10/16] remove over optimization --- .../record/query/expressions/Comparisons.java | 12 +- .../plan/cascades/values/RelOpValue.java | 24 --- .../resources/distinct-from.metrics.binpb | 184 +++++++++++++++++- .../test/resources/distinct-from.metrics.yaml | 139 ++++++++++++- .../src/test/resources/distinct-from.yamsql | 53 ++++- 5 files changed, 364 insertions(+), 48 deletions(-) diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/expressions/Comparisons.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/expressions/Comparisons.java index ad76c585e7..861c2f3ce5 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/expressions/Comparisons.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/expressions/Comparisons.java @@ -638,8 +638,8 @@ public enum Type { SORT(false), @API(API.Status.EXPERIMENTAL) LIKE, - IS_DISTINCT_FROM(true), - NOT_DISTINCT_FROM(false); + IS_DISTINCT_FROM(false), + NOT_DISTINCT_FROM(true); @Nonnull private static final Supplier> protoEnumBiMapSupplier = @@ -1337,9 +1337,7 @@ public BooleanWithConstraint semanticEqualsTyped(@Nonnull final Comparison other public Boolean eval(@Nullable FDBRecordStoreBase store, @Nonnull EvaluationContext context, @Nullable Object value) { // this is at evaluation time --> always use the context binding final Object comparand = getComparand(store, context); - if (comparand == null) { - return null; - } else if (comparand == COMPARISON_SKIPPED_BINDING) { + if (comparand == COMPARISON_SKIPPED_BINDING) { return Boolean.TRUE; } else { return evalComparison(type, value, comparand); @@ -1660,9 +1658,7 @@ public BooleanWithConstraint semanticEqualsTyped(@Nonnull final Comparison other public Boolean eval(@Nullable FDBRecordStoreBase store, @Nonnull EvaluationContext context, @Nullable Object v) { // this is at evaluation time --> always use the context binding final Object comparand = getComparand(store, context); - if (comparand == null) { - return null; - } else if (comparand == COMPARISON_SKIPPED_BINDING) { + if (comparand == COMPARISON_SKIPPED_BINDING) { return Boolean.TRUE; } else { return evalComparison(type, v, comparand); diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/RelOpValue.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/RelOpValue.java index 9042c74338..357a39b587 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/RelOpValue.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/RelOpValue.java @@ -184,7 +184,6 @@ private static Optional promoteOperandsAndCreatePredicate(@Nulla @Nonnull Value leftChild, @Nonnull Value rightChild, @Nonnull final Comparisons.Type comparisonType) { -/* if (leftChild.getResultType().getTypeCode() == Type.TypeCode.NULL && rightChild.getResultType().getTypeCode() == Type.TypeCode.NULL) { if (comparisonType == Comparisons.Type.NOT_DISTINCT_FROM) { return Optional.of(ConstantPredicate.TRUE); @@ -193,10 +192,6 @@ private static Optional promoteOperandsAndCreatePredicate(@Nulla } } - */ - - - // maximumType may return null, but only for non-primitive types which is not possible here final var maxtype = Verify.verifyNotNull(Type.maximumType(leftChild.getResultType(), rightChild.getResultType())); @@ -306,30 +301,11 @@ private static Value encapsulate(@Nonnull final String functionName, final Typed arg1 = arguments.get(1); final Type res1 = arg1.getResultType(); - /* - if ("isDistinctFrom".equals(functionName)) { - if (res0.getTypeCode() == Type.TypeCode.NULL && res1.getTypeCode() != Type.TypeCode.NULL) { - return encapsulate("notNull", Comparisons.Type.NOT_NULL, List.of(arg1)); - } else if (res1.getTypeCode() == Type.TypeCode.NULL && res0.getTypeCode() != Type.TypeCode.NULL) { - return encapsulate("notNull", Comparisons.Type.NOT_NULL, List.of(arg0)); - } - } - if ("notDistinctFrom".equals(functionName)) { - if (res0.getTypeCode() == Type.TypeCode.NULL && res1.getTypeCode() != Type.TypeCode.NULL) { - return encapsulate("isNull", Comparisons.Type.IS_NULL, List.of(arg1)); - } else if (res1.getTypeCode() == Type.TypeCode.NULL && res0.getTypeCode() != Type.TypeCode.NULL) { - return encapsulate("isNull", Comparisons.Type.IS_NULL, List.of(arg0)); - } - } - - */ - SemanticException.check(res1.isPrimitive() || res1.isEnum() || res1.isUuid(), SemanticException.ErrorCode.COMPARAND_TO_COMPARISON_IS_OF_COMPLEX_TYPE); final BinaryPhysicalOperator physicalOperator = getBinaryOperatorMap().get(new BinaryComparisonSignature(comparisonType, res0.getTypeCode(), res1.getTypeCode())); - System.out.println("comparisonType:" + comparisonType + " res0:" + res0.getTypeCode() + " res1:" + res1.getTypeCode()); Verify.verifyNotNull(physicalOperator, "unable to encapsulate comparison operation due to type mismatch(es)"); return new BinaryRelOpValue(functionName, diff --git a/yaml-tests/src/test/resources/distinct-from.metrics.binpb b/yaml-tests/src/test/resources/distinct-from.metrics.binpb index d36b1acdc7..7a6181ce67 100644 --- a/yaml-tests/src/test/resources/distinct-from.metrics.binpb +++ b/yaml-tests/src/test/resources/distinct-from.metrics.binpb @@ -1,11 +1,183 @@ -ž +ñ +U +distinct-from-tests>EXPLAIN select * from t1 WHERE col2 is distinct from null— +«‰ƒ¼a· µÒð=(50ÂóÇ8J@ \COVERING(I2 <,> -> [COL2: KEY[0], ID: KEY[2]]) | FILTER _.COL2 IS_DISTINCT_FROM NULL | FETCH™ digraph G { + fontname=courier; + rankdir=BT; + splines=polyline; + 1 [ label=<
Fetch Records
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(INT AS ID, )" ]; + 2 [ label=<
Predicate Filter
WHERE q60.COL2 IS_DISTINCT_FROM NULL
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 3 [ label=<
Covering Index Scan
range: <-∞, ∞>
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 4 [ label=<
Index
I2
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 3 -> 2 [ label=< q60> label="q60" 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=< q62> label="q62" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; +}Š +N +distinct-from-tests7EXPLAIN select * from t1 WHERE col1 is DISTINCT from 10· +«îêû`· ——×<(50’ƒ±8J@ lCOVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER _.COL1 IS_DISTINCT_FROM promote(@c10 AS INT) | FETCH© digraph G { + fontname=courier; + rankdir=BT; + splines=polyline; + 1 [ label=<
Fetch Records
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(INT AS ID, )" ]; + 2 [ label=<
Predicate Filter
WHERE q61.COL1 IS_DISTINCT_FROM promote(@c10 AS INT)
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 3 [ label=<
Covering Index Scan
range: <-∞, ∞>
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 4 [ label=<
Index
I1
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 3 -> 2 [ label=< q61> label="q61" 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=< q63> label="q63" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; +}ì P -distinct-from-tests9EXPLAIN select * from t1 WHERE col2 is distinct from nullÉ -œß»§_¶ ð¨Ÿ:(70ñ¿’8E@ ISCAN(I2 ([null],>)”digraph G { +distinct-from-tests9EXPLAIN select * from t1 WHERE null is distinct from col2— +«°ÊŒ· ²ëÎ(50ÅÑŠ8J@ \COVERING(I2 <,> -> [COL2: KEY[0], ID: KEY[2]]) | FILTER _.COL2 IS_DISTINCT_FROM NULL | FETCH™ digraph G { + fontname=courier; + rankdir=BT; + splines=polyline; + 1 [ label=<
Fetch Records
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(INT AS ID, )" ]; + 2 [ label=<
Predicate Filter
WHERE q60.COL2 IS_DISTINCT_FROM NULL
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 3 [ label=<
Covering Index Scan
range: <-∞, ∞>
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 4 [ label=<
Index
I2
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 3 -> 2 [ label=< q60> label="q60" 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=< q62> label="q62" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; +}ˆ +N +distinct-from-tests7EXPLAIN select * from t1 WHERE 10 is distinct from col1µ +«ü„‘· ¡(50è¼’8J@ kCOVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER _.COL1 IS_DISTINCT_FROM promote(@c6 AS INT) | FETCH¨ digraph G { + fontname=courier; + rankdir=BT; + splines=polyline; + 1 [ label=<
Fetch Records
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(INT AS ID, )" ]; + 2 [ label=<
Predicate Filter
WHERE q61.COL1 IS_DISTINCT_FROM promote(@c6 AS INT)
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 3 [ label=<
Covering Index Scan
range: <-∞, ∞>
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 4 [ label=<
Index
I1
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 3 -> 2 [ label=< q61> label="q61" 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=< q63> label="q63" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; +}¼ +P +distinct-from-tests9EXPLAIN select * from t1 WHERE null is distinct from nullç +ÑüܼÀ ˜ë(80‚Ëó8Q@ +ECOVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER false | FETCH€ digraph G { + fontname=courier; + rankdir=BT; + splines=polyline; + 1 [ label=<
Fetch Records
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(INT AS ID, )" ]; + 2 [ label=<
Predicate Filter
WHERE false
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 3 [ label=<
Covering Index Scan
range: <-∞, ∞>
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 4 [ label=<
Index
I1
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 3 -> 2 [ label=< q64> label="q64" 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=< q66> label="q66" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; +}Þ +L +distinct-from-tests5EXPLAIN select * from t1 WHERE 10 is distinct from 10 +ÑÄÑÍÀ ½°¼(80Ö‚‡8Q@ +XCOVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER @c6 IS_DISTINCT_FROM @c6 | FETCH“ digraph G { + fontname=courier; + rankdir=BT; + splines=polyline; + 1 [ label=<
Fetch Records
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(INT AS ID, )" ]; + 2 [ label=<
Predicate Filter
WHERE @c6 IS_DISTINCT_FROM @c6
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 3 [ label=<
Covering Index Scan
range: <-∞, ∞>
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 4 [ label=<
Index
I1
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 3 -> 2 [ label=< q64> label="q64" 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=< q66> label="q66" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; +}û +] +not-distinct-from-testsBEXPLAIN select * from t1 WHERE col2 is not distinct from null™ +«ŸªÃ¶ ££î(50áæÒ8J@ ]COVERING(I2 <,> -> [COL2: KEY[0], ID: KEY[2]]) | FILTER _.COL2 NOT_DISTINCT_FROM NULL | FETCHš digraph G { + fontname=courier; + rankdir=BT; + splines=polyline; + 1 [ label=<
Fetch Records
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(INT AS ID, )" ]; + 2 [ label=<
Predicate Filter
WHERE q60.COL2 NOT_DISTINCT_FROM NULL
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 3 [ label=<
Covering Index Scan
range: <-∞, ∞>
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 4 [ label=<
Index
I2
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 3 -> 2 [ label=< q60> label="q60" 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=< q62> label="q62" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; +}” +V +not-distinct-from-tests;EXPLAIN select * from t1 WHERE col1 is not distinct from 20¹ +«û†«¶ –Œ (50èÊ„8J@ mCOVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER _.COL1 NOT_DISTINCT_FROM promote(@c11 AS INT) | FETCHª digraph G { + fontname=courier; + rankdir=BT; + splines=polyline; + 1 [ label=<
Fetch Records
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(INT AS ID, )" ]; + 2 [ label=<
Predicate Filter
WHERE q61.COL1 NOT_DISTINCT_FROM promote(@c11 AS INT)
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 3 [ label=<
Covering Index Scan
range: <-∞, ∞>
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 4 [ label=<
Index
I1
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 3 -> 2 [ label=< q61> label="q61" 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=< q63> label="q63" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; +}ö +X +not-distinct-from-tests=EXPLAIN select * from t1 WHERE null is not distinct from col2™ +«‰Ñ˶ ó ¶(50å·Á8J@ ]COVERING(I2 <,> -> [COL2: KEY[0], ID: KEY[2]]) | FILTER _.COL2 NOT_DISTINCT_FROM NULL | FETCHš digraph G { + fontname=courier; + rankdir=BT; + splines=polyline; + 1 [ label=<
Fetch Records
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(INT AS ID, )" ]; + 2 [ label=<
Predicate Filter
WHERE q60.COL2 NOT_DISTINCT_FROM NULL
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 3 [ label=<
Covering Index Scan
range: <-∞, ∞>
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 4 [ label=<
Index
I2
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 3 -> 2 [ label=< q60> label="q60" 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=< q62> label="q62" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; +}’ +V +not-distinct-from-tests;EXPLAIN select * from t1 WHERE 20 is not distinct from col1· +«™½¦¶ çË®(50…õÄ8J@ lCOVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER _.COL1 NOT_DISTINCT_FROM promote(@c6 AS INT) | FETCH© digraph G { + fontname=courier; + rankdir=BT; + splines=polyline; + 1 [ label=<
Fetch Records
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(INT AS ID, )" ]; + 2 [ label=<
Predicate Filter
WHERE q61.COL1 NOT_DISTINCT_FROM promote(@c6 AS INT)
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 3 [ label=<
Covering Index Scan
range: <-∞, ∞>
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 4 [ label=<
Index
I1
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 3 -> 2 [ label=< q61> label="q61" 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=< q63> label="q63" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; +}Œ +_ +not-distinct-from-testsDEXPLAIN select count(*) from t1 WHERE null is not distinct from null¨ +Ӈר#Ì ²¦ˆ (<0úóð8`@ƒISCAN(I2 <,>) | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)‚digraph G { + fontname=courier; + rankdir=BT; + splines=polyline; + 1 [ label=<
Value Computation
MAP (coalesce_long(q6._0._0, promote(0l AS LONG)) AS _0)
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; + 2 [ label=<
Value Computation
$q6 OR NULL
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 3 [ label=<
Streaming Aggregate
COLLECT (count_star(*) AS _0)
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 4 [ label=<
Value Computation
MAP (q2 AS _0)
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, AS _0)" ]; + 5 [ label=<
Index Scan
range: <-∞, ∞>
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 6 [ label=<
Index
I2
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q88> label="q88" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 -> 4 [ label=< q2> label="q2" 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" ]; + 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; +}Ø +[ +not-distinct-from-tests@EXPLAIN select count(*) from t1 WHERE 10 is not distinct from 10ø +Ý•³×"Ü ÙöÀ (>0“†ö8v@ÏCOVERING(I2 <,> -> [COL2: KEY[0], ID: KEY[2]]) | FILTER @c9 NOT_DISTINCT_FROM @c9 | FETCH | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)†digraph G { fontname=courier; rankdir=BT; splines=polyline; - 1 [ label=<
Index Scan
range: ((null), ∞>
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; - 2 [ label=<
Index
I2
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; - 2 -> 1 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 1 [ label=<
Value Computation
MAP (coalesce_long(q6._0._0, promote(0l AS LONG)) AS _0)
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; + 2 [ label=<
Value Computation
$q6 OR NULL
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 3 [ label=<
Streaming Aggregate
COLLECT (count_star(*) AS _0)
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; + 4 [ label=<
Value Computation
MAP (q67 AS _0)
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, AS _0)" ]; + 5 [ label=<
Fetch Records
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(INT AS ID, )" ]; + 6 [ label=<
Predicate Filter
WHERE @c9 NOT_DISTINCT_FROM @c9
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 7 [ label=<
Covering Index Scan
range: <-∞, ∞>
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 8 [ label=<
Index
I2
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q113> label="q113" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 -> 4 [ label=< q67> label="q67" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 6 -> 5 [ label=< q74> label="q74" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 7 -> 6 [ label=< q72> label="q72" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 8 -> 7 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; } \ No newline at end of file diff --git a/yaml-tests/src/test/resources/distinct-from.metrics.yaml b/yaml-tests/src/test/resources/distinct-from.metrics.yaml index e0adcb3637..52a7528bf0 100644 --- a/yaml-tests/src/test/resources/distinct-from.metrics.yaml +++ b/yaml-tests/src/test/resources/distinct-from.metrics.yaml @@ -1,11 +1,134 @@ distinct-from-tests: -- query: EXPLAIN select * from t1 WHERE col2 is distinct from null - explain: ISCAN(I2 ([null],>) - task_count: 668 - task_total_time_ms: 199 +- query: EXPLAIN select * from t1 WHERE col2 is distinct from null + explain: 'COVERING(I2 <,> -> [COL2: KEY[0], ID: KEY[2]]) | FILTER _.COL2 IS_DISTINCT_FROM + NULL | FETCH' + task_count: 683 + task_total_time_ms: 204 + transform_count: 183 + transform_time_ms: 129 + transform_yield_count: 53 + insert_time_ms: 13 + insert_new_count: 74 + insert_reused_count: 9 +- query: EXPLAIN select * from t1 WHERE col1 is DISTINCT from 10 + explain: 'COVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER _.COL1 IS_DISTINCT_FROM + promote(@c10 AS INT) | FETCH' + task_count: 683 + task_total_time_ms: 203 + transform_count: 183 + transform_time_ms: 127 + transform_yield_count: 53 + insert_time_ms: 13 + insert_new_count: 74 + insert_reused_count: 9 +- query: EXPLAIN select * from t1 WHERE null is distinct from col2 + explain: 'COVERING(I2 <,> -> [COL2: KEY[0], ID: KEY[2]]) | FILTER _.COL2 IS_DISTINCT_FROM + NULL | FETCH' + task_count: 683 + task_total_time_ms: 52 + transform_count: 183 + transform_time_ms: 15 + transform_yield_count: 53 + insert_time_ms: 4 + insert_new_count: 74 + insert_reused_count: 9 +- query: EXPLAIN select * from t1 WHERE 10 is distinct from col1 + explain: 'COVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER _.COL1 IS_DISTINCT_FROM + promote(@c6 AS INT) | FETCH' + task_count: 683 + task_total_time_ms: 52 + transform_count: 183 + transform_time_ms: 17 + transform_yield_count: 53 + insert_time_ms: 4 + insert_new_count: 74 + insert_reused_count: 9 +- query: EXPLAIN select * from t1 WHERE null is distinct from null + explain: 'COVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER false | FETCH' + task_count: 721 + task_total_time_ms: 53 + transform_count: 192 + transform_time_ms: 16 + transform_yield_count: 56 + insert_time_ms: 3 + insert_new_count: 81 + insert_reused_count: 10 +- query: EXPLAIN select * from t1 WHERE 10 is distinct from 10 + explain: 'COVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER @c6 IS_DISTINCT_FROM + @c6 | FETCH' + task_count: 721 + task_total_time_ms: 55 + transform_count: 192 + transform_time_ms: 17 + transform_yield_count: 56 + insert_time_ms: 4 + insert_new_count: 81 + insert_reused_count: 10 +not-distinct-from-tests: +- query: EXPLAIN select * from t1 WHERE col2 is not distinct from null + explain: 'COVERING(I2 <,> -> [COL2: KEY[0], ID: KEY[2]]) | FILTER _.COL2 NOT_DISTINCT_FROM + NULL | FETCH' + task_count: 683 + task_total_time_ms: 45 + transform_count: 182 + transform_time_ms: 14 + transform_yield_count: 53 + insert_time_ms: 3 + insert_new_count: 74 + insert_reused_count: 9 +- query: EXPLAIN select * from t1 WHERE col1 is not distinct from 20 + explain: 'COVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER _.COL1 NOT_DISTINCT_FROM + promote(@c11 AS INT) | FETCH' + task_count: 683 + task_total_time_ms: 51 + transform_count: 182 + transform_time_ms: 19 + transform_yield_count: 53 + insert_time_ms: 4 + insert_new_count: 74 + insert_reused_count: 9 +- query: EXPLAIN select * from t1 WHERE null is not distinct from col2 + explain: 'COVERING(I2 <,> -> [COL2: KEY[0], ID: KEY[2]]) | FILTER _.COL2 NOT_DISTINCT_FROM + NULL | FETCH' + task_count: 683 + task_total_time_ms: 38 + transform_count: 182 + transform_time_ms: 11 + transform_yield_count: 53 + insert_time_ms: 3 + insert_new_count: 74 + insert_reused_count: 9 +- query: EXPLAIN select * from t1 WHERE 20 is not distinct from col1 + explain: 'COVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER _.COL1 NOT_DISTINCT_FROM + promote(@c6 AS INT) | FETCH' + task_count: 683 + task_total_time_ms: 38 transform_count: 182 - transform_time_ms: 122 - transform_yield_count: 55 - insert_time_ms: 12 - insert_new_count: 69 + transform_time_ms: 11 + transform_yield_count: 53 + insert_time_ms: 3 + insert_new_count: 74 insert_reused_count: 9 +- query: EXPLAIN select count(*) from t1 WHERE null is not distinct from null + explain: ISCAN(I2 <,>) | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY + NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0) + task_count: 723 + task_total_time_ms: 74 + transform_count: 204 + transform_time_ms: 27 + transform_yield_count: 60 + insert_time_ms: 3 + insert_new_count: 96 + insert_reused_count: 8 +- query: EXPLAIN select count(*) from t1 WHERE 10 is not distinct from 10 + explain: 'COVERING(I2 <,> -> [COL2: KEY[0], ID: KEY[2]]) | FILTER @c9 NOT_DISTINCT_FROM + @c9 | FETCH | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | + MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)' + task_count: 861 + task_total_time_ms: 72 + transform_count: 220 + transform_time_ms: 26 + transform_yield_count: 62 + insert_time_ms: 16 + insert_new_count: 118 + insert_reused_count: 6 diff --git a/yaml-tests/src/test/resources/distinct-from.yamsql b/yaml-tests/src/test/resources/distinct-from.yamsql index d2deb8a1fe..80c9319f98 100644 --- a/yaml-tests/src/test/resources/distinct-from.yamsql +++ b/yaml-tests/src/test/resources/distinct-from.yamsql @@ -46,7 +46,56 @@ test_block: name: distinct-from-tests tests: - - - query: select * from t1 WHERE col2 is distinct from null - - explain: "ISCAN(I2 ([null],>)" + - query: select * from t1 WHERE col2 is distinct from null + - explain: "COVERING(I2 <,> -> [COL2: KEY[0], ID: KEY[2]]) | FILTER _.COL2 IS_DISTINCT_FROM NULL | FETCH" - result: [{ID: 1, 10, 1}, {ID: 3, 10, 3}, {ID: 5, 10, 5}, {ID: 9, 20, 9}, {ID: 10, 20, 10}] + - + - query: select * from t1 WHERE col1 is DISTINCT from 10 + - explain: "COVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER _.COL1 IS_DISTINCT_FROM promote(@c10 AS INT) | FETCH" + - result: [{ID: 6, 20, !null }, {ID: 7, 20, !null }, {ID: 8, 20, !null }, {ID: 9, 20, 9}, {ID: 10, 20, 10}] + - + - query: select * from t1 WHERE null is distinct from col2 + - explain: "COVERING(I2 <,> -> [COL2: KEY[0], ID: KEY[2]]) | FILTER _.COL2 IS_DISTINCT_FROM NULL | FETCH" + - result: [{ID: 1, 10, 1}, {ID: 3, 10, 3}, {ID: 5, 10, 5}, {ID: 9, 20, 9}, {ID: 10, 20, 10}] + - + - query: select * from t1 WHERE 10 is distinct from col1 + - explain: "COVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER _.COL1 IS_DISTINCT_FROM promote(@c6 AS INT) | FETCH" + - result: [{ID: 6, 20, !null }, {ID: 7, 20, !null }, {ID: 8, 20, !null }, {ID: 9, 20, 9}, {ID: 10, 20, 10}] + - + - query: select * from t1 WHERE null is distinct from null + - explain: "COVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER false | FETCH" + - result: [] + - + - query: select * from t1 WHERE 10 is distinct from 10 + - explain: "COVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER @c6 IS_DISTINCT_FROM @c6 | FETCH" + - result: [] + +--- +test_block: + name: not-distinct-from-tests + tests: + - + - query: select * from t1 WHERE col2 is not distinct from null + - explain: "COVERING(I2 <,> -> [COL2: KEY[0], ID: KEY[2]]) | FILTER _.COL2 NOT_DISTINCT_FROM NULL | FETCH" + - result: [{ID: 2, 10, !null }, {ID: 4, 10, !null }, {ID: 6, 20, !null }, {ID: 7, 20, !null }, {ID: 8, 20, !null }] + - + - query: select * from t1 WHERE col1 is not distinct from 20 + - explain: "COVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER _.COL1 NOT_DISTINCT_FROM promote(@c11 AS INT) | FETCH" + - result: [{ID: 6, 20, !null }, {ID: 7, 20, !null }, {ID: 8, 20, !null }, {ID: 9, 20, 9}, {ID: 10, 20, 10}] + - + - query: select * from t1 WHERE null is not distinct from col2 + - explain: "COVERING(I2 <,> -> [COL2: KEY[0], ID: KEY[2]]) | FILTER _.COL2 NOT_DISTINCT_FROM NULL | FETCH" + - result: [{ID: 2, 10, !null }, {ID: 4, 10, !null }, {ID: 6, 20, !null }, {ID: 7, 20, !null }, {ID: 8, 20, !null }] + - + - query: select * from t1 WHERE 20 is not distinct from col1 + - explain: "COVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER _.COL1 NOT_DISTINCT_FROM promote(@c6 AS INT) | FETCH" + - result: [{ID: 6, 20, !null }, {ID: 7, 20, !null }, {ID: 8, 20, !null }, {ID: 9, 20, 9}, {ID: 10, 20, 10}] + - + - query: select count(*) from t1 WHERE null is not distinct from null + - explain: "ISCAN(I2 <,>) | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)" + - result: [{10}] + - + - query: select count(*) from t1 WHERE 10 is not distinct from 10 + - explain: "COVERING(I2 <,> -> [COL2: KEY[0], ID: KEY[2]]) | FILTER @c9 NOT_DISTINCT_FROM @c9 | FETCH | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)" + - result: [{10}] ... From 35b081ccde92fbc78e1d4bcd9c74b6f1ba02c302 Mon Sep 17 00:00:00 2001 From: Pengpeng Lu Date: Mon, 28 Jul 2025 15:06:41 -0700 Subject: [PATCH 11/16] toClassWithRealEquals take nonnull input --- .../record/query/expressions/Comparisons.java | 40 +++++---- .../resources/aggregate-index-tests.yamsql | 81 +++---------------- 2 files changed, 35 insertions(+), 86 deletions(-) diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/expressions/Comparisons.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/expressions/Comparisons.java index 861c2f3ce5..0432f12d52 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/expressions/Comparisons.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/expressions/Comparisons.java @@ -57,6 +57,7 @@ import com.apple.foundationdb.record.query.plan.cascades.BooleanWithConstraint; import com.apple.foundationdb.record.query.plan.cascades.Correlated; import com.apple.foundationdb.record.query.plan.cascades.CorrelationIdentifier; +import com.apple.foundationdb.record.query.plan.cascades.typing.Type; import com.apple.foundationdb.record.query.plan.explain.DefaultExplainFormatter; import com.apple.foundationdb.record.query.plan.explain.ExplainTokens; import com.apple.foundationdb.record.query.plan.explain.ExplainTokensWithPrecedence; @@ -75,6 +76,7 @@ import com.apple.foundationdb.record.util.ProtoUtils; import com.apple.foundationdb.tuple.ByteArrayUtil; import com.apple.foundationdb.tuple.ByteArrayUtil2; +import com.apple.foundationdb.tuple.Tuple; import com.google.auto.service.AutoService; import com.google.common.base.Suppliers; import com.google.common.base.Verify; @@ -213,11 +215,9 @@ private static Comparable toComparable(@Nullable Object obj) { } } - @Nullable - public static Object toClassWithRealEquals(@Nullable Object obj) { - if (obj == null) { - return null; - } else if (obj instanceof ByteString) { + @Nonnull + public static Object toClassWithRealEquals(@Nonnull Object obj) { + if (obj instanceof ByteString) { return obj; } else if (obj instanceof byte[]) { return ByteString.copyFrom((byte[])obj); @@ -247,7 +247,7 @@ private static boolean compareEquals(@Nonnull Object value, @Nonnull Object comp } @SpotBugsSuppressWarnings("NP_BOOLEAN_RETURN_NULL") - private static boolean compareNotDistinctFrom(Object value, Object comparand) { + private static boolean compareNotDistinctFrom(@Nullable Object value, @Nullable Object comparand) { if (value == null && comparand == null) { return true; } else if (value == null || comparand == null) { @@ -256,7 +256,7 @@ private static boolean compareNotDistinctFrom(Object value, Object comparand) { if (value instanceof Message) { return MessageHelpers.compareMessageEquals(value, comparand); } else { - return toClassWithRealEquals(value).equals(toClassWithRealEquals(comparand)); + return toClassWithRealEquals(Objects.requireNonNull(value)).equals(toClassWithRealEquals(Objects.requireNonNull(comparand))); } } } @@ -316,7 +316,12 @@ private static Boolean compareListStartsWith(@Nullable Object value, @Nonnull Li if (i > list.size()) { return false; } - if (!toClassWithRealEquals(comparand.get(i)).equals(toClassWithRealEquals(list.get(i)))) { + if (comparand.get(i) == null && list.get(i) == null) { + continue; + } + if (comparand.get(i) == null || list.get(i) == null) { + return false; + } else if (!toClassWithRealEquals(comparand.get(i)).equals(toClassWithRealEquals(list.get(i)))) { return false; } } @@ -341,11 +346,12 @@ private static Boolean compareIn(@Nullable Object value, @Nullable Object compar return true; } } else { - if (toClassWithRealEquals(value).equals(toClassWithRealEquals(comparandItem))) { + if (comparandItem == null) { + hasNull = true; + } else if (toClassWithRealEquals(value).equals(toClassWithRealEquals(comparandItem))) { return true; } } - hasNull |= comparandItem == null; } return hasNull ? null : false; } else { @@ -689,7 +695,7 @@ private static BiMap getProtoEnumBiMap() { } @Nullable - public static Type invertComparisonType(@Nonnull final Comparisons.Type type) { + public static Type invertComparisonType(@Nonnull final Type type) { if (type.isUnary()) { return null; } @@ -846,7 +852,7 @@ default Object getComparand() { /** * Get whether the comparison is with the result of a multi-column key. - * If so, {@link #getComparand} will return a {@link com.apple.foundationdb.tuple.Tuple}. + * If so, {@link #getComparand} will return a {@link Tuple}. * @return {@code true} if the comparand is for multiple key columns */ default boolean hasMultiColumnComparand() { @@ -1780,7 +1786,7 @@ public static class ListComparison implements Comparison { @SuppressWarnings("rawtypes") private final List comparand; @Nullable - private final Descriptors.FieldDescriptor.JavaType javaType; + private final JavaType javaType; @Nonnull @SuppressWarnings("rawtypes") @@ -1798,8 +1804,8 @@ public ListComparison(@Nonnull Type type, @Nonnull List comparand) { default: throw new RecordCoreException("ListComparison only supports EQUALS, NOT_EQUALS, STARTS_WITH and IN"); } - if (comparand == null || (this.type == Type.IN && comparand.stream().anyMatch(o -> o == null))) { - throw new NullPointerException("List comparand is null, or contains null"); + if (this.type == Type.IN && comparand.stream().anyMatch(o -> o == null)) { + throw new NullPointerException("List comparand contains null"); } if (comparand.isEmpty()) { javaType = null; @@ -1813,10 +1819,10 @@ public ListComparison(@Nonnull Type type, @Nonnull List comparand) { } } this.comparand = comparand; - this.comparandListWithEqualsSupplier = Suppliers.memoize(() -> Lists.transform(comparand, Comparisons::toClassWithRealEquals)); + this.comparandListWithEqualsSupplier = Suppliers.memoize(() -> Lists.transform(comparand, obj -> obj != null ? toClassWithRealEquals(obj) : null)); } - private static Descriptors.FieldDescriptor.JavaType getJavaType(@Nonnull Object o) { + private static JavaType getJavaType(@Nonnull Object o) { if (o instanceof Boolean) { return JavaType.BOOLEAN; } else if (o instanceof ByteString || o instanceof byte[]) { diff --git a/yaml-tests/src/test/resources/aggregate-index-tests.yamsql b/yaml-tests/src/test/resources/aggregate-index-tests.yamsql index f379f7c54c..f585ac178d 100644 --- a/yaml-tests/src/test/resources/aggregate-index-tests.yamsql +++ b/yaml-tests/src/test/resources/aggregate-index-tests.yamsql @@ -156,20 +156,8 @@ test_block: # At some point, should be able to roll up values from the aggregate index. However, even # controlling for that, it can still use the index - query: select max(col2) from T1 use index (mv8); - - supported_version: 4.1.9.0 - explain: "ISCAN(MV8 <,>) | MAP (_ AS _0) | AGG (max_l(_._0.COL2) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)" - result: [{!l 13}] - - - - query: select max(col2) from T1 use index (mv8); - - maxRows: 1 - # Cannot use FORCE_CONTINUATIONS with older versions due to: https://github.com/FoundationDB/fdb-record-layer/issues/3096 - # (Extra values being produced after exhausting source of an aggregate cursor) - # Can remove once we do not care about backwards compatibility before 4.1.9.0 - - initialVersionLessThan: 4.1.9.0 - # Different (incorrect) behavior for different past versions - - initialVersionAtLeast: 4.1.9.0 - - result: [{!l 13}] - - result: [] - # Min/max indexes need keep what amounts to a standard value index on their keys (in order to properly look up # the min/max). That index should be usable for normal queries just like a value index. Note that the scan is @@ -183,43 +171,14 @@ test_block: - result: [{!l 5}, {!l 4}, {!l 3}, {!l 2}, {!l 1}] - - query: select min(col3) from T2 group by col1, col2; - - supported_version: 4.1.9.0 - explain: "ISCAN(MV2 <,>) | MAP (_ AS _0) | AGG (min_l(_._0.COL3) AS _0) GROUP BY (_._0.COL1 AS _0, _._0.COL2 AS _1) | MAP (_._1._0 AS _0)" - result: [{!l 1}, {!l 2}, {!l 3}] - - - - query: select min(col3) from T2 group by col1, col2; - # Cannot use FORCE_CONTINUATIONS with older versions due to: https://github.com/FoundationDB/fdb-record-layer/issues/3096 - # (Extra values being produced after exhausting source of an aggregate cursor) - # Can remove once we do not care about backwards compatibility before 4.1.9.0 - - maxRows: 1 - - initialVersionLessThan: 4.1.9.0 - # Different (incorrect) behavior for different past versions - - initialVersionAtLeast: 4.1.9.0 - - result: [{!l 1}] - - result: [{!l 2}] - - result: [{!l 3}] - - result: [] - # this should use the aggregate index in the future, for now, it is using streaming aggregate # over base table scan. - query: select max(col2) from t2; - - supported_version: 4.1.9.0 - explain: "ISCAN(MV3 <,>) | MAP (_ AS _0) | AGG (max_l(_._0.COL2) AS _0) | ON EMPTY NULL | MAP (_._0._0 AS _0)" - result: [{!l 2}] - - - - query: select max(col2) from t2; - # Cannot use FORCE_CONTINUATIONS with older versions due to: https://github.com/FoundationDB/fdb-record-layer/issues/3096 - # (Extra values being produced after exhausting source of an aggregate cursor) - # Can remove once we do not care about backwards compatibility before 4.1.9.0 - - supported_version: 4.1.9.0 - - maxRows: 1 - - initialVersionLessThan: 4.1.9.0 - - result: [{!l 2}] - - result: [{!null _}] - - result: [{!l 2}] # ad infinitum - - initialVersionAtLeast: 4.1.9.0 - - result: [{!l 2}] - - result: [] - - query: select col1, sum(col2) from T1 USE INDEX (vi1) group by col1; - explain: "ISCAN(VI1 <,>) | MAP (_ AS _0) | AGG (sum_l(_._0.COL2) AS _0) GROUP BY (_._0.COL1 AS _0) | MAP (_._0._0 AS COL1, _._1._0 AS _1)" @@ -273,28 +232,12 @@ test_block: - # Permuted max index can also be used to evaluate other aggregate functions via aggregation and roll-up - query: select col3, sum(col2) as s from t2 use index (mv9) where col1 = 1 group by col1, col3 order by col3 asc; - - supported_version: 4.1.9.0 - explain: "ISCAN(MV9 [EQUALS promote(@c20 AS LONG)]) | MAP (_ AS _0) | AGG (sum_l(_._0.COL2) AS _0) GROUP BY (_._0.COL1 AS _0, _._0.COL3 AS _1) | MAP (_._0._1 AS COL3, _._1._0 AS S)" - result: [{COL3: 1, S: 1}, {COL3: 2, S: 2}, {COL3: 100, S: 1}, {COL3: 200, S: 2}] - - - - query: select col3, sum(col2) as s from t2 use index (mv9) where col1 = 1 group by col1, col3 order by col3 asc; - # Cannot use FORCE_CONTINUATIONS with older versions due to: https://github.com/FoundationDB/fdb-record-layer/issues/3096 - # (Extra values being produced after exhausting source of an aggregate cursor) - # Can remove once we do not care about backwards compatibility before 4.1.9.0 - - maxRows: 0 - - result: [{COL3: 1, S: 1}, {COL3: 2, S: 2}, {COL3: 100, S: 1}, {COL3: 200, S: 2}] - - query: select col3, sum(col2) as s from t2 use index (mv9) where col1 = 1 group by col1, col3 order by col3 desc; - - supported_version: 4.1.9.0 - explain: "ISCAN(MV9 [EQUALS promote(@c20 AS LONG)] REVERSE) | MAP (_ AS _0) | AGG (sum_l(_._0.COL2) AS _0) GROUP BY (_._0.COL1 AS _0, _._0.COL3 AS _1) | MAP (_._0._1 AS COL3, _._1._0 AS S)" - result: [{COL3: 200, S: 2}, {COL3: 100, S: 1}, {COL3: 2, S: 2}, {COL3: 1, S: 1}] - - - - query: select col3, sum(col2) as s from t2 use index (mv9) where col1 = 1 group by col1, col3 order by col3 desc; - # Cannot use FORCE_CONTINUATIONS with older versions due to: https://github.com/FoundationDB/fdb-record-layer/issues/3096 - # (Extra values being produced after exhausting source of an aggregate cursor) - # Can remove once we do not care about backwards compatibility before 4.1.9.0 - - maxRows: 0 - - result: [{COL3: 200, S: 2}, {COL3: 100, S: 1}, {COL3: 2, S: 2}, {COL3: 1, S: 1}] # - # # grouping by constant is not yet supported. # - query: select sum(col2) from t1 group by 3,2,1; @@ -379,9 +322,9 @@ test_block: - - query: select b, c, d, e, max(x) from t5 where a = 0 group by a, b, c, d, e order by b, max(x), c, d, e - explain: "AISCAN(MV16 [EQUALS promote(@c19 AS LONG)] BY_GROUP -> [_0: KEY:[0], _1: KEY:[1], _2: KEY:[3], _3: KEY:[4], _4: KEY:[5], _5: KEY:[2]]) | MAP (_._1 AS B, _._2 AS C, _._3 AS D, _._4 AS E, _._5 AS _4)" - - initialVersionLessThan: !current_version + - initialVersionLessThan: 4.3.5.0 - error: "0AF00" - - initialVersionAtLeast: !current_version + - initialVersionAtLeast: 4.3.5.0 - result: [ {b: "bar", c: 0, d: 1, e: "e1", _4: 11}, {b: "bar", c: 0, d: 1, e: "e2", _4: 11}, @@ -408,9 +351,9 @@ test_block: - - query: select b, c, d, e, min(x) from t5 where a = 0 group by a, b, c, d, e order by b, min(x), c, d, e - explain: "AISCAN(MV17 [EQUALS promote(@c19 AS LONG)] BY_GROUP -> [_0: KEY:[0], _1: KEY:[1], _2: KEY:[3], _3: KEY:[4], _4: KEY:[5], _5: KEY:[2]]) | MAP (_._1 AS B, _._2 AS C, _._3 AS D, _._4 AS E, _._5 AS _4)" - - initialVersionLessThan: !current_version + - initialVersionLessThan: 4.3.5.0 - error: "0AF00" - - initialVersionAtLeast: !current_version + - initialVersionAtLeast: 4.3.5.0 - result: [ {b: "bar", c: 0, d: 1, e: "e1", _4: 0}, {b: "bar", c: 0, d: 1, e: "e2", _4: 0}, @@ -437,9 +380,9 @@ test_block: - - query: select b, c, d, e, max(x) from t5 where a = 0 group by a, b, c, d, e order by b, c, max(x), d, e - explain: "AISCAN(MV18 [EQUALS promote(@c19 AS LONG)] BY_GROUP -> [_0: KEY:[0], _1: KEY:[1], _2: KEY:[2], _3: KEY:[4], _4: KEY:[5], _5: KEY:[3]]) | MAP (_._1 AS B, _._2 AS C, _._3 AS D, _._4 AS E, _._5 AS _4)" - - initialVersionLessThan: !current_version + - initialVersionLessThan: 4.3.5.0 - error: "0AF00" - - initialVersionAtLeast: !current_version + - initialVersionAtLeast: 4.3.5.0 - result: [ {b: "bar", c: 0, d: 1, e: "e1", _4: 11}, {b: "bar", c: 0, d: 1, e: "e2", _4: 11}, @@ -466,9 +409,9 @@ test_block: - - query: select b, c, d, e, min(x) from t5 where a = 0 group by a, b, c, d, e order by b, c, min(x), d, e - explain: "AISCAN(MV19 [EQUALS promote(@c19 AS LONG)] BY_GROUP -> [_0: KEY:[0], _1: KEY:[1], _2: KEY:[2], _3: KEY:[4], _4: KEY:[5], _5: KEY:[3]]) | MAP (_._1 AS B, _._2 AS C, _._3 AS D, _._4 AS E, _._5 AS _4)" - - initialVersionLessThan: !current_version + - initialVersionLessThan: 4.3.5.0 - error: "0AF00" - - initialVersionAtLeast: !current_version + - initialVersionAtLeast: 4.3.5.0 - result: [ {b: "bar", c: 0, d: 1, e: "e1", _4: 0}, {b: "bar", c: 0, d: 1, e: "e2", _4: 0}, @@ -567,9 +510,9 @@ test_block: - - query: select b, c, d, e, max(x) from t5 where a = 0 group by a, b, c, d, e having b IN ('foo', 'bar') and d IN (1, 2) order by max(x), c, e - explain: "[IN @c34] INUNION q0 -> { [IN promote(@c42 AS ARRAY(LONG))] INUNION q1 -> { AISCAN(MV16 [EQUALS promote(@c19 AS LONG), EQUALS q0] BY_GROUP -> [_0: KEY:[0], _1: KEY:[1], _2: KEY:[3], _3: KEY:[4], _4: KEY:[5], _5: KEY:[2]]) | FILTER _._3 EQUALS q1 | MAP (_._1 AS B, _._2 AS C, _._3 AS D, _._4 AS E, _._5 AS _4) } COMPARE BY (_._4, _.C, _.E, _.D) } COMPARE BY (_._4, _.C, _.E, _.B)" - - initialVersionLessThan: !current_version + - initialVersionLessThan: 4.3.5.0 - error: "0AF00" - - initialVersionAtLeast: !current_version + - initialVersionAtLeast: 4.3.5.0 - result: [ {b: "foo", c: 0, d: 2, e: "e2", _4: 8}, {b: "foo", c: 3, d: 1, e: "e1", _4: 8}, @@ -583,9 +526,9 @@ test_block: - - query: select b, c, d, e, min(x) from t5 where a = 0 group by a, b, c, d, e having b IN ('foo', 'bar') and d IN (1, 2) order by min(x), c, e - explain: "[IN @c34] INUNION q0 -> { [IN promote(@c42 AS ARRAY(LONG))] INUNION q1 -> { AISCAN(MV17 [EQUALS promote(@c19 AS LONG), EQUALS q0] BY_GROUP -> [_0: KEY:[0], _1: KEY:[1], _2: KEY:[3], _3: KEY:[4], _4: KEY:[5], _5: KEY:[2]]) | FILTER _._3 EQUALS q1 | MAP (_._1 AS B, _._2 AS C, _._3 AS D, _._4 AS E, _._5 AS _4) } COMPARE BY (_._4, _.C, _.E, _.D) } COMPARE BY (_._4, _.C, _.E, _.B)" - - initialVersionLessThan: !current_version + - initialVersionLessThan: 4.3.5.0 - error: "0AF00" - - initialVersionAtLeast: !current_version + - initialVersionAtLeast: 4.3.5.0 - result: [ {b: "bar", c: 0, d: 1, e: "e1", _4: 0}, {b: "bar", c: 0, d: 1, e: "e2", _4: 0}, From 70aa7e6bf4b02eff5bed9110920b8f987b0cecf8 Mon Sep 17 00:00:00 2001 From: Pengpeng Lu Date: Mon, 28 Jul 2025 15:46:49 -0700 Subject: [PATCH 12/16] comparisons methods --- .../foundationdb/record/query/expressions/Comparisons.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/expressions/Comparisons.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/expressions/Comparisons.java index 0432f12d52..1cf87dd37c 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/expressions/Comparisons.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/expressions/Comparisons.java @@ -233,7 +233,7 @@ public static Object toClassWithRealEquals(@Nonnull Object obj) { } @SuppressWarnings("unchecked") - public static int compare(@Nullable Object fieldValue, @Nullable Object comparand) { + public static int compare(@Nonnull Object fieldValue, @Nonnull Object comparand) { return toComparable(fieldValue).compareTo(toComparable(comparand)); } @@ -285,9 +285,6 @@ private static Boolean compareStartsWith(@Nullable Object value, @Nullable Objec @Nullable @SpotBugsSuppressWarnings("NP_BOOLEAN_RETURN_NULL") private static Boolean compareLike(@Nullable Object value, @Nullable Object pattern) { - if (value == null) { - return null; - } if (!(value instanceof String)) { throw new RecordCoreException("Illegal comparand value type: " + value); } From 3a8c3dc2bc2d077b469d96ec553efaec880397a9 Mon Sep 17 00:00:00 2001 From: Pengpeng Lu Date: Mon, 28 Jul 2025 16:06:04 -0700 Subject: [PATCH 13/16] checkstyle --- .../apple/foundationdb/record/query/expressions/Comparisons.java | 1 - 1 file changed, 1 deletion(-) diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/expressions/Comparisons.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/expressions/Comparisons.java index 1cf87dd37c..75823f50e9 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/expressions/Comparisons.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/expressions/Comparisons.java @@ -57,7 +57,6 @@ import com.apple.foundationdb.record.query.plan.cascades.BooleanWithConstraint; import com.apple.foundationdb.record.query.plan.cascades.Correlated; import com.apple.foundationdb.record.query.plan.cascades.CorrelationIdentifier; -import com.apple.foundationdb.record.query.plan.cascades.typing.Type; import com.apple.foundationdb.record.query.plan.explain.DefaultExplainFormatter; import com.apple.foundationdb.record.query.plan.explain.ExplainTokens; import com.apple.foundationdb.record.query.plan.explain.ExplainTokensWithPrecedence; From 0c45afe6bc78ce0b2242525c39ad28f6f6787777 Mon Sep 17 00:00:00 2001 From: Pengpeng Lu Date: Tue, 29 Jul 2025 11:20:41 -0700 Subject: [PATCH 14/16] fix compareLike --- .../record/query/expressions/Comparisons.java | 3 + .../plan/cascades/values/RelOpValue.java | 7 - .../src/test/java/YamlIntegrationTests.java | 1 - .../resources/distinct-from.metrics.binpb | 154 +++++++------- .../test/resources/distinct-from.metrics.yaml | 196 +++++++++--------- .../src/test/resources/distinct-from.yamsql | 4 +- 6 files changed, 182 insertions(+), 183 deletions(-) diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/expressions/Comparisons.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/expressions/Comparisons.java index b414d942c7..2adfe8f5cb 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/expressions/Comparisons.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/expressions/Comparisons.java @@ -282,6 +282,9 @@ private static Boolean compareStartsWith(@Nullable Object value, @Nullable Objec @Nullable @SpotBugsSuppressWarnings("NP_BOOLEAN_RETURN_NULL") private static Boolean compareLike(@Nullable Object value, @Nullable Object pattern) { + if (value == null) { + return null; + } if (!(value instanceof String)) { throw new RecordCoreException("Illegal comparand value type: " + value); } diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/RelOpValue.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/RelOpValue.java index 3f5d24b510..1ba73090a6 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/RelOpValue.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/RelOpValue.java @@ -184,13 +184,6 @@ private static Optional promoteOperandsAndCreatePredicate(@Nulla @Nonnull Value leftChild, @Nonnull Value rightChild, @Nonnull final Comparisons.Type comparisonType) { - if (leftChild.getResultType().getTypeCode() == Type.TypeCode.NULL && rightChild.getResultType().getTypeCode() == Type.TypeCode.NULL) { - if (comparisonType == Comparisons.Type.NOT_DISTINCT_FROM) { - return Optional.of(ConstantPredicate.TRUE); - } else if (comparisonType == Comparisons.Type.IS_DISTINCT_FROM) { - return Optional.of(ConstantPredicate.FALSE); - } - } // maximumType may return null, but only for non-primitive types which is not possible here final var maxtype = Verify.verifyNotNull(Type.maximumType(leftChild.getResultType(), rightChild.getResultType())); diff --git a/yaml-tests/src/test/java/YamlIntegrationTests.java b/yaml-tests/src/test/java/YamlIntegrationTests.java index 687013c4fd..ad4a974ece 100644 --- a/yaml-tests/src/test/java/YamlIntegrationTests.java +++ b/yaml-tests/src/test/java/YamlIntegrationTests.java @@ -207,7 +207,6 @@ void like(YamlTest.Runner runner) throws Exception { } @TestTemplate - @MaintainYamlTestConfig(YamlTestConfigFilters.CORRECT_EXPLAIN_AND_METRICS) void distinctFrom(YamlTest.Runner runner) throws Exception { runner.runYamsql("distinct-from.yamsql"); } diff --git a/yaml-tests/src/test/resources/distinct-from.metrics.binpb b/yaml-tests/src/test/resources/distinct-from.metrics.binpb index 7a6181ce67..efc2543695 100644 --- a/yaml-tests/src/test/resources/distinct-from.metrics.binpb +++ b/yaml-tests/src/test/resources/distinct-from.metrics.binpb @@ -1,79 +1,77 @@ -ñ +ð U -distinct-from-tests>EXPLAIN select * from t1 WHERE col2 is distinct from null— -«‰ƒ¼a· µÒð=(50ÂóÇ8J@ \COVERING(I2 <,> -> [COL2: KEY[0], ID: KEY[2]]) | FILTER _.COL2 IS_DISTINCT_FROM NULL | FETCH™ digraph G { +distinct-from-tests>EXPLAIN select * from t1 WHERE col2 is distinct from null– +²¿•¦g ðŒö (.0û­¯82@\COVERING(I2 <,> -> [COL2: KEY[0], ID: KEY[2]]) | FILTER _.COL2 IS_DISTINCT_FROM NULL | FETCH™ digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
Fetch Records
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(INT AS ID, )" ]; - 2 [ label=<
Predicate Filter
WHERE q60.COL2 IS_DISTINCT_FROM NULL
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 2 [ label=<
Predicate Filter
WHERE q55.COL2 IS_DISTINCT_FROM NULL
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; 3 [ label=<
Covering Index Scan
range: <-∞, ∞>
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; 4 [ label=<
Index
I2
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; - 3 -> 2 [ label=< q60> label="q60" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 3 -> 2 [ label=< q55> label="q55" 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=< q62> label="q62" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -}Š + 2 -> 1 [ label=< q57> label="q57" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; +}‰ N -distinct-from-tests7EXPLAIN select * from t1 WHERE col1 is DISTINCT from 10· -«îêû`· ——×<(50’ƒ±8J@ lCOVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER _.COL1 IS_DISTINCT_FROM promote(@c10 AS INT) | FETCH© digraph G { +distinct-from-tests7EXPLAIN select * from t1 WHERE col1 is DISTINCT from 10¶ +ž§Šsl Žª¬L(00ã—¢86@lCOVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER _.COL1 IS_DISTINCT_FROM promote(@c10 AS INT) | FETCH© digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
Fetch Records
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(INT AS ID, )" ]; - 2 [ label=<
Predicate Filter
WHERE q61.COL1 IS_DISTINCT_FROM promote(@c10 AS INT)
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 2 [ label=<
Predicate Filter
WHERE q55.COL1 IS_DISTINCT_FROM promote(@c10 AS INT)
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; 3 [ label=<
Covering Index Scan
range: <-∞, ∞>
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; 4 [ label=<
Index
I1
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; - 3 -> 2 [ label=< q61> label="q61" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 3 -> 2 [ label=< q55> label="q55" 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=< q63> label="q63" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -}ì + 2 -> 1 [ label=< q57> label="q57" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; +}ë P -distinct-from-tests9EXPLAIN select * from t1 WHERE null is distinct from col2— -«°ÊŒ· ²ëÎ(50ÅÑŠ8J@ \COVERING(I2 <,> -> [COL2: KEY[0], ID: KEY[2]]) | FILTER _.COL2 IS_DISTINCT_FROM NULL | FETCH™ digraph G { +distinct-from-tests9EXPLAIN select * from t1 WHERE null is distinct from col2– +²À…”g í°Ô (.0âîœ82@\COVERING(I2 <,> -> [COL2: KEY[0], ID: KEY[2]]) | FILTER _.COL2 IS_DISTINCT_FROM NULL | FETCH™ digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
Fetch Records
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(INT AS ID, )" ]; - 2 [ label=<
Predicate Filter
WHERE q60.COL2 IS_DISTINCT_FROM NULL
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 2 [ label=<
Predicate Filter
WHERE q55.COL2 IS_DISTINCT_FROM NULL
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; 3 [ label=<
Covering Index Scan
range: <-∞, ∞>
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; 4 [ label=<
Index
I2
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; - 3 -> 2 [ label=< q60> label="q60" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 3 -> 2 [ label=< q55> label="q55" 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=< q62> label="q62" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -}ˆ + 2 -> 1 [ label=< q57> label="q57" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; +}‡ N -distinct-from-tests7EXPLAIN select * from t1 WHERE 10 is distinct from col1µ -«ü„‘· ¡(50è¼’8J@ kCOVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER _.COL1 IS_DISTINCT_FROM promote(@c6 AS INT) | FETCH¨ digraph G { +distinct-from-tests7EXPLAIN select * from t1 WHERE 10 is distinct from col1´ +ÂÉ‹èrl ªâ¿L(00¯Áú86@kCOVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER _.COL1 IS_DISTINCT_FROM promote(@c6 AS INT) | FETCH¨ digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
Fetch Records
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(INT AS ID, )" ]; - 2 [ label=<
Predicate Filter
WHERE q61.COL1 IS_DISTINCT_FROM promote(@c6 AS INT)
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 2 [ label=<
Predicate Filter
WHERE q55.COL1 IS_DISTINCT_FROM promote(@c6 AS INT)
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; 3 [ label=<
Covering Index Scan
range: <-∞, ∞>
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; 4 [ label=<
Index
I1
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; - 3 -> 2 [ label=< q61> label="q61" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 3 -> 2 [ label=< q55> label="q55" 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=< q63> label="q63" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -}¼ + 2 -> 1 [ label=< q57> label="q57" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; +}å P -distinct-from-tests9EXPLAIN select * from t1 WHERE null is distinct from nullç -ÑüܼÀ ˜ë(80‚Ëó8Q@ -ECOVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER false | FETCH€ digraph G { +distinct-from-tests9EXPLAIN select * from t1 WHERE null is distinct from null +ÙÅë rl Ý«ŸP(00¢ìö88@ZCOVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER NULL IS_DISTINCT_FROM NULL | FETCH• digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
Fetch Records
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(INT AS ID, )" ]; - 2 [ label=<
Predicate Filter
WHERE false
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 2 [ label=<
Predicate Filter
WHERE NULL IS_DISTINCT_FROM NULL
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; 3 [ label=<
Covering Index Scan
range: <-∞, ∞>
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; 4 [ label=<
Index
I1
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; - 3 -> 2 [ label=< q64> label="q64" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 3 -> 2 [ label=< q54> label="q54" 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=< q66> label="q66" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -}Þ + 2 -> 1 [ label=< q56> label="q56" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; +}Ý L -distinct-from-tests5EXPLAIN select * from t1 WHERE 10 is distinct from 10 -ÑÄÑÍÀ ½°¼(80Ö‚‡8Q@ -XCOVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER @c6 IS_DISTINCT_FROM @c6 | FETCH“ digraph G { +distinct-from-tests5EXPLAIN select * from t1 WHERE 10 is distinct from 10Œ +Ù¨Í÷l ”ûÛ (00È ¾88@XCOVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER @c6 IS_DISTINCT_FROM @c6 | FETCH“ digraph G { fontname=courier; rankdir=BT; splines=polyline; @@ -81,103 +79,107 @@ L 2 [ label=<
Predicate Filter
WHERE @c6 IS_DISTINCT_FROM @c6
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; 3 [ label=<
Covering Index Scan
range: <-∞, ∞>
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; 4 [ label=<
Index
I1
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; - 3 -> 2 [ label=< q64> label="q64" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 3 -> 2 [ label=< q54> label="q54" 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=< q66> label="q66" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -}û + 2 -> 1 [ label=< q56> label="q56" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; +}ù ] -not-distinct-from-testsBEXPLAIN select * from t1 WHERE col2 is not distinct from null™ -«ŸªÃ¶ ££î(50áæÒ8J@ ]COVERING(I2 <,> -> [COL2: KEY[0], ID: KEY[2]]) | FILTER _.COL2 NOT_DISTINCT_FROM NULL | FETCHš digraph G { +not-distinct-from-testsBEXPLAIN select * from t1 WHERE col2 is not distinct from null— +²áôË f ‡ªÛ(.0»ä^82@]COVERING(I2 <,> -> [COL2: KEY[0], ID: KEY[2]]) | FILTER _.COL2 NOT_DISTINCT_FROM NULL | FETCHš digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
Fetch Records
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(INT AS ID, )" ]; - 2 [ label=<
Predicate Filter
WHERE q60.COL2 NOT_DISTINCT_FROM NULL
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 2 [ label=<
Predicate Filter
WHERE q55.COL2 NOT_DISTINCT_FROM NULL
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; 3 [ label=<
Covering Index Scan
range: <-∞, ∞>
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; 4 [ label=<
Index
I2
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; - 3 -> 2 [ label=< q60> label="q60" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 3 -> 2 [ label=< q55> label="q55" 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=< q62> label="q62" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -}” + 2 -> 1 [ label=< q57> label="q57" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; +}“ V -not-distinct-from-tests;EXPLAIN select * from t1 WHERE col1 is not distinct from 20¹ -«û†«¶ –Œ (50èÊ„8J@ mCOVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER _.COL1 NOT_DISTINCT_FROM promote(@c11 AS INT) | FETCHª digraph G { +not-distinct-from-tests;EXPLAIN select * from t1 WHERE col1 is not distinct from 20¸ +Âìºðk 远 (00ÛÓ¡86@mCOVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER _.COL1 NOT_DISTINCT_FROM promote(@c11 AS INT) | FETCHª digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
Fetch Records
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(INT AS ID, )" ]; - 2 [ label=<
Predicate Filter
WHERE q61.COL1 NOT_DISTINCT_FROM promote(@c11 AS INT)
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 2 [ label=<
Predicate Filter
WHERE q55.COL1 NOT_DISTINCT_FROM promote(@c11 AS INT)
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; 3 [ label=<
Covering Index Scan
range: <-∞, ∞>
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; 4 [ label=<
Index
I1
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; - 3 -> 2 [ label=< q61> label="q61" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 3 -> 2 [ label=< q55> label="q55" 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=< q63> label="q63" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -}ö + 2 -> 1 [ label=< q57> label="q57" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; +}ô X -not-distinct-from-tests=EXPLAIN select * from t1 WHERE null is not distinct from col2™ -«‰Ñ˶ ó ¶(50å·Á8J@ ]COVERING(I2 <,> -> [COL2: KEY[0], ID: KEY[2]]) | FILTER _.COL2 NOT_DISTINCT_FROM NULL | FETCHš digraph G { +not-distinct-from-tests=EXPLAIN select * from t1 WHERE null is not distinct from col2— +²©ÒÃf Ë‹Ÿ(.0¬Üc82@]COVERING(I2 <,> -> [COL2: KEY[0], ID: KEY[2]]) | FILTER _.COL2 NOT_DISTINCT_FROM NULL | FETCHš digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
Fetch Records
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(INT AS ID, )" ]; - 2 [ label=<
Predicate Filter
WHERE q60.COL2 NOT_DISTINCT_FROM NULL
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 2 [ label=<
Predicate Filter
WHERE q55.COL2 NOT_DISTINCT_FROM NULL
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; 3 [ label=<
Covering Index Scan
range: <-∞, ∞>
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; 4 [ label=<
Index
I2
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; - 3 -> 2 [ label=< q60> label="q60" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 3 -> 2 [ label=< q55> label="q55" 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=< q62> label="q62" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -}’ + 2 -> 1 [ label=< q57> label="q57" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; +}‘ V -not-distinct-from-tests;EXPLAIN select * from t1 WHERE 20 is not distinct from col1· -«™½¦¶ çË®(50…õÄ8J@ lCOVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER _.COL1 NOT_DISTINCT_FROM promote(@c6 AS INT) | FETCH© digraph G { +not-distinct-from-tests;EXPLAIN select * from t1 WHERE 20 is not distinct from col1¶ +¬¤¤k 冸(00ÌöÁ86@lCOVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER _.COL1 NOT_DISTINCT_FROM promote(@c6 AS INT) | FETCH© digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
Fetch Records
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(INT AS ID, )" ]; - 2 [ label=<
Predicate Filter
WHERE q61.COL1 NOT_DISTINCT_FROM promote(@c6 AS INT)
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 2 [ label=<
Predicate Filter
WHERE q55.COL1 NOT_DISTINCT_FROM promote(@c6 AS INT)
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; 3 [ label=<
Covering Index Scan
range: <-∞, ∞>
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; 4 [ label=<
Index
I1
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; - 3 -> 2 [ label=< q61> label="q61" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 3 -> 2 [ label=< q55> label="q55" 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=< q63> label="q63" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; -}Œ + 2 -> 1 [ label=< q57> label="q57" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; +}à _ -not-distinct-from-testsDEXPLAIN select count(*) from t1 WHERE null is not distinct from null¨ -Ӈר#Ì ²¦ˆ (<0úóð8`@ƒISCAN(I2 <,>) | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)‚digraph G { +not-distinct-from-testsDEXPLAIN select count(*) from t1 WHERE null is not distinct from nullü +óôò±´ Á¸(90ÖÀü8U@ÑCOVERING(I2 <,> -> [COL2: KEY[0], ID: KEY[2]]) | FILTER NULL NOT_DISTINCT_FROM NULL | FETCH | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)ˆdigraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
Value Computation
MAP (coalesce_long(q6._0._0, promote(0l AS LONG)) AS _0)
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
Value Computation
$q6 OR NULL
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; 3 [ label=<
Streaming Aggregate
COLLECT (count_star(*) AS _0)
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
Value Computation
MAP (q2 AS _0)
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, AS _0)" ]; - 5 [ label=<
Index Scan
range: <-∞, ∞>
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; - 6 [ label=<
Index
I2
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 4 [ label=<
Value Computation
MAP (q61 AS _0)
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, AS _0)" ]; + 5 [ label=<
Fetch Records
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(INT AS ID, )" ]; + 6 [ label=<
Predicate Filter
WHERE NULL NOT_DISTINCT_FROM NULL
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 7 [ label=<
Covering Index Scan
range: <-∞, ∞>
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; + 8 [ label=<
Index
I2
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q88> label="q88" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 5 -> 4 [ label=< q2> label="q2" 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 -> 3 [ label=< q107> label="q107" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 -> 4 [ label=< q61> label="q61" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 6 -> 5 [ label=< q73> label="q73" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 7 -> 6 [ label=< q71> label="q71" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 8 -> 7 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; }Ø [ not-distinct-from-tests@EXPLAIN select count(*) from t1 WHERE 10 is not distinct from 10ø -Ý•³×"Ü ÙöÀ (>0“†ö8v@ÏCOVERING(I2 <,> -> [COL2: KEY[0], ID: KEY[2]]) | FILTER @c9 NOT_DISTINCT_FROM @c9 | FETCH | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)†digraph G { +óÉŒ€´ ïØ (90㮈8U@ÏCOVERING(I2 <,> -> [COL2: KEY[0], ID: KEY[2]]) | FILTER @c9 NOT_DISTINCT_FROM @c9 | FETCH | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)†digraph G { fontname=courier; rankdir=BT; splines=polyline; 1 [ label=<
Value Computation
MAP (coalesce_long(q6._0._0, promote(0l AS LONG)) AS _0)
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0)" ]; 2 [ label=<
Value Computation
$q6 OR NULL
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; 3 [ label=<
Streaming Aggregate
COLLECT (count_star(*) AS _0)
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(LONG AS _0 AS _0)" ]; - 4 [ label=<
Value Computation
MAP (q67 AS _0)
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, AS _0)" ]; + 4 [ label=<
Value Computation
MAP (q61 AS _0)
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, AS _0)" ]; 5 [ label=<
Fetch Records
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="12" tooltip="RELATION(INT AS ID, )" ]; 6 [ label=<
Predicate Filter
WHERE @c9 NOT_DISTINCT_FROM @c9
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; 7 [ label=<
Covering Index Scan
range: <-∞, ∞>
> color="black" shape="plain" style="solid" fillcolor="black" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; 8 [ label=<
Index
I2
> color="black" shape="plain" style="filled" fillcolor="lightblue" fontname="courier" fontsize="8" tooltip="RELATION(INT AS ID, )" ]; 3 -> 2 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 4 -> 3 [ label=< q113> label="q113" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 5 -> 4 [ label=< q67> label="q67" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 6 -> 5 [ label=< q74> label="q74" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; - 7 -> 6 [ label=< q72> label="q72" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 4 -> 3 [ label=< q107> label="q107" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 5 -> 4 [ label=< q61> label="q61" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 6 -> 5 [ label=< q73> label="q73" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; + 7 -> 6 [ label=< q71> label="q71" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 8 -> 7 [ color="gray20" style="solid" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; 2 -> 1 [ label=< q6> label="q6" color="gray20" style="bold" fontname="courier" fontsize="8" arrowhead="normal" arrowtail="none" dir="both" ]; } \ No newline at end of file diff --git a/yaml-tests/src/test/resources/distinct-from.metrics.yaml b/yaml-tests/src/test/resources/distinct-from.metrics.yaml index 52a7528bf0..4c15eb3807 100644 --- a/yaml-tests/src/test/resources/distinct-from.metrics.yaml +++ b/yaml-tests/src/test/resources/distinct-from.metrics.yaml @@ -2,133 +2,135 @@ distinct-from-tests: - query: EXPLAIN select * from t1 WHERE col2 is distinct from null explain: 'COVERING(I2 <,> -> [COL2: KEY[0], ID: KEY[2]]) | FILTER _.COL2 IS_DISTINCT_FROM NULL | FETCH' - task_count: 683 - task_total_time_ms: 204 - transform_count: 183 - transform_time_ms: 129 - transform_yield_count: 53 - insert_time_ms: 13 - insert_new_count: 74 - insert_reused_count: 9 + task_count: 434 + task_total_time_ms: 42 + transform_count: 103 + transform_time_ms: 20 + transform_yield_count: 46 + insert_time_ms: 2 + insert_new_count: 50 + insert_reused_count: 7 - query: EXPLAIN select * from t1 WHERE col1 is DISTINCT from 10 explain: 'COVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER _.COL1 IS_DISTINCT_FROM promote(@c10 AS INT) | FETCH' - task_count: 683 - task_total_time_ms: 203 - transform_count: 183 - transform_time_ms: 127 - transform_yield_count: 53 - insert_time_ms: 13 - insert_new_count: 74 - insert_reused_count: 9 + task_count: 450 + task_total_time_ms: 241 + transform_count: 108 + transform_time_ms: 160 + transform_yield_count: 48 + insert_time_ms: 15 + insert_new_count: 54 + insert_reused_count: 7 - query: EXPLAIN select * from t1 WHERE null is distinct from col2 explain: 'COVERING(I2 <,> -> [COL2: KEY[0], ID: KEY[2]]) | FILTER _.COL2 IS_DISTINCT_FROM NULL | FETCH' - task_count: 683 - task_total_time_ms: 52 - transform_count: 183 - transform_time_ms: 15 - transform_yield_count: 53 - insert_time_ms: 4 - insert_new_count: 74 - insert_reused_count: 9 + task_count: 434 + task_total_time_ms: 42 + transform_count: 103 + transform_time_ms: 20 + transform_yield_count: 46 + insert_time_ms: 2 + insert_new_count: 50 + insert_reused_count: 7 - query: EXPLAIN select * from t1 WHERE 10 is distinct from col1 explain: 'COVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER _.COL1 IS_DISTINCT_FROM promote(@c6 AS INT) | FETCH' - task_count: 683 - task_total_time_ms: 52 - transform_count: 183 - transform_time_ms: 17 - transform_yield_count: 53 - insert_time_ms: 4 - insert_new_count: 74 - insert_reused_count: 9 + task_count: 450 + task_total_time_ms: 240 + transform_count: 108 + transform_time_ms: 160 + transform_yield_count: 48 + insert_time_ms: 14 + insert_new_count: 54 + insert_reused_count: 7 - query: EXPLAIN select * from t1 WHERE null is distinct from null - explain: 'COVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER false | FETCH' - task_count: 721 - task_total_time_ms: 53 - transform_count: 192 - transform_time_ms: 16 - transform_yield_count: 56 - insert_time_ms: 3 - insert_new_count: 81 - insert_reused_count: 10 + explain: 'COVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER NULL IS_DISTINCT_FROM + NULL | FETCH' + task_count: 473 + task_total_time_ms: 239 + transform_count: 108 + transform_time_ms: 168 + transform_yield_count: 48 + insert_time_ms: 8 + insert_new_count: 56 + insert_reused_count: 8 - query: EXPLAIN select * from t1 WHERE 10 is distinct from 10 explain: 'COVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER @c6 IS_DISTINCT_FROM @c6 | FETCH' - task_count: 721 - task_total_time_ms: 55 - transform_count: 192 - transform_time_ms: 17 - transform_yield_count: 56 - insert_time_ms: 4 - insert_new_count: 81 - insert_reused_count: 10 + task_count: 473 + task_total_time_ms: 43 + transform_count: 108 + transform_time_ms: 20 + transform_yield_count: 48 + insert_time_ms: 3 + insert_new_count: 56 + insert_reused_count: 8 not-distinct-from-tests: - query: EXPLAIN select * from t1 WHERE col2 is not distinct from null explain: 'COVERING(I2 <,> -> [COL2: KEY[0], ID: KEY[2]]) | FILTER _.COL2 NOT_DISTINCT_FROM NULL | FETCH' - task_count: 683 - task_total_time_ms: 45 - transform_count: 182 - transform_time_ms: 14 - transform_yield_count: 53 - insert_time_ms: 3 - insert_new_count: 74 - insert_reused_count: 9 + task_count: 434 + task_total_time_ms: 26 + transform_count: 102 + transform_time_ms: 11 + transform_yield_count: 46 + insert_time_ms: 1 + insert_new_count: 50 + insert_reused_count: 7 - query: EXPLAIN select * from t1 WHERE col1 is not distinct from 20 explain: 'COVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER _.COL1 NOT_DISTINCT_FROM promote(@c11 AS INT) | FETCH' - task_count: 683 - task_total_time_ms: 51 - transform_count: 182 + task_count: 450 + task_total_time_ms: 43 + transform_count: 107 transform_time_ms: 19 - transform_yield_count: 53 - insert_time_ms: 4 - insert_new_count: 74 - insert_reused_count: 9 + transform_yield_count: 48 + insert_time_ms: 2 + insert_new_count: 54 + insert_reused_count: 7 - query: EXPLAIN select * from t1 WHERE null is not distinct from col2 explain: 'COVERING(I2 <,> -> [COL2: KEY[0], ID: KEY[2]]) | FILTER _.COL2 NOT_DISTINCT_FROM NULL | FETCH' - task_count: 683 - task_total_time_ms: 38 - transform_count: 182 - transform_time_ms: 11 - transform_yield_count: 53 - insert_time_ms: 3 - insert_new_count: 74 - insert_reused_count: 9 + task_count: 434 + task_total_time_ms: 32 + transform_count: 102 + transform_time_ms: 15 + transform_yield_count: 46 + insert_time_ms: 1 + insert_new_count: 50 + insert_reused_count: 7 - query: EXPLAIN select * from t1 WHERE 20 is not distinct from col1 explain: 'COVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER _.COL1 NOT_DISTINCT_FROM promote(@c6 AS INT) | FETCH' - task_count: 683 - task_total_time_ms: 38 - transform_count: 182 - transform_time_ms: 11 - transform_yield_count: 53 + task_count: 450 + task_total_time_ms: 42 + transform_count: 107 + transform_time_ms: 18 + transform_yield_count: 48 insert_time_ms: 3 - insert_new_count: 74 - insert_reused_count: 9 + insert_new_count: 54 + insert_reused_count: 7 - query: EXPLAIN select count(*) from t1 WHERE null is not distinct from null - explain: ISCAN(I2 <,>) | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY - NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0) - task_count: 723 - task_total_time_ms: 74 - transform_count: 204 - transform_time_ms: 27 - transform_yield_count: 60 - insert_time_ms: 3 - insert_new_count: 96 - insert_reused_count: 8 + explain: 'COVERING(I2 <,> -> [COL2: KEY[0], ID: KEY[2]]) | FILTER NULL NOT_DISTINCT_FROM + NULL | FETCH | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | + MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)' + task_count: 755 + task_total_time_ms: 65 + transform_count: 180 + transform_time_ms: 37 + transform_yield_count: 57 + insert_time_ms: 4 + insert_new_count: 85 + insert_reused_count: 4 - query: EXPLAIN select count(*) from t1 WHERE 10 is not distinct from 10 explain: 'COVERING(I2 <,> -> [COL2: KEY[0], ID: KEY[2]]) | FILTER @c9 NOT_DISTINCT_FROM @c9 | FETCH | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)' - task_count: 861 - task_total_time_ms: 72 - transform_count: 220 - transform_time_ms: 26 - transform_yield_count: 62 - insert_time_ms: 16 - insert_new_count: 118 - insert_reused_count: 6 + task_count: 755 + task_total_time_ms: 39 + transform_count: 180 + transform_time_ms: 19 + transform_yield_count: 57 + insert_time_ms: 2 + insert_new_count: 85 + insert_reused_count: 4 diff --git a/yaml-tests/src/test/resources/distinct-from.yamsql b/yaml-tests/src/test/resources/distinct-from.yamsql index 80c9319f98..6c3e97a1c8 100644 --- a/yaml-tests/src/test/resources/distinct-from.yamsql +++ b/yaml-tests/src/test/resources/distinct-from.yamsql @@ -63,7 +63,7 @@ test_block: - result: [{ID: 6, 20, !null }, {ID: 7, 20, !null }, {ID: 8, 20, !null }, {ID: 9, 20, 9}, {ID: 10, 20, 10}] - - query: select * from t1 WHERE null is distinct from null - - explain: "COVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER false | FETCH" + - explain: "COVERING(I1 <,> -> [COL1: KEY[0], ID: KEY[2]]) | FILTER NULL IS_DISTINCT_FROM NULL | FETCH" - result: [] - - query: select * from t1 WHERE 10 is distinct from 10 @@ -92,7 +92,7 @@ test_block: - result: [{ID: 6, 20, !null }, {ID: 7, 20, !null }, {ID: 8, 20, !null }, {ID: 9, 20, 9}, {ID: 10, 20, 10}] - - query: select count(*) from t1 WHERE null is not distinct from null - - explain: "ISCAN(I2 <,>) | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)" + - explain: "COVERING(I2 <,> -> [COL2: KEY[0], ID: KEY[2]]) | FILTER NULL NOT_DISTINCT_FROM NULL | FETCH | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)" - result: [{10}] - - query: select count(*) from t1 WHERE 10 is not distinct from 10 From 6b82cb2c625d5ff6d9736d6e1cdba1995bf951fa Mon Sep 17 00:00:00 2001 From: Pengpeng Lu Date: Fri, 1 Aug 2025 22:55:59 -0700 Subject: [PATCH 15/16] add booleanValueTest --- .../plan/cascades/values/RelOpValue.java | 9 +- .../query/plan/cascades/BooleanValueTest.java | 132 +++++++++++++++++- 2 files changed, 138 insertions(+), 3 deletions(-) diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/RelOpValue.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/RelOpValue.java index ae1c3e6bfb..7226ff035d 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/RelOpValue.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/RelOpValue.java @@ -1074,8 +1074,15 @@ private enum BinaryPhysicalOperator { @Nullable public Object eval(@Nullable final Object arg1, @Nullable final Object arg2) { + // handle nulls if (arg1 == null || arg2 == null) { - return null; + if (type == Comparisons.Type.IS_DISTINCT_FROM) { + return arg1 != null || arg2 != null; + } else if (type == Comparisons.Type.NOT_DISTINCT_FROM) { + return arg1 == null && arg2 == null; + } else { + return null; + } } return evaluateFunction.apply(arg1, arg2); } diff --git a/fdb-record-layer-core/src/test/java/com/apple/foundationdb/record/query/plan/cascades/BooleanValueTest.java b/fdb-record-layer-core/src/test/java/com/apple/foundationdb/record/query/plan/cascades/BooleanValueTest.java index 4446060840..87cbbe3424 100644 --- a/fdb-record-layer-core/src/test/java/com/apple/foundationdb/record/query/plan/cascades/BooleanValueTest.java +++ b/fdb-record-layer-core/src/test/java/com/apple/foundationdb/record/query/plan/cascades/BooleanValueTest.java @@ -139,6 +139,10 @@ public Stream provideArguments(final ExtensionContext conte Arguments.of(List.of(BOOL_FALSE, BOOL_TRUE), new RelOpValue.EqualsFn(), ConstantPredicate.FALSE), Arguments.of(List.of(BOOL_TRUE, BOOL_TRUE), new RelOpValue.NotEqualsFn(), ConstantPredicate.FALSE), Arguments.of(List.of(BOOL_FALSE, BOOL_TRUE), new RelOpValue.NotEqualsFn(), ConstantPredicate.TRUE), + Arguments.of(List.of(BOOL_TRUE, BOOL_FALSE), new RelOpValue.IsDistinctFromFn(), ConstantPredicate.TRUE), + Arguments.of(List.of(BOOL_TRUE, BOOL_TRUE), new RelOpValue.IsDistinctFromFn(), ConstantPredicate.FALSE), + Arguments.of(List.of(BOOL_TRUE, BOOL_FALSE), new RelOpValue.NotDistinctFromFn(), ConstantPredicate.FALSE), + Arguments.of(List.of(BOOL_TRUE, BOOL_TRUE), new RelOpValue.NotDistinctFromFn(), ConstantPredicate.TRUE), Arguments.of(List.of(INT_1, INT_1), new RelOpValue.EqualsFn(), ConstantPredicate.TRUE), Arguments.of(List.of(INT_1, INT_2), new RelOpValue.EqualsFn(), ConstantPredicate.FALSE), @@ -154,6 +158,10 @@ public Stream provideArguments(final ExtensionContext conte Arguments.of(List.of(INT_1, INT_2), new RelOpValue.GteFn(), ConstantPredicate.FALSE), Arguments.of(List.of(INT_2, INT_1), new RelOpValue.GteFn(), ConstantPredicate.TRUE), Arguments.of(List.of(INT_1, INT_1), new RelOpValue.GteFn(), ConstantPredicate.TRUE), + Arguments.of(List.of(INT_1, INT_1), new RelOpValue.IsDistinctFromFn(), ConstantPredicate.FALSE), + Arguments.of(List.of(INT_1, INT_2), new RelOpValue.IsDistinctFromFn(), ConstantPredicate.TRUE), + Arguments.of(List.of(INT_1, INT_1), new RelOpValue.NotDistinctFromFn(), ConstantPredicate.TRUE), + Arguments.of(List.of(INT_1, INT_2), new RelOpValue.NotDistinctFromFn(), ConstantPredicate.FALSE), Arguments.of(List.of(LONG_1, LONG_1), new RelOpValue.EqualsFn(), ConstantPredicate.TRUE), Arguments.of(List.of(LONG_1, LONG_2), new RelOpValue.EqualsFn(), ConstantPredicate.FALSE), @@ -169,6 +177,10 @@ public Stream provideArguments(final ExtensionContext conte Arguments.of(List.of(LONG_1, LONG_2), new RelOpValue.GteFn(), ConstantPredicate.FALSE), Arguments.of(List.of(LONG_2, LONG_1), new RelOpValue.GteFn(), ConstantPredicate.TRUE), Arguments.of(List.of(LONG_1, LONG_1), new RelOpValue.GteFn(), ConstantPredicate.TRUE), + Arguments.of(List.of(LONG_1, LONG_1), new RelOpValue.NotDistinctFromFn(), ConstantPredicate.TRUE), + Arguments.of(List.of(LONG_1, LONG_2), new RelOpValue.NotDistinctFromFn(), ConstantPredicate.FALSE), + Arguments.of(List.of(LONG_1, LONG_1), new RelOpValue.IsDistinctFromFn(), ConstantPredicate.FALSE), + Arguments.of(List.of(LONG_1, LONG_2), new RelOpValue.IsDistinctFromFn(), ConstantPredicate.TRUE), Arguments.of(List.of(FLOAT_1, FLOAT_1), new RelOpValue.EqualsFn(), ConstantPredicate.TRUE), Arguments.of(List.of(FLOAT_1, FLOAT_2), new RelOpValue.EqualsFn(), ConstantPredicate.FALSE), @@ -184,6 +196,10 @@ public Stream provideArguments(final ExtensionContext conte Arguments.of(List.of(FLOAT_1, FLOAT_2), new RelOpValue.GteFn(), ConstantPredicate.FALSE), Arguments.of(List.of(FLOAT_2, FLOAT_1), new RelOpValue.GteFn(), ConstantPredicate.TRUE), Arguments.of(List.of(FLOAT_1, FLOAT_1), new RelOpValue.GteFn(), ConstantPredicate.TRUE), + Arguments.of(List.of(FLOAT_1, FLOAT_1), new RelOpValue.NotDistinctFromFn(), ConstantPredicate.TRUE), + Arguments.of(List.of(FLOAT_1, FLOAT_2), new RelOpValue.NotDistinctFromFn(), ConstantPredicate.FALSE), + Arguments.of(List.of(FLOAT_1, FLOAT_1), new RelOpValue.IsDistinctFromFn(), ConstantPredicate.FALSE), + Arguments.of(List.of(FLOAT_1, FLOAT_2), new RelOpValue.IsDistinctFromFn(), ConstantPredicate.TRUE), Arguments.of(List.of(DOUBLE_1, DOUBLE_1), new RelOpValue.EqualsFn(), ConstantPredicate.TRUE), Arguments.of(List.of(DOUBLE_1, DOUBLE_2), new RelOpValue.EqualsFn(), ConstantPredicate.FALSE), @@ -199,6 +215,10 @@ public Stream provideArguments(final ExtensionContext conte Arguments.of(List.of(DOUBLE_1, DOUBLE_2), new RelOpValue.GteFn(), ConstantPredicate.FALSE), Arguments.of(List.of(DOUBLE_2, DOUBLE_1), new RelOpValue.GteFn(), ConstantPredicate.TRUE), Arguments.of(List.of(DOUBLE_1, DOUBLE_1), new RelOpValue.GteFn(), ConstantPredicate.TRUE), + Arguments.of(List.of(DOUBLE_1, DOUBLE_1), new RelOpValue.NotDistinctFromFn(), ConstantPredicate.TRUE), + Arguments.of(List.of(DOUBLE_1, DOUBLE_2), new RelOpValue.NotDistinctFromFn(), ConstantPredicate.FALSE), + Arguments.of(List.of(DOUBLE_1, DOUBLE_1), new RelOpValue.IsDistinctFromFn(), ConstantPredicate.FALSE), + Arguments.of(List.of(DOUBLE_1, DOUBLE_2), new RelOpValue.IsDistinctFromFn(), ConstantPredicate.TRUE), Arguments.of(List.of(STRING_1, STRING_1), new RelOpValue.EqualsFn(), ConstantPredicate.TRUE), Arguments.of(List.of(STRING_1, STRING_2), new RelOpValue.EqualsFn(), ConstantPredicate.FALSE), @@ -214,11 +234,19 @@ public Stream provideArguments(final ExtensionContext conte Arguments.of(List.of(STRING_1, STRING_2), new RelOpValue.GteFn(), ConstantPredicate.FALSE), Arguments.of(List.of(STRING_2, STRING_1), new RelOpValue.GteFn(), ConstantPredicate.TRUE), Arguments.of(List.of(STRING_1, STRING_1), new RelOpValue.GteFn(), ConstantPredicate.TRUE), + Arguments.of(List.of(STRING_1, STRING_1), new RelOpValue.NotDistinctFromFn(), ConstantPredicate.TRUE), + Arguments.of(List.of(STRING_1, STRING_2), new RelOpValue.NotDistinctFromFn(), ConstantPredicate.FALSE), + Arguments.of(List.of(STRING_1, STRING_1), new RelOpValue.IsDistinctFromFn(), ConstantPredicate.FALSE), + Arguments.of(List.of(STRING_1, STRING_2), new RelOpValue.IsDistinctFromFn(), ConstantPredicate.TRUE), Arguments.of(List.of(BYTES_1, BYTES_1), new RelOpValue.EqualsFn(), ConstantPredicate.TRUE), Arguments.of(List.of(BYTES_1, BYTES_2), new RelOpValue.EqualsFn(), ConstantPredicate.FALSE), Arguments.of(List.of(BYTES_1, BYTES_1), new RelOpValue.NotEqualsFn(), ConstantPredicate.FALSE), Arguments.of(List.of(BYTES_1, BYTES_2), new RelOpValue.NotEqualsFn(), ConstantPredicate.TRUE), + Arguments.of(List.of(BYTES_1, BYTES_1), new RelOpValue.NotDistinctFromFn(), ConstantPredicate.TRUE), + Arguments.of(List.of(BYTES_1, BYTES_2), new RelOpValue.NotDistinctFromFn(), ConstantPredicate.FALSE), + Arguments.of(List.of(BYTES_1, BYTES_1), new RelOpValue.IsDistinctFromFn(), ConstantPredicate.FALSE), + Arguments.of(List.of(BYTES_1, BYTES_2), new RelOpValue.IsDistinctFromFn(), ConstantPredicate.TRUE), Arguments.of(List.of(LONG_1, INT_1), new RelOpValue.EqualsFn(), ConstantPredicate.TRUE), Arguments.of(List.of(LONG_1, INT_2), new RelOpValue.EqualsFn(), ConstantPredicate.FALSE), @@ -234,6 +262,10 @@ public Stream provideArguments(final ExtensionContext conte Arguments.of(List.of(LONG_1, INT_2), new RelOpValue.GteFn(), ConstantPredicate.FALSE), Arguments.of(List.of(LONG_2, INT_1), new RelOpValue.GteFn(), ConstantPredicate.TRUE), Arguments.of(List.of(LONG_1, INT_1), new RelOpValue.GteFn(), ConstantPredicate.TRUE), + Arguments.of(List.of(LONG_1, INT_1), new RelOpValue.NotDistinctFromFn(), ConstantPredicate.TRUE), + Arguments.of(List.of(LONG_1, INT_2), new RelOpValue.NotDistinctFromFn(), ConstantPredicate.FALSE), + Arguments.of(List.of(LONG_1, INT_1), new RelOpValue.IsDistinctFromFn(), ConstantPredicate.FALSE), + Arguments.of(List.of(LONG_1, INT_2), new RelOpValue.IsDistinctFromFn(), ConstantPredicate.TRUE), Arguments.of(List.of(INT_1, LONG_1), new RelOpValue.EqualsFn(), ConstantPredicate.TRUE), Arguments.of(List.of(INT_1, LONG_2), new RelOpValue.EqualsFn(), ConstantPredicate.FALSE), @@ -249,6 +281,10 @@ public Stream provideArguments(final ExtensionContext conte Arguments.of(List.of(INT_1, LONG_2), new RelOpValue.GteFn(), ConstantPredicate.FALSE), Arguments.of(List.of(INT_2, LONG_1), new RelOpValue.GteFn(), ConstantPredicate.TRUE), Arguments.of(List.of(INT_1, LONG_1), new RelOpValue.GteFn(), ConstantPredicate.TRUE), + Arguments.of(List.of(INT_1, LONG_1), new RelOpValue.NotDistinctFromFn(), ConstantPredicate.TRUE), + Arguments.of(List.of(INT_1, LONG_2), new RelOpValue.NotDistinctFromFn(), ConstantPredicate.FALSE), + Arguments.of(List.of(INT_1, LONG_1), new RelOpValue.IsDistinctFromFn(), ConstantPredicate.FALSE), + Arguments.of(List.of(INT_1, LONG_2), new RelOpValue.IsDistinctFromFn(), ConstantPredicate.TRUE), Arguments.of(List.of(FLOAT_1, INT_1), new RelOpValue.EqualsFn(), ConstantPredicate.TRUE), Arguments.of(List.of(FLOAT_1, INT_2), new RelOpValue.EqualsFn(), ConstantPredicate.FALSE), @@ -264,6 +300,10 @@ public Stream provideArguments(final ExtensionContext conte Arguments.of(List.of(FLOAT_1, INT_2), new RelOpValue.GteFn(), ConstantPredicate.FALSE), Arguments.of(List.of(FLOAT_2, INT_1), new RelOpValue.GteFn(), ConstantPredicate.TRUE), Arguments.of(List.of(FLOAT_1, INT_1), new RelOpValue.GteFn(), ConstantPredicate.TRUE), + Arguments.of(List.of(FLOAT_1, INT_1), new RelOpValue.NotDistinctFromFn(), ConstantPredicate.TRUE), + Arguments.of(List.of(FLOAT_1, INT_2), new RelOpValue.NotDistinctFromFn(), ConstantPredicate.FALSE), + Arguments.of(List.of(FLOAT_1, INT_1), new RelOpValue.IsDistinctFromFn(), ConstantPredicate.FALSE), + Arguments.of(List.of(FLOAT_1, INT_2), new RelOpValue.IsDistinctFromFn(), ConstantPredicate.TRUE), Arguments.of(List.of(INT_1, FLOAT_1), new RelOpValue.EqualsFn(), ConstantPredicate.TRUE), Arguments.of(List.of(INT_1, FLOAT_2), new RelOpValue.EqualsFn(), ConstantPredicate.FALSE), @@ -279,6 +319,10 @@ public Stream provideArguments(final ExtensionContext conte Arguments.of(List.of(INT_1, FLOAT_2), new RelOpValue.GteFn(), ConstantPredicate.FALSE), Arguments.of(List.of(INT_2, FLOAT_1), new RelOpValue.GteFn(), ConstantPredicate.TRUE), Arguments.of(List.of(INT_1, FLOAT_1), new RelOpValue.GteFn(), ConstantPredicate.TRUE), + Arguments.of(List.of(INT_1, FLOAT_1), new RelOpValue.NotDistinctFromFn(), ConstantPredicate.TRUE), + Arguments.of(List.of(INT_1, FLOAT_2), new RelOpValue.NotDistinctFromFn(), ConstantPredicate.FALSE), + Arguments.of(List.of(INT_1, FLOAT_1), new RelOpValue.IsDistinctFromFn(), ConstantPredicate.FALSE), + Arguments.of(List.of(INT_1, FLOAT_2), new RelOpValue.IsDistinctFromFn(), ConstantPredicate.TRUE), Arguments.of(List.of(DOUBLE_1, INT_1), new RelOpValue.EqualsFn(), ConstantPredicate.TRUE), Arguments.of(List.of(DOUBLE_1, INT_2), new RelOpValue.EqualsFn(), ConstantPredicate.FALSE), @@ -294,6 +338,10 @@ public Stream provideArguments(final ExtensionContext conte Arguments.of(List.of(DOUBLE_1, INT_2), new RelOpValue.GteFn(), ConstantPredicate.FALSE), Arguments.of(List.of(DOUBLE_2, INT_1), new RelOpValue.GteFn(), ConstantPredicate.TRUE), Arguments.of(List.of(DOUBLE_1, INT_1), new RelOpValue.GteFn(), ConstantPredicate.TRUE), + Arguments.of(List.of(DOUBLE_1, INT_1), new RelOpValue.NotDistinctFromFn(), ConstantPredicate.TRUE), + Arguments.of(List.of(DOUBLE_1, INT_2), new RelOpValue.NotDistinctFromFn(), ConstantPredicate.FALSE), + Arguments.of(List.of(DOUBLE_1, INT_1), new RelOpValue.IsDistinctFromFn(), ConstantPredicate.FALSE), + Arguments.of(List.of(DOUBLE_1, INT_2), new RelOpValue.IsDistinctFromFn(), ConstantPredicate.TRUE), Arguments.of(List.of(INT_1, DOUBLE_1), new RelOpValue.EqualsFn(), ConstantPredicate.TRUE), Arguments.of(List.of(INT_1, DOUBLE_2), new RelOpValue.EqualsFn(), ConstantPredicate.FALSE), @@ -309,6 +357,10 @@ public Stream provideArguments(final ExtensionContext conte Arguments.of(List.of(INT_1, DOUBLE_2), new RelOpValue.GteFn(), ConstantPredicate.FALSE), Arguments.of(List.of(INT_2, DOUBLE_1), new RelOpValue.GteFn(), ConstantPredicate.TRUE), Arguments.of(List.of(INT_1, DOUBLE_1), new RelOpValue.GteFn(), ConstantPredicate.TRUE), + Arguments.of(List.of(INT_1, DOUBLE_1), new RelOpValue.NotDistinctFromFn(), ConstantPredicate.TRUE), + Arguments.of(List.of(INT_1, DOUBLE_2), new RelOpValue.NotDistinctFromFn(), ConstantPredicate.FALSE), + Arguments.of(List.of(INT_1, DOUBLE_1), new RelOpValue.IsDistinctFromFn(), ConstantPredicate.FALSE), + Arguments.of(List.of(INT_1, DOUBLE_2), new RelOpValue.IsDistinctFromFn(), ConstantPredicate.TRUE), Arguments.of(List.of(FLOAT_1, LONG_1), new RelOpValue.EqualsFn(), ConstantPredicate.TRUE), Arguments.of(List.of(FLOAT_1, LONG_2), new RelOpValue.EqualsFn(), ConstantPredicate.FALSE), @@ -324,6 +376,10 @@ public Stream provideArguments(final ExtensionContext conte Arguments.of(List.of(FLOAT_1, LONG_2), new RelOpValue.GteFn(), ConstantPredicate.FALSE), Arguments.of(List.of(FLOAT_2, LONG_1), new RelOpValue.GteFn(), ConstantPredicate.TRUE), Arguments.of(List.of(FLOAT_1, LONG_1), new RelOpValue.GteFn(), ConstantPredicate.TRUE), + Arguments.of(List.of(FLOAT_1, LONG_1), new RelOpValue.NotDistinctFromFn(), ConstantPredicate.TRUE), + Arguments.of(List.of(FLOAT_1, LONG_2), new RelOpValue.NotDistinctFromFn(), ConstantPredicate.FALSE), + Arguments.of(List.of(FLOAT_1, LONG_1), new RelOpValue.IsDistinctFromFn(), ConstantPredicate.FALSE), + Arguments.of(List.of(FLOAT_1, LONG_2), new RelOpValue.IsDistinctFromFn(), ConstantPredicate.TRUE), Arguments.of(List.of(LONG_1, FLOAT_1), new RelOpValue.EqualsFn(), ConstantPredicate.TRUE), Arguments.of(List.of(LONG_1, FLOAT_2), new RelOpValue.EqualsFn(), ConstantPredicate.FALSE), @@ -339,6 +395,10 @@ public Stream provideArguments(final ExtensionContext conte Arguments.of(List.of(LONG_1, FLOAT_2), new RelOpValue.GteFn(), ConstantPredicate.FALSE), Arguments.of(List.of(LONG_2, FLOAT_1), new RelOpValue.GteFn(), ConstantPredicate.TRUE), Arguments.of(List.of(LONG_1, FLOAT_1), new RelOpValue.GteFn(), ConstantPredicate.TRUE), + Arguments.of(List.of(LONG_1, FLOAT_1), new RelOpValue.NotDistinctFromFn(), ConstantPredicate.TRUE), + Arguments.of(List.of(LONG_1, FLOAT_2), new RelOpValue.NotDistinctFromFn(), ConstantPredicate.FALSE), + Arguments.of(List.of(LONG_1, FLOAT_1), new RelOpValue.IsDistinctFromFn(), ConstantPredicate.FALSE), + Arguments.of(List.of(LONG_1, FLOAT_2), new RelOpValue.IsDistinctFromFn(), ConstantPredicate.TRUE), Arguments.of(List.of(DOUBLE_1, LONG_1), new RelOpValue.EqualsFn(), ConstantPredicate.TRUE), Arguments.of(List.of(DOUBLE_1, LONG_2), new RelOpValue.EqualsFn(), ConstantPredicate.FALSE), @@ -354,7 +414,10 @@ public Stream provideArguments(final ExtensionContext conte Arguments.of(List.of(DOUBLE_1, LONG_2), new RelOpValue.GteFn(), ConstantPredicate.FALSE), Arguments.of(List.of(DOUBLE_2, LONG_1), new RelOpValue.GteFn(), ConstantPredicate.TRUE), Arguments.of(List.of(DOUBLE_1, LONG_1), new RelOpValue.GteFn(), ConstantPredicate.TRUE), - + Arguments.of(List.of(DOUBLE_1, LONG_1), new RelOpValue.NotDistinctFromFn(), ConstantPredicate.TRUE), + Arguments.of(List.of(DOUBLE_1, LONG_2), new RelOpValue.NotDistinctFromFn(), ConstantPredicate.FALSE), + Arguments.of(List.of(DOUBLE_1, LONG_1), new RelOpValue.IsDistinctFromFn(), ConstantPredicate.FALSE), + Arguments.of(List.of(DOUBLE_1, LONG_2), new RelOpValue.IsDistinctFromFn(), ConstantPredicate.TRUE), Arguments.of(List.of(LONG_1, DOUBLE_1), new RelOpValue.EqualsFn(), ConstantPredicate.TRUE), Arguments.of(List.of(LONG_1, DOUBLE_2), new RelOpValue.EqualsFn(), ConstantPredicate.FALSE), @@ -370,6 +433,10 @@ public Stream provideArguments(final ExtensionContext conte Arguments.of(List.of(LONG_1, DOUBLE_2), new RelOpValue.GteFn(), ConstantPredicate.FALSE), Arguments.of(List.of(LONG_2, DOUBLE_1), new RelOpValue.GteFn(), ConstantPredicate.TRUE), Arguments.of(List.of(LONG_1, DOUBLE_1), new RelOpValue.GteFn(), ConstantPredicate.TRUE), + Arguments.of(List.of(LONG_1, DOUBLE_1), new RelOpValue.NotDistinctFromFn(), ConstantPredicate.TRUE), + Arguments.of(List.of(LONG_1, DOUBLE_2), new RelOpValue.NotDistinctFromFn(), ConstantPredicate.FALSE), + Arguments.of(List.of(LONG_1, DOUBLE_1), new RelOpValue.IsDistinctFromFn(), ConstantPredicate.FALSE), + Arguments.of(List.of(LONG_1, DOUBLE_2), new RelOpValue.IsDistinctFromFn(), ConstantPredicate.TRUE), Arguments.of(List.of(DOUBLE_1, FLOAT_1), new RelOpValue.EqualsFn(), ConstantPredicate.TRUE), Arguments.of(List.of(DOUBLE_1, FLOAT_2), new RelOpValue.EqualsFn(), ConstantPredicate.FALSE), @@ -385,6 +452,10 @@ public Stream provideArguments(final ExtensionContext conte Arguments.of(List.of(DOUBLE_1, FLOAT_2), new RelOpValue.GteFn(), ConstantPredicate.FALSE), Arguments.of(List.of(DOUBLE_2, FLOAT_1), new RelOpValue.GteFn(), ConstantPredicate.TRUE), Arguments.of(List.of(DOUBLE_1, FLOAT_1), new RelOpValue.GteFn(), ConstantPredicate.TRUE), + Arguments.of(List.of(DOUBLE_1, FLOAT_1), new RelOpValue.NotDistinctFromFn(), ConstantPredicate.TRUE), + Arguments.of(List.of(DOUBLE_1, FLOAT_2), new RelOpValue.NotDistinctFromFn(), ConstantPredicate.FALSE), + Arguments.of(List.of(DOUBLE_1, FLOAT_1), new RelOpValue.IsDistinctFromFn(), ConstantPredicate.FALSE), + Arguments.of(List.of(DOUBLE_1, FLOAT_2), new RelOpValue.IsDistinctFromFn(), ConstantPredicate.TRUE), Arguments.of(List.of(FLOAT_1, DOUBLE_1), new RelOpValue.EqualsFn(), ConstantPredicate.TRUE), Arguments.of(List.of(FLOAT_1, DOUBLE_2), new RelOpValue.EqualsFn(), ConstantPredicate.FALSE), @@ -400,6 +471,10 @@ public Stream provideArguments(final ExtensionContext conte Arguments.of(List.of(FLOAT_1, DOUBLE_2), new RelOpValue.GteFn(), ConstantPredicate.FALSE), Arguments.of(List.of(FLOAT_2, DOUBLE_1), new RelOpValue.GteFn(), ConstantPredicate.TRUE), Arguments.of(List.of(FLOAT_1, DOUBLE_1), new RelOpValue.GteFn(), ConstantPredicate.TRUE), + Arguments.of(List.of(FLOAT_1, DOUBLE_1), new RelOpValue.NotDistinctFromFn(), ConstantPredicate.TRUE), + Arguments.of(List.of(FLOAT_1, DOUBLE_2), new RelOpValue.NotDistinctFromFn(), ConstantPredicate.FALSE), + Arguments.of(List.of(FLOAT_1, DOUBLE_1), new RelOpValue.IsDistinctFromFn(), ConstantPredicate.FALSE), + Arguments.of(List.of(FLOAT_1, DOUBLE_2), new RelOpValue.IsDistinctFromFn(), ConstantPredicate.TRUE), Arguments.of(List.of(INT_NULL, INT_NULL), new RelOpValue.EqualsFn(), ConstantPredicate.NULL), Arguments.of(List.of(INT_NULL, INT_2), new RelOpValue.EqualsFn(), ConstantPredicate.NULL), @@ -415,6 +490,10 @@ public Stream provideArguments(final ExtensionContext conte Arguments.of(List.of(INT_NULL, INT_2), new RelOpValue.GteFn(), ConstantPredicate.NULL), Arguments.of(List.of(INT_2, INT_NULL), new RelOpValue.GteFn(), ConstantPredicate.NULL), Arguments.of(List.of(INT_NULL, INT_NULL), new RelOpValue.GteFn(), ConstantPredicate.NULL), + Arguments.of(List.of(INT_NULL, INT_NULL), new RelOpValue.NotDistinctFromFn(), ConstantPredicate.TRUE), + Arguments.of(List.of(INT_NULL, INT_2), new RelOpValue.NotDistinctFromFn(), ConstantPredicate.FALSE), + Arguments.of(List.of(INT_NULL, INT_NULL), new RelOpValue.IsDistinctFromFn(), ConstantPredicate.FALSE), + Arguments.of(List.of(INT_NULL, INT_2), new RelOpValue.IsDistinctFromFn(), ConstantPredicate.TRUE), Arguments.of(List.of(BOOL_NULL, BOOL_NULL), new RelOpValue.EqualsFn(), ConstantPredicate.NULL), Arguments.of(List.of(BOOL_NULL, BOOL_FALSE), new RelOpValue.EqualsFn(), ConstantPredicate.NULL), @@ -422,6 +501,12 @@ public Stream provideArguments(final ExtensionContext conte Arguments.of(List.of(BOOL_NULL, BOOL_NULL), new RelOpValue.NotEqualsFn(), ConstantPredicate.NULL), Arguments.of(List.of(BOOL_NULL, BOOL_FALSE), new RelOpValue.NotEqualsFn(), ConstantPredicate.NULL), Arguments.of(List.of(BOOL_NULL, BOOL_TRUE), new RelOpValue.NotEqualsFn(), ConstantPredicate.NULL), + Arguments.of(List.of(BOOL_NULL, BOOL_NULL), new RelOpValue.NotDistinctFromFn(), ConstantPredicate.TRUE), + Arguments.of(List.of(BOOL_NULL, BOOL_FALSE), new RelOpValue.NotDistinctFromFn(), ConstantPredicate.FALSE), + Arguments.of(List.of(BOOL_NULL, BOOL_TRUE), new RelOpValue.NotDistinctFromFn(), ConstantPredicate.FALSE), + Arguments.of(List.of(BOOL_NULL, BOOL_NULL), new RelOpValue.IsDistinctFromFn(), ConstantPredicate.FALSE), + Arguments.of(List.of(BOOL_NULL, BOOL_FALSE), new RelOpValue.IsDistinctFromFn(), ConstantPredicate.TRUE), + Arguments.of(List.of(BOOL_NULL, BOOL_TRUE), new RelOpValue.IsDistinctFromFn(), ConstantPredicate.TRUE), Arguments.of(List.of(NULL, LONG_1), new RelOpValue.EqualsFn(), ConstantPredicate.NULL), Arguments.of(List.of(NULL, LONG_NULL), new RelOpValue.EqualsFn(), ConstantPredicate.NULL), @@ -501,6 +586,36 @@ public Stream provideArguments(final ExtensionContext conte Arguments.of(List.of(NULL, STRING_NULL), new RelOpValue.GteFn(), ConstantPredicate.NULL), Arguments.of(List.of(NULL, UUID_1), new RelOpValue.GteFn(), ConstantPredicate.NULL), Arguments.of(List.of(NULL, UUID_NULL), new RelOpValue.GteFn(), ConstantPredicate.NULL), + Arguments.of(List.of(NULL, LONG_1), new RelOpValue.NotDistinctFromFn(), ConstantPredicate.FALSE), + Arguments.of(List.of(NULL, LONG_NULL), new RelOpValue.NotDistinctFromFn(), ConstantPredicate.TRUE), + Arguments.of(List.of(NULL, INT_1), new RelOpValue.NotDistinctFromFn(), ConstantPredicate.FALSE), + Arguments.of(List.of(NULL, INT_NULL), new RelOpValue.NotDistinctFromFn(), ConstantPredicate.TRUE), + Arguments.of(List.of(NULL, FLOAT_1), new RelOpValue.NotDistinctFromFn(), ConstantPredicate.FALSE), + Arguments.of(List.of(NULL, FLOAT_NULL), new RelOpValue.NotDistinctFromFn(), ConstantPredicate.TRUE), + Arguments.of(List.of(NULL, DOUBLE_1), new RelOpValue.NotDistinctFromFn(), ConstantPredicate.FALSE), + Arguments.of(List.of(NULL, DOUBLE_NULL), new RelOpValue.NotDistinctFromFn(), ConstantPredicate.TRUE), + Arguments.of(List.of(NULL, STRING_1), new RelOpValue.NotDistinctFromFn(), ConstantPredicate.FALSE), + Arguments.of(List.of(NULL, STRING_NULL), new RelOpValue.NotDistinctFromFn(), ConstantPredicate.TRUE), + Arguments.of(List.of(NULL, UUID_1), new RelOpValue.NotDistinctFromFn(), ConstantPredicate.FALSE), + Arguments.of(List.of(NULL, UUID_NULL), new RelOpValue.NotDistinctFromFn(), ConstantPredicate.TRUE), + Arguments.of(List.of(NULL, BOOL_FALSE), new RelOpValue.NotDistinctFromFn(), ConstantPredicate.FALSE), + Arguments.of(List.of(NULL, BOOL_TRUE), new RelOpValue.NotDistinctFromFn(), ConstantPredicate.FALSE), + Arguments.of(List.of(NULL, BOOL_NULL), new RelOpValue.NotDistinctFromFn(), ConstantPredicate.TRUE), + Arguments.of(List.of(NULL, LONG_1), new RelOpValue.IsDistinctFromFn(), ConstantPredicate.TRUE), + Arguments.of(List.of(NULL, LONG_NULL), new RelOpValue.IsDistinctFromFn(), ConstantPredicate.FALSE), + Arguments.of(List.of(NULL, INT_1), new RelOpValue.IsDistinctFromFn(), ConstantPredicate.TRUE), + Arguments.of(List.of(NULL, INT_NULL), new RelOpValue.IsDistinctFromFn(), ConstantPredicate.FALSE), + Arguments.of(List.of(NULL, FLOAT_1), new RelOpValue.IsDistinctFromFn(), ConstantPredicate.TRUE), + Arguments.of(List.of(NULL, FLOAT_NULL), new RelOpValue.IsDistinctFromFn(), ConstantPredicate.FALSE), + Arguments.of(List.of(NULL, DOUBLE_1), new RelOpValue.IsDistinctFromFn(), ConstantPredicate.TRUE), + Arguments.of(List.of(NULL, DOUBLE_NULL), new RelOpValue.IsDistinctFromFn(), ConstantPredicate.FALSE), + Arguments.of(List.of(NULL, STRING_1), new RelOpValue.IsDistinctFromFn(), ConstantPredicate.TRUE), + Arguments.of(List.of(NULL, STRING_NULL), new RelOpValue.IsDistinctFromFn(), ConstantPredicate.FALSE), + Arguments.of(List.of(NULL, UUID_1), new RelOpValue.IsDistinctFromFn(), ConstantPredicate.TRUE), + Arguments.of(List.of(NULL, UUID_NULL), new RelOpValue.IsDistinctFromFn(), ConstantPredicate.FALSE), + Arguments.of(List.of(NULL, BOOL_FALSE), new RelOpValue.IsDistinctFromFn(), ConstantPredicate.TRUE), + Arguments.of(List.of(NULL, BOOL_TRUE), new RelOpValue.IsDistinctFromFn(), ConstantPredicate.TRUE), + Arguments.of(List.of(NULL, BOOL_NULL), new RelOpValue.IsDistinctFromFn(), ConstantPredicate.FALSE), Arguments.of(List.of(F_ENUM_1, F_ENUM_2), new RelOpValue.EqualsFn(), new ValuePredicate(F_ENUM_1, new Comparisons.ValueComparison(Comparisons.Type.EQUALS, F_ENUM_2))), @@ -510,24 +625,32 @@ public Stream provideArguments(final ExtensionContext conte Arguments.of(List.of(UUID_STRING_1, UUID_1), new RelOpValue.LteFn(), ConstantPredicate.TRUE), Arguments.of(List.of(UUID_STRING_1, UUID_1), new RelOpValue.GtFn(), ConstantPredicate.FALSE), Arguments.of(List.of(UUID_STRING_1, UUID_1), new RelOpValue.GteFn(), ConstantPredicate.TRUE), + Arguments.of(List.of(UUID_STRING_1, UUID_1), new RelOpValue.NotDistinctFromFn(), ConstantPredicate.TRUE), + Arguments.of(List.of(UUID_STRING_1, UUID_1), new RelOpValue.IsDistinctFromFn(), ConstantPredicate.FALSE), Arguments.of(List.of(UUID_1, UUID_1), new RelOpValue.EqualsFn(), ConstantPredicate.TRUE), Arguments.of(List.of(UUID_1, UUID_1), new RelOpValue.NotEqualsFn(), ConstantPredicate.FALSE), Arguments.of(List.of(UUID_1, UUID_1), new RelOpValue.LtFn(), ConstantPredicate.FALSE), Arguments.of(List.of(UUID_1, UUID_1), new RelOpValue.LteFn(), ConstantPredicate.TRUE), Arguments.of(List.of(UUID_1, UUID_1), new RelOpValue.GtFn(), ConstantPredicate.FALSE), Arguments.of(List.of(UUID_1, UUID_1), new RelOpValue.GteFn(), ConstantPredicate.TRUE), + Arguments.of(List.of(UUID_1, UUID_1), new RelOpValue.NotDistinctFromFn(), ConstantPredicate.TRUE), + Arguments.of(List.of(UUID_1, UUID_1), new RelOpValue.IsDistinctFromFn(), ConstantPredicate.FALSE), Arguments.of(List.of(UUID_STRING_2, UUID_1), new RelOpValue.EqualsFn(), ConstantPredicate.FALSE), Arguments.of(List.of(UUID_STRING_2, UUID_1), new RelOpValue.NotEqualsFn(), ConstantPredicate.TRUE), Arguments.of(List.of(UUID_STRING_2, UUID_1), new RelOpValue.LtFn(), ConstantPredicate.FALSE), Arguments.of(List.of(UUID_STRING_2, UUID_1), new RelOpValue.LteFn(), ConstantPredicate.FALSE), Arguments.of(List.of(UUID_STRING_2, UUID_1), new RelOpValue.GtFn(), ConstantPredicate.TRUE), Arguments.of(List.of(UUID_STRING_2, UUID_1), new RelOpValue.GteFn(), ConstantPredicate.TRUE), + Arguments.of(List.of(UUID_STRING_2, UUID_1), new RelOpValue.NotDistinctFromFn(), ConstantPredicate.FALSE), + Arguments.of(List.of(UUID_STRING_2, UUID_1), new RelOpValue.IsDistinctFromFn(), ConstantPredicate.TRUE), Arguments.of(List.of(UUID_2, UUID_1), new RelOpValue.EqualsFn(), ConstantPredicate.FALSE), Arguments.of(List.of(UUID_2, UUID_1), new RelOpValue.NotEqualsFn(), ConstantPredicate.TRUE), Arguments.of(List.of(UUID_2, UUID_1), new RelOpValue.LtFn(), ConstantPredicate.FALSE), Arguments.of(List.of(UUID_2, UUID_1), new RelOpValue.LteFn(), ConstantPredicate.FALSE), Arguments.of(List.of(UUID_2, UUID_1), new RelOpValue.GtFn(), ConstantPredicate.TRUE), Arguments.of(List.of(UUID_2, UUID_1), new RelOpValue.GteFn(), ConstantPredicate.TRUE), + Arguments.of(List.of(UUID_2, UUID_1), new RelOpValue.NotDistinctFromFn(), ConstantPredicate.FALSE), + Arguments.of(List.of(UUID_2, UUID_1), new RelOpValue.IsDistinctFromFn(), ConstantPredicate.TRUE), /* translation of predicates involving a field value, make sure field value is always LHS */ Arguments.of(List.of(F, INT_1), new RelOpValue.EqualsFn(), new ValuePredicate(F, new Comparisons.SimpleComparison(Comparisons.Type.EQUALS, 1))), @@ -542,6 +665,11 @@ public Stream provideArguments(final ExtensionContext conte Arguments.of(List.of(INT_1, F), new RelOpValue.LteFn(), new ValuePredicate(F, new Comparisons.SimpleComparison(Comparisons.Type.GREATER_THAN_OR_EQUALS, 1))), Arguments.of(List.of(F, INT_1), new RelOpValue.GteFn(), new ValuePredicate(F, new Comparisons.SimpleComparison(Comparisons.Type.GREATER_THAN_OR_EQUALS, 1))), Arguments.of(List.of(INT_1, F), new RelOpValue.GteFn(), new ValuePredicate(F, new Comparisons.SimpleComparison(Comparisons.Type.LESS_THAN_OR_EQUALS, 1))), + Arguments.of(List.of(F, INT_1), new RelOpValue.NotDistinctFromFn(), new ValuePredicate(F, new Comparisons.SimpleComparison(Comparisons.Type.NOT_DISTINCT_FROM, 1))), + Arguments.of(List.of(INT_1, F), new RelOpValue.NotDistinctFromFn(), new ValuePredicate(F, new Comparisons.SimpleComparison(Comparisons.Type.NOT_DISTINCT_FROM, 1))), + Arguments.of(List.of(F, INT_1), new RelOpValue.IsDistinctFromFn(), new ValuePredicate(F, new Comparisons.SimpleComparison(Comparisons.Type.IS_DISTINCT_FROM, 1))), + Arguments.of(List.of(INT_1, F), new RelOpValue.IsDistinctFromFn(), new ValuePredicate(F, new Comparisons.SimpleComparison(Comparisons.Type.IS_DISTINCT_FROM, 1))), + Arguments.of(List.of(INT_1), new RelOpValue.IsNullFn(), ConstantPredicate.FALSE), Arguments.of(List.of(INT_1), new RelOpValue.NotNullFn(), ConstantPredicate.TRUE), @@ -801,7 +929,7 @@ void testEval(List args, BuiltInFunction function, QueryPredicate result) value = verifySerialization((Value)value); Object actual = ((Value)value).evalWithoutStore(evalContext); Object expected = result.evalWithoutStore(evalContext); - Assertions.assertEquals(actual, expected); + Assertions.assertEquals(expected, actual); } else { Assertions.assertThrows(SemanticException.class, () -> function.encapsulate(args)); } From 2eb1075630483ce78ed21b6cd9a9cc2bc81b2e9e Mon Sep 17 00:00:00 2001 From: Pengpeng Lu Date: Tue, 5 Aug 2025 11:34:36 -0700 Subject: [PATCH 16/16] rename operators --- .../plan/cascades/values/RelOpValue.java | 80 +++++++++---------- .../src/main/proto/record_query_plan.proto | 80 +++++++++---------- 2 files changed, 80 insertions(+), 80 deletions(-) diff --git a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/RelOpValue.java b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/RelOpValue.java index 7226ff035d..e0fde29b52 100644 --- a/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/RelOpValue.java +++ b/fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/RelOpValue.java @@ -930,42 +930,42 @@ private enum BinaryPhysicalOperator { GTE_NID(Comparisons.Type.GREATER_THAN_OR_EQUALS, Type.TypeCode.NULL, Type.TypeCode.UUID, (l, r) -> null), GTE_IDN(Comparisons.Type.GREATER_THAN_OR_EQUALS, Type.TypeCode.UUID, Type.TypeCode.NULL, (l, r) -> null), - IS_DISTINCT_FROM_BU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.BOOLEAN, Type.TypeCode.NULL, (l, r) -> Objects.nonNull(l)), + IS_DISTINCT_FROM_BN(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.BOOLEAN, Type.TypeCode.NULL, (l, r) -> Objects.nonNull(l)), IS_DISTINCT_FROM_BB(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.BOOLEAN, Type.TypeCode.BOOLEAN, (l, r) -> (boolean)l != (boolean)r), - IS_DISTINCT_FROM_IU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.INT, Type.TypeCode.NULL, (l, r) -> Objects.nonNull(l)), + IS_DISTINCT_FROM_IN(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.INT, Type.TypeCode.NULL, (l, r) -> Objects.nonNull(l)), IS_DISTINCT_FROM_II(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.INT, Type.TypeCode.INT, (l, r) -> (int)l != (int)r), IS_DISTINCT_FROM_IL(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.INT, Type.TypeCode.LONG, (l, r) -> (int)l != (long)r), IS_DISTINCT_FROM_IF(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.INT, Type.TypeCode.FLOAT, (l, r) -> (int)l != (float)r), IS_DISTINCT_FROM_ID(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.INT, Type.TypeCode.DOUBLE, (l, r) -> (int)l != (double)r), - IS_DISTINCT_FROM_LU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.LONG, Type.TypeCode.NULL, (l, r) -> Objects.nonNull(l)), + IS_DISTINCT_FROM_LN(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.LONG, Type.TypeCode.NULL, (l, r) -> Objects.nonNull(l)), IS_DISTINCT_FROM_LI(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.LONG, Type.TypeCode.INT, (l, r) -> (long)l != (int)r), IS_DISTINCT_FROM_LL(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.LONG, Type.TypeCode.LONG, (l, r) -> (long)l != (long)r), IS_DISTINCT_FROM_LF(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.LONG, Type.TypeCode.FLOAT, (l, r) -> (long)l != (float)r), IS_DISTINCT_FROM_LD(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.LONG, Type.TypeCode.DOUBLE, (l, r) -> (long)l != (double)r), - IS_DISTINCT_FROM_FU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.FLOAT, Type.TypeCode.NULL, (l, r) -> Objects.nonNull(l)), + IS_DISTINCT_FROM_FN(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.FLOAT, Type.TypeCode.NULL, (l, r) -> Objects.nonNull(l)), IS_DISTINCT_FROM_FI(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.FLOAT, Type.TypeCode.INT, (l, r) -> (float)l != (int)r), IS_DISTINCT_FROM_FL(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.FLOAT, Type.TypeCode.LONG, (l, r) -> (float)l != (long)r), IS_DISTINCT_FROM_FF(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.FLOAT, Type.TypeCode.FLOAT, (l, r) -> (float)l != (float)r), IS_DISTINCT_FROM_FD(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.FLOAT, Type.TypeCode.DOUBLE, (l, r) -> (float)l != (double)r), - IS_DISTINCT_FROM_DU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.DOUBLE, Type.TypeCode.NULL, (l, r) -> Objects.nonNull(l)), + IS_DISTINCT_FROM_DN(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.DOUBLE, Type.TypeCode.NULL, (l, r) -> Objects.nonNull(l)), IS_DISTINCT_FROM_DI(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.DOUBLE, Type.TypeCode.INT, (l, r) -> (double)l != (int)r), IS_DISTINCT_FROM_DL(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.DOUBLE, Type.TypeCode.LONG, (l, r) -> (double)l != (long)r), IS_DISTINCT_FROM_DF(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.DOUBLE, Type.TypeCode.FLOAT, (l, r) -> (double)l != (float)r), IS_DISTINCT_FROM_DD(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.DOUBLE, Type.TypeCode.DOUBLE, (l, r) -> (double)l != (double)r), - IS_DISTINCT_FROM_SU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.STRING, Type.TypeCode.NULL, (l, r) -> Objects.nonNull(l)), + IS_DISTINCT_FROM_SN(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.STRING, Type.TypeCode.NULL, (l, r) -> Objects.nonNull(l)), IS_DISTINCT_FROM_SS(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.STRING, Type.TypeCode.STRING, (l, r) -> !l.equals(r)), // TODO: locale-aware comparison - IS_DISTINCT_FROM_UB(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.BOOLEAN, (l, r) -> Objects.nonNull(r)), - IS_DISTINCT_FROM_UI(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.INT, (l, r) -> Objects.nonNull(r)), - IS_DISTINCT_FROM_UL(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.LONG, (l, r) -> Objects.nonNull(r)), - IS_DISTINCT_FROM_UF(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.FLOAT, (l, r) -> Objects.nonNull(r)), - IS_DISTINCT_FROM_UD(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.DOUBLE, (l, r) -> Objects.nonNull(r)), - IS_DISTINCT_FROM_US(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.STRING, (l, r) -> Objects.nonNull(r)), - IS_DISTINCT_FROM_UV(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.VERSION, (l, r) -> Objects.nonNull(r)), - IS_DISTINCT_FROM_VU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.VERSION, Type.TypeCode.NULL, (l, r) -> null), + IS_DISTINCT_FROM_NB(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.BOOLEAN, (l, r) -> Objects.nonNull(r)), + IS_DISTINCT_FROM_NI(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.INT, (l, r) -> Objects.nonNull(r)), + IS_DISTINCT_FROM_NL(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.LONG, (l, r) -> Objects.nonNull(r)), + IS_DISTINCT_FROM_NF(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.FLOAT, (l, r) -> Objects.nonNull(r)), + IS_DISTINCT_FROM_ND(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.DOUBLE, (l, r) -> Objects.nonNull(r)), + IS_DISTINCT_FROM_NS(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.STRING, (l, r) -> Objects.nonNull(r)), + IS_DISTINCT_FROM_NV(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.VERSION, (l, r) -> Objects.nonNull(r)), + IS_DISTINCT_FROM_VN(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.VERSION, Type.TypeCode.NULL, (l, r) -> null), IS_DISTINCT_FROM_VV(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.VERSION, Type.TypeCode.VERSION, (l, r) -> !l.equals(r)), - IS_DISTINCT_FROM_BYU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.BYTES, Type.TypeCode.NULL, (l, r) -> Objects.nonNull(l)), + IS_DISTINCT_FROM_BYN(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.BYTES, Type.TypeCode.NULL, (l, r) -> Objects.nonNull(l)), IS_DISTINCT_FROM_BYBY(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.BYTES, Type.TypeCode.BYTES, (l, r) -> Comparisons.evalComparison(Comparisons.Type.IS_DISTINCT_FROM, l, r)), - IS_DISTINCT_FROM_UBY(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.BYTES, (l, r) -> Objects.nonNull(r)), + IS_DISTINCT_FROM_NBY(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.BYTES, (l, r) -> Objects.nonNull(r)), IS_DISTINCT_FROM_EE(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.ENUM, Type.TypeCode.ENUM, (l, r) -> Comparisons.evalComparison(Comparisons.Type.IS_DISTINCT_FROM, l, r)), IS_DISTINCT_FROM_ES(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.ENUM, Type.TypeCode.STRING, (l, r) -> { final var otherValue = PromoteValue.PhysicalOperator.stringToEnumValue(((Descriptors.EnumValueDescriptor) l).getType(), (String) r); @@ -975,52 +975,52 @@ private enum BinaryPhysicalOperator { final var otherValue = PromoteValue.PhysicalOperator.stringToEnumValue(((Descriptors.EnumValueDescriptor) r).getType(), (String) l); return Comparisons.evalComparison(Comparisons.Type.EQUALS, otherValue, r); }), - IS_DISTINCT_FROM_EU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.ENUM, Type.TypeCode.NULL, (l, r) -> Objects.nonNull(l)), - IS_DISTINCT_FROM_UE(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.ENUM, (l, r) -> Objects.nonNull(r)), + IS_DISTINCT_FROM_EN(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.ENUM, Type.TypeCode.NULL, (l, r) -> Objects.nonNull(l)), + IS_DISTINCT_FROM_NE(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.ENUM, (l, r) -> Objects.nonNull(r)), IS_DISTINCT_FROM_IDID(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.UUID, Type.TypeCode.UUID, (l, r) -> Comparisons.evalComparison(Comparisons.Type.IS_DISTINCT_FROM, l, r)), IS_DISTINCT_FROM_IDS(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.UUID, Type.TypeCode.STRING, (l, r) -> Comparisons.evalComparison(Comparisons.Type.IS_DISTINCT_FROM, l, PromoteValue.PhysicalOperator.stringToUuidValue((String) r))), IS_DISTINCT_FROM_SID(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.STRING, Type.TypeCode.UUID, (l, r) -> Comparisons.evalComparison(Comparisons.Type.IS_DISTINCT_FROM, PromoteValue.PhysicalOperator.stringToUuidValue((String) l), r)), - IS_DISTINCT_FROM_UID(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.UUID, (l, r) -> Objects.nonNull(r)), - IS_DISTINCT_FROM_IDU(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.UUID, Type.TypeCode.NULL, (l, r) -> Objects.nonNull(l)), + IS_DISTINCT_FROM_NID(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.UUID, (l, r) -> Objects.nonNull(r)), + IS_DISTINCT_FROM_IDN(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.UUID, Type.TypeCode.NULL, (l, r) -> Objects.nonNull(l)), IS_DISTINCT_FROM_NN(Comparisons.Type.IS_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.NULL, (l, r) -> false), - NOT_DISTINCT_FROM_BU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.BOOLEAN, Type.TypeCode.NULL, (l, r) -> Objects.isNull(l)), + NOT_DISTINCT_FROM_BN(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.BOOLEAN, Type.TypeCode.NULL, (l, r) -> Objects.isNull(l)), NOT_DISTINCT_FROM_BB(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.BOOLEAN, Type.TypeCode.BOOLEAN, (l, r) -> (boolean)l == (boolean)r), - NOT_DISTINCT_FROM_IU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.INT, Type.TypeCode.NULL, (l, r) -> Objects.isNull(l)), + NOT_DISTINCT_FROM_IN(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.INT, Type.TypeCode.NULL, (l, r) -> Objects.isNull(l)), NOT_DISTINCT_FROM_II(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.INT, Type.TypeCode.INT, (l, r) -> (int)l == (int)r), NOT_DISTINCT_FROM_IL(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.INT, Type.TypeCode.LONG, (l, r) -> (int)l == (long)r), NOT_DISTINCT_FROM_IF(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.INT, Type.TypeCode.FLOAT, (l, r) -> (int)l == (float)r), NOT_DISTINCT_FROM_ID(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.INT, Type.TypeCode.DOUBLE, (l, r) -> (int)l == (double)r), - NOT_DISTINCT_FROM_LU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.LONG, Type.TypeCode.NULL, (l, r) -> Objects.isNull(l)), + NOT_DISTINCT_FROM_LN(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.LONG, Type.TypeCode.NULL, (l, r) -> Objects.isNull(l)), NOT_DISTINCT_FROM_LI(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.LONG, Type.TypeCode.INT, (l, r) -> (long)l == (int)r), NOT_DISTINCT_FROM_LL(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.LONG, Type.TypeCode.LONG, (l, r) -> (long)l == (long)r), NOT_DISTINCT_FROM_LF(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.LONG, Type.TypeCode.FLOAT, (l, r) -> (long)l == (float)r), NOT_DISTINCT_FROM_LD(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.LONG, Type.TypeCode.DOUBLE, (l, r) -> (long)l == (double)r), - NOT_DISTINCT_FROM_FU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.FLOAT, Type.TypeCode.NULL, (l, r) -> Objects.isNull(l)), + NOT_DISTINCT_FROM_FN(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.FLOAT, Type.TypeCode.NULL, (l, r) -> Objects.isNull(l)), NOT_DISTINCT_FROM_FI(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.FLOAT, Type.TypeCode.INT, (l, r) -> (float)l == (int)r), NOT_DISTINCT_FROM_FL(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.FLOAT, Type.TypeCode.LONG, (l, r) -> (float)l == (long)r), NOT_DISTINCT_FROM_FF(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.FLOAT, Type.TypeCode.FLOAT, (l, r) -> (float)l == (float)r), NOT_DISTINCT_FROM_FD(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.FLOAT, Type.TypeCode.DOUBLE, (l, r) -> (float)l == (double)r), - NOT_DISTINCT_FROM_DU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.DOUBLE, Type.TypeCode.NULL, (l, r) -> Objects.isNull(l)), + NOT_DISTINCT_FROM_DN(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.DOUBLE, Type.TypeCode.NULL, (l, r) -> Objects.isNull(l)), NOT_DISTINCT_FROM_DI(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.DOUBLE, Type.TypeCode.INT, (l, r) -> (double)l == (int)r), NOT_DISTINCT_FROM_DL(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.DOUBLE, Type.TypeCode.LONG, (l, r) -> (double)l == (long)r), NOT_DISTINCT_FROM_DF(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.DOUBLE, Type.TypeCode.FLOAT, (l, r) -> (double)l == (float)r), NOT_DISTINCT_FROM_DD(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.DOUBLE, Type.TypeCode.DOUBLE, (l, r) -> (double)l == (double)r), - NOT_DISTINCT_FROM_SU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.STRING, Type.TypeCode.NULL, (l, r) -> Objects.isNull(l)), + NOT_DISTINCT_FROM_SN(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.STRING, Type.TypeCode.NULL, (l, r) -> Objects.isNull(l)), NOT_DISTINCT_FROM_SS(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.STRING, Type.TypeCode.STRING, Object::equals), // TODO: locale-aware comparison - NOT_DISTINCT_FROM_UB(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.BOOLEAN, (l, r) -> Objects.isNull(r)), - NOT_DISTINCT_FROM_UI(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.INT, (l, r) -> Objects.isNull(r)), - NOT_DISTINCT_FROM_UL(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.LONG, (l, r) -> Objects.isNull(r)), - NOT_DISTINCT_FROM_UF(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.FLOAT, (l, r) -> Objects.isNull(r)), - NOT_DISTINCT_FROM_UD(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.DOUBLE, (l, r) -> Objects.isNull(r)), - NOT_DISTINCT_FROM_US(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.STRING, (l, r) -> Objects.isNull(r)), - NOT_DISTINCT_FROM_UV(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.VERSION, (l, r) -> Objects.isNull(r)), - NOT_DISTINCT_FROM_VU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.VERSION, Type.TypeCode.NULL, (l, r) -> Objects.isNull(r)), + NOT_DISTINCT_FROM_NB(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.BOOLEAN, (l, r) -> Objects.isNull(r)), + NOT_DISTINCT_FROM_NI(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.INT, (l, r) -> Objects.isNull(r)), + NOT_DISTINCT_FROM_NL(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.LONG, (l, r) -> Objects.isNull(r)), + NOT_DISTINCT_FROM_NF(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.FLOAT, (l, r) -> Objects.isNull(r)), + NOT_DISTINCT_FROM_ND(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.DOUBLE, (l, r) -> Objects.isNull(r)), + NOT_DISTINCT_FROM_NS(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.STRING, (l, r) -> Objects.isNull(r)), + NOT_DISTINCT_FROM_NV(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.VERSION, (l, r) -> Objects.isNull(r)), + NOT_DISTINCT_FROM_VN(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.VERSION, Type.TypeCode.NULL, (l, r) -> Objects.isNull(r)), NOT_DISTINCT_FROM_VV(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.VERSION, Type.TypeCode.VERSION, Object::equals), - NOT_DISTINCT_FROM_BYU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.BYTES, Type.TypeCode.NULL, (l, r) -> Objects.isNull(l)), + NOT_DISTINCT_FROM_BYN(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.BYTES, Type.TypeCode.NULL, (l, r) -> Objects.isNull(l)), NOT_DISTINCT_FROM_BYBY(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.BYTES, Type.TypeCode.BYTES, (l, r) -> Comparisons.evalComparison(Comparisons.Type.NOT_DISTINCT_FROM, l, r)), - NOT_DISTINCT_FROM_UBY(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.BYTES, (l, r) -> Objects.isNull(r)), + NOT_DISTINCT_FROM_NBY(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.BYTES, (l, r) -> Objects.isNull(r)), NOT_DISTINCT_FROM_EE(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.ENUM, Type.TypeCode.ENUM, (l, r) -> Comparisons.evalComparison(Comparisons.Type.NOT_DISTINCT_FROM, l, r)), NOT_DISTINCT_FROM_ES(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.ENUM, Type.TypeCode.STRING, (l, r) -> { @@ -1031,14 +1031,14 @@ private enum BinaryPhysicalOperator { final var otherValue = PromoteValue.PhysicalOperator.stringToEnumValue(((Descriptors.EnumValueDescriptor) r).getType(), (String) l); return Comparisons.evalComparison(Comparisons.Type.NOT_DISTINCT_FROM, otherValue, r); }), - NOT_DISTINCT_FROM_EU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.ENUM, Type.TypeCode.NULL, (l, r) -> Objects.isNull(l)), - NOT_DISTINCT_FROM_UE(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.ENUM, (l, r) -> Objects.isNull(r)), + NOT_DISTINCT_FROM_EN(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.ENUM, Type.TypeCode.NULL, (l, r) -> Objects.isNull(l)), + NOT_DISTINCT_FROM_NE(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.ENUM, (l, r) -> Objects.isNull(r)), NOT_DISTINCT_FROM_IDID(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UUID, Type.TypeCode.UUID, (l, r) -> Comparisons.evalComparison(Comparisons.Type.NOT_DISTINCT_FROM, l, r)), NOT_DISTINCT_FROM_IDS(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UUID, Type.TypeCode.STRING, (l, r) -> Comparisons.evalComparison(Comparisons.Type.NOT_DISTINCT_FROM, l, PromoteValue.PhysicalOperator.stringToUuidValue((String) r))), NOT_DISTINCT_FROM_SID(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.STRING, Type.TypeCode.UUID, (l, r) -> Comparisons.evalComparison(Comparisons.Type.NOT_DISTINCT_FROM, PromoteValue.PhysicalOperator.stringToUuidValue((String) l), r)), - NOT_DISTINCT_FROM_UID(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.UUID, (l, r) -> Objects.isNull(r)), - NOT_DISTINCT_FROM_IDU(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UUID, Type.TypeCode.NULL, (l, r) -> Objects.isNull(l)), + NOT_DISTINCT_FROM_NID(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.UUID, (l, r) -> Objects.isNull(r)), + NOT_DISTINCT_FROM_IDN(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.UUID, Type.TypeCode.NULL, (l, r) -> Objects.isNull(l)), NOT_DISTINCT_FROM_NN(Comparisons.Type.NOT_DISTINCT_FROM, Type.TypeCode.NULL, Type.TypeCode.NULL, (l, r) -> true), diff --git a/fdb-record-layer-core/src/main/proto/record_query_plan.proto b/fdb-record-layer-core/src/main/proto/record_query_plan.proto index 88d51ed5ab..ed3dce7683 100644 --- a/fdb-record-layer-core/src/main/proto/record_query_plan.proto +++ b/fdb-record-layer-core/src/main/proto/record_query_plan.proto @@ -1061,100 +1061,100 @@ message PBinaryRelOpValue { GT_IDN = 398; GTE_NID = 399; GTE_IDN = 400; - IS_DISTINCT_FROM_BU = 401; + IS_DISTINCT_FROM_BN = 401; IS_DISTINCT_FROM_BB = 402; - IS_DISTINCT_FROM_IU = 403; + IS_DISTINCT_FROM_IN = 403; IS_DISTINCT_FROM_II = 404; IS_DISTINCT_FROM_IL = 405; IS_DISTINCT_FROM_IF = 406; IS_DISTINCT_FROM_ID = 407; - IS_DISTINCT_FROM_LU = 408; + IS_DISTINCT_FROM_LN = 408; IS_DISTINCT_FROM_LI = 409; IS_DISTINCT_FROM_LL = 410; IS_DISTINCT_FROM_LF = 411; IS_DISTINCT_FROM_LD = 412; - IS_DISTINCT_FROM_FU = 413; + IS_DISTINCT_FROM_FN = 413; IS_DISTINCT_FROM_FI = 414; IS_DISTINCT_FROM_FL = 415; IS_DISTINCT_FROM_FF = 416; IS_DISTINCT_FROM_FD = 417; - IS_DISTINCT_FROM_DU = 418; + IS_DISTINCT_FROM_DN = 418; IS_DISTINCT_FROM_DI = 419; IS_DISTINCT_FROM_DL = 420; IS_DISTINCT_FROM_DF = 421; IS_DISTINCT_FROM_DD = 422; - IS_DISTINCT_FROM_SU = 423; + IS_DISTINCT_FROM_SN = 423; IS_DISTINCT_FROM_SS = 424; - IS_DISTINCT_FROM_UB = 425; - IS_DISTINCT_FROM_UI = 426; - IS_DISTINCT_FROM_UL = 427; - IS_DISTINCT_FROM_UF = 428; - IS_DISTINCT_FROM_UD = 429; - IS_DISTINCT_FROM_US = 430; - IS_DISTINCT_FROM_UV = 431; - IS_DISTINCT_FROM_VU = 432; + IS_DISTINCT_FROM_NB = 425; + IS_DISTINCT_FROM_NI = 426; + IS_DISTINCT_FROM_NL = 427; + IS_DISTINCT_FROM_NF = 428; + IS_DISTINCT_FROM_ND = 429; + IS_DISTINCT_FROM_NS = 430; + IS_DISTINCT_FROM_NV = 431; + IS_DISTINCT_FROM_VN = 432; IS_DISTINCT_FROM_VV = 433; - IS_DISTINCT_FROM_BYU = 434; + IS_DISTINCT_FROM_BYN = 434; IS_DISTINCT_FROM_BYBY = 435; - IS_DISTINCT_FROM_UBY = 436; + IS_DISTINCT_FROM_NBY = 436; IS_DISTINCT_FROM_EE = 437; IS_DISTINCT_FROM_ES = 438; IS_DISTINCT_FROM_SE = 439; - IS_DISTINCT_FROM_EU = 440; - IS_DISTINCT_FROM_UE = 441; + IS_DISTINCT_FROM_EN = 440; + IS_DISTINCT_FROM_NE = 441; IS_DISTINCT_FROM_IDID = 442; IS_DISTINCT_FROM_IDS = 443; IS_DISTINCT_FROM_SID = 444; - IS_DISTINCT_FROM_UID = 445; - IS_DISTINCT_FROM_IDU = 446; + IS_DISTINCT_FROM_NID = 445; + IS_DISTINCT_FROM_IDN = 446; IS_DISTINCT_FROM_NN = 447; - NOT_DISTINCT_FROM_BU = 448; + NOT_DISTINCT_FROM_BN = 448; NOT_DISTINCT_FROM_BB = 449; - NOT_DISTINCT_FROM_IU = 450; + NOT_DISTINCT_FROM_IN = 450; NOT_DISTINCT_FROM_II = 451; NOT_DISTINCT_FROM_IL = 452; NOT_DISTINCT_FROM_IF = 453; NOT_DISTINCT_FROM_ID = 454; - NOT_DISTINCT_FROM_LU = 455; + NOT_DISTINCT_FROM_LN = 455; NOT_DISTINCT_FROM_LI = 456; NOT_DISTINCT_FROM_LL = 457; NOT_DISTINCT_FROM_LF = 458; NOT_DISTINCT_FROM_LD = 459; - NOT_DISTINCT_FROM_FU = 460; + NOT_DISTINCT_FROM_FN = 460; NOT_DISTINCT_FROM_FI = 461; NOT_DISTINCT_FROM_FL = 462; NOT_DISTINCT_FROM_FF = 463; NOT_DISTINCT_FROM_FD = 464; - NOT_DISTINCT_FROM_DU = 465; + NOT_DISTINCT_FROM_DN = 465; NOT_DISTINCT_FROM_DI = 466; NOT_DISTINCT_FROM_DL = 467; NOT_DISTINCT_FROM_DF = 468; NOT_DISTINCT_FROM_DD = 469; - NOT_DISTINCT_FROM_SU = 470; + NOT_DISTINCT_FROM_SN = 470; NOT_DISTINCT_FROM_SS = 471; - NOT_DISTINCT_FROM_UB = 472; - NOT_DISTINCT_FROM_UI = 473; - NOT_DISTINCT_FROM_UL = 474; - NOT_DISTINCT_FROM_UF = 475; - NOT_DISTINCT_FROM_UD = 476; - NOT_DISTINCT_FROM_US = 477; - NOT_DISTINCT_FROM_UV = 478; - NOT_DISTINCT_FROM_VU = 479; + NOT_DISTINCT_FROM_NB = 472; + NOT_DISTINCT_FROM_NI = 473; + NOT_DISTINCT_FROM_NL = 474; + NOT_DISTINCT_FROM_NF = 475; + NOT_DISTINCT_FROM_ND = 476; + NOT_DISTINCT_FROM_NS = 477; + NOT_DISTINCT_FROM_NV = 478; + NOT_DISTINCT_FROM_VN = 479; NOT_DISTINCT_FROM_VV = 480; - NOT_DISTINCT_FROM_BYU = 481; + NOT_DISTINCT_FROM_BYN = 481; NOT_DISTINCT_FROM_BYBY = 482; - NOT_DISTINCT_FROM_UBY = 483; + NOT_DISTINCT_FROM_NBY = 483; NOT_DISTINCT_FROM_EE = 484; NOT_DISTINCT_FROM_ES = 485; NOT_DISTINCT_FROM_SE = 486; - NOT_DISTINCT_FROM_EU = 487; - NOT_DISTINCT_FROM_UE = 488; + NOT_DISTINCT_FROM_EN = 487; + NOT_DISTINCT_FROM_NE = 488; NOT_DISTINCT_FROM_IDID = 489; NOT_DISTINCT_FROM_IDS = 490; NOT_DISTINCT_FROM_SID = 491; - NOT_DISTINCT_FROM_UID = 492; - NOT_DISTINCT_FROM_IDU = 493; + NOT_DISTINCT_FROM_NID = 492; + NOT_DISTINCT_FROM_IDN = 493; NOT_DISTINCT_FROM_NN = 494; } optional PRelOpValue super = 1;