Skip to content

Commit e88ca3c

Browse files
committed
BREAKING: Change RowSet constructor to read already fetched Statement row
1 parent 6a96017 commit e88ca3c

6 files changed

Lines changed: 164 additions & 61 deletions

File tree

‎src/fb-cpp/Attachment.cpp‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,8 @@ RowSet Attachment::queryPreparedRowSet(Statement& statement, Transaction& transa
147147
throw FbCppException("Cannot use non-query SQL with Attachment::queryRowSet");
148148
}
149149

150-
const auto hasRow = statement.execute(transaction);
150+
statement.execute(transaction);
151151
const auto effectiveMaxRows = statement.getType() == StatementType::EXEC_PROCEDURE ? 1u : maxRows;
152-
return RowSet{statement, hasRow ? effectiveMaxRows : 0u, hasRow};
152+
153+
return RowSet{statement, effectiveMaxRows};
153154
}

‎src/fb-cpp/RowSet.cpp‎

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,18 +33,13 @@ using namespace fbcpp::impl;
3333

3434

3535
RowSet::RowSet(Statement& statement, unsigned maxRows)
36-
: RowSet{statement, maxRows, false}
37-
{
38-
}
39-
40-
RowSet::RowSet(Statement& statement, unsigned maxRows, bool includeCurrentRow)
4136
: client{&statement.getAttachment().getClient()},
4237
statusWrapper{statement.getAttachment().getClient()},
4338
numericConverter{statement.getAttachment().getClient()},
4439
calendarConverter{statement.getAttachment().getClient()}
4540
{
4641
assert(statement.isValid());
47-
assert(includeCurrentRow || statement.getResultSetHandle());
42+
assert(statement.hasCurrentRow() || statement.getResultSetHandle());
4843

4944
descriptors = statement.getOutputDescriptors();
5045

@@ -56,13 +51,14 @@ RowSet::RowSet(Statement& statement, unsigned maxRows, bool includeCurrentRow)
5651
auto resultSet = statement.getResultSetHandle();
5752
auto* dest = buffer.data();
5853

59-
if (includeCurrentRow && maxRows > 0u)
54+
if (statement.hasCurrentRow() && maxRows > 0u)
6055
{
6156
auto& currentRow = statement.getOutputMessage();
6257
assert(currentRow.size() == messageLength);
6358
std::copy(currentRow.begin(), currentRow.end(), dest);
6459
dest += messageLength;
6560
++count;
61+
statement.clearCurrentRow();
6662
}
6763

6864
if (!resultSet)

‎src/fb-cpp/RowSet.h‎

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -58,26 +58,18 @@ namespace fbcpp
5858

5959
public:
6060
///
61-
/// @brief Fetches up to `maxRows` rows from the current result set of
62-
/// `statement`.
61+
/// @brief Fetches up to `maxRows` rows from `statement`.
6362
///
64-
/// The statement must have an open result set (i.e. `execute()` was
65-
/// called and it is a SELECT-type statement). Rows are fetched via
66-
/// `IResultSet::fetchNext()` directly into the internal buffer.
63+
/// If `statement` is positioned on a current row (typically the row already
64+
/// fetched by `execute()` or a later fetch), that row is copied first and then
65+
/// consumed so a subsequent `RowSet` does not duplicate it. Remaining rows are
66+
/// fetched via `IResultSet::fetchNext()` directly into the internal buffer.
6767
///
68-
/// @param statement The statement with an open result set.
68+
/// @param statement The statement with a current row and/or an open result set.
6969
/// @param maxRows Maximum number of rows to fetch.
7070
///
7171
explicit RowSet(Statement& statement, unsigned maxRows);
7272

73-
///
74-
/// @brief Fetches up to `maxRows` rows from the current result set of `statement`.
75-
///
76-
/// When `includeCurrentRow` is true, the current output message already fetched by `statement.execute()` is
77-
/// copied as the first row before fetching the remaining rows from the result set.
78-
///
79-
explicit RowSet(Statement& statement, unsigned maxRows, bool includeCurrentRow);
80-
8173
RowSet(RowSet&& o) noexcept
8274
: client{o.client},
8375
count{o.count},

‎src/fb-cpp/Statement.cpp‎

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -196,9 +196,11 @@ Statement::Statement(Statement&& o) noexcept
196196
outMessage{std::move(o.outMessage)},
197197
outRow{std::make_unique<Row>(attachment->getClient(), outDescriptors, std::span{outMessage})},
198198
type{o.type},
199-
cursorFlags{o.cursorFlags}
199+
cursorFlags{o.cursorFlags},
200+
currentRow{o.currentRow}
200201
{
201202
o.outRow.reset();
203+
o.currentRow = false;
202204
}
203205

204206
Statement& Statement::operator=(Statement&& o) noexcept
@@ -220,8 +222,10 @@ Statement& Statement::operator=(Statement&& o) noexcept
220222
outRow = std::make_unique<Row>(attachment->getClient(), outDescriptors, std::span{outMessage});
221223
type = o.type;
222224
cursorFlags = o.cursorFlags;
225+
currentRow = o.currentRow;
223226

224227
o.outRow.reset();
228+
o.currentRow = false;
225229
}
226230

227231
return *this;
@@ -237,6 +241,7 @@ void Statement::free()
237241
resultSetHandle.reset();
238242
}
239243

