123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348 |
- #include "orasel.h"
- #include <math.h>
- #include <assert.h>
- /*
- * Uncomment next string if you will sell 'NULL' on unitialized NON text field
- */
- //#define NULL_ID "NULL"
- static char st_buf[65536];
- enum type_t {
- DB_STR = 0,
- DB_DATETIME,
- /* end of left alignment */
- DB_INT,
- DB_BITMAP,
- DB_DOUBLE /* MUST belast */
- };
- //---------------------------------------------------------
- struct dmap {
- OCIDefine** defh;
- union {
- dvoid* v;
- double* f;
- int* i;
- char* c;
- OCIDate* o;
- }* pv;
- dvoid** pval;
- ub2* ilen;
- sb2* ind;
- ub2* len;
- };
- typedef struct dmap dmap_t;
- //-----------------------------------------------------------------------------
- static void dmap_init(dmap_t* _d, unsigned n)
- {
- size_t sz = sizeof(*_d->defh) + sizeof(*_d->pv) + sizeof(*_d->pval) +
- sizeof(*_d->ilen) + sizeof(*_d->ind) + sizeof(*_d->len);
- unsigned char *p = safe_malloc(sz * n);
- _d->defh = (void*)p;
- p += n*sizeof(*_d->defh);
- _d->pv = (void*)p;
- p += n*sizeof(*_d->pv);
- _d->pval = (void*)p;
- p += n*sizeof(*_d->pval);
- _d->ilen = (void*)p;
- p += n*sizeof(*_d->ilen);
- _d->ind = (void*)p;
- p += n*sizeof(*_d->ind);
- _d->len = (void*)p;
- // p += n*sizeof(*_d->len);
- }
- //-----------------------------------------------------------------------------
- /*
- * Get and convert columns from a result. Define handlers and buffers
- */
- static void get_columns(const con_t* con, res_t* _r, dmap_t* _d)
- {
- OCIParam *param;
- size_t tsz;
- ub4 i, n;
- sword status;
- status = OCIAttrGet(con->stmthp, OCI_HTYPE_STMT, &n, NULL,
- OCI_ATTR_PARAM_COUNT, con->errhp);
- if (status != OCI_SUCCESS) oraxit(status, con);
- if (!n) donegood("Empty table");
- dmap_init(_d, n);
- _r->names = (Str**)safe_malloc(n * sizeof(Str*));
- _r->types = (unsigned char*)safe_malloc(n * sizeof(unsigned char));
- _r->col_n = n;
- tsz = 0;
- memset(_d->defh, 0, sizeof(_d->defh[0]) * n);
- for (i = 0; i < n; i++) {
- ub4 len;
- ub2 dtype;
- unsigned char ctype = DB_DOUBLE;
- status = OCIParamGet(con->stmthp, OCI_HTYPE_STMT, con->errhp,
- (dvoid**)(dvoid*)¶m, i+1);
- if (status != OCI_SUCCESS) goto ora_err;
- {
- text *name;
- status = OCIAttrGet(param, OCI_DTYPE_PARAM,
- (dvoid**)(dvoid*)&name, &len,
- OCI_ATTR_NAME, con->errhp);
- if (status != OCI_SUCCESS) goto ora_err;
- _r->names[i] = str_alloc((char*)name, len);
- }
- status = OCIAttrGet(param, OCI_DTYPE_PARAM,
- (dvoid**)(dvoid*)&dtype, NULL,
- OCI_ATTR_DATA_TYPE, con->errhp);
- if (status != OCI_SUCCESS) goto ora_err;
- switch (dtype) {
- case SQLT_UIN:
- set_bitmap:
- ctype = DB_BITMAP;
- len = sizeof(unsigned);
- break;
- case SQLT_INT:
- set_int:
- ctype = DB_INT;
- len = sizeof(int);
- break;
- case SQLT_VNU:
- case SQLT_NUM:
- len = 0; /* PRECISION is ub1 (byte) */
- status = OCIAttrGet(param, OCI_DTYPE_PARAM,
- (dvoid**)(dvoid*)&len, NULL,
- OCI_ATTR_PRECISION, con->errhp);
- if (status != OCI_SUCCESS) goto ora_err;
- if (len <= 11) {
- sb1 sc;
- status = OCIAttrGet(param, OCI_DTYPE_PARAM,
- (dvoid**)(dvoid*)&sc, NULL,
- OCI_ATTR_SCALE, con->errhp);
- if (status != OCI_SUCCESS) goto ora_err;
- if (!sc) {
- dtype = SQLT_INT;
- if (len != 11) goto set_int;
- dtype = SQLT_UIN;
- goto set_bitmap;
- }
- if(sc < 0) sc = 0;
- ctype += sc;
- }
- case SQLT_FLT:
- case SQLT_BFLOAT:
- case SQLT_BDOUBLE:
- case SQLT_IBFLOAT:
- case SQLT_IBDOUBLE:
- case SQLT_PDN:
- len = sizeof(double);
- dtype = SQLT_FLT;
- break;
- case SQLT_DATE:
- case SQLT_DAT:
- case SQLT_ODT:
- case SQLT_TIMESTAMP:
- case SQLT_TIMESTAMP_TZ:
- case SQLT_TIMESTAMP_LTZ:
- ctype = DB_DATETIME;
- len = sizeof(OCIDate);
- dtype = SQLT_ODT;
- break;
- case SQLT_CLOB:
- case SQLT_BLOB:
- case SQLT_CHR:
- case SQLT_STR:
- case SQLT_VST:
- case SQLT_VCS:
- case SQLT_AFC:
- case SQLT_AVC:
- ctype = DB_STR;
- dtype = SQLT_CHR;
- len = 0; /* DATA_SIZE is ub2 (word) */
- status = OCIAttrGet(param, OCI_DTYPE_PARAM,
- (dvoid**)(dvoid*)&len, NULL,
- OCI_ATTR_DATA_SIZE, con->errhp);
- if (status != OCI_SUCCESS) goto ora_err;
- ++len;
- break;
- default:
- errxit("unsupported datatype");
- }
- _r->types[i] = ctype;
- _d->ilen[i] = (ub2)len;
- _d->pv[i].v = st_buf + tsz;
- tsz += len;
- status = OCIDefineByPos(con->stmthp, &_d->defh[i], con->errhp,
- i+1, _d->pv[i].v, len, dtype, &_d->ind[i],
- &_d->len[i], NULL, OCI_DEFAULT);
- if (status != OCI_SUCCESS) goto ora_err;
- }
- if (tsz > sizeof(st_buf)) errxit("too large row");
- return;
- ora_err:
- oraxit(status, con);
- }
- //-----------------------------------------------------------------------------
- /*
- * Convert data fron db format to internal format
- */
- static void convert_row(const res_t* _res, Str*** _r, const dmap_t* _d)
- {
- unsigned i, n = _res->col_n;
- Str** v;
- *_r = v = (Str**)safe_malloc(n * sizeof(Str**));
- for (i = 0; i < n; i++, v++) {
- char buf[64];
- unsigned char t = _res->types[i];
- if (_d->ind[i] == -1) {
- static const struct {
- unsigned len;
- char s[1];
- }_empty = { 0, "" };
- #ifdef NULL_ID
- static const struct {
- unsigned len;
- char s[sizeof(NULL_ID)];
- }_null = { sizeof(NULL_ID)-1, NULL_ID };
- *v = (Str*)&_null;
- if (t != DB_STR) continue;
- #endif
- *v = (Str*)&_empty;
- continue;
- }
- // if (_d->ind[i]) errxit("truncated value in DB");
- switch (t) {
- case DB_STR:
- *v = str_alloc(_d->pv[i].c, _d->len[i]);
- break;
- case DB_INT:
- *v = str_alloc(buf, snprintf(buf, sizeof(buf), "%i",
- *_d->pv[i].i));
- break;
- case DB_BITMAP:
- *v = str_alloc(buf, snprintf(buf, sizeof(buf), "0x%X",
- *_d->pv[i].i));
- break;
- case DB_DATETIME:
- {
- struct tm tm;
- memset(&tm, 0, sizeof(tm));
- OCIDateGetTime(_d->pv[i].o, &tm.tm_hour,
- &tm.tm_min, &tm.tm_sec);
- OCIDateGetDate(_d->pv[i].o, &tm.tm_year,
- &tm.tm_mon, &tm.tm_mday);
- if (tm.tm_mon)
- --tm.tm_mon;
- if (tm.tm_year >= 1900)
- tm.tm_year -= 1900;
- *v = str_alloc(buf, strftime(buf, sizeof(buf),
- "%d-%b-%Y %T", &tm));
- }
- break;
- case DB_DOUBLE:
- *v = str_alloc(buf, snprintf(buf, sizeof(buf), "%g",
- *_d->pv[i].f));
- break;
- default:
- {
- double x = fabs(*_d->pv[i].f);
- const char *fmt = "%.*f";
- if (x && (x >= 1.0e6 || x < 1.0e-5))
- fmt = "%.*e";
- *v = str_alloc(buf, snprintf(buf, sizeof(buf),
- fmt, (t - DB_DOUBLE), *_d->pv[i].f));
- }
- break;
- }
- }
- }
- //-----------------------------------------------------------------------------
- /*
- * Get rows and convert it from oracle to db API representation
- */
- static void get_rows(const con_t* con, res_t* _r, dmap_t* _d)
- {
- ub4 rcnt;
- sword status;
- unsigned n = _r->col_n;
- memcpy(_d->len, _d->ilen, sizeof(_d->len[0]) * n);
- status = OCIStmtFetch2(con->stmthp, con->errhp, 1, OCI_FETCH_LAST, 0,
- OCI_DEFAULT);
- if (status != OCI_SUCCESS) {
- if (status == OCI_NO_DATA) donegood("Empty set");
- goto ora_err;
- }
- status = OCIAttrGet(con->stmthp, OCI_HTYPE_STMT, &rcnt, NULL,
- OCI_ATTR_CURRENT_POSITION, con->errhp);
- if (status != OCI_SUCCESS) goto ora_err;
- if (!rcnt) errxit("lastpos==0");
- _r->row_n = rcnt;
- _r->rows = (Str***)safe_malloc(rcnt * sizeof(Str**));
- while ( 1 ) {
- convert_row(_r, &_r->rows[--rcnt], _d);
- if (!rcnt) return;
- memcpy(_d->len, _d->ilen, sizeof(_d->len[0]) * n);
- status = OCIStmtFetch2(con->stmthp, con->errhp, 1,
- OCI_FETCH_PRIOR, 0, OCI_DEFAULT);
- if (status != OCI_SUCCESS) break;
- }
- ora_err:
- oraxit(status, con);
- }
- //-----------------------------------------------------------------------------
- /*
- * Read database answer and fill the structure
- */
- void get_res(const con_t* con, res_t* _r)
- {
- dmap_t dmap;
- unsigned n;
- unsigned char *pt;
- get_columns(con, _r, &dmap);
- get_rows(con, _r, &dmap);
- n = _r->col_n;
- pt = _r->types;
- do {
- --n;
- assert(DB_STR == 0 && DB_DATETIME == 1);
- pt[n] = (pt[n] <= DB_DATETIME);
- }while(n);
- }
- //-----------------------------------------------------------------------------
|