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 82d46f420f IGNITE-20346 ODBC: Implement column metadata fetching
(#2650)
82d46f420f is described below
commit 82d46f420f98665191110aefd0add421bddec161
Author: Igor Sapego <[email protected]>
AuthorDate: Tue Oct 3 14:26:08 2023 +0400
IGNITE-20346 ODBC: Implement column metadata fetching (#2650)
---
modules/platforms/cpp/CMakeLists.txt | 1 -
modules/platforms/cpp/DEVNOTES.md | 143 +++++----
modules/platforms/cpp/ignite/odbc/CMakeLists.txt | 1 +
.../cpp/ignite/odbc/app/application_data_buffer.h | 18 ++
.../ignite/odbc/query/column_metadata_query.cpp | 324 +++++++++++++++++++++
.../cpp/ignite/odbc/query/column_metadata_query.h | 185 ++++++++++++
modules/platforms/cpp/ignite/odbc/query/query.h | 3 +
.../cpp/ignite/odbc/query/type_info_query.cpp | 2 +-
.../platforms/cpp/ignite/odbc/sql_statement.cpp | 11 +-
modules/platforms/cpp/ignite/odbc/type_traits.cpp | 41 ++-
modules/platforms/cpp/ignite/odbc/type_traits.h | 36 +--
.../cpp/ignite/protocol/client_operation.h | 3 +
.../cpp/tests/odbc-test/api_robustness_test.cpp | 18 +-
.../cpp/tests/odbc-test/meta_queries_test.cpp | 34 +--
14 files changed, 705 insertions(+), 115 deletions(-)
diff --git a/modules/platforms/cpp/CMakeLists.txt
b/modules/platforms/cpp/CMakeLists.txt
index 2d75fcb554..fac1523dcf 100644
--- a/modules/platforms/cpp/CMakeLists.txt
+++ b/modules/platforms/cpp/CMakeLists.txt
@@ -26,7 +26,6 @@ set(CMAKE_PROJECT_VERSION ${PROJECT_VERSION})
option(ENABLE_CONAN "Use Conan package manager to get dependencies" ON)
option(ENABLE_CLIENT "Build Ignite.C++ Client module" ON)
option(ENABLE_ODBC "Build Ignite ODBC driver module" OFF)
-option(ENABLE_ODBC_MSI "Build Ignite ODBC driver installer for Windows" OFF)
option(ENABLE_TESTS "Build Ignite.C++ tests" OFF)
option(ENABLE_ADDRESS_SANITIZER "If address sanitizer is enabled" OFF)
option(ENABLE_UB_SANITIZER "If undefined behavior sanitizer is enabled" OFF)
diff --git a/modules/platforms/cpp/DEVNOTES.md
b/modules/platforms/cpp/DEVNOTES.md
index a81bef9d4f..39a267ed72 100644
--- a/modules/platforms/cpp/DEVNOTES.md
+++ b/modules/platforms/cpp/DEVNOTES.md
@@ -1,16 +1,18 @@
## Build C++
### Prerequisites
-* C++ compiler supporting C++17
-* One of build systems: make, ninja, MS Visual Studio, etc
-* Conan C/C++ package manager 1.X (optional)
-* CMake 3.10+
+* C++ compiler supporting C++17;
+* One of build systems: make, ninja, MS Visual Studio, etc;
+* Conan C/C++ package manager 1.X (optional);
+* CMake 3.10+;
+* To build the ODBC driver, it is required to have an ODBC driver manager with
headers on your system. On Windows, it
+ comes with your OS, but on Unix-like systems you may need to install one,
for example, unixODBC;
### Installing Conan Package Manager
The Conan package manager can be obtained from [its website](https://conan.io).
-Currently we support Conan versions 1.X. The version 2.0+ is **not** supported
yet.
+Currently, we support Conan versions 1.X. The version 2.0+ is **not**
supported yet.
One way to install Conan is as follows (need python in your system):
@@ -18,7 +20,7 @@ One way to install Conan is as follows (need python in your
system):
pip install conan==1.59.0
```
-Also before use it might be required to configure the default conan profile:
+Also, before use, it might be required to configure the default conan profile:
```
conan profile new --detect default
@@ -29,10 +31,8 @@ conan profile update settings.compiler.libcxx=libstdc++11
default
It is possible to build the project without Conan if all the dependencies are
installed on the system manually.
The project dependencies include the following libraries:
-
- - msgpack-c 4.0.0
- - gtest 1.12.1
- - unixodbc
+- msgpack-c 4.0.0
+- gtest 1.12.1
When the project is configured with the `-DENABLE_CONAN=OFF` CMake option, the
Conan machinery is turned off and
the dependencies are resolved by using the standard means of the build
platform. For example, the project can be
@@ -40,100 +40,143 @@ configured like this:
```shell
...
-cmake .. -DENABLE_CONAN=0 -DCMAKE_BUILD_TYPE=Release
+cmake .. -DENABLE_CONAN=OFF -DCMAKE_BUILD_TYPE=Release
...
```
-However Conan is enabled by default and so all the build examples below use it.
+However, Conan is enabled by default, and so all the build examples below use
it.
-### Linux Build
+### CMake options and examples of typical build configurations
-#### Building in debug mode with tests
+There are multiple configuration options supported by the CMake project that
can be used to choose what exactly and how
+should be built. You can check the whole list of available cmake options with
the command `cmake -LAH`. Below, you can
+see project-specific options only:
+- ENABLE_CONAN={ON|OFF}. ON by default. The effect of this exact option is
described in a section above;
+- ENABLE_CLIENT={ON|OFF}. ON by default. Indicates whether the C++ client
should be built;
+- ENABLE_ODBC={ON|OFF}. OFF by default. Indicates whether the ODBC driver
should be built;
+- ENABLE_TESTS={ON|OFF}. OFF by default. Indicates whether the tests for the
selected components should be built;
+- WARNINGS_AS_ERRORS={ON|OFF}. OFF by default. If enabled, compiler will treat
warnings as errors. It may be a good idea
+ to enable this option if you are planning on submitting a PR, but if you
just want to build a project just keep it
+ disabled;
-In this dir:
+There are also general CMake options that you should specify. They are build
type options. There are two types of build
+available - `Release` and `Debug`. The choice here depends on how are you
going to use resulting artifacts. If you are
+going to use them in production, it is probably a good idea to use `Release`
build type. If you are just an Ignite
+developer or planning to submit a patch for the project, use Debug.
+
+You should ALWAYS specify a build type.
+
+There are two options for this:
+- CMAKE_BUILD_TYPE={Debug|Release}. Used on single-configuration generators,
like Unix Makefile generator or Ninja. This
+ is a parameter that you should most likely use if you are using Unix-like OS;
+- CMAKE_CONFIGURATION_TYPES={Debug|Release}. Used on multi-configuration
generators like Visual Studio. If you are using
+ Visual Studio generator, you should specify this option, as it ignores
CMAKE_BUILD_TYPE.
+
+So, basically, if you are an Apache Ignite developer, you would want to
configure your project like this:
```shell
-mkdir cmake-build-debug
-cd cmake-build-debug
-cmake .. -DENABLE_TESTS=ON -DENABLE_ODBC=OFF -DCMAKE_BUILD_TYPE=Debug
-cmake --build . -j8
+cmake .. -DENABLE_ODBC=ON -DENABLE_TESTS=ON -DWARNINGS_AS_ERRORS=ON
-DCMAKE_BUILD_TYPE=Debug
```
-#### Building in release mode without tests
+But if you just want to compile the client to use in your project, the
following configuration is more fitting for you,
+considering default options:
-In this dir:
+```shell
+cmake .. -DCMAKE_BUILD_TYPE=Release
+```
+
+If you don't need the client and just want to compile the ODBC driver, just
add the following options:
```shell
-mkdir cmake-build-release
-cd cmake-build-release
-cmake .. -DENABLE_TESTS=OFF -DENABLE_ODBC=OFF -DCMAKE_BUILD_TYPE=Release
-cmake --build . -j8
+cmake .. -DENABLE_CLIENT=OFF -DENABLE_ODBC=ON -DCMAKE_BUILD_TYPE=Release
```
-### MacOS Build
+And do not forget to replace `CMAKE_BUILD_TYPE` with
`CMAKE_CONFIGURATION_TYPES` if you are using Visual Studio
+generator:
-On macOS it is typically required to use the C++ standard library from the
LLVM project:
+```shell
+cmake .. -DCMAKE_CONFIGURATION_TYPES=Release
+```
+
+Below, you can find more detailed line-by-line instructions and configurations
for different platforms and use-cases.
+
+
+### Linux and macOS Builds
+
+On macOS, it is typically required to specify the C++ standard library from
the LLVM project if you are using Conan:
```
conan profile update settings.compiler.libcxx=libc++11 default
```
-#### Building in debug mode with tests.
+#### Building in debug mode with tests and ODBC
In this dir:
```shell
mkdir cmake-build-debug
cd cmake-build-debug
-cmake .. -DENABLE_TESTS=ON -DENABLE_ODBC=OFF -DCMAKE_BUILD_TYPE=Debug
-cmake --build . -j8
+cmake .. -DENABLE_TESTS=ON -DENABLE_ODBC=ON -DCMAKE_BUILD_TYPE=Debug
+cmake --build .
+```
+
+#### Building only the client in release mode
+
+In this dir:
+
+```shell
+mkdir cmake-build-release
+cd cmake-build-release
+cmake .. -DCMAKE_BUILD_TYPE=Release
+cmake --build .
```
-#### Building in release mode without tests.
+#### Building only the ODBC driver in release mode
In this dir:
```shell
mkdir cmake-build-release
cd cmake-build-release
-cmake .. -DENABLE_TESTS=OFF -DENABLE_ODBC=OFF -DCMAKE_BUILD_TYPE=Release
-cmake --build . -j8
+cmake .. -DENABLE_CLIENT=OFF -DENABLE_ODBC=ON -DCMAKE_BUILD_TYPE=Release
+cmake --build .
```
### Windows Build
-#### Building in debug mode with tests
+#### Building in debug mode with tests and ODBC using single-config generator
-In this dir (using the ninja build system, other single-config systems can be
used too):
+In this dir (using Ninja, but any other single-config generator can be used):
```shell
mkdir cmake-build-debug
cd cmake-build-debug
-cmake .. -DENABLE_TESTS=ON -DENABLE_ODBC=OFF -DCMAKE_BUILD_TYPE=Debug -GNinja
-cmake --build . -j8
+cmake .. -DENABLE_TESTS=ON -DENABLE_ODBC=ON -DCMAKE_BUILD_TYPE=Debug -GNinja
+cmake --build .
```
-#### Building in release mode without tests
+#### Building only the client in release mode using single-config generator
-In this dir (using the ninja build system, other single-config systems can be
used too):
+In this dir (using Ninja, but any other single-config generator can be used):
```shell
mkdir cmake-build-release
cd cmake-build-release
-cmake .. -DENABLE_TESTS=OFF -DENABLE_ODBC=OFF -DCMAKE_BUILD_TYPE=Release
-GNinja
-cmake --build . -j8
+cmake .. -DCMAKE_BUILD_TYPE=Release -GNinja
+cmake --build .
```
#### Building with Visual Studio in multi-config mode
Run in this dir from, for example, [VS developer
PowerShell](https://learn.microsoft.com/en-us/visualstudio/ide/reference/command-prompt-powershell?view=vs-2022):
+We are using Visual Studio 17 2022 in this example, but any other multi-config
generator can be used.
```shell
mkdir cmake-build
cd cmake-build
-cmake .. -DENABLE_TESTS=ON
-cmake --build . --config Debug -j8
-cmake --build . --config Release -j8
+cmake .. -DENABLE_TESTS=ON -DENABLE_ODBC=ON
-DCMAKE_CONFIGURATION_TYPES="Debug;Release" -G "Visual Studio 17 2022"
+cmake --build . --config Debug
+cmake --build . --config Release
```
## Run Tests
@@ -144,29 +187,29 @@ cmake --build . --config Release -j8
### Starting Java Test Node
-Tests require a running Java node. You don't need to start it separately, if
there is no running test nodes, tests will
-start one internally. So prior to running tests you will obviously need to
build a Java part of the product. To do that
-the following command can be used from the root of the repo:
+Tests require a running Java node. You don't need to start it separately, if
there are no running test nodes, tests will
+start one internally. So prior to running tests, you will obviously need to
build a Java part of the product. To do
+that, the following command can be used from the root of the repo:
`./gradlew assemble compileIntegrationTestJava`
Or a faster variant:
`./gradlew assemble compileIntegrationTestJava -x check -x assembleDist -x
distTar -x distZip --parallel`
You can start a Test Node separately in the root repo. Tests will detect that
there is a running node and will not start
-another one. This can be useful for debugging. To start node from the console
you can use the following command prompt:
+another one. This can be useful for debugging. To start node from the console,
you can use the following command prompt:
`./gradlew :ignite-runner:runnerPlatformTest --no-daemon`
You can also run
`org.apache.ignite.internal.runner.app.PlatformTestNodeRunner` class in IDEA
with a debugger or
profiler, then run Client tests as usual.
-### Starting tests in Windows
+### Starting tests on Windows
In modules/platforms/cpp dir:
`./cmake-build-debug/bin/ignite-client-test.exe`
To run a specific test:
`./cmake-build-debug/bin/ignite-client-test.exe --gtest_filter=Test_Cases1*`
-### Starting tests in Linux
+### Starting tests on Linux
In modules/platforms/cpp dir:
`./cmake-build-debug/bin/ignite-client-test`
diff --git a/modules/platforms/cpp/ignite/odbc/CMakeLists.txt
b/modules/platforms/cpp/ignite/odbc/CMakeLists.txt
index ea20e78785..309ee4ce75 100644
--- a/modules/platforms/cpp/ignite/odbc/CMakeLists.txt
+++ b/modules/platforms/cpp/ignite/odbc/CMakeLists.txt
@@ -35,6 +35,7 @@ set(SOURCES
diagnostic/diagnostic_record_storage.cpp
meta/column_meta.cpp
meta/table_meta.cpp
+ query/column_metadata_query.cpp
query/data_query.cpp
query/table_metadata_query.cpp
query/type_info_query.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 fd7ea6ee8d..96b4b57b12 100644
--- a/modules/platforms/cpp/ignite/odbc/app/application_data_buffer.h
+++ b/modules/platforms/cpp/ignite/odbc/app/application_data_buffer.h
@@ -150,6 +150,24 @@ public:
*/
conversion_result put_bool(bool value);
+ /**
+ * Put in buffer value of type string.
+ *
+ * @param value Value.
+ * @return Conversion result.
+ */
+ conversion_result put_string(const std::optional<std::string> &value) {
+ return value ? put_string(*value) : put_null();
+ }
+
+ /**
+ * Put in buffer value of type string.
+ *
+ * @param value Value.
+ * @return Conversion result.
+ */
+ conversion_result put_string(const char *value) { return
put_string(std::string(value)); }
+
/**
* Put in buffer value of type string.
*
diff --git a/modules/platforms/cpp/ignite/odbc/query/column_metadata_query.cpp
b/modules/platforms/cpp/ignite/odbc/query/column_metadata_query.cpp
new file mode 100644
index 0000000000..fb31c62911
--- /dev/null
+++ b/modules/platforms/cpp/ignite/odbc/query/column_metadata_query.cpp
@@ -0,0 +1,324 @@
+/*
+ * 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 <utility>
+
+#include "ignite/odbc/log.h"
+#include "ignite/odbc/odbc_error.h"
+#include "ignite/odbc/query/column_metadata_query.h"
+#include "ignite/odbc/sql_connection.h"
+#include "ignite/odbc/type_traits.h"
+
+namespace {
+
+enum class result_column {
+ /** Catalog name. NULL if not applicable to the data source. */
+ TABLE_CAT = 1,
+
+ /** Schema name. NULL if not applicable to the data source. */
+ TABLE_SCHEM,
+
+ /** Table name. */
+ TABLE_NAME,
+
+ /** Column name. */
+ COLUMN_NAME,
+
+ /** SQL data type. */
+ DATA_TYPE,
+
+ /** Data source-dependent data type name. */
+ TYPE_NAME,
+
+ /** Column size. */
+ COLUMN_SIZE,
+
+ /** The length in bytes of data transferred on fetch. */
+ BUFFER_LENGTH,
+
+ /** The total number of significant digits to the right of the decimal
point. */
+ DECIMAL_DIGITS,
+
+ /** Precision. */
+ NUM_PREC_RADIX,
+
+ /** Nullability of the data in column. */
+ NULLABLE,
+
+ /** A description of the column. */
+ REMARKS
+};
+
+using namespace ignite;
+
+/**
+ * Reads result set metadata.
+ *
+ * @param reader Reader.
+ * @return Result set meta columns.
+ */
+std::vector<odbc_column_meta> read_meta(protocol::reader &reader) {
+ auto size = reader.read_int32();
+
+ std::vector<odbc_column_meta> columns;
+ columns.reserve(size);
+
+ for (std::int32_t column_idx = 0; column_idx < size; ++column_idx) {
+ auto has_data = reader.read_bool();
+ assert(has_data);
+
+ auto status = reader.read_int32();
+ assert(status == 0);
+
+ auto err_msg = reader.read_string_nullable();
+ assert(!err_msg);
+
+ odbc_column_meta column{};
+ column.label = reader.read_string();
+ column.schema = reader.read_string_nullable();
+ column.table = reader.read_string_nullable();
+ column.column = reader.read_string_nullable();
+
+ column.data_type = ignite_type(reader.read_int32());
+ column.data_type_name = reader.read_string();
+ reader.skip(); // data_type_class
+ column.nullable = reader.read_bool();
+ column.precision = reader.read_int32();
+ column.scale = reader.read_int32();
+
+ columns.emplace_back(std::move(column));
+ }
+
+ return columns;
+}
+
+} // anonymous namespace
+
+namespace ignite {
+
+column_metadata_query::column_metadata_query(
+ diagnosable_adapter &diag, sql_connection &connection, std::string schema,
std::string table, std::string column)
+ : query(diag, query_type::COLUMN_METADATA)
+ , m_connection(connection)
+ , m_schema(std::move(schema))
+ , m_table(std::move(table))
+ , m_column(std::move(column)) {
+ m_columns_meta.reserve(12);
+
+ const std::string sch;
+ const std::string tbl;
+
+ m_columns_meta.emplace_back(sch, tbl, "TABLE_CAT", ignite_type::STRING);
+ m_columns_meta.emplace_back(sch, tbl, "TABLE_SCHEM", ignite_type::STRING);
+ m_columns_meta.emplace_back(sch, tbl, "TABLE_NAME", ignite_type::STRING);
+ m_columns_meta.emplace_back(sch, tbl, "COLUMN_NAME", ignite_type::STRING);
+ m_columns_meta.emplace_back(sch, tbl, "DATA_TYPE", ignite_type::INT16);
+ m_columns_meta.emplace_back(sch, tbl, "TYPE_NAME", ignite_type::STRING);
+ m_columns_meta.emplace_back(sch, tbl, "COLUMN_SIZE", ignite_type::INT32);
+ m_columns_meta.emplace_back(sch, tbl, "BUFFER_LENGTH", ignite_type::INT32);
+ m_columns_meta.emplace_back(sch, tbl, "DECIMAL_DIGITS",
ignite_type::INT16);
+ m_columns_meta.emplace_back(sch, tbl, "NUM_PREC_RADIX",
ignite_type::INT16);
+ m_columns_meta.emplace_back(sch, tbl, "NULLABLE", ignite_type::INT16);
+ m_columns_meta.emplace_back(sch, tbl, "REMARKS", ignite_type::STRING);
+}
+
+sql_result column_metadata_query::execute() {
+ if (m_executed)
+ close();
+
+ sql_result result = make_request_get_columns_meta();
+
+ if (result == sql_result::AI_SUCCESS) {
+ m_executed = true;
+ m_fetched = false;
+
+ m_cursor = m_meta.begin();
+ }
+
+ return result;
+}
+
+sql_result column_metadata_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_meta.end())
+ return sql_result::AI_NO_DATA;
+
+ column_binding_map::iterator it;
+
+ for (it = column_bindings.begin(); it != column_bindings.end(); ++it)
+ get_column(it->first, it->second);
+
+ return sql_result::AI_SUCCESS;
+}
+
+sql_result column_metadata_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_meta.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;
+ }
+
+ const auto ¤t_column = *m_cursor;
+ switch (result_column(column_idx)) {
+ case result_column::TABLE_CAT: {
+ buffer.put_null();
+ break;
+ }
+
+ case result_column::TABLE_SCHEM: {
+ buffer.put_string(current_column.schema);
+ break;
+ }
+
+ case result_column::TABLE_NAME: {
+ buffer.put_string(current_column.table);
+ break;
+ }
+
+ case result_column::COLUMN_NAME: {
+ buffer.put_string(current_column.column);
+ break;
+ }
+
+ case result_column::DATA_TYPE: {
+
buffer.put_int16(ignite_type_to_sql_type(current_column.data_type));
+ break;
+ }
+
+ case result_column::TYPE_NAME: {
+ buffer.put_string(current_column.data_type_name);
+ break;
+ }
+
+ case result_column::COLUMN_SIZE: {
+ if (current_column.data_type == ignite_type::DECIMAL ||
current_column.data_type == ignite_type::NUMBER) {
+ buffer.put_int16(std::int16_t(current_column.precision));
+ break;
+ }
+
+ std::int32_t column_size =
ignite_type_max_column_size(current_column.data_type);
+ if (column_size < 0)
+ buffer.put_null();
+ else
+ buffer.put_int32(column_size);
+ break;
+ }
+
+ case result_column::BUFFER_LENGTH: {
+ buffer.put_null();
+ break;
+ }
+
+ case result_column::DECIMAL_DIGITS: {
+ std::int32_t dec_digits =
ignite_type_decimal_digits(current_column.data_type, current_column.scale);
+ if (dec_digits < 0)
+ buffer.put_null();
+ else
+ buffer.put_int16(std::int16_t(dec_digits));
+ break;
+ }
+
+ case result_column::NUM_PREC_RADIX: {
+ auto radix =
std::int16_t(ignite_type_num_precision_radix(current_column.data_type));
+ if (radix)
+ buffer.put_int16(radix);
+ else
+ buffer.put_null();
+ break;
+ }
+
+ case result_column::NULLABLE: {
+ buffer.put_int16(std::int16_t(current_column.nullable ?
SQL_NULLABLE : SQL_NO_NULLS));
+ break;
+ }
+
+ case result_column::REMARKS: {
+ buffer.put_string(current_column.label);
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ return sql_result::AI_SUCCESS;
+}
+
+sql_result column_metadata_query::close() {
+ m_meta.clear();
+
+ m_executed = false;
+
+ return sql_result::AI_SUCCESS;
+}
+
+sql_result column_metadata_query::make_request_get_columns_meta() {
+ auto success = m_diag.catch_errors([&] {
+ auto response =
+
m_connection.sync_request(protocol::client_operation::JDBC_COLUMN_META,
[&](protocol::writer &writer) {
+ writer.write(m_schema);
+ writer.write(m_table);
+ writer.write(m_column);
+ });
+
+ protocol::reader reader{response.get_bytes_view()};
+ m_has_result_set = reader.read_bool();
+
+ auto status = reader.read_int32();
+ auto err_msg = reader.read_string_nullable();
+ if (err_msg)
+ throw odbc_error(response_status_to_sql_state(status), *err_msg);
+
+ if (m_has_result_set) {
+ m_meta = read_meta(reader);
+ }
+
+ m_executed = true;
+ });
+
+ if (!success)
+ return sql_result::AI_ERROR;
+
+ size_t i = 0;
+ for (const auto &meta : m_meta) {
+ LOG_MSG("\n[" << i << "] SchemaName: " << (meta.schema ?
*meta.schema : "NULL") << "\n[" << i
+ << "] TableName: " << (meta.table ? *meta.table :
"NULL") << "\n[" << i
+ << "] ColumnName: " << (meta.column ? *meta.column :
"NULL") << "\n[" << i
+ << "] ColumnType: " <<
static_cast<std::int32_t>(meta.data_type));
+ ++i;
+ }
+
+ return sql_result::AI_SUCCESS;
+}
+
+} // namespace ignite
diff --git a/modules/platforms/cpp/ignite/odbc/query/column_metadata_query.h
b/modules/platforms/cpp/ignite/odbc/query/column_metadata_query.h
new file mode 100644
index 0000000000..50dab7ac62
--- /dev/null
+++ b/modules/platforms/cpp/ignite/odbc/query/column_metadata_query.h
@@ -0,0 +1,185 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "ignite/odbc/meta/column_meta.h"
+#include "ignite/odbc/query/query.h"
+
+namespace ignite {
+
+/** Connection forward-declaration. */
+class sql_connection;
+
+/**
+ * Column metadata.
+ */
+struct odbc_column_meta {
+ /**
+ * Default constructor.
+ */
+ odbc_column_meta() = default;
+
+ /** Label. */
+ std::string label;
+
+ /** Schema name. */
+ std::optional<std::string> schema;
+
+ /** Table name. */
+ std::optional<std::string> table;
+
+ /** Column name. */
+ std::optional<std::string> column;
+
+ /** Data type. */
+ ignite_type data_type{ignite_type::UNDEFINED};
+
+ /** Data type name. */
+ std::string data_type_name;
+
+ /** Nullability. */
+ bool nullable{false};
+
+ /** Precision. */
+ std::int32_t precision{0};
+
+ /** Scale. */
+ std::int32_t scale{0};
+};
+
+/**
+ * Query.
+ */
+class column_metadata_query : public query {
+public:
+ /**
+ * Constructor.
+ *
+ * @param diag Diagnostics collector.
+ * @param connection Associated connection.
+ * @param schema Schema search pattern.
+ * @param table Table search pattern.
+ * @param column Column search pattern.
+ */
+ column_metadata_query(diagnosable_adapter &diag, sql_connection
&connection, std::string schema, std::string table,
+ std::string column);
+
+ /**
+ * Destructor.
+ */
+ ~column_metadata_query() override = default;
+
+ /**
+ * Execute query.
+ *
+ * @return True on success.
+ */
+ sql_result execute() override;
+
+ /**
+ * Get column metadata.
+ *
+ * @return Column metadata.
+ */
+ const column_meta_vector *get_meta() override { return &m_columns_meta; }
+
+ /**
+ * Fetch next result row to application buffers.
+ *
+ * @param column_bindings Column bindings.
+ * @return Operation result.
+ */
+ sql_result fetch_next_row(column_binding_map &column_bindings) override;
+
+ /**
+ * Get data of the specified column in the result set.
+ *
+ * @param column_idx Column index.
+ * @param buffer Buffer to put column data to.
+ * @return Operation result.
+ */
+ sql_result get_column(std::uint16_t column_idx, application_data_buffer
&buffer) override;
+
+ /**
+ * Close query.
+ *
+ * @return True on success.
+ */
+ sql_result close() override;
+
+ /**
+ * Check if data is available.
+ *
+ * @return True if data is available.
+ */
+ bool is_data_available() const override { return m_cursor != m_meta.end();
}
+
+ /**
+ * Get number of rows affected by the statement.
+ *
+ * @return Number of rows affected by the statement.
+ */
+ std::int64_t affected_rows() const override { return 0; }
+
+ /**
+ * Move to the next result set.
+ *
+ * @return Operation result.
+ */
+ sql_result next_result_set() override { return sql_result::AI_NO_DATA; }
+
+private:
+ /**
+ * Make get columns metadata requests and use response to set internal
state.
+ *
+ * @return Operation result.
+ */
+ sql_result make_request_get_columns_meta();
+
+ /** Connection associated with the statement. */
+ sql_connection &m_connection;
+
+ /** Schema search pattern. */
+ std::string m_schema;
+
+ /** Table search pattern. */
+ std::string m_table;
+
+ /** Column search pattern. */
+ std::string m_column;
+
+ /** Query executed. */
+ bool m_executed{false};
+
+ /** Fetched flag. */
+ bool m_fetched{false};
+
+ /** Result set flag. */
+ bool m_has_result_set{false};
+
+ /** Fetched metadata. */
+ std::vector<odbc_column_meta> m_meta;
+
+ /** Metadata cursor. */
+ std::vector<odbc_column_meta>::iterator m_cursor;
+
+ /** Columns metadata. */
+ column_meta_vector m_columns_meta;
+};
+
+} // namespace ignite
diff --git a/modules/platforms/cpp/ignite/odbc/query/query.h
b/modules/platforms/cpp/ignite/odbc/query/query.h
index ce596eff70..49fe78d270 100644
--- a/modules/platforms/cpp/ignite/odbc/query/query.h
+++ b/modules/platforms/cpp/ignite/odbc/query/query.h
@@ -34,6 +34,9 @@ enum class query_type {
/** Table metadata. */
TABLE_METADATA,
+ /** Column metadata. */
+ COLUMN_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
index 0fb7fe3677..b428055385 100644
--- a/modules/platforms/cpp/ignite/odbc/query/type_info_query.cpp
+++ b/modules/platforms/cpp/ignite/odbc/query/type_info_query.cpp
@@ -293,7 +293,7 @@ sql_result type_info_query::get_column(std::uint16_t
column_idx, application_dat
case result_column::MINIMUM_SCALE:
case result_column::MAXIMUM_SCALE: {
-
buffer.put_int16(std::int16_t(ignite_type_decimal_digits(current_type)));
+
buffer.put_int16(std::int16_t(ignite_type_decimal_digits(current_type, -1)));
break;
}
diff --git a/modules/platforms/cpp/ignite/odbc/sql_statement.cpp
b/modules/platforms/cpp/ignite/odbc/sql_statement.cpp
index e29512ae98..4a3284de49 100644
--- a/modules/platforms/cpp/ignite/odbc/sql_statement.cpp
+++ b/modules/platforms/cpp/ignite/odbc/sql_statement.cpp
@@ -19,6 +19,7 @@
#include "ignite/odbc/log.h"
#include "ignite/odbc/odbc_error.h"
+#include "ignite/odbc/query/column_metadata_query.h"
#include "ignite/odbc/query/data_query.h"
#include "ignite/odbc/query/table_metadata_query.h"
#include "ignite/odbc/query/type_info_query.h"
@@ -554,16 +555,12 @@ void sql_statement::execute_get_columns_meta_query(
sql_result sql_statement::internal_execute_get_columns_meta_query(
const std::string &schema, const std::string &table, const std::string
&column) {
- UNUSED_VALUE schema;
- UNUSED_VALUE table;
- UNUSED_VALUE column;
if (m_current_query)
m_current_query->close();
- // TODO: IGNITE-20346 Implement table column metadata fetching
- add_status_record(sql_state::SHYC00_OPTIONAL_FEATURE_NOT_IMPLEMENTED,
"Column metadata is not supported.");
- return sql_result::AI_ERROR;
+ m_current_query = std::make_unique<column_metadata_query>(*this,
m_connection, schema, table, column);
+ return m_current_query->execute();
}
void sql_statement::execute_get_tables_meta_query(
@@ -1013,7 +1010,7 @@ sql_result sql_statement::internal_describe_param(
// TODO: IGNITE-19854 Implement meta fetching for a parameter
if (decimal_digits)
- *decimal_digits = int16_t(ignite_type_decimal_digits(type));
+ *decimal_digits = int16_t(ignite_type_decimal_digits(type, -1));
// TODO: IGNITE-19854 Implement meta fetching for a parameter
if (nullable)
diff --git a/modules/platforms/cpp/ignite/odbc/type_traits.cpp
b/modules/platforms/cpp/ignite/odbc/type_traits.cpp
index bdafc1c767..7e41d42387 100644
--- a/modules/platforms/cpp/ignite/odbc/type_traits.cpp
+++ b/modules/platforms/cpp/ignite/odbc/type_traits.cpp
@@ -596,16 +596,47 @@ std::int32_t ignite_type_num_precision_radix(ignite_type
typ) {
return sql_type_num_precision_radix(sql_type);
}
-std::int32_t sql_type_decimal_digits(std::int16_t) {
- // TODO: IGNITE-19854 Remove once parameters meta fetching is implemented
+std::int32_t sql_type_decimal_digits(std::int16_t type, std::int32_t scale) {
+ switch (type) {
+ case SQL_BIT:
+ case SQL_TINYINT:
+ case SQL_SMALLINT:
+ case SQL_INTEGER:
+ case SQL_BIGINT:
+ case SQL_REAL:
+ case SQL_FLOAT:
+ case SQL_DOUBLE:
+ return sql_type_column_size(type);
+
+ case SQL_TYPE_TIME:
+ case SQL_TYPE_TIMESTAMP:
+ return 9;
+
+ case SQL_DECIMAL:
+ case SQL_NUMERIC:
+ if (scale >= 0)
+ return scale;
+ break;
+
+ case SQL_GUID:
+ case SQL_TYPE_DATE:
+ case SQL_VARCHAR:
+ case SQL_CHAR:
+ case SQL_WCHAR:
+ case SQL_LONGVARBINARY:
+ case SQL_BINARY:
+ case SQL_VARBINARY:
+ case SQL_LONGVARCHAR:
+ default:
+ break;
+ }
return -1;
}
-std::int32_t ignite_type_decimal_digits(ignite_type typ) {
- // TODO: IGNITE-19854 Remove once parameters meta fetching is implemented
+std::int32_t ignite_type_decimal_digits(ignite_type typ, std::int32_t scale) {
std::int16_t sql_type = ignite_type_to_sql_type(typ);
- return sql_type_decimal_digits(sql_type);
+ return sql_type_decimal_digits(sql_type, scale);
}
bool is_sql_type_unsigned(std::int16_t type) {
diff --git a/modules/platforms/cpp/ignite/odbc/type_traits.h
b/modules/platforms/cpp/ignite/odbc/type_traits.h
index aa9b65cc7b..04e83e8564 100644
--- a/modules/platforms/cpp/ignite/odbc/type_traits.h
+++ b/modules/platforms/cpp/ignite/odbc/type_traits.h
@@ -123,7 +123,7 @@ const std::string &ignite_type_to_sql_type_name(ignite_type
typ);
* @param type Application type.
* @return True if the type is supported.
*/
-bool is_sql_type_supported(int16_t type);
+bool is_sql_type_supported(std::int16_t type);
/**
* Get corresponding binary type for ODBC SQL type.
@@ -131,7 +131,7 @@ bool is_sql_type_supported(int16_t type);
* @param sql_type SQL type.
* @return Binary type.
*/
-ignite_type sql_type_to_ignite_type(int16_t sql_type);
+ignite_type sql_type_to_ignite_type(std::int16_t sql_type);
/**
* Convert ODBC type to driver type alias.
@@ -139,7 +139,7 @@ ignite_type sql_type_to_ignite_type(int16_t sql_type);
* @param type ODBC type;
* @return Internal driver type.
*/
-odbc_native_type to_driver_type(int16_t type);
+odbc_native_type to_driver_type(std::int16_t type);
/**
* Convert Ignite data type to SQL data type.
@@ -147,7 +147,7 @@ odbc_native_type to_driver_type(int16_t type);
* @param typ Data type.
* @return SQL data type.
*/
-int16_t ignite_type_to_sql_type(ignite_type typ);
+std::int16_t ignite_type_to_sql_type(ignite_type typ);
/**
* Get Ignite type SQL nullability.
@@ -158,7 +158,7 @@ int16_t ignite_type_to_sql_type(ignite_type typ);
* SQL_NULLABLE_UNKNOWN if it is not known whether the
* column accepts NULL values.
*/
-int16_t ignite_type_nullability(ignite_type typ);
+std::int16_t ignite_type_nullability(ignite_type typ);
/**
* Get SQL type display size.
@@ -166,7 +166,7 @@ int16_t ignite_type_nullability(ignite_type typ);
* @param type SQL type.
* @return Display size.
*/
-int32_t sql_type_display_size(int16_t type);
+std::int32_t sql_type_display_size(std::int16_t type);
/**
* Get Ignite type display size.
@@ -174,7 +174,7 @@ int32_t sql_type_display_size(int16_t type);
* @param typ Ignite type.
* @return Display size.
*/
-int32_t ignite_type_display_size(ignite_type typ);
+std::int32_t ignite_type_display_size(ignite_type typ);
/**
* Get SQL type column size.
@@ -182,7 +182,7 @@ int32_t ignite_type_display_size(ignite_type typ);
* @param type SQL type.
* @return Column size.
*/
-int32_t sql_type_column_size(int16_t type);
+std::int32_t sql_type_column_size(std::int16_t type);
/**
* Get Ignite type column size.
@@ -190,7 +190,7 @@ int32_t sql_type_column_size(int16_t type);
* @param typ Ignite type.
* @return Column size.
*/
-int32_t ignite_type_max_column_size(ignite_type typ);
+std::int32_t ignite_type_max_column_size(ignite_type typ);
/**
* Get SQL type transfer octet length.
@@ -198,7 +198,7 @@ int32_t ignite_type_max_column_size(ignite_type typ);
* @param type SQL type.
* @return Transfer octet length.
*/
-int32_t sql_type_transfer_length(int16_t type);
+std::int32_t sql_type_transfer_length(std::int16_t type);
/**
* Get Ignite type transfer octet length.
@@ -206,7 +206,7 @@ int32_t sql_type_transfer_length(int16_t type);
* @param typ Ignite type.
* @return Transfer octet length.
*/
-int32_t ignite_type_transfer_length(ignite_type typ);
+std::int32_t ignite_type_transfer_length(ignite_type typ);
/**
* Get SQL type numeric precision radix.
@@ -214,7 +214,7 @@ int32_t ignite_type_transfer_length(ignite_type typ);
* @param type SQL type.
* @return Numeric precision radix.
*/
-int32_t sql_type_num_precision_radix(int8_t type);
+std::int32_t sql_type_num_precision_radix(int8_t type);
/**
* Get Ignite type numeric precision radix.
@@ -222,23 +222,25 @@ int32_t sql_type_num_precision_radix(int8_t type);
* @param typ Ignite type.
* @return Numeric precision radix.
*/
-int32_t ignite_type_num_precision_radix(ignite_type typ);
+std::int32_t ignite_type_num_precision_radix(ignite_type typ);
/**
* Get SQL type decimal digits.
*
* @param type SQL type.
+ * @param scale Scale if applies. Negative value means scale is not available.
* @return big_decimal digits.
*/
-int32_t sql_type_decimal_digits(int16_t type);
+std::int32_t sql_type_decimal_digits(std::int16_t type, std::int32_t scale);
/**
* Get Ignite type decimal digits.
*
- * @param typ Ignite type.
+* @param typ Ignite type.
+* @param scale Scale if applies. Negative value means scale is not available.
* @return big_decimal digits.
*/
-int32_t ignite_type_decimal_digits(ignite_type typ);
+std::int32_t ignite_type_decimal_digits(ignite_type typ, std::int32_t scale);
/**
* Checks if the SQL type is unsigned.
@@ -246,7 +248,7 @@ int32_t ignite_type_decimal_digits(ignite_type typ);
* @param type SQL type.
* @return True if unsigned or non-numeric.
*/
-bool is_sql_type_unsigned(int16_t type);
+bool is_sql_type_unsigned(std::int16_t type);
/**
* Checks if the Ignite type is unsigned.
diff --git a/modules/platforms/cpp/ignite/protocol/client_operation.h
b/modules/platforms/cpp/ignite/protocol/client_operation.h
index 99a1b70be7..1652977482 100644
--- a/modules/platforms/cpp/ignite/protocol/client_operation.h
+++ b/modules/platforms/cpp/ignite/protocol/client_operation.h
@@ -83,6 +83,9 @@ enum class client_operation {
/** Get table metadata. */
JDBC_TABLE_META = 38,
+ /** Get column metadata. */
+ JDBC_COLUMN_META = 39,
+
/** Begin transaction. */
TX_BEGIN = 43,
diff --git a/modules/platforms/cpp/tests/odbc-test/api_robustness_test.cpp
b/modules/platforms/cpp/tests/odbc-test/api_robustness_test.cpp
index 7fd7d73cd9..29114df565 100644
--- a/modules/platforms/cpp/tests/odbc-test/api_robustness_test.cpp
+++ b/modules/platforms/cpp/tests/odbc-test/api_robustness_test.cpp
@@ -245,9 +245,7 @@ TEST_F(api_robustness_test, sql_columns) {
SQLRETURN ret = SQLColumns(m_statement, catalogName, sizeof(catalogName),
schemaName, sizeof(schemaName), tableName,
sizeof(tableName), columnName, sizeof(columnName));
- UNUSED_VALUE ret;
- // TODO IGNITE-20346: Uncomment once column metadata is implemented.
- // ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, m_statement);
+ ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, m_statement);
// Sizes are nulls.
SQLColumns(m_conn, catalogName, 0, schemaName, 0, tableName, 0,
columnName, 0);
@@ -397,17 +395,11 @@ TEST_F(api_robustness_test, sql_col_attribute) {
// Everything is ok. Character attribute.
ret = SQLColAttribute(m_statement, 1, SQL_COLUMN_TABLE_NAME, buffer,
sizeof(buffer), &resLen, &numericAttr);
-
- UNUSED_VALUE ret;
- // TODO IGNITE-20346: Uncomment once column metadata is implemented.
- // ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, m_statement);
+ ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, m_statement);
// Everything is ok. Numeric attribute.
ret = SQLColAttribute(m_statement, 1, SQL_DESC_COUNT, buffer,
sizeof(buffer), &resLen, &numericAttr);
-
- UNUSED_VALUE ret;
- // TODO IGNITE-20346: Uncomment once column metadata is implemented.
- // ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, m_statement);
+ ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, m_statement);
SQLColAttribute(m_statement, 1, SQL_COLUMN_TABLE_NAME, buffer,
sizeof(buffer), &resLen, 0);
SQLColAttribute(m_statement, 1, SQL_COLUMN_TABLE_NAME, buffer,
sizeof(buffer), 0, &numericAttr);
@@ -444,9 +436,7 @@ TEST_F(api_robustness_test, sql_describe_col) {
ret = SQLDescribeCol(m_statement, 1, columnName, sizeof(columnName),
&columnNameLen, &dataType, &columnSize,
&decimalDigits, &nullable);
- UNUSED_VALUE ret;
- // TODO IGNITE-20346: Uncomment once column metadata is implemented.
- // ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, m_statement);
+ ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, m_statement);
SQLDescribeCol(
m_statement, 1, 0, sizeof(columnName), &columnNameLen, &dataType,
&columnSize, &decimalDigits, &nullable);
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 ed07bd9e5a..11af9248b4 100644
--- a/modules/platforms/cpp/tests/odbc-test/meta_queries_test.cpp
+++ b/modules/platforms/cpp/tests/odbc-test/meta_queries_test.cpp
@@ -546,23 +546,20 @@ TEST_F(meta_queries_test, get_data_with_tables) {
check_single_row_result_set_with_get_data(m_statement);
}
-// TODO: IGNITE-20346 Implement column metadata fetching
-#ifdef MUTED
TEST_F(meta_queries_test, get_data_with_columns) {
odbc_connect(get_basic_connection_string());
- SQLCHAR empty[] = "";
- SQLCHAR table[] = "TestType";
- SQLCHAR column[] = "str";
+ SQLCHAR any[] = "%";
+ SQLCHAR table[] = "META_QUERIES_TEST";
+ SQLCHAR column[] = "STR";
- SQLRETURN ret = SQLColumns(m_statement, empty, SQL_NTS, empty, SQL_NTS,
table, SQL_NTS, column, SQL_NTS);
+ SQLRETURN ret = SQLColumns(m_statement, any, SQL_NTS, any, SQL_NTS, table,
SQL_NTS, column, SQL_NTS);
if (!SQL_SUCCEEDED(ret))
FAIL() << (get_odbc_error_message(SQL_HANDLE_STMT, m_statement));
check_single_row_result_set_with_get_data(m_statement);
}
-#endif // MUTED
TEST_F(meta_queries_test, get_data_with_select_query) {
odbc_connect(get_basic_connection_string());
@@ -723,19 +720,17 @@ TEST_F(meta_queries_test, tables_meta) {
EXPECT_TRUE(ret == SQL_NO_DATA);
}
-// TODO: IGNITE-20346 Implement table column metadata fetching
-#ifdef MUTED
TEST_F(meta_queries_test, ddl_columns_meta) {
odbc_connect(get_basic_connection_string());
- SQLCHAR create_table[] = "create table TestTable(id int primary key,
testColumn varchar)";
+ SQLCHAR create_table[] = "create table if not exists DDL_COLUMNS_META(ID
int primary key, TEST_COLUMN varchar)";
SQLRETURN ret = SQLExecDirect(m_statement, create_table, SQL_NTS);
if (!SQL_SUCCEEDED(ret))
FAIL() << (get_odbc_error_message(SQL_HANDLE_STMT, m_statement));
SQLCHAR any[] = "%";
- SQLCHAR table[] = "TestTable";
+ SQLCHAR table[] = "DDL_COLUMNS_META";
ret = SQLColumns(m_statement, any, SQL_NTS, any, SQL_NTS, table, SQL_NTS,
any, SQL_NTS);
@@ -748,8 +743,8 @@ TEST_F(meta_queries_test, ddl_columns_meta) {
FAIL() << (get_odbc_error_message(SQL_HANDLE_STMT, m_statement));
check_string_column(m_statement, 1, "");
- check_string_column(m_statement, 2, "\"PUBLIC\"");
- check_string_column(m_statement, 3, "TESTTABLE");
+ check_string_column(m_statement, 2, "PUBLIC");
+ check_string_column(m_statement, 3, "DDL_COLUMNS_META");
check_string_column(m_statement, 4, "ID");
ret = SQLFetch(m_statement);
@@ -758,9 +753,9 @@ TEST_F(meta_queries_test, ddl_columns_meta) {
FAIL() << (get_odbc_error_message(SQL_HANDLE_STMT, m_statement));
check_string_column(m_statement, 1, "");
- check_string_column(m_statement, 2, "\"PUBLIC\"");
- check_string_column(m_statement, 3, "TESTTABLE");
- check_string_column(m_statement, 4, "TESTCOLUMN");
+ check_string_column(m_statement, 2, "PUBLIC");
+ check_string_column(m_statement, 3, "DDL_COLUMNS_META");
+ check_string_column(m_statement, 4, "TEST_COLUMN");
ret = SQLFetch(m_statement);
@@ -770,7 +765,7 @@ TEST_F(meta_queries_test, ddl_columns_meta) {
TEST_F(meta_queries_test, ddl_columns_meta_escaped) {
odbc_connect(get_basic_connection_string());
- SQLCHAR create_table[] = "create table ESG_FOCUS(id int primary key,
TEST_COLUMN varchar)";
+ SQLCHAR create_table[] = "create table if not exists ESG_FOCUS(id int
primary key, TEST_COLUMN varchar)";
SQLRETURN ret = SQLExecDirect(m_statement, create_table, SQL_NTS);
if (!SQL_SUCCEEDED(ret))
@@ -790,7 +785,7 @@ TEST_F(meta_queries_test, ddl_columns_meta_escaped) {
FAIL() << (get_odbc_error_message(SQL_HANDLE_STMT, m_statement));
check_string_column(m_statement, 1, "");
- check_string_column(m_statement, 2, "\"PUBLIC\"");
+ check_string_column(m_statement, 2, "PUBLIC");
check_string_column(m_statement, 3, "ESG_FOCUS");
check_string_column(m_statement, 4, "ID");
@@ -800,7 +795,7 @@ TEST_F(meta_queries_test, ddl_columns_meta_escaped) {
FAIL() << (get_odbc_error_message(SQL_HANDLE_STMT, m_statement));
check_string_column(m_statement, 1, "");
- check_string_column(m_statement, 2, "\"PUBLIC\"");
+ check_string_column(m_statement, 2, "PUBLIC");
check_string_column(m_statement, 3, "ESG_FOCUS");
check_string_column(m_statement, 4, "TEST_COLUMN");
@@ -808,7 +803,6 @@ TEST_F(meta_queries_test, ddl_columns_meta_escaped) {
ASSERT_EQ(ret, SQL_NO_DATA);
}
-#endif // MUTED
// TODO: IGNITE-19854 Implement metadata fetching for the non-executed query.
#ifdef MUTED