diff --git a/src/IntegrationTests/ITODBCCatalog/test_odbc_catalog.cpp b/src/IntegrationTests/ITODBCCatalog/test_odbc_catalog.cpp index b0f0be509..7d2512ddf 100644 --- a/src/IntegrationTests/ITODBCCatalog/test_odbc_catalog.cpp +++ b/src/IntegrationTests/ITODBCCatalog/test_odbc_catalog.cpp @@ -80,6 +80,10 @@ class TestSQLTables : public Fixture {}; class TestSQLColumns : public Fixture {}; +class TestSQLColAttribute : public Fixture {}; + +class TestSQLDescribeCol : public Fixture {}; + class TestSQLGetTypeInfo : public Fixture {}; // //class TestSQLCatalogKeys : public testing::Test { @@ -937,6 +941,364 @@ TEST_F(TestSQLColumns, META_DATA_CASE_INSENSITIVE_NOT_FOUND) { CheckRows(expected, result); } +TEST_F(TestSQLColAttribute, SQL_DESC_CONCISE_TYPE) { + SQLRETURN ret = SQL_ERROR; + std::wstring query = L"SELECT INTEGER \'1\' from ODBCTest.IoT LIMIT 1"; + ret = SQLPrepare(m_hstmt, (SQLTCHAR *)query.c_str(), SQL_NTS); + EXPECT_TRUE(SQL_SUCCEEDED(ret)); + SQLLEN numeric_attr = 0; + + ret = SQLColAttribute(m_hstmt, 1, SQL_DESC_CONCISE_TYPE, nullptr, 0, + nullptr, &numeric_attr); + EXPECT_TRUE(SQL_SUCCEEDED(ret)); + EXPECT_EQ(SQL_INTEGER, numeric_attr); + LogAnyDiagnostics(SQL_HANDLE_STMT, m_hstmt, ret); +} + +TEST_F(TestSQLDescribeCol, INTEGER_COLUMN) { + SQLRETURN ret = SQL_ERROR; + std::wstring query = L"SELECT INTEGER \'1\' from ODBCTest.IoT LIMIT 1"; + ret = SQLPrepare(m_hstmt, (SQLTCHAR*)query.c_str(), SQL_NTS); + EXPECT_TRUE(SQL_SUCCEEDED(ret)); + SQLTCHAR column_name[60]; + SQLSMALLINT column_name_length; + SQLSMALLINT data_type; + SQLULEN column_size; + SQLSMALLINT decimal_digits; + SQLSMALLINT nullable; + ret = SQLDescribeCol(m_hstmt, 1, column_name, 60, &column_name_length, + &data_type, &column_size, &decimal_digits, &nullable); + EXPECT_TRUE(SQL_SUCCEEDED(ret)); + std::wstring expected_column_name = L"_col0"; + EXPECT_STREQ(expected_column_name.c_str(), column_name); + EXPECT_EQ(SQL_INTEGER, data_type); + EXPECT_EQ((SQLULEN)11, column_size); + EXPECT_EQ(0, decimal_digits); + EXPECT_EQ(SQL_NULLABLE, nullable); + LogAnyDiagnostics(SQL_HANDLE_STMT, m_hstmt, ret); +} + +TEST_F(TestSQLDescribeCol, DOUBLE_COLUMN) { + SQLRETURN ret = SQL_ERROR; + std::wstring query = L"SELECT DOUBLE \'1.0\' from ODBCTest.IoT LIMIT 1"; + ret = SQLPrepare(m_hstmt, (SQLTCHAR *)query.c_str(), SQL_NTS); + EXPECT_TRUE(SQL_SUCCEEDED(ret)); + SQLTCHAR column_name[60]; + SQLSMALLINT column_name_length; + SQLSMALLINT data_type; + SQLULEN column_size; + SQLSMALLINT decimal_digits; + SQLSMALLINT nullable; + ret = SQLDescribeCol(m_hstmt, 1, column_name, 60, &column_name_length, + &data_type, &column_size, &decimal_digits, &nullable); + EXPECT_TRUE(SQL_SUCCEEDED(ret)); + std::wstring expected_column_name = L"_col0"; + EXPECT_STREQ(expected_column_name.c_str(), column_name); + EXPECT_EQ(SQL_DOUBLE, data_type); + EXPECT_EQ((SQLULEN)15, column_size); + EXPECT_EQ(0, decimal_digits); + EXPECT_EQ(SQL_NULLABLE, nullable); + LogAnyDiagnostics(SQL_HANDLE_STMT, m_hstmt, ret); +} + +TEST_F(TestSQLDescribeCol, BIGINT_COLUMN) { + SQLRETURN ret = SQL_ERROR; + std::wstring query = L"SELECT BIGINT \'2147483648\' from ODBCTest.IoT LIMIT 1"; + ret = SQLPrepare(m_hstmt, (SQLTCHAR *)query.c_str(), SQL_NTS); + EXPECT_TRUE(SQL_SUCCEEDED(ret)); + SQLTCHAR column_name[60]; + SQLSMALLINT column_name_length; + SQLSMALLINT data_type; + SQLULEN column_size; + SQLSMALLINT decimal_digits; + SQLSMALLINT nullable; + ret = SQLDescribeCol(m_hstmt, 1, column_name, 60, &column_name_length, + &data_type, &column_size, &decimal_digits, &nullable); + EXPECT_TRUE(SQL_SUCCEEDED(ret)); + std::wstring expected_column_name = L"_col0"; + EXPECT_STREQ(expected_column_name.c_str(), column_name); + EXPECT_EQ(SQL_BIGINT, data_type); + EXPECT_EQ((SQLULEN)20, column_size); + EXPECT_EQ(0, decimal_digits); + EXPECT_EQ(SQL_NULLABLE, nullable); + LogAnyDiagnostics(SQL_HANDLE_STMT, m_hstmt, ret); +} + +TEST_F(TestSQLDescribeCol, BOOLEAN_COLUMN) { + SQLRETURN ret = SQL_ERROR; + std::wstring query = + L"SELECT true from ODBCTest.IoT LIMIT 1"; + ret = SQLPrepare(m_hstmt, (SQLTCHAR *)query.c_str(), SQL_NTS); + EXPECT_TRUE(SQL_SUCCEEDED(ret)); + SQLTCHAR column_name[60]; + SQLSMALLINT column_name_length; + SQLSMALLINT data_type; + SQLULEN column_size; + SQLSMALLINT decimal_digits; + SQLSMALLINT nullable; + ret = SQLDescribeCol(m_hstmt, 1, column_name, 60, &column_name_length, + &data_type, &column_size, &decimal_digits, &nullable); + EXPECT_TRUE(SQL_SUCCEEDED(ret)); + std::wstring expected_column_name = L"_col0"; + EXPECT_STREQ(expected_column_name.c_str(), column_name); + EXPECT_EQ(SQL_BIT, data_type); + EXPECT_EQ((SQLULEN)1, column_size); + EXPECT_EQ(0, decimal_digits); + EXPECT_EQ(SQL_NULLABLE, nullable); + LogAnyDiagnostics(SQL_HANDLE_STMT, m_hstmt, ret); +} + +TEST_F(TestSQLDescribeCol, VARCHAR_COLUMN) { + SQLRETURN ret = SQL_ERROR; + std::wstring query = L"SELECT VARCHAR\'ABCDEFG\' from ODBCTest.IoT LIMIT 1"; + ret = SQLPrepare(m_hstmt, (SQLTCHAR *)query.c_str(), SQL_NTS); + EXPECT_TRUE(SQL_SUCCEEDED(ret)); + SQLTCHAR column_name[60]; + SQLSMALLINT column_name_length; + SQLSMALLINT data_type; + SQLULEN column_size; + SQLSMALLINT decimal_digits; + SQLSMALLINT nullable; + ret = SQLDescribeCol(m_hstmt, 1, column_name, 60, &column_name_length, + &data_type, &column_size, &decimal_digits, &nullable); + EXPECT_TRUE(SQL_SUCCEEDED(ret)); + std::wstring expected_column_name = L"_col0"; + EXPECT_STREQ(expected_column_name.c_str(), column_name); + EXPECT_EQ(SQL_WVARCHAR, data_type); + EXPECT_EQ((SQLULEN)INT_MAX, column_size); + EXPECT_EQ(0, decimal_digits); + EXPECT_EQ(SQL_NULLABLE, nullable); + LogAnyDiagnostics(SQL_HANDLE_STMT, m_hstmt, ret); +} + +TEST_F(TestSQLDescribeCol, TIMESERIES_COLUMN) { + SQLRETURN ret = SQL_ERROR; + std::wstring query = + L"WITH binned_timeseries AS(SELECT TIMESTAMP'2021-03-05 " + L"14:18:30.123456789' AS binned_timestamp, ROW(null, " + L"ARRAY[ARRAY[ROW(12345, ARRAY[1, 2, 3])]]) " + L"AS data FROM ODBCTest.IoT LIMIT " + L"1), interpolated_timeseries AS(SELECT " + L"CREATE_TIME_SERIES(binned_timestamp, data) FROM binned_timeseries) " + L"SELECT *FROM interpolated_timeseries"; + ret = SQLPrepare(m_hstmt, (SQLTCHAR *)query.c_str(), SQL_NTS); + ASSERT_TRUE(SQL_SUCCEEDED(ret)); + LogAnyDiagnostics(SQL_HANDLE_STMT, m_hstmt, ret); + SQLTCHAR column_name[60]; + SQLSMALLINT column_name_length; + SQLSMALLINT data_type; + SQLULEN column_size; + SQLSMALLINT decimal_digits; + SQLSMALLINT nullable; + ret = SQLDescribeCol(m_hstmt, 1, column_name, 60, &column_name_length, + &data_type, &column_size, &decimal_digits, &nullable); + EXPECT_TRUE(SQL_SUCCEEDED(ret)); + std::wstring expected_column_name = L"_col0"; + EXPECT_STREQ(expected_column_name.c_str(), column_name); + EXPECT_EQ(SQL_WVARCHAR, data_type); + EXPECT_EQ((SQLULEN)INT_MAX, column_size); + EXPECT_EQ(0, decimal_digits); + EXPECT_EQ(SQL_NULLABLE, nullable); + LogAnyDiagnostics(SQL_HANDLE_STMT, m_hstmt, ret); +} + +TEST_F(TestSQLDescribeCol, ARRAY_COLUMN) { + SQLRETURN ret = SQL_ERROR; + std::wstring query = + L"SELECT ARRAY[ARRAY[ARRAY[ARRAY[1.1, 2.3], ARRAY[1.1, 2.3]]], " + L"ARRAY[ARRAY[ARRAY[1.1, 2.3], ARRAY[1.1, 2.3]]]] from ODBCTest.IoT " + L"LIMIT 1"; + ret = SQLPrepare(m_hstmt, (SQLTCHAR *)query.c_str(), SQL_NTS); + EXPECT_TRUE(SQL_SUCCEEDED(ret)); + SQLTCHAR column_name[60]; + SQLSMALLINT column_name_length; + SQLSMALLINT data_type; + SQLULEN column_size; + SQLSMALLINT decimal_digits; + SQLSMALLINT nullable; + ret = SQLDescribeCol(m_hstmt, 1, column_name, 60, &column_name_length, + &data_type, &column_size, &decimal_digits, &nullable); + EXPECT_TRUE(SQL_SUCCEEDED(ret)); + std::wstring expected_column_name = L"_col0"; + EXPECT_STREQ(expected_column_name.c_str(), column_name); + EXPECT_EQ(SQL_WVARCHAR, data_type); + EXPECT_EQ((SQLULEN)INT_MAX, column_size); + EXPECT_EQ(0, decimal_digits); + EXPECT_EQ(SQL_NULLABLE, nullable); + LogAnyDiagnostics(SQL_HANDLE_STMT, m_hstmt, ret); +} + +TEST_F(TestSQLDescribeCol, ROW_COLUMN) { + SQLRETURN ret = SQL_ERROR; + std::wstring query = + L"SELECT ROW(ROW(ROW(INTEGER '03', BIGINT '10', true), " + L"ARRAY[ARRAY[1,2],ARRAY[1.1,2.2]])) from ODBCTest.IoT " + L"LIMIT 1"; + ret = SQLPrepare(m_hstmt, (SQLTCHAR *)query.c_str(), SQL_NTS); + EXPECT_TRUE(SQL_SUCCEEDED(ret)); + SQLTCHAR column_name[60]; + SQLSMALLINT column_name_length; + SQLSMALLINT data_type; + SQLULEN column_size; + SQLSMALLINT decimal_digits; + SQLSMALLINT nullable; + ret = SQLDescribeCol(m_hstmt, 1, column_name, 60, &column_name_length, + &data_type, &column_size, &decimal_digits, &nullable); + EXPECT_TRUE(SQL_SUCCEEDED(ret)); + std::wstring expected_column_name = L"_col0"; + EXPECT_STREQ(expected_column_name.c_str(), column_name); + EXPECT_EQ(SQL_WVARCHAR, data_type); + EXPECT_EQ((SQLULEN)INT_MAX, column_size); + EXPECT_EQ(0, decimal_digits); + EXPECT_EQ(SQL_NULLABLE, nullable); + LogAnyDiagnostics(SQL_HANDLE_STMT, m_hstmt, ret); +} + +TEST_F(TestSQLDescribeCol, NULL_COLUMN) { + SQLRETURN ret = SQL_ERROR; + std::wstring query = L"SELECT null from ODBCTest.IoT LIMIT 1"; + ret = SQLPrepare(m_hstmt, (SQLTCHAR *)query.c_str(), SQL_NTS); + EXPECT_TRUE(SQL_SUCCEEDED(ret)); + SQLTCHAR column_name[60]; + SQLSMALLINT column_name_length; + SQLSMALLINT data_type; + SQLULEN column_size; + SQLSMALLINT decimal_digits; + SQLSMALLINT nullable; + ret = SQLDescribeCol(m_hstmt, 1, column_name, 60, &column_name_length, + &data_type, &column_size, &decimal_digits, &nullable); + EXPECT_TRUE(SQL_SUCCEEDED(ret)); + std::wstring expected_column_name = L"_col0"; + EXPECT_STREQ(expected_column_name.c_str(), column_name); + EXPECT_EQ(SQL_WVARCHAR, data_type); + EXPECT_EQ((SQLULEN)INT_MAX, column_size); + EXPECT_EQ(0, decimal_digits); + EXPECT_EQ(SQL_NULLABLE, nullable); + LogAnyDiagnostics(SQL_HANDLE_STMT, m_hstmt, ret); +} + +TEST_F(TestSQLDescribeCol, TIMESTAMP_COLUMN) { + SQLRETURN ret = SQL_ERROR; + std::wstring query = + L"SELECT TIMESTAMP \'2021-01-02 18:01:13.000000000\' from ODBCTest.IoT " + L"LIMIT 1"; + ret = SQLPrepare(m_hstmt, (SQLTCHAR *)query.c_str(), SQL_NTS); + EXPECT_TRUE(SQL_SUCCEEDED(ret)); + SQLTCHAR column_name[60]; + SQLSMALLINT column_name_length; + SQLSMALLINT data_type; + SQLULEN column_size; + SQLSMALLINT decimal_digits; + SQLSMALLINT nullable; + ret = SQLDescribeCol(m_hstmt, 1, column_name, 60, &column_name_length, + &data_type, &column_size, &decimal_digits, &nullable); + EXPECT_TRUE(SQL_SUCCEEDED(ret)); + std::wstring expected_column_name = L"_col0"; + EXPECT_STREQ(expected_column_name.c_str(), column_name); + EXPECT_EQ(SQL_TYPE_TIMESTAMP, data_type); + std::string expected = "2021-01-02 18:01:13.000000000"; + EXPECT_EQ((SQLULEN)expected.size(), column_size); + EXPECT_EQ(0, decimal_digits); + EXPECT_EQ(SQL_NULLABLE, nullable); + LogAnyDiagnostics(SQL_HANDLE_STMT, m_hstmt, ret); +} + +TEST_F(TestSQLDescribeCol, DATE_COLUMN) { + SQLRETURN ret = SQL_ERROR; + std::wstring query = + L"SELECT DATE \'2021-01-02\' from ODBCTest.IoT LIMIT 1"; + ret = SQLPrepare(m_hstmt, (SQLTCHAR *)query.c_str(), SQL_NTS); + EXPECT_TRUE(SQL_SUCCEEDED(ret)); + SQLTCHAR column_name[60]; + SQLSMALLINT column_name_length; + SQLSMALLINT data_type; + SQLULEN column_size; + SQLSMALLINT decimal_digits; + SQLSMALLINT nullable; + ret = SQLDescribeCol(m_hstmt, 1, column_name, 60, &column_name_length, + &data_type, &column_size, &decimal_digits, &nullable); + EXPECT_TRUE(SQL_SUCCEEDED(ret)); + std::wstring expected_column_name = L"_col0"; + EXPECT_STREQ(expected_column_name.c_str(), column_name); + EXPECT_EQ(SQL_TYPE_DATE, data_type); + std::string expected = "2021-01-02"; + EXPECT_EQ((SQLULEN)expected.size(), column_size); + EXPECT_EQ(0, decimal_digits); + EXPECT_EQ(SQL_NULLABLE, nullable); + LogAnyDiagnostics(SQL_HANDLE_STMT, m_hstmt, ret); +} + +TEST_F(TestSQLDescribeCol, TIME_COLUMN) { + SQLRETURN ret = SQL_ERROR; + std::wstring query = + L"SELECT TIME \'06:39:45.123456789\' from ODBCTest.IoT LIMIT 1"; + ret = SQLPrepare(m_hstmt, (SQLTCHAR *)query.c_str(), SQL_NTS); + EXPECT_TRUE(SQL_SUCCEEDED(ret)); + SQLTCHAR column_name[60]; + SQLSMALLINT column_name_length; + SQLSMALLINT data_type; + SQLULEN column_size; + SQLSMALLINT decimal_digits; + SQLSMALLINT nullable; + ret = SQLDescribeCol(m_hstmt, 1, column_name, 60, &column_name_length, + &data_type, &column_size, &decimal_digits, &nullable); + EXPECT_TRUE(SQL_SUCCEEDED(ret)); + std::wstring expected_column_name = L"_col0"; + EXPECT_STREQ(expected_column_name.c_str(), column_name); + EXPECT_EQ(SQL_TYPE_TIME, data_type); + std::string expected = "06:39:45.123456789"; + EXPECT_EQ((SQLULEN)expected.size(), column_size); + EXPECT_EQ(0, decimal_digits); + EXPECT_EQ(SQL_NULLABLE, nullable); + LogAnyDiagnostics(SQL_HANDLE_STMT, m_hstmt, ret); +} + +TEST_F(TestSQLDescribeCol, INTERVAL_YEAR_TO_MONTH_COLUMN) { + SQLRETURN ret = SQL_ERROR; + std::wstring query = L"SELECT 1year from ODBCTest.IoT LIMIT 1"; + ret = SQLPrepare(m_hstmt, (SQLTCHAR *)query.c_str(), SQL_NTS); + EXPECT_TRUE(SQL_SUCCEEDED(ret)); + SQLTCHAR column_name[60]; + SQLSMALLINT column_name_length; + SQLSMALLINT data_type; + SQLULEN column_size; + SQLSMALLINT decimal_digits; + SQLSMALLINT nullable; + ret = SQLDescribeCol(m_hstmt, 1, column_name, 60, &column_name_length, + &data_type, &column_size, &decimal_digits, &nullable); + EXPECT_TRUE(SQL_SUCCEEDED(ret)); + std::wstring expected_column_name = L"_col0"; + EXPECT_STREQ(expected_column_name.c_str(), column_name); + EXPECT_EQ(SQL_WVARCHAR, data_type); + EXPECT_EQ((SQLULEN)INT_MAX, column_size); + EXPECT_EQ(0, decimal_digits); + EXPECT_EQ(SQL_NULLABLE, nullable); + LogAnyDiagnostics(SQL_HANDLE_STMT, m_hstmt, ret); +} + +TEST_F(TestSQLDescribeCol, INTERVAL_DAY_TO_SECOND_COLUMN) { + SQLRETURN ret = SQL_ERROR; + std::wstring query = L"SELECT 1d from ODBCTest.IoT LIMIT 1"; + ret = SQLPrepare(m_hstmt, (SQLTCHAR *)query.c_str(), SQL_NTS); + EXPECT_TRUE(SQL_SUCCEEDED(ret)); + SQLTCHAR column_name[60]; + SQLSMALLINT column_name_length; + SQLSMALLINT data_type; + SQLULEN column_size; + SQLSMALLINT decimal_digits; + SQLSMALLINT nullable; + ret = SQLDescribeCol(m_hstmt, 1, column_name, 60, &column_name_length, + &data_type, &column_size, &decimal_digits, &nullable); + EXPECT_TRUE(SQL_SUCCEEDED(ret)); + std::wstring expected_column_name = L"_col0"; + EXPECT_STREQ(expected_column_name.c_str(), column_name); + EXPECT_EQ(SQL_WVARCHAR, data_type); + EXPECT_EQ((SQLULEN)INT_MAX, column_size); + EXPECT_EQ(0, decimal_digits); + EXPECT_EQ(SQL_NULLABLE, nullable); + LogAnyDiagnostics(SQL_HANDLE_STMT, m_hstmt, ret); +} + //// We expect an empty result set for PrimaryKeys and ForeignKeys //// Tableau specified catalog and table //// NULL args diff --git a/src/IntegrationTests/ITODBCExecution/test_odbc_execution.cpp b/src/IntegrationTests/ITODBCExecution/test_odbc_execution.cpp index 61ecf839c..5843df999 100644 --- a/src/IntegrationTests/ITODBCExecution/test_odbc_execution.cpp +++ b/src/IntegrationTests/ITODBCExecution/test_odbc_execution.cpp @@ -144,7 +144,7 @@ TEST_F(TestSQLExecute, BASIC) { LogAnyDiagnostics(SQL_HANDLE_STMT, m_hstmt, ret); } -TEST_F(TestSQLExecute, DOUBLE_EXECUTE) { +TEST_F(TestSQLExecute, EXECUTE_TWICE) { std::wstring query = L"SELECT 12345 FROM ODBCTest.IoT LIMIT 5"; SQLRETURN ret = SQLPrepare(m_hstmt, (SQLTCHAR*)query.c_str(), SQL_NTS); LogAnyDiagnostics(SQL_HANDLE_STMT, m_hstmt, ret); @@ -167,6 +167,58 @@ TEST_F(TestSQLExecute, DOUBLE_EXECUTE) { // Second trial ret = SQLExecute(m_hstmt); EXPECT_EQ(SQL_ERROR, ret); + EXPECT_TRUE( + CheckSQLSTATE(SQL_HANDLE_STMT, m_hstmt, SQLSTATE_SEQUENCE_ERROR)); + LogAnyDiagnostics(SQL_HANDLE_STMT, m_hstmt, ret); +} + +TEST_F(TestSQLExecute, EXECUTE_TWICE_WITH_CLOSECURSOR) { + std::wstring query = L"SELECT 12345 FROM ODBCTest.IoT LIMIT 5"; + SQLRETURN ret = SQLPrepare(m_hstmt, (SQLTCHAR*)query.c_str(), SQL_NTS); + LogAnyDiagnostics(SQL_HANDLE_STMT, m_hstmt, ret); + EXPECT_TRUE(SQL_SUCCEEDED(ret)); + ret = SQLExecute(m_hstmt); + EXPECT_TRUE(SQL_SUCCEEDED(ret)); + int cnt = 0; + while ((ret = SQLFetch(m_hstmt)) != SQL_NO_DATA) { + if (SQL_SUCCEEDED(ret)) { + cnt++; + } + SQLINTEGER data = 0; + SQLLEN indicator = 0; + ret = SQLGetData(m_hstmt, 1, SQL_C_SLONG, &data, 0, &indicator); + EXPECT_TRUE(SQL_SUCCEEDED(ret)); + EXPECT_EQ((SQLLEN)sizeof(SQLINTEGER), indicator); + EXPECT_EQ(12345, data); + } + EXPECT_EQ(5, cnt); + // Second trial + ret = SQLCloseCursor(m_hstmt); + EXPECT_TRUE(SQL_SUCCEEDED(ret)); + ret = SQLExecute(m_hstmt); + EXPECT_TRUE(SQL_SUCCEEDED(ret)); + LogAnyDiagnostics(SQL_HANDLE_STMT, m_hstmt, ret); +} + +TEST_F(TestSQLExecute, PREPARE_AND_EXECDIRECT) { + std::wstring query = L"SELECT 12345 FROM ODBCTest.IoT LIMIT 5"; + SQLRETURN ret = SQLPrepare(m_hstmt, (SQLTCHAR*)query.c_str(), SQL_NTS); + LogAnyDiagnostics(SQL_HANDLE_STMT, m_hstmt, ret); + EXPECT_TRUE(SQL_SUCCEEDED(ret)); + ret = SQLExecDirect(m_hstmt, (SQLTCHAR*)query.c_str(), SQL_NTS); + int cnt = 0; + while ((ret = SQLFetch(m_hstmt)) != SQL_NO_DATA) { + if (SQL_SUCCEEDED(ret)) { + cnt++; + } + SQLINTEGER data = 0; + SQLLEN indicator = 0; + ret = SQLGetData(m_hstmt, 1, SQL_C_SLONG, &data, 0, &indicator); + EXPECT_TRUE(SQL_SUCCEEDED(ret)); + EXPECT_EQ((SQLLEN)sizeof(SQLINTEGER), indicator); + EXPECT_EQ(12345, data); + } + EXPECT_EQ(5, cnt); LogAnyDiagnostics(SQL_HANDLE_STMT, m_hstmt, ret); } @@ -238,7 +290,8 @@ TEST_F(TestSQLPrepare, PREPARE_METADATA) { TEST_F(TestSQLPrepare, ERROR_NULL_QUERY) { SQLRETURN ret = SQLPrepare(m_hstmt, NULL, SQL_NTS); EXPECT_EQ(SQL_ERROR, ret); - EXPECT_TRUE(CheckSQLSTATE(SQL_HANDLE_STMT, m_hstmt, SQLSTATE_MEMORY_ALLOCATION_ERROR)); + EXPECT_TRUE(CheckSQLSTATE(SQL_HANDLE_STMT, m_hstmt, + SQLSTATE_INVALID_USE_OF_NULL_POINTER)); LogAnyDiagnostics(SQL_HANDLE_STMT, m_hstmt, ret); } diff --git a/src/odfesqlodbc/communication.cpp b/src/odfesqlodbc/communication.cpp index 0c11af933..9947b3e50 100644 --- a/src/odfesqlodbc/communication.cpp +++ b/src/odfesqlodbc/communication.cpp @@ -80,9 +80,10 @@ bool Communication::SetClientEncoding(const std::string& encoding) { } PrefetchQueue* Communication::GetPrefetchQueue(StatementClass* stmt) { - if (stmt == nullptr || prefetch_queues_map.find(stmt) == prefetch_queues_map.end()) { + if (stmt == nullptr) { return nullptr; - } else { - return prefetch_queues_map[stmt].get(); } + auto queue_it = prefetch_queues_map.find(stmt); + return queue_it == prefetch_queues_map.end() ? nullptr + : queue_it->second.get(); } diff --git a/src/odfesqlodbc/es_apifunc.h b/src/odfesqlodbc/es_apifunc.h index 93ac0c0e0..a11231a56 100644 --- a/src/odfesqlodbc/es_apifunc.h +++ b/src/odfesqlodbc/es_apifunc.h @@ -78,7 +78,7 @@ RETCODE SQL_API ESAPI_StmtError(HSTMT StatementHandle, SQLSMALLINT RecNumber, SQLSMALLINT *TextLength, UWORD flag); RETCODE SQL_API API_ExecDirect(HSTMT StatementHandle, const SQLCHAR *StatementText, - SQLINTEGER TextLength, BOOL commit); + SQLINTEGER TextLength); RETCODE SQL_API API_Execute(HSTMT StatementHandle); RETCODE SQL_API ESAPI_Fetch(HSTMT StatementHandle); RETCODE SQL_API ESAPI_FreeConnect(HDBC ConnectionHandle); diff --git a/src/odfesqlodbc/es_helper.cpp b/src/odfesqlodbc/es_helper.cpp index 1c1a9f81a..dfc31112a 100644 --- a/src/odfesqlodbc/es_helper.cpp +++ b/src/odfesqlodbc/es_helper.cpp @@ -83,10 +83,6 @@ void Disconnect(void* conn) { delete static_cast< Communication* >(conn); } -void TSClearResult(TSResult* ts_result) { - delete ts_result; -} - PrefetchQueue* GetPrefetchQueue(void* conn, StatementClass* stmt) { return conn ? static_cast< Communication* >(conn)->GetPrefetchQueue(stmt) : nullptr; diff --git a/src/odfesqlodbc/es_helper.h b/src/odfesqlodbc/es_helper.h index 8ed80fb45..4529fec0e 100644 --- a/src/odfesqlodbc/es_helper.h +++ b/src/odfesqlodbc/es_helper.h @@ -23,7 +23,6 @@ // C++ interface std::string GetClientEncoding(void* conn); bool SetClientEncoding(void* conn, std::string& encoding); -void TSClearResult(TSResult* ts_result); void* ConnectDBParams(const runtime_options& rt_opts); std::string GetVersion(void* conn); PrefetchQueue* GetPrefetchQueue(void* conn, StatementClass* stmt); diff --git a/src/odfesqlodbc/es_info.cpp b/src/odfesqlodbc/es_info.cpp index ff30cbe1d..cea4f12ec 100644 --- a/src/odfesqlodbc/es_info.cpp +++ b/src/odfesqlodbc/es_info.cpp @@ -428,8 +428,8 @@ void ExecuteQuery(ConnectionClass *conn, HSTMT *stmt, // Execute query if (!SQL_SUCCEEDED(API_ExecDirect( - *stmt, reinterpret_cast< const SQLCHAR * >(query.c_str()), SQL_NTS, - 1))) { + *stmt, reinterpret_cast< const SQLCHAR * >(query.c_str()), + SQL_NTS))) { std::string error_msg = "Failed to execute query '" + query + "'."; throw std::runtime_error(error_msg.c_str()); } diff --git a/src/odfesqlodbc/es_parse_result.cpp b/src/odfesqlodbc/es_parse_result.cpp index 46f5ff5b9..3bccc6480 100644 --- a/src/odfesqlodbc/es_parse_result.cpp +++ b/src/odfesqlodbc/es_parse_result.cpp @@ -28,13 +28,6 @@ bool _CC_from_TSResult( QResultClass *q_res, ConnectionClass *conn, StatementClass *stmt, const char *next_token, const Aws::TimestreamQuery::Model::QueryOutcome &ts_result); -bool _CC_Metadata_from_TSResult( - QResultClass *q_res, ConnectionClass *conn, StatementClass *stmt, - const char *next_token, - const Aws::TimestreamQuery::Model::QueryOutcome &ts_result); -bool _CC_No_Metadata_from_TSResult(QResultClass *q_res, ConnectionClass *conn, const char *next_token, - const Aws::TimestreamQuery::Model::QueryOutcome &ts_result); - /** * Responsible for looping through columns, allocating memory for column fields * and setting column info @@ -217,24 +210,6 @@ BOOL CC_from_TSResult( : FALSE; } -BOOL CC_Metadata_from_TSResult( - QResultClass *q_res, ConnectionClass *conn, StatementClass *stmt, - const char *next_token, - const Aws::TimestreamQuery::Model::QueryOutcome &ts_result) { - ClearError(); - return _CC_Metadata_from_TSResult(q_res, conn, stmt, next_token, ts_result) - ? TRUE - : FALSE; -} - -BOOL CC_No_Metadata_from_TSResult(QResultClass *q_res, ConnectionClass *conn, const char *next_token, - const Aws::TimestreamQuery::Model::QueryOutcome &ts_result) { - ClearError(); - return _CC_No_Metadata_from_TSResult(q_res, conn, next_token, ts_result) - ? TRUE - : FALSE; -} - BOOL CC_Append_Table_Data( const Aws::TimestreamQuery::Model::QueryOutcome &ts_result, QResultClass *q_res, ColumnInfoClass &fields) { @@ -244,70 +219,6 @@ BOOL CC_Append_Table_Data( : FALSE; } -bool _CC_No_Metadata_from_TSResult(QResultClass *q_res, ConnectionClass *conn, const char *next_token, - const Aws::TimestreamQuery::Model::QueryOutcome &ts_result) { - // Note - NULL conn and/or cursor is valid - if (q_res == NULL) - return false; - - try { - - SQLULEN starting_cached_rows = q_res->num_cached_rows; - - // Assign table data and column headers - if (!AssignTableData(ts_result, q_res, *(q_res->fields))) - return false; - std::string command_type = "SELECT"; - // Update fields of QResult to reflect data written - UpdateResultFields(q_res, conn, starting_cached_rows, next_token, - command_type); - - // Return true (success) - return true; - } catch (const std::exception &e) { - SetError(e.what()); - } catch (...) { - SetError("Unknown exception thrown in _CC_No_Metadata_from_TSResult."); - } - - // Exception occurred, return false (error) - return false; -} - -bool _CC_Metadata_from_TSResult( - QResultClass *q_res, ConnectionClass *conn, StatementClass *stmt, - const char *next_token, - const Aws::TimestreamQuery::Model::QueryOutcome &ts_result) { - CSTR func = "_CC_Metadata_from_TSResult"; - // Note - NULL conn and/or cursor is valid - if (q_res == NULL) - return false; - - QR_set_conn(q_res, conn); - try { - // Assign table data and column headers - if (!AssignColumnHeaders(q_res, ts_result)) - return false; - - // Set command type and cursor name - std::string command = "SELECT"; - QR_set_command(q_res, command.c_str()); - QR_set_cursor(q_res, next_token); - if (next_token == NULL) - QR_set_reached_eof(q_res); - - // Return true (success) - return true; - } catch (const std::exception &e) { - SC_set_error(stmt, STMT_EXEC_ERROR, e.what(), func); - } catch (...) { - SC_set_error(stmt, STMT_EXEC_ERROR, "Unknown exception thrown", func); - } - - // Exception occurred, return false (error) - return false; -} - void print_log(const LogLevel &level, const std::string &s) { #if WIN32 #pragma warning(push) diff --git a/src/odfesqlodbc/es_parse_result.h b/src/odfesqlodbc/es_parse_result.h index ebaaa54da..c55b895f9 100644 --- a/src/odfesqlodbc/es_parse_result.h +++ b/src/odfesqlodbc/es_parse_result.h @@ -38,12 +38,6 @@ BOOL CC_from_TSResult( QResultClass *q_res, ConnectionClass *conn, StatementClass *stmt, const char *next_token, const Aws::TimestreamQuery::Model::QueryOutcome &ts_result); -BOOL CC_Metadata_from_TSResult( - QResultClass *q_res, ConnectionClass *conn, StatementClass *stmt, - const char *next_token, - const Aws::TimestreamQuery::Model::QueryOutcome &ts_result); -BOOL CC_No_Metadata_from_TSResult(QResultClass *q_res, ConnectionClass *conn, const char *next_token, - const Aws::TimestreamQuery::Model::QueryOutcome &ts_result); BOOL CC_Append_Table_Data(const Aws::TimestreamQuery::Model::QueryOutcome &ts_result, QResultClass *q_res, ColumnInfoClass &fields); #endif #endif diff --git a/src/odfesqlodbc/es_statement.cpp b/src/odfesqlodbc/es_statement.cpp index 738909436..418d47087 100644 --- a/src/odfesqlodbc/es_statement.cpp +++ b/src/odfesqlodbc/es_statement.cpp @@ -38,7 +38,7 @@ void print_tslog(const std::string &s) { #endif // WIN32 } -RETCODE ExecuteStatement(StatementClass *stmt, BOOL commit) { +RETCODE ExecuteStatement(StatementClass *stmt) { CSTR func = "ExecuteStatement"; int func_cs_count = 0; ConnectionClass *conn = SC_get_conn(stmt); @@ -80,7 +80,7 @@ RETCODE ExecuteStatement(StatementClass *stmt, BOOL commit) { conn->status = CONN_EXECUTING; - QResultClass *res = SendQueryGetResult(stmt, commit); + QResultClass *res = SendQueryGetResult(stmt); if (!res) { if (SC_get_errornumber(stmt) <= 0) { SC_set_error(stmt, STMT_NO_RESPONSE, @@ -150,12 +150,6 @@ RETCODE ExecuteStatement(StatementClass *stmt, BOOL commit) { SC_set_Result(stmt, res); } - // This will commit results for SQLExecDirect and will not commit - // results for SQLPrepare since only metadata is required for SQLPrepare - if (commit) { - GetNextResultSet(stmt); - } - stmt->diag_row_count = res->recent_processed_row_count; return CleanUp(); @@ -216,9 +210,7 @@ SQLRETURN GetNextResultSet(StatementClass *stmt) { RETCODE RePrepareStatement(StatementClass *stmt) { CSTR func = "RePrepareStatement"; - RETCODE result = SC_initialize_and_recycle(stmt); - if (result != SQL_SUCCESS) - return result; + SC_reset_result_for_rerun(stmt); if (!stmt->statement) { SC_set_error(stmt, STMT_NO_MEMORY_ERROR, "Expected statement to be allocated.", func); @@ -258,50 +250,46 @@ RETCODE PrepareStatement(StatementClass *stmt, const SQLCHAR *stmt_str, return SQL_SUCCESS; } -QResultClass *SendQueryGetResult(StatementClass *stmt, BOOL commit) { +QResultClass *SendQueryGetResult(StatementClass *stmt) { CSTR func = "SendQueryGetResult"; if (stmt == NULL) return NULL; + // Execute the query + ConnectionClass *cc = SC_get_conn(stmt); + if (!ExecDirect(cc->conn, stmt, stmt->statement)) { + return NULL; + } + // Allocate QResultClass QResultClass *res = QR_Constructor(); if (res == NULL) return NULL; - // Send command - ConnectionClass *cc = SC_get_conn(stmt); - if (!ExecDirect(cc->conn, stmt, stmt->statement)) { - QR_Destructor(res); - return NULL; - } res->rstatus = PORES_COMMAND_OK; PrefetchQueue *pPrefetchQueue = GetPrefetchQueue(cc->conn, stmt); if (pPrefetchQueue != nullptr && !pPrefetchQueue->IsEmpty()) { if (pPrefetchQueue->WaitForReadinessOfFront()) { bool success = false; - if (commit) { - auto outcome = pPrefetchQueue->Front(); - pPrefetchQueue->Pop(); - if (outcome.IsSuccess()) { - success = CC_from_TSResult(res, cc, stmt, res->cursor_name, - outcome); + auto outcome = pPrefetchQueue->Front(); + pPrefetchQueue->Pop(); + if (outcome.IsSuccess()) { + success = + CC_from_TSResult(res, cc, stmt, res->cursor_name, outcome); + + // Check for pagination + if (!outcome.GetResult().GetNextToken().empty() + && pPrefetchQueue->IsRetrieving()) { + QR_set_next_token( + res, outcome.GetResult().GetNextToken().c_str()); } else { - success = false; - SC_set_error(stmt, STMT_EXEC_ERROR, - outcome.GetError().GetMessage().c_str(), func); + QR_set_next_token(res, NULL); } } else { - // Use Front() to see only - auto outcome = pPrefetchQueue->Front(); - if (outcome.IsSuccess()) { - success = CC_Metadata_from_TSResult( - res, cc, stmt, res->cursor_name, outcome); - } else { - success = false; - SC_set_error(stmt, STMT_EXEC_ERROR, - outcome.GetError().GetMessage().c_str(), func); - } + success = false; + SC_set_error(stmt, STMT_EXEC_ERROR, + outcome.GetError().GetMessage().c_str(), func); } if (!success) { QR_Destructor(res); @@ -324,60 +312,6 @@ QResultClass *SendQueryGetResult(StatementClass *stmt, BOOL commit) { return res; } -RETCODE AssignResult(StatementClass *stmt) { - CSTR func = "AssignResult"; - if (stmt == NULL) - return SQL_ERROR; - - QResultClass *res = SC_get_Result(stmt); - if (!res /*|| !res->ts_result*/) { - return SQL_ERROR; - } - - // Commit result to QResultClass - ConnectionClass *cc = SC_get_conn(stmt); - PrefetchQueue *pPrefetchQueue = GetPrefetchQueue(cc->conn, stmt); - if (pPrefetchQueue != nullptr && !pPrefetchQueue->IsEmpty()) { - if (pPrefetchQueue->WaitForReadinessOfFront()) { - auto outcome = pPrefetchQueue->Front(); - pPrefetchQueue->Pop(); - if (outcome.IsSuccess()) { - if (!CC_No_Metadata_from_TSResult(res, cc, res->cursor_name, - outcome)) { - QR_Destructor(res); - return SQL_ERROR; - } - GetNextResultSet(stmt); - } else { - SC_set_error(stmt, STMT_EXEC_ERROR, - outcome.GetError().GetMessage().c_str(), func); - QR_Destructor(res); - return SQL_ERROR; - } - } else { - SC_set_error(stmt, STMT_OPERATION_CANCELLED, "Operation cancelled", - func); - QR_Destructor(res); - return SQL_ERROR; - } - } else { - if (pPrefetchQueue == nullptr) { - SC_set_error(stmt, STMT_INTERNAL_ERROR, - "PrefetchQueue is not found", func); - } - QR_Destructor(res); - return SQL_ERROR; - } - return SQL_SUCCESS; -} - -void ClearTSResult(void *ts_result) { - if (ts_result != NULL) { - TSResult *es_res = static_cast< TSResult * >(ts_result); - TSClearResult(es_res); - } -} - SQLRETURN API_Cancel(HSTMT hstmt) { // Verify pointer validity and convert to StatementClass if (hstmt == NULL) diff --git a/src/odfesqlodbc/es_statement.h b/src/odfesqlodbc/es_statement.h index feeb7ee59..fb408e5e9 100644 --- a/src/odfesqlodbc/es_statement.h +++ b/src/odfesqlodbc/es_statement.h @@ -26,12 +26,10 @@ extern "C" { #endif RETCODE RePrepareStatement(StatementClass *stmt); RETCODE PrepareStatement(StatementClass* stmt, const SQLCHAR *stmt_str, SQLINTEGER stmt_sz); -RETCODE ExecuteStatement(StatementClass *stmt, BOOL commit); -QResultClass *SendQueryGetResult(StatementClass *stmt, BOOL commit); -RETCODE AssignResult(StatementClass *stmt); +RETCODE ExecuteStatement(StatementClass *stmt); +QResultClass *SendQueryGetResult(StatementClass *stmt); SQLRETURN API_Cancel(HSTMT hstmt); SQLRETURN GetNextResultSet(StatementClass *stmt); -void ClearTSResult(void *ts_result); #ifdef __cplusplus } #endif diff --git a/src/odfesqlodbc/es_types.h b/src/odfesqlodbc/es_types.h index 1b11b1e19..388d28c58 100644 --- a/src/odfesqlodbc/es_types.h +++ b/src/odfesqlodbc/es_types.h @@ -290,13 +290,5 @@ typedef struct runtime_options { #define KEYWORD_DISPLAY_SIZE 255 #define KEYWORD_LENGTH_OF_STR 255 -typedef struct TSResult { - std::string command_type; // Timestream supports SELECT for query only - Aws::TimestreamQuery::Model::QueryResult sdk_result; - TSResult(const std::string& command_type = "SELECT") { - this->command_type = command_type; - } -} TSResult; - #endif #endif diff --git a/src/odfesqlodbc/execute.c b/src/odfesqlodbc/execute.c index 63ab864df..c4ebe0eda 100644 --- a/src/odfesqlodbc/execute.c +++ b/src/odfesqlodbc/execute.c @@ -35,23 +35,72 @@ #include "statement.h" RETCODE SQL_API API_Prepare(HSTMT hstmt, const SQLCHAR *stmt_str, - SQLINTEGER stmt_sz) { + SQLINTEGER stmt_sz) { + CSTR func = "API_Prepare"; if (hstmt == NULL) return SQL_ERROR; // We know cursor is not open at this point StatementClass *stmt = (StatementClass *)hstmt; + size_t original_stmt_len; + if (!stmt_str) { + SC_initialize_and_recycle(stmt); + SC_set_error(stmt, STMT_INVALID_NULL_ARG, "Invalid use of null pointer", + func); + return SQL_ERROR; + } + if (stmt_sz >= 0) + original_stmt_len = stmt_sz; + else if (SQL_NTS == stmt_sz) + original_stmt_len = strlen((char *)stmt_str); + else { + MYLOG(LOG_DEBUG, "invalid length=" FORMAT_INTEGER "\n", stmt_sz); + SC_initialize_and_recycle(stmt); + SC_set_error(stmt, STMT_INVALID_NULL_ARG, "Invalid buffer length", + func); + return SQL_ERROR; + } + + // Construct the metadata statement + const char *metadata_stmt_prefix = "SELECT * FROM ("; + const char *metadata_stmt_suffix = ") AS original LIMIT 0"; + const size_t metadata_stmt_affix_len = 36; + char *metadata_stmt; + metadata_stmt = + calloc(metadata_stmt_affix_len + original_stmt_len + 1, sizeof(char)); + if (!metadata_stmt) { + SC_initialize_and_recycle(stmt); + SC_set_error(stmt, STMT_NO_MEMORY_ERROR, + "No memory available to store statement to get metadata", + func); + return SQL_ERROR; + } + strcpy(metadata_stmt, metadata_stmt_prefix); + strncat(metadata_stmt, (char *)stmt_str, original_stmt_len); + strcat(metadata_stmt, metadata_stmt_suffix); + + // Prepare metadata statement to get metadata // PrepareStatement deallocates memory if necessary - RETCODE ret = PrepareStatement(stmt, stmt_str, stmt_sz); - if (ret != SQL_SUCCESS) + RETCODE ret = PrepareStatement( + stmt, (SQLCHAR *)metadata_stmt, + (SQLINTEGER)(metadata_stmt_affix_len + original_stmt_len)); + + // Not used afterwards + free(metadata_stmt); + + if (ret != SQL_SUCCESS) { return ret; + } - // Execute the statement - ret = ExecuteStatement(stmt, FALSE); + // Execute the metadata statement + ret = ExecuteStatement(stmt); if (ret == SQL_SUCCESS) stmt->prepared = PREPARED; + // Restore to original statement + strncpy_null(stmt->statement, (char *)stmt_str, original_stmt_len + 1); + return ret; } @@ -65,14 +114,15 @@ RETCODE SQL_API API_Execute(HSTMT hstmt) { RETCODE ret = SQL_ERROR; switch (stmt->prepared) { case PREPARED: - ret = AssignResult(stmt); + SC_reset_result_for_rerun(stmt); + ret = ExecuteStatement(stmt); stmt->prepared = EXECUTED; break; case EXECUTED: ret = RePrepareStatement(stmt); if (ret != SQL_SUCCESS) break; - ret = ExecuteStatement(stmt, TRUE); + ret = ExecuteStatement(stmt); if (ret != SQL_SUCCESS) break; stmt->prepared = EXECUTED; @@ -88,7 +138,7 @@ RETCODE SQL_API API_Execute(HSTMT hstmt) { } RETCODE SQL_API API_ExecDirect(HSTMT hstmt, const SQLCHAR *stmt_str, - SQLINTEGER stmt_sz, BOOL commit) { + SQLINTEGER stmt_sz) { if (hstmt == NULL) return SQL_ERROR; @@ -99,7 +149,7 @@ RETCODE SQL_API API_ExecDirect(HSTMT hstmt, const SQLCHAR *stmt_str, return ret; // Execute statement - ret = ExecuteStatement(hstmt, commit); + ret = ExecuteStatement(hstmt); if (ret != SQL_SUCCESS) return ret; stmt->prepared = NOT_PREPARED; diff --git a/src/odfesqlodbc/odbcapi.c b/src/odfesqlodbc/odbcapi.c index ae839aac4..c5ca87110 100644 --- a/src/odfesqlodbc/odbcapi.c +++ b/src/odfesqlodbc/odbcapi.c @@ -276,7 +276,7 @@ RETCODE SQL_API SQLExecDirect(HSTMT StatementHandle, SQLCHAR *StatementText, // Execute statement if statement is ready RETCODE ret = SQL_ERROR; if (!SC_opencheck(stmt, "SQLExecDirect")) - ret = API_ExecDirect(StatementHandle, StatementText, TextLength, 1); + ret = API_ExecDirect(StatementHandle, StatementText, TextLength); // Exit critical LEAVE_STMT_CS(stmt); diff --git a/src/odfesqlodbc/odbcapiw.c b/src/odfesqlodbc/odbcapiw.c index 1654f9d68..6ca376d9b 100644 --- a/src/odfesqlodbc/odbcapiw.c +++ b/src/odfesqlodbc/odbcapiw.c @@ -308,7 +308,7 @@ RETCODE SQL_API SQLExecDirectW(HSTMT StatementHandle, SQLWCHAR *StatementText, RETCODE ret = SQL_ERROR; if (!SC_opencheck(stmt, "SQLExecDirectW")) ret = API_ExecDirect(StatementHandle, (const SQLCHAR *)stxt, - (SQLINTEGER)slen, 1); + (SQLINTEGER)slen); // Exit critical LEAVE_STMT_CS(stmt); diff --git a/src/odfesqlodbc/qresult.c b/src/odfesqlodbc/qresult.c index b769c5f15..e1c717efb 100644 --- a/src/odfesqlodbc/qresult.c +++ b/src/odfesqlodbc/qresult.c @@ -190,7 +190,6 @@ QResultClass *QR_Constructor(void) { rv->dl_count = 0; rv->deleted = NULL; rv->deleted_keyset = NULL; - rv->ts_result = NULL; rv->next_token = NULL; } @@ -467,10 +466,6 @@ void QR_free_memory(QResultClass *self) { free(self->updated_tuples); self->updated_tuples = NULL; } - if (self->ts_result) { - ClearTSResult(self->ts_result); - self->ts_result = NULL; - } self->up_alloc = 0; self->up_count = 0; diff --git a/src/odfesqlodbc/qresult.h b/src/odfesqlodbc/qresult.h index 72ec3a286..5a84b3678 100644 --- a/src/odfesqlodbc/qresult.h +++ b/src/odfesqlodbc/qresult.h @@ -117,7 +117,6 @@ struct QResultClass_ { SQLLEN *updated; /* updated index info */ KeySet *updated_keyset; /* uddated keyset info */ TupleField *updated_tuples; /* uddated data by myself */ - void *ts_result; char *next_token; }; diff --git a/src/odfesqlodbc/results.c b/src/odfesqlodbc/results.c index 7814e579b..3a5839abf 100644 --- a/src/odfesqlodbc/results.c +++ b/src/odfesqlodbc/results.c @@ -324,7 +324,7 @@ RETCODE SQL_API API_DescribeCol(HSTMT hstmt, SQLUSMALLINT icol, return result; } -/* Returns result column descriptor information for a result set. */ +/* Returns result column descriptor information for a result set. */ RETCODE SQL_API API_ColAttributes(HSTMT hstmt, SQLUSMALLINT icol, SQLUSMALLINT fDescType, PTR rgbDesc, SQLSMALLINT cbDescMax, SQLSMALLINT *pcbDesc, diff --git a/src/odfesqlodbc/statement.c b/src/odfesqlodbc/statement.c index a0b0eb019..b364890e1 100644 --- a/src/odfesqlodbc/statement.c +++ b/src/odfesqlodbc/statement.c @@ -591,7 +591,7 @@ void SC_reset_result_for_rerun(StatementClass *self) { SC_set_Result(self, NULL); else { QR_reset_for_re_execute(res); - SC_set_Curres(self, NULL); + SC_set_Result(self, NULL); } } @@ -789,7 +789,7 @@ static const struct { {STMT_NO_RESPONSE, "08S01", "08S01"}, {STMT_COMMUNICATION_ERROR, "08S01", "08S01"}, {STMT_STRING_CONVERSION_ERROR, "22018", "22005"}, - {STMT_INVALID_STRING_OR_BUFFER_LENGTH_ERROR, "HY090", "HY090"}}; + {STMT_INVALID_STRING_OR_BUFFER_LENGTH_ERROR, "HY090", "S1090"}}; static ES_ErrorInfo *SC_create_errorinfo(const StatementClass *self, ES_ErrorInfo *eserror_fail_safe) {