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 0a1f0215c6 IGNITE-19216 ODBC type info fetching (#2603)
0a1f0215c6 is described below
commit 0a1f0215c6a3f3789c71321ef1ed5e634afa0db3
Author: Igor Sapego <[email protected]>
AuthorDate: Tue Sep 19 13:08:25 2023 +0400
IGNITE-19216 ODBC type info fetching (#2603)
---
.../apache/ignite/internal/client/ClientUtils.java | 2 +-
.../ignite/internal/client/TcpClientChannel.java | 4 +-
.../cpp/ignite/client/detail/table/schema.h | 2 +-
modules/platforms/cpp/ignite/odbc/CMakeLists.txt | 1 +
.../cpp/ignite/odbc/app/application_data_buffer.h | 2 +-
modules/platforms/cpp/ignite/odbc/query/query.h | 3 +
.../cpp/ignite/odbc/query/table_metadata_query.h | 20 +-
.../cpp/ignite/odbc/query/type_info_query.cpp | 334 +++++++++++++++++++++
.../odbc/query/{query.h => type_info_query.h} | 98 +++---
.../platforms/cpp/ignite/odbc/sql_statement.cpp | 16 +-
modules/platforms/cpp/ignite/odbc/type_traits.cpp | 133 ++++----
modules/platforms/cpp/ignite/odbc/type_traits.h | 19 +-
modules/platforms/cpp/ignite/protocol/utils.cpp | 4 +-
.../client-test/key_value_binary_view_test.cpp | 6 +-
.../cpp/tests/client-test/key_value_view_test.cpp | 6 +-
.../tests/client-test/record_binary_view_test.cpp | 6 +-
.../cpp/tests/client-test/record_view_test.cpp | 6 +-
.../cpp/tests/odbc-test/meta_queries_test.cpp | 18 +-
18 files changed, 521 insertions(+), 159 deletions(-)
diff --git
a/modules/client/src/main/java/org/apache/ignite/internal/client/ClientUtils.java
b/modules/client/src/main/java/org/apache/ignite/internal/client/ClientUtils.java
index eccf1b6235..a4a5594743 100644
---
a/modules/client/src/main/java/org/apache/ignite/internal/client/ClientUtils.java
+++
b/modules/client/src/main/java/org/apache/ignite/internal/client/ClientUtils.java
@@ -46,7 +46,7 @@ public class ClientUtils {
throw ExceptionUtils.wrap(e);
} catch (ExecutionException e) {
- //TODO: https://issues.apache.org/jira/browse/IGNITE-19539
+ //TODO: https://issues.apache.org/jira/browse/IGNITE-20436
throw ExceptionUtils.wrap(e);
}
}
diff --git
a/modules/client/src/main/java/org/apache/ignite/internal/client/TcpClientChannel.java
b/modules/client/src/main/java/org/apache/ignite/internal/client/TcpClientChannel.java
index 14716bf942..8b8b30c8ee 100644
---
a/modules/client/src/main/java/org/apache/ignite/internal/client/TcpClientChannel.java
+++
b/modules/client/src/main/java/org/apache/ignite/internal/client/TcpClientChannel.java
@@ -327,7 +327,7 @@ class TcpClientChannel implements ClientChannel,
ClientMessageHandler, ClientCon
metrics.requestsActiveDecrement();
- // TODO https://issues.apache.org/jira/browse/IGNITE-19539
+ // TODO https://issues.apache.org/jira/browse/IGNITE-20436
throw ExceptionUtils.wrap(t);
}
}
@@ -468,7 +468,7 @@ class TcpClientChannel implements ClientChannel,
ClientMessageHandler, ClientCon
}
try {
- // TODO https://issues.apache.org/jira/browse/IGNITE-19539
+ // TODO https://issues.apache.org/jira/browse/IGNITE-20436
Class<? extends Throwable> errCls = (Class<? extends Throwable>)
Class.forName(errClassName);
if (IgniteException.class.isAssignableFrom(errCls) ||
IgniteCheckedException.class.isAssignableFrom(errCls)) {
return copyExceptionWithCause(errCls, traceId, code, errMsg,
causeWithStackTrace);
diff --git a/modules/platforms/cpp/ignite/client/detail/table/schema.h
b/modules/platforms/cpp/ignite/client/detail/table/schema.h
index b277e991ee..d521ad5a0f 100644
--- a/modules/platforms/cpp/ignite/client/detail/table/schema.h
+++ b/modules/platforms/cpp/ignite/client/detail/table/schema.h
@@ -93,7 +93,7 @@ struct schema {
* @param reader Reader to use.
* @return Schema instance.
*/
- static std::shared_ptr<schema> read(protocol::reader& reader) {
+ static std::shared_ptr<schema> read(protocol::reader &reader) {
std::int32_t key_column_count = 0;
auto schema_version = reader.read_int32();
diff --git a/modules/platforms/cpp/ignite/odbc/CMakeLists.txt
b/modules/platforms/cpp/ignite/odbc/CMakeLists.txt
index 58f02b7ec8..ea20e78785 100644
--- a/modules/platforms/cpp/ignite/odbc/CMakeLists.txt
+++ b/modules/platforms/cpp/ignite/odbc/CMakeLists.txt
@@ -37,6 +37,7 @@ set(SOURCES
meta/table_meta.cpp
query/data_query.cpp
query/table_metadata_query.cpp
+ query/type_info_query.cpp
odbc.cpp
entry_points.cpp
ssl_mode.cpp
diff --git a/modules/platforms/cpp/ignite/odbc/app/application_data_buffer.h
b/modules/platforms/cpp/ignite/odbc/app/application_data_buffer.h
index 98a2ffcb74..fd7ea6ee8d 100644
--- a/modules/platforms/cpp/ignite/odbc/app/application_data_buffer.h
+++ b/modules/platforms/cpp/ignite/odbc/app/application_data_buffer.h
@@ -522,6 +522,6 @@ private:
};
/** Column binging map type alias. */
-typedef std::map<uint16_t, application_data_buffer> column_binding_map;
+typedef std::map<std::uint16_t, application_data_buffer> column_binding_map;
} // namespace ignite
diff --git a/modules/platforms/cpp/ignite/odbc/query/query.h
b/modules/platforms/cpp/ignite/odbc/query/query.h
index 279c36184a..ce596eff70 100644
--- a/modules/platforms/cpp/ignite/odbc/query/query.h
+++ b/modules/platforms/cpp/ignite/odbc/query/query.h
@@ -33,6 +33,9 @@ enum class query_type {
/** Table metadata. */
TABLE_METADATA,
+
+ /** Type info. */
+ TYPE_INFO,
};
/**
diff --git a/modules/platforms/cpp/ignite/odbc/query/table_metadata_query.h
b/modules/platforms/cpp/ignite/odbc/query/table_metadata_query.h
index b9b0b57f10..9ed65d83ab 100644
--- a/modules/platforms/cpp/ignite/odbc/query/table_metadata_query.h
+++ b/modules/platforms/cpp/ignite/odbc/query/table_metadata_query.h
@@ -46,28 +46,28 @@ public:
/**
* Destructor.
*/
- virtual ~table_metadata_query() = default;
+ ~table_metadata_query() override = default;
/**
* Execute query.
*
* @return True on success.
*/
- virtual sql_result execute();
+ sql_result execute() override;
/**
* Get column metadata.
*
* @return Column metadata.
*/
- virtual const column_meta_vector *get_meta();
+ const column_meta_vector *get_meta() override;
/**
* Fetch next result row to application buffers.
*
* @return Operation result.
*/
- virtual sql_result fetch_next_row(column_binding_map &column_bindings);
+ sql_result fetch_next_row(column_binding_map &column_bindings) override;
/**
* Get data of the specified column in the result set.
@@ -76,39 +76,39 @@ public:
* @param buffer Buffer to put column data to.
* @return Operation result.
*/
- virtual sql_result get_column(std::uint16_t column_idx,
application_data_buffer &buffer);
+ sql_result get_column(std::uint16_t column_idx, application_data_buffer
&buffer) override;
/**
* Close query.
*
* @return True on success.
*/
- virtual sql_result close();
+ sql_result close() override;
/**
* Check if data is available.
*
* @return True if data is available.
*/
- virtual bool is_data_available() const;
+ bool is_data_available() const override;
/**
* Get number of rows affected by the statement.
*
* @return Number of rows affected by the statement.
*/
- virtual std::int64_t affected_rows() const;
+ std::int64_t affected_rows() const override;
/**
* Move to the next result set.
*
* @return Operation result.
*/
- virtual sql_result next_result_set();
+ sql_result next_result_set() override;
private:
/**
- * Make get columns metadata requets and use response to set internal
state.
+ * Make get columns metadata requests and use response to set internal
state.
*
* @return True on success.
*/
diff --git a/modules/platforms/cpp/ignite/odbc/query/type_info_query.cpp
b/modules/platforms/cpp/ignite/odbc/query/type_info_query.cpp
new file mode 100644
index 0000000000..0fb7fe3677
--- /dev/null
+++ b/modules/platforms/cpp/ignite/odbc/query/type_info_query.cpp
@@ -0,0 +1,334 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "ignite/odbc/query/type_info_query.h"
+#include "ignite/odbc/system/odbc_constants.h"
+#include "ignite/odbc/type_traits.h"
+
+#include <cassert>
+
+namespace {
+
+enum class result_column {
+ /** Data source-dependent data-type name. */
+ TYPE_NAME = 1,
+
+ /** SQL data type. */
+ DATA_TYPE,
+
+ /** The maximum column size that the server supports for this data type. */
+ COLUMN_SIZE,
+
+ /** Character or characters used to prefix a literal. */
+ LITERAL_PREFIX,
+
+ /** Character or characters used to terminate a literal. */
+ LITERAL_SUFFIX,
+
+ /**
+ * A list of keywords, separated by commas, corresponding to each
+ * parameter that the application may specify in parentheses when using
+ * the name that is returned in the TYPE_NAME field.
+ */
+ CREATE_PARAMS,
+
+ /** Whether the data type accepts a NULL value. */
+ NULLABLE,
+
+ /**
+ * Whether a character data type is case-sensitive in collations and
+ * comparisons.
+ */
+ CASE_SENSITIVE,
+
+ /** How the data type is used in a WHERE clause. */
+ SEARCHABLE,
+
+ /** Whether the data type is unsigned. */
+ UNSIGNED_ATTRIBUTE,
+
+ /** Whether the data type has predefined fixed precision and scale. */
+ FIXED_PREC_SCALE,
+
+ /** Whether the data type is auto-incrementing. */
+ AUTO_UNIQUE_VALUE,
+
+ /**
+ * Localized version of the data source–dependent name of the data
+ * type.
+ */
+ LOCAL_TYPE_NAME,
+
+ /** The minimum scale of the data type on the data source. */
+ MINIMUM_SCALE,
+
+ /** The maximum scale of the data type on the data source. */
+ MAXIMUM_SCALE,
+
+ /**
+ * The value of the SQL data type as it appears in the SQL_DESC_TYPE
+ * field of the descriptor.
+ */
+ SQL_DATA_TYPE,
+
+ /**
+ * When the value of SQL_DATA_TYPE is SQL_DATETIME or SQL_INTERVAL,
+ * this column contains the datetime/interval sub-code.
+ */
+ SQL_DATETIME_SUB,
+
+ /**
+ * If the data type is an approximate numeric type, this column
+ * contains the value 2 to indicate that COLUMN_SIZE specifies a number
+ * of bits.
+ */
+ NUM_PREC_RADIX,
+
+ /**
+ * If the data type is an interval data type, then this column contains
+ * the value of the interval leading precision.
+ */
+ INTERVAL_PRECISION
+};
+
+} // anonymous namespace
+
+namespace ignite {
+
+type_info_query::type_info_query(diagnosable_adapter &diag, std::int16_t
sql_type)
+ : query(diag, query_type::TYPE_INFO) {
+ m_columns_meta.reserve(19);
+
+ const std::string sch;
+ const std::string tbl;
+
+ m_columns_meta.emplace_back(sch, tbl, "TYPE_NAME", ignite_type::STRING);
+ m_columns_meta.emplace_back(sch, tbl, "DATA_TYPE", ignite_type::INT16);
+ m_columns_meta.emplace_back(sch, tbl, "COLUMN_SIZE", ignite_type::INT32);
+ m_columns_meta.emplace_back(sch, tbl, "LITERAL_PREFIX",
ignite_type::STRING);
+ m_columns_meta.emplace_back(sch, tbl, "LITERAL_SUFFIX",
ignite_type::STRING);
+ m_columns_meta.emplace_back(sch, tbl, "CREATE_PARAMS",
ignite_type::STRING);
+ m_columns_meta.emplace_back(sch, tbl, "NULLABLE", ignite_type::INT16);
+ m_columns_meta.emplace_back(sch, tbl, "CASE_SENSITIVE",
ignite_type::INT16);
+ m_columns_meta.emplace_back(sch, tbl, "SEARCHABLE", ignite_type::INT16);
+ m_columns_meta.emplace_back(sch, tbl, "UNSIGNED_ATTRIBUTE",
ignite_type::INT16);
+ m_columns_meta.emplace_back(sch, tbl, "FIXED_PREC_SCALE",
ignite_type::INT16);
+ m_columns_meta.emplace_back(sch, tbl, "AUTO_UNIQUE_VALUE",
ignite_type::INT16);
+ m_columns_meta.emplace_back(sch, tbl, "LOCAL_TYPE_NAME",
ignite_type::STRING);
+ m_columns_meta.emplace_back(sch, tbl, "MINIMUM_SCALE", ignite_type::INT16);
+ m_columns_meta.emplace_back(sch, tbl, "MAXIMUM_SCALE", ignite_type::INT16);
+ m_columns_meta.emplace_back(sch, tbl, "SQL_DATA_TYPE", ignite_type::INT16);
+ m_columns_meta.emplace_back(sch, tbl, "SQL_DATETIME_SUB",
ignite_type::INT16);
+ m_columns_meta.emplace_back(sch, tbl, "NUM_PREC_RADIX",
ignite_type::INT32);
+ m_columns_meta.emplace_back(sch, tbl, "INTERVAL_PRECISION",
ignite_type::INT16);
+
+ assert(is_sql_type_supported(sql_type) || sql_type == SQL_ALL_TYPES);
+
+ if (sql_type == SQL_ALL_TYPES) {
+ m_types.push_back(ignite_type::BOOLEAN);
+ m_types.push_back(ignite_type::INT8);
+ m_types.push_back(ignite_type::INT16);
+ m_types.push_back(ignite_type::INT32);
+ m_types.push_back(ignite_type::INT64);
+ m_types.push_back(ignite_type::FLOAT);
+ m_types.push_back(ignite_type::DOUBLE);
+ m_types.push_back(ignite_type::DECIMAL);
+ m_types.push_back(ignite_type::DATE);
+ m_types.push_back(ignite_type::TIME);
+ m_types.push_back(ignite_type::DATETIME);
+ m_types.push_back(ignite_type::TIMESTAMP);
+ m_types.push_back(ignite_type::UUID);
+ m_types.push_back(ignite_type::BITMASK);
+ m_types.push_back(ignite_type::STRING);
+ m_types.push_back(ignite_type::BYTE_ARRAY);
+ // TODO: IGNITE-19969 implement support for period, duration and
big_integer
+ } else
+ m_types.push_back(sql_type_to_ignite_type(sql_type));
+}
+
+sql_result type_info_query::execute() {
+ m_cursor = m_types.begin();
+
+ m_executed = true;
+ m_fetched = false;
+
+ return sql_result::AI_SUCCESS;
+}
+
+sql_result type_info_query::fetch_next_row(column_binding_map
&column_bindings) {
+ if (!m_executed) {
+ m_diag.add_status_record(sql_state::SHY010_SEQUENCE_ERROR, "Query was
not executed.");
+ return sql_result::AI_ERROR;
+ }
+
+ if (!m_fetched)
+ m_fetched = true;
+ else
+ ++m_cursor;
+
+ if (m_cursor == m_types.end())
+ return sql_result::AI_NO_DATA;
+
+ for (auto &pair : column_bindings)
+ get_column(pair.first, pair.second);
+
+ return sql_result::AI_SUCCESS;
+}
+
+sql_result type_info_query::get_column(std::uint16_t column_idx,
application_data_buffer &buffer) {
+ if (!m_executed) {
+ m_diag.add_status_record(sql_state::SHY010_SEQUENCE_ERROR, "Query was
not executed.");
+ return sql_result::AI_ERROR;
+ }
+
+ if (m_cursor == m_types.end()) {
+ m_diag.add_status_record(sql_state::S24000_INVALID_CURSOR_STATE,
"Cursor has reached end of the result set.");
+ return sql_result::AI_ERROR;
+ }
+
+ auto current_type = *m_cursor;
+
+ switch (result_column(column_idx)) {
+ case result_column::TYPE_NAME: {
+ buffer.put_string(ignite_type_to_sql_type_name(current_type));
+
+ break;
+ }
+
+ case result_column::DATA_TYPE:
+ case result_column::SQL_DATA_TYPE: {
+ buffer.put_int16(ignite_type_to_sql_type(current_type));
+
+ break;
+ }
+
+ case result_column::COLUMN_SIZE: {
+ buffer.put_int32(ignite_type_max_column_size(current_type));
+
+ break;
+ }
+
+ case result_column::LITERAL_PREFIX: {
+ auto prefix = ignite_type_literal_prefix(current_type);
+ if (!prefix)
+ buffer.put_null();
+ else
+ buffer.put_string(*prefix);
+
+ break;
+ }
+
+ case result_column::LITERAL_SUFFIX: {
+ auto suffix = ignite_type_literal_suffix(current_type);
+ if (!suffix)
+ buffer.put_null();
+ else
+ buffer.put_string(*suffix);
+
+ break;
+ }
+
+ case result_column::CREATE_PARAMS: {
+ if (current_type == ignite_type::DECIMAL || current_type ==
ignite_type::NUMBER)
+ buffer.put_string("precision,scale");
+ else
+ buffer.put_null();
+
+ break;
+ }
+
+ case result_column::NULLABLE: {
+ buffer.put_int32(ignite_type_nullability(current_type));
+
+ break;
+ }
+
+ case result_column::CASE_SENSITIVE: {
+ if (current_type == ignite_type::STRING)
+ buffer.put_int16(SQL_TRUE);
+ else
+ buffer.put_int16(SQL_FALSE);
+
+ break;
+ }
+
+ case result_column::SEARCHABLE: {
+ buffer.put_int16(SQL_SEARCHABLE);
+
+ break;
+ }
+
+ case result_column::UNSIGNED_ATTRIBUTE: {
+ buffer.put_int16(is_ignite_type_unsigned(current_type));
+
+ break;
+ }
+
+ case result_column::FIXED_PREC_SCALE:
+ case result_column::AUTO_UNIQUE_VALUE: {
+ buffer.put_int16(SQL_FALSE);
+
+ break;
+ }
+
+ case result_column::LOCAL_TYPE_NAME: {
+ buffer.put_null();
+
+ break;
+ }
+
+ case result_column::MINIMUM_SCALE:
+ case result_column::MAXIMUM_SCALE: {
+
buffer.put_int16(std::int16_t(ignite_type_decimal_digits(current_type)));
+
+ break;
+ }
+
+ case result_column::SQL_DATETIME_SUB: {
+ buffer.put_null();
+
+ break;
+ }
+
+ case result_column::NUM_PREC_RADIX: {
+ buffer.put_int32(ignite_type_num_precision_radix(current_type));
+
+ break;
+ }
+
+ case result_column::INTERVAL_PRECISION: {
+ buffer.put_null();
+
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ return sql_result::AI_SUCCESS;
+}
+
+sql_result type_info_query::close() {
+ m_cursor = m_types.end();
+
+ m_executed = false;
+
+ return sql_result::AI_SUCCESS;
+}
+
+} // namespace ignite
diff --git a/modules/platforms/cpp/ignite/odbc/query/query.h
b/modules/platforms/cpp/ignite/odbc/query/type_info_query.h
similarity index 54%
copy from modules/platforms/cpp/ignite/odbc/query/query.h
copy to modules/platforms/cpp/ignite/odbc/query/type_info_query.h
index 279c36184a..2f2eccdd54 100644
--- a/modules/platforms/cpp/ignite/odbc/query/query.h
+++ b/modules/platforms/cpp/ignite/odbc/query/type_info_query.h
@@ -17,48 +17,48 @@
#pragma once
-#include "ignite/odbc/common_types.h"
-#include "ignite/odbc/diagnostic/diagnosable_adapter.h"
-#include "ignite/odbc/meta/column_meta.h"
-
-#include <cstdint>
-#include <map>
+#include "ignite/odbc/query/query.h"
namespace ignite {
-/** Query type. */
-enum class query_type {
- /** Data query type. */
- DATA,
-
- /** Table metadata. */
- TABLE_METADATA,
-};
-
/**
- * Query.
+ * Type info query.
*/
-class query {
+class type_info_query : public query {
public:
/**
- * Virtual destructor
+ * Constructor.
+ *
+ * @param diag Diagnostics collector.
+ * @param sql_type SQL type.
*/
- virtual ~query() = default;
+ type_info_query(diagnosable_adapter &diag, std::int16_t sql_type);
+
+ /**
+ * Destructor.
+ */
+ ~type_info_query() override = default;
/**
* Execute query.
*
- * @return Execution result.
+ * @return True on success.
+ */
+ sql_result execute() override;
+
+ /**
+ * Get column metadata.
+ *
+ * @return Column metadata.
*/
- virtual sql_result execute() = 0;
+ const column_meta_vector *get_meta() override { return &m_columns_meta; }
/**
* Fetch next result row to application buffers.
*
- * @param column_bindings Application buffers to put data to.
* @return Operation result.
*/
- virtual sql_result fetch_next_row(column_binding_map &m_column_bindings) =
0;
+ sql_result fetch_next_row(column_binding_map &column_bindings) override;
/**
* Get data of the specified column in the result set.
@@ -67,67 +67,51 @@ public:
* @param buffer Buffer to put column data to.
* @return Operation result.
*/
- virtual sql_result get_column(std::uint16_t column_idx,
application_data_buffer &buffer) = 0;
+ sql_result get_column(std::uint16_t column_idx, application_data_buffer
&buffer) override;
/**
* Close query.
*
- * @return Operation result.
- */
- virtual sql_result close() = 0;
-
- /**
- * Get column metadata.
- *
- * @return Column metadata.
+ * @return True on success.
*/
- [[nodiscard]] virtual const column_meta_vector *get_meta() {
- static const column_meta_vector empty;
-
- return ∅
- }
+ sql_result close() override;
/**
* Check if data is available.
*
* @return True if data is available.
*/
- [[nodiscard]] virtual bool is_data_available() const = 0;
+ bool is_data_available() const override { return m_cursor !=
m_types.end(); }
/**
* Get number of rows affected by the statement.
*
* @return Number of rows affected by the statement.
*/
- [[nodiscard]] virtual std::int64_t affected_rows() const = 0;
+ std::int64_t affected_rows() const override { return 0; }
/**
* Move to the next result set.
*
* @return Operation result.
*/
- virtual sql_result next_result_set() = 0;
+ sql_result next_result_set() override { return sql_result::AI_NO_DATA; }
- /**
- * Get query type.
- *
- * @return Query type.
- */
- [[nodiscard]] query_type get_type() const { return m_type; }
+private:
+ /** Columns metadata. */
+ column_meta_vector m_columns_meta;
-protected:
- /**
- * Constructor.
- */
- query(diagnosable_adapter &diag, query_type type)
- : m_diag(diag)
- , m_type(type) {}
+ /** Executed flag. */
+ bool m_executed{false};
+
+ /** Fetched flag. */
+ bool m_fetched{false};
- /** Diagnostics collector. */
- diagnosable_adapter &m_diag;
+ /** Requested types. */
+ std::vector<ignite_type> m_types;
- /** Query type. */
- query_type m_type;
+ /** Query cursor. */
+ std::vector<ignite_type>::const_iterator m_cursor{m_types.end()};
};
} // namespace ignite
diff --git a/modules/platforms/cpp/ignite/odbc/sql_statement.cpp
b/modules/platforms/cpp/ignite/odbc/sql_statement.cpp
index 26779ab8bc..e29512ae98 100644
--- a/modules/platforms/cpp/ignite/odbc/sql_statement.cpp
+++ b/modules/platforms/cpp/ignite/odbc/sql_statement.cpp
@@ -21,7 +21,7 @@
#include "ignite/odbc/odbc_error.h"
#include "ignite/odbc/query/data_query.h"
#include "ignite/odbc/query/table_metadata_query.h"
-#include "ignite/odbc/sql_connection.h"
+#include "ignite/odbc/query/type_info_query.h"
#include "ignite/odbc/sql_statement.h"
#include "ignite/odbc/system/odbc_constants.h"
#include "ignite/odbc/utility.h"
@@ -651,11 +651,11 @@ sql_result
sql_statement::internal_execute_special_columns_query(uint16_t type,
return sql_result::AI_ERROR;
}
-void sql_statement::execute_get_type_info_query(int16_t sql_type) {
+void sql_statement::execute_get_type_info_query(std::int16_t sql_type) {
IGNITE_ODBC_API_CALL(internal_execute_get_type_info_query(sql_type));
}
-sql_result sql_statement::internal_execute_get_type_info_query(int16_t
sql_type) {
+sql_result sql_statement::internal_execute_get_type_info_query(std::int16_t
sql_type) {
if (sql_type != SQL_ALL_TYPES && !is_sql_type_supported(sql_type)) {
std::stringstream builder;
builder << "Data type is not supported. [typeId=" << sql_type << ']';
@@ -668,9 +668,8 @@ sql_result
sql_statement::internal_execute_get_type_info_query(int16_t sql_type)
if (m_current_query)
m_current_query->close();
- // TODO: IGNITE-19216 Implement type info query
- add_status_record(sql_state::SHYC00_OPTIONAL_FEATURE_NOT_IMPLEMENTED,
"Type info query is not supported.");
- return sql_result::AI_ERROR;
+ m_current_query = std::make_unique<type_info_query>(*this, sql_type);
+ return m_current_query->execute();
}
void sql_statement::free_resources(uint16_t option) {
@@ -1008,12 +1007,15 @@ sql_result sql_statement::internal_describe_param(
if (data_type)
*data_type = ignite_type_to_sql_type(type);
+ // TODO: IGNITE-19854 Implement meta fetching for a parameter
if (param_size)
- *param_size = ignite_type_column_size(type);
+ *param_size = ignite_type_max_column_size(type);
+ // TODO: IGNITE-19854 Implement meta fetching for a parameter
if (decimal_digits)
*decimal_digits = int16_t(ignite_type_decimal_digits(type));
+ // TODO: IGNITE-19854 Implement meta fetching for a parameter
if (nullable)
*nullable = ignite_type_nullability(type);
diff --git a/modules/platforms/cpp/ignite/odbc/type_traits.cpp
b/modules/platforms/cpp/ignite/odbc/type_traits.cpp
index 9fc1075f29..bdafc1c767 100644
--- a/modules/platforms/cpp/ignite/odbc/type_traits.cpp
+++ b/modules/platforms/cpp/ignite/odbc/type_traits.cpp
@@ -76,8 +76,11 @@ const char *statement_attr_id_to_string(long id) {
*/
namespace sql_type_name {
-/** VARCHAR SQL type name constant. */
-const inline std::string VARCHAR("VARCHAR");
+/** BOOLEAN SQL type name constant. */
+const inline std::string BOOLEAN("BOOLEAN");
+
+/** TINYINT SQL type name constant. */
+const inline std::string TINYINT("TINYINT");
/** SMALLINT SQL type name constant. */
const inline std::string SMALLINT("SMALLINT");
@@ -85,45 +88,45 @@ const inline std::string SMALLINT("SMALLINT");
/** INTEGER SQL type name constant. */
const inline std::string INTEGER("INTEGER");
-/** DECIMAL SQL type name constant. */
-const inline std::string DECIMAL("DECIMAL");
+/** BIGINT SQL type name constant. */
+const inline std::string BIGINT("BIGINT");
/** FLOAT SQL type name constant. */
-const inline std::string FLOAT("FLOAT");
+const inline std::string REAL("REAL");
/** DOUBLE SQL type name constant. */
const inline std::string DOUBLE("DOUBLE");
-/** BIT SQL type name constant. */
-const inline std::string BIT("BIT");
-
-/** TINYINT SQL type name constant. */
-const inline std::string TINYINT("TINYINT");
-
-/** BIGINT SQL type name constant. */
-const inline std::string BIGINT("BIGINT");
+/** VARCHAR SQL type name constant. */
+const inline std::string VARCHAR("VARCHAR");
/** BINARY SQL type name constant. */
const inline std::string BINARY("VARBINARY");
-/** DATE SQL type name constant. */
-const inline std::string DATE("DATE");
+/** TIME SQL type name constant. */
+const inline std::string TIME("TIME");
/** TIMESTAMP SQL type name constant. */
const inline std::string TIMESTAMP("TIMESTAMP");
-/** TIME SQL type name constant. */
-const inline std::string TIME("TIME");
+/** DATE SQL type name constant. */
+const inline std::string DATE("DATE");
-/** GUID SQL type name constant. */
-const inline std::string GUID("GUID");
+/** DECIMAL SQL type name constant. */
+const inline std::string DECIMAL("DECIMAL");
+
+/** UUID SQL type name constant. */
+const inline std::string UUID("UUID");
-}; // namespace sql_type_name
+} // namespace sql_type_name
const std::string &ignite_type_to_sql_type_name(ignite_type typ) {
switch (typ) {
- case ignite_type::STRING:
- return sql_type_name::VARCHAR;
+ case ignite_type::BOOLEAN:
+ return sql_type_name::BOOLEAN;
+
+ case ignite_type::INT8:
+ return sql_type_name::TINYINT;
case ignite_type::INT16:
return sql_type_name::SMALLINT;
@@ -134,24 +137,21 @@ const std::string
&ignite_type_to_sql_type_name(ignite_type typ) {
case ignite_type::INT64:
return sql_type_name::BIGINT;
- case ignite_type::DECIMAL:
- case ignite_type::NUMBER:
- return sql_type_name::DECIMAL;
-
case ignite_type::FLOAT:
- return sql_type_name::FLOAT;
+ return sql_type_name::REAL;
case ignite_type::DOUBLE:
return sql_type_name::DOUBLE;
- case ignite_type::BOOLEAN:
- return sql_type_name::BIT;
+ case ignite_type::STRING:
+ return sql_type_name::VARCHAR;
- case ignite_type::INT8:
- return sql_type_name::TINYINT;
+ case ignite_type::DECIMAL:
+ case ignite_type::NUMBER:
+ return sql_type_name::DECIMAL;
case ignite_type::UUID:
- return sql_type_name::GUID;
+ return sql_type_name::UUID;
case ignite_type::DATE:
return sql_type_name::DATE;
@@ -263,13 +263,13 @@ ignite_type sql_type_to_ignite_type(std::int16_t
sql_type) {
return ignite_type::DATE;
case SQL_TYPE_TIMESTAMP:
- return ignite_type::TIMESTAMP;
+ return ignite_type::DATETIME;
case SQL_TYPE_TIME:
return ignite_type::TIME;
default:
- // TODO: Add proper support for all possible types.
+ // TODO: IGNITE-19969 implement support for period, duration and
big_integer
break;
}
@@ -405,14 +405,11 @@ std::int16_t ignite_type_to_sql_type(ignite_type typ) {
}
std::int16_t ignite_type_nullability(ignite_type typ) {
- // TODO: IGNITE-19854 Remove once parameters meta fetching is implemented
UNUSED_VALUE(typ);
-
- return SQL_NULLABLE_UNKNOWN;
+ return SQL_NULLABLE;
}
std::int32_t sql_type_display_size(std::int16_t type) {
- // TODO: IGNITE-19854 Remove once parameters meta fetching is implemented
switch (type) {
case SQL_VARCHAR:
case SQL_CHAR:
@@ -465,26 +462,12 @@ std::int32_t sql_type_display_size(std::int16_t type) {
}
std::int32_t ignite_type_display_size(ignite_type typ) {
- // TODO: IGNITE-19854 Remove once parameters meta fetching is implemented
std::int16_t sql_type = ignite_type_to_sql_type(typ);
-
return sql_type_display_size(sql_type);
}
std::int32_t sql_type_column_size(std::int16_t type) {
- // TODO: IGNITE-19854 Remove once parameters meta fetching is implemented
switch (type) {
- case SQL_VARCHAR:
- case SQL_CHAR:
- case SQL_WCHAR:
- case SQL_LONGVARBINARY:
- case SQL_BINARY:
- case SQL_VARBINARY:
- case SQL_LONGVARCHAR:
- case SQL_DECIMAL:
- case SQL_NUMERIC:
- return SQL_NO_TOTAL;
-
case SQL_BIT:
return 1;
@@ -519,20 +502,26 @@ std::int32_t sql_type_column_size(std::int16_t type) {
case SQL_GUID:
return 36;
+ case SQL_VARCHAR:
+ case SQL_CHAR:
+ case SQL_WCHAR:
+ case SQL_LONGVARBINARY:
+ case SQL_BINARY:
+ case SQL_VARBINARY:
+ case SQL_LONGVARCHAR:
+ case SQL_DECIMAL:
+ case SQL_NUMERIC:
default:
return SQL_NO_TOTAL;
}
}
-std::int32_t ignite_type_column_size(ignite_type typ) {
- // TODO: IGNITE-19854 Remove once parameters meta fetching is implemented
+std::int32_t ignite_type_max_column_size(ignite_type typ) {
std::int16_t sql_type = ignite_type_to_sql_type(typ);
-
return sql_type_column_size(sql_type);
}
std::int32_t sql_type_transfer_length(std::int16_t type) {
- // TODO: IGNITE-19854 Remove once parameters meta fetching is implemented
switch (type) {
case SQL_VARCHAR:
case SQL_CHAR:
@@ -582,7 +571,6 @@ std::int32_t ignite_type_transfer_length(ignite_type typ) {
}
std::int32_t sql_type_num_precision_radix(std::int16_t type) {
- // TODO: IGNITE-19854 Remove once parameters meta fetching is implemented
switch (type) {
case SQL_REAL:
case SQL_FLOAT:
@@ -642,4 +630,35 @@ bool is_ignite_type_unsigned(ignite_type typ) {
return is_sql_type_unsigned(sql_type);
}
+std::optional<std::string> ignite_type_literal_prefix(ignite_type typ) {
+ switch (typ) {
+ case ignite_type::STRING:
+ return "'";
+ case ignite_type::BYTE_ARRAY:
+ return "0x";
+ case ignite_type::DATE:
+ return "DATE '";
+ case ignite_type::TIME:
+ return "TIME '";
+ case ignite_type::TIMESTAMP:
+ return "TIMESTAMP '";
+ default:
+ break;
+ }
+ return {};
+}
+
+std::optional<std::string> ignite_type_literal_suffix(ignite_type typ) {
+ switch (typ) {
+ case ignite_type::STRING:
+ case ignite_type::DATE:
+ case ignite_type::TIME:
+ case ignite_type::TIMESTAMP:
+ return "'";
+ default:
+ break;
+ }
+ return {};
+}
+
} // namespace ignite
diff --git a/modules/platforms/cpp/ignite/odbc/type_traits.h
b/modules/platforms/cpp/ignite/odbc/type_traits.h
index 727af18d26..aa9b65cc7b 100644
--- a/modules/platforms/cpp/ignite/odbc/type_traits.h
+++ b/modules/platforms/cpp/ignite/odbc/type_traits.h
@@ -20,6 +20,7 @@
#include <ignite/common/ignite_type.h>
#include <cstdint>
+#include <optional>
#include <string>
namespace ignite {
@@ -189,7 +190,7 @@ int32_t sql_type_column_size(int16_t type);
* @param typ Ignite type.
* @return Column size.
*/
-int32_t ignite_type_column_size(ignite_type typ);
+int32_t ignite_type_max_column_size(ignite_type typ);
/**
* Get SQL type transfer octet length.
@@ -255,4 +256,20 @@ bool is_sql_type_unsigned(int16_t type);
*/
bool is_ignite_type_unsigned(ignite_type typ);
+/**
+ * Get literal prefix for an ignite type.
+ *
+ * @param typ Type.
+ * @return Prefix.
+ */
+std::optional<std::string> ignite_type_literal_prefix(ignite_type typ);
+
+/**
+ * Get literal suffix for an ignite type.
+ *
+ * @param typ Type.
+ * @return Suffix.
+ */
+std::optional<std::string> ignite_type_literal_suffix(ignite_type typ);
+
} // namespace ignite
diff --git a/modules/platforms/cpp/ignite/protocol/utils.cpp
b/modules/platforms/cpp/ignite/protocol/utils.cpp
index c937c9f59d..b3311c2f7c 100644
--- a/modules/platforms/cpp/ignite/protocol/utils.cpp
+++ b/modules/platforms/cpp/ignite/protocol/utils.cpp
@@ -90,8 +90,8 @@ T unpack_int(const msgpack_object &object) {
template<typename T>
T unpack_uint(const msgpack_object &object) {
- static_assert(
- std::numeric_limits<T>::is_integer &&
!std::numeric_limits<T>::is_signed, "Type T is not a unsigned integer type");
+ static_assert(std::numeric_limits<T>::is_integer &&
!std::numeric_limits<T>::is_signed,
+ "Type T is not a unsigned integer type");
auto u64_val = unpack_object<std::uint64_t>(object);
diff --git
a/modules/platforms/cpp/tests/client-test/key_value_binary_view_test.cpp
b/modules/platforms/cpp/tests/client-test/key_value_binary_view_test.cpp
index 43fe96213f..38fc94e035 100644
--- a/modules/platforms/cpp/tests/client-test/key_value_binary_view_test.cpp
+++ b/modules/platforms/cpp/tests/client-test/key_value_binary_view_test.cpp
@@ -842,7 +842,7 @@ TEST_F(key_value_binary_view_test,
remove_all_nonexisting_keys_return_all) {
EXPECT_EQ(res.size(), 2);
- // TODO: Key order should be preserved by the server (IGNITE-16004).
+ // TODO: Key order should be preserved by the server (IGNITE-20435).
EXPECT_EQ(1, res[0].column_count());
EXPECT_EQ(2, res[0].get<int64_t>("key"));
@@ -878,7 +878,7 @@ TEST_F(key_value_binary_view_test, remove_all_overlapped) {
EXPECT_EQ(res.size(), 2);
- // TODO: Key order should be preserved by the server (IGNITE-16004).
+ // TODO: Key order should be preserved by the server (IGNITE-20435).
EXPECT_EQ(1, res[0].column_count());
EXPECT_EQ(12, res[0].get<int64_t>("key"));
@@ -894,7 +894,7 @@ TEST_F(key_value_binary_view_test, remove_all_empty) {
TEST_F(key_value_binary_view_test, remove_all_exact_nonexisting) {
auto res = kv_view.remove_all(nullptr, {{get_tuple(1), get_tuple("foo")},
{get_tuple(2), get_tuple("bar")}});
- // TODO: Key order should be preserved by the server (IGNITE-16004).
+ // TODO: Key order should be preserved by the server (IGNITE-20435).
ASSERT_EQ(2, res.size());
}
diff --git a/modules/platforms/cpp/tests/client-test/key_value_view_test.cpp
b/modules/platforms/cpp/tests/client-test/key_value_view_test.cpp
index 3d0c5d4bc9..98ee0264b0 100644
--- a/modules/platforms/cpp/tests/client-test/key_value_view_test.cpp
+++ b/modules/platforms/cpp/tests/client-test/key_value_view_test.cpp
@@ -699,7 +699,7 @@ TEST_F(key_value_view_test,
remove_all_nonexisting_keys_return_all) {
EXPECT_EQ(res.size(), 2);
- // TODO: Key order should be preserved by the server (IGNITE-16004).
+ // TODO: Key order should be preserved by the server (IGNITE-20435).
EXPECT_EQ(2, res[0].key);
EXPECT_EQ(1, res[1].key);
}
@@ -732,7 +732,7 @@ TEST_F(key_value_view_test, remove_all_overlapped) {
EXPECT_EQ(res.size(), 2);
- // TODO: Key order should be preserved by the server (IGNITE-16004).
+ // TODO: Key order should be preserved by the server (IGNITE-20435).
EXPECT_EQ(12, res[0].key);
EXPECT_EQ(11, res[1].key);
}
@@ -746,7 +746,7 @@ TEST_F(key_value_view_test, remove_all_exact_nonexisting) {
auto res = kv_view.remove_all(
nullptr, {{test_key_type(1), test_value_type("foo")},
{test_key_type(2), test_value_type("bar")}});
- // TODO: Key order should be preserved by the server (IGNITE-16004).
+ // TODO: Key order should be preserved by the server (IGNITE-20435).
ASSERT_EQ(2, res.size());
}
diff --git
a/modules/platforms/cpp/tests/client-test/record_binary_view_test.cpp
b/modules/platforms/cpp/tests/client-test/record_binary_view_test.cpp
index 2c5823dcf5..b77e7e7425 100644
--- a/modules/platforms/cpp/tests/client-test/record_binary_view_test.cpp
+++ b/modules/platforms/cpp/tests/client-test/record_binary_view_test.cpp
@@ -845,7 +845,7 @@ TEST_F(record_binary_view_test,
remove_all_nonexisting_keys_return_all) {
EXPECT_EQ(res.size(), 2);
- // TODO: Key order should be preserved by the server (IGNITE-16004).
+ // TODO: Key order should be preserved by the server (IGNITE-20435).
EXPECT_EQ(1, res[0].column_count());
EXPECT_EQ(2, res[0].get<int64_t>("key"));
@@ -880,7 +880,7 @@ TEST_F(record_binary_view_test, remove_all_overlapped) {
EXPECT_EQ(res.size(), 2);
- // TODO: Key order should be preserved by the server (IGNITE-16004).
+ // TODO: Key order should be preserved by the server (IGNITE-20435).
EXPECT_EQ(1, res[0].column_count());
EXPECT_EQ(12, res[0].get<int64_t>("key"));
@@ -896,7 +896,7 @@ TEST_F(record_binary_view_test, remove_all_empty) {
TEST_F(record_binary_view_test, remove_all_exact_nonexisting) {
auto res = tuple_view.remove_all_exact(nullptr, {get_tuple(1, "foo"),
get_tuple(2, "bar")});
- // TODO: Key order should be preserved by the server (IGNITE-16004).
+ // TODO: Key order should be preserved by the server (IGNITE-20435).
ASSERT_EQ(2, res.size());
}
diff --git a/modules/platforms/cpp/tests/client-test/record_view_test.cpp
b/modules/platforms/cpp/tests/client-test/record_view_test.cpp
index 995b2b052b..73935a1331 100644
--- a/modules/platforms/cpp/tests/client-test/record_view_test.cpp
+++ b/modules/platforms/cpp/tests/client-test/record_view_test.cpp
@@ -874,7 +874,7 @@ TEST_F(record_view_test,
remove_all_nonexisting_keys_return_all) {
EXPECT_EQ(res.size(), 2);
- // TODO: Key order should be preserved by the server (IGNITE-16004).
+ // TODO: Key order should be preserved by the server (IGNITE-20435).
EXPECT_EQ(2, res[0].key);
EXPECT_EQ(1, res[1].key);
}
@@ -906,7 +906,7 @@ TEST_F(record_view_test, remove_all_overlapped) {
EXPECT_EQ(res.size(), 2);
- // TODO: Key order should be preserved by the server (IGNITE-16004).
+ // TODO: Key order should be preserved by the server (IGNITE-20435).
EXPECT_EQ(12, res[0].key);
EXPECT_EQ(11, res[1].key);
}
@@ -919,7 +919,7 @@ TEST_F(record_view_test, remove_all_empty) {
TEST_F(record_view_test, remove_all_exact_nonexisting) {
auto res = view.remove_all_exact(nullptr, {test_type(1, "foo"),
test_type(2, "bar")});
- // TODO: Key order should be preserved by the server (IGNITE-16004).
+ // TODO: Key order should be preserved by the server (IGNITE-20435).
ASSERT_EQ(2, res.size());
}
diff --git a/modules/platforms/cpp/tests/odbc-test/meta_queries_test.cpp
b/modules/platforms/cpp/tests/odbc-test/meta_queries_test.cpp
index 30dc1101ba..ed07bd9e5a 100644
--- a/modules/platforms/cpp/tests/odbc-test/meta_queries_test.cpp
+++ b/modules/platforms/cpp/tests/odbc-test/meta_queries_test.cpp
@@ -18,7 +18,6 @@
#include "odbc_connection.h"
#include "odbc_suite.h"
-#include "ignite/common/config.h"
#include "ignite/odbc/string_utils.h"
#include <gtest/gtest.h>
@@ -278,8 +277,6 @@ public:
}
};
-// TODO IGNITE-19216 Implement type info fetching
-#ifdef MUTED
TEST_F(meta_queries_test, test_get_type_info_all_types) {
odbc_connect(get_basic_connection_string());
@@ -287,8 +284,16 @@ TEST_F(meta_queries_test, test_get_type_info_all_types) {
if (!SQL_SUCCEEDED(ret))
FAIL() << (get_odbc_error_message(SQL_HANDLE_STMT, m_statement));
+
+ constexpr auto TYPES_NUM = 16;
+ for (int i = 0; i < TYPES_NUM; ++i) {
+ ret = SQLFetch(m_statement);
+ EXPECT_EQ(ret, SQL_SUCCESS) << "Index " << i;
+ }
+
+ ret = SQLFetch(m_statement);
+ EXPECT_EQ(ret, SQL_NO_DATA);
}
-#endif // MUTED
TEST_F(meta_queries_test, date_type_column_attribute_curdate) {
odbc_connect(get_basic_connection_string());
@@ -516,8 +521,6 @@ TEST_F(meta_queries_test,
col_attributes_column_scale_prepare) {
}
#endif // MUTED
-// TODO: IGNITE-19216 Implement type info query.
-#ifdef MUTED
TEST_F(meta_queries_test, get_data_with_get_type_info) {
odbc_connect(get_basic_connection_string());
@@ -528,7 +531,6 @@ TEST_F(meta_queries_test, get_data_with_get_type_info) {
check_single_row_result_set_with_get_data(m_statement);
}
-#endif // MUTED
TEST_F(meta_queries_test, get_data_with_tables) {
odbc_connect(get_basic_connection_string());
@@ -660,7 +662,7 @@ TEST_F(meta_queries_test, ddl_tables_meta_table_type_list) {
}
template<size_t n, size_t k>
-void check_meta(char columns[n][k], SQLLEN columns_len[n], std::string
table_name) {
+void check_meta(char columns[n][k], SQLLEN columns_len[n], const std::string
&table_name) {
std::string catalog(columns[0], columns_len[0]);
std::string schema(columns[1], columns_len[1]);
std::string table(columns[2], columns_len[2]);