aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/commands/schemacmds.c3
-rw-r--r--src/backend/parser/parse_utilcmd.c38
-rw-r--r--src/include/parser/parse_utilcmd.h3
-rw-r--r--src/test/regress/expected/create_schema.out98
-rw-r--r--src/test/regress/parallel_schedule2
-rw-r--r--src/test/regress/sql/create_schema.sql70
6 files changed, 192 insertions, 22 deletions
diff --git a/src/backend/commands/schemacmds.c b/src/backend/commands/schemacmds.c
index 66306d1fd18..ffa42f134fe 100644
--- a/src/backend/commands/schemacmds.c
+++ b/src/backend/commands/schemacmds.c
@@ -178,7 +178,8 @@ CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString,
* we cannot, in general, run parse analysis on one statement until we
* have actually executed the prior ones.
*/
- parsetree_list = transformCreateSchemaStmt(stmt);
+ parsetree_list = transformCreateSchemaStmtElements(stmt->schemaElts,
+ schemaName);
/*
* Execute each command contained in the CREATE SCHEMA. Since the grammar
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index cf73066fcfb..14926a7f2b1 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -95,12 +95,10 @@ typedef struct
bool ofType; /* true if statement contains OF typename */
} CreateStmtContext;
-/* State shared by transformCreateSchemaStmt and its subroutines */
+/* State shared by transformCreateSchemaStmtElements and its subroutines */
typedef struct
{
- const char *stmtType; /* "CREATE SCHEMA" or "ALTER SCHEMA" */
- char *schemaname; /* name of schema */
- RoleSpec *authrole; /* owner of schema */
+ const char *schemaname; /* name of schema */
List *sequences; /* CREATE SEQUENCE items */
List *tables; /* CREATE TABLE items */
List *views; /* CREATE VIEW items */
@@ -134,7 +132,7 @@ static void transformCheckConstraints(CreateStmtContext *cxt,
static void transformConstraintAttrs(CreateStmtContext *cxt,
List *constraintList);
static void transformColumnType(CreateStmtContext *cxt, ColumnDef *column);
-static void setSchemaName(char *context_schema, char **stmt_schema_name);
+static void setSchemaName(const char *context_schema, char **stmt_schema_name);
static void transformPartitionCmd(CreateStmtContext *cxt, PartitionCmd *cmd);
static List *transformPartitionRangeBounds(ParseState *pstate, List *blist,
Relation parent);
@@ -3803,14 +3801,18 @@ transformColumnType(CreateStmtContext *cxt, ColumnDef *column)
/*
- * transformCreateSchemaStmt -
- * analyzes the CREATE SCHEMA statement
+ * transformCreateSchemaStmtElements -
+ * analyzes the elements of a CREATE SCHEMA statement
*
- * Split the schema element list into individual commands and place
- * them in the result list in an order such that there are no forward
- * references (e.g. GRANT to a table created later in the list). Note
- * that the logic we use for determining forward references is
- * presently quite incomplete.
+ * Split the schema element list from a CREATE SCHEMA statement into
+ * individual commands and place them in the result list in an order
+ * such that there are no forward references (e.g. GRANT to a table
+ * created later in the list). Note that the logic we use for determining
+ * forward references is presently quite incomplete.
+ *
+ * "schemaName" is the name of the schema that will be used for the creation
+ * of the objects listed, that may be compiled from the schema name defined
+ * in the statement or a role specification.
*
* SQL also allows constraints to make forward references, so thumb through
* the table columns and move forward references to a posterior alter-table
@@ -3826,15 +3828,13 @@ transformColumnType(CreateStmtContext *cxt, ColumnDef *column)
* extent.
*/
List *
-transformCreateSchemaStmt(CreateSchemaStmt *stmt)
+transformCreateSchemaStmtElements(List *schemaElts, const char *schemaName)
{
CreateSchemaStmtContext cxt;
List *result;
ListCell *elements;
- cxt.stmtType = "CREATE SCHEMA";
- cxt.schemaname = stmt->schemaname;
- cxt.authrole = (RoleSpec *) stmt->authrole;
+ cxt.schemaname = schemaName;
cxt.sequences = NIL;
cxt.tables = NIL;
cxt.views = NIL;
@@ -3846,7 +3846,7 @@ transformCreateSchemaStmt(CreateSchemaStmt *stmt)
* Run through each schema element in the schema element list. Separate
* statements by type, and do preliminary analysis.
*/
- foreach(elements, stmt->schemaElts)
+ foreach(elements, schemaElts)
{
Node *element = lfirst(elements);
@@ -3931,10 +3931,10 @@ transformCreateSchemaStmt(CreateSchemaStmt *stmt)
* Set or check schema name in an element of a CREATE SCHEMA command
*/
static void
-setSchemaName(char *context_schema, char **stmt_schema_name)
+setSchemaName(const char *context_schema, char **stmt_schema_name)
{
if (*stmt_schema_name == NULL)
- *stmt_schema_name = context_schema;
+ *stmt_schema_name = unconstify(char *, context_schema);
else if (strcmp(context_schema, *stmt_schema_name) != 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_SCHEMA_DEFINITION),
diff --git a/src/include/parser/parse_utilcmd.h b/src/include/parser/parse_utilcmd.h
index 1056bf081b1..4ebd9276c83 100644
--- a/src/include/parser/parse_utilcmd.h
+++ b/src/include/parser/parse_utilcmd.h
@@ -30,7 +30,8 @@ extern CreateStatsStmt *transformStatsStmt(Oid relid, CreateStatsStmt *stmt,
const char *queryString);
extern void transformRuleStmt(RuleStmt *stmt, const char *queryString,
List **actions, Node **whereClause);
-extern List *transformCreateSchemaStmt(CreateSchemaStmt *stmt);
+extern List *transformCreateSchemaStmtElements(List *schemaElts,
+ const char *schemaName);
extern PartitionBoundSpec *transformPartitionBound(ParseState *pstate, Relation parent,
PartitionBoundSpec *spec);
extern List *expandTableLikeClause(RangeVar *heapRel,
diff --git a/src/test/regress/expected/create_schema.out b/src/test/regress/expected/create_schema.out
new file mode 100644
index 00000000000..93302a07efc
--- /dev/null
+++ b/src/test/regress/expected/create_schema.out
@@ -0,0 +1,98 @@
+--
+-- CREATE_SCHEMA
+--
+-- Schema creation with elements.
+CREATE ROLE regress_create_schema_role SUPERUSER;
+-- Cases where schema creation fails as objects are qualified with a schema
+-- that does not match with what's expected.
+-- This checks all the object types that include schema qualifications.
+CREATE SCHEMA AUTHORIZATION regress_create_schema_role
+ CREATE SEQUENCE schema_not_existing.seq;
+ERROR: CREATE specifies a schema (schema_not_existing) different from the one being created (regress_create_schema_role)
+CREATE SCHEMA AUTHORIZATION regress_create_schema_role
+ CREATE TABLE schema_not_existing.tab (id int);
+ERROR: CREATE specifies a schema (schema_not_existing) different from the one being created (regress_create_schema_role)
+CREATE SCHEMA AUTHORIZATION regress_create_schema_role
+ CREATE VIEW schema_not_existing.view AS SELECT 1;
+ERROR: CREATE specifies a schema (schema_not_existing) different from the one being created (regress_create_schema_role)
+CREATE SCHEMA AUTHORIZATION regress_create_schema_role
+ CREATE INDEX ON schema_not_existing.tab (id);
+ERROR: CREATE specifies a schema (schema_not_existing) different from the one being created (regress_create_schema_role)
+CREATE SCHEMA AUTHORIZATION regress_create_schema_role
+ CREATE TRIGGER schema_trig BEFORE INSERT ON schema_not_existing.tab
+ EXECUTE FUNCTION schema_trig.no_func();
+ERROR: CREATE specifies a schema (schema_not_existing) different from the one being created (regress_create_schema_role)
+-- Again, with a role specification and no schema names.
+SET ROLE regress_create_schema_role;
+CREATE SCHEMA AUTHORIZATION CURRENT_ROLE
+ CREATE SEQUENCE schema_not_existing.seq;
+ERROR: CREATE specifies a schema (schema_not_existing) different from the one being created (regress_create_schema_role)
+CREATE SCHEMA AUTHORIZATION CURRENT_ROLE
+ CREATE TABLE schema_not_existing.tab (id int);
+ERROR: CREATE specifies a schema (schema_not_existing) different from the one being created (regress_create_schema_role)
+CREATE SCHEMA AUTHORIZATION CURRENT_ROLE
+ CREATE VIEW schema_not_existing.view AS SELECT 1;
+ERROR: CREATE specifies a schema (schema_not_existing) different from the one being created (regress_create_schema_role)
+CREATE SCHEMA AUTHORIZATION CURRENT_ROLE
+ CREATE INDEX ON schema_not_existing.tab (id);
+ERROR: CREATE specifies a schema (schema_not_existing) different from the one being created (regress_create_schema_role)
+CREATE SCHEMA AUTHORIZATION CURRENT_ROLE
+ CREATE TRIGGER schema_trig BEFORE INSERT ON schema_not_existing.tab
+ EXECUTE FUNCTION schema_trig.no_func();
+ERROR: CREATE specifies a schema (schema_not_existing) different from the one being created (regress_create_schema_role)
+-- Again, with a schema name and a role specification.
+CREATE SCHEMA regress_schema_1 AUTHORIZATION CURRENT_ROLE
+ CREATE SEQUENCE schema_not_existing.seq;
+ERROR: CREATE specifies a schema (schema_not_existing) different from the one being created (regress_schema_1)
+CREATE SCHEMA regress_schema_1 AUTHORIZATION CURRENT_ROLE
+ CREATE TABLE schema_not_existing.tab (id int);
+ERROR: CREATE specifies a schema (schema_not_existing) different from the one being created (regress_schema_1)
+CREATE SCHEMA regress_schema_1 AUTHORIZATION CURRENT_ROLE
+ CREATE VIEW schema_not_existing.view AS SELECT 1;
+ERROR: CREATE specifies a schema (schema_not_existing) different from the one being created (regress_schema_1)
+CREATE SCHEMA regress_schema_1 AUTHORIZATION CURRENT_ROLE
+ CREATE INDEX ON schema_not_existing.tab (id);
+ERROR: CREATE specifies a schema (schema_not_existing) different from the one being created (regress_schema_1)
+CREATE SCHEMA regress_schema_1 AUTHORIZATION CURRENT_ROLE
+ CREATE TRIGGER schema_trig BEFORE INSERT ON schema_not_existing.tab
+ EXECUTE FUNCTION schema_trig.no_func();
+ERROR: CREATE specifies a schema (schema_not_existing) different from the one being created (regress_schema_1)
+RESET ROLE;
+-- Cases where the schema creation succeeds.
+-- The schema created matches the role name.
+CREATE SCHEMA AUTHORIZATION regress_create_schema_role
+ CREATE TABLE regress_create_schema_role.tab (id int);
+\d regress_create_schema_role.tab
+ Table "regress_create_schema_role.tab"
+ Column | Type | Collation | Nullable | Default
+--------+---------+-----------+----------+---------
+ id | integer | | |
+
+DROP SCHEMA regress_create_schema_role CASCADE;
+NOTICE: drop cascades to table regress_create_schema_role.tab
+-- Again, with a different role specification and no schema names.
+SET ROLE regress_create_schema_role;
+CREATE SCHEMA AUTHORIZATION CURRENT_ROLE
+ CREATE TABLE regress_create_schema_role.tab (id int);
+\d regress_create_schema_role.tab
+ Table "regress_create_schema_role.tab"
+ Column | Type | Collation | Nullable | Default
+--------+---------+-----------+----------+---------
+ id | integer | | |
+
+DROP SCHEMA regress_create_schema_role CASCADE;
+NOTICE: drop cascades to table tab
+-- Again, with a schema name and a role specification.
+CREATE SCHEMA regress_schema_1 AUTHORIZATION CURRENT_ROLE
+ CREATE TABLE regress_schema_1.tab (id int);
+\d regress_schema_1.tab
+ Table "regress_schema_1.tab"
+ Column | Type | Collation | Nullable | Default
+--------+---------+-----------+----------+---------
+ id | integer | | |
+
+DROP SCHEMA regress_schema_1 CASCADE;
+NOTICE: drop cascades to table regress_schema_1.tab
+RESET ROLE;
+-- Clean up
+DROP ROLE regress_create_schema_role;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 017e962fed2..d7f7e1638b8 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -51,7 +51,7 @@ test: copy copyselect copydml insert insert_conflict
# ----------
# More groups of parallel tests
# ----------
-test: create_misc create_operator create_procedure
+test: create_misc create_operator create_procedure create_schema
# These depend on create_misc and create_operator
test: create_index create_index_spgist create_view index_including index_including_gist
diff --git a/src/test/regress/sql/create_schema.sql b/src/test/regress/sql/create_schema.sql
new file mode 100644
index 00000000000..1b7064247a1
--- /dev/null
+++ b/src/test/regress/sql/create_schema.sql
@@ -0,0 +1,70 @@
+--
+-- CREATE_SCHEMA
+--
+
+-- Schema creation with elements.
+
+CREATE ROLE regress_create_schema_role SUPERUSER;
+
+-- Cases where schema creation fails as objects are qualified with a schema
+-- that does not match with what's expected.
+-- This checks all the object types that include schema qualifications.
+CREATE SCHEMA AUTHORIZATION regress_create_schema_role
+ CREATE SEQUENCE schema_not_existing.seq;
+CREATE SCHEMA AUTHORIZATION regress_create_schema_role
+ CREATE TABLE schema_not_existing.tab (id int);
+CREATE SCHEMA AUTHORIZATION regress_create_schema_role
+ CREATE VIEW schema_not_existing.view AS SELECT 1;
+CREATE SCHEMA AUTHORIZATION regress_create_schema_role
+ CREATE INDEX ON schema_not_existing.tab (id);
+CREATE SCHEMA AUTHORIZATION regress_create_schema_role
+ CREATE TRIGGER schema_trig BEFORE INSERT ON schema_not_existing.tab
+ EXECUTE FUNCTION schema_trig.no_func();
+-- Again, with a role specification and no schema names.
+SET ROLE regress_create_schema_role;
+CREATE SCHEMA AUTHORIZATION CURRENT_ROLE
+ CREATE SEQUENCE schema_not_existing.seq;
+CREATE SCHEMA AUTHORIZATION CURRENT_ROLE
+ CREATE TABLE schema_not_existing.tab (id int);
+CREATE SCHEMA AUTHORIZATION CURRENT_ROLE
+ CREATE VIEW schema_not_existing.view AS SELECT 1;
+CREATE SCHEMA AUTHORIZATION CURRENT_ROLE
+ CREATE INDEX ON schema_not_existing.tab (id);
+CREATE SCHEMA AUTHORIZATION CURRENT_ROLE
+ CREATE TRIGGER schema_trig BEFORE INSERT ON schema_not_existing.tab
+ EXECUTE FUNCTION schema_trig.no_func();
+-- Again, with a schema name and a role specification.
+CREATE SCHEMA regress_schema_1 AUTHORIZATION CURRENT_ROLE
+ CREATE SEQUENCE schema_not_existing.seq;
+CREATE SCHEMA regress_schema_1 AUTHORIZATION CURRENT_ROLE
+ CREATE TABLE schema_not_existing.tab (id int);
+CREATE SCHEMA regress_schema_1 AUTHORIZATION CURRENT_ROLE
+ CREATE VIEW schema_not_existing.view AS SELECT 1;
+CREATE SCHEMA regress_schema_1 AUTHORIZATION CURRENT_ROLE
+ CREATE INDEX ON schema_not_existing.tab (id);
+CREATE SCHEMA regress_schema_1 AUTHORIZATION CURRENT_ROLE
+ CREATE TRIGGER schema_trig BEFORE INSERT ON schema_not_existing.tab
+ EXECUTE FUNCTION schema_trig.no_func();
+RESET ROLE;
+
+-- Cases where the schema creation succeeds.
+-- The schema created matches the role name.
+CREATE SCHEMA AUTHORIZATION regress_create_schema_role
+ CREATE TABLE regress_create_schema_role.tab (id int);
+\d regress_create_schema_role.tab
+DROP SCHEMA regress_create_schema_role CASCADE;
+-- Again, with a different role specification and no schema names.
+SET ROLE regress_create_schema_role;
+CREATE SCHEMA AUTHORIZATION CURRENT_ROLE
+ CREATE TABLE regress_create_schema_role.tab (id int);
+\d regress_create_schema_role.tab
+DROP SCHEMA regress_create_schema_role CASCADE;
+-- Again, with a schema name and a role specification.
+CREATE SCHEMA regress_schema_1 AUTHORIZATION CURRENT_ROLE
+ CREATE TABLE regress_schema_1.tab (id int);
+\d regress_schema_1.tab
+DROP SCHEMA regress_schema_1 CASCADE;
+RESET ROLE;
+
+-- Clean up
+DROP ROLE regress_create_schema_role;