This is an automated email from the ASF dual-hosted git repository.
richardantal pushed a commit to branch 4.x
in repository https://gitbox.apache.org/repos/asf/phoenix.git
The following commit(s) were added to refs/heads/4.x by this push:
new c14b61d PHOENIX-6518 Implement SHOW CREATE TABLE SQL command
c14b61d is described below
commit c14b61d61ec7eb15d6f9cf5652e242c3e72b13ba
Author: Richard Antal <[email protected]>
AuthorDate: Thu Jul 29 11:03:53 2021 +0200
PHOENIX-6518 Implement SHOW CREATE TABLE SQL command
Change-Id: I2b8f693a94e1b9fee1e54ef09d2a28569de7a669
---
.../apache/phoenix/end2end/ShowCreateTableIT.java | 113 +++++++++++++++++++++
phoenix-core/src/main/antlr3/PhoenixSQL.g | 6 ++
.../org/apache/phoenix/jdbc/PhoenixStatement.java | 23 +++++
.../org/apache/phoenix/parse/ParseNodeFactory.java | 4 +
.../org/apache/phoenix/parse/ShowCreateTable.java | 38 +++++++
.../phoenix/parse/ShowCreateTableStatement.java | 68 +++++++++++++
.../java/org/apache/phoenix/util/QueryUtil.java | 29 ++++++
.../org/apache/phoenix/parse/QueryParserTest.java | 16 +++
8 files changed, 297 insertions(+)
diff --git
a/phoenix-core/src/it/java/org/apache/phoenix/end2end/ShowCreateTableIT.java
b/phoenix-core/src/it/java/org/apache/phoenix/end2end/ShowCreateTableIT.java
new file mode 100644
index 0000000..f4502d0
--- /dev/null
+++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/ShowCreateTableIT.java
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.phoenix.end2end;
+
+import org.apache.phoenix.util.SchemaUtil;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.util.Properties;
+
+import static org.junit.Assert.assertTrue;
+
+public class ShowCreateTableIT extends ParallelStatsDisabledIT {
+ @Test
+ public void testShowCreateTableBasic() throws Exception {
+ Properties props = new Properties();
+ Connection conn = DriverManager.getConnection(getUrl(), props);
+ String tableName = generateUniqueName();
+ String ddl = "CREATE TABLE " + tableName + "(K VARCHAR NOT NULL
PRIMARY KEY, INT INTEGER)";
+ conn.createStatement().execute(ddl);
+
+ ResultSet rs = conn.createStatement().executeQuery("SHOW CREATE TABLE
" + tableName );
+ assertTrue(rs.next());
+ assertTrue("Expected: :" + ddl + "\nResult: " + rs.getString(1),
+ rs.getString(1).contains(ddl));
+ }
+
+ @Ignore
+ @Test
+ public void testShowCreateTableLowerCase() throws Exception {
+ Properties props = new Properties();
+ Connection conn = DriverManager.getConnection(getUrl(), props);
+ String tableName = "lowercasetbl1";
+ String ddl = "CREATE TABLE \"" + tableName + "\"(K VARCHAR NOT NULL
PRIMARY KEY, INT INTEGER)";
+ conn.createStatement().execute(ddl);
+
+ ResultSet rs = conn.createStatement().executeQuery("SHOW CREATE TABLE
\"" + tableName + "\"");
+ assertTrue(rs.next());
+ assertTrue("Expected: :" + ddl + "\nResult: " + rs.getString(1),
+ rs.getString(1).contains(ddl));
+ }
+
+ @Test
+ public void testShowCreateTableUpperCase() throws Exception {
+ Properties props = new Properties();
+ Connection conn = DriverManager.getConnection(getUrl(), props);
+ String tableName = generateUniqueName();
+ String schemaName = generateUniqueName();
+ String tableFullName = SchemaUtil.getQualifiedTableName(schemaName,
tableName);
+ String ddl = "CREATE TABLE " + tableFullName + "(K VARCHAR NOT NULL
PRIMARY KEY, INT INTEGER)";
+ conn.createStatement().execute(ddl);
+
+ ResultSet rs = conn.createStatement().executeQuery("SHOW CREATE TABLE
" + tableFullName);
+ assertTrue(rs.next());
+ assertTrue("Expected: :" + ddl + "\nResult: " + rs.getString(1),
+ rs.getString(1).contains(ddl));
+ }
+
+ @Test
+ public void testShowCreateTableView() throws Exception {
+ Properties props = new Properties();
+ Connection conn = DriverManager.getConnection(getUrl(), props);
+ String tableName = generateUniqueName();
+ String viewName = generateUniqueName();
+
+ String schemaName = generateUniqueName();
+ String tableFullName = SchemaUtil.getQualifiedTableName(schemaName,
tableName);
+ String viewFullName = SchemaUtil.getQualifiedTableName(schemaName,
viewName);
+ String ddl = "CREATE TABLE " + tableFullName + "(K VARCHAR NOT NULL
PRIMARY KEY, INT INTEGER)";
+ conn.createStatement().execute(ddl);
+ String ddlView = "CREATE VIEW " + viewFullName + " AS SELECT * FROM "
+ tableFullName;
+ conn.createStatement().execute(ddlView);
+
+ ResultSet rs = conn.createStatement().executeQuery("SHOW CREATE TABLE
" + viewFullName);
+ assertTrue(rs.next());
+ assertTrue("Expected: :" + ddlView + "\nResult: " + rs.getString(1),
+ rs.getString(1).contains(ddlView));
+ }
+
+ @Test
+ public void testShowCreateTableIndex() throws Exception {
+ Properties props = new Properties();
+ Connection conn = DriverManager.getConnection(getUrl(), props);
+ String tableName = generateUniqueName();
+ String indexname = generateUniqueName();
+ String ddl = "CREATE TABLE " + tableName + "(K VARCHAR NOT NULL
PRIMARY KEY, INT INTEGER)";
+ conn.createStatement().execute(ddl);
+ String createIndex = "CREATE INDEX " + indexname + " ON " + tableName
+ "(K DESC)";
+ conn.createStatement().execute(createIndex);
+ ResultSet rs = conn.createStatement().executeQuery("SHOW CREATE TABLE
" + indexname);
+ assertTrue(rs.next());
+ assertTrue("Expected: " + createIndex + "\nResult: " + rs.getString(1),
+ rs.getString(1).contains(createIndex));
+ }
+}
diff --git a/phoenix-core/src/main/antlr3/PhoenixSQL.g
b/phoenix-core/src/main/antlr3/PhoenixSQL.g
index d79b742..1d66dba 100644
--- a/phoenix-core/src/main/antlr3/PhoenixSQL.g
+++ b/phoenix-core/src/main/antlr3/PhoenixSQL.g
@@ -428,6 +428,7 @@ oneStatement returns [BindableStatement ret]
| s=alter_index_node
| s=alter_table_node
| s=show_node
+ | s=show_create_table_node
| s=trace_node
| s=create_function_node
| s=drop_function_node
@@ -496,6 +497,11 @@ show_node returns [ShowStatement ret]
| SHOW SCHEMAS (LIKE pattern=string_literal)? { $ret =
factory.showSchemasStatement(pattern); }
;
+// Parse a describe statement. SHOW CREATE TABLE tablename/viewname/indexname
...
+show_create_table_node returns [ShowCreateTable ret]
+ : SHOW CREATE TABLE tablename=from_table_name { $ret =
factory.showCreateTable(tablename); }
+ ;
+
// Parse a create view statement.
create_view_node returns [CreateTableStatement ret]
: CREATE VIEW (IF NOT ex=EXISTS)? t=from_table_name
diff --git
a/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixStatement.java
b/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixStatement.java
index 2a76887..c116508 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixStatement.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixStatement.java
@@ -140,6 +140,8 @@ import org.apache.phoenix.parse.DMLStatement;
import org.apache.phoenix.parse.DeclareCursorStatement;
import org.apache.phoenix.parse.DeleteJarStatement;
import org.apache.phoenix.parse.DeleteStatement;
+import org.apache.phoenix.parse.ShowCreateTableStatement;
+import org.apache.phoenix.parse.ShowCreateTable;
import org.apache.phoenix.parse.DropColumnStatement;
import org.apache.phoenix.parse.DropFunctionStatement;
import org.apache.phoenix.parse.DropIndexStatement;
@@ -1311,6 +1313,22 @@ public class PhoenixStatement implements Statement,
SQLCloseable {
}
}
+ private static class ExecutableShowCreateTable extends
ShowCreateTableStatement
+ implements CompilableStatement {
+
+ public ExecutableShowCreateTable(TableName tableName) {
+ super(tableName);
+ }
+
+ @Override
+ public QueryPlan compilePlan(final PhoenixStatement stmt,
Sequence.ValueOp seqAction)
+ throws SQLException {
+ PreparedStatement delegateStmt =
QueryUtil.getShowCreateTableStmt(stmt.getConnection(), null,
+ getTableName());
+ return ((PhoenixPreparedStatement) delegateStmt).compileQuery();
+ }
+ }
+
private static class ExecutableCreateIndexStatement extends
CreateIndexStatement implements CompilableStatement {
public ExecutableCreateIndexStatement(NamedNode indexName,
NamedTableNode dataTable, IndexKeyConstraint ikConstraint, List<ColumnName>
includeColumns, List<ParseNode> splits,
@@ -1898,6 +1916,11 @@ public class PhoenixStatement implements Statement,
SQLCloseable {
return new ExecutableShowSchemasStatement(pattern);
}
+ @Override
+ public ShowCreateTable showCreateTable(TableName tableName) {
+ return new ExecutableShowCreateTable(tableName);
+ }
+
}
static class PhoenixStatementParser extends SQLParser {
diff --git
a/phoenix-core/src/main/java/org/apache/phoenix/parse/ParseNodeFactory.java
b/phoenix-core/src/main/java/org/apache/phoenix/parse/ParseNodeFactory.java
index 786b356..8138ea0 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/parse/ParseNodeFactory.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/ParseNodeFactory.java
@@ -952,4 +952,8 @@ public class ParseNodeFactory {
public ShowSchemasStatement showSchemasStatement(String pattern) {
return new ShowSchemasStatement(pattern);
}
+
+ public ShowCreateTable showCreateTable(TableName tableName) {
+ return new ShowCreateTableStatement(tableName);
+ }
}
diff --git
a/phoenix-core/src/main/java/org/apache/phoenix/parse/ShowCreateTable.java
b/phoenix-core/src/main/java/org/apache/phoenix/parse/ShowCreateTable.java
new file mode 100644
index 0000000..4fe77a7
--- /dev/null
+++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/ShowCreateTable.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.phoenix.parse;
+
+import org.apache.phoenix.jdbc.PhoenixStatement;
+
+/**
+ * Parent class for SHOW CREATE TABLE statements.
+ */
+public class ShowCreateTable implements BindableStatement {
+ @Override
+ public int getBindCount() {
+ return 0;
+ }
+
+ @Override
+ public PhoenixStatement.Operation getOperation() {
+ return PhoenixStatement.Operation.QUERY;
+ }
+
+ public ShowCreateTable() {}
+}
diff --git
a/phoenix-core/src/main/java/org/apache/phoenix/parse/ShowCreateTableStatement.java
b/phoenix-core/src/main/java/org/apache/phoenix/parse/ShowCreateTableStatement.java
new file mode 100644
index 0000000..2a9b127
--- /dev/null
+++
b/phoenix-core/src/main/java/org/apache/phoenix/parse/ShowCreateTableStatement.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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 org.apache.phoenix.parse;
+
+import org.apache.phoenix.compile.ColumnResolver;
+import com.google.common.base.Preconditions;
+import org.apache.phoenix.util.SchemaUtil;
+
+import java.util.Objects;
+
+/**
+ * ParseNode implementation for SHOW CREATE TABLE statements.
+ */
+public class ShowCreateTableStatement extends ShowCreateTable {
+
+ private TableName tableName;
+
+ public ShowCreateTableStatement(TableName tn) {
+ tableName = tn;
+ }
+
+ public TableName getTableName() {
+ return tableName;
+ }
+
+ public void toSQL(ColumnResolver resolver, StringBuilder buf) {
+ Preconditions.checkNotNull(buf);
+ buf.append("SHOW CREATE TABLE ");
+
+ buf.append(SchemaUtil
+ .getEscapedTableName(tableName.getSchemaName(),
tableName.getTableName()));
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder buf = new StringBuilder();
+ toSQL(null, buf);
+ return buf.toString();
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (!(other instanceof ShowCreateTableStatement)) return false;
+ ShowCreateTableStatement stmt = (ShowCreateTableStatement) other;
+ return Objects.equals(tableName, stmt.getTableName());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(tableName);
+ }
+}
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/util/QueryUtil.java
b/phoenix-core/src/main/java/org/apache/phoenix/util/QueryUtil.java
index 749b601..4ad09f6 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/util/QueryUtil.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/util/QueryUtil.java
@@ -88,6 +88,7 @@ import org.apache.phoenix.jdbc.PhoenixConnection;
import org.apache.phoenix.jdbc.PhoenixEmbeddedDriver;
import org.apache.phoenix.parse.HintNode;
import org.apache.phoenix.parse.HintNode.Hint;
+import org.apache.phoenix.parse.TableName;
import org.apache.phoenix.parse.WildcardParseNode;
import org.apache.phoenix.query.QueryConstants;
import org.apache.phoenix.query.QueryServices;
@@ -99,6 +100,8 @@ import org.apache.phoenix.schema.PTableType;
import org.apache.phoenix.schema.SortOrder;
import org.apache.phoenix.schema.tuple.Tuple;
import org.apache.phoenix.schema.types.PInteger;
+import org.apache.phoenix.schema.tool.SchemaExtractionProcessor;
+import org.apache.phoenix.schema.tool.SchemaProcessor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -769,6 +772,32 @@ public final class QueryUtil {
return stmt;
}
+ /**
+ * Util that generates a PreparedStatement against syscat to get the table
listing in a given schema.
+ */
+ public static PreparedStatement getShowCreateTableStmt(PhoenixConnection
connection, String catalog, TableName tn) throws SQLException {
+
+ String output;
+ SchemaProcessor processor = new SchemaExtractionProcessor(null,
+
connection.unwrap(PhoenixConnection.class).getQueryServices().getConfiguration(),
+ tn.getSchemaName() == null ? null : "\"" + tn.getSchemaName()+
"\"",
+ "\"" + tn.getTableName() + "\"");
+ try {
+ output = processor.process();
+ } catch (Exception e) {
+ LOGGER.error(e.getStackTrace().toString());
+ throw new SQLException(e.getMessage());
+ }
+
+ StringBuilder buf = new StringBuilder("select \n" +
+ " ? as \"CREATE STATEMENT\"");
+ PreparedStatement stmt = connection.prepareStatement(buf.toString());
+
+ stmt.setString(1, output);
+
+ return stmt;
+ }
+
public static void addTenantIdFilter(PhoenixConnection connection,
StringBuilder buf, String tenantIdPattern,
List<String> parameterValues) {
PName tenantId = connection.getTenantId();
diff --git
a/phoenix-core/src/test/java/org/apache/phoenix/parse/QueryParserTest.java
b/phoenix-core/src/test/java/org/apache/phoenix/parse/QueryParserTest.java
index fbf1cea..0dc86c5 100644
--- a/phoenix-core/src/test/java/org/apache/phoenix/parse/QueryParserTest.java
+++ b/phoenix-core/src/test/java/org/apache/phoenix/parse/QueryParserTest.java
@@ -912,4 +912,20 @@ public class QueryParserTest {
parseQueryThatShouldFail("show tables in 'foo'");
parseQueryThatShouldFail("show tables like foo");
}
+
+ @Test
+ public void testShowCreateTable() throws Exception {
+ // Happy paths
+ parseQuery("SHOW CREATE TABLE FOO");
+ parseQuery("show create table FOO");
+ parseQuery("SHOW CREATE TABLE s.FOO");
+ parseQuery("SHOW CREATE TABLE \"foo\"");
+ parseQuery("SHOW CREATE TABLE s.\"foo\"");
+ parseQuery("SHOW CREATE TABLE \"s\".FOO");
+
+ // Expected failures.
+ parseQueryThatShouldFail("SHOW CREATE VIEW foo");
+ parseQueryThatShouldFail("SHOW CREATE TABLE 'foo'");
+
+ }
}