Skip to content

Reinstate autogenerated session #489

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

Merged
merged 4 commits into from
Apr 17, 2025
Merged
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ The list of DSN parameters recognized by the driver is as follows:
| `HugeIntAsString` | `off` | Report integer column types that may underflow or overflow 64-bit signed integer (`SQL_BIGINT`) as a `String`/`SQL_VARCHAR` |
| `DriverLog` | `on` if `CMAKE_BUILD_TYPE` is `Debug`, `off` otherwise | Enable or disable the extended driver logging |
| `DriverLogFile` | `\temp\clickhouse-odbc-driver.log` on Windows, `/tmp/clickhouse-odbc-driver.log` otherwise | Path to the extended driver log file (used when `DriverLog` is `on`) |
| `AutoSessionId` | `off` | Auto generate session_id required to use some features of CH (e.g. TEMPORARY TABLE) |

### URL query string

Expand Down
5 changes: 4 additions & 1 deletion driver/config/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ void readDSNinfo(ConnInfo * ci, bool overwrite) {
GET_CONFIG(stringmaxlength, INI_STRINGMAXLENGTH, INI_STRINGMAXLENGTH_DEFAULT);
GET_CONFIG(driverlog, INI_DRIVERLOG, INI_DRIVERLOG_DEFAULT);
GET_CONFIG(driverlogfile, INI_DRIVERLOGFILE, INI_DRIVERLOGFILE_DEFAULT);
GET_CONFIG(auto_session_id, INI_AUTO_SESSION_ID, INI_AUTO_SESSION_ID_DEFAULT);

#undef GET_CONFIG
}
Expand Down Expand Up @@ -99,6 +100,7 @@ void writeDSNinfo(const ConnInfo * ci) {
WRITE_CONFIG(stringmaxlength, INI_STRINGMAXLENGTH);
WRITE_CONFIG(driverlog, INI_DRIVERLOG);
WRITE_CONFIG(driverlogfile, INI_DRIVERLOGFILE);
WRITE_CONFIG(auto_session_id, INI_AUTO_SESSION_ID);

#undef WRITE_CONFIG
}
Expand Down Expand Up @@ -342,7 +344,8 @@ key_value_map_t readDSNInfo(const std::string & dsn_utf8) {
INI_DATABASE,
INI_STRINGMAXLENGTH,
INI_DRIVERLOG,
INI_DRIVERLOGFILE
INI_DRIVERLOGFILE,
INI_AUTO_SESSION_ID
}
) {
if (
Expand Down
1 change: 1 addition & 0 deletions driver/config/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ struct ConnInfo {
std::string stringmaxlength;
std::string driverlog;
std::string driverlogfile;
std::string auto_session_id;
};

void readDSNinfo(ConnInfo * ci, bool overwrite);
Expand Down
2 changes: 2 additions & 0 deletions driver/config/ini_defines.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#define INI_STRINGMAXLENGTH "StringMaxLength"
#define INI_DRIVERLOG "DriverLog"
#define INI_DRIVERLOGFILE "DriverLogFile"
#define INI_AUTO_SESSION_ID "AutoSessionId"

#if defined(UNICODE)
# define INI_DSN_DEFAULT DSN_DEFAULT_UNICODE
Expand All @@ -50,6 +51,7 @@
#define INI_DATABASE_DEFAULT ""
#define INI_HUGE_INT_AS_STRING_DEFAULT "off"
#define INI_STRINGMAXLENGTH_DEFAULT "1048575"
#define INI_AUTO_SESSION_ID_DEFAULT "off"

#ifdef NDEBUG
# define INI_DRIVERLOG_DEFAULT "off"
Expand Down
27 changes: 26 additions & 1 deletion driver/connection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <Poco/Net/HTTPClientSession.h>
#include <Poco/NumberParser.h> // TODO: switch to std
#include <Poco/URI.h>
#include <random>

#if !defined(WORKAROUND_DISABLE_SSL)
# include <Poco/Net/AcceptCertificateHandler.h>
Expand Down Expand Up @@ -47,8 +48,15 @@ void SSLInit(bool ssl_strict, const std::string & privateKeyFile, const std::str
}
#endif

std::string GenerateSessionId() {
std::mt19937 generator(std::random_device{}());
std::uniform_int_distribution<std::uint64_t> distribution(0);
return std::string("clickhouse_odbc_" + std::to_string(distribution(generator)));
}

Connection::Connection(Environment & environment)
: ChildType(environment)
: ChildType(environment),
session_id(GenerateSessionId())
{
resetConfiguration();
}
Expand Down Expand Up @@ -84,6 +92,7 @@ Poco::URI Connection::getUri() const {

bool database_set = false;
bool default_format_set = false;
bool session_id_set = false;

for (const auto& parameter : uri.getQueryParameters()) {
if (Poco::UTF8::icompare(parameter.first, "default_format") == 0) {
Expand All @@ -92,6 +101,9 @@ Poco::URI Connection::getUri() const {
else if (Poco::UTF8::icompare(parameter.first, "database") == 0) {
database_set = true;
}
else if (Poco::UTF8::icompare(parameter.first, "session_id") == 0 && !parameter.second.empty()) {
session_id_set = true;
}
}

if (!default_format_set)
Expand All @@ -100,6 +112,12 @@ Poco::URI Connection::getUri() const {
if (!database_set)
uri.addQueryParameter("database", database);

// To use some features of CH (e.g. TEMPORARY TABLEs) we need a (named) session.
if (auto_session_id && !session_id_set) {
// DO not overwrite user-set session_id, just in case...
uri.addQueryParameter("session_id", session_id);
}

return uri;
}

Expand Down Expand Up @@ -379,6 +397,13 @@ void Connection::setConfiguration(const key_value_map_t & cs_fields, const key_v
getDriver().setAttr(CH_SQL_ATTR_DRIVERLOG, (isYes(value) ? SQL_OPT_TRACE_ON : SQL_OPT_TRACE_OFF));
}
}
else if (Poco::UTF8::icompare(key, INI_AUTO_SESSION_ID) == 0) {
recognized_key = true;
valid_value = (value.empty() || isYesOrNo(value));
if (valid_value) {
auto_session_id = isYes(value);
}
}

return std::make_tuple(recognized_key, valid_value);
};
Expand Down
1 change: 1 addition & 0 deletions driver/connection.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ class Connection
std::string database;
bool huge_int_as_string = false;
std::int32_t stringmaxlength = 0;
bool auto_session_id = false;

public:
std::string useragent;
Expand Down
8 changes: 6 additions & 2 deletions driver/test/misc_it.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ TEST_F(MiscellaneousTest, RowArraySizeAttribute) {
rc = ODBC_CALL_ON_STMT_THROW(hstmt, SQLGetStmtAttr(hstmt, SQL_ATTR_ROW_ARRAY_SIZE, &size, sizeof(size), 0));
ASSERT_EQ(size, 1);
}

{
size = 2;
rc = ODBC_CALL_ON_STMT_THROW(hstmt, SQLSetStmtAttr(hstmt, SQL_ATTR_ROW_ARRAY_SIZE, (SQLPOINTER)size, 0));
Expand Down Expand Up @@ -227,7 +227,11 @@ INSTANTIATE_TEST_SUITE_P(

std::make_tuple("AllGood_VerifyConnectionEarly_Empty", "VerifyConnectionEarly=", FailOn::Never),
std::make_tuple("AllGood_VerifyConnectionEarly_On", "VerifyConnectionEarly=on", FailOn::Never),
std::make_tuple("AllGood_VerifyConnectionEarly_Off", "VerifyConnectionEarly=off", FailOn::Never)
std::make_tuple("AllGood_VerifyConnectionEarly_Off", "VerifyConnectionEarly=off", FailOn::Never),

std::make_tuple("AllGood_AutoSessionId_Empty", "AutoSessionId=", FailOn::Never),
std::make_tuple("AllGood_AutoSessionId_On", "AutoSessionId=on", FailOn::Never),
std::make_tuple("AllGood_AutoSessionId_Off", "AutoSessionId=off", FailOn::Never)
),
[] (const auto & param_info) {
return std::get<0>(param_info.param);
Expand Down
2 changes: 2 additions & 0 deletions packaging/odbc.ini.sample
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ Description = DSN (localhost) for ClickHouse ODBC Driver (ANSI)
# DriverLog = yes
# DriverLogFile = /tmp/chlickhouse-odbc-driver.log

# AutoSessionId = off

[ClickHouse DSN (Unicode)]
Driver = ClickHouse ODBC Driver (Unicode)
Description = DSN (localhost) for ClickHouse ODBC Driver (Unicode)
Expand Down
Loading