Skip to content

copy_graph — copy one graph into another ​

Append every triple of one graph into another, inferred triples included. Returns the number of triples copied.

What it does ​

pgrdf.copy_graph(src_iri TEXT, dst_iri TEXT) → BIGINT
pgrdf.copy_graph(src BIGINT,   dst BIGINT)   → BIGINT
  • By IRI, both graphs must exist. Create the destination with pgrdf.add_graph(iri) first; an unknown source or destination IRI refuses with 42704.
  • By id, a missing destination is created and named urn:pgrdf:graph:<id>. Copying from an id that has no graph returns 0 and creates nothing.
  • Copy appends. Triples already in the destination stay. Copying twice puts every triple in twice. For an exact copy, clear the destination first (see below).
  • Inferred triples come along. The copy's materialization reads unknown in graph_inventory(), because no materialize run produced them for that graph. Run materialize on the copy if you rely on them.
  • The source is untouched, and may itself be locked. A locked destination refuses (55P03).
  • It is transactional, and its time grows with the number of triples copied.

Why you'd use it ​

  • Project managers — fork a baseline graph for a parallel experiment and keep the original untouched.
  • Data scientists — take a scratch copy of a production graph to experiment on.
  • Ontologists — start a new vocabulary version from a copy of the current one, then evolve the copy.
  • Backend engineers — copy production into staging, change staging, then move_graph it back.

Example ​

sql
SELECT pgrdf.add_graph('http://example.org/orders');
SELECT pgrdf.parse_turtle('
@prefix ex:   <http://example.org/> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix xsd:  <http://www.w3.org/2001/XMLSchema#> .

ex:RushOrder rdfs:subClassOf ex:Order .
ex:o1 a ex:Order     ; ex:total "120.00"^^xsd:decimal .
ex:o2 a ex:RushOrder ; ex:total "80.50"^^xsd:decimal .
', pgrdf.graph_id('http://example.org/orders'));
-- → 5

SELECT pgrdf.materialize(pgrdf.graph_id('http://example.org/orders'), 'rdfs')
       ->> 'inferred_triples_written';
-- → 1   (ex:o2 a ex:Order)

-- Copying by IRI needs the destination to exist.
SELECT pgrdf.add_graph('http://example.org/orders-fork');
SELECT pgrdf.copy_graph('http://example.org/orders', 'http://example.org/orders-fork');
-- → 6   (5 asserted + 1 inferred)

SELECT iri, asserted, inferred, materialization
  FROM pgrdf.graph_inventory()
 WHERE iri LIKE 'http://example.org/orders%';
--               iri               | asserted | inferred | materialization
-- --------------------------------+----------+----------+-----------------
--  http://example.org/orders      |        5 |        1 | current
--  http://example.org/orders-fork |        5 |        1 | unknown

SELECT pgrdf.graph_digest(pgrdf.graph_id('http://example.org/orders')) =
       pgrdf.graph_digest(pgrdf.graph_id('http://example.org/orders-fork')) AS identical;
-- → t

graph_digest compares the asserted triples, so it confirms the copy is the same graph.

Copy appends ​

Running the same copy again doubles the destination:

sql
SELECT pgrdf.copy_graph('http://example.org/orders', 'http://example.org/orders-fork');
-- → 6
SELECT asserted, inferred FROM pgrdf.graph_inventory()
 WHERE iri = 'http://example.org/orders-fork';
--  asserted | inferred
-- ----------+----------
--        10 |        2

For an exact copy, clear the destination first, then re-run reasoning on the result:

sql
BEGIN;
SELECT pgrdf.clear_graph('http://example.org/orders-fork');
SELECT pgrdf.copy_graph('http://example.org/orders', 'http://example.org/orders-fork');
COMMIT;

SELECT pgrdf.materialize(pgrdf.graph_id('http://example.org/orders-fork'), 'rdfs');
-- the fork's materialization now reads current

Refusals ​

SQLSTATEWhenExample message
42704The source or destination IRI is not a known graphcopy_graph: unknown iri "http://example.org/orders-copy"
22023Source and destination are the same graph, or an id is negativecopy_graph: src and dst must differ (both = 1)
55P03The destination is lockedpgrdf: graph 1 is locked (release review): copy_graph (destination) refused. Unlock with pgrdf.unlock_graph(1, '<reason>').

The full table is on Errors and diagnostics.

See also ​

pgRDF is released under the MIT license. Documentation built with VitePress, served via GitHub Pages.