Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1x4PCh-0077wz-0y for pgsql-hackers@arkaria.postgresql.org; Wed, 09 Sep 2026 20:47:35 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1x4PCf-000Dff-0c for pgsql-hackers@arkaria.postgresql.org; Wed, 09 Sep 2026 20:47:33 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1x4PCe-000DfW-2W for pgsql-hackers@lists.postgresql.org; Wed, 09 Sep 2026 20:47:32 +0000 Received: from sss.pgh.pa.us ([68.162.161.243]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.98.2) (envelope-from ) id 1x4PCb-00000003pyQ-3Tdv for pgsql-hackers@lists.postgresql.org; Wed, 09 Sep 2026 20:47:32 +0000 Received: from sss1.sss.pgh.pa.us (localhost [127.0.0.1]) by sss.pgh.pa.us (8.18.1/8.18.1) with ESMTP id 689KlA8S839740; Wed, 9 Sep 2026 16:47:10 -0400 From: Tom Lane To: Noah Misch cc: Nathan Bossart , Heikki Linnakangas , jian he , Kirill Reshke , Peter Eisentraut , PostgreSQL Hackers Subject: Re: CREATE SCHEMA ... CREATE DOMAIN support In-reply-to: <704997.1788978513@sss.pgh.pa.us> References: <1838711.1775503188@sss.pgh.pa.us> <20260904002924.a7.noahmisch@microsoft.com> <1504966.1788483626@sss.pgh.pa.us> <20260904035154.0b.noahmisch@microsoft.com> <1566169.1788531712@sss.pgh.pa.us> <20260904180712.cc.noahmisch@microsoft.com> <1584523.1788550238@sss.pgh.pa.us> <57046562-8fe6-4663-b4d7-724d195f38f7@iki.fi> <627673.1788972291@sss.pgh.pa.us> <20260909180238.b9.noahmisch@microsoft.com> <704997.1788978513@sss.pgh.pa.us> Comments: In-reply-to Tom Lane message dated "Wed, 09 Sep 2026 14:28:33 -0400" MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="----- =_aaaaaaaaaa0" Content-ID: <839718.1788986806.0@sss.pgh.pa.us> Date: Wed, 09 Sep 2026 16:47:10 -0400 Message-ID: <839739.1788986830@sss.pgh.pa.us> List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk ------- =_aaaaaaaaaa0 Content-Type: text/plain; charset="us-ascii" Content-ID: <839718.1788986806.1@sss.pgh.pa.us> Here's a finished reversion proposal that keeps 404db8f9e. 0001 is the same patch I posted earlier today. (This is against master, but I've confirmed it works on v19 too.) regards, tom lane ------- =_aaaaaaaaaa0 Content-Type: text/x-diff; name*0="v1-0001-Revert-Support-more-object-types-within-CREATE-SC.p"; name*1="atch"; charset="us-ascii" Content-ID: <839718.1788986806.2@sss.pgh.pa.us> Content-Description: v1-0001-Revert-Support-more-object-types-within-CREATE-SC.patch Content-Transfer-Encoding: quoted-printable =46rom 451259435be19b4ce85320e5a36d00dd980597ee Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Wed, 9 Sep 2026 14:11:32 -0400 Subject: [PATCH v1 1/2] Revert "Support more object types within CREATE SCHEMA". This reverts commit d516974840f4059d331ae6057ede3e4edd3c6747, along with parts of commit 049b742daad0965be4a846035408ae27ce1f9e14 ("psql: Tighten heuristics for BEGIN/END within CREATE SCHEMA"). While there's nothing particularly wrong with d51697484 in itself, it depends on a9c350d9e ("Don't try to re-order the subcommands of CREATE SCHEMA"), and concerns have been raised that the compatibility impact of that may be too great. It's not possible to revert 049b742da verbatim, because the CVE-2026-6464 patches 3045a25ba ("Teach psql to skip in-line COPY ... FROM STDIN data after a failure") and cf754f741 ("Save/restore more lexer state when skipping text due to \if") depend on infrastructure it added. Instead, rip out just the bits specifically needed to parse CREATE FUNCTION within CREATE SCHEMA. This results in psql code that matches v18-and-earlier as modified by CVE-2026-6464. --- doc/src/sgml/ref/create_schema.sgml | 25 +-- src/backend/parser/gram.y | 3 - src/backend/parser/parse_utilcmd.c | 88 ----------- src/bin/psql/psqlscanslash.l | 8 - src/bin/psql/tab-complete.in.c | 22 ++- src/fe_utils/psqlscan.l | 61 ++------ src/include/fe_utils/psqlscan_int.h | 6 - .../expected/create_schema.out | 38 +---- .../test_ddl_deparse/sql/create_schema.sql | 18 +-- src/test/regress/expected/create_schema.out | 147 +----------------- src/test/regress/sql/create_schema.sql | 81 +--------- 11 files changed, 31 insertions(+), 466 deletions(-) diff --git a/doc/src/sgml/ref/create_schema.sgml b/doc/src/sgml/ref/create= _schema.sgml index 4ecf82d6bcb..96bc496e777 100644 --- a/doc/src/sgml/ref/create_schema.sgml +++ b/doc/src/sgml/ref/create_schema.sgml @@ -100,27 +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 AGGREGATE, - CREATE COLLATION, - CREATE DOMAIN, - CREATE FUNCTION, - CREATE INDEX, - CREATE OPERATOR, - CREATE PROCEDURE, - CREATE SEQUENCE, - CREATE TABLE, - CREATE TEXT SEARCH CONFIGURATION, - CREATE TEXT SEARCH DICTIONARY, - CREATE TEXT SEARCH PARSER, - CREATE TEXT SEARCH TEMPLATE, - CREATE TRIGGER, - CREATE TYPE, - CREATE VIEW, - and GRANT are accepted as clauses + schema. Currently, only CREATE + TABLE, CREATE VIEW, CREATE + INDEX, CREATE SEQUENCE, CRE= ATE + TRIGGER and GRANT are accepted as cl= auses within CREATE SCHEMA. Other kinds of objects m= ay - be created within the schema in separate commands after the schem= a - is created. + be created in separate commands after the schema is created. diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 1015d303fbf..143e2876388 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -1653,11 +1653,8 @@ OptSchemaEltList: schema_stmt: CreateStmt | IndexStmt - | CreateDomainStmt - | CreateFunctionStmt | CreateSeqStmt | CreateTrigStmt - | DefineStmt | GrantStmt | ViewStmt ; diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse= _utilcmd.c index d83616a8507..c532a49b21d 100644 --- a/src/backend/parser/parse_utilcmd.c +++ b/src/backend/parser/parse_utilcmd.c @@ -124,8 +124,6 @@ static void transformConstraintAttrs(ParseState *pstat= e, static void transformColumnType(CreateStmtContext *cxt, ColumnDef *column= ); static void checkSchemaNameRV(ParseState *pstate, const char *context_sch= ema, RangeVar *relation); -static void checkSchemaNameList(const char *context_schema, - List *qualified_name); static CreateStmt *transformCreateSchemaCreateTable(ParseState *pstate, CreateStmt *stmt, List **fk_elements); @@ -4205,68 +4203,6 @@ transformCreateSchemaStmtElements(ParseState *pstat= e, List *schemaElts, } break; = - case T_CreateDomainStmt: - { - CreateDomainStmt *elp =3D (CreateDomainStmt *) element; - - checkSchemaNameList(schemaName, elp->domainname); - elements =3D lappend(elements, element); - } - break; - - case T_CreateFunctionStmt: - { - CreateFunctionStmt *elp =3D (CreateFunctionStmt *) element; - - checkSchemaNameList(schemaName, elp->funcname); - elements =3D lappend(elements, element); - } - break; - - /* - * CREATE TYPE can produce a DefineStmt, but also - * CreateEnumStmt, CreateRangeStmt, and CompositeTypeStmt. - * Allowing DefineStmt also provides support for several other - * commands: currently, CREATE AGGREGATE, CREATE COLLATION, - * CREATE OPERATOR, and text search objects. - */ - - case T_DefineStmt: - { - DefineStmt *elp =3D (DefineStmt *) element; - - checkSchemaNameList(schemaName, elp->defnames); - elements =3D lappend(elements, element); - } - break; - - case T_CreateEnumStmt: - { - CreateEnumStmt *elp =3D (CreateEnumStmt *) element; - - checkSchemaNameList(schemaName, elp->typeName); - elements =3D lappend(elements, element); - } - break; - - case T_CreateRangeStmt: - { - CreateRangeStmt *elp =3D (CreateRangeStmt *) element; - - checkSchemaNameList(schemaName, elp->typeName); - elements =3D lappend(elements, element); - } - break; - - case T_CompositeTypeStmt: - { - CompositeTypeStmt *elp =3D (CompositeTypeStmt *) element; - - checkSchemaNameRV(pstate, schemaName, elp->typevar); - elements =3D lappend(elements, element); - } - break; - case T_GrantStmt: elements =3D lappend(elements, element); break; @@ -4314,30 +4250,6 @@ checkSchemaNameRV(ParseState *pstate, const char *c= ontext_schema, } } = -/* - * checkSchemaNameList - * Check schema name in an element of a CREATE SCHEMA command, - * where the element's name is given by a List - * - * Much as above, but we don't have to worry about TEMP. - * Sadly, this also means we don't have a parse location to report. - */ -static void -checkSchemaNameList(const char *context_schema, List *qualified_name) -{ - char *obj_schema; - char *obj_name; - - DeconstructQualifiedName(qualified_name, &obj_schema, &obj_name); - if (obj_schema !=3D NULL && - strcmp(context_schema, obj_schema) !=3D 0) - ereport(ERROR, - (errcode(ERRCODE_INVALID_SCHEMA_DEFINITION), - errmsg("CREATE specifies a schema (%s) " - "different from the one being created (%s)", - obj_schema, context_schema))); -} - /* * transformCreateSchemaCreateTable * Process one CreateStmt for transformCreateSchemaStmtElements. diff --git a/src/bin/psql/psqlscanslash.l b/src/bin/psql/psqlscanslash.l index 298473afda8..fd1f042de52 100644 --- a/src/bin/psql/psqlscanslash.l +++ b/src/bin/psql/psqlscanslash.l @@ -738,8 +738,6 @@ psql_scan_get_lex_state(PsqlScanState state) PsqlScanStateSave *lex_state =3D pg_malloc_object(PsqlScanStateSave); StaticAssertDecl(sizeof(lex_state->init_idents) =3D=3D sizeof(state->ini= t_idents), "init_idents array lengths must match"); - StaticAssertDecl(sizeof(lex_state->sub_idents) =3D=3D sizeof(state->sub_= idents), - "sub_idents array lengths must match"); = lex_state->paren_depth =3D state->paren_depth; lex_state->begin_depth =3D state->begin_depth; @@ -747,9 +745,6 @@ psql_scan_get_lex_state(PsqlScanState state) lex_state->init_idents_count =3D state->init_idents_count; memcpy(lex_state->init_idents, state->init_idents, sizeof(lex_state->init_idents)); - lex_state->sub_idents_count =3D state->sub_idents_count; - memcpy(lex_state->sub_idents, state->sub_idents, - sizeof(lex_state->sub_idents)); return lex_state; } = @@ -766,9 +761,6 @@ psql_scan_set_lex_state(PsqlScanState state, state->init_idents_count =3D lex_state->init_idents_count; memcpy(state->init_idents, lex_state->init_idents, sizeof(state->init_idents)); - state->sub_idents_count =3D lex_state->sub_idents_count; - memcpy(state->sub_idents, lex_state->sub_idents, - sizeof(state->sub_idents)); } = /* diff --git a/src/bin/psql/tab-complete.in.c b/src/bin/psql/tab-complete.in= .c index 8e1a1d69740..8c292ce8898 100644 --- a/src/bin/psql/tab-complete.in.c +++ b/src/bin/psql/tab-complete.in.c @@ -2189,11 +2189,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("AGGREGATE", "COLLATION", "DOMAIN", "FUNCTION", - "INDEX", "OPERATOR", "PROCEDURE", "SEQUENCE", "TABLE", - "TEXT SEARCH CONFIGURATION", "TEXT SEARCH DICTIONARY", - "TEXT SEARCH PARSER", "TEXT SEARCH TEMPLATE", - "TRIGGER", "TYPE", "VIEW", + COMPLETE_WITH("TABLE", "VIEW", "INDEX", "SEQUENCE", "TRIGGER", /* for INDEX and TABLE/SEQUENCE, respectively */ "UNIQUE", "UNLOGGED"); else @@ -3493,15 +3489,15 @@ match_previous_words(int pattern_id, else if (Matches("CREATE", "DATABASE", MatchAny, "STRATEGY")) COMPLETE_WITH("WAL_LOG", "FILE_COPY"); = - /* CREATE DOMAIN --- is allowed inside CREATE SCHEMA, so use TailMatches= */ - else if (TailMatches("CREATE", "DOMAIN", MatchAny)) + /* CREATE DOMAIN */ + else if (Matches("CREATE", "DOMAIN", MatchAny)) COMPLETE_WITH("AS"); - else if (TailMatches("CREATE", "DOMAIN", MatchAny, "AS")) + else if (Matches("CREATE", "DOMAIN", MatchAny, "AS")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_datatypes); - else if (TailMatches("CREATE", "DOMAIN", MatchAny, "AS", MatchAny)) + else if (Matches("CREATE", "DOMAIN", MatchAny, "AS", MatchAny)) COMPLETE_WITH("COLLATE", "DEFAULT", "CONSTRAINT", "NOT NULL", "NULL", "CHECK ("); - else if (TailMatches("CREATE", "DOMAIN", MatchAny, "COLLATE")) + else if (Matches("CREATE", "DOMAIN", MatchAny, "COLLATE")) COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_collations); = /* CREATE EXTENSION */ @@ -3846,10 +3842,10 @@ match_previous_words(int pattern_id, else if (Matches("CREATE", "TABLESPACE", MatchAny, "OWNER", MatchAny)) COMPLETE_WITH("LOCATION"); = -/* CREATE TEXT SEARCH --- is allowed inside CREATE SCHEMA, so use TailMat= ches */ - else if (TailMatches("CREATE", "TEXT", "SEARCH")) +/* CREATE TEXT SEARCH */ + else if (Matches("CREATE", "TEXT", "SEARCH")) COMPLETE_WITH("CONFIGURATION", "DICTIONARY", "PARSER", "TEMPLATE"); - else if (TailMatches("CREATE", "TEXT", "SEARCH", "CONFIGURATION|DICTIONA= RY|PARSER|TEMPLATE", MatchAny)) + else if (Matches("CREATE", "TEXT", "SEARCH", "CONFIGURATION|DICTIONARY|P= ARSER|TEMPLATE", MatchAny)) COMPLETE_WITH("("); = /* CREATE TRANSFORM */ diff --git a/src/fe_utils/psqlscan.l b/src/fe_utils/psqlscan.l index 9cba4d8d691..76819112ba1 100644 --- a/src/fe_utils/psqlscan.l +++ b/src/fe_utils/psqlscan.l @@ -959,8 +959,8 @@ other . /* LCOV_EXCL_STOP */ = /* - * Record the first few keywords/identifiers of a statement or CREATE - * SCHEMA sub-statement in the idents[] array, of length idents_size. + * Record the first few keywords/identifiers of a statement + * in the idents[] array, of length idents_size. * *idents_count is the number of entries filled so far. * * We record the interesting keywords using their first character, which @@ -976,20 +976,18 @@ psqlscan_record_initial_keyword(const char *identifi= er, if (*idents_count < idents_size) { /* - * What we need to recognize is CREATE [OR REPLACE] FUNCTION/PROCEDURE - * and CREATE SCHEMA. Checking for SCHEMA is useless but not harmful - * in the CREATE SCHEMA sub-statement case. We record these keywords - * in lower case. We also need to recognize COPY ... FROM STDIN. - * (Note: the backend grammar doesn't distinguish STDIN from STDOUT, - * so we should not do so here either.) We record these keywords in - * upper case, to avoid conflicting with the first set. + * What we need to recognize is CREATE [OR REPLACE] FUNCTION/PROCEDURE. + * We record these keywords in lower case. We also need to recognize + * COPY ... FROM STDIN. (Note: the backend grammar doesn't + * distinguish STDIN from STDOUT, so we should not do so here either.) + * We record these keywords in upper case, to avoid conflicting with + * the first set. */ if (pg_strcasecmp(identifier, "create") =3D=3D 0 || pg_strcasecmp(identifier, "function") =3D=3D 0 || pg_strcasecmp(identifier, "procedure") =3D=3D 0 || pg_strcasecmp(identifier, "or") =3D=3D 0 || - pg_strcasecmp(identifier, "replace") =3D=3D 0 || - pg_strcasecmp(identifier, "schema") =3D=3D 0) + pg_strcasecmp(identifier, "replace") =3D=3D 0) idents[*idents_count] =3D pg_tolower((unsigned char) identifier[0]); else if (pg_strcasecmp(identifier, "copy") =3D=3D 0 || pg_strcasecmp(identifier, "from") =3D=3D 0 || @@ -1052,10 +1050,8 @@ psqlscan_is_copy_from_stdin(PsqlScanState state) * Short of writing a full parser here, the following heuristic should wo= rk. * * We track whether the beginning of the statement matches CREATE [OR REP= LACE] - * {FUNCTION|PROCEDURE}. For CREATE SCHEMA, track BEGIN .. END blocks on= ly - * after recognizing an embedded CREATE [OR REPLACE] {FUNCTION|PROCEDURE} - * subcommand. Once one of these conditions holds, count BEGIN and END - * pairs. We also have to account for CASE ... END. + * {FUNCTION|PROCEDURE}. If so, count BEGIN and END pairs. We also have= to + * account for CASE ... END. * * 2. Record enough information for psqlscan_is_copy_from_stdin() to reco= gnize * COPY FROM STDIN commands. @@ -1063,19 +1059,13 @@ psqlscan_is_copy_from_stdin(PsqlScanState state) static void psqlscan_track_identifier(PsqlScanState state, const char *identifier) { - bool is_create_schema; - /* None of this needs to happen when we're inside parentheses */ if (state->paren_depth !=3D 0) return; = /* Reset all my state at the start of each new statement */ if (state->init_idents_count =3D=3D 0) - { memset(state->init_idents, 0, sizeof(state->init_idents)); - state->sub_idents_count =3D 0; - memset(state->sub_idents, 0, sizeof(state->sub_idents)); - } = /* Record initial keywords if init_idents_count is small enough */ psqlscan_record_initial_keyword(identifier, @@ -1084,34 +1074,9 @@ psqlscan_track_identifier(PsqlScanState state, cons= t char *identifier) &state->init_idents_count); = /* - * In CREATE SCHEMA, track identifiers from each top-level CREATE schema - * element separately, so that BEGIN/END tracking is enabled only within - * CREATE [OR REPLACE] {FUNCTION|PROCEDURE} clauses. - */ - is_create_schema =3D (state->init_idents[0] =3D=3D 'c' && - state->init_idents[1] =3D=3D 's'); - if (is_create_schema && - state->begin_depth =3D=3D 0) - { - /* Reset sub-clause state at each top-level CREATE keyword */ - if (pg_strcasecmp(identifier, "create") =3D=3D 0) - { - state->sub_idents_count =3D 0; - memset(state->sub_idents, 0, sizeof(state->sub_idents)); - } - /* ... and record the first few keywords following that */ - psqlscan_record_initial_keyword(identifier, - state->sub_idents, - lengthof(state->sub_idents), - &state->sub_idents_count); - } - - /* - * Track BEGIN/CASE/END only when within an appropriate (sub) statement. + * Track BEGIN/CASE/END only when within an appropriate statement. */ - if (psqlscan_is_create_routine(state->init_idents) || - (is_create_schema && - psqlscan_is_create_routine(state->sub_idents))) + if (psqlscan_is_create_routine(state->init_idents)) { if (pg_strcasecmp(identifier, "begin") =3D=3D 0) state->begin_depth++; diff --git a/src/include/fe_utils/psqlscan_int.h b/src/include/fe_utils/ps= qlscan_int.h index b1661afd4af..cdb883259d0 100644 --- a/src/include/fe_utils/psqlscan_int.h +++ b/src/include/fe_utils/psqlscan_int.h @@ -122,9 +122,6 @@ typedef struct PsqlScanStateData int copy_stdin_count; /* number of COPY FROM STDIN commands */ int init_idents_count; /* # identifiers since start of statement */ char init_idents[8]; /* records the first few identifiers */ - int sub_idents_count; /* # identifiers since start of a CREATE - * SCHEMA element */ - char sub_idents[4]; /* records the first few of those identifiers */ = /* * Callback functions provided by the program making use of the lexer, @@ -150,9 +147,6 @@ typedef struct PsqlScanStateSave int copy_stdin_count; /* number of COPY FROM STDIN commands */ int init_idents_count; /* # identifiers since start of statement */ char init_idents[8]; /* records the first few identifiers */ - int sub_idents_count; /* # identifiers since start of a CREATE - * SCHEMA element */ - char sub_idents[4]; /* records the first few of those identifiers */ } PsqlScanStateSave; = = 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 a867786899b..6ed85ef7446 100644 --- a/src/test/modules/test_ddl_deparse/expected/create_schema.out +++ b/src/test/modules/test_ddl_deparse/expected/create_schema.out @@ -13,46 +13,10 @@ 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 COLLATION coll (LOCALE=3D"C") - CREATE DOMAIN d1 AS INT - CREATE FUNCTION et_add(int4, int4) RETURNS int4 LANGUAGE sql - AS 'SELECT $1 + $2' - CREATE PROCEDURE et_proc(int4, int4) - BEGIN ATOMIC SELECT et_add($1,$2); END - CREATE TYPE floatrange AS RANGE (subtype =3D float8, subtype_diff =3D f= loat8mi) - CREATE TYPE ss AS (a int) - CREATE TYPE sss - CREATE TYPE rainbow AS ENUM ('red', 'orange') - CREATE TEXT SEARCH PARSER et_ts_prs - (start =3D prsd_start, gettoken =3D prsd_nexttoken, end =3D prsd_end, - lextypes =3D prsd_lextype) -; + CREATE VIEW bar AS SELECT * FROM foo; 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 COLLATION -NOTICE: DDL test: type simple, tag CREATE DOMAIN -NOTICE: DDL test: type simple, tag CREATE FUNCTION -NOTICE: DDL test: type simple, tag CREATE PROCEDURE -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 -NOTICE: DDL test: type simple, tag CREATE TEXT SEARCH PARSER -DROP SCHEMA element_test CASCADE; -NOTICE: drop cascades to 11 other objects -DETAIL: drop cascades to table element_test.foo -drop cascades to view element_test.bar -drop cascades to collation element_test.coll -drop cascades to type element_test.d1 -drop cascades to function element_test.et_add(integer,integer) -drop cascades to function element_test.et_proc(integer,integer) -drop cascades to type element_test.floatrange -drop cascades to type element_test.ss -drop cascades to type element_test.sss -drop cascades to type element_test.rainbow -drop cascades to text search parser element_test.et_ts_prs CREATE SCHEMA regress_schema_1 CREATE TABLE t4( b INT, 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 7ba641d06d6..145aef2a75a 100644 --- a/src/test/modules/test_ddl_deparse/sql/create_schema.sql +++ b/src/test/modules/test_ddl_deparse/sql/create_schema.sql @@ -14,23 +14,7 @@ CREATE SCHEMA IF NOT EXISTS baz; = CREATE SCHEMA element_test CREATE TABLE foo (id int) - CREATE VIEW bar AS SELECT * FROM foo - CREATE COLLATION coll (LOCALE=3D"C") - CREATE DOMAIN d1 AS INT - CREATE FUNCTION et_add(int4, int4) RETURNS int4 LANGUAGE sql - AS 'SELECT $1 + $2' - CREATE PROCEDURE et_proc(int4, int4) - BEGIN ATOMIC SELECT et_add($1,$2); END - CREATE TYPE floatrange AS RANGE (subtype =3D float8, subtype_diff =3D f= loat8mi) - CREATE TYPE ss AS (a int) - CREATE TYPE sss - CREATE TYPE rainbow AS ENUM ('red', 'orange') - CREATE TEXT SEARCH PARSER et_ts_prs - (start =3D prsd_start, gettoken =3D prsd_nexttoken, end =3D prsd_end, - lextypes =3D prsd_lextype) -; - -DROP SCHEMA element_test CASCADE; + CREATE VIEW bar AS SELECT * FROM foo; = CREATE SCHEMA regress_schema_1 CREATE TABLE t4( diff --git a/src/test/regress/expected/create_schema.out b/src/test/regres= s/expected/create_schema.out index b9ae4c402fd..b34b9988962 100644 --- a/src/test/regress/expected/create_schema.out +++ b/src/test/regress/expected/create_schema.out @@ -5,7 +5,7 @@ CREATE ROLE regress_create_schema_role SUPERUSER; -- Cases where schema creation fails as objects are qualified with a sche= ma -- that does not match with what's expected. --- This checks most object types that include schema qualifications. +-- 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 th= e one being created (regress_create_schema_role) @@ -32,10 +32,6 @@ CREATE SCHEMA AUTHORIZATION regress_create_schema_role ERROR: CREATE specifies a schema (schema_not_existing) different from th= e one being created (regress_create_schema_role) LINE 2: CREATE TRIGGER schema_trig BEFORE INSERT ON schema_not_exi... ^ -CREATE SCHEMA AUTHORIZATION regress_create_schema_role - CREATE FUNCTION schema_not_existing.func(int) RETURNS int - AS 'SELECT $1' LANGUAGE sql; -ERROR: CREATE specifies a schema (schema_not_existing) different from th= e 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 @@ -181,146 +177,5 @@ drop cascades to table regress_schema_fk.t3 drop cascades to table regress_schema_fk.t4 drop cascades to table regress_schema_fk.t5 drop cascades to table regress_schema_fk.t6 --- Test miscellaneous object types within CREATE SCHEMA. -CREATE SCHEMA regress_schema_misc - CREATE AGGREGATE cs_sum(int4) - ( - SFUNC =3D int4_sum(int8, int4), - STYPE =3D int8, - INITCOND =3D '0' - ) - CREATE COLLATION cs_builtin_c ( PROVIDER =3D builtin, LOCALE =3D "C" ) - CREATE DOMAIN cs_positive AS integer CHECK (VALUE > 0) - CREATE FUNCTION cs_add(int4, int4) returns int4 language sql - as 'select $1 + $2' - CREATE OPERATOR + (function =3D cs_add, leftarg =3D int4, rightarg =3D = int4) - CREATE PROCEDURE cs_proc(int4, int4) - BEGIN ATOMIC - SELECT cs_add($1,$2); - END - -- this checks that psql is not fooled by an irrelevant BEGIN - CREATE VIEW begin AS SELECT 1 AS one - CREATE TEXT SEARCH CONFIGURATION cs_ts_conf (copy=3Denglish) - CREATE TEXT SEARCH DICTIONARY cs_ts_dict (template=3Dsimple) - CREATE TEXT SEARCH PARSER cs_ts_prs - (start =3D prsd_start, gettoken =3D prsd_nexttoken, end =3D prsd_end, - lextypes =3D prsd_lextype) - CREATE TEXT SEARCH TEMPLATE cs_ts_temp (lexize=3Ddsimple_lexize) - CREATE TYPE regress_schema_misc.cs_enum AS ENUM ('red', 'orange') - CREATE TYPE cs_composite AS (a int, b float8) - CREATE TYPE cs_range AS RANGE (subtype =3D float8, subtype_diff =3D flo= at8mi) - -- demonstrate creation of a base type with its I/O functions - CREATE TYPE cs_type - CREATE FUNCTION cs_type_in(cstring) - RETURNS cs_type LANGUAGE internal IMMUTABLE PARALLEL SAFE STRICT - AS 'int4in' - CREATE FUNCTION cs_type_out(cs_type) - RETURNS cstring LANGUAGE internal IMMUTABLE PARALLEL SAFE STRICT - AS 'int4out' - CREATE TYPE cs_type ( - INPUT =3D cs_type_in, - OUTPUT =3D cs_type_out, - LIKE =3D int4 - ) - GRANT USAGE ON TYPE cs_type TO public -; -NOTICE: return type cs_type is only a shell -NOTICE: argument type cs_type is only a shell -LINE 33: CREATE FUNCTION cs_type_out(cs_type) - ^ -\df regress_schema_misc.cs_add - List of functions - Schema | Name | Result data type | Argument data types | = Type = ----------------------+--------+------------------+---------------------+-= ----- - regress_schema_misc | cs_add | integer | integer, integer | = func -(1 row) - -\df regress_schema_misc.cs_proc - List of functions - Schema | Name | Result data type | Argument data types = | Type = ----------------------+---------+------------------+----------------------= --+------ - regress_schema_misc | cs_proc | | IN integer, IN intege= r | proc -(1 row) - -\da regress_schema_misc.cs_sum - List of aggregate functions - Schema | Name | Result data type | Argument data types | = Description = ----------------------+--------+------------------+---------------------+-= ------------ - regress_schema_misc | cs_sum | bigint | integer | = -(1 row) - -\do regress_schema_misc.+ - List of operators - Schema | Name | Left arg type | Right arg type | Result typ= e | Description = ----------------------+------+---------------+----------------+-----------= --+------------- - regress_schema_misc | + | integer | integer | integer = | = -(1 row) - -\dO regress_schema_misc.* - List of collations - Schema | Name | Provider | Collate | Ctype | Locale= | ICU Rules | Deterministic? = ----------------------+--------------+----------+---------+-------+-------= -+-----------+---------------- - regress_schema_misc | cs_builtin_c | builtin | | | C = | | yes -(1 row) - -\dT regress_schema_misc.* - List of data types - Schema | Name | Description = ----------------------+-----------------------------------+------------- - regress_schema_misc | regress_schema_misc.cs_composite | = - regress_schema_misc | regress_schema_misc.cs_enum | = - regress_schema_misc | regress_schema_misc.cs_multirange | = - regress_schema_misc | regress_schema_misc.cs_positive | = - regress_schema_misc | regress_schema_misc.cs_range | = - regress_schema_misc | regress_schema_misc.cs_type | = -(6 rows) - -\dF regress_schema_misc.* - List of text search configurations - Schema | Name | Description = ----------------------+------------+------------- - regress_schema_misc | cs_ts_conf | = -(1 row) - -\dFd regress_schema_misc.* - List of text search dictionaries - Schema | Name | Description = ----------------------+------------+------------- - regress_schema_misc | cs_ts_dict | = -(1 row) - -\dFp regress_schema_misc.* - List of text search parsers - Schema | Name | Description = ----------------------+-----------+------------- - regress_schema_misc | cs_ts_prs | = -(1 row) - -\dFt regress_schema_misc.* - List of text search templates - Schema | Name | Description = ----------------------+------------+------------- - regress_schema_misc | cs_ts_temp | = -(1 row) - -DROP SCHEMA regress_schema_misc CASCADE; -NOTICE: drop cascades to 17 other objects -DETAIL: drop cascades to function regress_schema_misc.cs_sum(integer) -drop cascades to collation regress_schema_misc.cs_builtin_c -drop cascades to type regress_schema_misc.cs_positive -drop cascades to function regress_schema_misc.cs_add(integer,integer) -drop cascades to operator regress_schema_misc.+(integer,integer) -drop cascades to function regress_schema_misc.cs_proc(integer,integer) -drop cascades to view regress_schema_misc.begin -drop cascades to text search configuration regress_schema_misc.cs_ts_conf -drop cascades to text search dictionary regress_schema_misc.cs_ts_dict -drop cascades to text search parser regress_schema_misc.cs_ts_prs -drop cascades to text search template regress_schema_misc.cs_ts_temp -drop cascades to type regress_schema_misc.cs_enum -drop cascades to type regress_schema_misc.cs_composite -drop cascades to type regress_schema_misc.cs_range -drop cascades to function regress_schema_misc.cs_type_out(regress_schema_= misc.cs_type) -drop cascades to type regress_schema_misc.cs_type -drop cascades to function regress_schema_misc.cs_type_in(cstring) -- Clean up DROP ROLE regress_create_schema_role; diff --git a/src/test/regress/sql/create_schema.sql b/src/test/regress/sql= /create_schema.sql index 526bb3cb065..0f2accc59ec 100644 --- a/src/test/regress/sql/create_schema.sql +++ b/src/test/regress/sql/create_schema.sql @@ -8,7 +8,7 @@ CREATE ROLE regress_create_schema_role SUPERUSER; = -- Cases where schema creation fails as objects are qualified with a sche= ma -- that does not match with what's expected. --- This checks most object types that include schema qualifications. +-- 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 @@ -20,9 +20,6 @@ CREATE SCHEMA AUTHORIZATION 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(); -CREATE SCHEMA AUTHORIZATION regress_create_schema_role - CREATE FUNCTION schema_not_existing.func(int) RETURNS int - AS 'SELECT $1' LANGUAGE sql; -- Again, with a role specification and no schema names. SET ROLE regress_create_schema_role; CREATE SCHEMA AUTHORIZATION CURRENT_ROLE @@ -101,81 +98,5 @@ CREATE SCHEMA regress_schema_fk = DROP SCHEMA regress_schema_fk CASCADE; = --- Test miscellaneous object types within CREATE SCHEMA. -CREATE SCHEMA regress_schema_misc - CREATE AGGREGATE cs_sum(int4) - ( - SFUNC =3D int4_sum(int8, int4), - STYPE =3D int8, - INITCOND =3D '0' - ) - - CREATE COLLATION cs_builtin_c ( PROVIDER =3D builtin, LOCALE =3D "C" ) - - CREATE DOMAIN cs_positive AS integer CHECK (VALUE > 0) - - CREATE FUNCTION cs_add(int4, int4) returns int4 language sql - as 'select $1 + $2' - - CREATE OPERATOR + (function =3D cs_add, leftarg =3D int4, rightarg =3D = int4) - - CREATE PROCEDURE cs_proc(int4, int4) - BEGIN ATOMIC - SELECT cs_add($1,$2); - END - - -- this checks that psql is not fooled by an irrelevant BEGIN - CREATE VIEW begin AS SELECT 1 AS one - - CREATE TEXT SEARCH CONFIGURATION cs_ts_conf (copy=3Denglish) - - CREATE TEXT SEARCH DICTIONARY cs_ts_dict (template=3Dsimple) - - CREATE TEXT SEARCH PARSER cs_ts_prs - (start =3D prsd_start, gettoken =3D prsd_nexttoken, end =3D prsd_end, - lextypes =3D prsd_lextype) - - CREATE TEXT SEARCH TEMPLATE cs_ts_temp (lexize=3Ddsimple_lexize) - - CREATE TYPE regress_schema_misc.cs_enum AS ENUM ('red', 'orange') - - CREATE TYPE cs_composite AS (a int, b float8) - - CREATE TYPE cs_range AS RANGE (subtype =3D float8, subtype_diff =3D flo= at8mi) - - -- demonstrate creation of a base type with its I/O functions - - CREATE TYPE cs_type - - CREATE FUNCTION cs_type_in(cstring) - RETURNS cs_type LANGUAGE internal IMMUTABLE PARALLEL SAFE STRICT - AS 'int4in' - - CREATE FUNCTION cs_type_out(cs_type) - RETURNS cstring LANGUAGE internal IMMUTABLE PARALLEL SAFE STRICT - AS 'int4out' - - CREATE TYPE cs_type ( - INPUT =3D cs_type_in, - OUTPUT =3D cs_type_out, - LIKE =3D int4 - ) - - GRANT USAGE ON TYPE cs_type TO public -; - -\df regress_schema_misc.cs_add -\df regress_schema_misc.cs_proc -\da regress_schema_misc.cs_sum -\do regress_schema_misc.+ -\dO regress_schema_misc.* -\dT regress_schema_misc.* -\dF regress_schema_misc.* -\dFd regress_schema_misc.* -\dFp regress_schema_misc.* -\dFt regress_schema_misc.* - -DROP SCHEMA regress_schema_misc CASCADE; - -- Clean up DROP ROLE regress_create_schema_role; -- = 2.52.0 ------- =_aaaaaaaaaa0 Content-Type: text/x-diff; name*0="v1-0002-Revert-Don-t-try-to-re-order-the-subcommands-of-C.p"; name*1="atch"; charset="us-ascii" Content-ID: <839718.1788986806.3@sss.pgh.pa.us> Content-Description: v1-0002-Revert-Don-t-try-to-re-order-the-subcommands-of-C.patch Content-Transfer-Encoding: quoted-printable =46rom 18806a814175b52ba55c25ea1266088c00612b40 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Wed, 9 Sep 2026 16:02:37 -0400 Subject: [PATCH v1 2/2] Revert "Don't try to re-order the subcommands of CREATE SCHEMA". This reverts commit a9c350d9ee66745aadcf7c0c95a567752a762171. While that intentionally changed our semantics for CREATE SCHEMA subcommands, it's being argued that the functionality gain does not justify potentially-subtle compatibility breakage. The most critical bit of functionality gain came from commit 404db8f9e ("Execute foreign key constraints in CREATE SCHEMA at the end"), which we're keeping because it's required by SQL spec. This is not an exact revert, partly because we're keeping 404db8f9e, and partly because I kept the API changes that allowed passing down a ParseState (which allows providing an error cursor for many of the errors thrown in CREATE SCHEMA). --- doc/src/sgml/ref/create_schema.sgml | 23 ++-- src/backend/commands/schemacmds.c | 7 +- src/backend/parser/parse_utilcmd.c | 116 +++++++++++++------- src/test/regress/expected/create_schema.out | 7 -- src/test/regress/expected/event_trigger.out | 2 +- src/test/regress/expected/namespace.out | 9 +- src/test/regress/sql/create_schema.sql | 5 - src/test/regress/sql/namespace.sql | 11 +- src/tools/pgindent/typedefs.list | 1 + 9 files changed, 102 insertions(+), 79 deletions(-) diff --git a/doc/src/sgml/ref/create_schema.sgml b/doc/src/sgml/ref/create= _schema.sgml index 96bc496e777..31c381a2b7a 100644 --- a/doc/src/sgml/ref/create_schema.sgml +++ b/doc/src/sgml/ref/create_schema.sgml @@ -131,14 +131,6 @@ CREATE SCHEMA IF NOT EXISTS AUTHORIZATION role_sp CREATE privilege for the current database. (Of course, superusers bypass this check.) - - - The schema_element - subcommands, if any, are executed in the order they are written. - An exception is that foreign key constraint clauses in CREATE - TABLE subcommands are postponed and added at the end. - This allows circular foreign key references, which are sometimes usefu= l. - = @@ -201,12 +193,15 @@ CREATE VIEW hollywood.winners AS = - Some other SQL implementations attempt to allow more kinds of forward - references to objects defined in - later schema_element - subcommands than just foreign key constraints. This is difficult or - impossible to do correctly in general, and it is not clear that the SQ= L - standard requires any such behavior except for foreign keys. + The SQL standard suggests, without saying so in so many words, that th= e + subcommands in CREATE SCHEMA can appear in any + order; but the only actual requirement it gives is that foreign keys + referencing table definitions that appear in later CREATE + SCHEMA subcommands should be accepted. The + present PostgreSQL implementation handles + that case, but does not handle all other cases of forward references i= n + subcommands; it might sometimes be necessary to reorder the subcommand= s + in order to avoid forward references. = diff --git a/src/backend/commands/schemacmds.c b/src/backend/commands/sche= macmds.c index de5bbd5662c..b016983f904 100644 --- a/src/backend/commands/schemacmds.c +++ b/src/backend/commands/schemacmds.c @@ -189,9 +189,10 @@ CreateSchemaCommand(ParseState *pstate, CreateSchemaS= tmt *stmt, = /* * Examine the list of commands embedded in the CREATE SCHEMA command, a= nd - * do preliminary transformations. Note that the result is still a list - * of raw parsetrees --- we cannot, in general, run parse analysis on on= e - * statement until we have actually executed the prior ones. + * 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. */ parsetree_list =3D transformCreateSchemaStmtElements(pstate, stmt->schemaElts, diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse= _utilcmd.c index c532a49b21d..f838311090b 100644 --- a/src/backend/parser/parse_utilcmd.c +++ b/src/backend/parser/parse_utilcmd.c @@ -96,6 +96,20 @@ typedef struct bool ofType; /* true if statement contains OF typename */ } CreateStmtContext; = +/* State shared by transformCreateSchemaStmtElements and its subroutines = */ +typedef struct +{ + ParseState *pstate; /* overall parse state */ + 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 */ + List *foreign_keys; /* generated ALTER ADD FOREIGN KEY items */ +} CreateSchemaStmtContext; + = static void transformColumnDefinition(CreateStmtContext *cxt, ColumnDef *column); @@ -122,8 +136,7 @@ static void transformCheckConstraints(CreateStmtContex= t *cxt, static void transformConstraintAttrs(ParseState *pstate, List *constraintList); static void transformColumnType(CreateStmtContext *cxt, ColumnDef *column= ); -static void checkSchemaNameRV(ParseState *pstate, const char *context_sch= ema, - RangeVar *relation); +static void checkSchemaNameRV(CreateSchemaStmtContext *cxt, RangeVar *rel= ation); static CreateStmt *transformCreateSchemaCreateTable(ParseState *pstate, CreateStmt *stmt, List **fk_elements); @@ -4112,17 +4125,17 @@ transformColumnType(CreateStmtContext *cxt, Column= Def *column) * transformCreateSchemaStmtElements - * analyzes the elements of a CREATE SCHEMA statement * - * This presently has two responsibilities. We verify that no subcommand= s are - * trying to create objects outside the new schema. We also pull out any - * foreign-key constraint clauses embedded in CREATE TABLE subcommands, a= nd - * convert them to ALTER TABLE ADD CONSTRAINT commands appended to the li= st. - * This supports forward references in foreign keys, which is required by= the - * SQL standard. - * - * 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 impossi= ble) - * to do correctly with not-yet-parse-analyzed commands. Now we'll just - * execute the elements in the order given, except for foreign keys. + * This presently has two responsibilities. We verify that no subcommand= s + * are trying to create objects outside the new schema. We also attempt = to + * re-order the subcommands such that there are no forward references + * (e.g. GRANT to a table created later in the list). Note that the logi= c + * we use for determining forward references is presently quite incomplet= e, + * and it's unlikely that we can do significantly better while working wi= th + * non-parse-analyzed commands. The only case that the SQL standard call= s + * out as required is to support forward references in foreign-key constr= aint + * clauses in CREATE TABLE subcommands. We do handle that, by pulling ou= t + * such clauses and converting them to ALTER TABLE ADD CONSTRAINT command= s + * appended to the list. * * "schemaName" is the name of the schema that will be used for the creat= ion * of the objects listed. It may be obtained from the schema name define= d @@ -4140,17 +4153,28 @@ List * transformCreateSchemaStmtElements(ParseState *pstate, List *schemaElts, const char *schemaName) { - List *elements =3D NIL; - List *fk_elements =3D NIL; - ListCell *lc; + CreateSchemaStmtContext cxt; + List *result; + ListCell *elements; + + cxt.pstate =3D pstate; + cxt.schemaname =3D schemaName; + cxt.sequences =3D NIL; + cxt.tables =3D NIL; + cxt.views =3D NIL; + cxt.indexes =3D NIL; + cxt.triggers =3D NIL; + cxt.grants =3D NIL; + cxt.foreign_keys =3D NIL; = /* * Run through each schema element in the schema element list. Check - * target schema names, and collect the list of actions to be done. + * target schema names, separate statements by type, and do preliminary + * analysis. */ - foreach(lc, schemaElts) + foreach(elements, schemaElts) { - Node *element =3D lfirst(lc); + Node *element =3D lfirst(elements); = switch (nodeTag(element)) { @@ -4158,8 +4182,8 @@ transformCreateSchemaStmtElements(ParseState *pstate= , List *schemaElts, { CreateSeqStmt *elp =3D (CreateSeqStmt *) element; = - checkSchemaNameRV(pstate, schemaName, elp->sequence); - elements =3D lappend(elements, element); + checkSchemaNameRV(&cxt, elp->sequence); + cxt.sequences =3D lappend(cxt.sequences, element); } break; = @@ -4167,12 +4191,16 @@ transformCreateSchemaStmtElements(ParseState *psta= te, List *schemaElts, { CreateStmt *elp =3D (CreateStmt *) element; = - checkSchemaNameRV(pstate, schemaName, elp->relation); + checkSchemaNameRV(&cxt, elp->relation); /* Pull out any foreign key clauses, add to fk_elements */ elp =3D transformCreateSchemaCreateTable(pstate, elp, - &fk_elements); - elements =3D lappend(elements, elp); + &cxt.foreign_keys); + + /* + * XXX todo: deal with other constraints + */ + cxt.tables =3D lappend(cxt.tables, elp); } break; = @@ -4180,8 +4208,12 @@ transformCreateSchemaStmtElements(ParseState *pstat= e, List *schemaElts, { ViewStmt *elp =3D (ViewStmt *) element; = - checkSchemaNameRV(pstate, schemaName, elp->view); - elements =3D lappend(elements, element); + checkSchemaNameRV(&cxt, elp->view); + + /* + * XXX todo: deal with references between views + */ + cxt.views =3D lappend(cxt.views, element); } break; = @@ -4189,8 +4221,8 @@ transformCreateSchemaStmtElements(ParseState *pstate= , List *schemaElts, { IndexStmt *elp =3D (IndexStmt *) element; = - checkSchemaNameRV(pstate, schemaName, elp->relation); - elements =3D lappend(elements, element); + checkSchemaNameRV(&cxt, elp->relation); + cxt.indexes =3D lappend(cxt.indexes, element); } break; = @@ -4198,13 +4230,13 @@ transformCreateSchemaStmtElements(ParseState *psta= te, List *schemaElts, { CreateTrigStmt *elp =3D (CreateTrigStmt *) element; = - checkSchemaNameRV(pstate, schemaName, elp->relation); - elements =3D lappend(elements, element); + checkSchemaNameRV(&cxt, elp->relation); + cxt.triggers =3D lappend(cxt.triggers, element); } break; = case T_GrantStmt: - elements =3D lappend(elements, element); + cxt.grants =3D lappend(cxt.grants, element); break; = default: @@ -4213,7 +4245,16 @@ transformCreateSchemaStmtElements(ParseState *pstat= e, List *schemaElts, } } = - return list_concat(elements, fk_elements); + result =3D NIL; + result =3D list_concat(result, cxt.sequences); + result =3D list_concat(result, cxt.tables); + result =3D list_concat(result, cxt.views); + result =3D list_concat(result, cxt.indexes); + result =3D list_concat(result, cxt.triggers); + result =3D list_concat(result, cxt.grants); + result =3D list_concat(result, cxt.foreign_keys); + + return result; } = /* @@ -4228,17 +4269,16 @@ transformCreateSchemaStmtElements(ParseState *psta= te, List *schemaElts, * that would likewise put the object into the wrong schema. */ static void -checkSchemaNameRV(ParseState *pstate, const char *context_schema, - RangeVar *relation) +checkSchemaNameRV(CreateSchemaStmtContext *cxt, RangeVar *relation) { if (relation->schemaname !=3D NULL && - strcmp(context_schema, relation->schemaname) !=3D 0) + strcmp(cxt->schemaname, relation->schemaname) !=3D 0) ereport(ERROR, (errcode(ERRCODE_INVALID_SCHEMA_DEFINITION), errmsg("CREATE specifies a schema (%s) " "different from the one being created (%s)", - relation->schemaname, context_schema), - parser_errposition(pstate, relation->location))); + relation->schemaname, cxt->schemaname), + parser_errposition(cxt->pstate, relation->location))); = if (relation->relpersistence =3D=3D RELPERSISTENCE_TEMP) { @@ -4246,7 +4286,7 @@ checkSchemaNameRV(ParseState *pstate, const char *co= ntext_schema, ereport(ERROR, (errcode(ERRCODE_INVALID_TABLE_DEFINITION), errmsg("cannot create temporary relation in non-temporary schema"), - parser_errposition(pstate, relation->location))); + parser_errposition(cxt->pstate, relation->location))); } } = diff --git a/src/test/regress/expected/create_schema.out b/src/test/regres= s/expected/create_schema.out index b34b9988962..7a9b71f97b3 100644 --- a/src/test/regress/expected/create_schema.out +++ b/src/test/regress/expected/create_schema.out @@ -88,13 +88,6 @@ ERROR: CREATE specifies a schema (schema_not_existing)= different from the one b LINE 2: CREATE TRIGGER schema_trig BEFORE INSERT ON schema_not_exi... ^ RESET ROLE; --- Forward references no longer work in general. -CREATE SCHEMA regress_schema_1 AUTHORIZATION CURRENT_ROLE - 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 diff --git a/src/test/regress/expected/event_trigger.out b/src/test/regres= s/expected/event_trigger.out index 065f586310f..f57e8ffa7a5 100644 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@ -425,12 +425,12 @@ NOTICE: END: command_tag=3DCREATE TABLE type=3Dtabl= e identity=3Devttrig.one NOTICE: END: command_tag=3DCREATE INDEX type=3Dindex identity=3Devttrig.= one_pkey NOTICE: END: command_tag=3DALTER SEQUENCE type=3Dsequence identity=3Devt= trig.one_col_a_seq NOTICE: END: command_tag=3DALTER SEQUENCE type=3Dsequence identity=3Devt= trig.one_col_c_seq -NOTICE: END: command_tag=3DCREATE INDEX type=3Dindex identity=3Devttrig.= one_idx NOTICE: END: command_tag=3DCREATE TABLE type=3Dtable identity=3Devttrig.= two NOTICE: END: command_tag=3DCREATE SEQUENCE type=3Dsequence identity=3Dev= ttrig.id_col_d_seq NOTICE: END: command_tag=3DCREATE TABLE type=3Dtable identity=3Devttrig.= id NOTICE: END: command_tag=3DALTER SEQUENCE type=3Dsequence identity=3Devt= trig.id_col_d_seq NOTICE: END: command_tag=3DCREATE VIEW type=3Dview identity=3Devttrig.on= e_view +NOTICE: END: command_tag=3DCREATE INDEX type=3Dindex identity=3Devttrig.= one_idx NOTICE: END: command_tag=3DALTER TABLE type=3Dtable identity=3Devttrig.t= wo -- View with column additions CREATE OR REPLACE VIEW evttrig.one_view AS SELECT * FROM evttrig.two, evt= trig.id; diff --git a/src/test/regress/expected/namespace.out b/src/test/regress/ex= pected/namespace.out index 2e582e783c2..dbbda72d395 100644 --- a/src/test/regress/expected/namespace.out +++ b/src/test/regress/expected/namespace.out @@ -10,14 +10,13 @@ SELECT pg_catalog.set_config('search_path', ' ', false= ); (1 row) = 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; BEGIN; diff --git a/src/test/regress/sql/create_schema.sql b/src/test/regress/sql= /create_schema.sql index 0f2accc59ec..57014ac4930 100644 --- a/src/test/regress/sql/create_schema.sql +++ b/src/test/regress/sql/create_schema.sql @@ -47,11 +47,6 @@ CREATE SCHEMA regress_schema_1 AUTHORIZATION CURRENT_RO= LE EXECUTE FUNCTION schema_trig.no_func(); RESET ROLE; = --- Forward references no longer work in general. -CREATE SCHEMA regress_schema_1 AUTHORIZATION CURRENT_ROLE - 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 diff --git a/src/test/regress/sql/namespace.sql b/src/test/regress/sql/nam= espace.sql index a75d4f580d3..306cdc2d8c6 100644 --- a/src/test/regress/sql/namespace.sql +++ b/src/test/regress/sql/namespace.sql @@ -7,16 +7,15 @@ 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/typedef= s.list index 1040a65bc14..0e48edf4109 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -587,6 +587,7 @@ CreateRangeStmt CreateReplicationSlotCmd CreateRoleStmt CreateSchemaStmt +CreateSchemaStmtContext CreateSeqStmt CreateStatsStmt CreateStmt -- = 2.52.0 ------- =_aaaaaaaaaa0--