diff --git a/e2e_test/ddl/schema.slt b/e2e_test/ddl/schema.slt index 218b4bf08bb0..d998233b3b08 100644 --- a/e2e_test/ddl/schema.slt +++ b/e2e_test/ddl/schema.slt @@ -67,3 +67,35 @@ drop schema Myschema; statement ok drop schema "Myschema"; + +# test derived schema name and authorization with user +statement ok +create user user_for_authorization; + +statement ok +create schema if not exists authorization user_for_authorization; + +statement ok +create schema myschema authorization user_for_authorization; + +query T rowsort +show schemas; +---- +information_schema +myschema +pg_catalog +public +rw_catalog +user_for_authorization + +statement error Permission denied +drop user user_for_authorization; + +statement ok +drop schema myschema; + +statement ok +drop schema user_for_authorization; + +statement ok +drop user user_for_authorization; diff --git a/src/frontend/planner_test/src/lib.rs b/src/frontend/planner_test/src/lib.rs index cb3e253f02ab..99bb73b5fe29 100644 --- a/src/frontend/planner_test/src/lib.rs +++ b/src/frontend/planner_test/src/lib.rs @@ -568,9 +568,15 @@ impl TestCase { Statement::CreateSchema { schema_name, if_not_exists, + user_specified, } => { - create_schema::handle_create_schema(handler_args, schema_name, if_not_exists) - .await?; + create_schema::handle_create_schema( + handler_args, + schema_name, + if_not_exists, + user_specified, + ) + .await?; } _ => return Err(anyhow!("Unsupported statement type")), } diff --git a/src/frontend/src/handler/create_schema.rs b/src/frontend/src/handler/create_schema.rs index 806fbce8af61..46972a2757e3 100644 --- a/src/frontend/src/handler/create_schema.rs +++ b/src/frontend/src/handler/create_schema.rs @@ -29,6 +29,7 @@ pub async fn handle_create_schema( handler_args: HandlerArgs, schema_name: ObjectName, if_not_exist: bool, + user_specified: Option, ) -> Result { let session = handler_args.session; let database_name = session.database(); @@ -62,6 +63,19 @@ pub async fn handle_create_schema( (db.id(), db.owner()) }; + let schema_owner = if let Some(user_specified) = user_specified { + let user_specified = Binder::resolve_user_name(user_specified)?; + session + .env() + .user_info_reader() + .read_guard() + .get_user_by_name(&user_specified) + .map(|u| u.id) + .ok_or_else(|| CatalogError::NotFound("user", user_specified.to_string()))? + } else { + session.user_id() + }; + session.check_privileges(&[ObjectCheckItem::new( db_owner, AclMode::Create, @@ -70,7 +84,7 @@ pub async fn handle_create_schema( let catalog_writer = session.catalog_writer()?; catalog_writer - .create_schema(db_id, &schema_name, session.user_id()) + .create_schema(db_id, &schema_name, schema_owner) .await?; Ok(PgResponse::empty_result(StatementType::CREATE_SCHEMA)) } diff --git a/src/frontend/src/handler/mod.rs b/src/frontend/src/handler/mod.rs index 7405ce7460c9..55f861afcd3a 100644 --- a/src/frontend/src/handler/mod.rs +++ b/src/frontend/src/handler/mod.rs @@ -363,7 +363,16 @@ pub async fn handle( Statement::CreateSchema { schema_name, if_not_exists, - } => create_schema::handle_create_schema(handler_args, schema_name, if_not_exists).await, + user_specified, + } => { + create_schema::handle_create_schema( + handler_args, + schema_name, + if_not_exists, + user_specified, + ) + .await + } Statement::CreateUser(stmt) => create_user::handle_create_user(handler_args, stmt).await, Statement::DeclareCursor { stmt } => { declare_cursor::handle_declare_cursor(handler_args, stmt).await diff --git a/src/sqlparser/src/ast/mod.rs b/src/sqlparser/src/ast/mod.rs index 919d87356a3f..359992ad365f 100644 --- a/src/sqlparser/src/ast/mod.rs +++ b/src/sqlparser/src/ast/mod.rs @@ -1452,6 +1452,7 @@ pub enum Statement { CreateSchema { schema_name: ObjectName, if_not_exists: bool, + user_specified: Option, }, /// CREATE DATABASE CreateDatabase { @@ -1980,12 +1981,19 @@ impl fmt::Display for Statement { Statement::CreateSchema { schema_name, if_not_exists, - } => write!( - f, - "CREATE SCHEMA {if_not_exists}{name}", - if_not_exists = if *if_not_exists { "IF NOT EXISTS " } else { "" }, - name = schema_name - ), + user_specified, + } => { + write!( + f, + "CREATE SCHEMA {if_not_exists}{name}", + if_not_exists = if *if_not_exists { "IF NOT EXISTS " } else { "" }, + name = schema_name + )?; + if let Some(user) = user_specified { + write!(f, " AUTHORIZATION {}", user)?; + } + Ok(()) + }, Statement::Grant { privileges, objects, diff --git a/src/sqlparser/src/parser.rs b/src/sqlparser/src/parser.rs index 84b1e1d97808..7bc2c336597a 100644 --- a/src/sqlparser/src/parser.rs +++ b/src/sqlparser/src/parser.rs @@ -2152,10 +2152,22 @@ impl Parser { pub fn parse_create_schema(&mut self) -> Result { let if_not_exists = self.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]); - let schema_name = self.parse_object_name()?; + let (schema_name, user_specified) = if self.parse_keyword(Keyword::AUTHORIZATION) { + let user_specified = self.parse_object_name()?; + (user_specified.clone(), Some(user_specified)) + } else { + let schema_name = self.parse_object_name()?; + let user_specified = if self.parse_keyword(Keyword::AUTHORIZATION) { + Some(self.parse_object_name()?) + } else { + None + }; + (schema_name, user_specified) + }; Ok(Statement::CreateSchema { schema_name, if_not_exists, + user_specified, }) } diff --git a/src/sqlparser/tests/sqlparser_postgres.rs b/src/sqlparser/tests/sqlparser_postgres.rs index 55e4eefe0e40..dd2020d5d3a9 100644 --- a/src/sqlparser/tests/sqlparser_postgres.rs +++ b/src/sqlparser/tests/sqlparser_postgres.rs @@ -342,6 +342,7 @@ fn parse_create_schema_if_not_exists() { Statement::CreateSchema { if_not_exists: true, schema_name, + .. } => assert_eq!("schema_name", schema_name.to_string()), _ => unreachable!(), }