IGNITE-5995: ODBC fix for SQLGetData.
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/0d8d166b Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/0d8d166b Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/0d8d166b Branch: refs/heads/ignite-5872 Commit: 0d8d166b77d37f8740f3e9dd0637c336b77b0c8f Parents: 3919d80 Author: Igor Sapego <isap...@gridgain.com> Authored: Thu Aug 10 15:31:44 2017 +0300 Committer: Igor Sapego <isap...@gridgain.com> Committed: Thu Aug 10 15:31:44 2017 +0300 ---------------------------------------------------------------------- .../impl/cache/query/query_fields_row_impl.h | 2 +- .../cpp/odbc-test/include/test_utils.h | 9 ++ .../cpp/odbc-test/src/meta_queries_test.cpp | 100 +++++++++++++++++++ .../platforms/cpp/odbc-test/src/test_utils.cpp | 13 +++ .../ignite/odbc/query/column_metadata_query.h | 3 + .../ignite/odbc/query/table_metadata_query.h | 3 + .../include/ignite/odbc/query/type_info_query.h | 3 + .../cpp/odbc/src/query/batch_query.cpp | 7 +- .../odbc/src/query/column_metadata_query.cpp | 16 ++- .../platforms/cpp/odbc/src/query/data_query.cpp | 7 +- .../cpp/odbc/src/query/table_metadata_query.cpp | 16 ++- .../cpp/odbc/src/query/type_info_query.cpp | 16 ++- 12 files changed, 183 insertions(+), 12 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/0d8d166b/modules/platforms/cpp/core/include/ignite/impl/cache/query/query_fields_row_impl.h ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/core/include/ignite/impl/cache/query/query_fields_row_impl.h b/modules/platforms/cpp/core/include/ignite/impl/cache/query/query_fields_row_impl.h index 63e0523..2943625 100644 --- a/modules/platforms/cpp/core/include/ignite/impl/cache/query/query_fields_row_impl.h +++ b/modules/platforms/cpp/core/include/ignite/impl/cache/query/query_fields_row_impl.h @@ -143,7 +143,7 @@ namespace ignite int32_t actualLen = reader.ReadInt8Array(dst, len); - if (actualLen == 0 || dst && len >= actualLen) + if (actualLen == 0 || (dst && len >= actualLen)) ++processed; return actualLen; http://git-wip-us.apache.org/repos/asf/ignite/blob/0d8d166b/modules/platforms/cpp/odbc-test/include/test_utils.h ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc-test/include/test_utils.h b/modules/platforms/cpp/odbc-test/include/test_utils.h index 6a58e54..5dc6d6e 100644 --- a/modules/platforms/cpp/odbc-test/include/test_utils.h +++ b/modules/platforms/cpp/odbc-test/include/test_utils.h @@ -43,6 +43,15 @@ namespace ignite_test enum { ODBC_BUFFER_SIZE = 1024 }; /** + * Extract error state. + * + * @param handleType Type of the handle. + * @param handle Handle. + * @return Error state. + */ + std::string GetOdbcErrorState(SQLSMALLINT handleType, SQLHANDLE handle); + + /** * Extract error message. * * @param handleType Type of the handle. http://git-wip-us.apache.org/repos/asf/ignite/blob/0d8d166b/modules/platforms/cpp/odbc-test/src/meta_queries_test.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc-test/src/meta_queries_test.cpp b/modules/platforms/cpp/odbc-test/src/meta_queries_test.cpp index 454a989..ff3695d 100644 --- a/modules/platforms/cpp/odbc-test/src/meta_queries_test.cpp +++ b/modules/platforms/cpp/odbc-test/src/meta_queries_test.cpp @@ -103,6 +103,9 @@ struct MetaQueriesTestSuiteFixture BOOST_REQUIRE(stmt != NULL); } + /** + * Disconnect. + */ void Disconnect() { // Releasing statement handle. @@ -116,6 +119,11 @@ struct MetaQueriesTestSuiteFixture SQLFreeHandle(SQL_HANDLE_ENV, env); } + /** + * Start additional node with the specified name. + * + * @param name Node name. + */ static Ignite StartAdditionalNode(const char* name) { #ifdef IGNITE_TESTS_32 @@ -126,6 +134,36 @@ struct MetaQueriesTestSuiteFixture } /** + * Checks single row result set for correct work with SQLGetData. + * + * @param stmt Statement. + */ + void CheckSingleRowResultSetWithGetData(SQLHSTMT stmt) + { + SQLRETURN ret = SQLFetch(stmt); + + if (!SQL_SUCCEEDED(ret)) + BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); + + char buf[1024]; + SQLLEN bufLen = sizeof(buf); + + ret = SQLGetData(stmt, 1, SQL_C_CHAR, buf, sizeof(buf), &bufLen); + + if (!SQL_SUCCEEDED(ret)) + BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); + + ret = SQLFetch(stmt); + + BOOST_REQUIRE_EQUAL(ret, SQL_NO_DATA); + + ret = SQLGetData(stmt, 1, SQL_C_CHAR, buf, sizeof(buf), &bufLen); + + BOOST_REQUIRE_EQUAL(ret, SQL_ERROR); + BOOST_CHECK_EQUAL(GetOdbcErrorState(SQL_HANDLE_STMT, stmt), "24000"); + } + + /** * Constructor. */ MetaQueriesTestSuiteFixture() : @@ -237,4 +275,66 @@ BOOST_AUTO_TEST_CASE(TestColAttributesColumnScale) BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); } +BOOST_AUTO_TEST_CASE(TestGetDataWithGetTypeInfo) +{ + Connect("DRIVER={Apache Ignite};ADDRESS=127.0.0.1:11110;SCHEMA=cache"); + + SQLRETURN ret = SQLGetTypeInfo(stmt, SQL_VARCHAR); + + if (!SQL_SUCCEEDED(ret)) + BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); + + CheckSingleRowResultSetWithGetData(stmt); +} + +BOOST_AUTO_TEST_CASE(TestGetDataWithTables) +{ + Connect("DRIVER={Apache Ignite};ADDRESS=127.0.0.1:11110;SCHEMA=cache"); + + SQLCHAR empty[] = ""; + SQLCHAR table[] = "TestType"; + + SQLRETURN ret = SQLTables(stmt, empty, SQL_NTS, empty, SQL_NTS, table, SQL_NTS, empty, SQL_NTS); + + if (!SQL_SUCCEEDED(ret)) + BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); + + CheckSingleRowResultSetWithGetData(stmt); +} + +BOOST_AUTO_TEST_CASE(TestGetDataWithColumns) +{ + Connect("DRIVER={Apache Ignite};ADDRESS=127.0.0.1:11110;SCHEMA=cache"); + + SQLCHAR empty[] = ""; + SQLCHAR table[] = "TestType"; + SQLCHAR column[] = "strField"; + + SQLRETURN ret = SQLColumns(stmt, empty, SQL_NTS, empty, SQL_NTS, table, SQL_NTS, column, SQL_NTS); + + if (!SQL_SUCCEEDED(ret)) + BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); + + CheckSingleRowResultSetWithGetData(stmt); +} + +BOOST_AUTO_TEST_CASE(TestGetDataWithSelectQuery) +{ + Connect("DRIVER={Apache Ignite};ADDRESS=127.0.0.1:11110;SCHEMA=cache"); + + SQLCHAR insertReq[] = "insert into TestType(_key, strField) VALUES(1, 'Lorem ipsum')"; + SQLRETURN ret = SQLExecDirect(stmt, insertReq, SQL_NTS); + + if (!SQL_SUCCEEDED(ret)) + BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); + + SQLCHAR selectReq[] = "select strField from TestType"; + ret = SQLExecDirect(stmt, selectReq, SQL_NTS); + + if (!SQL_SUCCEEDED(ret)) + BOOST_FAIL(GetOdbcErrorMessage(SQL_HANDLE_STMT, stmt)); + + CheckSingleRowResultSetWithGetData(stmt); +} + BOOST_AUTO_TEST_SUITE_END() http://git-wip-us.apache.org/repos/asf/ignite/blob/0d8d166b/modules/platforms/cpp/odbc-test/src/test_utils.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc-test/src/test_utils.cpp b/modules/platforms/cpp/odbc-test/src/test_utils.cpp index c7aa70a..6e8fe6a 100644 --- a/modules/platforms/cpp/odbc-test/src/test_utils.cpp +++ b/modules/platforms/cpp/odbc-test/src/test_utils.cpp @@ -21,6 +21,19 @@ namespace ignite_test { + std::string GetOdbcErrorState(SQLSMALLINT handleType, SQLHANDLE handle) + { + SQLCHAR sqlstate[7] = {}; + SQLINTEGER nativeCode; + + SQLCHAR message[ODBC_BUFFER_SIZE]; + SQLSMALLINT reallen = 0; + + SQLGetDiagRec(handleType, handle, 1, sqlstate, &nativeCode, message, ODBC_BUFFER_SIZE, &reallen); + + return std::string(reinterpret_cast<char*>(sqlstate)); + } + std::string GetOdbcErrorMessage(SQLSMALLINT handleType, SQLHANDLE handle) { SQLCHAR sqlstate[7] = {}; http://git-wip-us.apache.org/repos/asf/ignite/blob/0d8d166b/modules/platforms/cpp/odbc/include/ignite/odbc/query/column_metadata_query.h ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/include/ignite/odbc/query/column_metadata_query.h b/modules/platforms/cpp/odbc/include/ignite/odbc/query/column_metadata_query.h index 878a4be..875b1ce 100644 --- a/modules/platforms/cpp/odbc/include/ignite/odbc/query/column_metadata_query.h +++ b/modules/platforms/cpp/odbc/include/ignite/odbc/query/column_metadata_query.h @@ -130,6 +130,9 @@ namespace ignite /** Query executed. */ bool executed; + /** Fetched flag. */ + bool fetched; + /** Fetched metadata. */ meta::ColumnMetaVector meta; http://git-wip-us.apache.org/repos/asf/ignite/blob/0d8d166b/modules/platforms/cpp/odbc/include/ignite/odbc/query/table_metadata_query.h ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/include/ignite/odbc/query/table_metadata_query.h b/modules/platforms/cpp/odbc/include/ignite/odbc/query/table_metadata_query.h index cef963c..acd3f49 100644 --- a/modules/platforms/cpp/odbc/include/ignite/odbc/query/table_metadata_query.h +++ b/modules/platforms/cpp/odbc/include/ignite/odbc/query/table_metadata_query.h @@ -134,6 +134,9 @@ namespace ignite /** Query executed. */ bool executed; + /** Fetched flag. */ + bool fetched; + /** Fetched metadata. */ meta::TableMetaVector meta; http://git-wip-us.apache.org/repos/asf/ignite/blob/0d8d166b/modules/platforms/cpp/odbc/include/ignite/odbc/query/type_info_query.h ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/include/ignite/odbc/query/type_info_query.h b/modules/platforms/cpp/odbc/include/ignite/odbc/query/type_info_query.h index a7cee92..00cca08 100644 --- a/modules/platforms/cpp/odbc/include/ignite/odbc/query/type_info_query.h +++ b/modules/platforms/cpp/odbc/include/ignite/odbc/query/type_info_query.h @@ -105,6 +105,9 @@ namespace ignite /** Executed flag. */ bool executed; + /** Fetched flag. */ + bool fetched; + /** Requested types. */ std::vector<int8_t> types; http://git-wip-us.apache.org/repos/asf/ignite/blob/0d8d166b/modules/platforms/cpp/odbc/src/query/batch_query.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/src/query/batch_query.cpp b/modules/platforms/cpp/odbc/src/query/batch_query.cpp index df9fb05..46447c0 100644 --- a/modules/platforms/cpp/odbc/src/query/batch_query.cpp +++ b/modules/platforms/cpp/odbc/src/query/batch_query.cpp @@ -112,7 +112,12 @@ namespace ignite } if (dataRetrieved) - return SqlResult::AI_NO_DATA; + { + diag.AddStatusRecord(SqlState::S24000_INVALID_CURSOR_STATE, + "Cursor has reached end of the result set."); + + return SqlResult::AI_ERROR; + } if (columnIdx != 1) { http://git-wip-us.apache.org/repos/asf/ignite/blob/0d8d166b/modules/platforms/cpp/odbc/src/query/column_metadata_query.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/src/query/column_metadata_query.cpp b/modules/platforms/cpp/odbc/src/query/column_metadata_query.cpp index 8ba9323..b9c08f5 100644 --- a/modules/platforms/cpp/odbc/src/query/column_metadata_query.cpp +++ b/modules/platforms/cpp/odbc/src/query/column_metadata_query.cpp @@ -83,6 +83,7 @@ namespace ignite table(table), column(column), executed(false), + fetched(false), meta(), columnsMeta() { @@ -125,6 +126,7 @@ namespace ignite if (result == SqlResult::AI_SUCCESS) { executed = true; + fetched = false; cursor = meta.begin(); } @@ -146,6 +148,11 @@ namespace ignite return SqlResult::AI_ERROR; } + if (!fetched) + fetched = true; + else + ++cursor; + if (cursor == meta.end()) return SqlResult::AI_NO_DATA; @@ -154,8 +161,6 @@ namespace ignite for (it = columnBindings.begin(); it != columnBindings.end(); ++it) GetColumn(it->first, it->second); - ++cursor; - return SqlResult::AI_SUCCESS; } @@ -169,7 +174,12 @@ namespace ignite } if (cursor == meta.end()) - return SqlResult::AI_NO_DATA; + { + diag.AddStatusRecord(SqlState::S24000_INVALID_CURSOR_STATE, + "Cursor has reached end of the result set."); + + return SqlResult::AI_ERROR; + } const meta::ColumnMeta& currentColumn = *cursor; uint8_t columnType = currentColumn.GetDataType(); http://git-wip-us.apache.org/repos/asf/ignite/blob/0d8d166b/modules/platforms/cpp/odbc/src/query/data_query.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/src/query/data_query.cpp b/modules/platforms/cpp/odbc/src/query/data_query.cpp index 23d5240..f14d004 100644 --- a/modules/platforms/cpp/odbc/src/query/data_query.cpp +++ b/modules/platforms/cpp/odbc/src/query/data_query.cpp @@ -125,7 +125,12 @@ namespace ignite Row* row = cursor->GetRow(); if (!row) - return SqlResult::AI_NO_DATA; + { + diag.AddStatusRecord(SqlState::S24000_INVALID_CURSOR_STATE, + "Cursor has reached end of the result set."); + + return SqlResult::AI_ERROR; + } SqlResult::Type result = row->ReadColumnToBuffer(columnIdx, buffer); http://git-wip-us.apache.org/repos/asf/ignite/blob/0d8d166b/modules/platforms/cpp/odbc/src/query/table_metadata_query.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/src/query/table_metadata_query.cpp b/modules/platforms/cpp/odbc/src/query/table_metadata_query.cpp index 401a1d2..e66b281 100644 --- a/modules/platforms/cpp/odbc/src/query/table_metadata_query.cpp +++ b/modules/platforms/cpp/odbc/src/query/table_metadata_query.cpp @@ -63,6 +63,7 @@ namespace ignite table(table), tableType(tableType), executed(false), + fetched(false), meta(), columnsMeta() { @@ -98,6 +99,7 @@ namespace ignite if (result == SqlResult::AI_SUCCESS) { executed = true; + fetched = false; cursor = meta.begin(); } @@ -119,6 +121,11 @@ namespace ignite return SqlResult::AI_ERROR; } + if (!fetched) + fetched = true; + else + ++cursor; + if (cursor == meta.end()) return SqlResult::AI_NO_DATA; @@ -127,8 +134,6 @@ namespace ignite for (it = columnBindings.begin(); it != columnBindings.end(); ++it) GetColumn(it->first, it->second); - ++cursor; - return SqlResult::AI_SUCCESS; } @@ -142,7 +147,12 @@ namespace ignite } if (cursor == meta.end()) - return SqlResult::AI_NO_DATA; + { + diag.AddStatusRecord(SqlState::S24000_INVALID_CURSOR_STATE, + "Cursor has reached end of the result set."); + + return SqlResult::AI_ERROR; + } const meta::TableMeta& currentColumn = *cursor; http://git-wip-us.apache.org/repos/asf/ignite/blob/0d8d166b/modules/platforms/cpp/odbc/src/query/type_info_query.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/src/query/type_info_query.cpp b/modules/platforms/cpp/odbc/src/query/type_info_query.cpp index f6b3990..b4efca0 100644 --- a/modules/platforms/cpp/odbc/src/query/type_info_query.cpp +++ b/modules/platforms/cpp/odbc/src/query/type_info_query.cpp @@ -122,6 +122,7 @@ namespace ignite Query(diag, QueryType::TYPE_INFO), columnsMeta(), executed(false), + fetched(false), types(), cursor(types.end()) { @@ -185,6 +186,7 @@ namespace ignite cursor = types.begin(); executed = true; + fetched = false; return SqlResult::AI_SUCCESS; } @@ -203,6 +205,11 @@ namespace ignite return SqlResult::AI_ERROR; } + if (!fetched) + fetched = true; + else + ++cursor; + if (cursor == types.end()) return SqlResult::AI_NO_DATA; @@ -211,8 +218,6 @@ namespace ignite for (it = columnBindings.begin(); it != columnBindings.end(); ++it) GetColumn(it->first, it->second); - ++cursor; - return SqlResult::AI_SUCCESS; } @@ -228,7 +233,12 @@ namespace ignite } if (cursor == types.end()) - return SqlResult::AI_NO_DATA; + { + diag.AddStatusRecord(SqlState::S24000_INVALID_CURSOR_STATE, + "Cursor has reached end of the result set."); + + return SqlResult::AI_ERROR; + } int8_t currentType = *cursor;