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 b1fdda2508 IGNITE-21527 C++: Clean up IEP-54 leftovers (#3486)
b1fdda2508 is described below
commit b1fdda2508cdb47e429918432631d2ffc5b5e554
Author: Igor Sapego <[email protected]>
AuthorDate: Wed Mar 27 14:04:52 2024 +0400
IGNITE-21527 C++: Clean up IEP-54 leftovers (#3486)
---
.../org/apache/ignite/client/ClientTablesTest.java | 36 ------
modules/platforms/cpp/ignite/client/CMakeLists.txt | 29 ++++-
.../ignite/client/detail/compute/compute_impl.h | 7 +-
.../cpp/ignite/client/detail/table/schema.h | 102 ++++++++++++----
.../cpp/ignite/client/detail/table/table_impl.cpp | 106 ----------------
.../platforms/cpp/ignite/client/detail/utils.cpp | 70 +++++++++--
modules/platforms/cpp/ignite/client/detail/utils.h | 39 ++++++
.../cpp/ignite/client/detail/utils_test.cpp | 92 ++++++++++++++
.../platforms/cpp/tests/client-test/CMakeLists.txt | 1 +
.../cpp/tests/client-test/column_order_test.cpp | 136 +++++++++++++++++++++
.../cpp/tests/client-test/compute_test.cpp | 8 +-
.../platforms/cpp/tests/client-test/sql_test.cpp | 2 +-
12 files changed, 444 insertions(+), 184 deletions(-)
diff --git
a/modules/client/src/test/java/org/apache/ignite/client/ClientTablesTest.java
b/modules/client/src/test/java/org/apache/ignite/client/ClientTablesTest.java
index 75b82f9fb0..ee03b57143 100644
---
a/modules/client/src/test/java/org/apache/ignite/client/ClientTablesTest.java
+++
b/modules/client/src/test/java/org/apache/ignite/client/ClientTablesTest.java
@@ -19,17 +19,10 @@ package org.apache.ignite.client;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.Comparator;
-import java.util.concurrent.CompletionException;
import org.apache.ignite.client.fakes.FakeIgniteTables;
-import org.apache.ignite.internal.client.table.ClientTable;
-import org.apache.ignite.internal.table.TableViewInternal;
-import org.apache.ignite.lang.TableAlreadyExistsException;
import org.apache.ignite.table.Table;
-import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
/**
@@ -70,33 +63,4 @@ public class ClientTablesTest extends AbstractClientTest {
assertNull(table);
}
-
- @Test
- @Disabled("IGNITE-15179")
- public void testCreateTable() {
- var clientTable = ((FakeIgniteTables)
server.tables()).createTable("t1");
- assertEquals("t1", clientTable.name());
-
- var serverTables = server.tables().tables();
- assertEquals(1, serverTables.size());
-
- var serverTable = serverTables.get(0);
- assertEquals("t1", serverTable.name());
- assertEquals(((TableViewInternal) serverTable).tableId(),
((ClientTable) clientTable).tableId());
- }
-
- @Test
- @Disabled("IGNITE-15179")
- public void testCreateTableWhenExists() {
- ((FakeIgniteTables) server.tables()).createTable(DEFAULT_TABLE);
-
- var ex = assertThrows(CompletionException.class,
- () -> ((FakeIgniteTables)
server.tables()).createTable(DEFAULT_TABLE));
-
- assertTrue(ex.getMessage().endsWith(FakeIgniteTables.TABLE_EXISTS));
- assertEquals(TableAlreadyExistsException.class,
ex.getCause().getClass());
-
- var serverTables = server.tables().tables();
- assertEquals(1, serverTables.size());
- }
}
diff --git a/modules/platforms/cpp/ignite/client/CMakeLists.txt
b/modules/platforms/cpp/ignite/client/CMakeLists.txt
index 4b82c9f34b..7da3427464 100644
--- a/modules/platforms/cpp/ignite/client/CMakeLists.txt
+++ b/modules/platforms/cpp/ignite/client/CMakeLists.txt
@@ -65,16 +65,31 @@ set(PUBLIC_HEADERS
transaction/transactions.h
)
+add_library(${TARGET}-obj OBJECT ${SOURCES})
+target_include_directories(${TARGET}-obj PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
+
add_library(${TARGET} SHARED ${SOURCES})
-set_target_properties(${TARGET} PROPERTIES VERSION ${CMAKE_PROJECT_VERSION})
-set_target_properties(${TARGET} PROPERTIES POSITION_INDEPENDENT_CODE 1)
+set(LIBRARIES
+ ignite-common
+ ignite-tuple
+ ignite-network
+ ignite-protocol
+)
-if (WIN32)
- set_target_properties(${TARGET} PROPERTIES OUTPUT_NAME "ignite-client")
-endif()
+set(_target_libs ${TARGET} ${TARGET}-obj)
-target_link_libraries(${TARGET} ignite-common ignite-tuple ignite-network
ignite-protocol)
+foreach(_target_lib IN LISTS _target_libs)
+ set_target_properties(${_target_lib} PROPERTIES VERSION
${CMAKE_PROJECT_VERSION})
+ set_target_properties(${_target_lib} PROPERTIES POSITION_INDEPENDENT_CODE
1)
+
+ if (WIN32)
+ set_target_properties(${_target_lib} PROPERTIES OUTPUT_NAME
"ignite-client")
+ endif()
+
+ target_link_libraries(${_target_lib} ${LIBRARIES})
+endforeach()
+unset(_target_libs)
if (${INSTALL_IGNITE_FILES})
install(TARGETS ${TARGET}
@@ -85,3 +100,5 @@ if (${INSTALL_IGNITE_FILES})
ignite_install_headers(FILES ${PUBLIC_HEADERS} DESTINATION
${IGNITE_INCLUDEDIR}/client)
endif()
+
+ignite_test(utils_test detail/utils_test.cpp LIBS ${TARGET}-obj ${LIBRARIES})
diff --git a/modules/platforms/cpp/ignite/client/detail/compute/compute_impl.h
b/modules/platforms/cpp/ignite/client/detail/compute/compute_impl.h
index cb259eba66..8fb3e9d468 100644
--- a/modules/platforms/cpp/ignite/client/detail/compute/compute_impl.h
+++ b/modules/platforms/cpp/ignite/client/detail/compute/compute_impl.h
@@ -47,8 +47,8 @@ public:
, m_tables(std::move(tables)) {}
/**
- * Submits a compute job represented by the given class for an execution
on one of the specified nodes asynchronously. If the node
- * leaves the cluster, it will be restarted on one of the candidate nodes.
+ * Submits a compute job represented by the given class for an execution
on one of the specified nodes
+ * asynchronously. If the node leaves the cluster, it will be restarted on
one of the candidate nodes.
*
* @param nodes Candidate node to use for the job execution.
* @param units Deployment units. Can be empty.
@@ -61,7 +61,8 @@ public:
ignite_callback<std::optional<primitive>> callback);
/**
- * Submits a compute job represented by the given class for an execution
on one of the nodes where the given key is located.
+ * Submits a compute job represented by the given class for an execution
on one of the nodes where the given key is
+ * located.
*
* @param table_name Name of the table to be used with @c key to determine
target node.
* @param key Table key to be used to determine the target node for job
execution.
diff --git a/modules/platforms/cpp/ignite/client/detail/table/schema.h
b/modules/platforms/cpp/ignite/client/detail/table/schema.h
index 9d35828ce7..f15bb0cedb 100644
--- a/modules/platforms/cpp/ignite/client/detail/table/schema.h
+++ b/modules/platforms/cpp/ignite/client/detail/table/schema.h
@@ -23,6 +23,7 @@
#include <msgpack.h>
+#include <algorithm>
#include <array>
#include <memory>
#include <string>
@@ -34,11 +35,19 @@ namespace ignite::detail {
*/
struct column {
std::string name;
- ignite_type type{};
+ ignite_type type{ignite_type::UNDEFINED};
bool nullable{false};
- bool is_key{false};
- std::int32_t schema_index{0};
+ std::int32_t colocation_index{-1};
+ std::int32_t key_index{-1};
std::int32_t scale{0};
+ std::int32_t precision{0};
+
+ /**
+ * Check if the column is the part of the key.
+ *
+ * @return @c true, if the column is the part of the key.
+ */
+ [[nodiscard]] bool is_key() const { return key_index >= 0; }
/**
* Unpack column from MsgPack object.
@@ -47,18 +56,20 @@ struct column {
* @return Column value.
*/
[[nodiscard]] static column read(protocol::reader &reader) {
+ auto constexpr minimum_expected_columns = 7;
+
auto fields_num = reader.read_int32();
- assert(fields_num >= 7); // Expect at least six columns.
+ assert(fields_num >= minimum_expected_columns);
column res{};
res.name = reader.read_string();
res.type = static_cast<ignite_type>(reader.read_int32());
- res.is_key = reader.read_int32() >= 0;
+ res.key_index = reader.read_int32();
res.nullable = reader.read_bool();
- reader.skip(); // Colocation index.
+ res.colocation_index = reader.read_int32();
res.scale = reader.read_int32();
- reader.skip(); // Precision
- reader.skip(fields_num - 7);
+ res.precision = reader.read_int32();
+ reader.skip(fields_num - minimum_expected_columns);
return res;
}
@@ -68,9 +79,10 @@ struct column {
* Schema.
*/
struct schema {
- std::int32_t version{-1};
- std::int32_t key_column_count{0};
- std::vector<column> columns;
+ const std::int32_t version{-1};
+ const std::vector<column> columns;
+ const std::vector<const column *> key_columns;
+ const std::vector<const column *> val_columns;
// Default
schema() = default;
@@ -79,13 +91,62 @@ struct schema {
* Constructor.
*
* @param version Version.
- * @param key_column_count Key column count.
* @param columns Columns.
+ * @param key_columns Key Columns.
+ * @param val_columns Value Columns.
*/
- schema(std::int32_t version, std::int32_t key_column_count,
std::vector<column> &&columns)
+ schema(std::int32_t version, std::vector<column> &&columns,
std::vector<const column *> &&key_columns,
+ std::vector<const column *> &&val_columns)
: version(version)
- , key_column_count(key_column_count)
- , columns(std::move(columns)) {}
+ , columns(std::move(columns))
+ , key_columns(std::move(key_columns))
+ , val_columns(std::move(val_columns)) {}
+
+ /**
+ * Get column by index.
+ *
+ * @param key_only Key only flag.
+ * @param index Column index.
+ * @return Column reference.
+ */
+ [[nodiscard]] const column &get_column(bool key_only, std::int32_t index)
const {
+ assert(index >= 0);
+ return key_only ? *key_columns[index] : columns[index];
+ }
+
+ /**
+ * Create schema instance.
+ *
+ * @param version Version.
+ * @param cols Columns.
+ * @return A new schema instance.
+ */
+ static std::shared_ptr<schema> create_instance(std::int32_t version,
std::vector<column> &&cols) {
+ std::int32_t key_columns_cnt = 0;
+ for (const auto &column : cols) {
+ if (column.is_key())
+ ++key_columns_cnt;
+ }
+ std::int32_t val_columns_cnt = std::int32_t(cols.size()) -
key_columns_cnt;
+
+ std::vector<const column *> key_columns(key_columns_cnt, nullptr);
+
+ std::vector<const column *> val_columns;
+ val_columns.reserve(val_columns_cnt);
+
+ for (const auto &column : cols) {
+ if (column.is_key()) {
+ assert(column.key_index >= 0 && std::size_t(column.key_index)
< key_columns.size());
+ assert(key_columns[column.key_index] == nullptr);
+
+ key_columns[column.key_index] = &column;
+ } else {
+ val_columns.push_back(&column);
+ }
+ }
+
+ return std::make_shared<schema>(version, std::move(cols),
std::move(key_columns), std::move(val_columns));
+ }
/**
* Read schema using reader.
@@ -94,22 +155,19 @@ struct schema {
* @return Schema instance.
*/
static std::shared_ptr<schema> read(protocol::reader &reader) {
- std::int32_t key_column_count = 0;
auto schema_version = reader.read_int32();
auto columns_count = reader.read_int32();
- std::vector<column> columns;
- columns.reserve(columns_count);
+ std::vector<column> cols;
+ cols.reserve(columns_count);
for (std::int32_t column_idx = 0; column_idx < columns_count;
++column_idx) {
auto val = column::read(reader);
- if (val.is_key)
- ++key_column_count;
- columns.emplace_back(std::move(val));
+ cols.emplace_back(std::move(val));
}
- return std::make_shared<schema>(schema_version, key_column_count,
std::move(columns));
+ return create_instance(schema_version, std::move(cols));
}
};
diff --git a/modules/platforms/cpp/ignite/client/detail/table/table_impl.cpp
b/modules/platforms/cpp/ignite/client/detail/table/table_impl.cpp
index 41826d018a..f6cd913803 100644
--- a/modules/platforms/cpp/ignite/client/detail/table/table_impl.cpp
+++ b/modules/platforms/cpp/ignite/client/detail/table/table_impl.cpp
@@ -48,112 +48,6 @@ void write_table_operation_header(protocol::writer &writer,
std::int32_t id, tra
writer.write(sch.version);
}
-/**
- * Read tuple.
- *
- * @param reader Reader.
- * @param sch Schema.
- * @return Tuple.
- */
-ignite_tuple read_tuple(protocol::reader &reader, const schema *sch) {
- auto tuple_data = reader.read_binary();
-
- auto columns_cnt = std::int32_t(sch->columns.size());
- ignite_tuple res(columns_cnt);
- binary_tuple_parser parser(columns_cnt, tuple_data);
-
- for (std::int32_t i = 0; i < columns_cnt; ++i) {
- auto &column = sch->columns[i];
- res.set(column.name, protocol::read_next_column(parser, column.type,
column.scale));
- }
- return res;
-}
-
-/**
- * Read tuple.
- *
- * @param reader Reader.
- * @param sch Schema.
- * @param key_only Should only key fields be read or not.
- * @return Tuple.
- */
-ignite_tuple read_tuple(protocol::reader &reader, const schema *sch, bool
key_only) {
- auto tuple_data = reader.read_binary();
-
- auto columns_cnt = std::int32_t(key_only ? sch->key_column_count :
sch->columns.size());
- ignite_tuple res(columns_cnt);
- binary_tuple_parser parser(columns_cnt, tuple_data);
-
- for (std::int32_t i = 0; i < columns_cnt; ++i) {
- auto &column = sch->columns[i];
- res.set(column.name, protocol::read_next_column(parser, column.type,
column.scale));
- }
- return res;
-}
-
-/**
- * Read tuple.
- *
- * @param reader Reader.
- * @param sch Schema.
- * @return Tuple.
- */
-std::optional<ignite_tuple> read_tuple_opt(protocol::reader &reader, const
schema *sch) {
- if (reader.try_read_nil())
- return std::nullopt;
-
- return read_tuple(reader, sch);
-}
-
-/**
- * Read tuples.
- *
- * @param reader Reader.
- * @param sch Schema.
- * @param key_only Should only key fields be read or not.
- * @return Tuples.
- */
-std::vector<std::optional<ignite_tuple>> read_tuples_opt(protocol::reader
&reader, const schema *sch, bool key_only) {
- if (reader.try_read_nil())
- return {};
-
- auto count = reader.read_int32();
- std::vector<std::optional<ignite_tuple>> res;
- res.reserve(std::size_t(count));
-
- for (std::int32_t i = 0; i < count; ++i) {
- auto exists = reader.read_bool();
- if (!exists)
- res.emplace_back(std::nullopt);
- else
- res.emplace_back(read_tuple(reader, sch, key_only));
- }
-
- return res;
-}
-
-/**
- * Read tuples.
- *
- * @param reader Reader.
- * @param sch Schema.
- * @param key_only Should only key fields be read or not.
- * @return Tuples.
- */
-std::vector<ignite_tuple> read_tuples(protocol::reader &reader, const schema
*sch, bool key_only) {
- if (reader.try_read_nil())
- return {};
-
- auto count = reader.read_int32();
- std::vector<ignite_tuple> res;
- res.reserve(std::size_t(count));
-
- for (std::int32_t i = 0; i < count; ++i)
- res.emplace_back(read_tuple(reader, sch, key_only));
-
- return res;
-}
-
void
table_impl::load_latest_schema_async(ignite_callback<std::shared_ptr<schema>>
callback) {
auto latest_schema_version = m_latest_schema_version;
diff --git a/modules/platforms/cpp/ignite/client/detail/utils.cpp
b/modules/platforms/cpp/ignite/client/detail/utils.cpp
index c4cd833f87..5881094686 100644
--- a/modules/platforms/cpp/ignite/client/detail/utils.cpp
+++ b/modules/platforms/cpp/ignite/client/detail/utils.cpp
@@ -188,14 +188,16 @@ void append_column(binary_tuple_builder &builder,
ignite_type typ, const primiti
*/
std::vector<std::byte> pack_tuple(
const schema &sch, const ignite_tuple &tuple, bool key_only,
protocol::bitset_span &no_value) {
- auto count = std::int32_t(key_only ? sch.key_column_count :
sch.columns.size());
+ auto count = std::int32_t(key_only ? sch.key_columns.size() :
sch.columns.size());
binary_tuple_builder builder{count};
builder.start();
+ auto col_indices = reinterpret_cast<std::int32_t *>(alloca(count *
sizeof(std::int32_t)));
for (std::int32_t i = 0; i < count; ++i) {
- const auto &col = sch.columns[i];
+ const auto &col = sch.get_column(key_only, i);
auto col_idx = tuple.column_ordinal(col.name);
+ col_indices[i] = col_idx;
if (col_idx >= 0)
claim_column(builder, col.type, tuple.get(col_idx), col.scale);
@@ -206,8 +208,8 @@ std::vector<std::byte> pack_tuple(
std::int32_t written = 0;
builder.layout();
for (std::int32_t i = 0; i < count; ++i) {
- const auto &col = sch.columns[i];
- auto col_idx = tuple.column_ordinal(col.name);
+ const auto &col = sch.get_column(key_only, i);
+ auto col_idx = col_indices[i];
if (col_idx >= 0) {
append_column(builder, col.type, tuple.get(col_idx), col.scale);
@@ -221,8 +223,7 @@ std::vector<std::byte> pack_tuple(
if (!key_only && written < tuple.column_count()) {
std::vector<bool> written_ind(tuple.column_count(), false);
for (std::int32_t i = 0; i < count; ++i) {
- const auto &col = sch.columns[i];
- auto col_idx = tuple.column_ordinal(col.name);
+ auto col_idx = col_indices[i];
if (col_idx >= 0)
written_ind[col_idx] = true;
@@ -232,6 +233,7 @@ std::vector<std::byte> pack_tuple(
for (std::int32_t i = 0; i < tuple.column_count(); ++i) {
if (written_ind[i])
continue;
+
auto &name = tuple.column_name(i);
unmapped_columns << name << ",";
}
@@ -265,7 +267,7 @@ ignite_tuple concat(const ignite_tuple &left, const
ignite_tuple &right) {
}
void write_tuple(protocol::writer &writer, const schema &sch, const
ignite_tuple &tuple, bool key_only) {
- const std::size_t count = key_only ? sch.key_column_count :
sch.columns.size();
+ const std::size_t count = key_only ? sch.key_columns.size() :
sch.columns.size();
const std::size_t bytes_num = bytes_for_bits(count);
auto no_value_bytes = reinterpret_cast<std::byte *>(alloca(bytes_num));
@@ -283,4 +285,58 @@ void write_tuples(protocol::writer &writer, const schema
&sch, const std::vector
write_tuple(writer, sch, tuple, key_only);
}
+ignite_tuple read_tuple(protocol::reader &reader, const schema *sch, bool
key_only) {
+ auto tuple_data = reader.read_binary();
+
+ auto columns_cnt = std::int32_t(key_only ? sch->key_columns.size() :
sch->columns.size());
+ ignite_tuple res(columns_cnt);
+ binary_tuple_parser parser(columns_cnt, tuple_data);
+
+ for (std::int32_t i = 0; i < columns_cnt; ++i) {
+ auto &column = sch->get_column(key_only, i);
+ res.set(column.name, protocol::read_next_column(parser, column.type,
column.scale));
+ }
+ return res;
+}
+
+std::optional<ignite_tuple> read_tuple_opt(protocol::reader &reader, const
schema *sch) {
+ if (reader.try_read_nil())
+ return std::nullopt;
+
+ return read_tuple(reader, sch, false);
+}
+
+std::vector<ignite_tuple> read_tuples(protocol::reader &reader, const schema
*sch, bool key_only) {
+ if (reader.try_read_nil())
+ return {};
+
+ auto count = reader.read_int32();
+ std::vector<ignite_tuple> res;
+ res.reserve(std::size_t(count));
+
+ for (std::int32_t i = 0; i < count; ++i)
+ res.emplace_back(read_tuple(reader, sch, key_only));
+
+ return res;
+}
+
+std::vector<std::optional<ignite_tuple>> read_tuples_opt(protocol::reader
&reader, const schema *sch, bool key_only) {
+ if (reader.try_read_nil())
+ return {};
+
+ auto count = reader.read_int32();
+ std::vector<std::optional<ignite_tuple>> res;
+ res.reserve(std::size_t(count));
+
+ for (std::int32_t i = 0; i < count; ++i) {
+ auto exists = reader.read_bool();
+ if (!exists)
+ res.emplace_back(std::nullopt);
+ else
+ res.emplace_back(read_tuple(reader, sch, key_only));
+ }
+
+ return res;
+}
+
} // namespace ignite::detail
diff --git a/modules/platforms/cpp/ignite/client/detail/utils.h
b/modules/platforms/cpp/ignite/client/detail/utils.h
index 6a22aa107f..808f490f0b 100644
--- a/modules/platforms/cpp/ignite/client/detail/utils.h
+++ b/modules/platforms/cpp/ignite/client/detail/utils.h
@@ -56,4 +56,43 @@ void write_tuple(protocol::writer &writer, const schema
&sch, const ignite_tuple
*/
void write_tuples(protocol::writer &writer, const schema &sch, const
std::vector<ignite_tuple> &tuples, bool key_only);
+/**
+ * Read tuple.
+ *
+ * @param reader Reader.
+ * @param sch Schema.
+ * @param key_only Should only key fields be read or not.
+ * @return Tuple.
+ */
+ignite_tuple read_tuple(protocol::reader &reader, const schema *sch, bool
key_only);
+
+/**
+ * Read tuple.
+ *
+ * @param reader Reader.
+ * @param sch Schema.
+ * @return Tuple.
+ */
+std::optional<ignite_tuple> read_tuple_opt(protocol::reader &reader, const
schema *sch);
+
+/**
+ * Read tuples.
+ *
+ * @param reader Reader.
+ * @param sch Schema.
+ * @param key_only Should only key fields be read or not.
+ * @return Tuples.
+ */
+std::vector<ignite_tuple> read_tuples(protocol::reader &reader, const schema
*sch, bool key_only);
+
+/**
+ * Read tuples.
+ *
+ * @param reader Reader.
+ * @param sch Schema.
+ * @param key_only Should only key fields be read or not.
+ * @return Tuples.
+ */
+std::vector<std::optional<ignite_tuple>> read_tuples_opt(protocol::reader
&reader, const schema *sch, bool key_only);
+
} // namespace ignite::detail
diff --git a/modules/platforms/cpp/ignite/client/detail/utils_test.cpp
b/modules/platforms/cpp/ignite/client/detail/utils_test.cpp
new file mode 100644
index 0000000000..b152ced610
--- /dev/null
+++ b/modules/platforms/cpp/ignite/client/detail/utils_test.cpp
@@ -0,0 +1,92 @@
+/*
+ * 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/client/detail/utils.h"
+
+#include <gtest/gtest.h>
+
+using namespace ignite;
+using namespace detail;
+
+inline column make_column(std::string name, ignite_type type, std::int32_t
key_index = -1) {
+ column val;
+ val.name = std::move(name);
+ val.type = type;
+ val.key_index = key_index;
+
+ return val;
+}
+
+std::shared_ptr<schema> make_test_schema() {
+ std::vector<column> columns;
+ columns.push_back(make_column("VAL_COL1", ignite_type::INT32));
+ columns.push_back(make_column("KEY_COL1", ignite_type::STRING, 0));
+ columns.push_back(make_column("VAL_COL2", ignite_type::STRING));
+ columns.push_back(make_column("KEY_COL2", ignite_type::INT32, 1));
+
+ return schema::create_instance(0, std::move(columns));
+}
+
+ignite_tuple write_read_tuple(const ignite_tuple &tuple, const
std::shared_ptr<schema> &sch, bool key_only) {
+ std::vector<std::byte> message;
+ protocol::buffer_adapter buffer(message);
+
+ protocol::writer writer(buffer);
+
+ write_tuple(writer, *sch, tuple, key_only);
+
+ protocol::reader reader(message);
+ reader.skip(); // Skip bitset
+
+ return read_tuple(reader, sch.get(), key_only);
+}
+
+TEST(client_utils, tuple_write_read_random_order_all_columns) {
+ auto sch = make_test_schema();
+
+ ignite_tuple tuple{{"VAL_COL1", std::int32_t(42)}, {"VAL_COL2",
std::string("Lorem ipsum")},
+ {"KEY_COL2", std::int32_t(1337)}, {"KEY_COL1", std::string("Test
value")}};
+
+ auto res_tuple = write_read_tuple(tuple, sch, false);
+
+ ASSERT_EQ(4, res_tuple.column_count());
+ EXPECT_EQ("VAL_COL1", res_tuple.column_name(0));
+ EXPECT_EQ("KEY_COL1", res_tuple.column_name(1));
+ EXPECT_EQ("VAL_COL2", res_tuple.column_name(2));
+ EXPECT_EQ("KEY_COL2", res_tuple.column_name(3));
+
+ EXPECT_EQ(std::int32_t(42), res_tuple.get(0));
+ EXPECT_EQ(std::string("Test value"), res_tuple.get(1));
+ EXPECT_EQ(std::string("Lorem ipsum"), res_tuple.get(2));
+ EXPECT_EQ(std::int32_t(1337), res_tuple.get(3));
+}
+
+TEST(client_utils, tuple_write_read_random_order_key_only) {
+ auto sch = make_test_schema();
+
+ ignite_tuple tuple{{"VAL_COL1", std::int32_t(42)}, {"VAL_COL2",
std::string("Lorem ipsum")},
+ {"KEY_COL2", std::int32_t(1337)}, {"KEY_COL1", std::string("Test
value")}};
+
+ auto res_tuple = write_read_tuple(tuple, sch, true);
+
+ ASSERT_EQ(2, res_tuple.column_count());
+ EXPECT_EQ("KEY_COL1", res_tuple.column_name(0));
+ EXPECT_EQ("KEY_COL2", res_tuple.column_name(1));
+
+ EXPECT_EQ(std::string("Test value"), res_tuple.get(0));
+ EXPECT_EQ(std::int32_t(1337), res_tuple.get(1));
+}
diff --git a/modules/platforms/cpp/tests/client-test/CMakeLists.txt
b/modules/platforms/cpp/tests/client-test/CMakeLists.txt
index aafe31f62c..ff944b3191 100644
--- a/modules/platforms/cpp/tests/client-test/CMakeLists.txt
+++ b/modules/platforms/cpp/tests/client-test/CMakeLists.txt
@@ -21,6 +21,7 @@ set(TARGET ${PROJECT_NAME})
set(SOURCES
basic_authenticator_test.cpp
+ column_order_test.cpp
compute_test.cpp
gtest_logger.h
ignite_client_test.cpp
diff --git a/modules/platforms/cpp/tests/client-test/column_order_test.cpp
b/modules/platforms/cpp/tests/client-test/column_order_test.cpp
new file mode 100644
index 0000000000..4fdb033bc8
--- /dev/null
+++ b/modules/platforms/cpp/tests/client-test/column_order_test.cpp
@@ -0,0 +1,136 @@
+/*
+ * 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_runner_suite.h"
+
+#include "ignite/client/ignite_client.h"
+#include "ignite/client/ignite_client_configuration.h"
+
+#include <gmock/gmock-matchers.h>
+#include <gtest/gtest.h>
+
+#include <chrono>
+
+using namespace ignite;
+
+#define TEST_TABLE_NAME "column_order_test"
+
+/**
+ * Test suite.
+ */
+class column_order_test : public ignite_runner_suite {
+protected:
+ static const constexpr std::int32_t test_records = 10;
+
+ static void SetUpTestSuite() {
+ ignite_client_configuration cfg{get_node_addrs()};
+ cfg.set_logger(get_logger());
+ auto client = ignite_client::start(cfg, std::chrono::seconds(30));
+
+ client.get_sql().execute(nullptr, {"drop table if exists "
TEST_TABLE_NAME}, {});
+
+ client.get_sql().execute(nullptr,
+ {"create table column_order_test(val1 varchar, key1 int, val2
bigint, key2 varchar, primary key(key2, "
+ "key1))"},
+ {});
+
+ for (std::int32_t i = 0; i < test_records; ++i) {
+ auto stri = std::to_string(i);
+ client.get_sql().execute(nullptr, {"insert into " TEST_TABLE_NAME
" values(?, ?, ?, ?)"},
+ {"test val " + stri, std::int32_t(i), std::int64_t(i * 2),
"test key " + stri});
+ }
+ }
+
+ static void TearDownTestSuite() {
+ ignite_client_configuration cfg{get_node_addrs()};
+ cfg.set_logger(get_logger());
+ auto client = ignite_client::start(cfg, std::chrono::seconds(30));
+
+ client.get_sql().execute(nullptr, {"drop table if exists "
TEST_TABLE_NAME}, {});
+ }
+
+ void SetUp() override {
+ ignite_client_configuration cfg{get_node_addrs()};
+ cfg.set_logger(get_logger());
+
+ m_client = ignite_client::start(cfg, std::chrono::seconds(30));
+ auto table = m_client.get_tables().get_table(TEST_TABLE_NAME);
+ ASSERT_TRUE(table.has_value());
+
+ m_table = std::move(*table);
+ }
+
+ void TearDown() override {
+ // remove all
+ }
+
+ /** Ignite client. */
+ ignite_client m_client;
+
+ /** Test table. */
+ table m_table;
+};
+
+ignite_tuple make_test_key_tuple(std::int32_t index) {
+ return {{"key1", std::int32_t(index)}, {"key2", "test key " +
std::to_string(index)}};
+}
+
+ignite_tuple make_test_full_tuple(std::int32_t index) {
+ auto stri = std::to_string(index);
+ return {{"key1", std::int32_t(index)}, {"key2", "test key " + stri},
{"val1", "test val " + stri},
+ {"val2", std::int64_t(index * 2)}};
+}
+
+void check_test_tuple(const ignite_tuple &tuple, std::int32_t index, bool
key_only) {
+ ASSERT_EQ(key_only ? 2 : 4, tuple.column_count());
+
+ auto ref = make_test_full_tuple(index);
+ EXPECT_EQ(ref.get("key1").get<std::int32_t>(),
tuple.get("key1").get<std::int32_t>());
+ EXPECT_EQ(ref.get("key2").get<std::string>(),
tuple.get("key2").get<std::string>());
+
+ if (!key_only) {
+ EXPECT_EQ(ref.get("val1").get<std::string>(),
tuple.get("val1").get<std::string>());
+ EXPECT_EQ(ref.get("val2").get<std::int64_t>(),
tuple.get("val2").get<std::int64_t>());
+ }
+}
+
+TEST_F(column_order_test, test_key_columns_nondefault_ordering_get) {
+ auto tuple_view = m_table.get_record_binary_view();
+
+ for (std::int32_t i = 0; i < test_records; ++i) {
+ auto res = tuple_view.get(nullptr, make_test_key_tuple(i));
+
+ ASSERT_TRUE(res.has_value());
+ check_test_tuple(*res, i, false);
+ }
+}
+
+TEST_F(column_order_test, test_key_columns_nondefault_ordering_put_get_remove)
{
+ auto tuple_view = m_table.get_record_binary_view();
+
+ tuple_view.upsert(nullptr, make_test_full_tuple(13));
+
+ auto res = tuple_view.get(nullptr, make_test_key_tuple(13));
+ ASSERT_TRUE(res.has_value());
+ check_test_tuple(*res, 13, false);
+
+ bool removed = tuple_view.remove(nullptr, make_test_key_tuple(13));
+ ASSERT_TRUE(removed);
+
+ res = tuple_view.get(nullptr, make_test_key_tuple(13));
+ ASSERT_FALSE(res.has_value());
+}
diff --git a/modules/platforms/cpp/tests/client-test/compute_test.cpp
b/modules/platforms/cpp/tests/client-test/compute_test.cpp
index 53f257f7e3..8c982877ff 100644
--- a/modules/platforms/cpp/tests/client-test/compute_test.cpp
+++ b/modules/platforms/cpp/tests/client-test/compute_test.cpp
@@ -191,14 +191,15 @@ TEST_F(compute_test, unknown_node_execute_throws) {
try {
m_client.get_compute().execute({unknown_node}, {}, ECHO_JOB,
{"unused"});
} catch (const ignite_error &e) {
- EXPECT_THAT(e.what_str(), testing::HasSubstr("None of the
specified nodes are present in the cluster: [random]"));
+ EXPECT_THAT(e.what_str(),
+ testing::HasSubstr("None of the specified nodes are
present in the cluster: [random]"));
throw;
}
},
ignite_error);
}
-//TODO https://issues.apache.org/jira/browse/IGNITE-21553
+// TODO https://issues.apache.org/jira/browse/IGNITE-21553
TEST_F(compute_test, DISABLED_unknown_node_broadcast_throws) {
auto unknown_node = cluster_node("some", "random", {"127.0.0.1", 1234});
@@ -207,7 +208,8 @@ TEST_F(compute_test,
DISABLED_unknown_node_broadcast_throws) {
try {
m_client.get_compute().execute_broadcast({unknown_node}, {},
ECHO_JOB, {"unused"});
} catch (const ignite_error &e) {
- EXPECT_THAT(e.what_str(), testing::HasSubstr("None of the
specified nodes are present in the cluster: [random]"));
+ EXPECT_THAT(e.what_str(),
+ testing::HasSubstr("None of the specified nodes are
present in the cluster: [random]"));
throw;
}
},
diff --git a/modules/platforms/cpp/tests/client-test/sql_test.cpp
b/modules/platforms/cpp/tests/client-test/sql_test.cpp
index c4f2dd2ffe..23bcd762b3 100644
--- a/modules/platforms/cpp/tests/client-test/sql_test.cpp
+++ b/modules/platforms/cpp/tests/client-test/sql_test.cpp
@@ -83,7 +83,7 @@ protected:
ignite_client m_client;
};
-void check_columns(
+static void check_columns(
const result_set_metadata &meta,
std::initializer_list<std::tuple<std::string, ignite_type>> columns) {
ASSERT_EQ(columns.size(), meta.columns().size());