res.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485
  1. /*
  2. * $Id$
  3. *
  4. * Oracle module result related functions
  5. *
  6. * Copyright (C) 2007,2008 TRUNK MOBILE
  7. *
  8. * This file is part of Kamailio, a free SIP server.
  9. *
  10. * Kamailio is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License as published by
  12. * the Free Software Foundation; either version 2 of the License, or
  13. * (at your option) any later version
  14. *
  15. * Kamailio is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with this program; if not, write to the Free Software
  22. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  23. */
  24. #include <string.h>
  25. #include <time.h>
  26. #include <oci.h>
  27. #include "../../lib/srdb1/db_res.h"
  28. #include "../../lib/srdb1/db_row.h"
  29. #include "../../mem/mem.h"
  30. #include "../../dprint.h"
  31. #include "ora_con.h"
  32. #include "dbase.h"
  33. #include "asynch.h"
  34. #include "res.h"
  35. #define MAX_DEF_HANDLES 64
  36. struct dmap {
  37. OCIDefine* defh[MAX_DEF_HANDLES];
  38. union {
  39. dvoid* v;
  40. double* f;
  41. int* i;
  42. char* c;
  43. OCIDate* o;
  44. }pv[MAX_DEF_HANDLES];
  45. dvoid* pval[MAX_DEF_HANDLES];
  46. ub2 ilen[MAX_DEF_HANDLES];
  47. sb2 ind[MAX_DEF_HANDLES];
  48. ub2 len[MAX_DEF_HANDLES];
  49. };
  50. typedef struct dmap dmap_t;
  51. /*
  52. * Get and convert columns from a result. Define handlers and buffers
  53. */
  54. static int get_columns(ora_con_t* con, db1_res_t* _r, OCIStmt* _c, dmap_t* _d)
  55. {
  56. OCIParam *param;
  57. size_t tsz;
  58. ub4 i, n;
  59. sword status;
  60. status = OCIAttrGet(_c, OCI_HTYPE_STMT, &n, NULL, OCI_ATTR_PARAM_COUNT,
  61. con->errhp);
  62. if (status != OCI_SUCCESS) {
  63. LM_ERR("driver: %s\n", db_oracle_error(con, status));
  64. return -1;
  65. }
  66. if (!n) {
  67. LM_ERR("no columns\n");
  68. return -2;
  69. }
  70. if (n >= MAX_DEF_HANDLES) {
  71. LM_ERR("too many res. Rebuild with MAX_DEF_HANDLES >= %u\n", n);
  72. return -3;
  73. }
  74. if (db_allocate_columns(_r, n) != 0) {
  75. LM_ERR("could not allocate columns");
  76. return -4;
  77. }
  78. memset(RES_NAMES(_r), 0, sizeof(db_key_t) * n);
  79. RES_COL_N(_r) = n;
  80. tsz = 0;
  81. memset(_d->defh, 0, sizeof(_d->defh[0]) * n);
  82. for (i = 0; i < n; i++) {
  83. ub4 len;
  84. ub2 dtype;
  85. status = OCIParamGet(_c, OCI_HTYPE_STMT, con->errhp,
  86. (dvoid**)(dvoid*)&param, i+1);
  87. if (status != OCI_SUCCESS) goto ora_err;
  88. {
  89. text* name;
  90. str* sname;
  91. status = OCIAttrGet(param, OCI_DTYPE_PARAM,
  92. (dvoid**)(dvoid*)&name, &len, OCI_ATTR_NAME,
  93. con->errhp);
  94. if (status != OCI_SUCCESS) goto ora_err;
  95. sname = (str*)pkg_malloc(sizeof(str)+len+1);
  96. if (!sname) {
  97. db_free_columns(_r);
  98. LM_ERR("no private memory left\n");
  99. return -5;
  100. }
  101. sname->len = len;
  102. sname->s = (char*)sname + sizeof(str);
  103. memcpy(sname->s, name, len);
  104. sname->s[len] = '\0';
  105. RES_NAMES(_r)[i] = sname;
  106. }
  107. status = OCIAttrGet(param, OCI_DTYPE_PARAM,
  108. (dvoid**)(dvoid*)&dtype, NULL, OCI_ATTR_DATA_TYPE,
  109. con->errhp);
  110. if (status != OCI_SUCCESS) goto ora_err;
  111. switch (dtype) {
  112. case SQLT_UIN: /* unsigned integer */
  113. set_bitmap:
  114. LM_DBG("use DB1_BITMAP type");
  115. RES_TYPES(_r)[i] = DB1_BITMAP;
  116. len = sizeof(VAL_BITMAP((db_val_t*)NULL));
  117. break;
  118. case SQLT_INT: /* (ORANET TYPE) integer */
  119. set_int:
  120. LM_DBG("use DB1_INT result type");
  121. RES_TYPES(_r)[i] = DB1_INT;
  122. len = sizeof(VAL_INT((db_val_t*)NULL));
  123. break;
  124. // case SQLT_LNG: /* long */
  125. case SQLT_VNU: /* NUM with preceding length byte */
  126. case SQLT_NUM: /* (ORANET TYPE) oracle numeric */
  127. len = 0; /* PRECISION is ub1 */
  128. status = OCIAttrGet(param, OCI_DTYPE_PARAM,
  129. (dvoid**)(dvoid*)&len, NULL, OCI_ATTR_PRECISION,
  130. con->errhp);
  131. if (status != OCI_SUCCESS) goto ora_err;
  132. if (len <= 11) {
  133. sb1 sc;
  134. status = OCIAttrGet(param, OCI_DTYPE_PARAM,
  135. (dvoid**)(dvoid*)&sc, NULL,
  136. OCI_ATTR_SCALE, con->errhp);
  137. if (status != OCI_SUCCESS) goto ora_err;
  138. if (!sc) {
  139. dtype = SQLT_INT;
  140. if (len != 11) goto set_int;
  141. dtype = SQLT_UIN;
  142. goto set_bitmap;
  143. }
  144. }
  145. case SQLT_FLT: /* (ORANET TYPE) Floating point number */
  146. case SQLT_BFLOAT: /* Native Binary float*/
  147. case SQLT_BDOUBLE: /* NAtive binary double */
  148. case SQLT_IBFLOAT: /* binary float canonical */
  149. case SQLT_IBDOUBLE: /* binary double canonical */
  150. case SQLT_PDN: /* (ORANET TYPE) Packed Decimal Numeric */
  151. LM_DBG("use DB1_DOUBLE result type");
  152. RES_TYPES(_r)[i] = DB1_DOUBLE;
  153. len = sizeof(VAL_DOUBLE((db_val_t*)NULL));
  154. dtype = SQLT_FLT;
  155. break;
  156. // case SQLT_TIME: /* TIME */
  157. // case SQLT_TIME_TZ: /* TIME WITH TIME ZONE */
  158. case SQLT_DATE: /* ANSI Date */
  159. case SQLT_DAT: /* date in oracle format */
  160. case SQLT_ODT: /* OCIDate type */
  161. case SQLT_TIMESTAMP: /* TIMESTAMP */
  162. case SQLT_TIMESTAMP_TZ: /* TIMESTAMP WITH TIME ZONE */
  163. case SQLT_TIMESTAMP_LTZ:/* TIMESTAMP WITH LOCAL TZ */
  164. // case SQLT_INTERVAL_YM: /* INTERVAL YEAR TO MONTH */
  165. // case SQLT_INTERVAL_DS: /* INTERVAL DAY TO SECOND */
  166. LM_DBG("use DB1_DATETIME result type");
  167. RES_TYPES(_r)[i] = DB1_DATETIME;
  168. len = sizeof(OCIDate);
  169. dtype = SQLT_ODT;
  170. break;
  171. case SQLT_CLOB: /* character lob */
  172. case SQLT_BLOB: /* binary lob */
  173. // case SQLT_BFILEE: /* binary file lob */
  174. // case SQLT_CFILEE: /* character file lob */
  175. // case SQLT_BIN: /* binary data(DTYBIN) */
  176. // case SQLT_LBI: /* long binary */
  177. LM_DBG("use DB1_BLOB result type");
  178. RES_TYPES(_r)[i] = DB1_BLOB;
  179. goto dyn_str;
  180. case SQLT_CHR: /* (ORANET TYPE) character string */
  181. case SQLT_STR: /* zero terminated string */
  182. case SQLT_VST: /* OCIString type */
  183. case SQLT_VCS: /* Variable character string */
  184. case SQLT_AFC: /* Ansi fixed char */
  185. case SQLT_AVC: /* Ansi Var char */
  186. // case SQLT_RID: /* rowid */
  187. LM_DBG("use DB1_STR result type");
  188. RES_TYPES(_r)[i] = DB1_STR;
  189. dyn_str:
  190. dtype = SQLT_CHR;
  191. len = 0; /* DATA_SIZE is ub2 */
  192. status = OCIAttrGet(param, OCI_DTYPE_PARAM,
  193. (dvoid**)(dvoid*)&len, NULL, OCI_ATTR_DATA_SIZE,
  194. con->errhp);
  195. if (status != OCI_SUCCESS) goto ora_err;
  196. if (len >= 4000) {
  197. LM_DBG("use DB1_BLOB result type");
  198. RES_TYPES(_r)[i] = DB1_BLOB;
  199. }
  200. ++len;
  201. break;
  202. default:
  203. LM_ERR("unsupported datatype %d\n", dtype);
  204. goto stop_load;
  205. }
  206. _d->ilen[i] = (ub2)len;
  207. _d->pv[i].v = st_buf + tsz;
  208. tsz += len;
  209. status = OCIDefineByPos(_c, &_d->defh[i], con->errhp, i+1,
  210. _d->pv[i].v, len, dtype, &_d->ind[i],
  211. &_d->len[i], NULL, OCI_DEFAULT);
  212. if (status != OCI_SUCCESS) goto ora_err;
  213. }
  214. #if STATIC_BUF_LEN < 65536
  215. #error
  216. #endif
  217. if (tsz > 65536) {
  218. LM_ERR("Row size exceed 65K. IOB's are not supported");
  219. goto stop_load;
  220. }
  221. return 0;
  222. ora_err:
  223. LM_ERR("driver: %s\n", db_oracle_error(con, status));
  224. stop_load:
  225. db_free_columns(_r);
  226. return -6;
  227. }
  228. /*
  229. * Convert data fron db format to internal format
  230. */
  231. static int convert_row(db1_res_t* _res, db_row_t* _r, dmap_t* _d)
  232. {
  233. unsigned i, n = RES_COL_N(_res);
  234. ROW_N(_r) = n;
  235. ROW_VALUES(_r) = (db_val_t*)pkg_malloc(sizeof(db_val_t) * n);
  236. if (!ROW_VALUES(_r)) {
  237. nomem:
  238. LM_ERR("no private memory left\n");
  239. return -1;
  240. }
  241. memset(ROW_VALUES(_r), 0, sizeof(db_val_t) * n);
  242. for (i = 0; i < n; i++) {
  243. static const str dummy_string = {"", 0};
  244. db_val_t* v = &ROW_VALUES(_r)[i];
  245. db_type_t t = RES_TYPES(_res)[i];
  246. if (_d->ind[i] == -1) {
  247. /* Initialize the string pointers to a dummy empty
  248. * string so that we do not crash when the NULL flag
  249. * is set but the module does not check it properly
  250. */
  251. VAL_STRING(v) = dummy_string.s;
  252. VAL_STR(v) = dummy_string;
  253. VAL_BLOB(v) = dummy_string;
  254. VAL_TYPE(v) = t;
  255. VAL_NULL(v) = 1;
  256. continue;
  257. }
  258. if (_d->ind[i])
  259. LM_WARN("truncated value in DB\n");
  260. VAL_TYPE(v) = t;
  261. switch (t) {
  262. case DB1_INT:
  263. VAL_INT(v) = *_d->pv[i].i;
  264. break;
  265. case DB1_BIGINT:
  266. LM_ERR("BIGINT not supported");
  267. return -1;
  268. case DB1_BITMAP:
  269. VAL_BITMAP(v) = *_d->pv[i].i;
  270. break;
  271. case DB1_DOUBLE:
  272. VAL_DOUBLE(v) = *_d->pv[i].f;
  273. break;
  274. case DB1_DATETIME:
  275. {
  276. struct tm tm;
  277. memset(&tm, 0, sizeof(tm));
  278. OCIDateGetTime(_d->pv[i].o, &tm.tm_hour,
  279. &tm.tm_min, &tm.tm_sec);
  280. OCIDateGetDate(_d->pv[i].o, &tm.tm_year,
  281. &tm.tm_mon, &tm.tm_mday);
  282. if (tm.tm_mon)
  283. --tm.tm_mon;
  284. if (tm.tm_year >= 1900)
  285. tm.tm_year -= 1900;
  286. VAL_TIME(v) = mktime(&tm);
  287. }
  288. break;
  289. case DB1_STR:
  290. case DB1_BLOB:
  291. case DB1_STRING:
  292. {
  293. size_t len = _d->len[i];
  294. char *pstr = pkg_malloc(len+1);
  295. if (!pstr) goto nomem;
  296. memcpy(pstr, _d->pv[i].c, len);
  297. pstr[len] = '\0';
  298. VAL_FREE(v) = 1;
  299. if (t == DB1_STR) {
  300. VAL_STR(v).s = pstr;
  301. VAL_STR(v).len = len;
  302. } else if (t == DB1_BLOB) {
  303. VAL_BLOB(v).s = pstr;
  304. VAL_BLOB(v).len = len;
  305. } else {
  306. VAL_STRING(v) = pstr;
  307. }
  308. }
  309. break;
  310. default:
  311. LM_ERR("unknown type mapping (%u)\n", t);
  312. return -2;
  313. }
  314. }
  315. return 0;
  316. }
  317. /*
  318. * Get rows and convert it from oracle to db API representation
  319. */
  320. static int get_rows(ora_con_t* con, db1_res_t* _r, OCIStmt* _c, dmap_t* _d)
  321. {
  322. ub4 rcnt;
  323. sword status;
  324. unsigned n = RES_COL_N(_r);
  325. memcpy(_d->len, _d->ilen, sizeof(_d->len[0]) * n);
  326. // timelimited operation
  327. status = begin_timelimit(con, 0);
  328. if (status != OCI_SUCCESS) goto ora_err;
  329. do status = OCIStmtFetch2(_c, con->errhp, 1, OCI_FETCH_LAST, 0,
  330. OCI_DEFAULT);
  331. while (wait_timelimit(con, status));
  332. if (done_timelimit(con, status)) goto stop_load;
  333. if (status != OCI_SUCCESS) {
  334. if (status != OCI_NO_DATA)
  335. goto ora_err;
  336. RES_ROW_N(_r) = 0;
  337. RES_ROWS(_r) = NULL;
  338. return 0;
  339. }
  340. status = OCIAttrGet(_c, OCI_HTYPE_STMT, &rcnt, NULL,
  341. OCI_ATTR_CURRENT_POSITION, con->errhp);
  342. if (status != OCI_SUCCESS) goto ora_err;
  343. if (!rcnt) {
  344. LM_ERR("lastpos==0\n");
  345. goto stop_load;
  346. }
  347. RES_ROW_N(_r) = rcnt;
  348. RES_ROWS(_r) = (db_row_t*)pkg_malloc(sizeof(db_row_t) * rcnt);
  349. if (!RES_ROWS(_r)) {
  350. LM_ERR("no private memory left\n");
  351. return -1;
  352. }
  353. memset(RES_ROWS(_r), 0, sizeof(db_row_t) * rcnt);
  354. while ( 1 ) {
  355. if (convert_row(_r, &RES_ROWS(_r)[--rcnt], _d) < 0) {
  356. LM_ERR("erroc convert row\n");
  357. goto stop_load;
  358. }
  359. if (!rcnt)
  360. return 0;
  361. memcpy(_d->len, _d->ilen, sizeof(_d->len[0]) * n);
  362. // timelimited operation
  363. status = begin_timelimit(con, 0);
  364. if (status != OCI_SUCCESS) goto ora_err;
  365. do status = OCIStmtFetch2(_c, con->errhp, 1, OCI_FETCH_PRIOR, 0,
  366. OCI_DEFAULT);
  367. while (wait_timelimit(con, status));
  368. if (done_timelimit(con, status)) goto stop_load;
  369. if (status != OCI_SUCCESS) break;
  370. }
  371. ora_err:
  372. LM_ERR("driver: %s\n", db_oracle_error(con, status));
  373. stop_load:
  374. db_free_rows(_r);
  375. RES_ROW_N(_r) = 0; /* TODO: skipped in db_res.c :) */
  376. return -3;
  377. }
  378. /*
  379. * Read database answer and fill the structure
  380. */
  381. int db_oracle_store_result(const db1_con_t* _h, db1_res_t** _r)
  382. {
  383. dmap_t dmap;
  384. int rc;
  385. db1_res_t* r;
  386. ora_con_t* con;
  387. OCIStmt* hs;
  388. if (!_h || !_r) {
  389. badparam:
  390. LM_ERR("invalid parameter\n");
  391. return -1;
  392. }
  393. con = CON_ORA(_h);
  394. {
  395. query_data_t *pcb = con->pqdata;
  396. if (!pcb || !pcb->_rs)
  397. goto badparam;
  398. hs = *pcb->_rs;
  399. pcb->_rs = NULL; /* paranoid for next call */
  400. }
  401. rc = -1;
  402. if (_r) *_r = NULL; /* unification for all errors */
  403. r = db_new_result();
  404. if (!r) {
  405. LM_ERR("no memory left\n");
  406. goto done;
  407. }
  408. if (get_columns(con, r, hs, &dmap) < 0) {
  409. LM_ERR("error while getting column names\n");
  410. goto done;
  411. }
  412. if (get_rows(con, r, hs, &dmap) < 0) {
  413. LM_ERR("error while converting rows\n");
  414. db_free_columns(r);
  415. goto done;
  416. }
  417. rc = 0;
  418. *_r = r;
  419. done:
  420. OCIHandleFree(hs, OCI_HTYPE_STMT);
  421. return rc;
  422. }