From 0426e7499bd2b567064a0d657002d83e77e38e6c Mon Sep 17 00:00:00 2001 From: Michael Paquier Date: Tue, 8 Sep 2026 08:43:35 +0900 Subject: [PATCH v15 09/11] More test coverage for oid8 with compression and out-of-line values These two gaps have been pointed out by Claude, for the following items: - pg_column_compression() with oid8 vartags - More interesting: UPDATE with out-of-line TOAST datum that belongs to a different TOAST table, where toast_tuple_init() may try to compare two TOAST tuples with a different vartag once the oid8 flavor is introduced. As of the current state of the code, all vartags are OID-based. A follow-up patch will complicate that. --- src/test/regress/expected/compression.out | 41 +++++++++++++++++++++ src/test/regress/expected/strings.out | 43 +++++++++++++++++++++++ src/test/regress/sql/compression.sql | 22 ++++++++++++ src/test/regress/sql/strings.sql | 25 +++++++++++++ 4 files changed, 131 insertions(+) diff --git a/src/test/regress/expected/compression.out b/src/test/regress/expected/compression.out index 09f198149aa4..e9128193515a 100644 --- a/src/test/regress/expected/compression.out +++ b/src/test/regress/expected/compression.out @@ -66,6 +66,47 @@ SELECT SUBSTR(f1, 200, 5) FROM cmdata2; (1 row) DROP TABLE cmdata2; +-- pg_column_compression() with oid and oid8 +CREATE TABLE toastcomp_oid(f1 text) WITH (toast_value_type = 'oid'); +CREATE TABLE toastcomp_oid8(f1 text) WITH (toast_value_type = 'oid8'); +ALTER TABLE toastcomp_oid ALTER COLUMN f1 SET STORAGE EXTERNAL; +ALTER TABLE toastcomp_oid8 ALTER COLUMN f1 SET STORAGE EXTERNAL; +INSERT INTO toastcomp_oid VALUES (repeat('1234567890', 10000)); +INSERT INTO toastcomp_oid8 VALUES (repeat('1234567890', 10000)); +SELECT pg_column_compression(f1) IS NULL AS uncompressed FROM toastcomp_oid; + uncompressed +-------------- + t +(1 row) + +SELECT pg_column_compression(f1) IS NULL AS uncompressed FROM toastcomp_oid8; + uncompressed +-------------- + t +(1 row) + +-- out-of-line and compressed. +TRUNCATE toastcomp_oid; +TRUNCATE toastcomp_oid8; +ALTER TABLE toastcomp_oid ALTER COLUMN f1 SET STORAGE EXTENDED; +ALTER TABLE toastcomp_oid8 ALTER COLUMN f1 SET STORAGE EXTENDED; +ALTER TABLE toastcomp_oid SET (toast_tuple_target = 128); +ALTER TABLE toastcomp_oid8 SET (toast_tuple_target = 128); +INSERT INTO toastcomp_oid VALUES (repeat('1234567890', 10000)); +INSERT INTO toastcomp_oid8 VALUES (repeat('1234567890', 10000)); +SELECT pg_column_compression(f1) FROM toastcomp_oid; + pg_column_compression +----------------------- + pglz +(1 row) + +SELECT pg_column_compression(f1) FROM toastcomp_oid8; + pg_column_compression +----------------------- + pglz +(1 row) + +DROP TABLE toastcomp_oid, toastcomp_oid8; --test column type update varlena/non-varlena CREATE TABLE cmdata2 (f1 int); \d+ cmdata2 diff --git a/src/test/regress/expected/strings.out b/src/test/regress/expected/strings.out index 080cb039ce43..7e3a641259c2 100644 --- a/src/test/regress/expected/strings.out +++ b/src/test/regress/expected/strings.out @@ -2289,6 +2289,49 @@ ALTER TABLE toasttest_oid8 RESET (toast_value_type); -- Reset column storage to its default ALTER TABLE toasttest_oid ALTER COLUMN f1 SET STORAGE EXTENDED; ALTER TABLE toasttest_oid8 ALTER COLUMN f1 SET STORAGE EXTENDED; +-- UPDATE with out-of-line datum that belongs to another TOAST table. +CREATE TABLE toastupd_oid(f1 text) WITH (toast_value_type = 'oid'); +CREATE TABLE toastupd_oid8(f1 text) WITH (toast_value_type = 'oid8'); +ALTER TABLE toastupd_oid ALTER COLUMN f1 SET STORAGE EXTERNAL; +ALTER TABLE toastupd_oid8 ALTER COLUMN f1 SET STORAGE EXTERNAL; +SELECT reltoastrelid::regclass AS upd_oid_toast FROM pg_class + WHERE oid = 'toastupd_oid'::regclass \gset +SELECT reltoastrelid::regclass AS upd_oid8_toast FROM pg_class + WHERE oid = 'toastupd_oid8'::regclass \gset +INSERT INTO toastupd_oid VALUES (repeat('a', 100000)); +INSERT INTO toastupd_oid8 VALUES (repeat('b', 100000)); +-- old value is an oid8 pointer, new value an oid pointer. +UPDATE toastupd_oid8 SET f1 = toastupd_oid.f1 FROM toastupd_oid; +SELECT length(f1), substr(f1, 1, 3) FROM toastupd_oid8; + length | substr +--------+-------- + 100000 | aaa +(1 row) + +-- replaced value must be gone, leaving a single value behind. +SELECT count(*) FROM :upd_oid8_toast WHERE chunk_seq = 0; + count +------- + 1 +(1 row) + +-- reverse: old value is an oid pointer, new value an oid8 pointer. +TRUNCATE toastupd_oid; +INSERT INTO toastupd_oid VALUES (repeat('c', 100000)); +UPDATE toastupd_oid SET f1 = toastupd_oid8.f1 FROM toastupd_oid8; +SELECT length(f1), substr(f1, 1, 3) FROM toastupd_oid; + length | substr +--------+-------- + 100000 | aaa +(1 row) + +SELECT count(*) FROM :upd_oid_toast WHERE chunk_seq = 0; + count +------- + 1 +(1 row) + +DROP TABLE toastupd_oid, toastupd_oid8; -- test internally compressing datums -- this tests compressing a datum to a very small size which exercises a -- corner case in packed-varlena handling: even though small, the compressed diff --git a/src/test/regress/sql/compression.sql b/src/test/regress/sql/compression.sql index ce5ea37a660c..229143f06ddd 100644 --- a/src/test/regress/sql/compression.sql +++ b/src/test/regress/sql/compression.sql @@ -37,6 +37,28 @@ SELECT pg_column_compression(f1) FROM cmdata2; SELECT SUBSTR(f1, 200, 5) FROM cmdata2; DROP TABLE cmdata2; +-- pg_column_compression() with oid and oid8 +CREATE TABLE toastcomp_oid(f1 text) WITH (toast_value_type = 'oid'); +CREATE TABLE toastcomp_oid8(f1 text) WITH (toast_value_type = 'oid8'); +ALTER TABLE toastcomp_oid ALTER COLUMN f1 SET STORAGE EXTERNAL; +ALTER TABLE toastcomp_oid8 ALTER COLUMN f1 SET STORAGE EXTERNAL; +INSERT INTO toastcomp_oid VALUES (repeat('1234567890', 10000)); +INSERT INTO toastcomp_oid8 VALUES (repeat('1234567890', 10000)); +SELECT pg_column_compression(f1) IS NULL AS uncompressed FROM toastcomp_oid; +SELECT pg_column_compression(f1) IS NULL AS uncompressed FROM toastcomp_oid8; +-- out-of-line and compressed. +TRUNCATE toastcomp_oid; +TRUNCATE toastcomp_oid8; +ALTER TABLE toastcomp_oid ALTER COLUMN f1 SET STORAGE EXTENDED; +ALTER TABLE toastcomp_oid8 ALTER COLUMN f1 SET STORAGE EXTENDED; +ALTER TABLE toastcomp_oid SET (toast_tuple_target = 128); +ALTER TABLE toastcomp_oid8 SET (toast_tuple_target = 128); +INSERT INTO toastcomp_oid VALUES (repeat('1234567890', 10000)); +INSERT INTO toastcomp_oid8 VALUES (repeat('1234567890', 10000)); +SELECT pg_column_compression(f1) FROM toastcomp_oid; +SELECT pg_column_compression(f1) FROM toastcomp_oid8; +DROP TABLE toastcomp_oid, toastcomp_oid8; + --test column type update varlena/non-varlena CREATE TABLE cmdata2 (f1 int); \d+ cmdata2 diff --git a/src/test/regress/sql/strings.sql b/src/test/regress/sql/strings.sql index 3e7459d29ff1..4d6a1e02359c 100644 --- a/src/test/regress/sql/strings.sql +++ b/src/test/regress/sql/strings.sql @@ -727,6 +727,31 @@ ALTER TABLE toasttest_oid8 RESET (toast_value_type); ALTER TABLE toasttest_oid ALTER COLUMN f1 SET STORAGE EXTENDED; ALTER TABLE toasttest_oid8 ALTER COLUMN f1 SET STORAGE EXTENDED; +-- UPDATE with out-of-line datum that belongs to another TOAST table. +CREATE TABLE toastupd_oid(f1 text) WITH (toast_value_type = 'oid'); +CREATE TABLE toastupd_oid8(f1 text) WITH (toast_value_type = 'oid8'); +ALTER TABLE toastupd_oid ALTER COLUMN f1 SET STORAGE EXTERNAL; +ALTER TABLE toastupd_oid8 ALTER COLUMN f1 SET STORAGE EXTERNAL; +SELECT reltoastrelid::regclass AS upd_oid_toast FROM pg_class + WHERE oid = 'toastupd_oid'::regclass \gset +SELECT reltoastrelid::regclass AS upd_oid8_toast FROM pg_class + WHERE oid = 'toastupd_oid8'::regclass \gset +INSERT INTO toastupd_oid VALUES (repeat('a', 100000)); +INSERT INTO toastupd_oid8 VALUES (repeat('b', 100000)); +-- old value is an oid8 pointer, new value an oid pointer. +UPDATE toastupd_oid8 SET f1 = toastupd_oid.f1 FROM toastupd_oid; +SELECT length(f1), substr(f1, 1, 3) FROM toastupd_oid8; +-- replaced value must be gone, leaving a single value behind. +SELECT count(*) FROM :upd_oid8_toast WHERE chunk_seq = 0; +-- reverse: old value is an oid pointer, new value an oid8 pointer. +TRUNCATE toastupd_oid; +INSERT INTO toastupd_oid VALUES (repeat('c', 100000)); +UPDATE toastupd_oid SET f1 = toastupd_oid8.f1 FROM toastupd_oid8; +SELECT length(f1), substr(f1, 1, 3) FROM toastupd_oid; +SELECT count(*) FROM :upd_oid_toast WHERE chunk_seq = 0; + +DROP TABLE toastupd_oid, toastupd_oid8; + -- test internally compressing datums -- this tests compressing a datum to a very small size which exercises a -- 2.55.0