aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDavid Rowley <drowley@postgresql.org>2020-04-18 14:11:21 +1200
committerDavid Rowley <drowley@postgresql.org>2020-04-18 14:11:21 +1200
commita375f11c44cf245363f356508f7d5126bdaa18ae (patch)
tree190011eb48ecbe7bb1c71ed97d85d98f3df64c83 /src
parent6b02bee66cae232d587679eb476f4784c38abad1 (diff)
downloadpostgresql-a375f11c44cf245363f356508f7d5126bdaa18ae.tar.gz
postgresql-a375f11c44cf245363f356508f7d5126bdaa18ae.zip
Fix possible crash with GENERATED ALWAYS columns
In some corner cases, this could also lead to corrupted values being included in the tuple. Users who are concerned that they are affected by this should first upgrade and then perform a base backup of their database and restore onto an off-line server. They should then query each table with generated columns to ensure there are no rows where the generated expression does not match a newly calculated version of the GENERATED ALWAYS expression. If no crashes occur and no rows are returned then you're not affected. Fixes bug #16369. Reported-by: Cameron Ezell Discussion: https://postgr.es/m/16369-5845a6f1bef59884@postgresql.org Backpatch-through: 12 (where GENERATED ALWAYS columns were added.)
Diffstat (limited to 'src')
-rw-r--r--src/backend/executor/nodeModifyTable.c7
-rw-r--r--src/test/regress/expected/generated.out12
-rw-r--r--src/test/regress/sql/generated.sql7
3 files changed, 26 insertions, 0 deletions
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index 212b12ab514..08609f23dd1 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -311,6 +311,13 @@ ExecComputeStoredGenerated(EState *estate, TupleTableSlot *slot)
val = ExecEvalExpr(resultRelInfo->ri_GeneratedExprs[i], econtext, &isnull);
+ /*
+ * We must make a copy of val as we have no guarantees about where
+ * memory for a pass-by-reference Datum is located.
+ */
+ if (!isnull)
+ val = datumCopy(val, attr->attbyval, attr->attlen);
+
values[i] = val;
nulls[i] = isnull;
}
diff --git a/src/test/regress/expected/generated.out b/src/test/regress/expected/generated.out
index 8cffef04778..f87c86a8ced 100644
--- a/src/test/regress/expected/generated.out
+++ b/src/test/regress/expected/generated.out
@@ -320,6 +320,18 @@ SELECT * FROM gtest2;
1 |
(1 row)
+-- simple column reference for varlena types
+CREATE TABLE gtest_varlena (a varchar, b varchar GENERATED ALWAYS AS (a) STORED);
+INSERT INTO gtest_varlena (a) VALUES('01234567890123456789');
+INSERT INTO gtest_varlena (a) VALUES(NULL);
+SELECT * FROM gtest_varlena ORDER BY a;
+ a | b
+----------------------+----------------------
+ 01234567890123456789 | 01234567890123456789
+ |
+(2 rows)
+
+DROP TABLE gtest_varlena;
-- composite types
CREATE TYPE double_int as (a int, b int);
CREATE TABLE gtest4 (
diff --git a/src/test/regress/sql/generated.sql b/src/test/regress/sql/generated.sql
index ff5c8607def..bdcedbb9914 100644
--- a/src/test/regress/sql/generated.sql
+++ b/src/test/regress/sql/generated.sql
@@ -145,6 +145,13 @@ CREATE TABLE gtest2 (a int PRIMARY KEY, b int GENERATED ALWAYS AS (NULL) STORED)
INSERT INTO gtest2 VALUES (1);
SELECT * FROM gtest2;
+-- simple column reference for varlena types
+CREATE TABLE gtest_varlena (a varchar, b varchar GENERATED ALWAYS AS (a) STORED);
+INSERT INTO gtest_varlena (a) VALUES('01234567890123456789');
+INSERT INTO gtest_varlena (a) VALUES(NULL);
+SELECT * FROM gtest_varlena ORDER BY a;
+DROP TABLE gtest_varlena;
+
-- composite types
CREATE TYPE double_int as (a int, b int);
CREATE TABLE gtest4 (