Skip to content

Commit bf797a8

Browse files
committed
Disallow ALTER TABLE ONLY / DROP EXPRESSION
The current implementation cannot handle this correctly, so just forbid it for now. GENERATED clauses must be attached to the column definition and cannot be added later like DEFAULT, so if a child table has a generation expression that the parent does not have, the child column will necessarily be an attlocal column. So to implement ALTER TABLE ONLY / DROP EXPRESSION, we'd need extra code to update attislocal of the direct child tables, somewhat similar to how DROP COLUMN does it, so that the resulting state can be properly dumped and restored. Discussion: https://www.postgresql.org/message-id/flat/15830.1575468847%40sss.pgh.pa.us
1 parent 2f70fdb commit bf797a8

File tree

3 files changed

+26
-9
lines changed

3 files changed

+26
-9
lines changed

src/backend/commands/tablecmds.c

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -413,7 +413,7 @@ static ObjectAddress ATExecAddIdentity(Relation rel, const char *colName,
413413
static ObjectAddress ATExecSetIdentity(Relation rel, const char *colName,
414414
Node *def, LOCKMODE lockmode);
415415
static ObjectAddress ATExecDropIdentity(Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode);
416-
static void ATPrepDropExpression(Relation rel, AlterTableCmd *cmd, bool recursing);
416+
static void ATPrepDropExpression(Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode);
417417
static ObjectAddress ATExecDropExpression(Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode);
418418
static ObjectAddress ATExecSetStatistics(Relation rel, const char *colName, int16 colNum,
419419
Node *newValue, LOCKMODE lockmode);
@@ -4151,7 +4151,7 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
41514151
case AT_DropExpression: /* ALTER COLUMN DROP EXPRESSION */
41524152
ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
41534153
ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
4154-
ATPrepDropExpression(rel, cmd, recursing);
4154+
ATPrepDropExpression(rel, cmd, recurse, recursing, lockmode);
41554155
pass = AT_PASS_DROP;
41564156
break;
41574157
case AT_SetStatistics: /* ALTER COLUMN SET STATISTICS */
@@ -7262,8 +7262,24 @@ ATExecDropIdentity(Relation rel, const char *colName, bool missing_ok, LOCKMODE
72627262
* ALTER TABLE ALTER COLUMN DROP EXPRESSION
72637263
*/
72647264
static void
7265-
ATPrepDropExpression(Relation rel, AlterTableCmd *cmd, bool recursing)
7265+
ATPrepDropExpression(Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode)
72667266
{
7267+
/*
7268+
* Reject ONLY if there are child tables. We could implement this, but it
7269+
* is a bit complicated. GENERATED clauses must be attached to the column
7270+
* definition and cannot be added later like DEFAULT, so if a child table
7271+
* has a generation expression that the parent does not have, the child
7272+
* column will necessarily be an attlocal column. So to implement ONLY
7273+
* here, we'd need extra code to update attislocal of the direct child
7274+
* tables, somewhat similar to how DROP COLUMN does it, so that the
7275+
* resulting state can be properly dumped and restored.
7276+
*/
7277+
if (!recurse &&
7278+
find_inheritance_children(RelationGetRelid(rel), lockmode))
7279+
ereport(ERROR,
7280+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
7281+
errmsg("ALTER TABLE / DROP EXPRESSION must be applied to child tables too")));
7282+
72677283
/*
72687284
* Cannot drop generation expression from inherited columns.
72697285
*/

src/test/regress/expected/generated.out

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -805,13 +805,14 @@ CREATE TABLE gtest30 (
805805
b int GENERATED ALWAYS AS (a * 2) STORED
806806
);
807807
CREATE TABLE gtest30_1 () INHERITS (gtest30);
808-
ALTER TABLE ONLY gtest30 ALTER COLUMN b DROP EXPRESSION;
808+
ALTER TABLE ONLY gtest30 ALTER COLUMN b DROP EXPRESSION; -- error
809+
ERROR: ALTER TABLE / DROP EXPRESSION must be applied to child tables too
809810
\d gtest30
810-
Table "public.gtest30"
811-
Column | Type | Collation | Nullable | Default
812-
--------+---------+-----------+----------+---------
811+
Table "public.gtest30"
812+
Column | Type | Collation | Nullable | Default
813+
--------+---------+-----------+----------+------------------------------------
813814
a | integer | | |
814-
b | integer | | |
815+
b | integer | | | generated always as (a * 2) stored
815816
Number of child tables: 1 (Use \d+ to list them.)
816817

817818
\d gtest30_1

src/test/regress/sql/generated.sql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,7 @@ CREATE TABLE gtest30 (
411411
b int GENERATED ALWAYS AS (a * 2) STORED
412412
);
413413
CREATE TABLE gtest30_1 () INHERITS (gtest30);
414-
ALTER TABLE ONLY gtest30 ALTER COLUMN b DROP EXPRESSION;
414+
ALTER TABLE ONLY gtest30 ALTER COLUMN b DROP EXPRESSION; -- error
415415
\d gtest30
416416
\d gtest30_1
417417
ALTER TABLE gtest30_1 ALTER COLUMN b DROP EXPRESSION; -- error

0 commit comments

Comments
 (0)