Skip to content

Commit 564706b

Browse files
committed
Add test that check that compression is enabled
If the Compression parameter is set to 1, then the content encoding should be set to `zstd` otherwise it should be empty
1 parent 865f162 commit 564706b

File tree

7 files changed

+48
-38
lines changed

7 files changed

+48
-38
lines changed

driver/api/impl/impl.cpp

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -505,12 +505,8 @@ SQLRETURN GetStmtAttr(
505505
CASE_NUM(SQL_ATTR_RETRIEVE_DATA, SQLULEN, SQL_RD_ON);
506506
CASE_NUM(SQL_ATTR_USE_BOOKMARKS, SQLULEN, SQL_UB_OFF);
507507

508-
case SQL_CH_STMT_ATTR_LAST_QUERY_ID: {
509-
auto & query_id = statement.getQueryId();
510-
if (query_id.empty())
511-
throw SqlException("Invalid cursor state", "24000");
512-
513-
return fillOutputString<PTChar>(query_id, out_value, out_value_max_length, out_value_length, true);
508+
case SQL_CH_STMT_ATTR_NATIVE_STATEMENT_ATTR: {
509+
return fillOutputPOD<void*>(&statement, out_value, out_value_length);
514510
}
515511

516512
case SQL_ATTR_FETCH_BOOKMARK_PTR:

driver/platform/platform.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,4 +120,4 @@
120120
// User range is between SQL_DRIVER_STMT_ATTR_BASE (0x00004000) and 0x00007FFF, see
121121
// https://learn.microsoft.com/en-us/sql/odbc/reference/develop-app/driver-specific-data-types-descriptor-information-diagnostic
122122
#define SQL_CH_STMT_ATTR_BASE (SQL_DRIVER_STMT_ATTR_BASE + 1)
123-
#define SQL_CH_STMT_ATTR_LAST_QUERY_ID (SQL_CH_STMT_ATTR_BASE + 1)
123+
#define SQL_CH_STMT_ATTR_NATIVE_STATEMENT_ATTR (SQL_CH_STMT_ATTR_BASE + 1)

driver/statement.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,8 +173,9 @@ void Statement::requestNextPackOfResultSets(std::unique_ptr<ResultMutator> && mu
173173
// and so we cannot pass an rvalue to it (e.g.`std::string()`),
174174
// it will be deleted when the function returns.
175175
// We use a static variable that will never be deleted.
176-
static const std::string empty_query_id{};
177-
query_id = response->get("X-ClickHouse-Query-Id", empty_query_id);
176+
static const std::string empty_string{};
177+
query_id = response->get("X-ClickHouse-Query-Id", empty_string);
178+
content_encoding = response->get("Content-Encoding", empty_string);
178179

179180
Poco::Net::HTTPResponse::HTTPStatus status = response->getStatus();
180181
if (status != Poco::Net::HTTPResponse::HTTP_OK) {
@@ -370,6 +371,10 @@ const std::string & Statement::getQueryId() const {
370371
return query_id;
371372
}
372373

374+
const std::string & Statement::getContentEncoding() const {
375+
return content_encoding;
376+
}
377+
373378
bool Statement::advanceToNextResultSet() {
374379
if (!is_executed)
375380
return false;

driver/statement.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ class Statement
5050
/// Get the current query id, or an empty string if query id is not applicable or not available.
5151
const std::string & getQueryId() const;
5252

53+
/// Get the current content encoding, or an empty string if content encoding was not defined
54+
const std::string & getContentEncoding() const;
55+
5356
/// Make the next result set current, if any.
5457
bool advanceToNextResultSet();
5558

@@ -117,5 +120,6 @@ class Statement
117120
std::istream* in = nullptr;
118121
std::unique_ptr<ResultReader> result_reader;
119122
std::string query_id;
123+
std::string content_encoding;
120124
std::size_t next_param_set_idx = 0;
121125
};

driver/test/client_test_base.h

Lines changed: 4 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -47,33 +47,11 @@ class ClientTestBaseMixin
4747
ODBC_CALL_ON_DBC_THROW(hdbc, SQLAllocHandle(SQL_HANDLE_STMT, hdbc, &hstmt));
4848
}
4949

50-
std::string getQueryId()
50+
Statement & getStatement()
5151
{
52-
char query_id_data[74] = {};
53-
SQLINTEGER query_id_len{};
54-
SQLGetStmtAttr(hstmt, SQL_CH_STMT_ATTR_LAST_QUERY_ID, query_id_data, std::size(query_id_data), &query_id_len);
55-
56-
#ifdef _win_
57-
return toUTF8(reinterpret_cast<PTChar*>(query_id_data));
58-
#else
59-
// unixODBC usually converts all strings from the driver encoding to the application encoding,
60-
// similar to how Windows behaves. However, `SQLGetStmtAttr` appears to be an exception in unixODBC,
61-
// as it passes the result in the driver encoding unchanged.
62-
// See: https://github.com/lurcher/unixODBC/issues/22
63-
//
64-
// To solve this issue and ensure the result reaches the application in the correct encoding,
65-
// we would need to implement both `SQLGetStmtAttr` and `SQLGetStmtAttrW` in the driver.
66-
// This would introduce a number of workarounds and non-uniform solutions.
67-
// Currently, there is only one string attribute, `SQL_CH_STMT_ATTR_LAST_QUERY_ID`, which is internal,
68-
// so this added complexity in the driver is not currently justified.
69-
//
70-
// Since we know that the Query ID is 36 bytes long, we can infer the encoding of the result
71-
// and re-encode it accordingly here in the test.
72-
if (query_id_len == 36)
73-
return toUTF8(query_id_data);
74-
else
75-
return toUTF8(reinterpret_cast<char16_t*>(query_id_data));
76-
#endif
52+
Statement * statement = nullptr;
53+
SQLGetStmtAttr(hstmt, SQL_CH_STMT_ATTR_NATIVE_STATEMENT_ATTR, &statement, SQL_IS_POINTER, nullptr);
54+
return *statement;
7755
}
7856

7957
protected:

driver/test/error_handling_it.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#include "driver/statement.h"
12
#include "driver/test/client_utils.h"
23
#include "driver/test/client_test_base.h"
34
#include "driver/test/result_set_reader.hpp"
@@ -21,7 +22,7 @@ TEST_F(ErrorHandlingTest, ServerExceptionInBeginning)
2122
ODBC_CALL_ON_STMT_THROW(hstmt, SQLPrepare(hstmt, ptcharCast(query.data()), SQL_NTS));
2223
ASSERT_EQ(SQLExecute(hstmt), SQL_ERROR);
2324
auto error_message = extract_diagnostics(hstmt, SQL_HANDLE_STMT);
24-
auto query_id = getQueryId();
25+
auto query_id = getStatement().getQueryId();
2526

2627
auto expect_error_message = "1:[HY000][1]Error while processing query " + query_id + ": HTTP status code: 400";
2728
ASSERT_EQ(error_message.substr(0, expect_error_message.size()), expect_error_message);
@@ -53,7 +54,7 @@ TEST_F(ErrorHandlingTest, ServerExceptionInMiddleOfStream)
5354
error_message = extract_diagnostics(hstmt, SQL_HANDLE_STMT);
5455
}
5556

56-
auto query_id = getQueryId();
57+
auto query_id = getStatement().getQueryId();
5758
auto expect_error_message =
5859
"1:[HY000][1]Error while processing query " + query_id + ": "
5960
"ClickHouse exception: Code: 395. DB::Exception: Value passed to 'throwIf'";

driver/test/misc_it.cpp

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#include "driver/statement.h"
12
#include "driver/platform/platform.h"
23
#include "driver/test/client_utils.h"
34
#include "driver/test/client_test_base.h"
@@ -150,6 +151,31 @@ TEST_F(MiscellaneousTest, NullableNothing) {
150151
EXPECT_EQ(nullable, SQL_NULLABLE);
151152
}
152153

154+
TEST_F(MiscellaneousTest, CompressionMatchesConfiguration) {
155+
// Get version directly by calling `select version()`
156+
auto query = fromUTF8<PTChar>("select version()");
157+
ODBC_CALL_ON_STMT_THROW(hstmt, SQLExecDirect(hstmt, ptcharCast(query.data()), SQL_NTS));
158+
ODBC_CALL_ON_STMT_THROW(hstmt, SQLFetch(hstmt));
159+
std::basic_string<PTChar> query_version(256, '\0');
160+
SQLLEN query_version_len = 0;
161+
ODBC_CALL_ON_STMT_THROW(hstmt, SQLGetData(
162+
hstmt,
163+
1,
164+
getCTypeFor<SQLTCHAR*>(),
165+
query_version.data(),
166+
query_version.size(),
167+
&query_version_len
168+
));
169+
170+
Statement & statement = getStatement();
171+
Connection & connection = statement.getParent();
172+
173+
if (connection.enable_http_compression)
174+
EXPECT_EQ(statement.getContentEncoding(), "zstd");
175+
else
176+
EXPECT_TRUE(statement.getContentEncoding().empty());
177+
}
178+
153179
enum class FailOn {
154180
Connect,
155181
Execute,
@@ -369,7 +395,7 @@ TEST_P(CustomClientName, UserAgentTest) {
369395
SQLLEN sql_type = SQL_TYPE_NULL;
370396
ODBC_CALL_ON_STMT_THROW(hstmt, SQLColAttribute(hstmt, 1, SQL_DESC_TYPE, NULL, 0, NULL, &sql_type));
371397

372-
const auto query_id = getQueryId();
398+
const auto query_id = getStatement().getQueryId();
373399

374400
ResultSetReader reader{hstmt};
375401
while (reader.fetch())

0 commit comments

Comments
 (0)