diff --git a/presto-parser/src/main/antlr4/io/prestosql/sql/parser/SqlBase.g4 b/presto-parser/src/main/antlr4/io/prestosql/sql/parser/SqlBase.g4 index c308fe330b23..5e4f5164cc73 100644 --- a/presto-parser/src/main/antlr4/io/prestosql/sql/parser/SqlBase.g4 +++ b/presto-parser/src/main/antlr4/io/prestosql/sql/parser/SqlBase.g4 @@ -56,6 +56,7 @@ statement DROP COLUMN column=qualifiedName #dropColumn | ALTER TABLE tableName=qualifiedName ADD COLUMN column=columnDefinition #addColumn + | ANALYZE qualifiedName (WITH properties)? #analyze | CREATE (OR REPLACE)? VIEW qualifiedName (SECURITY (DEFINER | INVOKER))? AS query #createView | DROP VIEW (IF EXISTS)? qualifiedName #dropView diff --git a/presto-parser/src/main/java/io/prestosql/sql/SqlFormatter.java b/presto-parser/src/main/java/io/prestosql/sql/SqlFormatter.java index 0a26db29dad1..78da4d51b98c 100644 --- a/presto-parser/src/main/java/io/prestosql/sql/SqlFormatter.java +++ b/presto-parser/src/main/java/io/prestosql/sql/SqlFormatter.java @@ -18,6 +18,7 @@ import io.prestosql.sql.tree.AddColumn; import io.prestosql.sql.tree.AliasedRelation; import io.prestosql.sql.tree.AllColumns; +import io.prestosql.sql.tree.Analyze; import io.prestosql.sql.tree.AstVisitor; import io.prestosql.sql.tree.Call; import io.prestosql.sql.tree.CallArgument; @@ -956,6 +957,15 @@ protected Void visitDropColumn(DropColumn node, Integer context) return null; } + @Override + protected Void visitAnalyze(Analyze node, Integer context) + { + builder.append("ANALYZE ") + .append(formatName(node.getTableName())); + builder.append(formatPropertiesMultiLine(node.getProperties())); + return null; + } + @Override protected Void visitAddColumn(AddColumn node, Integer indent) { diff --git a/presto-parser/src/main/java/io/prestosql/sql/parser/AstBuilder.java b/presto-parser/src/main/java/io/prestosql/sql/parser/AstBuilder.java index 2cd52f6e106a..0b0b3e5d57f9 100644 --- a/presto-parser/src/main/java/io/prestosql/sql/parser/AstBuilder.java +++ b/presto-parser/src/main/java/io/prestosql/sql/parser/AstBuilder.java @@ -20,6 +20,7 @@ import io.prestosql.sql.tree.AddColumn; import io.prestosql.sql.tree.AliasedRelation; import io.prestosql.sql.tree.AllColumns; +import io.prestosql.sql.tree.Analyze; import io.prestosql.sql.tree.ArithmeticBinaryExpression; import io.prestosql.sql.tree.ArithmeticUnaryExpression; import io.prestosql.sql.tree.ArrayConstructor; @@ -365,6 +366,19 @@ public Node visitRenameColumn(SqlBaseParser.RenameColumnContext context) (Identifier) visit(context.to)); } + @Override + public Node visitAnalyze(SqlBaseParser.AnalyzeContext context) + { + List properties = ImmutableList.of(); + if (context.properties() != null) { + properties = visit(context.properties().property(), Property.class); + } + return new Analyze( + getLocation(context), + getQualifiedName(context.qualifiedName()), + properties); + } + @Override public Node visitAddColumn(SqlBaseParser.AddColumnContext context) { diff --git a/presto-parser/src/main/java/io/prestosql/sql/tree/Analyze.java b/presto-parser/src/main/java/io/prestosql/sql/tree/Analyze.java new file mode 100644 index 000000000000..cdd07ec945c5 --- /dev/null +++ b/presto-parser/src/main/java/io/prestosql/sql/tree/Analyze.java @@ -0,0 +1,99 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.prestosql.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 Analyze + extends Statement +{ + private final QualifiedName tableName; + private final List properties; + + public Analyze(QualifiedName tableName, List properties) + { + this(Optional.empty(), tableName, properties); + } + + public Analyze(NodeLocation location, QualifiedName tableName, List properties) + { + this(Optional.of(location), tableName, properties); + } + + private Analyze(Optional location, QualifiedName tableName, List properties) + { + super(location); + this.tableName = requireNonNull(tableName, "table is null"); + this.properties = ImmutableList.copyOf(requireNonNull(properties, "properties is null")); + } + + public QualifiedName getTableName() + { + return tableName; + } + + public List getProperties() + { + return properties; + } + + @Override + public R accept(AstVisitor visitor, C context) + { + return visitor.visitAnalyze(this, context); + } + + @Override + public List getChildren() + { + return properties; + } + + @Override + public int hashCode() + { + return Objects.hash(tableName, properties); + } + + @Override + public boolean equals(Object obj) + { + if (this == obj) { + return true; + } + + if ((obj == null) || (getClass() != obj.getClass())) { + return false; + } + Analyze o = (Analyze) obj; + return Objects.equals(tableName, o.tableName) && + Objects.equals(properties, o.properties); + } + + @Override + public String toString() + { + return toStringHelper(this) + .add("tableName", tableName) + .add("properties", properties) + .toString(); + } +} diff --git a/presto-parser/src/main/java/io/prestosql/sql/tree/AstVisitor.java b/presto-parser/src/main/java/io/prestosql/sql/tree/AstVisitor.java index 0f1f2c7d7803..2ad27c336c95 100644 --- a/presto-parser/src/main/java/io/prestosql/sql/tree/AstVisitor.java +++ b/presto-parser/src/main/java/io/prestosql/sql/tree/AstVisitor.java @@ -567,6 +567,11 @@ protected R visitAddColumn(AddColumn node, C context) return visitStatement(node, context); } + protected R visitAnalyze(Analyze node, C context) + { + return visitStatement(node, context); + } + protected R visitCreateView(CreateView node, C context) { return visitStatement(node, context); diff --git a/presto-parser/src/main/java/io/prestosql/sql/tree/DefaultTraversalVisitor.java b/presto-parser/src/main/java/io/prestosql/sql/tree/DefaultTraversalVisitor.java index f281104c2b39..0466095d10bb 100644 --- a/presto-parser/src/main/java/io/prestosql/sql/tree/DefaultTraversalVisitor.java +++ b/presto-parser/src/main/java/io/prestosql/sql/tree/DefaultTraversalVisitor.java @@ -544,6 +544,15 @@ protected R visitProperty(Property node, C context) return null; } + @Override + protected R visitAnalyze(Analyze node, C context) + { + for (Property property : node.getProperties()) { + process(property, context); + } + return null; + } + @Override protected R visitCreateView(CreateView node, C context) { diff --git a/presto-parser/src/test/java/io/prestosql/sql/parser/TestSqlParser.java b/presto-parser/src/test/java/io/prestosql/sql/parser/TestSqlParser.java index 4d01036a7061..97ad63f663c2 100644 --- a/presto-parser/src/test/java/io/prestosql/sql/parser/TestSqlParser.java +++ b/presto-parser/src/test/java/io/prestosql/sql/parser/TestSqlParser.java @@ -19,6 +19,7 @@ import io.prestosql.sql.tree.AddColumn; import io.prestosql.sql.tree.AliasedRelation; import io.prestosql.sql.tree.AllColumns; +import io.prestosql.sql.tree.Analyze; import io.prestosql.sql.tree.ArithmeticBinaryExpression; import io.prestosql.sql.tree.ArrayConstructor; import io.prestosql.sql.tree.AtTimeZone; @@ -1338,6 +1339,25 @@ public void testRenameColumn() assertStatement("ALTER TABLE foo.t RENAME COLUMN a TO b", new RenameColumn(QualifiedName.of("foo", "t"), identifier("a"), identifier("b"))); } + @Test + public void testAnalyze() + { + QualifiedName table = QualifiedName.of("foo"); + assertStatement("ANALYZE foo", new Analyze(table, ImmutableList.of())); + + assertStatement("ANALYZE foo WITH ( \"string\" = 'bar', \"long\" = 42, computed = concat('ban', 'ana'), a = ARRAY[ 'v1', 'v2' ] )", + new Analyze(table, ImmutableList.of( + new Property(new Identifier("string"), new StringLiteral("bar")), + new Property(new Identifier("long"), new LongLiteral("42")), + new Property( + new Identifier("computed"), + new FunctionCall(QualifiedName.of("concat"), ImmutableList.of(new StringLiteral("ban"), new StringLiteral("ana")))), + new Property(new Identifier("a"), new ArrayConstructor(ImmutableList.of(new StringLiteral("v1"), new StringLiteral("v2"))))))); + + assertStatement("EXPLAIN ANALYZE foo", new Explain(new Analyze(table, ImmutableList.of()), false, false, ImmutableList.of())); + assertStatement("EXPLAIN ANALYZE ANALYZE foo", new Explain(new Analyze(table, ImmutableList.of()), true, false, ImmutableList.of())); + } + @Test public void testAddColumn() { diff --git a/presto-parser/src/test/java/io/prestosql/sql/parser/TestSqlParserErrorHandling.java b/presto-parser/src/test/java/io/prestosql/sql/parser/TestSqlParserErrorHandling.java index e097530cbf33..238b2e4bfb5a 100644 --- a/presto-parser/src/test/java/io/prestosql/sql/parser/TestSqlParserErrorHandling.java +++ b/presto-parser/src/test/java/io/prestosql/sql/parser/TestSqlParserErrorHandling.java @@ -39,10 +39,10 @@ public Object[][] getStatements() { return new Object[][] { {"", - "line 1:1: mismatched input ''. Expecting: 'ALTER', 'CALL', 'COMMIT', 'CREATE', 'DEALLOCATE', 'DELETE', 'DESC', 'DESCRIBE', 'DROP', 'EXECUTE', 'EXPLAIN', 'GRANT', " + + "line 1:1: mismatched input ''. Expecting: 'ALTER', 'ANALYZE', 'CALL', 'COMMIT', 'CREATE', 'DEALLOCATE', 'DELETE', 'DESC', 'DESCRIBE', 'DROP', 'EXECUTE', 'EXPLAIN', 'GRANT', " + "'INSERT', 'PREPARE', 'RESET', 'REVOKE', 'ROLLBACK', 'SET', 'SHOW', 'START', 'USE', "}, {"@select", - "line 1:1: mismatched input '@'. Expecting: 'ALTER', 'CALL', 'COMMIT', 'CREATE', 'DEALLOCATE', 'DELETE', 'DESC', 'DESCRIBE', 'DROP', 'EXECUTE', 'EXPLAIN', 'GRANT', " + + "line 1:1: mismatched input '@'. Expecting: 'ALTER', 'ANALYZE', 'CALL', 'COMMIT', 'CREATE', 'DEALLOCATE', 'DELETE', 'DESC', 'DESCRIBE', 'DROP', 'EXECUTE', 'EXPLAIN', 'GRANT', " + "'INSERT', 'PREPARE', 'RESET', 'REVOKE', 'ROLLBACK', 'SET', 'SHOW', 'START', 'USE', "}, {"select * from foo where @what", "line 1:25: mismatched input '@'. Expecting: "},