Session variables
A jed session can carry named string settings — PostgreSQL’s GUC model, scoped to the session.
The host sets them through the API; SQL reads them with current_setting(). They are a clean way
to thread per-request context (a tenant id, a request id, a feature flag) into the queries a session
runs, without weaving it through every statement’s parameters.
Setting and reading
A variable is a string → string pair (PostgreSQL settings are all text). A custom variable must be namespaced — a dotted name like myapp.tenant — to stay distinct from built-in settings; a
non-dotted name is rejected with 42704. Names are case-insensitive; values are kept verbatim.
use jed::{CreateOptions, Database, SessionOptions};
fn main() -> jed::Result<()> {
let mut db = Database::create(CreateOptions { path: Some("app.jed".into()), ..Default::default() })?;
// Session variables are PostgreSQL's GUC model — they live on a SESSION, so mint one from the
// database rather than using the bare handle. A custom variable must be NAMESPACED — a dotted name
// like `myapp.tenant`; a non-dotted name is 42704.
let mut s = db.session(SessionOptions::default());
s.set_var("myapp.tenant", "acme")?;
// Read it back through the host API — the name is case-insensitive; an unset name is None.
assert_eq!(s.var("myapp.tenant"), Some("acme".to_string()));
// ... or in SQL with current_setting(): `SELECT current_setting('myapp.tenant')` -> "acme".
let _rows = s.query("SELECT current_setting('myapp.tenant')", &[])?;
// An unset name is 42704, unless the two-arg form passes missing_ok = true, which returns NULL:
// SELECT current_setting('myapp.unset') -- 42704
// SELECT current_setting('myapp.unset', true) -- NULL
// Variables are SESSION state, not data — they do NOT roll back with a transaction. reset_var
// clears one by name.
s.reset_var("myapp.tenant")?;
s.close();
Ok(())
}
package main
import (
"context"
"fmt"
"log"
jed "github.com/jackc/jed/impl/go"
)
func main() {
db, err := jed.CreateDatabase(jed.CreateOptions{Path: "app.jed"})
if err != nil {
log.Fatal(err)
}
defer db.Close()
ctx := context.Background()
// Session variables are PostgreSQL's GUC model — they live on a SESSION, so mint one from the
// database rather than using the bare handle. A custom variable must be NAMESPACED — a dotted name
// like myapp.tenant; a non-dotted name is 42704.
s := db.Session(jed.SessionOptions{})
defer s.Close()
if err := s.SetVar("myapp.tenant", "acme"); err != nil {
log.Fatal(err)
}
// Read it back through the host API — the name is case-insensitive; ok is false if it is unset.
if v, ok := s.Var("myapp.tenant"); ok {
fmt.Println("tenant:", v) // acme
}
// ... or in SQL with current_setting(): SELECT current_setting('myapp.tenant') -> "acme".
if _, err := s.Exec(ctx, "SELECT current_setting('myapp.tenant')"); err != nil {
log.Fatal(err)
}
// An unset name is 42704, unless the two-arg form passes missing_ok = true, which returns NULL:
// SELECT current_setting('myapp.unset') -- 42704
// SELECT current_setting('myapp.unset', true) -- NULL
// Variables are SESSION state, not data — they do NOT roll back with a transaction. ResetVar
// clears one by name.
if err := s.ResetVar("myapp.tenant"); err != nil {
log.Fatal(err)
}
}
import { createDatabase } from 'jed-ts';
const db = createDatabase({ path: 'app.jed' });
// Session variables are PostgreSQL's GUC model — they live on a SESSION, so mint one from the
// database rather than using the bare handle. A custom variable must be NAMESPACED — a dotted name
// like `myapp.tenant`; a non-dotted name is 42704.
const s = db.session({});
s.setVar('myapp.tenant', 'acme');
// Read it back through the host API — the name is case-insensitive; an unset name is undefined.
console.log('tenant:', s.var('myapp.tenant')); // acme
// ... or in SQL with current_setting(): `SELECT current_setting('myapp.tenant')` -> "acme".
s.query("SELECT current_setting('myapp.tenant')");
// An unset name is 42704, unless the two-arg form passes missing_ok = true, which returns NULL:
// SELECT current_setting('myapp.unset') -- 42704
// SELECT current_setting('myapp.unset', true) -- NULL
// Variables are SESSION state, not data — they do NOT roll back with a transaction. resetVar clears
// one by name.
s.resetVar('myapp.tenant');
s.close();
db.close();
Reading a variable in SQL
current_setting('name') returns the variable’s value as text:
- An unset name raises
42704(unrecognized configuration parameter). - The two-argument form
current_setting('name', true)passesmissing_ok— an unset name returns NULL instead of raising. current_settingis stable and null-propagating, so it composes in ordinary expressions.
They are session state, not data
Session variables live on the session, not in the database:
- They are not stored in the file, and they do not roll back when a transaction rolls back
(PostgreSQL’s
SET SESSIONbehavior). - Each session has its own independent set — a variable on one session is invisible to another.
reset_var(name)clears one variable by name.
Scope. This is the v1 surface — the host API plus the
current_setting()read. The SQLSET/RESET/SHOWgrammar, a built-intime_zonesetting, and transaction-scopedSET LOCALvariables are planned follow-ons.