Skip to content

Commit

Permalink
support for enums in rel ops
Browse files Browse the repository at this point in the history
  • Loading branch information
g31pranjal committed Jan 15, 2025
1 parent a7b8887 commit c59de90
Show file tree
Hide file tree
Showing 11 changed files with 272 additions and 29 deletions.
2 changes: 1 addition & 1 deletion docs/ReleaseNotes.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ Our API stability annotations have been updated to reflect greater API instabili
* **Feature** Feature 2 [(Issue #NNN)](https://github.com/FoundationDB/fdb-record-layer/issues/NNN)
* **Feature** Feature 3 [(Issue #NNN)](https://github.com/FoundationDB/fdb-record-layer/issues/NNN)
* **Feature** Feature 4 [(Issue #NNN)](https://github.com/FoundationDB/fdb-record-layer/issues/NNN)
* **Feature** Feature 5 [(Issue #NNN)](https://github.com/FoundationDB/fdb-record-layer/issues/NNN)
* **Feature** Support enums in rel ops [(Issue #3011)](https://github.com/FoundationDB/fdb-record-layer/issues/3011)
* **Breaking change** Change 1 [(Issue #NNN)](https://github.com/FoundationDB/fdb-record-layer/issues/NNN)
* **Breaking change** Change 2 [(Issue #NNN)](https://github.com/FoundationDB/fdb-record-layer/issues/NNN)
* **Breaking change** Change 3 [(Issue #NNN)](https://github.com/FoundationDB/fdb-record-layer/issues/NNN)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public enum ErrorCode {
FUNCTION_UNDEFINED_FOR_GIVEN_ARGUMENT_TYPES(9, "The function is not defined for the given argument types"),
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."),
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."),
INVALID_ENUM_VALUE(12, "Invalid enum value for the enum type"),

// insert, update, deletes
UPDATE_TRANSFORM_AMBIGUOUS(1_000, "The transformations used in an UPDATE statement are ambiguous."),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -493,13 +493,18 @@ static Type maximumType(@Nonnull final Type t1, @Nonnull final Type t2) {
return t1.withNullability(true);
}

if (t1.isPrimitive() != t2.isPrimitive()) {
return null;
}

boolean isResultNullable = t1.isNullable() || t2.isNullable();

if (t1.isPrimitive()) {
if (t1.isEnum() && t2.isEnum()) {
final var t1Enum = (Enum)t1;
final var t2Enum = (Enum)t2;
final var t1EnumValues = t1Enum.enumValues;
final var t2EnumValues = t2Enum.enumValues;
if (t1EnumValues == null) {
return t2EnumValues == null ? t1Enum.withNullability(isResultNullable) : null;
}
return t1EnumValues.equals(t2EnumValues) ? t1Enum.withNullability(isResultNullable) : null;
} else if ((t1.isPrimitive() || t1.isEnum()) && (t2.isPrimitive() || t2.isEnum())) {
if (t1.getTypeCode() == t2.getTypeCode()) {
return t1.withNullability(isResultNullable);
}
Expand All @@ -509,25 +514,11 @@ static Type maximumType(@Nonnull final Type t1, @Nonnull final Type t2) {
if (PromoteValue.isPromotable(t2, t1)) {
return t1.withNullability(isResultNullable);
}
// Type are primitive but not equal, no promotion possible.
return null;
}

if (t1.isEnum() != t2.isEnum()) {
// Type are primitive or enum but not compatible, no promotion possible.
return null;
}

if (t1.isEnum()) {
final var t1Enum = (Enum)t1;
final var t2Enum = (Enum)t2;
final var t1EnumValues = t1Enum.enumValues;
final var t2EnumValues = t2Enum.enumValues;
if (t1EnumValues == null) {
return t2EnumValues == null ? t1Enum.withNullability(isResultNullable) : null;
}
return t1EnumValues.equals(t2EnumValues) ? t1Enum.withNullability(isResultNullable) : null;
}

// neither of the types are null, primitives or enums
if (t1.getTypeCode() != t2.getTypeCode()) {
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@
* A value representing the contents of a (non-repeated, arbitrarily-nested) field of a quantifier.
*/
@API(API.Status.EXPERIMENTAL)
public class FieldValue extends AbstractValue implements ValueWithChild {
public class FieldValue extends AbstractValue implements ValueWithChild, CreatesDynamicTypesValue {
private static final ObjectPlanHash BASE_HASH = new ObjectPlanHash("Field-Value");

@Nonnull
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ enum PhysicalOperator {
NULL_TO_RECORD(Type.TypeCode.NULL, Type.TypeCode.RECORD, (descriptor, in) -> null),
NONE_TO_ARRAY(Type.TypeCode.NONE, Type.TypeCode.ARRAY, (descriptor, in) -> in),
NULL_TO_ENUM(Type.TypeCode.NULL, Type.TypeCode.ENUM, (descriptor, in) -> null),
STRING_TO_ENUM(Type.TypeCode.STRING, Type.TypeCode.ENUM, ((descriptor, in) -> ((Descriptors.EnumDescriptor)descriptor).findValueByName((String)in)));
STRING_TO_ENUM(Type.TypeCode.STRING, Type.TypeCode.ENUM, ((descriptor, in) -> stringToEnumValue((Descriptors.EnumDescriptor) descriptor, (String) in)));

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

public static Descriptors.EnumValueDescriptor stringToEnumValue(Descriptors.EnumDescriptor enumDescriptor, String value) {
final var maybeValue = enumDescriptor.findValueByName(value);
SemanticException.check(maybeValue != null, SemanticException.ErrorCode.INVALID_ENUM_VALUE, value);
return maybeValue;
}

@Nonnull
private static BiMap<PhysicalOperator, PPhysicalOperator> getProtoEnumBiMap() {
return protoEnumBiMapSupplier.get();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Streams;
import com.google.protobuf.Descriptors;
import com.google.protobuf.Message;

import javax.annotation.Nonnull;
Expand Down Expand Up @@ -275,7 +276,7 @@ private static Value encapsulate(@Nonnull final String functionName,
Verify.verify(arguments.size() == 1 || arguments.size() == 2);
final Typed arg0 = arguments.get(0);
final Type res0 = arg0.getResultType();
SemanticException.check(res0.isPrimitive(), SemanticException.ErrorCode.COMPARAND_TO_COMPARISON_IS_OF_COMPLEX_TYPE);
SemanticException.check(res0.isPrimitive() || res0.isEnum(), SemanticException.ErrorCode.COMPARAND_TO_COMPARISON_IS_OF_COMPLEX_TYPE);
if (arguments.size() == 1) {
final UnaryPhysicalOperator physicalOperator =
getUnaryOperatorMap().get(new UnaryComparisonSignature(comparisonType, res0.getTypeCode()));
Expand All @@ -289,7 +290,7 @@ private static Value encapsulate(@Nonnull final String functionName,
} else {
final Typed arg1 = arguments.get(1);
final Type res1 = arg1.getResultType();
SemanticException.check(res1.isPrimitive(), SemanticException.ErrorCode.COMPARAND_TO_COMPARISON_IS_OF_COMPLEX_TYPE);
SemanticException.check(res1.isPrimitive() || res1.isEnum(), SemanticException.ErrorCode.COMPARAND_TO_COMPARISON_IS_OF_COMPLEX_TYPE);

final BinaryPhysicalOperator physicalOperator =
getBinaryOperatorMap().get(new BinaryComparisonSignature(comparisonType, res0.getTypeCode(), res1.getTypeCode()));
Expand Down Expand Up @@ -664,6 +665,73 @@ private enum BinaryPhysicalOperator {
GT_BYBY(Comparisons.Type.GREATER_THAN, Type.TypeCode.BYTES, Type.TypeCode.BYTES, (l, r) -> Comparisons.evalComparison(Comparisons.Type.GREATER_THAN, l, r)),
GTE_BYU(Comparisons.Type.GREATER_THAN_OR_EQUALS, Type.TypeCode.BYTES, Type.TypeCode.UNKNOWN, (l, r) -> null),
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)),

EQ_EE(Comparisons.Type.EQUALS, Type.TypeCode.ENUM, Type.TypeCode.ENUM, (l, r) -> Comparisons.evalComparison(Comparisons.Type.EQUALS, l, r)),
EQ_ES(Comparisons.Type.EQUALS, 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.EQUALS, l, otherValue);
}),
EQ_SE(Comparisons.Type.EQUALS, 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);
}),
EQ_EU(Comparisons.Type.EQUALS, Type.TypeCode.ENUM, Type.TypeCode.UNKNOWN, (l, r) -> null),
EQ_UE(Comparisons.Type.EQUALS, Type.TypeCode.UNKNOWN, Type.TypeCode.ENUM, (l, r) -> null),
NEQ_EE(Comparisons.Type.NOT_EQUALS, Type.TypeCode.ENUM, Type.TypeCode.ENUM, (l, r) -> Comparisons.evalComparison(Comparisons.Type.NOT_EQUALS, l, r)),
NEQ_ES(Comparisons.Type.NOT_EQUALS, 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_EQUALS, l, otherValue);
}),
NEQ_SE(Comparisons.Type.NOT_EQUALS, 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);
}),
NEQ_EU(Comparisons.Type.NOT_EQUALS, Type.TypeCode.ENUM, Type.TypeCode.UNKNOWN, (l, r) -> null),
NEQ_UE(Comparisons.Type.NOT_EQUALS, Type.TypeCode.UNKNOWN, Type.TypeCode.ENUM, (l, r) -> null),
LT_EE(Comparisons.Type.LESS_THAN, Type.TypeCode.ENUM, Type.TypeCode.ENUM, (l, r) -> Comparisons.evalComparison(Comparisons.Type.LESS_THAN, l, r)),
LT_ES(Comparisons.Type.LESS_THAN, 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.LESS_THAN, l, otherValue);
}),
LT_SE(Comparisons.Type.LESS_THAN, 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.LESS_THAN, otherValue, r);
}),
LT_EU(Comparisons.Type.LESS_THAN, Type.TypeCode.ENUM, Type.TypeCode.UNKNOWN, (l, r) -> null),
LT_UE(Comparisons.Type.LESS_THAN, Type.TypeCode.UNKNOWN, Type.TypeCode.ENUM, (l, r) -> null),
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)),
LTE_ES(Comparisons.Type.LESS_THAN_OR_EQUALS, 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.LESS_THAN, l, otherValue);
}),
LTE_SE(Comparisons.Type.LESS_THAN_OR_EQUALS, 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.LESS_THAN, otherValue, r);
}),
LTE_EU(Comparisons.Type.LESS_THAN_OR_EQUALS, Type.TypeCode.ENUM, Type.TypeCode.UNKNOWN, (l, r) -> null),
LTE_UE(Comparisons.Type.LESS_THAN_OR_EQUALS, Type.TypeCode.UNKNOWN, Type.TypeCode.ENUM, (l, r) -> null),
GT_EE(Comparisons.Type.GREATER_THAN, Type.TypeCode.ENUM, Type.TypeCode.ENUM, (l, r) -> Comparisons.evalComparison(Comparisons.Type.GREATER_THAN, l, r)),
GT_ES(Comparisons.Type.GREATER_THAN, 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.GREATER_THAN, l, otherValue);
}),
GT_SE(Comparisons.Type.GREATER_THAN, 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.GREATER_THAN, otherValue, r);
}),
GT_EU(Comparisons.Type.GREATER_THAN, Type.TypeCode.ENUM, Type.TypeCode.UNKNOWN, (l, r) -> null),
GT_UE(Comparisons.Type.GREATER_THAN, Type.TypeCode.UNKNOWN, Type.TypeCode.ENUM, (l, r) -> null),
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)),
GTE_ES(Comparisons.Type.GREATER_THAN_OR_EQUALS, 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.GREATER_THAN_OR_EQUALS, l, otherValue);
}),
GTE_SE(Comparisons.Type.GREATER_THAN_OR_EQUALS, 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.GREATER_THAN_OR_EQUALS, otherValue, r);
}),
GTE_EU(Comparisons.Type.GREATER_THAN_OR_EQUALS, Type.TypeCode.ENUM, Type.TypeCode.UNKNOWN, (l, r) -> null),
GTE_UE(Comparisons.Type.GREATER_THAN_OR_EQUALS, Type.TypeCode.UNKNOWN, Type.TypeCode.ENUM, (l, r) -> null),
;

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

