diff --git a/mdbx.h b/mdbx.h index b0f62320..7bff6ad7 100644 --- a/mdbx.h +++ b/mdbx.h @@ -1572,18 +1572,33 @@ enum MDBX_cursor_op { * a page of duplicate data items. */ 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. + /** Positions cursor at first key-value pair greater than or equal to + * specified, return both key and data, and the return code depends on whether + * 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 + * but returns \ref MDBX_SUCCESS if key found exactly or * \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 + * Returns \ref MDBX_SUCCESS if key-value pair found exactly or * \ref MDBX_RESULT_TRUE if the next pair was returned. */ - MDBX_SET_LOWERBOUND + MDBX_SET_LOWERBOUND, + + /** Positions cursor at first key-value pair greater than specified, + * return both key and data, and the return code depends on whether a + * upper-bound was found. + * + * For non DUPSORT-ed collections this work the same to \ref MDBX_SET_RANGE, + * but returns \ref MDBX_SUCCESS if the greater key was found or + * \ref MDBX_NOTFOUND otherwise. + * + * 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 the greater pair was returned or + * \ref MDBX_NOTFOUND otherwise. */ + MDBX_SET_UPPERBOUND }; #ifndef __cplusplus /** \ingroup c_cursors */ diff --git a/src/core.c b/src/core.c index 9e4fa29d..85081cac 100644 --- a/src/core.c +++ b/src/core.c @@ -14487,7 +14487,7 @@ int mdbx_cursor_get(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data, break; case MDBX_FIRST_DUP: mfunc = mdbx_cursor_first; - mmove: + move: if (unlikely(data == NULL || !(mc->mc_flags & C_INITIALIZED))) return MDBX_EINVAL; if (unlikely(mc->mc_xcursor == NULL)) @@ -14515,7 +14515,8 @@ int mdbx_cursor_get(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data, break; case MDBX_LAST_DUP: mfunc = mdbx_cursor_last; - goto mmove; + goto move; + case MDBX_SET_UPPERBOUND: /* mostly same as MDBX_SET_LOWERBOUND */ case MDBX_SET_LOWERBOUND: { if (unlikely(key == NULL || data == NULL)) return MDBX_EINVAL; @@ -14548,6 +14549,15 @@ int mdbx_cursor_get(MDBX_cursor *mc, MDBX_val *key, MDBX_val *data, } if (rc == MDBX_SUCCESS && !csr.exact) rc = MDBX_RESULT_TRUE; + if (unlikely(op == MDBX_SET_UPPERBOUND)) { + /* minor fixups for MDBX_SET_UPPERBOUND */ + if (rc == MDBX_RESULT_TRUE) + /* already at great-than by MDBX_SET_LOWERBOUND */ + rc = MDBX_SUCCESS; + else if (rc == MDBX_SUCCESS) + /* exactly match, going next */ + rc = mdbx_cursor_next(mc, key, data, MDBX_NEXT); + } break; } default: