mirror of https://github.com/sipwise/kamailio.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
366 lines
7.9 KiB
366 lines
7.9 KiB
#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);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|