Contents
Test coverage
make coverage measures how well the test suite exercises ProvSQL, at two
granularities:
Function-call coverage (plpgsql + C). With
track_functions = all, the server records a call count per function inpg_stat_user_functions. After the run,coverage/zero_call.txtlistsprovsqlplpgsql/C functions with zero calls (fromzero_call_functions.sql). The coverage run drops theextension_upgradetest from the schedule, because itsDROP EXTENSIONwould purge these counters (they are keyed by function OID).pg_stat_user_functionsonly counts functions entered through the executor, sozero_call_functions.sqlfilters out the categories it structurally never counts, leaving genuine coverage gaps:LANGUAGE sqlfunctions (inlined), type input/output/cast functions and aggregate support functions (detected from the catalogs), and ProvSQL’s planner-rewritten placeholders/markers —provenance(), the comparison operators, the| (predicate)conditioning forms — which are declared for the parser but rewritten away before execution (listed explicitly in the query; keep it in sync with the source’s “Never executes” / “Placeholder” comments). A few C rows reached only viaDirectFunctionCall/SPI from the C core can still slip through, so cross-check a C entry against the gcovr line report; plpgsql rows are reliable.- C/C++ line and branch coverage. The extension is rebuilt with gcov
instrumentation (
--coverage, LTO off,-O0);gcovrthen produces a per-file line and branch report undercoverage/(openindex.html).
make coverage needs gcovr. Install it isolated with
pipx install gcovr (a system gcovr can clash with an unrelated jinja2 in
~/.local); override with make coverage GCOVR=/path/to/gcovr if needed.
How it works
Measuring coverage against a shared PostgreSQL server is awkward: provsql is in
shared_preload_libraries, so the postmaster holds the loaded .so (an
instrumented build only takes effect after a restart); the gcov .gcda files
are written by the backend processes next to the .gcno under src/, so the
server must run as the user who built the tree; the long-lived postmaster /
background-worker counters only flush on a clean stop; and installing an
instrumented build system-wide needs root and disturbs the running server.
test/coverage/run-coverage.sh sidesteps all of that. It stages the
instrumented extension into a private prefix under /tmp with
make install DESTDIR=... (no sudo, nothing written to the system PostgreSQL),
then runs the suite against a throwaway cluster it creates under
/tmp/provsql_coverage, owned by whoever runs make coverage. The cluster is
pointed at the staged build with extension_control_path (for CREATE
EXTENSION), dynamic_library_path, and an absolute shared_preload_libraries;
the staged control file’s module_pathname is rewritten to the staged .so so
the extension’s C functions load the instrumented copy. It sets
track_functions=all, runs the regression schedule (installcheck, under the
tdkc supervisor), and is stopped cleanly so every .gcda is flushed before
gcovr runs.
This relies on extension_control_path, so it needs PostgreSQL >= 18.
Override the cluster/staging location or port with PROVSQL_COVERAGE_DIR /
PROVSQL_COVERAGE_STAGE / PROVSQL_COVERAGE_PORT.
After a run
Nothing is installed into the system PostgreSQL, so there is nothing to undo there. The local build tree is left instrumented; rebuild the normal optimised objects when you next need them with:
make
Troubleshooting
- gcovr reports 0 % everywhere / no
.gcda. The backends could not write.gcda(wrong user) or ran an uninstrumented library. The temp-cluster script avoids both; if you measure by hand against your own server instead, it must run the instrumented build and run as the user who ownssrc/. ImportError: cannot import name 'Markup' from 'jinja2'. An oldgcovragainstjinja2 >= 3.1. Use apipx-installedgcovrand point the target at it withGCOVR=.
plpgsql line/branch coverage (not wired in)
pg_stat_user_functions gives plpgsql functions only a call count, not
statement coverage. For per-statement / per-branch plpgsql coverage, install
plpgsql_check and use its profiler
(plpgsql_coverage_statements(), plpgsql_coverage_branches()) over the
regression database after a run.