res.c 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  1. /*
  2. * $Id$
  3. *
  4. * Postgres module result related functions
  5. *
  6. * Portions Copyright (C) 2001-2003 FhG FOKUS
  7. * Copyright (C) 2003 August.Net Services, LLC
  8. * Portions Copyright (C) 2005 iptelorg GmbH
  9. *
  10. * This file is part of ser, a free SIP server.
  11. *
  12. * ser is free software; you can redistribute it and/or modify
  13. * it under the terms of the GNU General Public License as published by
  14. * the Free Software Foundation; either version 2 of the License, or
  15. * (at your option) any later version
  16. *
  17. * For a license to use the ser software under conditions
  18. * other than those described here, or to purchase support for this
  19. * software, please contact iptel.org by e-mail at the following addresses:
  20. * [email protected]
  21. *
  22. * ser is distributed in the hope that it will be useful,
  23. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  24. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  25. * GNU General Public License for more details.
  26. *
  27. * You should have received a copy of the GNU General Public License
  28. * along with this program; if not, write to the Free Software
  29. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  30. */
  31. #include "../../mem/mem.h"
  32. #include "../../dprint.h"
  33. #include "pg_type.h"
  34. #include "pg_con.h"
  35. #include "db_mod.h"
  36. #include "res.h"
  37. #include <netinet/in.h>
  38. #include <string.h>
  39. /*
  40. * Get and convert columns from a result
  41. */
  42. static inline int get_columns(db_res_t* res)
  43. {
  44. PGresult* pgres;
  45. int n, i, type;
  46. if (!res) {
  47. ERR("Invalid parameter\n");
  48. goto err;
  49. }
  50. pgres = (PGresult*)res->data;
  51. if (!pgres) {
  52. ERR("No postgres result found\n");
  53. goto err;
  54. }
  55. n = PQnfields(pgres);
  56. if (!n) {
  57. ERR("No columns\n");
  58. goto err;
  59. }
  60. if (n == 0) return 0;
  61. res->col.names = (db_key_t*)pkg_malloc(sizeof(db_key_t) * n);
  62. if (!res->col.names) {
  63. ERR("No memory left\n");
  64. goto err;
  65. }
  66. res->col.types = (db_type_t*)pkg_malloc(sizeof(db_type_t) * n);
  67. if (!res->col.types) {
  68. ERR("No memory left\n");
  69. goto err;
  70. }
  71. res->col.n = n;
  72. for(i = 0; i < n; i++) {
  73. if (PQfformat(pgres, i) == 0) {
  74. ERR("Text format of columns not supported\n");
  75. goto err;
  76. }
  77. res->col.names[i] = PQfname(pgres, i);
  78. type = PQftype(pgres, i);
  79. switch(type) {
  80. case BOOLOID: /* boolean, 'true'/'false' */
  81. case INT2OID: /* -32 thousand to 32 thousand, 2-byte storage */
  82. case INT4OID: /* -2 billion to 2 billion integer, 4-byte storage */
  83. case INT8OID: /* ~18 digit integer, 8-byte storage */
  84. res->col.types[i] = DB_INT;
  85. break;
  86. case FLOAT4OID: /* single-precision floating point number, 4-byte storage */
  87. case FLOAT8OID: /* double-precision floating point number, 8-byte storage */
  88. res->col.types[i] = DB_DOUBLE;
  89. break;
  90. case TIMESTAMPOID: /* date and time */
  91. case TIMESTAMPTZOID: /* date and time with time zone */
  92. res->col.types[i] = DB_DATETIME;
  93. break;
  94. case CHAROID: /* single character */
  95. case TEXTOID: /* variable-length string, no limit specified */
  96. case BPCHAROID: /* char(length), blank-padded string, fixed storage length */
  97. case VARCHAROID: /* varchar(length), non-blank-padded string, variable storage length */
  98. res->col.types[i] = DB_STRING;
  99. break;
  100. case BYTEAOID: /* variable-length string, binary values escaped" */
  101. res->col.types[i] = DB_BLOB;
  102. break;
  103. case BITOID: /* fixed-length bit string */
  104. case VARBITOID: /* variable-length bit string */
  105. res->col.types[i] = DB_BITMAP;
  106. break;
  107. default:
  108. ERR("Unsupported column type with oid %d\n", type);
  109. goto err;
  110. }
  111. }
  112. return 0;
  113. err:
  114. if (res->col.types) pkg_free(res->col.types);
  115. if (res->col.names) pkg_free(res->col.names);
  116. res->col.types = 0;
  117. res->col.names = 0;
  118. return -1;
  119. }
  120. /*
  121. * Release memory used by columns
  122. */
  123. static inline int free_columns(db_res_t* res)
  124. {
  125. if (!res) {
  126. ERR("Invalid parameter\n");
  127. return -1;
  128. }
  129. if (res->col.names) pkg_free(res->col.names);
  130. if (res->col.types) pkg_free(res->col.types);
  131. return 0;
  132. }
  133. /*
  134. * Release memory used by rows
  135. */
  136. static inline void free_rows(db_res_t* res)
  137. {
  138. int r;
  139. if (!res->rows) return;
  140. for(r = 0; r < res->n; r++) {
  141. pkg_free(res->rows[r].values);
  142. }
  143. pkg_free(res->rows);
  144. }
  145. static inline int convert_cell(db_con_t* con, db_res_t* res, int row, int col)
  146. {
  147. static str dummy_str = STR_STATIC_INIT("");
  148. PGresult* pgres;
  149. db_val_t* val;
  150. int type, pglen;
  151. const char* pgval;
  152. union {
  153. int i4;
  154. long long i8;
  155. float f4;
  156. double f8;
  157. char c[8];
  158. } tmp;
  159. val = &res->rows[row].values[col];
  160. pgres = (PGresult*)res->data;
  161. val->type = res->col.types[col];
  162. if (PQgetisnull(pgres, row, col)) {
  163. val->nul = 1;
  164. switch(res->col.types[col]) {
  165. case DB_INT: val->val.int_val = 0; break;
  166. case DB_DOUBLE: val->val.double_val = 0; break;
  167. case DB_STRING: val->val.string_val = dummy_str.s; break;
  168. case DB_STR: val->val.str_val = dummy_str; break;
  169. case DB_DATETIME: val->val.time_val = 0; break;
  170. case DB_BLOB: val->val.blob_val = dummy_str; break;
  171. case DB_BITMAP: val->val.bitmap_val = 0; break;
  172. }
  173. return 0;
  174. }
  175. val->nul = 0;
  176. type = PQftype(pgres, col);
  177. pgval = PQgetvalue(pgres, row, col);
  178. pglen = PQgetlength(pgres, row, col);
  179. /* Postgres delivers binary parameters in network byte order,
  180. * thus we have to convert them to host byte order. All data
  181. * returned by PQgetvalue is zero terminated. Memory allocator
  182. * in libpq aligns data in memory properly so reading multibyte
  183. * values from memory at once is safe.
  184. */
  185. switch(type) {
  186. case BOOLOID:
  187. val->val.int_val = *pgval;
  188. break;
  189. case INT2OID:
  190. val->val.int_val = ntohs(*(unsigned short*)pgval);
  191. break;
  192. case FLOAT4OID:
  193. /* FLOAT4 will be stored in (8-byte) double */
  194. /* FIXME: More efficient implementation could be done here
  195. * provided that we know that the numbers are stored in IEEE 754
  196. */
  197. tmp.i4 = ntohl(*(unsigned int*)pgval);
  198. val->val.double_val = tmp.f4;
  199. break;
  200. case INT4OID:
  201. val->val.int_val = ntohl(*(unsigned int*)pgval);
  202. break;
  203. case INT8OID:
  204. val->val.int_val = ntohl(*(unsigned int*)(pgval + 4));
  205. break;
  206. case FLOAT8OID:
  207. tmp.i8 = (((unsigned long long)ntohl(*(unsigned int*)pgval)) << 32) +
  208. (unsigned int)ntohl(*(unsigned int*)(pgval + 4));
  209. val->val.double_val = tmp.f8;
  210. break;
  211. case TIMESTAMPOID:
  212. case TIMESTAMPTZOID:
  213. tmp.i8 = (((unsigned long long)ntohl(*(unsigned int*)pgval)) << 32) +
  214. (unsigned int)ntohl(*(unsigned int*)(pgval + 4));
  215. if (CON_FLAGS(con) & PG_INT8_TIMESTAMP) {
  216. /* int8 format */
  217. val->val.time_val = tmp.i8 / 1000000 + PG_EPOCH_TIME;
  218. } else {
  219. /* double format */
  220. val->val.time_val = PG_EPOCH_TIME + (long long)tmp.f8;
  221. }
  222. break;
  223. case CHAROID: /* single character */
  224. case TEXTOID: /* variable-length string, no limit specified */
  225. case BPCHAROID: /* char(length), blank-padded string, fixed storage length */
  226. case VARCHAROID: /* varchar(length), non-blank-padded string, variable storage length */
  227. val->val.str_val.s = (char*)pgval;
  228. val->val.str_val.len = pglen;
  229. break;
  230. case BYTEAOID: /* variable-length string, binary values escaped" */
  231. val->val.blob_val.s = (char*)pgval;
  232. val->val.blob_val.len = pglen;
  233. break;
  234. case BITOID: /* fixed-length bit string */
  235. case VARBITOID: /* variable-length bit string */
  236. if (ntohl(*(unsigned int*)pgval) != 32) {
  237. ERR("Only 32-bit long bitfieds supported\n");
  238. return -1;
  239. }
  240. val->val.bitmap_val = ntohl(*(unsigned int*)(pgval + 4));
  241. break;
  242. default:
  243. ERR("Unsupported column type with oid %d\n", type);
  244. return -1;
  245. }
  246. return 0;
  247. }
  248. /*
  249. * Convert rows from postgres to db API representation
  250. */
  251. static inline int convert_rows(db_con_t* con, db_res_t* res)
  252. {
  253. db_row_t* row;
  254. int r, c;
  255. if (!res) {
  256. ERR("Invalid parameter\n");
  257. return -1;
  258. }
  259. res->n = PQntuples((PGresult*)res->data); /* Number of rows */
  260. /* Assert: number of columns is > 0, otherwise get_columns would fail */
  261. if (!res->n) {
  262. res->rows = 0;
  263. return 0;
  264. }
  265. res->rows = (struct db_row*)pkg_malloc(sizeof(db_row_t) * res->n);
  266. if (!res->rows) {
  267. ERR("No memory left\n");
  268. goto err;
  269. }
  270. for(r = 0; r < res->n; r++) {
  271. row = &res->rows[r];
  272. row->values = (db_val_t*)pkg_malloc(sizeof(db_val_t) * res->col.n);
  273. if (!row->values) {
  274. ERR("No memory left to allocate row\n");
  275. res->n = r; /* This is to make sure that the cleanup function release only rows
  276. * that has been really allocated
  277. */
  278. goto err;
  279. }
  280. row->n = res->col.n;
  281. for(c = 0; c < row->n; c++) {
  282. if (convert_cell(con, res, r, c) < 0) {
  283. row->n = c;
  284. res->n = r;
  285. goto err;
  286. }
  287. }
  288. }
  289. return 0;
  290. err:
  291. /* free_rows(res); Do not free here, pg_free_result will take care of it */
  292. return -1;
  293. }
  294. /*
  295. * Create a new result structure and initialize it
  296. */
  297. db_res_t* pg_new_result(PGresult* pgres)
  298. {
  299. db_res_t* r;
  300. r = (db_res_t*)pkg_malloc(sizeof(db_res_t));
  301. if (!r) {
  302. ERR("No memory left\n");
  303. return 0;
  304. }
  305. memset(r, 0, sizeof(db_res_t));
  306. r->data = pgres;
  307. return r;
  308. }
  309. /*
  310. * Fill the structure with data from database
  311. */
  312. int pg_convert_result(db_res_t* res, db_con_t* con)
  313. {
  314. if (!res) {
  315. ERR("Invalid parameter\n");
  316. return -1;
  317. }
  318. if (get_columns(res) < 0) {
  319. ERR("Error while getting column names\n");
  320. return -2;
  321. }
  322. if (convert_rows(con, res) < 0) {
  323. ERR("Error while converting rows\n");
  324. /* Do not free columns here, pg_free_result will do it */
  325. return -3;
  326. }
  327. return 0;
  328. }
  329. /*
  330. * Release memory used by a result structure
  331. */
  332. int pg_free_result(db_res_t* res)
  333. {
  334. if (!res) {
  335. ERR("Invalid parameter\n");
  336. return -1;
  337. }
  338. free_columns(res);
  339. free_rows(res);
  340. if (res->data) PQclear((PGresult*)res->data);
  341. pkg_free(res);
  342. return 0;
  343. }