diff --git a/partiql-ast/api/partiql-ast.api b/partiql-ast/api/partiql-ast.api index 194b0dbe9..54da223ce 100644 --- a/partiql-ast/api/partiql-ast.api +++ b/partiql-ast/api/partiql-ast.api @@ -25,7 +25,7 @@ public final class org/partiql/ast/Ast { public static final fun exprInCollection (Lorg/partiql/ast/expr/Expr;Lorg/partiql/ast/expr/Expr;Z)Lorg/partiql/ast/expr/ExprInCollection; public static final fun exprIsType (Lorg/partiql/ast/expr/Expr;Lorg/partiql/ast/DataType;Z)Lorg/partiql/ast/expr/ExprIsType; public static final fun exprLike (Lorg/partiql/ast/expr/Expr;Lorg/partiql/ast/expr/Expr;Lorg/partiql/ast/expr/Expr;Z)Lorg/partiql/ast/expr/ExprLike; - public static final fun exprLit (Lorg/partiql/ast/literal/Literal;)Lorg/partiql/ast/expr/ExprLit; + public static final fun exprLit (Lorg/partiql/ast/Literal;)Lorg/partiql/ast/expr/ExprLit; public static final fun exprMatch (Lorg/partiql/ast/expr/Expr;Lorg/partiql/ast/graph/GraphMatch;)Lorg/partiql/ast/expr/ExprMatch; public static final fun exprNot (Lorg/partiql/ast/expr/Expr;)Lorg/partiql/ast/expr/ExprNot; public static final fun exprNullIf (Lorg/partiql/ast/expr/Expr;Lorg/partiql/ast/expr/Expr;)Lorg/partiql/ast/expr/ExprNullIf; @@ -233,8 +233,8 @@ public abstract class org/partiql/ast/AstRewriter : org/partiql/ast/AstVisitor { public fun visitLet (Lorg/partiql/ast/Let;Ljava/lang/Object;)Lorg/partiql/ast/AstNode; public synthetic fun visitLetBinding (Lorg/partiql/ast/Let$Binding;Ljava/lang/Object;)Ljava/lang/Object; public fun visitLetBinding (Lorg/partiql/ast/Let$Binding;Ljava/lang/Object;)Lorg/partiql/ast/AstNode; - public synthetic fun visitLiteral (Lorg/partiql/ast/literal/Literal;Ljava/lang/Object;)Ljava/lang/Object; - public fun visitLiteral (Lorg/partiql/ast/literal/Literal;Ljava/lang/Object;)Lorg/partiql/ast/AstNode; + public synthetic fun visitLiteral (Lorg/partiql/ast/Literal;Ljava/lang/Object;)Ljava/lang/Object; + public fun visitLiteral (Lorg/partiql/ast/Literal;Ljava/lang/Object;)Lorg/partiql/ast/AstNode; public synthetic fun visitPathStepAllElements (Lorg/partiql/ast/expr/PathStep$AllElements;Ljava/lang/Object;)Ljava/lang/Object; public fun visitPathStepAllElements (Lorg/partiql/ast/expr/PathStep$AllElements;Ljava/lang/Object;)Lorg/partiql/ast/AstNode; public synthetic fun visitPathStepAllFields (Lorg/partiql/ast/expr/PathStep$AllFields;Ljava/lang/Object;)Ljava/lang/Object; @@ -350,7 +350,7 @@ public abstract class org/partiql/ast/AstVisitor { public fun visitKeyValue (Lorg/partiql/ast/ddl/KeyValue;Ljava/lang/Object;)Ljava/lang/Object; public fun visitLet (Lorg/partiql/ast/Let;Ljava/lang/Object;)Ljava/lang/Object; public fun visitLetBinding (Lorg/partiql/ast/Let$Binding;Ljava/lang/Object;)Ljava/lang/Object; - public fun visitLiteral (Lorg/partiql/ast/literal/Literal;Ljava/lang/Object;)Ljava/lang/Object; + public fun visitLiteral (Lorg/partiql/ast/Literal;Ljava/lang/Object;)Ljava/lang/Object; public fun visitNullable (Lorg/partiql/ast/ddl/AttributeConstraint$Null;Ljava/lang/Object;)Ljava/lang/Object; public fun visitOrderBy (Lorg/partiql/ast/OrderBy;Ljava/lang/Object;)Ljava/lang/Object; public fun visitPartitionBy (Lorg/partiql/ast/ddl/PartitionBy;Ljava/lang/Object;)Ljava/lang/Object; @@ -932,6 +932,42 @@ public class org/partiql/ast/Let$Builder { public fun toString ()Ljava/lang/String; } +public class org/partiql/ast/Literal : org/partiql/ast/AstEnum { + public static final field APPROX_NUM I + public static final field BOOL I + public static final field EXACT_NUM I + public static final field INT_NUM I + public static final field MISSING I + public static final field NULL I + public static final field STRING I + public static final field TYPED_STRING I + public static final field UNKNOWN I + public fun accept (Lorg/partiql/ast/AstVisitor;Ljava/lang/Object;)Ljava/lang/Object; + public static fun approxNum (Ljava/lang/String;)Lorg/partiql/ast/Literal; + public fun bigDecimalValue ()Ljava/math/BigDecimal; + public static fun bool (Z)Lorg/partiql/ast/Literal; + public fun booleanValue ()Z + protected fun canEqual (Ljava/lang/Object;)Z + public fun children ()Ljava/util/Collection; + public fun code ()I + public fun dataType ()Lorg/partiql/ast/DataType; + public fun equals (Ljava/lang/Object;)Z + public static fun exactNum (Ljava/lang/String;)Lorg/partiql/ast/Literal; + public static fun exactNum (Ljava/math/BigDecimal;)Lorg/partiql/ast/Literal; + public fun hashCode ()I + public static fun intNum (I)Lorg/partiql/ast/Literal; + public static fun intNum (J)Lorg/partiql/ast/Literal; + public static fun intNum (Ljava/lang/String;)Lorg/partiql/ast/Literal; + public static fun intNum (Ljava/math/BigInteger;)Lorg/partiql/ast/Literal; + public static fun missing ()Lorg/partiql/ast/Literal; + public fun name ()Ljava/lang/String; + public static fun nul ()Lorg/partiql/ast/Literal; + public fun numberValue ()Ljava/lang/String; + public static fun string (Ljava/lang/String;)Lorg/partiql/ast/Literal; + public fun stringValue ()Ljava/lang/String; + public static fun typedString (Lorg/partiql/ast/DataType;Ljava/lang/String;)Lorg/partiql/ast/Literal; +} + public class org/partiql/ast/Nulls : org/partiql/ast/AstEnum { public static final field FIRST I public static final field LAST I @@ -1660,8 +1696,8 @@ public class org/partiql/ast/expr/ExprLike$Builder { } public class org/partiql/ast/expr/ExprLit : org/partiql/ast/expr/Expr { - public field lit Lorg/partiql/ast/literal/Literal; - public fun (Lorg/partiql/ast/literal/Literal;)V + public field lit Lorg/partiql/ast/Literal; + public fun (Lorg/partiql/ast/Literal;)V public fun accept (Lorg/partiql/ast/AstVisitor;Ljava/lang/Object;)Ljava/lang/Object; protected fun canEqual (Ljava/lang/Object;)Z public fun children ()Ljava/util/Collection; @@ -2565,55 +2601,6 @@ public class org/partiql/ast/graph/GraphSelector$ShortestKGroup$Builder { public fun toString ()Ljava/lang/String; } -public abstract class org/partiql/ast/literal/Literal : org/partiql/ast/AstNode { - public fun ()V - public fun accept (Lorg/partiql/ast/AstVisitor;Ljava/lang/Object;)Ljava/lang/Object; - public fun bigDecimalValue ()Ljava/math/BigDecimal; - public fun booleanValue ()Z - public fun children ()Ljava/util/Collection; - public fun dataType ()Lorg/partiql/ast/DataType; - public abstract fun kind ()Lorg/partiql/ast/literal/LiteralKind; - public static fun litApprox (Ljava/lang/String;)Lorg/partiql/ast/literal/Literal; - public static fun litBool (Z)Lorg/partiql/ast/literal/Literal; - public static fun litExact (Ljava/lang/String;)Lorg/partiql/ast/literal/Literal; - public static fun litExact (Ljava/math/BigDecimal;)Lorg/partiql/ast/literal/Literal; - public static fun litInt (I)Lorg/partiql/ast/literal/Literal; - public static fun litInt (J)Lorg/partiql/ast/literal/Literal; - public static fun litInt (Ljava/lang/String;)Lorg/partiql/ast/literal/Literal; - public static fun litInt (Ljava/math/BigInteger;)Lorg/partiql/ast/literal/Literal; - public static fun litMissing ()Lorg/partiql/ast/literal/Literal; - public static fun litNull ()Lorg/partiql/ast/literal/Literal; - public static fun litString (Ljava/lang/String;)Lorg/partiql/ast/literal/Literal; - public static fun litTypedString (Lorg/partiql/ast/DataType;Ljava/lang/String;)Lorg/partiql/ast/literal/Literal; - public fun numberValue ()Ljava/lang/String; - public fun stringValue ()Ljava/lang/String; -} - -public class org/partiql/ast/literal/LiteralKind { - public static final field BOOLEAN I - public static final field MISSING I - public static final field NULL I - public static final field NUM_APPROX I - public static final field NUM_EXACT I - public static final field NUM_INT I - public static final field STRING I - public static final field TYPED_STRING I - public static final field UNKNOWN I - public static fun BOOLEAN ()Lorg/partiql/ast/literal/LiteralKind; - public static fun MISSING ()Lorg/partiql/ast/literal/LiteralKind; - public static fun NULL ()Lorg/partiql/ast/literal/LiteralKind; - public static fun NUM_APPROX ()Lorg/partiql/ast/literal/LiteralKind; - public static fun NUM_EXACT ()Lorg/partiql/ast/literal/LiteralKind; - public static fun NUM_INT ()Lorg/partiql/ast/literal/LiteralKind; - public static fun STRING ()Lorg/partiql/ast/literal/LiteralKind; - public static fun TYPED_STRING ()Lorg/partiql/ast/literal/LiteralKind; - public static fun UNKNOWN ()Lorg/partiql/ast/literal/LiteralKind; - protected fun canEqual (Ljava/lang/Object;)Z - public fun code ()I - public fun equals (Ljava/lang/Object;)Z - public fun hashCode ()I -} - public abstract class org/partiql/ast/sql/SqlBlock { public static final field Companion Lorg/partiql/ast/sql/SqlBlock$Companion; public field next Lorg/partiql/ast/sql/SqlBlock; diff --git a/partiql-ast/src/main/java/org/partiql/ast/AstVisitor.java b/partiql-ast/src/main/java/org/partiql/ast/AstVisitor.java index b36d27f0a..7c1767fe9 100644 --- a/partiql-ast/src/main/java/org/partiql/ast/AstVisitor.java +++ b/partiql-ast/src/main/java/org/partiql/ast/AstVisitor.java @@ -47,7 +47,6 @@ import org.partiql.ast.graph.GraphPattern; import org.partiql.ast.graph.GraphQuantifier; import org.partiql.ast.graph.GraphSelector; -import org.partiql.ast.literal.Literal; // TODO docs // Also include docs on how a library user could create a new variant for sum types and which methods to override diff --git a/partiql-ast/src/main/java/org/partiql/ast/Explain.java b/partiql-ast/src/main/java/org/partiql/ast/Explain.java index e660fedf4..d93dc73c8 100644 --- a/partiql-ast/src/main/java/org/partiql/ast/Explain.java +++ b/partiql-ast/src/main/java/org/partiql/ast/Explain.java @@ -3,7 +3,6 @@ import lombok.Builder; import lombok.EqualsAndHashCode; import org.jetbrains.annotations.NotNull; -import org.partiql.ast.literal.Literal; import java.util.ArrayList; import java.util.Collection; diff --git a/partiql-ast/src/main/java/org/partiql/ast/Literal.java b/partiql-ast/src/main/java/org/partiql/ast/Literal.java new file mode 100644 index 000000000..58943714e --- /dev/null +++ b/partiql-ast/src/main/java/org/partiql/ast/Literal.java @@ -0,0 +1,254 @@ +package org.partiql.ast; + +import lombok.EqualsAndHashCode; +import org.jetbrains.annotations.NotNull; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.Collection; +import java.util.Collections; + +import static java.util.Objects.requireNonNull; + +/** + * TODO docs + */ +@EqualsAndHashCode(callSuper = false) +public class Literal extends AstEnum { + public static final int UNKNOWN = 0; + // absent literals + public static final int NULL = 1; + public static final int MISSING = 2; + // boolean literal + public static final int BOOL = 3; + // numeric literals + public static final int APPROX_NUM = 4; + public static final int EXACT_NUM = 5; + public static final int INT_NUM = 6; + // string literal + public static final int STRING = 7; + // typed string literal + public static final int TYPED_STRING = 8; + + // Literal fields + private final int code; + private final Boolean boolValue; + private final String stringValue; + private final DataType dataType; + + /////// Constructors + private Literal(int code, Boolean value, String stringValue, DataType dataType) { + this.code = code; + this.boolValue = value; + this.stringValue = stringValue; + this.dataType = dataType; + } + + // Private constructor for absent literals + private Literal(int code) { + this.code = code; + // Rest set to null + this.boolValue = null; + this.stringValue = null; + this.dataType = null; + } + + // Private constructor for boolean literal + private Literal(boolean value) { + this.code = BOOL; + this.boolValue = value; + // Rest set to null + this.stringValue = null; + this.dataType = null; + } + + // Private constructor for literals stored w/ just a string (e.g. numerics, single-quoted strings) + private Literal(int code, String value) { + this.code = code; + this.stringValue = value; + // Rest set to null + this.boolValue = null; + this.dataType = null; + } + + // Private constructor for typed string literal + private Literal(DataType dataType, String value) { + this.code = TYPED_STRING; + this.stringValue = value; + this.dataType = dataType; + // Rest set to null + this.boolValue = null; + } + + @Override + public int code() { + return code; + } + + @NotNull + @Override + public String name() { + switch (code) { + case NULL: return "NULL"; + case MISSING: return "MISSING"; + case BOOL: return "BOOL"; + case APPROX_NUM: return "APPROX_NUM"; + case EXACT_NUM: return "EXACT_NUM"; + case INT_NUM: return "INT_NUM"; + case STRING: return "STRING"; + case TYPED_STRING: return "TYPED_STRING"; + default: return "UNKNOWN"; + } + } + + @Override + @NotNull + public Collection children() { + return Collections.emptyList(); + } + + @Override + public R accept(@NotNull AstVisitor visitor, C ctx) { + return visitor.visitLiteral(this, ctx); + } + + // Factory methods + @NotNull + public static Literal approxNum(@NotNull String value) { + return new Literal(APPROX_NUM, value); + } + + @NotNull + public static Literal bool(boolean value) { + return new Literal(value); + } + + @NotNull + public static Literal exactNum(@NotNull BigDecimal value) { + if (value.scale() == 0) { + return new Literal(EXACT_NUM, value + "."); + } else { + return new Literal(EXACT_NUM, value.toString()); + } + } + + @NotNull + public static Literal exactNum(@NotNull String value) { + return new Literal(EXACT_NUM, value); + } + + @NotNull + public static Literal intNum(int value) { + return new Literal(INT_NUM, Integer.toString(value)); + } + + @NotNull + public static Literal intNum(long value) { + return new Literal(INT_NUM, Long.toString(value)); + } + + @NotNull + public static Literal intNum(@NotNull BigInteger value) { + return new Literal(INT_NUM, value.toString()); + } + + @NotNull + public static Literal intNum(@NotNull String value) { + return new Literal(INT_NUM, value); + } + + @NotNull + public static Literal nul() { + return new Literal(NULL); + } + + @NotNull + public static Literal missing() { + return new Literal(MISSING); + } + + @NotNull + public static Literal string(@NotNull String value) { + return new Literal(STRING, value); + } + + @NotNull + public static Literal typedString(@NotNull DataType type, @NotNull String value) { + return new Literal(type, value); + } + + // Value extraction + /** + * TODO docs + * Valid for just BOOL + */ + public boolean booleanValue() { + if (code == BOOL) { + requireNonNull(boolValue, "bool value"); + return boolValue; + } + throw new UnsupportedOperationException(); + } + + /** + * TODO docs + * Valid for just APPROX_NUM, EXACT_NUM, and INT_NUM. + */ + @NotNull + public String numberValue() { + switch (code) { + case APPROX_NUM: + case EXACT_NUM: + case INT_NUM: + requireNonNull(stringValue, "string value for numerics"); + return stringValue; + default: + throw new UnsupportedOperationException(); + } + } + + /** + * TODO docs + * Valid for just EXACT_NUM and INT_NUM + */ + @NotNull + public BigDecimal bigDecimalValue() { + switch (code) { + case EXACT_NUM: + case INT_NUM: + requireNonNull(stringValue, "string value for exact and int numerics"); + return new BigDecimal(stringValue); + default: + throw new UnsupportedOperationException(); + } + } + + /** + * TODO docs + * Valid for just STRING and TYPED_STRING + */ + @NotNull + public String stringValue() { + switch (code) { + case STRING: + case TYPED_STRING: + requireNonNull(stringValue, "string value"); + return stringValue; + default: + throw new UnsupportedOperationException(); + } + } + + /** + * TODO docs + * Valid for just TYPED_STRING + */ + @NotNull + public DataType dataType() { + if (code == TYPED_STRING) { + requireNonNull(dataType, "data type"); + return dataType; + } + throw new UnsupportedOperationException(); + } +} diff --git a/partiql-ast/src/main/java/org/partiql/ast/expr/ExprLit.java b/partiql-ast/src/main/java/org/partiql/ast/expr/ExprLit.java index 30fc67c28..2d21d072c 100644 --- a/partiql-ast/src/main/java/org/partiql/ast/expr/ExprLit.java +++ b/partiql-ast/src/main/java/org/partiql/ast/expr/ExprLit.java @@ -4,7 +4,7 @@ import org.jetbrains.annotations.NotNull; import org.partiql.ast.AstNode; import org.partiql.ast.AstVisitor; -import org.partiql.ast.literal.Literal; +import org.partiql.ast.Literal; import java.util.ArrayList; import java.util.Collection; diff --git a/partiql-ast/src/main/java/org/partiql/ast/literal/Literal.java b/partiql-ast/src/main/java/org/partiql/ast/literal/Literal.java deleted file mode 100644 index d1e96ceb0..000000000 --- a/partiql-ast/src/main/java/org/partiql/ast/literal/Literal.java +++ /dev/null @@ -1,125 +0,0 @@ -package org.partiql.ast.literal; - -import org.jetbrains.annotations.NotNull; -import org.partiql.ast.AstNode; -import org.partiql.ast.AstVisitor; -import org.partiql.ast.DataType; - -import java.math.BigDecimal; -import java.math.BigInteger; -import java.util.Collection; -import java.util.Collections; - -public abstract class Literal extends AstNode { - @NotNull - public abstract LiteralKind kind(); - - @Override - @NotNull - public Collection children() { - return Collections.emptyList(); - } - - @Override - public R accept(@NotNull AstVisitor visitor, C ctx) { - return visitor.visitLiteral(this, ctx); - } - - // Factory methods - public static Literal litApprox(@NotNull String value) { - return new LiteralApprox(value); - } - - public static Literal litBool(boolean value) { - return new LiteralBool(value); - } - - public static Literal litExact(@NotNull BigDecimal value) { - if (value.scale() == 0) { - return new LiteralExact(value + "."); - } else { - return new LiteralExact(value.toString()); - } - } - - public static Literal litExact(@NotNull String value) { - return new LiteralExact(value); - } - - public static Literal litInt(int value) { - return new LiteralInt(Integer.toString(value)); - } - - public static Literal litInt(long value) { - return new LiteralInt(Long.toString(value)); - } - - public static Literal litInt(@NotNull BigInteger value) { - return new LiteralInt(value.toString()); - } - - public static Literal litInt(@NotNull String value) { - return new LiteralInt(value); - } - - public static Literal litNull() { - return new LiteralNull(); - } - - public static Literal litMissing() { - return new LiteralMissing(); - } - - public static Literal litString(@NotNull String value) { - return new LiteralString(value); - } - - public static Literal litTypedString(@NotNull DataType type, @NotNull String value) { - return new LiteralTypedString(type, value); - } - - // Value extraction - /** - * TODO docs - * Valid for just LiteralBool - */ - public boolean booleanValue() { - throw new UnsupportedOperationException(); - } - - /** - * TODO docs - * Valid for just LiteralApprox, LiteralInt, and LiteralExact - */ - @NotNull - public String numberValue() { - throw new UnsupportedOperationException(); - } - - /** - * TODO docs - * Valid for just LiteralInt and LiteralExact - */ - @NotNull - public BigDecimal bigDecimalValue() { - throw new UnsupportedOperationException(); - } - - /** - * TODO docs - * Valid for just LiteralString and LiteralTypedString - */ - @NotNull - public String stringValue() { - throw new UnsupportedOperationException(); - } - - /** - * TODO docs - * Valid for just LiteralTypedString - */ - @NotNull - public DataType dataType() { - throw new UnsupportedOperationException(); - } -} diff --git a/partiql-ast/src/main/java/org/partiql/ast/literal/LiteralApprox.java b/partiql-ast/src/main/java/org/partiql/ast/literal/LiteralApprox.java deleted file mode 100644 index cdaf43e21..000000000 --- a/partiql-ast/src/main/java/org/partiql/ast/literal/LiteralApprox.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.partiql.ast.literal; - -import lombok.EqualsAndHashCode; -import org.jetbrains.annotations.NotNull; - -@EqualsAndHashCode(callSuper = false) -class LiteralApprox extends Literal { - @NotNull - String value; - - LiteralApprox(@NotNull String value) { - this.value = value; - } - - @NotNull - @Override - public String numberValue() { - return value; - } - - @NotNull - @Override - public LiteralKind kind() { - return LiteralKind.NUM_APPROX(); - } -} diff --git a/partiql-ast/src/main/java/org/partiql/ast/literal/LiteralBool.java b/partiql-ast/src/main/java/org/partiql/ast/literal/LiteralBool.java deleted file mode 100644 index 49a744c57..000000000 --- a/partiql-ast/src/main/java/org/partiql/ast/literal/LiteralBool.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.partiql.ast.literal; - -import lombok.EqualsAndHashCode; -import org.jetbrains.annotations.NotNull; - -@EqualsAndHashCode(callSuper = false) -class LiteralBool extends Literal { - private final boolean value; - - LiteralBool(boolean value) { - this.value = value; - } - - @Override - public boolean booleanValue() { - return value; - } - - @NotNull - @Override - public LiteralKind kind() { - return LiteralKind.BOOLEAN(); - } -} diff --git a/partiql-ast/src/main/java/org/partiql/ast/literal/LiteralExact.java b/partiql-ast/src/main/java/org/partiql/ast/literal/LiteralExact.java deleted file mode 100644 index faa421d9e..000000000 --- a/partiql-ast/src/main/java/org/partiql/ast/literal/LiteralExact.java +++ /dev/null @@ -1,40 +0,0 @@ -package org.partiql.ast.literal; - -import lombok.EqualsAndHashCode; -import org.jetbrains.annotations.NotNull; - -import java.math.BigDecimal; -import java.math.MathContext; -import java.math.RoundingMode; - -/** - * TODO docs - * Differs from LiteralInt in that it will always include a decimal point. - */ -@EqualsAndHashCode(callSuper = false) -class LiteralExact extends Literal { - @NotNull - String value; - - LiteralExact(@NotNull String value) { - this.value = value; - } - - @NotNull - @Override - public String numberValue() { - return value; - } - - @NotNull - @Override - public BigDecimal bigDecimalValue() { - return new BigDecimal(value, new MathContext(38, RoundingMode.HALF_EVEN)); - } - - @NotNull - @Override - public LiteralKind kind() { - return LiteralKind.NUM_EXACT(); - } -} diff --git a/partiql-ast/src/main/java/org/partiql/ast/literal/LiteralInt.java b/partiql-ast/src/main/java/org/partiql/ast/literal/LiteralInt.java deleted file mode 100644 index 94bf83a4d..000000000 --- a/partiql-ast/src/main/java/org/partiql/ast/literal/LiteralInt.java +++ /dev/null @@ -1,37 +0,0 @@ -package org.partiql.ast.literal; - -import lombok.EqualsAndHashCode; -import org.jetbrains.annotations.NotNull; - -import java.math.BigDecimal; - -/** - * TODO docs - */ -@EqualsAndHashCode(callSuper = false) -class LiteralInt extends Literal { - @NotNull - String value; - - LiteralInt(@NotNull String value) { - this.value = value; - } - - @NotNull - @Override - public BigDecimal bigDecimalValue() { - return new BigDecimal(value); - } - - @NotNull - @Override - public String numberValue() { - return value; - } - - @NotNull - @Override - public LiteralKind kind() { - return LiteralKind.NUM_INT(); - } -} diff --git a/partiql-ast/src/main/java/org/partiql/ast/literal/LiteralKind.java b/partiql-ast/src/main/java/org/partiql/ast/literal/LiteralKind.java deleted file mode 100644 index e8d64765e..000000000 --- a/partiql-ast/src/main/java/org/partiql/ast/literal/LiteralKind.java +++ /dev/null @@ -1,63 +0,0 @@ -package org.partiql.ast.literal; - -import lombok.EqualsAndHashCode; - -// TODO convert to an enum -@EqualsAndHashCode(callSuper = false) -public class LiteralKind { - public static final int UNKNOWN = 0; - public static final int NULL = 1; - public static final int MISSING = 2; - public static final int BOOLEAN = 3; - public static final int NUM_APPROX = 4; - public static final int NUM_EXACT = 5; - public static final int NUM_INT = 6; - public static final int STRING = 7; - public static final int TYPED_STRING = 8; - - public static LiteralKind UNKNOWN() { - return new LiteralKind(UNKNOWN); - } - - public static LiteralKind NULL() { - return new LiteralKind(NULL); - } - - public static LiteralKind MISSING() { - return new LiteralKind(MISSING); - } - - public static LiteralKind BOOLEAN() { - return new LiteralKind(BOOLEAN); - } - - public static LiteralKind NUM_APPROX() { - return new LiteralKind(NUM_APPROX); - } - - public static LiteralKind NUM_EXACT() { - return new LiteralKind(NUM_EXACT); - } - - public static LiteralKind NUM_INT() { - return new LiteralKind(NUM_INT); - } - - public static LiteralKind STRING() { - return new LiteralKind(STRING); - } - - public static LiteralKind TYPED_STRING() { - return new LiteralKind(TYPED_STRING); - } - - private final int code; - - private LiteralKind(int code) { - this.code = code; - } - - public int code() { - return code; - } -} diff --git a/partiql-ast/src/main/java/org/partiql/ast/literal/LiteralMissing.java b/partiql-ast/src/main/java/org/partiql/ast/literal/LiteralMissing.java deleted file mode 100644 index e6e27da5e..000000000 --- a/partiql-ast/src/main/java/org/partiql/ast/literal/LiteralMissing.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.partiql.ast.literal; - -import lombok.EqualsAndHashCode; -import org.jetbrains.annotations.NotNull; - -@EqualsAndHashCode(callSuper = false) -class LiteralMissing extends Literal { - @NotNull - @Override - public LiteralKind kind() { - return LiteralKind.MISSING(); - } -} diff --git a/partiql-ast/src/main/java/org/partiql/ast/literal/LiteralNull.java b/partiql-ast/src/main/java/org/partiql/ast/literal/LiteralNull.java deleted file mode 100644 index b3fdb38a3..000000000 --- a/partiql-ast/src/main/java/org/partiql/ast/literal/LiteralNull.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.partiql.ast.literal; - -import lombok.EqualsAndHashCode; -import org.jetbrains.annotations.NotNull; - -@EqualsAndHashCode(callSuper = false) -class LiteralNull extends Literal { - @NotNull - @Override - public LiteralKind kind() { - return LiteralKind.NULL(); - } -} diff --git a/partiql-ast/src/main/java/org/partiql/ast/literal/LiteralString.java b/partiql-ast/src/main/java/org/partiql/ast/literal/LiteralString.java deleted file mode 100644 index 609c74215..000000000 --- a/partiql-ast/src/main/java/org/partiql/ast/literal/LiteralString.java +++ /dev/null @@ -1,29 +0,0 @@ -package org.partiql.ast.literal; - -import lombok.EqualsAndHashCode; -import org.jetbrains.annotations.NotNull; - -/** - * TODO docs - */ -@EqualsAndHashCode(callSuper = false) -class LiteralString extends Literal { - @NotNull - String value; - - LiteralString(@NotNull String value) { - this.value = value; - } - - @NotNull - @Override - public String stringValue() { - return value; - } - - @NotNull - @Override - public LiteralKind kind() { - return LiteralKind.STRING(); - } -} diff --git a/partiql-ast/src/main/java/org/partiql/ast/literal/LiteralTypedString.java b/partiql-ast/src/main/java/org/partiql/ast/literal/LiteralTypedString.java deleted file mode 100644 index c8fa8ca94..000000000 --- a/partiql-ast/src/main/java/org/partiql/ast/literal/LiteralTypedString.java +++ /dev/null @@ -1,37 +0,0 @@ -package org.partiql.ast.literal; - -import lombok.EqualsAndHashCode; -import org.jetbrains.annotations.NotNull; -import org.partiql.ast.DataType; - -@EqualsAndHashCode(callSuper = false) -class LiteralTypedString extends Literal { - @NotNull - private final DataType type; - - @NotNull - private final String value; - - LiteralTypedString(@NotNull DataType type, @NotNull String value) { - this.type = type; - this.value = value; - } - - @NotNull - @Override - public DataType dataType() { - return type; - } - - @NotNull - @Override - public String stringValue() { - return value; - } - - @NotNull - @Override - public LiteralKind kind() { - return LiteralKind.TYPED_STRING(); - } -} diff --git a/partiql-ast/src/main/java/org/partiql/ast/sql/SqlDialect.kt b/partiql-ast/src/main/java/org/partiql/ast/sql/SqlDialect.kt index 6c96a13c4..78107c1f7 100644 --- a/partiql-ast/src/main/java/org/partiql/ast/sql/SqlDialect.kt +++ b/partiql-ast/src/main/java/org/partiql/ast/sql/SqlDialect.kt @@ -33,6 +33,7 @@ import org.partiql.ast.Identifier import org.partiql.ast.IdentifierChain import org.partiql.ast.JoinType import org.partiql.ast.Let +import org.partiql.ast.Literal import org.partiql.ast.Nulls import org.partiql.ast.Order import org.partiql.ast.OrderBy @@ -81,7 +82,6 @@ import org.partiql.ast.expr.ExprVarRef import org.partiql.ast.expr.ExprVariant import org.partiql.ast.expr.PathStep import org.partiql.ast.expr.Scope -import org.partiql.ast.literal.LiteralKind /** * SqlDialect represents the base behavior for transforming an [AstNode] tree into a [SqlBlock] tree. @@ -227,19 +227,17 @@ public abstract class SqlDialect : AstVisitor() { override fun visitExprLit(node: ExprLit, tail: SqlBlock): SqlBlock { val lit = node.lit var t = tail - val litText = when (lit.kind().code()) { - LiteralKind.NULL -> "NULL" - LiteralKind.MISSING -> "MISSING" - LiteralKind.BOOLEAN -> lit.booleanValue().toString() - LiteralKind.NUM_APPROX -> lit.numberValue() - LiteralKind.NUM_EXACT -> lit.numberValue() - LiteralKind.NUM_INT -> lit.numberValue() - LiteralKind.STRING -> String.format("'%s'", lit.stringValue()) - LiteralKind.TYPED_STRING -> { + val litText = when (lit.code()) { + Literal.NULL -> "NULL" + Literal.MISSING -> "MISSING" + Literal.BOOL -> lit.booleanValue().toString() + Literal.APPROX_NUM, Literal.EXACT_NUM, Literal.INT_NUM -> lit.numberValue() + Literal.STRING -> String.format("'%s'", lit.stringValue()) + Literal.TYPED_STRING -> { t = visitDataType(lit.dataType(), t) String.format(" '%s'", lit.stringValue()) } - else -> error("Unsupported literal kind ${lit.kind()}") + else -> error("Unsupported literal type $lit") } return t concat litText } diff --git a/partiql-ast/src/main/kotlin/org/partiql/ast/Ast.kt b/partiql-ast/src/main/kotlin/org/partiql/ast/Ast.kt index e9dd69e44..e05dfaefe 100644 --- a/partiql-ast/src/main/kotlin/org/partiql/ast/Ast.kt +++ b/partiql-ast/src/main/kotlin/org/partiql/ast/Ast.kt @@ -53,7 +53,6 @@ import org.partiql.ast.graph.GraphPattern import org.partiql.ast.graph.GraphQuantifier import org.partiql.ast.graph.GraphRestrictor import org.partiql.ast.graph.GraphSelector -import org.partiql.ast.literal.Literal // TODO docs for all factory methods // Also consider defaults for nullable. Need to look more into backwards compatibility. diff --git a/partiql-ast/src/main/kotlin/org/partiql/ast/AstRewriter.kt b/partiql-ast/src/main/kotlin/org/partiql/ast/AstRewriter.kt index a6a74c6a9..8a05cdfdb 100644 --- a/partiql-ast/src/main/kotlin/org/partiql/ast/AstRewriter.kt +++ b/partiql-ast/src/main/kotlin/org/partiql/ast/AstRewriter.kt @@ -43,7 +43,6 @@ import org.partiql.ast.graph.GraphMatch import org.partiql.ast.graph.GraphPattern import org.partiql.ast.graph.GraphQuantifier import org.partiql.ast.graph.GraphSelector -import org.partiql.ast.literal.Literal // TODO docs public abstract class AstRewriter : AstVisitor() { diff --git a/partiql-ast/src/test/kotlin/org/partiql/ast/sql/SqlDialectTest.kt b/partiql-ast/src/test/kotlin/org/partiql/ast/sql/SqlDialectTest.kt index b02081fd5..62718ea35 100644 --- a/partiql-ast/src/test/kotlin/org/partiql/ast/sql/SqlDialectTest.kt +++ b/partiql-ast/src/test/kotlin/org/partiql/ast/sql/SqlDialectTest.kt @@ -84,6 +84,14 @@ import org.partiql.ast.Identifier import org.partiql.ast.IdentifierChain import org.partiql.ast.JoinType import org.partiql.ast.Let +import org.partiql.ast.Literal.approxNum +import org.partiql.ast.Literal.bool +import org.partiql.ast.Literal.exactNum +import org.partiql.ast.Literal.intNum +import org.partiql.ast.Literal.missing +import org.partiql.ast.Literal.nul +import org.partiql.ast.Literal.string +import org.partiql.ast.Literal.typedString import org.partiql.ast.Nulls import org.partiql.ast.Order import org.partiql.ast.OrderBy @@ -94,14 +102,6 @@ import org.partiql.ast.SetQuantifier import org.partiql.ast.expr.Expr import org.partiql.ast.expr.Scope import org.partiql.ast.expr.TrimSpec -import org.partiql.ast.literal.Literal.litApprox -import org.partiql.ast.literal.Literal.litBool -import org.partiql.ast.literal.Literal.litExact -import org.partiql.ast.literal.Literal.litInt -import org.partiql.ast.literal.Literal.litMissing -import org.partiql.ast.literal.Literal.litNull -import org.partiql.ast.literal.Literal.litString -import org.partiql.ast.literal.Literal.litTypedString import java.math.BigDecimal import kotlin.test.assertFails @@ -232,7 +232,7 @@ class SqlDialectTest { companion object { - private val NULL = exprLit(litNull()) + private val NULL = exprLit(nul()) @JvmStatic fun types() = listOf( @@ -405,49 +405,49 @@ class SqlDialectTest { @JvmStatic fun exprLitCases() = listOf( expect( - "NULL", exprLit(litNull()) + "NULL", exprLit(nul()) ), expect( - "MISSING", exprLit(litMissing()) + "MISSING", exprLit(missing()) ), expect( - "true", exprLit(litBool(true)) + "true", exprLit(bool(true)) ), expect( - "1", exprLit(litInt(1)) + "1", exprLit(intNum(1)) ), expect( - "2", exprLit(litInt(2)) + "2", exprLit(intNum(2)) ), expect( - "3", exprLit(litInt(3)) + "3", exprLit(intNum(3)) ), expect( - "4", exprLit(litInt(4)) + "4", exprLit(intNum(4)) ), expect( - "5.", exprLit(litExact("5.")) + "5.", exprLit(exactNum("5.")) ), - expect("1.1e0", exprLit(litApprox("1.1e0"))), - expect("1.2E0", exprLit(litApprox("1.2E0"))), - expect("1.2345E-5", exprLit(litApprox("1.2345E-5"))), + expect("1.1e0", exprLit(approxNum("1.1e0"))), + expect("1.2E0", exprLit(approxNum("1.2E0"))), + expect("1.2345E-5", exprLit(approxNum("1.2345E-5"))), expect( - "1.3", exprLit(litExact(BigDecimal.valueOf(1.3))) + "1.3", exprLit(exactNum(BigDecimal.valueOf(1.3))) ), expect( - """'hello'""", exprLit(litString("hello")) + """'hello'""", exprLit(string("hello")) ), expect( """hello""", id("hello") ), expect( - "DATE '0001-02-03'", exprLit(litTypedString(DataType.DATE(), "0001-02-03")) + "DATE '0001-02-03'", exprLit(typedString(DataType.DATE(), "0001-02-03")) ), expect( - "TIME '01:02:03.456-00:30'", exprLit(litTypedString(DataType.TIME(), "01:02:03.456-00:30")) + "TIME '01:02:03.456-00:30'", exprLit(typedString(DataType.TIME(), "01:02:03.456-00:30")) ), expect( - "TIMESTAMP '0001-02-03 04:05:06.78-00:30'", exprLit(litTypedString(DataType.TIMESTAMP(), "0001-02-03 04:05:06.78-00:30")) + "TIMESTAMP '0001-02-03 04:05:06.78-00:30'", exprLit(typedString(DataType.TIMESTAMP(), "0001-02-03 04:05:06.78-00:30")) ), // expect("""{{ '''Hello''' '''World''' }}""") { @@ -680,7 +680,7 @@ class SqlDialectTest { next = exprPathStepElement( element = exprOperator( symbol = "+", - lhs = exprLit(litInt(1)), + lhs = exprLit(intNum(1)), rhs = exprVarRef( identifierChain = idChain(id("a")), scope = Scope.DEFAULT() @@ -697,7 +697,7 @@ class SqlDialectTest { identifierChain = idChain(id("x")), scope = Scope.DEFAULT() ), - next = exprPathStepElement(exprLit(litString("y")), next = null) + next = exprPathStepElement(exprLit(string("y")), next = null) ) ), ) @@ -708,7 +708,7 @@ class SqlDialectTest { "foo(1)", exprCall( function = idChain(id("foo")), - args = listOf(exprLit(litInt(1))), + args = listOf(exprLit(intNum(1))), setq = null ) ), @@ -717,8 +717,8 @@ class SqlDialectTest { exprCall( function = idChain(id("foo")), args = listOf( - exprLit(litInt(1)), - exprLit(litInt(2)), + exprLit(intNum(1)), + exprLit(intNum(2)), ), setq = null ) @@ -730,7 +730,7 @@ class SqlDialectTest { root = id("foo"), next = idChain(id("bar")) ), - args = listOf(exprLit(litInt(1))), + args = listOf(exprLit(intNum(1))), setq = null ) ), @@ -742,8 +742,8 @@ class SqlDialectTest { next = idChain(id("bar")) ), args = listOf( - exprLit(litInt(1)), - exprLit(litInt(2)) + exprLit(intNum(1)), + exprLit(intNum(2)) ), setq = null ) @@ -829,9 +829,9 @@ class SqlDialectTest { "<<1, 2, 3>>", exprBag( values = listOf( - exprLit(litInt(1)), - exprLit(litInt(2)), - exprLit(litInt(3)) + exprLit(intNum(1)), + exprLit(intNum(2)), + exprLit(intNum(3)) ) ) ), @@ -843,9 +843,9 @@ class SqlDialectTest { "[1, 2, 3]", exprArray( values = listOf( - exprLit(litInt(1)), - exprLit(litInt(2)), - exprLit(litInt(3)) + exprLit(intNum(1)), + exprLit(intNum(2)), + exprLit(intNum(3)) ) ) ), @@ -865,9 +865,9 @@ class SqlDialectTest { rows = listOf( exprRowValue( values = listOf( - exprLit(litInt(1)), - exprLit(litInt(2)), - exprLit(litInt(3)) + exprLit(intNum(1)), + exprLit(intNum(2)), + exprLit(intNum(3)) ) ) ) @@ -883,9 +883,9 @@ class SqlDialectTest { "(1, 2, 3)", exprRowValue( values = listOf( - exprLit(litInt(1)), - exprLit(litInt(2)), - exprLit(litInt(3)) + exprLit(intNum(1)), + exprLit(intNum(2)), + exprLit(intNum(3)) ) ) ), @@ -916,7 +916,7 @@ class SqlDialectTest { fields = listOf( exprStructField( name = v("a"), - value = exprLit(litInt(1)) + value = exprLit(intNum(1)) ) ) ) @@ -927,11 +927,11 @@ class SqlDialectTest { fields = listOf( exprStructField( name = v("a"), - value = exprLit(litInt(1)) + value = exprLit(intNum(1)) ), exprStructField( name = v("b"), - value = exprLit(litBool(false)) + value = exprLit(bool(false)) ) ) ) @@ -1138,7 +1138,7 @@ class SqlDialectTest { exprCall( function = idChain(id("DATE_ADD")), args = listOf( - exprLit(litString("MINUTE")), + exprLit(string("MINUTE")), v("x"), v("y") ), @@ -1150,7 +1150,7 @@ class SqlDialectTest { exprCall( function = idChain(id("DATE_DIFF")), args = listOf( - exprLit(litString("MINUTE")), + exprLit(string("MINUTE")), v("x"), v("y") ), @@ -1947,7 +1947,7 @@ class SqlDialectTest { select = select("a"), from = table("T") ), - limit = exprLit(litInt(1)) + limit = exprLit(intNum(1)) ) ), expect( @@ -1957,7 +1957,7 @@ class SqlDialectTest { select = select("a"), from = table("T") ), - offset = exprLit(litInt(2)) + offset = exprLit(intNum(2)) ) ), expect( @@ -1967,8 +1967,8 @@ class SqlDialectTest { select = select("a"), from = table("T") ), - limit = exprLit(litInt(1)), - offset = exprLit(litInt(2)) + limit = exprLit(intNum(1)), + offset = exprLit(intNum(2)) ) ), expect( @@ -2389,7 +2389,7 @@ class SqlDialectTest { ) ) ), - limit = exprLit(litInt(1)) // LIMIT associated with SQL set op + limit = exprLit(intNum(1)) // LIMIT associated with SQL set op ) ), expect( @@ -2409,7 +2409,7 @@ class SqlDialectTest { select = select("b"), from = table("S"), ), - limit = exprLit(litInt(1)) // LIMIT associated with rhs SFW query + limit = exprLit(intNum(1)) // LIMIT associated with rhs SFW query ) ) ) @@ -2537,7 +2537,7 @@ class SqlDialectTest { "1 = (SELECT a FROM T)", exprOperator( symbol = "=", - lhs = exprLit(litInt(1)), + lhs = exprLit(intNum(1)), rhs = qSet( body = sfw( select = select("a"), @@ -2552,8 +2552,8 @@ class SqlDialectTest { symbol = "=", lhs = exprRowValue( values = listOf( - exprLit(litInt(1)), - exprLit(litInt(2)) + exprLit(intNum(1)), + exprLit(intNum(2)) ) ), rhs = qSet( diff --git a/partiql-parser/src/main/kotlin/org/partiql/parser/internal/PartiQLParserDefault.kt b/partiql-parser/src/main/kotlin/org/partiql/parser/internal/PartiQLParserDefault.kt index 5a45a2fc2..6d551db5c 100644 --- a/partiql-parser/src/main/kotlin/org/partiql/parser/internal/PartiQLParserDefault.kt +++ b/partiql-parser/src/main/kotlin/org/partiql/parser/internal/PartiQLParserDefault.kt @@ -134,6 +134,14 @@ import org.partiql.ast.Identifier import org.partiql.ast.IdentifierChain import org.partiql.ast.JoinType import org.partiql.ast.Let +import org.partiql.ast.Literal.approxNum +import org.partiql.ast.Literal.bool +import org.partiql.ast.Literal.exactNum +import org.partiql.ast.Literal.intNum +import org.partiql.ast.Literal.missing +import org.partiql.ast.Literal.nul +import org.partiql.ast.Literal.string +import org.partiql.ast.Literal.typedString import org.partiql.ast.Nulls import org.partiql.ast.Order import org.partiql.ast.Select @@ -164,14 +172,6 @@ import org.partiql.ast.graph.GraphPattern import org.partiql.ast.graph.GraphQuantifier import org.partiql.ast.graph.GraphRestrictor import org.partiql.ast.graph.GraphSelector -import org.partiql.ast.literal.Literal.litApprox -import org.partiql.ast.literal.Literal.litBool -import org.partiql.ast.literal.Literal.litExact -import org.partiql.ast.literal.Literal.litInt -import org.partiql.ast.literal.Literal.litMissing -import org.partiql.ast.literal.Literal.litNull -import org.partiql.ast.literal.Literal.litString -import org.partiql.ast.literal.Literal.litTypedString import org.partiql.parser.PartiQLLexerException import org.partiql.parser.PartiQLParser import org.partiql.parser.PartiQLParserException @@ -218,7 +218,7 @@ internal class PartiQLParserDefault : PartiQLParser { ctx.errorListener.report(error) val locations = SourceLocations() return PartiQLParser.Result( - mutableListOf(org.partiql.ast.Query(exprLit(litNull()))) as List, + mutableListOf(org.partiql.ast.Query(exprLit(nul()))) as List, locations ) } @@ -412,6 +412,8 @@ internal class PartiQLParserDefault : PartiQLParser { internal val DATE_PATTERN_REGEX = Regex("\\d\\d\\d\\d-\\d\\d-\\d\\d") internal val GENERIC_TIME_REGEX = Regex("\\d\\d:\\d\\d:\\d\\d(\\.\\d*)?([+|-]\\d\\d:\\d\\d)?") + + internal val GENERIC_TIMESTAMP_REGEX = Regex("\\d\\d\\d\\d-\\d\\d-\\d\\d\\s\\d\\d:\\d\\d:\\d\\d(\\.\\d*)?([+|-]\\d\\d:\\d\\d)?") } /** @@ -461,8 +463,8 @@ internal class PartiQLParserDefault : PartiQLParser { } explain( options = mapOf( - "type" to (type?.let { litString(it) } ?: litNull()), - "format" to (format?.let { litString(it) } ?: litNull()) + "type" to (type?.let { string(it) } ?: nul()), + "format" to (format?.let { string(it) } ?: nul()) ), statement = visit(ctx.statement()) as Statement, ) @@ -1862,11 +1864,11 @@ internal class PartiQLParserDefault : PartiQLParser { } override fun visitLiteralDecimal(ctx: GeneratedParser.LiteralDecimalContext) = translate(ctx) { - exprLit(litExact(ctx.text)) + exprLit(exactNum(ctx.text)) } override fun visitLiteralFloat(ctx: GeneratedParser.LiteralFloatContext) = translate(ctx) { - exprLit(litApprox(ctx.text)) + exprLit(approxNum(ctx.text)) } override fun visitArray(ctx: GeneratedParser.ArrayContext) = translate(ctx) { @@ -1875,19 +1877,19 @@ internal class PartiQLParserDefault : PartiQLParser { } override fun visitLiteralNull(ctx: GeneratedParser.LiteralNullContext) = translate(ctx) { - exprLit(litNull()) + exprLit(nul()) } override fun visitLiteralMissing(ctx: GeneratedParser.LiteralMissingContext) = translate(ctx) { - exprLit(litMissing()) + exprLit(missing()) } override fun visitLiteralTrue(ctx: GeneratedParser.LiteralTrueContext) = translate(ctx) { - exprLit(litBool(true)) + exprLit(bool(true)) } override fun visitLiteralFalse(ctx: GeneratedParser.LiteralFalseContext) = translate(ctx) { - exprLit(litBool(false)) + exprLit(bool(false)) } override fun visitLiteralIon(ctx: GeneratedParser.LiteralIonContext) = translate(ctx) { @@ -1898,12 +1900,12 @@ internal class PartiQLParserDefault : PartiQLParser { override fun visitLiteralString(ctx: GeneratedParser.LiteralStringContext) = translate(ctx) { val value = ctx.LITERAL_STRING().getStringValue() - exprLit(litString(value)) + exprLit(string(value)) } override fun visitLiteralInteger(ctx: GeneratedParser.LiteralIntegerContext) = translate(ctx) { val n = ctx.LITERAL_INTEGER().text - exprLit(litInt(n)) + exprLit(intNum(n)) } override fun visitLiteralDate(ctx: GeneratedParser.LiteralDateContext) = translate(ctx) { @@ -1912,11 +1914,20 @@ internal class PartiQLParserDefault : PartiQLParser { if (DATE_PATTERN_REGEX.matches(dateString).not()) { throw error(pattern, "Expected DATE string to be of the format yyyy-MM-dd") } - exprLit(litTypedString(DataType.DATE(), dateString)) + exprLit(typedString(DataType.DATE(), dateString)) } override fun visitLiteralTime(ctx: GeneratedParser.LiteralTimeContext) = translate(ctx) { - val (timeString, precision) = getTimeStringAndPrecision(ctx.LITERAL_STRING(), ctx.LITERAL_INTEGER()) + val pattern = ctx.LITERAL_STRING().symbol + val timeString = ctx.LITERAL_STRING().getStringValue() + if (GENERIC_TIME_REGEX.matches(timeString).not()) { + throw error(pattern, "Expected TIME string to be of the format HH:mm:ss[.SSS]") + } + val precision = ctx.LITERAL_INTEGER()?.let { + val p = it.text.toBigInteger().toInt() + if (p < 0 || 9 < p) throw error(it.symbol, "Precision out of bounds") + p + } val type = when (ctx.ZONE()) { null -> { if (precision == null) { @@ -1933,11 +1944,20 @@ internal class PartiQLParserDefault : PartiQLParser { } } } - exprLit(litTypedString(type, timeString)) + exprLit(typedString(type, timeString)) } override fun visitLiteralTimestamp(ctx: GeneratedParser.LiteralTimestampContext) = translate(ctx) { - val (timestampString, precision) = getTimeStringAndPrecision(ctx.LITERAL_STRING(), ctx.LITERAL_INTEGER()) + val pattern = ctx.LITERAL_STRING().symbol + val timestampString = ctx.LITERAL_STRING().getStringValue() + if (GENERIC_TIMESTAMP_REGEX.matches(timestampString).not()) { + throw error(pattern, "Expected TIMESTAMP string to be of the format yyyy-MM-dd HH:mm:ss[.SSS]") + } + val precision = ctx.LITERAL_INTEGER()?.let { + val p = it.text.toBigInteger().toInt() + if (p < 0 || 9 < p) throw error(it.symbol, "Precision out of bounds") + p + } val type = when (ctx.ZONE()) { null -> { if (precision == null) { @@ -1954,7 +1974,7 @@ internal class PartiQLParserDefault : PartiQLParser { } } } - exprLit(litTypedString(type, timestampString)) + exprLit(typedString(type, timestampString)) } override fun visitTuple(ctx: GeneratedParser.TupleContext) = translate(ctx) { @@ -2172,41 +2192,6 @@ internal class PartiQLParserDefault : PartiQLParser { else -> throw error(ctx, "Expected set quantifier ALL or DISTINCT") } - /** - * With the and nodes of a literal time expression, returns the parsed string and precision. - * TIME ()? (WITH TIME ZONE)? - */ - private fun getTimeStringAndPrecision( - stringNode: TerminalNode, - integerNode: TerminalNode?, - ): Pair { - val timeString = stringNode.getStringValue() - val precision = when (integerNode) { - null -> { - try { - getPrecisionFromTimeString(timeString) - } catch (e: Exception) { - throw error(stringNode.symbol, "Unable to parse precision.", e) - } - } - else -> { - val p = integerNode.text.toBigInteger().toInt() - if (p < 0 || 9 < p) throw error(integerNode.symbol, "Precision out of bounds") - p - } - } - return timeString to precision - } - - private fun getPrecisionFromTimeString(timeString: String): Int { - val matcher = GENERIC_TIME_REGEX.toPattern().matcher(timeString) - if (!matcher.find()) { - throw IllegalArgumentException("Time string does not match the format 'HH:MM:SS[.ddd....][+|-HH:MM]'") - } - val fraction = matcher.group(1)?.removePrefix(".") - return fraction?.length ?: 0 - } - /** * Converts a Path expression into a Projection Item (either ALL or EXPR). Note: A Projection Item only allows a * subset of a typical Path expressions. See the following examples. diff --git a/partiql-parser/src/test/kotlin/org/partiql/parser/internal/PartiQLParserBagOpTests.kt b/partiql-parser/src/test/kotlin/org/partiql/parser/internal/PartiQLParserBagOpTests.kt index df6bd2948..9b67e6d25 100644 --- a/partiql-parser/src/test/kotlin/org/partiql/parser/internal/PartiQLParserBagOpTests.kt +++ b/partiql-parser/src/test/kotlin/org/partiql/parser/internal/PartiQLParserBagOpTests.kt @@ -15,12 +15,12 @@ import org.partiql.ast.Ast.selectStar import org.partiql.ast.Ast.setOp import org.partiql.ast.AstNode import org.partiql.ast.FromType +import org.partiql.ast.Literal.intNum +import org.partiql.ast.Literal.string import org.partiql.ast.SetOpType import org.partiql.ast.SetQuantifier import org.partiql.ast.expr.Expr import org.partiql.ast.expr.ExprQuerySet -import org.partiql.ast.literal.Literal.litInt -import org.partiql.ast.literal.Literal.litString import kotlin.test.assertEquals class PartiQLParserBagOpTests { @@ -41,8 +41,8 @@ class PartiQLParserBagOpTests { exprStruct( fields = mutableListOf( exprStructField( - name = exprLit(litString("a")), - value = exprLit(litInt(i)) + name = exprLit(string("a")), + value = exprLit(intNum(i)) ) ) ) @@ -65,7 +65,7 @@ class PartiQLParserBagOpTests { offset = null ) - private fun createLit(i: Int) = exprLit(litInt(i)) + private fun createLit(i: Int) = exprLit(intNum(i)) // SQL Union @Test diff --git a/partiql-parser/src/test/kotlin/org/partiql/parser/internal/PartiQLParserDDLTests.kt b/partiql-parser/src/test/kotlin/org/partiql/parser/internal/PartiQLParserDDLTests.kt index 65a1bc0a0..4999e5b88 100644 --- a/partiql-parser/src/test/kotlin/org/partiql/parser/internal/PartiQLParserDDLTests.kt +++ b/partiql-parser/src/test/kotlin/org/partiql/parser/internal/PartiQLParserDDLTests.kt @@ -20,8 +20,8 @@ import org.partiql.ast.Ast.partitionBy import org.partiql.ast.Ast.tableConstraintUnique import org.partiql.ast.AstNode import org.partiql.ast.DataType +import org.partiql.ast.Literal.intNum import org.partiql.ast.expr.Scope -import org.partiql.ast.literal.Literal.litInt import org.partiql.value.PartiQLValueExperimental import java.util.stream.Stream import kotlin.test.assertEquals @@ -238,7 +238,7 @@ class PartiQLParserDDLTests { Scope.DEFAULT() ), exprLit( - litInt(0) + intNum(0) ) ) ) diff --git a/partiql-parser/src/test/kotlin/org/partiql/parser/internal/PartiQLParserOperatorTests.kt b/partiql-parser/src/test/kotlin/org/partiql/parser/internal/PartiQLParserOperatorTests.kt index 4fd2b9d18..fa75371bf 100644 --- a/partiql-parser/src/test/kotlin/org/partiql/parser/internal/PartiQLParserOperatorTests.kt +++ b/partiql-parser/src/test/kotlin/org/partiql/parser/internal/PartiQLParserOperatorTests.kt @@ -5,8 +5,8 @@ import org.partiql.ast.Ast.exprLit import org.partiql.ast.Ast.exprOperator import org.partiql.ast.Ast.query import org.partiql.ast.AstNode +import org.partiql.ast.Literal.intNum import org.partiql.ast.expr.Expr -import org.partiql.ast.literal.Literal.litInt import kotlin.test.assertEquals class PartiQLParserOperatorTests { @@ -22,7 +22,7 @@ class PartiQLParserOperatorTests { exprOperator( symbol = "-", lhs = null, - rhs = exprLit(litInt(2)) + rhs = exprLit(intNum(2)) ) } ) @@ -33,8 +33,8 @@ class PartiQLParserOperatorTests { queryBody { exprOperator( symbol = "<=", - lhs = exprLit(litInt(1)), - rhs = exprLit(litInt(2)) + lhs = exprLit(intNum(1)), + rhs = exprLit(intNum(2)) ) } ) @@ -46,7 +46,7 @@ class PartiQLParserOperatorTests { exprOperator( symbol = "==!", lhs = null, - rhs = exprLit(litInt(2)) + rhs = exprLit(intNum(2)) ) } ) @@ -57,8 +57,8 @@ class PartiQLParserOperatorTests { queryBody { exprOperator( symbol = "==!", - lhs = exprLit(litInt(1)), - rhs = exprLit(litInt(2)) + lhs = exprLit(intNum(1)), + rhs = exprLit(intNum(2)) ) } ) diff --git a/partiql-parser/src/test/kotlin/org/partiql/parser/internal/PartiQLParserSessionAttributeTests.kt b/partiql-parser/src/test/kotlin/org/partiql/parser/internal/PartiQLParserSessionAttributeTests.kt index 0513cb3a5..2fe4f8b7d 100644 --- a/partiql-parser/src/test/kotlin/org/partiql/parser/internal/PartiQLParserSessionAttributeTests.kt +++ b/partiql-parser/src/test/kotlin/org/partiql/parser/internal/PartiQLParserSessionAttributeTests.kt @@ -6,9 +6,9 @@ import org.partiql.ast.Ast.exprOperator import org.partiql.ast.Ast.exprSessionAttribute import org.partiql.ast.Ast.query import org.partiql.ast.AstNode +import org.partiql.ast.Literal.intNum import org.partiql.ast.expr.Expr import org.partiql.ast.expr.SessionAttribute -import org.partiql.ast.literal.Literal.litInt import kotlin.test.assertEquals class PartiQLParserSessionAttributeTests { @@ -47,7 +47,7 @@ class PartiQLParserSessionAttributeTests { queryBody { exprOperator( symbol = "=", - lhs = exprLit(litInt(1)), + lhs = exprLit(intNum(1)), rhs = exprSessionAttribute(SessionAttribute.CURRENT_USER()) ) } diff --git a/partiql-planner/src/main/kotlin/org/partiql/planner/internal/helpers/ToBinder.kt b/partiql-planner/src/main/kotlin/org/partiql/planner/internal/helpers/ToBinder.kt index b91651a38..899f2f424 100644 --- a/partiql-planner/src/main/kotlin/org/partiql/planner/internal/helpers/ToBinder.kt +++ b/partiql-planner/src/main/kotlin/org/partiql/planner/internal/helpers/ToBinder.kt @@ -3,6 +3,7 @@ package org.partiql.planner.internal.helpers import org.partiql.ast.Ast.identifier import org.partiql.ast.Identifier import org.partiql.ast.IdentifierChain +import org.partiql.ast.Literal import org.partiql.ast.expr.Expr import org.partiql.ast.expr.ExprCast import org.partiql.ast.expr.ExprLit @@ -10,7 +11,6 @@ import org.partiql.ast.expr.ExprPath import org.partiql.ast.expr.ExprSessionAttribute import org.partiql.ast.expr.ExprVarRef import org.partiql.ast.expr.PathStep -import org.partiql.ast.literal.LiteralKind private val col = { index: () -> Int -> "_${index()}" } @@ -69,7 +69,7 @@ private fun ExprPath.toBinder(index: () -> Int): Identifier { is PathStep.Field -> prev.field.toBinder() is PathStep.Element -> { val k = prev.element - if (k is ExprLit && k.lit.kind().code() == LiteralKind.STRING) { + if (k is ExprLit && k.lit.code() == Literal.STRING) { k.lit.stringValue().toBinder() } else { col(index).toBinder() diff --git a/partiql-planner/src/main/kotlin/org/partiql/planner/internal/transforms/NormalizeSelect.kt b/partiql-planner/src/main/kotlin/org/partiql/planner/internal/transforms/NormalizeSelect.kt index e526d1560..072172f6e 100644 --- a/partiql-planner/src/main/kotlin/org/partiql/planner/internal/transforms/NormalizeSelect.kt +++ b/partiql-planner/src/main/kotlin/org/partiql/planner/internal/transforms/NormalizeSelect.kt @@ -37,6 +37,7 @@ import org.partiql.ast.FromExpr import org.partiql.ast.FromJoin import org.partiql.ast.FromTableRef import org.partiql.ast.GroupBy +import org.partiql.ast.Literal.string import org.partiql.ast.QueryBody import org.partiql.ast.SelectItem import org.partiql.ast.SelectList @@ -48,7 +49,6 @@ import org.partiql.ast.expr.ExprQuerySet import org.partiql.ast.expr.ExprStruct import org.partiql.ast.expr.ExprVarRef import org.partiql.ast.expr.Scope -import org.partiql.ast.literal.Literal.litString import org.partiql.planner.internal.helpers.toBinder /** @@ -317,7 +317,7 @@ internal object NormalizeSelect { val structFields = node.items.map { item -> val itemExpr = item as? SelectItem.Expr ?: error("Expected the projection to be an expression.") exprStructField( - name = exprLit(litString(itemExpr.asAlias?.symbol!!)), + name = exprLit(string(itemExpr.asAlias?.symbol!!)), value = item.expr ) } @@ -343,14 +343,14 @@ internal object NormalizeSelect { private fun buildSimpleStruct(expr: Expr, name: String): ExprStruct = exprStruct( fields = listOf( exprStructField( - name = exprLit(litString(name)), + name = exprLit(string(name)), value = expr ) ) ) private fun structField(name: String, expr: Expr): ExprStruct.Field = exprStructField( - name = exprLit(litString(name)), + name = exprLit(string(name)), value = expr ) diff --git a/partiql-planner/src/main/kotlin/org/partiql/planner/internal/transforms/RelConverter.kt b/partiql-planner/src/main/kotlin/org/partiql/planner/internal/transforms/RelConverter.kt index 7ecdfeac7..bbc99472d 100644 --- a/partiql-planner/src/main/kotlin/org/partiql/planner/internal/transforms/RelConverter.kt +++ b/partiql-planner/src/main/kotlin/org/partiql/planner/internal/transforms/RelConverter.kt @@ -33,6 +33,7 @@ import org.partiql.ast.GroupBy import org.partiql.ast.GroupByStrategy import org.partiql.ast.IdentifierChain import org.partiql.ast.JoinType +import org.partiql.ast.Literal.intNum import org.partiql.ast.Nulls import org.partiql.ast.Order import org.partiql.ast.OrderBy @@ -48,7 +49,6 @@ import org.partiql.ast.expr.Expr import org.partiql.ast.expr.ExprCall import org.partiql.ast.expr.ExprQuerySet import org.partiql.ast.expr.Scope -import org.partiql.ast.literal.Literal.litInt import org.partiql.planner.internal.Env import org.partiql.planner.internal.helpers.toBinder import org.partiql.planner.internal.ir.Rel @@ -439,7 +439,7 @@ internal object RelConverter { relOpAggregateCallUnresolved( name, org.partiql.planner.internal.ir.SetQuantifier.ALL, - args = listOf(exprLit(litInt(1)).toRex(env)) + args = listOf(exprLit(intNum(1)).toRex(env)) ) } else { val setq = when (expr.setq?.code()) { diff --git a/partiql-planner/src/main/kotlin/org/partiql/planner/internal/transforms/RexConverter.kt b/partiql-planner/src/main/kotlin/org/partiql/planner/internal/transforms/RexConverter.kt index bcf281918..d5c382ad3 100644 --- a/partiql-planner/src/main/kotlin/org/partiql/planner/internal/transforms/RexConverter.kt +++ b/partiql-planner/src/main/kotlin/org/partiql/planner/internal/transforms/RexConverter.kt @@ -20,6 +20,7 @@ import com.amazon.ionelement.api.loadSingleElement import org.partiql.ast.AstNode import org.partiql.ast.AstVisitor import org.partiql.ast.DataType +import org.partiql.ast.Literal import org.partiql.ast.QueryBody import org.partiql.ast.SelectList import org.partiql.ast.SelectStar @@ -54,8 +55,6 @@ import org.partiql.ast.expr.ExprVariant import org.partiql.ast.expr.PathStep import org.partiql.ast.expr.Scope import org.partiql.ast.expr.TrimSpec -import org.partiql.ast.literal.Literal -import org.partiql.ast.literal.LiteralKind import org.partiql.errors.TypeCheckException import org.partiql.planner.internal.Env import org.partiql.planner.internal.ir.Rel @@ -107,6 +106,8 @@ import org.partiql.value.stringValue import org.partiql.value.timeValue import org.partiql.value.timestampValue import java.math.BigInteger +import java.math.MathContext +import java.math.RoundingMode import java.time.LocalDate import java.time.format.DateTimeFormatter import org.partiql.ast.SetQuantifier as AstSetQuantifier @@ -153,8 +154,8 @@ internal object RexConverter { } val cType = CompilerType( _delegate = type, - isNullValue = node.lit.kind().code() == LiteralKind.NULL, - isMissingValue = node.lit.kind().code() == LiteralKind.MISSING + isNullValue = node.lit.code() == Literal.NULL, + isMissingValue = node.lit.code() == Literal.MISSING ) val op = rexOpLit(pValue) return rex(cType, op) @@ -162,23 +163,23 @@ internal object RexConverter { private fun Literal.toPartiQLValue(): PartiQLValue { val lit = this - return when (lit.kind().code()) { - LiteralKind.NULL -> nullValue() - LiteralKind.MISSING -> missingValue() - LiteralKind.STRING -> stringValue(lit.stringValue()) - LiteralKind.BOOLEAN -> boolValue(lit.booleanValue()) - LiteralKind.NUM_EXACT -> { + return when (lit.code()) { + Literal.NULL -> nullValue() + Literal.MISSING -> missingValue() + Literal.STRING -> stringValue(lit.stringValue()) + Literal.BOOL -> boolValue(lit.booleanValue()) + Literal.EXACT_NUM -> { // TODO previous behavior inferred decimals with scale = 0 to be a PartiQLValue.IntValue with // PType of numeric. Since we're keeping numeric and decimal, need to take another look at // whether the literal should have type decimal or numeric. - val dec = lit.bigDecimalValue() + val dec = lit.bigDecimalValue().round(MathContext(38, RoundingMode.HALF_EVEN)) if (dec.scale() == 0) { intValue(dec.toBigInteger()) } else { decimalValue(dec) } } - LiteralKind.NUM_INT -> { + Literal.INT_NUM -> { val n = lit.numberValue() // 1st, try parse as int try { @@ -204,10 +205,10 @@ internal object RexConverter { throw ex } } - LiteralKind.NUM_APPROX -> { + Literal.APPROX_NUM -> { float64Value(lit.numberValue().toDouble()) } - LiteralKind.TYPED_STRING -> { + Literal.TYPED_STRING -> { val type = this.dataType() val typedString = this.stringValue() when (type.code()) { @@ -234,10 +235,6 @@ internal object RexConverter { } } - private fun PartiQLValue.toPType(): PType { - return this.type.toPType() - } - /** * TODO PartiQLValue will be replaced by Datum (i.e. IonDatum) is a subsequent PR. */ @@ -478,8 +475,8 @@ internal object RexConverter { is PathStep.Element -> { val key = visitExprCoerce(curStep.element, context) val op = when (val astKey = curStep.element) { - is ExprLit -> when (astKey.lit.kind().code()) { - LiteralKind.STRING -> rexOpPathKey(curPathNavi, key) + is ExprLit -> when (astKey.lit.code()) { + Literal.STRING -> rexOpPathKey(curPathNavi, key) else -> rexOpPathIndex(curPathNavi, key) } is ExprCast -> when (astKey.asType.code() == DataType.STRING) { diff --git a/partiql-planner/src/test/kotlin/org/partiql/planner/internal/transforms/NormalizeSelectTest.kt b/partiql-planner/src/test/kotlin/org/partiql/planner/internal/transforms/NormalizeSelectTest.kt index c3d645bd2..d68173229 100644 --- a/partiql-planner/src/test/kotlin/org/partiql/planner/internal/transforms/NormalizeSelectTest.kt +++ b/partiql-planner/src/test/kotlin/org/partiql/planner/internal/transforms/NormalizeSelectTest.kt @@ -15,11 +15,11 @@ import org.partiql.ast.Ast.selectItemExpr import org.partiql.ast.Ast.selectList import org.partiql.ast.Ast.selectValue import org.partiql.ast.FromType +import org.partiql.ast.Literal.intNum +import org.partiql.ast.Literal.string import org.partiql.ast.SelectItem import org.partiql.ast.expr.Expr import org.partiql.ast.expr.Scope -import org.partiql.ast.literal.Literal.litInt -import org.partiql.ast.literal.Literal.litString import kotlin.test.assertEquals class NormalizeSelectTest { @@ -172,7 +172,7 @@ class NormalizeSelectTest { constructor = exprStruct( items.map { exprStructField( - name = exprLit(litString(it.first)), + name = exprLit(string(it.first)), value = it.second ) } @@ -219,5 +219,5 @@ class NormalizeSelectTest { asAlias = asAlias?.let { identifier(asAlias, isDelimited = false) } ) - private fun lit(value: Int) = exprLit(litInt(value)) + private fun lit(value: Int) = exprLit(intNum(value)) }