99 lines
3.0 KiB
C++
99 lines
3.0 KiB
C++
#pragma once
|
|
|
|
#include <string>
|
|
#include <vector>
|
|
#include <mutex>
|
|
#include <cstdint>
|
|
#include <sql.h>
|
|
#include <sqlext.h>
|
|
#include <uv.h>
|
|
|
|
enum class CellType { Null, Int64, Double, String, Blob };
|
|
|
|
struct Cell {
|
|
CellType type = CellType::Null;
|
|
int64_t i64 = 0;
|
|
double dbl = 0.0;
|
|
std::string str;
|
|
std::vector<uint8_t> blob;
|
|
};
|
|
|
|
using Row = std::vector<Cell>;
|
|
using ResultSet = std::vector<Row>;
|
|
|
|
enum class ParamType { Int, BigInt, Float, Double, NVarChar, Bit, DateTime };
|
|
|
|
struct Param {
|
|
ParamType type;
|
|
std::string str_val;
|
|
int64_t int_val = 0;
|
|
double dbl_val = 0.0;
|
|
bool is_null = false;
|
|
|
|
static Param null_int() { Param p; p.type = ParamType::Int; p.is_null = true; return p; }
|
|
static Param null_bigint() { Param p; p.type = ParamType::BigInt; p.is_null = true; return p; }
|
|
static Param null_nvarchar() { Param p; p.type = ParamType::NVarChar; p.is_null = true; return p; }
|
|
};
|
|
|
|
class OdbcPool {
|
|
public:
|
|
struct Connection {
|
|
SQLHDBC hdbc = SQL_NULL_HDBC;
|
|
SQLHSTMT hstmt = SQL_NULL_HSTMT;
|
|
bool in_use = false;
|
|
bool in_transaction = false;
|
|
};
|
|
|
|
// RAII checkout guard. Returned by checkout().
|
|
struct ConnGuard {
|
|
Connection* conn = nullptr;
|
|
OdbcPool* pool = nullptr;
|
|
ConnGuard() = default;
|
|
ConnGuard(Connection* c, OdbcPool* p) : conn(c), pool(p) {}
|
|
~ConnGuard() { if (conn && pool) pool->release(conn); }
|
|
ConnGuard(const ConnGuard&) = delete;
|
|
ConnGuard(ConnGuard&& other) noexcept : conn(other.conn), pool(other.pool) { other.conn = nullptr; }
|
|
ConnGuard& operator=(ConnGuard&& other) noexcept {
|
|
if (this != &other) {
|
|
if (conn && pool) pool->release(conn);
|
|
conn = other.conn;
|
|
pool = other.pool;
|
|
other.conn = nullptr;
|
|
}
|
|
return *this;
|
|
}
|
|
Connection* operator->() const { return conn; }
|
|
Connection* get() const { return conn; }
|
|
explicit operator bool() const { return conn != nullptr; }
|
|
};
|
|
|
|
~OdbcPool();
|
|
int connect();
|
|
void disconnect();
|
|
|
|
bool execute(const std::string& sql, const std::vector<Param>& params, ResultSet& out);
|
|
bool execute(const std::string& sql, ResultSet& out);
|
|
int64_t execute_scalar(const std::string& sql, const std::vector<Param>& params = {}, int64_t fallback = 0);
|
|
|
|
// Transactional execution on an explicitly checked-out connection.
|
|
ConnGuard checkout();
|
|
bool execute(Connection* conn, const std::string& sql, const std::vector<Param>& params, ResultSet& out);
|
|
bool execute(Connection* conn, const std::string& sql, ResultSet& out);
|
|
bool begin(Connection* conn);
|
|
bool commit(Connection* conn);
|
|
bool rollback(Connection* conn);
|
|
|
|
void release(Connection* c);
|
|
|
|
const std::string& last_error() const { return last_error_; }
|
|
|
|
private:
|
|
SQLHENV henv_ = SQL_NULL_HENV;
|
|
std::vector<Connection> conns_;
|
|
std::mutex mutex_;
|
|
std::string last_error_;
|
|
Connection* checkout_raw();
|
|
};
|
|
|
|
OdbcPool& get_pool();
|