PageRenderTime 6240ms CodeModel.GetById 127ms RepoModel.GetById 25ms app.codeStats 1ms

/mordor/pq/preparedstatement.cpp

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