Skip to content

Commit b3b35e7

Browse files
andinuxclaude
andcommitted
test(pg): cover stale cloudsync_table_settings + dropped meta-table reopen
Mirrors the SQLite unit test do_test_stale_table_settings_dropped_meta. Drops the base table and its <table>_cloudsync meta-table without calling cloudsync_cleanup, reconnects to force a fresh backend, and verifies that cloudsync_init on a new table still succeeds. Before the shared fix in cloudsync_dbversion_rebuild this aborted with "An error occurred while trying to initialize context" because SQL_DBVERSION_BUILD_QUERY's string_agg over zero rows produced a NULL SQL string that was misreported as DBRES_NOMEM. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent dc9e1bd commit b3b35e7

File tree

2 files changed

+124
-0
lines changed

2 files changed

+124
-0
lines changed
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
-- 'Stale cloudsync_table_settings with dropped meta-table'
2+
-- Mirrors the SQLite unit test: Stale Table Settings Dropped Meta
3+
--
4+
-- When a user drops a tracked table and its <table>_cloudsync meta-table
5+
-- manually (without calling cloudsync_cleanup), cloudsync_table_settings is
6+
-- left with stale rows while pg_tables no longer has any matching
7+
-- *_cloudsync table. Before the fix in cloudsync_dbversion_rebuild, opening a
8+
-- new backend and calling any cloudsync function caused
9+
-- cloudsync_dbversion_build_query to produce a NULL SQL string (string_agg
10+
-- over zero rows), which was misreported as DBRES_NOMEM, making
11+
-- cloudsync_context_init fail and every cloudsync_* call ereport ERROR.
12+
13+
\set testid '51'
14+
\ir helper_test_init.sql
15+
16+
\connect postgres
17+
\ir helper_psql_conn_setup.sql
18+
19+
DROP DATABASE IF EXISTS cloudsync_test_51;
20+
CREATE DATABASE cloudsync_test_51;
21+
22+
\connect cloudsync_test_51
23+
\ir helper_psql_conn_setup.sql
24+
25+
CREATE EXTENSION IF NOT EXISTS cloudsync;
26+
27+
-- Phase 1: create a tracked table and initialize cloudsync on it.
28+
DROP TABLE IF EXISTS stale_doc CASCADE;
29+
CREATE TABLE stale_doc (id TEXT PRIMARY KEY NOT NULL, body TEXT);
30+
SELECT cloudsync_init('stale_doc', 'CLS', 1) AS _init \gset
31+
32+
-- Sanity: the meta-table exists and cloudsync_table_settings has a row for it.
33+
SELECT count(*) AS meta_exists FROM pg_tables WHERE tablename = 'stale_doc_cloudsync' \gset
34+
SELECT (:meta_exists::int = 1) AS meta_exists_ok \gset
35+
\if :meta_exists_ok
36+
\echo [PASS] (:testid) stale_doc_cloudsync meta-table created
37+
\else
38+
\echo [FAIL] (:testid) expected stale_doc_cloudsync to exist
39+
SELECT (:fail::int + 1) AS fail \gset
40+
\endif
41+
42+
SELECT count(*) AS settings_rows FROM cloudsync_table_settings WHERE tbl_name = 'stale_doc' \gset
43+
SELECT (:settings_rows::int > 0) AS settings_rows_ok \gset
44+
\if :settings_rows_ok
45+
\echo [PASS] (:testid) cloudsync_table_settings has row(s) for stale_doc
46+
\else
47+
\echo [FAIL] (:testid) expected cloudsync_table_settings row for stale_doc
48+
SELECT (:fail::int + 1) AS fail \gset
49+
\endif
50+
51+
-- Phase 2: drop BOTH the base table and the meta-table without calling
52+
-- cloudsync_cleanup. cloudsync_table_settings still references stale_doc,
53+
-- but pg_tables has no *_cloudsync tables at all now.
54+
DROP TABLE stale_doc;
55+
DROP TABLE stale_doc_cloudsync;
56+
57+
SELECT count(*) AS cloudsync_meta_tables FROM pg_tables WHERE tablename LIKE '%_cloudsync' \gset
58+
SELECT (:cloudsync_meta_tables::int = 0) AS no_meta_ok \gset
59+
\if :no_meta_ok
60+
\echo [PASS] (:testid) no *_cloudsync meta-tables remain in pg_tables
61+
\else
62+
\echo [FAIL] (:testid) expected zero *_cloudsync tables, got :cloudsync_meta_tables
63+
SELECT (:fail::int + 1) AS fail \gset
64+
\endif
65+
66+
-- Phase 3: reconnect to force a fresh backend. pg_cloudsync_context is a
67+
-- static per-process pointer, so a new backend means
68+
-- cloudsync_pg_context_init runs again on the next cloudsync call — which
69+
-- is exactly what used to fail under this bug.
70+
\connect cloudsync_test_51
71+
\ir helper_psql_conn_setup.sql
72+
73+
-- cloudsync_version is a pure function that does not touch the context, so
74+
-- this call cannot fail even with the bug present. It's here only as a
75+
-- trivial smoke check that the extension is still loadable.
76+
SELECT cloudsync_version() IS NOT NULL AS version_ok \gset
77+
\if :version_ok
78+
\echo [PASS] (:testid) cloudsync_version() reachable after reopen
79+
\else
80+
\echo [FAIL] (:testid) cloudsync_version() failed after reopen
81+
SELECT (:fail::int + 1) AS fail \gset
82+
\endif
83+
84+
-- The real check: calling a function that goes through get_cloudsync_context()
85+
-- must succeed. Before the fix, cloudsync_dbversion_rebuild returned
86+
-- DBRES_NOMEM here because SQL_DBVERSION_BUILD_QUERY's string_agg over zero
87+
-- rows produced a NULL SQL string, and the whole init path would ereport
88+
-- ERROR — any cloudsync_* call below would abort the script.
89+
CREATE TABLE stale_doc2 (id TEXT PRIMARY KEY NOT NULL, body TEXT);
90+
SELECT cloudsync_init('stale_doc2', 'CLS', 1) AS _init2 \gset
91+
92+
-- The new table's meta-table exists. If cloudsync_init failed (pre-fix
93+
-- behavior) this count will be 0, covering both the init-rc check and the
94+
-- meta-table creation in a single assertion.
95+
SELECT count(*) AS meta2_exists FROM pg_tables WHERE tablename = 'stale_doc2_cloudsync' \gset
96+
SELECT (:meta2_exists::int = 1) AS meta2_exists_ok \gset
97+
\if :meta2_exists_ok
98+
\echo [PASS] (:testid) cloudsync_init succeeded and stale_doc2_cloudsync was created
99+
\else
100+
\echo [FAIL] (:testid) expected stale_doc2_cloudsync to exist after cloudsync_init
101+
SELECT (:fail::int + 1) AS fail \gset
102+
\endif
103+
104+
-- An insert via the new cloudsync_init'd table should produce a cloudsync
105+
-- metadata entry — confirming the context is fully functional.
106+
INSERT INTO stale_doc2 (id, body) VALUES ('a', 'hello');
107+
108+
SELECT count(*) AS meta_rows FROM stale_doc2_cloudsync \gset
109+
SELECT (:meta_rows::int > 0) AS meta_rows_ok \gset
110+
\if :meta_rows_ok
111+
\echo [PASS] (:testid) stale_doc2_cloudsync has metadata after insert
112+
\else
113+
\echo [FAIL] (:testid) expected metadata rows in stale_doc2_cloudsync
114+
SELECT (:fail::int + 1) AS fail \gset
115+
\endif
116+
117+
-- Cleanup
118+
\ir helper_test_cleanup.sql
119+
\if :should_cleanup
120+
DROP DATABASE IF EXISTS cloudsync_test_51;
121+
\else
122+
\echo [INFO] !!!!!
123+
\endif

test/postgresql/full_test.sql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
\ir 48_row_filter_multi_table.sql
5959
\ir 49_row_filter_prefill.sql
6060
\ir 50_block_lww_existing_data.sql
61+
\ir 51_stale_table_settings_dropped_meta.sql
6162

6263
-- 'Test summary'
6364
\echo '\nTest summary:'

0 commit comments

Comments
 (0)