File indexing completed on 2025-02-23 05:15:20
0001 // 0002 // Copyright (C) 2011 Gevorg Voskanyan 0003 // Distributed under the Boost Software License, Version 1.0. 0004 // (See accompanying file LICENSE_1_0.txt or copy at 0005 // http://www.boost.org/LICENSE_1_0.txt) 0006 // 0007 0008 #define SOCI_POSTGRESQL_SOURCE 0009 #include "soci/postgresql/soci-postgresql.h" 0010 #include "soci/callbacks.h" 0011 #include "soci/connection-parameters.h" 0012 #include <cstring> 0013 0014 using namespace soci; 0015 using namespace soci::details; 0016 0017 postgresql_soci_error::postgresql_soci_error( 0018 std::string const & msg, char const *sqlst) 0019 : soci_error(msg), cat_(unknown) 0020 { 0021 std::memcpy(sqlstate_, sqlst, 5); 0022 0023 if (std::memcmp(sqlst, "08", 2) == 0) 0024 { 0025 cat_ = connection_error; 0026 } 0027 else if (std::memcmp(sqlst, "42501", 5) == 0) 0028 { 0029 cat_ = no_privilege; 0030 } 0031 else if (std::memcmp(sqlst, "42", 2) == 0) 0032 { 0033 cat_ = invalid_statement; 0034 } 0035 else if (std::memcmp(sqlst, "02", 2) == 0) 0036 { 0037 cat_ = no_data; 0038 } 0039 else if (std::memcmp(sqlst, "23", 2) == 0) 0040 { 0041 cat_ = constraint_violation; 0042 } 0043 else if ((std::memcmp(sqlst, "53", 2) == 0) || 0044 (std::memcmp(sqlst, "54", 2) == 0) || 0045 (std::memcmp(sqlst, "58", 2) == 0) || 0046 (std::memcmp(sqlst, "XX", 2) == 0)) 0047 { 0048 cat_ = system_error; 0049 } 0050 } 0051 0052 std::string postgresql_soci_error::sqlstate() const 0053 { 0054 return std::string(sqlstate_, 5); 0055 } 0056 0057 void 0058 details::postgresql_result::check_for_errors(char const* errMsg) const 0059 { 0060 static_cast<void>(check_for_data(errMsg)); 0061 } 0062 0063 bool 0064 details::postgresql_result::check_for_data(char const* errMsg) const 0065 { 0066 // This SQL state will be used if we can't get anything more precise. 0067 const char* fallback_sql_state = " "; 0068 0069 std::string msg(errMsg); 0070 0071 ExecStatusType const status = PQresultStatus(result_); 0072 switch (status) 0073 { 0074 case PGRES_EMPTY_QUERY: 0075 case PGRES_COMMAND_OK: 0076 // No data but don't throw neither. 0077 return false; 0078 0079 case PGRES_TUPLES_OK: 0080 return true; 0081 0082 case PGRES_FATAL_ERROR: 0083 msg += " Fatal error."; 0084 0085 if (PQstatus(sessionBackend_.conn_) == CONNECTION_BAD) 0086 { 0087 msg += " Connection failed."; 0088 0089 // It's useful to set it here to something at least slightly 0090 // more specific, as we're not going to get anything from 0091 // PG_DIAG_SQLSTATE below if the connection is lost. 0092 fallback_sql_state = "08000"; // connection_exception 0093 0094 // call the failover callback, if registered 0095 0096 failover_callback * callback = sessionBackend_.failoverCallback_; 0097 if (callback != NULL) 0098 { 0099 bool reconnected = false; 0100 0101 try 0102 { 0103 callback->started(); 0104 } 0105 catch (...) 0106 { 0107 // ignore exceptions from user callbacks 0108 } 0109 bool retry = false; 0110 do { 0111 std::string newTarget; 0112 0113 try 0114 { 0115 callback->failed(retry, newTarget); 0116 } 0117 catch (...) 0118 { 0119 // do not continue execution because 0120 // user callback generated an exception 0121 retry = false; 0122 } 0123 0124 if (retry) 0125 { 0126 connection_parameters parameters = 0127 sessionBackend_.connectionParameters_; 0128 0129 if (!newTarget.empty()) 0130 parameters.set_connect_string(newTarget); 0131 0132 sessionBackend_.clean_up(); 0133 0134 sessionBackend_.connect(parameters); 0135 0136 reconnected = true; 0137 } 0138 } while (retry && !reconnected); 0139 0140 if (reconnected == false) 0141 { 0142 try 0143 { 0144 callback->aborted(); 0145 } 0146 catch (...) 0147 { 0148 // ignore exceptions from user callbacks 0149 } 0150 } 0151 else 0152 { 0153 try 0154 { 0155 callback->finished(*sessionBackend_.session_); 0156 } 0157 catch (...) 0158 { 0159 // ignore exceptions from user callbacks 0160 } 0161 } 0162 } 0163 } 0164 0165 break; 0166 0167 default: 0168 // Some of the other status codes are not really errors but we're 0169 // not prepared to handle them right now and shouldn't ever receive 0170 // them so throw nevertheless 0171 0172 break; 0173 } 0174 0175 const char* const pqError = PQresultErrorMessage(result_); 0176 if (pqError && *pqError) 0177 { 0178 msg += " "; 0179 msg += pqError; 0180 } 0181 0182 const char* sqlstate = PQresultErrorField(result_, PG_DIAG_SQLSTATE); 0183 if (!sqlstate) 0184 { 0185 sqlstate = fallback_sql_state; 0186 } 0187 0188 throw postgresql_soci_error(msg, sqlstate); 0189 }