-- P1: inserts still pending when a TRUNCATE commits are added to -- n_ins_since_vacuum after the TRUNCATE resets it. -- -- One session. The procedure keeps the backend busy between the steps, and -- pending stats are only flushed while the backend is idle, so the first -- INSERT is still pending when the TRUNCATE commits. Runs on 14 and later. \set ON_ERROR_STOP 1 \pset footer off SELECT current_setting('server_version_num')::int >= 150000 AS has_force_flush \gset \if :has_force_flush \set flush 'SELECT pg_stat_force_next_flush()' \else \set flush 'SELECT pg_sleep(1.1)' \endif CREATE TABLE p1_pending (id int) WITH (autovacuum_enabled = off); CREATE TABLE p1_flushed (id int) WITH (autovacuum_enabled = off); CREATE PROCEDURE p1_steps() LANGUAGE plpgsql AS $$ BEGIN INSERT INTO p1_pending SELECT generate_series(1, 9); COMMIT; TRUNCATE p1_pending; COMMIT; INSERT INTO p1_pending SELECT generate_series(1, 6); END $$; \echo == P1: INSERT 9; TRUNCATE; INSERT 6 (one procedure, nothing flushed in between) CALL p1_steps(); :flush \g /dev/null SELECT n_live_tup, n_ins_since_vacuum, (SELECT count(*) FROM p1_pending) AS count FROM pg_stat_user_tables WHERE relname = 'p1_pending'; \echo expected n_ins_since_vacuum = 6 (rows inserted since the TRUNCATE); bug: 15 \echo == control: same statements, stats flushed after each step INSERT INTO p1_flushed SELECT generate_series(1, 9); :flush \g /dev/null TRUNCATE p1_flushed; :flush \g /dev/null INSERT INTO p1_flushed SELECT generate_series(1, 6); :flush \g /dev/null SELECT n_live_tup, n_ins_since_vacuum, (SELECT count(*) FROM p1_flushed) AS count FROM pg_stat_user_tables WHERE relname = 'p1_flushed'; \echo control gives n_ins_since_vacuum = 6 DROP PROCEDURE p1_steps(); DROP TABLE p1_pending, p1_flushed;