mirror of
https://github.com/postgres/postgres.git
synced 2025-05-03 22:24:49 +03:00
Disallow whole-row variables in GENERATED expressions.
This was previously allowed, but I think that was just an oversight. It's a clear violation of the rule that a generated column cannot depend on itself or other generated columns. Moreover, because the code was relying on the assumption that no such cross-references exist, it was pretty easy to crash ALTER TABLE and perhaps other places. Even if you managed not to crash, you got quite unstable, implementation-dependent results. Per report from Vitaly Ustinov. Back-patch to v12 where GENERATED came in. Discussion: https://postgr.es/m/CAM_DEiWR2DPT6U4xb-Ehigozzd3n3G37ZB1+867zbsEVtYoJww@mail.gmail.com
This commit is contained in:
parent
2b0ee126bb
commit
4b10074453
@ -3020,15 +3020,26 @@ check_nested_generated_walker(Node *node, void *context)
|
|||||||
AttrNumber attnum;
|
AttrNumber attnum;
|
||||||
|
|
||||||
relid = rt_fetch(var->varno, pstate->p_rtable)->relid;
|
relid = rt_fetch(var->varno, pstate->p_rtable)->relid;
|
||||||
|
if (!OidIsValid(relid))
|
||||||
|
return false; /* XXX shouldn't we raise an error? */
|
||||||
|
|
||||||
attnum = var->varattno;
|
attnum = var->varattno;
|
||||||
|
|
||||||
if (OidIsValid(relid) && AttributeNumberIsValid(attnum) && get_attgenerated(relid, attnum))
|
if (attnum > 0 && get_attgenerated(relid, attnum))
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
||||||
errmsg("cannot use generated column \"%s\" in column generation expression",
|
errmsg("cannot use generated column \"%s\" in column generation expression",
|
||||||
get_attname(relid, attnum, false)),
|
get_attname(relid, attnum, false)),
|
||||||
errdetail("A generated column cannot reference another generated column."),
|
errdetail("A generated column cannot reference another generated column."),
|
||||||
parser_errposition(pstate, var->location)));
|
parser_errposition(pstate, var->location)));
|
||||||
|
/* A whole-row Var is necessarily self-referential, so forbid it */
|
||||||
|
if (attnum == 0)
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
||||||
|
errmsg("cannot use whole-row variable in column generation expression"),
|
||||||
|
errdetail("This would cause the generated column to depend on its own value."),
|
||||||
|
parser_errposition(pstate, var->location)));
|
||||||
|
/* System columns were already checked in the parser */
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -46,6 +46,13 @@ ERROR: cannot use generated column "b" in column generation expression
|
|||||||
LINE 1: ...AYS AS (a * 2) STORED, c int GENERATED ALWAYS AS (b * 3) STO...
|
LINE 1: ...AYS AS (a * 2) STORED, c int GENERATED ALWAYS AS (b * 3) STO...
|
||||||
^
|
^
|
||||||
DETAIL: A generated column cannot reference another generated column.
|
DETAIL: A generated column cannot reference another generated column.
|
||||||
|
-- a whole-row var is a self-reference on steroids, so disallow that too
|
||||||
|
CREATE TABLE gtest_err_2c (a int PRIMARY KEY,
|
||||||
|
b int GENERATED ALWAYS AS (num_nulls(gtest_err_2c)) STORED);
|
||||||
|
ERROR: cannot use whole-row variable in column generation expression
|
||||||
|
LINE 2: b int GENERATED ALWAYS AS (num_nulls(gtest_err_2c)) STOR...
|
||||||
|
^
|
||||||
|
DETAIL: This would cause the generated column to depend on its own value.
|
||||||
-- invalid reference
|
-- invalid reference
|
||||||
CREATE TABLE gtest_err_3 (a int PRIMARY KEY, b int GENERATED ALWAYS AS (c * 2) STORED);
|
CREATE TABLE gtest_err_3 (a int PRIMARY KEY, b int GENERATED ALWAYS AS (c * 2) STORED);
|
||||||
ERROR: column "c" does not exist
|
ERROR: column "c" does not exist
|
||||||
|
@ -17,6 +17,9 @@ CREATE TABLE gtest_err_1 (a int PRIMARY KEY, b int GENERATED ALWAYS AS (a * 2) S
|
|||||||
-- references to other generated columns, including self-references
|
-- references to other generated columns, including self-references
|
||||||
CREATE TABLE gtest_err_2a (a int PRIMARY KEY, b int GENERATED ALWAYS AS (b * 2) STORED);
|
CREATE TABLE gtest_err_2a (a int PRIMARY KEY, b int GENERATED ALWAYS AS (b * 2) STORED);
|
||||||
CREATE TABLE gtest_err_2b (a int PRIMARY KEY, b int GENERATED ALWAYS AS (a * 2) STORED, c int GENERATED ALWAYS AS (b * 3) STORED);
|
CREATE TABLE gtest_err_2b (a int PRIMARY KEY, b int GENERATED ALWAYS AS (a * 2) STORED, c int GENERATED ALWAYS AS (b * 3) STORED);
|
||||||
|
-- a whole-row var is a self-reference on steroids, so disallow that too
|
||||||
|
CREATE TABLE gtest_err_2c (a int PRIMARY KEY,
|
||||||
|
b int GENERATED ALWAYS AS (num_nulls(gtest_err_2c)) STORED);
|
||||||
|
|
||||||
-- invalid reference
|
-- invalid reference
|
||||||
CREATE TABLE gtest_err_3 (a int PRIMARY KEY, b int GENERATED ALWAYS AS (c * 2) STORED);
|
CREATE TABLE gtest_err_3 (a int PRIMARY KEY, b int GENERATED ALWAYS AS (c * 2) STORED);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user