Bump trino-parser to Trino 358 (#1)

This commit is contained in:
Jia-Xuan Liu
2022-05-10 12:00:23 +08:00
committed by GitHub
parent 3f1dd179fa
commit fa025f7118
57 changed files with 3710 additions and 142 deletions
-10
View File
@@ -44,7 +44,6 @@
<artifactId>antlr4-runtime</artifactId>
</dependency>
<!-- for testing -->
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
@@ -63,16 +62,7 @@
<plugin>
<groupId>org.antlr</groupId>
<artifactId>antlr4-maven-plugin</artifactId>
<version>${dep.antlr.version}</version>
<executions>
<execution>
<goals>
<goal>antlr4</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
@@ -34,6 +34,10 @@ standaloneType
: type EOF
;
standaloneRowPattern
: rowPattern EOF
;
statement
: query #statementDefault
| USE schema=identifier #use
@@ -121,7 +125,7 @@ statement
| SHOW COLUMNS (FROM | IN) qualifiedName?
(LIKE pattern=string (ESCAPE escape=string)?)? #showColumns
| SHOW STATS FOR qualifiedName #showStats
| SHOW STATS FOR '(' querySpecification ')' #showStatsForQuery
| SHOW STATS FOR '(' query ')' #showStatsForQuery
| SHOW CURRENT? ROLES ((FROM | IN) identifier)? #showRoles
| SHOW ROLE GRANTS ((FROM | IN) identifier)? #showRoleGrants
| DESCRIBE qualifiedName #showColumns
@@ -191,7 +195,7 @@ limitRowCount
rowCount
: INTEGER_VALUE
| PARAMETER
| QUESTION_MARK
;
queryTerm
@@ -284,7 +288,7 @@ joinCriteria
;
sampledRelation
: aliasedRelation (
: patternRecognition (
TABLESAMPLE sampleType '(' percentage=expression ')'
)?
;
@@ -294,6 +298,53 @@ sampleType
| SYSTEM
;
patternRecognition
: aliasedRelation (
MATCH_RECOGNIZE '('
(PARTITION BY partition+=expression (',' partition+=expression)*)?
(ORDER BY sortItem (',' sortItem)*)?
(MEASURES measureDefinition (',' measureDefinition)*)?
rowsPerMatch?
(AFTER MATCH skipTo)?
(INITIAL | SEEK)?
PATTERN '(' rowPattern ')'
(SUBSET subsetDefinition (',' subsetDefinition)*)?
DEFINE variableDefinition (',' variableDefinition)*
')'
(AS? identifier columnAliases?)?)?
;
measureDefinition
: expression AS identifier
;
rowsPerMatch
: ONE ROW PER MATCH
| ALL ROWS PER MATCH emptyMatchHandling?
;
emptyMatchHandling
: SHOW EMPTY MATCHES
| OMIT EMPTY MATCHES
| WITH UNMATCHED ROWS
;
skipTo
: 'SKIP' TO NEXT ROW
| 'SKIP' PAST LAST ROW
| 'SKIP' TO FIRST identifier
| 'SKIP' TO LAST identifier
| 'SKIP' TO identifier
;
subsetDefinition
: name=identifier EQ '(' union+=identifier (',' union+=identifier)* ')'
;
variableDefinition
: identifier AS expression
;
aliasedRelation
: relationPrimary (AS? identifier columnAliases?)?
;
@@ -356,16 +407,18 @@ primaryExpression
| interval #intervalLiteral
| identifier string #typeConstructor
| DOUBLE PRECISION string #typeConstructor
// for wireprotocol pg style type consturctor
| string PG_CAST identifier #typeConstructor
| number #numericLiteral
| booleanValue #booleanLiteral
| string #stringLiteral
| BINARY_LITERAL #binaryLiteral
| PARAMETER #parameter
| QUESTION_MARK #parameter
| POSITION '(' valueExpression IN valueExpression ')' #position
| '(' expression (',' expression)+ ')' #rowConstructor
| ROW '(' expression (',' expression)* ')' #rowConstructor
| qualifiedName '(' ASTERISK ')' filter? over? #functionCall
| qualifiedName '(' (setQuantifier? expression (',' expression)*)?
| processingMode? qualifiedName '(' (setQuantifier? expression (',' expression)*)?
(ORDER BY sortItem (',' sortItem)*)? ')' filter? (nullTreatment? over)? #functionCall
| identifier '->' expression #lambda
| '(' (identifier (',' identifier)*)? ')' '->' expression #lambda
@@ -388,6 +441,9 @@ primaryExpression
| name=LOCALTIME ('(' precision=INTEGER_VALUE ')')? #specialDateTimeFunction
| name=LOCALTIMESTAMP ('(' precision=INTEGER_VALUE ')')? #specialDateTimeFunction
| name=CURRENT_USER #currentUser
| name=CURRENT_CATALOG #currentCatalog
// To support pg-style current_schema()
| name=CURRENT_SCHEMA ('(' ')')? #currentSchema
| name=CURRENT_PATH #currentPath
| SUBSTRING '(' valueExpression FROM valueExpression (FOR valueExpression)? ')' #substring
| NORMALIZE '(' valueExpression (',' normalForm)? ')' #normalize
@@ -396,6 +452,11 @@ primaryExpression
| GROUPING '(' (qualifiedName (',' qualifiedName)*)? ')' #groupingOperation
;
processingMode
: RUNNING
| FINAL
;
nullTreatment
: IGNORE NULLS
| RESPECT NULLS
@@ -496,6 +557,30 @@ frameBound
| expression boundType=(PRECEDING | FOLLOWING) #boundedFrame
;
rowPattern
: patternPrimary patternQuantifier? #quantifiedPrimary
| rowPattern rowPattern #patternConcatenation
| rowPattern '|' rowPattern #patternAlternation
;
patternPrimary
: identifier #patternVariable
| '(' ')' #emptyPattern
| PERMUTE '(' rowPattern (',' rowPattern)* ')' #patternPermutation
| '(' rowPattern ')' #groupedPattern
| '^' #partitionStartAnchor
| '$' #partitionEndAnchor
| '{-' rowPattern '-}' #excludedPattern
;
patternQuantifier
: ASTERISK (reluctant=QUESTION_MARK)? #zeroOrMoreQuantifier
| PLUS (reluctant=QUESTION_MARK)? #oneOrMoreQuantifier
| QUESTION_MARK (reluctant=QUESTION_MARK)? #zeroOrOneQuantifier
| '{' exactly=INTEGER_VALUE '}' (reluctant=QUESTION_MARK)? #rangeQuantifier
| '{' (atLeast=INTEGER_VALUE)? ',' (atMost=INTEGER_VALUE)? '}' (reluctant=QUESTION_MARK)? #rangeQuantifier
;
updateAssignment
: identifier EQ expression
;
@@ -571,26 +656,26 @@ number
nonReserved
// IMPORTANT: this rule must only contain tokens. Nested rules are not supported. See SqlParser.exitNonReserved
: ADD | ADMIN | ALL | ANALYZE | ANY | ARRAY | ASC | AT | AUTHORIZATION
: ADD | ADMIN | AFTER | ALL | ANALYZE | ANY | ARRAY | ASC | AT | AUTHORIZATION
| BERNOULLI
| CALL | CASCADE | CATALOGS | COLUMN | COLUMNS | COMMENT | COMMIT | COMMITTED | CURRENT
| DATA | DATE | DAY | DEFINER | DESC | DISTRIBUTED | DOUBLE
| EXCLUDING | EXPLAIN
| FETCH | FILTER | FIRST | FOLLOWING | FORMAT | FUNCTIONS
| DATA | DATE | DAY | DEFINE | DEFINER | DESC | DISTRIBUTED | DOUBLE
| EMPTY | EXCLUDING | EXPLAIN
| FETCH | FILTER | FINAL | FIRST | FOLLOWING | FORMAT | FUNCTIONS
| GRANT | GRANTED | GRANTS | GRAPHVIZ | GROUPS
| HOUR
| IF | IGNORE | INCLUDING | INPUT | INTERVAL | INVOKER | IO | ISOLATION
| IF | IGNORE | INCLUDING | INITIAL | INPUT | INTERVAL | INVOKER | IO | ISOLATION
| JSON
| LAST | LATERAL | LEVEL | LIMIT | LOGICAL
| MAP | MATCHED | MATERIALIZED | MERGE | MINUTE | MONTH
| MAP | MATCH | MATCHED | MATCHES | MATCH_RECOGNIZE | MATERIALIZED | MEASURES | MERGE | MINUTE | MONTH
| NEXT | NFC | NFD | NFKC | NFKD | NO | NONE | NULLIF | NULLS
| OFFSET | ONLY | OPTION | ORDINALITY | OUTPUT | OVER
| PARTITION | PARTITIONS | PATH | POSITION | PRECEDING | PRECISION | PRIVILEGES | PROPERTIES
| RANGE | READ | REFRESH | RENAME | REPEATABLE | REPLACE | RESET | RESPECT | RESTRICT | REVOKE | ROLE | ROLES | ROLLBACK | ROW | ROWS
| SCHEMA | SCHEMAS | SECOND | SECURITY | SERIALIZABLE | SESSION | SET | SETS
| SHOW | SOME | START | STATS | SUBSTRING | SYSTEM
| OFFSET | OMIT | ONE | ONLY | OPTION | ORDINALITY | OUTPUT | OVER
| PARTITION | PARTITIONS | PAST | PATH | PATTERN | PER | PERMUTE | POSITION | PRECEDING | PRECISION | PRIVILEGES | PROPERTIES
| RANGE | READ | REFRESH | RENAME | REPEATABLE | REPLACE | RESET | RESPECT | RESTRICT | REVOKE | ROLE | ROLES | ROLLBACK | ROW | ROWS | RUNNING
| SCHEMA | SCHEMAS | SECOND | SECURITY | SEEK | SERIALIZABLE | SESSION | SET | SETS
| SHOW | SOME | START | STATS | SUBSET | SUBSTRING | SYSTEM
| TABLES | TABLESAMPLE | TEXT | TIES | TIME | TIMESTAMP | TO | TRANSACTION | TRY_CAST | TYPE
| UNBOUNDED | UNCOMMITTED | UPDATE | USE | USER | SESSION_USER
| UNBOUNDED | UNCOMMITTED | UNMATCHED| UPDATE | USE | USER | SESSION_USER
| VALIDATE | VERBOSE | VIEW
| WINDOW | WITHOUT | WORK | WRITE
| YEAR
@@ -599,6 +684,7 @@ nonReserved
ADD: 'ADD';
ADMIN: 'ADMIN';
AFTER: 'AFTER';
ALL: 'ALL';
ALTER: 'ALTER';
ANALYZE: 'ANALYZE';
@@ -627,9 +713,11 @@ CREATE: 'CREATE';
CROSS: 'CROSS';
CUBE: 'CUBE';
CURRENT: 'CURRENT';
CURRENT_CATALOG: 'CURRENT_CATALOG';
CURRENT_DATE: 'CURRENT_DATE';
CURRENT_PATH: 'CURRENT_PATH';
CURRENT_ROLE: 'CURRENT_ROLE';
CURRENT_SCHEMA: 'CURRENT_SCHEMA';
CURRENT_TIME: 'CURRENT_TIME';
CURRENT_TIMESTAMP: 'CURRENT_TIMESTAMP';
CURRENT_USER: 'CURRENT_USER';
@@ -641,11 +729,13 @@ DEFINER: 'DEFINER';
DELETE: 'DELETE';
DESC: 'DESC';
DESCRIBE: 'DESCRIBE';
DEFINE: 'DEFINE';
DISTINCT: 'DISTINCT';
DISTRIBUTED: 'DISTRIBUTED';
DOUBLE: 'DOUBLE';
DROP: 'DROP';
ELSE: 'ELSE';
EMPTY: 'EMPTY';
END: 'END';
ESCAPE: 'ESCAPE';
EXCEPT: 'EXCEPT';
@@ -657,6 +747,7 @@ EXTRACT: 'EXTRACT';
FALSE: 'FALSE';
FETCH: 'FETCH';
FILTER: 'FILTER';
FINAL: 'FINAL';
FIRST: 'FIRST';
FOLLOWING: 'FOLLOWING';
FOR: 'FOR';
@@ -677,6 +768,7 @@ IF: 'IF';
IGNORE: 'IGNORE';
IN: 'IN';
INCLUDING: 'INCLUDING';
INITIAL: 'INITIAL';
INNER: 'INNER';
INPUT: 'INPUT';
INSERT: 'INSERT';
@@ -699,8 +791,12 @@ LOCALTIME: 'LOCALTIME';
LOCALTIMESTAMP: 'LOCALTIMESTAMP';
LOGICAL: 'LOGICAL';
MAP: 'MAP';
MATCH: 'MATCH';
MATCHED: 'MATCHED';
MATCHES: 'MATCHES';
MATCH_RECOGNIZE: 'MATCH_RECOGNIZE';
MATERIALIZED: 'MATERIALIZED';
MEASURES: 'MEASURES';
MERGE: 'MERGE';
MINUTE: 'MINUTE';
MONTH: 'MONTH';
@@ -718,7 +814,9 @@ NULL: 'NULL';
NULLIF: 'NULLIF';
NULLS: 'NULLS';
OFFSET: 'OFFSET';
OMIT: 'OMIT';
ON: 'ON';
ONE: 'ONE';
ONLY: 'ONLY';
OPTION: 'OPTION';
OR: 'OR';
@@ -729,7 +827,11 @@ OUTPUT: 'OUTPUT';
OVER: 'OVER';
PARTITION: 'PARTITION';
PARTITIONS: 'PARTITIONS';
PAST: 'PAST';
PATH: 'PATH';
PATTERN: 'PATTERN';
PER: 'PER';
PERMUTE: 'PERMUTE';
POSITION: 'POSITION';
PRECEDING: 'PRECEDING';
PRECISION: 'PRECISION';
@@ -754,10 +856,12 @@ ROLLBACK: 'ROLLBACK';
ROLLUP: 'ROLLUP';
ROW: 'ROW';
ROWS: 'ROWS';
RUNNING: 'RUNNING';
SCHEMA: 'SCHEMA';
SCHEMAS: 'SCHEMAS';
SECOND: 'SECOND';
SECURITY: 'SECURITY';
SEEK: 'SEEK';
SELECT: 'SELECT';
SERIALIZABLE: 'SERIALIZABLE';
SESSION: 'SESSION';
@@ -768,6 +872,7 @@ SHOW: 'SHOW';
SOME: 'SOME';
START: 'START';
STATS: 'STATS';
SUBSET: 'SUBSET';
SUBSTRING: 'SUBSTRING';
SYSTEM: 'SYSTEM';
TABLE: 'TABLE';
@@ -787,6 +892,7 @@ UESCAPE: 'UESCAPE';
UNBOUNDED: 'UNBOUNDED';
UNCOMMITTED: 'UNCOMMITTED';
UNION: 'UNION';
UNMATCHED: 'UNMATCHED';
UNNEST: 'UNNEST';
UPDATE: 'UPDATE';
USE: 'USE';
@@ -819,6 +925,7 @@ ASTERISK: '*';
SLASH: '/';
PERCENT: '%';
CONCAT: '||';
QUESTION_MARK : '?';
// for wireprotocol to use POSIX regular expressions
REGEX_MATCH: '~';
@@ -891,10 +998,6 @@ WS
: [ \r\n\t]+ -> channel(HIDDEN)
;
PARAMETER
: '?'
;
// Catch-all for anything we can't recognize.
// We use this to be able to ignore and recover all the text
// when splitting statements with DelimiterLexer
@@ -32,7 +32,9 @@ import io.trino.sql.tree.CharLiteral;
import io.trino.sql.tree.CoalesceExpression;
import io.trino.sql.tree.ComparisonExpression;
import io.trino.sql.tree.Cube;
import io.trino.sql.tree.CurrentCatalog;
import io.trino.sql.tree.CurrentPath;
import io.trino.sql.tree.CurrentSchema;
import io.trino.sql.tree.CurrentTime;
import io.trino.sql.tree.CurrentUser;
import io.trino.sql.tree.DateTimeDataType;
@@ -59,6 +61,7 @@ import io.trino.sql.tree.IntervalDayTimeDataType;
import io.trino.sql.tree.IntervalLiteral;
import io.trino.sql.tree.IsNotNullPredicate;
import io.trino.sql.tree.IsNullPredicate;
import io.trino.sql.tree.LabelDereference;
import io.trino.sql.tree.LambdaArgumentDeclaration;
import io.trino.sql.tree.LambdaExpression;
import io.trino.sql.tree.LikePredicate;
@@ -158,6 +161,18 @@ public final class ExpressionFormatter
.append(process(node.getTimeZone(), context)).toString();
}
@Override
protected String visitCurrentCatalog(CurrentCatalog node, Void context)
{
return "CURRENT_CATALOG";
}
@Override
protected String visitCurrentSchema(CurrentSchema node, Void context)
{
return "CURRENT_SCHEMA";
}
@Override
protected String visitCurrentUser(CurrentUser node, Void context)
{
@@ -363,6 +378,11 @@ public final class ExpressionFormatter
{
StringBuilder builder = new StringBuilder();
if (node.getProcessingMode().isPresent()) {
builder.append(node.getProcessingMode().get().getMode())
.append(" ");
}
String arguments = joinExpressions(node.getArguments());
if (node.getArguments().isEmpty() && "count".equalsIgnoreCase(node.getName().getSuffix())) {
arguments = "*";
@@ -736,6 +756,16 @@ public final class ExpressionFormatter
return builder.toString();
}
@Override
protected String visitLabelDereference(LabelDereference node, Void context)
{
// format LabelDereference L.x as "LABEL_DEREFERENCE("L", "x")"
// LabelDereference, like SymbolReference, is an IR-type expression. It is never a result of the parser.
// After being formatted this way for serialization, it will be parsed as functionCall
// and swapped back for LabelDereference.
return "LABEL_DEREFERENCE(" + formatIdentifier(node.getLabel()) + ", " + process(node.getReference()) + ")";
}
private String formatBinaryExpression(String operator, Expression left, Expression right)
{
return '(' + process(left, null) + ' ' + operator + ' ' + process(right, null) + ')';
@@ -0,0 +1,150 @@
/*
* 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;
import io.trino.sql.tree.AnchorPattern;
import io.trino.sql.tree.AstVisitor;
import io.trino.sql.tree.EmptyPattern;
import io.trino.sql.tree.ExcludedPattern;
import io.trino.sql.tree.Node;
import io.trino.sql.tree.OneOrMoreQuantifier;
import io.trino.sql.tree.PatternAlternation;
import io.trino.sql.tree.PatternConcatenation;
import io.trino.sql.tree.PatternPermutation;
import io.trino.sql.tree.PatternVariable;
import io.trino.sql.tree.QuantifiedPattern;
import io.trino.sql.tree.RangeQuantifier;
import io.trino.sql.tree.RowPattern;
import io.trino.sql.tree.ZeroOrMoreQuantifier;
import io.trino.sql.tree.ZeroOrOneQuantifier;
import static java.lang.String.format;
import static java.util.stream.Collectors.joining;
public final class RowPatternFormatter
{
private RowPatternFormatter() {}
public static String formatPattern(RowPattern pattern)
{
return new Formatter().process(pattern, null);
}
public static class Formatter
extends AstVisitor<String, Void>
{
@Override
protected String visitNode(Node node, Void context)
{
throw new UnsupportedOperationException();
}
@Override
protected String visitRowPattern(RowPattern node, Void context)
{
throw new UnsupportedOperationException(format("not yet implemented: %s.visit%s", getClass().getName(), node.getClass().getSimpleName()));
}
@Override
protected String visitPatternAlternation(PatternAlternation node, Void context)
{
return node.getPatterns().stream()
.map(child -> process(child, context))
.collect(joining(" | ", "(", ")"));
}
@Override
protected String visitPatternConcatenation(PatternConcatenation node, Void context)
{
return node.getPatterns().stream()
.map(child -> process(child, context))
.collect(joining(" ", "(", ")"));
}
@Override
protected String visitQuantifiedPattern(QuantifiedPattern node, Void context)
{
return "(" + process(node.getPattern(), context) + process(node.getPatternQuantifier(), context) + ")";
}
@Override
protected String visitPatternVariable(PatternVariable node, Void context)
{
return ExpressionFormatter.formatExpression(node.getName());
}
@Override
protected String visitEmptyPattern(EmptyPattern node, Void context)
{
return "()";
}
@Override
protected String visitPatternPermutation(PatternPermutation node, Void context)
{
return node.getPatterns().stream()
.map(child -> process(child, context))
.collect(joining(", ", "PERMUTE(", ")"));
}
@Override
protected String visitAnchorPattern(AnchorPattern node, Void context)
{
switch (node.getType()) {
case PARTITION_START:
return "^";
case PARTITION_END:
return "$";
default:
throw new IllegalStateException("unexpected anchor pattern type: " + node.getType());
}
}
@Override
protected String visitExcludedPattern(ExcludedPattern node, Void context)
{
return "{-" + process(node.getPattern(), context) + "-}";
}
@Override
protected String visitZeroOrMoreQuantifier(ZeroOrMoreQuantifier node, Void context)
{
String greedy = node.isGreedy() ? "" : "?";
return "*" + greedy;
}
@Override
protected String visitOneOrMoreQuantifier(OneOrMoreQuantifier node, Void context)
{
String greedy = node.isGreedy() ? "" : "?";
return "+" + greedy;
}
@Override
protected String visitZeroOrOneQuantifier(ZeroOrOneQuantifier node, Void context)
{
String greedy = node.isGreedy() ? "" : "?";
return "?" + greedy;
}
@Override
protected String visitRangeQuantifier(RangeQuantifier node, Void context)
{
String greedy = node.isGreedy() ? "" : "?";
String atLeast = node.getAtLeast().map(ExpressionFormatter::formatExpression).orElse("");
String atMost = node.getAtMost().map(ExpressionFormatter::formatExpression).orElse("");
return "{" + atLeast + "," + atMost + "}" + greedy;
}
}
}
@@ -72,6 +72,7 @@ import io.trino.sql.tree.NaturalJoin;
import io.trino.sql.tree.Node;
import io.trino.sql.tree.Offset;
import io.trino.sql.tree.OrderBy;
import io.trino.sql.tree.PatternRecognitionRelation;
import io.trino.sql.tree.Prepare;
import io.trino.sql.tree.PrincipalSpecification;
import io.trino.sql.tree.Property;
@@ -89,6 +90,7 @@ import io.trino.sql.tree.Revoke;
import io.trino.sql.tree.RevokeRoles;
import io.trino.sql.tree.Rollback;
import io.trino.sql.tree.Row;
import io.trino.sql.tree.RowPattern;
import io.trino.sql.tree.SampledRelation;
import io.trino.sql.tree.Select;
import io.trino.sql.tree.SelectItem;
@@ -120,7 +122,6 @@ import io.trino.sql.tree.Unnest;
import io.trino.sql.tree.Update;
import io.trino.sql.tree.UpdateAssignment;
import io.trino.sql.tree.Values;
import io.trino.sql.tree.WindowDefinition;
import io.trino.sql.tree.With;
import io.trino.sql.tree.WithQuery;
@@ -131,6 +132,7 @@ import java.util.Optional;
import java.util.stream.Collectors;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.collect.Iterables.getOnlyElement;
import static com.google.common.collect.Iterables.transform;
@@ -139,6 +141,7 @@ import static io.trino.sql.ExpressionFormatter.formatGroupBy;
import static io.trino.sql.ExpressionFormatter.formatOrderBy;
import static io.trino.sql.ExpressionFormatter.formatStringLiteral;
import static io.trino.sql.ExpressionFormatter.formatWindowSpecification;
import static io.trino.sql.RowPatternFormatter.formatPattern;
import static java.lang.String.format;
import static java.util.stream.Collectors.joining;
@@ -186,6 +189,14 @@ public final class SqlFormatter
return null;
}
@Override
protected Void visitRowPattern(RowPattern node, Integer indent)
{
checkArgument(indent == 0, "visitRowPattern should only be called at root");
builder.append(formatPattern(node));
return null;
}
@Override
protected Void visitUnnest(Unnest node, Integer indent)
{
@@ -327,21 +338,9 @@ public final class SqlFormatter
if (!node.getWindows().isEmpty()) {
append(indent, "WINDOW");
if (node.getWindows().size() == 1) {
builder.append(" ")
.append(formatWindowDefinition(node.getWindows().get(0)))
.append("\n");
}
else {
int size = node.getWindows().size();
builder.append("\n");
for (int i = 0; i < size - 1; i++) {
append(indent + 1, formatWindowDefinition(node.getWindows().get(i)))
.append(",\n");
}
append(indent + 1, formatWindowDefinition(node.getWindows().get(size - 1)))
.append("\n");
}
formatDefinitionList(node.getWindows().stream()
.map(definition -> formatExpression(definition.getName()) + " AS " + formatWindowSpecification(definition.getWindow()))
.collect(toImmutableList()), indent + 1);
}
if (node.getOrderBy().isPresent()) {
@@ -358,11 +357,6 @@ public final class SqlFormatter
return null;
}
private String formatWindowDefinition(WindowDefinition definition)
{
return formatExpression(definition.getName()) + " AS " + formatWindowSpecification(definition.getWindow());
}
@Override
protected Void visitOrderBy(OrderBy node, Integer indent)
{
@@ -526,6 +520,97 @@ public final class SqlFormatter
return null;
}
@Override
protected Void visitPatternRecognitionRelation(PatternRecognitionRelation node, Integer indent)
{
processRelationSuffix(node.getInput(), indent);
builder.append(" MATCH_RECOGNIZE (\n");
if (!node.getPartitionBy().isEmpty()) {
append(indent + 1, "PARTITION BY ")
.append(node.getPartitionBy().stream()
.map(ExpressionFormatter::formatExpression)
.collect(joining(", ")))
.append("\n");
}
if (node.getOrderBy().isPresent()) {
process(node.getOrderBy().get(), indent + 1);
}
if (!node.getMeasures().isEmpty()) {
append(indent + 1, "MEASURES");
formatDefinitionList(node.getMeasures().stream()
.map(measure -> formatExpression(measure.getExpression()) + " AS " + formatExpression(measure.getName()))
.collect(toImmutableList()), indent + 2);
}
if (node.getRowsPerMatch().isPresent()) {
String rowsPerMatch;
switch (node.getRowsPerMatch().get()) {
case ONE:
rowsPerMatch = "ONE ROW PER MATCH";
break;
case ALL_SHOW_EMPTY:
rowsPerMatch = "ALL ROWS PER MATCH SHOW EMPTY MATCHES";
break;
case ALL_OMIT_EMPTY:
rowsPerMatch = "ALL ROWS PER MATCH OMIT EMPTY MATCHES";
break;
case ALL_WITH_UNMATCHED:
rowsPerMatch = "ALL ROWS PER MATCH WITH UNMATCHED ROWS";
break;
default:
// RowsPerMatch of type WINDOW cannot occur in MATCH_RECOGNIZE clause
throw new IllegalStateException("unexpected rowsPerMatch: " + node.getRowsPerMatch().get());
}
append(indent + 1, rowsPerMatch)
.append("\n");
}
if (node.getAfterMatchSkipTo().isPresent()) {
String skipTo;
switch (node.getAfterMatchSkipTo().get().getPosition()) {
case PAST_LAST:
skipTo = "AFTER MATCH SKIP PAST LAST ROW";
break;
case NEXT:
skipTo = "AFTER MATCH SKIP TO NEXT ROW";
break;
case LAST:
checkState(node.getAfterMatchSkipTo().get().getIdentifier().isPresent(), "missing identifier in AFTER MATCH SKIP TO LAST");
skipTo = "AFTER MATCH SKIP TO LAST " + formatExpression(node.getAfterMatchSkipTo().get().getIdentifier().get());
break;
case FIRST:
checkState(node.getAfterMatchSkipTo().get().getIdentifier().isPresent(), "missing identifier in AFTER MATCH SKIP TO FIRST");
skipTo = "AFTER MATCH SKIP TO FIRST " + formatExpression(node.getAfterMatchSkipTo().get().getIdentifier().get());
break;
default:
throw new IllegalStateException("unexpected skipTo: " + node.getAfterMatchSkipTo().get());
}
append(indent + 1, skipTo)
.append("\n");
}
if (node.getPatternSearchMode().isPresent()) {
append(indent + 1, node.getPatternSearchMode().get().getMode().name())
.append("\n");
}
append(indent + 1, "PATTERN (")
.append(formatPattern(node.getPattern()))
.append(")\n");
if (!node.getSubsets().isEmpty()) {
append(indent + 1, "SUBSET");
formatDefinitionList(node.getSubsets().stream()
.map(subset -> formatExpression(subset.getName()) + " = " + subset.getIdentifiers().stream()
.map(ExpressionFormatter::formatExpression).collect(joining(", ", "(", ")")))
.collect(toImmutableList()), indent + 2);
}
append(indent + 1, "DEFINE");
formatDefinitionList(node.getVariableDefinitions().stream()
.map(variable -> formatExpression(variable.getName()) + " AS " + formatExpression(variable.getExpression()))
.collect(toImmutableList()), indent + 2);
builder.append(")");
return null;
}
@Override
protected Void visitSampledRelation(SampledRelation node, Integer indent)
{
@@ -542,7 +627,7 @@ public final class SqlFormatter
private void processRelationSuffix(Relation relation, Integer indent)
{
if ((relation instanceof AliasedRelation) || (relation instanceof SampledRelation)) {
if ((relation instanceof AliasedRelation) || (relation instanceof SampledRelation) || (relation instanceof PatternRecognitionRelation)) {
builder.append("( ");
process(relation, indent + 1);
append(indent, ")");
@@ -1572,7 +1657,7 @@ public final class SqlFormatter
builder.append(node.getType().get());
builder.append(" ");
}
builder.append(node.getName())
builder.append(formatName(node.getName()))
.append(" TO ")
.append(formatPrincipal(node.getGrantee()));
if (node.isWithGrantOption()) {
@@ -1689,6 +1774,24 @@ public final class SqlFormatter
{
return Strings.repeat(INDENT, indent);
}
private void formatDefinitionList(List<String> elements, int indent)
{
if (elements.size() == 1) {
builder.append(" ")
.append(getOnlyElement(elements))
.append("\n");
}
else {
builder.append("\n");
for (int i = 0; i < elements.size() - 1; i++) {
append(indent, elements.get(i))
.append(",\n");
}
append(indent, elements.get(elements.size() - 1))
.append("\n");
}
}
}
private static void appendAliasColumns(StringBuilder builder, List<Identifier> columns)
@@ -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.ArithmeticUnaryExpression;
import io.trino.sql.tree.ArrayConstructor;
@@ -46,7 +47,9 @@ import io.trino.sql.tree.CreateTable;
import io.trino.sql.tree.CreateTableAsSelect;
import io.trino.sql.tree.CreateView;
import io.trino.sql.tree.Cube;
import io.trino.sql.tree.CurrentCatalog;
import io.trino.sql.tree.CurrentPath;
import io.trino.sql.tree.CurrentSchema;
import io.trino.sql.tree.CurrentTime;
import io.trino.sql.tree.CurrentUser;
import io.trino.sql.tree.DataType;
@@ -65,7 +68,9 @@ 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.Except;
import io.trino.sql.tree.ExcludedPattern;
import io.trino.sql.tree.Execute;
import io.trino.sql.tree.ExistsPredicate;
import io.trino.sql.tree.Explain;
@@ -112,6 +117,7 @@ import io.trino.sql.tree.LikePredicate;
import io.trino.sql.tree.Limit;
import io.trino.sql.tree.LogicalBinaryExpression;
import io.trino.sql.tree.LongLiteral;
import io.trino.sql.tree.MeasureDefinition;
import io.trino.sql.tree.Merge;
import io.trino.sql.tree.MergeCase;
import io.trino.sql.tree.MergeDelete;
@@ -125,18 +131,30 @@ import io.trino.sql.tree.NullIfExpression;
import io.trino.sql.tree.NullLiteral;
import io.trino.sql.tree.NumericParameter;
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.PatternPermutation;
import io.trino.sql.tree.PatternQuantifier;
import io.trino.sql.tree.PatternRecognitionRelation;
import io.trino.sql.tree.PatternRecognitionRelation.RowsPerMatch;
import io.trino.sql.tree.PatternSearchMode;
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.QueryBody;
import io.trino.sql.tree.QuerySpecification;
import io.trino.sql.tree.RangeQuantifier;
import io.trino.sql.tree.RefreshMaterializedView;
import io.trino.sql.tree.Relation;
import io.trino.sql.tree.RenameColumn;
@@ -150,6 +168,7 @@ import io.trino.sql.tree.Rollback;
import io.trino.sql.tree.Rollup;
import io.trino.sql.tree.Row;
import io.trino.sql.tree.RowDataType;
import io.trino.sql.tree.RowPattern;
import io.trino.sql.tree.SampledRelation;
import io.trino.sql.tree.SearchedCaseExpression;
import io.trino.sql.tree.Select;
@@ -174,12 +193,14 @@ import io.trino.sql.tree.ShowTables;
import io.trino.sql.tree.SimpleCaseExpression;
import io.trino.sql.tree.SimpleGroupBy;
import io.trino.sql.tree.SingleColumn;
import io.trino.sql.tree.SkipTo;
import io.trino.sql.tree.SortItem;
import io.trino.sql.tree.StartTransaction;
import io.trino.sql.tree.Statement;
import io.trino.sql.tree.StringLiteral;
import io.trino.sql.tree.SubqueryExpression;
import io.trino.sql.tree.SubscriptExpression;
import io.trino.sql.tree.SubsetDefinition;
import io.trino.sql.tree.Table;
import io.trino.sql.tree.TableElement;
import io.trino.sql.tree.TableSubquery;
@@ -195,6 +216,7 @@ import io.trino.sql.tree.Update;
import io.trino.sql.tree.UpdateAssignment;
import io.trino.sql.tree.Use;
import io.trino.sql.tree.Values;
import io.trino.sql.tree.VariableDefinition;
import io.trino.sql.tree.WhenClause;
import io.trino.sql.tree.Window;
import io.trino.sql.tree.WindowDefinition;
@@ -203,6 +225,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 io.trino.sql.util.IntervalLiteralUtil;
import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.Token;
@@ -217,12 +241,25 @@ import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.collect.Iterables.getOnlyElement;
import static io.trino.sql.QueryUtil.functionCall;
import static io.trino.sql.QueryUtil.identifier;
import static io.trino.sql.QueryUtil.query;
import static io.trino.sql.QueryUtil.selectAll;
import static io.trino.sql.QueryUtil.selectList;
import static io.trino.sql.QueryUtil.simpleQuery;
import static io.trino.sql.parser.SqlBaseParser.TIME;
import static io.trino.sql.parser.SqlBaseParser.TIMESTAMP;
import static io.trino.sql.tree.AnchorPattern.Type.PARTITION_END;
import static io.trino.sql.tree.AnchorPattern.Type.PARTITION_START;
import static io.trino.sql.tree.PatternRecognitionRelation.RowsPerMatch.ALL_OMIT_EMPTY;
import static io.trino.sql.tree.PatternRecognitionRelation.RowsPerMatch.ALL_SHOW_EMPTY;
import static io.trino.sql.tree.PatternRecognitionRelation.RowsPerMatch.ALL_WITH_UNMATCHED;
import static io.trino.sql.tree.PatternRecognitionRelation.RowsPerMatch.ONE;
import static io.trino.sql.tree.PatternSearchMode.Mode.INITIAL;
import static io.trino.sql.tree.PatternSearchMode.Mode.SEEK;
import static io.trino.sql.tree.ProcessingMode.Mode.FINAL;
import static io.trino.sql.tree.ProcessingMode.Mode.RUNNING;
import static io.trino.sql.tree.SkipTo.skipPastLastRow;
import static io.trino.sql.tree.SkipTo.skipToFirst;
import static io.trino.sql.tree.SkipTo.skipToLast;
import static io.trino.sql.tree.SkipTo.skipToNextRow;
import static io.trino.sql.util.EscapedCharsUtil.replaceEscapedChars;
import static java.lang.String.format;
import static java.util.Locale.ENGLISH;
@@ -265,6 +302,12 @@ class AstBuilder
return visit(context.pathSpecification());
}
@Override
public Node visitStandaloneRowPattern(SqlBaseParser.StandaloneRowPatternContext context)
{
return visit(context.rowPattern());
}
// ******************* statements **********************
@Override
@@ -805,7 +848,7 @@ class AstBuilder
rowCount = new LongLiteral(getLocation(context.offset.INTEGER_VALUE()), context.offset.getText());
}
else {
rowCount = new Parameter(getLocation(context.offset.PARAMETER()), parameterPosition);
rowCount = new Parameter(getLocation(context.offset.QUESTION_MARK()), parameterPosition);
parameterPosition++;
}
offset = Optional.of(new Offset(Optional.of(getLocation(context.OFFSET())), rowCount));
@@ -819,7 +862,7 @@ class AstBuilder
rowCount = Optional.of(new LongLiteral(getLocation(context.fetchFirst.INTEGER_VALUE()), context.fetchFirst.getText()));
}
else {
rowCount = Optional.of(new Parameter(getLocation(context.fetchFirst.PARAMETER()), parameterPosition));
rowCount = Optional.of(new Parameter(getLocation(context.fetchFirst.QUESTION_MARK()), parameterPosition));
parameterPosition++;
}
}
@@ -837,7 +880,7 @@ class AstBuilder
rowCount = new LongLiteral(getLocation(context.limit.rowCount().INTEGER_VALUE()), context.limit.getText());
}
else {
rowCount = new Parameter(getLocation(context.limit.rowCount().PARAMETER()), parameterPosition);
rowCount = new Parameter(getLocation(context.limit.rowCount().QUESTION_MARK()), parameterPosition);
parameterPosition++;
}
@@ -1125,8 +1168,8 @@ class AstBuilder
@Override
public Node visitShowStatsForQuery(SqlBaseParser.ShowStatsForQueryContext context)
{
QuerySpecification specification = (QuerySpecification) visitQuerySpecification(context.querySpecification());
return new ShowStats(Optional.of(getLocation(context)), new TableSubquery(query(specification)));
Query query = (Query) visit(context.query());
return new ShowStats(Optional.of(getLocation(context)), new TableSubquery(query));
}
@Override
@@ -1404,7 +1447,7 @@ class AstBuilder
@Override
public Node visitSampledRelation(SqlBaseParser.SampledRelationContext context)
{
Relation child = (Relation) visit(context.aliasedRelation());
Relation child = (Relation) visit(context.patternRecognition());
if (context.TABLESAMPLE() == null) {
return child;
@@ -1417,6 +1460,114 @@ class AstBuilder
(Expression) visit(context.percentage));
}
@Override
public Node visitPatternRecognition(SqlBaseParser.PatternRecognitionContext context)
{
Relation child = (Relation) visit(context.aliasedRelation());
if (context.MATCH_RECOGNIZE() == null) {
return child;
}
Optional<OrderBy> orderBy = Optional.empty();
if (context.ORDER() != null) {
orderBy = Optional.of(new OrderBy(getLocation(context.ORDER()), visit(context.sortItem(), SortItem.class)));
}
Optional<PatternSearchMode> searchMode = Optional.empty();
if (context.INITIAL() != null) {
searchMode = Optional.of(new PatternSearchMode(getLocation(context.INITIAL()), INITIAL));
}
else if (context.SEEK() != null) {
searchMode = Optional.of(new PatternSearchMode(getLocation(context.SEEK()), SEEK));
}
PatternRecognitionRelation relation = new PatternRecognitionRelation(
getLocation(context),
child,
visit(context.partition, Expression.class),
orderBy,
visit(context.measureDefinition(), MeasureDefinition.class),
getRowsPerMatch(context.rowsPerMatch()),
visitIfPresent(context.skipTo(), SkipTo.class),
searchMode,
(RowPattern) visit(context.rowPattern()),
visit(context.subsetDefinition(), SubsetDefinition.class),
visit(context.variableDefinition(), VariableDefinition.class));
if (context.identifier() == null) {
return relation;
}
List<Identifier> aliases = null;
if (context.columnAliases() != null) {
aliases = visit(context.columnAliases().identifier(), Identifier.class);
}
return new AliasedRelation(getLocation(context), relation, (Identifier) visit(context.identifier()), aliases);
}
@Override
public Node visitMeasureDefinition(SqlBaseParser.MeasureDefinitionContext context)
{
return new MeasureDefinition(getLocation(context), (Expression) visit(context.expression()), (Identifier) visit(context.identifier()));
}
private Optional<RowsPerMatch> getRowsPerMatch(SqlBaseParser.RowsPerMatchContext context)
{
if (context == null) {
return Optional.empty();
}
if (context.ONE() != null) {
return Optional.of(ONE);
}
if (context.emptyMatchHandling() == null) {
return Optional.of(ALL_SHOW_EMPTY);
}
if (context.emptyMatchHandling().SHOW() != null) {
return Optional.of(ALL_SHOW_EMPTY);
}
if (context.emptyMatchHandling().OMIT() != null) {
return Optional.of(ALL_OMIT_EMPTY);
}
return Optional.of(ALL_WITH_UNMATCHED);
}
@Override
public Node visitSkipTo(SqlBaseParser.SkipToContext context)
{
if (context.PAST() != null) {
return skipPastLastRow(getLocation(context));
}
if (context.NEXT() != null) {
return skipToNextRow(getLocation(context));
}
if (context.FIRST() != null) {
return skipToFirst(getLocation(context), (Identifier) visit(context.identifier()));
}
return skipToLast(getLocation(context), (Identifier) visit(context.identifier()));
}
@Override
public Node visitSubsetDefinition(SqlBaseParser.SubsetDefinitionContext context)
{
return new SubsetDefinition(getLocation(context), (Identifier) visit(context.name), visit(context.union, Identifier.class));
}
@Override
public Node visitVariableDefinition(SqlBaseParser.VariableDefinitionContext context)
{
return new VariableDefinition(getLocation(context), (Identifier) visit(context.identifier()), (Expression) visit(context.expression()));
}
@Override
public Node visitAliasedRelation(SqlBaseParser.AliasedRelationContext context)
{
@@ -1752,6 +1903,18 @@ class AstBuilder
return new CurrentTime(getLocation(context), function);
}
@Override
public Node visitCurrentCatalog(SqlBaseParser.CurrentCatalogContext context)
{
return new CurrentCatalog(getLocation(context.CURRENT_CATALOG()));
}
@Override
public Node visitCurrentSchema(SqlBaseParser.CurrentSchemaContext context)
{
return new CurrentSchema(getLocation(context.CURRENT_SCHEMA()));
}
@Override
public Node visitCurrentUser(SqlBaseParser.CurrentUserContext context)
{
@@ -1871,11 +2034,14 @@ class AstBuilder
SqlBaseParser.NullTreatmentContext nullTreatment = context.nullTreatment();
SqlBaseParser.ProcessingModeContext processingMode = context.processingMode();
if (name.toString().equalsIgnoreCase("if")) {
check(context.expression().size() == 2 || context.expression().size() == 3, "Invalid number of arguments for 'if' function", context);
check(!window.isPresent(), "OVER clause not valid for 'if' function", context);
check(!distinct, "DISTINCT not valid for 'if' function", context);
check(nullTreatment == null, "Null treatment clause not valid for 'if' function", context);
check(processingMode == null, "Running or final semantics not valid for 'if' function", context);
check(!filter.isPresent(), "FILTER not valid for 'if' function", context);
Expression elseExpression = null;
@@ -1895,6 +2061,7 @@ class AstBuilder
check(!window.isPresent(), "OVER clause not valid for 'nullif' function", context);
check(!distinct, "DISTINCT not valid for 'nullif' function", context);
check(nullTreatment == null, "Null treatment clause not valid for 'nullif' function", context);
check(processingMode == null, "Running or final semantics not valid for 'nullif' function", context);
check(!filter.isPresent(), "FILTER not valid for 'nullif' function", context);
return new NullIfExpression(
@@ -1908,6 +2075,7 @@ class AstBuilder
check(!window.isPresent(), "OVER clause not valid for 'coalesce' function", context);
check(!distinct, "DISTINCT not valid for 'coalesce' function", context);
check(nullTreatment == null, "Null treatment clause not valid for 'coalesce' function", context);
check(processingMode == null, "Running or final semantics not valid for 'coalesce' function", context);
check(!filter.isPresent(), "FILTER not valid for 'coalesce' function", context);
return new CoalesceExpression(getLocation(context), visit(context.expression(), Expression.class));
@@ -1918,6 +2086,7 @@ class AstBuilder
check(!window.isPresent(), "OVER clause not valid for 'try' function", context);
check(!distinct, "DISTINCT not valid for 'try' function", context);
check(nullTreatment == null, "Null treatment clause not valid for 'try' function", context);
check(processingMode == null, "Running or final semantics not valid for 'try' function", context);
check(!filter.isPresent(), "FILTER not valid for 'try' function", context);
return new TryExpression(getLocation(context), (Expression) visit(getOnlyElement(context.expression())));
@@ -1928,6 +2097,7 @@ class AstBuilder
check(!window.isPresent(), "OVER clause not valid for 'format' function", context);
check(!distinct, "DISTINCT not valid for 'format' function", context);
check(nullTreatment == null, "Null treatment clause not valid for 'format' function", context);
check(processingMode == null, "Running or final semantics not valid for 'format' function", context);
check(!filter.isPresent(), "FILTER not valid for 'format' function", context);
return new Format(getLocation(context), visit(context.expression(), Expression.class));
@@ -1938,6 +2108,7 @@ class AstBuilder
check(!window.isPresent(), "OVER clause not valid for '$internal$bind' function", context);
check(!distinct, "DISTINCT not valid for '$internal$bind' function", context);
check(nullTreatment == null, "Null treatment clause not valid for '$internal$bind' function", context);
check(processingMode == null, "Running or final semantics not valid for '$internal$bind' function", context);
check(!filter.isPresent(), "FILTER not valid for '$internal$bind' function", context);
int numValues = context.expression().size() - 1;
@@ -1962,6 +2133,16 @@ class AstBuilder
}
}
Optional<ProcessingMode> mode = Optional.empty();
if (processingMode != null) {
if (processingMode.RUNNING() != null) {
mode = Optional.of(new ProcessingMode(getLocation(processingMode), RUNNING));
}
else if (processingMode.FINAL() != null) {
mode = Optional.of(new ProcessingMode(getLocation(processingMode), FINAL));
}
}
return new FunctionCall(
Optional.of(getLocation(context)),
name,
@@ -1970,6 +2151,7 @@ class AstBuilder
orderBy,
distinct,
nulls,
mode,
visit(context.expression(), Expression.class));
}
@@ -2103,6 +2285,114 @@ class AstBuilder
return new Identifier(getLocation(context), identifier, true);
}
@Override
public Node visitPatternAlternation(SqlBaseParser.PatternAlternationContext context)
{
List<RowPattern> parts = visit(context.rowPattern(), RowPattern.class);
return new PatternAlternation(getLocation(context), parts);
}
@Override
public Node visitPatternConcatenation(SqlBaseParser.PatternConcatenationContext context)
{
List<RowPattern> parts = visit(context.rowPattern(), RowPattern.class);
return new PatternConcatenation(getLocation(context), parts);
}
@Override
public Node visitQuantifiedPrimary(SqlBaseParser.QuantifiedPrimaryContext context)
{
RowPattern primary = (RowPattern) visit(context.patternPrimary());
if (context.patternQuantifier() != null) {
return new QuantifiedPattern(getLocation(context), primary, (PatternQuantifier) visit(context.patternQuantifier()));
}
return primary;
}
@Override
public Node visitPatternVariable(SqlBaseParser.PatternVariableContext context)
{
return new PatternVariable(getLocation(context), (Identifier) visit(context.identifier()));
}
@Override
public Node visitEmptyPattern(SqlBaseParser.EmptyPatternContext context)
{
return new EmptyPattern(getLocation(context));
}
@Override
public Node visitPatternPermutation(SqlBaseParser.PatternPermutationContext context)
{
return new PatternPermutation(getLocation(context), visit(context.rowPattern(), RowPattern.class));
}
@Override
public Node visitGroupedPattern(SqlBaseParser.GroupedPatternContext context)
{
// skip parentheses
return visit(context.rowPattern());
}
@Override
public Node visitPartitionStartAnchor(SqlBaseParser.PartitionStartAnchorContext context)
{
return new AnchorPattern(getLocation(context), PARTITION_START);
}
@Override
public Node visitPartitionEndAnchor(SqlBaseParser.PartitionEndAnchorContext context)
{
return new AnchorPattern(getLocation(context), PARTITION_END);
}
@Override
public Node visitExcludedPattern(SqlBaseParser.ExcludedPatternContext context)
{
return new ExcludedPattern(getLocation(context), (RowPattern) visit(context.rowPattern()));
}
@Override
public Node visitZeroOrMoreQuantifier(SqlBaseParser.ZeroOrMoreQuantifierContext context)
{
boolean greedy = context.reluctant == null;
return new ZeroOrMoreQuantifier(getLocation(context), greedy);
}
@Override
public Node visitOneOrMoreQuantifier(SqlBaseParser.OneOrMoreQuantifierContext context)
{
boolean greedy = context.reluctant == null;
return new OneOrMoreQuantifier(getLocation(context), greedy);
}
@Override
public Node visitZeroOrOneQuantifier(SqlBaseParser.ZeroOrOneQuantifierContext context)
{
boolean greedy = context.reluctant == null;
return new ZeroOrOneQuantifier(getLocation(context), greedy);
}
@Override
public Node visitRangeQuantifier(SqlBaseParser.RangeQuantifierContext context)
{
boolean greedy = context.reluctant == null;
Optional<LongLiteral> atLeast = Optional.empty();
Optional<LongLiteral> atMost = Optional.empty();
if (context.exactly != null) {
atLeast = Optional.of(new LongLiteral(getLocation(context.exactly), context.exactly.getText()));
atMost = Optional.of(new LongLiteral(getLocation(context.exactly), context.exactly.getText()));
}
if (context.atLeast != null) {
atLeast = Optional.of(new LongLiteral(getLocation(context.atLeast), context.atLeast.getText()));
}
if (context.atMost != null) {
atMost = Optional.of(new LongLiteral(getLocation(context.atMost), context.atMost.getText()));
}
return new RangeQuantifier(getLocation(context), greedy, atLeast, atMost);
}
// ************** literals **************
@Override
@@ -2157,7 +2447,8 @@ class AstBuilder
if (type.equalsIgnoreCase("decimal")) {
return new DecimalLiteral(getLocation(context), value);
}
if (type.equalsIgnoreCase("char")) {
// bpchar for PostgreSQL wire protocol, handle blank-padding char
if (type.equalsIgnoreCase("char") || type.equalsIgnoreCase("bpchar")) {
return new CharLiteral(getLocation(context), value);
}
// for PostgreSQL wire protocol, handle interval pattern
@@ -2219,7 +2510,7 @@ class AstBuilder
@Override
public Node visitParameter(SqlBaseParser.ParameterContext context)
{
io.trino.sql.tree.Parameter parameter = new io.trino.sql.tree.Parameter(getLocation(context), parameterPosition);
Parameter parameter = new Parameter(getLocation(context), parameterPosition);
parameterPosition++;
return parameter;
}
@@ -17,6 +17,7 @@ import io.trino.sql.tree.DataType;
import io.trino.sql.tree.Expression;
import io.trino.sql.tree.Node;
import io.trino.sql.tree.PathSpecification;
import io.trino.sql.tree.RowPattern;
import io.trino.sql.tree.Statement;
import org.antlr.v4.runtime.BaseErrorListener;
import org.antlr.v4.runtime.CharStreams;
@@ -99,6 +100,11 @@ public class SqlParser
return (PathSpecification) invokeParser("path specification", expression, SqlBaseParser::standalonePathSpecification, new ParsingOptions());
}
public RowPattern createRowPattern(String pattern)
{
return (RowPattern) invokeParser("row pattern", pattern, SqlBaseParser::standaloneRowPattern, new ParsingOptions());
}
private Node invokeParser(String name, String sql, Function<SqlBaseParser, ParserRuleContext> parseFunction, ParsingOptions parsingOptions)
{
try {
@@ -43,7 +43,7 @@ public class AddColumn
private AddColumn(Optional<NodeLocation> location, QualifiedName name, ColumnDefinition column, boolean tableExists, boolean columnNotExists)
{
super(location);
this.name = requireNonNull(name, "table is null");
this.name = requireNonNull(name, "name is null");
this.column = requireNonNull(column, "column is null");
this.tableExists = tableExists;
this.columnNotExists = columnNotExists;
@@ -41,7 +41,7 @@ public class Analyze
private Analyze(Optional<NodeLocation> location, QualifiedName tableName, List<Property> properties)
{
super(location);
this.tableName = requireNonNull(tableName, "table is null");
this.tableName = requireNonNull(tableName, "tableName is null");
this.properties = ImmutableList.copyOf(requireNonNull(properties, "properties is null"));
}
@@ -0,0 +1,96 @@
/*
* 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 AnchorPattern
extends RowPattern
{
public enum Type
{
PARTITION_START,
PARTITION_END
}
private final Type type;
public AnchorPattern(NodeLocation location, Type type)
{
this(Optional.of(location), type);
}
private AnchorPattern(Optional<NodeLocation> location, Type type)
{
super(location);
this.type = requireNonNull(type, "type is null");
}
public Type getType()
{
return type;
}
@Override
public <R, C> R accept(AstVisitor<R, C> visitor, C context)
{
return visitor.visitAnchorPattern(this, context);
}
@Override
public List<Node> getChildren()
{
return ImmutableList.of();
}
@Override
public boolean equals(Object obj)
{
if (this == obj) {
return true;
}
if ((obj == null) || (getClass() != obj.getClass())) {
return false;
}
AnchorPattern o = (AnchorPattern) obj;
return Objects.equals(type, o.type);
}
@Override
public int hashCode()
{
return getClass().hashCode();
}
@Override
public String toString()
{
return toStringHelper(this)
.add("type", type)
.toString();
}
@Override
public boolean shallowEquals(Node other)
{
return sameClass(this, other);
}
}
@@ -292,6 +292,11 @@ public abstract class AstVisitor<R, C>
return visitExpression(node, context);
}
protected R visitProcessingMode(ProcessingMode node, C context)
{
return visitNode(node, context);
}
protected R visitLambdaExpression(LambdaExpression node, C context)
{
return visitExpression(node, context);
@@ -842,6 +847,16 @@ public abstract class AstVisitor<R, C>
return visitExpression(node, context);
}
protected R visitCurrentCatalog(CurrentCatalog node, C context)
{
return visitExpression(node, context);
}
protected R visitCurrentSchema(CurrentSchema node, C context)
{
return visitExpression(node, context);
}
protected R visitCurrentUser(CurrentUser node, C context)
{
return visitExpression(node, context);
@@ -916,4 +931,109 @@ public abstract class AstVisitor<R, C>
{
return visitStatement(node, context);
}
protected R visitMeasureDefinition(MeasureDefinition node, C context)
{
return visitNode(node, context);
}
protected R visitSkipTo(SkipTo node, C context)
{
return visitNode(node, context);
}
protected R visitPatternSearchMode(PatternSearchMode node, C context)
{
return visitNode(node, context);
}
protected R visitSubsetDefinition(SubsetDefinition node, C context)
{
return visitNode(node, context);
}
protected R visitVariableDefinition(VariableDefinition node, C context)
{
return visitNode(node, context);
}
protected R visitPatternRecognitionRelation(PatternRecognitionRelation node, C context)
{
return visitRelation(node, context);
}
protected R visitLabelDereference(LabelDereference node, C context)
{
return visitExpression(node, context);
}
protected R visitRowPattern(RowPattern node, C context)
{
return visitNode(node, context);
}
protected R visitPatternAlternation(PatternAlternation node, C context)
{
return visitRowPattern(node, context);
}
protected R visitPatternConcatenation(PatternConcatenation node, C context)
{
return visitRowPattern(node, context);
}
protected R visitQuantifiedPattern(QuantifiedPattern node, C context)
{
return visitRowPattern(node, context);
}
protected R visitAnchorPattern(AnchorPattern node, C context)
{
return visitRowPattern(node, context);
}
protected R visitEmptyPattern(EmptyPattern node, C context)
{
return visitRowPattern(node, context);
}
protected R visitExcludedPattern(ExcludedPattern node, C context)
{
return visitRowPattern(node, context);
}
protected R visitPatternPermutation(PatternPermutation node, C context)
{
return visitRowPattern(node, context);
}
protected R visitPatternVariable(PatternVariable node, C context)
{
return visitRowPattern(node, context);
}
protected R visitPatternQuantifier(PatternQuantifier node, C context)
{
return visitNode(node, context);
}
protected R visitZeroOrMoreQuantifier(ZeroOrMoreQuantifier node, C context)
{
return visitPatternQuantifier(node, context);
}
protected R visitOneOrMoreQuantifier(OneOrMoreQuantifier node, C context)
{
return visitPatternQuantifier(node, context);
}
protected R visitZeroOrOneQuantifier(ZeroOrOneQuantifier node, C context)
{
return visitPatternQuantifier(node, context);
}
protected R visitRangeQuantifier(RangeQuantifier node, C context)
{
return visitPatternQuantifier(node, context);
}
}
@@ -65,7 +65,7 @@ public class BindExpression
private BindExpression(Optional<NodeLocation> location, List<Expression> values, Expression function)
{
super(location);
this.values = requireNonNull(values, "value is null");
this.values = requireNonNull(values, "values is null");
this.function = requireNonNull(function, "function is null");
}
@@ -48,7 +48,7 @@ public final class Comment
{
super(location);
this.type = requireNonNull(type, "type is null");
this.name = requireNonNull(name, "table is null");
this.name = requireNonNull(name, "name is null");
this.comment = requireNonNull(comment, "comment is null");
}
@@ -41,7 +41,7 @@ public class ComparisonExpression
private ComparisonExpression(Optional<NodeLocation> location, Operator operator, Expression left, Expression right)
{
super(location);
requireNonNull(operator, "type is null");
requireNonNull(operator, "operator is null");
requireNonNull(left, "left is null");
requireNonNull(right, "right is null");
@@ -44,7 +44,7 @@ public class CreateTable
private CreateTable(Optional<NodeLocation> location, QualifiedName name, List<TableElement> elements, boolean notExists, List<Property> properties, Optional<String> comment)
{
super(location);
this.name = requireNonNull(name, "table is null");
this.name = requireNonNull(name, "name is null");
this.elements = ImmutableList.copyOf(requireNonNull(elements, "elements is null"));
this.notExists = notExists;
this.properties = requireNonNull(properties, "properties is null");
@@ -0,0 +1,70 @@
/*
* 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;
public class CurrentCatalog
extends Expression
{
public CurrentCatalog(NodeLocation location)
{
this(Optional.of(location));
}
private CurrentCatalog(Optional<NodeLocation> location)
{
super(location);
}
@Override
public List<Node> getChildren()
{
return ImmutableList.of();
}
@Override
public <R, C> R accept(AstVisitor<R, C> visitor, C context)
{
return visitor.visitCurrentCatalog(this, context);
}
@Override
public int hashCode()
{
return Objects.hash();
}
@Override
public boolean equals(Object obj)
{
if (this == obj) {
return true;
}
if ((obj == null) || (getClass() != obj.getClass())) {
return false;
}
return true;
}
@Override
public boolean shallowEquals(Node other)
{
return sameClass(this, other);
}
}
@@ -0,0 +1,70 @@
/*
* 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;
public class CurrentSchema
extends Expression
{
public CurrentSchema(NodeLocation location)
{
this(Optional.of(location));
}
private CurrentSchema(Optional<NodeLocation> location)
{
super(location);
}
@Override
public List<Node> getChildren()
{
return ImmutableList.of();
}
@Override
public <R, C> R accept(AstVisitor<R, C> visitor, C context)
{
return visitor.visitCurrentSchema(this, context);
}
@Override
public int hashCode()
{
return Objects.hash();
}
@Override
public boolean equals(Object obj)
{
if (this == obj) {
return true;
}
if ((obj == null) || (getClass() != obj.getClass())) {
return false;
}
return true;
}
@Override
public boolean shallowEquals(Node other)
{
return sameClass(this, other);
}
}
@@ -71,7 +71,7 @@ public class CurrentTime
private CurrentTime(Optional<NodeLocation> location, Function function, Integer precision)
{
super(location);
requireNonNull(function, "type is null");
requireNonNull(function, "function is null");
this.function = function;
this.precision = precision;
}
@@ -801,4 +801,66 @@ public abstract class DefaultTraversalVisitor<C>
return null;
}
@Override
protected Void visitExcludedPattern(ExcludedPattern node, C context)
{
process(node.getPattern(), context);
return null;
}
@Override
protected Void visitPatternAlternation(PatternAlternation node, C context)
{
for (RowPattern rowPattern : node.getPatterns()) {
process(rowPattern, context);
}
return null;
}
@Override
protected Void visitPatternConcatenation(PatternConcatenation node, C context)
{
for (RowPattern rowPattern : node.getPatterns()) {
process(rowPattern, context);
}
return null;
}
@Override
protected Void visitPatternPermutation(PatternPermutation node, C context)
{
for (RowPattern rowPattern : node.getPatterns()) {
process(rowPattern, context);
}
return null;
}
@Override
protected Void visitPatternVariable(PatternVariable node, C context)
{
process(node.getName(), context);
return null;
}
@Override
protected Void visitQuantifiedPattern(QuantifiedPattern node, C context)
{
process(node.getPattern(), context);
return null;
}
@Override
protected Void visitLabelDereference(LabelDereference node, C context)
{
process(node.getReference(), context);
return null;
}
}
@@ -0,0 +1,78 @@
/*
* 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.Optional;
import static com.google.common.base.MoreObjects.toStringHelper;
public class EmptyPattern
extends RowPattern
{
public EmptyPattern(NodeLocation location)
{
this(Optional.of(location));
}
private EmptyPattern(Optional<NodeLocation> location)
{
super(location);
}
@Override
public <R, C> R accept(AstVisitor<R, C> visitor, C context)
{
return visitor.visitEmptyPattern(this, context);
}
@Override
public List<Node> getChildren()
{
return ImmutableList.of();
}
@Override
public boolean equals(Object obj)
{
if (this == obj) {
return true;
}
if ((obj == null) || (getClass() != obj.getClass())) {
return false;
}
return true;
}
@Override
public int hashCode()
{
return getClass().hashCode();
}
@Override
public String toString()
{
return toStringHelper(this)
.toString();
}
@Override
public boolean shallowEquals(Node other)
{
return sameClass(this, other);
}
}
@@ -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 ExcludedPattern
extends RowPattern
{
private final RowPattern pattern;
public ExcludedPattern(NodeLocation location, RowPattern pattern)
{
this(Optional.of(location), pattern);
}
private ExcludedPattern(Optional<NodeLocation> location, RowPattern pattern)
{
super(location);
this.pattern = requireNonNull(pattern, "pattern is null");
}
public RowPattern getPattern()
{
return pattern;
}
@Override
public <R, C> R accept(AstVisitor<R, C> visitor, C context)
{
return visitor.visitExcludedPattern(this, context);
}
@Override
public List<Node> getChildren()
{
return ImmutableList.of(pattern);
}
@Override
public boolean equals(Object obj)
{
if (this == obj) {
return true;
}
if ((obj == null) || (getClass() != obj.getClass())) {
return false;
}
ExcludedPattern o = (ExcludedPattern) obj;
return Objects.equals(pattern, o.pattern);
}
@Override
public int hashCode()
{
return Objects.hash(pattern);
}
@Override
public String toString()
{
return toStringHelper(this)
.add("pattern", pattern)
.toString();
}
@Override
public boolean shallowEquals(Node other)
{
return sameClass(this, other);
}
}
@@ -42,7 +42,7 @@ public class Execute
{
super(location);
this.name = requireNonNull(name, "name is null");
this.parameters = requireNonNull(ImmutableList.copyOf(parameters), "parameters is null");
this.parameters = ImmutableList.copyOf(requireNonNull(parameters, "parameters is null"));
}
public Identifier getName()
@@ -185,6 +185,16 @@ public class ExpressionRewriter<C>
return rewriteExpression(node, context, treeRewriter);
}
public Expression rewriteCurrentCatalog(CurrentCatalog node, C context, ExpressionTreeRewriter<C> treeRewriter)
{
return rewriteExpression(node, context, treeRewriter);
}
public Expression rewriteCurrentSchema(CurrentSchema node, C context, ExpressionTreeRewriter<C> treeRewriter)
{
return rewriteExpression(node, context, treeRewriter);
}
public Expression rewriteCurrentUser(CurrentUser node, C context, ExpressionTreeRewriter<C> treeRewriter)
{
return rewriteExpression(node, context, treeRewriter);
@@ -244,4 +254,9 @@ public class ExpressionRewriter<C>
{
return rewriteExpression(node, context, treeRewriter);
}
public Expression rewriteLabelDereference(LabelDereference node, C context, ExpressionTreeRewriter<C> treeRewriter)
{
return rewriteExpression(node, context, treeRewriter);
}
}
@@ -25,7 +25,7 @@ import static com.google.common.collect.ImmutableList.toImmutableList;
public final class ExpressionTreeRewriter<C>
{
private final ExpressionRewriter<C> rewriter;
private final AstVisitor<Expression, ExpressionTreeRewriter.Context<C>> visitor;
private final AstVisitor<Expression, Context<C>> visitor;
public static <T extends Expression> T rewriteWith(ExpressionRewriter<Void> rewriter, T node)
{
@@ -68,7 +68,7 @@ public final class ExpressionTreeRewriter<C>
}
private class RewritingVisitor
extends AstVisitor<Expression, ExpressionTreeRewriter.Context<C>>
extends AstVisitor<Expression, Context<C>>
{
@Override
protected Expression visitExpression(Expression node, Context<C> context)
@@ -547,7 +547,16 @@ public final class ExpressionTreeRewriter<C>
if (!sameElements(node.getArguments(), arguments) || !sameElements(rewrittenWindow, node.getWindow())
|| !sameElements(filter, node.getFilter())) {
return new FunctionCall(node.getLocation(), node.getName(), rewrittenWindow, filter, node.getOrderBy().map(orderBy -> rewriteOrderBy(orderBy, context)), node.isDistinct(), node.getNullTreatment(), arguments);
return new FunctionCall(
node.getLocation(),
node.getName(),
rewrittenWindow,
filter,
node.getOrderBy().map(orderBy -> rewriteOrderBy(orderBy, context)),
node.isDistinct(),
node.getNullTreatment(),
node.getProcessingMode(),
arguments);
}
return node;
}
@@ -989,6 +998,32 @@ public final class ExpressionTreeRewriter<C>
return node;
}
@Override
protected Expression visitCurrentCatalog(CurrentCatalog node, Context<C> context)
{
if (!context.isDefaultRewrite()) {
Expression result = rewriter.rewriteCurrentCatalog(node, context.get(), ExpressionTreeRewriter.this);
if (result != null) {
return result;
}
}
return node;
}
@Override
protected Expression visitCurrentSchema(CurrentSchema node, Context<C> context)
{
if (!context.isDefaultRewrite()) {
Expression result = rewriter.rewriteCurrentSchema(node, context.get(), ExpressionTreeRewriter.this);
if (result != null) {
return result;
}
}
return node;
}
@Override
protected Expression visitCurrentUser(CurrentUser node, Context<C> context)
{
@@ -1032,6 +1067,24 @@ public final class ExpressionTreeRewriter<C>
return node;
}
@Override
protected Expression visitLabelDereference(LabelDereference node, Context<C> context)
{
if (!context.isDefaultRewrite()) {
Expression result = rewriter.rewriteLabelDereference(node, context.get(), ExpressionTreeRewriter.this);
if (result != null) {
return result;
}
}
SymbolReference reference = rewrite(node.getReference(), context.get());
if (node.getReference() != reference) {
return new LabelDereference(node.getLabel(), reference);
}
return node;
}
}
public static class Context<C>
@@ -31,16 +31,17 @@ public class FunctionCall
private final Optional<OrderBy> orderBy;
private final boolean distinct;
private final Optional<NullTreatment> nullTreatment;
private final Optional<ProcessingMode> processingMode;
private final List<Expression> arguments;
public FunctionCall(QualifiedName name, List<Expression> arguments)
{
this(Optional.empty(), name, Optional.empty(), Optional.empty(), Optional.empty(), false, Optional.empty(), arguments);
this(Optional.empty(), name, Optional.empty(), Optional.empty(), Optional.empty(), false, Optional.empty(), Optional.empty(), arguments);
}
public FunctionCall(NodeLocation location, QualifiedName name, List<Expression> arguments)
{
this(Optional.of(location), name, Optional.empty(), Optional.empty(), Optional.empty(), false, Optional.empty(), arguments);
this(Optional.of(location), name, Optional.empty(), Optional.empty(), Optional.empty(), false, Optional.empty(), Optional.empty(), arguments);
}
public FunctionCall(
@@ -51,6 +52,7 @@ public class FunctionCall
Optional<OrderBy> orderBy,
boolean distinct,
Optional<NullTreatment> nullTreatment,
Optional<ProcessingMode> processingMode,
List<Expression> arguments)
{
super(location);
@@ -60,6 +62,7 @@ public class FunctionCall
requireNonNull(filter, "filter is null");
requireNonNull(orderBy, "orderBy is null");
requireNonNull(nullTreatment, "nullTreatment is null");
requireNonNull(processingMode, "processingMode is null");
requireNonNull(arguments, "arguments is null");
this.name = name;
@@ -68,6 +71,7 @@ public class FunctionCall
this.orderBy = orderBy;
this.distinct = distinct;
this.nullTreatment = nullTreatment;
this.processingMode = processingMode;
this.arguments = arguments;
}
@@ -96,6 +100,11 @@ public class FunctionCall
return nullTreatment;
}
public Optional<ProcessingMode> getProcessingMode()
{
return processingMode;
}
public List<Expression> getArguments()
{
return arguments;
@@ -139,13 +148,14 @@ public class FunctionCall
Objects.equals(orderBy, o.orderBy) &&
Objects.equals(distinct, o.distinct) &&
Objects.equals(nullTreatment, o.nullTreatment) &&
Objects.equals(processingMode, o.processingMode) &&
Objects.equals(arguments, o.arguments);
}
@Override
public int hashCode()
{
return Objects.hash(name, distinct, nullTreatment, window, filter, orderBy, arguments);
return Objects.hash(name, distinct, nullTreatment, processingMode, window, filter, orderBy, arguments);
}
// TODO: make this a proper Tree node so that we can report error
@@ -166,6 +176,7 @@ public class FunctionCall
return name.equals(otherFunction.name) &&
distinct == otherFunction.distinct &&
nullTreatment.equals(otherFunction.nullTreatment);
nullTreatment.equals(otherFunction.nullTreatment) &&
processingMode.equals(otherFunction.processingMode);
}
}
@@ -21,6 +21,7 @@ import java.util.Optional;
import java.util.regex.Pattern;
import static com.google.common.base.Preconditions.checkArgument;
import static java.util.Locale.ENGLISH;
import static java.util.Objects.requireNonNull;
public class Identifier
@@ -66,6 +67,15 @@ public class Identifier
return delimited;
}
public String getCanonicalValue()
{
if (isDelimited()) {
return value;
}
return value.toUpperCase(ENGLISH);
}
@Override
public <R, C> R accept(AstVisitor<R, C> visitor, C context)
{
@@ -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.
* <p>
* 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.
* <p>
* 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, C> R accept(AstVisitor<R, C> visitor, C context)
{
return visitor.visitLabelDereference(this, context);
}
@Override
public List<Node> 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);
}
}
@@ -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<NodeLocation> 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, C> R accept(AstVisitor<R, C> 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);
}
}
@@ -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<NodeLocation> location, boolean greedy)
{
super(location, greedy);
}
@Override
public <R, C> R accept(AstVisitor<R, C> visitor, C context)
{
return visitor.visitOneOrMoreQuantifier(this, context);
}
}
@@ -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<RowPattern> patterns;
public PatternAlternation(NodeLocation location, List<RowPattern> patterns)
{
this(Optional.of(location), patterns);
}
private PatternAlternation(Optional<NodeLocation> location, List<RowPattern> patterns)
{
super(location);
this.patterns = requireNonNull(patterns, "patterns is null");
checkArgument(!patterns.isEmpty(), "patterns list is empty");
}
public List<RowPattern> getPatterns()
{
return patterns;
}
@Override
public <R, C> R accept(AstVisitor<R, C> visitor, C context)
{
return visitor.visitPatternAlternation(this, context);
}
@Override
public List<Node> 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);
}
}
@@ -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<RowPattern> patterns;
public PatternConcatenation(NodeLocation location, List<RowPattern> patterns)
{
this(Optional.of(location), patterns);
}
private PatternConcatenation(Optional<NodeLocation> location, List<RowPattern> patterns)
{
super(location);
this.patterns = requireNonNull(patterns, "patterns is null");
checkArgument(!patterns.isEmpty(), "patterns list is empty");
}
public List<RowPattern> getPatterns()
{
return patterns;
}
@Override
public <R, C> R accept(AstVisitor<R, C> visitor, C context)
{
return visitor.visitPatternConcatenation(this, context);
}
@Override
public List<Node> 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);
}
}
@@ -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<RowPattern> patterns;
public PatternPermutation(NodeLocation location, List<RowPattern> patterns)
{
this(Optional.of(location), patterns);
}
private PatternPermutation(Optional<NodeLocation> location, List<RowPattern> patterns)
{
super(location);
this.patterns = requireNonNull(patterns, "patterns is null");
checkArgument(!patterns.isEmpty(), "patterns list is empty");
}
public List<RowPattern> getPatterns()
{
return patterns;
}
@Override
public <R, C> R accept(AstVisitor<R, C> visitor, C context)
{
return visitor.visitPatternPermutation(this, context);
}
@Override
public List<Node> 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);
}
}
@@ -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<NodeLocation> location, boolean greedy)
{
super(location);
this.greedy = greedy;
}
public boolean isGreedy()
{
return greedy;
}
@Override
public <R, C> R accept(AstVisitor<R, C> visitor, C context)
{
return visitor.visitPatternQuantifier(this, context);
}
@Override
public List<Node> 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();
}
}
@@ -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<Expression> partitionBy;
private final Optional<OrderBy> orderBy;
private final List<MeasureDefinition> measures;
private final Optional<RowsPerMatch> rowsPerMatch;
private final Optional<SkipTo> afterMatchSkipTo;
private final Optional<PatternSearchMode> patternSearchMode;
private final RowPattern pattern;
private final List<SubsetDefinition> subsets;
private final List<VariableDefinition> variableDefinitions;
public PatternRecognitionRelation(
Relation input,
List<Expression> partitionBy,
Optional<OrderBy> orderBy,
List<MeasureDefinition> measures,
Optional<RowsPerMatch> rowsPerMatch,
Optional<SkipTo> afterMatchSkipTo,
Optional<PatternSearchMode> patternSearchMode,
RowPattern pattern,
List<SubsetDefinition> subsets,
List<VariableDefinition> variableDefinitions)
{
this(Optional.empty(), input, partitionBy, orderBy, measures, rowsPerMatch, afterMatchSkipTo, patternSearchMode, pattern, subsets, variableDefinitions);
}
public PatternRecognitionRelation(
NodeLocation location,
Relation input,
List<Expression> partitionBy,
Optional<OrderBy> orderBy,
List<MeasureDefinition> measures,
Optional<RowsPerMatch> rowsPerMatch,
Optional<SkipTo> afterMatchSkipTo,
Optional<PatternSearchMode> patternSearchMode,
RowPattern pattern,
List<SubsetDefinition> subsets,
List<VariableDefinition> variableDefinitions)
{
this(Optional.of(location), input, partitionBy, orderBy, measures, rowsPerMatch, afterMatchSkipTo, patternSearchMode, pattern, subsets, variableDefinitions);
}
private PatternRecognitionRelation(
Optional<NodeLocation> location,
Relation input,
List<Expression> partitionBy,
Optional<OrderBy> orderBy,
List<MeasureDefinition> measures,
Optional<RowsPerMatch> rowsPerMatch,
Optional<SkipTo> afterMatchSkipTo,
Optional<PatternSearchMode> patternSearchMode,
RowPattern pattern,
List<SubsetDefinition> subsets,
List<VariableDefinition> 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<Expression> getPartitionBy()
{
return partitionBy;
}
public Optional<OrderBy> getOrderBy()
{
return orderBy;
}
public List<MeasureDefinition> getMeasures()
{
return measures;
}
public Optional<RowsPerMatch> getRowsPerMatch()
{
return rowsPerMatch;
}
public Optional<SkipTo> getAfterMatchSkipTo()
{
return afterMatchSkipTo;
}
public Optional<PatternSearchMode> getPatternSearchMode()
{
return patternSearchMode;
}
public RowPattern getPattern()
{
return pattern;
}
public List<SubsetDefinition> getSubsets()
{
return subsets;
}
public List<VariableDefinition> getVariableDefinitions()
{
return variableDefinitions;
}
@Override
public <R, C> R accept(AstVisitor<R, C> visitor, C context)
{
return visitor.visitPatternRecognitionRelation(this, context);
}
@Override
public List<Node> getChildren()
{
ImmutableList.Builder<Node> 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();
}
}
@@ -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<NodeLocation> location, Mode mode)
{
super(location);
this.mode = requireNonNull(mode, "mode is null");
}
public Mode getMode()
{
return mode;
}
@Override
public <R, C> R accept(AstVisitor<R, C> visitor, C context)
{
return visitor.visitPatternSearchMode(this, context);
}
@Override
public List<Node> 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
}
}
@@ -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<NodeLocation> location, Identifier name)
{
super(location);
this.name = requireNonNull(name, "name is null");
}
public Identifier getName()
{
return name;
}
@Override
public <R, C> R accept(AstVisitor<R, C> visitor, C context)
{
return visitor.visitPatternVariable(this, context);
}
@Override
public List<Node> 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);
}
}
@@ -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<NodeLocation> location, Mode mode)
{
super(location);
this.mode = requireNonNull(mode, "mode is null");
}
public Mode getMode()
{
return mode;
}
@Override
public <R, C> R accept(AstVisitor<R, C> visitor, C context)
{
return visitor.visitProcessingMode(this, context);
}
@Override
public List<Node> 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
}
}
@@ -49,7 +49,7 @@ public class QuantifiedComparisonExpression
private QuantifiedComparisonExpression(Optional<NodeLocation> 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");
@@ -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<NodeLocation> 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, C> R accept(AstVisitor<R, C> visitor, C context)
{
return visitor.visitQuantifiedPattern(this, context);
}
@Override
public List<Node> 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);
}
}
@@ -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<LongLiteral> atLeast;
private final Optional<LongLiteral> atMost;
public RangeQuantifier(boolean greedy, Optional<LongLiteral> atLeast, Optional<LongLiteral> atMost)
{
this(Optional.empty(), greedy, atLeast, atMost);
}
public RangeQuantifier(NodeLocation location, boolean greedy, Optional<LongLiteral> atLeast, Optional<LongLiteral> atMost)
{
this(Optional.of(location), greedy, atLeast, atMost);
}
private RangeQuantifier(Optional<NodeLocation> location, boolean greedy, Optional<LongLiteral> atLeast, Optional<LongLiteral> atMost)
{
super(location, greedy);
this.atLeast = requireNonNull(atLeast, "atLeast is null");
this.atMost = requireNonNull(atMost, "atMost is null");
}
public Optional<LongLiteral> getAtLeast()
{
return atLeast;
}
public Optional<LongLiteral> getAtMost()
{
return atMost;
}
@Override
public <R, C> R accept(AstVisitor<R, C> visitor, C context)
{
return visitor.visitRangeQuantifier(this, context);
}
@Override
public List<Node> getChildren()
{
ImmutableList.Builder<Node> 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();
}
}
@@ -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<NodeLocation> location)
{
super(location);
}
@Override
public <R, C> R accept(AstVisitor<R, C> visitor, C context)
{
return visitor.visitRowPattern(this, context);
}
}
@@ -40,7 +40,7 @@ public class SetPath
private SetPath(Optional<NodeLocation> location, PathSpecification pathSpecification)
{
super(location);
this.pathSpecification = requireNonNull(pathSpecification, "path is null");
this.pathSpecification = requireNonNull(pathSpecification, "pathSpecification is null");
}
public PathSpecification getPathSpecification()
@@ -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> 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<NodeLocation> 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<NodeLocation> 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<NodeLocation> 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<NodeLocation> location, Identifier identifier)
{
return new SkipTo(location, LAST, Optional.of(identifier));
}
private SkipTo(Optional<NodeLocation> location, Position position, Optional<Identifier> 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<Identifier> getIdentifier()
{
return identifier;
}
@Override
public <R, C> R accept(AstVisitor<R, C> 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;
}
}
@@ -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<Identifier> identifiers;
public SubsetDefinition(Identifier name, List<Identifier> identifiers)
{
this(Optional.empty(), name, identifiers);
}
public SubsetDefinition(NodeLocation location, Identifier name, List<Identifier> identifiers)
{
this(Optional.of(location), name, identifiers);
}
private SubsetDefinition(Optional<NodeLocation> location, Identifier name, List<Identifier> 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<Identifier> getIdentifiers()
{
return identifiers;
}
@Override
public <R, C> R accept(AstVisitor<R, C> 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);
}
}
@@ -25,33 +25,21 @@ public class Table
extends QueryBody
{
private final QualifiedName name;
private final Optional<QualifiedName> 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<NodeLocation> location, QualifiedName name, Optional<QualifiedName> cannerflowName)
private Table(Optional<NodeLocation> 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<QualifiedName> getCannerflowName()
{
return cannerflowName;
}
@Override
public <R, C> R accept(AstVisitor<R, C> visitor, C context)
{
@@ -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()
@@ -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");
}
@@ -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<NodeLocation> 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, C> R accept(AstVisitor<R, C> 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);
}
}
@@ -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<NodeLocation> location, boolean greedy)
{
super(location, greedy);
}
@Override
public <R, C> R accept(AstVisitor<R, C> visitor, C context)
{
return visitor.visitZeroOrMoreQuantifier(this, context);
}
}
@@ -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<NodeLocation> location, boolean greedy)
{
super(location, greedy);
}
@Override
public <R, C> R accept(AstVisitor<R, C> visitor, C context)
{
return visitor.visitZeroOrOneQuantifier(this, context);
}
}
@@ -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;
@@ -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;
@@ -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
* <p>
* 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)
{
@@ -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<ParserAssert> rowPattern(String sql)
{
return createAssertion(new SqlParser()::createRowPattern, sql);
}
private ParserAssert(Node actual, RecursiveComparisonConfiguration recursiveComparisonConfiguration)
{
super(actual, recursiveComparisonConfiguration);
@@ -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<SelectItem> selects, Optional<Expression> 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");
@@ -50,8 +50,8 @@ public class TestSqlParserErrorHandling
{"select * from 'oops",
"line 1:15: mismatched input '''. Expecting: '(', 'LATERAL', 'UNNEST', <identifier>"},
{"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', <EOF>, <identifier>"},
"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', <EOF>, <identifier>"},
{"select *\nfrom x\nwhere from",
"line 3:7: mismatched input 'from'. Expecting: <expression>"},
{"select ",
@@ -121,8 +121,8 @@ public class TestSqlParserErrorHandling
{"SELECT foo(*) filter (",
"line 1:23: mismatched input '<EOF>'. 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', <EOF>"},
"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', <EOF>"},
{"SELECT * FROM t WHERE EXISTS (",
"line 1:31: mismatched input '<EOF>'. Expecting: <query>"},
{"SELECT \"\" FROM t",
@@ -34,6 +34,14 @@ public class TestStatementBuilder
{
private static final SqlParser SQL_PARSER = new SqlParser();
@Test
public void testPreparedGrantWithQuotes()
{
printStatement("prepare p from grant select on table hive.test.\"case\" to role test");
printStatement("prepare p from grant select on hive.test.\"case\" to role test");
printStatement("prepare p from grant select on table hive.test.\"case\" to role \"case\"");
}
@Test
public void testStatementBuilder()
{