res.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. /*
  2. * $Id$
  3. *
  4. * UNIXODBC module result related functions
  5. *
  6. * Copyright (C) 2005-2006 Marco Lorrai
  7. * Copyright (C) 2007-2008 1&1 Internet AG
  8. *
  9. * This file is part of Kamailio, a free SIP server.
  10. *
  11. * Kamailio is free software; you can redistribute it and/or modify
  12. * it under the terms of the GNU General Public License as published by
  13. * the Free Software Foundation; either version 2 of the License, or
  14. * (at your option) any later version
  15. *
  16. * Kamailio is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19. * GNU General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU General Public License
  22. * along with this program; if not, write to the Free Software
  23. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  24. *
  25. *
  26. * History:
  27. * --------
  28. * 2005-12-01 initial commit (chgen)
  29. * 2006-04-04 fixed memory leak in convert_rows (sgupta)
  30. * 2006-05-05 removed static allocation of 1k per column data (sgupta)
  31. */
  32. #include "../../mem/mem.h"
  33. #include "../../dprint.h"
  34. #include "row.h"
  35. #include "../../lib/srdb1/db_res.h"
  36. #include "connection.h"
  37. #include "res.h"
  38. #include "list.h"
  39. #include <stdlib.h>
  40. #include <string.h>
  41. /*
  42. * Get and convert columns from a result
  43. */
  44. int db_unixodbc_get_columns(const db1_con_t* _h, db1_res_t* _r)
  45. {
  46. int col;
  47. SQLSMALLINT cols; /* because gcc don't like RES_COL_N */
  48. if ((!_h) || (!_r)) {
  49. LM_ERR("invalid parameter\n");
  50. return -1;
  51. }
  52. /* Save number of columns in the result structure */
  53. SQLNumResultCols(CON_RESULT(_h), &cols);
  54. RES_COL_N(_r) = cols;
  55. if (!RES_COL_N(_r)) {
  56. LM_ERR("no columns returned from the query\n");
  57. return -2;
  58. } else {
  59. LM_DBG("%d columns returned from the query\n", RES_COL_N(_r));
  60. }
  61. if (db_allocate_columns(_r, RES_COL_N(_r)) != 0) {
  62. LM_ERR("could not allocate columns\n");
  63. return -3;
  64. }
  65. for(col = 0; col < RES_COL_N(_r); col++)
  66. {
  67. RES_NAMES(_r)[col] = (str*)pkg_malloc(sizeof(str));
  68. if (! RES_NAMES(_r)[col]) {
  69. LM_ERR("no private memory left\n");
  70. db_free_columns(_r);
  71. return -4;
  72. }
  73. LM_DBG("allocate %lu bytes for RES_NAMES[%d] at %p\n",
  74. (unsigned long)sizeof(str),col, RES_NAMES(_r)[col]);
  75. char columnname[80];
  76. SQLRETURN ret;
  77. SQLSMALLINT namelength, datatype, decimaldigits, nullable;
  78. SQLULEN columnsize;
  79. ret = SQLDescribeCol(CON_RESULT(_h), col + 1, (SQLCHAR *)columnname, 80,
  80. &namelength, &datatype, &columnsize, &decimaldigits, &nullable);
  81. if(!SQL_SUCCEEDED(ret)) {
  82. LM_ERR("SQLDescribeCol failed: %d\n", ret);
  83. db_unixodbc_extract_error("SQLExecDirect", CON_RESULT(_h), SQL_HANDLE_STMT,
  84. NULL);
  85. // FIXME should we fail here completly?
  86. }
  87. /* The pointer that is here returned is part of the result structure. */
  88. RES_NAMES(_r)[col]->s = columnname;
  89. RES_NAMES(_r)[col]->len = namelength;
  90. LM_DBG("RES_NAMES(%p)[%d]=[%.*s]\n", RES_NAMES(_r)[col], col,
  91. RES_NAMES(_r)[col]->len, RES_NAMES(_r)[col]->s);
  92. switch(datatype)
  93. {
  94. case SQL_SMALLINT:
  95. case SQL_INTEGER:
  96. case SQL_TINYINT:
  97. case SQL_DECIMAL:
  98. case SQL_NUMERIC:
  99. LM_DBG("use DB1_INT result type\n");
  100. RES_TYPES(_r)[col] = DB1_INT;
  101. break;
  102. case SQL_BIGINT:
  103. LM_DBG("use DB1_BIGINT result type\n");
  104. RES_TYPES(_r)[col] = DB1_BIGINT;
  105. break;
  106. case SQL_REAL:
  107. case SQL_FLOAT:
  108. case SQL_DOUBLE:
  109. LM_DBG("use DB1_DOUBLE result type\n");
  110. RES_TYPES(_r)[col] = DB1_DOUBLE;
  111. break;
  112. case SQL_TYPE_TIMESTAMP:
  113. case SQL_DATE:
  114. case SQL_TIME:
  115. case SQL_TIMESTAMP:
  116. case SQL_TYPE_DATE:
  117. case SQL_TYPE_TIME:
  118. LM_DBG("use DB1_DATETIME result type\n");
  119. RES_TYPES(_r)[col] = DB1_DATETIME;
  120. break;
  121. case SQL_CHAR:
  122. case SQL_VARCHAR:
  123. case SQL_WCHAR:
  124. case SQL_WVARCHAR:
  125. LM_DBG("use DB1_STRING result type\n");
  126. RES_TYPES(_r)[col] = DB1_STRING;
  127. break;
  128. case SQL_BINARY:
  129. case SQL_VARBINARY:
  130. case SQL_LONGVARBINARY:
  131. case SQL_BIT:
  132. case SQL_LONGVARCHAR:
  133. case SQL_WLONGVARCHAR:
  134. LM_DBG("use DB1_BLOB result type\n");
  135. RES_TYPES(_r)[col] = DB1_BLOB;
  136. break;
  137. default:
  138. LM_WARN("unhandled data type column (%.*s) type id (%d), "
  139. "use DB1_STRING as default\n", RES_NAMES(_r)[col]->len,
  140. RES_NAMES(_r)[col]->s, datatype);
  141. RES_TYPES(_r)[col] = DB1_STRING;
  142. break;
  143. }
  144. }
  145. return 0;
  146. }
  147. /*
  148. * Convert rows from UNIXODBC to db API representation
  149. */
  150. static inline int db_unixodbc_convert_rows(const db1_con_t* _h, db1_res_t* _r)
  151. {
  152. int i = 0, ret = 0;
  153. SQLSMALLINT columns;
  154. list* rows = NULL;
  155. list* rowstart = NULL;
  156. strn* temp_row = NULL;
  157. if((!_h) || (!_r)) {
  158. LM_ERR("invalid parameter\n");
  159. return -1;
  160. }
  161. SQLNumResultCols(CON_RESULT(_h), (SQLSMALLINT *)&columns);
  162. while(SQL_SUCCEEDED(ret = SQLFetch(CON_RESULT(_h))))
  163. {
  164. temp_row = db_unixodbc_new_cellrow(columns);
  165. if (!temp_row) {
  166. LM_ERR("no private memory left\n");
  167. return -1;
  168. }
  169. for(i=0; i < columns; i++)
  170. {
  171. if (!db_unixodbc_load_cell(_h, i+1, temp_row + i, RES_TYPES(_r)[i])) {
  172. db_unixodbc_free_cellrow(columns, temp_row);
  173. return -5;
  174. }
  175. }
  176. if (db_unixodbc_list_insert(&rowstart, &rows, columns, temp_row) < 0) {
  177. LM_ERR("insert failed\n");
  178. db_unixodbc_free_cellrow(columns, temp_row);
  179. return -5;
  180. }
  181. RES_ROW_N(_r)++;
  182. /* free temporary row data */
  183. db_unixodbc_free_cellrow(columns, temp_row);
  184. temp_row = NULL;
  185. }
  186. CON_ROW(_h) = NULL;
  187. if (!RES_ROW_N(_r)) {
  188. RES_ROWS(_r) = 0;
  189. return 0;
  190. }
  191. if (db_allocate_rows(_r) != 0) {
  192. LM_ERR("could not allocate rows");
  193. db_unixodbc_list_destroy(rowstart);
  194. return -2;
  195. }
  196. i = 0;
  197. rows = rowstart;
  198. while(rows)
  199. {
  200. CON_ROW(_h) = rows->data;
  201. if (!CON_ROW(_h))
  202. {
  203. LM_ERR("string null\n");
  204. RES_ROW_N(_r) = i;
  205. db_free_rows(_r);
  206. db_unixodbc_list_destroy(rowstart);
  207. return -3;
  208. }
  209. if (db_unixodbc_convert_row(_h, _r, &(RES_ROWS(_r)[i]), rows->lengths) < 0) {
  210. LM_ERR("converting row failed #%d\n", i);
  211. RES_ROW_N(_r) = i;
  212. db_free_rows(_r);
  213. db_unixodbc_list_destroy(rowstart);
  214. return -4;
  215. }
  216. i++;
  217. rows = rows->next;
  218. }
  219. db_unixodbc_list_destroy(rowstart);
  220. return 0;
  221. }
  222. /*
  223. * Fill the structure with data from database
  224. */
  225. int db_unixodbc_convert_result(const db1_con_t* _h, db1_res_t* _r)
  226. {
  227. if (!_h || !_r) {
  228. LM_ERR("invalid parameter\n");
  229. return -1;
  230. }
  231. if (db_unixodbc_get_columns(_h, _r) < 0) {
  232. LM_ERR("getting column names failed\n");
  233. return -2;
  234. }
  235. if (db_unixodbc_convert_rows(_h, _r) < 0) {
  236. LM_ERR("converting rows failed\n");
  237. db_free_columns(_r);
  238. return -3;
  239. }
  240. return 0;
  241. }