Skip to content

Commit c59de90

Browse files
committed
support for enums in rel ops
1 parent a7b8887 commit c59de90

File tree

11 files changed

+272
-29
lines changed

11 files changed

+272
-29
lines changed

docs/ReleaseNotes.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ Our API stability annotations have been updated to reflect greater API instabili
3333
* **Feature** Feature 2 [(Issue #NNN)](https://github.com/FoundationDB/fdb-record-layer/issues/NNN)
3434
* **Feature** Feature 3 [(Issue #NNN)](https://github.com/FoundationDB/fdb-record-layer/issues/NNN)
3535
* **Feature** Feature 4 [(Issue #NNN)](https://github.com/FoundationDB/fdb-record-layer/issues/NNN)
36-
* **Feature** Feature 5 [(Issue #NNN)](https://github.com/FoundationDB/fdb-record-layer/issues/NNN)
36+
* **Feature** Support enums in rel ops [(Issue #3011)](https://github.com/FoundationDB/fdb-record-layer/issues/3011)
3737
* **Breaking change** Change 1 [(Issue #NNN)](https://github.com/FoundationDB/fdb-record-layer/issues/NNN)
3838
* **Breaking change** Change 2 [(Issue #NNN)](https://github.com/FoundationDB/fdb-record-layer/issues/NNN)
3939
* **Breaking change** Change 3 [(Issue #NNN)](https://github.com/FoundationDB/fdb-record-layer/issues/NNN)

fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/SemanticException.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ public enum ErrorCode {
4949
FUNCTION_UNDEFINED_FOR_GIVEN_ARGUMENT_TYPES(9, "The function is not defined for the given argument types"),
5050
ORDERING_IS_OF_INCOMPATIBLE_TYPE(10, "The specified ordering expecting an argument of a primitive or record type, is invoked with an argument of an array type or other complex type."),
5151
ARGUMENT_TO_COLLATE_IS_OF_COMPLEX_TYPE(11, "The argument to a collate expression expecting an argument of a primitive type, is invoked with an argument of a complex type, e.g. an array or a record."),
52+
INVALID_ENUM_VALUE(12, "Invalid enum value for the enum type"),
5253

5354
// insert, update, deletes
5455
UPDATE_TRANSFORM_AMBIGUOUS(1_000, "The transformations used in an UPDATE statement are ambiguous."),

fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/typing/Type.java

Lines changed: 12 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -493,13 +493,18 @@ static Type maximumType(@Nonnull final Type t1, @Nonnull final Type t2) {
493493
return t1.withNullability(true);
494494
}
495495

496-
if (t1.isPrimitive() != t2.isPrimitive()) {
497-
return null;
498-
}
499-
500496
boolean isResultNullable = t1.isNullable() || t2.isNullable();
501497

502-
if (t1.isPrimitive()) {
498+
if (t1.isEnum() && t2.isEnum()) {
499+
final var t1Enum = (Enum)t1;
500+
final var t2Enum = (Enum)t2;
501+
final var t1EnumValues = t1Enum.enumValues;
502+
final var t2EnumValues = t2Enum.enumValues;
503+
if (t1EnumValues == null) {
504+
return t2EnumValues == null ? t1Enum.withNullability(isResultNullable) : null;
505+
}
506+
return t1EnumValues.equals(t2EnumValues) ? t1Enum.withNullability(isResultNullable) : null;
507+
} else if ((t1.isPrimitive() || t1.isEnum()) && (t2.isPrimitive() || t2.isEnum())) {
503508
if (t1.getTypeCode() == t2.getTypeCode()) {
504509
return t1.withNullability(isResultNullable);
505510
}
@@ -509,25 +514,11 @@ static Type maximumType(@Nonnull final Type t1, @Nonnull final Type t2) {
509514
if (PromoteValue.isPromotable(t2, t1)) {
510515
return t1.withNullability(isResultNullable);
511516
}
512-
// Type are primitive but not equal, no promotion possible.
513-
return null;
514-
}
515-
516-
if (t1.isEnum() != t2.isEnum()) {
517+
// Type are primitive or enum but not compatible, no promotion possible.
517518
return null;
518519
}
519520

520-
if (t1.isEnum()) {
521-
final var t1Enum = (Enum)t1;
522-
final var t2Enum = (Enum)t2;
523-
final var t1EnumValues = t1Enum.enumValues;
524-
final var t2EnumValues = t2Enum.enumValues;
525-
if (t1EnumValues == null) {
526-
return t2EnumValues == null ? t1Enum.withNullability(isResultNullable) : null;
527-
}
528-
return t1EnumValues.equals(t2EnumValues) ? t1Enum.withNullability(isResultNullable) : null;
529-
}
530-
521+
// neither of the types are null, primitives or enums
531522
if (t1.getTypeCode() != t2.getTypeCode()) {
532523
return null;
533524
}

fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/FieldValue.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@
7070
* A value representing the contents of a (non-repeated, arbitrarily-nested) field of a quantifier.
7171
*/
7272
@API(API.Status.EXPERIMENTAL)
73-
public class FieldValue extends AbstractValue implements ValueWithChild {
73+
public class FieldValue extends AbstractValue implements ValueWithChild, CreatesDynamicTypesValue {
7474
private static final ObjectPlanHash BASE_HASH = new ObjectPlanHash("Field-Value");
7575

7676
@Nonnull

fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/PromoteValue.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ enum PhysicalOperator {
8787
NULL_TO_RECORD(Type.TypeCode.NULL, Type.TypeCode.RECORD, (descriptor, in) -> null),
8888
NONE_TO_ARRAY(Type.TypeCode.NONE, Type.TypeCode.ARRAY, (descriptor, in) -> in),
8989
NULL_TO_ENUM(Type.TypeCode.NULL, Type.TypeCode.ENUM, (descriptor, in) -> null),
90-
STRING_TO_ENUM(Type.TypeCode.STRING, Type.TypeCode.ENUM, ((descriptor, in) -> ((Descriptors.EnumDescriptor)descriptor).findValueByName((String)in)));
90+
STRING_TO_ENUM(Type.TypeCode.STRING, Type.TypeCode.ENUM, ((descriptor, in) -> stringToEnumValue((Descriptors.EnumDescriptor) descriptor, (String) in)));
9191

9292
@Nonnull
9393
private static final Supplier<BiMap<PhysicalOperator, PPhysicalOperator>> protoEnumBiMapSupplier =
@@ -139,6 +139,12 @@ public static PhysicalOperator fromProto(@Nonnull final PlanSerializationContext
139139
return Objects.requireNonNull(getProtoEnumBiMap().inverse().get(physicalOperatorProto));
140140
}
141141

142+
public static Descriptors.EnumValueDescriptor stringToEnumValue(Descriptors.EnumDescriptor enumDescriptor, String value) {
143+
final var maybeValue = enumDescriptor.findValueByName(value);
144+
SemanticException.check(maybeValue != null, SemanticException.ErrorCode.INVALID_ENUM_VALUE, value);
145+
return maybeValue;
146+
}
147+
142148
@Nonnull
143149
private static BiMap<PhysicalOperator, PPhysicalOperator> getProtoEnumBiMap() {
144150
return protoEnumBiMapSupplier.get();

fdb-record-layer-core/src/main/java/com/apple/foundationdb/record/query/plan/cascades/values/RelOpValue.java

Lines changed: 74 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
import com.google.common.collect.ImmutableMap;
5959
import com.google.common.collect.Iterables;
6060
import com.google.common.collect.Streams;
61+
import com.google.protobuf.Descriptors;
6162
import com.google.protobuf.Message;
6263

6364
import javax.annotation.Nonnull;
@@ -275,7 +276,7 @@ private static Value encapsulate(@Nonnull final String functionName,
275276
Verify.verify(arguments.size() == 1 || arguments.size() == 2);
276277
final Typed arg0 = arguments.get(0);
277278
final Type res0 = arg0.getResultType();
278-
SemanticException.check(res0.isPrimitive(), SemanticException.ErrorCode.COMPARAND_TO_COMPARISON_IS_OF_COMPLEX_TYPE);
279+
SemanticException.check(res0.isPrimitive() || res0.isEnum(), SemanticException.ErrorCode.COMPARAND_TO_COMPARISON_IS_OF_COMPLEX_TYPE);
279280
if (arguments.size() == 1) {
280281
final UnaryPhysicalOperator physicalOperator =
281282
getUnaryOperatorMap().get(new UnaryComparisonSignature(comparisonType, res0.getTypeCode()));
@@ -289,7 +290,7 @@ private static Value encapsulate(@Nonnull final String functionName,
289290
} else {
290291
final Typed arg1 = arguments.get(1);
291292
final Type res1 = arg1.getResultType();
292-
SemanticException.check(res1.isPrimitive(), SemanticException.ErrorCode.COMPARAND_TO_COMPARISON_IS_OF_COMPLEX_TYPE);
293+
SemanticException.check(res1.isPrimitive() || res1.isEnum(), SemanticException.ErrorCode.COMPARAND_TO_COMPARISON_IS_OF_COMPLEX_TYPE);
293294

294295
final BinaryPhysicalOperator physicalOperator =
295296
getBinaryOperatorMap().get(new BinaryComparisonSignature(comparisonType, res0.getTypeCode(), res1.getTypeCode()));
@@ -664,6 +665,73 @@ private enum BinaryPhysicalOperator {
664665
GT_BYBY(Comparisons.Type.GREATER_THAN, Type.TypeCode.BYTES, Type.TypeCode.BYTES, (l, r) -> Comparisons.evalComparison(Comparisons.Type.GREATER_THAN, l, r)),
665666
GTE_BYU(Comparisons.Type.GREATER_THAN_OR_EQUALS, Type.TypeCode.BYTES, Type.TypeCode.UNKNOWN, (l, r) -> null),
666667
GTE_BYBY(Comparisons.Type.GREATER_THAN_OR_EQUALS, Type.TypeCode.BYTES, Type.TypeCode.BYTES, (l, r) -> Comparisons.evalComparison(Comparisons.Type.GREATER_THAN_OR_EQUALS, l, r)),
668+
669+
EQ_EE(Comparisons.Type.EQUALS, Type.TypeCode.ENUM, Type.TypeCode.ENUM, (l, r) -> Comparisons.evalComparison(Comparisons.Type.EQUALS, l, r)),
670+
EQ_ES(Comparisons.Type.EQUALS, Type.TypeCode.ENUM, Type.TypeCode.STRING, (l, r) -> {
671+
final var otherValue = PromoteValue.PhysicalOperator.stringToEnumValue(((Descriptors.EnumValueDescriptor) l).getType(), (String) r);
672+
return Comparisons.evalComparison(Comparisons.Type.EQUALS, l, otherValue);
673+
}),
674+
EQ_SE(Comparisons.Type.EQUALS, Type.TypeCode.STRING, Type.TypeCode.ENUM, (l, r) -> {
675+
final var otherValue = PromoteValue.PhysicalOperator.stringToEnumValue(((Descriptors.EnumValueDescriptor) r).getType(), (String) l);
676+
return Comparisons.evalComparison(Comparisons.Type.EQUALS, otherValue, r);
677+
}),
678+
EQ_EU(Comparisons.Type.EQUALS, Type.TypeCode.ENUM, Type.TypeCode.UNKNOWN, (l, r) -> null),
679+
EQ_UE(Comparisons.Type.EQUALS, Type.TypeCode.UNKNOWN, Type.TypeCode.ENUM, (l, r) -> null),
680+
NEQ_EE(Comparisons.Type.NOT_EQUALS, Type.TypeCode.ENUM, Type.TypeCode.ENUM, (l, r) -> Comparisons.evalComparison(Comparisons.Type.NOT_EQUALS, l, r)),
681+
NEQ_ES(Comparisons.Type.NOT_EQUALS, Type.TypeCode.ENUM, Type.TypeCode.STRING, (l, r) -> {
682+
final var otherValue = PromoteValue.PhysicalOperator.stringToEnumValue(((Descriptors.EnumValueDescriptor) l).getType(), (String) r);
683+
return Comparisons.evalComparison(Comparisons.Type.NOT_EQUALS, l, otherValue);
684+
}),
685+
NEQ_SE(Comparisons.Type.NOT_EQUALS, Type.TypeCode.STRING, Type.TypeCode.ENUM, (l, r) -> {
686+
final var otherValue = PromoteValue.PhysicalOperator.stringToEnumValue(((Descriptors.EnumValueDescriptor) r).getType(), (String) l);
687+
return Comparisons.evalComparison(Comparisons.Type.EQUALS, otherValue, r);
688+
}),
689+
NEQ_EU(Comparisons.Type.NOT_EQUALS, Type.TypeCode.ENUM, Type.TypeCode.UNKNOWN, (l, r) -> null),
690+
NEQ_UE(Comparisons.Type.NOT_EQUALS, Type.TypeCode.UNKNOWN, Type.TypeCode.ENUM, (l, r) -> null),
691+
LT_EE(Comparisons.Type.LESS_THAN, Type.TypeCode.ENUM, Type.TypeCode.ENUM, (l, r) -> Comparisons.evalComparison(Comparisons.Type.LESS_THAN, l, r)),
692+
LT_ES(Comparisons.Type.LESS_THAN, Type.TypeCode.ENUM, Type.TypeCode.STRING, (l, r) -> {
693+
final var otherValue = PromoteValue.PhysicalOperator.stringToEnumValue(((Descriptors.EnumValueDescriptor) l).getType(), (String) r);
694+
return Comparisons.evalComparison(Comparisons.Type.LESS_THAN, l, otherValue);
695+
}),
696+
LT_SE(Comparisons.Type.LESS_THAN, Type.TypeCode.STRING, Type.TypeCode.ENUM, (l, r) -> {
697+
final var otherValue = PromoteValue.PhysicalOperator.stringToEnumValue(((Descriptors.EnumValueDescriptor) r).getType(), (String) l);
698+
return Comparisons.evalComparison(Comparisons.Type.LESS_THAN, otherValue, r);
699+
}),
700+
LT_EU(Comparisons.Type.LESS_THAN, Type.TypeCode.ENUM, Type.TypeCode.UNKNOWN, (l, r) -> null),
701+
LT_UE(Comparisons.Type.LESS_THAN, Type.TypeCode.UNKNOWN, Type.TypeCode.ENUM, (l, r) -> null),
702+
LTE_EE(Comparisons.Type.LESS_THAN_OR_EQUALS, Type.TypeCode.ENUM, Type.TypeCode.ENUM, (l, r) -> Comparisons.evalComparison(Comparisons.Type.LESS_THAN_OR_EQUALS, l, r)),
703+
LTE_ES(Comparisons.Type.LESS_THAN_OR_EQUALS, Type.TypeCode.ENUM, Type.TypeCode.STRING, (l, r) -> {
704+
final var otherValue = PromoteValue.PhysicalOperator.stringToEnumValue(((Descriptors.EnumValueDescriptor) l).getType(), (String) r);
705+
return Comparisons.evalComparison(Comparisons.Type.LESS_THAN, l, otherValue);
706+
}),
707+
LTE_SE(Comparisons.Type.LESS_THAN_OR_EQUALS, Type.TypeCode.STRING, Type.TypeCode.ENUM, (l, r) -> {
708+
final var otherValue = PromoteValue.PhysicalOperator.stringToEnumValue(((Descriptors.EnumValueDescriptor) r).getType(), (String) l);
709+
return Comparisons.evalComparison(Comparisons.Type.LESS_THAN, otherValue, r);
710+
}),
711+
LTE_EU(Comparisons.Type.LESS_THAN_OR_EQUALS, Type.TypeCode.ENUM, Type.TypeCode.UNKNOWN, (l, r) -> null),
712+
LTE_UE(Comparisons.Type.LESS_THAN_OR_EQUALS, Type.TypeCode.UNKNOWN, Type.TypeCode.ENUM, (l, r) -> null),
713+
GT_EE(Comparisons.Type.GREATER_THAN, Type.TypeCode.ENUM, Type.TypeCode.ENUM, (l, r) -> Comparisons.evalComparison(Comparisons.Type.GREATER_THAN, l, r)),
714+
GT_ES(Comparisons.Type.GREATER_THAN, Type.TypeCode.ENUM, Type.TypeCode.STRING, (l, r) -> {
715+
final var otherValue = PromoteValue.PhysicalOperator.stringToEnumValue(((Descriptors.EnumValueDescriptor) l).getType(), (String) r);
716+
return Comparisons.evalComparison(Comparisons.Type.GREATER_THAN, l, otherValue);
717+
}),
718+
GT_SE(Comparisons.Type.GREATER_THAN, Type.TypeCode.STRING, Type.TypeCode.ENUM, (l, r) -> {
719+
final var otherValue = PromoteValue.PhysicalOperator.stringToEnumValue(((Descriptors.EnumValueDescriptor) r).getType(), (String) l);
720+
return Comparisons.evalComparison(Comparisons.Type.GREATER_THAN, otherValue, r);
721+
}),
722+
GT_EU(Comparisons.Type.GREATER_THAN, Type.TypeCode.ENUM, Type.TypeCode.UNKNOWN, (l, r) -> null),
723+
GT_UE(Comparisons.Type.GREATER_THAN, Type.TypeCode.UNKNOWN, Type.TypeCode.ENUM, (l, r) -> null),
724+
GTE_EE(Comparisons.Type.GREATER_THAN_OR_EQUALS, Type.TypeCode.ENUM, Type.TypeCode.ENUM, (l, r) -> Comparisons.evalComparison(Comparisons.Type.GREATER_THAN_OR_EQUALS, l, r)),
725+
GTE_ES(Comparisons.Type.GREATER_THAN_OR_EQUALS, Type.TypeCode.ENUM, Type.TypeCode.STRING, (l, r) -> {
726+
final var otherValue = PromoteValue.PhysicalOperator.stringToEnumValue(((Descriptors.EnumValueDescriptor) l).getType(), (String) r);
727+
return Comparisons.evalComparison(Comparisons.Type.GREATER_THAN_OR_EQUALS, l, otherValue);
728+
}),
729+
GTE_SE(Comparisons.Type.GREATER_THAN_OR_EQUALS, Type.TypeCode.STRING, Type.TypeCode.ENUM, (l, r) -> {
730+
final var otherValue = PromoteValue.PhysicalOperator.stringToEnumValue(((Descriptors.EnumValueDescriptor) r).getType(), (String) l);
731+
return Comparisons.evalComparison(Comparisons.Type.GREATER_THAN_OR_EQUALS, otherValue, r);
732+
}),
733+
GTE_EU(Comparisons.Type.GREATER_THAN_OR_EQUALS, Type.TypeCode.ENUM, Type.TypeCode.UNKNOWN, (l, r) -> null),
734+
GTE_UE(Comparisons.Type.GREATER_THAN_OR_EQUALS, Type.TypeCode.UNKNOWN, Type.TypeCode.ENUM, (l, r) -> null),
667735
;
668736

669737
@Nonnull
@@ -753,7 +821,10 @@ private enum UnaryPhysicalOperator {
753821
IS_NOT_NULL_BI(Comparisons.Type.NOT_NULL, Type.TypeCode.BOOLEAN, Objects::nonNull),
754822

755823
IS_NULL_BY(Comparisons.Type.IS_NULL, Type.TypeCode.BYTES, Objects::isNull),
756-
IS_NOT_NULL_BY(Comparisons.Type.NOT_NULL, Type.TypeCode.BYTES, Objects::nonNull);
824+
IS_NOT_NULL_BY(Comparisons.Type.NOT_NULL, Type.TypeCode.BYTES, Objects::nonNull),
825+
826+
IS_NULL_EI(Comparisons.Type.IS_NULL, Type.TypeCode.ENUM, Objects::isNull),
827+
IS_NOT_NULL_EI(Comparisons.Type.NOT_NULL, Type.TypeCode.ENUM, Objects::nonNull);
757828

758829
@Nonnull
759830
private static final Supplier<BiMap<UnaryPhysicalOperator, PUnaryPhysicalOperator>> protoEnumBiMapSupplier =

fdb-record-layer-core/src/main/proto/record_query_plan.proto

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -831,6 +831,37 @@ message PBinaryRelOpValue {
831831
GTE_BYU = 209;
832832
GTE_BYBY = 210;
833833

834+
EQ_EE = 211;
835+
EQ_ES = 212;
836+
EQ_SE = 213;
837+
EQ_EU = 214;
838+
EQ_UE = 215;
839+
NEQ_EE = 216;
840+
NEQ_ES = 217;
841+
NEQ_SE = 218;
842+
NEQ_EU = 219;
843+
NEQ_UE = 220;
844+
LT_EE = 221;
845+
LT_ES = 222;
846+
LT_SE = 223;
847+
LT_EU = 224;
848+
LT_UE = 225;
849+
LTE_EE = 226;
850+
LTE_ES = 227;
851+
LTE_SE = 228;
852+
LTE_EU = 229;
853+
LTE_UE = 230;
854+
GT_EE = 231;
855+
GT_ES = 232;
856+
GT_SE = 233;
857+
GT_EU = 234;
858+
GT_UE = 235;
859+
GTE_EE = 236;
860+
GTE_ES = 237;
861+
GTE_SE = 238;
862+
GTE_EU = 239;
863+
GTE_UE = 240;
864+
834865
}
835866
optional PRelOpValue super = 1;
836867
optional PBinaryPhysicalOperator operator = 2;
@@ -865,6 +896,9 @@ message PUnaryRelOpValue {
865896

866897
IS_NULL_BY = 15;
867898
IS_NOT_NULL_BY = 16;
899+
900+
IS_NULL_EI = 17;
901+
IS_NOT_NULL_EI = 18;
868902
}
869903
optional PRelOpValue super = 1;
870904
optional PUnaryPhysicalOperator operator = 2;

0 commit comments

Comments
 (0)