#!/bin/bash
# Reproducer: "unexpected table_index_fetch_tuple call during logical decoding"
# when a relcache entry is built while streaming an in-progress transaction and
# the relation has a TOASTed pg_constraint.conbin followed by further constraints.
#
# Needs: wal_level=logical, logical_decoding_work_mem=64kB, psql pointing at a scratch DB.
set -u
PSQL="psql -X -At -v ON_ERROR_STOP=1"

$PSQL <<'SQL'
DROP TABLE IF EXISTS t, filler;
DO $$ BEGIN
  EXECUTE format('CREATE TABLE t (id int PRIMARY KEY, v text,
                    CONSTRAINT a_big CHECK (v <> ALL (ARRAY[%s])))',
    (SELECT string_agg(quote_literal(md5(i::text)), ',') FROM generate_series(1, 400) i));
END $$;
CREATE TABLE filler (id int, pad text);
SELECT 'a_big conbin toasted: ' || (pg_column_toast_chunk_id(conbin) IS NOT NULL)
  FROM pg_constraint WHERE conname = 'a_big';
SELECT 'slot: ' || slot_name FROM pg_create_logical_replication_slot('repro', 'test_decoding');
SQL

# Session 1: in-progress transaction whose first change touches t, followed by
# enough changes to exceed logical_decoding_work_mem so it gets streamed.
$PSQL -c "BEGIN;
          INSERT INTO t VALUES (1, 'y');
          INSERT INTO filler SELECT i, repeat('x', 200) FROM generate_series(1, 10000) i;
          SELECT pg_sleep(10);
          COMMIT;" >/dev/null &

until [ "$($PSQL -c "SELECT count(*) FROM pg_stat_activity WHERE wait_event = 'PgSleep'")" = 1 ]; do sleep 0.2; done

# Session 2: fresh backend (cold relcache) decodes with streaming while session 1 is open.
$PSQL <<'SQL'
\set VERBOSITY verbose
SELECT count(*) FROM pg_logical_slot_peek_changes('repro', NULL, NULL, 'stream-changes', '1');
SQL
wait

# Same WAL, after session 1 committed: decodes without error.
$PSQL -c "SELECT 'after commit: ' || count(*) FROM pg_logical_slot_peek_changes('repro', NULL, NULL, 'stream-changes', '1')"

$PSQL -c "SELECT pg_drop_replication_slot('repro')" >/dev/null
