#!/bin/sh set -eu repo=$(CDPATH= cd -- "$(dirname "$0")/.." && pwd) output=$(mktemp) cleanup() { rm -f "$output"; } trap cleanup EXIT INT TERM docker compose exec -T db psql -X -U rf4 -d rf4_spotter \ < "$repo/deploy/query-plan-gate.sql" > "$output" grep -Eq '100000[[:space:]]*\|[[:space:]]*90000[[:space:]]*\|[[:space:]]*20000[[:space:]]*\|[[:space:]]*5000' "$output" for plan in activity_72h records_count records_page spot_detail public_spot_pages; do grep -F "PLAN $plan" "$output" >/dev/null done # Public query budget from docs/query-performance.md. Five EXPLAIN statements # must finish below it on the local alpha-sized fixture. awk ' /Execution Time:/ { count += 1; if (($3 + 0) > 250) { print "Query plan exceeded 250 ms: " $0 > "/dev/stderr"; failed = 1 } } END { if (count != 5 || failed) exit 1 } ' "$output" # Selective paths must use an index. public_spot_pages may legitimately scan # many approved rows while producing the distinct sitemap set. awk ' /PLAN activity_72h/ { section = "activity"; next } /PLAN records_count/ { section = "records_count"; next } /PLAN records_page/ { section = "records_page"; next } /PLAN spot_detail/ { section = "spot_detail"; next } /PLAN public_spot_pages/ { section = "public_spot_pages"; next } section == "activity" && /Index Scan/ { activity = 1 } section == "records_page" && /Index Scan/ { records = 1 } section == "spot_detail" && /Index Scan/ { spot = 1 } END { if (!activity || !records || !spot) exit 1 } ' "$output" grep 'Execution Time:' "$output" echo "Query-plan gate passed: 100000 temporary reports, indexed selective paths, all plans under 250 ms"