# pg_tre - PostgreSQL extension: native index AM for approximate regex # # Build orchestration: # 1. Build TRE (statically) from the vendored submodule via its autotools. # 2. Build the Lime parser generator (single-file C) from the submodule. # 3. Generate src/query/tre_grammar.{c,h} from src/query/tre_grammar.y. # 4. Compile sparsemap, pg_tre source tree, and the generated parser into # the PGXS-driven shared library. # # Requires PostgreSQL 17 or newer. Override PG_CONFIG to pick an install. # # make PG_CONFIG=~/.pgrx/18.3/pgrx-install/bin/pg_config # make PG_CONFIG=~/.pgrx/18.3/pgrx-install/bin/pg_config install # make PG_CONFIG=~/.pgrx/18.3/pgrx-install/bin/pg_config installcheck # EXTENSION = pg_tre MODULE_big = pg_tre DATA = sql/pg_tre--4.5.1.sql sql/pg_tre--3.2.0.sql sql/pg_tre--3.1.0.sql sql/pg_tre--3.0.2.sql sql/pg_tre--1.5.6.sql sql/pg_tre--1.5.5.sql sql/pg_tre--1.5.4.sql sql/pg_tre--1.5.3.sql sql/pg_tre--1.5.2.sql sql/pg_tre--1.5.0.sql sql/pg_tre--1.3.0.sql sql/pg_tre--1.1.1--1.2.1.sql sql/pg_tre--1.1.0--1.1.1.sql sql/pg_tre--1.1.0.sql sql/pg_tre--1.0.0--1.1.0.sql sql/pg_tre--1.0.0.sql sql/pg_tre--0.1.0--1.0.0.sql \ sql/pg_tre--4.5.0--4.5.1.sql \ sql/pg_tre--4.4.1--4.5.0.sql \ sql/pg_tre--4.4.0--4.4.1.sql \ sql/pg_tre--4.3.1--4.4.0.sql \ sql/pg_tre--4.3.0--4.3.1.sql \ sql/pg_tre--4.2.3--4.3.0.sql \ sql/pg_tre--4.2.2--4.2.3.sql \ sql/pg_tre--4.2.1--4.2.2.sql \ sql/pg_tre--4.2.0--4.2.1.sql \ sql/pg_tre--4.1.0--4.2.0.sql \ sql/pg_tre--4.0.2--4.1.0.sql \ sql/pg_tre--4.0.1--4.0.2.sql \ sql/pg_tre--4.0.0--4.0.1.sql \ sql/pg_tre--3.2.6--4.0.0.sql \ sql/pg_tre--3.2.5--3.2.6.sql \ sql/pg_tre--3.2.4--3.2.5.sql \ sql/pg_tre--3.2.3--3.2.4.sql \ sql/pg_tre--3.2.2--3.2.3.sql \ sql/pg_tre--3.2.1--3.2.2.sql \ sql/pg_tre--3.2.0--3.2.1.sql \ sql/pg_tre--3.1.0--3.2.0.sql \ sql/pg_tre--3.0.2--3.1.0.sql \ sql/pg_tre--3.0.1--3.0.2.sql \ sql/pg_tre--3.0.0--3.0.1.sql \ sql/pg_tre--2.1.0--3.0.0.sql \ sql/pg_tre--2.0.4--2.1.0.sql \ sql/pg_tre--2.0.3--2.0.4.sql \ sql/pg_tre--2.0.2--2.0.3.sql \ sql/pg_tre--2.0.1--2.0.2.sql \ sql/pg_tre--2.0.0--2.0.1.sql \ sql/pg_tre--1.12.0--2.0.0.sql \ sql/pg_tre--1.11.0--1.12.0.sql \ sql/pg_tre--1.10.1--1.11.0.sql \ sql/pg_tre--1.10.0--1.10.1.sql \ sql/pg_tre--1.9.0--1.10.0.sql \ sql/pg_tre--1.8.2--1.9.0.sql \ sql/pg_tre--1.8.1--1.8.2.sql \ sql/pg_tre--1.8.0--1.8.1.sql \ sql/pg_tre--1.7.0--1.8.0.sql \ sql/pg_tre--1.6.1--1.7.0.sql \ sql/pg_tre--1.6.0--1.6.1.sql \ sql/pg_tre--1.5.8--1.6.0.sql \ sql/pg_tre--1.5.7--1.5.8.sql \ sql/pg_tre--1.5.6--1.5.7.sql \ sql/pg_tre--1.5.5--1.5.6.sql \ sql/pg_tre--1.5.4--1.5.5.sql \ sql/pg_tre--1.5.3--1.5.4.sql \ sql/pg_tre--1.5.2--1.5.3.sql \ sql/pg_tre--1.5.1--1.5.2.sql \ sql/pg_tre--1.5.0--1.5.1.sql \ sql/pg_tre--1.4.1--1.5.0.sql \ sql/pg_tre--1.4.0--1.4.1.sql \ sql/pg_tre--1.3.0--1.4.0.sql \ sql/pg_tre--1.2.4--1.3.0.sql \ sql/pg_tre--1.2.3--1.2.4.sql \ sql/pg_tre--1.2.2--1.2.3.sql \ sql/pg_tre--1.2.1--1.2.2.sql DATA_built = REGRESS = pg_tre parser scan_exact incremental p5_read planner utf8 similarity trgm_similarity like_accel word_similarity selectivity order_by concurrently cardinality vacuum_inline posting_recycle multi_level_merge run_catalog build_estimate build_dedup flush_to_run crack_on_read coalesce coalesce_vacuum coalesce_density density_scaling vacuum_repack reloptions testregex custom_costs utf8_fuzzy amvalidate parallel_build upgrade_online surf_prefix pending_reclaim merge_page_reclaim churned_heap_scan sparsemap_corrupt_guard sparsemap_smallset similarity_multibyte vacuum_pending_dead pending_distinct collation_guard encoding_nonutf8 regex_class_index encoding_matrix collation_matrix tre_ctype_strategies regex_syntax_edges tre_collation_classes tre_upstream_fixes rep_extract regex_groups_index class_pieces tid_packing pending_limit REGRESS_OPTS = --inputdir=test --outputdir=test # ------------------------------------------------------------------ # Vendored submodules # ------------------------------------------------------------------ TRE_DIR = vendor/tre LIME_DIR = vendor/lime TRE_LIB = $(TRE_DIR)/lib/.libs/libtre.a TRE_CONFIGURE = $(TRE_DIR)/configure TRE_CONFIG_H = $(TRE_DIR)/config.h # Applied in order on top of vendor/tre. The mbdecoder and icase-class # patches are git format-patches against upstream + the patches before # them. Keep this list in step with flake.nix (postPatch), # bench/stress/stress-suite.sh and scripts/asan-check.sh. TRE_PATCH = patches/tre-progress-hook.patch patches/tre-mbdecoder.patch \ patches/tre-icase-class.patch patches/tre-upstream-fixes.patch \ patches/tre-icase-allcases.patch TRE_PATCH_STAMP = $(TRE_DIR)/.pg_tre-patched LIME_BIN = $(LIME_DIR)/lime # Grammar artifacts generated by Lime. GRAMMAR_Y = src/query/tre_grammar.y GRAMMAR_C = src/query/tre_grammar.c GRAMMAR_H = src/query/tre_grammar.h # ------------------------------------------------------------------ # pg_tre source files (compiled into MODULE_big) # ------------------------------------------------------------------ OBJS = \ src/module.o \ src/util/pattern_cache.o \ src/util/tre_match.o \ src/util/sparsemap.o \ src/util/bloom.o \ src/util/hash.o \ src/util/surf.o \ src/util/utf8.o \ src/util/type_pattern.o \ src/util/upgrade.o \ src/am/amapi.o \ src/am/ambuild.o \ src/am/aminsert.o \ src/am/amscan.o \ src/am/amvacuum.o \ src/am/amcost.o \ src/am/amoptions.o \ src/am/sel.o \ src/pages/buffer.o \ src/pages/meta.o \ src/pages/upper.o \ src/pages/posting.o \ src/pages/coalesced.o \ src/pages/pending.o \ src/pages/surf_page.o \ src/pages/run_catalog.o \ src/pages/free_log.o \ src/query/tre_grammar.o \ src/query/tokens.o \ src/query/parser.o \ src/query/regex_ast.o \ src/query/extract.o \ src/query/tiling.o \ src/query/uleven.o \ src/query/trgm_similarity.o \ src/query/like_translate.o \ src/query/debug.o # src/query/tiling.o -- Phase 5 READ side, uncomment when integrating # src/query/uleven.o -- Phase 5 READ side, uncomment when integrating # Sparsemap is vendored in-tree (verbatim); silence upstream # missing-prototype warnings, and PG19's -Wimplicit-fallthrough (its # fall-throughs carry comments, not attributes), without disabling them # globally. src/util/sparsemap.o: CFLAGS += -Wno-missing-prototypes -Wno-implicit-fallthrough # Grammar-generated files may have warnings; disable pedantic checks. src/query/tre_grammar.o: CFLAGS += -Wno-unused-parameter -Wno-missing-prototypes # tre_match.c reaches into TRE's internal tre_tnfa_t (num_states) to # enforce pg_tre.max_nfa_states, so it needs the lib/ include dir and # the generated config.h the way TRE's own sources are compiled. src/util/tre_match.o: CFLAGS += -I$(srcdir)/$(TRE_DIR)/lib -I$(srcdir)/$(TRE_DIR) # ------------------------------------------------------------------ # Include paths & compile flags # ------------------------------------------------------------------ PG_CPPFLAGS = \ -I$(srcdir)/include \ -I$(srcdir)/$(TRE_DIR)/local_includes \ -I$(srcdir)/$(TRE_DIR) \ -I$(srcdir)/$(TRE_DIR)/lib \ -DSPARSEMAP_PREFIX=__tre_ \ -Wno-declaration-after-statement # Link TRE statically. SHLIB_LINK = $(TRE_LIB) -lm PG_CONFIG ?= pg_config PGXS := $(shell $(PG_CONFIG) --pgxs) include $(PGXS) # ------------------------------------------------------------------ # TAP test environment # ------------------------------------------------------------------ # PG_REGRESS: pg_regress binary path; defaults to the one # shipped with the install pointed at by # PG_CONFIG. # PG_TAP_PERL5LIB: where PostgreSQL/Test/Cluster.pm lives. On a # PGDG-style install it's `--includedir-server # /../src/test/perl`; on the pgrx layout it's # `~/.pgrx//src/test/perl`. Override on # the command line for non-standard layouts. # PG_TAP_TMPDIR: scratch directory for TAP tmp_check trees. # NO_NIX_SHELL=1: skip the nix-shell wrapper if your perl # already has IPC::Run installed. PG_REGRESS ?= $(shell $(PG_CONFIG) --pkglibdir 2>/dev/null)/pgxs/src/test/regress/pg_regress PG_TAP_PERL5LIB ?= $(shell dirname $$(dirname $$($(PG_CONFIG) --pkglibdir 2>/dev/null)))/src/test/perl PG_TAP_TMPDIR ?= /tmp/pg_tre_tap_tmp # ------------------------------------------------------------------ # PG version guard: require >= 17. # ------------------------------------------------------------------ PG_VERSION_RAW := $(shell $(PG_CONFIG) --version 2>/dev/null) PG_MAJOR := $(shell echo '$(PG_VERSION_RAW)' | awk '{print $$2}' | cut -d. -f1) # Targets that only package or clean the source tree need no # PostgreSQL install and must not trip the version guard (the # release-tarball CI job runs `make dist` on a runner whose default # pg_config may be older than PG17). Skip the guard only when every # requested goal is PG-independent; a bare `make` (empty MAKECMDGOALS, # i.e. the default build) still enforces it. PG_INDEPENDENT_GOALS := dist clean distclean PG_SKIP_VERSION_CHECK := ifneq ($(MAKECMDGOALS),) ifeq ($(filter-out $(PG_INDEPENDENT_GOALS),$(MAKECMDGOALS)),) PG_SKIP_VERSION_CHECK := yes endif endif ifneq ($(PG_SKIP_VERSION_CHECK),yes) ifeq ($(PG_MAJOR),) $(error Could not determine PostgreSQL major version from PG_CONFIG=$(PG_CONFIG)) endif ifeq ($(shell test $(PG_MAJOR) -lt 17 2>/dev/null && echo yes),yes) $(error pg_tre requires PostgreSQL 17 or newer; found $(PG_MAJOR)) endif endif # ------------------------------------------------------------------ # TRE static build # ------------------------------------------------------------------ # Apply pg_tre's local patch to the vendored TRE submodule. This adds # the periodic tre_progress_check() calls the matcher needs for # wall-clock match-timeout enforcement (pg_tre.match_timeout_ms). The # submodule is pinned to pristine upstream, so the patch must be # (re)applied after any `git submodule update`. Guarded by a stamp and # an idempotent reverse-check so re-running make never double-applies. # The patches go on in order and later ones touch files earlier ones do, # so "patch N reverses cleanly" only means applied for the last patch: # if it reverses, the whole series is in. $(TRE_PATCH_STAMP): $(TRE_PATCH) @if git -C $(TRE_DIR) apply --reverse --check -p1 $(abspath $(lastword $(TRE_PATCH))) >/dev/null 2>&1; then \ echo "==> patch TRE: all $(words $(TRE_PATCH)) patches already applied"; \ else \ for p in $(abspath $(TRE_PATCH)); do \ echo "==> patch TRE ($$(basename $$p))"; \ if git -C $(TRE_DIR) apply --reverse --check -p1 $$p >/dev/null 2>&1; then \ echo " already applied"; \ else \ git -C $(TRE_DIR) apply -p1 $$p || exit 1; \ fi; \ done; \ fi @touch $@ $(TRE_CONFIGURE): $(TRE_DIR)/configure.ac $(TRE_PATCH_STAMP) @echo "==> autoreconf TRE" cd $(TRE_DIR) && ./utils/autogen.sh >/dev/null $(TRE_CONFIG_H): $(TRE_CONFIGURE) @echo "==> configure TRE" cd $(TRE_DIR) && ./configure \ --enable-static --disable-shared --disable-nls \ --without-alloca \ CFLAGS="-fPIC -O2 -g" >/dev/null $(TRE_LIB): $(TRE_CONFIG_H) $(TRE_PATCH_STAMP) @echo "==> build TRE" $(MAKE) -C $(TRE_DIR) >/dev/null # ------------------------------------------------------------------ # Lime generator # ------------------------------------------------------------------ # As of Lime v0.9.x the CLI's main() references the C-skin "bison" # backend, the JIT-inline helpers, and one flex-skin symbol from # separate translation units, so the generator no longer builds from # lime.c alone. We compile the minimum needed for C grammar output # (no Rust target -> emit_rust.c omitted; its stub stays in lime.c). LIME_SRCS = $(LIME_DIR)/lime.c \ $(LIME_DIR)/src/emit_c_skin_bison.c \ $(LIME_DIR)/src/jit_inline.c \ $(LIME_DIR)/src/lex/emit_c_skin_flex.c $(LIME_BIN): $(LIME_SRCS) @echo "==> build Lime generator" $(CC) -O2 -I$(LIME_DIR)/include -I$(LIME_DIR)/src -I$(LIME_DIR)/src/lex \ -o $@ $(LIME_SRCS) # ------------------------------------------------------------------ # Grammar codegen # ------------------------------------------------------------------ $(GRAMMAR_C) $(GRAMMAR_H): $(GRAMMAR_Y) $(LIME_BIN) @echo "==> generate regex parser" $(LIME_BIN) -q -T$(LIME_DIR)/limpar.c -d$(@D) $< # Dependency: our objects on TRE's config, shlib on the static archive. # Use $(shlib) (set by PGXS to pg_tre.so on Linux, pg_tre.dylib on macOS) # so the vendored TRE archive is built before linking on every platform. src/util/tre_match.o src/util/pattern_cache.o src/module.o: $(TRE_CONFIG_H) $(shlib): $(TRE_LIB) # Query path depends on generated grammar. src/query/tokens.o src/query/extract.o: $(GRAMMAR_H) src/query/tre_grammar.o: $(GRAMMAR_C) $(GRAMMAR_H) # Generated prerequisites for EVERY object and its LLVM bitcode sibling. # Many sources transitively include TRE headers (tre-config.h) and the # generated grammar header; listing only a few objects above let `make # -j` race a compile ahead of TRE's ./configure or the Lime codegen # ("tre-config.h: No such file or directory"). Order-only (|) so a # stamp rebuild doesn't force a full recompile. $(OBJS) and # $(with_llvm) come from the PGXS include above, so these rules see # the full object list. GEN_PREREQS = $(TRE_CONFIG_H) $(GRAMMAR_H) $(GRAMMAR_C) $(OBJS): | $(GEN_PREREQS) ifeq ($(with_llvm),yes) $(OBJS:.o=.bc): | $(GEN_PREREQS) endif # ------------------------------------------------------------------ # Convenience targets # ------------------------------------------------------------------ .PHONY: localcheck tapcheck tap vendor-clean distclean-full dist \ format format-check format-diff format-single format-changed \ coverage coverage-build coverage-clean coverage-report \ test-shell test-stress test-wal-audit test-replication test-all # ------------------------------------------------------------------ # Code formatting (clang-format with PostgreSQL style) # ------------------------------------------------------------------ # .clang-format and .clang-format-ignore at the repo root configure # the style and the exclusion list. CI runs `make format-check` on # every PR via .github/workflows/formatting.yml. FMT_FILES := $(shell find src include -name '*.c' -o -name '*.h' 2>/dev/null \ | grep -vE 'src/util/sparsemap\.c|include/pg_tre/sparsemap\.h|include/pg_tre/popcount\.h|src/query/tre_grammar\.[ch]') format: @echo "==> Formatting C code with clang-format" @command -v clang-format >/dev/null 2>&1 || { \ echo "clang-format not found; install via your package manager."; \ exit 1; \ } @clang-format -i --style=file $(FMT_FILES) @echo " formatted $(words $(FMT_FILES)) files" format-check: @echo "==> Checking C code formatting" @command -v clang-format >/dev/null 2>&1 || { \ echo "clang-format not found; install via your package manager."; \ exit 1; \ } @clang-format --dry-run --Werror --style=file $(FMT_FILES) || { \ echo ""; \ echo "Formatting check failed. Run 'make format' to fix."; \ exit 1; \ } @echo " OK ($(words $(FMT_FILES)) files clean)" format-diff: @for f in $(FMT_FILES); do \ diff -u $$f <(clang-format --style=file $$f) || true; \ done # Check formatting only on files modified vs main. Useful for PR # reviewers and the formatting.yml CI workflow during the # transition period before the existing tree has been reformatted # in one go. When BASE is unset, falls back to staged changes. format-changed: @command -v clang-format >/dev/null 2>&1 || { \ echo "clang-format not found."; exit 1; \ } @base=$${BASE:-origin/main}; \ files=$$(git diff --name-only $$base...HEAD -- 'src/*.c' 'src/*.h' \ 'src/**/*.c' 'src/**/*.h' 'include/**/*.h' 2>/dev/null \ | grep -vE 'src/util/sparsemap\.c|include/pg_tre/sparsemap\.h|include/pg_tre/popcount\.h|src/query/tre_grammar\.[ch]'); \ if [ -z "$$files" ]; then \ echo "No C files changed vs $$base."; \ exit 0; \ fi; \ echo "==> Checking formatting on changed files:"; \ echo "$$files" | sed 's/^/ /'; \ clang-format --dry-run --Werror --style=file $$files format-single: @if [ -z "$(FILE)" ]; then \ echo "Usage: make format-single FILE=path/to/file.c"; \ exit 1; \ fi @clang-format -i --style=file $(FILE) @echo "$(FILE) formatted" # ------------------------------------------------------------------ # Code coverage (Linux only — requires lcov: apt install lcov) # ------------------------------------------------------------------ COVERAGE_DIR = coverage-html COVERAGE_INFO = coverage.info coverage-clean: @echo "==> Cleaning coverage data" @find . -name '*.gcda' -delete 2>/dev/null || true @find . -name '*.gcno' -delete 2>/dev/null || true @if [ -d $(COVERAGE_DIR) ]; then find $(COVERAGE_DIR) -mindepth 1 -delete && rmdir $(COVERAGE_DIR); fi @if [ -f $(COVERAGE_INFO) ]; then mv $(COVERAGE_INFO) /tmp/old-cov-$$$$.info; fi coverage-build: coverage-clean @command -v lcov >/dev/null 2>&1 || { \ echo "lcov not found; install via your package manager."; \ exit 1; \ } @echo "==> Building with coverage instrumentation" $(MAKE) clean $(MAKE) PG_CFLAGS="--coverage -O0 -g" SHLIB_LINK="$(TRE_LIB) -lm --coverage" $(MAKE) install coverage: coverage-build @echo "==> Running tests under coverage" @lcov --zerocounters --directory . 2>/dev/null || true -bash scripts/run-regress.sh @echo "==> Locating .gcda files written by the backend" @find . -name '*.gcda' -printf '%p\t%u\n' 2>/dev/null | head -50 || true @echo "==> Capturing coverage data" @lcov --capture --directory . --output-file $(COVERAGE_INFO) \ --base-directory $(shell pwd) --no-external --rc branch_coverage=1 \ --ignore-errors mismatch,empty 2>/dev/null || \ lcov --capture --directory . --output-file $(COVERAGE_INFO) \ --base-directory $(shell pwd) --no-external \ --ignore-errors empty 2>/dev/null || \ : > $(COVERAGE_INFO) @lcov --remove $(COVERAGE_INFO) \ '*/test/*' '*/bench/*' '*/fuzz/*' '*/vendor/*' \ '*/util/sparsemap.c' '*/query/tre_grammar.c' \ --output-file $(COVERAGE_INFO) --rc branch_coverage=1 \ --ignore-errors unused 2>/dev/null || true @echo "==> Generating HTML report" @if [ -s $(COVERAGE_INFO) ]; then \ genhtml $(COVERAGE_INFO) --output-directory $(COVERAGE_DIR) \ --title "pg_tre Coverage" --legend --show-details \ --rc branch_coverage=1; \ echo ""; \ echo " Coverage report: $(COVERAGE_DIR)/index.html"; \ lcov --summary $(COVERAGE_INFO) --rc branch_coverage=1; \ else \ echo " No coverage data captured (empty $(COVERAGE_INFO))."; \ fi coverage-report: @if [ ! -f $(COVERAGE_INFO) ]; then \ echo "No coverage data. Run 'make coverage' first."; \ exit 1; \ fi @lcov --summary $(COVERAGE_INFO) --rc branch_coverage=1 # ------------------------------------------------------------------ # Release tarball # ------------------------------------------------------------------ PG_TRE_VERSION = 4.5.1 DIST_NAME = pg_tre-$(PG_TRE_VERSION) dist: @echo "==> Creating $(DIST_NAME).tar.gz" git archive --format=tar --prefix=$(DIST_NAME)/ HEAD -o $(DIST_NAME).tar @echo " Archiving submodules" @ ( cd vendor/tre && git archive --format=tar --prefix=$(DIST_NAME)/vendor/tre/ HEAD ) \ > $(DIST_NAME)-tre.tar @ ( cd vendor/lime && git archive --format=tar --prefix=$(DIST_NAME)/vendor/lime/ HEAD ) \ > $(DIST_NAME)-lime.tar @# one archive per --concatenate: given two, GNU tar 1.35 appends only the @# first, so the 4.4.0-4.5.1 release tarballs had no vendor/lime tar --concatenate --file=$(DIST_NAME).tar $(DIST_NAME)-tre.tar tar --concatenate --file=$(DIST_NAME).tar $(DIST_NAME)-lime.tar rm -f $(DIST_NAME)-tre.tar $(DIST_NAME)-lime.tar @for f in vendor/tre/configure.ac vendor/lime/lime.c; do \ tar tf $(DIST_NAME).tar | grep -qx "$(DIST_NAME)/$$f" || \ { echo "dist: $$f missing from $(DIST_NAME).tar" >&2; exit 1; }; \ done gzip -f $(DIST_NAME).tar @echo " $(DIST_NAME).tar.gz ready" @ls -la $(DIST_NAME).tar.gz @echo " SHA256: $$(sha256sum $(DIST_NAME).tar.gz | awk '{print $$1}')" # Local regression runner that sidesteps our nix-build pg_regress # exec-path quirk. Invokes scripts/run-regress.sh against an already- # running postmaster (must have pg_tre in shared_preload_libraries). # Named localcheck to avoid overriding PGXS's standard `check` target. localcheck: PG_CONFIG='$(PG_CONFIG)' bash scripts/run-regress.sh # Shell-based test scripts under test/scripts/. Each script is # self-contained (initdb's its own cluster on a private port, # cleans up on exit), modeled on pg_textsearch's # test/scripts/*.sh layout. test-wal-audit: @echo "==> wal_audit.sh" PG_CONFIG='$(PG_CONFIG)' PATH=$$(dirname $(PG_CONFIG)):$$PATH \ bash test/scripts/wal_audit.sh test-stress: @echo "==> stress.sh" PG_CONFIG='$(PG_CONFIG)' PATH=$$(dirname $(PG_CONFIG)):$$PATH \ ITERATIONS=$${ITERATIONS:-30} \ bash test/scripts/stress.sh test-replication: @echo "==> replication.sh" PG_CONFIG='$(PG_CONFIG)' PATH=$$(dirname $(PG_CONFIG)):$$PATH \ bash test/scripts/replication.sh test-shell: test-wal-audit test-replication @echo "All shell-based tests completed." @echo "Run 'make test-stress' separately for the long-running test." test-all: localcheck test-shell @echo "Regression suite + shell tests completed." # TAP test runner for Phase 7 durability testing. # Tests: crash recovery, streaming replication, REINDEX CONCURRENTLY, # pg_upgrade (dump/restore), and soak testing. # Requires prove(1) and PostgreSQL::Test::Cluster module. tapcheck: @echo "Running TAP tests for pg_tre durability..." @if ! command -v prove >/dev/null 2>&1; then \ echo "ERROR: prove not found. Install Test::More and Test::Harness."; \ exit 1; \ fi PG_CONFIG='$(PG_CONFIG)' PERL5LIB='$(shell $(PG_CONFIG) --libdir)/perl5' \ prove -v test/t/*.pl # TAP tests for v1.0.0-final blockers: concurrency, replication, crash recovery. # These are the production-ready tests that gate the v1.0.0 release. tap: @echo "Running TAP tests (concurrency, replication, crash_recovery)..." @if ! command -v prove >/dev/null 2>&1; then \ echo "ERROR: prove not found. Install Test::More and Test::Harness."; \ exit 1; \ fi @if ! command -v nix-shell >/dev/null 2>&1 || [ -n "$(NO_NIX_SHELL)" ]; then \ PG_CONFIG='$(PG_CONFIG)' \ PERL5LIB='$(PG_TAP_PERL5LIB)' \ PG_REGRESS='$(PG_REGRESS)' \ TMPDIR='$(PG_TAP_TMPDIR)' \ PATH=$$(dirname $(PG_CONFIG)):$$PATH \ prove -v tap/*.pl; \ else \ PG_BIN_DIR=$$(dirname $(PG_CONFIG)); \ nix-shell -p '(perl.withPackages (p: [ p.IPCRun ]))' --run " \ export PG_CONFIG='$(PG_CONFIG)'; \ export PERL5LIB='$(PG_TAP_PERL5LIB)'; \ export PG_REGRESS='$(PG_REGRESS)'; \ export TMPDIR='$(PG_TAP_TMPDIR)'; \ export PATH=$$PG_BIN_DIR:\$$PATH; \ mkdir -p \\\"\$$TMPDIR\\\"; \ prove -v tap/*.pl"; \ fi vendor-clean: -$(MAKE) -C $(TRE_DIR) distclean 2>/dev/null || true -@if git -C $(TRE_DIR) apply --reverse --check -p1 $(abspath $(TRE_PATCH)) >/dev/null 2>&1; then \ echo "==> unpatch TRE (progress hook)"; \ git -C $(TRE_DIR) apply --reverse -p1 $(abspath $(TRE_PATCH)); \ fi rm -f $(TRE_PATCH_STAMP) rm -f $(LIME_BIN) distclean-full: clean vendor-clean rm -f $(GRAMMAR_C) $(GRAMMAR_H) clean: clean-grammar clean-grammar: rm -f $(GRAMMAR_C) $(GRAMMAR_H) src/query/tre_grammar.o