Lightweight 0.20260303.0
Loading...
Searching...
No Matches
SqlConnection.hpp
1// SPDX-License-Identifier: Apache-2.0
2
3#pragma once
4
5#if defined(_WIN32) || defined(_WIN64)
6 #include <Windows.h>
7#endif
8
9#include "Api.hpp"
10#include "SqlConnectInfo.hpp"
11#include "SqlError.hpp"
12#include "SqlLogger.hpp"
13#include "SqlServerType.hpp"
14
15#include <atomic>
16#include <chrono>
17#include <expected>
18#include <format>
19#include <functional>
20#include <memory>
21#include <optional>
22#include <string>
23#include <string_view>
24#include <system_error>
25
26#include <sql.h>
27#include <sqlext.h>
28#include <sqlspi.h>
29#include <sqltypes.h>
30
31namespace Lightweight
32{
33
34class SqlQueryBuilder;
35class SqlMigrationQueryBuilder;
36class SqlQueryFormatter;
37
38/// @brief Represents a connection to a SQL database.
39class SqlConnection final
40{
41 public:
42 /// @brief Constructs a new SQL connection to the default connection.
43 ///
44 /// The default connection is set via SetDefaultConnectInfo.
45 /// In case the default connection is not set, the connection will fail.
46 /// And in case the connection fails, the last error will be set.
47 LIGHTWEIGHT_API SqlConnection();
48
49 /// @brief Constructs a new SQL connection to the given connect informaton.
50 ///
51 /// @param connectInfo The connection information to use. If `std::nullopt`,
52 /// no connection is established and the object is left
53 /// in an unconnected state — use `Connect(...)` later.
54 /// If a value is provided and the connection fails,
55 /// `SqlException` is thrown carrying the ODBC diagnostic
56 /// read from the DBC handle.
57 LIGHTWEIGHT_API explicit SqlConnection(std::optional<SqlConnectionString> connectInfo);
58
59 /// Move constructor.
60 LIGHTWEIGHT_API SqlConnection(SqlConnection&& /*other*/) noexcept;
61 /// Move assignment operator.
62 LIGHTWEIGHT_API SqlConnection& operator=(SqlConnection&& /*other*/) noexcept;
63 SqlConnection(SqlConnection const& /*other*/) = delete;
64 SqlConnection& operator=(SqlConnection const& /*other*/) = delete;
65
66 /// Destructs this SQL connection object,
67 LIGHTWEIGHT_API ~SqlConnection() noexcept;
68
69 /// Retrieves the default connection information.
70 LIGHTWEIGHT_API static SqlConnectionString const& DefaultConnectionString() noexcept;
71
72 /// Sets the default connection information.
73 ///
74 /// @param connectionString The connection information to use.
75 LIGHTWEIGHT_API static void SetDefaultConnectionString(SqlConnectionString const& connectionString) noexcept;
76
77 /// Sets the default connection information as SqlConnectionDataSource.
78 LIGHTWEIGHT_API static void SetDefaultDataSource(SqlConnectionDataSource const& dataSource) noexcept;
79
80 /// Sets a callback to be called after each connection being established.
81 LIGHTWEIGHT_API static void SetPostConnectedHook(std::function<void(SqlConnection&)> hook);
82
83 /// Resets the post connected hook.
84 LIGHTWEIGHT_API static void ResetPostConnectedHook();
85
86 /// @brief Retrieves the connection ID.
87 ///
88 /// This is a unique identifier for the connection, which is useful for debugging purposes.
89 /// Note, this ID will not change if the connection is moved nor when it is reused via the connection pool.
90 [[nodiscard]] uint64_t ConnectionId() const noexcept
91 {
92 return m_connectionId;
93 }
94
95 /// Closes the connection (attempting to put it back into the connect[[ion pool).
96 LIGHTWEIGHT_API void Close() noexcept;
97
98 /// Connects to the given database with the given username and password.
99 ///
100 /// This method can be called on a connection that has been closed via Close().
101 /// If the ODBC handles have been freed, they will be automatically reallocated.
102 ///
103 /// @retval true if the connection was successful.
104 /// @retval false if the connection failed. Use LastError() to retrieve the error information.
105 LIGHTWEIGHT_API bool Connect(SqlConnectionDataSource const& info) noexcept;
106
107 /// Connects to the given database with the given connection string.
108 ///
109 /// This method can be called on a connection that has been closed via Close().
110 /// If the ODBC handles have been freed, they will be automatically reallocated.
111 ///
112 /// @retval true if the connection was successful.
113 /// @retval false if the connection failed. Use LastError() to retrieve the error information.
114 LIGHTWEIGHT_API bool Connect(SqlConnectionString sqlConnectionString) noexcept;
115
116 /// Retrieves the last error information with respect to this SQL connection handle.
117 [[nodiscard]] LIGHTWEIGHT_API SqlErrorInfo LastError() const;
118
119 /// Retrieves the name of the database in use.
120 [[nodiscard]] LIGHTWEIGHT_API std::string DatabaseName() const;
121
122 /// Retrieves the name of the user.
123 [[nodiscard]] LIGHTWEIGHT_API std::string UserName() const;
124
125 /// Retrieves the name of the server.
126 [[nodiscard]] LIGHTWEIGHT_API std::string ServerName() const;
127
128 /// Retrieves the reported server version.
129 [[nodiscard]] LIGHTWEIGHT_API std::string ServerVersion() const;
130
131 /// Retrieves the type of the server.
132 [[nodiscard]] SqlServerType ServerType() const noexcept;
133
134 /// Retrieves the name of the driver used for this connection.
135 [[nodiscard]] std::string const& DriverName() const noexcept;
136
137 /// Retrieves a query formatter suitable for the SQL server being connected.
138 [[nodiscard]] SqlQueryFormatter const& QueryFormatter() const noexcept;
139
140 /// Creates a new query builder for the given table, compatible with the current connection.
141 ///
142 /// @param table The table to query.
143 /// If not provided, the query will be a generic query builder.
144 [[nodiscard]] LIGHTWEIGHT_API SqlQueryBuilder Query(std::string_view const& table = {}) const;
145
146 /// Creates a new query builder for the given table with an alias, compatible with the current connection.
147 ///
148 /// @param table The table to query.
149 /// @param tableAlias The alias to use for the table.
150 [[nodiscard]] LIGHTWEIGHT_API SqlQueryBuilder QueryAs(std::string_view const& table,
151 std::string_view const& tableAlias) const;
152
153 /// Creates a new migration query builder, compatible the current connection.
154 [[nodiscard]] LIGHTWEIGHT_API SqlMigrationQueryBuilder Migration() const;
155
156 /// Tests if a transaction is active.
157 [[nodiscard]] LIGHTWEIGHT_API bool TransactionActive() const noexcept;
158
159 /// Tests if transactions are allowed.
160 [[nodiscard]] LIGHTWEIGHT_API bool TransactionsAllowed() const noexcept;
161
162 /// Tests if the connection is still active.
163 [[nodiscard]] LIGHTWEIGHT_API bool IsAlive() const noexcept;
164
165 /// Retrieves the connection information.
166 [[nodiscard]] LIGHTWEIGHT_API SqlConnectionString const& ConnectionString() const noexcept;
167
168 /// Retrieves the native handle.
169 [[nodiscard]] SQLHDBC NativeHandle() const noexcept
170 {
171 return m_hDbc;
172 }
173
174 /// Retrieves the last time the connection was used.
175 [[nodiscard]] LIGHTWEIGHT_API std::chrono::steady_clock::time_point LastUsed() const noexcept;
176
177 /// Sets the last time the connection was used.
178 LIGHTWEIGHT_API void SetLastUsed(std::chrono::steady_clock::time_point lastUsed) noexcept;
179
180 /// Checks the result of an SQL operation, and throws an exception if it is not successful.
181 LIGHTWEIGHT_API void RequireSuccess(SQLRETURN sqlResult,
182 std::source_location sourceLocation = std::source_location::current()) const;
183
184 private:
185 /// Ensures ODBC handles are allocated. Called by Connect() methods.
186 /// If handles were freed by Close(), this method reallocates them.
187 void EnsureHandlesAllocated();
188
189 void PostConnect();
190
191 // Private data members
192 // Note: move/move assignment operators implemented manually
193 // if adding new data members, make sure to update them accordingly.
194 SQLHENV m_hEnv {};
195 SQLHDBC m_hDbc {};
196 uint64_t m_connectionId;
197 SqlServerType m_serverType = SqlServerType::UNKNOWN;
198 SqlQueryFormatter const* m_queryFormatter {};
199 std::string m_driverName;
200
201 struct Data;
202 Data* m_data {};
203};
204
205inline SqlServerType SqlConnection::ServerType() const noexcept
206{
207 return m_serverType;
208}
209
210inline std::string const& SqlConnection::DriverName() const noexcept
211{
212 return m_driverName;
213}
214
216{
217 return *m_queryFormatter;
218}
219
220} // namespace Lightweight
Represents a connection to a SQL database.
LIGHTWEIGHT_API void RequireSuccess(SQLRETURN sqlResult, std::source_location sourceLocation=std::source_location::current()) const
Checks the result of an SQL operation, and throws an exception if it is not successful.
static LIGHTWEIGHT_API void ResetPostConnectedHook()
Resets the post connected hook.
LIGHTWEIGHT_API std::string ServerName() const
Retrieves the name of the server.
SqlServerType ServerType() const noexcept
Retrieves the type of the server.
LIGHTWEIGHT_API SqlMigrationQueryBuilder Migration() const
Creates a new migration query builder, compatible the current connection.
LIGHTWEIGHT_API bool TransactionActive() const noexcept
Tests if a transaction is active.
LIGHTWEIGHT_API bool IsAlive() const noexcept
Tests if the connection is still active.
LIGHTWEIGHT_API SqlQueryBuilder Query(std::string_view const &table={}) const
LIGHTWEIGHT_API SqlQueryBuilder QueryAs(std::string_view const &table, std::string_view const &tableAlias) const
LIGHTWEIGHT_API SqlConnection(std::optional< SqlConnectionString > connectInfo)
Constructs a new SQL connection to the given connect informaton.
LIGHTWEIGHT_API bool TransactionsAllowed() const noexcept
Tests if transactions are allowed.
uint64_t ConnectionId() const noexcept
Retrieves the connection ID.
SqlQueryFormatter const & QueryFormatter() const noexcept
Retrieves a query formatter suitable for the SQL server being connected.
LIGHTWEIGHT_API void SetLastUsed(std::chrono::steady_clock::time_point lastUsed) noexcept
Sets the last time the connection was used.
LIGHTWEIGHT_API void Close() noexcept
Closes the connection (attempting to put it back into the connect[[ion pool).
static LIGHTWEIGHT_API void SetDefaultDataSource(SqlConnectionDataSource const &dataSource) noexcept
Sets the default connection information as SqlConnectionDataSource.
static LIGHTWEIGHT_API SqlConnectionString const & DefaultConnectionString() noexcept
Retrieves the default connection information.
LIGHTWEIGHT_API SqlErrorInfo LastError() const
Retrieves the last error information with respect to this SQL connection handle.
LIGHTWEIGHT_API SqlConnection()
Constructs a new SQL connection to the default connection.
LIGHTWEIGHT_API SqlConnection(SqlConnection &&) noexcept
Move constructor.
static LIGHTWEIGHT_API void SetDefaultConnectionString(SqlConnectionString const &connectionString) noexcept
LIGHTWEIGHT_API std::string DatabaseName() const
Retrieves the name of the database in use.
LIGHTWEIGHT_API std::chrono::steady_clock::time_point LastUsed() const noexcept
Retrieves the last time the connection was used.
SQLHDBC NativeHandle() const noexcept
Retrieves the native handle.
LIGHTWEIGHT_API std::string ServerVersion() const
Retrieves the reported server version.
LIGHTWEIGHT_API SqlConnectionString const & ConnectionString() const noexcept
Retrieves the connection information.
std::string const & DriverName() const noexcept
Retrieves the name of the driver used for this connection.
LIGHTWEIGHT_API std::string UserName() const
Retrieves the name of the user.
static LIGHTWEIGHT_API void SetPostConnectedHook(std::function< void(SqlConnection &)> hook)
Sets a callback to be called after each connection being established.
LIGHTWEIGHT_API bool Connect(SqlConnectionDataSource const &info) noexcept
Query builder for building SQL migration queries.
Definition Migrate.hpp:469
API Entry point for building SQL queries.
Definition SqlQuery.hpp:32
API to format SQL queries for different SQL dialects.
Represents a connection data source as a DSN, username, password, and timeout.
Represents an ODBC connection string.
Represents an ODBC SQL error.
Definition SqlError.hpp:33