"MDB_CURSOR_FULL: Internal error - cursor stack limit reached",
"MDB_PAGE_FULL: Internal error - page has no more space",
"MDB_MAP_RESIZED: Database contents grew beyond environment mapsize",
- "MDB_INCOMPATIBLE: Database flags changed or would change",
+ "MDB_INCOMPATIBLE: Operation and DB incompatible, or DB flags changed",
"MDB_BAD_RSLOT: Invalid reuse of reader locktable slot",
"MDB_BAD_TXN: Transaction cannot recover - it must be aborted",
"MDB_BAD_VALSIZE: Too big key/data, key is empty, or wrong DUPFIXED size",
{
int rc;
int exact = 0;
+ int (*mfunc)(MDB_cursor *mc, MDB_val *key, MDB_val *data);
assert(mc);
break;
case MDB_GET_BOTH:
case MDB_GET_BOTH_RANGE:
- if (data == NULL || mc->mc_xcursor == NULL) {
+ if (data == NULL) {
rc = EINVAL;
break;
}
+ if (mc->mc_xcursor == NULL) {
+ rc = MDB_INCOMPATIBLE;
+ break;
+ }
/* FALLTHRU */
case MDB_SET:
case MDB_SET_KEY:
rc = mdb_cursor_set(mc, key, data, op, &exact);
break;
case MDB_GET_MULTIPLE:
- if (data == NULL ||
- !(mc->mc_db->md_flags & MDB_DUPFIXED) ||
- !(mc->mc_flags & C_INITIALIZED)) {
+ if (data == NULL || !(mc->mc_flags & C_INITIALIZED)) {
rc = EINVAL;
break;
}
+ if (!(mc->mc_db->md_flags & MDB_DUPFIXED)) {
+ rc = MDB_INCOMPATIBLE;
+ break;
+ }
rc = MDB_SUCCESS;
if (!(mc->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED) ||
(mc->mc_xcursor->mx_cursor.mc_flags & C_EOF))
break;
goto fetchm;
case MDB_NEXT_MULTIPLE:
- if (data == NULL ||
- !(mc->mc_db->md_flags & MDB_DUPFIXED)) {
+ if (data == NULL) {
rc = EINVAL;
break;
}
+ if (!(mc->mc_db->md_flags & MDB_DUPFIXED)) {
+ rc = MDB_INCOMPATIBLE;
+ break;
+ }
if (!(mc->mc_flags & C_INITIALIZED))
rc = mdb_cursor_first(mc, key, data);
else
rc = mdb_cursor_first(mc, key, data);
break;
case MDB_FIRST_DUP:
- if (data == NULL ||
- !(mc->mc_db->md_flags & MDB_DUPSORT) ||
- !(mc->mc_flags & C_INITIALIZED) ||
- !(mc->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED)) {
+ mfunc = mdb_cursor_first;
+ mmove:
+ if (data == NULL || !(mc->mc_flags & C_INITIALIZED)) {
+ rc = EINVAL;
+ break;
+ }
+ if (mc->mc_xcursor == NULL) {
+ rc = MDB_INCOMPATIBLE;
+ break;
+ }
+ if (!(mc->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED)) {
rc = EINVAL;
break;
}
- rc = mdb_cursor_first(&mc->mc_xcursor->mx_cursor, data, NULL);
+ rc = mfunc(&mc->mc_xcursor->mx_cursor, data, NULL);
break;
case MDB_LAST:
rc = mdb_cursor_last(mc, key, data);
break;
case MDB_LAST_DUP:
- if (data == NULL ||
- !(mc->mc_db->md_flags & MDB_DUPSORT) ||
- !(mc->mc_flags & C_INITIALIZED) ||
- !(mc->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED)) {
- rc = EINVAL;
- break;
- }
- rc = mdb_cursor_last(&mc->mc_xcursor->mx_cursor, data, NULL);
- break;
+ mfunc = mdb_cursor_last;
+ goto mmove;
default:
DPRINTF("unhandled/unimplemented cursor operation %u", op);
rc = EINVAL;
dcount = data[1].mv_size;
data[1].mv_size = 0;
if (!F_ISSET(mc->mc_db->md_flags, MDB_DUPFIXED))
- return EINVAL;
+ return MDB_INCOMPATIBLE;
}
nospill = flags & MDB_NOSPILL;
if (mc == NULL || countp == NULL)
return EINVAL;
- if (!(mc->mc_db->md_flags & MDB_DUPSORT))
- return EINVAL;
+ if (mc->mc_xcursor == NULL)
+ return MDB_INCOMPATIBLE;
leaf = NODEPTR(mc->mc_pg[mc->mc_top], mc->mc_ki[mc->mc_top]);
if (!F_ISSET(leaf->mn_flags, F_DUPDATA)) {
/* 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))
- return EINVAL;
+ return MDB_INCOMPATIBLE;
} else if (rc == MDB_NOTFOUND && (flags & MDB_CREATE)) {
/* Create if requested */
MDB_db dummy;