diff --git a/server/core_storage.go b/server/core_storage.go index 3240318cd..35e40ccf3 100644 --- a/server/core_storage.go +++ b/server/core_storage.go @@ -698,11 +698,16 @@ func storagePrepBatch(batch *pgx.Batch, authoritativeWrite bool, op *StorageOpWr // Existing permission checks are not applicable for new storage objects. query = ` INSERT INTO storage (collection, key, user_id, value, version, read, write, create_time, update_time) - VALUES ($1, $2, $3, $4, $5, $6, $7, now(), now()) + SELECT $1, $2, $3, $4, $5, $6, $7, now(), now() + WHERE NOT EXISTS(SELECT 1 FROM storage WHERE collection = $1 AND key = $2 AND user_id = $3) -- avoids ON CONFLICT hitting pre-existing object, and immediately cancels insert + ON CONFLICT (collection, key, user_id) DO UPDATE + SET version = excluded.version + WHERE storage.version = excluded.version AND storage.read = excluded.read AND storage.write = excluded.write -- needed to return a row on concurrent write of same object RETURNING read, write, version, create_time, update_time` // Outcomes: - // - NoRows - insert failed due to constraint violation (concurrent insert) + // - Row is returned if object was new or if concurrent writer wrote object with the same values (ON CONFLICT UPDATE needed) + // - NoRows - insert was ignored due to constraint violation (non-OCC already existing row), or concurrent write wrote object with different values (UPDATE did not happen) } batch.Queue(query, params...)