IGNITE-4227: ODBC: Implemented SQLError. This closes #1237.
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/bc695f8e Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/bc695f8e Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/bc695f8e Branch: refs/heads/ignite-4242 Commit: bc695f8e3306c6d74d4fe53d9a98adedd43ad8f0 Parents: f2dc1d7 Author: Igor Sapego <[email protected]> Authored: Tue Nov 22 12:05:15 2016 +0300 Committer: devozerov <[email protected]> Committed: Tue Nov 22 12:05:15 2016 +0300 ---------------------------------------------------------------------- .../cpp/odbc-test/src/api_robustness_test.cpp | 45 +++++++++++++++ .../platforms/cpp/odbc/include/ignite/odbc.h | 12 +++- .../ignite/odbc/diagnostic/diagnosable.h | 7 +++ .../odbc/diagnostic/diagnosable_adapter.h | 10 ++++ .../ignite/odbc/diagnostic/diagnostic_record.h | 19 +++++++ .../odbc/diagnostic/diagnostic_record_storage.h | 16 ++++++ .../odbc/os/win/src/system/socket_client.cpp | 4 +- .../odbc/src/diagnostic/diagnostic_record.cpp | 16 +++++- .../diagnostic/diagnostic_record_storage.cpp | 18 ++++++ modules/platforms/cpp/odbc/src/entry_points.cpp | 26 ++++----- modules/platforms/cpp/odbc/src/odbc.cpp | 59 ++++++++++++++++++++ 11 files changed, 214 insertions(+), 18 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/bc695f8e/modules/platforms/cpp/odbc-test/src/api_robustness_test.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc-test/src/api_robustness_test.cpp b/modules/platforms/cpp/odbc-test/src/api_robustness_test.cpp index fbd5f12..13a5ea6 100644 --- a/modules/platforms/cpp/odbc-test/src/api_robustness_test.cpp +++ b/modules/platforms/cpp/odbc-test/src/api_robustness_test.cpp @@ -1066,4 +1066,49 @@ BOOST_AUTO_TEST_CASE(TestFetchScrollFirst) CheckFetchScrollUnsupportedOrientation(SQL_FETCH_FIRST); } +BOOST_AUTO_TEST_CASE(TestSQLError) +{ + // There are no checks because we do not really care what is the result of these + // calls as long as they do not cause segmentation fault. + + Connect("DRIVER={Apache Ignite};address=127.0.0.1:11110;cache=cache"); + + SQLCHAR state[6] = { 0 }; + SQLINTEGER nativeCode = 0; + SQLCHAR message[ODBC_BUFFER_SIZE] = { 0 }; + SQLSMALLINT messageLen = 0; + + // Everything is ok. + SQLRETURN ret = SQLError(env, 0, 0, state, &nativeCode, message, sizeof(message), &messageLen); + + if (ret != SQL_SUCCESS && ret != SQL_NO_DATA) + BOOST_FAIL("Unexpected error"); + + ret = SQLError(0, dbc, 0, state, &nativeCode, message, sizeof(message), &messageLen); + + if (ret != SQL_SUCCESS && ret != SQL_NO_DATA) + BOOST_FAIL("Unexpected error"); + + ret = SQLError(0, 0, stmt, state, &nativeCode, message, sizeof(message), &messageLen); + + if (ret != SQL_SUCCESS && ret != SQL_NO_DATA) + BOOST_FAIL("Unexpected error"); + + SQLError(0, 0, 0, state, &nativeCode, message, sizeof(message), &messageLen); + + SQLError(0, 0, stmt, 0, &nativeCode, message, sizeof(message), &messageLen); + + SQLError(0, 0, stmt, state, 0, message, sizeof(message), &messageLen); + + SQLError(0, 0, stmt, state, &nativeCode, 0, sizeof(message), &messageLen); + + SQLError(0, 0, stmt, state, &nativeCode, message, 0, &messageLen); + + SQLError(0, 0, stmt, state, &nativeCode, message, sizeof(message), 0); + + SQLError(0, 0, stmt, 0, 0, 0, 0, 0); + + SQLError(0, 0, 0, 0, 0, 0, 0, 0); +} + BOOST_AUTO_TEST_SUITE_END() http://git-wip-us.apache.org/repos/asf/ignite/blob/bc695f8e/modules/platforms/cpp/odbc/include/ignite/odbc.h ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/include/ignite/odbc.h b/modules/platforms/cpp/odbc/include/ignite/odbc.h index ec0861c..345cdb8 100644 --- a/modules/platforms/cpp/odbc/include/ignite/odbc.h +++ b/modules/platforms/cpp/odbc/include/ignite/odbc.h @@ -255,6 +255,16 @@ namespace ignite SQLRETURN SQLParamData(SQLHSTMT stmt, SQLPOINTER* value); SQLRETURN SQLPutData(SQLHSTMT stmt, SQLPOINTER data, SQLLEN strLengthOrIndicator); + + SQLRETURN SQLError(SQLHENV env, + SQLHDBC conn, + SQLHSTMT stmt, + SQLCHAR* state, + SQLINTEGER* error, + SQLCHAR* msgBuf, + SQLSMALLINT msgBufLen, + SQLSMALLINT* msgResLen); + } // namespace ignite -#endif //_IGNITE_ODBC +#endif //_IGNITE_ODBC \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/bc695f8e/modules/platforms/cpp/odbc/include/ignite/odbc/diagnostic/diagnosable.h ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/include/ignite/odbc/diagnostic/diagnosable.h b/modules/platforms/cpp/odbc/include/ignite/odbc/diagnostic/diagnosable.h index 909fe01..6937fcc 100644 --- a/modules/platforms/cpp/odbc/include/ignite/odbc/diagnostic/diagnosable.h +++ b/modules/platforms/cpp/odbc/include/ignite/odbc/diagnostic/diagnosable.h @@ -48,6 +48,13 @@ namespace ignite virtual const diagnostic::DiagnosticRecordStorage& GetDiagnosticRecords() const = 0; /** + * Get diagnostic record. + * + * @return Diagnostic record. + */ + virtual diagnostic::DiagnosticRecordStorage& GetDiagnosticRecords() = 0; + + /** * Add new status record. * * @param sqlState SQL state. http://git-wip-us.apache.org/repos/asf/ignite/blob/bc695f8e/modules/platforms/cpp/odbc/include/ignite/odbc/diagnostic/diagnosable_adapter.h ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/include/ignite/odbc/diagnostic/diagnosable_adapter.h b/modules/platforms/cpp/odbc/include/ignite/odbc/diagnostic/diagnosable_adapter.h index 63d26ca..548eecd 100644 --- a/modules/platforms/cpp/odbc/include/ignite/odbc/diagnostic/diagnosable_adapter.h +++ b/modules/platforms/cpp/odbc/include/ignite/odbc/diagnostic/diagnosable_adapter.h @@ -62,6 +62,16 @@ namespace ignite } /** + * Get diagnostic record. + * + * @return Diagnostic record. + */ + virtual diagnostic::DiagnosticRecordStorage& GetDiagnosticRecords() + { + return diagnosticRecords; + } + + /** * Add new status record. * * @param sqlState SQL state. http://git-wip-us.apache.org/repos/asf/ignite/blob/bc695f8e/modules/platforms/cpp/odbc/include/ignite/odbc/diagnostic/diagnostic_record.h ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/include/ignite/odbc/diagnostic/diagnostic_record.h b/modules/platforms/cpp/odbc/include/ignite/odbc/diagnostic/diagnostic_record.h index 670e0aa..80d5090 100644 --- a/modules/platforms/cpp/odbc/include/ignite/odbc/diagnostic/diagnostic_record.h +++ b/modules/platforms/cpp/odbc/include/ignite/odbc/diagnostic/diagnostic_record.h @@ -127,6 +127,19 @@ namespace ignite */ int32_t GetColumnNumber() const; + /** + * Check if the record was retrieved with the SQLError previously. + * + * return True if the record was retrieved with the SQLError + * previously. + */ + bool IsRetrieved() const; + + /** + * Mark record as retrieved with the SQLError. + */ + void MarkRetrieved(); + private: /** SQL state diagnostic code. */ SqlState sqlState; @@ -157,6 +170,12 @@ namespace ignite * result set or the parameter number in the set of parameters. */ int32_t columnNum; + + /** + * Flag that shows if the record was retrieved with the + * SQLError previously. + */ + bool retrieved; }; } } http://git-wip-us.apache.org/repos/asf/ignite/blob/bc695f8e/modules/platforms/cpp/odbc/include/ignite/odbc/diagnostic/diagnostic_record_storage.h ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/include/ignite/odbc/diagnostic/diagnostic_record_storage.h b/modules/platforms/cpp/odbc/include/ignite/odbc/diagnostic/diagnostic_record_storage.h index 4cc3576..b45bb7d 100644 --- a/modules/platforms/cpp/odbc/include/ignite/odbc/diagnostic/diagnostic_record_storage.h +++ b/modules/platforms/cpp/odbc/include/ignite/odbc/diagnostic/diagnostic_record_storage.h @@ -139,6 +139,22 @@ namespace ignite const DiagnosticRecord& GetStatusRecord(int32_t idx) const; /** + * Get specified status record. + * + * @param idx Status record index. + * @return Status record instance reference. + */ + DiagnosticRecord& GetStatusRecord(int32_t idx); + + /** + * Get last non-retrieved status record index. + * + * @return Index of the last non-retrieved status record or zero + * if nothing was found. + */ + int32_t GetLastNonRetrieved() const; + + /** * Check if the record is in the success state. * * @return True if the record is in the success state. http://git-wip-us.apache.org/repos/asf/ignite/blob/bc695f8e/modules/platforms/cpp/odbc/os/win/src/system/socket_client.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/os/win/src/system/socket_client.cpp b/modules/platforms/cpp/odbc/os/win/src/system/socket_client.cpp index bc4cdc0..e248323 100644 --- a/modules/platforms/cpp/odbc/os/win/src/system/socket_client.cpp +++ b/modules/platforms/cpp/odbc/os/win/src/system/socket_client.cpp @@ -83,8 +83,8 @@ namespace ignite // Attempt to connect to an address until one succeeds for (addrinfo *it = result; it != NULL; it = it->ai_next) { - LOG_MSG("Addr: %u.%u.%u.%u\n", it->ai_addr->sa_data[2], it->ai_addr->sa_data[3], - it->ai_addr->sa_data[4], it->ai_addr->sa_data[5]); + LOG_MSG("Addr: %u.%u.%u.%u\n", it->ai_addr->sa_data[2] & 0xFF, it->ai_addr->sa_data[3] & 0xFF, + it->ai_addr->sa_data[4] & 0xFF, it->ai_addr->sa_data[5] & 0xFF); // Create a SOCKET for connecting to server socketHandle = socket(it->ai_family, it->ai_socktype, it->ai_protocol); http://git-wip-us.apache.org/repos/asf/ignite/blob/bc695f8e/modules/platforms/cpp/odbc/src/diagnostic/diagnostic_record.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/src/diagnostic/diagnostic_record.cpp b/modules/platforms/cpp/odbc/src/diagnostic/diagnostic_record.cpp index 1b654d2..215d77f 100644 --- a/modules/platforms/cpp/odbc/src/diagnostic/diagnostic_record.cpp +++ b/modules/platforms/cpp/odbc/src/diagnostic/diagnostic_record.cpp @@ -89,7 +89,8 @@ namespace ignite connectionName(), serverName(), rowNum(0), - columnNum(0) + columnNum(0), + retrieved(false) { // No-op. } @@ -102,7 +103,8 @@ namespace ignite connectionName(connectionName), serverName(serverName), rowNum(rowNum), - columnNum(columnNum) + columnNum(columnNum), + retrieved(false) { // No-op. } @@ -260,6 +262,16 @@ namespace ignite { return columnNum; } + + bool DiagnosticRecord::IsRetrieved() const + { + return retrieved; + } + + void DiagnosticRecord::MarkRetrieved() + { + retrieved = true; + } } } } http://git-wip-us.apache.org/repos/asf/ignite/blob/bc695f8e/modules/platforms/cpp/odbc/src/diagnostic/diagnostic_record_storage.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/src/diagnostic/diagnostic_record_storage.cpp b/modules/platforms/cpp/odbc/src/diagnostic/diagnostic_record_storage.cpp index 99ef292..c075567 100644 --- a/modules/platforms/cpp/odbc/src/diagnostic/diagnostic_record_storage.cpp +++ b/modules/platforms/cpp/odbc/src/diagnostic/diagnostic_record_storage.cpp @@ -102,6 +102,24 @@ namespace ignite return statusRecords[idx - 1]; } + DiagnosticRecord& DiagnosticRecordStorage::GetStatusRecord(int32_t idx) + { + return statusRecords[idx - 1]; + } + + int32_t DiagnosticRecordStorage::GetLastNonRetrieved() const + { + for (size_t i = 0; i < statusRecords.size(); ++i) + { + const DiagnosticRecord& record = statusRecords[i]; + + if (!record.IsRetrieved()) + return static_cast<int32_t>(i + 1); + } + + return 0; + } + bool DiagnosticRecordStorage::IsSuccessful() const { return result == SQL_RESULT_SUCCESS || http://git-wip-us.apache.org/repos/asf/ignite/blob/bc695f8e/modules/platforms/cpp/odbc/src/entry_points.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/src/entry_points.cpp b/modules/platforms/cpp/odbc/src/entry_points.cpp index 08016cc..a85b3cf 100644 --- a/modules/platforms/cpp/odbc/src/entry_points.cpp +++ b/modules/platforms/cpp/odbc/src/entry_points.cpp @@ -412,6 +412,19 @@ SQLRETURN SQL_API SQLPutData(SQLHSTMT stmt, return ignite::SQLPutData(stmt, data, strLengthOrIndicator); } +SQLRETURN SQL_API SQLError(SQLHENV env, + SQLHDBC conn, + SQLHSTMT stmt, + SQLCHAR* state, + SQLINTEGER* error, + SQLCHAR* msgBuf, + SQLSMALLINT msgBufLen, + SQLSMALLINT* msgResLen) +{ + return ignite::SQLError(env, conn, stmt, state, + error, msgBuf, msgBufLen, msgResLen); +} + // // ==== Not implemented ==== // @@ -434,19 +447,6 @@ SQLRETURN SQL_API SQLColAttributes(SQLHSTMT stmt, return SQL_SUCCESS; } -SQLRETURN SQL_API SQLError(SQLHENV env, - SQLHDBC conn, - SQLHSTMT stmt, - SQLCHAR* state, - SQLINTEGER* error, - SQLCHAR* msgBuf, - SQLSMALLINT msgBufLen, - SQLSMALLINT* msgResLen) -{ - LOG_MSG("SQLError called\n"); - return SQL_ERROR; -} - SQLRETURN SQL_API SQLGetCursorName(SQLHSTMT stmt, SQLCHAR* nameBuf, SQLSMALLINT nameBufLen, http://git-wip-us.apache.org/repos/asf/ignite/blob/bc695f8e/modules/platforms/cpp/odbc/src/odbc.cpp ---------------------------------------------------------------------- diff --git a/modules/platforms/cpp/odbc/src/odbc.cpp b/modules/platforms/cpp/odbc/src/odbc.cpp index 79036eb..684ed08 100644 --- a/modules/platforms/cpp/odbc/src/odbc.cpp +++ b/modules/platforms/cpp/odbc/src/odbc.cpp @@ -1255,4 +1255,63 @@ namespace ignite return statement->GetDiagnosticRecords().GetReturnCode(); } + SQLRETURN SQLError(SQLHENV env, + SQLHDBC conn, + SQLHSTMT stmt, + SQLCHAR* state, + SQLINTEGER* error, + SQLCHAR* msgBuf, + SQLSMALLINT msgBufLen, + SQLSMALLINT* msgResLen) + { + using namespace ignite::utility; + using namespace ignite::odbc; + using namespace ignite::odbc::diagnostic; + using namespace ignite::odbc::type_traits; + + using ignite::odbc::app::ApplicationDataBuffer; + + LOG_MSG("SQLError called\n"); + + SQLHANDLE handle = 0; + + if (env != 0) + handle = static_cast<SQLHANDLE>(env); + else if (conn != 0) + handle = static_cast<SQLHANDLE>(conn); + else if (stmt != 0) + handle = static_cast<SQLHANDLE>(stmt); + else + return SQL_INVALID_HANDLE; + + Diagnosable *diag = reinterpret_cast<Diagnosable*>(handle); + + DiagnosticRecordStorage& records = diag->GetDiagnosticRecords(); + + int32_t recNum = records.GetLastNonRetrieved(); + + if (recNum < 1 || recNum > records.GetStatusRecordsNumber()) + return SQL_NO_DATA; + + DiagnosticRecord& record = records.GetStatusRecord(recNum); + + record.MarkRetrieved(); + + if (state) + CopyStringToBuffer(record.GetSqlState(), reinterpret_cast<char*>(state), 6); + + if (error) + *error = 0; + + SqlLen outResLen; + ApplicationDataBuffer outBuffer(IGNITE_ODBC_C_TYPE_CHAR, msgBuf, msgBufLen, &outResLen); + + outBuffer.PutString(record.GetMessageText()); + + if (msgResLen) + *msgResLen = static_cast<SQLSMALLINT>(outResLen); + + return SQL_SUCCESS; + } + } // namespace ignite;
