Fix possible crash with GENERATED ALWAYS columns
authorDavid Rowley
Sat, 18 Apr 2020 02:11:21 +0000 (14:11 +1200)
committerDavid Rowley
Sat, 18 Apr 2020 02:11:21 +0000 (14:11 +1200)
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.)

src/backend/executor/nodeModifyTable.c
src/test/regress/expected/generated.out
src/test/regress/sql/generated.sql

index 212b12ab514da7a29f7e1af8103337da410df4a4..08609f23dd1f4748b48c0ef60a9d2046cf5c4115 100644 (file)
@@ -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;
        }
index 8cffef04778f3841f4c69c32557d5b8f8de7d81e..f87c86a8ced0c978077bfb96f4a2ecd813d868d2 100644 (file)
@@ -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 (
index ff5c8607def4417b6824b60c3eb7f3bdb42c4fc9..bdcedbb9914bd699a7f5e8307bf264fa22584230 100644 (file)
@@ -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 (