PageRenderTime 30ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/mordor/pq/result.cpp

http://github.com/mozy/mordor
C++ | 246 lines | 214 code | 25 blank | 7 comment | 37 complexity | 7413e76570cb605cb555ee4782cd6201 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. // Copyright (c) 2010 - Mozy, Inc.
  2. #include "result.h"
  3. #include <boost/date_time/posix_time/posix_time_types.hpp>
  4. #include "mordor/assert.h"
  5. #include "mordor/endian.h"
  6. #include "mordor/socket.h"
  7. #define BOOLOID 16
  8. #define CHAROID 18
  9. #define INT8OID 20
  10. #define INT2OID 21
  11. #define INT4OID 23
  12. #define CIDROID 650
  13. #define FLOAT4OID 700
  14. #define FLOAT8OID 701
  15. #define INETOID 869
  16. #define TIMESTAMPOID 1114
  17. #define TIMESTAMPTZOID 1184
  18. #define INT4ARRAYOID 1007
  19. namespace Mordor {
  20. namespace PQ {
  21. size_t
  22. Result::rows() const
  23. {
  24. return (size_t)PQntuples(m_result.get());
  25. }
  26. size_t
  27. Result::columns() const
  28. {
  29. return (size_t)PQnfields(m_result.get());
  30. }
  31. size_t
  32. Result::column(const char *name) const
  33. {
  34. return (size_t)PQfnumber(m_result.get(), name);
  35. }
  36. Oid
  37. Result::getType(size_t column) const
  38. {
  39. return PQftype(m_result.get(), (int)column);
  40. }
  41. bool Result::getIsNull(size_t row, size_t column) const {
  42. return PQgetisnull(m_result.get(), (int)row, (int)column) == 1;
  43. }
  44. template <>
  45. std::string
  46. Result::get<std::string>(size_t row, size_t column) const
  47. {
  48. return std::string(PQgetvalue(m_result.get(), (int)row, (int)column),
  49. PQgetlength(m_result.get(), (int)row, (int)column));
  50. }
  51. template <>
  52. const char *
  53. Result::get<const char *>(size_t row, size_t column) const
  54. {
  55. return PQgetvalue(m_result.get(), (int)row, (int)column);
  56. }
  57. template <>
  58. bool
  59. Result::get<bool>(size_t row, size_t column) const
  60. {
  61. MORDOR_ASSERT(getType(column) == BOOLOID);
  62. MORDOR_ASSERT(PQgetlength(m_result.get(), (int)row, (int)column) == 1);
  63. return !!*PQgetvalue(m_result.get(), (int)row, (int)column);
  64. }
  65. template <>
  66. char
  67. Result::get<char>(size_t row, size_t column) const
  68. {
  69. MORDOR_ASSERT(getType(column) == CHAROID);
  70. MORDOR_ASSERT(PQgetlength(m_result.get(), (int)row, (int)column) == 1);
  71. return *PQgetvalue(m_result.get(), (int)row, (int)column);
  72. }
  73. template <>
  74. long long
  75. Result::get<long long>(size_t row, size_t column) const
  76. {
  77. switch (getType(column)) {
  78. case INT8OID:
  79. MORDOR_ASSERT(PQgetlength(m_result.get(), (int)row, (int)column) == 8);
  80. return byteswapOnLittleEndian(*(long long *)PQgetvalue(m_result.get(), (int)row, (int)column));
  81. case INT2OID:
  82. MORDOR_ASSERT(PQgetlength(m_result.get(), (int)row, (int)column) == 2);
  83. return byteswapOnLittleEndian(*(short *)PQgetvalue(m_result.get(), (int)row, (int)column));
  84. case INT4OID:
  85. MORDOR_ASSERT(PQgetlength(m_result.get(), (int)row, (int)column) == 4);
  86. return byteswapOnLittleEndian(*(int *)PQgetvalue(m_result.get(), (int)row, (int)column));
  87. default:
  88. MORDOR_NOTREACHED();
  89. }
  90. }
  91. template <>
  92. short
  93. Result::get<short>(size_t row, size_t column) const
  94. {
  95. MORDOR_ASSERT(getType(column) == INT2OID);
  96. MORDOR_ASSERT(PQgetlength(m_result.get(), (int)row, (int)column) == 2);
  97. return byteswapOnLittleEndian(*(short *)PQgetvalue(m_result.get(), (int)row, (int)column));
  98. }
  99. template <>
  100. int
  101. Result::get<int>(size_t row, size_t column) const
  102. {
  103. switch (getType(column)) {
  104. case INT2OID:
  105. MORDOR_ASSERT(PQgetlength(m_result.get(), (int)row, (int)column) == 2);
  106. return byteswapOnLittleEndian(*(short *)PQgetvalue(m_result.get(), (int)row, (int)column));
  107. case INT4OID:
  108. MORDOR_ASSERT(PQgetlength(m_result.get(), (int)row, (int)column) == 4);
  109. return byteswapOnLittleEndian(*(int *)PQgetvalue(m_result.get(), (int)row, (int)column));
  110. default:
  111. MORDOR_NOTREACHED();
  112. }
  113. }
  114. template <>
  115. float
  116. Result::get<float>(size_t row, size_t column) const
  117. {
  118. MORDOR_ASSERT(getType(column) == FLOAT4OID);
  119. MORDOR_ASSERT(PQgetlength(m_result.get(), (int)row, (int)column) == 4);
  120. int temp = byteswapOnLittleEndian(*(int *)PQgetvalue(m_result.get(), (int)row, (int)column));
  121. return *(float *)&temp;
  122. }
  123. template <>
  124. double
  125. Result::get<double>(size_t row, size_t column) const
  126. {
  127. int templ;
  128. long long templl;
  129. switch (getType(column)) {
  130. case FLOAT4OID:
  131. MORDOR_ASSERT(PQgetlength(m_result.get(), (int)row, (int)column) == 4);
  132. templ = byteswapOnLittleEndian(*(int *)PQgetvalue(m_result.get(), (int)row, (int)column));
  133. return *(float *)&templ;
  134. case FLOAT8OID:
  135. MORDOR_ASSERT(PQgetlength(m_result.get(), (int)row, (int)column) == 8);
  136. templl = byteswapOnLittleEndian(*(long long *)PQgetvalue(m_result.get(), (int)row, (int)column));
  137. return *(double *)&templl;
  138. default:
  139. MORDOR_NOTREACHED();
  140. }
  141. }
  142. static const boost::posix_time::ptime postgres_epoch(boost::gregorian::date(2000, 1, 1));
  143. template<>
  144. boost::posix_time::ptime
  145. Result::get<boost::posix_time::ptime>(size_t row, size_t column) const
  146. {
  147. MORDOR_ASSERT(getType(column) == TIMESTAMPOID ||
  148. getType(column) == TIMESTAMPTZOID);
  149. if (PQgetlength(m_result.get(), (int)row, (int)column) == 0)
  150. return boost::posix_time::ptime();
  151. MORDOR_ASSERT(PQgetlength(m_result.get(), (int)row, (int)column) == 8);
  152. long long microseconds = byteswapOnLittleEndian(*(long long *)PQgetvalue(m_result.get(), (int)row, (int)column));
  153. return postgres_epoch +
  154. boost::posix_time::seconds((long)(microseconds / 1000000)) +
  155. boost::posix_time::microseconds(microseconds % 1000000);
  156. }
  157. template<>
  158. std::vector<int>
  159. Result::get<std::vector<int> >(size_t row, size_t column) const
  160. {
  161. std::vector<int> result;
  162. MORDOR_ASSERT(getType(column) == INT4ARRAYOID);
  163. MORDOR_ASSERT(PQgetlength(m_result.get(), (int)row, (int)column) >= 12);
  164. const int *array = (const int *)PQgetvalue(m_result.get(), (int)row, (int)column);
  165. // No embedded NULLs
  166. MORDOR_ASSERT(array[1] == 0);
  167. // Correct element type
  168. MORDOR_ASSERT(byteswapOnLittleEndian(array[2]) == INT4OID);
  169. // Number of dimensions
  170. switch (byteswapOnLittleEndian(array[0])) {
  171. case 0:
  172. return result;
  173. case 1:
  174. MORDOR_ASSERT(PQgetlength(m_result.get(), (int)row, (int)column) >= 20);
  175. break;
  176. default:
  177. MORDOR_NOTREACHED();
  178. }
  179. int numberOfElements = byteswapOnLittleEndian(array[3]);
  180. // Ignore starting index
  181. array = &array[5];
  182. // Now verify we have the entire array, as described
  183. MORDOR_ASSERT(PQgetlength(m_result.get(), (int)row, (int)column) == 20 + numberOfElements * 8);
  184. result.resize(numberOfElements);
  185. for (int i = 0; i < numberOfElements; ++i) {
  186. // Correct element size
  187. MORDOR_ASSERT(byteswapOnLittleEndian(array[i * 2]) == 4);
  188. result[i] = byteswapOnLittleEndian(array[i * 2 + 1]);
  189. }
  190. return result;
  191. }
  192. template<>
  193. std::pair<IPAddress::ptr, unsigned int>
  194. Result::get<std::pair<IPAddress::ptr, unsigned int> >(size_t row, size_t column) const
  195. {
  196. MORDOR_ASSERT(getType(column) == INETOID || getType(column) == CIDROID);
  197. MORDOR_ASSERT(PQgetlength(m_result.get(), (int)row, (int)column) >= 2);
  198. const char *bytes = PQgetvalue(m_result.get(), (int)row, (int)column);
  199. std::pair<IPAddress::ptr, unsigned int> result;
  200. switch (bytes[0]) {
  201. case AF_INET:
  202. MORDOR_ASSERT(PQgetlength(m_result.get(), (int)row, (int)column) == 8);
  203. result.second = bytes[1];
  204. result.first.reset(new IPv4Address(byteswapOnLittleEndian(*(unsigned int*)&bytes[4])));
  205. return result;
  206. case AF_INET + 1:
  207. MORDOR_ASSERT(PQgetlength(m_result.get(), (int)row, (int)column) == 20);
  208. result.second = bytes[1];
  209. result.first.reset(new IPv6Address((const unsigned char *)&bytes[4]));
  210. return result;
  211. default:
  212. MORDOR_NOTREACHED();
  213. }
  214. }
  215. template<>
  216. IPAddress::ptr
  217. Result::get<IPAddress::ptr>(size_t row, size_t column) const
  218. {
  219. return get<std::pair<IPAddress::ptr, unsigned int> >(row, column).first;
  220. }
  221. }}