Graph lifecycle UDFs
Four partition-level primitives —
drop_graph,clear_graph,copy_graph,move_graph— that manage a named graph as a first-class lifecycle unit, not a row-by-row table.
What it does
The lifecycle UDFs treat each named graph as the partition-level object it really is. They all return BIGINT and share the same stable error-prefix contract.
| UDF | Signature | What it does |
|---|---|---|
drop_graph | pgrdf.drop_graph(id BIGINT, cascade BOOLEAN DEFAULT TRUE) → BIGINT | DETACH + DROP the LIST partition; remove the _pgrdf_graphs row. Returns pre-drop triple count. |
clear_graph | pgrdf.clear_graph(id BIGINT) → BIGINT | TRUNCATE ONLY the partition. Partition + IRI binding survive. Returns rows-removed count. |
copy_graph | pgrdf.copy_graph(src BIGINT, dst BIGINT) → BIGINT | INSERT INTO … SELECT every row from src to dst. Auto-creates dst if missing. Returns count copied. |
move_graph | pgrdf.move_graph(src BIGINT, dst BIGINT) → BIGINT | Composes copy_graph(src, dst) + drop_graph(src, cascade => TRUE) in the caller's transaction. Returns count moved. |
All four are idempotent on absent inputs (return 0, no error), all four reject negative ids with a stable prefix, and all four cooperate with the _pgrdf_graphs IRI-mapping table so the IRI surface stays consistent across mutations.
Why you'd use them
- Project managers scoping multi-tenant or multi-snapshot workloads: tenant rollback is
drop_graph(tenant_id), snapshot promotion ismove_graph(staging_id, prod_id). No row-by-row delete; no application-level orchestration. - Data scientists building incremental pipelines: stage data into a scratch graph, validate it, then
move_graphit into the named production graph atomically inside one Postgres transaction. - Ontologists publishing iterative ontology versions:
copy_graph(old_version_id, new_version_id)to fork a baseline, evolve it, materialize the new closure, swap viamove_graph. - Backend engineers writing graph-management code paths: a single SQL call per operation. Stable error prefixes (
drop_graph:,clear_graph:,copy_graph:,move_graph:) make programmatic error handling reliable. - Operators doing maintenance: drop or clear a stale graph without writing a
DELETE FROM … WHERE graph_id = Nagainst the giant_pgrdf_quadsparent (which would lock-walk the whole partition hierarchy).
Worked end-to-end example
-- 1. Stage some data into a scratch graph
SELECT pgrdf.add_graph(900, 'http://example.org/orders/2026-Q1-staging');
SELECT pgrdf.load_turtle('/data/orders-2026-Q1.ttl', 900);
-- → 48,217
-- 2. Materialize OWL 2 RL inferences on the staged graph
SELECT pgrdf.materialize(900);
-- → {"base_triples": 48217, "inferred_triples_written": 11042, ...}
-- 3. Validate against SHACL shapes
SELECT pgrdf.validate(900, 200);
-- → {"conforms": true, "results": []}
-- 4. Promote staging → production atomically
BEGIN;
SELECT pgrdf.drop_graph(100); -- ditch the old production graph
-- → 38,910
SELECT pgrdf.move_graph(900, 100); -- relabel staging as production
-- → 59,259
SELECT pgrdf.add_graph(100, 'http://example.org/orders/2026-Q1');
COMMIT;The whole flow — load → infer → validate → promote — runs in one Postgres connection. A rollback at any step unwinds everything (lifecycle UDFs commit with the caller's transaction).
End-to-end integration tests
The four UDFs are exercised together by tests/regression/sql/92-lifecycle-end-to-end.sql, which locks five interaction-level invariants no per-UDF file can:
- Load → copy → drop round-trip — the destination graph still answers the original BGP after the source is dropped.
move_graphis a faithful compose of copy + drop —srcanswers like a freshly-dropped graph;dstlike a freshly-copied graph.clear_graphisolation under a shared dict cache — clearing one graph does not touch a sibling that loaded the same vocabulary.- SPARQL
GRAPH <iri>projection survives the lifecycle — IRI rebinding + partition routing both hold throughmove_graph. - Drop-then-rebind loop — re-allocate a recycled
graph_idwith a fresh IRI; no stale_pgrdf_graphsstate blocks it.
See also
- Per-graph LIST partitions — the substrate the lifecycle UDFs manage.
- Named graphs — IRI ↔ id mapping — what the
_pgrdf_graphsrow each UDF maintains looks like. - GRAPH
<iri> { … }in SPARQL — how the partition surface presents to SPARQL queries.