Debugging

This page covers tools and techniques for diagnosing issues in ProvSQL.

Debug Builds

Build with debug symbols and no optimization:

make DEBUG=1

This passes -O0 -g to the compiler, making GDB-based debugging practical.

Verbose Logging

The provsql.verbose_level GUC controls runtime debug output. Set it per-session:

SET provsql.verbose_level = 50;

The GUC is an integer 0--100. Only three thresholds actually gate output:

Level Output
0 (default) Quiet. Values between 1 and 19 behave the same as 0.
20+ Full query text before and after ProvSQL rewriting (PostgreSQL 15+ only, via pg_get_querydef), plus verbose output from the Boolean circuit and DOT export code.
40+ Adds timing of the rewriting phase.
50+ Adds a dump of the PostgreSQL Query node tree before and after rewriting (via elog_node_display).

The elog_node_display output (level ≥ 50) shows the full internal representation of the query tree. This is invaluable for understanding exactly what the rewriter changed, but produces very large output.

Inspecting Circuits

ProvSQL provides SQL functions for examining the provenance circuit stored in the mmap backend. These are useful for verifying that the rewriter produced the expected circuit structure.

  • get_gate_type -- returns the gate type of a token (e.g., times, plus, input).
  • get_children -- returns the child tokens of a gate.
  • get_infos -- returns the integer annotations of a gate (used by aggregation and semimodule gates).
  • get_nb_gates -- returns the total number of gates in the circuit store.
  • identify_token -- returns the human-readable label of an input gate (from a provenance mapping).

Example session:

-- Run a query and capture the provenance token
SELECT *, provenance() FROM my_table WHERE condition;

-- Inspect the circuit rooted at a token
SELECT provsql.get_gate_type('some-uuid');
SELECT provsql.get_children('some-uuid');

Visualizing Circuits

view_circuit renders a provenance circuit as an ASCII box-art diagram and is often the fastest way to verify that the rewriter built the correct circuit structure. See ../user/export for usage details and requirements.

Disabling Provenance

To quickly check whether a bug is in ProvSQL's rewriting or elsewhere:

SET provsql.active = false;

This disables the planner hook entirely -- queries run as if the extension were not loaded (though provsql columns are still stripped from results).

GDB Tips

Attach GDB to a PostgreSQL backend process:

# Find the backend PID (from a psql session)
SELECT pg_backend_pid();

# Attach
gdb -p <pid>

# Useful breakpoints
break provsql_planner
break process_query
break make_provenance_expression
break get_provenance_attributes

When debugging the mmap background worker, attach to the worker process instead (find it via ps aux | grep provsql).

PostgreSQL ships with print(void *) and pprint(void *) functions (src/backend/nodes/print.c, declared in src/include/nodes/print.h) that dump any Node * to the backend's stderr, with pprint producing pretty-printed output. From GDB you can invoke them on the current backend with call pprint(q) to inspect a Query tree, or similarly on any other node pointer. See the PostgreSQL Developer FAQ for more debugging tips.