# HG changeset patch # User František Kučera # Date 1590433877 -7200 # Node ID cd9db43db1200c0b7d41880e280ab99303cfdc14 # Parent 24c05e69d68fe52e20bfb2e23ce29ff6f01b1b4b SqlException: ODBC diagnostics diff -r 24c05e69d68f -r cd9db43db120 nbproject/configurations.xml --- a/nbproject/configurations.xml Mon May 25 19:36:06 2020 +0200 +++ b/nbproject/configurations.xml Mon May 25 21:11:17 2020 +0200 @@ -47,6 +47,7 @@ DriverManager.h OdbcCommon.h PreparedStatement.cpp + SqlException.cpp SqlException.h relpipe-tr-sql.cpp @@ -112,6 +113,8 @@ + + @@ -158,6 +161,8 @@ + + diff -r 24c05e69d68f -r cd9db43db120 src/CMakeLists.txt --- a/src/CMakeLists.txt Mon May 25 19:36:06 2020 +0200 +++ b/src/CMakeLists.txt Mon May 25 21:11:17 2020 +0200 @@ -36,6 +36,7 @@ PreparedStatement.cpp Connection.cpp DriverManager.cpp + SqlException.cpp relpipe-tr-sql.cpp ) diff -r 24c05e69d68f -r cd9db43db120 src/DriverManager.cpp --- a/src/DriverManager.cpp Mon May 25 19:36:06 2020 +0200 +++ b/src/DriverManager.cpp Mon May 25 21:11:17 2020 +0200 @@ -31,7 +31,7 @@ DriverManager::DriverManager() { env = OdbcCommon::allocateHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE); SQLRETURN result = SQLSetEnvAttr(env, SQL_ATTR_ODBC_VERSION, (void*) SQL_OV_ODBC3, 0); - if (OdbcCommon::isNotSuccessful(result)) throw SqlException(L"Unable to set ODBC version"); // TODO:, result, SQL_HANDLE_ENV, environment); + if (OdbcCommon::isNotSuccessful(result)) throw SqlException(L"Unable to set ODBC version", result, SQL_HANDLE_ENV, env); } DriverManager::~DriverManager() { @@ -51,7 +51,7 @@ // TODO: check nameLength and descriptionLength whether values were truncated? if (OdbcCommon::isSuccessful(result)) list.push_back({convertor.from_bytes((char*) name), convertor.from_bytes((char*) description)}); else if (result == SQL_NO_DATA_FOUND) break; - else throw SqlException(L"Unable to list data sources: " + std::to_wstring(result)); + else throw SqlException(L"Unable to list data sources: " + std::to_wstring(result), result, SQL_HANDLE_ENV, env); } return list; } diff -r 24c05e69d68f -r cd9db43db120 src/SqlException.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/SqlException.cpp Mon May 25 21:11:17 2020 +0200 @@ -0,0 +1,63 @@ +/** + * Relational pipes + * Copyright © 2020 František Kučera (Frantovo.cz, GlobalCode.info) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include + +#include +#include + +#include "SqlException.h" + +namespace relpipe { +namespace tr { +namespace sql { + +SqlException::SqlException(std::wstring message) : message(message) { +} + +SqlException::SqlException(std::wstring message, SQLRETURN resultCode, SQLSMALLINT handleType, SQLHANDLE handle) : message(message), resultCode(resultCode) { + std::wstring_convert < std::codecvt_utf8> convertor; // TODO: support also other encodings + SQLCHAR buffer[SQL_MAX_MESSAGE_LENGTH + 1]; + SQLCHAR sqlstate[SQL_SQLSTATE_SIZE + 1]; + memset(buffer, 0, sizeof (buffer)); + memset(sqlstate, 0, sizeof (sqlstate)); + SQLINTEGER sqlcode; + SQLSMALLINT length; + for (SQLSMALLINT i = 1; SQLGetDiagRec(handleType, handle, i, sqlstate, &sqlcode, buffer, SQL_MAX_MESSAGE_LENGTH + 1, &length) == SQL_SUCCESS; i++) { + diagnostics.push_back({convertor.from_bytes((char*) sqlstate), sqlcode, convertor.from_bytes((char*) buffer)}); + } +} + +std::vector SqlException::getDiagnostics() const { + return diagnostics; +} + +std::wstring SqlException::getMessage() const { + return message; +} + +SQLRETURN SqlException::getResultCode() const { + return resultCode; +} + + + +} +} +} diff -r 24c05e69d68f -r cd9db43db120 src/SqlException.h --- a/src/SqlException.h Mon May 25 19:36:06 2020 +0200 +++ b/src/SqlException.h Mon May 25 21:11:17 2020 +0200 @@ -17,24 +17,37 @@ #pragma once #include - -using namespace std; +#include namespace relpipe { namespace tr { namespace sql { class SqlException { -private: - wstring message; public: - SqlException(wstring message) : message(message) { - } + class SqlDiagnosticsRecord { + public: + std::wstring sqlState; + int sqlCode; + std::wstring message; + }; - wstring getMessge() { - return message; - } +private: + std::wstring message; + std::vector diagnostics; + signed short int resultCode; +public: + + SqlException(std::wstring message); + + SqlException(std::wstring message, signed short int resultCode, signed short int handleType, void* handle); + + std::wstring getMessage() const; + + signed short int getResultCode() const; + + std::vector getDiagnostics() const; }; diff -r 24c05e69d68f -r cd9db43db120 src/relpipe-tr-sql.cpp --- a/src/relpipe-tr-sql.cpp Mon May 25 19:36:06 2020 +0200 +++ b/src/relpipe-tr-sql.cpp Mon May 25 21:11:17 2020 +0200 @@ -81,7 +81,10 @@ fwprintf(stderr, L"Debug: Input stream: eof=%ls, lastRead=%d\n", (cin.eof() ? L"true" : L"false"), cin.gcount()); resultCode = e.getExitCode(); } catch (SqlException& e) { - fwprintf(stderr, L"Caught SQL exception: %ls\n", e.getMessge().c_str()); + fwprintf(stderr, L"Caught SQL exception: %ls\n", e.getMessage().c_str()); + for (SqlException::SqlDiagnosticsRecord dr : e.getDiagnostics()) { + fwprintf(stderr, L"\tstate: %ls, code: %d, message: %ls\n", dr.sqlState.c_str(), dr.sqlCode, dr.message.c_str()); + } fwprintf(stderr, L"Debug: Input stream: eof=%ls, lastRead=%d\n", (cin.eof() ? L"true" : L"false"), cin.gcount()); resultCode = CLI::EXIT_CODE_UNEXPECTED_ERROR; } catch (RelpipeReaderException& e) {