blob: 1c09418b2d56ca1805a9b2b6c710342bc849645a [file] [log] [blame]
/*
* 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;
/**
* Test suite.
*/
class sql_test : public ignite_runner_suite {
protected:
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"}, {});
client.get_sql().execute(nullptr, {"CREATE TABLE TEST(ID INT PRIMARY KEY, VAL VARCHAR)"}, {});
for (std::int32_t i = 0; i < 10; ++i) {
client.get_sql().execute(nullptr, {"INSERT INTO TEST VALUES (?, ?)"}, {i, "s-" + std::to_string(i)});
}
client.get_sql().execute(nullptr,
{"INSERT INTO TBL_ALL_COLUMNS_SQL VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"},
{std::int64_t(42), std::string("test"), std::int8_t(1), std::int16_t(2), std::int32_t(3), std::int64_t(4),
.5f, .6, uuid(0x123e4567e89b12d3, 0x7456426614174000), ignite_date(2023, 2, 7),
ignite_time(17, 4, 12, 3543634), ignite_time(17, 4, 12, 3543634),
ignite_date_time({2020, 7, 28}, {2, 15, 52, 6349879}),
ignite_date_time({2020, 7, 28}, {2, 15, 52, 6349879}), ignite_timestamp(3875238472, 248760634),
ignite_timestamp(3875238472, 248760634),
std::vector<std::byte>{std::byte(1), std::byte(2), std::byte(42)}, big_decimal(123456789098765), true});
}
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, {"DELETE FROM TBL_ALL_COLUMNS_SQL"}, {});
client.get_sql().execute(nullptr, {"DROP TABLE TEST"}, {});
client.get_sql().execute(nullptr, {"DROP TABLE IF EXISTS TestDdlDml"}, {});
}
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));
}
void TearDown() override {
// remove all
}
/** Ignite client. */
ignite_client m_client;
};
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());
size_t i = 0;
for (auto &column : columns) {
EXPECT_EQ(i, meta.index_of(std::get<0>(column)));
EXPECT_EQ(meta.columns()[i].name(), std::get<0>(column));
EXPECT_EQ(meta.columns()[i].type(), std::get<1>(column));
++i;
}
}
TEST_F(sql_test, sql_simple_select) {
auto result_set = m_client.get_sql().execute(nullptr, {"select 42, 'Lorem'"}, {});
EXPECT_FALSE(result_set.was_applied());
EXPECT_TRUE(result_set.has_rowset());
EXPECT_EQ(-1, result_set.affected_rows());
// TODO: Uncomment after https://issues.apache.org/jira/browse/IGNITE-19106 Column namings are partially broken
// check_columns(result_set.metadata(), {{"42", ignite_type::INT32}, {"'Lorem'", ignite_type::STRING}});
auto page = result_set.current_page();
EXPECT_EQ(1, page.size());
EXPECT_EQ(42, page.front().get(0).get<std::int32_t>());
EXPECT_EQ("Lorem", page.front().get(1).get<std::string>());
EXPECT_FALSE(result_set.has_more_pages());
EXPECT_EQ(0, result_set.current_page().size());
}
TEST_F(sql_test, sql_table_select) {
auto result_set = m_client.get_sql().execute(nullptr, {"select id, val from TEST order by id"}, {});
EXPECT_FALSE(result_set.was_applied());
EXPECT_TRUE(result_set.has_rowset());
EXPECT_EQ(-1, result_set.affected_rows());
check_columns(result_set.metadata(), {{"ID", ignite_type::INT32}, {"VAL", ignite_type::STRING}});
auto page = result_set.current_page();
EXPECT_EQ(10, page.size());
for (std::int32_t i = 0; i < std::int32_t(page.size()); ++i) {
EXPECT_EQ(i, page[i].get(0).get<std::int32_t>());
EXPECT_EQ("s-" + std::to_string(i), page[i].get(1).get<std::string>());
}
EXPECT_FALSE(result_set.has_more_pages());
EXPECT_EQ(0, result_set.current_page().size());
}
TEST_F(sql_test, sql_select_multiple_pages) {
sql_statement statement{"select id, val from TEST order by id"};
statement.page_size(1);
auto result_set = m_client.get_sql().execute(nullptr, statement, {});
EXPECT_FALSE(result_set.was_applied());
EXPECT_TRUE(result_set.has_rowset());
EXPECT_EQ(-1, result_set.affected_rows());
check_columns(result_set.metadata(), {{"ID", ignite_type::INT32}, {"VAL", ignite_type::STRING}});
for (std::int32_t i = 0; i < 10; ++i) {
auto page = result_set.current_page();
EXPECT_EQ(1, page.size()) << "i=" << i;
EXPECT_EQ(i, page.front().get(0).get<std::int32_t>());
EXPECT_EQ("s-" + std::to_string(i), page.front().get(1).get<std::string>());
if (i < 9) {
ASSERT_TRUE(result_set.has_more_pages());
result_set.fetch_next_page();
}
}
EXPECT_FALSE(result_set.has_more_pages());
EXPECT_EQ(0, result_set.current_page().size());
}
TEST_F(sql_test, sql_close_non_empty_cursor) {
sql_statement statement{"select id, val from TEST order by id"};
statement.page_size(3);
auto result_set = m_client.get_sql().execute(nullptr, statement, {});
EXPECT_FALSE(result_set.was_applied());
EXPECT_TRUE(result_set.has_rowset());
EXPECT_EQ(-1, result_set.affected_rows());
auto page = result_set.current_page();
ASSERT_TRUE(result_set.has_more_pages());
result_set.close();
}
TEST_F(sql_test, sql_ddl_dml) {
auto result_set = m_client.get_sql().execute(nullptr, {"DROP TABLE IF EXISTS SQL_DDL_DML_TEST"}, {});
EXPECT_FALSE(result_set.has_rowset());
EXPECT_EQ(-1, result_set.affected_rows());
EXPECT_TRUE(result_set.metadata().columns().empty());
result_set =
m_client.get_sql().execute(nullptr, {"CREATE TABLE SQL_DDL_DML_TEST(ID BIGINT PRIMARY KEY, VAL VARCHAR)"}, {});
EXPECT_TRUE(result_set.was_applied());
EXPECT_FALSE(result_set.has_rowset());
EXPECT_EQ(-1, result_set.affected_rows());
EXPECT_TRUE(result_set.metadata().columns().empty());
result_set = m_client.get_sql().execute(
nullptr, {"INSERT INTO SQL_DDL_DML_TEST VALUES (?, ?)"}, {std::int64_t(13), std::string("Hello")});
EXPECT_FALSE(result_set.was_applied());
EXPECT_FALSE(result_set.has_rowset());
EXPECT_EQ(1, result_set.affected_rows());
EXPECT_TRUE(result_set.metadata().columns().empty());
result_set = m_client.get_sql().execute(
nullptr, {"INSERT INTO SQL_DDL_DML_TEST VALUES (?, ?)"}, {std::int64_t(14), std::string("World")});
EXPECT_FALSE(result_set.was_applied());
EXPECT_FALSE(result_set.has_rowset());
EXPECT_EQ(1, result_set.affected_rows());
EXPECT_TRUE(result_set.metadata().columns().empty());
result_set = m_client.get_sql().execute(nullptr, {"UPDATE SQL_DDL_DML_TEST SET VAL = ?"}, {std::string("Test")});
EXPECT_FALSE(result_set.was_applied());
EXPECT_FALSE(result_set.has_rowset());
EXPECT_EQ(2, result_set.affected_rows());
EXPECT_TRUE(result_set.metadata().columns().empty());
result_set = m_client.get_sql().execute(nullptr, {"DROP TABLE SQL_DDL_DML_TEST"}, {});
EXPECT_TRUE(result_set.was_applied());
EXPECT_FALSE(result_set.has_rowset());
EXPECT_EQ(-1, result_set.affected_rows());
EXPECT_TRUE(result_set.metadata().columns().empty());
}
TEST_F(sql_test, sql_insert_null) {
auto result_set = m_client.get_sql().execute(nullptr, {"DROP TABLE IF EXISTS SQL_INSERT_NULL_TEST"}, {});
result_set =
m_client.get_sql().execute(nullptr, {"CREATE TABLE SQL_INSERT_NULL_TEST(ID INT PRIMARY KEY, VAL VARCHAR)"}, {});
ASSERT_TRUE(result_set.was_applied());
result_set = m_client.get_sql().execute(nullptr, {"INSERT INTO SQL_INSERT_NULL_TEST VALUES (13, NULL)"}, {});
EXPECT_FALSE(result_set.was_applied());
EXPECT_FALSE(result_set.has_rowset());
EXPECT_EQ(1, result_set.affected_rows());
EXPECT_TRUE(result_set.metadata().columns().empty());
result_set = m_client.get_sql().execute(nullptr, {"DROP TABLE SQL_INSERT_NULL_TEST"}, {});
EXPECT_TRUE(result_set.was_applied());
}
TEST_F(sql_test, sql_invalid_query) {
EXPECT_THROW(
{
try {
m_client.get_sql().execute(nullptr, {"not a query"}, {});
} catch (const ignite_error &e) {
EXPECT_THAT(e.what_str(), ::testing::HasSubstr("Failed to parse query: Non-query expression"));
throw;
}
},
ignite_error);
}
TEST_F(sql_test, sql_unknown_table) {
EXPECT_THROW(
{
try {
m_client.get_sql().execute(nullptr, {"select id from unknown_table"}, {});
} catch (const ignite_error &e) {
EXPECT_THAT(e.what_str(), ::testing::HasSubstr("Object 'UNKNOWN_TABLE' not found"));
throw;
}
},
ignite_error);
}
TEST_F(sql_test, sql_unknown_column) {
EXPECT_THROW(
{
try {
m_client.get_sql().execute(nullptr, {"select unknown_column from test"}, {});
} catch (const ignite_error &e) {
EXPECT_THAT(e.what_str(), ::testing::HasSubstr("Column 'UNKNOWN_COLUMN' not found in any table"));
throw;
}
},
ignite_error);
}
TEST_F(sql_test, sql_create_existing_table) {
EXPECT_THROW(
{
try {
m_client.get_sql().execute(nullptr, {"CREATE TABLE TEST(ID INT PRIMARY KEY, VAL VARCHAR)"}, {});
} catch (const ignite_error &e) {
EXPECT_THAT(e.what_str(), ::testing::HasSubstr("Table already exists"));
throw;
}
},
ignite_error);
}
TEST_F(sql_test, sql_add_existing_column) {
EXPECT_THROW(
{
try {
m_client.get_sql().execute(nullptr, {"ALTER TABLE TEST ADD COLUMN ID INT"}, {});
} catch (const ignite_error &e) {
EXPECT_THAT(e.what_str(), ::testing::HasSubstr("Column already exists"));
throw;
}
},
ignite_error);
}
TEST_F(sql_test, sql_alter_nonexisting_table) {
EXPECT_THROW(
{
try {
m_client.get_sql().execute(nullptr, {"ALTER TABLE UNKNOWN_TABLE ADD COLUMN ID INT"}, {});
} catch (const ignite_error &e) {
EXPECT_THAT(e.what_str(), ::testing::HasSubstr("The table does not exist"));
throw;
}
},
ignite_error);
}
TEST_F(sql_test, sql_statement_defaults) {
sql_statement statement;
EXPECT_EQ(statement.page_size(), sql_statement::DEFAULT_PAGE_SIZE);
EXPECT_EQ(statement.schema(), sql_statement::DEFAULT_SCHEMA);
EXPECT_EQ(statement.timeout(), sql_statement::DEFAULT_TIMEOUT);
}
TEST_F(sql_test, decimal_literal) {
auto result_set = m_client.get_sql().execute(nullptr, {"SELECT CAST('12345.6789' AS DECIMAL(9, 4))"}, {});
EXPECT_TRUE(result_set.has_rowset());
auto value = result_set.current_page().front().get(0).get<big_decimal>();
EXPECT_EQ(4, value.get_scale());
EXPECT_EQ(9, value.get_precision());
std::stringstream ss;
ss << value;
auto value_str = ss.str();
EXPECT_EQ("12345.6789", value_str);
}
TEST_F(sql_test, all_type_arguments) {
auto result_set = m_client.get_sql().execute(nullptr,
{"select str,int8,int16,int32,int64,float,double,uuid,date,\"TIME\",time2,"
"\"DATETIME\",datetime2,timestamp,timestamp2,blob,decimal,boolean from TBL_ALL_COLUMNS_SQL"},
{});
EXPECT_TRUE(result_set.has_rowset());
auto row = result_set.current_page().front();
EXPECT_EQ(row.get(0).get<std::string>(), "test");
EXPECT_EQ(row.get(1).get<std::int8_t>(), 1);
EXPECT_EQ(row.get(2).get<std::int16_t>(), 2);
EXPECT_EQ(row.get(3).get<std::int32_t>(), 3);
EXPECT_EQ(row.get(4).get<std::int64_t>(), 4);
EXPECT_FLOAT_EQ(row.get(5).get<float>(), 0.5f);
EXPECT_DOUBLE_EQ(row.get(6).get<double>(), 0.6);
EXPECT_EQ(row.get(7).get<uuid>(), uuid(0x123e4567e89b12d3, 0x7456426614174000));
EXPECT_EQ(row.get(8).get<ignite_date>(), ignite_date(2023, 2, 7));
EXPECT_EQ(row.get(9).get<ignite_time>(), ignite_time(17, 4, 12, 3000000));
EXPECT_EQ(row.get(10).get<ignite_time>(), ignite_time(17, 4, 12, 3000000));
EXPECT_EQ(row.get(11).get<ignite_date_time>(), ignite_date_time({2020, 7, 28}, {2, 15, 52, 6000000}));
EXPECT_EQ(row.get(12).get<ignite_date_time>(), ignite_date_time({2020, 7, 28}, {2, 15, 52, 6000000}));
EXPECT_EQ(row.get(13).get<ignite_timestamp>(), ignite_timestamp(3875238472, 248000000));
EXPECT_EQ(row.get(14).get<ignite_timestamp>(), ignite_timestamp(3875238472, 248000000));
EXPECT_EQ(row.get(16).get<big_decimal>(), big_decimal(123456789098765));
EXPECT_EQ(row.get(17).get<bool>(), true);
auto blob = row.get(15).get<std::vector<std::byte>>();
EXPECT_EQ(blob[0], std::byte(1));
EXPECT_EQ(blob[1], std::byte(2));
EXPECT_EQ(blob[2], std::byte(42));
}
TEST_F(sql_test, uuid_literal) {
auto result_set =
m_client.get_sql().execute(nullptr, {"SELECT CAST('df6bbb13-f2d2-42b4-bef9-7ab8524a0704' AS UUID)"}, {});
EXPECT_TRUE(result_set.has_rowset());
auto value = result_set.current_page().front().get(0).get<uuid>();
std::stringstream ss;
ss << value;
auto value_str = ss.str();
EXPECT_EQ("df6bbb13-f2d2-42b4-bef9-7ab8524a0704", value_str);
}
TEST_F(sql_test, uuid_argument) {
uuid req{0x123e4567e89b12d3, 0x7456426614174000};
auto result_set =
m_client.get_sql().execute(nullptr, {"select MAX(UUID) from TBL_ALL_COLUMNS_SQL WHERE UUID = ?"}, {req});
EXPECT_TRUE(result_set.has_rowset());
auto value = result_set.current_page().front().get(0).get<uuid>();
EXPECT_EQ(req, value);
}