22 explicit command(std::string_view connection)
24 env_ = alloc<SQL_HANDLE_ENV>(env_);
27 env_.get(), SQL_ATTR_ODBC_VERSION, SQLPOINTER(SQL_OV_ODBC3), 0),
29 dbc_ = alloc<SQL_HANDLE_DBC>(env_);
30 check(SQLSetConnectAttr(
32 SQL_ATTR_LOGIN_TIMEOUT,
33 SQLPOINTER(std::chrono::seconds{timeout}.count()),
37 check(SQLDriverConnectW(
40 unicode::utf<SQLWCHAR>(connection).data(),
47 stmt_ = alloc<SQL_HANDLE_STMT>(dbc_);
48 id_quote_ = info(dbc_, SQL_IDENTIFIER_QUOTE_CHAR).at(0);
49 dbms_ = to_lower(info(dbc_, SQL_DBMS_NAME));
54 auto stop = std::stop_callback{tok, [&] { SQLCancel(stmt_.get()); }};
55 check(SQLFreeStmt(stmt_.get(), SQL_RESET_PARAMS), stmt_);
57 auto txt = qry.
text(id_quote_,
param_mark()) | unicode::utf<SQLWCHAR>;
58 if (txt != prepared_) {
59 check(SQLPrepareW(stmt_.get(), txt.data(), SQL_NTS), stmt_);
60 prepared_ = std::move(txt);
62 auto ps = qry.
params() | std::views::transform(params::make) |
63 std::ranges::to<std::vector>();
64 for (
size_t i{}; i < ps.size(); ++i)
65 params::bind(stmt_, SQLUSMALLINT(i + 1), ps[i]);
68 SQL_ATTR_QUERY_TIMEOUT,
69 SQLPOINTER(std::chrono::seconds{timeout}.count()),
72 auto ec = SQLExecute(stmt_.get());
73 for (; SQL_NO_DATA != ec; ec = SQLMoreResults(stmt_.get())) {
77 check(SQLNumResultCols(stmt_.get(), &cols), stmt_);
79 for (
int i{}; i < cols; ++i)
80 ret.columns.push_back(name(stmt_, i + 1));
81 ec = SQLFetch(stmt_.get());
82 for (; SQL_NO_DATA != ec; ec = SQLFetch(stmt_.get())) {
84 auto& row = ret.rows.emplace_back(cols);
85 for (
int i{}; i < cols; ++i)
86 row[i] = get_data(stmt_, i + 1);
96 check(SQLEndTran(SQL_HANDLE_DBC, dbc_.get(), SQL_ROLLBACK), dbc_);
97 auto val = SQLPOINTER(on ? SQL_AUTOCOMMIT_ON : SQL_AUTOCOMMIT_OFF);
98 check(SQLSetConnectAttr(dbc_.get(), SQL_ATTR_AUTOCOMMIT, val, 0), dbc_);