IS_NULL_BY(Comparisons.Type.IS_NULL, Type.TypeCode.BYTES, Objects::isNull),
IS_NOT_NULL_BY(Comparisons.Type.NOT_NULL, Type.TypeCode.BYTES, Objects::nonNull);
IS_NOT_NULL_BY(Comparisons.Type.NOT_NULL, Type.TypeCode.BYTES, Objects::nonNull),

IS_NULL_EI(Comparisons.Type.IS_NULL, Type.TypeCode.ENUM, Objects::isNull),
IS_NOT_NULL_EI(Comparisons.Type.NOT_NULL, Type.TypeCode.ENUM, Objects::nonNull);

@Nonnull
private static final Supplier<BiMap<UnaryPhysicalOperator, PUnaryPhysicalOperator>> protoEnumBiMapSupplier =
Expand Down
34 changes: 34 additions & 0 deletions fdb-record-layer-core/src/main/proto/record_query_plan.proto
Original file line number Diff line number Diff line change
Expand Up @@ -831,6 +831,37 @@ message PBinaryRelOpValue {
GTE_BYU = 209;
GTE_BYBY = 210;

EQ_EE = 211;
EQ_ES = 212;
EQ_SE = 213;
EQ_EU = 214;
EQ_UE = 215;
NEQ_EE = 216;
NEQ_ES = 217;
NEQ_SE = 218;
NEQ_EU = 219;
NEQ_UE = 220;
LT_EE = 221;
LT_ES = 222;
LT_SE = 223;
LT_EU = 224;
LT_UE = 225;
LTE_EE = 226;
LTE_ES = 227;
LTE_SE = 228;
LTE_EU = 229;
LTE_UE = 230;
GT_EE = 231;
GT_ES = 232;
GT_SE = 233;
GT_EU = 234;
GT_UE = 235;
GTE_EE = 236;
GTE_ES = 237;
GTE_SE = 238;
GTE_EU = 239;
GTE_UE = 240;

}
optional PRelOpValue super = 1;
optional PBinaryPhysicalOperator operator = 2;
Expand Down Expand Up @@ -865,6 +896,9 @@ message PUnaryRelOpValue {

IS_NULL_BY = 15;
IS_NOT_NULL_BY = 16;

IS_NULL_EI = 17;
IS_NOT_NULL_EI = 18;
}
optional PRelOpValue super = 1;
optional PUnaryPhysicalOperator operator = 2;
Expand Down
Loading

0 comments on commit c59de90

Please sign in to comment.