Skip to content

Commit

Permalink
[Enhancement] (nereids)implement showCreateViewCommand in nereids
Browse files Browse the repository at this point in the history
  • Loading branch information
msridhar78 committed Nov 10, 2024
1 parent 9c66acd commit 4e0bd5e
Show file tree
Hide file tree
Showing 7 changed files with 231 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ supportedShowStatement
| SHOW VIEW
(FROM |IN) tableName=multipartIdentifier
((FROM | IN) database=identifier)? #showView
| SHOW CREATE VIEW name=multipartIdentifier #showCreateView
;

unsupportedOtherStatement
Expand Down Expand Up @@ -245,7 +246,6 @@ unsupportedShowStatement
| SHOW STORAGE? ENGINES #showStorageEngines
| SHOW AUTHORS #showAuthors
| SHOW BRIEF? CREATE TABLE name=multipartIdentifier #showCreateTable
| SHOW CREATE VIEW name=multipartIdentifier #showCreateView
| SHOW CREATE MATERIALIZED VIEW name=multipartIdentifier #showMaterializedView
| SHOW CREATE (DATABASE | SCHEMA) name=multipartIdentifier #showCreateDatabase
| SHOW CREATE CATALOG name=identifier #showCreateCatalog
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@
import org.apache.doris.nereids.DorisParser.ShowConstraintContext;
import org.apache.doris.nereids.DorisParser.ShowCreateMTMVContext;
import org.apache.doris.nereids.DorisParser.ShowCreateProcedureContext;
import org.apache.doris.nereids.DorisParser.ShowCreateViewContext;
import org.apache.doris.nereids.DorisParser.ShowProcedureStatusContext;
import org.apache.doris.nereids.DorisParser.ShowVariablesContext;
import org.apache.doris.nereids.DorisParser.ShowViewContext;
Expand Down Expand Up @@ -426,6 +427,7 @@
import org.apache.doris.nereids.trees.plans.commands.ShowConstraintsCommand;
import org.apache.doris.nereids.trees.plans.commands.ShowCreateMTMVCommand;
import org.apache.doris.nereids.trees.plans.commands.ShowCreateProcedureCommand;
import org.apache.doris.nereids.trees.plans.commands.ShowCreateViewCommand;
import org.apache.doris.nereids.trees.plans.commands.ShowProcedureStatusCommand;
import org.apache.doris.nereids.trees.plans.commands.ShowVariablesCommand;
import org.apache.doris.nereids.trees.plans.commands.ShowViewCommand;
Expand Down Expand Up @@ -4046,4 +4048,9 @@ public ShowViewCommand visitShowView(ShowViewContext ctx) {
}
return new ShowViewCommand(databaseName, new TableNameInfo(tableNameParts));
}

