Skip to content

Bugfix for postgres - #49

Open
shiling wants to merge 1 commit into
masterfrom
postgres-fix
Open

Bugfix for postgres#49
shiling wants to merge 1 commit into
masterfrom
postgres-fix

Conversation

@shiling

@shiling shiling commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Bug

There are two failing tests for postgres, these are the raw logs:

picoded.dstack.jsql_json.postgres.JSql_Json_DataObjectMap_Postgres_test > removePropertyViaDataObject_saveAll FAILED
    java.lang.AssertionError

picoded.dstack.jsql_json.postgres.JSql_Json_DataObjectMap_Postgres_test > removePropertyViaDataObject_saveDelta FAILED
    java.lang.AssertionError

They indicate DataObject.saveAll and DataObject.saveDelta fail to save deleted properties when using Postgres backend.

Diagnosis

Here's the AI diagnosis of the bug

When a user calls testObject.remove("prop") and saves the object using .saveDelta() or .saveAll(), the backend is expected to remove "prop" from the JSON column in the database. However, in PostgresJsonb_DataObjectMap.DataObjectRemoteDataMap_update, updates are applied via a native ON CONFLICT upsert with the following DO UPDATE clause:

data = dataStorageTable.data || EXCLUDED.data

The issue:

In PostgreSQL/CockroachDB, the JSONB concatenation operator || merges two JSONB documents. Since the deleted keys are omitted from EXCLUDED.data (serialized as null or skipped), the concatenation operator || retains their old values from the left-hand operand (dataStorageTable.data) instead of deleting them.

Additionally, under partial saves (saveDelta()), if a non-binary field was modified, serializeDataMap would only process keys within the delta keySet, causing binMap (and thus bData) to serialize to null and inadvertently drop any existing binary properties on conflict update.

Fix

Here's how the AI fixed the bug

  1. Dynamic JSONB Subtraction (PostgresJsonb_DataObjectMap.java):

• We now analyze the list of keys to be processed and detect if any keys are deleted/removed (their value is null or ObjectToken.NULL in fullMap).
• If there are deleted keys, we dynamically append PostgreSQL's jsonb subtraction operator (- 'key') to the on-conflict upsert statement, e.g.:

data = (dataStorageTable.data || EXCLUDED.data) - 'removed_key_1' - 'removed_key_2'

This cleanly and safely drops the removed keys from the merged JSONB document.

  1. Robust Binary Preservation (JsonbUtils.java):

• Modified serializeDataMap to always build the binary map (binMap) from the complete set of existing fields (fullSet) instead of the partial delta keySet. This guarantees that existing binary properties are always preserved during partial updates to JSON properties.

@shiling

shiling commented Aug 7, 2026

Copy link
Copy Markdown
Contributor Author

Tests for Postgres + CockroachDB which were failing before are now passing.

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