Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitcd07163

Browse files
committed
Reject attempts to alter composite types used in indexes.
find_composite_type_dependencies() ignored indexes, which is a poordecision because an expression index could have a stored column ofa composite (or other container) type even when the underlying tabledoes not. Teach it to detect such cases and error out. We have towork a bit harder than for other relations because the pg_depend entrywon't identify the specific index column of concern, but it's not muchnew code.This does not address bug #17872's original complaint that droppinga column in such a type might lead to violations of the uniquenessproperty that a unique index is supposed to ensure. That seems ofmuch less concern to me because it won't lead to crashes.Per bug #17872 from Alexander Lakhin. Back-patch to all supportedbranches.Discussion:https://postgr.es/m/17872-d0fbb799dc3fd85d@postgresql.org
1 parentad5fe74 commitcd07163

File tree

3 files changed

+68
-10
lines changed

3 files changed

+68
-10
lines changed

‎src/backend/commands/tablecmds.c

Lines changed: 49 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5680,6 +5680,7 @@ find_composite_type_dependencies(Oid typeOid, Relation origRelation,
56805680
{
56815681
Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
56825682
Relationrel;
5683+
TupleDesctupleDesc;
56835684
Form_pg_attribute att;
56845685

56855686
/* Check for directly dependent types */
@@ -5696,18 +5697,58 @@ find_composite_type_dependencies(Oid typeOid, Relation origRelation,
56965697
continue;
56975698
}
56985699

5699-
/* Else, ignore dependees that aren't user columns of relations */
5700-
/* (we assume system columns are never of interesting types) */
5701-
if (pg_depend->classid != RelationRelationId ||
5702-
pg_depend->objsubid <= 0)
5700+
/* Else, ignore dependees that aren't relations */
5701+
if (pg_depend->classid != RelationRelationId)
57035702
continue;
57045703

57055704
rel = relation_open(pg_depend->objid, AccessShareLock);
5706-
att =TupleDescAttr(rel->rd_att, pg_depend->objsubid - 1);
5705+
tupleDesc =RelationGetDescr(rel);
57075706

5708-
if (rel->rd_rel->relkind == RELKIND_RELATION ||
5709-
rel->rd_rel->relkind == RELKIND_MATVIEW ||
5710-
rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
5707+
/*
5708+
* If objsubid identifies a specific column, refer to that in error
5709+
* messages. Otherwise, search to see if there's a user column of the
5710+
* type. (We assume system columns are never of interesting types.)
5711+
* The search is needed because an index containing an expression
5712+
* column of the target type will just be recorded as a whole-relation
5713+
* dependency. If we do not find a column of the type, the dependency
5714+
* must indicate that the type is transiently referenced in an index
5715+
* expression but not stored on disk, which we assume is OK, just as
5716+
* we do for references in views. (It could also be that the target
5717+
* type is embedded in some container type that is stored in an index
5718+
* column, but the previous recursion should catch such cases.)
5719+
*/
5720+
if (pg_depend->objsubid > 0 && pg_depend->objsubid <= tupleDesc->natts)
5721+
att = TupleDescAttr(tupleDesc, pg_depend->objsubid - 1);
5722+
else
5723+
{
5724+
att = NULL;
5725+
for (int attno = 1; attno <= tupleDesc->natts; attno++)
5726+
{
5727+
att = TupleDescAttr(tupleDesc, attno - 1);
5728+
if (att->atttypid == typeOid && !att->attisdropped)
5729+
break;
5730+
att = NULL;
5731+
}
5732+
if (att == NULL)
5733+
{
5734+
/* No such column, so assume OK */
5735+
relation_close(rel, AccessShareLock);
5736+
continue;
5737+
}
5738+
}
5739+
5740+
/*
5741+
* We definitely should reject if the relation has storage. If it's
5742+
* partitioned, then perhaps we don't have to reject: if there are
5743+
* partitions then we'll fail when we find one, else there is no
5744+
* stored data to worry about. However, it's possible that the type
5745+
* change would affect conclusions about whether the type is sortable
5746+
* or hashable and thus (if it's a partitioning column) break the
5747+
* partitioning rule. For now, reject for partitioned rels too.
5748+
*/
5749+
if (RELKIND_HAS_STORAGE(rel->rd_rel->relkind) ||
5750+
rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE ||
5751+
rel->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
57115752
{
57125753
if (origTypeName)
57135754
ereport(ERROR,

‎src/test/regress/expected/alter_table.out

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3082,6 +3082,13 @@ CREATE TYPE test_type1 AS (a int, b text);
30823082
CREATE TABLE test_tbl1 (x int, y test_type1);
30833083
ALTER TYPE test_type1 ALTER ATTRIBUTE b TYPE varchar; -- fails
30843084
ERROR: cannot alter type "test_type1" because column "test_tbl1.y" uses it
3085+
DROP TABLE test_tbl1;
3086+
CREATE TABLE test_tbl1 (x int, y text);
3087+
CREATE INDEX test_tbl1_idx ON test_tbl1((row(x,y)::test_type1));
3088+
ALTER TYPE test_type1 ALTER ATTRIBUTE b TYPE varchar; -- fails
3089+
ERROR: cannot alter type "test_type1" because column "test_tbl1_idx.row" uses it
3090+
DROP TABLE test_tbl1;
3091+
DROP TYPE test_type1;
30853092
CREATE TYPE test_type2 AS (a int, b text);
30863093
CREATE TABLE test_tbl2 OF test_type2;
30873094
CREATE TABLE test_tbl2_subclass () INHERITS (test_tbl2);
@@ -3193,7 +3200,8 @@ Typed table of type: test_type2
31933200
c | text | | |
31943201
Inherits: test_tbl2
31953202

3196-
DROP TABLE test_tbl2_subclass;
3203+
DROP TABLE test_tbl2_subclass, test_tbl2;
3204+
DROP TYPE test_type2;
31973205
CREATE TYPE test_typex AS (a int, b text);
31983206
CREATE TABLE test_tblx (x int, y test_typex check ((y).a > 0));
31993207
ALTER TYPE test_typex DROP ATTRIBUTE a; -- fails

‎src/test/regress/sql/alter_table.sql

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1971,6 +1971,14 @@ CREATE TYPE test_type1 AS (a int, b text);
19711971
CREATETABLEtest_tbl1 (xint, y test_type1);
19721972
ALTERTYPE test_type1 ALTER ATTRIBUTE b TYPEvarchar;-- fails
19731973

1974+
DROPTABLE test_tbl1;
1975+
CREATETABLEtest_tbl1 (xint, ytext);
1976+
CREATEINDEXtest_tbl1_idxON test_tbl1((row(x,y)::test_type1));
1977+
ALTERTYPE test_type1 ALTER ATTRIBUTE b TYPEvarchar;-- fails
1978+
1979+
DROPTABLE test_tbl1;
1980+
DROPTYPE test_type1;
1981+
19741982
CREATETYPEtest_type2AS (aint, btext);
19751983
CREATETABLEtest_tbl2 OF test_type2;
19761984
CREATETABLEtest_tbl2_subclass () INHERITS (test_tbl2);
@@ -1998,7 +2006,8 @@ ALTER TYPE test_type2 RENAME ATTRIBUTE a TO aa CASCADE;
19982006
\d test_tbl2
19992007
\d test_tbl2_subclass
20002008

2001-
DROPTABLE test_tbl2_subclass;
2009+
DROPTABLE test_tbl2_subclass, test_tbl2;
2010+
DROPTYPE test_type2;
20022011

20032012
CREATETYPEtest_typexAS (aint, btext);
20042013
CREATETABLEtest_tblx (xint, y test_typexcheck ((y).a>0));

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp