Mark Statement::execute() and the fetch family [[nodiscard]] (#59)#60
Closed
mariuz wants to merge 1 commit into
Closed
Mark Statement::execute() and the fetch family [[nodiscard]] (#59)#60mariuz wants to merge 1 commit into
mariuz wants to merge 1 commit into
Conversation
…ndes#59) execute() on a SELECT opens the cursor and already fetches the first row, so the natural-looking 'execute(); while (fetchNext())' loop compiles and runs but silently drops row one. Marking execute() and the cursor-movement methods [[nodiscard]] (with a reason message) turns that shape into a compiler warning at every call site. Intentional discards - DDL/DML executes and reads of a known-existing row - are annotated with an explicit (void) cast in the tests, and the README example gains a short note about the idiom. Closes asfernandes#59
asfernandes
reviewed
Jul 21, 2026
| /// @param transaction Transaction that will own the execution context. | ||
| /// @return `true` when execution yields a record. | ||
| /// | ||
| [[nodiscard("execute() already fetches a SELECT's first row; looping on fetchNext() alone skips it")]] |
Owner
There was a problem hiding this comment.
As you see, this is not needed for DDL and I do not want that (void) thing everywhere.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #59, as offered there.
What
Statement::execute()and the cursor-movement family (fetchNext/fetchPrior/fetchFirst/fetchLast/fetchAbsolute/fetchRelative) are now[[nodiscard]], each with a C++20 reason message, so the silent first-row-loss shapebecomes a compiler warning at the call site. The doxygen comments gain the missing
@returnlines and a note on the execute-fetches-first-row semantics.The tests' intentional discards (DDL/DML executes, reads of a known-existing row, re-execution checks) are annotated with explicit
(void)casts — 49 sites, found mechanically by compiling with the new header and fixing every warning, so the suite stays warning-free under-Wall//W4.The README example gains a short note explaining why the loop is
if (execute()) do … while (fetchNext());and what the(void)idiom is for.Why
While writing 43 small fb-cpp programs (hands-on companions to a Firebird architecture paper), three of them independently wrote the
execute(); while (fetchNext())shape and silently lost the first row — no error, just missing data. Details and field report in #59.Verification
-std=c++20 -Wall, Linux aarch64).clang-format20.1.8 (the versioncheck-format.shuses) byte-for-byte.(void)casts only.🤖 Generated with Claude Code