Instead of returning a Dbc (BDB cursor object) and having the caller deal with the cursor, make BerkeleyBatch handle the cursor internally.
Split from #18971
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.
Reviewers, this pull request conflicts with the following ones:
If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.
869+            bool ret = m_batch.ReadAtCursor(ssKey, ssValue, complete);
870+            if (complete) {
871+                m_batch.CloseCursor();
872                 break;
873-            else if (ret != 0)
874+            }
} else if (!ret) {
              
            738@@ -738,27 +739,32 @@ void BerkeleyDatabase::ReloadDbEnv()
739     }
740 }
741 
742-Dbc* BerkeleyBatch::GetCursor()
743+bool BerkeleyBatch::CreateCursor()
StartCursor would be a better name, after all, the whole process (including details like whether something is created) is internal.
              
            StartCursor.
              
            This does limit flexibility a bit, though I guess one cursor at a time is enough for all our current and future use cases.
If another cursor was needed, you could use another Batch object. But we barely use cursors, so one is enough for now.
If another cursor was needed, you could use another Batch object. But we barely use cursors, so one is enough for now.
Ohh! I missed that it’s on the batch, not on the database object.
744@@ -742,8 +745,8 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet)
745             if (!strErr.empty())
746                 pwallet->WalletLogPrintf("%s\n", strErr);
747         }
748-        pcursor->close();
In commit “walletdb: Handle cursor internally” (cda86544ae9de430e4558b87945046d5612202ac)
Minor: I think it’d be a little clearer to keep this close here as m_batch.CloseCursor() so it’s more obvious cursor is closed in all cases, and so you don’t need to add a new close call in a different place above.
catch block and removed the ones inside the loop except for the ones right before the early return.
              
            751+    int ret = pdb->cursor(nullptr, &m_cursor, 0);
752     if (ret != 0)
753-        return nullptr;
754-    return pcursor;
755+        return false;
756+    return true;
return ret == 0.
              
            
Instead of returning a Dbc (BDB cursor object) and having the caller
deal with the cursor, make BerkeleyBatch handle the cursor internally.
This prepares BerkeleyBatch to work with other database systems as Dbc
objects are BDB specific.
757 
758-int BerkeleyBatch::ReadAtCursor(Dbc* pcursor, CDataStream& ssKey, CDataStream& ssValue)
759+bool BerkeleyBatch::ReadAtCursor(CDataStream& ssKey, CDataStream& ssValue, bool& complete)
760 {
761+    complete = false;
762+    if (m_cursor == nullptr) return false;
assert(m_cursor)? There was no check for pcursor.
              
            StartCursor must be called before.
              
            334@@ -335,7 +335,7 @@ void BerkeleyEnvironment::CheckpointLSN(const std::string& strFile)
335 }
336 
337 
338-BerkeleyBatch::BerkeleyBatch(BerkeleyDatabase& database, const char* pszMode, bool fFlushOnCloseIn) : pdb(nullptr), activeTxn(nullptr)
339+BerkeleyBatch::BerkeleyBatch(BerkeleyDatabase& database, const char* pszMode, bool fFlushOnCloseIn) : pdb(nullptr), activeTxn(nullptr), m_cursor(nullptr)