Skip to content

Commit

Permalink
Adds parsing and modeling of CTEs (#1736)
Browse files Browse the repository at this point in the history
* Adds parsing and ast modeling for CTEs
* Adds parsing and ast modeling for WITH clause
* Fixes the expression tree to exclude SELECTs
* Adds a dedicated subquery grammar node to allow for query expressions
  • Loading branch information
johnedquinn authored Feb 7, 2025
1 parent 920a76f commit 3f0e2e1
Show file tree
Hide file tree
Showing 22 changed files with 868 additions and 142 deletions.
59 changes: 59 additions & 0 deletions partiql-ast/api/partiql-ast.api
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,9 @@ 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/expr/ExprQuerySet;
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 exprQuerySet (Lorg/partiql/ast/QueryBody;Lorg/partiql/ast/OrderBy;Lorg/partiql/ast/expr/Expr;Lorg/partiql/ast/expr/Expr;Lorg/partiql/ast/With;)Lorg/partiql/ast/expr/ExprQuerySet;
public static synthetic fun exprQuerySet$default (Lorg/partiql/ast/QueryBody;Lorg/partiql/ast/OrderBy;Lorg/partiql/ast/expr/Expr;Lorg/partiql/ast/expr/Expr;ILjava/lang/Object;)Lorg/partiql/ast/expr/ExprQuerySet;
public static synthetic fun exprQuerySet$default (Lorg/partiql/ast/QueryBody;Lorg/partiql/ast/OrderBy;Lorg/partiql/ast/expr/Expr;Lorg/partiql/ast/expr/Expr;Lorg/partiql/ast/With;ILjava/lang/Object;)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;
Expand Down Expand Up @@ -213,6 +215,8 @@ public final class org/partiql/ast/Ast {
public static final fun upsert (Lorg/partiql/ast/Identifier;Lorg/partiql/ast/Identifier$Simple;Lorg/partiql/ast/dml/InsertSource;)Lorg/partiql/ast/dml/Upsert;
public static final fun upsert (Lorg/partiql/ast/Identifier;Lorg/partiql/ast/dml/InsertSource;)Lorg/partiql/ast/dml/Upsert;
public static synthetic fun upsert$default (Lorg/partiql/ast/Identifier;Lorg/partiql/ast/Identifier$Simple;Lorg/partiql/ast/dml/InsertSource;ILjava/lang/Object;)Lorg/partiql/ast/dml/Upsert;
public static final fun with (Ljava/util/List;Z)Lorg/partiql/ast/With;
public static final fun withListElement (Lorg/partiql/ast/Identifier$Simple;Lorg/partiql/ast/expr/ExprQuerySet;Ljava/util/List;)Lorg/partiql/ast/WithListElement;
}

public abstract class org/partiql/ast/AstEnum : org/partiql/ast/AstNode {
Expand Down Expand Up @@ -431,6 +435,10 @@ public abstract class org/partiql/ast/AstRewriter : org/partiql/ast/AstVisitor {
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 synthetic fun visitWith (Lorg/partiql/ast/With;Ljava/lang/Object;)Ljava/lang/Object;
public fun visitWith (Lorg/partiql/ast/With;Ljava/lang/Object;)Lorg/partiql/ast/AstNode;
public synthetic fun visitWithListElement (Lorg/partiql/ast/WithListElement;Ljava/lang/Object;)Ljava/lang/Object;
public fun visitWithListElement (Lorg/partiql/ast/WithListElement;Ljava/lang/Object;)Lorg/partiql/ast/AstNode;
}

public abstract class org/partiql/ast/AstVisitor {
Expand Down Expand Up @@ -572,6 +580,8 @@ public abstract class org/partiql/ast/AstVisitor {
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 fun visitWith (Lorg/partiql/ast/With;Ljava/lang/Object;)Ljava/lang/Object;
public fun visitWithListElement (Lorg/partiql/ast/WithListElement;Ljava/lang/Object;)Ljava/lang/Object;
}

public final class org/partiql/ast/DataType : org/partiql/ast/AstEnum {
Expand Down Expand Up @@ -1054,21 +1064,27 @@ public class org/partiql/ast/Identifier$Simple$Builder {
public final class org/partiql/ast/JoinType : org/partiql/ast/AstEnum {
public static final field CROSS I
public static final field FULL I
public static final field FULL_CROSS I
public static final field FULL_OUTER I
public static final field INNER I
public static final field INNER_CROSS I
public static final field LEFT I
public static final field LEFT_CROSS I
public static final field LEFT_OUTER I
public static final field RIGHT I
public static final field RIGHT_CROSS I
public static final field RIGHT_OUTER I
public static fun CROSS ()Lorg/partiql/ast/JoinType;
public static fun FULL ()Lorg/partiql/ast/JoinType;
public static fun FULL_CROSS ()Lorg/partiql/ast/JoinType;
public static fun FULL_OUTER ()Lorg/partiql/ast/JoinType;
public static fun INNER ()Lorg/partiql/ast/JoinType;
public static fun INNER_CROSS ()Lorg/partiql/ast/JoinType;
public static fun LEFT ()Lorg/partiql/ast/JoinType;
public static fun LEFT_CROSS ()Lorg/partiql/ast/JoinType;
public static fun LEFT_OUTER ()Lorg/partiql/ast/JoinType;
public static fun RIGHT ()Lorg/partiql/ast/JoinType;
public static fun RIGHT_CROSS ()Lorg/partiql/ast/JoinType;
public static fun RIGHT_OUTER ()Lorg/partiql/ast/JoinType;
public fun accept (Lorg/partiql/ast/AstVisitor;Ljava/lang/Object;)Ljava/lang/Object;
public fun code ()I
Expand Down Expand Up @@ -1455,6 +1471,46 @@ public abstract class org/partiql/ast/Statement : org/partiql/ast/AstNode {
public fun <init> ()V
}

public final class org/partiql/ast/With : org/partiql/ast/AstNode {
public fun <init> (Ljava/util/List;)V
public fun <init> (Ljava/util/List;Z)V
public fun accept (Lorg/partiql/ast/AstVisitor;Ljava/lang/Object;)Ljava/lang/Object;
public static fun builder ()Lorg/partiql/ast/With$Builder;
public fun equals (Ljava/lang/Object;)Z
public fun getChildren ()Ljava/util/List;
public fun getElements ()Ljava/util/List;
public fun hashCode ()I
public fun isRecursive ()Z
}

public class org/partiql/ast/With$Builder {
public fun build ()Lorg/partiql/ast/With;
public fun elements (Ljava/util/List;)Lorg/partiql/ast/With$Builder;
public fun isRecursive (Z)Lorg/partiql/ast/With$Builder;
public fun toString ()Ljava/lang/String;
}

public final class org/partiql/ast/WithListElement : org/partiql/ast/AstNode {
public fun <init> (Lorg/partiql/ast/Identifier$Simple;Lorg/partiql/ast/expr/ExprQuerySet;)V
public fun <init> (Lorg/partiql/ast/Identifier$Simple;Lorg/partiql/ast/expr/ExprQuerySet;Ljava/util/List;)V
public fun accept (Lorg/partiql/ast/AstVisitor;Ljava/lang/Object;)Ljava/lang/Object;
public static fun builder ()Lorg/partiql/ast/WithListElement$Builder;
public fun equals (Ljava/lang/Object;)Z
public fun getAsQuery ()Lorg/partiql/ast/expr/ExprQuerySet;
public fun getChildren ()Ljava/util/List;
public fun getColumnList ()Ljava/util/List;
public fun getQueryName ()Lorg/partiql/ast/Identifier$Simple;
public fun hashCode ()I
}

public class org/partiql/ast/WithListElement$Builder {
public fun asQuery (Lorg/partiql/ast/expr/ExprQuerySet;)Lorg/partiql/ast/WithListElement$Builder;
public fun build ()Lorg/partiql/ast/WithListElement;
public fun queryName (Lorg/partiql/ast/Identifier$Simple;)Lorg/partiql/ast/WithListElement$Builder;
public fun toString ()Ljava/lang/String;
public fun withColumnList (Ljava/util/List;)Lorg/partiql/ast/WithListElement$Builder;
}

public abstract class org/partiql/ast/ddl/AttributeConstraint : org/partiql/ast/AstNode {
protected final field name Lorg/partiql/ast/Identifier;
protected fun <init> (Lorg/partiql/ast/Identifier;)V
Expand Down Expand Up @@ -2422,6 +2478,7 @@ public class org/partiql/ast/expr/ExprPosition$Builder {

public final class org/partiql/ast/expr/ExprQuerySet : org/partiql/ast/expr/Expr {
public fun <init> (Lorg/partiql/ast/QueryBody;Lorg/partiql/ast/OrderBy;Lorg/partiql/ast/expr/Expr;Lorg/partiql/ast/expr/Expr;)V
public fun <init> (Lorg/partiql/ast/QueryBody;Lorg/partiql/ast/OrderBy;Lorg/partiql/ast/expr/Expr;Lorg/partiql/ast/expr/Expr;Lorg/partiql/ast/With;)V
public fun accept (Lorg/partiql/ast/AstVisitor;Ljava/lang/Object;)Ljava/lang/Object;
public static fun builder ()Lorg/partiql/ast/expr/ExprQuerySet$Builder;
public fun equals (Ljava/lang/Object;)Z
Expand All @@ -2430,6 +2487,7 @@ public final class org/partiql/ast/expr/ExprQuerySet : org/partiql/ast/expr/Expr
public fun getLimit ()Lorg/partiql/ast/expr/Expr;
public fun getOffset ()Lorg/partiql/ast/expr/Expr;
public fun getOrderBy ()Lorg/partiql/ast/OrderBy;
public fun getWith ()Lorg/partiql/ast/With;
public fun hashCode ()I
}

Expand All @@ -2440,6 +2498,7 @@ public class org/partiql/ast/expr/ExprQuerySet$Builder {
public fun offset (Lorg/partiql/ast/expr/Expr;)Lorg/partiql/ast/expr/ExprQuerySet$Builder;
public fun orderBy (Lorg/partiql/ast/OrderBy;)Lorg/partiql/ast/expr/ExprQuerySet$Builder;
public fun toString ()Ljava/lang/String;
public fun with (Lorg/partiql/ast/With;)Lorg/partiql/ast/expr/ExprQuerySet$Builder;
}

public final class org/partiql/ast/expr/ExprRowValue : org/partiql/ast/expr/Expr {
Expand Down
8 changes: 8 additions & 0 deletions partiql-ast/src/main/java/org/partiql/ast/AstVisitor.java
Original file line number Diff line number Diff line change
Expand Up @@ -515,6 +515,14 @@ public R visitLet(Let node, C ctx) {
return defaultVisit(node, ctx);
}

public R visitWith(With node, C ctx) {
return defaultVisit(node, ctx);
}

public R visitWithListElement(WithListElement node, C ctx) {
return defaultVisit(node, ctx);
}

public R visitLetBinding(Let.Binding node, C ctx) {
return defaultVisit(node, ctx);
}
Expand Down
31 changes: 31 additions & 0 deletions partiql-ast/src/main/java/org/partiql/ast/JoinType.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,27 @@ public final class JoinType extends AstEnum {
* Cross join variant.
*/
public static final int CROSS = 7;

/**
* Left cross join variant.
*/
public static final int LEFT_CROSS = 8;

/**
* Right cross join variant.
*/
public static final int RIGHT_CROSS = 9;

/**
* Outer cross join variant.
*/
public static final int INNER_CROSS = 10;

/**
* Full cross join variant.
*/
public static final int FULL_CROSS = 11;

public static JoinType INNER() {
return new JoinType(INNER);
}
Expand Down Expand Up @@ -84,6 +100,18 @@ public static JoinType LEFT_CROSS() {
return new JoinType(LEFT_CROSS);
}

public static JoinType RIGHT_CROSS() {
return new JoinType(RIGHT_CROSS);
}

public static JoinType INNER_CROSS() {
return new JoinType(INNER_CROSS);
}

public static JoinType FULL_CROSS() {
return new JoinType(FULL_CROSS);
}

private final int code;

private JoinType(int code) {
Expand All @@ -108,6 +136,9 @@ public String name() {
case FULL_OUTER: return "FULL_OUTER";
case CROSS: return "CROSS";
case LEFT_CROSS: return "LEFT_CROSS";
case RIGHT_CROSS: return "RIGHT_CROSS";
case INNER_CROSS: return "INNER_CROSS";
case FULL_CROSS: return "FULL_CROSS";
default: throw new IllegalStateException("Invalid JoinType code: " + code);
}
}
Expand Down
73 changes: 73 additions & 0 deletions partiql-ast/src/main/java/org/partiql/ast/With.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package org.partiql.ast;

import lombok.Builder;
import lombok.EqualsAndHashCode;
import org.jetbrains.annotations.NotNull;

import java.util.ArrayList;
import java.util.List;

/**
* <p>
* Represents a PartiQL WITH clause.
* </p>
* <p>{@code <with clause> ::= WITH [ RECURSIVE ] <with list>}</p>
* <p>{@code <with list> ::= <with list element> [ { <comma> <with list element> }... ]}</p>
* @see WithListElement
* @see org.partiql.ast.expr.ExprQuerySet
*/
@Builder(builderClassName = "Builder")
@EqualsAndHashCode(callSuper = false)
public final class With extends AstNode {

@NotNull
private final List<WithListElement> elements;

private final boolean isRecursive;

/**
* Creates a new WITH clause with the specified elements and RECURSIVE set to the specified value.
* @param elements the list of WITH list elements
* @param isRecursive true if this WITH clause specified RECURSIVE;
*/
public With(@NotNull List<WithListElement> elements, boolean isRecursive) {
this.elements = elements;
this.isRecursive = isRecursive;
}

/**
* Creates a new WITH clause with the specified elements and RECURSIVE set to false.
* @param elements the list of WITH list elements
*/
public With(@NotNull List<WithListElement> elements) {
this(elements, false);
}

@NotNull
@Override
public List<AstNode> getChildren() {
return new ArrayList<>(elements);
}

@Override
public <R, C> R accept(@NotNull AstVisitor<R, C> visitor, C ctx) {
return visitor.visitWith(this, ctx);
}

/**
* Returns the list of WITH list elements.
* @return the list of WITH list elements
*/
@NotNull
public List<WithListElement> getElements() {
return this.elements;
}

/**
* Returns whether this WITH clause specified RECURSIVE.
* @return whether this WITH clause specified RECURSIVE.
*/
public boolean isRecursive() {
return this.isRecursive;
}
}
109 changes: 109 additions & 0 deletions partiql-ast/src/main/java/org/partiql/ast/WithListElement.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package org.partiql.ast;

import lombok.Builder;
import lombok.EqualsAndHashCode;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.partiql.ast.expr.ExprQuerySet;

import java.util.ArrayList;
import java.util.List;

/**
* <p>
* Represents a {@code <with list element>}.
* </p>
* <p>
* {@code
* <with list element> ::=
* <query name>
* [ <left paren> <with column list> <right paren> ]
* AS <left paren> <query expression> <right paren>
* [ <search or cycle clause> ]
* }
* </p>
* <p>{@code <with column list> ::= <column name list>}</p>
* <p>{@code <column name list> ::= <column name> [ { <comma> <column name> }... ]}</p>
* <p>{@code <column name> ::= <identifier>}</p>
* @see With
* @see ExprQuerySet
*/
@Builder(builderClassName = "Builder")
@EqualsAndHashCode(callSuper = false)
public final class WithListElement extends AstNode {
// TODO: Add support for the search/cycle clause.

@NotNull
private final Identifier.Simple queryName;

@NotNull
private final ExprQuerySet asQuery;

@Nullable
private final List<Identifier.Simple> withColumnList;

/**
* Creates a new instance of {@link WithListElement}.
* @param queryName the name to bind
* @param asQuery the query that defines the with list element
* @param columnList the list of column names to be output from the query
*/
public WithListElement(@NotNull Identifier.Simple queryName, @NotNull ExprQuerySet asQuery, @Nullable List<Identifier.Simple> columnList) {
this.queryName = queryName;
this.asQuery = asQuery;
this.withColumnList = columnList;
}

/**
* Creates a new instance of {@link WithListElement}.
* @param queryName the name to bind
* @param asQuery the query that defines the with list element
*/
public WithListElement(@NotNull Identifier.Simple queryName, @NotNull ExprQuerySet asQuery) {
this(queryName, asQuery, null);
}

@NotNull
@Override
public List<AstNode> getChildren() {
List<AstNode> children = new ArrayList<>();
children.add(queryName);
if (withColumnList != null) {
children.addAll(withColumnList);
}
children.add(asQuery);
return children;
}

@Override
public <R, C> R accept(@NotNull AstVisitor<R, C> visitor, C ctx) {
return visitor.visitWithListElement(this, ctx);
}

/**
* Returns the query name.
* @return the query name
*/
@NotNull
public Identifier.Simple getQueryName() {
return this.queryName;
}

/**
* Returns the list of column names to be output from the query.
* @return the list of column names to be output from the query. This may return null.
*/
@Nullable
public List<Identifier.Simple> getColumnList() {
return this.withColumnList;
}

/**
* Returns the query that defines the with list element.
* @return the query that defines the with list element
*/
@NotNull
public ExprQuerySet getAsQuery() {
return this.asQuery;
}
}
Loading

0 comments on commit 3f0e2e1

Please sign in to comment.