Tags: sqliteai/sqlite-sync-dev
Tags
fix: update schema hash on extension version change When upgrading from an older version, the schema hash algorithm may differ. Call cloudsync_update_schema_hash before updating the stored version to ensure hash compatibility across synced devices.
refactor: move all savepoint management from shared layer to platform… … wrappers (#17) * refactor: move all savepoint management from shared layer to platform wrappers Move database_begin_savepoint, database_commit_savepoint, and database_rollback_savepoint calls out of cloudsync_begin_alter and cloudsync_commit_alter (shared CRDT logic) into the platform-specific wrappers in cloudsync_sqlite.c and cloudsync_postgresql.c. This fixes the PostgreSQL "subtransaction left non-empty SPI stack" warning by ensuring SPI_connect() is called before the savepoint boundary, and creates architectural symmetry where shared code is pure business logic and all transaction management lives in platform wrappers.
Dev (#14) * fix(network): cloudsync_network_check_changes must not return the nrows value in case of error `SELECT cloudysnc_network_check_changes();` was returning "Runtime error: 0" in case of error response from the cloudsync microservice instead of the real error message * feat(rls): add complete support for RLS with batch merge in cloudsync_payload_apply * Feat/add support for status endpoint (#10) * feat(network): add support for new status endpoint * refactor(network): structured JSON responses for sync functions. Example: {"send":{"status":"synced","localVersion":5,"serverVersion":5},"receive":{"rows":3,"tables":["tasks"]}} * Feat/network support for multi org cloudsync (#11) * Disable notnull prikey constraints (#12) * The cloudsync extension now enforces NULL primary key rejection at runtime (any write with a NULL PK returns an error), so the explicit NOT NULL constraint on primary key columns is no longer a schema requirement * test: add null primary key rejection tests for SQLite and PostgreSQL * docs: remove NOT NULL requirement from primary key definitions The extension now enforces NULL primary key rejection at runtime, so the explicit NOT NULL constraint on PK columns is no longer a schema requirement. Replace the "must be NOT NULL" guidance with a note about runtime enforcement. * docs: add first draft of PERFORMANCE.md and CHANGELOG.md * fix(postgresql): resolve commit_alter crash and BYTEA handling in column_text Guard savepoint commit/rollback against missing subtransactions to prevent segfault in autocommit mode. Add BYTEA support to database_column_text so encoded PKs are readable during refill_metatable after ALTER TABLE. Enable alter table sync test (31). * test: new alter table test for postgres * feat: update endpoints to use databaseMangedId for /v2/cloudsync api * feat(network)!: replace URL connection string with a UUID (managedDatabaseId) BREAKING CHANGE: cloudsync_network_init now accepts a UUID string instead of the previous URL string. URL connection strings are no longer accepted. The managed database identifier returned by the CloudSync service when a new database is registered for sync. For SQLiteCloud projects, this value can be obtained from the project's OffSync page on the dashboard. * docs: update docs for the new managedDatabaseId arg for cloudsync_network_init * docs(examples): update example for the new managedDatabaseId arg for cloudsync_network_init
fix(sqlite): PRIVATE functions used inside triggers require SQLITE_IN… …NOCUOUS ... otherwise the cloudsync_init function returns this error: table_add_stmts error: 1 unsafe use of cloudsync_is_sync() Runtime error: An error occurred while adding test_sync table information to global context (unsafe use of cloudsync_is_sync()) (21)
Fix 35 bugs and bump version to 0.9.111 (#9) * Fix 35 bugs across CloudSync SQLite/PostgreSQL sync extension Comprehensive audit identified and fixed 35 bugs (1 CRITICAL, 7 HIGH, 18 MEDIUM, 9 LOW) across the entire codebase. All 84 SQLite tests and 26 PostgreSQL tests pass with 0 failures and 0 memory leaks. ## src/cloudsync.c (13 fixes) - [HIGH] Guard NULL db_version_stmt in cloudsync_dbversion_rerun — set db_version = CLOUDSYNC_MIN_DB_VERSION and return 0 when stmt is NULL, preventing NULL dereference after schema rebuild failure - [MEDIUM] Add early return for NULL stmt in dbvm_execute to prevent crash when called with uninitialized statement pointer - [MEDIUM] Change (bool)dbvm_count() to (dbvm_count() > 0) in table_pk_exists — prevents negative return values being cast to true, giving false positive "pk exists" results - [MEDIUM] Add NULL check on database_column_text result in cloudsync_refill_metatable before calling strlen — prevents crash on corrupted or empty column data - [MEDIUM] Route early returns in cloudsync_payload_apply through goto cleanup so CLEANUP callback and vm finalize always run — prevents resource leaks and callback contract violation - [MEDIUM] Change return false to goto abort_add_table when ROWIDONLY rejected — ensures table_free runs on the partially allocated table, preventing memory leak - [MEDIUM] Initialize *persistent = false at top of cloudsync_colvalue_stmt — prevents use of uninitialized value when table_lookup returns NULL - [LOW] Add NULL check on database_column_blob in merge_did_cid_win — prevents memcmp with NULL pointer on corrupted cloudsync table - [LOW] Handle partial failure in table_add_to_context_cb — clean up col_name, col_merge_stmt, col_value_stmt at index on error instead of leaving dangling pointers - [LOW] Remove unused pragma_checked field from cloudsync_context - [LOW] Change pointer comparison to strcmp in cloudsync_set_schema — pointer equality missed cases where different string pointers had identical content - [LOW] Fix cloudsync_payload_get NULL check: blob == NULL (always false for char** arg) changed to *blob == NULL - [LOW] Pass extra meta_ref args to SQL_CLOUDSYNC_UPSERT_COL_INIT_OR_BUMP_VERSION mprintf call to match updated PostgreSQL format string ## src/sqlite/cloudsync_sqlite.c (5 fixes) - [HIGH] Split DEFAULT_FLAGS into FLAGS_PURE (SQLITE_UTF8 | SQLITE_INNOCUOUS | SQLITE_DETERMINISTIC) and FLAGS_VOLATILE (SQLITE_UTF8). Pure functions: cloudsync_version, cloudsync_pk_encode, cloudsync_pk_decode. All others volatile — fixes cloudsync_uuid() returning identical values within the same query when SQLite cached deterministic results - [HIGH] Fix realloc inconsistency in dbsync_update_payload_append: on second realloc failure, state was inconsistent (new_values resized, old_values not, capacity not updated). Both reallocs now checked before updating pointers and capacity - [MEDIUM] Move payload->count++ after all database_value_dup NULL checks in dbsync_update_payload_append — prevents count increment when allocation failed, which would cause use-after-free on cleanup - [MEDIUM] Add dbsync_update_payload_free(payload) before 3 early returns in dbsync_update_final — prevents memory leak of entire aggregate payload on error paths - [MEDIUM] Clean up partial database_value_dup allocations on OOM in dbsync_update_payload_append — free dup'd values at current index when count is not incremented to prevent leak ## src/sqlite/database_sqlite.c (6 fixes) - [MEDIUM] Replace fixed 4096-byte trigger WHEN clause buffers with dynamic cloudsync_memory_mprintf — prevents silent truncation for tables with long filter expressions - [MEDIUM] Check cloudsync_memory_mprintf return for NULL before storing in col_names[] in database_build_trigger_when — prevents strlen(NULL) crash in filter_is_column under OOM - [LOW] Use consistent PRId64 format with (int64_t) cast for schema hash in database_check_schema_hash and database_update_schema_hash — prevents format string mismatch on platforms where uint64_t and int64_t have different printf specifiers - [LOW] Fix DEBUG_DBFUNCTION using undeclared variable 'table' instead of 'table_name' in database_create_metatable (line 568) and database_create_triggers (line 782) — compile error when debug macros enabled - [LOW] Remove dead else branch in database_pk_rowid — unreachable code after sqlite3_prepare_v2 success check ## src/sqlite/sql_sqlite.c (1 fix) - [MEDIUM] Change %s to %q in SQL_INSERT_SETTINGS_STR_FORMAT — prevents SQL injection via malformed setting key/value strings ## src/dbutils.c (1 fix) - [MEDIUM] Change snprintf to cloudsync_memory_mprintf for settings insert using the new %q format — ensures proper SQL escaping ## src/utils.c (1 fix) - [MEDIUM] Fix integer overflow in cloudsync_blob_compare: (int)(size1 - size2) overflows for large size_t values, changed to (size1 > size2) ? 1 : -1 ## src/network.c (1 fix) - [MEDIUM] Remove trailing semicolon from savepoint name "cloudsync_logout_savepoint;" — semicolon in name caused savepoint/release mismatch ## src/postgresql/sql_postgresql.c (1 fix) - [CRITICAL] Replace EXCLUDED.col_version with %s.col_version (table reference) in SQL_CLOUDSYNC_UPSERT_COL_INIT_OR_BUMP_VERSION — PostgreSQL EXCLUDED refers to the proposed INSERT row (always col_version=1), not the existing row. This caused col_version to never increment correctly on conflict, breaking CRDT merge logic ## src/postgresql/cloudsync_postgresql.c (4 fixes) - [HIGH] Change PG_RETURN_INT32(rc) to PG_RETURN_BOOL(rc == DBRES_OK) in pg_cloudsync_terminate — SQL declaration returns BOOLEAN but code returned raw integer, causing protocol mismatch - [HIGH] Copy blob data with palloc+memcpy before databasevm_reset in cloudsync_col_value, and fix PG_RETURN_CSTRING to PG_RETURN_BYTEA_P — reset invalidates SPI tuple memory, causing use-after-free; wrong return type caused type mismatch with SQL declaration - [MEDIUM] Use palloc0 instead of cloudsync_memory_alloc+memset in aggregate context — palloc0 is lifetime-safe in PG aggregate memory context; cloudsync_memory_alloc uses wrong allocator - [MEDIUM] Free SPI_tuptable in all paths of get_column_oid — prevents SPI tuple table leak on early return ## src/postgresql/database_postgresql.c (3 fixes) - [MEDIUM] Use sql_escape_identifier for table_name/schema in CREATE INDEX — prevents SQL injection via specially crafted table names - [MEDIUM] Use sql_escape_literal for table_name in trigger WHEN clause — prevents SQL injection in trigger condition - [LOW] Use SPI_getvalue instead of DatumGetName for type safety in database_pk_names — DatumGetName assumes Name type which may not match the actual column type from information_schema ## test/unit.c (3 new tests) - do_test_blob_compare_large_sizes: verifies overflow fix for large size_t values in cloudsync_blob_compare - do_test_deterministic_flags: verifies cloudsync_uuid() returns different values in same query (non-deterministic flag working) - do_test_schema_hash_consistency: verifies int64 hash format roundtrip through cloudsync_schema_versions table Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Bump version to 0.9.111 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * Update .gitignore
perf(postgres): use SQL template casting for non-PK column types (#4) * perf(postgres): use SQL template casting for non-PK column types Refactor type conversion for non-PK columns to use SQL template casting ($n::typename) instead of per-value SPI_execute_with_args("SELECT $1::typename") calls. This matches the pattern already used for primary key columns. Changes: - sql_postgresql.c: Add format_type() lookup and $n::coltype casting to SQL_BUILD_UPSERT_PK_AND_COL for non-PK column values - cloudsync_postgresql.c: Simplify cloudsync_decode_bytea_to_pgvalue() to return base types only (INT8, FLOAT8, TEXT, BYTEA) without SPI casting - cloudsync_postgresql.c: Remove lookup_column_type_oid() function - Add test 19 (19_uuid_pk_with_unmapped_cols.sql) covering UUID PK with unmapped non-PK types (JSONB, UUID, INET, CIDR) and all CRUD operations: INSERT, UPDATE non-PK, UPDATE mapped cols, DELETE, RESURRECT, UPDATE PK Performance benefit: Eliminates one SPI_execute call per non-PK column value during payload application, reducing overhead for unmapped PostgreSQL types. * test(postgres): new tests
feat: add support for UUID primary keys in PG (#3) * Fix for PG UUID used as PK * build(postgres): update test target for the current test files * docs(docs/postgresql/CLIENT.md): clarify primary key requirements for PostgreSQL and SQLite, added support for UUID primary keys * test(claude): add custom command for claude code to run sqlite-to-pg tests for the specified table schema --------- Co-authored-by: Marco Bambini <marco@creolabs.com>
PreviousNext