diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index 229393b01f..b34b8b94b3 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -2976,15 +2976,26 @@ check_nested_generated_walker(Node *node, void *context) AttrNumber attnum; relid = rt_fetch(var->varno, pstate->p_rtable)->relid; + if (!OidIsValid(relid)) + return false; /* XXX shouldn't we raise an error? */ + attnum = var->varattno; - if (OidIsValid(relid) && AttributeNumberIsValid(attnum) && get_attgenerated(relid, attnum)) + if (attnum > 0 && get_attgenerated(relid, attnum)) ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), + (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), errmsg("cannot use generated column \"%s\" in column generation expression", get_attname(relid, attnum, false)), errdetail("A generated column cannot reference another generated column."), 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; } diff --git a/src/test/regress/expected/generated.out b/src/test/regress/expected/generated.out index 82a9e73ebc..6a6b77677f 100644 --- a/src/test/regress/expected/generated.out +++ b/src/test/regress/expected/generated.out @@ -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... ^ 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 CREATE TABLE gtest_err_3 (a int PRIMARY KEY, b int GENERATED ALWAYS AS (c * 2) STORED); ERROR: column "c" does not exist diff --git a/src/test/regress/sql/generated.sql b/src/test/regress/sql/generated.sql index 208f1d91fa..58a7d4104f 100644 --- a/src/test/regress/sql/generated.sql +++ b/src/test/regress/sql/generated.sql @@ -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 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); +-- 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 CREATE TABLE gtest_err_3 (a int PRIMARY KEY, b int GENERATED ALWAYS AS (c * 2) STORED);