Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions odbc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ add_library(ydb-odbc SHARED
src/utils/convert.cpp
src/utils/error_manager.cpp
src/odbc_driver.cpp
src/connection_attributes.cpp
src/connection.cpp
src/statement.cpp
src/environment.cpp
Expand All @@ -23,7 +24,6 @@ target_link_libraries(ydb-odbc
YDB-CPP-SDK::Table
YDB-CPP-SDK::Scheme
YDB-CPP-SDK::Driver
ODBC::ODBC
)

set_target_properties(ydb-odbc PROPERTIES
Expand All @@ -43,7 +43,7 @@ add_subdirectory(tests)

include(GNUInstallDirs)

install(FILES
install(FILES
odbcinst.ini
DESTINATION ${CMAKE_INSTALL_SYSCONFDIR}/odbcinst.d
RENAME ydb-odbc.ini
Expand Down
52 changes: 47 additions & 5 deletions odbc/src/connection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@
#include "statement.h"
#include "utils/error_manager.h"

#include <cstring>
#include <string>
#include <map>
#include <string>

#include <sql.h>
#include <sqlext.h>
Expand Down Expand Up @@ -79,11 +78,24 @@ SQLRETURN TConnection::Connect(const std::string& serverName,
}

SQLRETURN TConnection::Disconnect() {
QuerySession_.reset();
Tx_.reset();
YdbSchemeClient_.reset();
YdbTableClient_.reset();
YdbClient_.reset();
YdbDriver_.reset();
return SQL_SUCCESS;
}

NQuery::TSession& TConnection::GetOrCreateQuerySession() {
if (!QuerySession_) {
auto sessionResult = YdbClient_->GetSession().ExtractValueSync();
NStatusHelpers::ThrowOnError(sessionResult);
QuerySession_.emplace(std::move(sessionResult.GetSession()));
}
return *QuerySession_;
}

std::unique_ptr<TStatement> TConnection::CreateStatement() {
return std::make_unique<TStatement>(this);
}
Expand All @@ -94,8 +106,8 @@ void TConnection::RemoveStatement(TStatement* stmt) {
}

SQLRETURN TConnection::SetAutocommit(bool value) {
Autocommit_ = value;
if (Autocommit_ && Tx_) {
Attributes_.SetAutocommit(value);
if (Attributes_.GetAutocommit() && Tx_) {
auto status = Tx_->Commit().ExtractValueSync();
NStatusHelpers::ThrowOnError(status);
Tx_.reset();
Expand All @@ -104,7 +116,22 @@ SQLRETURN TConnection::SetAutocommit(bool value) {
}

bool TConnection::GetAutocommit() const {
return Autocommit_;
return Attributes_.GetAutocommit();
}

SQLRETURN TConnection::SetConnectAttr(SQLINTEGER attr, SQLPOINTER value, SQLINTEGER stringLength) {
return Attributes_.SetConnectAttr(attr, value, stringLength, [this](bool autocommit) {
return SetAutocommit(autocommit);
}, *this);
}

SQLRETURN TConnection::GetConnectAttr(SQLINTEGER attr, SQLPOINTER value, SQLINTEGER bufferLength,
SQLINTEGER* stringLengthPtr) {
return Attributes_.GetConnectAttr(attr, value, bufferLength, stringLengthPtr, *this);
}

NQuery::TTxSettings TConnection::MakeTxSettings() const {
return Attributes_.MakeTxSettings();
}

const std::optional<NQuery::TTransaction>& TConnection::GetTx() {
Expand All @@ -115,6 +142,10 @@ void TConnection::SetTx(const NQuery::TTransaction& tx) {
Tx_ = tx;
}

void TConnection::Reset() {
Tx_.reset();
}

SQLRETURN TConnection::CommitTx() {
auto status = Tx_->Commit().ExtractValueSync();
NStatusHelpers::ThrowOnError(status);
Expand All @@ -129,5 +160,16 @@ SQLRETURN TConnection::RollbackTx() {
return SQL_SUCCESS;
}

void TConnection::SetEnvironment(TEnvironment* env){
if (ParentEnv_){
throw std::logic_error("Connection already bound to environment");
}
ParentEnv_ = env;
}

TEnvironment* TConnection::GetEnvironment(){
return ParentEnv_;
}

} // namespace NOdbc
} // namespace NYdb
15 changes: 13 additions & 2 deletions odbc/src/connection.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include "environment.h"
#include "connection_attributes.h"
#include "utils/error_manager.h"

#include <ydb-cpp-sdk/client/driver/driver.h>
Expand All @@ -27,14 +28,15 @@ class TConnection : public TErrorManager {
std::unique_ptr<NTable::TTableClient> YdbTableClient_;
std::unique_ptr<NScheme::TSchemeClient> YdbSchemeClient_;
std::optional<NQuery::TTransaction> Tx_;
std::optional<NQuery::TSession> QuerySession_;

std::vector<std::unique_ptr<TStatement>> Statements_;
std::string Endpoint_;
std::string Database_;
std::string AuthToken_;
TEnvironment* ParentEnv_;

bool Autocommit_ = true;

TConnectionAttributes Attributes_;
public:
SQLRETURN Connect(const std::string& serverName,
const std::string& userName,
Expand All @@ -47,17 +49,26 @@ class TConnection : public TErrorManager {
void RemoveStatement(TStatement* stmt);

NYdb::NQuery::TQueryClient* GetClient() { return YdbClient_.get(); }
NQuery::TSession& GetOrCreateQuerySession();
NYdb::NTable::TTableClient* GetTableClient() { return YdbTableClient_.get(); }
NScheme::TSchemeClient* GetSchemeClient() { return YdbSchemeClient_.get(); }

SQLRETURN SetAutocommit(bool value);
bool GetAutocommit() const;

SQLRETURN SetConnectAttr(SQLINTEGER attr, SQLPOINTER value, SQLINTEGER stringLength);
SQLRETURN GetConnectAttr(SQLINTEGER attr, SQLPOINTER value, SQLINTEGER bufferLength, SQLINTEGER* stringLengthPtr);
NQuery::TTxSettings MakeTxSettings() const;

const std::optional<NQuery::TTransaction>& GetTx();
void SetTx(const NQuery::TTransaction& tx);
void Reset();

SQLRETURN CommitTx();
SQLRETURN RollbackTx();

void SetEnvironment(TEnvironment* env);
TEnvironment* GetEnvironment();
};

} // namespace NOdbc
Expand Down
141 changes: 141 additions & 0 deletions odbc/src/connection_attributes.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
#include "connection_attributes.h"

#include <cstdint>

namespace NYdb {
namespace NOdbc {

std::optional<NQuery::TTxSettings::ETransactionMode> TConnectionAttributes::ResolveTxMode(SQLUINTEGER accessMode, SQLUINTEGER txnIsolation) {
if (accessMode == SQL_MODE_READ_ONLY) {
switch (txnIsolation) {
case SQL_TXN_READ_UNCOMMITTED:
return NQuery::TTxSettings::TS_STALE_RO;
case SQL_TXN_READ_COMMITTED:
return NQuery::TTxSettings::TS_ONLINE_RO;
case SQL_TXN_REPEATABLE_READ:
case SQL_TXN_SERIALIZABLE:
return NQuery::TTxSettings::TS_SNAPSHOT_RO;
default:
return std::nullopt;
}
}

switch (txnIsolation) {
case SQL_TXN_REPEATABLE_READ:
case SQL_TXN_SERIALIZABLE:
return NQuery::TTxSettings::TS_SERIALIZABLE_RW;
default:
return std::nullopt;
}
}

SQLRETURN TConnectionAttributes::SetAutocommit(bool value) {
Autocommit_ = value;
return SQL_SUCCESS;
}

bool TConnectionAttributes::GetAutocommit() const {
return Autocommit_;
}

SQLRETURN TConnectionAttributes::SetConnectAttr(
SQLINTEGER attr,
SQLPOINTER value,
SQLINTEGER /*stringLength*/,
const std::function<SQLRETURN(bool)>& applyAutocommit,
TErrorManager& errors) {
switch (attr) {
case SQL_ATTR_AUTOCOMMIT: {
const intptr_t val = reinterpret_cast<intptr_t>(value);
if (val == static_cast<intptr_t>(SQL_AUTOCOMMIT_ON)) {
return applyAutocommit(true);
}
if (val == static_cast<intptr_t>(SQL_AUTOCOMMIT_OFF)) {
return applyAutocommit(false);
}
return errors.AddError("HY024", 0, "Invalid SQL_ATTR_AUTOCOMMIT value");
}
case SQL_ATTR_ACCESS_MODE: {
const intptr_t val = reinterpret_cast<intptr_t>(value);
if (val == static_cast<intptr_t>(SQL_MODE_READ_WRITE)) {
AccessMode_ = SQL_MODE_READ_WRITE;
auto txMode = ResolveTxMode(AccessMode_, TxnIsolation_);
if (!txMode) {
return errors.AddError("HYC00", 0, "Transaction isolation is not supported for read-write mode");
}
TxMode_ = *txMode;
return SQL_SUCCESS;
}
if (val == static_cast<intptr_t>(SQL_MODE_READ_ONLY)) {
AccessMode_ = SQL_MODE_READ_ONLY;
auto txMode = ResolveTxMode(AccessMode_, TxnIsolation_);
if (!txMode) {
return errors.AddError("HYC00", 0, "Transaction isolation is not supported for read-only mode");
}
TxMode_ = *txMode;
return SQL_SUCCESS;
}
return errors.AddError("HY024", 0, "Invalid SQL_ATTR_ACCESS_MODE value");
}
case SQL_ATTR_TXN_ISOLATION: {
const intptr_t val = reinterpret_cast<intptr_t>(value);
const SQLUINTEGER isolation = static_cast<SQLUINTEGER>(val);
auto txMode = ResolveTxMode(AccessMode_, isolation);
if (!txMode) {
return errors.AddError("HYC00", 0, "SQL_ATTR_TXN_ISOLATION value is not supported");
}
TxnIsolation_ = isolation;
TxMode_ = *txMode;
return SQL_SUCCESS;
}
default:
return errors.AddError("HYC00", 0, "Optional feature not implemented");
}
}

SQLRETURN TConnectionAttributes::GetConnectAttr(
SQLINTEGER attr,
SQLPOINTER value,
SQLINTEGER /*bufferLength*/,
SQLINTEGER* stringLengthPtr,
TErrorManager& errors) const {
if (!value) {
return errors.AddError("HY009", 0, "Invalid use of null pointer");
}
if (stringLengthPtr) {
*stringLengthPtr = 0;
}
auto* out = reinterpret_cast<SQLUINTEGER*>(value);
switch (attr) {
case SQL_ATTR_AUTOCOMMIT:
*out = GetAutocommit() ? SQL_AUTOCOMMIT_ON : SQL_AUTOCOMMIT_OFF;
return SQL_SUCCESS;
case SQL_ATTR_ACCESS_MODE:
*out = AccessMode_;
return SQL_SUCCESS;
case SQL_ATTR_TXN_ISOLATION:
*out = TxnIsolation_;
return SQL_SUCCESS;
default:
return errors.AddError("HYC00", 0, "Optional feature not implemented");
}
}

NQuery::TTxSettings TConnectionAttributes::MakeTxSettings() const {
switch (TxMode_) {
case NQuery::TTxSettings::TS_ONLINE_RO:
return NQuery::TTxSettings::OnlineRO();
case NQuery::TTxSettings::TS_STALE_RO:
return NQuery::TTxSettings::StaleRO();
case NQuery::TTxSettings::TS_SNAPSHOT_RO:
return NQuery::TTxSettings::SnapshotRO();
case NQuery::TTxSettings::TS_SNAPSHOT_RW:
return NQuery::TTxSettings::SnapshotRW();
case NQuery::TTxSettings::TS_SERIALIZABLE_RW:
default:
return NQuery::TTxSettings::SerializableRW();
}
}

} // namespace NOdbc
} // namespace NYdb
48 changes: 48 additions & 0 deletions odbc/src/connection_attributes.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#pragma once

#include "utils/error_manager.h"

#include <ydb-cpp-sdk/client/query/tx.h>

#include <functional>
#include <optional>

#include <sql.h>
#include <sqlext.h>

namespace NYdb {
namespace NOdbc {

class TConnectionAttributes {
public:
SQLRETURN SetAutocommit(bool value);
bool GetAutocommit() const;

SQLRETURN SetConnectAttr(
SQLINTEGER attr,
SQLPOINTER value,
SQLINTEGER stringLength,
const std::function<SQLRETURN(bool)>& applyAutocommit,
TErrorManager& errors);

SQLRETURN GetConnectAttr(
SQLINTEGER attr,
SQLPOINTER value,
SQLINTEGER bufferLength,
SQLINTEGER* stringLengthPtr,
TErrorManager& errors) const;

NQuery::TTxSettings MakeTxSettings() const;

private:
static std::optional<NQuery::TTxSettings::ETransactionMode> ResolveTxMode(SQLUINTEGER accessMode, SQLUINTEGER txnIsolation);

private:
bool Autocommit_ = true;
SQLUINTEGER AccessMode_ = SQL_MODE_READ_WRITE;
SQLUINTEGER TxnIsolation_ = SQL_TXN_SERIALIZABLE;
NQuery::TTxSettings::ETransactionMode TxMode_ = NQuery::TTxSettings::TS_SERIALIZABLE_RW;
};

} // namespace NOdbc
} // namespace NYdb
Loading