Skip to content

fix(safe-mode): rate pg_background, pg_cron and TimescaleDB calls as writes - #4043

Merged
datlechin merged 2 commits into
mainfrom
fix/classifier-function-followups
Nov 4, 2026
Merged

datlechin merged 2 commits into
mainfrom
fix/classifier-function-followups

Conversation

@datlechin

Copy link
Copy Markdown
Member

Summary

  • pg_background's launch, submit, run and cancel functions, pg_cron's job functions, and TimescaleDB's chunk, hypertable, job, policy and restore functions are writes in Read-Only and Safe Mode on both apps. drop_chunks is one of them. Before this they read as reads.
  • dblink_close (which commits the transaction dblink_open began) and dblink_cancel_query are writes.
  • The Linux app knows DuckDB's postgres_execute, postgres_query, mysql_query, mysql_execute, sqlite_query, json_execute_serialized_sql, dbgen and dsdgen, as the Mac app does. Before this they read as reads there.
  • core/crates/core/tests/fixtures/state_changing_functions.json holds every family, the DuckDB-only list included, and both suites compare against it.
  • Each name was checked against the extension's own install scripts at its latest release: pg_background 2.0.4, pg_cron 1.6.8, TimescaleDB 2.31.0 (plus functions removed since 2.14 that older servers still have), dblink in PostgreSQL 18.6, and the DuckDB 2.0 postgres, mysql and sqlite extensions. Procedures are left out, since they need CALL, which is already a write.
  • Not part of this: the lexical-grammar probe rows (Docker, DuckDB 2.0 CLI).

Deliberately not fixed here

  • A DROP or TRUNCATE sent through dblink_exec, postgres_execute or another runner is still a write, not destructive. Reading the SQL a call sends took five review rounds, and every round found new misses or false alarms: escapes and continued strings, ||, U&'', the remote dialect, which argument holds the SQL (dblink's (text, text) overloads are ambiguous without types), views and WITH NO DATA, and quadratic or unbounded scans. It needs its own design.
  • drop_chunks is a write, not destructive, and on the Mac pg_background and pg_cron calls are not refused to MCP clients as server-side code. Both were tried here; matching the names under every spelling (U&"...", UESCAPE, an escaped cron schema) kept turning up bypasses, so they go to a follow-up.
  • A CTE whose name matches a listed function and carries a column list, such as WITH schedule(day) AS (...), reads as a call of that function. Both scanners already do this for setval, crosstab and the rest. The bare pg_cron names make it easier to hit.

Test plan

  • SQLStatementClassifierTests (new: extension writes and reads), SQLStateChangingFunctionsTests and the TableProQuery suites, through verify.sh package TableProCore.
  • The hosted QueryClassifier and statement gate suites, built unsigned, since this Mac has no signing identity.
  • cargo test -p tablepro-core and clippy in the Linux image, including a_function_that_runs_sql_text_or_signals_writes.

@datlechin
datlechin enabled auto-merge (squash) November 4, 2026 13:58
@datlechin
datlechin merged commit a6887e5 into main Nov 4, 2026
41 of 50 checks passed
@datlechin
datlechin deleted the fix/classifier-function-followups branch November 5, 2026 02:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant