visitor, C context)
{
diff --git a/core/trino-parser/src/main/java/io/trino/sql/tree/LabelDereference.java b/core/trino-parser/src/main/java/io/trino/sql/tree/LabelDereference.java
new file mode 100644
index 000000000..450f34111
--- /dev/null
+++ b/core/trino-parser/src/main/java/io/trino/sql/tree/LabelDereference.java
@@ -0,0 +1,93 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License 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 io.trino.sql.tree;
+
+import com.google.common.collect.ImmutableList;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
+import static java.util.Objects.requireNonNull;
+
+/**
+ * A temporary IR representation of a label-prefixed column reference
+ * in the context of row pattern recognition.
+ *
+ * It is created from a DereferenceExpression when the MEASURES or DEFINE
+ * expressions are rewritten using the TranslationMap:
+ * A.price -> DereferenceExpression("A", "price") -> LabelDereference("A", price_symbol).
+ * Next, the LabelDereference is processed by the LogicalIndexExtractor,
+ * and it is removed from the expression.
+ *
+ * LabelDereference is a synthetic AST node. It had to be introduced in order to carry
+ * the rewritten symbol (`price_symbol` in the example). The DereferenceExpression
+ * cannot be used for that purpose, because it only contains identifiers, and a Symbol
+ * cannot be safely converted to an Identifier.
+ */
+public class LabelDereference
+ extends Expression
+{
+ private final String label;
+ private final SymbolReference reference;
+
+ public LabelDereference(String label, SymbolReference reference)
+ {
+ super(Optional.empty());
+ this.label = requireNonNull(label, "label is null");
+ this.reference = requireNonNull(reference, "reference is null");
+ }
+
+ public String getLabel()
+ {
+ return label;
+ }
+
+ public SymbolReference getReference()
+ {
+ return reference;
+ }
+
+ @Override
+ public R accept(AstVisitor visitor, C context)
+ {
+ return visitor.visitLabelDereference(this, context);
+ }
+
+ @Override
+ public List getChildren()
+ {
+ return ImmutableList.of(reference);
+ }
+
+ @Override
+ public boolean equals(Object o)
+ {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ LabelDereference that = (LabelDereference) o;
+ return Objects.equals(label, that.label) &&
+ Objects.equals(reference, that.reference);
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return Objects.hash(label, reference);
+ }
+}
diff --git a/core/trino-parser/src/main/java/io/trino/sql/tree/MeasureDefinition.java b/core/trino-parser/src/main/java/io/trino/sql/tree/MeasureDefinition.java
new file mode 100644
index 000000000..7eae5bbe3
--- /dev/null
+++ b/core/trino-parser/src/main/java/io/trino/sql/tree/MeasureDefinition.java
@@ -0,0 +1,109 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License 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 io.trino.sql.tree;
+
+import com.google.common.collect.ImmutableList;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static java.util.Objects.requireNonNull;
+
+public class MeasureDefinition
+ extends Node
+{
+ private final Expression expression;
+ private final Identifier name;
+
+ public MeasureDefinition(Expression expression, Identifier name)
+ {
+ this(Optional.empty(), expression, name);
+ }
+
+ public MeasureDefinition(NodeLocation location, Expression expression, Identifier name)
+ {
+ this(Optional.of(location), expression, name);
+ }
+
+ private MeasureDefinition(Optional location, Expression expression, Identifier name)
+ {
+ super(location);
+ this.expression = requireNonNull(expression, "expression is null");
+ this.name = requireNonNull(name, "name is null");
+ }
+
+ public Expression getExpression()
+ {
+ return expression;
+ }
+
+ public Identifier getName()
+ {
+ return name;
+ }
+
+ @Override
+ public R accept(AstVisitor visitor, C context)
+ {
+ return visitor.visitMeasureDefinition(this, context);
+ }
+
+ @Override
+ public List extends Node> getChildren()
+ {
+ return ImmutableList.of(expression);
+ }
+
+ @Override
+ public String toString()
+ {
+ return toStringHelper(this)
+ .add("expression", expression)
+ .add("name", name)
+ .toString();
+ }
+
+ @Override
+ public boolean equals(Object o)
+ {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ MeasureDefinition that = (MeasureDefinition) o;
+ return Objects.equals(expression, that.expression) &&
+ Objects.equals(name, that.name);
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return Objects.hash(expression, name);
+ }
+
+ @Override
+ public boolean shallowEquals(Node other)
+ {
+ if (!sameClass(this, other)) {
+ return false;
+ }
+
+ return Objects.equals(name, ((MeasureDefinition) other).name);
+ }
+}
diff --git a/core/trino-parser/src/main/java/io/trino/sql/tree/OneOrMoreQuantifier.java b/core/trino-parser/src/main/java/io/trino/sql/tree/OneOrMoreQuantifier.java
new file mode 100644
index 000000000..409a6c53a
--- /dev/null
+++ b/core/trino-parser/src/main/java/io/trino/sql/tree/OneOrMoreQuantifier.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License 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 io.trino.sql.tree;
+
+import java.util.Optional;
+
+public class OneOrMoreQuantifier
+ extends PatternQuantifier
+{
+ public OneOrMoreQuantifier(boolean greedy)
+ {
+ this(Optional.empty(), greedy);
+ }
+
+ public OneOrMoreQuantifier(NodeLocation location, boolean greedy)
+ {
+ this(Optional.of(location), greedy);
+ }
+
+ public OneOrMoreQuantifier(Optional location, boolean greedy)
+ {
+ super(location, greedy);
+ }
+
+ @Override
+ public R accept(AstVisitor visitor, C context)
+ {
+ return visitor.visitOneOrMoreQuantifier(this, context);
+ }
+}
diff --git a/core/trino-parser/src/main/java/io/trino/sql/tree/PatternAlternation.java b/core/trino-parser/src/main/java/io/trino/sql/tree/PatternAlternation.java
new file mode 100644
index 000000000..9239d2c66
--- /dev/null
+++ b/core/trino-parser/src/main/java/io/trino/sql/tree/PatternAlternation.java
@@ -0,0 +1,92 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License 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 io.trino.sql.tree;
+
+import com.google.common.collect.ImmutableList;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.base.Preconditions.checkArgument;
+import static java.util.Objects.requireNonNull;
+
+public class PatternAlternation
+ extends RowPattern
+{
+ private final List patterns;
+
+ public PatternAlternation(NodeLocation location, List patterns)
+ {
+ this(Optional.of(location), patterns);
+ }
+
+ private PatternAlternation(Optional location, List patterns)
+ {
+ super(location);
+ this.patterns = requireNonNull(patterns, "patterns is null");
+ checkArgument(!patterns.isEmpty(), "patterns list is empty");
+ }
+
+ public List getPatterns()
+ {
+ return patterns;
+ }
+
+ @Override
+ public R accept(AstVisitor visitor, C context)
+ {
+ return visitor.visitPatternAlternation(this, context);
+ }
+
+ @Override
+ public List getChildren()
+ {
+ return ImmutableList.copyOf(patterns);
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj) {
+ return true;
+ }
+ if ((obj == null) || (getClass() != obj.getClass())) {
+ return false;
+ }
+ PatternAlternation o = (PatternAlternation) obj;
+ return Objects.equals(patterns, o.patterns);
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return Objects.hash(patterns);
+ }
+
+ @Override
+ public String toString()
+ {
+ return toStringHelper(this)
+ .add("patterns", patterns)
+ .toString();
+ }
+
+ @Override
+ public boolean shallowEquals(Node other)
+ {
+ return sameClass(this, other);
+ }
+}
diff --git a/core/trino-parser/src/main/java/io/trino/sql/tree/PatternConcatenation.java b/core/trino-parser/src/main/java/io/trino/sql/tree/PatternConcatenation.java
new file mode 100644
index 000000000..0a62a31e5
--- /dev/null
+++ b/core/trino-parser/src/main/java/io/trino/sql/tree/PatternConcatenation.java
@@ -0,0 +1,92 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License 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 io.trino.sql.tree;
+
+import com.google.common.collect.ImmutableList;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.base.Preconditions.checkArgument;
+import static java.util.Objects.requireNonNull;
+
+public class PatternConcatenation
+ extends RowPattern
+{
+ private final List patterns;
+
+ public PatternConcatenation(NodeLocation location, List patterns)
+ {
+ this(Optional.of(location), patterns);
+ }
+
+ private PatternConcatenation(Optional location, List patterns)
+ {
+ super(location);
+ this.patterns = requireNonNull(patterns, "patterns is null");
+ checkArgument(!patterns.isEmpty(), "patterns list is empty");
+ }
+
+ public List getPatterns()
+ {
+ return patterns;
+ }
+
+ @Override
+ public R accept(AstVisitor visitor, C context)
+ {
+ return visitor.visitPatternConcatenation(this, context);
+ }
+
+ @Override
+ public List getChildren()
+ {
+ return ImmutableList.copyOf(patterns);
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj) {
+ return true;
+ }
+ if ((obj == null) || (getClass() != obj.getClass())) {
+ return false;
+ }
+ PatternConcatenation o = (PatternConcatenation) obj;
+ return Objects.equals(patterns, o.patterns);
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return Objects.hash(patterns);
+ }
+
+ @Override
+ public String toString()
+ {
+ return toStringHelper(this)
+ .add("patterns", patterns)
+ .toString();
+ }
+
+ @Override
+ public boolean shallowEquals(Node other)
+ {
+ return sameClass(this, other);
+ }
+}
diff --git a/core/trino-parser/src/main/java/io/trino/sql/tree/PatternPermutation.java b/core/trino-parser/src/main/java/io/trino/sql/tree/PatternPermutation.java
new file mode 100644
index 000000000..438ec6dd2
--- /dev/null
+++ b/core/trino-parser/src/main/java/io/trino/sql/tree/PatternPermutation.java
@@ -0,0 +1,92 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License 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 io.trino.sql.tree;
+
+import com.google.common.collect.ImmutableList;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.base.Preconditions.checkArgument;
+import static java.util.Objects.requireNonNull;
+
+public class PatternPermutation
+ extends RowPattern
+{
+ private final List patterns;
+
+ public PatternPermutation(NodeLocation location, List patterns)
+ {
+ this(Optional.of(location), patterns);
+ }
+
+ private PatternPermutation(Optional location, List patterns)
+ {
+ super(location);
+ this.patterns = requireNonNull(patterns, "patterns is null");
+ checkArgument(!patterns.isEmpty(), "patterns list is empty");
+ }
+
+ public List getPatterns()
+ {
+ return patterns;
+ }
+
+ @Override
+ public R accept(AstVisitor visitor, C context)
+ {
+ return visitor.visitPatternPermutation(this, context);
+ }
+
+ @Override
+ public List getChildren()
+ {
+ return ImmutableList.copyOf(patterns);
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj) {
+ return true;
+ }
+ if ((obj == null) || (getClass() != obj.getClass())) {
+ return false;
+ }
+ PatternPermutation o = (PatternPermutation) obj;
+ return Objects.equals(patterns, o.patterns);
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return Objects.hash(patterns);
+ }
+
+ @Override
+ public String toString()
+ {
+ return toStringHelper(this)
+ .add("patterns", patterns)
+ .toString();
+ }
+
+ @Override
+ public boolean shallowEquals(Node other)
+ {
+ return sameClass(this, other);
+ }
+}
diff --git a/core/trino-parser/src/main/java/io/trino/sql/tree/PatternQuantifier.java b/core/trino-parser/src/main/java/io/trino/sql/tree/PatternQuantifier.java
new file mode 100644
index 000000000..a66e0e9e4
--- /dev/null
+++ b/core/trino-parser/src/main/java/io/trino/sql/tree/PatternQuantifier.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License 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 io.trino.sql.tree;
+
+import com.google.common.collect.ImmutableList;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+
+public abstract class PatternQuantifier
+ extends Node
+{
+ private final boolean greedy;
+
+ protected PatternQuantifier(Optional location, boolean greedy)
+ {
+ super(location);
+ this.greedy = greedy;
+ }
+
+ public boolean isGreedy()
+ {
+ return greedy;
+ }
+
+ @Override
+ public R accept(AstVisitor visitor, C context)
+ {
+ return visitor.visitPatternQuantifier(this, context);
+ }
+
+ @Override
+ public List getChildren()
+ {
+ return ImmutableList.of();
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj) {
+ return true;
+ }
+ if ((obj == null) || (getClass() != obj.getClass())) {
+ return false;
+ }
+ PatternQuantifier o = (PatternQuantifier) obj;
+ return greedy == o.greedy;
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return Objects.hash(greedy);
+ }
+
+ @Override
+ public boolean shallowEquals(Node other)
+ {
+ if (!sameClass(this, other)) {
+ return false;
+ }
+
+ PatternQuantifier otherNode = (PatternQuantifier) other;
+ return greedy == otherNode.greedy;
+ }
+
+ @Override
+ public String toString()
+ {
+ return toStringHelper(this)
+ .add("greedy", greedy)
+ .toString();
+ }
+}
diff --git a/core/trino-parser/src/main/java/io/trino/sql/tree/PatternRecognitionRelation.java b/core/trino-parser/src/main/java/io/trino/sql/tree/PatternRecognitionRelation.java
new file mode 100644
index 000000000..0dc5eb55b
--- /dev/null
+++ b/core/trino-parser/src/main/java/io/trino/sql/tree/PatternRecognitionRelation.java
@@ -0,0 +1,356 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License 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 io.trino.sql.tree;
+
+import com.google.common.collect.ImmutableList;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.base.Preconditions.checkArgument;
+import static java.util.Objects.requireNonNull;
+
+public class PatternRecognitionRelation
+ extends Relation
+{
+ private final Relation input;
+ private final List partitionBy;
+ private final Optional orderBy;
+ private final List measures;
+ private final Optional rowsPerMatch;
+ private final Optional afterMatchSkipTo;
+ private final Optional patternSearchMode;
+ private final RowPattern pattern;
+ private final List subsets;
+ private final List variableDefinitions;
+
+ public PatternRecognitionRelation(
+ Relation input,
+ List partitionBy,
+ Optional orderBy,
+ List measures,
+ Optional rowsPerMatch,
+ Optional afterMatchSkipTo,
+ Optional patternSearchMode,
+ RowPattern pattern,
+ List subsets,
+ List variableDefinitions)
+ {
+ this(Optional.empty(), input, partitionBy, orderBy, measures, rowsPerMatch, afterMatchSkipTo, patternSearchMode, pattern, subsets, variableDefinitions);
+ }
+
+ public PatternRecognitionRelation(
+ NodeLocation location,
+ Relation input,
+ List partitionBy,
+ Optional orderBy,
+ List measures,
+ Optional rowsPerMatch,
+ Optional afterMatchSkipTo,
+ Optional patternSearchMode,
+ RowPattern pattern,
+ List subsets,
+ List variableDefinitions)
+ {
+ this(Optional.of(location), input, partitionBy, orderBy, measures, rowsPerMatch, afterMatchSkipTo, patternSearchMode, pattern, subsets, variableDefinitions);
+ }
+
+ private PatternRecognitionRelation(
+ Optional location,
+ Relation input,
+ List partitionBy,
+ Optional orderBy,
+ List measures,
+ Optional rowsPerMatch,
+ Optional afterMatchSkipTo,
+ Optional patternSearchMode,
+ RowPattern pattern,
+ List subsets,
+ List variableDefinitions)
+ {
+ super(location);
+ this.input = requireNonNull(input, "input is null");
+ this.partitionBy = requireNonNull(partitionBy, "partitionBy is null");
+ this.orderBy = requireNonNull(orderBy, "orderBy is null");
+ this.measures = requireNonNull(measures, "measures is null");
+ this.rowsPerMatch = requireNonNull(rowsPerMatch, "rowsPerMatch is null");
+ this.afterMatchSkipTo = requireNonNull(afterMatchSkipTo, "afterMatchSkipTo is null");
+ this.patternSearchMode = requireNonNull(patternSearchMode, "patternSearchMode is null");
+ this.pattern = requireNonNull(pattern, "pattern is null");
+ this.subsets = requireNonNull(subsets, "subsets is null");
+ requireNonNull(variableDefinitions, "variableDefinitions is null");
+ checkArgument(!variableDefinitions.isEmpty(), "variableDefinitions is empty");
+ this.variableDefinitions = variableDefinitions;
+ }
+
+ public Relation getInput()
+ {
+ return input;
+ }
+
+ public List getPartitionBy()
+ {
+ return partitionBy;
+ }
+
+ public Optional getOrderBy()
+ {
+ return orderBy;
+ }
+
+ public List getMeasures()
+ {
+ return measures;
+ }
+
+ public Optional getRowsPerMatch()
+ {
+ return rowsPerMatch;
+ }
+
+ public Optional getAfterMatchSkipTo()
+ {
+ return afterMatchSkipTo;
+ }
+
+ public Optional getPatternSearchMode()
+ {
+ return patternSearchMode;
+ }
+
+ public RowPattern getPattern()
+ {
+ return pattern;
+ }
+
+ public List getSubsets()
+ {
+ return subsets;
+ }
+
+ public List getVariableDefinitions()
+ {
+ return variableDefinitions;
+ }
+
+ @Override
+ public R accept(AstVisitor visitor, C context)
+ {
+ return visitor.visitPatternRecognitionRelation(this, context);
+ }
+
+ @Override
+ public List getChildren()
+ {
+ ImmutableList.Builder builder = ImmutableList.builder();
+ builder.add(input);
+ builder.addAll(partitionBy);
+ orderBy.ifPresent(builder::add);
+ builder.addAll(measures);
+ afterMatchSkipTo.ifPresent(builder::add);
+ builder.add(pattern)
+ .addAll(subsets)
+ .addAll(variableDefinitions);
+ patternSearchMode.ifPresent(builder::add);
+
+ return builder.build();
+ }
+
+ @Override
+ public String toString()
+ {
+ return toStringHelper(this)
+ .add("input", input)
+ .add("partitionBy", partitionBy)
+ .add("orderBy", orderBy.orElse(null))
+ .add("measures", measures)
+ .add("rowsPerMatch", rowsPerMatch.orElse(null))
+ .add("afterMatchSkipTo", afterMatchSkipTo)
+ .add("patternSearchMode", patternSearchMode.orElse(null))
+ .add("pattern", pattern)
+ .add("subsets", subsets)
+ .add("variableDefinitions", variableDefinitions)
+ .omitNullValues()
+ .toString();
+ }
+
+ @Override
+ public boolean equals(Object o)
+ {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ PatternRecognitionRelation that = (PatternRecognitionRelation) o;
+ return Objects.equals(input, that.input) &&
+ Objects.equals(partitionBy, that.partitionBy) &&
+ Objects.equals(orderBy, that.orderBy) &&
+ Objects.equals(measures, that.measures) &&
+ Objects.equals(rowsPerMatch, that.rowsPerMatch) &&
+ Objects.equals(afterMatchSkipTo, that.afterMatchSkipTo) &&
+ Objects.equals(patternSearchMode, that.patternSearchMode) &&
+ Objects.equals(pattern, that.pattern) &&
+ Objects.equals(subsets, that.subsets) &&
+ Objects.equals(variableDefinitions, that.variableDefinitions);
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return Objects.hash(input, partitionBy, orderBy, measures, rowsPerMatch, afterMatchSkipTo, patternSearchMode, pattern, subsets, variableDefinitions);
+ }
+
+ @Override
+ public boolean shallowEquals(Node other)
+ {
+ if (!sameClass(this, other)) {
+ return false;
+ }
+
+ return rowsPerMatch.equals(((PatternRecognitionRelation) other).rowsPerMatch);
+ }
+
+ public enum RowsPerMatch
+ {
+ // ONE option applies to the MATCH_RECOGNIZE clause. This is the default option.
+ // Output a single summary row for every match, including empty matches.
+ // In the case of an empty match, output the starting row of the match attempt.
+ ONE {
+ @Override
+ public boolean isOneRow()
+ {
+ return true;
+ }
+
+ @Override
+ public boolean isEmptyMatches()
+ {
+ return true;
+ }
+
+ @Override
+ public boolean isUnmatchedRows()
+ {
+ return false;
+ }
+ },
+
+ // ALL_SHOW_EMPTY option applies to the MATCH_RECOGNIZE clause.
+ // Output all rows of every match, including empty matches.
+ // In the case of an empty match, output the starting row of the match attempt.
+ // Do not produce output for the rows matched within exclusion `{- ... -}`.
+ ALL_SHOW_EMPTY {
+ @Override
+ public boolean isOneRow()
+ {
+ return false;
+ }
+
+ @Override
+ public boolean isEmptyMatches()
+ {
+ return true;
+ }
+
+ @Override
+ public boolean isUnmatchedRows()
+ {
+ return false;
+ }
+ },
+
+ // ALL_OMIT_EMPTY option applies to the MATCH_RECOGNIZE clause.
+ // Output all rows of every non-empty match.
+ // Do not produce output for the rows matched within exclusion `{- ... -}`
+ ALL_OMIT_EMPTY {
+ @Override
+ public boolean isOneRow()
+ {
+ return false;
+ }
+
+ @Override
+ public boolean isEmptyMatches()
+ {
+ return false;
+ }
+
+ @Override
+ public boolean isUnmatchedRows()
+ {
+ return false;
+ }
+ },
+
+ // ALL_WITH_UNMATCHED option applies to the MATCH_RECOGNIZE clause.
+ // Output all rows of every match, including empty matches.
+ // Produce an additional output row for every unmatched row.
+ // Pattern exclusions are not allowed with this option.
+ ALL_WITH_UNMATCHED {
+ @Override
+ public boolean isOneRow()
+ {
+ return false;
+ }
+
+ @Override
+ public boolean isEmptyMatches()
+ {
+ return true;
+ }
+
+ @Override
+ public boolean isUnmatchedRows()
+ {
+ return true;
+ }
+ },
+
+ // WINDOW option applies to pattern recognition within window specification.
+ // Output one row for every input row:
+ // - if the row is skipped by some previous match, produce output as for unmatched row
+ // - if match is found (either empty or non-empty), output a single-row summary
+ // - if no match is found, produce output as for unmatched row
+ WINDOW {
+ @Override
+ public boolean isOneRow()
+ {
+ return true;
+ }
+
+ @Override
+ public boolean isEmptyMatches()
+ {
+ return true;
+ }
+
+ @Override
+ public boolean isUnmatchedRows()
+ {
+ return true;
+ }
+ };
+
+ public abstract boolean isOneRow();
+
+ public abstract boolean isEmptyMatches();
+
+ public abstract boolean isUnmatchedRows();
+ }
+}
diff --git a/core/trino-parser/src/main/java/io/trino/sql/tree/PatternSearchMode.java b/core/trino-parser/src/main/java/io/trino/sql/tree/PatternSearchMode.java
new file mode 100644
index 000000000..1302f1eba
--- /dev/null
+++ b/core/trino-parser/src/main/java/io/trino/sql/tree/PatternSearchMode.java
@@ -0,0 +1,93 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License 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 io.trino.sql.tree;
+
+import com.google.common.collect.ImmutableList;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static java.util.Objects.requireNonNull;
+
+public final class PatternSearchMode
+ extends Node
+{
+ private final Mode mode;
+
+ public PatternSearchMode(Mode mode)
+ {
+ this(Optional.empty(), mode);
+ }
+
+ public PatternSearchMode(NodeLocation location, Mode mode)
+ {
+ this(Optional.of(location), mode);
+ }
+
+ public PatternSearchMode(Optional location, Mode mode)
+ {
+ super(location);
+ this.mode = requireNonNull(mode, "mode is null");
+ }
+
+ public Mode getMode()
+ {
+ return mode;
+ }
+
+ @Override
+ public R accept(AstVisitor visitor, C context)
+ {
+ return visitor.visitPatternSearchMode(this, context);
+ }
+
+ @Override
+ public List getChildren()
+ {
+ return ImmutableList.of();
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj) {
+ return true;
+ }
+ if ((obj == null) || (getClass() != obj.getClass())) {
+ return false;
+ }
+ return mode == ((PatternSearchMode) obj).mode;
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return Objects.hash(mode);
+ }
+
+ @Override
+ public String toString()
+ {
+ return toStringHelper(this)
+ .add("mode", mode)
+ .toString();
+ }
+
+ public enum Mode
+ {
+ INITIAL, SEEK
+ }
+}
diff --git a/core/trino-parser/src/main/java/io/trino/sql/tree/PatternVariable.java b/core/trino-parser/src/main/java/io/trino/sql/tree/PatternVariable.java
new file mode 100644
index 000000000..7aa932600
--- /dev/null
+++ b/core/trino-parser/src/main/java/io/trino/sql/tree/PatternVariable.java
@@ -0,0 +1,90 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License 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 io.trino.sql.tree;
+
+import com.google.common.collect.ImmutableList;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static java.util.Objects.requireNonNull;
+
+public class PatternVariable
+ extends RowPattern
+{
+ private final Identifier name;
+
+ public PatternVariable(NodeLocation location, Identifier name)
+ {
+ this(Optional.of(location), name);
+ }
+
+ private PatternVariable(Optional location, Identifier name)
+ {
+ super(location);
+ this.name = requireNonNull(name, "name is null");
+ }
+
+ public Identifier getName()
+ {
+ return name;
+ }
+
+ @Override
+ public R accept(AstVisitor visitor, C context)
+ {
+ return visitor.visitPatternVariable(this, context);
+ }
+
+ @Override
+ public List getChildren()
+ {
+ return ImmutableList.of(name);
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj) {
+ return true;
+ }
+ if ((obj == null) || (getClass() != obj.getClass())) {
+ return false;
+ }
+ PatternVariable o = (PatternVariable) obj;
+ return Objects.equals(name, o.name);
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return Objects.hash(name);
+ }
+
+ @Override
+ public String toString()
+ {
+ return toStringHelper(this)
+ .add("name", name)
+ .toString();
+ }
+
+ @Override
+ public boolean shallowEquals(Node other)
+ {
+ return sameClass(this, other);
+ }
+}
diff --git a/core/trino-parser/src/main/java/io/trino/sql/tree/ProcessingMode.java b/core/trino-parser/src/main/java/io/trino/sql/tree/ProcessingMode.java
new file mode 100644
index 000000000..b569cc723
--- /dev/null
+++ b/core/trino-parser/src/main/java/io/trino/sql/tree/ProcessingMode.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License 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 io.trino.sql.tree;
+
+import com.google.common.collect.ImmutableList;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static java.util.Objects.requireNonNull;
+
+public final class ProcessingMode
+ extends Node
+{
+ private final Mode mode;
+
+ public ProcessingMode(NodeLocation location, Mode mode)
+ {
+ this(Optional.of(location), mode);
+ }
+
+ public ProcessingMode(Optional location, Mode mode)
+ {
+ super(location);
+ this.mode = requireNonNull(mode, "mode is null");
+ }
+
+ public Mode getMode()
+ {
+ return mode;
+ }
+
+ @Override
+ public R accept(AstVisitor visitor, C context)
+ {
+ return visitor.visitProcessingMode(this, context);
+ }
+
+ @Override
+ public List getChildren()
+ {
+ return ImmutableList.of();
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj) {
+ return true;
+ }
+ if ((obj == null) || (getClass() != obj.getClass())) {
+ return false;
+ }
+ return mode == ((ProcessingMode) obj).mode;
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return Objects.hash(mode);
+ }
+
+ @Override
+ public String toString()
+ {
+ return toStringHelper(this)
+ .add("mode", mode)
+ .toString();
+ }
+
+ public enum Mode
+ {
+ RUNNING, FINAL
+ }
+}
diff --git a/core/trino-parser/src/main/java/io/trino/sql/tree/QuantifiedComparisonExpression.java b/core/trino-parser/src/main/java/io/trino/sql/tree/QuantifiedComparisonExpression.java
index 0eabc2606..10ef15623 100644
--- a/core/trino-parser/src/main/java/io/trino/sql/tree/QuantifiedComparisonExpression.java
+++ b/core/trino-parser/src/main/java/io/trino/sql/tree/QuantifiedComparisonExpression.java
@@ -49,7 +49,7 @@ public class QuantifiedComparisonExpression
private QuantifiedComparisonExpression(Optional location, ComparisonExpression.Operator operator, Quantifier quantifier, Expression value, Expression subquery)
{
super(location);
- this.operator = requireNonNull(operator, "comparisonType is null");
+ this.operator = requireNonNull(operator, "operator is null");
this.quantifier = requireNonNull(quantifier, "quantifier is null");
this.value = requireNonNull(value, "value is null");
this.subquery = requireNonNull(subquery, "subquery is null");
diff --git a/core/trino-parser/src/main/java/io/trino/sql/tree/QuantifiedPattern.java b/core/trino-parser/src/main/java/io/trino/sql/tree/QuantifiedPattern.java
new file mode 100644
index 000000000..c1a4bdd83
--- /dev/null
+++ b/core/trino-parser/src/main/java/io/trino/sql/tree/QuantifiedPattern.java
@@ -0,0 +1,99 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License 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 io.trino.sql.tree;
+
+import com.google.common.collect.ImmutableList;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static java.util.Objects.requireNonNull;
+
+public class QuantifiedPattern
+ extends RowPattern
+{
+ private final RowPattern pattern;
+ private final PatternQuantifier patternQuantifier;
+
+ public QuantifiedPattern(NodeLocation location, RowPattern pattern, PatternQuantifier patternQuantifier)
+ {
+ this(Optional.of(location), pattern, patternQuantifier);
+ }
+
+ private QuantifiedPattern(Optional location, RowPattern pattern, PatternQuantifier patternQuantifier)
+ {
+ super(location);
+ this.pattern = requireNonNull(pattern, "pattern is null");
+ this.patternQuantifier = requireNonNull(patternQuantifier, "patternQuantifier is null");
+ }
+
+ public RowPattern getPattern()
+ {
+ return pattern;
+ }
+
+ public PatternQuantifier getPatternQuantifier()
+ {
+ return patternQuantifier;
+ }
+
+ @Override
+ public R accept(AstVisitor visitor, C context)
+ {
+ return visitor.visitQuantifiedPattern(this, context);
+ }
+
+ @Override
+ public List getChildren()
+ {
+ return ImmutableList.of(pattern, patternQuantifier);
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj) {
+ return true;
+ }
+ if ((obj == null) || (getClass() != obj.getClass())) {
+ return false;
+ }
+ QuantifiedPattern o = (QuantifiedPattern) obj;
+ return Objects.equals(pattern, o.pattern) &&
+ Objects.equals(patternQuantifier, o.patternQuantifier);
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return Objects.hash(pattern, patternQuantifier);
+ }
+
+ @Override
+ public String toString()
+ {
+ return toStringHelper(this)
+ .add("pattern", pattern)
+ .add("patternQuantifier", patternQuantifier)
+ .toString();
+ }
+
+ @Override
+ public boolean shallowEquals(Node other)
+ {
+ return sameClass(this, other);
+ }
+}
diff --git a/core/trino-parser/src/main/java/io/trino/sql/tree/RangeQuantifier.java b/core/trino-parser/src/main/java/io/trino/sql/tree/RangeQuantifier.java
new file mode 100644
index 000000000..402acf513
--- /dev/null
+++ b/core/trino-parser/src/main/java/io/trino/sql/tree/RangeQuantifier.java
@@ -0,0 +1,103 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License 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 io.trino.sql.tree;
+
+import com.google.common.collect.ImmutableList;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static java.util.Objects.requireNonNull;
+
+public class RangeQuantifier
+ extends PatternQuantifier
+{
+ private final Optional atLeast;
+ private final Optional atMost;
+
+ public RangeQuantifier(boolean greedy, Optional atLeast, Optional atMost)
+ {
+ this(Optional.empty(), greedy, atLeast, atMost);
+ }
+
+ public RangeQuantifier(NodeLocation location, boolean greedy, Optional atLeast, Optional atMost)
+ {
+ this(Optional.of(location), greedy, atLeast, atMost);
+ }
+
+ private RangeQuantifier(Optional location, boolean greedy, Optional atLeast, Optional atMost)
+ {
+ super(location, greedy);
+ this.atLeast = requireNonNull(atLeast, "atLeast is null");
+ this.atMost = requireNonNull(atMost, "atMost is null");
+ }
+
+ public Optional getAtLeast()
+ {
+ return atLeast;
+ }
+
+ public Optional getAtMost()
+ {
+ return atMost;
+ }
+
+ @Override
+ public R accept(AstVisitor visitor, C context)
+ {
+ return visitor.visitRangeQuantifier(this, context);
+ }
+
+ @Override
+ public List getChildren()
+ {
+ ImmutableList.Builder children = ImmutableList.builder();
+ atLeast.ifPresent(children::add);
+ atMost.ifPresent(children::add);
+ return children.build();
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (this == obj) {
+ return true;
+ }
+ if ((obj == null) || (getClass() != obj.getClass())) {
+ return false;
+ }
+ RangeQuantifier o = (RangeQuantifier) obj;
+ return isGreedy() == o.isGreedy() &&
+ Objects.equals(atLeast, o.atLeast) &&
+ Objects.equals(atMost, o.atMost);
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return Objects.hash(isGreedy(), atLeast, atMost);
+ }
+
+ @Override
+ public String toString()
+ {
+ return toStringHelper(this)
+ .add("atLeast", atLeast)
+ .add("atMost", atMost)
+ .add("greedy", isGreedy())
+ .toString();
+ }
+}
diff --git a/core/trino-parser/src/main/java/io/trino/sql/tree/RowPattern.java b/core/trino-parser/src/main/java/io/trino/sql/tree/RowPattern.java
new file mode 100644
index 000000000..dc7833d1b
--- /dev/null
+++ b/core/trino-parser/src/main/java/io/trino/sql/tree/RowPattern.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License 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 io.trino.sql.tree;
+
+import java.util.Optional;
+
+public abstract class RowPattern
+ extends Node
+{
+ protected RowPattern(Optional location)
+ {
+ super(location);
+ }
+
+ @Override
+ public R accept(AstVisitor visitor, C context)
+ {
+ return visitor.visitRowPattern(this, context);
+ }
+}
diff --git a/core/trino-parser/src/main/java/io/trino/sql/tree/SetPath.java b/core/trino-parser/src/main/java/io/trino/sql/tree/SetPath.java
index 6e1a512c6..ebbb55d81 100644
--- a/core/trino-parser/src/main/java/io/trino/sql/tree/SetPath.java
+++ b/core/trino-parser/src/main/java/io/trino/sql/tree/SetPath.java
@@ -40,7 +40,7 @@ public class SetPath
private SetPath(Optional location, PathSpecification pathSpecification)
{
super(location);
- this.pathSpecification = requireNonNull(pathSpecification, "path is null");
+ this.pathSpecification = requireNonNull(pathSpecification, "pathSpecification is null");
}
public PathSpecification getPathSpecification()
diff --git a/core/trino-parser/src/main/java/io/trino/sql/tree/SkipTo.java b/core/trino-parser/src/main/java/io/trino/sql/tree/SkipTo.java
new file mode 100644
index 000000000..4b4e8c2bd
--- /dev/null
+++ b/core/trino-parser/src/main/java/io/trino/sql/tree/SkipTo.java
@@ -0,0 +1,178 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License 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 io.trino.sql.tree;
+
+import com.google.common.collect.ImmutableList;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.base.Preconditions.checkArgument;
+import static io.trino.sql.tree.SkipTo.Position.FIRST;
+import static io.trino.sql.tree.SkipTo.Position.LAST;
+import static io.trino.sql.tree.SkipTo.Position.NEXT;
+import static io.trino.sql.tree.SkipTo.Position.PAST_LAST;
+import static java.util.Objects.requireNonNull;
+
+public class SkipTo
+ extends Node
+{
+ private final Position position;
+ private final Optional identifier;
+
+ public enum Position
+ {
+ PAST_LAST,
+ NEXT,
+ FIRST,
+ LAST
+ }
+
+ // default
+ public static SkipTo skipPastLastRow()
+ {
+ return skipPastLastRow(Optional.empty());
+ }
+
+ public static SkipTo skipPastLastRow(NodeLocation location)
+ {
+ return skipPastLastRow(Optional.of(location));
+ }
+
+ private static SkipTo skipPastLastRow(Optional location)
+ {
+ return new SkipTo(location, PAST_LAST, Optional.empty());
+ }
+
+ public static SkipTo skipToNextRow()
+ {
+ return skipToNextRow(Optional.empty());
+ }
+
+ public static SkipTo skipToNextRow(NodeLocation location)
+ {
+ return skipToNextRow(Optional.of(location));
+ }
+
+ private static SkipTo skipToNextRow(Optional location)
+ {
+ return new SkipTo(location, NEXT, Optional.empty());
+ }
+
+ public static SkipTo skipToFirst(Identifier identifier)
+ {
+ return skipToFirst(Optional.empty(), identifier);
+ }
+
+ public static SkipTo skipToFirst(NodeLocation location, Identifier identifier)
+ {
+ return skipToFirst(Optional.of(location), identifier);
+ }
+
+ private static SkipTo skipToFirst(Optional location, Identifier identifier)
+ {
+ return new SkipTo(location, FIRST, Optional.of(identifier));
+ }
+
+ public static SkipTo skipToLast(Identifier identifier)
+ {
+ return skipToLast(Optional.empty(), identifier);
+ }
+
+ public static SkipTo skipToLast(NodeLocation location, Identifier identifier)
+ {
+ return skipToLast(Optional.of(location), identifier);
+ }
+
+ private static SkipTo skipToLast(Optional location, Identifier identifier)
+ {
+ return new SkipTo(location, LAST, Optional.of(identifier));
+ }
+
+ private SkipTo(Optional location, Position position, Optional identifier)
+ {
+ super(location);
+ requireNonNull(position, "position is null");
+ requireNonNull(identifier, "identifier is null");
+ checkArgument(identifier.isPresent() || (position == PAST_LAST || position == NEXT), "missing identifier in SKIP TO " + position.name());
+ checkArgument(!identifier.isPresent() || (position == FIRST || position == LAST), "unexpected identifier in SKIP TO " + position.name());
+ this.position = position;
+ this.identifier = identifier;
+ }
+
+ public Position getPosition()
+ {
+ return position;
+ }
+
+ public Optional getIdentifier()
+ {
+ return identifier;
+ }
+
+ @Override
+ public R accept(AstVisitor visitor, C context)
+ {
+ return visitor.visitSkipTo(this, context);
+ }
+
+ @Override
+ public List extends Node> getChildren()
+ {
+ return identifier.map(ImmutableList::of).orElse(ImmutableList.of());
+ }
+
+ @Override
+ public String toString()
+ {
+ return toStringHelper(this)
+ .add("position", position)
+ .add("identifier", identifier.orElse(null))
+ .omitNullValues()
+ .toString();
+ }
+
+ @Override
+ public boolean equals(Object o)
+ {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ SkipTo that = (SkipTo) o;
+ return Objects.equals(position, that.position) &&
+ Objects.equals(identifier, that.identifier);
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return Objects.hash(position, identifier);
+ }
+
+ @Override
+ public boolean shallowEquals(Node other)
+ {
+ if (!sameClass(this, other)) {
+ return false;
+ }
+
+ return position == ((SkipTo) other).position;
+ }
+}
diff --git a/core/trino-parser/src/main/java/io/trino/sql/tree/SubsetDefinition.java b/core/trino-parser/src/main/java/io/trino/sql/tree/SubsetDefinition.java
new file mode 100644
index 000000000..bd2474124
--- /dev/null
+++ b/core/trino-parser/src/main/java/io/trino/sql/tree/SubsetDefinition.java
@@ -0,0 +1,110 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License 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 io.trino.sql.tree;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.base.Preconditions.checkArgument;
+import static java.util.Objects.requireNonNull;
+
+public class SubsetDefinition
+ extends Node
+{
+ private final Identifier name;
+ private final List identifiers;
+
+ public SubsetDefinition(Identifier name, List identifiers)
+ {
+ this(Optional.empty(), name, identifiers);
+ }
+
+ public SubsetDefinition(NodeLocation location, Identifier name, List identifiers)
+ {
+ this(Optional.of(location), name, identifiers);
+ }
+
+ private SubsetDefinition(Optional location, Identifier name, List identifiers)
+ {
+ super(location);
+ this.name = requireNonNull(name, "name is null");
+ requireNonNull(identifiers, "identifiers is null");
+ checkArgument(!identifiers.isEmpty(), "identifiers is empty");
+ this.identifiers = identifiers;
+ }
+
+ public Identifier getName()
+ {
+ return name;
+ }
+
+ public List getIdentifiers()
+ {
+ return identifiers;
+ }
+
+ @Override
+ public R accept(AstVisitor visitor, C context)
+ {
+ return visitor.visitSubsetDefinition(this, context);
+ }
+
+ @Override
+ public List extends Node> getChildren()
+ {
+ return identifiers;
+ }
+
+ @Override
+ public String toString()
+ {
+ return toStringHelper(this)
+ .add("name", name)
+ .add("identifiers", identifiers)
+ .toString();
+ }
+
+ @Override
+ public boolean equals(Object o)
+ {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ SubsetDefinition that = (SubsetDefinition) o;
+ return Objects.equals(name, that.name) &&
+ Objects.equals(identifiers, that.identifiers);
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return Objects.hash(name, identifiers);
+ }
+
+ @Override
+ public boolean shallowEquals(Node other)
+ {
+ if (!sameClass(this, other)) {
+ return false;
+ }
+
+ return Objects.equals(name, ((SubsetDefinition) other).name);
+ }
+}
diff --git a/core/trino-parser/src/main/java/io/trino/sql/tree/Table.java b/core/trino-parser/src/main/java/io/trino/sql/tree/Table.java
index cea24c7fc..de4585366 100644
--- a/core/trino-parser/src/main/java/io/trino/sql/tree/Table.java
+++ b/core/trino-parser/src/main/java/io/trino/sql/tree/Table.java
@@ -25,33 +25,21 @@ public class Table
extends QueryBody
{
private final QualifiedName name;
- private final Optional cannerflowName;
public Table(QualifiedName name)
{
- this(Optional.empty(), name, Optional.empty());
- }
-
- public Table(QualifiedName name, QualifiedName cannerflowName)
- {
- this(Optional.empty(), name, Optional.of(cannerflowName));
+ this(Optional.empty(), name);
}
public Table(NodeLocation location, QualifiedName name)
{
- this(Optional.of(location), name, Optional.empty());
+ this(Optional.of(location), name);
}
- public Table(NodeLocation location, QualifiedName name, QualifiedName cannerflowName)
- {
- this(Optional.of(location), name, Optional.of(cannerflowName));
- }
-
- private Table(Optional location, QualifiedName name, Optional cannerflowName)
+ private Table(Optional location, QualifiedName name)
{
super(location);
this.name = name;
- this.cannerflowName = cannerflowName;
}
public QualifiedName getName()
@@ -59,11 +47,6 @@ public class Table
return name;
}
- public Optional getCannerflowName()
- {
- return cannerflowName;
- }
-
@Override
public R accept(AstVisitor visitor, C context)
{
diff --git a/core/trino-parser/src/main/java/io/trino/sql/tree/TypeParameter.java b/core/trino-parser/src/main/java/io/trino/sql/tree/TypeParameter.java
index 0f22818a7..a72a3f782 100644
--- a/core/trino-parser/src/main/java/io/trino/sql/tree/TypeParameter.java
+++ b/core/trino-parser/src/main/java/io/trino/sql/tree/TypeParameter.java
@@ -29,7 +29,7 @@ public class TypeParameter
public TypeParameter(DataType type)
{
super(Optional.empty());
- this.type = requireNonNull(type, "value is null");
+ this.type = requireNonNull(type, "type is null");
}
public DataType getValue()
diff --git a/core/trino-parser/src/main/java/io/trino/sql/tree/Update.java b/core/trino-parser/src/main/java/io/trino/sql/tree/Update.java
index 0aa6419db..6a717427a 100644
--- a/core/trino-parser/src/main/java/io/trino/sql/tree/Update.java
+++ b/core/trino-parser/src/main/java/io/trino/sql/tree/Update.java
@@ -43,7 +43,7 @@ public class Update
{
super(location);
this.table = requireNonNull(table, "table is null");
- this.assignments = requireNonNull(assignments, "targets is null");
+ this.assignments = requireNonNull(assignments, "assignments is null");
this.where = requireNonNull(where, "where is null");
}
diff --git a/core/trino-parser/src/main/java/io/trino/sql/tree/VariableDefinition.java b/core/trino-parser/src/main/java/io/trino/sql/tree/VariableDefinition.java
new file mode 100644
index 000000000..9c79ce1cd
--- /dev/null
+++ b/core/trino-parser/src/main/java/io/trino/sql/tree/VariableDefinition.java
@@ -0,0 +1,109 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License 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 io.trino.sql.tree;
+
+import com.google.common.collect.ImmutableList;
+
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static java.util.Objects.requireNonNull;
+
+public class VariableDefinition
+ extends Node
+{
+ private final Identifier name;
+ private final Expression expression;
+
+ public VariableDefinition(Identifier name, Expression expression)
+ {
+ this(Optional.empty(), name, expression);
+ }
+
+ public VariableDefinition(NodeLocation location, Identifier name, Expression expression)
+ {
+ this(Optional.of(location), name, expression);
+ }
+
+ private VariableDefinition(Optional location, Identifier name, Expression expression)
+ {
+ super(location);
+ this.name = requireNonNull(name, "name is null");
+ this.expression = requireNonNull(expression, "expression is null");
+ }
+
+ public Identifier getName()
+ {
+ return name;
+ }
+
+ public Expression getExpression()
+ {
+ return expression;
+ }
+
+ @Override
+ public R accept(AstVisitor visitor, C context)
+ {
+ return visitor.visitVariableDefinition(this, context);
+ }
+
+ @Override
+ public List extends Node> getChildren()
+ {
+ return ImmutableList.of(expression);
+ }
+
+ @Override
+ public String toString()
+ {
+ return toStringHelper(this)
+ .add("name", name)
+ .add("expression", expression)
+ .toString();
+ }
+
+ @Override
+ public boolean equals(Object o)
+ {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ VariableDefinition that = (VariableDefinition) o;
+ return Objects.equals(name, that.name) &&
+ Objects.equals(expression, that.expression);
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return Objects.hash(name, expression);
+ }
+
+ @Override
+ public boolean shallowEquals(Node other)
+ {
+ if (!sameClass(this, other)) {
+ return false;
+ }
+
+ return Objects.equals(name, ((VariableDefinition) other).name);
+ }
+}
diff --git a/core/trino-parser/src/main/java/io/trino/sql/tree/ZeroOrMoreQuantifier.java b/core/trino-parser/src/main/java/io/trino/sql/tree/ZeroOrMoreQuantifier.java
new file mode 100644
index 000000000..46f378d17
--- /dev/null
+++ b/core/trino-parser/src/main/java/io/trino/sql/tree/ZeroOrMoreQuantifier.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License 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 io.trino.sql.tree;
+
+import java.util.Optional;
+
+public class ZeroOrMoreQuantifier
+ extends PatternQuantifier
+{
+ public ZeroOrMoreQuantifier(boolean greedy)
+ {
+ this(Optional.empty(), greedy);
+ }
+
+ public ZeroOrMoreQuantifier(NodeLocation location, boolean greedy)
+ {
+ this(Optional.of(location), greedy);
+ }
+
+ public ZeroOrMoreQuantifier(Optional location, boolean greedy)
+ {
+ super(location, greedy);
+ }
+
+ @Override
+ public R accept(AstVisitor visitor, C context)
+ {
+ return visitor.visitZeroOrMoreQuantifier(this, context);
+ }
+}
diff --git a/core/trino-parser/src/main/java/io/trino/sql/tree/ZeroOrOneQuantifier.java b/core/trino-parser/src/main/java/io/trino/sql/tree/ZeroOrOneQuantifier.java
new file mode 100644
index 000000000..551645adf
--- /dev/null
+++ b/core/trino-parser/src/main/java/io/trino/sql/tree/ZeroOrOneQuantifier.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License 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 io.trino.sql.tree;
+
+import java.util.Optional;
+
+public class ZeroOrOneQuantifier
+ extends PatternQuantifier
+{
+ public ZeroOrOneQuantifier(boolean greedy)
+ {
+ this(Optional.empty(), greedy);
+ }
+
+ public ZeroOrOneQuantifier(NodeLocation location, boolean greedy)
+ {
+ this(Optional.of(location), greedy);
+ }
+
+ public ZeroOrOneQuantifier(Optional location, boolean greedy)
+ {
+ super(location, greedy);
+ }
+
+ @Override
+ public R accept(AstVisitor visitor, C context)
+ {
+ return visitor.visitZeroOrOneQuantifier(this, context);
+ }
+}
diff --git a/core/trino-parser/src/main/java/io/trino/sql/util/EscapedChars.java b/core/trino-parser/src/main/java/io/trino/sql/util/EscapedChars.java
index c51004881..f36ae791d 100644
--- a/core/trino-parser/src/main/java/io/trino/sql/util/EscapedChars.java
+++ b/core/trino-parser/src/main/java/io/trino/sql/util/EscapedChars.java
@@ -1,15 +1,8 @@
/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License 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.
+ * Copyright (C) Canner, Inc - All Rights Reserved
+ * Unauthorized copying of this file, via any medium is strictly prohibited
+ * Proprietary and confidential
+ * Written by Canner dev team contact@canner.io, Nov 2021
*/
package io.trino.sql.util;
diff --git a/core/trino-parser/src/main/java/io/trino/sql/util/EscapedCharsUtil.java b/core/trino-parser/src/main/java/io/trino/sql/util/EscapedCharsUtil.java
index b442c3ed0..48ba74658 100644
--- a/core/trino-parser/src/main/java/io/trino/sql/util/EscapedCharsUtil.java
+++ b/core/trino-parser/src/main/java/io/trino/sql/util/EscapedCharsUtil.java
@@ -1,15 +1,8 @@
/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License 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.
+ * Copyright (C) Canner, Inc - All Rights Reserved
+ * Unauthorized copying of this file, via any medium is strictly prohibited
+ * Proprietary and confidential
+ * Written by Canner dev team contact@canner.io, Nov 2021
*/
package io.trino.sql.util;
diff --git a/core/trino-parser/src/main/java/io/trino/sql/util/IntervalLiteralUtil.java b/core/trino-parser/src/main/java/io/trino/sql/util/IntervalLiteralUtil.java
index a10027c6d..b3ff9c785 100644
--- a/core/trino-parser/src/main/java/io/trino/sql/util/IntervalLiteralUtil.java
+++ b/core/trino-parser/src/main/java/io/trino/sql/util/IntervalLiteralUtil.java
@@ -1,15 +1,8 @@
/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License 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.
+ * Copyright (C) Canner, Inc - All Rights Reserved
+ * Unauthorized copying of this file, via any medium is strictly prohibited
+ * Proprietary and confidential
+ * Written by Canner dev team contact@canner.io, Feb 2022
*/
package io.trino.sql.util;
@@ -32,9 +25,9 @@ public final class IntervalLiteralUtil
*
* e.g.
* when client sends a query like
- * select CAST((CAST(now() AS timestamp) + (INTERVAL '-30 day')) AS date);
+ * select CAST((CAST(now() AS timestamp) + (INTERVAL '-30 day')) AS date);
* will get the same result as
- * select CAST((CAST(now() AS timestamp) + (INTERVAL - '30' day)) AS date);
+ * select CAST((CAST(now() AS timestamp) + (INTERVAL - '30' day)) AS date);
*/
public static IntervalLiteral parse(NodeLocation location, String text)
{
diff --git a/core/trino-parser/src/test/java/io/trino/sql/parser/ParserAssert.java b/core/trino-parser/src/test/java/io/trino/sql/parser/ParserAssert.java
index 21f70b7a4..8c20a7a4b 100644
--- a/core/trino-parser/src/test/java/io/trino/sql/parser/ParserAssert.java
+++ b/core/trino-parser/src/test/java/io/trino/sql/parser/ParserAssert.java
@@ -16,6 +16,7 @@ package io.trino.sql.parser;
import io.trino.sql.SqlFormatter;
import io.trino.sql.tree.Expression;
import io.trino.sql.tree.Node;
+import io.trino.sql.tree.RowPattern;
import io.trino.sql.tree.Statement;
import org.assertj.core.api.AssertProvider;
import org.assertj.core.api.RecursiveComparisonAssert;
@@ -35,7 +36,7 @@ public class ParserAssert
@Override
public String toStringOf(Object object)
{
- if (object instanceof Statement || object instanceof Expression) {
+ if (object instanceof Statement || object instanceof Expression || object instanceof RowPattern) {
return SqlFormatter.formatSql((Node) object);
}
return super.toStringOf(object);
@@ -57,6 +58,11 @@ public class ParserAssert
return createAssertion(statement -> new SqlParser().createStatement(statement, new ParsingOptions(AS_DECIMAL)), sql);
}
+ public static AssertProvider rowPattern(String sql)
+ {
+ return createAssertion(new SqlParser()::createRowPattern, sql);
+ }
+
private ParserAssert(Node actual, RecursiveComparisonConfiguration recursiveComparisonConfiguration)
{
super(actual, recursiveComparisonConfiguration);
diff --git a/core/trino-parser/src/test/java/io/trino/sql/parser/TestSqlParser.java b/core/trino-parser/src/test/java/io/trino/sql/parser/TestSqlParser.java
index 940760e17..cdc684799 100644
--- a/core/trino-parser/src/test/java/io/trino/sql/parser/TestSqlParser.java
+++ b/core/trino-parser/src/test/java/io/trino/sql/parser/TestSqlParser.java
@@ -22,6 +22,7 @@ import io.trino.sql.tree.AliasedRelation;
import io.trino.sql.tree.AllColumns;
import io.trino.sql.tree.AllRows;
import io.trino.sql.tree.Analyze;
+import io.trino.sql.tree.AnchorPattern;
import io.trino.sql.tree.ArithmeticBinaryExpression;
import io.trino.sql.tree.ArrayConstructor;
import io.trino.sql.tree.AtTimeZone;
@@ -58,6 +59,7 @@ import io.trino.sql.tree.DropRole;
import io.trino.sql.tree.DropSchema;
import io.trino.sql.tree.DropTable;
import io.trino.sql.tree.DropView;
+import io.trino.sql.tree.EmptyPattern;
import io.trino.sql.tree.Execute;
import io.trino.sql.tree.ExistsPredicate;
import io.trino.sql.tree.Explain;
@@ -106,17 +108,24 @@ import io.trino.sql.tree.NotExpression;
import io.trino.sql.tree.NullIfExpression;
import io.trino.sql.tree.NullLiteral;
import io.trino.sql.tree.Offset;
+import io.trino.sql.tree.OneOrMoreQuantifier;
import io.trino.sql.tree.OrderBy;
import io.trino.sql.tree.Parameter;
import io.trino.sql.tree.PathElement;
import io.trino.sql.tree.PathSpecification;
+import io.trino.sql.tree.PatternAlternation;
+import io.trino.sql.tree.PatternConcatenation;
+import io.trino.sql.tree.PatternVariable;
import io.trino.sql.tree.Prepare;
import io.trino.sql.tree.PrincipalSpecification;
+import io.trino.sql.tree.ProcessingMode;
import io.trino.sql.tree.Property;
import io.trino.sql.tree.QualifiedName;
import io.trino.sql.tree.QuantifiedComparisonExpression;
+import io.trino.sql.tree.QuantifiedPattern;
import io.trino.sql.tree.Query;
import io.trino.sql.tree.QuerySpecification;
+import io.trino.sql.tree.RangeQuantifier;
import io.trino.sql.tree.RefreshMaterializedView;
import io.trino.sql.tree.RenameColumn;
import io.trino.sql.tree.RenameSchema;
@@ -172,6 +181,8 @@ import io.trino.sql.tree.WindowReference;
import io.trino.sql.tree.WindowSpecification;
import io.trino.sql.tree.With;
import io.trino.sql.tree.WithQuery;
+import io.trino.sql.tree.ZeroOrMoreQuantifier;
+import io.trino.sql.tree.ZeroOrOneQuantifier;
import org.testng.annotations.Test;
import java.util.ArrayList;
@@ -195,6 +206,7 @@ import static io.trino.sql.QueryUtil.table;
import static io.trino.sql.QueryUtil.values;
import static io.trino.sql.SqlFormatter.formatSql;
import static io.trino.sql.parser.ParserAssert.expression;
+import static io.trino.sql.parser.ParserAssert.rowPattern;
import static io.trino.sql.parser.ParserAssert.statement;
import static io.trino.sql.parser.ParsingOptions.DecimalLiteralTreatment.AS_DECIMAL;
import static io.trino.sql.parser.TreeNodes.columnDefinition;
@@ -210,6 +222,8 @@ import static io.trino.sql.tree.ArithmeticUnaryExpression.negative;
import static io.trino.sql.tree.ArithmeticUnaryExpression.positive;
import static io.trino.sql.tree.DateTimeDataType.Type.TIMESTAMP;
import static io.trino.sql.tree.FrameBound.Type.CURRENT_ROW;
+import static io.trino.sql.tree.ProcessingMode.Mode.FINAL;
+import static io.trino.sql.tree.ProcessingMode.Mode.RUNNING;
import static io.trino.sql.tree.SortItem.NullOrdering.UNDEFINED;
import static io.trino.sql.tree.SortItem.Ordering.ASCENDING;
import static io.trino.sql.tree.SortItem.Ordering.DESCENDING;
@@ -647,6 +661,113 @@ public class TestSqlParser
subquery(valuesQuery)));
}
+ @Test
+ public void testRowPattern()
+ {
+ assertThat(rowPattern("(A B)* | CC+? DD?? E | (F | G)"))
+ .isEqualTo(
+ new PatternAlternation(
+ location(1, 1),
+ ImmutableList.of(
+ new PatternAlternation(
+ location(1, 1),
+ ImmutableList.of(
+ new QuantifiedPattern(
+ location(1, 1),
+ new PatternConcatenation(
+ location(1, 2),
+ ImmutableList.of(
+ new PatternVariable(location(1, 2), new Identifier(location(1, 2), "A", false)),
+ new PatternVariable(location(1, 4), new Identifier(location(1, 4), "B", false)))),
+ new ZeroOrMoreQuantifier(location(1, 6), true)),
+ new PatternConcatenation(
+ location(1, 10),
+ ImmutableList.of(
+ new PatternConcatenation(
+ location(1, 10),
+ ImmutableList.of(
+ new QuantifiedPattern(location(1, 10), new PatternVariable(location(1, 10), new Identifier(location(1, 10), "CC", false)), new OneOrMoreQuantifier(location(1, 12), false)),
+ new QuantifiedPattern(location(1, 15), new PatternVariable(location(1, 15), new Identifier(location(1, 15), "DD", false)), new ZeroOrOneQuantifier(location(1, 17), false)))),
+ new PatternVariable(location(1, 20), new Identifier(location(1, 20), "E", false)))))),
+ new PatternAlternation(
+ location(1, 25),
+ ImmutableList.of(
+ new PatternVariable(location(1, 25), new Identifier(location(1, 25), "F", false)),
+ new PatternVariable(location(1, 29), new Identifier(location(1, 29), "G", false)))))));
+
+ assertThat(rowPattern("A | B | C D E F"))
+ .isEqualTo(
+ new PatternAlternation(
+ location(1, 1),
+ ImmutableList.of(
+ new PatternAlternation(
+ location(1, 1),
+ ImmutableList.of(
+ new PatternVariable(location(1, 1), new Identifier(location(1, 1), "A", false)),
+ new PatternVariable(location(1, 5), new Identifier(location(1, 5), "B", false)))),
+ new PatternConcatenation(
+ location(1, 9),
+ ImmutableList.of(
+ new PatternConcatenation(
+ location(1, 9),
+ ImmutableList.of(
+ new PatternConcatenation(
+ location(1, 9),
+ ImmutableList.of(
+ new PatternVariable(location(1, 9), new Identifier(location(1, 9), "C", false)),
+ new PatternVariable(location(1, 11), new Identifier(location(1, 11), "D", false)))),
+ new PatternVariable(location(1, 13), new Identifier(location(1, 13), "E", false)))),
+ new PatternVariable(location(1, 15), new Identifier(location(1, 15), "F", false)))))));
+
+ assertThatThrownBy(() -> SQL_PARSER.createRowPattern("A!"))
+ .isInstanceOf(ParsingException.class)
+ .hasMessageMatching("line 1:2: mismatched input '!'.*");
+
+ assertThatThrownBy(() -> SQL_PARSER.createRowPattern("A**"))
+ .isInstanceOf(ParsingException.class)
+ .hasMessageMatching("line 1:3: mismatched input '*'.*");
+
+ assertThat(rowPattern("A??"))
+ .isEqualTo(new QuantifiedPattern(
+ location(1, 1),
+ new PatternVariable(location(1, 1), new Identifier(location(1, 1), "A", false)),
+ new ZeroOrOneQuantifier(location(1, 2), false)));
+
+ assertThat(rowPattern("^$"))
+ .isEqualTo(new PatternConcatenation(
+ location(1, 1),
+ ImmutableList.of(
+ new AnchorPattern(location(1, 1), AnchorPattern.Type.PARTITION_START),
+ new AnchorPattern(location(1, 2), AnchorPattern.Type.PARTITION_END))));
+
+ assertThat(rowPattern("()"))
+ .isEqualTo(new EmptyPattern(location(1, 1)));
+
+ assertThat(rowPattern("A{3}"))
+ .isEqualTo(new QuantifiedPattern(
+ location(1, 1),
+ new PatternVariable(location(1, 1), new Identifier(location(1, 1), "A", false)),
+ new RangeQuantifier(location(1, 2), true, Optional.of(new LongLiteral(location(1, 3), "3")), Optional.of(new LongLiteral(location(1, 3), "3")))));
+
+ assertThat(rowPattern("A{3,}"))
+ .isEqualTo(new QuantifiedPattern(
+ location(1, 1),
+ new PatternVariable(location(1, 1), new Identifier(location(1, 1), "A", false)),
+ new RangeQuantifier(location(1, 2), true, Optional.of(new LongLiteral(location(1, 3), "3")), Optional.empty())));
+
+ assertThat(rowPattern("A{,3}"))
+ .isEqualTo(new QuantifiedPattern(
+ location(1, 1),
+ new PatternVariable(location(1, 1), new Identifier(location(1, 1), "A", false)),
+ new RangeQuantifier(location(1, 2), true, Optional.empty(), Optional.of(new LongLiteral(location(1, 4), "3")))));
+
+ assertThat(rowPattern("A{3,4}"))
+ .isEqualTo(new QuantifiedPattern(
+ location(1, 1),
+ new PatternVariable(location(1, 1), new Identifier(location(1, 1), "A", false)),
+ new RangeQuantifier(location(1, 2), true, Optional.of(new LongLiteral(location(1, 3), "3")), Optional.of(new LongLiteral(location(1, 5), "4")))));
+ }
+
@Test
public void testPrecedenceAndAssociativity()
{
@@ -2402,8 +2523,12 @@ public class TestSqlParser
for (String fullName : tableNames) {
QualifiedName qualifiedName = makeQualifiedName(fullName);
+
+ // Simple SELECT
assertStatement(format("SHOW STATS FOR (SELECT * FROM %s)", qualifiedName),
createShowStats(qualifiedName, ImmutableList.of(new AllColumns()), Optional.empty()));
+
+ // SELECT with predicate
assertStatement(format("SHOW STATS FOR (SELECT * FROM %s WHERE field > 0)", qualifiedName),
createShowStats(qualifiedName,
ImmutableList.of(new AllColumns()),
@@ -2411,6 +2536,8 @@ public class TestSqlParser
new ComparisonExpression(ComparisonExpression.Operator.GREATER_THAN,
new Identifier("field"),
new LongLiteral("0")))));
+
+ // SELECT with more complex predicate
assertStatement(format("SHOW STATS FOR (SELECT * FROM %s WHERE field > 0 or field < 0)", qualifiedName),
createShowStats(qualifiedName,
ImmutableList.of(new AllColumns()),
@@ -2423,6 +2550,128 @@ public class TestSqlParser
new Identifier("field"),
new LongLiteral("0"))))));
}
+
+ // SELECT with LIMIT
+ assertThat(statement("SHOW STATS FOR (SELECT * FROM t LIMIT 10)"))
+ .isEqualTo(
+ new ShowStats(
+ Optional.of(location(1, 1)),
+ new TableSubquery(
+ new Query(
+ location(1, 17),
+ Optional.empty(),
+ new QuerySpecification(
+ location(1, 17),
+ new Select(
+ location(1, 17),
+ false,
+ ImmutableList.of(new AllColumns(location(1, 24), Optional.empty(), ImmutableList.of()))),
+ Optional.of(new Table(
+ location(1, 31),
+ QualifiedName.of(ImmutableList.of(new Identifier(location(1, 31), "t", false))))),
+ Optional.empty(),
+ Optional.empty(),
+ Optional.empty(),
+ ImmutableList.of(),
+ Optional.empty(),
+ Optional.empty(),
+ Optional.of(new Limit(location(1, 33), new LongLiteral(location(1, 39), "10")))),
+ Optional.empty(),
+ Optional.empty(),
+ Optional.empty()))));
+
+ // SELECT with ORDER BY ... LIMIT
+ assertThat(statement("SHOW STATS FOR (SELECT * FROM t ORDER BY field LIMIT 10)"))
+ .isEqualTo(
+ new ShowStats(
+ Optional.of(location(1, 1)),
+ new TableSubquery(
+ new Query(
+ location(1, 17),
+ Optional.empty(),
+ new QuerySpecification(
+ location(1, 17),
+ new Select(
+ location(1, 17),
+ false,
+ ImmutableList.of(new AllColumns(location(1, 24), Optional.empty(), ImmutableList.of()))),
+ Optional.of(new Table(
+ location(1, 31),
+ QualifiedName.of(ImmutableList.of(new Identifier(location(1, 31), "t", false))))),
+ Optional.empty(),
+ Optional.empty(),
+ Optional.empty(),
+ ImmutableList.of(),
+ Optional.of(new OrderBy(location(1, 33), ImmutableList.of(
+ new SortItem(location(1, 42), new Identifier(location(1, 42), "field", false), ASCENDING, UNDEFINED)))),
+ Optional.empty(),
+ Optional.of(new Limit(location(1, 48), new LongLiteral(location(1, 54), "10")))),
+ Optional.empty(),
+ Optional.empty(),
+ Optional.empty()))));
+
+ // SELECT with WITH
+ assertThat(statement("SHOW STATS FOR (\n" +
+ " WITH t AS (SELECT 1 )\n" +
+ " SELECT * FROM t)"))
+ .isEqualTo(
+ new ShowStats(
+ Optional.of(location(1, 1)),
+ new TableSubquery(
+ new Query(
+ location(2, 4),
+ Optional.of(
+ new With(
+ location(2, 4),
+ false,
+ ImmutableList.of(
+ new WithQuery(
+ location(2, 9),
+ new Identifier(location(2, 9), "t", false),
+ new Query(
+ location(2, 15),
+ Optional.empty(),
+ new QuerySpecification(
+ location(2, 15),
+ new Select(
+ location(2, 15),
+ false,
+ ImmutableList.of(
+ new SingleColumn(
+ location(2, 22),
+ new LongLiteral(location(2, 22), "1"),
+ Optional.empty()))),
+ Optional.empty(),
+ Optional.empty(),
+ Optional.empty(),
+ Optional.empty(),
+ ImmutableList.of(),
+ Optional.empty(),
+ Optional.empty(),
+ Optional.empty()),
+ Optional.empty(),
+ Optional.empty(),
+ Optional.empty()),
+ Optional.empty())))),
+ new QuerySpecification(
+ location(3, 4),
+ new Select(
+ location(3, 4),
+ false,
+ ImmutableList.of(new AllColumns(location(3, 11), Optional.empty(), ImmutableList.of()))),
+ Optional.of(new Table(
+ location(3, 18),
+ QualifiedName.of(ImmutableList.of(new Identifier(location(3, 18), "t", false))))),
+ Optional.empty(),
+ Optional.empty(),
+ Optional.empty(),
+ ImmutableList.of(),
+ Optional.empty(),
+ Optional.empty(),
+ Optional.empty()),
+ Optional.empty(),
+ Optional.empty(),
+ Optional.empty()))));
}
private static ShowStats createShowStats(QualifiedName name, List selects, Optional where)
@@ -2462,6 +2711,7 @@ public class TestSqlParser
Optional.empty(),
false,
Optional.empty(),
+ Optional.empty(),
ImmutableList.of(new Identifier("x"))))));
}
@@ -2500,6 +2750,7 @@ public class TestSqlParser
Optional.of(new OrderBy(ImmutableList.of(new SortItem(identifier("x"), DESCENDING, UNDEFINED)))),
false,
Optional.empty(),
+ Optional.empty(),
ImmutableList.of(identifier("x"))));
assertStatement("SELECT array_agg(x ORDER BY t.y) FROM t",
simpleQuery(
@@ -2511,6 +2762,7 @@ public class TestSqlParser
Optional.of(new OrderBy(ImmutableList.of(new SortItem(new DereferenceExpression(new Identifier("t"), identifier("y")), ASCENDING, UNDEFINED)))),
false,
Optional.empty(),
+ Optional.empty(),
ImmutableList.of(new Identifier("x")))),
table(QualifiedName.of("t"))));
}
@@ -2778,6 +3030,7 @@ public class TestSqlParser
Optional.empty(),
false,
Optional.of(NullTreatment.IGNORE),
+ Optional.empty(),
ImmutableList.of(new Identifier("x"), new LongLiteral("1"))));
assertExpression("lead(x, 1) respect nulls over()",
new FunctionCall(
@@ -2788,6 +3041,34 @@ public class TestSqlParser
Optional.empty(),
false,
Optional.of(NullTreatment.RESPECT),
+ Optional.empty(),
+ ImmutableList.of(new Identifier("x"), new LongLiteral("1"))));
+ }
+
+ @Test
+ public void testProcessingMode()
+ {
+ assertExpression("RUNNING LAST(x, 1)",
+ new FunctionCall(
+ Optional.empty(),
+ QualifiedName.of("LAST"),
+ Optional.empty(),
+ Optional.empty(),
+ Optional.empty(),
+ false,
+ Optional.empty(),
+ Optional.of(new ProcessingMode(Optional.empty(), RUNNING)),
+ ImmutableList.of(new Identifier("x"), new LongLiteral("1"))));
+ assertExpression("FINAL FIRST(x, 1)",
+ new FunctionCall(
+ Optional.empty(),
+ QualifiedName.of("FIRST"),
+ Optional.empty(),
+ Optional.empty(),
+ Optional.empty(),
+ false,
+ Optional.empty(),
+ Optional.of(new ProcessingMode(Optional.empty(), FINAL)),
ImmutableList.of(new Identifier("x"), new LongLiteral("1"))));
}
@@ -2803,6 +3084,7 @@ public class TestSqlParser
Optional.empty(),
false,
Optional.empty(),
+ Optional.empty(),
ImmutableList.of()));
assertExpression("rank() OVER (someWindow PARTITION BY x ORDER BY y ROWS CURRENT ROW)",
@@ -2818,6 +3100,7 @@ public class TestSqlParser
Optional.empty(),
false,
Optional.empty(),
+ Optional.empty(),
ImmutableList.of()));
assertExpression("rank() OVER (PARTITION BY x ORDER BY y ROWS CURRENT ROW)",
@@ -2833,6 +3116,7 @@ public class TestSqlParser
Optional.empty(),
false,
Optional.empty(),
+ Optional.empty(),
ImmutableList.of()));
}
@@ -2866,6 +3150,7 @@ public class TestSqlParser
Optional.empty()));
}
+ @Test
public void testUpdate()
{
assertStatement("" +
@@ -2904,18 +3189,30 @@ public class TestSqlParser
return QualifiedName.of(parts);
}
+ /**
+ * @deprecated use {@link ParserAssert#statement(String)} instead
+ */
+ @Deprecated
private static void assertStatement(String query, Statement expected)
{
assertParsed(query, expected, SQL_PARSER.createStatement(query, new ParsingOptions()));
assertFormattedSql(SQL_PARSER, expected);
}
+ /**
+ * @deprecated use {@link ParserAssert#statement(String)} instead
+ */
+ @Deprecated
private static void assertInvalidStatement(String statement, String expectedErrorMessageRegex)
{
assertThatThrownBy(() -> SQL_PARSER.createStatement(statement, new ParsingOptions()))
.isInstanceOfSatisfying(ParsingException.class, e -> assertTrue(e.getErrorMessage().matches(expectedErrorMessageRegex)));
}
+ /**
+ * @deprecated use {@link ParserAssert#expression(String)} instead
+ */
+ @Deprecated
private static void assertExpression(String expression, Expression expected)
{
requireNonNull(expression, "expression is null");
diff --git a/core/trino-parser/src/test/java/io/trino/sql/parser/TestSqlParserErrorHandling.java b/core/trino-parser/src/test/java/io/trino/sql/parser/TestSqlParserErrorHandling.java
index 4a004a6fa..3e6620302 100644
--- a/core/trino-parser/src/test/java/io/trino/sql/parser/TestSqlParserErrorHandling.java
+++ b/core/trino-parser/src/test/java/io/trino/sql/parser/TestSqlParserErrorHandling.java
@@ -50,8 +50,8 @@ public class TestSqlParserErrorHandling
{"select * from 'oops",
"line 1:15: mismatched input '''. Expecting: '(', 'LATERAL', 'UNNEST', "},
{"select *\nfrom x\nfrom",
- "line 3:1: mismatched input 'from'. Expecting: ',', '.', 'AS', 'CROSS', 'EXCEPT', 'FETCH', 'FULL', 'GROUP', 'HAVING', 'INNER', 'INTERSECT', 'JOIN', 'LEFT', 'LIMIT', 'NATURAL', 'OFFSET', " +
- "'ORDER', 'RIGHT', 'TABLESAMPLE', 'UNION', 'WHERE', 'WINDOW', , "},
+ "line 3:1: mismatched input 'from'. Expecting: ',', '.', 'AS', 'CROSS', 'EXCEPT', 'FETCH', 'FULL', 'GROUP', 'HAVING', 'INNER', 'INTERSECT', 'JOIN', 'LEFT', " +
+ "'LIMIT', 'MATCH_RECOGNIZE', 'NATURAL', 'OFFSET', 'ORDER', 'RIGHT', 'TABLESAMPLE', 'UNION', 'WHERE', 'WINDOW', , "},
{"select *\nfrom x\nwhere from",
"line 3:7: mismatched input 'from'. Expecting: "},
{"select ",
@@ -121,8 +121,8 @@ public class TestSqlParserErrorHandling
{"SELECT foo(*) filter (",
"line 1:23: mismatched input ''. Expecting: 'WHERE'"},
{"SELECT * FROM t t x",
- "line 1:19: mismatched input 'x'. Expecting: '(', ',', 'CROSS', 'EXCEPT', 'FETCH', 'FULL', 'GROUP', 'HAVING', 'INNER', 'INTERSECT', 'JOIN', 'LEFT', 'LIMIT', 'NATURAL', 'OFFSET', 'ORDER', " +
- "'RIGHT', 'TABLESAMPLE', 'UNION', 'WHERE', 'WINDOW', "},
+ "line 1:19: mismatched input 'x'. Expecting: '(', ',', 'CROSS', 'EXCEPT', 'FETCH', 'FULL', 'GROUP', 'HAVING', 'INNER', 'INTERSECT', 'JOIN', 'LEFT', 'LIMIT', " +
+ "'MATCH_RECOGNIZE', 'NATURAL', 'OFFSET', 'ORDER', 'RIGHT', 'TABLESAMPLE', 'UNION', 'WHERE', 'WINDOW', "},
{"SELECT * FROM t WHERE EXISTS (",
"line 1:31: mismatched input ''. Expecting: