v6-0001-virtual-generated-columns-misc-changes.no-cfbot

application/octet-stream

Filename: v6-0001-virtual-generated-columns-misc-changes.no-cfbot
Type: application/octet-stream
Part: 0
Message: Re: Virtual generated columns
From 96c6dddfbee75200321ad6a7d0eee6c49a544f74 Mon Sep 17 00:00:00 2001
From: jian he <jian.universality@gmail.com>
Date: Wed, 18 Sep 2024 10:29:46 +0800
Subject: [PATCH v6 1/1] virtual generated columns misc changes.

* change tests on contrib/pageinspect/sql/page.sql
* also change relcache.c make cached constr->has_not_null,
constr->has_generated_stored, constr->has_generated_virtual more accurate.

Discussion: https://www.postgresql.org/message-id/flat/a368248e-69e4-40be-9c07-6c3b5880b0a6@eisentraut.org
---
 contrib/pageinspect/expected/page.out         | 20 +++++++++++--------
 contrib/pageinspect/sql/page.sql              |  8 ++++++--
 src/backend/commands/tablecmds.c              |  2 +-
 src/backend/utils/cache/relcache.c            | 12 +++++++++--
 .../regress/expected/generated_virtual.out    |  4 ++--
 5 files changed, 31 insertions(+), 15 deletions(-)

diff --git a/contrib/pageinspect/expected/page.out b/contrib/pageinspect/expected/page.out
index bacd371a9d..02b1bbb1ab 100644
--- a/contrib/pageinspect/expected/page.out
+++ b/contrib/pageinspect/expected/page.out
@@ -212,10 +212,12 @@ drop table test8;
 -- stored
 create table test9s (a int not null, b int generated always as (a * 2) stored);
 insert into test9s values (131584);
-select t_infomask, t_bits, t_data from heap_page_items(get_raw_page('test9s', 0));
- t_infomask | t_bits |       t_data       
-------------+--------+--------------------
-       2048 |        | \x0002020000040400
+select sub.raw_flags as t_infomask_info, t_bits is null as expect_true, t_data 
+from heap_page_items(get_raw_page('test9s', 0)),
+     heap_tuple_infomask_flags(t_infomask, 0) sub;
+   t_infomask_info   | expect_true |       t_data       
+---------------------+-------------+--------------------
+ {HEAP_XMAX_INVALID} | t           | \x0002020000040400
 (1 row)
 
 select tuple_data_split('test9s'::regclass, t_data, t_infomask, t_infomask2, t_bits)
@@ -229,10 +231,12 @@ drop table test9s;
 -- virtual
 create table test9v (a int not null, b int generated always as (a * 2) virtual);
 insert into test9v values (131584);
-select t_infomask, t_bits, t_data from heap_page_items(get_raw_page('test9v', 0));
- t_infomask |  t_bits  |   t_data   
-------------+----------+------------
-       2049 | 10000000 | \x00020200
+select sub.raw_flags as t_infomask_info, t_bits is not null as expect_true, t_data 
+from heap_page_items(get_raw_page('test9v', 0)),
+     heap_tuple_infomask_flags(t_infomask, 0) sub;
+         t_infomask_info          | expect_true |   t_data   
+----------------------------------+-------------+------------
+ {HEAP_HASNULL,HEAP_XMAX_INVALID} | t           | \x00020200
 (1 row)
 
 select tuple_data_split('test9v'::regclass, t_data, t_infomask, t_infomask2, t_bits)
diff --git a/contrib/pageinspect/sql/page.sql b/contrib/pageinspect/sql/page.sql
index 923687d063..81866db25a 100644
--- a/contrib/pageinspect/sql/page.sql
+++ b/contrib/pageinspect/sql/page.sql
@@ -88,7 +88,9 @@ drop table test8;
 -- stored
 create table test9s (a int not null, b int generated always as (a * 2) stored);
 insert into test9s values (131584);
-select t_infomask, t_bits, t_data from heap_page_items(get_raw_page('test9s', 0));
+select sub.raw_flags as t_infomask_info, t_bits is null as expect_true, t_data
+from heap_page_items(get_raw_page('test9s', 0)),
+     heap_tuple_infomask_flags(t_infomask, 0) sub;
 select tuple_data_split('test9s'::regclass, t_data, t_infomask, t_infomask2, t_bits)
     from heap_page_items(get_raw_page('test9s', 0));
 drop table test9s;
@@ -96,7 +98,9 @@ drop table test9s;
 -- virtual
 create table test9v (a int not null, b int generated always as (a * 2) virtual);
 insert into test9v values (131584);
