This is an automated email from the ASF dual-hosted git repository. isapego pushed a commit to branch ignite-19216 in repository https://gitbox.apache.org/repos/asf/ignite-3.git
commit 88a3efe1d0961d174bff4143d677cbab0bb213bc Author: Igor Sapego <[email protected]> AuthorDate: Tue Sep 19 02:00:29 2023 +0400 IGNITE-19216 Ported type_info_query --- modules/platforms/cpp/ignite/odbc/CMakeLists.txt | 1 + modules/platforms/cpp/ignite/odbc/query/query.h | 3 + .../cpp/ignite/odbc/query/type_info_query.cpp | 380 +++++++++++++++++++++ .../odbc/query/{query.h => type_info_query.h} | 103 +++--- .../platforms/cpp/ignite/odbc/sql_statement.cpp | 11 +- 5 files changed, 433 insertions(+), 65 deletions(-) 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/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/type_info_query.cpp b/modules/platforms/cpp/ignite/odbc/query/type_info_query.cpp new file mode 100644 index 0000000000..2ac8611fb2 --- /dev/null +++ b/modules/platforms/cpp/ignite/odbc/query/type_info_query.cpp @@ -0,0 +1,380 @@ +/* + * 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/system/odbc_constants.h" +#include "ignite/odbc/type_traits.h" +#include "ignite/odbc/query/type_info_query.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.push_back(column_meta(sch, tbl, "TYPE_NAME", ignite_type::STRING)); + m_columns_meta.push_back(column_meta(sch, tbl, "DATA_TYPE", ignite_type::INT16)); + m_columns_meta.push_back(column_meta(sch, tbl, "COLUMN_SIZE", ignite_type::INT32)); + m_columns_meta.push_back(column_meta(sch, tbl, "LITERAL_PREFIX", ignite_type::STRING)); + m_columns_meta.push_back(column_meta(sch, tbl, "LITERAL_SUFFIX", ignite_type::STRING)); + m_columns_meta.push_back(column_meta(sch, tbl, "CREATE_PARAMS", ignite_type::STRING)); + m_columns_meta.push_back(column_meta(sch, tbl, "NULLABLE", ignite_type::INT16)); + m_columns_meta.push_back(column_meta(sch, tbl, "CASE_SENSITIVE", ignite_type::INT16)); + m_columns_meta.push_back(column_meta(sch, tbl, "SEARCHABLE", ignite_type::INT16)); + m_columns_meta.push_back(column_meta(sch, tbl, "UNSIGNED_ATTRIBUTE", ignite_type::INT16)); + m_columns_meta.push_back(column_meta(sch, tbl, "FIXED_PREC_SCALE", ignite_type::INT16)); + m_columns_meta.push_back(column_meta(sch, tbl, "AUTO_UNIQUE_VALUE", ignite_type::INT16)); + m_columns_meta.push_back(column_meta(sch, tbl, "LOCAL_TYPE_NAME", ignite_type::STRING)); + m_columns_meta.push_back(column_meta(sch, tbl, "MINIMUM_SCALE", ignite_type::INT16)); + m_columns_meta.push_back(column_meta(sch, tbl, "MAXIMUM_SCALE", ignite_type::INT16)); + m_columns_meta.push_back(column_meta(sch, tbl, "SQL_DATA_TYPE", ignite_type::INT16)); + m_columns_meta.push_back(column_meta(sch, tbl, "SQL_DATETIME_SUB", ignite_type::INT16)); + m_columns_meta.push_back(column_meta(sch, tbl, "NUM_PREC_RADIX", ignite_type::INT32)); + m_columns_meta.push_back(column_meta(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::STRING); + m_types.push_back(ignite_type::INT16); + m_types.push_back(ignite_type::INT32); + m_types.push_back(ignite_type::DECIMAL); + m_types.push_back(ignite_type::FLOAT); + m_types.push_back(ignite_type::DOUBLE); + m_types.push_back(ignite_type::BOOLEAN); + m_types.push_back(ignite_type::INT8); + m_types.push_back(ignite_type::INT64); + m_types.push_back(ignite_type::UUID); + m_types.push_back(ignite_type::BYTE_ARRAY); + } + 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; +} + +const column_meta_vector* type_info_query::get_meta() +{ + return &m_columns_meta; +} + +sql_result type_info_query::fetch_next_row(column_binding_map & columnBindings) +{ + if (!m_executed) + { + m_diag.add_status_record(sql_state::SHY010_SEQUENCE_ERROR, "Query was not m_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; + + column_binding_map::iterator it; + + for (it = columnBindings.begin(); it != columnBindings.end(); ++it) + get_column(it->first, it->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 m_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_column_size(current_type)); + + break; + } + + case result_column::LITERAL_PREFIX: + { + if (current_type == ignite_type::STRING) + buffer.put_string("'"); + else if (current_type == ignite_type::BYTE_ARRAY) + buffer.put_string("0x"); + else + buffer.put_null(); + + break; + } + + case result_column::LITERAL_SUFFIX: + { + if (current_type == ignite_type::STRING) + buffer.put_string("'"); + else + buffer.put_null(); + + break; + } + + case result_column::CREATE_PARAMS: + { + 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(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; +} + +bool type_info_query::is_data_available() const +{ + return m_cursor != m_types.end(); +} + +int64_t type_info_query::affected_rows() const +{ + return 0; +} + +sql_result type_info_query::next_result_set() +{ + return sql_result::AI_NO_DATA; +} + +} // 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 55% copy from modules/platforms/cpp/ignite/odbc/query/query.h copy to modules/platforms/cpp/ignite/odbc/query/type_info_query.h index 279c36184a..4cb75227ac 100644 --- a/modules/platforms/cpp/ignite/odbc/query/query.h +++ b/modules/platforms/cpp/ignite/odbc/query/type_info_query.h @@ -17,48 +17,49 @@ #pragma once -#include "ignite/odbc/common_types.h" -#include "ignite/odbc/diagnostic/diagnosable_adapter.h" -#include "ignite/odbc/meta/column_meta.h" +#include "ignite/odbc/query/query.h" -#include <cstdint> -#include <map> - -namespace ignite { - -/** Query type. */ -enum class query_type { - /** Data query type. */ - DATA, - - /** Table metadata. */ - TABLE_METADATA, -}; +namespace ignite +{ /** - * 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. + */ + virtual ~type_info_query() = default; /** * Execute query. * - * @return Execution result. + * @return True on success. + */ + virtual sql_result execute(); + + /** + * Get column metadata. + * + * @return Column metadata. */ - virtual sql_result execute() = 0; + virtual const column_meta_vector* get_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; + virtual sql_result fetch_next_row(column_binding_map& column_bindings); /** * Get data of the specified column in the result set. @@ -67,67 +68,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; + virtual sql_result get_column(std::uint16_t column_idx, application_data_buffer& buffer); /** * 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 ∅ - } + virtual sql_result close(); /** * Check if data is available. * * @return True if data is available. */ - [[nodiscard]] virtual bool is_data_available() const = 0; + virtual bool is_data_available() const; /** * 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; + virtual std::int64_t affected_rows() const; /** * Move to the next result set. * * @return Operation result. */ - virtual sql_result next_result_set() = 0; + virtual sql_result next_result_set(); - /** - * 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..690030af47 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) {
