Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/fb-cpp/Attachment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,8 @@ RowSet Attachment::queryPreparedRowSet(Statement& statement, Transaction& transa
throw FbCppException("Cannot use non-query SQL with Attachment::queryRowSet");
}

const auto hasRow = statement.execute(transaction);
statement.execute(transaction);
const auto effectiveMaxRows = statement.getType() == StatementType::EXEC_PROCEDURE ? 1u : maxRows;
return RowSet{statement, hasRow ? effectiveMaxRows : 0u, hasRow};

return RowSet{statement, effectiveMaxRows};
}
10 changes: 3 additions & 7 deletions src/fb-cpp/RowSet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,13 @@ using namespace fbcpp::impl;


RowSet::RowSet(Statement& statement, unsigned maxRows)
: RowSet{statement, maxRows, false}
{
}

RowSet::RowSet(Statement& statement, unsigned maxRows, bool includeCurrentRow)
: client{&statement.getAttachment().getClient()},
statusWrapper{statement.getAttachment().getClient()},
numericConverter{statement.getAttachment().getClient()},
calendarConverter{statement.getAttachment().getClient()}
{
assert(statement.isValid());
assert(includeCurrentRow || statement.getResultSetHandle());
assert(statement.hasCurrentRow() || statement.getResultSetHandle());

descriptors = statement.getOutputDescriptors();

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

if (includeCurrentRow && maxRows > 0u)
if (statement.hasCurrentRow() && maxRows > 0u)
{
auto& currentRow = statement.getOutputMessage();
assert(currentRow.size() == messageLength);
std::copy(currentRow.begin(), currentRow.end(), dest);
dest += messageLength;
++count;
statement.clearCurrentRow();
}

if (!resultSet)
Expand Down
20 changes: 6 additions & 14 deletions src/fb-cpp/RowSet.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,26 +58,18 @@ namespace fbcpp

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

///
/// @brief Fetches up to `maxRows` rows from the current result set of `statement`.
///
/// When `includeCurrentRow` is true, the current output message already fetched by `statement.execute()` is
/// copied as the first row before fetching the remaining rows from the result set.
///
explicit RowSet(Statement& statement, unsigned maxRows, bool includeCurrentRow);

RowSet(RowSet&& o) noexcept
: client{o.client},
count{o.count},
Expand Down
37 changes: 28 additions & 9 deletions src/fb-cpp/Statement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -196,9 +196,11 @@ Statement::Statement(Statement&& o) noexcept
outMessage{std::move(o.outMessage)},
outRow{std::make_unique<Row>(attachment->getClient(), outDescriptors, std::span{outMessage})},
type{o.type},
cursorFlags{o.cursorFlags}
cursorFlags{o.cursorFlags},
currentRow{o.currentRow}
{
o.outRow.reset();
o.currentRow = false;
}

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

o.outRow.reset();
o.currentRow = false;
}

return *this;
Expand All @@ -237,6 +241,7 @@ void Statement::free()
resultSetHandle.reset();
}

currentRow = false;
statementHandle->free(&statusWrapper);
statementHandle.reset();
}
Expand Down Expand Up @@ -266,6 +271,8 @@ bool Statement::execute(Transaction& transaction)
resultSetHandle.reset();
}

currentRow = false;

const auto outMessageData = outMessage.data();

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

default:
statementHandle->execute(&statusWrapper, transaction.getHandle().get(), inMetadata.get(), inMessage.data(),
outMetadata.get(), outMessageData);
currentRow = !outDescriptors.empty();
return true;
}
}
Expand All @@ -298,43 +307,53 @@ bool Statement::fetchNext()
{
assert(isValid());

return resultSetHandle && resultSetHandle->fetchNext(&statusWrapper, outMessage.data()) == fb::IStatus::RESULT_OK;
currentRow =
resultSetHandle && resultSetHandle->fetchNext(&statusWrapper, outMessage.data()) == fb::IStatus::RESULT_OK;
return currentRow;
}

bool Statement::fetchPrior()
{
assert(isValid());

return resultSetHandle && resultSetHandle->fetchPrior(&statusWrapper, outMessage.data()) == fb::IStatus::RESULT_OK;
currentRow =
resultSetHandle && resultSetHandle->fetchPrior(&statusWrapper, outMessage.data()) == fb::IStatus::RESULT_OK;
return currentRow;
}

bool Statement::fetchFirst()
{
assert(isValid());

return resultSetHandle && resultSetHandle->fetchFirst(&statusWrapper, outMessage.data()) == fb::IStatus::RESULT_OK;
currentRow =
resultSetHandle && resultSetHandle->fetchFirst(&statusWrapper, outMessage.data()) == fb::IStatus::RESULT_OK;
return currentRow;
}

bool Statement::fetchLast()
{
assert(isValid());

return resultSetHandle && resultSetHandle->fetchLast(&statusWrapper, outMessage.data()) == fb::IStatus::RESULT_OK;
currentRow =
resultSetHandle && resultSetHandle->fetchLast(&statusWrapper, outMessage.data()) == fb::IStatus::RESULT_OK;
return currentRow;
}

bool Statement::fetchAbsolute(unsigned position)
{
assert(isValid());

return resultSetHandle &&
currentRow = resultSetHandle &&
resultSetHandle->fetchAbsolute(&statusWrapper, static_cast<int>(position), outMessage.data()) ==
fb::IStatus::RESULT_OK;
fb::IStatus::RESULT_OK;
return currentRow;
}

bool Statement::fetchRelative(int offset)
{
assert(isValid());

return resultSetHandle &&
currentRow = resultSetHandle &&
resultSetHandle->fetchRelative(&statusWrapper, offset, outMessage.data()) == fb::IStatus::RESULT_OK;
return currentRow;
}
19 changes: 19 additions & 0 deletions src/fb-cpp/Statement.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,8 @@ namespace fbcpp
///
class FB_CPP_EXPORT Statement final
{
friend class RowSet;

public:
///
/// Prepares an SQL statement.
Expand Down Expand Up @@ -209,6 +211,17 @@ namespace fbcpp
return statementHandle != nullptr;
}

///
/// Returns whether the statement is positioned on a current output row.
///
/// A current row is present after a successful `execute()` or fetch that produced
/// output, until the row is consumed by `RowSet` or replaced by a later fetch.
///
bool hasCurrentRow() const noexcept
{
return currentRow;
}

///
/// @brief Provides direct access to the underlying Firebird statement handle.
/// @return Smart pointer to the low-level `fb::IStatement` interface.
Expand Down Expand Up @@ -2260,6 +2273,11 @@ namespace fbcpp
private:
Client& getClient() noexcept;

void clearCurrentRow() noexcept
{
currentRow = false;
}

private:
Attachment* attachment;
impl::StatusWrapper statusWrapper;
Expand All @@ -2276,6 +2294,7 @@ namespace fbcpp
std::unique_ptr<Row> outRow;
StatementType type;
unsigned cursorFlags = 0;
bool currentRow = false;
};

///
Expand Down
Loading
Loading