=== Applying patches on top of PostgreSQL commit ID 5142f0093e648d1a32fdcc7c835d17fa103e1239 === /etc/rc.d/jail: WARNING: Per-jail configuration via jail_* variables is obsolete. Please consider migrating to /etc/jail.conf. Mon Apr 20 00:46:23 UTC 2026 On branch cf/5985 nothing to commit, working tree clean === using 'git am' to apply patch ./v13-0001-Don-t-try-to-re-order-the-subcommands-of-CREATE-.patch === Applying: Don't try to re-order the subcommands of CREATE SCHEMA. Using index info to reconstruct a base tree... M doc/src/sgml/ref/create_schema.sgml M src/backend/commands/extension.c M src/backend/commands/schemacmds.c M src/backend/parser/parse_utilcmd.c M src/backend/tcop/utility.c M src/include/commands/schemacmds.h M src/include/parser/parse_utilcmd.h M src/test/regress/expected/create_schema.out M src/test/regress/expected/create_view.out M src/test/regress/expected/event_trigger.out M src/test/regress/expected/namespace.out M src/test/regress/sql/create_schema.sql M src/test/regress/sql/namespace.sql M src/tools/pgindent/typedefs.list Falling back to patching base and 3-way merge... Auto-merging src/tools/pgindent/typedefs.list Auto-merging src/test/regress/sql/create_schema.sql Auto-merging src/test/regress/expected/event_trigger.out CONFLICT (content): Merge conflict in src/test/regress/expected/event_trigger.out Auto-merging src/test/regress/expected/create_schema.out CONFLICT (content): Merge conflict in src/test/regress/expected/create_schema.out Auto-merging src/backend/tcop/utility.c Auto-merging src/backend/parser/parse_utilcmd.c CONFLICT (content): Merge conflict in src/backend/parser/parse_utilcmd.c Auto-merging doc/src/sgml/ref/create_schema.sgml CONFLICT (content): Merge conflict in doc/src/sgml/ref/create_schema.sgml error: Failed to merge in the changes. hint: Use 'git am --show-current-patch=diff' to see the failed patch Patch failed at 0001 Don't try to re-order the subcommands of CREATE SCHEMA. When you have resolved this problem, run "git am --continue". If you prefer to skip this patch, run "git am --skip" instead. To restore the original branch and stop patching, run "git am --abort". === using patch(1) to apply patch ./v13-0001-Don-t-try-to-re-order-the-subcommands-of-CREATE-.patch === patching file doc/src/sgml/ref/create_schema.sgml Hunk #1 succeeded at 154 with fuzz 2 (offset 23 lines). Hunk #2 FAILED at 198. 1 out of 2 hunks FAILED -- saving rejects to file doc/src/sgml/ref/create_schema.sgml.rej patching file src/backend/commands/extension.c Hunk #1 FAILED at 1952. 1 out of 1 hunk FAILED -- saving rejects to file src/backend/commands/extension.c.rej patching file src/backend/commands/schemacmds.c Hunk #1 FAILED at 49. Hunk #2 FAILED at 189. Hunk #3 FAILED at 219. 3 out of 3 hunks FAILED -- saving rejects to file src/backend/commands/schemacmds.c.rej patching file src/backend/parser/parse_utilcmd.c Hunk #1 FAILED at 99. Hunk #2 FAILED at 137. Hunk #3 FAILED at 4395. Hunk #4 FAILED at 4447. Hunk #5 FAILED at 4456. Hunk #6 FAILED at 4469. Hunk #7 FAILED at 4482. Hunk #8 FAILED at 4491. Hunk #9 FAILED at 4506. 9 out of 9 hunks FAILED -- saving rejects to file src/backend/parser/parse_utilcmd.c.rej patching file src/backend/tcop/utility.c Hunk #1 FAILED at 1122. 1 out of 1 hunk FAILED -- saving rejects to file src/backend/tcop/utility.c.rej patching file src/include/commands/schemacmds.h Hunk #1 FAILED at 16. 1 out of 1 hunk FAILED -- saving rejects to file src/include/commands/schemacmds.h.rej patching file src/include/parser/parse_utilcmd.h Hunk #1 FAILED at 30. 1 out of 1 hunk FAILED -- saving rejects to file src/include/parser/parse_utilcmd.h.rej patching file src/test/regress/expected/create_schema.out Hunk #1 FAILED at 9. 1 out of 1 hunk FAILED -- saving rejects to file src/test/regress/expected/create_schema.out.rej patching file src/test/regress/expected/create_view.out Hunk #1 FAILED at 128. 1 out of 1 hunk FAILED -- saving rejects to file src/test/regress/expected/create_view.out.rej patching file src/test/regress/expected/event_trigger.out Hunk #1 FAILED at 425. 1 out of 1 hunk FAILED -- saving rejects to file src/test/regress/expected/event_trigger.out.rej patching file src/test/regress/expected/namespace.out Hunk #1 FAILED at 10. 1 out of 1 hunk FAILED -- saving rejects to file src/test/regress/expected/namespace.out.rej patching file src/test/regress/sql/create_schema.sql Hunk #1 succeeded at 55 with fuzz 2 (offset 8 lines). patching file src/test/regress/sql/namespace.sql Hunk #1 FAILED at 7. 1 out of 1 hunk FAILED -- saving rejects to file src/test/regress/sql/namespace.sql.rej patching file src/tools/pgindent/typedefs.list Hunk #1 FAILED at 585. 1 out of 1 hunk FAILED -- saving rejects to file src/tools/pgindent/typedefs.list.rej Unstaged changes after reset: M doc/src/sgml/ref/create_schema.sgml M src/test/regress/sql/create_schema.sql Removing doc/src/sgml/ref/create_schema.sgml.rej Removing src/backend/commands/extension.c.rej Removing src/backend/commands/schemacmds.c.rej Removing src/backend/parser/parse_utilcmd.c.rej Removing src/backend/tcop/utility.c.rej Removing src/include/commands/schemacmds.h.rej Removing src/include/parser/parse_utilcmd.h.rej Removing src/test/regress/expected/create_schema.out.rej Removing src/test/regress/expected/create_view.out.rej Removing src/test/regress/expected/event_trigger.out.rej Removing src/test/regress/expected/namespace.out.rej Removing src/test/regress/sql/namespace.sql.rej Removing src/tools/pgindent/typedefs.list.rej === using 'git apply' to apply patch ./v13-0001-Don-t-try-to-re-order-the-subcommands-of-CREATE-.patch === Applied patch to 'doc/src/sgml/ref/create_schema.sgml' with conflicts. Applied patch to 'src/backend/commands/extension.c' cleanly. Applied patch to 'src/backend/commands/schemacmds.c' cleanly. Applied patch to 'src/backend/parser/parse_utilcmd.c' with conflicts. Applied patch to 'src/backend/tcop/utility.c' cleanly. Applied patch to 'src/include/commands/schemacmds.h' cleanly. Applied patch to 'src/include/parser/parse_utilcmd.h' cleanly. Applied patch to 'src/test/regress/expected/create_schema.out' with conflicts. Applied patch to 'src/test/regress/expected/create_view.out' cleanly. Applied patch to 'src/test/regress/expected/event_trigger.out' with conflicts. Applied patch to 'src/test/regress/expected/namespace.out' cleanly. Applied patch to 'src/test/regress/sql/create_schema.sql' cleanly. Applied patch to 'src/test/regress/sql/namespace.sql' cleanly. Applied patch to 'src/tools/pgindent/typedefs.list' cleanly. U doc/src/sgml/ref/create_schema.sgml U src/backend/parser/parse_utilcmd.c U src/test/regress/expected/create_schema.out U src/test/regress/expected/event_trigger.out diff --cc doc/src/sgml/ref/create_schema.sgml index 4ecf82d6bcb,9e6f0e24339..00000000000 --- a/doc/src/sgml/ref/create_schema.sgml +++ b/doc/src/sgml/ref/create_schema.sgml @@@ -150,9 -135,6 +150,12 @@@ CREATE SCHEMA IF NOT EXISTS AUTHORIZATI The schema_element subcommands, if any, are executed in the order they are written. ++<<<<<<< ours + 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 useful. ++======= ++>>>>>>> theirs diff --cc src/backend/parser/parse_utilcmd.c index 37071502a9f,cb2e57610b2..00000000000 --- a/src/backend/parser/parse_utilcmd.c +++ b/src/backend/parser/parse_utilcmd.c @@@ -122,16 -122,11 +122,21 @@@ static void transformFKConstraints(Crea bool isAddConstraint); static void transformCheckConstraints(CreateStmtContext *cxt, bool skipValidation); -static void transformConstraintAttrs(CreateStmtContext *cxt, +static void transformConstraintAttrs(ParseState *pstate, List *constraintList); static void transformColumnType(CreateStmtContext *cxt, ColumnDef *column); ++<<<<<<< ours +static void checkSchemaNameRV(ParseState *pstate, const char *context_schema, + RangeVar *relation); +static void checkSchemaNameList(const char *context_schema, + List *qualified_name); +static CreateStmt *transformCreateSchemaCreateTable(ParseState *pstate, + CreateStmt *stmt, + List **fk_elements); ++======= + static void checkSchemaName(ParseState *pstate, const char *context_schema, + RangeVar *relation); ++>>>>>>> theirs static void transformPartitionCmd(CreateStmtContext *cxt, PartitionBoundSpec *bound); static List *transformPartitionRangeBounds(ParseState *pstate, List *blist, Relation parent); @@@ -4397,17 -4384,12 +4402,26 @@@ transformColumnType(CreateStmtContext * * transformCreateSchemaStmtElements - * analyzes the elements of a CREATE SCHEMA statement * ++<<<<<<< ours + * This presently has two responsibilities. We verify that no subcommands are + * trying to create objects outside the new schema. We also pull out any + * foreign-key constraint clauses embedded in CREATE TABLE subcommands, and + * convert them to ALTER TABLE ADD CONSTRAINT commands appended to the list. + * 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 impossible) + * 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 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. ++>>>>>>> theirs * * "schemaName" is the name of the schema that will be used for the creation * of the objects listed. It may be obtained from the schema name defined @@@ -4416,17 -4398,12 +4430,23 @@@ * 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. ++<<<<<<< ours + * + * Note it's important that we not modify the input data structure. We create + * a new result List, and we copy any CREATE TABLE subcommands that we might + * modify. ++======= ++>>>>>>> theirs */ List * transformCreateSchemaStmtElements(ParseState *pstate, List *schemaElts, const char *schemaName) { List *elements = NIL; ++<<<<<<< ours + List *fk_elements = NIL; ++======= ++>>>>>>> theirs ListCell *lc; /* @@@ -4443,7 -4420,7 +4463,11 @@@ { CreateSeqStmt *elp = (CreateSeqStmt *) element; ++<<<<<<< ours + checkSchemaNameRV(pstate, schemaName, elp->sequence); ++======= + checkSchemaName(pstate, schemaName, elp->sequence); ++>>>>>>> theirs elements = lappend(elements, element); } break; @@@ -4452,12 -4429,8 +4476,17 @@@ { CreateStmt *elp = (CreateStmt *) element; ++<<<<<<< ours + checkSchemaNameRV(pstate, schemaName, elp->relation); + /* Pull out any foreign key clauses, add to fk_elements */ + elp = transformCreateSchemaCreateTable(pstate, + elp, + &fk_elements); + elements = lappend(elements, elp); ++======= + checkSchemaName(pstate, schemaName, elp->relation); + elements = lappend(elements, element); ++>>>>>>> theirs } break; @@@ -4465,7 -4438,7 +4494,11 @@@ { ViewStmt *elp = (ViewStmt *) element; ++<<<<<<< ours + checkSchemaNameRV(pstate, schemaName, elp->view); ++======= + checkSchemaName(pstate, schemaName, elp->view); ++>>>>>>> theirs elements = lappend(elements, element); } break; @@@ -4474,7 -4447,7 +4507,11 @@@ { IndexStmt *elp = (IndexStmt *) element; ++<<<<<<< ours + checkSchemaNameRV(pstate, schemaName, elp->relation); ++======= + checkSchemaName(pstate, schemaName, elp->relation); ++>>>>>>> theirs elements = lappend(elements, element); } break; @@@ -4483,69 -4456,7 +4520,73 @@@ { CreateTrigStmt *elp = (CreateTrigStmt *) element; ++<<<<<<< ours + checkSchemaNameRV(pstate, schemaName, elp->relation); + elements = lappend(elements, element); + } + break; + + case T_CreateDomainStmt: + { + CreateDomainStmt *elp = (CreateDomainStmt *) element; + + checkSchemaNameList(schemaName, elp->domainname); + elements = lappend(elements, element); + } + break; + + case T_CreateFunctionStmt: + { + CreateFunctionStmt *elp = (CreateFunctionStmt *) element; + + checkSchemaNameList(schemaName, elp->funcname); + elements = 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 = (DefineStmt *) element; + + checkSchemaNameList(schemaName, elp->defnames); + elements = lappend(elements, element); + } + break; + + case T_CreateEnumStmt: + { + CreateEnumStmt *elp = (CreateEnumStmt *) element; + + checkSchemaNameList(schemaName, elp->typeName); + elements = lappend(elements, element); + } + break; + + case T_CreateRangeStmt: + { + CreateRangeStmt *elp = (CreateRangeStmt *) element; + + checkSchemaNameList(schemaName, elp->typeName); + elements = lappend(elements, element); + } + break; + + case T_CompositeTypeStmt: + { + CompositeTypeStmt *elp = (CompositeTypeStmt *) element; + + checkSchemaNameRV(pstate, schemaName, elp->typevar); ++======= + checkSchemaName(pstate, schemaName, elp->relation); ++>>>>>>> theirs elements = lappend(elements, element); } break; @@@ -4560,220 -4471,40 +4601,256 @@@ } } ++<<<<<<< ours + return list_concat(elements, fk_elements); +} + +/* + * checkSchemaNameRV + * Check schema name in an element of a CREATE SCHEMA command, + * where the element's name is given by a RangeVar + * + * 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 +checkSchemaNameRV(ParseState *pstate, const char *context_schema, + RangeVar *relation) +{ + if (relation->schemaname != NULL && + strcmp(context_schema, relation->schemaname) != 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))); + + 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))); + } +} + +/* + * 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 != NULL && + strcmp(context_schema, obj_schema) != 0) ++======= + return elements; + } + + /* + * 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 + checkSchemaName(ParseState *pstate, const char *context_schema, + RangeVar *relation) + { + if (relation->schemaname != NULL && + strcmp(context_schema, relation->schemaname) != 0) ++>>>>>>> theirs ereport(ERROR, (errcode(ERRCODE_INVALID_SCHEMA_DEFINITION), errmsg("CREATE specifies a schema (%s) " "different from the one being created (%s)", ++<<<<<<< ours + obj_schema, context_schema))); +} + +/* + * transformCreateSchemaCreateTable + * Process one CreateStmt for transformCreateSchemaStmtElements. + * + * We remove any foreign-key clauses in the statement and convert them into + * ALTER TABLE commands, which we append to *fk_elements. + */ +static CreateStmt * +transformCreateSchemaCreateTable(ParseState *pstate, + CreateStmt *stmt, + List **fk_elements) +{ + CreateStmt *newstmt; + List *newElts = NIL; + ListCell *lc; + + /* + * Flat-copy the CreateStmt node, allowing us to replace its tableElts + * list without damaging the input data structure. Most sub-nodes will be + * shared with the input, though. + */ + newstmt = makeNode(CreateStmt); + memcpy(newstmt, stmt, sizeof(CreateStmt)); + + /* Scan for foreign-key constraints */ + foreach(lc, stmt->tableElts) + { + Node *element = lfirst(lc); + AlterTableStmt *alterstmt; + AlterTableCmd *altercmd; + + if (IsA(element, Constraint)) + { + Constraint *constr = (Constraint *) element; + + if (constr->contype != CONSTR_FOREIGN) + { + /* Other constraint types pass through unchanged */ + newElts = lappend(newElts, constr); + continue; + } + + /* Make it into an ALTER TABLE ADD CONSTRAINT command */ + altercmd = makeNode(AlterTableCmd); + altercmd->subtype = AT_AddConstraint; + altercmd->name = NULL; + altercmd->def = (Node *) copyObject(constr); + + alterstmt = makeNode(AlterTableStmt); + alterstmt->relation = copyObject(stmt->relation); + alterstmt->cmds = list_make1(altercmd); + alterstmt->objtype = OBJECT_TABLE; + + *fk_elements = lappend(*fk_elements, alterstmt); + } + else if (IsA(element, ColumnDef)) + { + ColumnDef *entry = (ColumnDef *) element; + ColumnDef *newentry; + List *entryconstraints; + bool afterFK = false; + + /* + * We must preprocess the list of column constraints to attach + * attributes such as DEFERRED to the appropriate constraint node. + * Do this on a copy. (But execution of the CreateStmt will run + * transformConstraintAttrs on the copy, so we are nonetheless + * relying on transformConstraintAttrs to be idempotent.) + */ + entryconstraints = copyObject(entry->constraints); + transformConstraintAttrs(pstate, entryconstraints); + + /* Scan the column constraints ... */ + foreach_node(Constraint, colconstr, entryconstraints) + { + switch (colconstr->contype) + { + case CONSTR_FOREIGN: + /* colconstr is already a copy, OK to modify */ + colconstr->fk_attrs = list_make1(makeString(entry->colname)); + + /* Make it into an ALTER TABLE ADD CONSTRAINT command */ + altercmd = makeNode(AlterTableCmd); + altercmd->subtype = AT_AddConstraint; + altercmd->name = NULL; + altercmd->def = (Node *) colconstr; + + alterstmt = makeNode(AlterTableStmt); + alterstmt->relation = copyObject(stmt->relation); + alterstmt->cmds = list_make1(altercmd); + alterstmt->objtype = OBJECT_TABLE; + + *fk_elements = lappend(*fk_elements, alterstmt); + + /* Remove the Constraint node from entryconstraints */ + entryconstraints = + foreach_delete_current(entryconstraints, colconstr); + + /* + * Immediately-following attribute constraints should + * be dropped, too. + */ + afterFK = true; + break; + + /* + * Column constraint lists separate a Constraint node + * from its attributes (e.g. NOT ENFORCED); so a + * column-level foreign key constraint may be + * represented by multiple Constraint nodes. After + * transformConstraintAttrs, the foreign key + * Constraint node contains all required information, + * making it okay to put into *fk_elements as a + * stand-alone Constraint. But since we removed the + * foreign key Constraint node from entryconstraints, + * we must remove any dependent attribute nodes too, + * else the later re-execution of + * transformConstraintAttrs will misbehave. + */ + case CONSTR_ATTR_DEFERRABLE: + case CONSTR_ATTR_NOT_DEFERRABLE: + case CONSTR_ATTR_DEFERRED: + case CONSTR_ATTR_IMMEDIATE: + case CONSTR_ATTR_ENFORCED: + case CONSTR_ATTR_NOT_ENFORCED: + if (afterFK) + entryconstraints = + foreach_delete_current(entryconstraints, + colconstr); + break; + + default: + /* Any following constraint attributes are unrelated */ + afterFK = false; + break; + } + } + + /* Now make a modified ColumnDef to put into newElts */ + newentry = makeNode(ColumnDef); + memcpy(newentry, entry, sizeof(ColumnDef)); + newentry->constraints = entryconstraints; + newElts = lappend(newElts, newentry); + } + else + { + /* Other node types pass through unchanged */ + newElts = lappend(newElts, element); + } + } + + newstmt->tableElts = newElts; + return newstmt; ++======= + 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))); + } ++>>>>>>> theirs } /* diff --cc src/test/regress/expected/create_schema.out index bfe211338ab,4ab947a60a8..00000000000 --- a/src/test/regress/expected/create_schema.out +++ b/src/test/regress/expected/create_schema.out @@@ -32,10 -32,6 +32,13 @@@ CREATE SCHEMA AUTHORIZATION regress_cre 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... ^ ++<<<<<<< ours +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 the one being created (regress_create_schema_role) ++======= ++>>>>>>> theirs -- Again, with a role specification and no schema names. SET ROLE regress_create_schema_role; CREATE SCHEMA AUTHORIZATION CURRENT_ROLE diff --cc src/test/regress/expected/event_trigger.out index 065f586310f,4c32e1dcaf5..00000000000 --- a/src/test/regress/expected/event_trigger.out +++ b/src/test/regress/expected/event_trigger.out @@@ -431,7 -432,6 +431,10 @@@ NOTICE: END: command_tag=CREATE SEQUEN 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 VIEW type=view identity=evttrig.one_view ++<<<<<<< ours +NOTICE: END: command_tag=ALTER TABLE type=table identity=evttrig.two ++======= ++>>>>>>> theirs -- View with column additions CREATE OR REPLACE VIEW evttrig.one_view AS SELECT * FROM evttrig.two, evttrig.id; NOTICE: END: command_tag=CREATE VIEW type=view identity=evttrig.one_view