db_oracle/res.c

Go to the documentation of this file.
00001 /*
00002  * $Id$
00003  *
00004  * Oracle module result related functions
00005  *
00006  * Copyright (C) 2007,2008 TRUNK MOBILE
00007  *
00008  * This file is part of Kamailio, a free SIP server.
00009  *
00010  * Kamailio is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2 of the License, or
00013  * (at your option) any later version
00014  *
00015  * Kamailio is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  * GNU General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License
00021  * along with this program; if not, write to the Free Software
00022  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00023  */
00024 
00025 
00026 #include <string.h>
00027 #include <time.h>
00028 #include <oci.h>
00029 #include "../../db/db_res.h"
00030 #include "../../db/db_row.h"
00031 #include "../../mem/mem.h"
00032 #include "../../dprint.h"
00033 #include "ora_con.h"
00034 #include "dbase.h"
00035 #include "asynch.h"
00036 #include "res.h"
00037 
00038 
00039 #define MAX_DEF_HANDLES 64
00040 
00041 struct dmap {
00042     OCIDefine* defh[MAX_DEF_HANDLES];
00043     union {
00044    dvoid* v;
00045    double* f;
00046    int* i;
00047    char* c;
00048    OCIDate* o;
00049     }pv[MAX_DEF_HANDLES];
00050     dvoid* pval[MAX_DEF_HANDLES];
00051     ub2 ilen[MAX_DEF_HANDLES];
00052     sb2 ind[MAX_DEF_HANDLES];
00053     ub2 len[MAX_DEF_HANDLES];
00054 };
00055 typedef struct dmap dmap_t;
00056 
00057 
00058 /*
00059  * Get and convert columns from a result. Define handlers and buffers
00060  */
00061 static int get_columns(ora_con_t* con, db_res_t* _r, OCIStmt* _c, dmap_t* _d)
00062 {
00063    OCIParam *param;
00064    size_t tsz;
00065    ub4 i, n;
00066    sword status;
00067 
00068    status = OCIAttrGet(_c, OCI_HTYPE_STMT, &n, NULL, OCI_ATTR_PARAM_COUNT,
00069       con->errhp);
00070 
00071    if (status != OCI_SUCCESS) {
00072       LM_ERR("driver: %s\n", db_oracle_error(con, status));
00073       return -1;
00074    }
00075 
00076    if (!n) {
00077       LM_ERR("no columns\n");
00078       return -2;
00079    }
00080 
00081    if (n >= MAX_DEF_HANDLES) {
00082       LM_ERR("too many res. Rebuild with MAX_DEF_HANDLES >= %u\n", n);
00083       return -3;
00084    }
00085 
00086    if (db_allocate_columns(_r, n) != 0) {
00087       LM_ERR("could not allocate columns");
00088       return -4;
00089    }
00090    memset(RES_NAMES(_r), 0, sizeof(db_key_t) * n);
00091 
00092    RES_COL_N(_r) = n;
00093 
00094    tsz = 0;
00095    memset(_d->defh, 0, sizeof(_d->defh[0]) * n);
00096    for (i = 0; i < n; i++) {
00097       ub4 len;
00098       ub2 dtype;
00099 
00100       status = OCIParamGet(_c, OCI_HTYPE_STMT, con->errhp,
00101          (dvoid**)(dvoid*)&param, i+1);
00102       if (status != OCI_SUCCESS) goto ora_err;
00103 
00104       {
00105          text* name;
00106          str* sname;
00107          status = OCIAttrGet(param, OCI_DTYPE_PARAM,
00108             (dvoid**)(dvoid*)&name, &len, OCI_ATTR_NAME,
00109             con->errhp);
00110          if (status != OCI_SUCCESS) goto ora_err;
00111          sname = (str*)pkg_malloc(sizeof(str)+len+1);
00112          if (!sname) {
00113             db_free_columns(_r);
00114             LM_ERR("no private memory left\n");
00115             return -5;
00116          }
00117          sname->len = len;
00118          sname->s = (char*)sname + sizeof(str);
00119          memcpy(sname->s, name, len);
00120          sname->s[len] = '\0';
00121          RES_NAMES(_r)[i] = sname;
00122       }
00123 
00124       status = OCIAttrGet(param, OCI_DTYPE_PARAM,
00125          (dvoid**)(dvoid*)&dtype, NULL, OCI_ATTR_DATA_TYPE,
00126          con->errhp);
00127       if (status != OCI_SUCCESS) goto ora_err;
00128 
00129       switch (dtype) {
00130       case SQLT_UIN:    /* unsigned integer */
00131 set_bitmap:
00132          LM_DBG("use DB_BITMAP type");
00133          RES_TYPES(_r)[i] = DB_BITMAP;
00134          len = sizeof(VAL_BITMAP((db_val_t*)NULL));
00135          break;
00136 
00137       case SQLT_INT:    /* (ORANET TYPE) integer */
00138 set_int:
00139          LM_DBG("use DB_INT result type");
00140          RES_TYPES(_r)[i] = DB_INT;
00141          len = sizeof(VAL_INT((db_val_t*)NULL));
00142          break;
00143 
00144 //    case SQLT_LNG:    /* long */
00145       case SQLT_VNU:    /* NUM with preceding length byte */
00146       case SQLT_NUM:    /* (ORANET TYPE) oracle numeric */
00147          len = 0; /* PRECISION is ub1 */
00148          status = OCIAttrGet(param, OCI_DTYPE_PARAM,
00149             (dvoid**)(dvoid*)&len, NULL, OCI_ATTR_PRECISION,
00150             con->errhp);
00151          if (status != OCI_SUCCESS) goto ora_err;
00152          if (len <= 11) {
00153             sb1 sc;
00154             status = OCIAttrGet(param, OCI_DTYPE_PARAM,
00155                (dvoid**)(dvoid*)&sc, NULL,
00156                OCI_ATTR_SCALE, con->errhp);
00157             if (status != OCI_SUCCESS) goto ora_err;
00158             if (!sc) {
00159                dtype = SQLT_INT;
00160                if (len != 11) goto set_int;
00161                dtype = SQLT_UIN;
00162                goto set_bitmap;
00163             }
00164          }
00165       case SQLT_FLT:    /* (ORANET TYPE) Floating point number */
00166       case SQLT_BFLOAT:       /* Native Binary float*/
00167       case SQLT_BDOUBLE:   /* NAtive binary double */
00168       case SQLT_IBFLOAT:   /* binary float canonical */
00169       case SQLT_IBDOUBLE:  /* binary double canonical */
00170       case SQLT_PDN:    /* (ORANET TYPE) Packed Decimal Numeric */
00171          LM_DBG("use DB_DOUBLE result type");
00172          RES_TYPES(_r)[i] = DB_DOUBLE;
00173          len = sizeof(VAL_DOUBLE((db_val_t*)NULL));
00174          dtype = SQLT_FLT;
00175          break;
00176 
00177 //    case SQLT_TIME:      /* TIME */
00178 //    case SQLT_TIME_TZ:   /* TIME WITH TIME ZONE */
00179       case SQLT_DATE:      /* ANSI Date */
00180       case SQLT_DAT:    /* date in oracle format */
00181       case SQLT_ODT:    /* OCIDate type */
00182       case SQLT_TIMESTAMP: /* TIMESTAMP */
00183       case SQLT_TIMESTAMP_TZ: /* TIMESTAMP WITH TIME ZONE */
00184       case SQLT_TIMESTAMP_LTZ:/* TIMESTAMP WITH LOCAL TZ */
00185 //    case SQLT_INTERVAL_YM:  /* INTERVAL YEAR TO MONTH */
00186 //    case SQLT_INTERVAL_DS:  /* INTERVAL DAY TO SECOND */
00187          LM_DBG("use DB_DATETIME result type");
00188          RES_TYPES(_r)[i] = DB_DATETIME;
00189          len = sizeof(OCIDate);
00190          dtype = SQLT_ODT;
00191          break;
00192 
00193       case SQLT_CLOB:      /* character lob */
00194       case SQLT_BLOB:      /* binary lob */
00195 //    case SQLT_BFILEE: /* binary file lob */
00196 //    case SQLT_CFILEE: /* character file lob */
00197 //    case SQLT_BIN:    /* binary data(DTYBIN) */
00198 //    case SQLT_LBI:    /* long binary */
00199          LM_DBG("use DB_BLOB result type");
00200          RES_TYPES(_r)[i] = DB_BLOB;
00201          goto dyn_str;
00202 
00203       case SQLT_CHR:    /* (ORANET TYPE) character string */
00204       case SQLT_STR:    /* zero terminated string */
00205       case SQLT_VST:    /* OCIString type */
00206       case SQLT_VCS:    /* Variable character string */
00207       case SQLT_AFC:    /* Ansi fixed char */
00208       case SQLT_AVC:    /* Ansi Var char */
00209 //    case SQLT_RID:    /* rowid */
00210          LM_DBG("use DB_STR result type");
00211          RES_TYPES(_r)[i] = DB_STR;
00212 dyn_str:
00213          dtype = SQLT_CHR;
00214          len = 0; /* DATA_SIZE is ub2 */
00215          status = OCIAttrGet(param, OCI_DTYPE_PARAM,
00216             (dvoid**)(dvoid*)&len, NULL, OCI_ATTR_DATA_SIZE,
00217             con->errhp);
00218          if (status != OCI_SUCCESS) goto ora_err;
00219          if (len >= 4000) {
00220             LM_DBG("use DB_BLOB result type");
00221             RES_TYPES(_r)[i] = DB_BLOB;
00222          }
00223          ++len;
00224          break;
00225 
00226       default:
00227          LM_ERR("unsupported datatype %d\n", dtype);
00228          goto stop_load;
00229       }
00230       _d->ilen[i] = (ub2)len;
00231       _d->pv[i].v = st_buf + tsz;
00232       tsz += len;
00233       status = OCIDefineByPos(_c, &_d->defh[i], con->errhp, i+1,
00234          _d->pv[i].v, len, dtype, &_d->ind[i],
00235          &_d->len[i], NULL, OCI_DEFAULT);
00236       if (status != OCI_SUCCESS) goto ora_err;
00237    }
00238 
00239 #if STATIC_BUF_LEN < 65536
00240 #error
00241 #endif
00242    if (tsz > 65536) {
00243       LM_ERR("Row size exceed 65K. IOB's are not supported");
00244       goto stop_load;
00245    }
00246    return 0;
00247 
00248 ora_err:
00249    LM_ERR("driver: %s\n", db_oracle_error(con, status));
00250 stop_load:
00251    db_free_columns(_r);
00252    return -6;
00253 }
00254 
00255 
00256 /*
00257  * Convert data fron db format to internal format
00258  */
00259 static int convert_row(db_res_t* _res, db_row_t* _r, dmap_t* _d)
00260 {
00261    unsigned i, n = RES_COL_N(_res);
00262 
00263    ROW_N(_r) = n;
00264    ROW_VALUES(_r) = (db_val_t*)pkg_malloc(sizeof(db_val_t) * n);
00265    if (!ROW_VALUES(_r)) {
00266 nomem:
00267       LM_ERR("no private memory left\n");
00268       return -1;
00269    }
00270    memset(ROW_VALUES(_r), 0, sizeof(db_val_t) * n);
00271 
00272    for (i = 0; i < n; i++) {
00273       static const str dummy_string = {"", 0};
00274 
00275       db_val_t* v = &ROW_VALUES(_r)[i];
00276       db_type_t t = RES_TYPES(_res)[i];
00277 
00278       if (_d->ind[i] == -1) {
00279          /* Initialize the string pointers to a dummy empty
00280           * string so that we do not crash when the NULL flag
00281           * is set but the module does not check it properly
00282           */
00283          VAL_STRING(v) = dummy_string.s;
00284          VAL_STR(v) = dummy_string;
00285          VAL_BLOB(v) = dummy_string;
00286          VAL_TYPE(v) = t;
00287          VAL_NULL(v) = 1;
00288          continue;
00289       }
00290 
00291       if (_d->ind[i])
00292          LM_WARN("truncated value in DB\n");
00293 
00294       VAL_TYPE(v) = t;
00295       switch (t) {
00296       case DB_INT:
00297          VAL_INT(v) = *_d->pv[i].i;
00298          break;
00299 
00300       case DB_BIGINT:
00301          LM_ERR("BIGINT not supported");
00302          return -1;
00303 
00304       case DB_BITMAP:
00305          VAL_BITMAP(v) = *_d->pv[i].i;
00306          break;
00307 
00308       case DB_DOUBLE:
00309          VAL_DOUBLE(v) = *_d->pv[i].f;
00310          break;
00311 
00312       case DB_DATETIME:
00313          {
00314             struct tm tm;
00315             memset(&tm, 0, sizeof(tm));
00316             OCIDateGetTime(_d->pv[i].o, &tm.tm_hour,
00317                &tm.tm_min, &tm.tm_sec);
00318             OCIDateGetDate(_d->pv[i].o, &tm.tm_year,
00319                &tm.tm_mon, &tm.tm_mday);
00320             if (tm.tm_mon)
00321                --tm.tm_mon;
00322             if (tm.tm_year >= 1900)
00323                tm.tm_year -= 1900;
00324             VAL_TIME(v) = mktime(&tm);
00325          }
00326          break;
00327 
00328       case DB_STR:
00329       case DB_BLOB:
00330       case DB_STRING:
00331          {
00332             size_t len = _d->len[i];
00333             char *pstr = pkg_malloc(len+1);
00334             if (!pstr) goto nomem;
00335             memcpy(pstr, _d->pv[i].c, len);
00336             pstr[len] = '\0';
00337             VAL_FREE(v) = 1;
00338             if (t == DB_STR) {
00339                VAL_STR(v).s = pstr;
00340                VAL_STR(v).len = len;
00341             } else if (t == DB_BLOB) {
00342                VAL_BLOB(v).s = pstr;
00343                VAL_BLOB(v).len = len;
00344             } else {
00345                VAL_STRING(v) = pstr;
00346             }
00347          }
00348          break;
00349 
00350       default:
00351          LM_ERR("unknown type mapping (%u)\n", t);
00352          return -2;
00353       }
00354    }
00355 
00356    return 0;
00357 }
00358 
00359 
00360 /*
00361  * Get rows and convert it from oracle to db API representation
00362  */
00363 static int get_rows(ora_con_t* con, db_res_t* _r, OCIStmt* _c, dmap_t* _d)
00364 {
00365    ub4 rcnt;
00366    sword status;
00367    unsigned n = RES_COL_N(_r);
00368 
00369    memcpy(_d->len, _d->ilen, sizeof(_d->len[0]) * n);
00370 
00371    // timelimited operation
00372    status = begin_timelimit(con, 0);
00373    if (status != OCI_SUCCESS) goto ora_err;
00374    do status = OCIStmtFetch2(_c, con->errhp, 1, OCI_FETCH_LAST, 0,
00375       OCI_DEFAULT);
00376    while (wait_timelimit(con, status));
00377    if (done_timelimit(con, status)) goto stop_load;
00378    if (status != OCI_SUCCESS) {
00379       if (status != OCI_NO_DATA)
00380          goto ora_err;
00381 
00382       RES_ROW_N(_r) = 0;
00383       RES_ROWS(_r) = NULL;
00384       return 0;
00385    }
00386 
00387    status = OCIAttrGet(_c, OCI_HTYPE_STMT, &rcnt, NULL,
00388       OCI_ATTR_CURRENT_POSITION, con->errhp);
00389    if (status != OCI_SUCCESS) goto ora_err;
00390    if (!rcnt) {
00391       LM_ERR("lastpos==0\n");
00392       goto stop_load;
00393    }
00394 
00395    RES_ROW_N(_r) = rcnt;
00396    RES_ROWS(_r) = (db_row_t*)pkg_malloc(sizeof(db_row_t) * rcnt);
00397    if (!RES_ROWS(_r)) {
00398       LM_ERR("no private memory left\n");
00399       return -1;
00400    }
00401    memset(RES_ROWS(_r), 0, sizeof(db_row_t) * rcnt);
00402 
00403    while ( 1 ) {
00404       if (convert_row(_r, &RES_ROWS(_r)[--rcnt], _d) < 0) {
00405          LM_ERR("erroc convert row\n");
00406          goto stop_load;
00407       }
00408 
00409       if (!rcnt)
00410          return 0;
00411 
00412       memcpy(_d->len, _d->ilen, sizeof(_d->len[0]) * n);
00413       // timelimited operation
00414       status = begin_timelimit(con, 0);
00415       if (status != OCI_SUCCESS) goto ora_err;
00416       do status = OCIStmtFetch2(_c, con->errhp, 1, OCI_FETCH_PRIOR, 0,
00417          OCI_DEFAULT);
00418       while (wait_timelimit(con, status));
00419       if (done_timelimit(con, status)) goto stop_load;
00420       if (status != OCI_SUCCESS) break;
00421    }
00422 ora_err:
00423    LM_ERR("driver: %s\n", db_oracle_error(con, status));
00424 stop_load:
00425    db_free_rows(_r);
00426    RES_ROW_N(_r) = 0;   /* TODO: skipped in db_res.c :) */
00427    return -3;
00428 }
00429 
00430 
00431 /*
00432  * Read database answer and fill the structure
00433  */
00434 int db_oracle_store_result(const db_con_t* _h, db_res_t** _r)
00435 {
00436    dmap_t dmap;
00437    int rc;
00438    db_res_t* r;
00439    ora_con_t* con;
00440    OCIStmt* hs;
00441 
00442    if (!_h || !_r) {
00443 badparam:
00444       LM_ERR("invalid parameter\n");
00445       return -1;
00446    }
00447 
00448    con = CON_ORA(_h);
00449    {
00450        query_data_t *pcb = con->pqdata;
00451        
00452 
00453        if (!pcb || !pcb->_rs)
00454           goto badparam;
00455           
00456        hs = *pcb->_rs;
00457        pcb->_rs = NULL; /* paranoid for next call */
00458    }      
00459    
00460    rc = -1;
00461    if (_r)  *_r = NULL; /* unification for all errors */
00462 
00463    r = db_new_result();
00464    if (!r) {
00465       LM_ERR("no memory left\n");
00466       goto done;
00467    }
00468 
00469    if (get_columns(con, r, hs, &dmap) < 0) {
00470       LM_ERR("error while getting column names\n");
00471       goto done;
00472    }
00473 
00474    if (get_rows(con, r, hs, &dmap) < 0) {
00475       LM_ERR("error while converting rows\n");
00476       db_free_columns(r);
00477       goto done;
00478    }
00479 
00480    rc = 0;
00481    *_r = r;
00482 done:
00483    OCIHandleFree(hs, OCI_HTYPE_STMT);
00484    return rc;
00485 }

Generated on Tue May 22 14:00:29 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6