dbase.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498
  1. /*
  2. * $Id$
  3. *
  4. * UNIXODBC module core 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-03 fixed invalid handle to extract error (sgupta)
  30. * 2006-04-04 removed deprecated ODBC functions, closed cursors on error
  31. * (sgupta)
  32. * 2006-05-05 Fixed reconnect code to actually work on connection loss
  33. * (sgupta)
  34. */
  35. #include "../../mem/mem.h"
  36. #include "../../dprint.h"
  37. #include "../../lib/srdb1/db_query.h"
  38. #include "val.h"
  39. #include "connection.h"
  40. #include "row.h"
  41. #include "res.h"
  42. #include "list.h"
  43. #include "db_unixodbc.h"
  44. #include "dbase.h"
  45. /*
  46. * Reconnect if connection is broken
  47. */
  48. static int reconnect(const db1_con_t* _h)
  49. {
  50. int ret = 0;
  51. SQLCHAR outstr[1024];
  52. SQLSMALLINT outstrlen;
  53. char conn_str[MAX_CONN_STR_LEN];
  54. LM_ERR("Attempting DB reconnect\n");
  55. /* Disconnect */
  56. SQLDisconnect (CON_CONNECTION(_h));
  57. /* Reconnect */
  58. if (!db_unixodbc_build_conn_str(CON_ID(_h), conn_str)) {
  59. LM_ERR("failed to build connection string\n");
  60. return ret;
  61. }
  62. ret = SQLDriverConnect(CON_CONNECTION(_h), (void *)1,
  63. (SQLCHAR*)conn_str, SQL_NTS, outstr, sizeof(outstr),
  64. &outstrlen, SQL_DRIVER_COMPLETE);
  65. if (!SQL_SUCCEEDED(ret)) {
  66. LM_ERR("failed to connect\n");
  67. db_unixodbc_extract_error("SQLDriverConnect", CON_CONNECTION(_h),
  68. SQL_HANDLE_DBC, NULL);
  69. return ret;
  70. }
  71. ret = SQLAllocHandle(SQL_HANDLE_STMT, CON_CONNECTION(_h),
  72. &CON_RESULT(_h));
  73. if (!SQL_SUCCEEDED(ret)) {
  74. LM_ERR("Statement allocation error %d\n", (int)(long)CON_CONNECTION(_h));
  75. db_unixodbc_extract_error("SQLAllocStmt", CON_CONNECTION(_h), SQL_HANDLE_DBC,NULL);
  76. return ret;
  77. }
  78. return ret;
  79. }
  80. /*
  81. * Send an SQL query to the server
  82. */
  83. static int db_unixodbc_submit_query(const db1_con_t* _h, const str* _s)
  84. {
  85. int ret = 0;
  86. SQLCHAR sqlstate[7];
  87. if (!_h || !_s || !_s->s) {
  88. LM_ERR("invalid parameter value\n");
  89. return -1;
  90. }
  91. /* first do some cleanup if required */
  92. if(CON_RESULT(_h))
  93. {
  94. SQLCloseCursor(CON_RESULT(_h));
  95. SQLFreeHandle(SQL_HANDLE_STMT, CON_RESULT(_h));
  96. }
  97. ret = SQLAllocHandle(SQL_HANDLE_STMT, CON_CONNECTION(_h), &CON_RESULT(_h));
  98. if (!SQL_SUCCEEDED(ret))
  99. {
  100. LM_ERR("statement allocation error %d\n",
  101. (int)(long)CON_CONNECTION(_h));
  102. db_unixodbc_extract_error("SQLAllocStmt", CON_CONNECTION(_h), SQL_HANDLE_DBC,
  103. (char*)sqlstate);
  104. /* Connection broken */
  105. if( !strncmp((char*)sqlstate,"08003",5) ||
  106. !strncmp((char*)sqlstate,"08S01",5) ) {
  107. ret = reconnect(_h);
  108. if( !SQL_SUCCEEDED(ret) ) return ret;
  109. } else {
  110. return ret;
  111. }
  112. }
  113. ret=SQLExecDirect(CON_RESULT(_h), (SQLCHAR*)_s->s, _s->len);
  114. /* Handle SQL_NO_DATA as a valid return code. DELETE and UPDATE statements may return this return code if nothing was deleted/updated. */
  115. if (!SQL_SUCCEEDED(ret) && (ret != SQL_NO_DATA))
  116. {
  117. SQLCHAR sqlstate[7];
  118. LM_ERR("rv=%d. Query= %.*s\n", ret, _s->len, _s->s);
  119. db_unixodbc_extract_error("SQLExecDirect", CON_RESULT(_h), SQL_HANDLE_STMT,
  120. (char*)sqlstate);
  121. /* Connection broken */
  122. if( !strncmp((char*)sqlstate,"08003",5) ||
  123. !strncmp((char*)sqlstate,"08S01",5) ||
  124. !strncmp((char*)sqlstate,"HY000",5) /* ODBC 3 General error */
  125. )
  126. {
  127. ret = reconnect(_h);
  128. if( SQL_SUCCEEDED(ret) ) {
  129. /* Try again */
  130. ret=SQLExecDirect(CON_RESULT(_h), (SQLCHAR*)_s->s, _s->len);
  131. if (!SQL_SUCCEEDED(ret)) {
  132. LM_ERR("rv=%d. Query= %.*s\n", ret, _s->len, _s->s);
  133. db_unixodbc_extract_error("SQLExecDirect", CON_RESULT(_h),
  134. SQL_HANDLE_STMT, (char*)sqlstate);
  135. /* Close the cursor */
  136. SQLCloseCursor(CON_RESULT(_h));
  137. SQLFreeHandle(SQL_HANDLE_STMT, CON_RESULT(_h));
  138. }
  139. }
  140. }
  141. else {
  142. /* Close the cursor */
  143. SQLCloseCursor(CON_RESULT(_h));
  144. SQLFreeHandle(SQL_HANDLE_STMT, CON_RESULT(_h));
  145. }
  146. }
  147. return ret;
  148. }
  149. /*
  150. * Initialize database module
  151. * No function should be called before this
  152. */
  153. db1_con_t* db_unixodbc_init(const str* _url)
  154. {
  155. return db_do_init(_url, (void*)db_unixodbc_new_connection);
  156. }
  157. /*
  158. * Shut down database module
  159. * No function should be called after this
  160. */
  161. void db_unixodbc_close(db1_con_t* _h)
  162. {
  163. return db_do_close(_h, db_unixodbc_free_connection);
  164. }
  165. /*
  166. * Retrieve result set
  167. */
  168. static int db_unixodbc_store_result(const db1_con_t* _h, db1_res_t** _r)
  169. {
  170. if ((!_h) || (!_r))
  171. {
  172. LM_ERR("invalid parameter value\n");
  173. return -1;
  174. }
  175. *_r = db_new_result();
  176. if (*_r == 0)
  177. {
  178. LM_ERR("no memory left\n");
  179. return -2;
  180. }
  181. if (db_unixodbc_convert_result(_h, *_r) < 0)
  182. {
  183. LM_ERR("failed to convert result\n");
  184. LM_DBG("freeing result set at %p\n", _r);
  185. pkg_free(*_r);
  186. *_r = 0;
  187. return -4;
  188. }
  189. return 0;
  190. }
  191. /*
  192. * Release a result set from memory
  193. */
  194. int db_unixodbc_free_result(db1_con_t* _h, db1_res_t* _r)
  195. {
  196. if ((!_h) || (!_r))
  197. {
  198. LM_ERR("invalid parameter value\n");
  199. return -1;
  200. }
  201. if (db_free_result(_r) < 0)
  202. {
  203. LM_ERR("failed to free result structure\n");
  204. return -1;
  205. }
  206. SQLFreeHandle(SQL_HANDLE_STMT, CON_RESULT(_h));
  207. CON_RESULT(_h) = 0;
  208. return 0;
  209. }
  210. /*
  211. * Query table for specified rows
  212. * _h: structure representing database connection
  213. * _k: key names
  214. * _op: operators
  215. * _v: values of the keys that must match
  216. * _c: column names to return
  217. * _n: number of key=values pairs to compare
  218. * _nc: number of columns to return
  219. * _o: order by the specified column
  220. */
  221. int db_unixodbc_query(const db1_con_t* _h, const db_key_t* _k, const db_op_t* _op,
  222. const db_val_t* _v, const db_key_t* _c, const int _n, const int _nc,
  223. const db_key_t _o, db1_res_t** _r)
  224. {
  225. return db_do_query(_h, _k, _op, _v, _c, _n, _nc, _o, _r,
  226. db_unixodbc_val2str, db_unixodbc_submit_query, db_unixodbc_store_result);
  227. }
  228. /*!
  229. * \brief Gets a partial result set, fetch rows from a result
  230. *
  231. * Gets a partial result set, fetch a number of rows from a databae result.
  232. * This function initialize the given result structure on the first run, and
  233. * fetches the nrows number of rows. On subsequenting runs, it uses the
  234. * existing result and fetches more rows, until it reaches the end of the
  235. * result set. Because of this the result needs to be null in the first
  236. * invocation of the function. If the number of wanted rows is zero, the
  237. * function returns anything with a result of zero.
  238. * \param _h structure representing the database connection
  239. * \param _r pointer to a structure representing the result
  240. * \param nrows number of fetched rows
  241. * \return return zero on success, negative value on failure
  242. */
  243. int db_unixodbc_fetch_result(const db1_con_t* _h, db1_res_t** _r, const int nrows)
  244. {
  245. int row_n = 0, i = 0, ret = 0, len;
  246. SQLSMALLINT columns;
  247. list* rows = NULL;
  248. list* rowstart = NULL;
  249. strn* temp_row = NULL;
  250. if ((!_h) || (!_r) || nrows < 0)
  251. {
  252. LM_ERR("invalid parameter value\n");
  253. return -1;
  254. }
  255. /* exit if the fetch count is zero */
  256. if (nrows == 0) {
  257. if (*_r)
  258. db_free_result(*_r);
  259. *_r = 0;
  260. return 0;
  261. }
  262. /* On the first fetch for a query, allocate structures and get columns */
  263. if(*_r == NULL) {
  264. /* Allocate a new result structure */
  265. *_r = db_new_result();
  266. LM_DBG("just allocated a new db result structure");
  267. if (*_r == NULL) {
  268. LM_ERR("no memory left\n");
  269. return -2;
  270. }
  271. /* Get columns names and count */
  272. if (db_unixodbc_get_columns(_h, *_r) < 0) {
  273. LM_ERR("getting column names failed\n");
  274. db_free_columns(*_r);
  275. return -2;
  276. }
  277. /* On subsequent fetch attempts, reuse already allocated structures */
  278. } else {
  279. LM_DBG("db result structure already exist, reusing\n");
  280. /* free old rows */
  281. if(RES_ROWS(*_r) != NULL)
  282. db_free_rows(*_r);
  283. RES_ROWS(*_r) = 0;
  284. RES_ROW_N(*_r) = 0;
  285. }
  286. SQLNumResultCols(CON_RESULT(_h), (SQLSMALLINT *)&columns);
  287. /* Now fetch nrows at most */
  288. len = sizeof(db_row_t) * nrows;
  289. RES_ROWS(*_r) = (struct db_row*)pkg_malloc(len);
  290. if (!RES_ROWS(*_r)) {
  291. LM_ERR("no memory left\n");
  292. return -5;
  293. }
  294. LM_DBG("allocated %d bytes for RES_ROWS at %p\n", len, RES_ROWS(*_r));
  295. LM_DBG("Now fetching %i rows at most\n", nrows);
  296. while(SQL_SUCCEEDED(ret = SQLFetch(CON_RESULT(_h)))) {
  297. /* Allocate a temporary row */
  298. temp_row = db_unixodbc_new_cellrow(columns);
  299. if (!temp_row) {
  300. LM_ERR("no private memory left\n");
  301. pkg_free(RES_ROWS(*_r));
  302. pkg_free(*_r);
  303. *_r = 0;
  304. return -1;
  305. }
  306. LM_DBG("fetching %d columns for row %d...\n",columns, row_n);
  307. for(i=0; i < columns; i++) {
  308. LM_DBG("fetching column %d\n",i);
  309. if (!db_unixodbc_load_cell(_h, i+1, temp_row + i, RES_TYPES(*_r)[i])) {
  310. pkg_free(RES_ROWS(*_r));
  311. db_unixodbc_free_cellrow(columns, temp_row);
  312. pkg_free(*_r);
  313. *_r = 0;
  314. return -5;
  315. }
  316. }
  317. LM_DBG("got temp_row at %p\n", temp_row);
  318. if (db_unixodbc_list_insert(&rowstart, &rows, columns, temp_row) < 0) {
  319. LM_ERR("SQL result row insert failed\n");
  320. pkg_free(RES_ROWS(*_r));
  321. db_unixodbc_free_cellrow(columns, temp_row);
  322. pkg_free(*_r);
  323. *_r = 0;
  324. return -5;
  325. }
  326. /* Free temporary row data */
  327. LM_DBG("freeing temp_row at %p\n", temp_row);
  328. db_unixodbc_free_cellrow(columns, temp_row);
  329. temp_row = NULL;
  330. row_n++;
  331. if (row_n == nrows) {
  332. break;
  333. }
  334. }
  335. CON_ROW(_h) = NULL;
  336. RES_ROW_N(*_r) = row_n;
  337. if (!row_n) {
  338. LM_DBG("no more rows to process for db fetch");
  339. pkg_free(RES_ROWS(*_r));
  340. RES_ROWS(*_r) = 0;
  341. return 0;
  342. }
  343. /* Convert rows to internal format */
  344. memset(RES_ROWS(*_r), 0, len);
  345. i = 0;
  346. rows = rowstart;
  347. while(rows)
  348. {
  349. LM_DBG("converting row #%d\n", i);
  350. CON_ROW(_h) = rows->data;
  351. if (!CON_ROW(_h))
  352. {
  353. LM_ERR("string null\n");
  354. RES_ROW_N(*_r) = row_n;
  355. db_free_rows(*_r);
  356. return -3;
  357. }
  358. if (db_unixodbc_convert_row(_h, *_r, &(RES_ROWS(*_r)[i]), rows->lengths) < 0) {
  359. LM_ERR("converting fetched row #%d failed\n", i);
  360. RES_ROW_N(*_r) = i;
  361. db_free_rows(*_r);
  362. return -4;
  363. }
  364. i++;
  365. rows = rows->next;
  366. }
  367. db_unixodbc_list_destroy(rowstart);
  368. /* update the total number of rows processed */
  369. RES_LAST_ROW(*_r) += row_n;
  370. LM_DBG("fetch from db processed %d rows so far\n", RES_LAST_ROW(*_r));
  371. return 0;
  372. }
  373. /*
  374. * Execute a raw SQL query
  375. */
  376. int db_unixodbc_raw_query(const db1_con_t* _h, const str* _s, db1_res_t** _r)
  377. {
  378. return db_do_raw_query(_h, _s, _r, db_unixodbc_submit_query,
  379. db_unixodbc_store_result);
  380. }
  381. /*
  382. * Insert a row into specified table
  383. * _h: structure representing database connection
  384. * _k: key names
  385. * _v: values of the keys
  386. * _n: number of key=value pairs
  387. */
  388. int db_unixodbc_insert(const db1_con_t* _h, const db_key_t* _k, const db_val_t* _v, const int _n)
  389. {
  390. return db_do_insert(_h, _k, _v, _n, db_unixodbc_val2str,
  391. db_unixodbc_submit_query);
  392. }
  393. /*
  394. * Delete a row from the specified table
  395. * _h: structure representing database connection
  396. * _k: key names
  397. * _o: operators
  398. * _v: values of the keys that must match
  399. * _n: number of key=value pairs
  400. */
  401. int db_unixodbc_delete(const db1_con_t* _h, const db_key_t* _k, const db_op_t* _o,
  402. const db_val_t* _v, const int _n)
  403. {
  404. return db_do_delete(_h, _k, _o, _v, _n, db_unixodbc_val2str,
  405. db_unixodbc_submit_query);
  406. }
  407. /*
  408. * Update some rows in the specified table
  409. * _h: structure representing database connection
  410. * _k: key names
  411. * _o: operators
  412. * _v: values of the keys that must match
  413. * _uk: updated columns
  414. * _uv: updated values of the columns
  415. * _n: number of key=value pairs
  416. * _un: number of columns to update
  417. */
  418. int db_unixodbc_update(const db1_con_t* _h, const db_key_t* _k, const db_op_t* _o,
  419. const db_val_t* _v, const db_key_t* _uk, const db_val_t* _uv, const int _n, const int _un)
  420. {
  421. return db_do_update(_h, _k, _o, _v, _uk, _uv, _n, _un, db_unixodbc_val2str,
  422. db_unixodbc_submit_query);
  423. }
  424. /*
  425. * Just like insert, but replace the row if it exists
  426. */
  427. int db_unixodbc_replace(const db1_con_t* _h, const db_key_t* _k, const db_val_t* _v, const int _n,
  428. const int _un, const int _m)
  429. {
  430. return db_do_replace(_h, _k, _v, _n, db_unixodbc_val2str,
  431. db_unixodbc_submit_query);
  432. }
  433. /*
  434. * Store name of table that will be used by
  435. * subsequent database functions
  436. */
  437. int db_unixodbc_use_table(db1_con_t* _h, const str* _t)
  438. {
  439. return db_use_table(_h, _t);
  440. }