Summary
src/client.rs::preflight_startup_script runs the user-configured startup script on a throwaway connection with no timeout. The built-in driver wraps the same preflight in a 30-second tokio::time::timeout. A broken script that blocks (or a stalled host) hangs pool creation — and therefore every metadata/query RPC — indefinitely.
Builtin behavior (upstream main)
src-tauri/src/pool_manager.rs:65:
/// The PostgreSQL startup-script preflight opens a real network connection, so
/// bound it the same way as SQLite: a broken script or a stalled host must
/// never wedge pool creation indefinitely.
const POSTGRES_STARTUP_SCRIPT_TIMEOUT_MS: u64 = 30_000;
…and at line 991, the preflight is wrapped:
let timeout = Duration::from_millis(POSTGRES_STARTUP_SCRIPT_TIMEOUT_MS);
tokio::time::timeout(timeout, run_postgres_startup_script(&cfg, tls_connector.clone(), &script))
.await
.map_err(|_| format!("Timed out running PostgreSQL startup script after {} ms", timeout.as_millis()))?;
Plugin behavior (this repo)
src/client.rs:452 — preflight_startup_script runs tx.batch_execute(script) directly with no timeout wrapper. There are zero tokio::time::timeout calls anywhere in src/. The script's BEGIN/batch_execute/ROLLBACK sequence runs until it finishes or the TCP connection dies; a script that blocks (e.g. an advisory lock, a slow function, a pg_sleep) hangs the preflight, which runs before build_pool returns, so the entire connection is unusable until then.
Impact
- Severity: Medium. Requires a startup script configured and a script/host that stalls. Uncommon, but the builtin explicitly added the guard with a comment saying "a broken script or a stalled host must never wedge pool creation indefinitely" — this is a parity regression on a deliberate robustness guard.
- The error message also differs: the builtin says "Timed out running PostgreSQL startup script after 30000 ms" (clear cause); the plugin hangs with no feedback.
Fix
Wrap the preflight body in tokio::time::timeout(Duration::from_millis(30_000), …) and map the elapsed error to the same "Timed out running PostgreSQL startup script after 30000 ms" message. Define POSTGRES_STARTUP_SCRIPT_TIMEOUT_MS to match the builtin. Add a unit/integration test exercising the timeout (a pg_sleep(35) startup script should fail with the timeout message, not hang) — per repo TDD guidance, prove the divergence first.
Related
- Builtin reference:
TabularisDB/tabularis pool_manager.rs:65 + :991.
Summary
src/client.rs::preflight_startup_scriptruns the user-configured startup script on a throwaway connection with no timeout. The built-in driver wraps the same preflight in a 30-secondtokio::time::timeout. A broken script that blocks (or a stalled host) hangs pool creation — and therefore every metadata/query RPC — indefinitely.Builtin behavior (upstream
main)src-tauri/src/pool_manager.rs:65:…and at line 991, the preflight is wrapped:
Plugin behavior (this repo)
src/client.rs:452—preflight_startup_scriptrunstx.batch_execute(script)directly with no timeout wrapper. There are zerotokio::time::timeoutcalls anywhere insrc/. The script'sBEGIN/batch_execute/ROLLBACKsequence runs until it finishes or the TCP connection dies; a script that blocks (e.g. an advisory lock, a slow function, apg_sleep) hangs the preflight, which runs beforebuild_poolreturns, so the entire connection is unusable until then.Impact
Fix
Wrap the preflight body in
tokio::time::timeout(Duration::from_millis(30_000), …)and map the elapsed error to the same "Timed out running PostgreSQL startup script after 30000 ms" message. DefinePOSTGRES_STARTUP_SCRIPT_TIMEOUT_MSto match the builtin. Add a unit/integration test exercising the timeout (apg_sleep(35)startup script should fail with the timeout message, not hang) — per repo TDD guidance, prove the divergence first.Related
TabularisDB/tabularispool_manager.rs:65+:991.