/mordor/pq/preparedstatement.cpp
C++ | 303 lines | 279 code | 23 blank | 1 comment | 21 complexity | 21dc22ab23af70e58168076182a3a473 MD5 | raw file
1// Copyright (c) 2010 - Mozy, Inc. 2 3#include "preparedstatement.h" 4 5#include "mordor/assert.h" 6#include "mordor/endian.h" 7#include "mordor/log.h" 8#include "mordor/iomanager.h" 9 10#include "connection.h" 11#include "exception.h" 12 13#define BOOLOID 16 14#define CHAROID 18 15#define INT8OID 20 16#define INT2OID 21 17#define INT4OID 23 18#define FLOAT4OID 700 19#define FLOAT8OID 701 20#define TIMESTAMPOID 1114 21#define TIMESTAMPTZOID 1184 22 23namespace Mordor { 24namespace PQ { 25 26static Logger::ptr g_log = Log::lookup("mordor:pq"); 27 28void 29PreparedStatement::bind(size_t param, const Null &) 30{ 31 ensure(param); 32 m_paramValues[param - 1].clear(); 33 m_params[param - 1] = NULL; 34 m_paramLengths[param - 1] = 0; 35 m_paramFormats[param - 1] = 1; 36 setType(param, 0); 37} 38 39void 40PreparedStatement::bind(size_t param, const std::string &value) 41{ 42 ensure(param); 43 m_paramValues[param - 1] = value; 44 m_params[param - 1] = m_paramValues[param - 1].c_str(); 45 m_paramLengths[param - 1] = m_paramValues[param - 1].size(); 46 m_paramFormats[param - 1] = 1; 47 setType(param, 0); 48} 49 50void 51PreparedStatement::bind(size_t param, const char *value) 52{ 53 ensure(param); 54 m_paramValues[param - 1] = value; 55 m_params[param - 1] = m_paramValues[param - 1].c_str(); 56 m_paramLengths[param - 1] = m_paramValues[param - 1].size(); 57 m_paramFormats[param - 1] = 1; 58 setType(param, 0); 59} 60 61void 62PreparedStatement::bind(size_t param, bool value) 63{ 64 ensure(param); 65 m_paramValues[param - 1].resize(1); 66 m_paramValues[param - 1][0] = value ? 1 : 0; 67 m_params[param - 1] = m_paramValues[param - 1].c_str(); 68 m_paramLengths[param - 1] = m_paramValues[param - 1].size(); 69 m_paramFormats[param - 1] = 1; 70 setType(param, BOOLOID); 71} 72 73void 74PreparedStatement::bind(size_t param, char value) 75{ 76 ensure(param); 77 m_paramValues[param - 1].resize(1); 78 m_paramValues[param - 1][0] = value; 79 m_params[param - 1] = m_paramValues[param - 1].c_str(); 80 m_paramLengths[param - 1] = m_paramValues[param - 1].size(); 81 m_paramFormats[param - 1] = 1; 82 setType(param, CHAROID); 83} 84 85void 86PreparedStatement::bind(size_t param, short value) 87{ 88 ensure(param); 89 m_paramValues[param - 1].resize(2); 90 *(short *)&m_paramValues[param - 1][0] = byteswapOnLittleEndian(value); 91 m_params[param - 1] = m_paramValues[param - 1].c_str(); 92 m_paramLengths[param - 1] = m_paramValues[param - 1].size(); 93 m_paramFormats[param - 1] = 1; 94 setType(param, INT2OID); 95} 96 97void 98PreparedStatement::bind(size_t param, int value) 99{ 100 ensure(param); 101 m_paramValues[param - 1].resize(4); 102 *(int *)&m_paramValues[param - 1][0] = byteswapOnLittleEndian(value); 103 m_params[param - 1] = m_paramValues[param - 1].c_str(); 104 m_paramLengths[param - 1] = m_paramValues[param - 1].size(); 105 m_paramFormats[param - 1] = 1; 106 setType(param, INT4OID); 107} 108 109void 110PreparedStatement::bind(size_t param, long long value) 111{ 112 ensure(param); 113 m_paramValues[param - 1].resize(8); 114 *(long long *)&m_paramValues[param - 1][0] = byteswapOnLittleEndian(value); 115 m_params[param - 1] = m_paramValues[param - 1].c_str(); 116 m_paramLengths[param - 1] = m_paramValues[param - 1].size(); 117 m_paramFormats[param - 1] = 1; 118 setType(param, INT8OID); 119} 120 121void 122PreparedStatement::bind(size_t param, float value) 123{ 124 ensure(param); 125 m_paramValues[param - 1].resize(4); 126 *(int *)&m_paramValues[param - 1][0] = byteswapOnLittleEndian(*(int *)&value); 127 m_params[param - 1] = m_paramValues[param - 1].c_str(); 128 m_paramLengths[param - 1] = m_paramValues[param - 1].size(); 129 m_paramFormats[param - 1] = 1; 130 setType(param, FLOAT4OID); 131} 132 133void 134PreparedStatement::bind(size_t param, double value) 135{ 136 ensure(param); 137 m_paramValues[param - 1].resize(8); 138 *(long long *)&m_paramValues[param - 1][0] = byteswapOnLittleEndian(*(long long *)&value); 139 m_params[param - 1] = m_paramValues[param - 1].c_str(); 140 m_paramLengths[param - 1] = m_paramValues[param - 1].size(); 141 m_paramFormats[param - 1] = 1; 142 setType(param, FLOAT8OID); 143} 144 145static const boost::posix_time::ptime postgres_epoch(boost::gregorian::date(2000, 1, 1)); 146 147void 148PreparedStatement::bind(size_t param, const boost::posix_time::ptime &value, bool timezone) 149{ 150 if (value.is_not_a_date_time()) { 151 bind(param, Null()); 152 return; 153 } 154 ensure(param); 155 m_paramValues[param - 1].resize(8); 156 long long ticks = (value - postgres_epoch).total_microseconds(); 157 *(long long *)&m_paramValues[param - 1][0] = byteswapOnLittleEndian(*(long long *)&ticks); 158 m_params[param - 1] = m_paramValues[param - 1].c_str(); 159 m_paramLengths[param - 1] = m_paramValues[param - 1].size(); 160 m_paramFormats[param - 1] = 1; 161 setType(param, timezone ? TIMESTAMPTZOID : TIMESTAMPOID); 162} 163 164void 165PreparedStatement::bindUntyped(size_t param, const std::string &value) 166{ 167 ensure(param); 168 m_paramValues[param - 1] = value; 169 m_params[param - 1] = m_paramValues[param - 1].c_str(); 170 m_paramLengths[param - 1] = m_paramValues[param - 1].size(); 171 m_paramFormats[param - 1] = 0; 172 setType(param, 0); 173} 174 175Result 176PreparedStatement::execute() 177{ 178 PGconn *conn = m_conn.lock().get(); 179 boost::shared_ptr<PGresult> result, next; 180 int nParams = (int)m_params.size(); 181 Oid *paramTypes = NULL; 182 int *paramLengths = NULL, *paramFormats = NULL; 183 const char **params = NULL; 184 if (nParams) { 185 if (m_name.empty()) 186 paramTypes = &m_paramTypes[0]; 187 params = &m_params[0]; 188 paramLengths = &m_paramLengths[0]; 189 paramFormats = &m_paramFormats[0]; 190 } 191 const char *api = NULL; 192#ifndef WINDOWS 193 SchedulerSwitcher switcher(m_scheduler); 194#endif 195 if (m_name.empty()) { 196#ifndef WINDOWS 197 if (m_scheduler) { 198 api = "PQsendQueryParams"; 199 if (!PQsendQueryParams(conn, m_command.c_str(), 200 nParams, paramTypes, params, paramLengths, paramFormats, m_resultFormat)) 201 throwException(conn); 202 flush(conn, m_scheduler); 203 next.reset(nextResult(conn, m_scheduler), &PQclear); 204 while (next) { 205 result = next; 206 next.reset(nextResult(conn, m_scheduler), &PQclear); 207 if (next) { 208 ExecStatusType status = PQresultStatus(next.get()); 209 MORDOR_LOG_VERBOSE(g_log) << conn << "PQresultStatus(" << 210 next.get() << "): " << PQresStatus(status); 211 switch (status) { 212 case PGRES_COMMAND_OK: 213 case PGRES_TUPLES_OK: 214 break; 215 default: 216 throwException(next.get()); 217 MORDOR_NOTREACHED(); 218 } 219 } 220 } 221 } else 222#endif 223 { 224 api = "PQexecParams"; 225 result.reset(PQexecParams(conn, m_command.c_str(), 226 nParams, paramTypes, params, paramLengths, paramFormats, m_resultFormat), 227 &PQclear); 228 } 229 } else { 230#ifndef WINDOWS 231 if (m_scheduler) { 232 api = "PQsendQueryPrepared"; 233 if (!PQsendQueryPrepared(conn, m_name.c_str(), 234 nParams, params, paramLengths, paramFormats, 1)) 235 throwException(conn); 236 flush(conn, m_scheduler); 237 next.reset(nextResult(conn, m_scheduler), &PQclear); 238 while (next) { 239 result = next; 240 next.reset(nextResult(conn, m_scheduler), &PQclear); 241 if (next) { 242 ExecStatusType status = PQresultStatus(next.get()); 243 MORDOR_LOG_VERBOSE(g_log) << conn << "PQresultStatus(" << 244 next.get() << "): " << PQresStatus(status); 245 switch (status) { 246 case PGRES_COMMAND_OK: 247 case PGRES_TUPLES_OK: 248 break; 249 default: 250 throwException(next.get()); 251 MORDOR_NOTREACHED(); 252 } 253 } 254 } 255 } else 256#endif 257 { 258 api = "PQexecPrepared"; 259 result.reset(PQexecPrepared(conn, m_name.c_str(), 260 nParams, params, paramLengths, paramFormats, m_resultFormat), 261 &PQclear); 262 } 263 } 264 if (!result) 265 throwException(conn); 266 ExecStatusType status = PQresultStatus(result.get()); 267 MORDOR_ASSERT(api); 268 MORDOR_LOG_VERBOSE(g_log) << conn << " " << api << "(\"" << m_command 269 << m_name << "\", " << nParams << "), PQresultStatus(" << result.get() 270 << "): " << PQresStatus(status); 271 switch (status) { 272 case PGRES_COMMAND_OK: 273 case PGRES_TUPLES_OK: 274 return Result(result); 275 default: 276 throwException(result.get()); 277 MORDOR_NOTREACHED(); 278 } 279} 280 281void 282PreparedStatement::setType(size_t param, Oid type) 283{ 284 if (m_name.empty()) 285 m_paramTypes[param - 1] = type; 286} 287 288void 289PreparedStatement::ensure(size_t param) 290{ 291 if (m_params.size() < param) { 292 m_paramValues.resize(param); 293 m_params.resize(param); 294 for (size_t i = 0; i < param; ++i) 295 m_params[i] = m_paramValues[i].c_str(); 296 m_paramLengths.resize(param); 297 m_paramFormats.resize(param); 298 if (m_name.empty()) 299 m_paramTypes.resize(param); 300 } 301} 302 303}}