diff --git a/partiql-ast/api/partiql-ast.api b/partiql-ast/api/partiql-ast.api index 54da223ce..cfa712f5c 100644 --- a/partiql-ast/api/partiql-ast.api +++ b/partiql-ast/api/partiql-ast.api @@ -4,7 +4,15 @@ public final class org/partiql/ast/Ast { public static final fun columnConstraintNullable (Lorg/partiql/ast/IdentifierChain;Z)Lorg/partiql/ast/ddl/AttributeConstraint$Null; public static final fun columnConstraintUnique (Lorg/partiql/ast/IdentifierChain;Z)Lorg/partiql/ast/ddl/AttributeConstraint$Unique; public static final fun columnDefinition (Lorg/partiql/ast/Identifier;Lorg/partiql/ast/DataType;ZLjava/util/List;Ljava/lang/String;)Lorg/partiql/ast/ddl/ColumnDefinition; + public static final fun conflictTargetConstraint (Lorg/partiql/ast/IdentifierChain;)Lorg/partiql/ast/dml/ConflictTarget$Constraint; + public static final fun conflictTargetIndex (Ljava/util/List;)Lorg/partiql/ast/dml/ConflictTarget$Index; public static final fun createTable (Lorg/partiql/ast/IdentifierChain;Ljava/util/List;Ljava/util/List;Lorg/partiql/ast/ddl/PartitionBy;Ljava/util/List;)Lorg/partiql/ast/ddl/CreateTable; + public static final fun delete (Lorg/partiql/ast/IdentifierChain;Lorg/partiql/ast/expr/Expr;)Lorg/partiql/ast/dml/Delete; + public static final fun doNothing ()Lorg/partiql/ast/dml/ConflictAction$DoNothing; + public static final fun doReplace (Lorg/partiql/ast/dml/DoReplaceAction;Lorg/partiql/ast/expr/Expr;)Lorg/partiql/ast/dml/ConflictAction$DoReplace; + public static final fun doReplaceActionExcluded ()Lorg/partiql/ast/dml/DoReplaceAction$Excluded; + public static final fun doUpdate (Lorg/partiql/ast/dml/DoUpdateAction;Lorg/partiql/ast/expr/Expr;)Lorg/partiql/ast/dml/ConflictAction$DoUpdate; + public static final fun doUpdateActionExcluded ()Lorg/partiql/ast/dml/DoUpdateAction$Excluded; public static final fun exclude (Ljava/util/List;)Lorg/partiql/ast/Exclude; public static final fun excludePath (Lorg/partiql/ast/expr/ExprVarRef;Ljava/util/List;)Lorg/partiql/ast/ExcludePath; public static final fun excludeStepCollIndex (I)Lorg/partiql/ast/ExcludeStep$CollIndex; @@ -41,6 +49,7 @@ public final class org/partiql/ast/Ast { public static final fun exprPosition (Lorg/partiql/ast/expr/Expr;Lorg/partiql/ast/expr/Expr;)Lorg/partiql/ast/expr/ExprPosition; public static final fun exprQuerySet (Lorg/partiql/ast/QueryBody;Lorg/partiql/ast/OrderBy;Lorg/partiql/ast/expr/Expr;Lorg/partiql/ast/expr/Expr;)Lorg/partiql/ast/expr/ExprQuerySet; public static final fun exprRowValue (Ljava/util/List;)Lorg/partiql/ast/expr/ExprRowValue; + public static final fun exprRowValue (Ljava/util/List;Z)Lorg/partiql/ast/expr/ExprRowValue; public static final fun exprSessionAttribute (Lorg/partiql/ast/expr/SessionAttribute;)Lorg/partiql/ast/expr/ExprSessionAttribute; public static final fun exprStruct (Ljava/util/List;)Lorg/partiql/ast/expr/ExprStruct; public static final fun exprStructField (Lorg/partiql/ast/expr/Expr;Lorg/partiql/ast/expr/Expr;)Lorg/partiql/ast/expr/ExprStruct$Field; @@ -75,23 +84,35 @@ public final class org/partiql/ast/Ast { public static final fun groupByKey (Lorg/partiql/ast/expr/Expr;Lorg/partiql/ast/Identifier;)Lorg/partiql/ast/GroupBy$Key; public static final fun identifier (Ljava/lang/String;Z)Lorg/partiql/ast/Identifier; public static final fun identifierChain (Lorg/partiql/ast/Identifier;Lorg/partiql/ast/IdentifierChain;)Lorg/partiql/ast/IdentifierChain; + public static final fun insert (Lorg/partiql/ast/IdentifierChain;Lorg/partiql/ast/Identifier;Lorg/partiql/ast/dml/InsertSource;Lorg/partiql/ast/dml/OnConflict;)Lorg/partiql/ast/dml/Insert; + public static final fun insertSourceDefault ()Lorg/partiql/ast/dml/InsertSource$FromDefault; + public static final fun insertSourceExpr (Ljava/util/List;Lorg/partiql/ast/expr/Expr;)Lorg/partiql/ast/dml/InsertSource$FromExpr; public static final fun keyValue (Ljava/lang/String;Ljava/lang/String;)Lorg/partiql/ast/ddl/KeyValue; public static final fun let (Ljava/util/List;)Lorg/partiql/ast/Let; public static final fun letBinding (Lorg/partiql/ast/expr/Expr;Lorg/partiql/ast/Identifier;)Lorg/partiql/ast/Let$Binding; + public static final fun onConflict (Lorg/partiql/ast/dml/ConflictAction;Lorg/partiql/ast/dml/ConflictTarget;)Lorg/partiql/ast/dml/OnConflict; public static final fun orderBy (Ljava/util/List;)Lorg/partiql/ast/OrderBy; public static final fun partitionBy (Ljava/util/List;)Lorg/partiql/ast/ddl/PartitionBy; public static final fun query (Lorg/partiql/ast/expr/Expr;)Lorg/partiql/ast/Query; public static final fun queryBodySFW (Lorg/partiql/ast/Select;Lorg/partiql/ast/Exclude;Lorg/partiql/ast/From;Lorg/partiql/ast/Let;Lorg/partiql/ast/expr/Expr;Lorg/partiql/ast/GroupBy;Lorg/partiql/ast/expr/Expr;)Lorg/partiql/ast/QueryBody$SFW; public static final fun queryBodySetOp (Lorg/partiql/ast/SetOp;ZLorg/partiql/ast/expr/Expr;Lorg/partiql/ast/expr/Expr;)Lorg/partiql/ast/QueryBody$SetOp; + public static final fun replace (Lorg/partiql/ast/IdentifierChain;Lorg/partiql/ast/Identifier;Lorg/partiql/ast/dml/InsertSource;)Lorg/partiql/ast/dml/Replace; public static final fun selectItemExpr (Lorg/partiql/ast/expr/Expr;Lorg/partiql/ast/Identifier;)Lorg/partiql/ast/SelectItem$Expr; public static final fun selectItemStar (Lorg/partiql/ast/expr/Expr;)Lorg/partiql/ast/SelectItem$Star; public static final fun selectList (Ljava/util/List;Lorg/partiql/ast/SetQuantifier;)Lorg/partiql/ast/SelectList; public static final fun selectPivot (Lorg/partiql/ast/expr/Expr;Lorg/partiql/ast/expr/Expr;)Lorg/partiql/ast/SelectPivot; public static final fun selectStar (Lorg/partiql/ast/SetQuantifier;)Lorg/partiql/ast/SelectStar; public static final fun selectValue (Lorg/partiql/ast/expr/Expr;Lorg/partiql/ast/SetQuantifier;)Lorg/partiql/ast/SelectValue; + public static final fun setClause (Lorg/partiql/ast/dml/UpdateTarget;Lorg/partiql/ast/expr/Expr;)Lorg/partiql/ast/dml/SetClause; public static final fun setOp (Lorg/partiql/ast/SetOpType;Lorg/partiql/ast/SetQuantifier;)Lorg/partiql/ast/SetOp; public static final fun sort (Lorg/partiql/ast/expr/Expr;Lorg/partiql/ast/Order;Lorg/partiql/ast/Nulls;)Lorg/partiql/ast/Sort; public static final fun tableConstraintUnique (Lorg/partiql/ast/IdentifierChain;Ljava/util/List;Z)Lorg/partiql/ast/ddl/TableConstraint$Unique; + public static final fun update (Lorg/partiql/ast/IdentifierChain;Ljava/util/List;Lorg/partiql/ast/expr/Expr;)Lorg/partiql/ast/dml/Update; + public static final fun updateTarget (Lorg/partiql/ast/Identifier;Ljava/util/List;)Lorg/partiql/ast/dml/UpdateTarget; + public static final fun updateTargetStepElement (I)Lorg/partiql/ast/dml/UpdateTargetStep$Element; + public static final fun updateTargetStepElement (Ljava/lang/String;)Lorg/partiql/ast/dml/UpdateTargetStep$Element; + public static final fun updateTargetStepField (Lorg/partiql/ast/Identifier;)Lorg/partiql/ast/dml/UpdateTargetStep$Field; + public static final fun upsert (Lorg/partiql/ast/IdentifierChain;Lorg/partiql/ast/Identifier;Lorg/partiql/ast/dml/InsertSource;)Lorg/partiql/ast/dml/Upsert; } public abstract class org/partiql/ast/AstEnum : org/partiql/ast/AstNode { @@ -111,8 +132,24 @@ public abstract class org/partiql/ast/AstRewriter : org/partiql/ast/AstVisitor { public fun ()V public synthetic fun defaultReturn (Lorg/partiql/ast/AstNode;Ljava/lang/Object;)Ljava/lang/Object; public fun defaultReturn (Lorg/partiql/ast/AstNode;Ljava/lang/Object;)Lorg/partiql/ast/AstNode; + public synthetic fun visitConflictActionDoNothing (Lorg/partiql/ast/dml/ConflictAction$DoNothing;Ljava/lang/Object;)Ljava/lang/Object; + public fun visitConflictActionDoNothing (Lorg/partiql/ast/dml/ConflictAction$DoNothing;Ljava/lang/Object;)Lorg/partiql/ast/AstNode; + public synthetic fun visitConflictActionDoReplace (Lorg/partiql/ast/dml/ConflictAction$DoReplace;Ljava/lang/Object;)Ljava/lang/Object; + public fun visitConflictActionDoReplace (Lorg/partiql/ast/dml/ConflictAction$DoReplace;Ljava/lang/Object;)Lorg/partiql/ast/AstNode; + public synthetic fun visitConflictActionDoUpdate (Lorg/partiql/ast/dml/ConflictAction$DoUpdate;Ljava/lang/Object;)Ljava/lang/Object; + public fun visitConflictActionDoUpdate (Lorg/partiql/ast/dml/ConflictAction$DoUpdate;Ljava/lang/Object;)Lorg/partiql/ast/AstNode; + public synthetic fun visitConflictTargetConstraint (Lorg/partiql/ast/dml/ConflictTarget$Constraint;Ljava/lang/Object;)Ljava/lang/Object; + public fun visitConflictTargetConstraint (Lorg/partiql/ast/dml/ConflictTarget$Constraint;Ljava/lang/Object;)Lorg/partiql/ast/AstNode; + public synthetic fun visitConflictTargetIndex (Lorg/partiql/ast/dml/ConflictTarget$Index;Ljava/lang/Object;)Ljava/lang/Object; + public fun visitConflictTargetIndex (Lorg/partiql/ast/dml/ConflictTarget$Index;Ljava/lang/Object;)Lorg/partiql/ast/AstNode; public synthetic fun visitDdl (Lorg/partiql/ast/ddl/Ddl;Ljava/lang/Object;)Ljava/lang/Object; public fun visitDdl (Lorg/partiql/ast/ddl/Ddl;Ljava/lang/Object;)Lorg/partiql/ast/AstNode; + public synthetic fun visitDelete (Lorg/partiql/ast/dml/Delete;Ljava/lang/Object;)Ljava/lang/Object; + public fun visitDelete (Lorg/partiql/ast/dml/Delete;Ljava/lang/Object;)Lorg/partiql/ast/AstNode; + public synthetic fun visitDoReplaceActionExcluded (Lorg/partiql/ast/dml/DoReplaceAction$Excluded;Ljava/lang/Object;)Ljava/lang/Object; + public fun visitDoReplaceActionExcluded (Lorg/partiql/ast/dml/DoReplaceAction$Excluded;Ljava/lang/Object;)Lorg/partiql/ast/AstNode; + public synthetic fun visitDoUpdateActionExcluded (Lorg/partiql/ast/dml/DoUpdateAction$Excluded;Ljava/lang/Object;)Ljava/lang/Object; + public fun visitDoUpdateActionExcluded (Lorg/partiql/ast/dml/DoUpdateAction$Excluded;Ljava/lang/Object;)Lorg/partiql/ast/AstNode; public synthetic fun visitExclude (Lorg/partiql/ast/Exclude;Ljava/lang/Object;)Ljava/lang/Object; public fun visitExclude (Lorg/partiql/ast/Exclude;Ljava/lang/Object;)Lorg/partiql/ast/AstNode; public synthetic fun visitExcludePath (Lorg/partiql/ast/ExcludePath;Ljava/lang/Object;)Ljava/lang/Object; @@ -229,12 +266,20 @@ public abstract class org/partiql/ast/AstRewriter : org/partiql/ast/AstVisitor { public fun visitIdentifier (Lorg/partiql/ast/Identifier;Ljava/lang/Object;)Lorg/partiql/ast/AstNode; public synthetic fun visitIdentifierChain (Lorg/partiql/ast/IdentifierChain;Ljava/lang/Object;)Ljava/lang/Object; public fun visitIdentifierChain (Lorg/partiql/ast/IdentifierChain;Ljava/lang/Object;)Lorg/partiql/ast/AstNode; + public synthetic fun visitInsert (Lorg/partiql/ast/dml/Insert;Ljava/lang/Object;)Ljava/lang/Object; + public fun visitInsert (Lorg/partiql/ast/dml/Insert;Ljava/lang/Object;)Lorg/partiql/ast/AstNode; + public synthetic fun visitInsertSourceFromDefault (Lorg/partiql/ast/dml/InsertSource$FromDefault;Ljava/lang/Object;)Ljava/lang/Object; + public fun visitInsertSourceFromDefault (Lorg/partiql/ast/dml/InsertSource$FromDefault;Ljava/lang/Object;)Lorg/partiql/ast/AstNode; + public synthetic fun visitInsertSourceFromExpr (Lorg/partiql/ast/dml/InsertSource$FromExpr;Ljava/lang/Object;)Ljava/lang/Object; + public fun visitInsertSourceFromExpr (Lorg/partiql/ast/dml/InsertSource$FromExpr;Ljava/lang/Object;)Lorg/partiql/ast/AstNode; public synthetic fun visitLet (Lorg/partiql/ast/Let;Ljava/lang/Object;)Ljava/lang/Object; 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;Ljava/lang/Object;)Ljava/lang/Object; public fun visitLiteral (Lorg/partiql/ast/Literal;Ljava/lang/Object;)Lorg/partiql/ast/AstNode; + public synthetic fun visitOnConflict (Lorg/partiql/ast/dml/OnConflict;Ljava/lang/Object;)Ljava/lang/Object; + public fun visitOnConflict (Lorg/partiql/ast/dml/OnConflict;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; @@ -249,6 +294,8 @@ public abstract class org/partiql/ast/AstRewriter : org/partiql/ast/AstVisitor { public fun visitQueryBodySFW (Lorg/partiql/ast/QueryBody$SFW;Ljava/lang/Object;)Lorg/partiql/ast/AstNode; public synthetic fun visitQueryBodySetOp (Lorg/partiql/ast/QueryBody$SetOp;Ljava/lang/Object;)Ljava/lang/Object; public fun visitQueryBodySetOp (Lorg/partiql/ast/QueryBody$SetOp;Ljava/lang/Object;)Lorg/partiql/ast/AstNode; + public synthetic fun visitReplace (Lorg/partiql/ast/dml/Replace;Ljava/lang/Object;)Ljava/lang/Object; + public fun visitReplace (Lorg/partiql/ast/dml/Replace;Ljava/lang/Object;)Lorg/partiql/ast/AstNode; public synthetic fun visitSelectItemExpr (Lorg/partiql/ast/SelectItem$Expr;Ljava/lang/Object;)Ljava/lang/Object; public fun visitSelectItemExpr (Lorg/partiql/ast/SelectItem$Expr;Ljava/lang/Object;)Lorg/partiql/ast/AstNode; public synthetic fun visitSelectItemStar (Lorg/partiql/ast/SelectItem$Star;Ljava/lang/Object;)Ljava/lang/Object; @@ -261,8 +308,20 @@ public abstract class org/partiql/ast/AstRewriter : org/partiql/ast/AstVisitor { public fun visitSelectStar (Lorg/partiql/ast/SelectStar;Ljava/lang/Object;)Lorg/partiql/ast/AstNode; public synthetic fun visitSelectValue (Lorg/partiql/ast/SelectValue;Ljava/lang/Object;)Ljava/lang/Object; public fun visitSelectValue (Lorg/partiql/ast/SelectValue;Ljava/lang/Object;)Lorg/partiql/ast/AstNode; + public synthetic fun visitSetClause (Lorg/partiql/ast/dml/SetClause;Ljava/lang/Object;)Ljava/lang/Object; + public fun visitSetClause (Lorg/partiql/ast/dml/SetClause;Ljava/lang/Object;)Lorg/partiql/ast/AstNode; public synthetic fun visitSetOp (Lorg/partiql/ast/SetOp;Ljava/lang/Object;)Ljava/lang/Object; public fun visitSetOp (Lorg/partiql/ast/SetOp;Ljava/lang/Object;)Lorg/partiql/ast/AstNode; + public synthetic fun visitUpdate (Lorg/partiql/ast/dml/Update;Ljava/lang/Object;)Ljava/lang/Object; + public fun visitUpdate (Lorg/partiql/ast/dml/Update;Ljava/lang/Object;)Lorg/partiql/ast/AstNode; + public synthetic fun visitUpdateTarget (Lorg/partiql/ast/dml/UpdateTarget;Ljava/lang/Object;)Ljava/lang/Object; + public fun visitUpdateTarget (Lorg/partiql/ast/dml/UpdateTarget;Ljava/lang/Object;)Lorg/partiql/ast/AstNode; + public synthetic fun visitUpdateTargetStepElement (Lorg/partiql/ast/dml/UpdateTargetStep$Element;Ljava/lang/Object;)Ljava/lang/Object; + public fun visitUpdateTargetStepElement (Lorg/partiql/ast/dml/UpdateTargetStep$Element;Ljava/lang/Object;)Lorg/partiql/ast/AstNode; + public synthetic fun visitUpdateTargetStepField (Lorg/partiql/ast/dml/UpdateTargetStep$Field;Ljava/lang/Object;)Ljava/lang/Object; + public fun visitUpdateTargetStepField (Lorg/partiql/ast/dml/UpdateTargetStep$Field;Ljava/lang/Object;)Lorg/partiql/ast/AstNode; + public synthetic fun visitUpsert (Lorg/partiql/ast/dml/Upsert;Ljava/lang/Object;)Ljava/lang/Object; + public fun visitUpsert (Lorg/partiql/ast/dml/Upsert;Ljava/lang/Object;)Lorg/partiql/ast/AstNode; } public abstract class org/partiql/ast/AstVisitor { @@ -272,9 +331,21 @@ public abstract class org/partiql/ast/AstVisitor { public fun visit (Lorg/partiql/ast/AstNode;Ljava/lang/Object;)Ljava/lang/Object; public fun visitCheck (Lorg/partiql/ast/ddl/AttributeConstraint$Check;Ljava/lang/Object;)Ljava/lang/Object; public fun visitColumnDefinition (Lorg/partiql/ast/ddl/ColumnDefinition;Ljava/lang/Object;)Ljava/lang/Object; + public fun visitConflictAction (Lorg/partiql/ast/dml/ConflictAction;Ljava/lang/Object;)Ljava/lang/Object; + public fun visitConflictActionDoNothing (Lorg/partiql/ast/dml/ConflictAction$DoNothing;Ljava/lang/Object;)Ljava/lang/Object; + public fun visitConflictActionDoReplace (Lorg/partiql/ast/dml/ConflictAction$DoReplace;Ljava/lang/Object;)Ljava/lang/Object; + public fun visitConflictActionDoUpdate (Lorg/partiql/ast/dml/ConflictAction$DoUpdate;Ljava/lang/Object;)Ljava/lang/Object; + public fun visitConflictTarget (Lorg/partiql/ast/dml/ConflictTarget;Ljava/lang/Object;)Ljava/lang/Object; + public fun visitConflictTargetConstraint (Lorg/partiql/ast/dml/ConflictTarget$Constraint;Ljava/lang/Object;)Ljava/lang/Object; + public fun visitConflictTargetIndex (Lorg/partiql/ast/dml/ConflictTarget$Index;Ljava/lang/Object;)Ljava/lang/Object; public fun visitCreateTable (Lorg/partiql/ast/ddl/CreateTable;Ljava/lang/Object;)Ljava/lang/Object; public fun visitDataType (Lorg/partiql/ast/DataType;Ljava/lang/Object;)Ljava/lang/Object; public fun visitDdl (Lorg/partiql/ast/ddl/Ddl;Ljava/lang/Object;)Ljava/lang/Object; + public fun visitDelete (Lorg/partiql/ast/dml/Delete;Ljava/lang/Object;)Ljava/lang/Object; + public fun visitDoReplaceAction (Lorg/partiql/ast/dml/DoReplaceAction;Ljava/lang/Object;)Ljava/lang/Object; + public fun visitDoReplaceActionExcluded (Lorg/partiql/ast/dml/DoReplaceAction$Excluded;Ljava/lang/Object;)Ljava/lang/Object; + public fun visitDoUpdateAction (Lorg/partiql/ast/dml/DoUpdateAction;Ljava/lang/Object;)Ljava/lang/Object; + public fun visitDoUpdateActionExcluded (Lorg/partiql/ast/dml/DoUpdateAction$Excluded;Ljava/lang/Object;)Ljava/lang/Object; public fun visitExclude (Lorg/partiql/ast/Exclude;Ljava/lang/Object;)Ljava/lang/Object; public fun visitExcludePath (Lorg/partiql/ast/ExcludePath;Ljava/lang/Object;)Ljava/lang/Object; public fun visitExcludeStep (Lorg/partiql/ast/ExcludeStep;Ljava/lang/Object;)Ljava/lang/Object; @@ -347,11 +418,16 @@ public abstract class org/partiql/ast/AstVisitor { public fun visitGroupByKey (Lorg/partiql/ast/GroupBy$Key;Ljava/lang/Object;)Ljava/lang/Object; public fun visitIdentifier (Lorg/partiql/ast/Identifier;Ljava/lang/Object;)Ljava/lang/Object; public fun visitIdentifierChain (Lorg/partiql/ast/IdentifierChain;Ljava/lang/Object;)Ljava/lang/Object; + public fun visitInsert (Lorg/partiql/ast/dml/Insert;Ljava/lang/Object;)Ljava/lang/Object; + public fun visitInsertSource (Lorg/partiql/ast/dml/InsertSource;Ljava/lang/Object;)Ljava/lang/Object; + public fun visitInsertSourceFromDefault (Lorg/partiql/ast/dml/InsertSource$FromDefault;Ljava/lang/Object;)Ljava/lang/Object; + public fun visitInsertSourceFromExpr (Lorg/partiql/ast/dml/InsertSource$FromExpr;Ljava/lang/Object;)Ljava/lang/Object; 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;Ljava/lang/Object;)Ljava/lang/Object; public fun visitNullable (Lorg/partiql/ast/ddl/AttributeConstraint$Null;Ljava/lang/Object;)Ljava/lang/Object; + public fun visitOnConflict (Lorg/partiql/ast/dml/OnConflict;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; public fun visitPathStep (Lorg/partiql/ast/expr/PathStep;Ljava/lang/Object;)Ljava/lang/Object; @@ -363,6 +439,7 @@ public abstract class org/partiql/ast/AstVisitor { public fun visitQueryBody (Lorg/partiql/ast/QueryBody;Ljava/lang/Object;)Ljava/lang/Object; public fun visitQueryBodySFW (Lorg/partiql/ast/QueryBody$SFW;Ljava/lang/Object;)Ljava/lang/Object; public fun visitQueryBodySetOp (Lorg/partiql/ast/QueryBody$SetOp;Ljava/lang/Object;)Ljava/lang/Object; + public fun visitReplace (Lorg/partiql/ast/dml/Replace;Ljava/lang/Object;)Ljava/lang/Object; public fun visitSelect (Lorg/partiql/ast/Select;Ljava/lang/Object;)Ljava/lang/Object; public fun visitSelectItem (Lorg/partiql/ast/SelectItem;Ljava/lang/Object;)Ljava/lang/Object; public fun visitSelectItemExpr (Lorg/partiql/ast/SelectItem$Expr;Ljava/lang/Object;)Ljava/lang/Object; @@ -371,12 +448,19 @@ public abstract class org/partiql/ast/AstVisitor { public fun visitSelectPivot (Lorg/partiql/ast/SelectPivot;Ljava/lang/Object;)Ljava/lang/Object; public fun visitSelectStar (Lorg/partiql/ast/SelectStar;Ljava/lang/Object;)Ljava/lang/Object; public fun visitSelectValue (Lorg/partiql/ast/SelectValue;Ljava/lang/Object;)Ljava/lang/Object; + public fun visitSetClause (Lorg/partiql/ast/dml/SetClause;Ljava/lang/Object;)Ljava/lang/Object; public fun visitSetOp (Lorg/partiql/ast/SetOp;Ljava/lang/Object;)Ljava/lang/Object; public fun visitSort (Lorg/partiql/ast/Sort;Ljava/lang/Object;)Ljava/lang/Object; public fun visitStatement (Lorg/partiql/ast/Statement;Ljava/lang/Object;)Ljava/lang/Object; public fun visitStructField (Lorg/partiql/ast/DataType$StructField;Ljava/lang/Object;)Ljava/lang/Object; public fun visitUnique (Lorg/partiql/ast/ddl/AttributeConstraint$Unique;Ljava/lang/Object;)Ljava/lang/Object; public fun visitUnique (Lorg/partiql/ast/ddl/TableConstraint$Unique;Ljava/lang/Object;)Ljava/lang/Object; + public fun visitUpdate (Lorg/partiql/ast/dml/Update;Ljava/lang/Object;)Ljava/lang/Object; + public fun visitUpdateTarget (Lorg/partiql/ast/dml/UpdateTarget;Ljava/lang/Object;)Ljava/lang/Object; + public fun visitUpdateTargetStep (Lorg/partiql/ast/dml/UpdateTargetStep;Ljava/lang/Object;)Ljava/lang/Object; + public fun visitUpdateTargetStepElement (Lorg/partiql/ast/dml/UpdateTargetStep$Element;Ljava/lang/Object;)Ljava/lang/Object; + public fun visitUpdateTargetStepField (Lorg/partiql/ast/dml/UpdateTargetStep$Field;Ljava/lang/Object;)Ljava/lang/Object; + public fun visitUpsert (Lorg/partiql/ast/dml/Upsert;Ljava/lang/Object;)Ljava/lang/Object; } public class org/partiql/ast/DataType : org/partiql/ast/AstEnum { @@ -1434,6 +1518,360 @@ public class org/partiql/ast/ddl/TableConstraint$Unique : org/partiql/ast/ddl/Ta public fun hashCode ()I } +public abstract class org/partiql/ast/dml/ConflictAction : org/partiql/ast/AstNode { + public fun ()V +} + +public final class org/partiql/ast/dml/ConflictAction$DoNothing : org/partiql/ast/dml/ConflictAction { + public fun ()V + public fun accept (Lorg/partiql/ast/AstVisitor;Ljava/lang/Object;)Ljava/lang/Object; + public static fun builder ()Lorg/partiql/ast/dml/ConflictAction$DoNothing$Builder; + public fun children ()Ljava/util/Collection; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I +} + +public class org/partiql/ast/dml/ConflictAction$DoNothing$Builder { + public fun build ()Lorg/partiql/ast/dml/ConflictAction$DoNothing; + public fun toString ()Ljava/lang/String; +} + +public final class org/partiql/ast/dml/ConflictAction$DoReplace : org/partiql/ast/dml/ConflictAction { + public final field action Lorg/partiql/ast/dml/DoReplaceAction; + public final field condition Lorg/partiql/ast/expr/Expr; + public fun (Lorg/partiql/ast/dml/DoReplaceAction;Lorg/partiql/ast/expr/Expr;)V + public fun accept (Lorg/partiql/ast/AstVisitor;Ljava/lang/Object;)Ljava/lang/Object; + public static fun builder ()Lorg/partiql/ast/dml/ConflictAction$DoReplace$Builder; + public fun children ()Ljava/util/Collection; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I +} + +public class org/partiql/ast/dml/ConflictAction$DoReplace$Builder { + public fun action (Lorg/partiql/ast/dml/DoReplaceAction;)Lorg/partiql/ast/dml/ConflictAction$DoReplace$Builder; + public fun build ()Lorg/partiql/ast/dml/ConflictAction$DoReplace; + public fun condition (Lorg/partiql/ast/expr/Expr;)Lorg/partiql/ast/dml/ConflictAction$DoReplace$Builder; + public fun toString ()Ljava/lang/String; +} + +public final class org/partiql/ast/dml/ConflictAction$DoUpdate : org/partiql/ast/dml/ConflictAction { + public final field action Lorg/partiql/ast/dml/DoUpdateAction; + public final field condition Lorg/partiql/ast/expr/Expr; + public fun (Lorg/partiql/ast/dml/DoUpdateAction;Lorg/partiql/ast/expr/Expr;)V + public fun accept (Lorg/partiql/ast/AstVisitor;Ljava/lang/Object;)Ljava/lang/Object; + public static fun builder ()Lorg/partiql/ast/dml/ConflictAction$DoUpdate$Builder; + public fun children ()Ljava/util/Collection; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I +} + +public class org/partiql/ast/dml/ConflictAction$DoUpdate$Builder { + public fun action (Lorg/partiql/ast/dml/DoUpdateAction;)Lorg/partiql/ast/dml/ConflictAction$DoUpdate$Builder; + public fun build ()Lorg/partiql/ast/dml/ConflictAction$DoUpdate; + public fun condition (Lorg/partiql/ast/expr/Expr;)Lorg/partiql/ast/dml/ConflictAction$DoUpdate$Builder; + public fun toString ()Ljava/lang/String; +} + +public abstract class org/partiql/ast/dml/ConflictTarget : org/partiql/ast/AstNode { + public fun ()V +} + +public final class org/partiql/ast/dml/ConflictTarget$Constraint : org/partiql/ast/dml/ConflictTarget { + public final field name Lorg/partiql/ast/IdentifierChain; + public fun (Lorg/partiql/ast/IdentifierChain;)V + public fun accept (Lorg/partiql/ast/AstVisitor;Ljava/lang/Object;)Ljava/lang/Object; + public static fun builder ()Lorg/partiql/ast/dml/ConflictTarget$Constraint$Builder; + public fun children ()Ljava/util/Collection; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I +} + +public class org/partiql/ast/dml/ConflictTarget$Constraint$Builder { + public fun build ()Lorg/partiql/ast/dml/ConflictTarget$Constraint; + public fun name (Lorg/partiql/ast/IdentifierChain;)Lorg/partiql/ast/dml/ConflictTarget$Constraint$Builder; + public fun toString ()Ljava/lang/String; +} + +public final class org/partiql/ast/dml/ConflictTarget$Index : org/partiql/ast/dml/ConflictTarget { + public final field indexes Ljava/util/List; + public fun (Ljava/util/List;)V + public fun accept (Lorg/partiql/ast/AstVisitor;Ljava/lang/Object;)Ljava/lang/Object; + public static fun builder ()Lorg/partiql/ast/dml/ConflictTarget$Index$Builder; + public fun children ()Ljava/util/Collection; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I +} + +public class org/partiql/ast/dml/ConflictTarget$Index$Builder { + public fun build ()Lorg/partiql/ast/dml/ConflictTarget$Index; + public fun indexes (Ljava/util/List;)Lorg/partiql/ast/dml/ConflictTarget$Index$Builder; + public fun toString ()Ljava/lang/String; +} + +public final class org/partiql/ast/dml/Delete : org/partiql/ast/Statement { + public final field condition Lorg/partiql/ast/expr/Expr; + public final field tableName Lorg/partiql/ast/IdentifierChain; + public fun (Lorg/partiql/ast/IdentifierChain;Lorg/partiql/ast/expr/Expr;)V + public fun accept (Lorg/partiql/ast/AstVisitor;Ljava/lang/Object;)Ljava/lang/Object; + public static fun builder ()Lorg/partiql/ast/dml/Delete$Builder; + public fun children ()Ljava/util/Collection; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I +} + +public class org/partiql/ast/dml/Delete$Builder { + public fun build ()Lorg/partiql/ast/dml/Delete; + public fun condition (Lorg/partiql/ast/expr/Expr;)Lorg/partiql/ast/dml/Delete$Builder; + public fun tableName (Lorg/partiql/ast/IdentifierChain;)Lorg/partiql/ast/dml/Delete$Builder; + public fun toString ()Ljava/lang/String; +} + +public abstract class org/partiql/ast/dml/DoReplaceAction : org/partiql/ast/AstNode { + public fun ()V +} + +public final class org/partiql/ast/dml/DoReplaceAction$Excluded : org/partiql/ast/dml/DoReplaceAction { + public fun ()V + public fun accept (Lorg/partiql/ast/AstVisitor;Ljava/lang/Object;)Ljava/lang/Object; + public static fun builder ()Lorg/partiql/ast/dml/DoReplaceAction$Excluded$Builder; + public fun children ()Ljava/util/Collection; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I +} + +public class org/partiql/ast/dml/DoReplaceAction$Excluded$Builder { + public fun build ()Lorg/partiql/ast/dml/DoReplaceAction$Excluded; + public fun toString ()Ljava/lang/String; +} + +public abstract class org/partiql/ast/dml/DoUpdateAction : org/partiql/ast/AstNode { + public fun ()V +} + +public final class org/partiql/ast/dml/DoUpdateAction$Excluded : org/partiql/ast/dml/DoUpdateAction { + public fun ()V + public fun accept (Lorg/partiql/ast/AstVisitor;Ljava/lang/Object;)Ljava/lang/Object; + public static fun builder ()Lorg/partiql/ast/dml/DoUpdateAction$Excluded$Builder; + public fun children ()Ljava/util/Collection; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I +} + +public class org/partiql/ast/dml/DoUpdateAction$Excluded$Builder { + public fun build ()Lorg/partiql/ast/dml/DoUpdateAction$Excluded; + public fun toString ()Ljava/lang/String; +} + +public final class org/partiql/ast/dml/Insert : org/partiql/ast/Statement { + public final field asAlias Lorg/partiql/ast/Identifier; + public final field onConflict Lorg/partiql/ast/dml/OnConflict; + public final field source Lorg/partiql/ast/dml/InsertSource; + public final field tableName Lorg/partiql/ast/IdentifierChain; + public fun (Lorg/partiql/ast/IdentifierChain;Lorg/partiql/ast/Identifier;Lorg/partiql/ast/dml/InsertSource;Lorg/partiql/ast/dml/OnConflict;)V + public fun accept (Lorg/partiql/ast/AstVisitor;Ljava/lang/Object;)Ljava/lang/Object; + public static fun builder ()Lorg/partiql/ast/dml/Insert$Builder; + public fun children ()Ljava/util/Collection; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I +} + +public class org/partiql/ast/dml/Insert$Builder { + public fun asAlias (Lorg/partiql/ast/Identifier;)Lorg/partiql/ast/dml/Insert$Builder; + public fun build ()Lorg/partiql/ast/dml/Insert; + public fun onConflict (Lorg/partiql/ast/dml/OnConflict;)Lorg/partiql/ast/dml/Insert$Builder; + public fun source (Lorg/partiql/ast/dml/InsertSource;)Lorg/partiql/ast/dml/Insert$Builder; + public fun tableName (Lorg/partiql/ast/IdentifierChain;)Lorg/partiql/ast/dml/Insert$Builder; + public fun toString ()Ljava/lang/String; +} + +public abstract class org/partiql/ast/dml/InsertSource : org/partiql/ast/AstNode { + public fun ()V +} + +public final class org/partiql/ast/dml/InsertSource$FromDefault : org/partiql/ast/dml/InsertSource { + public fun ()V + public fun accept (Lorg/partiql/ast/AstVisitor;Ljava/lang/Object;)Ljava/lang/Object; + public static fun builder ()Lorg/partiql/ast/dml/InsertSource$FromDefault$Builder; + public fun children ()Ljava/util/Collection; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I +} + +public class org/partiql/ast/dml/InsertSource$FromDefault$Builder { + public fun build ()Lorg/partiql/ast/dml/InsertSource$FromDefault; + public fun toString ()Ljava/lang/String; +} + +public final class org/partiql/ast/dml/InsertSource$FromExpr : org/partiql/ast/dml/InsertSource { + public final field columns Ljava/util/List; + public final field expr Lorg/partiql/ast/expr/Expr; + public fun (Ljava/util/List;Lorg/partiql/ast/expr/Expr;)V + public fun accept (Lorg/partiql/ast/AstVisitor;Ljava/lang/Object;)Ljava/lang/Object; + public static fun builder ()Lorg/partiql/ast/dml/InsertSource$FromExpr$Builder; + public fun children ()Ljava/util/Collection; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I +} + +public class org/partiql/ast/dml/InsertSource$FromExpr$Builder { + public fun build ()Lorg/partiql/ast/dml/InsertSource$FromExpr; + public fun columns (Ljava/util/List;)Lorg/partiql/ast/dml/InsertSource$FromExpr$Builder; + public fun expr (Lorg/partiql/ast/expr/Expr;)Lorg/partiql/ast/dml/InsertSource$FromExpr$Builder; + public fun toString ()Ljava/lang/String; +} + +public final class org/partiql/ast/dml/OnConflict : org/partiql/ast/AstNode { + public final field action Lorg/partiql/ast/dml/ConflictAction; + public final field target Lorg/partiql/ast/dml/ConflictTarget; + public fun (Lorg/partiql/ast/dml/ConflictAction;Lorg/partiql/ast/dml/ConflictTarget;)V + public fun accept (Lorg/partiql/ast/AstVisitor;Ljava/lang/Object;)Ljava/lang/Object; + public static fun builder ()Lorg/partiql/ast/dml/OnConflict$Builder; + public fun children ()Ljava/util/Collection; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I +} + +public class org/partiql/ast/dml/OnConflict$Builder { + public fun action (Lorg/partiql/ast/dml/ConflictAction;)Lorg/partiql/ast/dml/OnConflict$Builder; + public fun build ()Lorg/partiql/ast/dml/OnConflict; + public fun target (Lorg/partiql/ast/dml/ConflictTarget;)Lorg/partiql/ast/dml/OnConflict$Builder; + public fun toString ()Ljava/lang/String; +} + +public final class org/partiql/ast/dml/Replace : org/partiql/ast/Statement { + public final field asAlias Lorg/partiql/ast/Identifier; + public final field source Lorg/partiql/ast/dml/InsertSource; + public final field tableName Lorg/partiql/ast/IdentifierChain; + public fun (Lorg/partiql/ast/IdentifierChain;Lorg/partiql/ast/Identifier;Lorg/partiql/ast/dml/InsertSource;)V + public fun accept (Lorg/partiql/ast/AstVisitor;Ljava/lang/Object;)Ljava/lang/Object; + public static fun builder ()Lorg/partiql/ast/dml/Replace$Builder; + public fun children ()Ljava/util/Collection; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I +} + +public class org/partiql/ast/dml/Replace$Builder { + public fun asAlias (Lorg/partiql/ast/Identifier;)Lorg/partiql/ast/dml/Replace$Builder; + public fun build ()Lorg/partiql/ast/dml/Replace; + public fun source (Lorg/partiql/ast/dml/InsertSource;)Lorg/partiql/ast/dml/Replace$Builder; + public fun tableName (Lorg/partiql/ast/IdentifierChain;)Lorg/partiql/ast/dml/Replace$Builder; + public fun toString ()Ljava/lang/String; +} + +public final class org/partiql/ast/dml/SetClause : org/partiql/ast/AstNode { + public final field expr Lorg/partiql/ast/expr/Expr; + public final field target Lorg/partiql/ast/dml/UpdateTarget; + public fun (Lorg/partiql/ast/dml/UpdateTarget;Lorg/partiql/ast/expr/Expr;)V + public fun accept (Lorg/partiql/ast/AstVisitor;Ljava/lang/Object;)Ljava/lang/Object; + public static fun builder ()Lorg/partiql/ast/dml/SetClause$Builder; + public fun children ()Ljava/util/Collection; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I +} + +public class org/partiql/ast/dml/SetClause$Builder { + public fun build ()Lorg/partiql/ast/dml/SetClause; + public fun expr (Lorg/partiql/ast/expr/Expr;)Lorg/partiql/ast/dml/SetClause$Builder; + public fun target (Lorg/partiql/ast/dml/UpdateTarget;)Lorg/partiql/ast/dml/SetClause$Builder; + public fun toString ()Ljava/lang/String; +} + +public final class org/partiql/ast/dml/Update : org/partiql/ast/Statement { + public final field condition Lorg/partiql/ast/expr/Expr; + public final field setClauses Ljava/util/List; + public final field tableName Lorg/partiql/ast/IdentifierChain; + public fun (Lorg/partiql/ast/IdentifierChain;Ljava/util/List;Lorg/partiql/ast/expr/Expr;)V + public fun accept (Lorg/partiql/ast/AstVisitor;Ljava/lang/Object;)Ljava/lang/Object; + public static fun builder ()Lorg/partiql/ast/dml/Update$Builder; + public fun children ()Ljava/util/Collection; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I +} + +public class org/partiql/ast/dml/Update$Builder { + public fun build ()Lorg/partiql/ast/dml/Update; + public fun condition (Lorg/partiql/ast/expr/Expr;)Lorg/partiql/ast/dml/Update$Builder; + public fun setClauses (Ljava/util/List;)Lorg/partiql/ast/dml/Update$Builder; + public fun tableName (Lorg/partiql/ast/IdentifierChain;)Lorg/partiql/ast/dml/Update$Builder; + public fun toString ()Ljava/lang/String; +} + +public final class org/partiql/ast/dml/UpdateTarget : org/partiql/ast/AstNode { + public final field root Lorg/partiql/ast/Identifier; + public final field steps Ljava/util/List; + public fun (Lorg/partiql/ast/Identifier;Ljava/util/List;)V + public fun accept (Lorg/partiql/ast/AstVisitor;Ljava/lang/Object;)Ljava/lang/Object; + public static fun builder ()Lorg/partiql/ast/dml/UpdateTarget$Builder; + public fun children ()Ljava/util/Collection; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I +} + +public class org/partiql/ast/dml/UpdateTarget$Builder { + public fun build ()Lorg/partiql/ast/dml/UpdateTarget; + public fun root (Lorg/partiql/ast/Identifier;)Lorg/partiql/ast/dml/UpdateTarget$Builder; + public fun steps (Ljava/util/List;)Lorg/partiql/ast/dml/UpdateTarget$Builder; + public fun toString ()Ljava/lang/String; +} + +public abstract class org/partiql/ast/dml/UpdateTargetStep : org/partiql/ast/AstNode { + public fun ()V +} + +public final class org/partiql/ast/dml/UpdateTargetStep$Element : org/partiql/ast/dml/UpdateTargetStep { + public final field key Lorg/partiql/ast/Literal; + public fun (I)V + public fun (Ljava/lang/String;)V + public fun (Lorg/partiql/ast/Literal;)V + public fun accept (Lorg/partiql/ast/AstVisitor;Ljava/lang/Object;)Ljava/lang/Object; + public static fun builder ()Lorg/partiql/ast/dml/UpdateTargetStep$Element$Builder; + public fun children ()Ljava/util/Collection; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I +} + +public class org/partiql/ast/dml/UpdateTargetStep$Element$Builder { + public fun build ()Lorg/partiql/ast/dml/UpdateTargetStep$Element; + public fun key (Lorg/partiql/ast/Literal;)Lorg/partiql/ast/dml/UpdateTargetStep$Element$Builder; + public fun toString ()Ljava/lang/String; +} + +public final class org/partiql/ast/dml/UpdateTargetStep$Field : org/partiql/ast/dml/UpdateTargetStep { + public final field key Lorg/partiql/ast/Identifier; + public fun (Lorg/partiql/ast/Identifier;)V + public fun accept (Lorg/partiql/ast/AstVisitor;Ljava/lang/Object;)Ljava/lang/Object; + public static fun builder ()Lorg/partiql/ast/dml/UpdateTargetStep$Field$Builder; + public fun children ()Ljava/util/Collection; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I +} + +public class org/partiql/ast/dml/UpdateTargetStep$Field$Builder { + public fun build ()Lorg/partiql/ast/dml/UpdateTargetStep$Field; + public fun key (Lorg/partiql/ast/Identifier;)Lorg/partiql/ast/dml/UpdateTargetStep$Field$Builder; + public fun toString ()Ljava/lang/String; +} + +public final class org/partiql/ast/dml/Upsert : org/partiql/ast/Statement { + public final field asAlias Lorg/partiql/ast/Identifier; + public final field source Lorg/partiql/ast/dml/InsertSource; + public final field tableName Lorg/partiql/ast/IdentifierChain; + public fun (Lorg/partiql/ast/IdentifierChain;Lorg/partiql/ast/Identifier;Lorg/partiql/ast/dml/InsertSource;)V + public fun accept (Lorg/partiql/ast/AstVisitor;Ljava/lang/Object;)Ljava/lang/Object; + public static fun builder ()Lorg/partiql/ast/dml/Upsert$Builder; + public fun children ()Ljava/util/Collection; + public fun equals (Ljava/lang/Object;)Z + public fun hashCode ()I +} + +public class org/partiql/ast/dml/Upsert$Builder { + public fun asAlias (Lorg/partiql/ast/Identifier;)Lorg/partiql/ast/dml/Upsert$Builder; + public fun build ()Lorg/partiql/ast/dml/Upsert; + public fun source (Lorg/partiql/ast/dml/InsertSource;)Lorg/partiql/ast/dml/Upsert$Builder; + public fun tableName (Lorg/partiql/ast/IdentifierChain;)Lorg/partiql/ast/dml/Upsert$Builder; + public fun toString ()Ljava/lang/String; +} + public abstract class org/partiql/ast/expr/Expr : org/partiql/ast/AstNode { public fun ()V } @@ -1902,8 +2340,10 @@ public class org/partiql/ast/expr/ExprQuerySet$Builder { } public class org/partiql/ast/expr/ExprRowValue : org/partiql/ast/expr/Expr { + public field isExplicit Z public final field values Ljava/util/List; public fun (Ljava/util/List;)V + public fun (ZLjava/util/List;)V public fun accept (Lorg/partiql/ast/AstVisitor;Ljava/lang/Object;)Ljava/lang/Object; public static fun builder ()Lorg/partiql/ast/expr/ExprRowValue$Builder; protected fun canEqual (Ljava/lang/Object;)Z @@ -1914,6 +2354,7 @@ public class org/partiql/ast/expr/ExprRowValue : org/partiql/ast/expr/Expr { public class org/partiql/ast/expr/ExprRowValue$Builder { public fun build ()Lorg/partiql/ast/expr/ExprRowValue; + public fun isExplicit (Z)Lorg/partiql/ast/expr/ExprRowValue$Builder; public fun toString ()Ljava/lang/String; public fun values (Ljava/util/List;)Lorg/partiql/ast/expr/ExprRowValue$Builder; } @@ -2644,6 +3085,8 @@ public abstract class org/partiql/ast/sql/SqlDialect : org/partiql/ast/AstVisito public fun visitDataType (Lorg/partiql/ast/DataType;Lorg/partiql/ast/sql/SqlBlock;)Lorg/partiql/ast/sql/SqlBlock; public synthetic fun visitDdl (Lorg/partiql/ast/ddl/Ddl;Ljava/lang/Object;)Ljava/lang/Object; public fun visitDdl (Lorg/partiql/ast/ddl/Ddl;Lorg/partiql/ast/sql/SqlBlock;)Lorg/partiql/ast/sql/SqlBlock; + public synthetic fun visitDelete (Lorg/partiql/ast/dml/Delete;Ljava/lang/Object;)Ljava/lang/Object; + public fun visitDelete (Lorg/partiql/ast/dml/Delete;Lorg/partiql/ast/sql/SqlBlock;)Lorg/partiql/ast/sql/SqlBlock; public synthetic fun visitExclude (Lorg/partiql/ast/Exclude;Ljava/lang/Object;)Ljava/lang/Object; public fun visitExclude (Lorg/partiql/ast/Exclude;Lorg/partiql/ast/sql/SqlBlock;)Lorg/partiql/ast/sql/SqlBlock; public synthetic fun visitExcludePath (Lorg/partiql/ast/ExcludePath;Ljava/lang/Object;)Ljava/lang/Object; @@ -2735,6 +3178,8 @@ public abstract class org/partiql/ast/sql/SqlDialect : org/partiql/ast/AstVisito public fun visitIdentifier (Lorg/partiql/ast/Identifier;Lorg/partiql/ast/sql/SqlBlock;)Lorg/partiql/ast/sql/SqlBlock; public synthetic fun visitIdentifierChain (Lorg/partiql/ast/IdentifierChain;Ljava/lang/Object;)Ljava/lang/Object; public fun visitIdentifierChain (Lorg/partiql/ast/IdentifierChain;Lorg/partiql/ast/sql/SqlBlock;)Lorg/partiql/ast/sql/SqlBlock; + public synthetic fun visitInsert (Lorg/partiql/ast/dml/Insert;Ljava/lang/Object;)Ljava/lang/Object; + public fun visitInsert (Lorg/partiql/ast/dml/Insert;Lorg/partiql/ast/sql/SqlBlock;)Lorg/partiql/ast/sql/SqlBlock; public synthetic fun visitLet (Lorg/partiql/ast/Let;Ljava/lang/Object;)Ljava/lang/Object; public fun visitLet (Lorg/partiql/ast/Let;Lorg/partiql/ast/sql/SqlBlock;)Lorg/partiql/ast/sql/SqlBlock; public synthetic fun visitLetBinding (Lorg/partiql/ast/Let$Binding;Ljava/lang/Object;)Ljava/lang/Object; @@ -2755,6 +3200,8 @@ public abstract class org/partiql/ast/sql/SqlDialect : org/partiql/ast/AstVisito public fun visitQueryBodySFW (Lorg/partiql/ast/QueryBody$SFW;Lorg/partiql/ast/sql/SqlBlock;)Lorg/partiql/ast/sql/SqlBlock; public synthetic fun visitQueryBodySetOp (Lorg/partiql/ast/QueryBody$SetOp;Ljava/lang/Object;)Ljava/lang/Object; public fun visitQueryBodySetOp (Lorg/partiql/ast/QueryBody$SetOp;Lorg/partiql/ast/sql/SqlBlock;)Lorg/partiql/ast/sql/SqlBlock; + public synthetic fun visitReplace (Lorg/partiql/ast/dml/Replace;Ljava/lang/Object;)Ljava/lang/Object; + public fun visitReplace (Lorg/partiql/ast/dml/Replace;Lorg/partiql/ast/sql/SqlBlock;)Lorg/partiql/ast/sql/SqlBlock; public synthetic fun visitSelectItemExpr (Lorg/partiql/ast/SelectItem$Expr;Ljava/lang/Object;)Ljava/lang/Object; public fun visitSelectItemExpr (Lorg/partiql/ast/SelectItem$Expr;Lorg/partiql/ast/sql/SqlBlock;)Lorg/partiql/ast/sql/SqlBlock; public synthetic fun visitSelectItemStar (Lorg/partiql/ast/SelectItem$Star;Ljava/lang/Object;)Ljava/lang/Object; @@ -2771,6 +3218,10 @@ public abstract class org/partiql/ast/sql/SqlDialect : org/partiql/ast/AstVisito public fun visitSetOp (Lorg/partiql/ast/SetOp;Lorg/partiql/ast/sql/SqlBlock;)Lorg/partiql/ast/sql/SqlBlock; public synthetic fun visitSort (Lorg/partiql/ast/Sort;Ljava/lang/Object;)Ljava/lang/Object; public fun visitSort (Lorg/partiql/ast/Sort;Lorg/partiql/ast/sql/SqlBlock;)Lorg/partiql/ast/sql/SqlBlock; + public synthetic fun visitUpdate (Lorg/partiql/ast/dml/Update;Ljava/lang/Object;)Ljava/lang/Object; + public fun visitUpdate (Lorg/partiql/ast/dml/Update;Lorg/partiql/ast/sql/SqlBlock;)Lorg/partiql/ast/sql/SqlBlock; + public synthetic fun visitUpsert (Lorg/partiql/ast/dml/Upsert;Ljava/lang/Object;)Ljava/lang/Object; + public fun visitUpsert (Lorg/partiql/ast/dml/Upsert;Lorg/partiql/ast/sql/SqlBlock;)Lorg/partiql/ast/sql/SqlBlock; } public final class org/partiql/ast/sql/SqlDialect$Companion { 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 7c1767fe9..1c458f7b5 100644 --- a/partiql-ast/src/main/java/org/partiql/ast/AstVisitor.java +++ b/partiql-ast/src/main/java/org/partiql/ast/AstVisitor.java @@ -7,6 +7,20 @@ import org.partiql.ast.ddl.KeyValue; import org.partiql.ast.ddl.PartitionBy; import org.partiql.ast.ddl.TableConstraint; +import org.partiql.ast.dml.ConflictAction; +import org.partiql.ast.dml.ConflictTarget; +import org.partiql.ast.dml.Delete; +import org.partiql.ast.dml.DoReplaceAction; +import org.partiql.ast.dml.DoUpdateAction; +import org.partiql.ast.dml.Insert; +import org.partiql.ast.dml.InsertSource; +import org.partiql.ast.dml.OnConflict; +import org.partiql.ast.dml.Replace; +import org.partiql.ast.dml.SetClause; +import org.partiql.ast.dml.Update; +import org.partiql.ast.dml.UpdateTarget; +import org.partiql.ast.dml.UpdateTargetStep; +import org.partiql.ast.dml.Upsert; import org.partiql.ast.expr.Expr; import org.partiql.ast.expr.ExprAnd; import org.partiql.ast.expr.ExprArray; @@ -116,6 +130,106 @@ public R visitQuery(Query node, C ctx) { return defaultVisit(node, ctx); } + public R visitInsert(Insert node, C ctx) { + return defaultVisit(node, ctx); + } + + public R visitUpsert(Upsert node, C ctx) { + return defaultVisit(node, ctx); + } + + public R visitReplace(Replace node, C ctx) { + return defaultVisit(node, ctx); + } + + public R visitUpdate(Update node, C ctx) { + return defaultVisit(node, ctx); + } + + public R visitUpdateTarget(UpdateTarget node, C ctx) { + return defaultVisit(node, ctx); + } + + public R visitUpdateTargetStep(UpdateTargetStep node, C ctx) { + return node.accept(this, ctx); + } + + public R visitUpdateTargetStepElement(UpdateTargetStep.Element node, C ctx) { + return defaultVisit(node, ctx); + } + + public R visitUpdateTargetStepField(UpdateTargetStep.Field node, C ctx) { + return defaultVisit(node, ctx); + } + + public R visitDelete(Delete node, C ctx) { + return defaultVisit(node, ctx); + } + + public R visitSetClause(SetClause node, C ctx) { + return defaultVisit(node, ctx); + } + + public R visitInsertSource(InsertSource node, C ctx) { + return node.accept(this, ctx); + } + + public R visitInsertSourceFromExpr(InsertSource.FromExpr node, C ctx) { + return defaultVisit(node, ctx); + } + + public R visitInsertSourceFromDefault(InsertSource.FromDefault node, C ctx) { + return defaultVisit(node, ctx); + } + + public R visitOnConflict(OnConflict node, C ctx) { + return defaultVisit(node, ctx); + } + + public R visitConflictTarget(ConflictTarget node, C ctx) { + return node.accept(this, ctx); + } + + public R visitConflictTargetIndex(ConflictTarget.Index node, C ctx) { + return defaultVisit(node, ctx); + } + + public R visitConflictTargetConstraint(ConflictTarget.Constraint node, C ctx) { + return defaultVisit(node, ctx); + } + + public R visitConflictAction(ConflictAction node, C ctx) { + return node.accept(this, ctx); + } + + public R visitConflictActionDoNothing(ConflictAction.DoNothing node, C ctx) { + return defaultVisit(node, ctx); + } + + public R visitConflictActionDoReplace(ConflictAction.DoReplace node, C ctx) { + return defaultVisit(node, ctx); + } + + public R visitConflictActionDoUpdate(ConflictAction.DoUpdate node, C ctx) { + return defaultVisit(node, ctx); + } + + public R visitDoReplaceAction(DoReplaceAction node, C ctx) { + return node.accept(this, ctx); + } + + public R visitDoReplaceActionExcluded(DoReplaceAction.Excluded node, C ctx) { + return defaultVisit(node, ctx); + } + + public R visitDoUpdateAction(DoUpdateAction node, C ctx) { + return node.accept(this, ctx); + } + + public R visitDoUpdateActionExcluded(DoUpdateAction.Excluded node, C ctx) { + return defaultVisit(node, ctx); + } + public R visitExplain(Explain node, C ctx) { return defaultVisit(node, ctx); } diff --git a/partiql-ast/src/main/java/org/partiql/ast/dml/ConflictAction.java b/partiql-ast/src/main/java/org/partiql/ast/dml/ConflictAction.java new file mode 100644 index 000000000..621581960 --- /dev/null +++ b/partiql-ast/src/main/java/org/partiql/ast/dml/ConflictAction.java @@ -0,0 +1,144 @@ +package org.partiql.ast.dml; + +import lombok.Builder; +import lombok.EqualsAndHashCode; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.partiql.ast.AstNode; +import org.partiql.ast.AstVisitor; +import org.partiql.ast.expr.Expr; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * This is the mandatory action of the ON CONFLICT clause. + * @see Insert#onConflict + * @see OnConflict#action + */ +public abstract class ConflictAction extends AstNode { + + /** + * This is the DO NOTHING variant of the conflict action. + * @see ConflictAction + * @see OnConflict#action + * @see Insert#onConflict + */ + @Builder(builderClassName = "Builder") + @EqualsAndHashCode(callSuper = false) + public static final class DoNothing extends ConflictAction { + + /** + * TODO + */ + public DoNothing() {} + + @NotNull + @Override + public Collection children() { + return new ArrayList<>(); + } + + @Override + public R accept(@NotNull AstVisitor visitor, C ctx) { + return visitor.visitConflictActionDoNothing(this, ctx); + } + } + + /** + * This is the DO REPLACE variant of the conflict action. + * @see ConflictAction + * @see OnConflict#action + * @see Insert#onConflict + */ + @Builder(builderClassName = "Builder") + @EqualsAndHashCode(callSuper = false) + public static final class DoReplace extends ConflictAction { + /** + * TODO + */ + @NotNull + public final DoReplaceAction action; + + /** + * TODO + */ + @Nullable + public final Expr condition; + + /** + * TODO + * @param action TODO + * @param condition TODO + */ + public DoReplace(@NotNull DoReplaceAction action, @Nullable Expr condition) { + this.action = action; + this.condition = condition; + } + + @NotNull + @Override + public Collection children() { + List children = new ArrayList<>(); + children.add(action); + if (condition != null) { + children.add(condition); + } + return children; + } + + @Override + public R accept(@NotNull AstVisitor visitor, C ctx) { + return visitor.visitConflictActionDoReplace(this, ctx); + } + } + + /** + * This is the DO UPDATE variant of the conflict action. + * @see ConflictAction + * @see OnConflict#action + * @see Insert#onConflict + */ + @Builder(builderClassName = "Builder") + @EqualsAndHashCode(callSuper = false) + public static final class DoUpdate extends ConflictAction { + /** + * TODO + */ + @NotNull + public final DoUpdateAction action; + + /** + * TODO + */ + @Nullable + public final Expr condition; + + /** + * TODO + * @param action TODO + * @param condition TODO + */ + public DoUpdate(@NotNull DoUpdateAction action, @Nullable Expr condition) { + this.action = action; + this.condition = condition; + } + + @NotNull + @Override + public Collection children() { + List children = new ArrayList<>(); + children.add(action); + if (condition != null) { + children.add(condition); + } + return children; + } + + @Override + public R accept(@NotNull AstVisitor visitor, C ctx) { + return visitor.visitConflictActionDoUpdate(this, ctx); + } + } +} diff --git a/partiql-ast/src/main/java/org/partiql/ast/dml/ConflictTarget.java b/partiql-ast/src/main/java/org/partiql/ast/dml/ConflictTarget.java new file mode 100644 index 000000000..a9fd7f7ea --- /dev/null +++ b/partiql-ast/src/main/java/org/partiql/ast/dml/ConflictTarget.java @@ -0,0 +1,92 @@ +package org.partiql.ast.dml; + +import lombok.Builder; +import lombok.EqualsAndHashCode; +import org.jetbrains.annotations.NotNull; +import org.partiql.ast.AstNode; +import org.partiql.ast.AstVisitor; +import org.partiql.ast.Identifier; +import org.partiql.ast.IdentifierChain; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * This represents the potential targets for the ON CONFLICT clause. + * @see OnConflict + * @see OnConflict#target + */ +public abstract class ConflictTarget extends AstNode { + + /** + * This is the index variant of the conflict target. + * @see OnConflict + * @see ConflictTarget + */ + @Builder(builderClassName = "Builder") + @EqualsAndHashCode(callSuper = false) + public static final class Index extends ConflictTarget { + /** + * TODO + */ + // TODO: Should this be a list of identifiers? Or paths? Expressions? + @NotNull + public final List indexes; + + /** + * TODO + * @param indexes TODO + */ + public Index(@NotNull List indexes) { + this.indexes = indexes; + } + + @NotNull + @Override + public Collection children() { + return new ArrayList<>(indexes); + } + + @Override + public R accept(@NotNull AstVisitor visitor, C ctx) { + return visitor.visitConflictTargetIndex(this, ctx); + } + } + + /** + * This is the ON CONSTRAINT variant of the conflict target. + * @see OnConflict + * @see ConflictTarget + */ + @Builder(builderClassName = "Builder") + @EqualsAndHashCode(callSuper = false) + public static final class Constraint extends ConflictTarget { + /** + * TODO + */ + @NotNull + public final IdentifierChain name; + + /** + * TODO + * @param name TODO + */ + public Constraint(@NotNull IdentifierChain name) { + this.name = name; + } + + @NotNull + @Override + public Collection children() { + List children = new ArrayList<>(); + children.add(name); + return children; + } + + @Override + public R accept(@NotNull AstVisitor visitor, C ctx) { + return visitor.visitConflictTargetConstraint(this, ctx); + } + } +} diff --git a/partiql-ast/src/main/java/org/partiql/ast/dml/Delete.java b/partiql-ast/src/main/java/org/partiql/ast/dml/Delete.java new file mode 100644 index 000000000..fe5891d2b --- /dev/null +++ b/partiql-ast/src/main/java/org/partiql/ast/dml/Delete.java @@ -0,0 +1,60 @@ +package org.partiql.ast.dml; + +import lombok.Builder; +import lombok.EqualsAndHashCode; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.partiql.ast.AstNode; +import org.partiql.ast.AstVisitor; +import org.partiql.ast.IdentifierChain; +import org.partiql.ast.Statement; +import org.partiql.ast.expr.Expr; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * This is the delete searched statement. + */ +@Builder(builderClassName = "Builder") +@EqualsAndHashCode(callSuper = false) +public final class Delete extends Statement { + /** + * TODO + */ + @NotNull + public final IdentifierChain tableName; + + /** + * TODO + */ + @Nullable + public final Expr condition; + + /** + * TODO + * @param tableName TODO + * @param condition TODO + */ + public Delete(@NotNull IdentifierChain tableName, @Nullable Expr condition) { + this.tableName = tableName; + this.condition = condition; + } + + @NotNull + @Override + public Collection children() { + List kids = new ArrayList<>(); + kids.add(tableName); + if (condition != null) { + kids.add(condition); + } + return kids; + } + + @Override + public R accept(@NotNull AstVisitor visitor, C ctx) { + return visitor.visitDelete(this, ctx); + } +} diff --git a/partiql-ast/src/main/java/org/partiql/ast/dml/DoReplaceAction.java b/partiql-ast/src/main/java/org/partiql/ast/dml/DoReplaceAction.java new file mode 100644 index 000000000..845cdb3a5 --- /dev/null +++ b/partiql-ast/src/main/java/org/partiql/ast/dml/DoReplaceAction.java @@ -0,0 +1,44 @@ +package org.partiql.ast.dml; + +import lombok.Builder; +import lombok.EqualsAndHashCode; +import org.jetbrains.annotations.NotNull; +import org.partiql.ast.AstNode; +import org.partiql.ast.AstVisitor; + +import java.util.ArrayList; +import java.util.Collection; + +/** + * This represents the potential actions after the DO REPLACE clause. While there are more variants beyond EXCLUDED, + * only EXCLUDED is currently implemented. + * @see ConflictAction.DoReplace + * @see OnConflict#action + */ +public abstract class DoReplaceAction extends AstNode { + // TODO: There are more variants than just EXCLUDED. See the Javadoc above. + + /** + * This is the EXCLUDED variant of the DO REPLACE clause. + * @see ConflictAction.DoReplace + */ + @Builder(builderClassName = "Builder") + @EqualsAndHashCode(callSuper = false) + public static final class Excluded extends DoReplaceAction { + /** + * TODO + */ + public Excluded() {} + + @NotNull + @Override + public Collection children() { + return new ArrayList<>(); + } + + @Override + public R accept(@NotNull AstVisitor visitor, C ctx) { + return visitor.visitDoReplaceActionExcluded(this, ctx); + } + } +} diff --git a/partiql-ast/src/main/java/org/partiql/ast/dml/DoUpdateAction.java b/partiql-ast/src/main/java/org/partiql/ast/dml/DoUpdateAction.java new file mode 100644 index 000000000..2b2d9334e --- /dev/null +++ b/partiql-ast/src/main/java/org/partiql/ast/dml/DoUpdateAction.java @@ -0,0 +1,44 @@ +package org.partiql.ast.dml; + +import lombok.Builder; +import lombok.EqualsAndHashCode; +import org.jetbrains.annotations.NotNull; +import org.partiql.ast.AstNode; +import org.partiql.ast.AstVisitor; + +import java.util.ArrayList; +import java.util.Collection; + +/** + * This represents the potential actions after the DO UPDATE clause. While there are more variants beyond EXCLUDED, + * only EXCLUDED is currently implemented. + * @see ConflictAction.DoUpdate + * @see OnConflict#action + */ +public abstract class DoUpdateAction extends AstNode { + // TODO: There are more variants than just EXCLUDED. See the Javadoc above. + + /** + * This is the EXCLUDED variant of the DO UPDATE clause. + * @see ConflictAction.DoReplace + */ + @Builder(builderClassName = "Builder") + @EqualsAndHashCode(callSuper = false) + public static final class Excluded extends DoUpdateAction { + /** + * TODO + */ + public Excluded() {} + + @NotNull + @Override + public Collection children() { + return new ArrayList<>(); + } + + @Override + public R accept(@NotNull AstVisitor visitor, C ctx) { + return visitor.visitDoUpdateActionExcluded(this, ctx); + } + } +} diff --git a/partiql-ast/src/main/java/org/partiql/ast/dml/Insert.java b/partiql-ast/src/main/java/org/partiql/ast/dml/Insert.java new file mode 100644 index 000000000..a7e681c88 --- /dev/null +++ b/partiql-ast/src/main/java/org/partiql/ast/dml/Insert.java @@ -0,0 +1,81 @@ +package org.partiql.ast.dml; + +import lombok.Builder; +import lombok.EqualsAndHashCode; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.partiql.ast.AstNode; +import org.partiql.ast.AstVisitor; +import org.partiql.ast.Identifier; +import org.partiql.ast.IdentifierChain; +import org.partiql.ast.Statement; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * This is the insert statement. + * @see InsertSource + */ +@Builder(builderClassName = "Builder") +@EqualsAndHashCode(callSuper = false) +public final class Insert extends Statement { + /** + * TODO + */ + @NotNull + public final IdentifierChain tableName; + + /** + * TODO + */ + @Nullable + public final Identifier asAlias; + + /** + * TODO + */ + @NotNull + public final InsertSource source; + + /** + * TODO + */ + @Nullable + public final OnConflict onConflict; + + /** + * TODO + * @param tableName TODO + * @param asAlias TODO + * @param source TODO + * @param onConflict TODO + */ + public Insert(@NotNull IdentifierChain tableName, @Nullable Identifier asAlias, @NotNull InsertSource source, @Nullable OnConflict onConflict) { + this.tableName = tableName; + this.asAlias = asAlias; + this.source = source; + this.onConflict = onConflict; + } + + @NotNull + @Override + public Collection children() { + List kids = new ArrayList<>(); + kids.add(tableName); + if (asAlias != null) { + kids.add(asAlias); + } + kids.add(source); + if (onConflict != null) { + kids.add(onConflict); + } + return kids; + } + + @Override + public R accept(@NotNull AstVisitor visitor, C ctx) { + return visitor.visitInsert(this, ctx); + } +} diff --git a/partiql-ast/src/main/java/org/partiql/ast/dml/InsertSource.java b/partiql-ast/src/main/java/org/partiql/ast/dml/InsertSource.java new file mode 100644 index 000000000..f8ed3d42d --- /dev/null +++ b/partiql-ast/src/main/java/org/partiql/ast/dml/InsertSource.java @@ -0,0 +1,95 @@ +package org.partiql.ast.dml; + +import lombok.Builder; +import lombok.EqualsAndHashCode; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.partiql.ast.AstNode; +import org.partiql.ast.AstVisitor; +import org.partiql.ast.Identifier; +import org.partiql.ast.expr.Expr; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * This specifies the data to be inserted. + * @see Insert + */ +public abstract class InsertSource extends AstNode { + + /** + * This specifies the data to be inserted from a subquery or expression. This represents (and generalizes) + * SQL:1999's <from subquery> EBNF rule. + * @see Insert + * @see InsertSource + */ + @Builder(builderClassName = "Builder") + @EqualsAndHashCode(callSuper = false) + public static final class FromExpr extends InsertSource { + /** + * TODO + */ + @Nullable + public final List columns; + + /** + * TODO + */ + @NotNull + public final Expr expr; + + /** + * TODO + * @param columns TODO + * @param expr TODO + */ + public FromExpr(@Nullable List columns, @NotNull Expr expr) { + this.columns = columns; + this.expr = expr; + } + + @NotNull + @Override + public Collection children() { + List kids = new ArrayList<>(); + if (columns != null) { + kids.addAll(columns); + } + kids.add(expr); + return kids; + } + + @Override + public R accept(@NotNull AstVisitor visitor, C ctx) { + return visitor.visitInsertSourceFromExpr(this, ctx); + } + } + + /** + * This specifies the data to be inserted from the DEFAULT VALUES clause. + * @see Insert + * @see InsertSource + */ + @Builder(builderClassName = "Builder") + @EqualsAndHashCode(callSuper = false) + public static final class FromDefault extends InsertSource { + + /** + * TODO + */ + public FromDefault() {} + + @NotNull + @Override + public Collection children() { + return new ArrayList<>(); + } + + @Override + public R accept(@NotNull AstVisitor visitor, C ctx) { + return visitor.visitInsertSourceFromDefault(this, ctx); + } + } +} diff --git a/partiql-ast/src/main/java/org/partiql/ast/dml/OnConflict.java b/partiql-ast/src/main/java/org/partiql/ast/dml/OnConflict.java new file mode 100644 index 000000000..6493ab054 --- /dev/null +++ b/partiql-ast/src/main/java/org/partiql/ast/dml/OnConflict.java @@ -0,0 +1,59 @@ +package org.partiql.ast.dml; + +import lombok.Builder; +import lombok.EqualsAndHashCode; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.partiql.ast.AstNode; +import org.partiql.ast.AstVisitor; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * This is the ON CONFLICT clause for the INSERT statement. + * @see Insert + * @see Insert#onConflict + */ +@Builder(builderClassName = "Builder") +@EqualsAndHashCode(callSuper = false) +public final class OnConflict extends AstNode { + /** + * TODO + */ + @NotNull + public final ConflictAction action; + + /** + * TODO + */ + @Nullable + public final ConflictTarget target; + + /** + * TODO + * @param action TODO + * @param target TODO + */ + public OnConflict(@NotNull ConflictAction action, @Nullable ConflictTarget target) { + this.action = action; + this.target = target; + } + + @NotNull + @Override + public Collection children() { + List kids = new ArrayList<>(); + kids.add(action); + if (target != null) { + kids.add(target); + } + return kids; + } + + @Override + public R accept(@NotNull AstVisitor visitor, C ctx) { + return visitor.visitOnConflict(this, ctx); + } +} diff --git a/partiql-ast/src/main/java/org/partiql/ast/dml/Replace.java b/partiql-ast/src/main/java/org/partiql/ast/dml/Replace.java new file mode 100644 index 000000000..52ad4958e --- /dev/null +++ b/partiql-ast/src/main/java/org/partiql/ast/dml/Replace.java @@ -0,0 +1,70 @@ +package org.partiql.ast.dml; + +import lombok.Builder; +import lombok.EqualsAndHashCode; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.partiql.ast.AstNode; +import org.partiql.ast.AstVisitor; +import org.partiql.ast.Identifier; +import org.partiql.ast.IdentifierChain; +import org.partiql.ast.Statement; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * This is the REPLACE INTO statement. + * @see InsertSource + */ +@Builder(builderClassName = "Builder") +@EqualsAndHashCode(callSuper = false) +public final class Replace extends Statement { + /** + * TODO + */ + @NotNull + public final IdentifierChain tableName; + + /** + * TODO + */ + @Nullable + public final Identifier asAlias; + + /** + * TODO + */ + @NotNull + public final InsertSource source; + + /** + * TODO + * @param tableName TODO + * @param asAlias TODO + * @param source TODO + */ + public Replace(@NotNull IdentifierChain tableName, @Nullable Identifier asAlias, @NotNull InsertSource source) { + this.tableName = tableName; + this.asAlias = asAlias; + this.source = source; + } + + @NotNull + @Override + public Collection children() { + List kids = new ArrayList<>(); + kids.add(tableName); + if (asAlias != null) { + kids.add(asAlias); + } + kids.add(source); + return kids; + } + + @Override + public R accept(@NotNull AstVisitor visitor, C ctx) { + return visitor.visitReplace(this, ctx); + } +} diff --git a/partiql-ast/src/main/java/org/partiql/ast/dml/SetClause.java b/partiql-ast/src/main/java/org/partiql/ast/dml/SetClause.java new file mode 100644 index 000000000..dbe830569 --- /dev/null +++ b/partiql-ast/src/main/java/org/partiql/ast/dml/SetClause.java @@ -0,0 +1,56 @@ +package org.partiql.ast.dml; + +import lombok.Builder; +import lombok.EqualsAndHashCode; +import org.jetbrains.annotations.NotNull; +import org.partiql.ast.AstNode; +import org.partiql.ast.AstVisitor; +import org.partiql.ast.expr.Expr; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * This is the SET clause. This deviates from SQL, as we allow for paths on the LHS of the set assignment. + * @see Update + */ +@Builder(builderClassName = "Builder") +@EqualsAndHashCode(callSuper = false) +public final class SetClause extends AstNode { + /** + * TODO + */ + @NotNull + public final UpdateTarget target; + + /** + * TODO + */ + @NotNull + public final Expr expr; + + /** + * TODO + * @param target TODO + * @param expr TODO + */ + public SetClause(@NotNull UpdateTarget target, @NotNull Expr expr) { + this.target = target; + this.expr = expr; + } + + @NotNull + @Override + public Collection children() { + List kids = new ArrayList<>(); + kids.add(target); + kids.add(expr); + return kids; + } + + @Override + public R accept(@NotNull AstVisitor visitor, C ctx) { + return visitor.visitSetClause(this, ctx); + } +} diff --git a/partiql-ast/src/main/java/org/partiql/ast/dml/Update.java b/partiql-ast/src/main/java/org/partiql/ast/dml/Update.java new file mode 100644 index 000000000..76ae68d9e --- /dev/null +++ b/partiql-ast/src/main/java/org/partiql/ast/dml/Update.java @@ -0,0 +1,70 @@ +package org.partiql.ast.dml; + +import lombok.Builder; +import lombok.EqualsAndHashCode; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.partiql.ast.AstNode; +import org.partiql.ast.AstVisitor; +import org.partiql.ast.IdentifierChain; +import org.partiql.ast.Statement; +import org.partiql.ast.expr.Expr; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * This is the update searched statement. + * @see SetClause + */ +@Builder(builderClassName = "Builder") +@EqualsAndHashCode(callSuper = false) +public final class Update extends Statement { + /** + * TODO + */ + @NotNull + public final IdentifierChain tableName; + + /** + * TODO + */ + @NotNull + public final List setClauses; + + /** + * TODO + */ + @Nullable + public final Expr condition; + + /** + * TODO + * @param tableName TODO + * @param setClauses TODO + * @param condition TODO + */ + public Update(@NotNull IdentifierChain tableName, @NotNull List setClauses, @Nullable Expr condition) { + this.tableName = tableName; + this.setClauses = setClauses; + this.condition = condition; + } + + @NotNull + @Override + public Collection children() { + List kids = new ArrayList<>(); + kids.add(tableName); + kids.addAll(setClauses); + if (condition != null) { + kids.add(condition); + } + return kids; + } + + @Override + public R accept(@NotNull AstVisitor visitor, C ctx) { + return visitor.visitUpdate(this, ctx); + } +} diff --git a/partiql-ast/src/main/java/org/partiql/ast/dml/UpdateTarget.java b/partiql-ast/src/main/java/org/partiql/ast/dml/UpdateTarget.java new file mode 100644 index 000000000..bc9949f58 --- /dev/null +++ b/partiql-ast/src/main/java/org/partiql/ast/dml/UpdateTarget.java @@ -0,0 +1,57 @@ +package org.partiql.ast.dml; + +import lombok.Builder; +import lombok.EqualsAndHashCode; +import org.jetbrains.annotations.NotNull; +import org.partiql.ast.AstNode; +import org.partiql.ast.AstVisitor; +import org.partiql.ast.Identifier; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * This references a column or column's nested properties. In SQL:1999, the EBNF rule is <update target>. + * This implementation differs from SQL by allowing for references to deeply nested data of varying types. + * @see SetClause + */ +@Builder(builderClassName = "Builder") +@EqualsAndHashCode(callSuper = false) +public final class UpdateTarget extends AstNode { + /** + * TODO + */ + @NotNull + public final Identifier root; + + /** + * TODO + */ + @NotNull + public final List steps; + + /** + * TODO + * @param root TODO + * @param steps TODO + */ + public UpdateTarget(@NotNull Identifier root, @NotNull List steps) { + this.root = root; + this.steps = steps; + } + + @NotNull + @Override + public Collection children() { + List kids = new ArrayList<>(); + kids.add(root); + kids.addAll(steps); + return kids; + } + + @Override + public R accept(@NotNull AstVisitor visitor, C ctx) { + return visitor.visitUpdateTarget(this, ctx); + } +} diff --git a/partiql-ast/src/main/java/org/partiql/ast/dml/UpdateTargetStep.java b/partiql-ast/src/main/java/org/partiql/ast/dml/UpdateTargetStep.java new file mode 100644 index 000000000..700ff9b5b --- /dev/null +++ b/partiql-ast/src/main/java/org/partiql/ast/dml/UpdateTargetStep.java @@ -0,0 +1,112 @@ +package org.partiql.ast.dml; + +import lombok.Builder; +import lombok.EqualsAndHashCode; +import org.jetbrains.annotations.NotNull; +import org.partiql.ast.AstNode; +import org.partiql.ast.AstVisitor; +import org.partiql.ast.Identifier; +import org.partiql.ast.Literal; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * This references a column or column's nested properties. In SQL:1999, the EBNF rule is <update target>. + * This implementation differs from SQL by allowing for references to deeply nested data of varying types. + * + * @see SetClause + */ +public abstract class UpdateTargetStep extends AstNode { + + /** + * This is a reference to a field of an array/struct using the bracket notation. + * @see UpdateTarget + * @see UpdateTargetStep + */ + @Builder(builderClassName = "Builder") + @EqualsAndHashCode(callSuper = false) + public static final class Element extends UpdateTargetStep { + // TODO: Should we explicitly have an ElementInt and ElementString? Especially once PartiQLValue is removed. + + /** + * TODO + */ + @NotNull + public final Literal key; + + /** + * TODO + * @param key TODO + */ + public Element(@NotNull Literal key) { + this.key = key; + } + + /** + * TODO + * @param key TODO + */ + public Element(int key) { + this.key = Literal.intNum(key); + } + + /** + * TODO + * @param key TODO + */ + public Element(@NotNull String key) { + this.key = Literal.string(key); + } + + @NotNull + @Override + public Collection children() { + List kids = new ArrayList<>(); + kids.add(key); + return kids; + } + + @Override + public R accept(@NotNull AstVisitor visitor, C ctx) { + return visitor.visitUpdateTargetStepElement(this, ctx); + } + } + + /** + * This is a reference to a field of a struct using the dot notation. + * @see UpdateTarget + * @see UpdateTargetStep + */ + @Builder(builderClassName = "Builder") + @EqualsAndHashCode(callSuper = false) + public static final class Field extends UpdateTargetStep { + /** + * TODO + */ + @NotNull + public final Identifier key; + + /** + * TODO + * @param key TODO + */ + public Field(@NotNull Identifier key) { + this.key = key; + } + + @NotNull + @Override + public Collection children() { + List kids = new ArrayList<>(); + kids.add(key); + return kids; + } + + @Override + public R accept(@NotNull AstVisitor visitor, C ctx) { + return visitor.visitUpdateTargetStepField(this, ctx); + } + } +} \ No newline at end of file diff --git a/partiql-ast/src/main/java/org/partiql/ast/dml/Upsert.java b/partiql-ast/src/main/java/org/partiql/ast/dml/Upsert.java new file mode 100644 index 000000000..ec61b4dc4 --- /dev/null +++ b/partiql-ast/src/main/java/org/partiql/ast/dml/Upsert.java @@ -0,0 +1,70 @@ +package org.partiql.ast.dml; + +import lombok.Builder; +import lombok.EqualsAndHashCode; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.partiql.ast.AstNode; +import org.partiql.ast.AstVisitor; +import org.partiql.ast.Identifier; +import org.partiql.ast.IdentifierChain; +import org.partiql.ast.Statement; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * This is the UPSERT INTO statement. + * @see InsertSource + */ +@Builder(builderClassName = "Builder") +@EqualsAndHashCode(callSuper = false) +public final class Upsert extends Statement { + /** + * TODO + */ + @NotNull + public final IdentifierChain tableName; + + /** + * TODO + */ + @Nullable + public final Identifier asAlias; + + /** + * TODO + */ + @NotNull + public final InsertSource source; + + /** + * TODO + * @param tableName TODO + * @param asAlias TODO + * @param source TODO + */ + public Upsert(@NotNull IdentifierChain tableName, @Nullable Identifier asAlias, @NotNull InsertSource source) { + this.tableName = tableName; + this.asAlias = asAlias; + this.source = source; + } + + @NotNull + @Override + public Collection children() { + List kids = new ArrayList<>(); + kids.add(tableName); + if (asAlias != null) { + kids.add(asAlias); + } + kids.add(source); + return kids; + } + + @Override + public R accept(@NotNull AstVisitor visitor, C ctx) { + return visitor.visitUpsert(this, ctx); + } +} diff --git a/partiql-ast/src/main/java/org/partiql/ast/expr/ExprRowValue.java b/partiql-ast/src/main/java/org/partiql/ast/expr/ExprRowValue.java index 391d55d1f..612ff066f 100644 --- a/partiql-ast/src/main/java/org/partiql/ast/expr/ExprRowValue.java +++ b/partiql-ast/src/main/java/org/partiql/ast/expr/ExprRowValue.java @@ -10,16 +10,43 @@ import java.util.List; /** - * TODO docs, equals, hashcode - * Also add optional [ROW] keyword property. https://ronsavage.github.io/SQL/sql-99.bnf.html#row%20value%20constructor + * This represents SQL:1999's row value constructor. EBNF: + * + * <row value constructor> ::= + * <row value constructor element> + * | [ ROW ] <left paren> <row value constructor element list> <right paren> + * | <row subquery> + * + * This specifically models the second variant where the keyword {@code ROW} is used. */ @lombok.Builder(builderClassName = "Builder") @EqualsAndHashCode(callSuper = false) public class ExprRowValue extends Expr { + /** + * Specifies whether the ROW keyword explicitly precedes the elements in the textual representation. For example, + * {@code ROW (1, 2, 3)} versus {@code (1, 2, 3)}. In the first example, {@code isExplicit} is true. + */ + public boolean isExplicit; + @NotNull public final List values; + /** + * By default, {@link ExprRowValue#isExplicit} is false. + * @param values TODO + */ public ExprRowValue(@NotNull List values) { + this.isExplicit = false; + this.values = values; + } + + /** + * TODO + * @param isExplicit TODO + * @param values TODO + */ + public ExprRowValue(boolean isExplicit, @NotNull List values) { + this.isExplicit = isExplicit; this.values = values; } diff --git a/partiql-ast/src/main/java/org/partiql/ast/expr/ExprValues.java b/partiql-ast/src/main/java/org/partiql/ast/expr/ExprValues.java index cb0af0232..1af83eac0 100644 --- a/partiql-ast/src/main/java/org/partiql/ast/expr/ExprValues.java +++ b/partiql-ast/src/main/java/org/partiql/ast/expr/ExprValues.java @@ -11,17 +11,28 @@ import java.util.List; /** - * TODO docs, equals, hashcode - * Also may not be an [Expr]? - * Tracking issue for VALUES and subqueries -- https://github.com/partiql/partiql-lang-kotlin/issues/1641. + * This represents SQL:1999's table value constructor. + * + * <table value constructor> ::= VALUES <row value expression list> + * */ @Builder(builderClassName = "Builder") @EqualsAndHashCode(callSuper = false) public class ExprValues extends Expr { + // TODO: May not be an expr? + // TODO: Tracking issue for VALUES and subqueries -- https://github.com/partiql/partiql-lang-kotlin/issues/1641. + + /** + * TODO + */ @NotNull - public final List rows; + public final List rows; - public ExprValues(@NotNull List rows) { + /** + * TODO + * @param rows TODO + */ + public ExprValues(@NotNull List rows) { this.rows = rows; } 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 78107c1f7..2d4db952c 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 @@ -49,6 +49,11 @@ import org.partiql.ast.SetOpType import org.partiql.ast.SetQuantifier import org.partiql.ast.Sort import org.partiql.ast.ddl.Ddl +import org.partiql.ast.dml.Delete +import org.partiql.ast.dml.Insert +import org.partiql.ast.dml.Replace +import org.partiql.ast.dml.Update +import org.partiql.ast.dml.Upsert import org.partiql.ast.expr.Expr import org.partiql.ast.expr.ExprAnd import org.partiql.ast.expr.ExprArray @@ -772,6 +777,26 @@ public abstract class SqlDialect : AstVisitor() { throw UnsupportedOperationException("DDL has not been supported yet in SqlDialect") } + override fun visitInsert(node: Insert?, ctx: SqlBlock?): SqlBlock { + throw UnsupportedOperationException("INSERT has not been supported yet in SqlDialect") + } + + override fun visitDelete(node: Delete?, ctx: SqlBlock?): SqlBlock { + throw UnsupportedOperationException("DELETE has not been supported yet in SqlDialect") + } + + override fun visitUpsert(node: Upsert?, ctx: SqlBlock?): SqlBlock { + throw UnsupportedOperationException("UPSERT has not been supported yet in SqlDialect") + } + + override fun visitReplace(node: Replace?, ctx: SqlBlock?): SqlBlock { + throw UnsupportedOperationException("REPLACE has not been supported yet in SqlDialect") + } + + override fun visitUpdate(node: Update?, ctx: SqlBlock?): SqlBlock { + throw UnsupportedOperationException("UPDATE has not been supported yet in SqlDialect") + } + // --- Block Constructor Helpers private infix fun SqlBlock.concat(rhs: String): SqlBlock { 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 e05dfaefe..b11360b42 100644 --- a/partiql-ast/src/main/kotlin/org/partiql/ast/Ast.kt +++ b/partiql-ast/src/main/kotlin/org/partiql/ast/Ast.kt @@ -6,6 +6,20 @@ import org.partiql.ast.ddl.CreateTable import org.partiql.ast.ddl.KeyValue import org.partiql.ast.ddl.PartitionBy import org.partiql.ast.ddl.TableConstraint +import org.partiql.ast.dml.ConflictAction +import org.partiql.ast.dml.ConflictTarget +import org.partiql.ast.dml.Delete +import org.partiql.ast.dml.DoReplaceAction +import org.partiql.ast.dml.DoUpdateAction +import org.partiql.ast.dml.Insert +import org.partiql.ast.dml.InsertSource +import org.partiql.ast.dml.OnConflict +import org.partiql.ast.dml.Replace +import org.partiql.ast.dml.SetClause +import org.partiql.ast.dml.Update +import org.partiql.ast.dml.UpdateTarget +import org.partiql.ast.dml.UpdateTargetStep +import org.partiql.ast.dml.Upsert import org.partiql.ast.expr.Expr import org.partiql.ast.expr.ExprAnd import org.partiql.ast.expr.ExprArray @@ -205,7 +219,8 @@ public object Ast { } @JvmStatic - public fun exprValues(rows: List): ExprValues { + public fun exprValues(rows: List): ExprValues { + // TODO: Is exprTable the right name here? IMO, ExprValues should really just be called TableValueConstructor to match the EBNF return ExprValues(rows) } @@ -214,6 +229,11 @@ public object Ast { return ExprRowValue(values) } + @JvmStatic + public fun exprRowValue(values: List, isExplicit: Boolean): ExprRowValue { + return ExprRowValue(isExplicit, values) + } + @JvmStatic public fun exprVariant(value: String, encoding: String): ExprVariant { return ExprVariant(value, encoding) @@ -449,6 +469,106 @@ public object Ast { return Query(expr) } + @JvmStatic + public fun insert(tableName: IdentifierChain, asAlias: Identifier?, source: InsertSource, onConflict: OnConflict?): Insert { + return Insert(tableName, asAlias, source, onConflict) + } + + @JvmStatic + public fun upsert(tableName: IdentifierChain, asAlias: Identifier?, source: InsertSource): Upsert { + return Upsert(tableName, asAlias, source) + } + + @JvmStatic + public fun replace(tableName: IdentifierChain, asAlias: Identifier?, source: InsertSource): Replace { + return Replace(tableName, asAlias, source) + } + + @JvmStatic + public fun update(tableName: IdentifierChain, setClauses: List, condition: Expr?): Update { + return Update(tableName, setClauses, condition) + } + + @JvmStatic + public fun delete(tableName: IdentifierChain, condition: Expr?): Delete { + return Delete(tableName, condition) + } + + @JvmStatic + public fun setClause(target: UpdateTarget, value: Expr): SetClause { + return SetClause(target, value) + } + + @JvmStatic + public fun insertSourceExpr(columns: List?, expr: Expr): InsertSource.FromExpr { + return InsertSource.FromExpr(columns, expr) + } + + @JvmStatic + public fun insertSourceDefault(): InsertSource.FromDefault { + return InsertSource.FromDefault() + } + + @JvmStatic + public fun onConflict(action: ConflictAction, target: ConflictTarget?): OnConflict { + return OnConflict(action, target) + } + + @JvmStatic + public fun conflictTargetIndex(indexes: List): ConflictTarget.Index { + return ConflictTarget.Index(indexes) + } + + @JvmStatic + public fun conflictTargetConstraint(constraint: IdentifierChain): ConflictTarget.Constraint { + return ConflictTarget.Constraint(constraint) + } + + @JvmStatic + public fun doNothing(): ConflictAction.DoNothing { + return ConflictAction.DoNothing() + } + + @JvmStatic + public fun doReplace(action: DoReplaceAction, condition: Expr?): ConflictAction.DoReplace { + return ConflictAction.DoReplace(action, condition) + } + + @JvmStatic + public fun doUpdate(action: DoUpdateAction, condition: Expr?): ConflictAction.DoUpdate { + return ConflictAction.DoUpdate(action, condition) + } + + @JvmStatic + public fun doReplaceActionExcluded(): DoReplaceAction.Excluded { + return DoReplaceAction.Excluded() + } + + @JvmStatic + public fun doUpdateActionExcluded(): DoUpdateAction.Excluded { + return DoUpdateAction.Excluded() + } + + @JvmStatic + public fun updateTarget(root: Identifier, steps: List): UpdateTarget { + return UpdateTarget(root, steps) + } + + @JvmStatic + public fun updateTargetStepElement(key: Int): UpdateTargetStep.Element { + return UpdateTargetStep.Element(key) + } + + @JvmStatic + public fun updateTargetStepElement(key: String): UpdateTargetStep.Element { + return UpdateTargetStep.Element(key) + } + + @JvmStatic + public fun updateTargetStepField(key: Identifier): UpdateTargetStep.Field { + return UpdateTargetStep.Field(key) + } + @JvmStatic public fun queryBodySFW( select: Select, 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 8a05cdfdb..b54415dfd 100644 --- a/partiql-ast/src/main/kotlin/org/partiql/ast/AstRewriter.kt +++ b/partiql-ast/src/main/kotlin/org/partiql/ast/AstRewriter.kt @@ -5,6 +5,20 @@ import org.partiql.ast.Ast.exprQuerySet import org.partiql.ast.Ast.identifier import org.partiql.ast.Ast.query import org.partiql.ast.ddl.Ddl +import org.partiql.ast.dml.ConflictAction +import org.partiql.ast.dml.ConflictTarget +import org.partiql.ast.dml.Delete +import org.partiql.ast.dml.DoReplaceAction +import org.partiql.ast.dml.DoUpdateAction +import org.partiql.ast.dml.Insert +import org.partiql.ast.dml.InsertSource +import org.partiql.ast.dml.OnConflict +import org.partiql.ast.dml.Replace +import org.partiql.ast.dml.SetClause +import org.partiql.ast.dml.Update +import org.partiql.ast.dml.UpdateTarget +import org.partiql.ast.dml.UpdateTargetStep +import org.partiql.ast.dml.Upsert import org.partiql.ast.expr.Expr import org.partiql.ast.expr.ExprAnd import org.partiql.ast.expr.ExprArray @@ -352,7 +366,7 @@ public abstract class AstRewriter : AstVisitor() { } override fun visitExprValues(node: ExprValues, ctx: C): AstNode { - val values = _visitList(node.rows, ctx, ::visitExprRowValue) + val values = _visitList(node.rows, ctx, ::visitExpr) return if (values !== node.rows) { ExprValues(values) } else { @@ -757,4 +771,156 @@ public abstract class AstRewriter : AstVisitor() { override fun visitDdl(node: Ddl, ctx: C): AstNode { throw UnsupportedOperationException("DDL has not been supported yet in AstRewriter") } + + override fun visitInsert(node: Insert, ctx: C): AstNode { + val source = visitInsertSource(node.source, ctx) as InsertSource + val target = visitIdentifierChain(node.tableName, ctx) as IdentifierChain + val asAlias = node.asAlias?.let { visitIdentifier(it, ctx) as Identifier } + val onConflict = node.onConflict?.let { visitOnConflict(it, ctx) as OnConflict } + if (source !== node.source || target !== node.tableName || asAlias !== node.asAlias || onConflict !== node.onConflict) { + return Insert(target, asAlias, source, onConflict) + } + return node + } + + override fun visitInsertSourceFromExpr(node: InsertSource.FromExpr, ctx: C): AstNode { + val expr = visitExpr(node.expr, ctx) as Expr + val columns = node.columns?.let { _visitList(it, ctx, ::visitIdentifier) } + if (expr !== node.expr || columns != node.columns) { + return InsertSource.FromExpr(columns, expr) + } + return node + } + + override fun visitInsertSourceFromDefault(node: InsertSource.FromDefault, ctx: C): AstNode { + return node + } + + override fun visitOnConflict(node: OnConflict, ctx: C): AstNode { + val action = visitConflictAction(node.action, ctx) as ConflictAction + val target = visitConflictTarget(node.target, ctx) as ConflictTarget + if (action !== node.action || target !== node.target) { + return OnConflict(action, target) + } + return node + } + + override fun visitConflictActionDoNothing(node: ConflictAction.DoNothing, ctx: C): AstNode { + return node + } + + override fun visitConflictActionDoReplace(node: ConflictAction.DoReplace, ctx: C): AstNode { + val action = visitDoReplaceAction(node.action, ctx) as DoReplaceAction + val condition = node.condition?.let { visitExpr(it, ctx) as Expr } + if (action !== node.action || condition !== node.condition) { + return ConflictAction.DoReplace(action, condition) + } + return node + } + + override fun visitConflictActionDoUpdate(node: ConflictAction.DoUpdate, ctx: C): AstNode { + val action = visitDoUpdateAction(node.action, ctx) as DoUpdateAction + val condition = node.condition?.let { visitExpr(it, ctx) as Expr } + if (action !== node.action || condition !== node.condition) { + return ConflictAction.DoUpdate(action, condition) + } + return node + } + + override fun visitConflictTargetConstraint(node: ConflictTarget.Constraint, ctx: C): AstNode { + val constraint = visitIdentifierChain(node.name, ctx) as IdentifierChain + if (constraint !== node.name) { + return ConflictTarget.Constraint(constraint) + } + return node + } + + override fun visitConflictTargetIndex(node: ConflictTarget.Index, ctx: C): AstNode { + val indexes = _visitList(node.indexes, ctx, ::visitIdentifier) + if (indexes !== node.indexes) { + return ConflictTarget.Index(indexes) + } + return node + } + + override fun visitDoReplaceActionExcluded(node: DoReplaceAction.Excluded, ctx: C): AstNode { + return node + } + + override fun visitDoUpdateActionExcluded(node: DoUpdateAction.Excluded, ctx: C): AstNode { + return node + } + + override fun visitDelete(node: Delete, ctx: C): AstNode { + val tableName = visitIdentifierChain(node.tableName, ctx) as IdentifierChain + val condition = node.condition?.let { visitExpr(it, ctx) as Expr } + if (tableName !== node.tableName || condition !== node.condition) { + return Delete(tableName, condition) + } + return node + } + + override fun visitUpsert(node: Upsert, ctx: C): AstNode { + val tableName = visitIdentifierChain(node.tableName, ctx) as IdentifierChain + val source = visitInsertSource(node.source, ctx) as InsertSource + val asAlias = node.asAlias?.let { visitIdentifier(it, ctx) as Identifier } + if (tableName !== node.tableName || source !== node.source || asAlias !== node.asAlias) { + return Upsert(tableName, asAlias, source) + } + return node + } + + override fun visitReplace(node: Replace, ctx: C): AstNode { + val tableName = visitIdentifierChain(node.tableName, ctx) as IdentifierChain + val source = visitInsertSource(node.source, ctx) as InsertSource + val asAlias = node.asAlias?.let { visitIdentifier(it, ctx) as Identifier } + if (tableName !== node.tableName || source !== node.source || asAlias !== node.asAlias) { + return Replace(tableName, asAlias, source) + } + return node + } + + override fun visitSetClause(node: SetClause, ctx: C): AstNode { + val target = visitUpdateTarget(node.target, ctx) as UpdateTarget + val expr = visitExpr(node.expr, ctx) as Expr + if (target !== node.target || expr !== node.expr) { + return SetClause(target, expr) + } + return node + } + + override fun visitUpdate(node: Update, ctx: C): AstNode { + val tableName = visitIdentifierChain(node.tableName, ctx) as IdentifierChain + val setClauses = _visitList(node.setClauses, ctx, ::visitSetClause) + val condition = node.condition?.let { visitExpr(it, ctx) as Expr } + if (tableName !== node.tableName || setClauses !== node.setClauses || condition !== node.condition) { + return Update(tableName, setClauses, condition) + } + return node + } + + override fun visitUpdateTarget(node: UpdateTarget, ctx: C): AstNode { + val root = visitIdentifier(node.root, ctx) as Identifier + val steps = _visitList(node.steps, ctx, ::visitUpdateTargetStep) + if (root !== node.root || steps !== node.steps) { + return UpdateTarget(root, steps) + } + return node + } + + override fun visitUpdateTargetStepElement(node: UpdateTargetStep.Element, ctx: C): AstNode { + val exprLit = visitLiteral(node.key, ctx) as Literal + if (exprLit !== node.key) { + return UpdateTargetStep.Element(exprLit) + } + return node + } + + override fun visitUpdateTargetStepField(node: UpdateTargetStep.Field, ctx: C): AstNode { + val key = visitIdentifier(node.key, ctx) as Identifier + if (key !== node.key) { + return UpdateTargetStep.Field(key) + } + return node + } } diff --git a/partiql-parser/src/main/antlr/PartiQLParser.g4 b/partiql-parser/src/main/antlr/PartiQLParser.g4 index a56fbad35..3f050e3d8 100644 --- a/partiql-parser/src/main/antlr/PartiQLParser.g4 +++ b/partiql-parser/src/main/antlr/PartiQLParser.g4 @@ -17,11 +17,23 @@ statements ; statement - : dql # QueryDql - | dml # QueryDml - | ddl # QueryDdl - | execCommand # QueryExec // TODO delete in `v1` release - | EXPLAIN (PAREN_LEFT explainOption (COMMA explainOption)* PAREN_RIGHT)? statement # Explain + // DQL + : dql + + // DML + | insertStatement + | updateStatementSearched + | deleteStatementSearched + | upsertStatement + | replaceStatement + + // DDL + | createCommand + | dropCommand + + // OTHER + | explainStatement + // TODO: SQL's : | execCommand ; /** @@ -30,9 +42,6 @@ statement * */ -explainOption - : param=IDENTIFIER value=IDENTIFIER; - asIdent : AS symbolPrimitive; @@ -48,6 +57,14 @@ symbolPrimitive | nonReserved # IdentifierUnquoted ; +// ::= [ ] +qualifiedName : (qualifier+=symbolPrimitive PERIOD)* name=symbolPrimitive; + +tableName : symbolPrimitive; +tableConstraintName : symbolPrimitive; +columnName : symbolPrimitive; +columnConstraintName : symbolPrimitive; + /** * * DATA QUERY LANGUAGE (DQL) @@ -56,6 +73,20 @@ symbolPrimitive dql : expr; + +// +// +// EXPLAIN +// +// + +explainStatement + : EXPLAIN (PAREN_LEFT explainOption (COMMA explainOption)* PAREN_RIGHT)? statement # Explain + ; + +explainOption + : param=IDENTIFIER value=IDENTIFIER + ; /** * @@ -76,12 +107,6 @@ execCommand * Currently, this is a small subset of SQL DDL that is likely to make sense for PartiQL as well. */ -// ::= [ ] -qualifiedName : (qualifier+=symbolPrimitive PERIOD)* name=symbolPrimitive; - -tableName : symbolPrimitive; -tableConstraintName : symbolPrimitive; -columnName : symbolPrimitive; comment : COMMENT LITERAL_STRING; ddl @@ -91,7 +116,7 @@ ddl createCommand : CREATE TABLE qualifiedName ( PAREN_LEFT tableDef PAREN_RIGHT )? tableExtension* # CreateTable - | CREATE INDEX ON symbolPrimitive PAREN_LEFT pathSimple ( COMMA pathSimple )* PAREN_RIGHT # CreateIndex + // TODO: Do we need this? | CREATE INDEX ON symbolPrimitive PAREN_LEFT pathSimple ( COMMA pathSimple )* PAREN_RIGHT # CreateIndex ; dropCommand @@ -153,139 +178,135 @@ keyValuePair : key=LITERAL_STRING EQ value=LITERAL_STRING; partitionBy : PAREN_LEFT columnName (COMMA columnName)* PAREN_RIGHT #PartitionColList ; + /** * * DATA MANIPULATION LANGUAGE (DML) - * + * TODO: Determine future of REMOVE DML statement: https://github.com/partiql/partiql-lang-kotlin/issues/1668 + * TODO: Determine future of FROM (INSERT, SET, REMOVE) statements: https://github.com/partiql/partiql-lang-kotlin/issues/1669 + * TODO: Implement the RETURNING clause for INSERT/UPDATE. See https://github.com/partiql/partiql-lang-kotlin/issues/1667 */ -// TODO delete / rewrite rules ahead of `v1` release. Legacy DML rules can be deleted. Spec'd rules (e.g. PartiQL RFC -// and SQL spec) should be easier to rewrite once the legacy DML rules are deleted. -dml - : updateClause dmlBaseCommand+ whereClause? returningClause? # DmlBaseWrapper - | fromClause whereClause? dmlBaseCommand+ returningClause? # DmlBaseWrapper - | deleteCommand # DmlDelete - | insertCommandReturning # DmlInsertReturning - | dmlBaseCommand # DmlBase - ; + +// +// +// DML Statements +// +// -dmlBaseCommand - : insertStatement - | insertStatementLegacy - | setCommand - | replaceCommand - | removeCommand - | upsertCommand - ; +/** + * @see https://github.com/partiql/partiql-lang/blob/main/RFCs/0011-partiql-insert.md#2-proposed-grammar-and-semantics + */ +insertStatement: INSERT INTO tblName=qualifiedName asIdent? insertSource onConflict?; -pathSimple - : symbolPrimitive pathSimpleSteps*; +/** + * @see https://ronsavage.github.io/SQL/sql-99.bnf.html#update%20statement:%20searched + */ +updateStatementSearched: UPDATE targetTable=qualifiedName SET setClauseList ( WHERE searchCond=expr )?; -pathSimpleSteps - : BRACKET_LEFT key=literal BRACKET_RIGHT # PathSimpleLiteral - | BRACKET_LEFT key=symbolPrimitive BRACKET_RIGHT # PathSimpleSymbol - | PERIOD key=symbolPrimitive # PathSimpleDotSymbol +/** + * @see https://ronsavage.github.io/SQL/sql-99.bnf.html#delete%20statement:%20searched + */ +deleteStatementSearched: DELETE FROM targetTable=qualifiedName ( WHERE searchCond=expr )?; + +/** + * @see https://github.com/partiql/partiql-lang/blob/main/RFCs/0030-partiql-upsert-replace.md + */ +upsertStatement: UPSERT INTO tblName=qualifiedName asIdent? insertSource; + +/** + * @see https://github.com/partiql/partiql-lang/blob/main/RFCs/0030-partiql-upsert-replace.md + */ +replaceStatement: REPLACE INTO tblName=qualifiedName asIdent? insertSource; + +// +// +// INSERT STATEMENT STRUCTURES +// +// + +insertSource + : insertFromSubquery + | insertFromDefault ; -// Based on https://github.com/partiql/partiql-docs/blob/main/RFCs/0011-partiql-insert.md -// TODO add parsing of target attributes: https://github.com/partiql/partiql-lang-kotlin/issues/841 -replaceCommand - : REPLACE INTO symbolPrimitive asIdent? value=expr; +insertFromSubquery: insertColumnList? expr; -// Based on https://github.com/partiql/partiql-docs/blob/main/RFCs/0011-partiql-insert.md -// TODO add parsing of target attributes: https://github.com/partiql/partiql-lang-kotlin/issues/841 -upsertCommand - : UPSERT INTO symbolPrimitive asIdent? value=expr; +insertFromDefault: DEFAULT VALUES; -removeCommand - : REMOVE pathSimple; +insertColumnList: PAREN_LEFT names+=symbolPrimitive ( COMMA names+=symbolPrimitive )* PAREN_RIGHT; -// FIXME #001 -// There is a bug in the old SqlParser that needed to be replicated to the PartiQLParser for the sake of ... -// ... same functionality. Using 2 returning clauses always uses the second clause. This should be fixed. -// See GH Issue: https://github.com/partiql/partiql-lang-kotlin/issues/698 -// We essentially use the returning clause, because we currently support this with the SqlParser. -// See https://github.com/partiql/partiql-lang-kotlin/issues/708 -insertCommandReturning - : INSERT INTO pathSimple VALUE value=expr ( AT pos=expr )? onConflictLegacy? returningClause?; +// +// +// UPDATE STATEMENT STRUCTURES +// +// -// See the Grammar at https://github.com/partiql/partiql-docs/blob/main/RFCs/0011-partiql-insert.md#2-proposed-grammar-and-semantics -insertStatement - : INSERT INTO symbolPrimitive asIdent? value=expr onConflict? - ; +/** + * @see https://ronsavage.github.io/SQL/sql-99.bnf.html#set%20clause%20list + */ +setClauseList: setClause ( COMMA setClause )*; -onConflict - : ON CONFLICT conflictTarget? conflictAction - ; +/** + * @see https://ronsavage.github.io/SQL/sql-99.bnf.html#set%20clause + * The above referenced set clause doesn't exactly allow for the flexibility provided by updateTarget (previously + * named pathSimple). The SQL:1999 EBNF states that can either be a column name or a column name + * followed by square brackets and a literal (or other simple value). Since PartiQL allows for setting a nested attribute + * the updateTarget here provides for a superset of SQL's + */ +setClause: updateTarget EQ expr; -insertStatementLegacy - : INSERT INTO pathSimple VALUE value=expr ( AT pos=expr )? onConflictLegacy? - ; +updateTarget: symbolPrimitive updateTargetStep*; -onConflictLegacy - : ON CONFLICT WHERE expr DO NOTHING +// TODO: https://github.com/partiql/partiql-lang-kotlin/issues/1671 +updateTargetStep + : updateTargetStepElement + | updateTargetStepField ; -/** - ::= - ( [, ]... ) - | ( { | } ) - | ON CONSTRAINT -*/ +updateTargetStepElement: BRACKET_LEFT key=literal BRACKET_RIGHT; + +updateTargetStepField: PERIOD key=symbolPrimitive; + +// +// +// ON CONFLICT CLAUSE +// @see https://github.com/partiql/partiql-lang/blob/main/RFCs/0030-partiql-upsert-replace.md +// TODO: Add the rest of the grammar +// + +onConflict: ON CONFLICT conflictTarget? conflictAction; + conflictTarget - : PAREN_LEFT symbolPrimitive (COMMA symbolPrimitive)* PAREN_RIGHT - | ON CONSTRAINT constraintName; + : conflictTargetIndex + | conflictTargetConstraint + ; -constraintName - : qualifiedName; +conflictTargetIndex: PAREN_LEFT symbolPrimitive (COMMA symbolPrimitive)* PAREN_RIGHT; -conflictAction - : DO NOTHING - | DO REPLACE doReplace - | DO UPDATE doUpdate; - -/* - ::= EXCLUDED - | SET [, ]... - | VALUE - [ WHERE ] -*/ -doReplace - : EXCLUDED ( WHERE condition=expr )?; - // :TODO add the rest of the grammar - -/* - ::= EXCLUDED - | SET [, ]... - | VALUE - [ WHERE ] -*/ -doUpdate - : EXCLUDED ( WHERE condition=expr )?; - // :TODO add the rest of the grammar +conflictTargetConstraint: ON CONSTRAINT constraintName ; -updateClause - : UPDATE tableBaseReference; +constraintName: qualifiedName; -setCommand - : SET setAssignment ( COMMA setAssignment )*; +conflictAction + : doNothing + | doReplace + | doUpdate + ; -setAssignment - : pathSimple EQ expr; +doNothing: DO NOTHING; -deleteCommand - : DELETE fromClauseSimple whereClause? returningClause?; +doReplace: DO REPLACE doReplaceAction ( WHERE condition=expr )?; -returningClause - : RETURNING returningColumn ( COMMA returningColumn )*; +doUpdate: DO UPDATE doUpdateAction ( WHERE condition=expr )?; -returningColumn - : status=(MODIFIED|ALL) age=(OLD|NEW) ASTERISK - | status=(MODIFIED|ALL) age=(OLD|NEW) col=expr +doReplaceAction + : EXCLUDED + // ... ; -fromClauseSimple - : FROM pathSimple asIdent? atIdent? byIdent? # FromClauseSimpleExplicit - | FROM pathSimple symbolPrimitive # FromClauseSimpleImplicit +doUpdateAction + : EXCLUDED + // ... ; whereClause @@ -675,9 +696,9 @@ exprPrimary | exprPrimary pathStep+ # ExprPrimaryPath | exprGraphMatchMany # ExprPrimaryBase | caseExpr # ExprPrimaryBase - | valueList # ExprPrimaryBase - | values # ExprPrimaryBase | windowFunction # ExprPrimaryBase + | rowValueConstructor # ExprPrimaryBase + | tableValueConstructor # ExprPrimaryBase ; /** @@ -685,6 +706,40 @@ exprPrimary * PRIMARY EXPRESSIONS * */ + +/** + * From SQL:1999: + * ::= VALUES + * Or: + * ::= VALUES + * + * Since this can be used as a (top-level value), we are making this an [expr]. + */ +tableValueConstructor + : VALUES rowValueExpressionList + ; + +/** + * From SQL:1999: + * ::= + * [ { }... ] + */ +rowValueExpressionList + : expr ( COMMA expr )* + ; + +/** + * From SQL:1999: + * ::= + * + * | [ ROW ] + * | + * + * Since the other variants are covered by [expr], this ANTLR rule specifically targets the second variant. + */ +rowValueConstructor + : ROW? PAREN_LEFT expr ( COMMA expr )* PAREN_RIGHT + ; exprTerm : PAREN_LEFT expr PAREN_RIGHT # ExprTermWrappedQuery @@ -706,15 +761,6 @@ coalesce caseExpr : CASE case=expr? (WHEN whens+=expr THEN thens+=expr)+ (ELSE else=expr)? END; -values - : VALUES valueRow ( COMMA valueRow )*; - -valueRow - : PAREN_LEFT expr ( COMMA expr )* PAREN_RIGHT; - -valueList - : PAREN_LEFT expr ( COMMA expr )+ PAREN_RIGHT; - sequenceConstructor : datatype=(LIST|SEXP) PAREN_LEFT (expr ( COMMA expr )* )? PAREN_RIGHT; diff --git a/partiql-parser/src/main/antlr/PartiQLTokens.g4 b/partiql-parser/src/main/antlr/PartiQLTokens.g4 index 654803a21..c4c9f6a53 100644 --- a/partiql-parser/src/main/antlr/PartiQLTokens.g4 +++ b/partiql-parser/src/main/antlr/PartiQLTokens.g4 @@ -202,6 +202,7 @@ RESTRICT: 'RESTRICT'; REVOKE: 'REVOKE'; RIGHT: 'RIGHT'; ROLLBACK: 'ROLLBACK'; +ROW: 'ROW'; ROWS: 'ROWS'; SCHEMA: 'SCHEMA'; SCROLL: 'SCROLL'; 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 6d551db5c..6897b858a 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 @@ -35,7 +35,15 @@ import org.partiql.ast.Ast.columnConstraintCheck import org.partiql.ast.Ast.columnConstraintNullable import org.partiql.ast.Ast.columnConstraintUnique import org.partiql.ast.Ast.columnDefinition +import org.partiql.ast.Ast.conflictTargetConstraint +import org.partiql.ast.Ast.conflictTargetIndex import org.partiql.ast.Ast.createTable +import org.partiql.ast.Ast.delete +import org.partiql.ast.Ast.doNothing +import org.partiql.ast.Ast.doReplace +import org.partiql.ast.Ast.doReplaceActionExcluded +import org.partiql.ast.Ast.doUpdate +import org.partiql.ast.Ast.doUpdateActionExcluded import org.partiql.ast.Ast.exclude import org.partiql.ast.Ast.excludePath import org.partiql.ast.Ast.excludeStepCollIndex @@ -71,11 +79,13 @@ import org.partiql.ast.Ast.exprPathStepElement import org.partiql.ast.Ast.exprPathStepField import org.partiql.ast.Ast.exprPosition import org.partiql.ast.Ast.exprQuerySet +import org.partiql.ast.Ast.exprRowValue import org.partiql.ast.Ast.exprSessionAttribute import org.partiql.ast.Ast.exprStruct import org.partiql.ast.Ast.exprStructField import org.partiql.ast.Ast.exprSubstring import org.partiql.ast.Ast.exprTrim +import org.partiql.ast.Ast.exprValues import org.partiql.ast.Ast.exprVarRef import org.partiql.ast.Ast.exprVariant import org.partiql.ast.Ast.exprWindow @@ -104,22 +114,31 @@ import org.partiql.ast.Ast.groupBy import org.partiql.ast.Ast.groupByKey import org.partiql.ast.Ast.identifier import org.partiql.ast.Ast.identifierChain +import org.partiql.ast.Ast.insert +import org.partiql.ast.Ast.insertSourceDefault +import org.partiql.ast.Ast.insertSourceExpr import org.partiql.ast.Ast.keyValue import org.partiql.ast.Ast.letBinding +import org.partiql.ast.Ast.onConflict import org.partiql.ast.Ast.orderBy import org.partiql.ast.Ast.partitionBy import org.partiql.ast.Ast.query import org.partiql.ast.Ast.queryBodySFW import org.partiql.ast.Ast.queryBodySetOp +import org.partiql.ast.Ast.replace import org.partiql.ast.Ast.selectItemExpr import org.partiql.ast.Ast.selectItemStar import org.partiql.ast.Ast.selectList import org.partiql.ast.Ast.selectPivot import org.partiql.ast.Ast.selectStar import org.partiql.ast.Ast.selectValue +import org.partiql.ast.Ast.setClause import org.partiql.ast.Ast.setOp import org.partiql.ast.Ast.sort import org.partiql.ast.Ast.tableConstraintUnique +import org.partiql.ast.Ast.update +import org.partiql.ast.Ast.updateTarget +import org.partiql.ast.Ast.upsert import org.partiql.ast.AstNode import org.partiql.ast.DataType import org.partiql.ast.DatetimeField @@ -154,12 +173,19 @@ import org.partiql.ast.ddl.AttributeConstraint import org.partiql.ast.ddl.ColumnDefinition import org.partiql.ast.ddl.PartitionBy import org.partiql.ast.ddl.TableConstraint +import org.partiql.ast.dml.ConflictAction +import org.partiql.ast.dml.ConflictTarget +import org.partiql.ast.dml.InsertSource +import org.partiql.ast.dml.OnConflict +import org.partiql.ast.dml.UpdateTargetStep import org.partiql.ast.expr.Expr import org.partiql.ast.expr.ExprArray import org.partiql.ast.expr.ExprBag import org.partiql.ast.expr.ExprCall +import org.partiql.ast.expr.ExprLit import org.partiql.ast.expr.ExprPath import org.partiql.ast.expr.ExprQuerySet +import org.partiql.ast.expr.ExprRowValue import org.partiql.ast.expr.PathStep import org.partiql.ast.expr.Scope import org.partiql.ast.expr.SessionAttribute @@ -437,12 +463,6 @@ internal class PartiQLParserDefault : PartiQLParser { * */ - override fun visitQueryDql(ctx: GeneratedParser.QueryDqlContext): AstNode = visitDql(ctx.dql()) - - override fun visitQueryDml(ctx: GeneratedParser.QueryDmlContext): AstNode = translate(ctx) { - throw error(ctx, "DML no longer supported in the default PartiQLParser.") - } - override fun visitExplain(ctx: GeneratedParser.ExplainContext) = translate(ctx) { var type: String? = null var format: String? = null @@ -521,8 +541,6 @@ internal class PartiQLParserDefault : PartiQLParser { * */ - override fun visitQueryDdl(ctx: GeneratedParser.QueryDdlContext): AstNode = visitDdl(ctx.ddl()) - // TODO: Drop Table; Not sure if we want to add this in V1 // override fun visitDropTable(ctx: GeneratedParser.DropTableContext) = translate(ctx) { // val table = visitQualifiedName(ctx.qualifiedName()) @@ -679,10 +697,6 @@ internal class PartiQLParserDefault : PartiQLParser { * */ - override fun visitQueryExec(ctx: GeneratedParser.QueryExecContext) = translate(ctx) { - throw error(ctx, "EXEC no longer supported in the default PartiQLParser.") - } - /** * TODO EXEC accepts an `expr` as the procedure name so we have to unpack the string. * - https://github.com/partiql/partiql-lang-kotlin/issues/707 @@ -697,130 +711,128 @@ internal class PartiQLParserDefault : PartiQLParser { * */ - /** - * The PartiQL grammars allows for multiple DML commands in one UPDATE statement. - * This function unwraps DML commands to the more limited DML.BatchLegacy.Op commands. - */ - override fun visitDmlBaseWrapper(ctx: GeneratedParser.DmlBaseWrapperContext) = translate(ctx) { - throw error(ctx, "DML no longer supported in the default PartiQLParser.") - } - - override fun visitDmlDelete(ctx: GeneratedParser.DmlDeleteContext) = translate(ctx) { - throw error(ctx, "DML no longer supported in the default PartiQLParser.") + override fun visitInsertStatement(ctx: GeneratedParser.InsertStatementContext) = translate(ctx) { + val idChain = visitQualifiedName(ctx.tblName) + val onConflict = ctx.onConflict()?.let { visitOnConflict(it) } + val asAlias = ctx.asIdent()?.let { visitAsIdent(it) } + val source = visitInsertSource(ctx.insertSource()) + insert(idChain, asAlias, source, onConflict) } - override fun visitDmlInsertReturning(ctx: GeneratedParser.DmlInsertReturningContext) = translate(ctx) { - throw error(ctx, "DML no longer supported in the default PartiQLParser.") + override fun visitInsertSource(ctx: org.partiql.parser.internal.antlr.PartiQLParser.InsertSourceContext?): InsertSource { + return super.visitInsertSource(ctx) as InsertSource } - override fun visitDmlBase(ctx: GeneratedParser.DmlBaseContext) = translate(ctx) { - throw error(ctx, "DML no longer supported in the default PartiQLParser.") + override fun visitInsertFromSubquery(ctx: GeneratedParser.InsertFromSubqueryContext) = translate(ctx) { + val expr = visitExpr(ctx.expr()) + val columns = ctx.insertColumnList()?.let { it.symbolPrimitive().map { visitSymbolPrimitive(it) } } + insertSourceExpr(columns, expr) } - override fun visitDmlBaseCommand(ctx: GeneratedParser.DmlBaseCommandContext) = translate(ctx) { - throw error(ctx, "DML no longer supported in the default PartiQLParser.") + override fun visitInsertFromDefault(ctx: org.partiql.parser.internal.antlr.PartiQLParser.InsertFromDefaultContext) = translate(ctx) { + insertSourceDefault() } - override fun visitRemoveCommand(ctx: GeneratedParser.RemoveCommandContext) = translate(ctx) { - throw error(ctx, "DML no longer supported in the default PartiQLParser.") + override fun visitOnConflict(ctx: GeneratedParser.OnConflictContext): OnConflict = translate(ctx) { + val action = visitConflictAction(ctx.conflictAction()) + val target = ctx.conflictTarget()?.let { visitConflictTarget(it) } + onConflict(action, target) } - override fun visitDeleteCommand(ctx: GeneratedParser.DeleteCommandContext) = translate(ctx) { - throw error(ctx, "DML no longer supported in the default PartiQLParser.") + override fun visitConflictTarget(ctx: GeneratedParser.ConflictTargetContext): ConflictTarget = translate(ctx) { + super.visitConflictTarget(ctx) as ConflictTarget } - /** - * Legacy INSERT with RETURNING clause is not represented in the AST as this grammar .. - * .. only exists for backwards compatibility. The RETURNING clause is ignored. - * - * TODO remove insertCommandReturning grammar rule - * - https://github.com/partiql/partiql-lang-kotlin/issues/698 - * - https://github.com/partiql/partiql-lang-kotlin/issues/708 - */ - override fun visitInsertCommandReturning(ctx: GeneratedParser.InsertCommandReturningContext) = translate(ctx) { - throw error(ctx, "DML no longer supported in the default PartiQLParser.") + override fun visitConflictTargetIndex(ctx: GeneratedParser.ConflictTargetIndexContext): ConflictTarget.Index = translate(ctx) { + val indexes = ctx.symbolPrimitive().map { visitSymbolPrimitive(it) } + conflictTargetIndex(indexes) } - override fun visitInsertStatementLegacy(ctx: GeneratedParser.InsertStatementLegacyContext) = translate(ctx) { - throw error(ctx, "DML no longer supported in the default PartiQLParser.") + override fun visitConflictTargetConstraint(ctx: GeneratedParser.ConflictTargetConstraintContext) = translate(ctx) { + val constraint = visitQualifiedName(ctx.constraintName().qualifiedName()) + conflictTargetConstraint(constraint) } - override fun visitInsertStatement(ctx: GeneratedParser.InsertStatementContext) = translate(ctx) { - throw error(ctx, "DML no longer supported in the default PartiQLParser.") + override fun visitConflictAction(ctx: GeneratedParser.ConflictActionContext): ConflictAction = translate(ctx) { + super.visitConflictAction(ctx) as ConflictAction } - override fun visitReplaceCommand(ctx: GeneratedParser.ReplaceCommandContext) = translate(ctx) { - throw error(ctx, "DML no longer supported in the default PartiQLParser.") - } - - override fun visitUpsertCommand(ctx: GeneratedParser.UpsertCommandContext) = translate(ctx) { - throw error(ctx, "DML no longer supported in the default PartiQLParser.") - } - - override fun visitReturningClause(ctx: GeneratedParser.ReturningClauseContext) = translate(ctx) { - throw error(ctx, "DML no longer supported in the default PartiQLParser.") + override fun visitDoReplace(ctx: GeneratedParser.DoReplaceContext) = translate(ctx) { + val condition = ctx.condition?.let { visitExpr(it) } + val doReplaceAction = visitDoReplaceAction(ctx.doReplaceAction()) + doReplace(doReplaceAction, condition) } - override fun visitReturningColumn(ctx: GeneratedParser.ReturningColumnContext) = translate(ctx) { - throw error(ctx, "DML no longer supported in the default PartiQLParser.") + override fun visitDoNothing(ctx: GeneratedParser.DoNothingContext) = translate(ctx) { + doNothing() } - override fun visitOnConflict(ctx: GeneratedParser.OnConflictContext) = translate(ctx) { - throw error(ctx, "DML no longer supported in the default PartiQLParser.") + override fun visitDoUpdate(ctx: GeneratedParser.DoUpdateContext) = translate(ctx) { + val condition = ctx.condition?.let { visitExpr(it) } + val action = visitDoUpdateAction(ctx.doUpdateAction()) + doUpdate(action, condition) } - /** - * TODO Remove this when we remove INSERT LEGACY as no other conflict actions are allowed in PartiQL.g4. - */ - override fun visitOnConflictLegacy(ctx: GeneratedParser.OnConflictLegacyContext) = translate(ctx) { - throw error(ctx, "DML no longer supported in the default PartiQLParser.") + override fun visitDoReplaceAction(ctx: GeneratedParser.DoReplaceActionContext) = translate(ctx) { + doReplaceActionExcluded() } - override fun visitConflictTarget(ctx: GeneratedParser.ConflictTargetContext) = translate(ctx) { - throw error(ctx, "DML no longer supported in the default PartiQLParser.") + override fun visitDoUpdateAction(ctx: GeneratedParser.DoUpdateActionContext) = translate(ctx) { + doUpdateActionExcluded() } - override fun visitConflictAction(ctx: GeneratedParser.ConflictActionContext) = translate(ctx) { - throw error(ctx, "DML no longer supported in the default PartiQLParser.") + override fun visitUpdateTarget(ctx: GeneratedParser.UpdateTargetContext) = translate(ctx) { + val root = visitSymbolPrimitive(ctx.symbolPrimitive()) + val steps = ctx.updateTargetStep().map { visitUpdateTargetStep(it) } + updateTarget(root, steps) } - override fun visitDoReplace(ctx: GeneratedParser.DoReplaceContext) = translate(ctx) { - throw error(ctx, "DML no longer supported in the default PartiQLParser.") + override fun visitUpdateTargetStep(ctx: GeneratedParser.UpdateTargetStepContext): UpdateTargetStep { + return super.visitUpdateTargetStep(ctx) as UpdateTargetStep } - override fun visitDoUpdate(ctx: GeneratedParser.DoUpdateContext) = translate(ctx) { - throw error(ctx, "DML no longer supported in the default PartiQLParser.") + override fun visitUpdateTargetStepElement(ctx: GeneratedParser.UpdateTargetStepElementContext) = translate(ctx) { + val exprLit = visit(ctx.literal()) as ExprLit // TODO: Literals should have their own base in the G4 to allow for overriding the visitLiteral to get type safety. + val literal = exprLit.lit + UpdateTargetStep.Element(literal) } - // "simple paths" used by previous DDL's CREATE INDEX - override fun visitPathSimple(ctx: GeneratedParser.PathSimpleContext) = translate(ctx) { - throw error(ctx, "DDL no longer supported in the default PartiQLParser.") + override fun visitUpdateTargetStepField(ctx: GeneratedParser.UpdateTargetStepFieldContext) = translate(ctx) { + val key = visitSymbolPrimitive(ctx.symbolPrimitive()) + UpdateTargetStep.Field(key) } - // "simple paths" used by previous DDL's CREATE INDEX - override fun visitPathSimpleLiteral(ctx: GeneratedParser.PathSimpleLiteralContext) = translate(ctx) { - throw error(ctx, "DDL no longer supported in the default PartiQLParser.") + override fun visitUpdateStatementSearched(ctx: GeneratedParser.UpdateStatementSearchedContext) = translate(ctx) { + val tableName = visitQualifiedName(ctx.targetTable) + val setClauseList = ctx.setClauseList().setClause().map { visitSetClause(it) } + val condition = ctx.searchCond?.let { visitExpr(it) } + update(tableName, setClauseList, condition) } - // "simple paths" used by previous DDL's CREATE INDEX - override fun visitPathSimpleSymbol(ctx: GeneratedParser.PathSimpleSymbolContext) = translate(ctx) { - throw error(ctx, "DDL no longer supported in the default PartiQLParser.") + override fun visitSetClause(ctx: GeneratedParser.SetClauseContext) = translate(ctx) { + val target = visitUpdateTarget(ctx.updateTarget()) + val value = visitExpr(ctx.expr()) + setClause(target, value) } - // "simple paths" used by previous DDL's CREATE INDEX - override fun visitPathSimpleDotSymbol(ctx: GeneratedParser.PathSimpleDotSymbolContext) = translate(ctx) { - throw error(ctx, "DDL no longer supported in the default PartiQLParser.") + override fun visitDeleteStatementSearched(ctx: GeneratedParser.DeleteStatementSearchedContext) = translate(ctx) { + val tableName = visitQualifiedName(ctx.targetTable) + val condition = ctx.searchCond?.let { visitExpr(it) } + delete(tableName, condition) } - /** - * TODO current PartiQL.g4 grammar models a SET with no UPDATE target as valid DML command. - */ - override fun visitSetCommand(ctx: GeneratedParser.SetCommandContext) = translate(ctx) { - throw error(ctx, "DML no longer supported in the default PartiQLParser.") + override fun visitUpsertStatement(ctx: GeneratedParser.UpsertStatementContext) = translate(ctx) { + val idChain = visitQualifiedName(ctx.tblName) + val asAlias = ctx.asIdent()?.let { visitAsIdent(it) } + val source = visitInsertSource(ctx.insertSource()) + upsert(idChain, asAlias, source) } - override fun visitSetAssignment(ctx: GeneratedParser.SetAssignmentContext) = translate(ctx) { - throw error(ctx, "DML no longer supported in the default PartiQLParser.") + override fun visitReplaceStatement(ctx: GeneratedParser.ReplaceStatementContext) = translate(ctx) { + val idChain = visitQualifiedName(ctx.tblName) + val asAlias = ctx.asIdent()?.let { visitAsIdent(it) } + val source = visitInsertSource(ctx.insertSource()) + replace(idChain, asAlias, source) } /** @@ -1363,20 +1375,6 @@ internal class PartiQLParserDefault : PartiQLParser { } } - /** - * TODO Remove as/at/by aliases from DELETE command grammar in PartiQL.g4 - */ - override fun visitFromClauseSimpleExplicit(ctx: GeneratedParser.FromClauseSimpleExplicitContext) = translate(ctx) { - throw error(ctx, "DML no longer supported in the default PartiQLParser.") - } - - /** - * TODO Remove fromClauseSimple rule from DELETE command grammar in PartiQL.g4 - */ - override fun visitFromClauseSimpleImplicit(ctx: GeneratedParser.FromClauseSimpleImplicitContext) = translate(ctx) { - throw error(ctx, "DML no longer supported in the default PartiQLParser.") - } - /** * SIMPLE EXPRESSIONS */ @@ -1599,19 +1597,20 @@ internal class PartiQLParserDefault : PartiQLParser { exprPathStepAllFields(null) } - override fun visitValues(ctx: GeneratedParser.ValuesContext) = translate(ctx) { - val rows = visitOrEmpty(ctx.valueRow()) - exprBag(rows) - } - - override fun visitValueRow(ctx: GeneratedParser.ValueRowContext) = translate(ctx) { + override fun visitRowValueConstructor(ctx: GeneratedParser.RowValueConstructorContext) = translate(ctx) { + val isExplicit = ctx.ROW() != null val expressions = visitOrEmpty(ctx.expr()) - exprArray(expressions) + exprRowValue(expressions, isExplicit) } - override fun visitValueList(ctx: GeneratedParser.ValueListContext) = translate(ctx) { - val expressions = visitOrEmpty(ctx.expr()) - exprArray(expressions) + override fun visitTableValueConstructor(ctx: GeneratedParser.TableValueConstructorContext) = translate(ctx) { + val rows = ctx.rowValueExpressionList().expr().map { + when (val row = visitAs(it)) { + is ExprRowValue -> row + else -> exprRowValue(listOf(row), false) + } + } + exprValues(rows) } override fun visitExprGraphMatchMany(ctx: GeneratedParser.ExprGraphMatchManyContext) = translate(ctx) { diff --git a/partiql-parser/src/test/kotlin/org/partiql/parser/internal/ArgumentsProviderBase.kt b/partiql-parser/src/test/kotlin/org/partiql/parser/internal/ArgumentsProviderBase.kt new file mode 100644 index 000000000..12f51ce23 --- /dev/null +++ b/partiql-parser/src/test/kotlin/org/partiql/parser/internal/ArgumentsProviderBase.kt @@ -0,0 +1,40 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at: + * + * http://aws.amazon.com/apache2.0/ + * + * or in the "license" file accompanying this file. This file is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific + * language governing permissions and limitations under the License. + */ + +package org.partiql.parser.internal + +import org.junit.jupiter.api.extension.ExtensionContext +import org.junit.jupiter.params.provider.Arguments +import org.junit.jupiter.params.provider.ArgumentsProvider +import java.util.stream.Stream + +/** + * Reduces some of the boilerplate associated with the style of parameterized testing frequently + * utilized in this package. + * + * Since JUnit5 requires `@JvmStatic` on its `@MethodSource` argument factory methods, this requires all + * of the argument lists to reside in the companion object of a test class. This can be annoying since it + * forces the test to be separated from its tests cases. + * + * Classes that derive from this class can be defined near the `@ParameterizedTest` functions instead. + */ +abstract class ArgumentsProviderBase : ArgumentsProvider { + + abstract fun getParameters(): List + + @Throws(Exception::class) + override fun provideArguments(extensionContext: ExtensionContext): Stream? { + return getParameters().map { Arguments.of(it) }.stream() + } +} diff --git a/partiql-parser/src/test/kotlin/org/partiql/parser/internal/DeleteStatementTests.kt b/partiql-parser/src/test/kotlin/org/partiql/parser/internal/DeleteStatementTests.kt new file mode 100644 index 000000000..c338233e7 --- /dev/null +++ b/partiql-parser/src/test/kotlin/org/partiql/parser/internal/DeleteStatementTests.kt @@ -0,0 +1,41 @@ +package org.partiql.parser.internal + +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.ArgumentsSource + +class DeleteStatementTests { + + @ParameterizedTest + @ArgumentsSource(SuccessTestCases::class) + fun success(tc: PTestDef) { + tc.assert() + } + + @ParameterizedTest + @ArgumentsSource(FailureTestCases::class) + fun failure(tc: PTestDef) { + tc.assert() + } + + object SuccessTestCases : ArgumentsProviderBase() { + override fun getParameters(): List { + val m = mapOf( + "Simplest test" to "DELETE FROM tbl", + "Simplest deletion with condition" to "DELETE FROM tbl WHERE a = 2", + "Namespaced table name" to "DELETE FROM \"CaT1\".schema1.\"TBL_1\"", + "Namespaced table name with condition" to "DELETE FROM \"CaT1\".schema1.\"TBL_1\" WHERE y < x", + ).entries.map { ParserTestCaseSimple(it.key, it.value, isValid = true) } + return m + } + } + + object FailureTestCases : ArgumentsProviderBase() { + override fun getParameters(): List { + val m = mapOf( + "Lack of table name" to "DELETE FROM WHERE a = 2", + "Lack of condition" to "DELETE FROM tbl WHERE", + ).entries.map { ParserTestCaseSimple(it.key, it.value, isValid = false) } + return m + } + } +} diff --git a/partiql-parser/src/test/kotlin/org/partiql/parser/internal/InsertStatementTests.kt b/partiql-parser/src/test/kotlin/org/partiql/parser/internal/InsertStatementTests.kt new file mode 100644 index 000000000..52d27e03d --- /dev/null +++ b/partiql-parser/src/test/kotlin/org/partiql/parser/internal/InsertStatementTests.kt @@ -0,0 +1,73 @@ +package org.partiql.parser.internal + +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.ArgumentsSource + +class InsertStatementTests { + + @ParameterizedTest + @ArgumentsSource(SuccessTestCases::class) + fun success(tc: PTestDef) { + tc.assert() + } + + @ParameterizedTest + @ArgumentsSource(FailureTestCases::class) + fun failure(tc: PTestDef) { + tc.assert() + } + + object SuccessTestCases : ArgumentsProviderBase() { + override fun getParameters(): List { + val m = mapOf( + "Simplest insert of a row" to "INSERT INTO tbl VALUES (1, 2, 3)", + "Column definitions" to "INSERT INTO tbl (a, b, c) VALUES (1, 2, 3)", + "Multiple rows" to "INSERT INTO tbl VALUES (1, 2, 3), (4, 5, 6), (7, 8, 8)", + "Multiple explicit rows" to "INSERT INTO tbl VALUES ROW (1, 2, 3), (4, 5, 6), ROW (7, 8, 8)", + "Multiple explicit rows to disambiguate a single parenthesized expression" to "INSERT INTO tbl VALUES ROW (1), 2, ROW (3)", + "Multiple non-row values" to "INSERT INTO tbl VALUES 1, 2, 3", + "Using DEFAULT VALUES" to "INSERT INTO tbl DEFAULT VALUES", + "Explicit bag" to "INSERT INTO tbl << 1, 2, 3 >>", + "Explicit array" to "INSERT INTO tbl [ 1, 2, 3 ]", + "Namespaced table name with delimited alias" to "INSERT INTO \"CaT1\".schema1.\"TBL_1\" AS \"myt\" VALUES (1, 2, 3)", + "Namespaced table name with regular alias" to "INSERT INTO \"CaT1\".schema1.\"TBL_1\" AS myt VALUES (1, 2, 3)", + "Do nothing on conflict" to "INSERT INTO tbl << 1, 2, 3 >> ON CONFLICT DO NOTHING", + "Do nothing on conflict with target index" to "INSERT INTO tbl << 1, 2, 3 >> ON CONFLICT (a, b) DO NOTHING", + "Do nothing on conflict with named constraint" to "INSERT INTO tbl << 1, 2, 3 >> ON CONFLICT ON CONSTRAINT my_constraint DO NOTHING", + "Do replace excluded on conflict" to "INSERT INTO tbl << 1, 2, 3 >> ON CONFLICT DO REPLACE EXCLUDED", + "Do replace excluded on conflict with condition" to "INSERT INTO tbl << 1, 2, 3 >> ON CONFLICT DO REPLACE EXCLUDED WHERE a < 2", + "Do replace excluded on conflict with target index" to "INSERT INTO tbl << 1, 2, 3 >> ON CONFLICT (a, b) DO REPLACE EXCLUDED", + "Do replace excluded on conflict with target index with condition" to "INSERT INTO tbl << 1, 2, 3 >> ON CONFLICT (a, b) DO REPLACE EXCLUDED WHERE a < 2", + "Do replace excluded on conflict with named constraint" to "INSERT INTO tbl << 1, 2, 3 >> ON CONFLICT ON CONSTRAINT my_constraint DO REPLACE EXCLUDED", + "Do replace excluded on conflict with named constraint with condition" to "INSERT INTO tbl << 1, 2, 3 >> ON CONFLICT ON CONSTRAINT my_constraint DO REPLACE EXCLUDED WHERE a < 2", + "Do update excluded on conflict" to "INSERT INTO tbl << 1, 2, 3 >> ON CONFLICT DO UPDATE EXCLUDED", + "Do update excluded on conflict with condition" to "INSERT INTO tbl << 1, 2, 3 >> ON CONFLICT DO UPDATE EXCLUDED WHERE a < 2", + "Do update excluded on conflict with target index" to "INSERT INTO tbl << 1, 2, 3 >> ON CONFLICT (a, b) DO UPDATE EXCLUDED", + "Do update excluded on conflict with target index with condition" to "INSERT INTO tbl << 1, 2, 3 >> ON CONFLICT (a, b) DO UPDATE EXCLUDED WHERE a < 2", + "Do update excluded on conflict with named constraint" to "INSERT INTO tbl << 1, 2, 3 >> ON CONFLICT ON CONSTRAINT my_constraint DO UPDATE EXCLUDED", + "Do update excluded on conflict with named constraint with condition" to "INSERT INTO tbl << 1, 2, 3 >> ON CONFLICT ON CONSTRAINT my_constraint DO UPDATE EXCLUDED WHERE a < 2", + ).entries.map { ParserTestCaseSimple(it.key, it.value, isValid = true) } + return m + } + } + + object FailureTestCases : ArgumentsProviderBase() { + override fun getParameters(): List { + val m = mapOf( + "Lack of table name" to "INSERT INTO VALUES (1, 2, 3)", + "Trailing comma for VALUES" to "INSERT INTO tbl VALUES (1, 2, 3), (4, 5, 6),", + "Not DEFAULT VALUES" to "INSERT INTO tbl DEFAULT VALUE", + "Bad column definitions" to "INSERT INTO tbl (a.b, b, c) VALUES (1, 2, 3)", + "Empty column definitions" to "INSERT INTO tbl () VALUES (1, 2, 3)", + "No values" to "INSERT INTO tbl (a, b) VALUES", + "Bad alias" to "INSERT INTO tbl AS alias1.alias2 (a, b) VALUES", + "Do something on conflict" to "INSERT INTO tbl << 1, 2, 3 >> ON CONFLICT DO SOMETHING", + "No parenthesis on conflict with target index" to "INSERT INTO tbl << 1, 2, 3 >> ON CONFLICT a, b DO NOTHING", + "Bad reference for index on conflict with target index" to "INSERT INTO tbl << 1, 2, 3 >> ON CONFLICT (a, b.c) DO NOTHING", + "Do nothing on conflict with no named constraint" to "INSERT INTO tbl << 1, 2, 3 >> ON CONFLICT ON CONSTRAINT DO NOTHING", + "Do update excluded on conflict with condition in wrong spot" to "INSERT INTO tbl << 1, 2, 3 >> ON CONFLICT WHERE a < 2 DO UPDATE EXCLUDED", + ).entries.map { ParserTestCaseSimple(it.key, it.value, isValid = false) } + return m + } + } +} diff --git a/partiql-parser/src/test/kotlin/org/partiql/parser/internal/ParserTestCaseSimple.kt b/partiql-parser/src/test/kotlin/org/partiql/parser/internal/ParserTestCaseSimple.kt index 8005d79de..5843db6c8 100644 --- a/partiql-parser/src/test/kotlin/org/partiql/parser/internal/ParserTestCaseSimple.kt +++ b/partiql-parser/src/test/kotlin/org/partiql/parser/internal/ParserTestCaseSimple.kt @@ -28,4 +28,8 @@ class ParserTestCaseSimple( } } } + + override fun toString(): String { + return name + } } diff --git a/partiql-parser/src/test/kotlin/org/partiql/parser/internal/ReplaceStatementTests.kt b/partiql-parser/src/test/kotlin/org/partiql/parser/internal/ReplaceStatementTests.kt new file mode 100644 index 000000000..7092c41cf --- /dev/null +++ b/partiql-parser/src/test/kotlin/org/partiql/parser/internal/ReplaceStatementTests.kt @@ -0,0 +1,51 @@ +package org.partiql.parser.internal + +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.ArgumentsSource + +class ReplaceStatementTests { + + @ParameterizedTest + @ArgumentsSource(SuccessTestCases::class) + fun success(tc: PTestDef) { + tc.assert() + } + + @ParameterizedTest + @ArgumentsSource(FailureTestCases::class) + fun failure(tc: PTestDef) { + tc.assert() + } + + object SuccessTestCases : ArgumentsProviderBase() { + override fun getParameters(): List { + val m = mapOf( + "Simplest test" to "REPLACE INTO tbl VALUES (1, 2, 3)", + "Column definitions" to "REPLACE INTO tbl (a, b, c) VALUES (1, 2, 3)", + "Multiple rows" to "REPLACE INTO tbl VALUES (1, 2, 3), (4, 5, 6), (7, 8, 8)", + "Multiple non-row values" to "REPLACE INTO tbl VALUES 1, 2, 3", + "Using DEFAULT VALUES" to "REPLACE INTO tbl DEFAULT VALUES", + "Explicit bag" to "REPLACE INTO tbl << 1, 2, 3 >>", + "Explicit array" to "REPLACE INTO tbl [ 1, 2, 3 ]", + "Namespaced table name with delimited alias" to "REPLACE INTO \"CaT1\".schema1.\"TBL_1\" AS \"myt\" VALUES (1, 2, 3)", + "Namespaced table name with regular alias" to "REPLACE INTO \"CaT1\".schema1.\"TBL_1\" AS myt VALUES (1, 2, 3)", + ).entries.map { ParserTestCaseSimple(it.key, it.value, isValid = true) } + return m + } + } + + object FailureTestCases : ArgumentsProviderBase() { + override fun getParameters(): List { + val m = mapOf( + "Lack of table name" to "REPLACE INTO VALUES (1, 2, 3)", + "Trailing comma for VALUES" to "REPLACE INTO tbl VALUES (1, 2, 3), (4, 5, 6),", + "Not DEFAULT VALUES" to "REPLACE INTO tbl DEFAULT VALUE", + "Bad column definitions" to "REPLACE INTO tbl (a.b, b, c) VALUES (1, 2, 3)", + "Empty column definitions" to "REPLACE INTO tbl () VALUES (1, 2, 3)", + "No values" to "REPLACE INTO tbl (a, b) VALUES", + "Bad alias" to "REPLACE INTO tbl AS alias1.alias2 (a, b) VALUES", + ).entries.map { ParserTestCaseSimple(it.key, it.value, isValid = false) } + return m + } + } +} diff --git a/partiql-parser/src/test/kotlin/org/partiql/parser/internal/UpdateStatementTests.kt b/partiql-parser/src/test/kotlin/org/partiql/parser/internal/UpdateStatementTests.kt new file mode 100644 index 000000000..15051fbe5 --- /dev/null +++ b/partiql-parser/src/test/kotlin/org/partiql/parser/internal/UpdateStatementTests.kt @@ -0,0 +1,49 @@ +package org.partiql.parser.internal + +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.ArgumentsSource + +class UpdateStatementTests { + + @ParameterizedTest + @ArgumentsSource(SuccessTestCases::class) + fun success(tc: PTestDef) { + tc.assert() + } + + @ParameterizedTest + @ArgumentsSource(FailureTestCases::class) + fun failure(tc: PTestDef) { + tc.assert() + } + + object SuccessTestCases : ArgumentsProviderBase() { + override fun getParameters(): List { + val m = mapOf( + "Simplest test" to "UPDATE tbl SET x = 1", + "With multiple sets" to "UPDATE tbl SET x = 1, y = 2, z = 3", + "With multiple sets and condition" to "UPDATE tbl SET x = 1, y = 2, z = 3 WHERE a < 4", + "Namespaced table name" to "UPDATE \"CaT1\".schema1.\"TBL_1\" SET x = 1, y = 2", + "Namespaced table name with condition" to "UPDATE \"CaT1\".schema1.\"TBL_1\" SET x = 1, y = 2 WHERE y < x", + "Multiple complex steps" to "UPDATE tbl SET x.y.z = 1, x['y'].z[0].\"a\".b = 2", + ).entries.map { ParserTestCaseSimple(it.key, it.value, isValid = true) } + return m + } + } + + object FailureTestCases : ArgumentsProviderBase() { + override fun getParameters(): List { + val m = mapOf( + "Lack of table name" to "UPDATE SET x = 1 WHERE a = 2", + "Lack of condition" to "UPDATE tbl SET x = 1 WHERE", + "Lack of SET" to "UPDATE tbl WHERE a = 2", + "Bad step index" to "UPDATE tbl SET x[1 + 2] = 0", + "Bad step key" to "UPDATE tbl SET x['a' || 'b'] = 0", + "Bad step number where root is not a col ref" to "UPDATE tbl SET 1 = 0", + "Bad step string where root is not a col ref" to "UPDATE tbl SET 'a' = 0", + "Bad step struct where root is not a col ref" to "UPDATE tbl SET {'a': 1}.a = 0", + ).entries.map { ParserTestCaseSimple(it.key, it.value, isValid = false) } + return m + } + } +} diff --git a/partiql-parser/src/test/kotlin/org/partiql/parser/internal/UpsertStatementTests.kt b/partiql-parser/src/test/kotlin/org/partiql/parser/internal/UpsertStatementTests.kt new file mode 100644 index 000000000..b2fdf2a87 --- /dev/null +++ b/partiql-parser/src/test/kotlin/org/partiql/parser/internal/UpsertStatementTests.kt @@ -0,0 +1,51 @@ +package org.partiql.parser.internal + +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.ArgumentsSource + +class UpsertStatementTests { + + @ParameterizedTest + @ArgumentsSource(SuccessTestCases::class) + fun success(tc: PTestDef) { + tc.assert() + } + + @ParameterizedTest + @ArgumentsSource(FailureTestCases::class) + fun failure(tc: PTestDef) { + tc.assert() + } + + object SuccessTestCases : ArgumentsProviderBase() { + override fun getParameters(): List { + val m = mapOf( + "Simplest test" to "UPSERT INTO tbl VALUES (1, 2, 3)", + "Column definitions" to "UPSERT INTO tbl (a, b, c) VALUES (1, 2, 3)", + "Multiple rows" to "UPSERT INTO tbl VALUES (1, 2, 3), (4, 5, 6), (7, 8, 8)", + "Multiple non-row values" to "UPSERT INTO tbl VALUES 1, 2, 3", + "Using DEFAULT VALUES" to "UPSERT INTO tbl DEFAULT VALUES", + "Explicit bag" to "UPSERT INTO tbl << 1, 2, 3 >>", + "Explicit array" to "UPSERT INTO tbl [ 1, 2, 3 ]", + "Namespaced table name with delimited alias" to "UPSERT INTO \"CaT1\".schema1.\"TBL_1\" AS \"myt\" VALUES (1, 2, 3)", + "Namespaced table name with regular alias" to "UPSERT INTO \"CaT1\".schema1.\"TBL_1\" AS myt VALUES (1, 2, 3)", + ).entries.map { ParserTestCaseSimple(it.key, it.value, isValid = true) } + return m + } + } + + object FailureTestCases : ArgumentsProviderBase() { + override fun getParameters(): List { + val m = mapOf( + "Lack of table name" to "UPSERT INTO VALUES (1, 2, 3)", + "Trailing comma for VALUES" to "UPSERT INTO tbl VALUES (1, 2, 3), (4, 5, 6),", + "Not DEFAULT VALUES" to "UPSERT INTO tbl DEFAULT VALUE", + "Bad column definitions" to "UPSERT INTO tbl (a.b, b, c) VALUES (1, 2, 3)", + "Empty column definitions" to "UPSERT INTO tbl () VALUES (1, 2, 3)", + "No values" to "UPSERT INTO tbl (a, b) VALUES", + "Bad alias" to "UPSERT INTO tbl AS alias1.alias2 (a, b) VALUES", + ).entries.map { ParserTestCaseSimple(it.key, it.value, isValid = false) } + return m + } + } +} 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 d5c382ad3..0f8fab3ae 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 @@ -46,10 +46,12 @@ import org.partiql.ast.expr.ExprOverlay import org.partiql.ast.expr.ExprPath import org.partiql.ast.expr.ExprPosition import org.partiql.ast.expr.ExprQuerySet +import org.partiql.ast.expr.ExprRowValue import org.partiql.ast.expr.ExprSessionAttribute import org.partiql.ast.expr.ExprStruct import org.partiql.ast.expr.ExprSubstring import org.partiql.ast.expr.ExprTrim +import org.partiql.ast.expr.ExprValues import org.partiql.ast.expr.ExprVarRef import org.partiql.ast.expr.ExprVariant import org.partiql.ast.expr.PathStep @@ -139,6 +141,12 @@ internal object RexConverter { override fun defaultReturn(node: AstNode, context: Env): Rex = throw IllegalArgumentException("unsupported rex $node") + override fun visitExprRowValue(node: ExprRowValue, ctx: Env): Rex { + val values = node.values.map { visitExprCoerce(it, ctx) } + val op = rexOpCollection(values) + return rex(LIST, op) // TODO: We only do this for legacy reasons. This should return a rexOpRow! + } + override fun visitExprLit(node: ExprLit, context: Env): Rex { val pValue = node.lit.toPartiQLValue() val type = when (pValue) { @@ -571,6 +579,11 @@ internal object RexConverter { return rex(ANY, op) } + override fun visitExprValues(node: ExprValues, ctx: Env): Rex { + val rows = node.rows.map { visitExprCoerce(it, ctx) } + return rex(BAG, rexOpCollection(rows)) + } + /** * Construct Rel(Scan([path])). *