diff --git a/presto-main/src/main/java/com/facebook/presto/sql/rewrite/ShowQueriesRewrite.java b/presto-main/src/main/java/com/facebook/presto/sql/rewrite/ShowQueriesRewrite.java index 4d4f7e909199f..b97d922996bcf 100644 --- a/presto-main/src/main/java/com/facebook/presto/sql/rewrite/ShowQueriesRewrite.java +++ b/presto-main/src/main/java/com/facebook/presto/sql/rewrite/ShowQueriesRewrite.java @@ -376,7 +376,7 @@ protected Node visitShowCatalogs(ShowCatalogs node, Void context) Optional predicate = Optional.empty(); Optional likePattern = node.getLikePattern(); if (likePattern.isPresent()) { - predicate = Optional.of(new LikePredicate(identifier("Catalog"), new StringLiteral(likePattern.get()), Optional.empty())); + predicate = Optional.of(new LikePredicate(identifier("Catalog"), new StringLiteral(likePattern.get()), node.getEscape().map(StringLiteral::new))); } return simpleQuery( diff --git a/presto-parser/src/main/antlr4/com/facebook/presto/sql/parser/SqlBase.g4 b/presto-parser/src/main/antlr4/com/facebook/presto/sql/parser/SqlBase.g4 index 69eeac54ed838..0df96e02722aa 100644 --- a/presto-parser/src/main/antlr4/com/facebook/presto/sql/parser/SqlBase.g4 +++ b/presto-parser/src/main/antlr4/com/facebook/presto/sql/parser/SqlBase.g4 @@ -113,7 +113,8 @@ statement (LIKE pattern=string (ESCAPE escape=string)?)? #showTables | SHOW SCHEMAS ((FROM | IN) identifier)? (LIKE pattern=string (ESCAPE escape=string)?)? #showSchemas - | SHOW CATALOGS (LIKE pattern=string)? #showCatalogs + | SHOW CATALOGS + (LIKE pattern=string (ESCAPE escape=string)?)? #showCatalogs | SHOW COLUMNS (FROM | IN) qualifiedName #showColumns | SHOW STATS FOR qualifiedName #showStats | SHOW STATS FOR '(' querySpecification ')' #showStatsForQuery diff --git a/presto-parser/src/main/java/com/facebook/presto/sql/SqlFormatter.java b/presto-parser/src/main/java/com/facebook/presto/sql/SqlFormatter.java index 649fa1498301e..1e4292d3d8a14 100644 --- a/presto-parser/src/main/java/com/facebook/presto/sql/SqlFormatter.java +++ b/presto-parser/src/main/java/com/facebook/presto/sql/SqlFormatter.java @@ -756,6 +756,10 @@ protected Void visitShowCatalogs(ShowCatalogs node, Integer context) builder.append(" LIKE ") .append(formatStringLiteral(value))); + node.getEscape().ifPresent((value) -> + builder.append(" ESCAPE ") + .append(formatStringLiteral(value))); + return null; } diff --git a/presto-parser/src/main/java/com/facebook/presto/sql/parser/AstBuilder.java b/presto-parser/src/main/java/com/facebook/presto/sql/parser/AstBuilder.java index b038253c45f4a..ff6dc617b2b3b 100644 --- a/presto-parser/src/main/java/com/facebook/presto/sql/parser/AstBuilder.java +++ b/presto-parser/src/main/java/com/facebook/presto/sql/parser/AstBuilder.java @@ -965,6 +965,8 @@ public Node visitShowCatalogs(SqlBaseParser.ShowCatalogsContext context) { return new ShowCatalogs(getLocation(context), getTextIfPresent(context.pattern) + .map(AstBuilder::unquote), + getTextIfPresent(context.escape) .map(AstBuilder::unquote)); } diff --git a/presto-parser/src/main/java/com/facebook/presto/sql/tree/ShowCatalogs.java b/presto-parser/src/main/java/com/facebook/presto/sql/tree/ShowCatalogs.java index b78e8b055fb72..6e3eab9222334 100644 --- a/presto-parser/src/main/java/com/facebook/presto/sql/tree/ShowCatalogs.java +++ b/presto-parser/src/main/java/com/facebook/presto/sql/tree/ShowCatalogs.java @@ -16,6 +16,7 @@ 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; @@ -25,21 +26,23 @@ public final class ShowCatalogs extends Statement { private final Optional likePattern; + private final Optional escape; - public ShowCatalogs(Optional likePattern) + public ShowCatalogs(Optional likePattern, Optional escape) { - this(Optional.empty(), likePattern); + this(Optional.empty(), likePattern, escape); } - public ShowCatalogs(NodeLocation location, Optional likePattern) + public ShowCatalogs(NodeLocation location, Optional likePattern, Optional escape) { - this(Optional.of(location), likePattern); + this(Optional.of(location), likePattern, escape); } - public ShowCatalogs(Optional location, Optional likePattern) + public ShowCatalogs(Optional location, Optional likePattern, Optional escape) { super(location); this.likePattern = requireNonNull(likePattern, "likePattern is null"); + this.escape = requireNonNull(escape, "escape is null"); } public Optional getLikePattern() @@ -47,6 +50,11 @@ public Optional getLikePattern() return likePattern; } + public Optional getEscape() + { + return escape; + } + @Override public R accept(AstVisitor visitor, C context) { @@ -62,7 +70,7 @@ public List getChildren() @Override public int hashCode() { - return 0; + return Objects.hash(likePattern, escape); } @Override @@ -71,12 +79,20 @@ public boolean equals(Object obj) if (this == obj) { return true; } - return (obj != null) && (getClass() == obj.getClass()); + if ((obj == null) || (getClass() != obj.getClass())) { + return false; + } + ShowCatalogs o = (ShowCatalogs) obj; + return Objects.equals(likePattern, o.likePattern) && + Objects.equals(escape, o.escape); } @Override public String toString() { - return toStringHelper(this).toString(); + return toStringHelper(this) + .add("likePattern", likePattern) + .add("escape", escape) + .toString(); } } diff --git a/presto-parser/src/test/java/com/facebook/presto/sql/parser/TestSqlParser.java b/presto-parser/src/test/java/com/facebook/presto/sql/parser/TestSqlParser.java index b9fbef1252e36..7ae5163cfc067 100644 --- a/presto-parser/src/test/java/com/facebook/presto/sql/parser/TestSqlParser.java +++ b/presto-parser/src/test/java/com/facebook/presto/sql/parser/TestSqlParser.java @@ -707,8 +707,9 @@ public void testShowSession() @Test public void testShowCatalogs() { - assertStatement("SHOW CATALOGS", new ShowCatalogs(Optional.empty())); - assertStatement("SHOW CATALOGS LIKE '%'", new ShowCatalogs(Optional.of("%"))); + assertStatement("SHOW CATALOGS", new ShowCatalogs(Optional.empty(), Optional.empty())); + assertStatement("SHOW CATALOGS LIKE '%'", new ShowCatalogs(Optional.of("%"), Optional.empty())); + assertStatement("SHOW CATALOGS LIKE '%$_%' ESCAPE '$'", new ShowCatalogs(Optional.of("%$_%"), Optional.of("$"))); } @Test diff --git a/presto-parser/src/test/java/com/facebook/presto/sql/parser/TestSqlParserErrorHandling.java b/presto-parser/src/test/java/com/facebook/presto/sql/parser/TestSqlParserErrorHandling.java index 70f24dcfc2b50..aa43462393176 100644 --- a/presto-parser/src/test/java/com/facebook/presto/sql/parser/TestSqlParserErrorHandling.java +++ b/presto-parser/src/test/java/com/facebook/presto/sql/parser/TestSqlParserErrorHandling.java @@ -117,7 +117,9 @@ public Object[][] getStatements() {"SELECT * FROM t WHERE EXISTS (", "line 1:31: mismatched input ''. Expecting: "}, {"SHOW SESSION LIKE '%$_%' ESCAPE", - "line 1:32: mismatched input ''. Expecting: "}}; + "line 1:32: mismatched input ''. Expecting: "}, + {"SHOW CATALOGS LIKE '%$_%' ESCAPE", + "line 1:33: mismatched input ''. Expecting: "}}; } @Test(dataProvider = "statements") diff --git a/presto-tests/src/main/java/com/facebook/presto/tests/AbstractTestQueries.java b/presto-tests/src/main/java/com/facebook/presto/tests/AbstractTestQueries.java index 3fc6a16700307..584b2ea6de2fa 100644 --- a/presto-tests/src/main/java/com/facebook/presto/tests/AbstractTestQueries.java +++ b/presto-tests/src/main/java/com/facebook/presto/tests/AbstractTestQueries.java @@ -2565,6 +2565,32 @@ public void testShowCatalogsLike() assertEquals(result.getOnlyColumnAsSet(), ImmutableSet.of(getSession().getCatalog().get())); } + @Test + public void testShowCatalogsLikeWithEscape() + { + try { + MaterializedResult result = computeActual(getSession(), "SHOW CATALOGS LIKE 't$_%' ESCAPE ''"); + assertTrue(false); + } + catch (Exception e) { + assertEquals("Escape string must be a single character", e.getMessage()); + } + + try { + MaterializedResult result = computeActual(getSession(), "SHOW CATALOGS LIKE 't$_%' ESCAPE '$$'"); + assertTrue(false); + } + catch (Exception e) { + assertEquals("Escape string must be a single character", e.getMessage()); + } + + MaterializedResult result = computeActual(getSession(), "SHOW CATALOGS LIKE '%testing$_%' ESCAPE '$'"); + assertEquals("[[testing_catalog]]", result.getMaterializedRows().toString()); + + result = computeActual(getSession(), "SHOW CATALOGS LIKE '$_%' ESCAPE '$'"); + assertEquals("[]", result.getMaterializedRows().toString()); + } + @Test public void testShowSchemas() {