From eb9ceee6083629ccc1d4e8aea1b2f0da92fb7be9 Mon Sep 17 00:00:00 2001 From: Rivers Zhang Date: Wed, 12 Aug 2026 22:37:55 -0400 Subject: [PATCH] Handle ix_addk rcode correctly during master swing ERR_NOMASTER is treated as a duplicate key error, which causes upsert to misbehave during master swing: an upsert may miss its index entry, or may fail incorrectly during verify-retry. Case 1) upsert misses its index entry ``` mydb4> create table t2 (i int primary key)$$ [create table t2 (i int primary key)] rc 0 ``` Upsert receives a good rcode, but misses its index entry: ``` mydb4> insert into t2 values(3) on conflict do nothing (rows inserted=1) [insert into t2 values(3) on conflict do nothing] rc 0 mydb4> select * from t2 (i=3) mydb4> select count(*) from t2 where i = 3 (count(*)=0) ``` Case 2) upsert fails incorrectly during verify-retry Insert-on-conflict-do-nothing, still receives a dupkey error: ``` mydb4> begin [begin] rc 0 mydb4> insert into t2 values(6) on conflict do nothing [insert into t2 values(6) on conflict do nothing] rc 0 mydb4> insert into t2 values(6) on conflict do nothing [insert into t2 values(6) on conflict do nothing] rc 0 mydb4> update t2 set i = sleep(1) where i = 1 [update t2 set i = sleep(1) where i = 1] rc 0 mydb4> commit [commit] failed with rc 2 Transaction is uncommittable: Duplicate insert on key 'COMDB2_PK' in table 't2' index 0 ``` Database logs the following: ``` [ERROR] Forced VERIFY-FAIL for uncommittable blocksql transaction ``` Signed-off-by: Rivers Zhang --- db/indices.c | 16 +++++++++------- db/osqlblockproc.c | 1 + 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/db/indices.c b/db/indices.c index 6332f3dca9..fe6114323f 100644 --- a/db/indices.c +++ b/db/indices.c @@ -514,13 +514,15 @@ int add_record_indices(struct ireq *iq, void *trans, blob_buffer_t *blobs, goto done; } else if (rc != 0) { *ixfailnum = ixnum; - /* If following changes, update OSQL_INSREC in osqlcomm.c */ - *opfailcode = OP_FAILED_UNIQ; /* really? */ - - // If this transaction has already added this key and adding this key again - // violates a duplicate key constraint, then this txn is uncommittable. - if (dup_txn_insert == 1) { - iq->dup_key_insert = 1; + if (rc == IX_DUP) { + *opfailcode = OP_FAILED_UNIQ; + // If this transaction has already added this key and adding this key again + // violates a duplicate key constraint, then this txn is uncommittable. + if (dup_txn_insert) { + iq->dup_key_insert = 1; + } + } else { + *opfailcode = OP_FAILED_INTERNAL; } ERR(rc, "add error", 0); diff --git a/db/osqlblockproc.c b/db/osqlblockproc.c index 42b7d30383..ad4092fe6d 100644 --- a/db/osqlblockproc.c +++ b/db/osqlblockproc.c @@ -1181,6 +1181,7 @@ static int apply_changes(struct ireq *iq, blocksql_tran_t *tran, void *iq_tran, if (iq->vfy_idx_track) { hash_clear(iq->vfy_idx_hash); + iq->dup_key_insert = 0; } /* create a cursor */