public LogicalPlan visitShowCreateView(ShowCreateViewContext ctx) {
List<String> nameParts = visitMultipartIdentifier(ctx.name);
return new ShowCreateViewCommand(new TableNameInfo(nameParts));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ public enum PlanType {
PREPARED_COMMAND,
EXECUTE_COMMAND,
SHOW_CONFIG_COMMAND,
SHOW_CREATE_VIEW_COMMAND,
SHOW_VARIABLES_COMMAND,
SHOW_VIEW_COMMAND,
REPLAY_COMMAND
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
// 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.doris.nereids.trees.plans.commands;

import org.apache.doris.catalog.Column;
import org.apache.doris.catalog.DatabaseIf;
import org.apache.doris.catalog.Env;
import org.apache.doris.catalog.MTMV;
import org.apache.doris.catalog.ScalarType;
import org.apache.doris.catalog.TableIf;
import org.apache.doris.catalog.View;
import org.apache.doris.common.AnalysisException;
import org.apache.doris.common.ErrorCode;
import org.apache.doris.common.ErrorReport;
import org.apache.doris.mysql.privilege.PrivPredicate;
import org.apache.doris.nereids.trees.plans.PlanType;
import org.apache.doris.nereids.trees.plans.commands.info.TableNameInfo;
import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor;
import org.apache.doris.qe.ConnectContext;
import org.apache.doris.qe.ShowResultSet;
import org.apache.doris.qe.ShowResultSetMetaData;
import org.apache.doris.qe.StmtExecutor;

import com.google.common.collect.Lists;

import java.util.List;

/**
* Represents the command for SHOW CREATE VIEW.
*/
public class ShowCreateViewCommand extends ShowCommand {
private static final ShowResultSetMetaData VIEW_META_DATA =
ShowResultSetMetaData.builder()
.addColumn(new Column("View", ScalarType.createVarchar(20)))
.addColumn(new Column("Create View", ScalarType.createVarchar(30)))
.addColumn(new Column("character_set_client", ScalarType.createVarchar(30)))
.addColumn(new Column("collation_connection", ScalarType.createVarchar(30)))
.build();

private final TableNameInfo tblNameInfo;

public ShowCreateViewCommand(TableNameInfo tableNameInfo) {
super(PlanType.SHOW_CREATE_VIEW_COMMAND);
this.tblNameInfo = tableNameInfo;
}

private void validate(ConnectContext ctx) throws AnalysisException {
tblNameInfo.analyze(ctx);

TableIf tableIf = Env.getCurrentEnv().getCatalogMgr()
.getCatalogOrAnalysisException(tblNameInfo.getCtl())
.getDbOrAnalysisException(tblNameInfo.getDb()).getTableOrAnalysisException(tblNameInfo.getTbl());

if (tableIf instanceof MTMV) {
ErrorReport.reportAnalysisException("not support async materialized view, "
+ "please use `show create materialized view`");
}

PrivPredicate wanted;
if (tableIf instanceof View) {
wanted = PrivPredicate.SHOW_VIEW;
} else {
wanted = PrivPredicate.SHOW;
}

if (!Env.getCurrentEnv().getAccessManager().checkTblPriv(ConnectContext.get(),
tblNameInfo.getCtl(), tblNameInfo.getDb(), tblNameInfo.getTbl(), wanted)) {
ErrorReport.reportAnalysisException(ErrorCode.ERR_TABLEACCESS_DENIED_ERROR, "SHOW CREATE TABLE",
ConnectContext.get().getQualifiedUser(),
ConnectContext.get().getRemoteIP(),
tblNameInfo.getDb() + ": " + tblNameInfo.getTbl());
}
}

@Override
public <R, C> R accept(PlanVisitor<R, C> visitor, C context) {
return visitor.visitShowCreateViewCommand(this, context);
}

@Override
public ShowResultSet doRun(ConnectContext ctx, StmtExecutor executor) throws Exception {
validate(ctx);
// If dbName is not provided, use the default database from the context
String effectiveDbName = (tblNameInfo.getDb() == null || tblNameInfo.getDb().isEmpty())
? ctx.getDatabase() : tblNameInfo.getDb();

// If catalog is not provided, use the default catalog (e.g., internal)
String effectiveCatalog = (tblNameInfo.getCtl() == null || tblNameInfo.getCtl().isEmpty())
? "internal" : tblNameInfo.getCtl();

// Fetch the catalog, database, and view metadata
Env env = Env.getCurrentEnv();
DatabaseIf db = env.getCatalogMgr().getCatalogOrAnalysisException(effectiveCatalog)
.getDbOrMetaException(effectiveDbName);
TableIf view = db.getTableOrMetaException(tblNameInfo.getTbl());

if (!(view instanceof View)) {
ErrorReport.reportAnalysisException(ErrorCode.ERR_WRONG_OBJECT, effectiveDbName, tblNameInfo.getTbl(),
"VIEW", "Use 'SHOW CREATE TABLE '" + tblNameInfo.getTbl());
}

List<List<String>> rows = Lists.newArrayList();
// Lock the view to ensure consistent metadata access
view.readLock();
try {
List<String> createViewStmt = Lists.newArrayList();
env.getDdlStmt(null, null, view, createViewStmt, null, null, false, true, false, -1L, false, false);

if (!createViewStmt.isEmpty()) {
rows.add(Lists.newArrayList(view.getName(), createViewStmt.get(0), "utf8mb4", "utf8mb4_0900_bin"));
}
} finally {
view.readUnlock();
}

// Set the result set and send it using the executor
return new ShowResultSet(VIEW_META_DATA, rows);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
import org.apache.doris.nereids.trees.plans.commands.ShowConstraintsCommand;
import org.apache.doris.nereids.trees.plans.commands.ShowCreateMTMVCommand;
import org.apache.doris.nereids.trees.plans.commands.ShowCreateProcedureCommand;
import org.apache.doris.nereids.trees.plans.commands.ShowCreateViewCommand;
import org.apache.doris.nereids.trees.plans.commands.ShowProcedureStatusCommand;
import org.apache.doris.nereids.trees.plans.commands.ShowVariablesCommand;
import org.apache.doris.nereids.trees.plans.commands.ShowViewCommand;
Expand Down Expand Up @@ -242,4 +243,8 @@ default R visitShowVariablesCommand(ShowVariablesCommand showVariablesCommand, C
default R visitShowViewCommand(ShowViewCommand showViewCommand, C context) {
return visitCommand(showViewCommand, context);
}

default R visitShowCreateViewCommand(ShowCreateViewCommand showCreateViewCommand, C context) {
return visitCommand(showCreateViewCommand, context);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
-- This file is automatically generated. You should know what you did if you want to edit this
-- !cmd --
view_show_create_view CREATE VIEW `view_show_create_view` AS SELECT `internal`.`regression_test_nereids_p0_show`.`table_for_view_test`.`id`, `internal`.`regression_test_nereids_p0_show`.`table_for_view_test`.`name` FROM `internal`.`regression_test_nereids_p0_show`.`table_for_view_test`; utf8mb4 utf8mb4_0900_bin

-- !cmd --
view_show_create_view_2 CREATE VIEW `view_show_create_view_2` AS SELECT `internal`.`regression_test_nereids_p0_show`.`table_for_view_test_2`.`key_field`, `internal`.`regression_test_nereids_p0_show`.`table_for_view_test_2`.`value` FROM `internal`.`regression_test_nereids_p0_show`.`table_for_view_test_2`; utf8mb4 utf8mb4_0900_bin

Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// 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.

suite("test_show_create_view", "query,arrow_flight_sql") {
String view_name = "view_show_create_view";
String table_name = "table_for_view_test";
try {
// Create a table for testing
sql """
CREATE TABLE IF NOT EXISTS ${table_name} (
id INT COMMENT "Primary key",
name STRING COMMENT "Name field"
)
DISTRIBUTED BY HASH(id) BUCKETS 5
PROPERTIES ("replication_num" = "1");
"""

// Create a view based on the created table
sql """
CREATE VIEW IF NOT EXISTS ${view_name} AS
SELECT id, name FROM ${table_name}
"""

// Execute the SHOW CREATE VIEW command
checkNereidsExecute("""show create view `${view_name}`;""")
qt_cmd("""show create view `${view_name}`;""")
} finally {
// Drop the view and table after testing
try_sql("DROP VIEW IF EXISTS `${view_name}`")
try_sql("DROP TABLE IF EXISTS `${table_name}`")
}

// Additional case: Create another view based on a different table
String view_name_2 = "view_show_create_view_2";
String table_name_2 = "table_for_view_test_2";
try {
// Create another table for testing
sql """
CREATE TABLE IF NOT EXISTS ${table_name_2} (
`key_field` INT COMMENT "Key field",
`value` STRING COMMENT "Value field"
)
DISTRIBUTED BY HASH(key_field) BUCKETS 3
PROPERTIES ("replication_num" = "1");
"""

// Create a view based on the new table
sql """
CREATE VIEW IF NOT EXISTS ${view_name_2} AS
SELECT key_field, value FROM ${table_name_2}
"""

// Execute the SHOW CREATE VIEW command for the new view
checkNereidsExecute("""show create view `${view_name_2}`;""")
qt_cmd("""show create view `${view_name_2}`;""")

} finally {
// Drop the view and table after testing
try_sql("DROP VIEW IF EXISTS `${view_name_2}`")
try_sql("DROP TABLE IF EXISTS `${table_name_2}`")
}
}

0 comments on commit 4e0bd5e

Please sign in to comment.