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
39 changes: 39 additions & 0 deletions src/fb-cpp/Attachment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@
#include "Attachment.h"
#include "Client.h"
#include "Exception.h"
#include "RowSet.h"
#include "Statement.h"
#include "Transaction.h"

using namespace fbcpp;
using namespace fbcpp::impl;
Expand Down Expand Up @@ -93,3 +96,39 @@ void Attachment::dropDatabase()
{
disconnectOrDrop(true);
}

bool Attachment::execute(Transaction& transaction, std::string_view sql, const StatementOptions& options)
{
Statement statement{*this, transaction, sql, options};
return statement.execute(transaction);
}

RowSet Attachment::queryRowSet(
Transaction& transaction, std::string_view sql, unsigned maxRows, const StatementOptions& options)
{
Statement statement{*this, transaction, sql, options};
return queryPreparedRowSet(statement, transaction, maxRows);
}

RowSet Attachment::queryPreparedRowSet(Statement& statement, Transaction& transaction, unsigned maxRows)
{
switch (statement.getType())
{
case StatementType::SELECT:
case StatementType::SELECT_FOR_UPDATE:
break;

case StatementType::EXEC_PROCEDURE:
if (!statement.getOutputDescriptors().empty())
break;

throw FbCppException("Cannot use procedure without output columns with Attachment::queryRowSet");

default:
throw FbCppException("Cannot use non-query SQL with Attachment::queryRowSet");
}

const auto hasRow = statement.execute(transaction);
const auto effectiveMaxRows = statement.getType() == StatementType::EXEC_PROCEDURE ? 1u : maxRows;
return RowSet{statement, hasRow ? effectiveMaxRows : 0u, hasRow};
}
197 changes: 196 additions & 1 deletion src/fb-cpp/Attachment.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,16 @@
#define FBCPP_ATTACHMENT_H

#include "fb-api.h"
#include "RowSet.h"
#include "SmartPtrs.h"
#include "StatementOptions.h"
#include <cstddef>
#include <cstdint>
#include <memory>
#include <optional>
#include <string>
#include <string_view>
#include <vector>
#include <cstddef>


///
Expand All @@ -41,6 +44,8 @@
namespace fbcpp
{
class Client;
class Statement;
class Transaction;

///
/// Represents options used when creating an Attachment object.
Expand Down Expand Up @@ -301,14 +306,204 @@ namespace fbcpp
///
void dropDatabase();

///
/// Prepares and executes an SQL statement using the supplied transaction.
///
bool execute(Transaction& transaction, std::string_view sql, const StatementOptions& options = {});

///
/// Prepares, binds parameters, and executes an SQL statement using the supplied transaction.
///
template <typename Params>
bool execute(Transaction& transaction, std::string_view sql, const Params& params);

///
/// Prepares, binds parameters, and executes an SQL statement using the supplied transaction and statement
/// options.
///
template <typename Params>
bool execute(
Transaction& transaction, std::string_view sql, const StatementOptions& options, const Params& params);

///
/// Prepares and executes a query using the supplied transaction and returns up to maxRows rows.
///
RowSet queryRowSet(
Transaction& transaction, std::string_view sql, unsigned maxRows, const StatementOptions& options = {});

///
/// Prepares, binds parameters, and executes a query using the supplied transaction and returns up to maxRows
/// rows.
///
template <typename Params>
RowSet queryRowSet(Transaction& transaction, std::string_view sql, unsigned maxRows, const Params& params);

///
/// Prepares, binds parameters, and executes a query using the supplied transaction and statement options and
/// returns up to maxRows rows.
///
template <typename Params>
RowSet queryRowSet(Transaction& transaction, std::string_view sql, unsigned maxRows,
const StatementOptions& options, const Params& params);

///
/// Prepares and executes a query using the supplied transaction and returns the first column of the first row.
///
template <typename T>
std::optional<T> queryScalar(
Transaction& transaction, std::string_view sql, const StatementOptions& options = {});

///
/// Prepares, binds parameters, and executes a query using the supplied transaction and returns the first column
/// of the first row.
///
template <typename T, typename Params>
std::optional<T> queryScalar(Transaction& transaction, std::string_view sql, const Params& params);

///
/// Prepares, binds parameters, and executes a query using the supplied transaction and statement options and
/// returns the first column of the first row.
///
template <typename T, typename Params>
std::optional<T> queryScalar(
Transaction& transaction, std::string_view sql, const StatementOptions& options, const Params& params);

///
/// Prepares and executes a query using the supplied transaction and returns the first row mapped as T.
///
template <typename T>
std::optional<T> queryFirstRowAs(
Transaction& transaction, std::string_view sql, const StatementOptions& options = {});

///
/// Prepares, binds parameters, and executes a query using the supplied transaction and returns the first row
/// mapped as T.
///
template <typename T, typename Params>
std::optional<T> queryFirstRowAs(Transaction& transaction, std::string_view sql, const Params& params);

///
/// Prepares, binds parameters, and executes a query using the supplied transaction and statement options and
/// returns the first row mapped as T.
///
template <typename T, typename Params>
std::optional<T> queryFirstRowAs(
Transaction& transaction, std::string_view sql, const StatementOptions& options, const Params& params);

private:
void disconnectOrDrop(bool drop);
RowSet queryPreparedRowSet(Statement& statement, Transaction& transaction, unsigned maxRows);

private:
Client* client;
FbRef<fb::IAttachment> handle;
};

