merchant

Merchant backend to process payments, run by merchants
Log | Files | Refs | Submodules | README | LICENSE

commit 019c04add75050e4c98e406ccbc1682ab2e7243e
parent 53a94687260c75ab3febf17f6f76c25bb7ff1eb3
Author: Christian Grothoff <christian@grothoff.org>
Date:   Wed,  5 Aug 2026 23:26:04 +0200

lock row for update to ensure we do not trip the assert on concurrent DELETE

Diffstat:
Msrc/backenddb/test_merchantdb.c | 22++++++++++++++++++++++
Msrc/backenddb/update_product.sql | 4+++-
2 files changed, 25 insertions(+), 1 deletion(-)

diff --git a/src/backenddb/test_merchantdb.c b/src/backenddb/test_merchantdb.c @@ -2070,6 +2070,28 @@ run_test_products (struct TestProducts_Closure *cls) TEST_RET_ON_FAIL (test_lookup_products (&cls->instance, 0, NULL)); + /* Updating a product that has just been deleted must be reported via + 'no_product' (which the HTTP layer turns into a 404), never as a + hard error. merchant_do_update_product re-reads the inventory row + and then ASSERTs that the subsequent UPDATE still finds it; without + the FOR UPDATE on that re-read, a DELETE committing in the window + between the two statements turns this into a P0004 assertion + failure (HTTP 500). Reproducing that window needs a second + database connection, which this harness does not have; what is + asserted here is that the very same code path returns 'no_product' + when the row is gone. */ + TEST_RET_ON_FAIL (test_update_product ( + &cls->instance, + &cls->products[0], + 0, + NULL, + GNUNET_DB_STATUS_SUCCESS_ONE_RESULT, + false, + true, + false, + false, + false, + -1)); return 0; } diff --git a/src/backenddb/update_product.sql b/src/backenddb/update_product.sql @@ -91,7 +91,9 @@ SELECT total_stock ,product_serial INTO rec FROM merchant_inventory - WHERE product_id=in_product_id; + WHERE product_id=in_product_id + FOR UPDATE; -- lock, or a concurrent DELETE makes the UPDATE below + -- fail the ASSERT (=> HTTP 500 instead of 404) IF NOT FOUND THEN