aboutsummaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
authorPeter Eisentraut <peter@eisentraut.org>2021-05-04 11:45:37 +0200
committerPeter Eisentraut <peter@eisentraut.org>2021-05-04 12:10:22 +0200
commit64190d65f2995203df401738b77adc5ebd4d2fce (patch)
tree51f22aa655ba9ffe02d689bad48ed6b35c7a487a /src/backend
parente48ce7ef0ef8de3d8e9e56be4d23d7830681b18b (diff)
downloadpostgresql-64190d65f2995203df401738b77adc5ebd4d2fce.tar.gz
postgresql-64190d65f2995203df401738b77adc5ebd4d2fce.zip
Fix ALTER TABLE / INHERIT with generated columns
When running ALTER TABLE t2 INHERIT t1, we must check that columns in t2 that correspond to a generated column in t1 are also generated and have the same generation expression. Otherwise, this would allow creating setups that a normal CREATE TABLE sequence would not allow. Discussion: https://www.postgresql.org/message-id/22de27f6-7096-8d96-4619-7b882932ca25@2ndquadrant.com
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/commands/tablecmds.c60
1 files changed, 60 insertions, 0 deletions
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index faba2641352..44499ec08b3 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -13910,6 +13910,66 @@ MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel)
attributeName)));
/*
+ * If parent column is generated, child column must be, too.
+ */
+ if (attribute->attgenerated && !childatt->attgenerated)
+ ereport(ERROR,
+ (errcode(ERRCODE_DATATYPE_MISMATCH),
+ errmsg("column \"%s\" in child table must be a generated column",
+ attributeName)));
+
+ /*
+ * Check that both generation expressions match.
+ *
+ * The test we apply is to see whether they reverse-compile to the
+ * same source string. This insulates us from issues like whether
+ * attributes have the same physical column numbers in parent and
+ * child relations. (See also constraints_equivalent().)
+ */
+ if (attribute->attgenerated && childatt->attgenerated)
+ {
+ TupleConstr *child_constr = child_rel->rd_att->constr;
+ TupleConstr *parent_constr = parent_rel->rd_att->constr;
+ char *child_expr = NULL;
+ char *parent_expr = NULL;
+
+ Assert(child_constr != NULL);
+ Assert(parent_constr != NULL);
+
+ for (int i = 0; i < child_constr->num_defval; i++)
+ {
+ if (child_constr->defval[i].adnum == childatt->attnum)
+ {
+ child_expr =
+ TextDatumGetCString(DirectFunctionCall2(pg_get_expr,
+ CStringGetTextDatum(child_constr->defval[i].adbin),
+ ObjectIdGetDatum(child_rel->rd_id)));
+ break;
+ }
+ }
+ Assert(child_expr != NULL);
+
+ for (int i = 0; i < parent_constr->num_defval; i++)
+ {
+ if (parent_constr->defval[i].adnum == attribute->attnum)
+ {
+ parent_expr =
+ TextDatumGetCString(DirectFunctionCall2(pg_get_expr,
+ CStringGetTextDatum(parent_constr->defval[i].adbin),
+ ObjectIdGetDatum(parent_rel->rd_id)));
+ break;
+ }
+ }
+ Assert(parent_expr != NULL);
+
+ if (strcmp(child_expr, parent_expr) != 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_DATATYPE_MISMATCH),
+ errmsg("column \"%s\" in child table has a conflicting generation expression",
+ attributeName)));
+ }
+
+ /*
* OK, bump the child column's inheritance count. (If we fail
* later on, this change will just roll back.)
*/