File indexing completed on 2025-02-23 05:15:20
0001 // 0002 // Copyright (C) 2004-2008 Maciej Sobczak, Stephen Hutton 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/soci-platform.h" 0010 #include "soci/postgresql/soci-postgresql.h" 0011 #include "soci/session.h" 0012 #include <libpq/libpq-fs.h> // libpq 0013 #include <cctype> 0014 #include <cstdio> 0015 #include <cstring> 0016 #include <ctime> 0017 #include <sstream> 0018 0019 using namespace soci; 0020 using namespace soci::details; 0021 0022 namespace // unnamed 0023 { 0024 0025 // helper function for hardcoded queries 0026 void hard_exec(postgresql_session_backend & session_backend, 0027 PGconn * conn, char const * query, char const * errMsg) 0028 { 0029 postgresql_result(session_backend, PQexec(conn, query)).check_for_errors(errMsg); 0030 } 0031 0032 } // namespace unnamed 0033 0034 postgresql_session_backend::postgresql_session_backend( 0035 connection_parameters const& parameters, bool single_row_mode) 0036 : statementCount_(0), conn_(0) 0037 { 0038 single_row_mode_ = single_row_mode; 0039 0040 connect(parameters); 0041 } 0042 0043 void postgresql_session_backend::connect( 0044 connection_parameters const& parameters) 0045 { 0046 PGconn* conn = PQconnectdb(parameters.get_connect_string().c_str()); 0047 if (0 == conn || CONNECTION_OK != PQstatus(conn)) 0048 { 0049 std::string msg = "Cannot establish connection to the database."; 0050 if (0 != conn) 0051 { 0052 msg += '\n'; 0053 msg += PQerrorMessage(conn); 0054 PQfinish(conn); 0055 } 0056 0057 throw soci_error(msg); 0058 } 0059 0060 // Increase the number of digits used for floating point values to ensure 0061 // that the conversions to/from text round trip correctly, which is not the 0062 // case with the default value of 0. Use the maximal supported value, which 0063 // was 2 until 9.x and is 3 since it. 0064 int const version = PQserverVersion(conn); 0065 hard_exec(*this, conn, 0066 version >= 90000 ? "SET extra_float_digits = 3" 0067 : "SET extra_float_digits = 2", 0068 "Cannot set extra_float_digits parameter"); 0069 0070 conn_ = conn; 0071 connectionParameters_ = parameters; 0072 } 0073 0074 postgresql_session_backend::~postgresql_session_backend() 0075 { 0076 clean_up(); 0077 } 0078 0079 bool postgresql_session_backend::is_connected() 0080 { 0081 // For the connection to work, its status must be OK, but this is not 0082 // sufficient, so try to actually do something with it, even if it's 0083 // something as trivial as sending an empty command to the server. 0084 if ( PQstatus(conn_) != CONNECTION_OK ) 0085 return false; 0086 0087 postgresql_result(*this, PQexec(conn_, "/* ping */")); 0088 0089 // And then check it again. 0090 return PQstatus(conn_) == CONNECTION_OK; 0091 } 0092 0093 void postgresql_session_backend::begin() 0094 { 0095 hard_exec(*this, conn_, "BEGIN", "Cannot begin transaction."); 0096 } 0097 0098 void postgresql_session_backend::commit() 0099 { 0100 hard_exec(*this, conn_, "COMMIT", "Cannot commit transaction."); 0101 } 0102 0103 void postgresql_session_backend::rollback() 0104 { 0105 hard_exec(*this, conn_, "ROLLBACK", "Cannot rollback transaction."); 0106 } 0107 0108 void postgresql_session_backend::deallocate_prepared_statement( 0109 const std::string & statementName) 0110 { 0111 const std::string & query = "DEALLOCATE " + statementName; 0112 0113 hard_exec(*this, conn_, query.c_str(), 0114 "Cannot deallocate prepared statement."); 0115 } 0116 0117 bool postgresql_session_backend::get_next_sequence_value( 0118 session & s, std::string const & sequence, long long & value) 0119 { 0120 s << "select nextval('" + sequence + "')", into(value); 0121 0122 return true; 0123 } 0124 0125 void postgresql_session_backend::clean_up() 0126 { 0127 if (0 != conn_) 0128 { 0129 PQfinish(conn_); 0130 conn_ = 0; 0131 } 0132 } 0133 0134 std::string postgresql_session_backend::get_next_statement_name() 0135 { 0136 char nameBuf[20] = { 0 }; // arbitrary length 0137 sprintf(nameBuf, "st_%d", ++statementCount_); 0138 return nameBuf; 0139 } 0140 0141 postgresql_statement_backend * postgresql_session_backend::make_statement_backend() 0142 { 0143 return new postgresql_statement_backend(*this, single_row_mode_); 0144 } 0145 0146 postgresql_rowid_backend * postgresql_session_backend::make_rowid_backend() 0147 { 0148 return new postgresql_rowid_backend(*this); 0149 } 0150 0151 postgresql_blob_backend * postgresql_session_backend::make_blob_backend() 0152 { 0153 return new postgresql_blob_backend(*this); 0154 }