#!/bin/bash
# Prerequisites:
# - PG binaries must be on PATH
# - contrib module test_decoding must be installed.
set -u

PORT=${PGPORT:-54329}
REPRO_BASE=$(mktemp -d)

echo "REPRO_BASE=$REPRO_BASE"
initdb -D "$REPRO_BASE/pgdata" -A trust >/dev/null
cat >> "$REPRO_BASE/pgdata/postgresql.conf" <<EOF
port = $PORT
listen_addresses = ''
unix_socket_directories = '$REPRO_BASE'
wal_level = replica
EOF
pg_ctl -D "$REPRO_BASE/pgdata" -l "$REPRO_BASE/server.log" -w start >/dev/null

q() { psql -h "$REPRO_BASE" -p "$PORT" -X -A -t -q postgres -c "$1"; }

# Session A reads its commands from a fifo so the steps can be ordered exactly.
mkfifo "$REPRO_BASE/session_a.fifo"
psql -h "$REPRO_BASE" -p "$PORT" -X -A -t -q postgres < "$REPRO_BASE/session_a.fifo" > "$REPRO_BASE/session_a.log" 2>&1 &
exec 3> "$REPRO_BASE/session_a.fifo"
a() { echo "$1" >&3; }
wait_for() { until grep -q "^$1\$" "$REPRO_BASE/session_a.log"; do sleep 0.1; done; }

q "create table t (a int)"

# Session A: leave a transaction block in the aborted state, with an XID assigned.
a "begin;"
a "select pg_current_xact_id() is not null;"
a "select 1/0;"
a "\\echo aborted"
wait_for aborted

# Creating the first logical slot enables logical decoding.
q "select pg_create_logical_replication_slot('s', 'test_decoding')" > /dev/null

# Commit row 1 from another session.
q "insert into t values (1)"

# Session A: roll back, then commit rows 2 and 3 in separate transactions
a "rollback;"
a "insert into t values (2);"
a "insert into t values (3);"
a "\\echo done"
wait_for done
exec 3>&-
wait

echo
echo "rows committed:"
q "select a from t order by a"

decoded=$(q "select data from pg_logical_slot_get_changes('s', null, null) where data like '%INSERT%'")
echo
echo "changes decoded from slot s:"
echo "$decoded"
