spqrguard blocks direct writes to SPQR-managed tables. Writes through a
router are not affected.
This guide shows how to add spqrguard to an existing cluster. It requires a
coordinator with a configured
shard_data file. The
coordinator uses that file to connect to shard primaries and sync metadata.
How the pieces fit together
The write block applies when the session settings
spqrguard.prevent_distributed_table_modify and
spqrguard.prevent_reference_table_modify are unset. Direct connections
normally leave them unset and inherit the block. Router connections set both
values to off, so routed writes remain allowed.
SPQR currently accepts only extension version 2.3. The spqrguard repo
might show a newer default version. Always create the extension with
VERSION '2.3'. Before upgrading SPQR, recheck the accepted versions in
SetUpSPQRGuard
or release notes.
Before you start
You will restart every shard, router, and coordinator. Traffic stays online if each layer is redundant and you restart one instance at a time. You need:- Superuser access to every routed database.
spqrguardbuilt for each PostgreSQL major version in the cluster.- Access to configs of all shards, routers, and coordinators.
- A tested failover procedure if using HA.
- Backups of configs and affected databases.
1. Install the extension files on every shard host
Installspqrguard on every primary and replica. Use the same revision
everywhere. If there’s no package, build from source:
pg_config from the right PostgreSQL major version. Repeat for each
major version in the cluster.
Before the next step, check that PostgreSQL sees the extension files on every
instance:
default_version might be newer than 2.3.
That’s fine.
2. Preload the module and restart PostgreSQL
Addspqrguard to shared_preload_libraries in postgresql.conf. Keep the
existing libraries:
spqrguard must appear in the list. Both settings should show unset.
3. Create extension version 2.3 in every routed database
On each shard primary, run this for every routed database:2.3. Streaming replication copies the catalog change to
standbys. Module files and shared_preload_libraries must still be present on
each standby. For logical replication, create the extension on each node.
If an older version is installed:
4. Enable relation metadata maintenance
Turn on metadata maintenance but keep the write block off. On every router, add the following underquery_routing:
query_routing.forbid_direct_shard_queries is a deprecated alias for
query_routing.use_spqrguard.
On every coordinator, use:
5. Verify relation metadata
First check that the write block is still off. Run this on every routed database on every shard. It should return no enabled rows:42— prevent changes to distributed tables.69— prevent changes to reference tables.
true, that shard already blocks direct writes. Set it to
false until all metadata checks pass.
Connect to the coordinator console and run:
6. Enable the direct-write block
After all metadata checks pass, change every coordinator config:7. Test both connection paths
Use fresh connections. Don’t reuse sessions from earlier steps.A direct write must fail
Connect directly to each shard primary. Choose a distributed table without statement-level triggers or external side effects. Replaceyour_schema.your_distributed_table with its qualified name:
DELETE must fail before changing data:
your_schema.your_reference_table with its qualified name:
spqr_metadata are protected. If a managed table can
still be changed directly, check its relation OID in the metadata. Also confirm
that the session setting is unset, not off.
A routed write must succeed
Connect through every router. Run a valid single-shard write and roll it back. Use a real shard key and a safe non-key column. Replace allyour_*
identifiers:
spqrguard error. Router connections set both
settings to off, which allows writes. Direct connections leave them unset
and inherit the block.
For HA shards, test a failover. Repeat the direct-write check on the new
primary.
Rollback
If writes through SPQR start failing, disable the block first. Investigate afterward. Run this on every routed database on every shard primary:query_routing.use_spqrguard enabled on every router. Removing the
extension or its shared_preload_libraries entry is a separate procedure. It
is not needed for rollback.