Fix obscure MDB_MULTIPLE bug
authorHoward Chu <hyc@symas.com>
Mon, 12 Aug 2013 00:15:03 +0000 (17:15 -0700)
committerHoward Chu <hyc@symas.com>
Mon, 12 Aug 2013 00:15:03 +0000 (17:15 -0700)
If a key has a single existing value, and then a put (MDB_MULTIPLE)
is done where the first of the multiple values matches the existing
value, the put would return SUCCESS without writing any of the
values. Fixed to loop to the next value as intended.

libraries/liblmdb/mdb.c

index 9b8b675279e14e618908a97f8f5aa57b951766c4..c1f0d030a0fc159a3b7845f87758256d8a48ba5e 100644 (file)
@@ -5653,9 +5653,16 @@ more:
                                        mc->mc_dbx->md_dcmp = mdb_cmp_cint;
 #endif
 #endif
-                               /* if data matches, ignore it */
-                               if (!mc->mc_dbx->md_dcmp(data, &dkey))
-                                       return (flags == MDB_NODUPDATA) ? MDB_KEYEXIST : MDB_SUCCESS;
+                               /* if data matches, skip it */
+                               if (!mc->mc_dbx->md_dcmp(data, &dkey)) {
+                                       if (flags == MDB_NODUPDATA)
+                                               rc = MDB_KEYEXIST;
+                                       else if (flags & MDB_MULTIPLE)
+                                               goto next_mult;
+                                       else
+                                               rc = MDB_SUCCESS;
+                                       return rc;
+                               }
 
                                /* create a fake page for the dup items */
                                memcpy(dbuf, dkey.mv_data, dkey.mv_size);
@@ -5936,15 +5943,16 @@ put_sub:
                        mc->mc_db->md_entries++;
                if (flags & MDB_MULTIPLE) {
                        if (!rc) {
+next_mult:
                                mcount++;
+                               /* let caller know how many succeeded, if any */
+                               data[1].mv_size = mcount;
                                if (mcount < dcount) {
                                        data[0].mv_data = (char *)data[0].mv_data + data[0].mv_size;
                                        leaf = NODEPTR(mc->mc_pg[mc->mc_top], mc->mc_ki[mc->mc_top]);
                                        goto more;
                                }
                        }
-                       /* let caller know how many succeeded, if any */
-                       data[1].mv_size = mcount;
                }
        }
 done: