diff --git a/doc/src/sgml/ref/create_schema.sgml b/doc/src/sgml/ref/create_schema.sgml index ed69298ccc6c..238fd949934c 100644 --- a/doc/src/sgml/ref/create_schema.sgml +++ b/doc/src/sgml/ref/create_schema.sgml @@ -100,10 +100,12 @@ CREATE SCHEMA IF NOT EXISTS AUTHORIZATION role_sp An SQL statement defining an object to be created within the - schema. Currently, only CREATE - TABLE, CREATE VIEW, CREATE + schema. Currently, only CREATE COLLATION, + CREATE DOMAIN, CREATE TABLE, + CREATE VIEW, CREATE INDEX, CREATE SEQUENCE, CREATE - TRIGGER and GRANT are accepted as clauses + TRIGGER, CREATE TYPE and + GRANT are accepted as clauses within CREATE SCHEMA. Other kinds of objects may be created in separate commands after the schema is created. @@ -193,12 +195,10 @@ CREATE VIEW hollywood.winners AS - The SQL standard specifies that the subcommands in CREATE - SCHEMA can appear in any order. The present - PostgreSQL implementation does not - handle all cases of forward references in subcommands; it might - sometimes be necessary to reorder the subcommands in order to avoid - forward references. + PostgreSQL executes the subcommands + in CREATE SCHEMA in the order given. Other + implementations may try to rearrange the subcommands into dependency + order, but that is hard if not impossible to do correctly. diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index c75b7131ed70..e3d6a1073836 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -2621,6 +2621,22 @@ read_objtype_from_string(const char *objtype) return -1; /* keep compiler quiet */ } +const char * +stringify_objtype(ObjectType objtype) +{ + int i; + + for (i = 0; i < lengthof(ObjectTypeMap); i++) + { + if (ObjectTypeMap[i].tm_type == objtype) + return ObjectTypeMap[i].tm_name; + } + ereport(ERROR, + errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("unrecognized object type %d", objtype)); + + return NULL; /* keep compiler quiet */ +} /* * Interfaces to reference fields of ObjectPropertyType */ diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c index 93ef1ad106fd..062b1aade492 100644 --- a/src/backend/commands/extension.c +++ b/src/backend/commands/extension.c @@ -1773,14 +1773,17 @@ CreateExtensionInternal(char *extensionName, if (!OidIsValid(schemaOid)) { + ParseState *pstate = make_parsestate(NULL); CreateSchemaStmt *csstmt = makeNode(CreateSchemaStmt); + pstate->p_sourcetext = "(generated CREATE SCHEMA command)"; + csstmt->schemaname = schemaName; csstmt->authrole = NULL; /* will be created by current user */ csstmt->schemaElts = NIL; csstmt->if_not_exists = false; - CreateSchemaCommand(csstmt, "(generated CREATE SCHEMA command)", - -1, -1); + + CreateSchemaCommand(pstate, csstmt, -1, -1); /* * CreateSchemaCommand includes CommandCounterIncrement, so new diff --git a/src/backend/commands/schemacmds.c b/src/backend/commands/schemacmds.c index 3cc1472103a7..09928c58d9db 100644 --- a/src/backend/commands/schemacmds.c +++ b/src/backend/commands/schemacmds.c @@ -49,7 +49,7 @@ static void AlterSchemaOwner_internal(HeapTuple tup, Relation rel, Oid newOwnerI * a subquery. */ Oid -CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString, +CreateSchemaCommand(ParseState *pstate, CreateSchemaStmt *stmt, int stmt_location, int stmt_len) { const char *schemaName = stmt->schemaname; @@ -189,12 +189,13 @@ CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString, /* * Examine the list of commands embedded in the CREATE SCHEMA command, and - * reorganize them into a sequentially executable order with no forward - * references. Note that the result is still a list of raw parsetrees --- - * we cannot, in general, run parse analysis on one statement until we - * have actually executed the prior ones. + * do preliminary transformations (mostly, verify that none are trying to + * create objects outside the new schema). Note that the result is still + * a list of raw parsetrees --- we cannot, in general, run parse analysis + * on one statement until we have actually executed the prior ones. */ - parsetree_list = transformCreateSchemaStmtElements(stmt->schemaElts, + parsetree_list = transformCreateSchemaStmtElements(pstate, + stmt->schemaElts, schemaName); /* @@ -219,7 +220,7 @@ CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString, /* do this step */ ProcessUtility(wrapper, - queryString, + pstate->p_sourcetext, false, PROCESS_UTILITY_SUBCOMMAND, NULL, diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 57bf7a7c7f2c..9281c5342118 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -1627,6 +1627,8 @@ schema_stmt: | CreateTrigStmt | GrantStmt | ViewStmt + | CreateDomainStmt + | DefineStmt ; diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c index e96b38a59d50..ea3ade024518 100644 --- a/src/backend/parser/parse_utilcmd.c +++ b/src/backend/parser/parse_utilcmd.c @@ -61,6 +61,7 @@ #include "rewrite/rewriteManip.h" #include "utils/acl.h" #include "utils/builtins.h" +#include "utils/formatting.h" #include "utils/lsyscache.h" #include "utils/partcache.h" #include "utils/rel.h" @@ -95,18 +96,6 @@ typedef struct bool ofType; /* true if statement contains OF typename */ } CreateStmtContext; -/* State shared by transformCreateSchemaStmtElements and its subroutines */ -typedef struct -{ - const char *schemaname; /* name of schema */ - List *sequences; /* CREATE SEQUENCE items */ - List *tables; /* CREATE TABLE items */ - List *views; /* CREATE VIEW items */ - List *indexes; /* CREATE INDEX items */ - List *triggers; /* CREATE TRIGGER items */ - List *grants; /* GRANT items */ -} CreateSchemaStmtContext; - static void transformColumnDefinition(CreateStmtContext *cxt, ColumnDef *column); @@ -133,7 +122,8 @@ static void transformCheckConstraints(CreateStmtContext *cxt, static void transformConstraintAttrs(CreateStmtContext *cxt, List *constraintList); static void transformColumnType(CreateStmtContext *cxt, ColumnDef *column); -static void setSchemaName(const char *context_schema, char **stmt_schema_name); +static void checkSchemaName(ParseState *pstate, const char *context_schema, + RangeVar *relation); static void transformPartitionCmd(CreateStmtContext *cxt, PartitionCmd *cmd); static List *transformPartitionRangeBounds(ParseState *pstate, List *blist, Relation parent); @@ -4075,51 +4065,35 @@ transformColumnType(CreateStmtContext *cxt, ColumnDef *column) * transformCreateSchemaStmtElements - * analyzes the elements of a CREATE SCHEMA statement * - * 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. + * This is now somewhat vestigial: its only real responsibility is to complain + * if any of the elements are trying to create objects outside the new schema. + * We used to try to re-order the commands in a way that would work even if + * the user-written order would not, but that's too hard (perhaps impossible) + * to do correctly with not-yet-parse-analyzed commands. Now we'll just + * execute the elements in the order given. * * "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 + * of the objects listed. It may be obtained 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 - * command. - * * The result is a list of parse nodes that still need to be analyzed --- * but we can't analyze the later commands until we've executed the earlier * ones, because of possible inter-object references. - * - * Note: this breaks the rules a little bit by modifying schema-name fields - * within passed-in structs. However, the transformation would be the same - * if done over, so it should be all right to scribble on the input to this - * extent. */ List * -transformCreateSchemaStmtElements(List *schemaElts, const char *schemaName) +transformCreateSchemaStmtElements(ParseState *pstate, List *schemaElts, + const char *schemaName) { - CreateSchemaStmtContext cxt; - List *result; - ListCell *elements; - - cxt.schemaname = schemaName; - cxt.sequences = NIL; - cxt.tables = NIL; - cxt.views = NIL; - cxt.indexes = NIL; - cxt.triggers = NIL; - cxt.grants = NIL; + List *elements = NIL; + ListCell *lc; /* - * Run through each schema element in the schema element list. Separate - * statements by type, and do preliminary analysis. + * Run through each schema element in the schema element list. Check + * target schema names, and collect the list of actions to be done. */ - foreach(elements, schemaElts) + foreach(lc, schemaElts) { - Node *element = lfirst(elements); + Node *element = lfirst(lc); switch (nodeTag(element)) { @@ -4127,8 +4101,8 @@ transformCreateSchemaStmtElements(List *schemaElts, const char *schemaName) { CreateSeqStmt *elp = (CreateSeqStmt *) element; - setSchemaName(cxt.schemaname, &elp->sequence->schemaname); - cxt.sequences = lappend(cxt.sequences, element); + checkSchemaName(pstate, schemaName, elp->sequence); + elements = lappend(elements, element); } break; @@ -4136,12 +4110,8 @@ transformCreateSchemaStmtElements(List *schemaElts, const char *schemaName) { CreateStmt *elp = (CreateStmt *) element; - setSchemaName(cxt.schemaname, &elp->relation->schemaname); - - /* - * XXX todo: deal with constraints - */ - cxt.tables = lappend(cxt.tables, element); + checkSchemaName(pstate, schemaName, elp->relation); + elements = lappend(elements, element); } break; @@ -4149,12 +4119,8 @@ transformCreateSchemaStmtElements(List *schemaElts, const char *schemaName) { ViewStmt *elp = (ViewStmt *) element; - setSchemaName(cxt.schemaname, &elp->view->schemaname); - - /* - * XXX todo: deal with references between views - */ - cxt.views = lappend(cxt.views, element); + checkSchemaName(pstate, schemaName, elp->view); + elements = lappend(elements, element); } break; @@ -4162,8 +4128,8 @@ transformCreateSchemaStmtElements(List *schemaElts, const char *schemaName) { IndexStmt *elp = (IndexStmt *) element; - setSchemaName(cxt.schemaname, &elp->relation->schemaname); - cxt.indexes = lappend(cxt.indexes, element); + checkSchemaName(pstate, schemaName, elp->relation); + elements = lappend(elements, element); } break; @@ -4171,47 +4137,147 @@ transformCreateSchemaStmtElements(List *schemaElts, const char *schemaName) { CreateTrigStmt *elp = (CreateTrigStmt *) element; - setSchemaName(cxt.schemaname, &elp->relation->schemaname); - cxt.triggers = lappend(cxt.triggers, element); + checkSchemaName(pstate, schemaName, elp->relation); + elements = lappend(elements, element); } break; case T_GrantStmt: - cxt.grants = lappend(cxt.grants, element); + elements = lappend(elements, element); + break; + + case T_CreateDomainStmt: + { + char *domain_schema = NULL; + CreateDomainStmt *elp = (CreateDomainStmt *) element; + + /* + * The schema of the DOMAIN must match the schema being created. + * If the domain name length exceeds 3, it will fail in + * DeconstructQualifiedName. + */ + if (list_length(elp->domainname) == 2) + domain_schema = strVal(list_nth(elp->domainname, 0)); + else if (list_length(elp->domainname) == 3) + domain_schema = strVal(list_nth(elp->domainname, 1)); + + if (domain_schema != NULL && strcmp(domain_schema, schemaName) != 0) + ereport(ERROR, + errcode(ERRCODE_INVALID_SCHEMA_DEFINITION), + errmsg("CREATE specifies a schema (%s) " + "different from the one being created (%s)", + schemaName, domain_schema)); + elements = lappend(elements, element); + } break; + case T_DefineStmt: + { + char *coll_schema = NULL; + char *collName; + DefineStmt *stmt = (DefineStmt *) element; + + if (stmt->kind != OBJECT_COLLATION && stmt->kind != OBJECT_TYPE) + ereport(ERROR, + errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("CREATE SCHEMA ... CREATE %s currently not supported", + asc_toupper(stringify_objtype(stmt->kind), + strlen(stringify_objtype(stmt->kind))))); + + DeconstructQualifiedName(stmt->defnames, &coll_schema, &collName); + if (coll_schema && strcmp(coll_schema, schemaName) != 0) + ereport(ERROR, + errcode(ERRCODE_INVALID_SCHEMA_DEFINITION), + errmsg("CREATE specifies a schema (%s) " + "different from the one being created (%s)", + schemaName, coll_schema)); + + elements = lappend(elements, element); + } + break; + + case T_CompositeTypeStmt: + { + CompositeTypeStmt *stmt = (CompositeTypeStmt *) element; + + checkSchemaName(pstate, schemaName, stmt->typevar); + elements = lappend(elements, element); + } + break; + + case T_CreateEnumStmt: + { + char *schema = NULL; + char *typname; + CreateEnumStmt *stmt = (CreateEnumStmt *) element; + DeconstructQualifiedName(stmt->typeName, &schema, &typname); + if (schema && strcmp(schema, schemaName) != 0) + ereport(ERROR, + errcode(ERRCODE_INVALID_SCHEMA_DEFINITION), + errmsg("CREATE specifies a schema (%s) " + "different from the one being created (%s)", + schemaName, schema)); + + elements = lappend(elements, element); + } + break; + + case T_CreateRangeStmt: + { + char *schema = NULL; + char *typname; + CreateRangeStmt *stmt = (CreateRangeStmt *) element; + DeconstructQualifiedName(stmt->typeName, &schema, &typname); + if (schema && strcmp(schema, schemaName) != 0) + ereport(ERROR, + errcode(ERRCODE_INVALID_SCHEMA_DEFINITION), + errmsg("CREATE specifies a schema (%s) " + "different from the one being created (%s)", + schemaName, schema)); + + elements = lappend(elements, element); + } + break; default: elog(ERROR, "unrecognized node type: %d", (int) nodeTag(element)); } } - result = NIL; - result = list_concat(result, cxt.sequences); - result = list_concat(result, cxt.tables); - result = list_concat(result, cxt.views); - result = list_concat(result, cxt.indexes); - result = list_concat(result, cxt.triggers); - result = list_concat(result, cxt.grants); - - return result; + return elements; } /* - * setSchemaName - * Set or check schema name in an element of a CREATE SCHEMA command + * checkSchemaName + * Check schema name in an element of a CREATE SCHEMA command + * + * It's okay if the command doesn't specify a target schema name, because + * CreateSchemaCommand will set up the default creation schema to be the + * new schema. But if a target schema name is given, it had better match. + * We also have to check that the command doesn't say CREATE TEMP, since + * that would likewise put the object into the wrong schema. */ static void -setSchemaName(const char *context_schema, char **stmt_schema_name) +checkSchemaName(ParseState *pstate, const char *context_schema, + RangeVar *relation) { - if (*stmt_schema_name == NULL) - *stmt_schema_name = unconstify(char *, context_schema); - else if (strcmp(context_schema, *stmt_schema_name) != 0) + if (relation->schemaname != NULL && + strcmp(context_schema, relation->schemaname) != 0) ereport(ERROR, - (errcode(ERRCODE_INVALID_SCHEMA_DEFINITION), - errmsg("CREATE specifies a schema (%s) " + errcode(ERRCODE_INVALID_SCHEMA_DEFINITION), + errmsg("CREATE specifies a schema (%s) " "different from the one being created (%s)", - *stmt_schema_name, context_schema))); + relation->schemaname, context_schema), + parser_errposition(pstate, relation->location)); + + if (relation->relpersistence == RELPERSISTENCE_TEMP) + { + /* spell this error the same as in RangeVarAdjustRelationPersistence */ + ereport(ERROR, + errcode(ERRCODE_INVALID_TABLE_DEFINITION), + errmsg("cannot create temporary relation in non-temporary schema"), + parser_errposition(pstate, relation->location)); + } } /* diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index 918db53dd5e7..4f7cc80a8f09 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -1111,8 +1111,7 @@ ProcessUtilitySlow(ParseState *pstate, * relation and attribute manipulation */ case T_CreateSchemaStmt: - CreateSchemaCommand((CreateSchemaStmt *) parsetree, - queryString, + CreateSchemaCommand(pstate, (CreateSchemaStmt *) parsetree, pstmt->stmt_location, pstmt->stmt_len); diff --git a/src/bin/psql/tab-complete.in.c b/src/bin/psql/tab-complete.in.c index 6176741d20b1..7bff08a2f750 100644 --- a/src/bin/psql/tab-complete.in.c +++ b/src/bin/psql/tab-complete.in.c @@ -2188,7 +2188,7 @@ match_previous_words(int pattern_id, { /* only some object types can be created as part of CREATE SCHEMA */ if (HeadMatches("CREATE", "SCHEMA")) - COMPLETE_WITH("TABLE", "VIEW", "INDEX", "SEQUENCE", "TRIGGER", + COMPLETE_WITH("TABLE", "VIEW", "INDEX", "SEQUENCE", "TRIGGER", "DOMAIN", "COLLATION", /* for INDEX and TABLE/SEQUENCE, respectively */ "UNIQUE", "UNLOGGED"); else @@ -3373,10 +3373,10 @@ match_previous_words(int pattern_id, else if (Matches("CREATE", "ACCESS", "METHOD", MatchAny, "TYPE", MatchAny)) COMPLETE_WITH("HANDLER"); - /* CREATE COLLATION */ - else if (Matches("CREATE", "COLLATION", MatchAny)) + /* CREATE COLLATION --- is allowed inside CREATE SCHEMA, so use TailMatches */ + else if (TailMatches("CREATE", "COLLATION", MatchAny)) COMPLETE_WITH("(", "FROM"); - else if (Matches("CREATE", "COLLATION", MatchAny, "FROM")) + else if (TailMatches("CREATE", "COLLATION", MatchAny, "FROM")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_collations); else if (HeadMatches("CREATE", "COLLATION", MatchAny, "(*")) { @@ -3402,15 +3402,15 @@ match_previous_words(int pattern_id, else if (Matches("CREATE", "DATABASE", MatchAny, "STRATEGY")) COMPLETE_WITH("WAL_LOG", "FILE_COPY"); - /* CREATE DOMAIN */ - else if (Matches("CREATE", "DOMAIN", MatchAny)) + /* CREATE DOMAIN --- is allowed inside CREATE SCHEMA, so use TailMatches */ + else if (TailMatches("CREATE", "DOMAIN", MatchAny)) COMPLETE_WITH("AS"); - else if (Matches("CREATE", "DOMAIN", MatchAny, "AS")) + else if (TailMatches("CREATE", "DOMAIN", MatchAny, "AS")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_datatypes); - else if (Matches("CREATE", "DOMAIN", MatchAny, "AS", MatchAny)) + else if (TailMatches("CREATE", "DOMAIN", MatchAny, "AS", MatchAny)) COMPLETE_WITH("COLLATE", "DEFAULT", "CONSTRAINT", "NOT NULL", "NULL", "CHECK ("); - else if (Matches("CREATE", "DOMAIN", MatchAny, "COLLATE")) + else if (TailMatches("CREATE", "DOMAIN", MatchAny, "COLLATE")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_collations); /* CREATE EXTENSION */ diff --git a/src/include/catalog/objectaddress.h b/src/include/catalog/objectaddress.h index 630434b73cf1..96e6abc9ffdd 100644 --- a/src/include/catalog/objectaddress.h +++ b/src/include/catalog/objectaddress.h @@ -79,6 +79,7 @@ extern char *getObjectDescription(const ObjectAddress *object, extern char *getObjectDescriptionOids(Oid classid, Oid objid); extern int read_objtype_from_string(const char *objtype); +extern const char *stringify_objtype(ObjectType objtype); extern char *getObjectTypeDescription(const ObjectAddress *object, bool missing_ok); extern char *getObjectIdentity(const ObjectAddress *object, diff --git a/src/include/commands/schemacmds.h b/src/include/commands/schemacmds.h index 8557176b66aa..835265bb67c3 100644 --- a/src/include/commands/schemacmds.h +++ b/src/include/commands/schemacmds.h @@ -16,12 +16,9 @@ #define SCHEMACMDS_H #include "catalog/objectaddress.h" -#include "nodes/parsenodes.h" - -extern Oid CreateSchemaCommand(CreateSchemaStmt *stmt, - const char *queryString, - int stmt_location, int stmt_len); +#include "parser/parse_node.h" +extern Oid CreateSchemaCommand(ParseState *pstate, CreateSchemaStmt *stmt, int stmt_location, int stmt_len); extern ObjectAddress RenameSchema(const char *oldname, const char *newname); extern ObjectAddress AlterSchemaOwner(const char *name, Oid newOwnerId); extern void AlterSchemaOwner_oid(Oid schemaoid, Oid newOwnerId); diff --git a/src/include/parser/parse_utilcmd.h b/src/include/parser/parse_utilcmd.h index 4965fac4495e..d151bba03eb5 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 *transformCreateSchemaStmtElements(List *schemaElts, +extern List *transformCreateSchemaStmtElements(ParseState *pstate, + List *schemaElts, const char *schemaName); extern PartitionBoundSpec *transformPartitionBound(ParseState *pstate, Relation parent, PartitionBoundSpec *spec); diff --git a/src/test/modules/test_ddl_deparse/expected/create_schema.out b/src/test/modules/test_ddl_deparse/expected/create_schema.out index 8ab4eb033852..b2c85682b204 100644 --- a/src/test/modules/test_ddl_deparse/expected/create_schema.out +++ b/src/test/modules/test_ddl_deparse/expected/create_schema.out @@ -13,7 +13,19 @@ CREATE SCHEMA IF NOT EXISTS baz; NOTICE: schema "baz" already exists, skipping CREATE SCHEMA element_test CREATE TABLE foo (id int) - CREATE VIEW bar AS SELECT * FROM foo; + CREATE VIEW bar AS SELECT * FROM foo + CREATE DOMAIN d1 AS INT + CREATE COLLATION coll (LOCALE="C") + CREATE TYPE floatrange AS RANGE (subtype = float8, subtype_diff = float8mi) + CREATE TYPE ss AS (a int) + CREATE TYPE sss + CREATE TYPE rainbow AS ENUM ('red', 'orange'); NOTICE: DDL test: type simple, tag CREATE SCHEMA NOTICE: DDL test: type simple, tag CREATE TABLE NOTICE: DDL test: type simple, tag CREATE VIEW +NOTICE: DDL test: type simple, tag CREATE DOMAIN +NOTICE: DDL test: type simple, tag CREATE COLLATION +NOTICE: DDL test: type simple, tag CREATE TYPE +NOTICE: DDL test: type simple, tag CREATE TYPE +NOTICE: DDL test: type simple, tag CREATE TYPE +NOTICE: DDL test: type simple, tag CREATE TYPE diff --git a/src/test/modules/test_ddl_deparse/sql/create_schema.sql b/src/test/modules/test_ddl_deparse/sql/create_schema.sql index f314dc2b840b..5ce79b524bd0 100644 --- a/src/test/modules/test_ddl_deparse/sql/create_schema.sql +++ b/src/test/modules/test_ddl_deparse/sql/create_schema.sql @@ -14,4 +14,10 @@ CREATE SCHEMA IF NOT EXISTS baz; CREATE SCHEMA element_test CREATE TABLE foo (id int) - CREATE VIEW bar AS SELECT * FROM foo; + CREATE VIEW bar AS SELECT * FROM foo + CREATE DOMAIN d1 AS INT + CREATE COLLATION coll (LOCALE="C") + CREATE TYPE floatrange AS RANGE (subtype = float8, subtype_diff = float8mi) + CREATE TYPE ss AS (a int) + CREATE TYPE sss + CREATE TYPE rainbow AS ENUM ('red', 'orange'); diff --git a/src/test/regress/expected/collate.icu.utf8.out b/src/test/regress/expected/collate.icu.utf8.out index 69805d4b9ec5..4c3033854476 100644 --- a/src/test/regress/expected/collate.icu.utf8.out +++ b/src/test/regress/expected/collate.icu.utf8.out @@ -2690,6 +2690,28 @@ SELECT * FROM t5 ORDER BY c ASC, a ASC; 3 | d1 | d1 (3 rows) +--CREATE SCHEMA CREATE COLLATION +--fail. Execute subcommands in order; we do not implicitly reorder them. +CREATE SCHEMA regress_schema_4 AUTHORIZATION CURRENT_ROLE + CREATE TABLE tts(a TEXT COLLATE coll_icu_und) + CREATE COLLATION coll_icu_und FROM "und-x-icu"; +ERROR: collation "coll_icu_und" for encoding "UTF8" does not exist +LINE 2: CREATE TABLE tts(a TEXT COLLATE coll_icu_und) + ^ +CREATE SCHEMA regress_schema_4 + CREATE COLLATION coll_icu_und FROM "und-x-icu" + CREATE TABLE tts(a TEXT COLLATE coll_icu_und); +\dO regress_schema_4.* + List of collations + Schema | Name | Provider | Collate | Ctype | Locale | ICU Rules | Deterministic? +------------------+--------------+----------+---------+-------+--------+-----------+---------------- + regress_schema_4 | coll_icu_und | icu | | | und | | yes +(1 row) + +DROP SCHEMA regress_schema_4 CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to collation regress_schema_4.coll_icu_und +drop cascades to table regress_schema_4.tts -- cleanup RESET search_path; SET client_min_messages TO warning; diff --git a/src/test/regress/expected/create_schema.out b/src/test/regress/expected/create_schema.out index 93302a07efc3..6409aee73619 100644 --- a/src/test/regress/expected/create_schema.out +++ b/src/test/regress/expected/create_schema.out @@ -9,55 +9,92 @@ CREATE ROLE regress_create_schema_role SUPERUSER; 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) +LINE 2: CREATE SEQUENCE schema_not_existing.seq; + ^ 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) +LINE 2: CREATE TABLE schema_not_existing.tab (id int); + ^ 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) +LINE 2: CREATE VIEW schema_not_existing.view AS SELECT 1; + ^ 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) +LINE 2: 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(); ERROR: CREATE specifies a schema (schema_not_existing) different from the one being created (regress_create_schema_role) +LINE 2: CREATE TRIGGER schema_trig BEFORE INSERT ON schema_not_exi... + ^ -- 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) +LINE 2: CREATE SEQUENCE schema_not_existing.seq; + ^ 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) +LINE 2: CREATE TABLE schema_not_existing.tab (id int); + ^ 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) +LINE 2: CREATE VIEW schema_not_existing.view AS SELECT 1; + ^ 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) +LINE 2: 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(); ERROR: CREATE specifies a schema (schema_not_existing) different from the one being created (regress_create_schema_role) +LINE 2: CREATE TRIGGER schema_trig BEFORE INSERT ON schema_not_exi... + ^ -- 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) +LINE 2: CREATE SEQUENCE schema_not_existing.seq; + ^ 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) +LINE 2: 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; ERROR: CREATE specifies a schema (schema_not_existing) different from the one being created (regress_schema_1) +LINE 2: 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); ERROR: CREATE specifies a schema (schema_not_existing) different from the one being created (regress_schema_1) +LINE 2: 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(); ERROR: CREATE specifies a schema (schema_not_existing) different from the one being created (regress_schema_1) +LINE 2: CREATE TRIGGER schema_trig BEFORE INSERT ON schema_not_exi... + ^ RESET ROLE; +--error. Forward reference is not allowed. +CREATE SCHEMA regress_schema_2 + CREATE VIEW abcd_view AS SELECT a FROM abcd + CREATE TABLE abcd (a int); +ERROR: relation "abcd" does not exist +LINE 2: CREATE VIEW abcd_view AS SELECT a FROM abcd + ^ -- Cases where the schema creation succeeds. -- The schema created matches the role name. CREATE SCHEMA AUTHORIZATION regress_create_schema_role @@ -94,5 +131,187 @@ CREATE SCHEMA regress_schema_1 AUTHORIZATION CURRENT_ROLE DROP SCHEMA regress_schema_1 CASCADE; NOTICE: drop cascades to table regress_schema_1.tab RESET ROLE; +-- Cases where the schema creation with domain. +--fail. cannot CREATE DOMAIN to other schema +CREATE SCHEMA regress_schema_2 AUTHORIZATION CURRENT_ROLE + CREATE DOMAIN public.ss AS TEXT NOT NULL DEFAULT 'hello' CONSTRAINT nn CHECK (VALUE <> 'hello') + CREATE TABLE t(a ss); +ERROR: CREATE specifies a schema (regress_schema_2) different from the one being created (public) +--fail. cannot CREATE DOMAIN to other schema +CREATE SCHEMA regress_schema_2 AUTHORIZATION CURRENT_ROLE + CREATE DOMAIN postgres.public.ss AS TEXT NOT NULL CONSTRAINT nn CHECK (VALUE <> 'hello') DEFAULT 'hello' + CREATE TABLE t(a ss); +ERROR: CREATE specifies a schema (regress_schema_2) different from the one being created (public) +--fail. improper qualified name +CREATE SCHEMA regress_schema_2 CREATE DOMAIN ss.postgres.regress_schema_2.ss AS TEXT; +ERROR: improper qualified name (too many dotted names): ss.postgres.regress_schema_2.ss +--fail. Execute subcommands in order; we do not implicitly reorder them. +CREATE SCHEMA regress_schema_2 AUTHORIZATION CURRENT_ROLE + CREATE DOMAIN ss1 AS ss + CREATE DOMAIN ss AS TEXT; +ERROR: type "ss" does not exist +LINE 2: CREATE DOMAIN ss1 AS ss + ^ +--ok, qualified schema name for domain should be same as the created schema. +CREATE SCHEMA regress_schema_2 AUTHORIZATION CURRENT_ROLE + CREATE DOMAIN regress_schema_2.ss AS TEXT NOT NULL CONSTRAINT nn CHECK (VALUE <> 'hello') DEFAULT 'hello' COLLATE "C" + CREATE TABLE t(a regress_schema_2.ss); +\dD regress_schema_2.* + List of domains + Schema | Name | Type | Collation | Nullable | Default | Check +------------------+------+------+-----------+----------+---------------+-------------------------------- + regress_schema_2 | ss | text | C | not null | 'hello'::text | CHECK (VALUE <> 'hello'::text) +(1 row) + +--ok, no qualified schema name for domain. +CREATE SCHEMA regress_schema_3 AUTHORIZATION CURRENT_ROLE + CREATE DOMAIN ss AS TEXT CONSTRAINT nn CHECK (VALUE <> 'hello') NOT NULL DEFAULT 'hello' + CREATE DOMAIN ss1 AS ss + CREATE VIEW test AS SELECT 'hello'::ss AS test + CREATE TABLE t(a ss1); +\dD regress_schema_3.* + List of domains + Schema | Name | Type | Collation | Nullable | Default | Check +------------------+------+---------------------+-----------+----------+---------------+-------------------------------- + regress_schema_3 | ss | text | | not null | 'hello'::text | CHECK (VALUE <> 'hello'::text) + regress_schema_3 | ss1 | regress_schema_3.ss | | | 'hello'::text | +(2 rows) + +-- Cases where the schema creation with collations +--fail. cannot CREATE DOMAIN to other schema +CREATE SCHEMA regress_schema_4 AUTHORIZATION CURRENT_ROLE + CREATE COLLATION public.coll_icu_und FROM "und-x-icu"; +ERROR: CREATE specifies a schema (regress_schema_4) different from the one being created (public) +--fail. improper qualified name +CREATE SCHEMA regress_schema_4 AUTHORIZATION CURRENT_ROLE + CREATE COLLATION postgres.public.coll_icu_und FROM "und-x-icu"; +ERROR: cross-database references are not implemented: postgres.public.coll_icu_und +--fail. only support collation object for DefineStmt node +CREATE SCHEMA regress_schema_4 AUTHORIZATION CURRENT_ROLE + CREATE AGGREGATE balk(int4)(SFUNC = int4_sum(int8, int4),STYPE = int8, PARALLEL = SAFE, INITCOND = '0'); +ERROR: CREATE SCHEMA ... CREATE AGGREGATE currently not supported +--ok, qualified schema name for domain should be same as the created schema +CREATE SCHEMA regress_schema_4 AUTHORIZATION CURRENT_ROLE + CREATE COLLATION regress_schema_4.coll (LOCALE="C") + CREATE TABLE t(a TEXT COLLATE regress_schema_4.coll); +\dO regress_schema_4.* + List of collations + Schema | Name | Provider | Collate | Ctype | Locale | ICU Rules | Deterministic? +------------------+------+----------+---------+-------+--------+-----------+---------------- + regress_schema_4 | coll | libc | C | C | | | yes +(1 row) + +--ok, no qualified schema name for collation +CREATE SCHEMA regress_schema_5 AUTHORIZATION CURRENT_ROLE + CREATE COLLATION coll (LOCALE="C") + CREATE TABLE t(a TEXT COLLATE coll); +\dO regress_schema_5.* + List of collations + Schema | Name | Provider | Collate | Ctype | Locale | ICU Rules | Deterministic? +------------------+------+----------+---------+-------+--------+-----------+---------------- + regress_schema_5 | coll | libc | C | C | | | yes +(1 row) + +-----CREATE SCHEMA CREATE TYPE +--fail. cannot CREATE TYPE to other schema +CREATE SCHEMA regress_schema_6 CREATE TYPE public.ss AS (a int); +ERROR: CREATE specifies a schema (public) different from the one being created (regress_schema_6) +LINE 1: CREATE SCHEMA regress_schema_6 CREATE TYPE public.ss AS (a i... + ^ +CREATE SCHEMA regress_schema_6 CREATE TYPE public.ss; +ERROR: CREATE specifies a schema (regress_schema_6) different from the one being created (public) +CREATE SCHEMA regress_schema_6 CREATE TYPE public.rainbow AS ENUM ('red', 'orange'); +ERROR: CREATE specifies a schema (regress_schema_6) different from the one being created (public) +CREATE SCHEMA regress_schema_6 CREATE TYPE public.floatrange AS RANGE (subtype = float8, subtype_diff = float8mi); +ERROR: CREATE specifies a schema (regress_schema_6) different from the one being created (public) +--fail. improper qualified name +CREATE SCHEMA regress_schema_6 AUTHORIZATION CURRENT_ROLE + CREATE TYPE postgres.public.floatrange AS RANGE (subtype = float8, subtype_diff = float8mi); +ERROR: cross-database references are not implemented: postgres.public.floatrange +--all the following 4 should error, because we execute subcommands in order +CREATE SCHEMA regress_schema_6 CREATE TABLE tts(a ss) CREATE TYPE ss; +ERROR: type "ss" does not exist +LINE 1: CREATE SCHEMA regress_schema_6 CREATE TABLE tts(a ss) CREATE... + ^ +CREATE SCHEMA regress_schema_6 CREATE TABLE tts(a ss) CREATE TYPE ss AS (a int); +ERROR: type "ss" does not exist +LINE 1: CREATE SCHEMA regress_schema_6 CREATE TABLE tts(a ss) CREATE... + ^ +CREATE SCHEMA regress_schema_6 CREATE TABLE tts(a rainbow) CREATE TYPE rainbow AS ENUM ('red', 'orange'); +ERROR: type "rainbow" does not exist +LINE 1: CREATE SCHEMA regress_schema_6 CREATE TABLE tts(a rainbow) C... + ^ +CREATE SCHEMA regress_schema_6 + CREATE TABLE tts(a floatrange) + CREATE TYPE floatrange AS RANGE (subtype = float8, subtype_diff = float8mi); +ERROR: type "floatrange" does not exist +LINE 2: CREATE TABLE tts(a floatrange) + ^ +--ok +CREATE SCHEMA regress_schema_6 + CREATE TYPE floatrange AS RANGE (subtype = float8, subtype_diff = float8mi) + CREATE TYPE ss AS (a int) + CREATE TYPE sss + CREATE TYPE rainbow AS ENUM ('red', 'orange'); +\dT regress_schema_6.* + List of data types + Schema | Name | Description +------------------+----------------------------------+------------- + regress_schema_6 | regress_schema_6.floatmultirange | + regress_schema_6 | regress_schema_6.floatrange | + regress_schema_6 | regress_schema_6.rainbow | + regress_schema_6 | regress_schema_6.ss | + regress_schema_6 | regress_schema_6.sss | +(5 rows) + +--schema qualified, ok +CREATE SCHEMA regress_schema_7 + CREATE TYPE regress_schema_7.floatrange AS RANGE (subtype = float8, subtype_diff = float8mi) + CREATE TYPE regress_schema_7.ss AS (a int) + CREATE TYPE regress_schema_7.sss + CREATE TYPE regress_schema_7.rainbow AS ENUM ('red', 'orange') + CREATE TABLE t(a floatrange, b ss, c rainbow); +\dT regress_schema_7.* + List of data types + Schema | Name | Description +------------------+----------------------------------+------------- + regress_schema_7 | regress_schema_7.floatmultirange | + regress_schema_7 | regress_schema_7.floatrange | + regress_schema_7 | regress_schema_7.rainbow | + regress_schema_7 | regress_schema_7.ss | + regress_schema_7 | regress_schema_7.sss | +(5 rows) + +DROP SCHEMA regress_schema_2 CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to type regress_schema_2.ss +drop cascades to table regress_schema_2.t +DROP SCHEMA regress_schema_3 CASCADE; +NOTICE: drop cascades to 4 other objects +DETAIL: drop cascades to type regress_schema_3.ss +drop cascades to type regress_schema_3.ss1 +drop cascades to view regress_schema_3.test +drop cascades to table regress_schema_3.t +DROP SCHEMA regress_schema_4 CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to collation regress_schema_4.coll +drop cascades to table regress_schema_4.t +DROP SCHEMA regress_schema_5 CASCADE; +NOTICE: drop cascades to 2 other objects +DETAIL: drop cascades to collation regress_schema_5.coll +drop cascades to table regress_schema_5.t +DROP SCHEMA regress_schema_6 CASCADE; +NOTICE: drop cascades to 4 other objects +DETAIL: drop cascades to type regress_schema_6.floatrange +drop cascades to type regress_schema_6.ss +drop cascades to type regress_schema_6.sss +drop cascades to type regress_schema_6.rainbow +DROP SCHEMA regress_schema_7 CASCADE; +NOTICE: drop cascades to 5 other objects +DETAIL: drop cascades to type regress_schema_7.floatrange +drop cascades to type regress_schema_7.ss +drop cascades to type regress_schema_7.sss +drop cascades to type regress_schema_7.rainbow +drop cascades to table regress_schema_7.t -- Clean up DROP ROLE regress_create_schema_role; diff --git a/src/test/regress/expected/create_type.out b/src/test/regress/expected/create_type.out index 5181c4290b4c..28eadcde20d1 100644 --- a/src/test/regress/expected/create_type.out +++ b/src/test/regress/expected/create_type.out @@ -35,6 +35,18 @@ CREATE FUNCTION int44out(city_budget) NOTICE: argument type city_budget is only a shell LINE 1: CREATE FUNCTION int44out(city_budget) ^ +----- CREATE SCHEMA CREATE TYPE test +--error. cannot CREATE TYPE to other schema +CREATE SCHEMA regress_schema_1 + CREATE TYPE public.widget ( + internallength = 24, + input = widget_in, + output = widget_out, + typmod_in = numerictypmodin, + typmod_out = numerictypmodout, + alignment = double + ); +ERROR: CREATE specifies a schema (regress_schema_1) different from the one being created (public) CREATE TYPE widget ( internallength = 24, input = widget_in, diff --git a/src/test/regress/expected/create_view.out b/src/test/regress/expected/create_view.out index 49dd13c345cc..3ad55dca2271 100644 --- a/src/test/regress/expected/create_view.out +++ b/src/test/regress/expected/create_view.out @@ -126,6 +126,8 @@ ERROR: cannot create temporary relation in non-temporary schema CREATE SCHEMA test_view_schema CREATE TEMP VIEW testview AS SELECT 1; ERROR: cannot create temporary relation in non-temporary schema +LINE 2: CREATE TEMP VIEW testview AS SELECT 1; + ^ -- joins: if any of the join relations are temporary, the view -- should also be temporary -- should be non-temp diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regress/expected/event_trigger.out index 16e4530708cc..4a7fd2bc59a8 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -424,12 +424,12 @@ NOTICE: END: command_tag=CREATE TABLE type=table identity=evttrig.one NOTICE: END: command_tag=CREATE INDEX type=index identity=evttrig.one_pkey NOTICE: END: command_tag=ALTER SEQUENCE type=sequence identity=evttrig.one_col_a_seq NOTICE: END: command_tag=ALTER SEQUENCE type=sequence identity=evttrig.one_col_c_seq +NOTICE: END: command_tag=CREATE INDEX type=index identity=evttrig.one_idx NOTICE: END: command_tag=CREATE TABLE type=table identity=evttrig.two NOTICE: END: command_tag=ALTER TABLE type=table identity=evttrig.two NOTICE: END: command_tag=CREATE SEQUENCE type=sequence identity=evttrig.id_col_d_seq NOTICE: END: command_tag=CREATE TABLE type=table identity=evttrig.id NOTICE: END: command_tag=ALTER SEQUENCE type=sequence identity=evttrig.id_col_d_seq -NOTICE: END: command_tag=CREATE INDEX type=index identity=evttrig.one_idx -- Partitioned tables with a partitioned index CREATE TABLE evttrig.parted ( id int PRIMARY KEY) diff --git a/src/test/regress/expected/namespace.out b/src/test/regress/expected/namespace.out index dbbda72d3951..2e582e783c26 100644 --- a/src/test/regress/expected/namespace.out +++ b/src/test/regress/expected/namespace.out @@ -10,13 +10,14 @@ SELECT pg_catalog.set_config('search_path', ' ', false); (1 row) CREATE SCHEMA test_ns_schema_1 - CREATE UNIQUE INDEX abc_a_idx ON abc (a) - CREATE VIEW abc_view AS - SELECT a+1 AS a, b+1 AS b FROM abc CREATE TABLE abc ( a serial, b int UNIQUE - ); + ) + CREATE UNIQUE INDEX abc_a_idx ON abc (a) + CREATE VIEW abc_view AS + SELECT a+1 AS a, b+1 AS b FROM abc +; -- verify that the correct search_path restored on abort SET search_path to public; BEGIN; diff --git a/src/test/regress/sql/collate.icu.utf8.sql b/src/test/regress/sql/collate.icu.utf8.sql index dbc190227d02..06a46662f7fd 100644 --- a/src/test/regress/sql/collate.icu.utf8.sql +++ b/src/test/regress/sql/collate.icu.utf8.sql @@ -997,6 +997,18 @@ INSERT INTO t5 (a, b) values (1, 'D1'), (2, 'D2'), (3, 'd1'); -- rewriting.) SELECT * FROM t5 ORDER BY c ASC, a ASC; +--CREATE SCHEMA CREATE COLLATION +--fail. Execute subcommands in order; we do not implicitly reorder them. +CREATE SCHEMA regress_schema_4 AUTHORIZATION CURRENT_ROLE + CREATE TABLE tts(a TEXT COLLATE coll_icu_und) + CREATE COLLATION coll_icu_und FROM "und-x-icu"; + +CREATE SCHEMA regress_schema_4 + CREATE COLLATION coll_icu_und FROM "und-x-icu" + CREATE TABLE tts(a TEXT COLLATE coll_icu_und); +\dO regress_schema_4.* +DROP SCHEMA regress_schema_4 CASCADE; + -- cleanup RESET search_path; diff --git a/src/test/regress/sql/create_schema.sql b/src/test/regress/sql/create_schema.sql index 1b7064247a1c..645f3308fb64 100644 --- a/src/test/regress/sql/create_schema.sql +++ b/src/test/regress/sql/create_schema.sql @@ -47,6 +47,11 @@ CREATE SCHEMA regress_schema_1 AUTHORIZATION CURRENT_ROLE EXECUTE FUNCTION schema_trig.no_func(); RESET ROLE; +--error. Forward reference is not allowed. +CREATE SCHEMA regress_schema_2 + CREATE VIEW abcd_view AS SELECT a FROM abcd + CREATE TABLE abcd (a int); + -- Cases where the schema creation succeeds. -- The schema created matches the role name. CREATE SCHEMA AUTHORIZATION regress_create_schema_role @@ -66,5 +71,106 @@ CREATE SCHEMA regress_schema_1 AUTHORIZATION CURRENT_ROLE DROP SCHEMA regress_schema_1 CASCADE; RESET ROLE; +-- Cases where the schema creation with domain. +--fail. cannot CREATE DOMAIN to other schema +CREATE SCHEMA regress_schema_2 AUTHORIZATION CURRENT_ROLE + CREATE DOMAIN public.ss AS TEXT NOT NULL DEFAULT 'hello' CONSTRAINT nn CHECK (VALUE <> 'hello') + CREATE TABLE t(a ss); +--fail. cannot CREATE DOMAIN to other schema +CREATE SCHEMA regress_schema_2 AUTHORIZATION CURRENT_ROLE + CREATE DOMAIN postgres.public.ss AS TEXT NOT NULL CONSTRAINT nn CHECK (VALUE <> 'hello') DEFAULT 'hello' + CREATE TABLE t(a ss); + +--fail. improper qualified name +CREATE SCHEMA regress_schema_2 CREATE DOMAIN ss.postgres.regress_schema_2.ss AS TEXT; + +--fail. Execute subcommands in order; we do not implicitly reorder them. +CREATE SCHEMA regress_schema_2 AUTHORIZATION CURRENT_ROLE + CREATE DOMAIN ss1 AS ss + CREATE DOMAIN ss AS TEXT; + +--ok, qualified schema name for domain should be same as the created schema. +CREATE SCHEMA regress_schema_2 AUTHORIZATION CURRENT_ROLE + CREATE DOMAIN regress_schema_2.ss AS TEXT NOT NULL CONSTRAINT nn CHECK (VALUE <> 'hello') DEFAULT 'hello' COLLATE "C" + CREATE TABLE t(a regress_schema_2.ss); +\dD regress_schema_2.* + +--ok, no qualified schema name for domain. +CREATE SCHEMA regress_schema_3 AUTHORIZATION CURRENT_ROLE + CREATE DOMAIN ss AS TEXT CONSTRAINT nn CHECK (VALUE <> 'hello') NOT NULL DEFAULT 'hello' + CREATE DOMAIN ss1 AS ss + CREATE VIEW test AS SELECT 'hello'::ss AS test + CREATE TABLE t(a ss1); +\dD regress_schema_3.* + +-- Cases where the schema creation with collations +--fail. cannot CREATE DOMAIN to other schema +CREATE SCHEMA regress_schema_4 AUTHORIZATION CURRENT_ROLE + CREATE COLLATION public.coll_icu_und FROM "und-x-icu"; + +--fail. improper qualified name +CREATE SCHEMA regress_schema_4 AUTHORIZATION CURRENT_ROLE + CREATE COLLATION postgres.public.coll_icu_und FROM "und-x-icu"; + +--fail. only support collation object for DefineStmt node +CREATE SCHEMA regress_schema_4 AUTHORIZATION CURRENT_ROLE + CREATE AGGREGATE balk(int4)(SFUNC = int4_sum(int8, int4),STYPE = int8, PARALLEL = SAFE, INITCOND = '0'); + +--ok, qualified schema name for domain should be same as the created schema +CREATE SCHEMA regress_schema_4 AUTHORIZATION CURRENT_ROLE + CREATE COLLATION regress_schema_4.coll (LOCALE="C") + CREATE TABLE t(a TEXT COLLATE regress_schema_4.coll); +\dO regress_schema_4.* + +--ok, no qualified schema name for collation +CREATE SCHEMA regress_schema_5 AUTHORIZATION CURRENT_ROLE + CREATE COLLATION coll (LOCALE="C") + CREATE TABLE t(a TEXT COLLATE coll); +\dO regress_schema_5.* + + +-----CREATE SCHEMA CREATE TYPE +--fail. cannot CREATE TYPE to other schema +CREATE SCHEMA regress_schema_6 CREATE TYPE public.ss AS (a int); +CREATE SCHEMA regress_schema_6 CREATE TYPE public.ss; +CREATE SCHEMA regress_schema_6 CREATE TYPE public.rainbow AS ENUM ('red', 'orange'); +CREATE SCHEMA regress_schema_6 CREATE TYPE public.floatrange AS RANGE (subtype = float8, subtype_diff = float8mi); + +--fail. improper qualified name +CREATE SCHEMA regress_schema_6 AUTHORIZATION CURRENT_ROLE + CREATE TYPE postgres.public.floatrange AS RANGE (subtype = float8, subtype_diff = float8mi); + +--all the following 4 should error, because we execute subcommands in order +CREATE SCHEMA regress_schema_6 CREATE TABLE tts(a ss) CREATE TYPE ss; +CREATE SCHEMA regress_schema_6 CREATE TABLE tts(a ss) CREATE TYPE ss AS (a int); +CREATE SCHEMA regress_schema_6 CREATE TABLE tts(a rainbow) CREATE TYPE rainbow AS ENUM ('red', 'orange'); +CREATE SCHEMA regress_schema_6 + CREATE TABLE tts(a floatrange) + CREATE TYPE floatrange AS RANGE (subtype = float8, subtype_diff = float8mi); + +--ok +CREATE SCHEMA regress_schema_6 + CREATE TYPE floatrange AS RANGE (subtype = float8, subtype_diff = float8mi) + CREATE TYPE ss AS (a int) + CREATE TYPE sss + CREATE TYPE rainbow AS ENUM ('red', 'orange'); +\dT regress_schema_6.* + +--schema qualified, ok +CREATE SCHEMA regress_schema_7 + CREATE TYPE regress_schema_7.floatrange AS RANGE (subtype = float8, subtype_diff = float8mi) + CREATE TYPE regress_schema_7.ss AS (a int) + CREATE TYPE regress_schema_7.sss + CREATE TYPE regress_schema_7.rainbow AS ENUM ('red', 'orange') + CREATE TABLE t(a floatrange, b ss, c rainbow); +\dT regress_schema_7.* + +DROP SCHEMA regress_schema_2 CASCADE; +DROP SCHEMA regress_schema_3 CASCADE; +DROP SCHEMA regress_schema_4 CASCADE; +DROP SCHEMA regress_schema_5 CASCADE; +DROP SCHEMA regress_schema_6 CASCADE; +DROP SCHEMA regress_schema_7 CASCADE; + -- Clean up DROP ROLE regress_create_schema_role; diff --git a/src/test/regress/sql/create_type.sql b/src/test/regress/sql/create_type.sql index c25018029c24..41b6f9a74ec2 100644 --- a/src/test/regress/sql/create_type.sql +++ b/src/test/regress/sql/create_type.sql @@ -32,6 +32,18 @@ CREATE FUNCTION int44out(city_budget) AS :'regresslib' LANGUAGE C STRICT IMMUTABLE; +----- CREATE SCHEMA CREATE TYPE test +--error. cannot CREATE TYPE to other schema +CREATE SCHEMA regress_schema_1 + CREATE TYPE public.widget ( + internallength = 24, + input = widget_in, + output = widget_out, + typmod_in = numerictypmodin, + typmod_out = numerictypmodout, + alignment = double + ); + CREATE TYPE widget ( internallength = 24, input = widget_in, diff --git a/src/test/regress/sql/namespace.sql b/src/test/regress/sql/namespace.sql index 306cdc2d8c6a..a75d4f580d3a 100644 --- a/src/test/regress/sql/namespace.sql +++ b/src/test/regress/sql/namespace.sql @@ -7,15 +7,16 @@ SELECT pg_catalog.set_config('search_path', ' ', false); CREATE SCHEMA test_ns_schema_1 + CREATE TABLE abc ( + a serial, + b int UNIQUE + ) + CREATE UNIQUE INDEX abc_a_idx ON abc (a) CREATE VIEW abc_view AS SELECT a+1 AS a, b+1 AS b FROM abc - - CREATE TABLE abc ( - a serial, - b int UNIQUE - ); +; -- verify that the correct search_path restored on abort SET search_path to public; diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list index 37f26f6c6b75..2d7158e39e68 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -558,7 +558,6 @@ CreateRangeStmt CreateReplicationSlotCmd CreateRoleStmt CreateSchemaStmt -CreateSchemaStmtContext CreateSeqStmt CreateStatsStmt CreateStmt