diff --git a/src/backend/commands/ddl_deparse.c b/src/backend/commands/ddl_deparse.c --- a/src/backend/commands/ddl_deparse.c +++ b/src/backend/commands/ddl_deparse.c @@ -796,7 +796,7 @@ */ static void deparse_ColumnDef(JsonbInState *state, Oid relid, List *dpcontext, - ColumnDef *coldef) + ColumnDef *coldef, const CollectedATSubcmd *sub) { HeapTuple attrTup; Form_pg_attribute attrForm; @@ -894,7 +894,15 @@ */ constraint = find_column_constraint(coldef, CONSTR_DEFAULT); if (constraint != NULL) - deparse_column_default(state, relid, attrForm->attnum, dpcontext); + { + if (sub != NULL && sub->default_expr_captured) + new_jsonb_string_clause(state, "default", " DEFAULT %{default_expr}s", + "default_expr", sub->default_expr != NULL ? + deparse_expression(sub->default_expr, dpcontext, false, false) : + "NULL"); + else + deparse_column_default(state, relid, attrForm->attnum, dpcontext); + } else new_jsonb_null(state, "default"); @@ -1668,7 +1676,7 @@ } if (raw != NULL) - deparse_ColumnDef(state, objectId, dpcontext, raw); + deparse_ColumnDef(state, objectId, dpcontext, raw, NULL); else deparse_ColumnDef_like(state, objectId, dpcontext, att); @@ -1713,7 +1721,7 @@ (ColumnDef *) elt); else deparse_ColumnDef(state, objectId, dpcontext, - (ColumnDef *) elt); + (ColumnDef *) elt, NULL); nelems++; break; @@ -2098,11 +2106,15 @@ * * Some subcommands (ADD/SET IDENTITY) are rewritten by parse analysis, with * their options split out into a separate internal ALTER SEQUENCE. The raw - * subcommand is what carries the clause as the user wrote it. + * subcommand is what carries the clause as the user wrote it. Matching + * occurrences are consumed in collection order, so repeated identity clauses + * for the same column do not all reuse the first raw clause. Their collected + * order follows their raw order; internally generated clauses and recursed + * children are filtered out before reaching this helper. */ static AlterTableCmd * find_raw_alter_column(AlterTableStmt *rawstmt, AlterTableType subtype, - const char *colname) + const char *colname, List **matched_cmds) { ListCell *lc; @@ -2112,8 +2124,12 @@ if (rawcmd->subtype == subtype && rawcmd->name != NULL && - strcmp(rawcmd->name, colname) == 0) + strcmp(rawcmd->name, colname) == 0 && + !list_member_ptr(*matched_cmds, rawcmd)) + { + *matched_cmds = lappend(*matched_cmds, rawcmd); return rawcmd; + } } elog(ERROR, "could not find raw ALTER COLUMN subcommand for column \"%s\"", @@ -2328,7 +2344,7 @@ static bool deparse_AlterTableSubcmd(JsonbInState *state, Oid relId, List *dpcontext, CollectedATSubcmd *sub, AlterTableCmd *subcmd, - AlterTableStmt *rawstmt, List *cmds) + AlterTableStmt *rawstmt, List *cmds, List **matched_cmds) { switch (subcmd->subtype) { @@ -2354,7 +2370,7 @@ new_jsonb_null(state, "if_not_exists"); insert_jsonb_key(state, "definition"); - deparse_ColumnDef(state, relId, dpcontext, rawcoldef); + deparse_ColumnDef(state, relId, dpcontext, rawcoldef, sub); end_jsonb_object(state); } return true; @@ -2399,9 +2415,13 @@ * Tolerate its absence and render it as written, as the * CREATE TABLE path does in deparse_column_default(). */ - defexpr = get_stored_default_expr(relId, - ((Form_pg_attribute) GETSTRUCT(atup))->attnum, - dpcontext, true); + if (sub->default_expr_captured) + defexpr = sub->default_expr != NULL ? + deparse_expression(sub->default_expr, dpcontext, false, false) : NULL; + else + defexpr = get_stored_default_expr(relId, + ((Form_pg_attribute) GETSTRUCT(atup))->attnum, + dpcontext, true); append_jsonb_pair2(state, "fmt", jbv_str("ALTER COLUMN %{column}I SET DEFAULT %{definition}s"), "column", jbv_str(subcmd->name)); @@ -2455,7 +2475,7 @@ */ AlterTableCmd *rawcmd = find_raw_alter_column(rawstmt, AT_AddIdentity, - subcmd->name); + subcmd->name, matched_cmds); Constraint *coldef = castNode(Constraint, rawcmd->def); begin_jsonb_object(state); @@ -2478,7 +2498,7 @@ */ AlterTableCmd *rawcmd = find_raw_alter_column(rawstmt, AT_SetIdentity, - subcmd->name); + subcmd->name, matched_cmds); ListCell *lc; begin_jsonb_object(state); @@ -3244,6 +3264,7 @@ List *dpcontext; int nsubcmds = 0; ListCell *cell; + List *matched_cmds = NIL; Assert(IsA(rawstmt, AlterTableStmt)); @@ -3252,7 +3273,12 @@ begin_jsonb_object(state); append_jsonb_pair1(state, "fmt", - jbv_str("ALTER TABLE%{only}s %{identity}D %{subcmds:, }s")); + jbv_str("ALTER TABLE%{if_exists}s%{only}s %{identity}D %{subcmds:, }s")); + + if (rawstmt->missing_ok) + new_jsonb_clause(state, "if_exists", " IF EXISTS"); + else + new_jsonb_null(state, "if_exists"); /* ONLY, from the raw statement */ if (!rawstmt->relation->inh) @@ -3329,7 +3355,7 @@ continue; if (deparse_AlterTableSubcmd(state, relId, dpcontext, sub, subcmd, - rawstmt, cmds)) + rawstmt, cmds, &matched_cmds)) nsubcmds++; } } @@ -3386,10 +3412,14 @@ case OBJECT_COLUMN: begin_jsonb_object(state); append_jsonb_pair3(state, - "fmt", jbv_str("ALTER TABLE%{only}s %{identity}D " + "fmt", jbv_str("ALTER TABLE%{if_exists}s%{only}s %{identity}D " "RENAME COLUMN %{oldname}I TO %{newname}I"), "oldname", jbv_str(node->subname), "newname", jbv_str(node->newname)); + if (node->missing_ok) + new_jsonb_clause(state, "if_exists", " IF EXISTS"); + else + new_jsonb_null(state, "if_exists"); if (!node->relation->inh) new_jsonb_clause(state, "only", " ONLY"); else @@ -3413,10 +3443,14 @@ begin_jsonb_object(state); append_jsonb_pair3(state, - "fmt", jbv_str("ALTER TABLE%{only}s %{identity}D " + "fmt", jbv_str("ALTER TABLE%{if_exists}s%{only}s %{identity}D " "RENAME CONSTRAINT %{oldname}I TO %{newname}I"), "oldname", jbv_str(node->subname), "newname", jbv_str(node->newname)); + if (node->missing_ok) + new_jsonb_clause(state, "if_exists", " IF EXISTS"); + else + new_jsonb_null(state, "if_exists"); if (!node->relation->inh) new_jsonb_clause(state, "only", " ONLY"); else @@ -3451,8 +3485,12 @@ begin_jsonb_object(state); append_jsonb_pair2(state, - "fmt", jbv_str("ALTER TABLE %{identity}D SET SCHEMA %{newschema}I"), + "fmt", jbv_str("ALTER TABLE%{if_exists}s %{identity}D SET SCHEMA %{newschema}I"), "newschema", jbv_str(node->newschema)); + if (node->missing_ok) + new_jsonb_clause(state, "if_exists", " IF EXISTS"); + else + new_jsonb_null(state, "if_exists"); new_jsonb_for_qualname(state, old_schema, get_rel_name(objectId), "identity", true); end_jsonb_object(state); diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c --- a/src/backend/commands/event_trigger.c +++ b/src/backend/commands/event_trigger.c @@ -1915,6 +1915,55 @@ newsub->address = address; newsub->parsetree = copyObject(subcmd); newsub->using_text = NULL; + newsub->default_expr_captured = false; + newsub->default_expr = NULL; + + /* + * Retain this subcommand's default before the next one can replace it. + * Collection precedes ATExecCmd's CommandCounterIncrement, so use + * SnapshotSelf to see catalog changes made by the current command. Do not + * read a domain's fallback default when an explicit NULL left no + * pg_attrdef row: a captured NULL represents DEFAULT NULL. + */ + if (address.classId == RelationRelationId && + OidIsValid(address.objectId) && address.objectSubId > 0 && + ((((const AlterTableCmd *) subcmd)->subtype == AT_ColumnDefault && + ((const AlterTableCmd *) subcmd)->def != NULL) || + (((const AlterTableCmd *) subcmd)->subtype == AT_AddColumn && + castNode(ColumnDef, ((const AlterTableCmd *) subcmd)->def)->raw_default != NULL && + !castNode(ColumnDef, ((const AlterTableCmd *) subcmd)->def)->generated))) + { + Relation attrdefrel; + ScanKeyData keys[2]; + SysScanDesc scan; + HeapTuple tuple; + + attrdefrel = table_open(AttrDefaultRelationId, AccessShareLock); + ScanKeyInit(&keys[0], Anum_pg_attrdef_adrelid, + BTEqualStrategyNumber, F_OIDEQ, + ObjectIdGetDatum(address.objectId)); + ScanKeyInit(&keys[1], Anum_pg_attrdef_adnum, + BTEqualStrategyNumber, F_INT2EQ, + Int16GetDatum(address.objectSubId)); + scan = systable_beginscan(attrdefrel, AttrDefaultIndexId, true, + SnapshotSelf, 2, keys); + tuple = systable_getnext(scan); + if (HeapTupleIsValid(tuple)) + { + Datum adbin; + bool isnull; + + adbin = heap_getattr(tuple, Anum_pg_attrdef_adbin, + RelationGetDescr(attrdefrel), &isnull); + if (isnull) + elog(ERROR, "null adbin for attribute %d of relation %u", + address.objectSubId, address.objectId); + newsub->default_expr = stringToNode(TextDatumGetCString(adbin)); + } + newsub->default_expr_captured = true; + systable_endscan(scan); + table_close(attrdefrel, AccessShareLock); + } /* * For ALTER COLUMN TYPE, attach the USING text rendered at prep time (if diff --git a/src/include/tcop/deparse_utility.h b/src/include/tcop/deparse_utility.h --- a/src/include/tcop/deparse_utility.h +++ b/src/include/tcop/deparse_utility.h @@ -46,6 +46,14 @@ * subcommand), or NULL. See EventTriggerCollectAlterColumnTypeUsing(). */ char *using_text; + + /* + * ADD COLUMN and SET DEFAULT must retain the expression in effect for + * this subcommand, before a later subcommand replaces it. A captured NULL + * expression represents an explicit DEFAULT NULL. + */ + bool default_expr_captured; + Node *default_expr; } CollectedATSubcmd; typedef struct CollectedCommand diff --git a/src/test/modules/test_ddl_deparse/expected/deparse_alter_table.out b/src/test/modules/test_ddl_deparse/expected/deparse_alter_table.out --- a/src/test/modules/test_ddl_deparse/expected/deparse_alter_table.out +++ b/src/test/modules/test_ddl_deparse/expected/deparse_alter_table.out @@ -115,6 +115,89 @@ NOTICE: DDL test: type alter table, tag ALTER TABLE NOTICE: subcommand: type DROP COLUMN (and recurse) desc column ........pg.dropped.2........ of table deparse_at.u2 NOTICE: subcommand: type ALTER COLUMN SET TYPE desc column a of table deparse_at.u2 +-- Repeated identity options must match successive raw subcommands, even when +-- they have the same column name and subtype. +CREATE TABLE deparse_at.id_repeat (a int GENERATED BY DEFAULT AS IDENTITY); +NOTICE: deparsed DDL: CREATE TABLE deparse_at.id_repeat (a pg_catalog.int4 GENERATED BY DEFAULT AS IDENTITY) +NOTICE: DDL test: type simple, tag CREATE SEQUENCE +NOTICE: DDL test: type simple, tag CREATE TABLE +NOTICE: DDL test: type simple, tag ALTER SEQUENCE +ALTER TABLE deparse_at.id_repeat + ALTER COLUMN a SET GENERATED ALWAYS, + ALTER COLUMN a SET GENERATED BY DEFAULT; +NOTICE: deparsed DDL: ALTER TABLE deparse_at.id_repeat ALTER COLUMN a SET GENERATED ALWAYS, ALTER COLUMN a SET GENERATED BY DEFAULT +NOTICE: DDL test: type simple, tag ALTER SEQUENCE +NOTICE: DDL test: type alter table, tag ALTER TABLE +NOTICE: subcommand: type SET IDENTITY (and recurse) desc column a of table deparse_at.id_repeat +NOTICE: DDL test: type simple, tag ALTER SEQUENCE +NOTICE: DDL test: type alter table, tag ALTER TABLE +NOTICE: subcommand: type SET IDENTITY (and recurse) desc column a of table deparse_at.id_repeat +SELECT attidentity FROM pg_attribute + WHERE attrelid = 'deparse_at.id_repeat'::regclass AND attname = 'a'; + attidentity +------------- + d +(1 row) + +ALTER TABLE deparse_at.id_repeat + ALTER COLUMN a SET INCREMENT BY 3, + ALTER COLUMN a SET INCREMENT BY 7; +NOTICE: deparsed DDL: ALTER TABLE deparse_at.id_repeat ALTER COLUMN a SET INCREMENT BY 3, ALTER COLUMN a SET INCREMENT BY 7 +NOTICE: DDL test: type simple, tag ALTER SEQUENCE +NOTICE: DDL test: type alter table, tag ALTER TABLE +NOTICE: subcommand: type SET IDENTITY (and recurse) desc +NOTICE: DDL test: type simple, tag ALTER SEQUENCE +NOTICE: DDL test: type alter table, tag ALTER TABLE +NOTICE: subcommand: type SET IDENTITY (and recurse) desc +SELECT seqincrement FROM pg_sequence + WHERE seqrelid = 'deparse_at.id_repeat_a_seq'::regclass; + seqincrement +-------------- + 7 +(1 row) + +-- Each default belongs to its own subcommand. Existing rows receive the ADD +-- COLUMN default, while subsequent inserts receive the later SET DEFAULT. +CREATE TABLE deparse_at.defaults (a int); +NOTICE: deparsed DDL: CREATE TABLE deparse_at.defaults (a pg_catalog.int4) +NOTICE: DDL test: type simple, tag CREATE TABLE +INSERT INTO deparse_at.defaults VALUES (1); +ALTER TABLE deparse_at.defaults + ADD COLUMN b int DEFAULT 1, + ALTER COLUMN b SET DEFAULT 2; +NOTICE: deparsed DDL: ALTER TABLE deparse_at.defaults ADD COLUMN b pg_catalog.int4 DEFAULT 1, ALTER COLUMN b SET DEFAULT 2 +NOTICE: DDL test: type alter table, tag ALTER TABLE +NOTICE: subcommand: type ADD COLUMN (and recurse) desc column b of table deparse_at.defaults +NOTICE: subcommand: type ALTER COLUMN SET DEFAULT desc column b of table deparse_at.defaults +INSERT INTO deparse_at.defaults (a) VALUES (2); +SELECT * FROM deparse_at.defaults ORDER BY a; + a | b +---+--- + 1 | 1 + 2 | 2 +(2 rows) + +ALTER TABLE deparse_at.defaults + ALTER COLUMN b SET DEFAULT 3, + ALTER COLUMN b SET DEFAULT 4; +NOTICE: deparsed DDL: ALTER TABLE deparse_at.defaults ALTER COLUMN b SET DEFAULT 3, ALTER COLUMN b SET DEFAULT 4 +NOTICE: DDL test: type alter table, tag ALTER TABLE +NOTICE: subcommand: type ALTER COLUMN SET DEFAULT desc column b of table deparse_at.defaults +NOTICE: subcommand: type ALTER COLUMN SET DEFAULT desc column b of table deparse_at.defaults +ALTER TABLE deparse_at.defaults + ALTER COLUMN b SET DEFAULT NULL, + ALTER COLUMN b SET DEFAULT 5; +NOTICE: deparsed DDL: ALTER TABLE deparse_at.defaults ALTER COLUMN b SET DEFAULT NULL, ALTER COLUMN b SET DEFAULT 5 +NOTICE: DDL test: type alter table, tag ALTER TABLE +NOTICE: subcommand: type ALTER COLUMN SET DEFAULT desc column b of table deparse_at.defaults +NOTICE: subcommand: type ALTER COLUMN SET DEFAULT desc column b of table deparse_at.defaults +ALTER TABLE deparse_at.defaults + ALTER COLUMN b SET DEFAULT 6, + ALTER COLUMN b DROP DEFAULT; +NOTICE: deparsed DDL: ALTER TABLE deparse_at.defaults ALTER COLUMN b DROP DEFAULT, ALTER COLUMN b SET DEFAULT 6 +NOTICE: DDL test: type alter table, tag ALTER TABLE +NOTICE: subcommand: type ALTER COLUMN SET DEFAULT desc column b of table deparse_at.defaults +NOTICE: subcommand: type ALTER COLUMN SET DEFAULT desc column b of table deparse_at.defaults -- SET STATISTICS by column number, for an unnamed expression column of an -- index reached via ALTER TABLE naming that index. The subcommand carries -- the column position instead of a name. The core tests reach such a column @@ -193,14 +276,57 @@ NOTICE: deparsed DDL: ALTER TABLE deparse_at.tr ENABLE ALWAYS RULE trg_rule NOTICE: DDL test: type alter table, tag ALTER TABLE NOTICE: subcommand: type ENABLE RULE (always) desc +-- Table-level IF EXISTS must survive reconstruction in each supported ALTER +-- form. ONLY follows IF EXISTS where both clauses are allowed. +CREATE TABLE deparse_at.guarded (a int CONSTRAINT guarded_check CHECK (a > 0)); +NOTICE: deparsed DDL: CREATE TABLE deparse_at.guarded (a pg_catalog.int4, CONSTRAINT guarded_check CHECK ((a > 0))) +NOTICE: DDL test: type simple, tag CREATE TABLE +ALTER TABLE IF EXISTS ONLY deparse_at.guarded ADD COLUMN b int; +NOTICE: deparsed DDL: ALTER TABLE IF EXISTS ONLY deparse_at.guarded ADD COLUMN b pg_catalog.int4 +NOTICE: DDL test: type alter table, tag ALTER TABLE +NOTICE: subcommand: type ADD COLUMN desc column b of table deparse_at.guarded +ALTER TABLE IF EXISTS ONLY deparse_at.guarded RENAME COLUMN b TO c; +NOTICE: deparsed DDL: ALTER TABLE IF EXISTS ONLY deparse_at.guarded RENAME COLUMN b TO c +NOTICE: DDL test: type simple, tag ALTER TABLE +ALTER TABLE IF EXISTS ONLY deparse_at.guarded + RENAME CONSTRAINT guarded_check TO renamed_check; +NOTICE: deparsed DDL: ALTER TABLE IF EXISTS ONLY deparse_at.guarded RENAME CONSTRAINT guarded_check TO renamed_check +NOTICE: DDL test: type simple, tag ALTER TABLE +ALTER TABLE IF EXISTS deparse_at.guarded RENAME TO guarded_renamed; +NOTICE: deparsed DDL: ALTER TABLE IF EXISTS deparse_at.guarded RENAME TO guarded_renamed +NOTICE: DDL test: type simple, tag ALTER TABLE +CREATE SCHEMA deparse_guard; +NOTICE: DDL test: type simple, tag CREATE SCHEMA +ALTER TABLE IF EXISTS deparse_at.guarded_renamed SET SCHEMA deparse_guard; +NOTICE: deparsed DDL: ALTER TABLE IF EXISTS deparse_at.guarded_renamed SET SCHEMA deparse_guard +NOTICE: DDL test: type simple, tag ALTER TABLE +SELECT column_name FROM information_schema.columns + WHERE table_schema = 'deparse_guard' AND table_name = 'guarded_renamed' + ORDER BY ordinal_position; + column_name +------------- + a + c +(2 rows) + +DROP TABLE deparse_guard.guarded_renamed; +DROP SCHEMA deparse_guard; -- IF EXISTS on a missing table is a no-op: nothing is collected, so there is -- nothing to deparse and no warning. ALTER TABLE IF EXISTS deparse_at.nonesuch ADD COLUMN z int; NOTICE: relation "nonesuch" does not exist, skipping +ALTER TABLE IF EXISTS deparse_at.nonesuch RENAME COLUMN a TO b; +NOTICE: relation "nonesuch" does not exist, skipping +ALTER TABLE IF EXISTS deparse_at.nonesuch RENAME CONSTRAINT c TO d; +NOTICE: relation "nonesuch" does not exist, skipping +ALTER TABLE IF EXISTS deparse_at.nonesuch RENAME TO other; +NOTICE: relation "nonesuch" does not exist, skipping +ALTER TABLE IF EXISTS deparse_at.nonesuch SET SCHEMA public; +NOTICE: relation "nonesuch" does not exist, skipping RESET test_ddl_deparse.print_deparsed_ddl; RESET test_ddl_deparse.execute_deparsed_ddl; DROP SCHEMA deparse_at CASCADE; -NOTICE: drop cascades to 13 other objects +NOTICE: drop cascades to 15 other objects DETAIL: drop cascades to table deparse_at.t drop cascades to table deparse_at.con drop cascades to table deparse_at.ref @@ -209,6 +335,8 @@ drop cascades to table deparse_at.nnmc drop cascades to table deparse_at.u drop cascades to table deparse_at.u2 +drop cascades to table deparse_at.id_repeat +drop cascades to table deparse_at.defaults drop cascades to table deparse_at.ei drop cascades to table deparse_at.ui3 drop cascades to table deparse_at.cl diff --git a/src/test/modules/test_ddl_deparse/sql/deparse_alter_table.sql b/src/test/modules/test_ddl_deparse/sql/deparse_alter_table.sql --- a/src/test/modules/test_ddl_deparse/sql/deparse_alter_table.sql +++ b/src/test/modules/test_ddl_deparse/sql/deparse_alter_table.sql @@ -62,6 +62,39 @@ INSERT INTO deparse_at.u2 VALUES (1, 42); ALTER TABLE deparse_at.u2 DROP COLUMN b, ALTER COLUMN a TYPE text USING b::text; +-- Repeated identity options must match successive raw subcommands, even when +-- they have the same column name and subtype. +CREATE TABLE deparse_at.id_repeat (a int GENERATED BY DEFAULT AS IDENTITY); +ALTER TABLE deparse_at.id_repeat + ALTER COLUMN a SET GENERATED ALWAYS, + ALTER COLUMN a SET GENERATED BY DEFAULT; +SELECT attidentity FROM pg_attribute + WHERE attrelid = 'deparse_at.id_repeat'::regclass AND attname = 'a'; +ALTER TABLE deparse_at.id_repeat + ALTER COLUMN a SET INCREMENT BY 3, + ALTER COLUMN a SET INCREMENT BY 7; +SELECT seqincrement FROM pg_sequence + WHERE seqrelid = 'deparse_at.id_repeat_a_seq'::regclass; + +-- Each default belongs to its own subcommand. Existing rows receive the ADD +-- COLUMN default, while subsequent inserts receive the later SET DEFAULT. +CREATE TABLE deparse_at.defaults (a int); +INSERT INTO deparse_at.defaults VALUES (1); +ALTER TABLE deparse_at.defaults + ADD COLUMN b int DEFAULT 1, + ALTER COLUMN b SET DEFAULT 2; +INSERT INTO deparse_at.defaults (a) VALUES (2); +SELECT * FROM deparse_at.defaults ORDER BY a; +ALTER TABLE deparse_at.defaults + ALTER COLUMN b SET DEFAULT 3, + ALTER COLUMN b SET DEFAULT 4; +ALTER TABLE deparse_at.defaults + ALTER COLUMN b SET DEFAULT NULL, + ALTER COLUMN b SET DEFAULT 5; +ALTER TABLE deparse_at.defaults + ALTER COLUMN b SET DEFAULT 6, + ALTER COLUMN b DROP DEFAULT; + -- SET STATISTICS by column number, for an unnamed expression column of an -- index reached via ALTER TABLE naming that index. The subcommand carries -- the column position instead of a name. The core tests reach such a column @@ -99,9 +132,29 @@ ALTER TABLE deparse_at.tr ENABLE TRIGGER USER; ALTER TABLE deparse_at.tr ENABLE ALWAYS RULE trg_rule; +-- Table-level IF EXISTS must survive reconstruction in each supported ALTER +-- form. ONLY follows IF EXISTS where both clauses are allowed. +CREATE TABLE deparse_at.guarded (a int CONSTRAINT guarded_check CHECK (a > 0)); +ALTER TABLE IF EXISTS ONLY deparse_at.guarded ADD COLUMN b int; +ALTER TABLE IF EXISTS ONLY deparse_at.guarded RENAME COLUMN b TO c; +ALTER TABLE IF EXISTS ONLY deparse_at.guarded + RENAME CONSTRAINT guarded_check TO renamed_check; +ALTER TABLE IF EXISTS deparse_at.guarded RENAME TO guarded_renamed; +CREATE SCHEMA deparse_guard; +ALTER TABLE IF EXISTS deparse_at.guarded_renamed SET SCHEMA deparse_guard; +SELECT column_name FROM information_schema.columns + WHERE table_schema = 'deparse_guard' AND table_name = 'guarded_renamed' + ORDER BY ordinal_position; +DROP TABLE deparse_guard.guarded_renamed; +DROP SCHEMA deparse_guard; + -- IF EXISTS on a missing table is a no-op: nothing is collected, so there is -- nothing to deparse and no warning. ALTER TABLE IF EXISTS deparse_at.nonesuch ADD COLUMN z int; +ALTER TABLE IF EXISTS deparse_at.nonesuch RENAME COLUMN a TO b; +ALTER TABLE IF EXISTS deparse_at.nonesuch RENAME CONSTRAINT c TO d; +ALTER TABLE IF EXISTS deparse_at.nonesuch RENAME TO other; +ALTER TABLE IF EXISTS deparse_at.nonesuch SET SCHEMA public; RESET test_ddl_deparse.print_deparsed_ddl; RESET test_ddl_deparse.execute_deparsed_ddl;