template <typename T>
std::optional<T> Attachment::queryScalar(
Transaction& transaction, std::string_view sql, const StatementOptions& options)
{
auto rowSet = queryRowSet(transaction, sql, 1u, options);

if (rowSet.getCount() == 0u)
return std::nullopt;

return rowSet.getRow(0).get<std::optional<T>>(0);
}

template <typename T>
std::optional<T> Attachment::queryFirstRowAs(
Transaction& transaction, std::string_view sql, const StatementOptions& options)
{
auto rowSet = queryRowSet(transaction, sql, 1u, options);

if (rowSet.getCount() == 0u)
return std::nullopt;

return rowSet.getRow(0).get<T>();
}
} // namespace fbcpp

#include "Statement.h"

namespace fbcpp
{
template <typename Params>
bool Attachment::execute(Transaction& transaction, std::string_view sql, const Params& params)
{
return execute(transaction, sql, StatementOptions{}, params);
}

template <typename Params>
bool Attachment::execute(
Transaction& transaction, std::string_view sql, const StatementOptions& options, const Params& params)
{
Statement statement{*this, transaction, sql, options};
statement.set(params);
return statement.execute(transaction);
}

template <typename Params>
RowSet Attachment::queryRowSet(
Transaction& transaction, std::string_view sql, unsigned maxRows, const Params& params)
{
return queryRowSet(transaction, sql, maxRows, StatementOptions{}, params);
}

template <typename Params>
RowSet Attachment::queryRowSet(Transaction& transaction, std::string_view sql, unsigned maxRows,
const StatementOptions& options, const Params& params)
{
Statement statement{*this, transaction, sql, options};
statement.set(params);
return queryPreparedRowSet(statement, transaction, maxRows);
}

template <typename T, typename Params>
std::optional<T> Attachment::queryScalar(Transaction& transaction, std::string_view sql, const Params& params)
{
auto rowSet = queryRowSet(transaction, sql, 1u, params);

if (rowSet.getCount() == 0u)
return std::nullopt;

return rowSet.getRow(0).template get<std::optional<T>>(0);
}

template <typename T, typename Params>
std::optional<T> Attachment::queryScalar(
Transaction& transaction, std::string_view sql, const StatementOptions& options, const Params& params)
{
auto rowSet = queryRowSet(transaction, sql, 1u, options, params);

if (rowSet.getCount() == 0u)
return std::nullopt;

return rowSet.getRow(0).template get<std::optional<T>>(0);
}

template <typename T, typename Params>
std::optional<T> Attachment::queryFirstRowAs(Transaction& transaction, std::string_view sql, const Params& params)
{
auto rowSet = queryRowSet(transaction, sql, 1u, params);

if (rowSet.getCount() == 0u)
return std::nullopt;

return rowSet.getRow(0).template get<T>();
}

template <typename T, typename Params>
std::optional<T> Attachment::queryFirstRowAs(
Transaction& transaction, std::string_view sql, const StatementOptions& options, const Params& params)
{
auto rowSet = queryRowSet(transaction, sql, 1u, options, params);

if (rowSet.getCount() == 0u)
return std::nullopt;

return rowSet.getRow(0).template get<T>();
}
} // namespace fbcpp

#endif // FBCPP_ATTACHMENT_H
26 changes: 24 additions & 2 deletions src/fb-cpp/RowSet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,21 +23,28 @@
*/

#include "RowSet.h"
#include "Attachment.h"
#include "Client.h"
#include "Statement.h"
#include <algorithm>

using namespace fbcpp;
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(statement.getResultSetHandle());
assert(includeCurrentRow || statement.getResultSetHandle());

descriptors = statement.getOutputDescriptors();

Expand All @@ -49,7 +56,22 @@ RowSet::RowSet(Statement& statement, unsigned maxRows)
auto resultSet = statement.getResultSetHandle();
auto* dest = buffer.data();

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

if (!resultSet)
{
buffer.resize(static_cast<std::size_t>(dest - buffer.data()));
return;
}

for (unsigned i = count; i < maxRows; ++i)
{
if (resultSet->fetchNext(&statusWrapper, dest) != fb::IStatus::RESULT_OK)
break;
Expand Down
8 changes: 8 additions & 0 deletions src/fb-cpp/RowSet.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,14 @@ namespace fbcpp
///
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
Loading
Loading