Fix InvalidCastException and PostgreSQL transaction abort in HTTP sync#12
Conversation
Bug 1: SyncAgentController.CompleteApplyBulkChangesAsync hard-casts values to JsonElement, which fails when values are already native .NET types (e.g. from MessagePack deserialization or newer System.Text.Json versions that may resolve object? differently). Fixed by using pattern matching (is JsonElement) and passing through native types without conversion. Applied the same fix to the client-side ConvertJsonValueToNetObject for robustness. Bug 2: PostgreSQLSyncProvider.ApplyChangesAsync catches DML exceptions but continues the transaction. Unlike SQLite, PostgreSQL enters an 'aborted' state (25P02) after any error within a transaction, causing all subsequent commands to fail. Fixed by wrapping each DML statement in a SAVEPOINT so failures can be rolled back without aborting the entire transaction. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ment Includes fixes for InvalidCastException and PostgreSQL transaction abort in HTTP sync (see adospace/CoreSync#12). Using local packages until upstream PR is merged. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Hi, sorry, but I think this PR has some problems. Regarding the second fix, I'm not convinced that PostgreSQL should behave like SQLite. |
Problem
When using the HTTP sync protocol with a PostgreSQL server and SQLite mobile clients (mixed-provider sync), two bugs cause server-side failures:
Bug 1: InvalidCastException in CompleteApplyBulkChangesAsync
Root cause:
CompleteApplyBulkChangesAsync(line 174) hard-castsitemValueEntry.Value.ValuetoJsonElement, but values may already be native .NET types. This happens when:JsonElementSystem.Text.Json(e.g., .NET 10) may deserializeobject?properties differentlyFix: Use pattern matching (
is JsonElement) instead of a hard cast. If the value is already a native .NET type, skip the conversion.Bug 2: PostgreSQL transaction abort (25P02)
Root cause: In
PostgreSQLSyncProvider.ApplyChangesAsync, when a DML statement fails (e.g., FK constraint violation), the exception is caught and logged, but the transaction continues. Unlike SQLite, PostgreSQL enters an "aborted" state after any error within a transaction — all subsequent commands are rejected with error 25P02.Fix: Wrap each DML operation in a
SAVEPOINT. On failure, rollback to the savepoint so the transaction remains usable for subsequent items. This matches the SQLite provider's behavior of skipping failed items gracefully.Reproduction
Expected: Sync completes successfully
Actual: Server crashes with InvalidCastException, and any SQL errors cascade into 25P02
Changes
SyncAgentController.csis JsonElementinstead of hard cast inCompleteApplyBulkChangesAsyncSyncProviderHttpClient.csConvertJsonValueToNetObjectfor robustnessPostgreSQLSyncProvider.csSAVEPOINT/RELEASE/ROLLBACK TO SAVEPOINTfor error recoveryTesting
Verified end-to-end with: