Feat: model pooler mode in ConnectionParams for PgBouncer transaction-mode + custom types (tabularis-postgresql-plugin#157, #1097 residual)
Maintainers usually reply within 1 day
A pull request for this has already been merged.
- #1128 by @aesslinger — merged
Assessment
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Newbie friendliness
- 25/100
- Issue type
- Feature
- Clarity
- Mostly clear
- Activity status
- Stale
- Tech stack
- postgresql, rust, typescript
Research direction
Start with the ConnectionParams struct in src-tauri/src/models.rs, where the new pooler_mode: Option<String> field with #[serde(default)] goes, then find the PostgreSQL connection settings form in the frontend to add the dropdown and hint text. The work is already claimed by linked PR #1128 and depends on companion issue tabularis-postgresql-plugin#157, so check those first. Done means the field round-trips through serde and the dropdown shows the max_prepared_statements hint for transaction mode.
Written by the indexing model from the issue text.
Description
Background
rc.9 of the postgresql-plugin fixed the primary PgBouncer prepared-statement failure (#1097) by routing all user-issued queries through the unnamed-statement protocol. However, a residual gap remains: when a query returns columns with non-builtin types (custom enums, composites, extension types), tokio-postgres's internal type resolution fires a named typeinfo_statement that splits across two Syncs — the same pooler-unsafe pattern. Under PgBouncer transaction mode, this fails with ERROR: prepared statement "typeinfo_statement" does not exist (SQLSTATE 26000/42P05).
The plugin can't eliminate this trigger without patching tokio-postgres, but it can adapt its own behavior (avoid its own prepare() calls, surface actionable error messages) — if it knows the connection goes through a transaction-mode pooler. Currently neither the host nor the plugin models this.
What needs to happen on the host side
1. Add pooler_mode to ConnectionParams (src-tauri/src/models.rs)
/// Connection pooler mode, set by the user when connecting through PgBouncer
/// or another transaction-mode pooler. Drives driver-side behavior:
/// the postgresql-plugin avoids its own named-statement `prepare()` calls
/// and surfaces actionable error messages for tokio-postgres's internal
/// `typeinfo_statement` (which requires `max_prepared_statements > 0` on
/// the pooler side for custom types). None for direct connections.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub pooler_mode: Option<String>, // "transaction" | "session" | None
Forwarded to the plugin automatically via serde in every RPC params object. The plugin parses it in ConnectionParams::from_value and uses it to gate pooler-unsafe behavior. See companion issue tabularis-postgresql-plugin#157 for the plugin-side consumption.
2. Expose in the PostgreSQL connection UI
A "Pooler mode" dropdown in the connection settings (None / PgBouncer transaction / PgBouncer session). When set to "transaction," show a hint:
When using PgBouncer in transaction mode with custom types (enums, composites, extension types), set
max_prepared_statements > 0in pgbouncer.ini. This enables server-side prepared statement caching so named statements survive connection reassignment.
3. No host-side query-path changes needed
The query execution path is entirely in the plugin. The host's role is to model the pooler mode and forward it — the plugin does the rest. The builtin Postgres driver is frozen (deprecated, not receiving this fix per the #1097 discussion); the plugin is the forward path.
Why this modeling approach (PostgreSQL ecosystem perspective)
The PostgreSQL ecosystem converged on a two-part answer for prepared statements under transaction-mode poolers:
- Client side: use the unnamed statement where possible (the plugin did this in rc.9).
- Pooler side:
max_prepared_statements > 0for named statements that can't be eliminated from the client/driver (tokio-postgres's internaltypeinfo_statement).
Modeling pooler mode as a first-class connection property lets the plugin adapt its behavior without unreliable runtime detection (SHOW server_version through PgBouncer returns the backend version, not PgBouncer's; SHOW CONFIG requires a separate admin connection). The user explicitly declares "this is a pooler connection," and the system adapts.
This is the same pattern as JDBC's preferQueryMode and libpq's prepare_threshold — connection-level configuration that drives prepared-statement behavior.
Scope
ConnectionParamsgets one newOption<String>field (pooler_mode) — backward-compatible (#[serde(default)]).- Connection UI gets a dropdown + hint text.
- No query-path changes on the host side.
- Plugin-side changes tracked in tabularis-postgresql-plugin#157.
References
- #1097 — the original PgBouncer prepared-statement bug
- tabularis-postgresql-plugin#157 — companion issue (plugin-side consumption of
pooler_mode) - psaus's feedback on #1097: "the limitation is triggered by any column with a non-builtin type, and enums, composites and extension types are common use cases, not rare ones"
- PgBouncer
max_prepared_statementsdocs: https://www.pgbouncer.org/config.html#max_prepared_statements (added in PgBouncer 1.21, 2023)
- Dominant language
- TypeScript
- Stars
- 5.1k
- Forks
- 335
- Avg merge
- 1d 7h
- Merged PRs (30d)
- 255
Getting set up
- No Dockerfile or Docker Compose file
- No pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from TabularisDB/tabularis
-
[Feat]: Make editor crash reports actionable with copy, AI analysis, and issue creationPossibly taken @Detoy claimed this 1 day ago. Openfeature request
Difficulty 4/5 3-5 days Newbie friendliness 45/100
TabularisDB/tabularis#1360 · 3 comments · 1 assignee ·
Maintainers usually reply within 1 day
-
[Feat]: Align the Web password login page with Tabularis designPossibly taken @Detoy claimed this 4 days ago. Openfeature request
TabularisDB/tabularis#1341 · 2 comments · 1 assignee ·
Maintainers usually reply within 1 day
-
Difficulty 5/5 Over a week Newbie friendliness 25/100
TabularisDB/tabularis#1328 ·
Maintainers usually reply within 1 day
-
[Bug]: OpenAI compatible provider requires API key, even when not actually required by providerPossibly taken @dyk1454683243-sudo claimed this 4 days ago. Openbug
Difficulty 3/5 1-2 days Newbie friendliness 58/100
TabularisDB/tabularis#1323 · 2 comments · 1 assignee ·
Maintainers usually reply within 1 day
-
feature request good first issue
Difficulty 4/5 3-5 days Newbie friendliness 55/100
TabularisDB/tabularis#1314 ·
Maintainers usually reply within 1 day
All issues in TabularisDB/tabularis
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
JuliusBrussee/caveman#1449 ·
Maintainers usually reply within 1 day
-
Difficulty 1/5 Under an hour Newbie friendliness 78/100
linagora/twake-calendar-frontend#1924 ·
Maintainers usually reply within 1 day
-
Add: Class TV ModaOpencheck:passed streams:add
Difficulty 1/5 Under an hour Newbie friendliness 65/100
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
libnativeapi/nativeapi#21 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 62/100
GiganticMinecraft/seichi-playguide#183 ·
Maintainers usually reply within 1 day