diff --git a/mdbx.h b/mdbx.h index 765f11e3..0123a139 100644 --- a/mdbx.h +++ b/mdbx.h @@ -5138,6 +5138,10 @@ mdbx_cursor_eof(const MDBX_cursor *cursor); MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API int mdbx_cursor_on_first(const MDBX_cursor *cursor); +/** FIXME */ +MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API int +mdbx_cursor_on_first_dup(const MDBX_cursor *cursor); + /** \brief Determines whether the cursor is pointed to the last key-value pair * or not. * \ingroup c_cursors @@ -5152,6 +5156,10 @@ mdbx_cursor_on_first(const MDBX_cursor *cursor); MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API int mdbx_cursor_on_last(const MDBX_cursor *cursor); +/** FIXME */ +MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API int +mdbx_cursor_on_last_dup(const MDBX_cursor *cursor); + /** \addtogroup c_rqest * \details \note The estimation result varies greatly depending on the filling * of specific pages and the overall balance of the b-tree: diff --git a/mdbx.h++ b/mdbx.h++ index c973573b..eaa5279c 100644 --- a/mdbx.h++ +++ b/mdbx.h++ @@ -4467,6 +4467,8 @@ public: inline bool eof() const; inline bool on_first() const; inline bool on_last() const; + inline bool on_first_multival() const; + inline bool on_last_multival() const; inline estimate_result estimate(const slice &key, const slice &value) const; inline estimate_result estimate(const slice &key) const; inline estimate_result estimate(move_operation operation) const; @@ -6396,6 +6398,14 @@ inline bool cursor::on_last() const { return error::boolean_or_throw(::mdbx_cursor_on_last(*this)); } +inline bool cursor::on_first_multival() const { + return error::boolean_or_throw(::mdbx_cursor_on_first_dup(*this)); +} + +inline bool cursor::on_last_multival() const { + return error::boolean_or_throw(::mdbx_cursor_on_last_dup(*this)); +} + inline cursor::estimate_result cursor::estimate(const slice &key, const slice &value) const { return estimate_result(*this, multi_exactkey_lowerboundvalue, key, value); diff --git a/src/core.c b/src/core.c index 909b8469..2e577a93 100644 --- a/src/core.c +++ b/src/core.c @@ -24533,6 +24533,29 @@ int mdbx_cursor_on_first(const MDBX_cursor *mc) { return MDBX_RESULT_TRUE; } +int mdbx_cursor_on_first_dup(const MDBX_cursor *mc) { + if (unlikely(mc == NULL)) + return MDBX_EINVAL; + + if (unlikely(mc->mc_signature != MDBX_MC_LIVE)) + return (mc->mc_signature == MDBX_MC_READY4CLOSE) ? MDBX_EINVAL + : MDBX_EBADSIGN; + + if (!(mc->mc_flags & C_INITIALIZED)) + return mc->mc_db->md_entries ? MDBX_RESULT_FALSE : MDBX_RESULT_TRUE; + + if (!mc->mc_xcursor) + return MDBX_RESULT_TRUE; + + mc = &mc->mc_xcursor->mx_cursor; + for (size_t i = 0; i < mc->mc_snum; ++i) { + if (mc->mc_ki[i]) + return MDBX_RESULT_FALSE; + } + + return MDBX_RESULT_TRUE; +} + int mdbx_cursor_on_last(const MDBX_cursor *mc) { if (unlikely(mc == NULL)) return MDBX_EINVAL; @@ -24553,6 +24576,30 @@ int mdbx_cursor_on_last(const MDBX_cursor *mc) { return MDBX_RESULT_TRUE; } +int mdbx_cursor_on_last_dup(const MDBX_cursor *mc) { + if (unlikely(mc == NULL)) + return MDBX_EINVAL; + + if (unlikely(mc->mc_signature != MDBX_MC_LIVE)) + return (mc->mc_signature == MDBX_MC_READY4CLOSE) ? MDBX_EINVAL + : MDBX_EBADSIGN; + + if (!(mc->mc_flags & C_INITIALIZED)) + return mc->mc_db->md_entries ? MDBX_RESULT_FALSE : MDBX_RESULT_TRUE; + + if (!mc->mc_xcursor) + return MDBX_RESULT_TRUE; + + mc = &mc->mc_xcursor->mx_cursor; + for (size_t i = 0; i < mc->mc_snum; ++i) { + size_t nkeys = page_numkeys(mc->mc_pg[i]); + if (mc->mc_ki[i] < nkeys - 1) + return MDBX_RESULT_FALSE; + } + + return MDBX_RESULT_TRUE; +} + int mdbx_cursor_eof(const MDBX_cursor *mc) { if (unlikely(mc == NULL)) return MDBX_EINVAL;