pgsql-fix-inherit-rename.4.patch
application/octect-stream
Filename: pgsql-fix-inherit-rename.4.patch
Type: application/octect-stream
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: context
| File | + | − |
|---|---|---|
| src/backend/catalog/pg_inherits.c | 62 | 0 |
| src/backend/commands/tablecmds.c | 19 | 0 |
| src/include/catalog/pg_inherits_fn.h | 1 | 0 |
| src/test/regress/expected/inherit.out | 78 | 0 |
| src/test/regress/sql/inherit.sql | 36 | 0 |
*** a/src/backend/catalog/pg_inherits.c
--- b/src/backend/catalog/pg_inherits.c
***************
*** 28,33 ****
--- 28,34 ----
#include "parser/parse_type.h"
#include "storage/lmgr.h"
#include "utils/fmgroids.h"
+ #include "utils/lsyscache.h"
#include "utils/syscache.h"
#include "utils/tqual.h"
***************
*** 190,195 **** find_all_inheritors(Oid parentrelId, LOCKMODE lockmode)
--- 191,257 ----
return rels_list;
}
+ /*
+ * find_column_origin
+ *
+ * It returns a list of relation OIDs that defines the given column originally.
+ * In most cases, a certain column has one origin, unless it (or its parent)
+ * has multiple inheritance tree.
+ * Note that it returns a unique OID for diamond-type inheritance tree, because
+ * it shares same origin.
+ */
+ List *
+ find_column_origin(Oid relOid, const char *colName)
+ {
+ Relation inhRel;
+ SysScanDesc scan;
+ ScanKeyData skey[1];
+ HeapTuple tuple;
+ List *results = NIL;
+
+ /*
+ * This relation does not contain the given column, is also means
+ * the parent relation also.
+ */
+ if (get_attnum(relOid, colName) == InvalidAttrNumber)
+ return NIL;
+
+ inhRel = heap_open(InheritsRelationId, AccessShareLock);
+
+ ScanKeyInit(&skey[0],
+ Anum_pg_inherits_inhrelid,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(relOid));
+
+ scan = systable_beginscan(inhRel, InheritsRelidSeqnoIndexId,
+ true, SnapshotNow, 1, &skey);
+
+ while (HeapTupleIsValid(tuple = systable_getnext(scan)))
+ {
+ Form_pg_inherits inhForm = (Form_pg_inherits) GETSTRUCT(tuple);
+ List *temp;
+
+ temp = find_column_origin(inhForm->inhparent, colName);
+ if (temp == NIL)
+ continue;
+
+ /*
+ * Add to the queue only those children not already seen. This avoids
+ * making duplicate entries in case of multiple inheritance paths from
+ * the same parent. (It'll also keep us from getting into an infinite
+ * loop, though theoretically there can't be any cycles in the
+ * inheritance graph anyway.)
+ */
+ results = list_concat_unique_oid(results, temp);
+ }
+ systable_endscan(scan);
+ heap_close(inhRel, AccessShareLock);
+
+ if (results == NIL)
+ results = list_make1_oid(relOid);
+
+ return results;
+ }
/*
* has_subclass - does this relation have any children?
*** a/src/backend/commands/tablecmds.c
--- b/src/backend/commands/tablecmds.c
***************
*** 2009,2014 **** renameatt(Oid myrelid,
--- 2009,2025 ----
errmsg("cannot rename inherited column \"%s\"",
oldattname)));
+ /*
+ * if the attribute is multiple inherited, forbid the renaming,
+ * even if we are already inside a recursive rename, because we
+ * have no reasonable way to keep its integrity.
+ */
+ if (list_length(find_column_origin(myrelid, oldattname)) > 1)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
+ (errmsg("cannot rename multiple inherited column \"%s\"",
+ oldattname))));
+
/* new name should not already exist */
/* this test is deliberately not attisdropped-aware */
***************
*** 5771,5776 **** ATPrepAlterColumnType(List **wqueue,
--- 5782,5788 ----
bool recurse, bool recursing,
AlterTableCmd *cmd)
{
+ Oid relOid = RelationGetRelid(rel);
char *colName = cmd->name;
TypeName *typeName = (TypeName *) cmd->def;
HeapTuple tuple;
***************
*** 5806,5811 **** ATPrepAlterColumnType(List **wqueue,
--- 5818,5830 ----
errmsg("cannot alter inherited column \"%s\"",
colName)));
+ /* Don't alter multiple inherited columns */
+ if (list_length(find_column_origin(relOid, colName)) > 1)
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
+ (errmsg("cannot alter multiple inherited column \"%s\"",
+ colName))));
+
/* Look up the target type */
targettype = typenameTypeId(NULL, typeName, &targettypmod);
*** a/src/include/catalog/pg_inherits_fn.h
--- b/src/include/catalog/pg_inherits_fn.h
***************
*** 19,24 ****
--- 19,25 ----
extern List *find_inheritance_children(Oid parentrelId, LOCKMODE lockmode);
extern List *find_all_inheritors(Oid parentrelId, LOCKMODE lockmode);
+ extern List *find_column_origin(Oid relOid, const char *colName);
extern bool has_subclass(Oid relationId);
extern bool typeInheritsFrom(Oid subclassTypeId, Oid superclassTypeId);
*** a/src/test/regress/expected/inherit.out
--- b/src/test/regress/expected/inherit.out
***************
*** 1053,1055 **** NOTICE: merging column "a" with inherited definition
--- 1053,1133 ----
ERROR: column "a" has a storage parameter conflict
DETAIL: MAIN versus EXTENDED
DROP TABLE t1, t2, t3, t4, t12_storage, t12_comments, t1_inh, t13_inh, t13_like, t_all;
+ -- Test for renaming and type changes (simple multiple inheritance)
+ CREATE TABLE t1 (a int, b int);
+ CREATE TABLE s1 (b int, c int);
+ CREATE TABLE ts (d int) INHERITS (t1, s1);
+ NOTICE: merging multiple inherited definitions of column "b"
+ ALTER TABLE s1 ALTER b TYPE float; -- to be failed
+ ERROR: cannot alter multiple inherited column "b"
+ ALTER TABLE s1 ALTER c TYPE float;
+ ALTER TABLE ts ALTER c TYPE text; -- to be failed
+ ERROR: cannot alter inherited column "c"
+ ALTER TABLE ts ALTER d TYPE text;
+ ALTER TABLE t1 RENAME a TO aa;
+ ALTER TABLE t1 RENAME b TO bb; -- to be failed
+ ERROR: cannot rename multiple inherited column "b"
+ ALTER TABLE ts RENAME aa TO aaa; -- to be failed
+ ERROR: cannot rename inherited column "aa"
+ ALTER TABLE ts RENAME d TO dd;
+ \d+ ts
+ Table "public.ts"
+ Column | Type | Modifiers | Storage | Description
+ --------+------------------+-----------+----------+-------------
+ aa | integer | | plain |
+ b | integer | | plain |
+ c | double precision | | plain |
+ dd | text | | extended |
+ Inherits: t1,
+ s1
+ Has OIDs: no
+
+ DROP TABLE ts;
+ -- Test for renaming and type changes (diamond inheritance)
+ CREATE TABLE t2 (x int) INHERITS (t1);
+ CREATE TABLE t3 (y int) INHERITS (t1);
+ CREATE TABLE t4 (z int) INHERITS (t2, t3);
+ NOTICE: merging multiple inherited definitions of column "aa"
+ NOTICE: merging multiple inherited definitions of column "b"
+ ALTER TABLE t1 ALTER aa TYPE float;
+ ALTER TABLE t1 RENAME aa TO aaa;
+ \d+ t4
+ Table "public.t4"
+ Column | Type | Modifiers | Storage | Description
+ --------+------------------+-----------+---------+-------------
+ aaa | double precision | | plain |
+ b | integer | | plain |
+ x | integer | | plain |
+ y | integer | | plain |
+ z | integer | | plain |
+ Inherits: t2,
+ t3
+ Has OIDs: no
+
+ CREATE TABLE ts (d int) INHERITS (t2, s1);
+ NOTICE: merging multiple inherited definitions of column "b"
+ ALTER TABLE t1 ALTER aaa TYPE text;
+ ALTER TABLE t1 ALTER b TYPE text; -- to be failed
+ ERROR: cannot alter multiple inherited column "b"
+ ALTER TABLE t1 RENAME aaa TO aaaa;
+ ALTER TABLE t1 RENAME b TO bb; -- to be failed
+ ERROR: cannot rename multiple inherited column "b"
+ \d+ ts
+ Table "public.ts"
+ Column | Type | Modifiers | Storage | Description
+ --------+------------------+-----------+----------+-------------
+ aaaa | text | | extended |
+ b | integer | | plain |
+ x | integer | | plain |
+ c | double precision | | plain |
+ d | integer | | plain |
+ Inherits: t2,
+ s1
+ Has OIDs: no
+
+ DROP TABLE t1, s1 CASCADE;
+ NOTICE: drop cascades to 4 other objects
+ DETAIL: drop cascades to table t2
+ drop cascades to table ts
+ drop cascades to table t3
+ drop cascades to table t4
*** a/src/test/regress/sql/inherit.sql
--- b/src/test/regress/sql/inherit.sql
***************
*** 334,336 **** CREATE TABLE inh_error1 () INHERITS (t1, t4);
--- 334,372 ----
CREATE TABLE inh_error2 (LIKE t4 INCLUDING STORAGE) INHERITS (t1);
DROP TABLE t1, t2, t3, t4, t12_storage, t12_comments, t1_inh, t13_inh, t13_like, t_all;
+
+ -- Test for renaming and type changes (simple multiple inheritance)
+ CREATE TABLE t1 (a int, b int);
+ CREATE TABLE s1 (b int, c int);
+ CREATE TABLE ts (d int) INHERITS (t1, s1);
+
+ ALTER TABLE s1 ALTER b TYPE float; -- to be failed
+ ALTER TABLE s1 ALTER c TYPE float;
+ ALTER TABLE ts ALTER c TYPE text; -- to be failed
+ ALTER TABLE ts ALTER d TYPE text;
+
+ ALTER TABLE t1 RENAME a TO aa;
+ ALTER TABLE t1 RENAME b TO bb; -- to be failed
+ ALTER TABLE ts RENAME aa TO aaa; -- to be failed
+ ALTER TABLE ts RENAME d TO dd;
+ \d+ ts
+
+ DROP TABLE ts;
+
+ -- Test for renaming and type changes (diamond inheritance)
+ CREATE TABLE t2 (x int) INHERITS (t1);
+ CREATE TABLE t3 (y int) INHERITS (t1);
+ CREATE TABLE t4 (z int) INHERITS (t2, t3);
+
+ ALTER TABLE t1 ALTER aa TYPE float;
+ ALTER TABLE t1 RENAME aa TO aaa;
+ \d+ t4
+
+ CREATE TABLE ts (d int) INHERITS (t2, s1);
+ ALTER TABLE t1 ALTER aaa TYPE text;
+ ALTER TABLE t1 ALTER b TYPE text; -- to be failed
+ ALTER TABLE t1 RENAME aaa TO aaaa;
+ ALTER TABLE t1 RENAME b TO bb; -- to be failed
+ \d+ ts
+
+ DROP TABLE t1, s1 CASCADE;