PageRenderTime 406ms CodeModel.GetById 121ms app.highlight 141ms RepoModel.GetById 141ms app.codeStats 0ms

/mordor/pq/preparedstatement.cpp

http://github.com/mozy/mordor
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}}