Thread

  1. [PATCH] Enhance tests for TOAST processing by REPACK.

    Antonin Houska <ah@cybertec.at> — 2026-04-20T11:30:04Z

    It seems appropriate to test more kinds of TOASTing than we used to.
    ---
     .../expected/repack_toast.out                 | 11 +--
     .../injection_points/specs/repack_toast.spec  | 71 +++++++++++++++----
     2 files changed, 63 insertions(+), 19 deletions(-)
    
    diff --git a/src/test/modules/injection_points/expected/repack_toast.out b/src/test/modules/injection_points/expected/repack_toast.out
    index b56dde134f8..063d730ba8f 100644
    --- a/src/test/modules/injection_points/expected/repack_toast.out
    +++ b/src/test/modules/injection_points/expected/repack_toast.out
    @@ -10,10 +10,13 @@ step wait_before_lock:
     	REPACK (CONCURRENTLY) repack_test;
      <waiting ...>
     step change: 
    -	UPDATE repack_test SET j=get_long_string() where i=2;
    -	DELETE FROM repack_test WHERE i=3;
    -	INSERT INTO repack_test(i, j) VALUES (4, get_long_string());
    -	UPDATE repack_test SET i=3 where i=1;
    +	DELETE FROM repack_test WHERE i=1;
    +	INSERT INTO repack_test(i, j) VALUES (1, gen_external());
    +	UPDATE repack_test SET i=10 where i=2;
    +	UPDATE repack_test SET j=gen_external() where i=3;
    +	UPDATE repack_test SET j=gen_compressible(1) where i=4;
    +	UPDATE repack_test SET j=gen_compressible_external(2) where i=5;
    +	UPDATE repack_test SET j=gen_inline() where i=6;
     
     step check2: 
     	INSERT INTO relfilenodes(node)
    diff --git a/src/test/modules/injection_points/specs/repack_toast.spec b/src/test/modules/injection_points/specs/repack_toast.spec
    index b878b198971..9a6dc2eb124 100644
    --- a/src/test/modules/injection_points/specs/repack_toast.spec
    +++ b/src/test/modules/injection_points/specs/repack_toast.spec
    @@ -5,17 +5,43 @@ setup
     {
     	CREATE EXTENSION injection_points;
     
    -	-- Return a string that needs to be TOASTed.
    -	CREATE FUNCTION get_long_string()
    +	-- Generate text consisting of repeated strings so that it can be
    +	-- compressed easily.
    +	CREATE FUNCTION gen_compressible(seed int)
    +	RETURNS text
    +	LANGUAGE sql IMMUTABLE as $$
    +		SELECT repeat(md5((seed * 1000)::text), 5000);
    +	$$;
    +
    +	-- Like above, but too big even after compression.
    +	CREATE FUNCTION gen_compressible_external(seed int)
    +	RETURNS text
    +	LANGUAGE sql IMMUTABLE as $$
    +		SELECT repeat(md5((seed * 1000)::text), 10000);
    +	$$;
    +
    +	-- Generate a string of random characters that is not likely to be
    +	-- compressed, but is big enough to be stored externally.
    +	CREATE FUNCTION gen_external()
     	RETURNS text
     	LANGUAGE sql as $$
     		SELECT string_agg(chr(65 + trunc(25 * random())::int), '')
     		FROM generate_series(1, 2048) s(x);
     	$$;
     
    +	-- Not compressible like above, but small enough to stay in-line.
    +	CREATE FUNCTION gen_inline()
    +	RETURNS text
    +	LANGUAGE sql as $$
    +		SELECT string_agg(chr(65 + trunc(25 * random())::int), '')
    +		FROM generate_series(1, 1024) s(x);
    +	$$;
    +
     	CREATE TABLE repack_test(i int PRIMARY KEY, j text);
    -	INSERT INTO repack_test(i, j) VALUES (1, get_long_string()),
    -		(2, get_long_string()), (3, get_long_string());
    +	INSERT INTO repack_test(i, j) VALUES
    +		(1, gen_external()), (2, gen_external()),
    +		(3, gen_external()), (4, gen_external()),
    +		(5, gen_external()), (6, gen_external());
     
     	CREATE TABLE relfilenodes(node oid);
     
    @@ -27,7 +53,10 @@ teardown
     {
     	DROP TABLE repack_test;
     	DROP EXTENSION injection_points;
    -	DROP FUNCTION get_long_string();
    +	DROP FUNCTION gen_compressible(int);
    +	DROP FUNCTION gen_compressible_external(int);
    +	DROP FUNCTION gen_external();
    +	DROP FUNCTION gen_inline();
     
     	DROP TABLE relfilenodes;
     	DROP TABLE data_s1;
    @@ -74,17 +103,29 @@ teardown
     
     session s2
     step change
    -# Separately test UPDATE of both plain ("i") and TOASTed ("j") attribute. In
    -# the first case, the new tuple we get from reorderbuffer.c contains "j" as a
    -# TOAST pointer, which we need to update so it points to the new heap. In the
    -# latter case, we receive "j" as "external indirect" value - here we test that
    -# the decoding worker writes the tuple to a file correctly and that the
    -# backend executing REPACK manages to restore it.
    +# Separately test different kinds of UPDATE:
    +#
    +# 1. The new tuple we get from reorderbuffer.c contains "j" as a TOAST
    +# pointer. However, as the TOASTed value stays unchanged, it points to the old
    +# tuple, so we need to adjust it.
    +#
    +# 2. We receive "j" as "external indirect" value - here we test that the
    +# decoding worker writes the tuple to a file correctly and that the backend
    +# executing REPACK manages to restore it.
    +#
    +# 3. Value of "j" is compressed.
    +#
    +# 4. Value of "j" is compressed and externalized.
    +#
    +# 5. Value of "j" stays in-line.
     {
    -	UPDATE repack_test SET j=get_long_string() where i=2;
    -	DELETE FROM repack_test WHERE i=3;
    -	INSERT INTO repack_test(i, j) VALUES (4, get_long_string());
    -	UPDATE repack_test SET i=3 where i=1;
    +	DELETE FROM repack_test WHERE i=1;
    +	INSERT INTO repack_test(i, j) VALUES (1, gen_external());
    +	UPDATE repack_test SET i=10 where i=2;
    +	UPDATE repack_test SET j=gen_external() where i=3;
    +	UPDATE repack_test SET j=gen_compressible(1) where i=4;
    +	UPDATE repack_test SET j=gen_compressible_external(2) where i=5;
    +	UPDATE repack_test SET j=gen_inline() where i=6;
     }
     # Check the table from the perspective of s2.
     step check2
    -- 
    2.47.3
    
    
    --=-=-=--