getres.c 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. #include "orasel.h"
  2. #include <math.h>
  3. #include <assert.h>
  4. /*
  5. * Uncomment next string if you will sell 'NULL' on unitialized NON text field
  6. */
  7. //#define NULL_ID "NULL"
  8. static char st_buf[65536];
  9. enum type_t {
  10. DB_STR = 0,
  11. DB_DATETIME,
  12. /* end of left alignment */
  13. DB_INT,
  14. DB_BITMAP,
  15. DB_DOUBLE /* MUST belast */
  16. };
  17. //---------------------------------------------------------
  18. struct dmap {
  19. OCIDefine** defh;
  20. union {
  21. dvoid* v;
  22. double* f;
  23. int* i;
  24. char* c;
  25. OCIDate* o;
  26. }* pv;
  27. dvoid** pval;
  28. ub2* ilen;
  29. sb2* ind;
  30. ub2* len;
  31. };
  32. typedef struct dmap dmap_t;
  33. //-----------------------------------------------------------------------------
  34. static void dmap_init(dmap_t* _d, unsigned n)
  35. {
  36. size_t sz = sizeof(*_d->defh) + sizeof(*_d->pv) + sizeof(*_d->pval) +
  37. sizeof(*_d->ilen) + sizeof(*_d->ind) + sizeof(*_d->len);
  38. unsigned char *p = safe_malloc(sz * n);
  39. _d->defh = (void*)p;
  40. p += n*sizeof(*_d->defh);
  41. _d->pv = (void*)p;
  42. p += n*sizeof(*_d->pv);
  43. _d->pval = (void*)p;
  44. p += n*sizeof(*_d->pval);
  45. _d->ilen = (void*)p;
  46. p += n*sizeof(*_d->ilen);
  47. _d->ind = (void*)p;
  48. p += n*sizeof(*_d->ind);
  49. _d->len = (void*)p;
  50. // p += n*sizeof(*_d->len);
  51. }
  52. //-----------------------------------------------------------------------------
  53. /*
  54. * Get and convert columns from a result. Define handlers and buffers
  55. */
  56. static void get_columns(const con_t* con, res_t* _r, dmap_t* _d)
  57. {
  58. OCIParam *param;
  59. size_t tsz;
  60. ub4 i, n;
  61. sword status;
  62. status = OCIAttrGet(con->stmthp, OCI_HTYPE_STMT, &n, NULL,
  63. OCI_ATTR_PARAM_COUNT, con->errhp);
  64. if (status != OCI_SUCCESS) oraxit(status, con);
  65. if (!n) donegood("Empty table");
  66. dmap_init(_d, n);
  67. _r->names = (Str**)safe_malloc(n * sizeof(Str*));
  68. _r->types = (unsigned char*)safe_malloc(n * sizeof(unsigned char));
  69. _r->col_n = n;
  70. tsz = 0;
  71. memset(_d->defh, 0, sizeof(_d->defh[0]) * n);
  72. for (i = 0; i < n; i++) {
  73. ub4 len;
  74. ub2 dtype;
  75. unsigned char ctype = DB_DOUBLE;
  76. status = OCIParamGet(con->stmthp, OCI_HTYPE_STMT, con->errhp,
  77. (dvoid**)(dvoid*)&param, i+1);
  78. if (status != OCI_SUCCESS) goto ora_err;
  79. {
  80. text *name;
  81. status = OCIAttrGet(param, OCI_DTYPE_PARAM,
  82. (dvoid**)(dvoid*)&name, &len,
  83. OCI_ATTR_NAME, con->errhp);
  84. if (status != OCI_SUCCESS) goto ora_err;
  85. _r->names[i] = str_alloc((char*)name, len);
  86. }
  87. status = OCIAttrGet(param, OCI_DTYPE_PARAM,
  88. (dvoid**)(dvoid*)&dtype, NULL,
  89. OCI_ATTR_DATA_TYPE, con->errhp);
  90. if (status != OCI_SUCCESS) goto ora_err;
  91. switch (dtype) {
  92. case SQLT_UIN:
  93. set_bitmap:
  94. ctype = DB_BITMAP;
  95. len = sizeof(unsigned);
  96. break;
  97. case SQLT_INT:
  98. set_int:
  99. ctype = DB_INT;
  100. len = sizeof(int);
  101. break;
  102. case SQLT_VNU:
  103. case SQLT_NUM:
  104. len = 0; /* PRECISION is ub1 (byte) */
  105. status = OCIAttrGet(param, OCI_DTYPE_PARAM,
  106. (dvoid**)(dvoid*)&len, NULL,
  107. OCI_ATTR_PRECISION, con->errhp);
  108. if (status != OCI_SUCCESS) goto ora_err;
  109. if (len <= 11) {
  110. sb1 sc;
  111. status = OCIAttrGet(param, OCI_DTYPE_PARAM,
  112. (dvoid**)(dvoid*)&sc, NULL,
  113. OCI_ATTR_SCALE, con->errhp);
  114. if (status != OCI_SUCCESS) goto ora_err;
  115. if (!sc) {
  116. dtype = SQLT_INT;
  117. if (len != 11) goto set_int;
  118. dtype = SQLT_UIN;
  119. goto set_bitmap;
  120. }
  121. if(sc < 0) sc = 0;
  122. ctype += sc;
  123. }
  124. case SQLT_FLT:
  125. case SQLT_BFLOAT:
  126. case SQLT_BDOUBLE:
  127. case SQLT_IBFLOAT:
  128. case SQLT_IBDOUBLE:
  129. case SQLT_PDN:
  130. len = sizeof(double);
  131. dtype = SQLT_FLT;
  132. break;
  133. case SQLT_DATE:
  134. case SQLT_DAT:
  135. case SQLT_ODT:
  136. case SQLT_TIMESTAMP:
  137. case SQLT_TIMESTAMP_TZ:
  138. case SQLT_TIMESTAMP_LTZ:
  139. ctype = DB_DATETIME;
  140. len = sizeof(OCIDate);
  141. dtype = SQLT_ODT;
  142. break;
  143. case SQLT_CLOB:
  144. case SQLT_BLOB:
  145. case SQLT_CHR:
  146. case SQLT_STR:
  147. case SQLT_VST:
  148. case SQLT_VCS:
  149. case SQLT_AFC:
  150. case SQLT_AVC:
  151. ctype = DB_STR;
  152. dtype = SQLT_CHR;
  153. len = 0; /* DATA_SIZE is ub2 (word) */
  154. status = OCIAttrGet(param, OCI_DTYPE_PARAM,
  155. (dvoid**)(dvoid*)&len, NULL,
  156. OCI_ATTR_DATA_SIZE, con->errhp);
  157. if (status != OCI_SUCCESS) goto ora_err;
  158. ++len;
  159. break;
  160. default:
  161. errxit("unsupported datatype");
  162. }
  163. _r->types[i] = ctype;
  164. _d->ilen[i] = (ub2)len;
  165. _d->pv[i].v = st_buf + tsz;
  166. tsz += len;
  167. status = OCIDefineByPos(con->stmthp, &_d->defh[i], con->errhp,
  168. i+1, _d->pv[i].v, len, dtype, &_d->ind[i],
  169. &_d->len[i], NULL, OCI_DEFAULT);
  170. if (status != OCI_SUCCESS) goto ora_err;
  171. }
  172. if (tsz > sizeof(st_buf)) errxit("too large row");
  173. return;
  174. ora_err:
  175. oraxit(status, con);
  176. }
  177. //-----------------------------------------------------------------------------
  178. /*
  179. * Convert data fron db format to internal format
  180. */
  181. static void convert_row(const res_t* _res, Str*** _r, const dmap_t* _d)
  182. {
  183. unsigned i, n = _res->col_n;
  184. Str** v;
  185. *_r = v = (Str**)safe_malloc(n * sizeof(Str**));
  186. for (i = 0; i < n; i++, v++) {
  187. char buf[64];
  188. unsigned char t = _res->types[i];
  189. if (_d->ind[i] == -1) {
  190. static const struct {
  191. unsigned len;
  192. char s[1];
  193. }_empty = { 0, "" };
  194. #ifdef NULL_ID
  195. static const struct {
  196. unsigned len;
  197. char s[sizeof(NULL_ID)];
  198. }_null = { sizeof(NULL_ID)-1, NULL_ID };
  199. *v = (Str*)&_null;
  200. if (t != DB_STR) continue;
  201. #endif
  202. *v = (Str*)&_empty;
  203. continue;
  204. }
  205. // if (_d->ind[i]) errxit("truncated value in DB");
  206. switch (t) {
  207. case DB_STR:
  208. *v = str_alloc(_d->pv[i].c, _d->len[i]);
  209. break;
  210. case DB_INT:
  211. *v = str_alloc(buf, snprintf(buf, sizeof(buf), "%i",
  212. *_d->pv[i].i));
  213. break;
  214. case DB_BITMAP:
  215. *v = str_alloc(buf, snprintf(buf, sizeof(buf), "0x%X",
  216. *_d->pv[i].i));
  217. break;
  218. case DB_DATETIME:
  219. {
  220. struct tm tm;
  221. memset(&tm, 0, sizeof(tm));
  222. OCIDateGetTime(_d->pv[i].o, &tm.tm_hour,
  223. &tm.tm_min, &tm.tm_sec);
  224. OCIDateGetDate(_d->pv[i].o, &tm.tm_year,
  225. &tm.tm_mon, &tm.tm_mday);
  226. if (tm.tm_mon)
  227. --tm.tm_mon;
  228. if (tm.tm_year >= 1900)
  229. tm.tm_year -= 1900;
  230. *v = str_alloc(buf, strftime(buf, sizeof(buf),
  231. "%d-%b-%Y %T", &tm));
  232. }
  233. break;
  234. case DB_DOUBLE:
  235. *v = str_alloc(buf, snprintf(buf, sizeof(buf), "%g",
  236. *_d->pv[i].f));
  237. break;
  238. default:
  239. {
  240. double x = fabs(*_d->pv[i].f);
  241. const char *fmt = "%.*f";
  242. if (x && (x >= 1.0e6 || x < 1.0e-5))
  243. fmt = "%.*e";
  244. *v = str_alloc(buf, snprintf(buf, sizeof(buf),
  245. fmt, (t - DB_DOUBLE), *_d->pv[i].f));
  246. }
  247. break;
  248. }
  249. }
  250. }
  251. //-----------------------------------------------------------------------------
  252. /*
  253. * Get rows and convert it from oracle to db API representation
  254. */
  255. static void get_rows(const con_t* con, res_t* _r, dmap_t* _d)
  256. {
  257. ub4 rcnt;
  258. sword status;
  259. unsigned n = _r->col_n;
  260. memcpy(_d->len, _d->ilen, sizeof(_d->len[0]) * n);
  261. status = OCIStmtFetch2(con->stmthp, con->errhp, 1, OCI_FETCH_LAST, 0,
  262. OCI_DEFAULT);
  263. if (status != OCI_SUCCESS) {
  264. if (status == OCI_NO_DATA) donegood("Empty set");
  265. goto ora_err;
  266. }
  267. status = OCIAttrGet(con->stmthp, OCI_HTYPE_STMT, &rcnt, NULL,
  268. OCI_ATTR_CURRENT_POSITION, con->errhp);
  269. if (status != OCI_SUCCESS) goto ora_err;
  270. if (!rcnt) errxit("lastpos==0");
  271. _r->row_n = rcnt;
  272. _r->rows = (Str***)safe_malloc(rcnt * sizeof(Str**));
  273. while ( 1 ) {
  274. convert_row(_r, &_r->rows[--rcnt], _d);
  275. if (!rcnt) return;
  276. memcpy(_d->len, _d->ilen, sizeof(_d->len[0]) * n);
  277. status = OCIStmtFetch2(con->stmthp, con->errhp, 1,
  278. OCI_FETCH_PRIOR, 0, OCI_DEFAULT);
  279. if (status != OCI_SUCCESS) break;
  280. }
  281. ora_err:
  282. oraxit(status, con);
  283. }
  284. //-----------------------------------------------------------------------------
  285. /*
  286. * Read database answer and fill the structure
  287. */
  288. void get_res(const con_t* con, res_t* _r)
  289. {
  290. dmap_t dmap;
  291. unsigned n;
  292. unsigned char *pt;
  293. get_columns(con, _r, &dmap);
  294. get_rows(con, _r, &dmap);
  295. n = _r->col_n;
  296. pt = _r->types;
  297. do {
  298. --n;
  299. assert(DB_STR == 0 && DB_DATETIME == 1);
  300. pt[n] = (pt[n] <= DB_DATETIME);
  301. }while(n);
  302. }
  303. //-----------------------------------------------------------------------------