-select t_infomask, t_bits, t_data from heap_page_items(get_raw_page('test9v', 0));
+select sub.raw_flags as t_infomask_info, t_bits is not null as expect_true, t_data
+from heap_page_items(get_raw_page('test9v', 0)),
+     heap_tuple_infomask_flags(t_infomask, 0) sub;
 select tuple_data_split('test9v'::regclass, t_data, t_infomask, t_infomask2, t_bits)
     from heap_page_items(get_raw_page('test9v', 0));
 drop table test9v;
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index b01e431355..03f9376d8b 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -9731,7 +9731,7 @@ ATAddForeignKeyConstraint(List **wqueue, AlteredTableInfo *tab, Relation rel,
 	{
 		char		attgenerated = TupleDescAttr(RelationGetDescr(rel), fkattnum[i] - 1)->attgenerated;
 
-		if (attgenerated)
+		if (attgenerated == ATTRIBUTE_GENERATED_STORED)
 		{
 			/*
 			 * Check restrictions on UPDATE/DELETE actions, per SQL standard
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index c8a711cb7e..a421ee6d38 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -3541,6 +3541,8 @@ RelationBuildLocalRelation(const char *relname,
 	int			natts = tupDesc->natts;
 	int			i;
 	bool		has_not_null;
+	bool		has_generated_stored;
+	bool		has_generated_virtual;
 	bool		nailit;
 
 	Assert(natts >= 0);
@@ -3617,6 +3619,8 @@ RelationBuildLocalRelation(const char *relname,
 	rel->rd_att = CreateTupleDescCopy(tupDesc);
 	rel->rd_att->tdrefcount = 1;	/* mark as refcounted */
 	has_not_null = false;
+	has_generated_stored = false;
+	has_generated_virtual = false;
 	for (i = 0; i < natts; i++)
 	{
 		Form_pg_attribute satt = TupleDescAttr(tupDesc, i);
@@ -3626,13 +3630,17 @@ RelationBuildLocalRelation(const char *relname,
 		datt->attgenerated = satt->attgenerated;
 		datt->attnotnull = satt->attnotnull;
 		has_not_null |= satt->attnotnull;
+		has_generated_stored |= (satt->attgenerated == ATTRIBUTE_GENERATED_STORED);
+		has_generated_virtual |= (satt->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL);
 	}
 
-	if (has_not_null)
+	if (has_not_null || has_generated_stored || has_generated_virtual)
 	{
 		TupleConstr *constr = (TupleConstr *) palloc0(sizeof(TupleConstr));
 
-		constr->has_not_null = true;
+		constr->has_not_null = has_not_null;
+		constr->has_generated_stored = has_generated_stored;
+		constr->has_generated_virtual = has_generated_virtual;
 		rel->rd_att->constr = constr;
 	}
 
diff --git a/src/test/regress/expected/generated_virtual.out b/src/test/regress/expected/generated_virtual.out
index 4cf4f8118f..c32ef7f787 100644
--- a/src/test/regress/expected/generated_virtual.out
+++ b/src/test/regress/expected/generated_virtual.out
@@ -678,9 +678,9 @@ CREATE TABLE gtest22c (a int, b int GENERATED ALWAYS AS (a * 2) VIRTUAL);
 CREATE TABLE gtest23a (x int PRIMARY KEY, y int);
 --INSERT INTO gtest23a VALUES (1, 11), (2, 22), (3, 33);
 CREATE TABLE gtest23x (a int PRIMARY KEY, b int GENERATED ALWAYS AS (a * 2) VIRTUAL REFERENCES gtest23a (x) ON UPDATE CASCADE);  -- error
-ERROR:  invalid ON UPDATE action for foreign key constraint containing generated column
+ERROR:  foreign key constraints on virtual generated columns are not supported
 CREATE TABLE gtest23x (a int PRIMARY KEY, b int GENERATED ALWAYS AS (a * 2) VIRTUAL REFERENCES gtest23a (x) ON DELETE SET NULL);  -- error
-ERROR:  invalid ON DELETE action for foreign key constraint containing generated column
+ERROR:  foreign key constraints on virtual generated columns are not supported
 CREATE TABLE gtest23b (a int PRIMARY KEY, b int GENERATED ALWAYS AS (a * 2) VIRTUAL REFERENCES gtest23a (x));
 ERROR:  foreign key constraints on virtual generated columns are not supported
 --\d gtest23b
-- 
2.34.1