Skip to content

Go ​

pgx works with pgRDF like any other extension: every capability is a SQL function. Examples use the Docker setup from the install guide.

bash
go get github.com/jackc/pgx/v5
go
package main

import (
	"context"
	"errors"
	"fmt"
	"log"

	"github.com/jackc/pgx/v5"
	"github.com/jackc/pgx/v5/pgconn"
)

func main() {
	ctx := context.Background()
	conn, err := pgx.Connect(ctx, "postgres://postgres:pgrdf@localhost:5432/postgres")
	if err != nil { log.Fatal(err) }
	defer conn.Close(ctx)

	if _, err := conn.Exec(ctx, "CREATE EXTENSION IF NOT EXISTS pgrdf"); err != nil { log.Fatal(err) }

	// create a graph and load Turtle
	var graphID int64
	if err := conn.QueryRow(ctx, `SELECT pgrdf.add_graph($1)`,
		"http://example.org/people").Scan(&graphID); err != nil { log.Fatal(err) }

	var n int64
	err = conn.QueryRow(ctx, `SELECT pgrdf.parse_turtle($1, $2)`,
		`@prefix ex: <http://example.org/> .
		 @prefix foaf: <http://xmlns.com/foaf/0.1/> .
		 ex:alice foaf:name "Alice" ; foaf:knows ex:bob .
		 ex:bob   foaf:name "Bob" .`, graphID).Scan(&n)
	if err != nil { log.Fatal(err) }
	fmt.Println("loaded", n, "triples")

	// SPARQL: each row is a JSONB object → map[string]any
	rows, err := conn.Query(ctx, `SELECT sparql FROM pgrdf.sparql($1)`,
		`PREFIX foaf: <http://xmlns.com/foaf/0.1/>
		 SELECT ?who ?friend WHERE { ?a foaf:name ?who ; foaf:knows ?b . ?b foaf:name ?friend }`)
	if err != nil { log.Fatal(err) }
	for rows.Next() {
		var b map[string]any
		if err := rows.Scan(&b); err != nil { log.Fatal(err) }
		fmt.Println(b["who"], "→", b["friend"])
	}
	if err := rows.Err(); err != nil { log.Fatal(err) }

	// refusals carry a SQLSTATE
	_, err = conn.Exec(ctx, `SELECT pgrdf.materialize($1, 'bogus')`, graphID)
	var pgErr *pgconn.PgError
	if errors.As(err, &pgErr) {
		fmt.Println(pgErr.Code, pgErr.Message)   // 22023 materialize: unknown profile ...
	}
}

Typed bindings ​

For a fixed query shape, scan the JSONB into a struct:

go
type Person struct {
	Who    string `json:"who"`
	Friend string `json:"friend"`
}

rows, _ := conn.Query(ctx, `SELECT sparql FROM pgrdf.sparql($1)`, query)
people, err := pgx.CollectRows(rows, pgx.RowTo[Person])

Was the answer complete? ​

Run this on the same connection, right after the query:

go
var stats map[string]any
conn.QueryRow(ctx, `SELECT pgrdf.last_call_stats()`).Scan(&stats)
complete := stats["path_depth_truncations"] == float64(0) &&
	stats["filter_clauses_dropped"] == float64(0)

With a pgxpool.Pool, acquire one connection (pool.Acquire) for the query and the stats call so both run in the same session.

Error codes ​

CodeMeaning
55P03graph locked
55000wrong state (e.g. unlock an unlocked graph)
22023invalid argument
0A000unsupported construct
42704unknown graph
2BP01drop without cascade over inferred triples
54000configured limit exceeded

Full list: errors and diagnostics.

Tips ​

  • pgrdf.load_turtle(path, …) reads from the database server's filesystem. For local files, read them and use parse_turtle.
  • SQL parameters protect the SQL call, not the SPARQL text inside it. Escape user input you splice into queries.
  • Values in SPARQL results are strings. Convert numbers with strconv.

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