This is an automated email from the ASF dual-hosted git repository.
isapego pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git
The following commit(s) were added to refs/heads/main by this push:
new 87211743d1 IGNITE-21605 C++ Client: Pass client time zone to server
(#3753)
87211743d1 is described below
commit 87211743d1f325b478c5eea959b0c5ac8ef89582
Author: Igor Sapego <[email protected]>
AuthorDate: Tue May 14 18:11:40 2024 +0400
IGNITE-21605 C++ Client: Pass client time zone to server (#3753)
---
.idea/inspectionProfiles/Project_Default.xml | 7 ++--
.../cpp/ignite/client/detail/sql/sql_impl.cpp | 13 +++++---
.../cpp/ignite/client/detail/utils_test.cpp | 2 +-
.../cpp/ignite/client/sql/sql_statement.h | 29 ++++++++++++++--
.../cpp/ignite/odbc/config/configuration.cpp | 4 +++
.../cpp/ignite/odbc/config/configuration.h | 17 ++++++++--
.../platforms/cpp/ignite/odbc/query/data_query.cpp | 8 ++++-
modules/platforms/cpp/ignite/odbc/string_utils.h | 3 ++
modules/platforms/cpp/ignite/odbc/utility.cpp | 1 +
.../platforms/cpp/tests/client-test/sql_test.cpp | 20 +++++++++++
.../cpp/tests/odbc-test/connection_test.cpp | 39 +++++++++++++++++++++-
11 files changed, 128 insertions(+), 15 deletions(-)
diff --git a/.idea/inspectionProfiles/Project_Default.xml
b/.idea/inspectionProfiles/Project_Default.xml
index 3ac91d24c4..451a802506 100644
--- a/.idea/inspectionProfiles/Project_Default.xml
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -139,7 +139,6 @@
<inspection_tool class="AndroidLintAlwaysShowAction" enabled="false"
level="WARNING" enabled_by_default="false" />
<inspection_tool class="AndroidLintAnimatorKeep" enabled="false"
level="WARNING" enabled_by_default="false" />
<inspection_tool class="AndroidLintAppCompatCustomView" enabled="false"
level="ERROR" enabled_by_default="false" />
- <inspection_tool class="AndroidLintAppCompatMethod" enabled="false"
level="WARNING" enabled_by_default="false" />
<inspection_tool class="AndroidLintAppCompatResource" enabled="false"
level="ERROR" enabled_by_default="false" />
<inspection_tool class="AndroidLintAppLinkUrlError" enabled="false"
level="ERROR" enabled_by_default="false" />
<inspection_tool class="AndroidLintApplySharedPref" enabled="false"
level="WARNING" enabled_by_default="false" />
@@ -255,7 +254,6 @@
<inspection_tool class="AndroidLintMenuTitle" enabled="false"
level="ERROR" enabled_by_default="false" />
<inspection_tool class="AndroidLintMergeMarker" enabled="false"
level="ERROR" enabled_by_default="false" />
<inspection_tool class="AndroidLintMergeRootFrame" enabled="false"
level="WARNING" enabled_by_default="false" />
- <inspection_tool class="AndroidLintMinSdkTooLow" enabled="false"
level="WARNING" enabled_by_default="false" />
<inspection_tool class="AndroidLintMipmapIcons" enabled="false"
level="WARNING" enabled_by_default="false" />
<inspection_tool class="AndroidLintMissingApplicationIcon" enabled="false"
level="WARNING" enabled_by_default="false" />
<inspection_tool class="AndroidLintMissingBackupPin" enabled="false"
level="WARNING" enabled_by_default="false" />
@@ -312,7 +310,6 @@
<inspection_tool class="AndroidLintRecycle" enabled="false"
level="WARNING" enabled_by_default="false" />
<inspection_tool class="AndroidLintRecyclerView" enabled="false"
level="WARNING" enabled_by_default="false" />
<inspection_tool class="AndroidLintReferenceType" enabled="false"
level="ERROR" enabled_by_default="false" />
- <inspection_tool class="AndroidLintRegistered" enabled="false"
level="WARNING" enabled_by_default="false" />
<inspection_tool class="AndroidLintRelativeOverlap" enabled="false"
level="WARNING" enabled_by_default="false" />
<inspection_tool class="AndroidLintRequiredSize" enabled="false"
level="ERROR" enabled_by_default="false" />
<inspection_tool class="AndroidLintResAuto" enabled="false" level="ERROR"
enabled_by_default="false" />
@@ -1056,7 +1053,9 @@
<inspection_tool class="SystemGetenv" enabled="true" level="WARNING"
enabled_by_default="true" />
<inspection_tool class="TestCaseInProductCode" enabled="true"
level="WARNING" enabled_by_default="true" />
<inspection_tool class="TestCaseWithConstructor" enabled="true"
level="WARNING" enabled_by_default="true" />
- <inspection_tool class="TestCaseWithNoTestMethods" enabled="true"
level="WARNING" enabled_by_default="true" />
+ <inspection_tool class="TestCaseWithNoTestMethods" enabled="true"
level="WARNING" enabled_by_default="true">
+ <option name="ignoreSupers" value="true" />
+ </inspection_tool>
<inspection_tool class="TestMethodInProductCode" enabled="true"
level="WARNING" enabled_by_default="true" />
<inspection_tool class="TestNGDataProvider" enabled="false"
level="WARNING" enabled_by_default="false" />
<inspection_tool class="TestOnlyProblems" enabled="true" level="WARNING"
enabled_by_default="true" />
diff --git a/modules/platforms/cpp/ignite/client/detail/sql/sql_impl.cpp
b/modules/platforms/cpp/ignite/client/detail/sql/sql_impl.cpp
index 7f15a72144..9da64e6a6e 100644
--- a/modules/platforms/cpp/ignite/client/detail/sql/sql_impl.cpp
+++ b/modules/platforms/cpp/ignite/client/detail/sql/sql_impl.cpp
@@ -15,12 +15,11 @@
* limitations under the License.
*/
-#include "sql_impl.h"
-
+#include "ignite/client/detail/sql/sql_impl.h"
#include "ignite/client/detail/sql/result_set_impl.h"
#include "ignite/client/detail/utils.h"
-#include <ignite/tuple/binary_tuple_builder.h>
+#include "ignite/tuple/binary_tuple_builder.h"
namespace ignite::detail {
@@ -29,7 +28,13 @@ void write_statement(protocol::writer &writer, const
sql_statement &statement) {
writer.write(statement.page_size());
writer.write(std::int64_t(statement.timeout().count()));
writer.write_nil(); // Session timeout (unused, session is closed by the
server immediately).
- writer.write_nil(); // TODO: IGNITE-21605 Time zone id.
+
+ const auto &timezone = statement.timezone_id();
+ if (!timezone.empty()) {
+ writer.write(timezone);
+ } else {
+ writer.write_nil();
+ }
const auto &properties = statement.properties();
auto props_num = std::int32_t(properties.size());
diff --git a/modules/platforms/cpp/ignite/client/detail/utils_test.cpp
b/modules/platforms/cpp/ignite/client/detail/utils_test.cpp
index b152ced610..6706eb8b55 100644
--- a/modules/platforms/cpp/ignite/client/detail/utils_test.cpp
+++ b/modules/platforms/cpp/ignite/client/detail/utils_test.cpp
@@ -89,4 +89,4 @@ TEST(client_utils, tuple_write_read_random_order_key_only) {
EXPECT_EQ(std::string("Test value"), res_tuple.get(0));
EXPECT_EQ(std::int32_t(1337), res_tuple.get(1));
-}
+}
\ No newline at end of file
diff --git a/modules/platforms/cpp/ignite/client/sql/sql_statement.h
b/modules/platforms/cpp/ignite/client/sql/sql_statement.h
index a2fc9dcb7a..badde50259 100644
--- a/modules/platforms/cpp/ignite/client/sql/sql_statement.h
+++ b/modules/platforms/cpp/ignite/client/sql/sql_statement.h
@@ -51,16 +51,18 @@ public:
* @param schema Schema.
* @param page_size Page size.
* @param properties Properties list.
+ * @param timezone_id Timezone ID.
*/
sql_statement( // NOLINT(google-explicit-constructor)
std::string query, std::chrono::milliseconds timeout =
DEFAULT_TIMEOUT, std::string schema = DEFAULT_SCHEMA,
std::int32_t page_size = DEFAULT_PAGE_SIZE,
- std::initializer_list<std::pair<const std::string, primitive>>
properties = {})
+ std::initializer_list<std::pair<const std::string, primitive>>
properties = {}, std::string timezone_id = {})
: m_query(std::move(query))
, m_timeout(timeout)
, m_schema(std::move(schema))
, m_page_size(page_size)
- , m_properties(properties) {}
+ , m_properties(properties)
+ , m_timezone_id(std::move(timezone_id)) {}
/**
* Gets the query text.
@@ -132,6 +134,26 @@ public:
*/
void properties(std::initializer_list<std::pair<const std::string,
primitive>> val) { m_properties = val; }
+ /**
+ * Gets the Timezone ID.
+ *
+ * @return Timezone ID.
+ */
+ [[nodiscard]] const std::string &timezone_id() const { return
m_timezone_id; }
+
+ /**
+ * Sets the Timezone ID.
+ *
+ * Examples: "America/New_York", "UTC+3".
+ * Affects time-related SQL functions (e.g. @c CURRENT_TIME) and string
literal conversions
+ * (e.g. <tt>TIMESTAMP WITH LOCAL TIME ZONE '1992-01-18
02:30:00.123'</tt>).
+ *
+ * If left empty, defaults to server time zone.
+ *
+ * @param val Timezone ID.
+ */
+ void timezone_id(std::string val) { m_timezone_id = std::move(val); }
+
private:
/** Query text. */
std::string m_query;
@@ -147,6 +169,9 @@ private:
/** Properties. */
std::unordered_map<std::string, primitive> m_properties;
+
+ /** Timezone ID. */
+ std::string m_timezone_id;
};
} // namespace ignite
diff --git a/modules/platforms/cpp/ignite/odbc/config/configuration.cpp
b/modules/platforms/cpp/ignite/odbc/config/configuration.cpp
index 4468e8c7d0..bd75d20a09 100644
--- a/modules/platforms/cpp/ignite/odbc/config/configuration.cpp
+++ b/modules/platforms/cpp/ignite/odbc/config/configuration.cpp
@@ -45,6 +45,9 @@ static inline const std::string identity{"identity"};
/** Key for authentication secret. */
static inline const std::string secret{"secret"};
+/** Key for timezone. */
+static inline const std::string timezone{"timezone"};
+
} // namespace key
namespace ignite {
@@ -93,6 +96,7 @@ void configuration::from_config_map(const config_map
&config_params) {
try_get_string_param(m_schema, config_params, key::schema);
try_get_string_param(m_auth_identity, config_params, key::identity);
try_get_string_param(m_auth_secret, config_params, key::secret);
+ try_get_string_param(m_timezone, config_params, key::timezone);
}
} // namespace ignite
diff --git a/modules/platforms/cpp/ignite/odbc/config/configuration.h
b/modules/platforms/cpp/ignite/odbc/config/configuration.h
index c40f1c2b09..5dc663921c 100644
--- a/modules/platforms/cpp/ignite/odbc/config/configuration.h
+++ b/modules/platforms/cpp/ignite/odbc/config/configuration.h
@@ -43,11 +43,14 @@ public:
/** Default value for TCP port attribute. */
static inline const std::uint16_t port{10800};
- /** Default value for address attribute. */
+ /** Default value for Address attribute. */
static inline const std::vector<end_point> address{{host, port}};
- /** Default value for Driver attribute. */
+ /** Default value for Schema attribute. */
static inline const std::string schema{"PUBLIC"};
+
+ /** Default value for Timezone attribute. */
+ static inline const std::string timezone{};
};
// Default.
@@ -100,6 +103,13 @@ public:
*/
[[nodiscard]] const value_with_default<std::string> &get_auth_secret()
const { return m_auth_secret; };
+ /**
+ * Get Timezone.
+ *
+ * @return Timezone.
+ */
+ [[nodiscard]] const value_with_default<std::string> &get_timezone() const
{ return m_timezone; };
+
/**
* Fill from configuration params.
*
@@ -126,6 +136,9 @@ private:
/** Secret. */
value_with_default<std::string> m_auth_secret{"", false};
+
+ /** Timezone. */
+ value_with_default<std::string> m_timezone{"", false};
};
} // namespace ignite
diff --git a/modules/platforms/cpp/ignite/odbc/query/data_query.cpp
b/modules/platforms/cpp/ignite/odbc/query/data_query.cpp
index 00b46b9e1c..7fea78dfeb 100644
--- a/modules/platforms/cpp/ignite/odbc/query/data_query.cpp
+++ b/modules/platforms/cpp/ignite/odbc/query/data_query.cpp
@@ -274,7 +274,13 @@ sql_result data_query::make_request_execute() {
writer.write(m_connection.get_configuration().get_page_size().get_value());
writer.write(std::int64_t(m_connection.get_timeout()) * 1000);
writer.write_nil(); // Session timeout (unused, session is closed
by the server immediately).
- writer.write_nil(); // TODO: IGNITE-21605 Time zone id.
+
+ auto timezone = m_connection.get_configuration().get_timezone();
+ if (timezone.is_set()) {
+ writer.write(timezone.get_value());
+ } else {
+ writer.write_nil();
+ }
// Properties are not used for now.
writer.write(0);
diff --git a/modules/platforms/cpp/ignite/odbc/string_utils.h
b/modules/platforms/cpp/ignite/odbc/string_utils.h
index daeea585a6..1961883fda 100644
--- a/modules/platforms/cpp/ignite/odbc/string_utils.h
+++ b/modules/platforms/cpp/ignite/odbc/string_utils.h
@@ -19,8 +19,11 @@
#include <algorithm>
#include <functional>
+#include <string_view>
#include <sstream>
+#include <cctype>
+
namespace ignite {
/**
diff --git a/modules/platforms/cpp/ignite/odbc/utility.cpp
b/modules/platforms/cpp/ignite/odbc/utility.cpp
index a3dd49b3c0..009b351961 100644
--- a/modules/platforms/cpp/ignite/odbc/utility.cpp
+++ b/modules/platforms/cpp/ignite/odbc/utility.cpp
@@ -18,6 +18,7 @@
#include "ignite/odbc/utility.h"
#include "ignite/odbc/system/odbc_constants.h"
+#include <algorithm>
#include <cstring>
namespace ignite {
diff --git a/modules/platforms/cpp/tests/client-test/sql_test.cpp
b/modules/platforms/cpp/tests/client-test/sql_test.cpp
index 23bcd762b3..c6860082b1 100644
--- a/modules/platforms/cpp/tests/client-test/sql_test.cpp
+++ b/modules/platforms/cpp/tests/client-test/sql_test.cpp
@@ -79,6 +79,13 @@ protected:
// remove all
}
+ primitive execute_statement_one_result(const sql_statement &statement) {
+ auto result_set0 = m_client.get_sql().execute(nullptr, statement, {});
+
+ EXPECT_TRUE(result_set0.has_rowset());
+ return result_set0.current_page().front().get(0);
+ }
+
/** Ignite client. */
ignite_client m_client;
};
@@ -479,3 +486,16 @@ TEST_F(sql_test, execute_script_fail) {
EXPECT_EQ(ignite_type::INT32, value.get_type());
EXPECT_EQ(1, value.get<std::int32_t>());
}
+
+TEST_F(sql_test, timezone_passed) {
+ sql_statement statement{"SELECT CURRENT_TIMESTAMP"};
+ statement.timezone_id("UTC+8");
+ auto ts0 = execute_statement_one_result(statement);
+ EXPECT_EQ(ignite_type::DATETIME, ts0.get_type());
+
+ statement.timezone_id("UTC-2");
+ auto ts1 = execute_statement_one_result(statement);
+ EXPECT_EQ(ignite_type::DATETIME, ts1.get_type());
+
+ EXPECT_NE(ts0.get<ignite_date_time>(), ts1.get<ignite_date_time>());
+}
diff --git a/modules/platforms/cpp/tests/odbc-test/connection_test.cpp
b/modules/platforms/cpp/tests/odbc-test/connection_test.cpp
index 052542dfa9..5f3d3ccca8 100644
--- a/modules/platforms/cpp/tests/odbc-test/connection_test.cpp
+++ b/modules/platforms/cpp/tests/odbc-test/connection_test.cpp
@@ -59,4 +59,41 @@ TEST_F(connection_test, dbms_cluster_name) {
// Test cluster name: see PlatformTestNodeRunner.
EXPECT_EQ(std::string("cluster"), std::string(reinterpret_cast<char
*>(buffer)));
-}
\ No newline at end of file
+}
+
+TEST_F(connection_test, timezone_passed) {
+ EXPECT_NO_THROW(odbc_connect_throw(get_basic_connection_string()+
"timezone=UTC+5;"));
+ auto ret = exec_query("SELECT CURRENT_TIMESTAMP");
+ ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, m_statement);
+
+ SQLCHAR buffer[1024];
+ SQLLEN column_len = sizeof(buffer);
+
+ ret = SQLBindCol(m_statement, 1, SQL_C_CHAR, &buffer, column_len,
&column_len);
+ ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, m_statement);
+
+ ret = SQLFetch(m_statement);
+ ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, m_statement);
+
+ ASSERT_GT(column_len, 0);
+ ASSERT_LT(column_len, 1024);
+ std::string ts0((char*)buffer, column_len);
+ odbc_clean_up();
+
+ EXPECT_NO_THROW(odbc_connect_throw(get_basic_connection_string()+
"timezone=UTC-8;"));
+ ret = exec_query("SELECT CURRENT_TIMESTAMP");
+ ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, m_statement);
+
+ ret = SQLBindCol(m_statement, 1, SQL_C_CHAR, &buffer, column_len,
&column_len);
+ ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, m_statement);
+
+ ret = SQLFetch(m_statement);
+ ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, m_statement);
+
+ ASSERT_GT(column_len, 0);
+ ASSERT_LT(column_len, 1024);
+ std::string ts1((char*)buffer, column_len);
+ odbc_clean_up();
+
+ EXPECT_NE(ts0, ts1);
+}