From 5e02e7fb562afd42d112253e2c88d326874d93df Mon Sep 17 00:00:00 2001 From: Leonid Yuriev Date: Tue, 17 Nov 2020 08:01:08 +0300 Subject: [PATCH] mdbx: add `MDBX_SET_LOWERBOUND` for `mdbx_cursor_get()`. Change-Id: I3638fdd10be8dfe128c43b465e9ca71f89175b3e --- mdbx.h | 15 ++++++++++++++- src/core.c | 27 +++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/mdbx.h b/mdbx.h index 79a6ba7c..1d4ad575 100644 --- a/mdbx.h +++ b/mdbx.h @@ -1505,7 +1505,20 @@ enum MDBX_cursor_op { /** \ref MDBX_DUPFIXED -only: Position at previous page and return up to * a page of duplicate data items. */ - MDBX_PREV_MULTIPLE + MDBX_PREV_MULTIPLE, + + /** Position at first key-value pair greater than or equal to specified, + * return both key and data, and the return code depends on a exact match. + * + * For non DUPSORT-ed collections this work the same to \ref MDBX_SET_RANGE, + * but returns \ref MDBX_SUCCESS if key found exactly and + * \ref MDBX_RESULT_TRUE if greater key was found. + * + * For DUPSORT-ed a data value is taken into account for duplicates, + * i.e. for a pairs/tuples of a key and an each data value of duplicates. + * Returns \ref MDBX_SUCCESS if key-value pair found exactly and + * \ref MDBX_RESULT_TRUE if the next pair was returned. */ + MDBX_SET_LOWERBOUND }; #ifndef __cplusplus /** \ingroup c_cursors */ diff --git a/src/core.c b/src/core.c index 4148ae73..8404c537 100644 --- a/src/core.c +++ b/src/core.c @@ -12575,6 +12575,33 @@ int mdbx_cursor_get(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data, case MDBX_LAST_DUP: mfunc = mdbx_cursor_last; goto mmove; + case MDBX_SET_LOWERBOUND: { + if (unlikely(key == NULL || data == NULL)) + return MDBX_EINVAL; + MDBX_val save_data = *data; + rc = mdbx_cursor_set(mc, key, data, MDBX_SET_RANGE, &exact); + if (rc == MDBX_SUCCESS && exact && mc->mc_xcursor) { + mc->mc_flags &= ~C_DEL; + if (mc->mc_xcursor->mx_cursor.mc_flags & C_INITIALIZED) { + *data = save_data; + exact = 0; + rc = mdbx_cursor_set(&mc->mc_xcursor->mx_cursor, data, NULL, + MDBX_SET_RANGE, &exact); + if (rc == MDBX_NOTFOUND) { + mdbx_cassert(mc, !exact); + rc = mdbx_cursor_next(mc, key, data, MDBX_NEXT_NODUP); + } + } else { + int cmp = mc->mc_dbx->md_dcmp(&save_data, data); + exact = (cmp == 0); + if (cmp > 0) + rc = mdbx_cursor_next(mc, key, data, MDBX_NEXT_NODUP); + } + } + if (rc == MDBX_SUCCESS && !exact) + rc = MDBX_RESULT_TRUE; + break; + } default: mdbx_debug("unhandled/unimplemented cursor operation %u", op); return MDBX_EINVAL;