5#if defined(_WIN32) || defined(_WIN64)
10#include "SqlConnection.hpp"
11#include "SqlQuery.hpp"
12#include "SqlServerType.hpp"
19#include <source_location>
36template <
typename QueryObject>
38 { queryObject.ToSql() } -> std::convertible_to<std::string>;
42class SqlVariantRowCursor;
72 [[nodiscard]] LIGHTWEIGHT_API
bool IsAlive() const noexcept;
74 [[nodiscard]] LIGHTWEIGHT_API
bool IsPrepared() const noexcept;
77 [[nodiscard]] LIGHTWEIGHT_API
SqlConnection& Connection() noexcept;
80 [[nodiscard]] LIGHTWEIGHT_API
SqlConnection const& Connection() const noexcept;
83 [[nodiscard]] LIGHTWEIGHT_API
SqlErrorInfo LastError() const;
90 std::string_view
const& tableAlias)
const;
93 [[nodiscard]] LIGHTWEIGHT_API SQLHSTMT NativeHandle() const noexcept;
99 LIGHTWEIGHT_API
void Prepare(std::string_view query) &;
101 LIGHTWEIGHT_API
SqlStatement Prepare(std::string_view query) &&;
111 [[nodiscard]] std::
string const& PreparedQuery() const noexcept;
113 template <SqlInputParameterBinder Arg>
114 void BindInputParameter(SQLSMALLINT columnIndex, Arg const& arg);
116 template <SqlInputParameterBinder Arg, typename ColumnName>
117 void BindInputParameter(SQLSMALLINT columnIndex, Arg const& arg, ColumnName&& columnNameHint);
122 template <SqlOutputColumnBinder... Args>
123 void BindOutputColumns(Args*... args);
131 template <typename... Records>
132 requires(((std::is_class_v<Records> && std::is_aggregate_v<Records>) && ...))
133 void BindOutputColumnsToRecord(Records*... records);
135 template <SqlOutputColumnBinder T>
136 void BindOutputColumn(SQLUSMALLINT columnIndex, T* arg);
139 template <SqlInputParameterBinder... Args>
140 void Execute(Args const&... args);
143 LIGHTWEIGHT_API
void ExecuteWithVariants(std::vector<
SqlVariant> const& args);
153 template <SqlInputParameterBatchBinder FirstColumnBatch, std::ranges::contiguous_range... MoreColumnBatches>
154 void ExecuteBatchNative(FirstColumnBatch const& firstColumnBatch, MoreColumnBatches const&... moreColumnBatches);
164 template <SqlInputParameterBatchBinder FirstColumnBatch, std::ranges::range... MoreColumnBatches>
165 void ExecuteBatchSoft(FirstColumnBatch const& firstColumnBatch, MoreColumnBatches const&... moreColumnBatches);
172 template <SqlInputParameterBatchBinder FirstColumnBatch, std::ranges::range... MoreColumnBatches>
173 void ExecuteBatch(FirstColumnBatch const& firstColumnBatch, MoreColumnBatches const&... moreColumnBatches);
179 LIGHTWEIGHT_API
void ExecuteBatch(std::span<
SqlRawColumn const> columns,
size_t rowCount);
182 LIGHTWEIGHT_API
void ExecuteDirect(std::string_view const& query,
183 std::source_location location = std::source_location::current());
186 void ExecuteDirect(
SqlQueryObject auto const& query, std::source_location location = std::source_location::current());
189 template <typename Callable>
191 void MigrateDirect(Callable const& callable, std::source_location location = std::source_location::current());
195 template <typename T>
197 [[nodiscard]] std::optional<T> ExecuteDirectScalar(std::string_view const& query,
198 std::source_location location = std::source_location::current());
200 template <typename T>
202 [[nodiscard]] T ExecuteDirectScalar(std::string_view const& query,
203 std::source_location location = std::source_location::current());
207 template <typename T>
209 [[nodiscard]] std::optional<T> ExecuteDirectScalar(
SqlQueryObject auto const& query,
210 std::source_location location = std::source_location::current());
212 template <typename T>
214 [[nodiscard]] T ExecuteDirectScalar(
SqlQueryObject auto const& query,
215 std::source_location location = std::source_location::current());
218 [[nodiscard]] LIGHTWEIGHT_API
size_t NumRowsAffected() const;
221 [[nodiscard]] LIGHTWEIGHT_API
size_t NumColumnsAffected() const;
224 [[nodiscard]] LIGHTWEIGHT_API
size_t LastInsertId(std::string_view tableName);
232 [[nodiscard]] LIGHTWEIGHT_API
bool FetchRow();
234 [[nodiscard]] LIGHTWEIGHT_API std::expected<
bool,
SqlErrorInfo> TryFetchRow(
235 std::source_location location = std::source_location::current()) noexcept;
240 void CloseCursor() noexcept;
246 SqlVariantRowCursor GetVariantRowCursor() noexcept;
251 template <SqlGetColumnNativeType T>
252 [[nodiscard]]
bool GetColumn(SQLUSMALLINT column, T* result) const;
255 template <SqlGetColumnNativeType T>
256 [[nodiscard]] T GetColumn(SQLUSMALLINT column) const;
261 template <SqlGetColumnNativeType T>
262 [[nodiscard]] std::optional<T> GetNullableColumn(SQLUSMALLINT column) const;
267 template <SqlGetColumnNativeType T>
268 [[nodiscard]] T GetColumnOr(SQLUSMALLINT column, T&& defaultValue) const;
271 LIGHTWEIGHT_API
void RequireSuccess(SQLRETURN error,
272 std::source_location sourceLocation = std::source_location::current()) const;
273 LIGHTWEIGHT_API
void PlanPostExecuteCallback(std::function<
void()>&& cb) override;
274 LIGHTWEIGHT_API
void PlanPostProcessOutputColumn(std::function<
void()>&& cb) override;
275 [[nodiscard]] LIGHTWEIGHT_API SqlServerType ServerType() const noexcept override;
276 [[nodiscard]] LIGHTWEIGHT_API std::
string const& DriverName() const noexcept override;
277 LIGHTWEIGHT_API
void ProcessPostExecuteCallbacks();
279 LIGHTWEIGHT_API SQLLEN* ProvideInputIndicator() override;
280 LIGHTWEIGHT_API SQLLEN* ProvideInputIndicators(
size_t rowCount) override;
281 LIGHTWEIGHT_API
void ClearBatchIndicators();
282 LIGHTWEIGHT_API
void RequireIndicators();
283 LIGHTWEIGHT_API SQLLEN* GetIndicatorForColumn(SQLUSMALLINT column) noexcept;
287 std::unique_ptr<Data,
void (*)(Data*)> m_data;
290 std::string m_preparedQuery;
291 std::optional<SQLSMALLINT> m_numColumns;
292 SQLSMALLINT m_expectedParameterCount {};
309 m_stmt { other.m_stmt }
311 other.m_stmt =
nullptr;
318 m_stmt = other.m_stmt;
319 other.m_stmt =
nullptr;
328 m_stmt->CloseCursor();
336 return m_stmt->NumRowsAffected();
342 return m_stmt->NumColumnsAffected();
348 template <SqlOutputColumnBinder... Args>
351 m_stmt->BindOutputColumns(args...);
354 template <SqlOutputColumnBinder T>
355 LIGHTWEIGHT_FORCE_INLINE
void BindOutputColumn(SQLUSMALLINT columnIndex, T* arg)
357 m_stmt->BindOutputColumn(columnIndex, arg);
361 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE
bool FetchRow()
363 return m_stmt->FetchRow();
369 template <SqlGetColumnNativeType T>
370 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE
bool GetColumn(SQLUSMALLINT column, T* result)
const
372 return m_stmt->GetColumn<T>(column, result);
376 template <SqlGetColumnNativeType T>
377 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE T
GetColumn(SQLUSMALLINT column)
const
379 return m_stmt->GetColumn<T>(column);
385 template <SqlGetColumnNativeType T>
386 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE std::optional<T>
GetNullableColumn(SQLUSMALLINT column)
const
388 return m_stmt->GetNullableColumn<T>(column);
394 template <SqlGetColumnNativeType T>
395 [[nodiscard]] T
GetColumnOr(SQLUSMALLINT column, T&& defaultValue)
const
397 return m_stmt->GetColumnOr(column, std::forward<T>(defaultValue));
404struct [[nodiscard]] SqlSentinelIterator
408class [[nodiscard]] SqlVariantRowIterator
411 explicit SqlVariantRowIterator(SqlSentinelIterator )
noexcept:
416 explicit SqlVariantRowIterator(SqlResultCursor& cursor)
noexcept:
417 _numResultColumns {
static_cast<SQLUSMALLINT
>(cursor.NumColumnsAffected()) },
420 _row.reserve(_numResultColumns);
424 SqlVariantRow& operator*() noexcept
429 SqlVariantRow
const& operator*() const noexcept
434 SqlVariantRowIterator& operator++() noexcept
436 _end = !_cursor->FetchRow();
440 for (
auto const i: std::views::iota(SQLUSMALLINT(1), SQLUSMALLINT(_numResultColumns + 1)))
441 _row.emplace_back(_cursor->GetColumn<SqlVariant>(i));
446 bool operator!=(SqlSentinelIterator )
const noexcept
451 bool operator!=(SqlVariantRowIterator
const& )
const noexcept
458 SQLUSMALLINT _numResultColumns = 0;
459 SqlResultCursor* _cursor;
463class [[nodiscard]] SqlVariantRowCursor
466 explicit SqlVariantRowCursor(SqlResultCursor&& cursor):
467 _resultCursor { std::move(cursor) }
471 SqlVariantRowIterator begin() noexcept
473 return SqlVariantRowIterator { _resultCursor };
476 static SqlSentinelIterator end() noexcept
478 return SqlSentinelIterator {};
482 SqlResultCursor _resultCursor;
509 _connection { &conn }
516 using difference_type = bool;
517 using value_type = T;
519 iterator& operator++()
521 _is_end = !_stmt->FetchRow();
527 _stmt->CloseCursor();
532 LIGHTWEIGHT_FORCE_INLINE value_type operator*()
noexcept
536 Reflection::EnumerateMembers(res, [
this]<
size_t I>(
auto&& value) {
537 auto tmp = _stmt->GetColumn<
typename Reflection::MemberTypeOf<I, value_type>::ValueType>(I + 1);
544 LIGHTWEIGHT_FORCE_INLINE
constexpr bool operator!=(iterator
const& other)
const noexcept
546 return _is_end != other._is_end;
549 constexpr iterator(std::default_sentinel_t )
noexcept:
555 _stmt { std::make_unique<SqlStatement>(conn) }
559 LIGHTWEIGHT_FORCE_INLINE
SqlStatement& Statement()
noexcept
565 bool _is_end =
false;
566 std::unique_ptr<SqlStatement> _stmt;
571 auto it = iterator { *_connection };
572 auto& stmt = it.Statement();
573 stmt.
Prepare(it.Statement().Query(RecordTableName<T>).Select().template Fields<T>().All());
579 iterator end()
noexcept
581 return iterator { std::default_sentinel };
589inline LIGHTWEIGHT_FORCE_INLINE
bool SqlStatement::IsAlive() const noexcept
591 return m_connection && m_connection->
IsAlive() && m_hStmt !=
nullptr;
594inline LIGHTWEIGHT_FORCE_INLINE
bool SqlStatement::IsPrepared() const noexcept
596 return !m_preparedQuery.empty();
601 return *m_connection;
606 return *m_connection;
621 Prepare(queryObject.ToSql());
626 return Prepare(queryObject.ToSql());
629inline LIGHTWEIGHT_FORCE_INLINE std::string
const& SqlStatement::PreparedQuery() const noexcept
631 return m_preparedQuery;
634template <SqlOutputColumnBinder... Args>
640 ((++i, RequireSuccess(SqlDataBinder<Args>::OutputColumn(m_hStmt, i, args, GetIndicatorForColumn(i), *
this))), ...);
643template <
typename... Records>
644 requires(((std::is_class_v<Records> && std::is_aggregate_v<Records>) && ...))
650 ((Reflection::EnumerateMembers(*records,
651 [
this, &i]<
size_t I,
typename FieldType>(FieldType& value) {
653 RequireSuccess(SqlDataBinder<FieldType>::OutputColumn(
654 m_hStmt, i, &value, GetIndicatorForColumn(i), *
this));
659template <SqlOutputColumnBinder T>
660inline LIGHTWEIGHT_FORCE_INLINE
void SqlStatement::BindOutputColumn(SQLUSMALLINT columnIndex, T* arg)
664 RequireSuccess(SqlDataBinder<T>::OutputColumn(m_hStmt, columnIndex, arg, GetIndicatorForColumn(columnIndex), *
this));
667template <SqlInputParameterBinder Arg>
668inline LIGHTWEIGHT_FORCE_INLINE
void SqlStatement::BindInputParameter(SQLSMALLINT columnIndex, Arg
const& arg)
671 m_expectedParameterCount = (std::numeric_limits<
decltype(m_expectedParameterCount)>::max)();
672 RequireSuccess(SqlDataBinder<Arg>::InputParameter(m_hStmt, columnIndex, arg, *
this));
675template <SqlInputParameterBinder Arg,
typename ColumnName>
676inline LIGHTWEIGHT_FORCE_INLINE
void SqlStatement::BindInputParameter(SQLSMALLINT columnIndex,
678 ColumnName&& columnNameHint)
681 BindInputParameter(columnIndex, arg);
684template <SqlInputParameterBinder... Args>
693 if (!(m_expectedParameterCount == (std::numeric_limits<
decltype(m_expectedParameterCount)>::max)()
694 &&
sizeof...(args) == 0)
695 && !(m_expectedParameterCount ==
sizeof...(args)))
696 throw std::invalid_argument {
"Invalid argument count" };
701 RequireSuccess(SqlDataBinder<Args>::InputParameter(m_hStmt, i, args, *
this))),
704 auto const result = SQLExecute(m_hStmt);
706 if (result != SQL_NO_DATA && result != SQL_SUCCESS && result != SQL_SUCCESS_WITH_INFO)
709 ProcessPostExecuteCallbacks();
714concept SqlNativeContiguousValueConcept =
715 std::same_as<T, bool>
716 || std::same_as<T, char>
717 || std::same_as<T, unsigned char>
718 || std::same_as<T, wchar_t>
719 || std::same_as<T, std::int16_t>
720 || std::same_as<T, std::uint16_t>
721 || std::same_as<T, std::int32_t>
722 || std::same_as<T, std::uint32_t>
723 || std::same_as<T, std::int64_t>
724 || std::same_as<T, std::uint64_t>
725 || std::same_as<T, float>
726 || std::same_as<T, double>
727 || std::same_as<T, SqlDate>
728 || std::same_as<T, SqlTime>
729 || std::same_as<T, SqlDateTime>
730 || std::same_as<T, SqlFixedString<T::Capacity, typename T::value_type, T::PostRetrieveOperation>>;
732template <
typename FirstColumnBatch,
typename... MoreColumnBatches>
733concept SqlNativeBatchable =
734 std::ranges::contiguous_range<FirstColumnBatch>
735 && (std::ranges::contiguous_range<MoreColumnBatches> && ...)
736 && SqlNativeContiguousValueConcept<std::ranges::range_value_t<FirstColumnBatch>>
737 && (SqlNativeContiguousValueConcept<std::ranges::range_value_t<MoreColumnBatches>> && ...);
741template <SqlInputParameterBatchBinder FirstColumnBatch, std::ranges::contiguous_range... MoreColumnBatches>
743 MoreColumnBatches
const&... moreColumnBatches)
745 static_assert(SqlNativeBatchable<FirstColumnBatch, MoreColumnBatches...>,
746 "Must be a supported native contiguous element type.");
748 if (m_expectedParameterCount != 1 +
sizeof...(moreColumnBatches))
749 throw std::invalid_argument {
"Invalid number of columns" };
751 auto const rowCount = std::ranges::size(firstColumnBatch);
752 if (!((std::size(moreColumnBatches) == rowCount) && ...))
753 throw std::invalid_argument {
"Uneven number of rows" };
759 RequireSuccess(SQLSetStmtAttr(m_hStmt, SQL_ATTR_PARAMSET_SIZE, (SQLPOINTER) rowCount, 0));
760 RequireSuccess(SQLSetStmtAttr(m_hStmt, SQL_ATTR_PARAM_BIND_OFFSET_PTR, &rowStart, 0));
761 RequireSuccess(SQLSetStmtAttr(m_hStmt, SQL_ATTR_PARAM_BIND_TYPE, SQL_PARAM_BIND_BY_COLUMN, 0));
762 RequireSuccess(SQLSetStmtAttr(m_hStmt, SQL_ATTR_PARAM_OPERATION_PTR, SQL_PARAM_PROCEED, 0));
763 ClearBatchIndicators();
764 RequireSuccess(SqlDataBinder<std::remove_cvref_t<
decltype(*std::ranges::data(firstColumnBatch))>>::
765 BatchInputParameter(m_hStmt, 1, std::ranges::data(firstColumnBatch), rowCount, *
this));
766 SQLUSMALLINT column = 1;
767 (RequireSuccess(SqlDataBinder<std::remove_cvref_t<
decltype(*std::ranges::data(moreColumnBatches))>>::
768 BatchInputParameter(m_hStmt, ++column, std::ranges::data(moreColumnBatches), rowCount, *
this)),
770 RequireSuccess(SQLExecute(m_hStmt));
771 ProcessPostExecuteCallbacks();
775template <SqlInputParameterBatchBinder FirstColumnBatch, std::ranges::range... MoreColumnBatches>
777 MoreColumnBatches
const&... moreColumnBatches)
781 if constexpr (SqlNativeBatchable<FirstColumnBatch, MoreColumnBatches...>)
787template <SqlInputParameterBatchBinder FirstColumnBatch, std::ranges::range... MoreColumnBatches>
790 if (m_expectedParameterCount != 1 +
sizeof...(moreColumnBatches))
791 throw std::invalid_argument {
"Invalid number of columns" };
793 auto const rowCount = std::ranges::size(firstColumnBatch);
794 if (!((std::size(moreColumnBatches) == rowCount) && ...))
795 throw std::invalid_argument {
"Uneven number of rows" };
797 for (
auto const rowIndex: std::views::iota(
size_t { 0 }, rowCount))
800 [&]<SqlInputParameterBinder... ColumnValues>(ColumnValues
const&... columnsInRow) {
801 SQLUSMALLINT column = 0;
802 ((++column, SqlDataBinder<ColumnValues>::InputParameter(m_hStmt, column, columnsInRow, *this)), ...);
803 RequireSuccess(SQLExecute(m_hStmt));
804 ProcessPostExecuteCallbacks();
806 std::make_tuple(std::ref(*std::ranges::next(std::ranges::begin(firstColumnBatch), rowIndex)),
807 std::ref(*std::ranges::next(std::ranges::begin(moreColumnBatches), rowIndex))...));
811template <SqlGetColumnNativeType T>
815 RequireSuccess(SqlDataBinder<T>::GetColumn(m_hStmt, column, result, &indicator, *
this));
816 return indicator != SQL_NULL_DATA;
822 template <
typename T>
823 concept SqlNullableType = (std::same_as<T, SqlVariant> || IsSpecializationOf<std::optional, T>);
827template <SqlGetColumnNativeType T>
832 RequireSuccess(SqlDataBinder<T>::GetColumn(m_hStmt, column, &result, &indicator, *
this));
833 if constexpr (!detail::SqlNullableType<T>)
834 if (indicator == SQL_NULL_DATA)
835 throw std::runtime_error {
"Column value is NULL" };
839template <SqlGetColumnNativeType T>
844 RequireSuccess(SqlDataBinder<T>::GetColumn(m_hStmt, column, &result, &indicator, *
this));
845 if (indicator == SQL_NULL_DATA)
847 return { std::move(result) };
850template <SqlGetColumnNativeType T>
853 return GetNullableColumn<T>(column).value_or(std::forward<T>(defaultValue));
857 std::source_location location)
862template <
typename Callable>
863 requires std::invocable<Callable, SqlMigrationQueryBuilder&>
868 auto const queries = migration.GetPlan().ToSql();
869 for (
auto const& query: queries)
877 requires(!std::same_as<T, SqlVariant>)
880 auto const _ = detail::Finally([
this] { CloseCursor(); });
881 ExecuteDirect(query, location);
882 RequireSuccess(FetchRow());
883 return GetNullableColumn<T>(1);
887 requires(std::same_as<T, SqlVariant>)
890 auto const _ = detail::Finally([
this] { CloseCursor(); });
891 ExecuteDirect(query, location);
892 RequireSuccess(FetchRow());
893 if (
auto result = GetNullableColumn<T>(1); result.has_value())
899 requires(!std::same_as<T, SqlVariant>)
902 return ExecuteDirectScalar<T>(query.ToSql(), location);
906 requires(std::same_as<T, SqlVariant>)
909 return ExecuteDirectScalar<T>(query.ToSql(), location);
915 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 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 bool FetchRow()
Fetches the next row of the result set.
SQL query result row iterator.
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.
void ExecuteBatch(FirstColumnBatch const &firstColumnBatch, MoreColumnBatches const &... moreColumnBatches)
void ExecuteBatchSoft(FirstColumnBatch const &firstColumnBatch, MoreColumnBatches const &... moreColumnBatches)
void CloseCursor() noexcept
void Execute(Args const &... args)
Binds the given arguments to the prepared statement and executes it.
void ExecuteBatchNative(FirstColumnBatch const &firstColumnBatch, MoreColumnBatches const &... moreColumnBatches)
LIGHTWEIGHT_API SqlErrorInfo LastError() const
Retrieves the last error information with respect to this SQL statement handle.
SqlVariantRowCursor GetVariantRowCursor() noexcept
Retrieves the variant row cursor for reading an SQL query result of unknown column types and column c...
SqlResultCursor GetResultCursor() noexcept
Retrieves the result cursor for reading an SQL query result.
bool GetColumn(SQLUSMALLINT column, T *result) const
LIGHTWEIGHT_API SqlStatement()
Construct a new SqlStatement object, using a new connection, and connect to the default database.
void BindOutputColumnsToRecord(Records *... records)
T GetColumnOr(SQLUSMALLINT column, T &&defaultValue) const
LIGHTWEIGHT_API SqlStatement(std::nullopt_t)
Construct a new empty SqlStatement object. No SqlConnection is associated with this statement.
std::optional< T > ExecuteDirectScalar(std::string_view const &query, std::source_location location=std::source_location::current())
LIGHTWEIGHT_API void ExecuteDirect(std::string_view const &query, std::source_location location=std::source_location::current())
Executes the given query directly.
std::optional< T > GetNullableColumn(SQLUSMALLINT column) const
LIGHTWEIGHT_API SqlStatement(SqlConnection &relatedConnection)
Construct a new SqlStatement object, using the given connection.
void BindOutputColumns(Args *... args)
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.