1 // 2 // Diagnostics.h 3 // 4 // Library: Data/ODBC 5 // Package: ODBC 6 // Module: Diagnostics 7 // 8 // Definition of Diagnostics. 9 // 10 // Copyright (c) 2006, Applied Informatics Software Engineering GmbH. 11 // and Contributors. 12 // 13 // SPDX-License-Identifier: BSL-1.0 14 // 15 16 17 #ifndef Data_ODBC_Diagnostics_INCLUDED 18 #define Data_ODBC_Diagnostics_INCLUDED 19 20 21 #include "Poco/Data/ODBC/ODBC.h" 22 #include <vector> 23 #include <cstring> 24 #ifdef POCO_OS_FAMILY_WINDOWS 25 #include <windows.h> 26 #endif 27 #include <sqlext.h> 28 29 30 namespace Poco { 31 namespace Data { 32 namespace ODBC { 33 34 35 template <typename H, SQLSMALLINT handleType> 36 class Diagnostics 37 /// Utility class providing functionality for retrieving ODBC diagnostic 38 /// records. Diagnostics object must be created with corresponding handle 39 /// as constructor argument. During construction, diagnostic records fields 40 /// are populated and the object is ready for querying. 41 { 42 public: 43 44 static const unsigned int SQL_STATE_SIZE = SQL_SQLSTATE_SIZE + 1; 45 static const unsigned int SQL_MESSAGE_LENGTH = SQL_MAX_MESSAGE_LENGTH + 1; 46 static const unsigned int SQL_NAME_LENGTH = 128; 47 static const std::string DATA_TRUNCATED; 48 49 struct DiagnosticFields 50 { 51 /// SQLGetDiagRec fields 52 SQLCHAR _sqlState[SQL_STATE_SIZE]; 53 SQLCHAR _message[SQL_MESSAGE_LENGTH]; 54 SQLINTEGER _nativeError; 55 }; 56 57 typedef std::vector<DiagnosticFields> FieldVec; 58 typedef typename FieldVec::const_iterator Iterator; 59 Diagnostics(const H & handle)60 explicit Diagnostics(const H& handle): _handle(handle) 61 /// Creates and initializes the Diagnostics. 62 { 63 std::memset(_connectionName, 0, sizeof(_connectionName)); 64 std::memset(_serverName, 0, sizeof(_serverName)); 65 diagnostics(); 66 } 67 ~Diagnostics()68 ~Diagnostics() 69 /// Destroys the Diagnostics. 70 { 71 } 72 sqlState(int index)73 std::string sqlState(int index) const 74 /// Returns SQL state. 75 { 76 poco_assert (index < count()); 77 return std::string((char*) _fields[index]._sqlState); 78 } 79 message(int index)80 std::string message(int index) const 81 /// Returns error message. 82 { 83 poco_assert (index < count()); 84 return std::string((char*) _fields[index]._message); 85 } 86 nativeError(int index)87 long nativeError(int index) const 88 /// Returns native error code. 89 { 90 poco_assert (index < count()); 91 return _fields[index]._nativeError; 92 } 93 connectionName()94 std::string connectionName() const 95 /// Returns the connection name. 96 /// If there is no active connection, connection name defaults to NONE. 97 /// If connection name is not applicable for query context (such as when querying environment handle), 98 /// connection name defaults to NOT_APPLICABLE. 99 { 100 return std::string((char*) _connectionName); 101 } 102 serverName()103 std::string serverName() const 104 /// Returns the server name. 105 /// If the connection has not been established, server name defaults to NONE. 106 /// If server name is not applicable for query context (such as when querying environment handle), 107 /// connection name defaults to NOT_APPLICABLE. 108 { 109 return std::string((char*) _serverName); 110 } 111 count()112 int count() const 113 /// Returns the number of contained diagnostic records. 114 { 115 return (int) _fields.size(); 116 } 117 reset()118 void reset() 119 /// Resets the diagnostic fields container. 120 { 121 _fields.clear(); 122 } 123 fields()124 const FieldVec& fields() const 125 { 126 return _fields; 127 } 128 begin()129 Iterator begin() const 130 { 131 return _fields.begin(); 132 } 133 end()134 Iterator end() const 135 { 136 return _fields.end(); 137 } 138 diagnostics()139 const Diagnostics& diagnostics() 140 { 141 DiagnosticFields df; 142 SQLSMALLINT count = 1; 143 SQLSMALLINT messageLength = 0; 144 static const std::string none = "None"; 145 static const std::string na = "Not applicable"; 146 147 reset(); 148 149 while (!Utility::isError(SQLGetDiagRec(handleType, 150 _handle, 151 count, 152 df._sqlState, 153 &df._nativeError, 154 df._message, 155 SQL_MESSAGE_LENGTH, 156 &messageLength))) 157 { 158 if (1 == count) 159 { 160 // success of the following two calls is optional 161 // (they fail if connection has not been established yet 162 // or return empty string if not applicable for the context) 163 if (Utility::isError(SQLGetDiagField(handleType, 164 _handle, 165 count, 166 SQL_DIAG_CONNECTION_NAME, 167 _connectionName, 168 sizeof(_connectionName), 169 &messageLength))) 170 { 171 std::size_t len = sizeof(_connectionName) > none.length() ? 172 none.length() : sizeof(_connectionName) - 1; 173 std::memcpy(_connectionName, none.c_str(), len); 174 } 175 else if (0 == _connectionName[0]) 176 { 177 std::size_t len = sizeof(_connectionName) > na.length() ? 178 na.length() : sizeof(_connectionName) - 1; 179 std::memcpy(_connectionName, na.c_str(), len); 180 } 181 182 if (Utility::isError(SQLGetDiagField(handleType, 183 _handle, 184 count, 185 SQL_DIAG_SERVER_NAME, 186 _serverName, 187 sizeof(_serverName), 188 &messageLength))) 189 { 190 std::size_t len = sizeof(_serverName) > none.length() ? 191 none.length() : sizeof(_serverName) - 1; 192 std::memcpy(_serverName, none.c_str(), len); 193 } 194 else if (0 == _serverName[0]) 195 { 196 std::size_t len = sizeof(_serverName) > na.length() ? 197 na.length() : sizeof(_serverName) - 1; 198 std::memcpy(_serverName, na.c_str(), len); 199 } 200 } 201 202 _fields.push_back(df); 203 204 std::memset(df._sqlState, 0, SQL_STATE_SIZE); 205 std::memset(df._message, 0, SQL_MESSAGE_LENGTH); 206 df._nativeError = 0; 207 208 ++count; 209 } 210 211 return *this; 212 } 213 214 private: 215 216 Diagnostics(); 217 218 /// SQLGetDiagField fields 219 SQLCHAR _connectionName[SQL_NAME_LENGTH]; 220 SQLCHAR _serverName[SQL_NAME_LENGTH]; 221 222 /// Diagnostics container 223 FieldVec _fields; 224 225 /// Context handle 226 const H& _handle; 227 }; 228 229 230 typedef Diagnostics<SQLHENV, SQL_HANDLE_ENV> EnvironmentDiagnostics; 231 typedef Diagnostics<SQLHDBC, SQL_HANDLE_DBC> ConnectionDiagnostics; 232 typedef Diagnostics<SQLHSTMT, SQL_HANDLE_STMT> StatementDiagnostics; 233 typedef Diagnostics<SQLHDESC, SQL_HANDLE_DESC> DescriptorDiagnostics; 234 235 236 } } } // namespace Poco::Data::ODBC 237 238 239 #endif 240