Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix displaying server version #430

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
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
2 changes: 1 addition & 1 deletion driver/api/odbc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ SQLRETURN SQL_API EXPORTED_FUNCTION_MAYBE_W(SQLGetInfo)(
CASE_STRING(SQL_DM_VER, "03.80.0000.0000")
CASE_STRING(SQL_DRIVER_NAME, DRIVER_FILE_NAME)
CASE_STRING(SQL_DBMS_NAME, "ClickHouse")
CASE_STRING(SQL_DBMS_VER, "01.00.0000")
CASE_STRING(SQL_DBMS_VER, connection.getServerVersion())
CASE_STRING(SQL_SERVER_NAME, connection.server)
CASE_STRING(SQL_DATA_SOURCE_NAME, connection.dsn)
CASE_STRING(SQL_CATALOG_TERM, "catalog")
Expand Down
83 changes: 76 additions & 7 deletions driver/connection.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#include "driver/result_set.h"
#include "driver/utils/utils.h"
#include "driver/config/ini_defines.h"
#include "driver/connection.h"
Expand All @@ -8,6 +9,9 @@
#include <Poco/Net/HTTPClientSession.h>
#include <Poco/NumberParser.h> // TODO: switch to std
#include <Poco/URI.h>
#include <atomic>
#include <memory>
#include <mutex>
#include <random>

#if !defined(WORKAROUND_DISABLE_SSL)
Expand Down Expand Up @@ -536,17 +540,82 @@ void Connection::setConfiguration(const key_value_map_t & cs_fields, const key_v

void Connection::verifyConnection() {
LOG("Verifying connection and credentials...");
auto & statement = allocateChild<Statement>();

try {
statement.executeQuery("SELECT 1");
getServerVersion();
}

// RAII-like wrapper for child objects
template <typename ChildType>
class ChildHolder {
ChildType & child;

public:
ChildHolder(ChildType & child)
: child(child)
{}

~ChildHolder() {
child.deallocateSelf();
}
catch (...) {
statement.deallocateSelf();
throw;

ChildHolder(const ChildHolder&) = delete;
ChildHolder& operator=(const ChildHolder&) = delete;

ChildType* operator->() {
return &child;
}

statement.deallocateSelf();
const ChildType* operator->() const {
return &child;
}

ChildType & operator*() {
return child;
}

const ChildType & operator*() const {
return child;
}
};

std::string_view Connection::getServerVersion() {
// Try to load server version only once
if (const auto & val = std::atomic_load(&server_version); val && !val->empty())
return *val;

{
struct GetVesionStringValueResultMutator : public ResultMutator
{
std::string & version_string;
GetVesionStringValueResultMutator(std::string & version_string_)
: version_string(version_string_)
{}

void transformRow(const std::vector<ColumnInfo> & columns_info, Row & row)
{
if (row.fields.size() >= 1)
{
auto val = std::get_if<DataSourceType< DataSourceTypeId::String>>(&row.fields[0].data);
if (!val)
throw SqlException("Can't get server version", "HYC00");

version_string = val->value;
}
}
};

std::string result_server_version;

LOG("Querying server version");
auto statement = ChildHolder(allocateChild<Statement>());

statement->executeQuery("SELECT version()", std::make_unique<GetVesionStringValueResultMutator>(result_server_version));

std::string_view result = result_server_version;
std::atomic_store(&server_version, std::make_shared<std::string>(std::move(result_server_version)));

return result;
}
}

std::string Connection::buildCredentialsString() const {
Expand Down
5 changes: 5 additions & 0 deletions driver/connection.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include <memory>
#include <mutex>
#include <string_view>

class DescriptorRecord;
class Descriptor;
Expand Down Expand Up @@ -65,6 +66,9 @@ class Connection
// Return a crafted User-Agent string.
std::string buildUserAgentString() const;

// Query server for a version
std::string_view getServerVersion();

// Reset the descriptor and initialize it with default attributes.
void initAsAD(Descriptor & desc, bool user = false); // as Application Descriptor
void initAsID(Descriptor & desc); // as Implementation Descriptor
Expand Down Expand Up @@ -99,6 +103,7 @@ class Connection
private:
std::unordered_map<SQLHANDLE, std::shared_ptr<Descriptor>> descriptors;
std::unordered_map<SQLHANDLE, std::shared_ptr<Statement>> statements;
mutable std::shared_ptr<std::string> server_version;
};

template <> Descriptor& Connection::allocateChild<Descriptor>();
Expand Down
7 changes: 5 additions & 2 deletions driver/utils/type_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ inline SQLRETURN fillOutputBuffer(
// Extra string copy happens here for wide char strings, and strings that require encoding change.
template <typename CharType, typename LengthType1, typename LengthType2, typename ConversionContext>
inline SQLRETURN fillOutputString(
const std::string & in_value,
std::string_view in_value,
void * out_value,
LengthType1 out_value_max_length,
LengthType2 * out_value_length,
Expand Down Expand Up @@ -253,7 +253,7 @@ inline SQLRETURN fillOutputString(

template <typename CharType, typename LengthType1, typename LengthType2, typename ConversionContext = DefaultConversionContext>
inline SQLRETURN fillOutputString(
const std::string & in_value,
std::string_view in_value,
void * out_value,
LengthType1 out_value_max_length,
LengthType2 * out_value_length,
Expand Down Expand Up @@ -1935,6 +1935,9 @@ namespace value_manip {
if constexpr (std::is_same_v<SourceType, std::string>) {
return fillOutputString<SQLCHAR>(src, dest.value, dest.value_max_size, dest.value_size, true, std::forward<ConversionContext>(context));
}
if constexpr (std::is_same_v<SourceType, std::string_view>) {
return fillOutputString<SQLCHAR>(src, dest.value, dest.value_max_size, dest.value_size, true, std::forward<ConversionContext>(context));
}
else if constexpr (is_string_data_source_type_v<SourceType>) {
return fillOutputString<SQLCHAR>(src.value, dest.value, dest.value_max_size, dest.value_size, true, std::forward<ConversionContext>(context));
}
Expand Down