From eba317b65bccd759342cb049c692cdaed29e5af7 Mon Sep 17 00:00:00 2001 From: "F.D.Castel" Date: Wed, 11 Mar 2026 23:00:35 -0300 Subject: [PATCH 1/3] Add getOutputMessage() accessor to Statement Symmetrical with the existing getInputMessage(), provides direct access to the raw output message buffer for consumers that need to read fetched row data at the raw byte level. Closes #42 (REQ-2). --- src/fb-cpp/Statement.h | 8 ++++++++ src/test/Statement.cpp | 21 +++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/src/fb-cpp/Statement.h b/src/fb-cpp/Statement.h index 396e7eb..f8590d7 100644 --- a/src/fb-cpp/Statement.h +++ b/src/fb-cpp/Statement.h @@ -408,6 +408,14 @@ namespace fbcpp return outMetadata; } + /// + /// @brief Provides direct access to the raw output message buffer. + /// + std::vector& getOutputMessage() noexcept + { + return outMessage; + } + /// /// @brief Returns the type classification reported by the server. /// diff --git a/src/test/Statement.cpp b/src/test/Statement.cpp index e1b45f9..d566d22 100644 --- a/src/test/Statement.cpp +++ b/src/test/Statement.cpp @@ -336,6 +336,27 @@ BOOST_AUTO_TEST_CASE(descriptorMetadataFields) BOOST_CHECK(inDescriptors[0].alias.empty()); } +BOOST_AUTO_TEST_CASE(getOutputMessageMatchesMetadataLength) +{ + const auto database = getTempFile("Statement-getOutputMessageMatchesMetadataLength.fdb"); + + Attachment attachment{CLIENT, database, AttachmentOptions().setCreateDatabase(true)}; + FbDropDatabase attachmentDrop{attachment}; + + Transaction transaction{attachment}; + Statement stmt{attachment, transaction, "select 42 from rdb$database"}; + + auto& outMsg = stmt.getOutputMessage(); + BOOST_CHECK(!outMsg.empty()); + + // After fetch, the output message buffer contains the fetched data. + BOOST_REQUIRE(stmt.execute(transaction)); + BOOST_CHECK_EQUAL(stmt.getInt32(0).value(), 42); + + // The buffer reference should remain the same object. + BOOST_CHECK_EQUAL(&outMsg, &stmt.getOutputMessage()); +} + BOOST_AUTO_TEST_SUITE_END() From 2c87ad2df3c3a6a845bf3ce4735bffc1524e8d05 Mon Sep 17 00:00:00 2001 From: "F.D.Castel" Date: Thu, 12 Mar 2026 15:30:04 -0300 Subject: [PATCH 2/3] test: validate output buffer via metadata offset --- src/test/Statement.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/test/Statement.cpp b/src/test/Statement.cpp index d566d22..72e5063 100644 --- a/src/test/Statement.cpp +++ b/src/test/Statement.cpp @@ -336,9 +336,9 @@ BOOST_AUTO_TEST_CASE(descriptorMetadataFields) BOOST_CHECK(inDescriptors[0].alias.empty()); } -BOOST_AUTO_TEST_CASE(getOutputMessageMatchesMetadataLength) +BOOST_AUTO_TEST_CASE(getOutputMessageContainsFetchedValueAtMetadataOffset) { - const auto database = getTempFile("Statement-getOutputMessageMatchesMetadataLength.fdb"); + const auto database = getTempFile("Statement-getOutputMessageContainsFetchedValueAtMetadataOffset.fdb"); Attachment attachment{CLIENT, database, AttachmentOptions().setCreateDatabase(true)}; FbDropDatabase attachmentDrop{attachment}; @@ -349,12 +349,17 @@ BOOST_AUTO_TEST_CASE(getOutputMessageMatchesMetadataLength) auto& outMsg = stmt.getOutputMessage(); BOOST_CHECK(!outMsg.empty()); - // After fetch, the output message buffer contains the fetched data. + auto outMetadata = stmt.getOutputMetadata(); + FbUniquePtr tempStatus{CLIENT.newStatus()}; + impl::StatusWrapper tempWrapper{CLIENT, tempStatus.get()}; + const auto valueOffset = outMetadata->getOffset(&tempWrapper, 0u); + BOOST_REQUIRE(stmt.execute(transaction)); BOOST_CHECK_EQUAL(stmt.getInt32(0).value(), 42); - // The buffer reference should remain the same object. - BOOST_CHECK_EQUAL(&outMsg, &stmt.getOutputMessage()); + BOOST_REQUIRE_GE(outMsg.size(), valueOffset + sizeof(std::int32_t)); + const auto* data = &outMsg[valueOffset]; + BOOST_CHECK_EQUAL(*reinterpret_cast(data), 42); } BOOST_AUTO_TEST_SUITE_END() From 2608b7cfb7adb13568a69bba81848fedfde7fe9d Mon Sep 17 00:00:00 2001 From: "F.D.Castel" Date: Sat, 14 Mar 2026 00:03:55 -0300 Subject: [PATCH 3/3] test: use getOutputDescriptors offset instead of IMetaData::getOffset --- src/test/Statement.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/test/Statement.cpp b/src/test/Statement.cpp index 72e5063..e8722a9 100644 --- a/src/test/Statement.cpp +++ b/src/test/Statement.cpp @@ -349,10 +349,7 @@ BOOST_AUTO_TEST_CASE(getOutputMessageContainsFetchedValueAtMetadataOffset) auto& outMsg = stmt.getOutputMessage(); BOOST_CHECK(!outMsg.empty()); - auto outMetadata = stmt.getOutputMetadata(); - FbUniquePtr tempStatus{CLIENT.newStatus()}; - impl::StatusWrapper tempWrapper{CLIENT, tempStatus.get()}; - const auto valueOffset = outMetadata->getOffset(&tempWrapper, 0u); + const auto valueOffset = stmt.getOutputDescriptors()[0].offset; BOOST_REQUIRE(stmt.execute(transaction)); BOOST_CHECK_EQUAL(stmt.getInt32(0).value(), 42);