244+
currentRow = false;
240245
statementHandle->free(&statusWrapper);
241246
statementHandle.reset();
242247
}
@@ -266,6 +271,8 @@ bool Statement::execute(Transaction& transaction)
266271
resultSetHandle.reset();
267272
}
268273

274+
currentRow = false;
275+
269276
const auto outMessageData = outMessage.data();
270277

271278
if (outMessageData)
@@ -280,11 +287,13 @@ bool Statement::execute(Transaction& transaction)
280287
case StatementType::SELECT_FOR_UPDATE:
281288
resultSetHandle.reset(statementHandle->openCursor(&statusWrapper, transaction.getHandle().get(),
282289
inMetadata.get(), inMessage.data(), outMetadata.get(), cursorFlags));
283-
return resultSetHandle->fetchNext(&statusWrapper, outMessageData) == fb::IStatus::RESULT_OK;
290+
currentRow = resultSetHandle->fetchNext(&statusWrapper, outMessageData) == fb::IStatus::RESULT_OK;
291+
return currentRow;
284292

285293
default:
286294
statementHandle->execute(&statusWrapper, transaction.getHandle().get(), inMetadata.get(), inMessage.data(),
287295
outMetadata.get(), outMessageData);
296+
currentRow = !outDescriptors.empty();
288297
return true;
289298
}
290299
}
@@ -298,43 +307,52 @@ bool Statement::fetchNext()
298307
{
299308
assert(isValid());
300309

301-
return resultSetHandle && resultSetHandle->fetchNext(&statusWrapper, outMessage.data()) == fb::IStatus::RESULT_OK;
310+
currentRow = resultSetHandle && resultSetHandle->fetchNext(&statusWrapper, outMessage.data()) == fb::IStatus::RESULT_OK;
311+
return currentRow;
302312
}
303313

304314
bool Statement::fetchPrior()
305315
{
306316
assert(isValid());
307317

308-
return resultSetHandle && resultSetHandle->fetchPrior(&statusWrapper, outMessage.data()) == fb::IStatus::RESULT_OK;
318+
currentRow =
319+
resultSetHandle && resultSetHandle->fetchPrior(&statusWrapper, outMessage.data()) == fb::IStatus::RESULT_OK;
320+
return currentRow;
309321
}
310322

311323
bool Statement::fetchFirst()
312324
{
313325
assert(isValid());
314326

315-
return resultSetHandle && resultSetHandle->fetchFirst(&statusWrapper, outMessage.data()) == fb::IStatus::RESULT_OK;
327+
currentRow =
328+
resultSetHandle && resultSetHandle->fetchFirst(&statusWrapper, outMessage.data()) == fb::IStatus::RESULT_OK;
329+
return currentRow;
316330
}
317331

318332
bool Statement::fetchLast()
319333
{
320334
assert(isValid());
321335

322-
return resultSetHandle && resultSetHandle->fetchLast(&statusWrapper, outMessage.data()) == fb::IStatus::RESULT_OK;
336+
currentRow =
337+
resultSetHandle && resultSetHandle->fetchLast(&statusWrapper, outMessage.data()) == fb::IStatus::RESULT_OK;
338+
return currentRow;
323339
}
324340

325341
bool Statement::fetchAbsolute(unsigned position)
326342
{
327343
assert(isValid());
328344

329-
return resultSetHandle &&
345+
currentRow = resultSetHandle &&
330346
resultSetHandle->fetchAbsolute(&statusWrapper, static_cast<int>(position), outMessage.data()) ==
331-
fb::IStatus::RESULT_OK;
347+
fb::IStatus::RESULT_OK;
348+
return currentRow;
332349
}
333350

334351
bool Statement::fetchRelative(int offset)
335352
{
336353
assert(isValid());
337354

338-
return resultSetHandle &&
355+
currentRow = resultSetHandle &&
339356
resultSetHandle->fetchRelative(&statusWrapper, offset, outMessage.data()) == fb::IStatus::RESULT_OK;
357+
return currentRow;
340358
}

‎src/fb-cpp/Statement.h‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,8 @@ namespace fbcpp
141141
///
142142
class FB_CPP_EXPORT Statement final
143143
{
144+
friend class RowSet;
145+
144146
public:
145147
///
146148
/// Prepares an SQL statement.
@@ -209,6 +211,17 @@ namespace fbcpp
209211
return statementHandle != nullptr;
210212
}
211213

214+
///
215+
/// Returns whether the statement is positioned on a current output row.
216+
///
217+
/// A current row is present after a successful `execute()` or fetch that produced
218+
/// output, until the row is consumed by `RowSet` or replaced by a later fetch.
219+
///
220+
bool hasCurrentRow() const noexcept
221+
{
222+
return currentRow;
223+
}
224+
212225
///
213226
/// @brief Provides direct access to the underlying Firebird statement handle.
214227
/// @return Smart pointer to the low-level `fb::IStatement` interface.
@@ -2260,6 +2273,11 @@ namespace fbcpp
22602273
private:
22612274
Client& getClient() noexcept;
22622275

2276+
void clearCurrentRow() noexcept
2277+
{
2278+
currentRow = false;
2279+
}
2280+
22632281
private:
22642282
Attachment* attachment;
22652283
impl::StatusWrapper statusWrapper;
@@ -2276,6 +2294,7 @@ namespace fbcpp
22762294
std::unique_ptr<Row> outRow;
22772295
StatementType type;
22782296
unsigned cursorFlags = 0;
2297+
bool currentRow = false;
22792298
};
22802299

22812300
///

0 commit comments

Comments
 (0)