diff --git a/libraries/liblmdb/CHANGES b/libraries/liblmdb/CHANGES
index 957742e752..b35ca61d76 100644
--- a/libraries/liblmdb/CHANGES
+++ b/libraries/liblmdb/CHANGES
@@ -1,5 +1,7 @@
LMDB 0.9 Change Log
+LMDB 0.9.16 Release Engineering
+
LMDB 0.9.15 Release (2015/06/19)
Fix txn init (ITS#7961,#7987)
Fix MDB_PREV_DUP (ITS#7955,#7671)
diff --git a/libraries/liblmdb/lmdb.h b/libraries/liblmdb/lmdb.h
index 2f523579c8..e935509d9e 100644
--- a/libraries/liblmdb/lmdb.h
+++ b/libraries/liblmdb/lmdb.h
@@ -413,7 +413,14 @@ typedef enum MDB_cursor_op {
#define MDB_PAGE_FULL (-30786)
/** Database contents grew beyond environment mapsize */
#define MDB_MAP_RESIZED (-30785)
- /** MDB_INCOMPATIBLE: Operation and DB incompatible, or DB flags changed */
+ /** Operation and DB incompatible, or DB type changed. This can mean:
+ *
+ * - The operation expects an #MDB_DUPSORT / #MDB_DUPFIXED database.
+ *
- Opening a named DB when the unnamed DB has #MDB_DUPSORT / #MDB_INTEGERKEY.
+ *
- Accessing a data record as a database, or vice versa.
+ *
- The database was dropped and recreated with different flags.
+ *
+ */
#define MDB_INCOMPATIBLE (-30784)
/** Invalid reuse of reader locktable slot */
#define MDB_BAD_RSLOT (-30783)
@@ -1034,8 +1041,9 @@ int mdb_txn_renew(MDB_txn *txn);
* any other transaction in the process may use this function.
*
* To use named databases (with name != NULL), #mdb_env_set_maxdbs()
- * must be called before opening the environment. Database names
- * are kept as keys in the unnamed database.
+ * must be called before opening the environment. Database names are
+ * keys in the unnamed database, and may be read but not written.
+ *
* @param[in] txn A transaction handle returned by #mdb_txn_begin()
* @param[in] name The name of the database to open. If only a single
* database is needed in the environment, this value may be NULL.
diff --git a/libraries/liblmdb/mdb.c b/libraries/liblmdb/mdb.c
index 6bdf3151dc..adc20f893b 100644
--- a/libraries/liblmdb/mdb.c
+++ b/libraries/liblmdb/mdb.c
@@ -2822,8 +2822,8 @@ mdb_txn_reset0(MDB_txn *txn, const char *act)
}
if (!txn->mt_parent) {
- if (mdb_midl_shrink(&txn->mt_free_pgs))
- env->me_free_pgs = txn->mt_free_pgs;
+ mdb_midl_shrink(&txn->mt_free_pgs);
+ env->me_free_pgs = txn->mt_free_pgs;
/* me_pgstate: */
env->me_pghead = NULL;
env->me_pglast = 0;
@@ -3395,7 +3395,8 @@ mdb_txn_commit(MDB_txn *txn)
goto fail;
}
data.mv_data = &txn->mt_dbs[i];
- rc = mdb_cursor_put(&mc, &txn->mt_dbxs[i].md_name, &data, 0);
+ rc = mdb_cursor_put(&mc, &txn->mt_dbxs[i].md_name, &data,
+ F_SUBDATA);
if (rc)
goto fail;
}
@@ -3408,8 +3409,8 @@ mdb_txn_commit(MDB_txn *txn)
mdb_midl_free(env->me_pghead);
env->me_pghead = NULL;
- if (mdb_midl_shrink(&txn->mt_free_pgs))
- env->me_free_pgs = txn->mt_free_pgs;
+ mdb_midl_shrink(&txn->mt_free_pgs);
+ env->me_free_pgs = txn->mt_free_pgs;
#if (MDB_DEBUG) > 2
mdb_audit(txn);
@@ -5214,6 +5215,8 @@ mdb_page_search(MDB_cursor *mc, MDB_val *key, int flags)
&mc->mc_dbx->md_name, &exact);
if (!exact)
return MDB_NOTFOUND;
+ if ((leaf->mn_flags & (F_DUPDATA|F_SUBDATA)) != F_SUBDATA)
+ return MDB_INCOMPATIBLE; /* not a named DB */
rc = mdb_node_read(mc->mc_txn, leaf, &data);
if (rc)
return rc;
@@ -5725,8 +5728,10 @@ set2:
if (leaf == NULL) {
DPUTS("===> inexact leaf not found, goto sibling");
- if ((rc = mdb_cursor_sibling(mc, 1)) != MDB_SUCCESS)
+ if ((rc = mdb_cursor_sibling(mc, 1)) != MDB_SUCCESS) {
+ mc->mc_flags |= C_EOF;
return rc; /* no entries matched */
+ }
mp = mc->mc_pg[mc->mc_top];
mdb_cassert(mc, IS_LEAF(mp));
leaf = NODEPTR(mp, 0);
@@ -6404,6 +6409,9 @@ prep_subDB:
goto new_sub;
}
current:
+ /* LMDB passes F_SUBDATA in 'flags' to write a DB record */
+ if ((leaf->mn_flags ^ flags) & F_SUBDATA)
+ return MDB_INCOMPATIBLE;
/* overflow page overwrites need special handling */
if (F_ISSET(leaf->mn_flags, F_BIGDATA)) {
MDB_page *omp;
@@ -6674,6 +6682,11 @@ mdb_cursor_del(MDB_cursor *mc, unsigned int flags)
goto fail;
}
}
+ /* LMDB passes F_SUBDATA in 'flags' to delete a DB record */
+ else if ((leaf->mn_flags ^ flags) & F_SUBDATA) {
+ rc = MDB_INCOMPATIBLE;
+ goto fail;
+ }
/* add overflow pages to free list */
if (F_ISSET(leaf->mn_flags, F_BIGDATA)) {
@@ -9169,7 +9182,7 @@ int mdb_dbi_open(MDB_txn *txn, const char *name, unsigned int flags, MDB_dbi *db
if (rc == MDB_SUCCESS) {
/* make sure this is actually a DB */
MDB_node *node = NODEPTR(mc.mc_pg[mc.mc_top], mc.mc_ki[mc.mc_top]);
- if (!(node->mn_flags & F_SUBDATA))
+ if ((node->mn_flags & (F_DUPDATA|F_SUBDATA)) != F_SUBDATA)
return MDB_INCOMPATIBLE;
} else if (rc == MDB_NOTFOUND && (flags & MDB_CREATE)) {
/* Create if requested */
@@ -9362,7 +9375,7 @@ int mdb_drop(MDB_txn *txn, MDB_dbi dbi, int del)
/* Can't delete the main DB */
if (del && dbi > MAIN_DBI) {
- rc = mdb_del0(txn, MAIN_DBI, &mc->mc_dbx->md_name, NULL, 0);
+ rc = mdb_del0(txn, MAIN_DBI, &mc->mc_dbx->md_name, NULL, F_SUBDATA);
if (!rc) {
txn->mt_dbflags[dbi] = DB_STALE;
mdb_dbi_close(txn->mt_env, dbi);
diff --git a/libraries/liblmdb/midl.c b/libraries/liblmdb/midl.c
index 16782dcafc..57a9d4920e 100644
--- a/libraries/liblmdb/midl.c
+++ b/libraries/liblmdb/midl.c
@@ -116,7 +116,7 @@ void mdb_midl_free(MDB_IDL ids)
free(ids-1);
}
-int mdb_midl_shrink( MDB_IDL *idp )
+void mdb_midl_shrink( MDB_IDL *idp )
{
MDB_IDL ids = *idp;
if (*(--ids) > MDB_IDL_UM_MAX &&
@@ -124,9 +124,7 @@ int mdb_midl_shrink( MDB_IDL *idp )
{
*ids++ = MDB_IDL_UM_MAX;
*idp = ids;
- return 1;
}
- return 0;
}
static int mdb_midl_grow( MDB_IDL *idp, int num )
diff --git a/libraries/liblmdb/midl.h b/libraries/liblmdb/midl.h
index 9b041d72d1..2331e78398 100644
--- a/libraries/liblmdb/midl.h
+++ b/libraries/liblmdb/midl.h
@@ -98,9 +98,8 @@ void mdb_midl_free(MDB_IDL ids);
/** Shrink an IDL.
* Return the IDL to the default size if it has grown larger.
* @param[in,out] idp Address of the IDL to shrink.
- * @return 0 on no change, non-zero if shrunk.
*/
-int mdb_midl_shrink(MDB_IDL *idp);
+void mdb_midl_shrink(MDB_IDL *idp);
/** Make room for num additional elements in an IDL.
* @param[in,out] idp Address of the IDL.