blob: 1769b9a6a63d3251e49b6318e891b4923a13ec85 [file]
/*
* 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 "odbc_connection.h"
#include "odbc_suite.h"
#include "ignite/common/detail/string_utils.h"
#include <gtest/gtest.h>
#include <algorithm>
#include <string>
#include <vector>
using namespace ignite;
/**
* Checks single row result set for correct work with SQLGetData.
*
* @param stmt Statement.
*/
void check_single_row_result_set_with_get_data(SQLHSTMT stmt) {
SQLRETURN ret = SQLFetch(stmt);
if (!SQL_SUCCEEDED(ret))
FAIL() << get_odbc_error_message(SQL_HANDLE_STMT, stmt);
char buf[1024];
SQLLEN buf_len = sizeof(buf);
ret = SQLGetData(stmt, 1, SQL_C_CHAR, buf, sizeof(buf), &buf_len);
if (!SQL_SUCCEEDED(ret))
FAIL() << get_odbc_error_message(SQL_HANDLE_STMT, stmt);
ret = SQLFetch(stmt);
ASSERT_EQ(ret, SQL_NO_DATA);
ret = SQLGetData(stmt, 1, SQL_C_CHAR, buf, sizeof(buf), &buf_len);
ASSERT_EQ(ret, SQL_ERROR);
EXPECT_EQ(get_odbc_error_state(SQL_HANDLE_STMT, stmt), "24000");
}
/**
* Check string column.
*
* @param stmt Statement.
* @param colId Column ID to check.
* @param value Expected value.
*/
void check_string_column(SQLHSTMT stmt, int colId, const std::string &value) {
char buf[1024];
SQLLEN bufLen = sizeof(buf);
SQLRETURN ret = SQLGetData(stmt, colId, SQL_C_CHAR, buf, sizeof(buf), &bufLen);
if (!SQL_SUCCEEDED(ret))
FAIL() << get_odbc_error_message(SQL_HANDLE_STMT, stmt);
if (bufLen <= 0)
EXPECT_TRUE(value.empty());
else
EXPECT_EQ(std::string(buf, static_cast<size_t>(bufLen)), value);
}
/**
* Check result set column metadata using SQLDescribeCol.
*
* @param stmt Statement.
* @param idx Index.
* @param exp_name Expected name.
* @param exp_data_type Expected data type.
* @param exp_size Expected column size.
* @param exp_scale Expected column scale.
* @param exp_nullability expected nullability.
*/
void check_column_meta_with_sqldescribe_col(SQLHSTMT stmt, SQLUSMALLINT idx, const std::string &exp_name,
SQLSMALLINT exp_data_type, SQLULEN exp_size, SQLSMALLINT exp_scale, SQLSMALLINT exp_nullability) {
std::vector<SQLCHAR> name(ODBC_BUFFER_SIZE);
SQLSMALLINT name_len = 0;
SQLSMALLINT data_type = 0;
SQLULEN size;
SQLSMALLINT scale;
SQLSMALLINT nullability;
SQLRETURN ret = SQLDescribeCol(
stmt, idx, &name[0], (SQLSMALLINT) name.size(), &name_len, &data_type, &size, &scale, &nullability);
ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
EXPECT_GE(name_len, 0);
EXPECT_LE(name_len, static_cast<SQLSMALLINT>(ODBC_BUFFER_SIZE));
std::string name_str(name.begin(), name.begin() + name_len);
EXPECT_EQ(name_str, exp_name);
EXPECT_EQ(data_type, exp_data_type);
EXPECT_EQ(size, exp_size);
EXPECT_EQ(scale, exp_scale);
EXPECT_EQ(nullability, exp_nullability);
}
/**
* Check result set column metadata using SQLColAttribute.
*
* @param stmt Statement.
* @param idx Index.
* @param exp_name Expected name.
* @param exp_data_type Expected data type.
* @param exp_size Expected column size.
* @param exp_scale Expected column scale.
* @param exp_nullability expected nullability.
*/
void check_column_meta_with_sqlcol_attribute(SQLHSTMT stmt, SQLUSMALLINT idx, const std::string &exp_name,
SQLLEN exp_data_type, SQLULEN exp_size, SQLLEN exp_scale, SQLLEN exp_nullability) {
std::vector<SQLCHAR> name(ODBC_BUFFER_SIZE);
SQLSMALLINT name_len = 0;
SQLLEN data_type = 0;
SQLLEN size;
SQLLEN scale;
SQLLEN nullability;
SQLRETURN ret = SQLColAttribute(stmt, idx, SQL_DESC_NAME, &name[0], (SQLSMALLINT) name.size(), &name_len, nullptr);
ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
ret = SQLColAttribute(stmt, idx, SQL_DESC_TYPE, nullptr, 0, nullptr, &data_type);
ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
ret = SQLColAttribute(stmt, idx, SQL_DESC_PRECISION, nullptr, 0, nullptr, &size);
ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
ret = SQLColAttribute(stmt, idx, SQL_DESC_SCALE, nullptr, 0, nullptr, &scale);
ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
ret = SQLColAttribute(stmt, idx, SQL_DESC_NULLABLE, nullptr, 0, nullptr, &nullability);
ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, stmt);
EXPECT_GE(name_len, 0);
EXPECT_LE(name_len, static_cast<SQLSMALLINT>(ODBC_BUFFER_SIZE));
std::string name_str(name.begin(), name.begin() + name_len);
EXPECT_EQ(name_str, exp_name);
EXPECT_EQ(data_type, exp_data_type);
EXPECT_EQ(size, exp_size);
EXPECT_EQ(scale, exp_scale);
EXPECT_EQ(nullability, exp_nullability);
}
/**
* Test suite.
*/
class meta_queries_test : public odbc_suite {
public:
static void SetUpTestSuite() {
odbc_connection conn;
conn.odbc_connect(get_basic_connection_string());
auto table_avail = conn.wait_for_table(TABLE_NAME_ALL_COLUMNS_SQL, std::chrono::seconds(10));
if (!table_avail) {
FAIL() << "Table '" + TABLE_NAME_ALL_COLUMNS_SQL + "' is not available";
}
conn.exec_query("DROP TABLE IF EXISTS META_QUERIES_TEST");
SQLRETURN ret = conn.exec_query("CREATE TABLE META_QUERIES_TEST(ID INT PRIMARY KEY, STR VARCHAR(60))");
if (!SQL_SUCCEEDED(ret)) {
FAIL() << conn.get_statement_error_message();
}
}
static void TearDownTestSuite() {
odbc_connection conn;
conn.odbc_connect(get_basic_connection_string());
conn.exec_query("DROP TABLE META_QUERIES_TEST");
}
void SetUp() override {
odbc_connect(get_basic_connection_string());
exec_query("DELETE FROM " + TABLE_NAME_ALL_COLUMNS_SQL);
odbc_clean_up();
}
void TearDown() override {
odbc_connect(get_basic_connection_string());
exec_query("DROP TABLE IF EXISTS test_scale_precision");
odbc_clean_up();
}
/**
* @param exec Function to call before tests. May be PrepareQuery or ExecQuery.
*
* 1. Connect to node using ODBC.
* 2. Create table with decimal and char columns with specified size and scale.
* 3. Execute or prepare statement.
* 4. Check precision and scale of every column using SQLDescribeCol.
*/
template<typename F1, typename F2>
void check_col_precision_and_scale(F1 exec, F2 check) {
odbc_connect(get_basic_connection_string());
SQLRETURN ret = exec_query("create table test_scale_precision("
" id int primary key,"
" dec1 decimal(3,0),"
" dec2 decimal(42,12),"
" dec3 decimal,"
" vchar1 varchar(3),"
" vchar2 varchar(42),"
" vchar3 varchar not null,"
" vchar4 varchar"
")");
ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, m_statement);
ret = SQLFreeStmt(m_statement, SQL_CLOSE);
ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, m_statement);
ret = exec_query(
"insert into "
"test_scale_precision(id, dec1, dec2, dec3, vchar1, vchar2, vchar3, vchar4) "
"values (1, 12, 160.23, -1234.56789, 'TST', 'Lorem Ipsum', 'C', 'Some test varchar')");
ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, m_statement);
ret = SQLFreeStmt(m_statement, SQL_CLOSE);
ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, m_statement);
ret = (this->*exec)("select id, dec1, dec2, dec3, vchar1, vchar2, vchar3, vchar4 from PUBLIC.test_scale_precision");
ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, m_statement);
SQLSMALLINT columnCount = 0;
ret = SQLNumResultCols(m_statement, &columnCount);
ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, m_statement);
EXPECT_EQ(columnCount, 8);
check(m_statement, 1, "ID", SQL_INTEGER, 10, 0, SQL_NO_NULLS);
check(m_statement, 2, "DEC1", SQL_DECIMAL, 3, 0, SQL_NULLABLE);
check(m_statement, 3, "DEC2", SQL_DECIMAL, 42, 12, SQL_NULLABLE);
check(m_statement, 4, "DEC3", SQL_DECIMAL, 32767, 0, SQL_NULLABLE);
check(m_statement, 5, "VCHAR1", SQL_VARCHAR, 3, 0, SQL_NULLABLE);
check(m_statement, 6, "VCHAR2", SQL_VARCHAR, 42, 0, SQL_NULLABLE);
check(m_statement, 7, "VCHAR3", SQL_VARCHAR, 65536, 0, SQL_NO_NULLS);
check(m_statement, 8, "VCHAR4", SQL_VARCHAR, 65536, 0, SQL_NULLABLE);
}
void insert_test_string() {
auto insert_req = "INSERT INTO " + TABLE_NAME_ALL_COLUMNS_SQL + "(key, str) VALUES(42, 'Lorem ipsum')";
SQLRETURN ret = exec_query(insert_req);
if (!SQL_SUCCEEDED(ret))
FAIL() << get_odbc_error_message(SQL_HANDLE_STMT, m_statement);
// Resetting parameters.
ret = SQLFreeStmt(m_statement, SQL_RESET_PARAMS);
if (!SQL_SUCCEEDED(ret))
FAIL() << get_odbc_error_message(SQL_HANDLE_STMT, m_statement);
}
void check_parameter(SQLUSMALLINT idx, SQLSMALLINT expDataType, SQLSMALLINT expNullability) {
SQLSMALLINT dataType{0};
SQLSMALLINT nullability{0};
SQLRETURN ret = SQLDescribeParam(m_statement, idx, &dataType, NULL, NULL, &nullability);
ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, m_statement);
ASSERT_EQ(expDataType, dataType);
ASSERT_EQ(expNullability, nullability);
}
void check_parameter(SQLUSMALLINT idx, SQLSMALLINT expDataType, SQLSMALLINT expNullability, SQLULEN expParamSize,
SQLSMALLINT expDecDigits) {
SQLSMALLINT dataType{0};
SQLULEN paramSize{0};
SQLSMALLINT decDigits{0};
SQLSMALLINT nullability{0};
SQLRETURN ret = SQLDescribeParam(m_statement, idx, &dataType, &paramSize, &decDigits, &nullability);
ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, m_statement);
ASSERT_EQ(expDataType, dataType);
ASSERT_EQ(expNullability, nullability);
ASSERT_EQ(expParamSize, paramSize);
ASSERT_EQ(expDecDigits, decDigits);
}
};
TEST_F(meta_queries_test, test_get_type_info_all_types) {
odbc_connect(get_basic_connection_string());
SQLRETURN ret = SQLGetTypeInfo(m_statement, SQL_ALL_TYPES);
if (!SQL_SUCCEEDED(ret))
FAIL() << (get_odbc_error_message(SQL_HANDLE_STMT, m_statement));
constexpr auto TYPES_NUM = 15;
for (int i = 0; i < TYPES_NUM; ++i) {
ret = SQLFetch(m_statement);
EXPECT_EQ(ret, SQL_SUCCESS) << "Index " << i;
}
ret = SQLFetch(m_statement);
EXPECT_EQ(ret, SQL_NO_DATA);
}
TEST_F(meta_queries_test, date_type_column_attribute_curdate) {
odbc_connect(get_basic_connection_string());
SQLCHAR req[] = "select {fn CURDATE()}";
SQLRETURN ret = SQLExecDirect(m_statement, req, SQL_NTS);
if (!SQL_SUCCEEDED(ret))
FAIL() << (get_odbc_error_message(SQL_HANDLE_STMT, m_statement));
SQLLEN int_val = 0;
ret = SQLColAttribute(m_statement, 1, SQL_DESC_TYPE, nullptr, 0, nullptr, &int_val);
if (!SQL_SUCCEEDED(ret))
FAIL() << (get_odbc_error_message(SQL_HANDLE_STMT, m_statement));
EXPECT_EQ(int_val, SQL_TYPE_DATE);
}
TEST_F(meta_queries_test, date_type_column_attribute_literal) {
odbc_connect(get_basic_connection_string());
SQLCHAR req[] = "select DATE '2020-10-25'";
SQLExecDirect(m_statement, req, SQL_NTS);
SQLLEN int_val = 0;
SQLRETURN ret = SQLColAttribute(m_statement, 1, SQL_DESC_TYPE, nullptr, 0, nullptr, &int_val);
if (!SQL_SUCCEEDED(ret))
FAIL() << (get_odbc_error_message(SQL_HANDLE_STMT, m_statement));
EXPECT_EQ(int_val, SQL_TYPE_DATE);
}
TEST_F(meta_queries_test, date_type_column_attribute_field) {
odbc_connect(get_basic_connection_string());
SQLCHAR req[] = "select {fn CONVERT(\"DATE\", DATE)} from TBL_ALL_COLUMNS_SQL";
SQLRETURN ret = SQLExecDirect(m_statement, req, SQL_NTS);
if (!SQL_SUCCEEDED(ret))
FAIL() << (get_odbc_error_message(SQL_HANDLE_STMT, m_statement));
SQLLEN int_val = 0;
ret = SQLColAttribute(m_statement, 1, SQL_DESC_TYPE, nullptr, 0, nullptr, &int_val);
if (!SQL_SUCCEEDED(ret))
FAIL() << (get_odbc_error_message(SQL_HANDLE_STMT, m_statement));
EXPECT_EQ(int_val, SQL_TYPE_DATE);
}
TEST_F(meta_queries_test, time_type_column_attribute_literal) {
odbc_connect(get_basic_connection_string());
SQLCHAR req[] = "select TIME '12:42:13'";
SQLExecDirect(m_statement, req, SQL_NTS);
SQLLEN int_val = 0;
SQLRETURN ret = SQLColAttribute(m_statement, 1, SQL_DESC_TYPE, nullptr, 0, nullptr, &int_val);
if (!SQL_SUCCEEDED(ret))
FAIL() << (get_odbc_error_message(SQL_HANDLE_STMT, m_statement));
EXPECT_EQ(int_val, SQL_TYPE_TIME);
}
TEST_F(meta_queries_test, time_type_column_attribute_field) {
odbc_connect(get_basic_connection_string());
SQLCHAR req[] = "select time2 from TBL_ALL_COLUMNS_SQL";
SQLExecDirect(m_statement, req, SQL_NTS);
SQLLEN int_val = 0;
SQLRETURN ret = SQLColAttribute(m_statement, 1, SQL_DESC_TYPE, nullptr, 0, nullptr, &int_val);
if (!SQL_SUCCEEDED(ret))
FAIL() << (get_odbc_error_message(SQL_HANDLE_STMT, m_statement));
EXPECT_EQ(int_val, SQL_TYPE_TIME);
}
TEST_F(meta_queries_test, col_attributes_column_length) {
odbc_connect(get_basic_connection_string());
SQLCHAR req[] = "select str from META_QUERIES_TEST";
SQLExecDirect(m_statement, req, SQL_NTS);
SQLLEN int_val;
SQLCHAR str_buf[1024];
SQLSMALLINT str_len;
SQLRETURN ret = SQLColAttribute(m_statement, 1, SQL_COLUMN_LENGTH, str_buf, sizeof(str_buf), &str_len, &int_val);
if (!SQL_SUCCEEDED(ret))
FAIL() << (get_odbc_error_message(SQL_HANDLE_STMT, m_statement));
EXPECT_EQ(int_val, 60);
}
TEST_F(meta_queries_test, col_attributes_column_presicion) {
odbc_connect(get_basic_connection_string());
SQLCHAR req[] = "select str from META_QUERIES_TEST";
SQLExecDirect(m_statement, req, SQL_NTS);
SQLLEN int_val;
SQLCHAR str_buf[1024];
SQLSMALLINT str_len;
SQLRETURN ret = SQLColAttribute(m_statement, 1, SQL_COLUMN_PRECISION, str_buf, sizeof(str_buf), &str_len, &int_val);
if (!SQL_SUCCEEDED(ret))
FAIL() << (get_odbc_error_message(SQL_HANDLE_STMT, m_statement));
EXPECT_EQ(int_val, 60);
}
TEST_F(meta_queries_test, col_attributes_column_scale) {
odbc_connect(get_basic_connection_string());
SQLCHAR req[] = "select str from TBL_ALL_COLUMNS_SQL";
SQLExecDirect(m_statement, req, SQL_NTS);
SQLLEN int_val;
SQLCHAR str_buf[1024];
SQLSMALLINT str_len;
SQLRETURN ret = SQLColAttribute(m_statement, 1, SQL_COLUMN_SCALE, str_buf, sizeof(str_buf), &str_len, &int_val);
if (!SQL_SUCCEEDED(ret))
FAIL() << (get_odbc_error_message(SQL_HANDLE_STMT, m_statement));
}
TEST_F(meta_queries_test, col_attributes_column_length_prepare) {
odbc_connect(get_basic_connection_string());
insert_test_string();
SQLCHAR req[] = "select \"DECIMAL\" from TBL_ALL_COLUMNS_SQL";
SQLPrepare(m_statement, req, SQL_NTS);
SQLLEN int_val;
SQLCHAR str_buf[1024];
SQLSMALLINT str_len;
SQLRETURN ret = SQLColAttribute(m_statement, 1, SQL_COLUMN_LENGTH, str_buf, sizeof(str_buf), &str_len, &int_val);
if (!SQL_SUCCEEDED(ret))
FAIL() << (get_odbc_error_message(SQL_HANDLE_STMT, m_statement));
EXPECT_EQ(int_val, 19);
ret = SQLExecute(m_statement);
ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, m_statement);
ret = SQLColAttribute(m_statement, 1, SQL_COLUMN_LENGTH, str_buf, sizeof(str_buf), &str_len, &int_val);
if (!SQL_SUCCEEDED(ret))
FAIL() << (get_odbc_error_message(SQL_HANDLE_STMT, m_statement));
EXPECT_EQ(int_val, 19);
}
TEST_F(meta_queries_test, col_attributes_column_presicion_prepare) {
odbc_connect(get_basic_connection_string());
insert_test_string();
SQLCHAR req[] = "select \"DECIMAL\" from TBL_ALL_COLUMNS_SQL";
SQLPrepare(m_statement, req, SQL_NTS);
SQLLEN int_val;
SQLCHAR str_buf[1024];
SQLSMALLINT str_len;
SQLRETURN ret = SQLColAttribute(m_statement, 1, SQL_COLUMN_PRECISION, str_buf, sizeof(str_buf), &str_len, &int_val);
if (!SQL_SUCCEEDED(ret))
FAIL() << (get_odbc_error_message(SQL_HANDLE_STMT, m_statement));
EXPECT_EQ(int_val, 19);
ret = SQLExecute(m_statement);
ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, m_statement);
ret = SQLColAttribute(m_statement, 1, SQL_COLUMN_PRECISION, str_buf, sizeof(str_buf), &str_len, &int_val);
if (!SQL_SUCCEEDED(ret))
FAIL() << (get_odbc_error_message(SQL_HANDLE_STMT, m_statement));
EXPECT_EQ(int_val, 19);
}
TEST_F(meta_queries_test, col_attributes_column_scale_prepare) {
odbc_connect(get_basic_connection_string());
insert_test_string();
SQLCHAR req[] = "select \"DECIMAL\" from TBL_ALL_COLUMNS_SQL";
SQLPrepare(m_statement, req, SQL_NTS);
SQLLEN int_val;
SQLCHAR str_buf[1024];
SQLSMALLINT str_len;
SQLRETURN ret = SQLColAttribute(m_statement, 1, SQL_COLUMN_SCALE, str_buf, sizeof(str_buf), &str_len, &int_val);
if (!SQL_SUCCEEDED(ret))
FAIL() << (get_odbc_error_message(SQL_HANDLE_STMT, m_statement));
EXPECT_EQ(int_val, 3);
ret = SQLExecute(m_statement);
ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, m_statement);
ret = SQLColAttribute(m_statement, 1, SQL_COLUMN_SCALE, str_buf, sizeof(str_buf), &str_len, &int_val);
if (!SQL_SUCCEEDED(ret))
FAIL() << (get_odbc_error_message(SQL_HANDLE_STMT, m_statement));
EXPECT_EQ(int_val, 3);
}
TEST_F(meta_queries_test, col_attributes_column_nullability_prepare) {
odbc_connect(get_basic_connection_string());
insert_test_string();
SQLCHAR req[] = "select \"DECIMAL\" from TBL_ALL_COLUMNS_SQL";
SQLPrepare(m_statement, req, SQL_NTS);
SQLLEN int_val;
SQLCHAR str_buf[1024];
SQLSMALLINT str_len;
SQLRETURN ret = SQLColAttribute(m_statement, 1, SQL_DESC_NULLABLE, str_buf, sizeof(str_buf), &str_len, &int_val);
if (!SQL_SUCCEEDED(ret))
FAIL() << (get_odbc_error_message(SQL_HANDLE_STMT, m_statement));
EXPECT_EQ(int_val, SQL_NULLABLE);
ret = SQLExecute(m_statement);
ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, m_statement);
ret = SQLColAttribute(m_statement, 1, SQL_DESC_NULLABLE, str_buf, sizeof(str_buf), &str_len, &int_val);
if (!SQL_SUCCEEDED(ret))
FAIL() << (get_odbc_error_message(SQL_HANDLE_STMT, m_statement));
EXPECT_EQ(int_val, SQL_NULLABLE);
}
TEST_F(meta_queries_test, get_data_with_get_type_info) {
odbc_connect(get_basic_connection_string());
SQLRETURN ret = SQLGetTypeInfo(m_statement, SQL_VARCHAR);
if (!SQL_SUCCEEDED(ret))
FAIL() << (get_odbc_error_message(SQL_HANDLE_STMT, m_statement));
check_single_row_result_set_with_get_data(m_statement);
}
TEST_F(meta_queries_test, get_data_with_tables) {
odbc_connect(get_basic_connection_string());
SQLCHAR any[] = "%";
auto table = to_sqlchar(to_upper(TABLE_NAME_ALL_COLUMNS_SQL));
SQLRETURN ret = SQLTables(m_statement, any, SQL_NTS, any, SQL_NTS, table.data(), SQL_NTS, any, 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);
}
TEST_F(meta_queries_test, get_data_with_columns) {
odbc_connect(get_basic_connection_string());
SQLCHAR any[] = "%";
SQLCHAR table[] = "META_QUERIES_TEST";
SQLCHAR column[] = "STR";
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);
}
TEST_F(meta_queries_test, get_data_with_select_query) {
odbc_connect(get_basic_connection_string());
SQLCHAR insert_req[] = "insert into META_QUERIES_TEST(id, str) VALUES(1, 'Lorem ipsum')";
SQLRETURN ret = SQLExecDirect(m_statement, insert_req, SQL_NTS);
if (!SQL_SUCCEEDED(ret))
FAIL() << (get_odbc_error_message(SQL_HANDLE_STMT, m_statement));
SQLCHAR select_req[] = "select str from META_QUERIES_TEST";
ret = SQLExecDirect(m_statement, select_req, 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);
}
TEST_F(meta_queries_test, insert_too_long_value_fails) {
odbc_connect(get_basic_connection_string());
SQLCHAR insert_req[] = "insert into META_QUERIES_TEST(id, str) "
"VALUES(42, '0000000000111111111122222222223333333333444444444455555555556666666666')";
SQLRETURN ret = SQLExecDirect(m_statement, insert_req, SQL_NTS);
if (SQL_SUCCEEDED(ret))
FAIL() << ("Exception need to be raised");
}
TEST_F(meta_queries_test, get_info_scroll_options) {
odbc_connect(get_basic_connection_string());
SQLUINTEGER val = 0;
SQLRETURN ret = SQLGetInfo(m_conn, SQL_SCROLL_OPTIONS, &val, 0, nullptr);
if (!SQL_SUCCEEDED(ret))
FAIL() << (get_odbc_error_message(SQL_HANDLE_DBC, m_conn));
EXPECT_NE(val, 0);
}
TEST_F(meta_queries_test, ddl_tables_meta) {
odbc_connect(get_basic_connection_string());
SQLCHAR any[] = "%";
SQLCHAR table[] = "META_QUERIES_TEST";
SQLRETURN ret = SQLTables(m_statement, any, SQL_NTS, any, SQL_NTS, table, SQL_NTS, any, SQL_NTS);
if (!SQL_SUCCEEDED(ret))
FAIL() << (get_odbc_error_message(SQL_HANDLE_STMT, m_statement));
ret = SQLFetch(m_statement);
if (!SQL_SUCCEEDED(ret))
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, "META_QUERIES_TEST");
check_string_column(m_statement, 4, "TABLE");
ret = SQLFetch(m_statement);
ASSERT_EQ(ret, SQL_NO_DATA);
}
TEST_F(meta_queries_test, ddl_tables_meta_table_type_list) {
odbc_connect(get_basic_connection_string());
SQLCHAR *type_lists[] = {(SQLCHAR *) "TABLE", (SQLCHAR *) "TABLE,VIEW"};
for (auto &type_list : type_lists) {
SQLCHAR any[] = "%";
SQLCHAR table[] = "META_QUERIES_TEST";
SQLRETURN ret = SQLTables(m_statement, any, SQL_NTS, any, SQL_NTS, table, SQL_NTS, type_list, SQL_NTS);
if (!SQL_SUCCEEDED(ret))
FAIL() << (get_odbc_error_message(SQL_HANDLE_STMT, m_statement));
ret = SQLFetch(m_statement);
if (!SQL_SUCCEEDED(ret))
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, "META_QUERIES_TEST");
check_string_column(m_statement, 4, "TABLE");
ret = SQLFetch(m_statement);
ASSERT_EQ(ret, SQL_NO_DATA);
}
}
template<size_t n, size_t k>
void check_meta(char columns[n][k], SQLLEN columns_len[n], const std::string &table_name) {
std::string catalog(columns[0], columns_len[0]);
std::string schema(columns[1], columns_len[1]);
std::string table(columns[2], columns_len[2]);
std::string table_type(columns[3], columns_len[3]);
EXPECT_EQ(catalog, std::string(""));
EXPECT_EQ(table, table_name);
EXPECT_EQ(table_type, std::string("TABLE"));
EXPECT_EQ(columns_len[4], SQL_NULL_DATA);
}
TEST_F(meta_queries_test, tables_meta) {
odbc_connect(get_basic_connection_string());
SQLRETURN ret;
enum { COLUMNS_NUM = 5 };
// Five columns: TABLE_CAT, TABLE_SCHEM, TABLE_NAME, TABLE_TYPE, REMARKS
char columns[COLUMNS_NUM][ODBC_BUFFER_SIZE];
SQLLEN columns_len[COLUMNS_NUM];
// Binding columns.
for (size_t i = 0; i < COLUMNS_NUM; ++i) {
columns_len[i] = ODBC_BUFFER_SIZE;
ret = SQLBindCol(
m_statement, static_cast<SQLSMALLINT>(i + 1), SQL_C_CHAR, columns[i], columns_len[i], &columns_len[i]);
if (!SQL_SUCCEEDED(ret))
FAIL() << (get_odbc_error_message(SQL_HANDLE_STMT, m_statement));
}
SQLCHAR catalog_pattern[] = "%";
SQLCHAR schema_pattern[] = "%";
SQLCHAR table_pattern[] = "TBL_ALL_COLUMNS%";
SQLCHAR table_type_pattern[] = "%";
ret = SQLTables(m_statement, catalog_pattern, SQL_NTS, schema_pattern, SQL_NTS, table_pattern, SQL_NTS,
table_type_pattern, SQL_NTS);
if (!SQL_SUCCEEDED(ret))
FAIL() << (get_odbc_error_message(SQL_HANDLE_STMT, m_statement));
ret = SQLFetch(m_statement);
if (!SQL_SUCCEEDED(ret))
FAIL() << (get_odbc_error_message(SQL_HANDLE_STMT, m_statement));
check_meta<COLUMNS_NUM, ODBC_BUFFER_SIZE>(columns, columns_len, "TBL_ALL_COLUMNS");
ret = SQLFetch(m_statement);
if (!SQL_SUCCEEDED(ret))
FAIL() << (get_odbc_error_message(SQL_HANDLE_STMT, m_statement));
check_meta<COLUMNS_NUM, ODBC_BUFFER_SIZE>(columns, columns_len, "TBL_ALL_COLUMNS_NOT_NULL");
ret = SQLFetch(m_statement);
if (!SQL_SUCCEEDED(ret))
FAIL() << (get_odbc_error_message(SQL_HANDLE_STMT, m_statement));
check_meta<COLUMNS_NUM, ODBC_BUFFER_SIZE>(columns, columns_len, "TBL_ALL_COLUMNS_SQL");
ret = SQLFetch(m_statement);
EXPECT_TRUE(ret == SQL_NO_DATA);
}
TEST_F(meta_queries_test, ddl_columns_meta) {
odbc_connect(get_basic_connection_string());
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[] = "DDL_COLUMNS_META";
ret = SQLColumns(m_statement, any, SQL_NTS, any, SQL_NTS, table, SQL_NTS, any, SQL_NTS);
if (!SQL_SUCCEEDED(ret))
FAIL() << (get_odbc_error_message(SQL_HANDLE_STMT, m_statement));
ret = SQLFetch(m_statement);
if (!SQL_SUCCEEDED(ret))
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, "DDL_COLUMNS_META");
check_string_column(m_statement, 4, "ID");
ret = SQLFetch(m_statement);
if (!SQL_SUCCEEDED(ret))
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, "DDL_COLUMNS_META");
check_string_column(m_statement, 4, "TEST_COLUMN");
ret = SQLFetch(m_statement);
ASSERT_EQ(ret, SQL_NO_DATA);
}
TEST_F(meta_queries_test, ddl_columns_meta_escaped) {
odbc_connect(get_basic_connection_string());
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))
FAIL() << (get_odbc_error_message(SQL_HANDLE_STMT, m_statement));
SQLCHAR any[] = "%";
SQLCHAR table[] = "ESG\\_FOCUS";
ret = SQLColumns(m_statement, any, SQL_NTS, any, SQL_NTS, table, SQL_NTS, any, SQL_NTS);
if (!SQL_SUCCEEDED(ret))
FAIL() << (get_odbc_error_message(SQL_HANDLE_STMT, m_statement));
ret = SQLFetch(m_statement);
if (!SQL_SUCCEEDED(ret))
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, "ESG_FOCUS");
check_string_column(m_statement, 4, "ID");
ret = SQLFetch(m_statement);
if (!SQL_SUCCEEDED(ret))
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, "ESG_FOCUS");
check_string_column(m_statement, 4, "TEST_COLUMN");
ret = SQLFetch(m_statement);
ASSERT_EQ(ret, SQL_NO_DATA);
}
TEST_F(meta_queries_test, sqlnum_result_cols_after_sqlprepare) {
odbc_connect(get_basic_connection_string());
SQLRETURN ret = prepare_query("select 1, TRUE, 'Lorem Ipsum', 42 * 2");
ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, m_statement);
SQLSMALLINT column_count = 0;
ret = SQLNumResultCols(m_statement, &column_count);
ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, m_statement);
EXPECT_EQ(column_count, 4);
ret = SQLExecute(m_statement);
ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, m_statement);
column_count = 0;
ret = SQLNumResultCols(m_statement, &column_count);
ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, m_statement);
EXPECT_EQ(column_count, 4);
}
/**
* Check that SQLDescribeCol return valid scale and precision for columns of different type after Prepare.
*/
TEST_F(meta_queries_test, sqldescribe_col_precision_and_scale_after_prepare) {
check_col_precision_and_scale(&odbc_suite::prepare_query, &check_column_meta_with_sqldescribe_col);
}
/**
* Check that SQLDescribeCol return valid scale and precision for columns of different type after Execute.
*/
TEST_F(meta_queries_test, sqldescribe_col_precision_and_scale_after_exec) {
check_col_precision_and_scale(&odbc_suite::exec_query, &check_column_meta_with_sqldescribe_col);
}
/**
* Check that SQLColAttribute return valid scale and precision for columns of different type after Prepare.
*/
TEST_F(meta_queries_test, sqlcol_attribute_precision_and_scale_after_prepare) {
check_col_precision_and_scale(&odbc_suite::prepare_query, &check_column_meta_with_sqlcol_attribute);
}
/**
* Check that SQLColAttribute return valid scale and precision for columns of different type after Execute.
*/
TEST_F(meta_queries_test, sqlcol_attribute_precision_and_scale_after_exec) {
check_col_precision_and_scale(&odbc_suite::exec_query, &check_column_meta_with_sqlcol_attribute);
}
TEST_F(meta_queries_test, primary_keys_single_column) {
odbc_connect(get_basic_connection_string());
auto ret = exec_query("drop table if exists primary_keys_single_column");
ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, m_statement);
ret = exec_query("create table if not exists primary_keys_single_column(ID int primary key, TEST_COLUMN varchar)");
ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, m_statement);
SQLCHAR any[] = "%";
SQLCHAR table[] = "PRIMARY_KEYS_SINGLE_COLUMN";
ret = SQLPrimaryKeys(m_statement, any, SQL_NTS, any, SQL_NTS, table, SQL_NTS);
ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, m_statement);
ret = SQLFetch(m_statement);
ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, m_statement);
check_string_column(m_statement, 1, "");
check_string_column(m_statement, 2, "PUBLIC");
check_string_column(m_statement, 3, "PRIMARY_KEYS_SINGLE_COLUMN");
check_string_column(m_statement, 4, "ID");
check_string_column(m_statement, 5, "1");
check_string_column(m_statement, 6, "PK_PRIMARY_KEYS_SINGLE_COLUMN");
ret = SQLFetch(m_statement);
ASSERT_EQ(ret, SQL_NO_DATA);
}
TEST_F(meta_queries_test, primary_keys_multiple_columns) {
odbc_connect(get_basic_connection_string());
auto ret = exec_query("drop table if exists primary_keys_multiple_columns");
ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, m_statement);
ret = exec_query(
"create table if not exists primary_keys_multiple_columns(ID1 int, ID2 varchar, primary key (ID1, ID2))");
ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, m_statement);
SQLCHAR any[] = "%";
SQLCHAR table[] = "PRIMARY_KEYS_MULTIPLE_COLUMNS";
ret = SQLPrimaryKeys(m_statement, any, SQL_NTS, any, SQL_NTS, table, SQL_NTS);
ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, m_statement);
ret = SQLFetch(m_statement);
ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, m_statement);
check_string_column(m_statement, 1, "");
check_string_column(m_statement, 2, "PUBLIC");
check_string_column(m_statement, 3, "PRIMARY_KEYS_MULTIPLE_COLUMNS");
check_string_column(m_statement, 4, "ID1");
check_string_column(m_statement, 5, "1");
check_string_column(m_statement, 6, "PK_PRIMARY_KEYS_MULTIPLE_COLUMNS");
ret = SQLFetch(m_statement);
ODBC_FAIL_ON_ERROR(ret, SQL_HANDLE_STMT, m_statement);
check_string_column(m_statement, 1, "");
check_string_column(m_statement, 2, "PUBLIC");
check_string_column(m_statement, 3, "PRIMARY_KEYS_MULTIPLE_COLUMNS");
check_string_column(m_statement, 4, "ID2");
check_string_column(m_statement, 5, "2");
check_string_column(m_statement, 6, "PK_PRIMARY_KEYS_MULTIPLE_COLUMNS");
ret = SQLFetch(m_statement);
ASSERT_EQ(ret, SQL_NO_DATA);
}
TEST_F(meta_queries_test, sql_describe_param) {
odbc_connect(get_basic_connection_string());
SQLCHAR request[] =
"INSERT INTO TBL_ALL_COLUMNS_SQL("
" key,str,int8,int16,int32,int64,\"FLOAT\",\"DOUBLE\",\"UUID\",\"DATE\",\"TIME\",\"DATETIME\",\"DECIMAL\""
") VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
SQLRETURN ret = SQLPrepare(m_statement, request, SQL_NTS);
if (!SQL_SUCCEEDED(ret))
FAIL() << (get_odbc_error_message(SQL_HANDLE_STMT, m_statement));
check_parameter(1, SQL_BIGINT, SQL_NULLABLE);
check_parameter(2, SQL_VARCHAR, SQL_NULLABLE);
check_parameter(3, SQL_TINYINT, SQL_NULLABLE);
check_parameter(4, SQL_SMALLINT, SQL_NULLABLE);
check_parameter(5, SQL_INTEGER, SQL_NULLABLE);
check_parameter(6, SQL_BIGINT, SQL_NULLABLE);
check_parameter(7, SQL_FLOAT, SQL_NULLABLE);
check_parameter(8, SQL_DOUBLE, SQL_NULLABLE);
check_parameter(9, SQL_GUID, SQL_NULLABLE);
check_parameter(10, SQL_TYPE_DATE, SQL_NULLABLE);
check_parameter(11, SQL_TYPE_TIME, SQL_NULLABLE);
check_parameter(12, SQL_TYPE_TIMESTAMP, SQL_NULLABLE);
check_parameter(13, SQL_DECIMAL, SQL_NULLABLE, 19, 3);
}