Skip to content

Commit 4b10074

Browse files
committed
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
1 parent 2b0ee12 commit 4b10074

File tree

3 files changed

+23
-2
lines changed

3 files changed

+23
-2
lines changed

src/backend/catalog/heap.c

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3020,15 +3020,26 @@ check_nested_generated_walker(Node *node, void *context)
30203020
AttrNumber attnum;
30213021

30223022
relid = rt_fetch(var->varno, pstate->p_rtable)->relid;
3023+
if (!OidIsValid(relid))
3024+
return false; /* XXX shouldn't we raise an error? */
3025+
30233026
attnum = var->varattno;
30243027

3025-
if (OidIsValid(relid) && AttributeNumberIsValid(attnum) && get_attgenerated(relid, attnum))
3028+
if (attnum > 0 && get_attgenerated(relid, attnum))
30263029
ereport(ERROR,
3027-
(errcode(ERRCODE_SYNTAX_ERROR),
3030+
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
30283031
errmsg("cannot use generated column \"%s\" in column generation expression",
30293032
get_attname(relid, attnum, false)),
30303033
errdetail("A generated column cannot reference another generated column."),
30313034
parser_errposition(pstate, var->location)));
3035+
/* A whole-row Var is necessarily self-referential, so forbid it */
3036+
if (attnum == 0)
3037+
ereport(ERROR,
3038+
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
3039+
errmsg("cannot use whole-row variable in column generation expression"),
3040+
errdetail("This would cause the generated column to depend on its own value."),
3041+
parser_errposition(pstate, var->location)));
3042+
/* System columns were already checked in the parser */
30323043

30333044
return false;
30343045
}

src/test/regress/expected/generated.out

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,13 @@ ERROR: cannot use generated column "b" in column generation expression
4646
LINE 1: ...AYS AS (a * 2) STORED, c int GENERATED ALWAYS AS (b * 3) STO...
4747
^
4848
DETAIL: A generated column cannot reference another generated column.
49+
-- a whole-row var is a self-reference on steroids, so disallow that too
50+
CREATE TABLE gtest_err_2c (a int PRIMARY KEY,
51+
b int GENERATED ALWAYS AS (num_nulls(gtest_err_2c)) STORED);
52+
ERROR: cannot use whole-row variable in column generation expression
53+
LINE 2: b int GENERATED ALWAYS AS (num_nulls(gtest_err_2c)) STOR...
54+
^
55+
DETAIL: This would cause the generated column to depend on its own value.
4956
-- invalid reference
5057
CREATE TABLE gtest_err_3 (a int PRIMARY KEY, b int GENERATED ALWAYS AS (c * 2) STORED);
5158
ERROR: column "c" does not exist

src/test/regress/sql/generated.sql

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ CREATE TABLE gtest_err_1 (a int PRIMARY KEY, b int GENERATED ALWAYS AS (a * 2) S
1717
-- references to other generated columns, including self-references
1818
CREATE TABLE gtest_err_2a (a int PRIMARY KEY, b int GENERATED ALWAYS AS (b * 2) STORED);
1919
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);
20+
-- a whole-row var is a self-reference on steroids, so disallow that too
21+
CREATE TABLE gtest_err_2c (a int PRIMARY KEY,
22+
b int GENERATED ALWAYS AS (num_nulls(gtest_err_2c)) STORED);
2023

2124
-- invalid reference
2225
CREATE TABLE gtest_err_3 (a int PRIMARY KEY, b int GENERATED ALWAYS AS (c * 2) STORED);

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy