5#if defined(_WIN32) || defined(_WIN64)
10#include "SqlConnection.hpp"
11#include "SqlQuery.hpp"
12#include "SqlServerType.hpp"
13#include "TracyProfiler.hpp"
20#include <source_location>
37template <
typename QueryObject>
39 { queryObject.ToSql() } -> std::convertible_to<std::string>;
43class SqlVariantRowCursor;
76 [[nodiscard]] LIGHTWEIGHT_API
bool IsAlive() const noexcept;
79 [[nodiscard]] LIGHTWEIGHT_API
bool IsPrepared() const noexcept;
82 [[nodiscard]] LIGHTWEIGHT_API
SqlConnection& Connection() noexcept;
85 [[nodiscard]] LIGHTWEIGHT_API
SqlConnection const& Connection() const noexcept;
88 [[nodiscard]] LIGHTWEIGHT_API
SqlErrorInfo LastError() const;
95 std::string_view
const& tableAlias)
const;
98 [[nodiscard]] LIGHTWEIGHT_API SQLHSTMT NativeHandle() const noexcept;
104 LIGHTWEIGHT_API
void Prepare(std::string_view query) &;
119 [[nodiscard]] std::
string const& PreparedQuery() const noexcept;
122 template <SqlInputParameterBinder Arg>
123 void BindInputParameter(SQLSMALLINT columnIndex, Arg const& arg);
126 template <SqlInputParameterBinder Arg, typename ColumnName>
127 void BindInputParameter(SQLSMALLINT columnIndex, Arg const& arg, ColumnName&& columnNameHint);
130 template <SqlInputParameterBinder... Args>
144 template <SqlInputParameterBatchBinder FirstColumnBatch, std::ranges::contiguous_range... MoreColumnBatches>
145 [[nodiscard]]
SqlResultCursor ExecuteBatchNative(FirstColumnBatch const& firstColumnBatch,
146 MoreColumnBatches const&... moreColumnBatches);
156 template <SqlInputParameterBatchBinder FirstColumnBatch, std::ranges::range... MoreColumnBatches>
157 [[nodiscard]]
SqlResultCursor ExecuteBatchSoft(FirstColumnBatch const& firstColumnBatch,
158 MoreColumnBatches const&... moreColumnBatches);
165 template <SqlInputParameterBatchBinder FirstColumnBatch, std::ranges::range... MoreColumnBatches>
167 MoreColumnBatches const&... moreColumnBatches);
177 ExecuteDirect(std::string_view const& query, std::source_location location = std::source_location::current());
181 std::source_location location = std::source_location::current());
184 template <typename Callable>
186 void MigrateDirect(Callable const& callable, std::source_location location = std::source_location::current());
190 template <typename T>
192 [[nodiscard]] std::optional<T> ExecuteDirectScalar(std::string_view const& query,
193 std::source_location location = std::source_location::current());
196 template <typename T>
198 [[nodiscard]] T ExecuteDirectScalar(std::string_view const& query,
199 std::source_location location = std::source_location::current());
203 template <typename T>
205 [[nodiscard]] std::optional<T> ExecuteDirectScalar(
SqlQueryObject auto const& query,
206 std::source_location location = std::source_location::current());
209 template <typename T>
211 [[nodiscard]] T ExecuteDirectScalar(
SqlQueryObject auto const& query,
212 std::source_location location = std::source_location::current());
215 [[nodiscard]] LIGHTWEIGHT_API
size_t LastInsertId(std::string_view tableName);
220 [[nodiscard]] LIGHTWEIGHT_API
size_t NumRowsAffected() const;
221 [[nodiscard]] LIGHTWEIGHT_API
size_t NumColumnsAffected() const;
222 [[nodiscard]] LIGHTWEIGHT_API
bool FetchRow();
223 [[nodiscard]] LIGHTWEIGHT_API std::expected<
bool,
SqlErrorInfo> TryFetchRow(
224 std::source_location location = std::source_location::current()) noexcept;
225 void CloseCursor() noexcept;
227 template <SqlOutputColumnBinder... Args>
228 void BindOutputColumns(Args*... args);
230 template <typename... Records>
231 requires(((std::is_class_v<Records> && std::is_aggregate_v<Records>) && ...))
232 void BindOutputColumnsToRecord(Records*... records);
234 template <SqlOutputColumnBinder T>
235 void BindOutputColumn(SQLUSMALLINT columnIndex, T* arg);
237 template <SqlGetColumnNativeType T>
238 [[nodiscard]]
bool GetColumn(SQLUSMALLINT column, T* result) const;
240 template <SqlGetColumnNativeType T>
241 [[nodiscard]] T GetColumn(SQLUSMALLINT column) const;
243 template <SqlGetColumnNativeType T>
244 [[nodiscard]] std::optional<T> GetNullableColumn(SQLUSMALLINT column) const;
246 template <SqlGetColumnNativeType T>
247 [[nodiscard]] T GetColumnOr(SQLUSMALLINT column, T&& defaultValue) const;
249 LIGHTWEIGHT_API
void RequireSuccess(SQLRETURN error,
250 std::source_location sourceLocation = std::source_location::current()) const;
251 LIGHTWEIGHT_API
void PlanPostExecuteCallback(std::function<
void()>&& cb) override;
252 LIGHTWEIGHT_API
void PlanPostProcessOutputColumn(std::function<
void()>&& cb) override;
253 [[nodiscard]] LIGHTWEIGHT_API SqlServerType ServerType() const noexcept override;
254 [[nodiscard]] LIGHTWEIGHT_API std::
string const& DriverName() const noexcept override;
255 LIGHTWEIGHT_API
void ProcessPostExecuteCallbacks();
257 LIGHTWEIGHT_API SQLLEN* ProvideInputIndicator() override;
258 LIGHTWEIGHT_API SQLLEN* ProvideInputIndicators(
size_t rowCount) override;
259 LIGHTWEIGHT_API
void ClearBatchIndicators();
260 LIGHTWEIGHT_API
void RequireIndicators();
261 LIGHTWEIGHT_API SQLLEN* GetIndicatorForColumn(SQLUSMALLINT column) noexcept;
265 std::unique_ptr<Data,
void (*)(Data*)> m_data;
268 std::string m_preparedQuery;
269 std::optional<SQLSMALLINT> m_numColumns;
270 SQLSMALLINT m_expectedParameterCount {};
283 SqlResultCursor() =
delete;
284 SqlResultCursor(SqlResultCursor
const&) =
delete;
285 SqlResultCursor& operator=(SqlResultCursor
const&) =
delete;
289 m_stmt { other.m_stmt }
291 other.m_stmt =
nullptr;
299 m_stmt = other.m_stmt;
300 other.m_stmt =
nullptr;
309 m_stmt->CloseCursor();
317 return m_stmt->NumRowsAffected();
323 return m_stmt->NumColumnsAffected();
329 template <SqlOutputColumnBinder... Args>
332 m_stmt->BindOutputColumns(args...);
336 template <SqlOutputColumnBinder T>
339 m_stmt->BindOutputColumn(columnIndex, arg);
343 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE
bool FetchRow()
345 return m_stmt->FetchRow();
349 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE std::expected<bool, SqlErrorInfo>
TryFetchRow(
350 std::source_location location = std::source_location::current()) noexcept
352 return m_stmt->TryFetchRow(location);
356 template <
typename... Records>
357 requires(((std::is_class_v<Records> && std::is_aggregate_v<Records>) && ...))
360 m_stmt->BindOutputColumnsToRecord(records...);
366 template <SqlGetColumnNativeType T>
367 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE
bool GetColumn(SQLUSMALLINT column, T* result)
const
369 return m_stmt->GetColumn<T>(column, result);
373 template <SqlGetColumnNativeType T>
374 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE T
GetColumn(SQLUSMALLINT column)
const
376 return m_stmt->GetColumn<T>(column);
382 template <SqlGetColumnNativeType T>
383 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE std::optional<T>
GetNullableColumn(SQLUSMALLINT column)
const
385 return m_stmt->GetNullableColumn<T>(column);
391 template <SqlGetColumnNativeType T>
392 [[nodiscard]] T
GetColumnOr(SQLUSMALLINT column, T&& defaultValue)
const
394 return m_stmt->GetColumnOr(column, std::forward<T>(defaultValue));
401struct [[nodiscard]] SqlSentinelIterator
405class [[nodiscard]] SqlVariantRowIterator
408 explicit SqlVariantRowIterator(SqlSentinelIterator )
noexcept:
413 explicit SqlVariantRowIterator(SqlResultCursor& cursor)
noexcept:
414 _numResultColumns {
static_cast<SQLUSMALLINT
>(cursor.NumColumnsAffected()) },
417 _row.reserve(_numResultColumns);
421 SqlVariantRow& operator*() noexcept
426 SqlVariantRow
const& operator*() const noexcept
431 SqlVariantRowIterator& operator++() noexcept
433 _end = !_cursor->FetchRow();
437 for (
auto const i: std::views::iota(SQLUSMALLINT(1), SQLUSMALLINT(_numResultColumns + 1)))
438 _row.emplace_back(_cursor->GetColumn<SqlVariant>(i));
443 bool operator!=(SqlSentinelIterator )
const noexcept
448 bool operator!=(SqlVariantRowIterator
const& )
const noexcept
455 SQLUSMALLINT _numResultColumns = 0;
456 SqlResultCursor* _cursor;
460class [[nodiscard]] SqlVariantRowCursor
463 explicit SqlVariantRowCursor(SqlResultCursor&& cursor):
464 _resultCursor { std::move(cursor) }
468 SqlVariantRowIterator begin() noexcept
470 return SqlVariantRowIterator { _resultCursor };
473 static SqlSentinelIterator end() noexcept
475 return SqlSentinelIterator {};
479 SqlResultCursor _resultCursor;
507 _connection { &conn }
514 using difference_type = bool;
515 using value_type = T;
517 iterator& operator++()
521 _is_end = !_cursor->FetchRow();
528 LIGHTWEIGHT_FORCE_INLINE value_type operator*() noexcept
532 Reflection::EnumerateMembers(res, [
this]<
size_t I>(
auto&& value) {
533 auto tmp = _cursor->GetColumn<
typename Reflection::MemberTypeOf<I, value_type>::ValueType>(I + 1);
540 LIGHTWEIGHT_FORCE_INLINE
constexpr bool operator!=(iterator
const& other)
const noexcept
542 return _is_end != other._is_end;
545 constexpr iterator(std::default_sentinel_t )
noexcept:
547 _cursor { std::nullopt }
551 explicit iterator(SqlConnection& conn):
552 _stmt { std::make_unique<SqlStatement>(conn) },
553 _cursor { std::nullopt }
557 LIGHTWEIGHT_FORCE_INLINE SqlStatement& Statement() noexcept
562 void SetCursor(SqlResultCursor cursor)
noexcept
564 _cursor.emplace(std::move(cursor));
568 bool _is_end =
false;
569 std::unique_ptr<SqlStatement> _stmt;
570 std::optional<SqlResultCursor> _cursor;
576 auto it = iterator { *_connection };
577 auto& stmt = it.Statement();
578 stmt.Prepare(it.Statement().Query(RecordTableName<T>).Select().template Fields<T>().All());
579 it.SetCursor(stmt.Execute());
587 return iterator { std::default_sentinel };
597 return m_connection && m_connection->
IsAlive() && m_hStmt !=
nullptr;
602 return !m_preparedQuery.empty();
607 return *m_connection;
612 return *m_connection;
627 Prepare(queryObject.ToSql());
632 return Prepare(queryObject.ToSql());
637 return m_preparedQuery;
641template <SqlOutputColumnBinder... Args>
642inline LIGHTWEIGHT_FORCE_INLINE
void SqlStatement::BindOutputColumns(Args*... args)
647 ((++i, RequireSuccess(SqlDataBinder<Args>::OutputColumn(m_hStmt, i, args, GetIndicatorForColumn(i), *
this))), ...);
650template <
typename... Records>
651 requires(((std::is_class_v<Records> && std::is_aggregate_v<Records>) && ...))
652void SqlStatement::BindOutputColumnsToRecord(Records*... records)
657 ((Reflection::EnumerateMembers(*records,
658 [
this, &i]<
size_t I,
typename FieldType>(FieldType& value) {
660 RequireSuccess(SqlDataBinder<FieldType>::OutputColumn(
661 m_hStmt, i, &value, GetIndicatorForColumn(i), *
this));
667template <SqlOutputColumnBinder T>
668inline LIGHTWEIGHT_FORCE_INLINE
void SqlStatement::BindOutputColumn(SQLUSMALLINT columnIndex, T* arg)
672 RequireSuccess(SqlDataBinder<T>::OutputColumn(m_hStmt, columnIndex, arg, GetIndicatorForColumn(columnIndex), *
this));
676template <SqlInputParameterBinder Arg>
680 m_expectedParameterCount = (std::numeric_limits<
decltype(m_expectedParameterCount)>::max)();
681 RequireSuccess(SqlDataBinder<Arg>::InputParameter(m_hStmt,
static_cast<SQLUSMALLINT
>(columnIndex), arg, *
this));
685template <SqlInputParameterBinder Arg,
typename ColumnName>
688 ColumnName&& columnNameHint)
694template <SqlInputParameterBinder... Args>
701 ZoneScopedN(
"SqlStatement::Execute");
702 ZoneTextObject(m_preparedQuery);
705 if (!(m_expectedParameterCount == (std::numeric_limits<
decltype(m_expectedParameterCount)>::max)()
706 &&
sizeof...(args) == 0)
707 && !(m_expectedParameterCount ==
sizeof...(args)))
708 throw std::invalid_argument {
"Invalid argument count" };
713 RequireSuccess(SqlDataBinder<Args>::InputParameter(m_hStmt, i, args, *
this))),
716 auto const result = SQLExecute(m_hStmt);
718 if (result != SQL_NO_DATA && result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO)
721 ProcessPostExecuteCallbacks();
727concept SqlNativeContiguousValueConcept =
728 std::same_as<T, bool>
729 || std::same_as<T, char>
730 || std::same_as<T, unsigned char>
731 || std::same_as<T, wchar_t>
732 || std::same_as<T, std::int16_t>
733 || std::same_as<T, std::uint16_t>
734 || std::same_as<T, std::int32_t>
735 || std::same_as<T, std::uint32_t>
736 || std::same_as<T, std::int64_t>
737 || std::same_as<T, std::uint64_t>
738 || std::same_as<T, float>
739 || std::same_as<T, double>
740 || std::same_as<T, SqlDate>
741 || std::same_as<T, SqlTime>
742 || std::same_as<T, SqlDateTime>
743 || std::same_as<T, SqlFixedString<T::Capacity, typename T::value_type, T::PostRetrieveOperation>>;
745template <
typename FirstColumnBatch,
typename... MoreColumnBatches>
746concept SqlNativeBatchable =
747 std::ranges::contiguous_range<FirstColumnBatch>
748 && (std::ranges::contiguous_range<MoreColumnBatches> && ...)
749 && SqlNativeContiguousValueConcept<std::ranges::range_value_t<FirstColumnBatch>>
750 && (SqlNativeContiguousValueConcept<std::ranges::range_value_t<MoreColumnBatches>> && ...);
754template <SqlInputParameterBatchBinder FirstColumnBatch, std::ranges::contiguous_range... MoreColumnBatches>
756 MoreColumnBatches
const&... moreColumnBatches)
758 static_assert(SqlNativeBatchable<FirstColumnBatch, MoreColumnBatches...>,
759 "Must be a supported native contiguous element type.");
761 ZoneScopedN(
"SqlStatement::ExecuteBatchNative");
762 ZoneTextObject(m_preparedQuery);
764 if (m_expectedParameterCount != 1 +
sizeof...(moreColumnBatches))
765 throw std::invalid_argument {
"Invalid number of columns" };
767 auto const rowCount = std::ranges::size(firstColumnBatch);
769 if (!((std::size(moreColumnBatches) == rowCount) && ...))
770 throw std::invalid_argument {
"Uneven number of rows" };
776 RequireSuccess(SQLSetStmtAttr(m_hStmt, SQL_ATTR_PARAMSET_SIZE, (SQLPOINTER) rowCount, 0));
777 RequireSuccess(SQLSetStmtAttr(m_hStmt, SQL_ATTR_PARAM_BIND_OFFSET_PTR, &rowStart, 0));
778 RequireSuccess(SQLSetStmtAttr(m_hStmt, SQL_ATTR_PARAM_BIND_TYPE, SQL_PARAM_BIND_BY_COLUMN, 0));
779 RequireSuccess(SQLSetStmtAttr(m_hStmt, SQL_ATTR_PARAM_OPERATION_PTR, SQL_PARAM_PROCEED, 0));
780 ClearBatchIndicators();
781 RequireSuccess(SqlDataBinder<std::remove_cvref_t<
decltype(*std::ranges::data(firstColumnBatch))>>::
782 BatchInputParameter(m_hStmt, 1, std::ranges::data(firstColumnBatch), rowCount, *
this));
783 SQLUSMALLINT column = 1;
784 (RequireSuccess(SqlDataBinder<std::remove_cvref_t<
decltype(*std::ranges::data(moreColumnBatches))>>::
785 BatchInputParameter(m_hStmt, ++column, std::ranges::data(moreColumnBatches), rowCount, *
this)),
787 RequireSuccess(SQLExecute(m_hStmt));
788 ProcessPostExecuteCallbacks();
794template <SqlInputParameterBatchBinder FirstColumnBatch, std::ranges::range... MoreColumnBatches>
796 MoreColumnBatches
const&... moreColumnBatches)
800 if constexpr (SqlNativeBatchable<FirstColumnBatch, MoreColumnBatches...>)
806template <SqlInputParameterBatchBinder FirstColumnBatch, std::ranges::range... MoreColumnBatches>
808 MoreColumnBatches
const&... moreColumnBatches)
810 ZoneScopedN(
"SqlStatement::ExecuteBatchSoft");
811 ZoneTextObject(m_preparedQuery);
813 if (m_expectedParameterCount != 1 +
sizeof...(moreColumnBatches))
814 throw std::invalid_argument {
"Invalid number of columns" };
816 auto const rowCount = std::ranges::size(firstColumnBatch);
818 if (!((std::size(moreColumnBatches) == rowCount) && ...))
819 throw std::invalid_argument {
"Uneven number of rows" };
821 for (
auto const rowIndex: std::views::iota(
size_t { 0 }, rowCount))
824 [&]<SqlInputParameterBinder... ColumnValues>(ColumnValues
const&... columnsInRow) {
825 SQLUSMALLINT column = 0;
826 ((++column, SqlDataBinder<ColumnValues>::InputParameter(m_hStmt, column, columnsInRow, *this)), ...);
827 RequireSuccess(SQLExecute(m_hStmt));
828 ProcessPostExecuteCallbacks();
831 std::ref(*std::ranges::next(std::ranges::begin(firstColumnBatch),
static_cast<std::ptrdiff_t
>(rowIndex))),
833 *std::ranges::next(std::ranges::begin(moreColumnBatches),
static_cast<std::ptrdiff_t
>(rowIndex)))...));
838template <SqlGetColumnNativeType T>
839inline bool SqlStatement::GetColumn(SQLUSMALLINT column, T* result)
const
842 RequireSuccess(SqlDataBinder<T>::GetColumn(m_hStmt, column, result, &indicator, *
this));
843 return indicator != SQL_NULL_DATA;
849 template <
typename T>
850 concept SqlNullableType = (std::same_as<T, SqlVariant> || IsSpecializationOf<std::optional, T>);
854template <SqlGetColumnNativeType T>
855inline T SqlStatement::GetColumn(SQLUSMALLINT column)
const
859 RequireSuccess(SqlDataBinder<T>::GetColumn(m_hStmt, column, &result, &indicator, *
this));
860 if constexpr (!detail::SqlNullableType<T>)
861 if (indicator == SQL_NULL_DATA)
862 throw std::runtime_error {
"Column value is NULL" };
866template <SqlGetColumnNativeType T>
867inline std::optional<T> SqlStatement::GetNullableColumn(SQLUSMALLINT column)
const
871 RequireSuccess(SqlDataBinder<T>::GetColumn(m_hStmt, column, &result, &indicator, *
this));
872 if (indicator == SQL_NULL_DATA)
874 return { std::move(result) };
877template <SqlGetColumnNativeType T>
878T SqlStatement::GetColumnOr(SQLUSMALLINT column, T&& defaultValue)
const
880 return GetNullableColumn<T>(column).value_or(std::forward<T>(defaultValue));
884 std::source_location location)
889template <
typename Callable>
890 requires std::invocable<Callable, SqlMigrationQueryBuilder&>
893 ZoneScopedN(
"SqlStatement::MigrateDirect");
896 auto const queries = migration.GetPlan().ToSql();
897 ZoneValue(queries.size());
898 for (
auto const& query: queries)
900 [[maybe_unused]]
auto cursor =
ExecuteDirect(query, location);
905 requires(!std::same_as<T, SqlVariant>)
908 auto cursor = ExecuteDirect(query, location);
909 RequireSuccess(FetchRow());
910 return GetNullableColumn<T>(1);
914 requires(std::same_as<T, SqlVariant>)
917 auto cursor = ExecuteDirect(query, location);
918 RequireSuccess(FetchRow());
919 if (
auto result = GetNullableColumn<T>(1); result.has_value())
925 requires(!std::same_as<T, SqlVariant>)
928 return ExecuteDirectScalar<T>(query.ToSql(), location);
932 requires(std::same_as<T, SqlVariant>)
935 return ExecuteDirectScalar<T>(query.ToSql(), location);
938inline LIGHTWEIGHT_FORCE_INLINE
void SqlStatement::CloseCursor() noexcept
941 SQLFreeStmt(m_hStmt, SQL_CLOSE);
Represents a connection to a SQL database.
LIGHTWEIGHT_API bool IsAlive() const noexcept
Tests if the connection is still active.
SqlQueryFormatter const & QueryFormatter() const noexcept
Retrieves a query formatter suitable for the SQL server being connected.
virtual void OnExecute(std::string_view const &query)=0
Invoked when a prepared query is executed.
static LIGHTWEIGHT_API SqlLogger & GetLogger()
Retrieves the currently configured logger.
virtual void OnFetchEnd()=0
Invoked when fetching is done.
void OnBindInputParameter(std::string_view const &name, T &&value)
Invoked when an input parameter is bound.
Query builder for building SQL migration queries.
API Entry point for building SQL queries.
API for reading an SQL query result set.
LIGHTWEIGHT_FORCE_INLINE void BindOutputColumnsToRecord(Records *... records)
Binds the given records to the prepared statement to store the fetched data to.
constexpr SqlResultCursor(SqlResultCursor &&other) noexcept
Move constructor.
LIGHTWEIGHT_FORCE_INLINE SqlResultCursor(SqlStatement &stmt) noexcept
Constructs a result cursor for the given SQL statement.
constexpr SqlResultCursor & operator=(SqlResultCursor &&other) noexcept
Move assignment operator.
LIGHTWEIGHT_FORCE_INLINE bool GetColumn(SQLUSMALLINT column, T *result) const
LIGHTWEIGHT_FORCE_INLINE void BindOutputColumns(Args *... args)
LIGHTWEIGHT_FORCE_INLINE std::optional< T > GetNullableColumn(SQLUSMALLINT column) const
LIGHTWEIGHT_FORCE_INLINE T GetColumn(SQLUSMALLINT column) const
Retrieves the value of the column at the given index for the currently selected row.
T GetColumnOr(SQLUSMALLINT column, T &&defaultValue) const
LIGHTWEIGHT_FORCE_INLINE size_t NumColumnsAffected() const
Retrieves the number of columns affected by the last query.
LIGHTWEIGHT_FORCE_INLINE size_t NumRowsAffected() const
Retrieves the number of rows affected by the last query.
LIGHTWEIGHT_FORCE_INLINE void BindOutputColumn(SQLUSMALLINT columnIndex, T *arg)
Binds a single output column at the given index to store fetched data.
LIGHTWEIGHT_FORCE_INLINE bool FetchRow()
Fetches the next row of the result set.
LIGHTWEIGHT_FORCE_INLINE std::expected< bool, SqlErrorInfo > TryFetchRow(std::source_location location=std::source_location::current()) noexcept
Attempts to fetch the next row, returning an error info on failure instead of throwing.
SQL query result row iterator.
SqlRowIterator(SqlConnection &conn)
Constructs a row iterator using the given SQL connection.
iterator end() noexcept
Returns a sentinel iterator representing the end of the result set.
iterator begin()
Returns an iterator to the first row of the result set.
High level API for (prepared) raw SQL statements.
LIGHTWEIGHT_API void Prepare(std::string_view query) &
LIGHTWEIGHT_API SQLHSTMT NativeHandle() const noexcept
Retrieves the native handle of the statement.
LIGHTWEIGHT_API SqlQueryBuilder QueryAs(std::string_view const &table, std::string_view const &tableAlias) const
Creates a new query builder for the given table with an alias, compatible with the SQL server being c...
void MigrateDirect(Callable const &callable, std::source_location location=std::source_location::current())
Executes an SQL migration query, as created b the callback.
LIGHTWEIGHT_API SqlConnection & Connection() noexcept
Retrieves the connection associated with this statement.
std::string const & PreparedQuery() const noexcept
Retrieves the last prepared query string.
SqlResultCursor Execute(Args const &... args)
Binds the given arguments to the prepared statement and executes it.
SqlResultCursor ExecuteBatch(FirstColumnBatch const &firstColumnBatch, MoreColumnBatches const &... moreColumnBatches)
LIGHTWEIGHT_API SqlErrorInfo LastError() const
Retrieves the last error information with respect to this SQL statement handle.
LIGHTWEIGHT_API SqlStatement(SqlStatement &&other) noexcept
Move constructor.
LIGHTWEIGHT_API SqlStatement()
Construct a new SqlStatement object, using a new connection, and connect to the default database.
LIGHTWEIGHT_API bool IsPrepared() const noexcept
Checks whether the statement has been prepared.
void BindInputParameter(SQLSMALLINT columnIndex, Arg const &arg)
Binds an input parameter to the prepared statement at the given column index.
LIGHTWEIGHT_API SqlStatement & operator=(SqlStatement &&other) noexcept
Move assignment operator.
LIGHTWEIGHT_API SqlStatement(std::nullopt_t)
Construct a new empty SqlStatement object. No SqlConnection is associated with this statement.
LIGHTWEIGHT_API SqlResultCursor ExecuteDirect(std::string_view const &query, std::source_location location=std::source_location::current())
Executes the given query directly.
LIGHTWEIGHT_API bool IsAlive() const noexcept
Checks whether the statement's connection is alive and the statement handle is valid.
std::optional< T > ExecuteDirectScalar(std::string_view const &query, std::source_location location=std::source_location::current())
SqlResultCursor ExecuteBatchNative(FirstColumnBatch const &firstColumnBatch, MoreColumnBatches const &... moreColumnBatches)
LIGHTWEIGHT_API SqlStatement(SqlConnection &relatedConnection)
Construct a new SqlStatement object, using the given connection.
SqlResultCursor ExecuteBatchSoft(FirstColumnBatch const &firstColumnBatch, MoreColumnBatches const &... moreColumnBatches)
Represents an SQL query object, that provides a ToSql() method.
constexpr auto SqlNullValue
Represents an ODBC SQL error.
static SqlErrorInfo FromStatementHandle(SQLHSTMT hStmt)
Constructs an ODBC error info object from the given ODBC statement handle.
A non-owning reference to a raw column data for batch processing.
Represents a value that can be any of the supported SQL data types.