+ if (F_ISSET(leaf->mn_flags, F_DUPDATA)) {
+ mdb_xcursor_init1(cursor->mc_txn, cursor->mc_dbi, cursor->mc_xcursor, leaf);
+ }
+ if (data) {
+ if ((rc = mdb_read_data(cursor->mc_txn, leaf, data) != MDB_SUCCESS))
+ return rc;
+
+ if (F_ISSET(leaf->mn_flags, F_DUPDATA)) {
+ rc = mdb_cursor_first(&cursor->mc_xcursor->mx_cursor, data, NULL);
+ if (rc != MDB_SUCCESS)
+ return rc;
+ }
+ }
+
+ return mdb_set_key(leaf, key);
+}
+
+static int
+mdb_cursor_prev(MDB_cursor *cursor, MDB_val *key, MDB_val *data, MDB_cursor_op op)
+{
+ MDB_ppage *top;
+ MDB_page *mp;
+ MDB_node *leaf;
+ int rc;
+
+ assert(cursor->mc_initialized);
+
+ top = CURSOR_TOP(cursor);
+ mp = top->mp_page;
+
+ if (cursor->mc_txn->mt_dbs[cursor->mc_dbi].md_flags & MDB_DUPSORT) {
+ leaf = NODEPTR(mp, top->mp_ki);
+ if ((op == MDB_PREV || op == MDB_PREV_DUP) && F_ISSET(leaf->mn_flags, F_DUPDATA)) {
+ rc = mdb_cursor_prev(&cursor->mc_xcursor->mx_cursor, data, NULL, MDB_PREV);
+ if (op != MDB_PREV || rc == MDB_SUCCESS)
+ return rc;
+ }
+ }
+
+ DPRINTF("cursor_prev: top page is %lu in cursor %p", mp->mp_pgno, (void *) cursor);
+
+ if (top->mp_ki == 0) {
+ DPRINTF("=====> move to prev sibling page");
+ if (mdb_sibling(cursor, 0) != MDB_SUCCESS) {
+ return MDB_NOTFOUND;
+ }
+ top = CURSOR_TOP(cursor);
+ mp = top->mp_page;
+ top->mp_ki = NUMKEYS(mp) - 1;
+ DPRINTF("prev page is %lu, key index %u", mp->mp_pgno, top->mp_ki);
+ } else
+ top->mp_ki--;
+
+ cursor->mc_eof = 0;
+
+ DPRINTF("==> cursor points to page %lu with %u keys, key index %u",
+ mp->mp_pgno, NUMKEYS(mp), top->mp_ki);
+
+ assert(IS_LEAF(mp));
+ leaf = NODEPTR(mp, top->mp_ki);
+
+ if (F_ISSET(leaf->mn_flags, F_DUPDATA)) {
+ mdb_xcursor_init1(cursor->mc_txn, cursor->mc_dbi, cursor->mc_xcursor, leaf);
+ }
+ if (data) {
+ if ((rc = mdb_read_data(cursor->mc_txn, leaf, data) != MDB_SUCCESS))
+ return rc;
+
+ if (F_ISSET(leaf->mn_flags, F_DUPDATA)) {
+ rc = mdb_cursor_last(&cursor->mc_xcursor->mx_cursor, data, NULL);
+ if (rc != MDB_SUCCESS)
+ return rc;
+ }
+ }