Integrate with zodb-pgjsonb#
The zodb-pgjsonb storage backend uses zodb-json-codec to transcode ZODB pickle records into PostgreSQL JSONB. This guide explains the codec functions designed for that integration.
The data pipeline#
When a ZODB object is stored, its pickle bytes flow through the codec into PostgreSQL:
pickle bytes --> Rust decode --> JSON --> PostgreSQL JSONB column
On read, the reverse path reconstructs the original pickle bytes:
PostgreSQL JSONB --> JSON --> Rust encode --> pickle bytes
Two fast paths for decoding#
The codec provides two PG-specific decode functions. Both handle null-byte sanitization and persistent reference extraction in a single pass.
Python dict path#
decode_zodb_record_for_pg() returns a Python dict.
The GIL is released during the Rust pickle-parsing phase, then reacquired to build the Python dict.
from zodb_json_codec import decode_zodb_record_for_pg
class_mod, class_name, state_dict, refs = decode_zodb_record_for_pg(pickle_data)
# class_mod: "persistent.mapping" (str)
# class_name: "PersistentMapping" (str)
# state_dict: {"data": {"key": "value"}} (dict)
# refs: [123456789, ...] (list of int OIDs)
Use this path when you need to inspect or transform the state in Python before writing to the database (for example, extracting extra columns via a state processor).
Direct JSON string path#
decode_zodb_record_for_pg_json() returns a JSON string directly.
The entire pipeline – pickle decode, JSON serialization, null-byte sanitization, and ref extraction – runs in Rust with the GIL released.
from zodb_json_codec import decode_zodb_record_for_pg_json
class_mod, class_name, json_str, refs = decode_zodb_record_for_pg_json(pickle_data)
# json_str is a ready-to-insert JSON string
This is the fastest path: no intermediate Python dicts are allocated, and other Python threads can run during the entire operation.
Null-byte sanitization#
PostgreSQL JSONB cannot store \u0000 (null bytes) in strings.
Both PG decode functions automatically replace strings containing null bytes with {"@ns:" "<base64>"} markers.
On encode, these markers are transparently converted back to the original byte sequences.
Persistent reference extraction#
The refs list returned by both functions contains all persistent reference OIDs found in the object state, as Python integers (big-endian interpretation of the 8-byte ZODB OID).
Cross-database references with non-standard OID sizes are silently skipped.
zodb-pgjsonb stores these in a refs column for pure-SQL garbage collection (pack) without needing to deserialize the JSON.
Encoding back to pickle#
To reconstruct ZODB pickle bytes from a JSON record:
from zodb_json_codec import encode_zodb_record
record = {
"@cls": ["persistent.mapping", "PersistentMapping"],
"@s": {"data": {"key": "value"}},
}
pickle_bytes = encode_zodb_record(record)
The encoder produces two concatenated pickles (class pickle + state pickle) in protocol 3 format, matching ZODB’s expected record layout.