|
| 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 |
0 commit comments