aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Eisentraut <peter@eisentraut.org>2020-11-03 15:14:50 +0100
committerPeter Eisentraut <peter@eisentraut.org>2020-11-03 15:28:23 +0100
commitbf797a8d9768239f5e3204b013044274b2c7c24a (patch)
treece75879be917cffaf411ec7e3017caa0870b1e8c
parent2f70fdb0644c32c4154236c2b5c241bec92eac5e (diff)
downloadpostgresql-bf797a8d9768239f5e3204b013044274b2c7c24a.tar.gz
postgresql-bf797a8d9768239f5e3204b013044274b2c7c24a.zip
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
-rw-r--r--src/backend/commands/tablecmds.c22
-rw-r--r--src/test/regress/expected/generated.out11
-rw-r--r--src/test/regress/sql/generated.sql2
3 files changed, 26 insertions, 9 deletions
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 1b105ba1c42..4bb33ee03cd 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -413,7 +413,7 @@ static ObjectAddress ATExecAddIdentity(Relation rel, const char *colName,
static ObjectAddress ATExecSetIdentity(Relation rel, const char *colName,
Node *def, LOCKMODE lockmode);
static ObjectAddress ATExecDropIdentity(Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode);
-static void ATPrepDropExpression(Relation rel, AlterTableCmd *cmd, bool recursing);
+static void ATPrepDropExpression(Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode);
static ObjectAddress ATExecDropExpression(Relation rel, const char *colName, bool missing_ok, LOCKMODE lockmode);
static ObjectAddress ATExecSetStatistics(Relation rel, const char *colName, int16 colNum,
Node *newValue, LOCKMODE lockmode);
@@ -4151,7 +4151,7 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
case AT_DropExpression: /* ALTER COLUMN DROP EXPRESSION */
ATSimplePermissions(rel, ATT_TABLE | ATT_FOREIGN_TABLE);
ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode, context);
- ATPrepDropExpression(rel, cmd, recursing);
+ ATPrepDropExpression(rel, cmd, recurse, recursing, lockmode);
pass = AT_PASS_DROP;
break;
case AT_SetStatistics: /* ALTER COLUMN SET STATISTICS */
@@ -7262,9 +7262,25 @@ ATExecDropIdentity(Relation rel, const char *colName, bool missing_ok, LOCKMODE
* ALTER TABLE ALTER COLUMN DROP EXPRESSION
*/
static void
-ATPrepDropExpression(Relation rel, AlterTableCmd *cmd, bool recursing)
+ATPrepDropExpression(Relation rel, AlterTableCmd *cmd, bool recurse, bool recursing, LOCKMODE lockmode)
{
/*
+ * Reject ONLY if there are child tables. We could implement this, but it
+ * is a bit complicated. 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 ONLY
+ * here, 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.
+ */
+ if (!recurse &&
+ find_inheritance_children(RelationGetRelid(rel), lockmode))
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("ALTER TABLE / DROP EXPRESSION must be applied to child tables too")));
+
+ /*
* Cannot drop generation expression from inherited columns.
*/
if (!recursing)
diff --git a/src/test/regress/expected/generated.out b/src/test/regress/expected/generated.out
index 7ccc3c65ed1..4b062603044 100644
--- a/src/test/regress/expected/generated.out
+++ b/src/test/regress/expected/generated.out
@@ -805,13 +805,14 @@ CREATE TABLE gtest30 (
b int GENERATED ALWAYS AS (a * 2) STORED
);
CREATE TABLE gtest30_1 () INHERITS (gtest30);
-ALTER TABLE ONLY gtest30 ALTER COLUMN b DROP EXPRESSION;
+ALTER TABLE ONLY gtest30 ALTER COLUMN b DROP EXPRESSION; -- error
+ERROR: ALTER TABLE / DROP EXPRESSION must be applied to child tables too
\d gtest30
- Table "public.gtest30"
- Column | Type | Collation | Nullable | Default
---------+---------+-----------+----------+---------
+ Table "public.gtest30"
+ Column | Type | Collation | Nullable | Default
+--------+---------+-----------+----------+------------------------------------
a | integer | | |
- b | integer | | |
+ b | integer | | | generated always as (a * 2) stored
Number of child tables: 1 (Use \d+ to list them.)
\d gtest30_1
diff --git a/src/test/regress/sql/generated.sql b/src/test/regress/sql/generated.sql
index 4cff1279c77..c86ad34b006 100644
--- a/src/test/regress/sql/generated.sql
+++ b/src/test/regress/sql/generated.sql
@@ -411,7 +411,7 @@ CREATE TABLE gtest30 (
b int GENERATED ALWAYS AS (a * 2) STORED
);
CREATE TABLE gtest30_1 () INHERITS (gtest30);
-ALTER TABLE ONLY gtest30 ALTER COLUMN b DROP EXPRESSION;
+ALTER TABLE ONLY gtest30 ALTER COLUMN b DROP EXPRESSION; -- error
\d gtest30
\d gtest30_1
ALTER TABLE gtest30_1 ALTER COLUMN b DROP EXPRESSION; -- error