db_oracle/dbase.c

Go to the documentation of this file.
00001 /*
00002  * $Id$
00003  *
00004  * Oracle module core 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 #include <stdio.h>
00026 #include <string.h>
00027 #include <stdlib.h>
00028 #include <time.h>
00029 #include <oci.h>
00030 #include "../../mem/mem.h"
00031 #include "../../dprint.h"
00032 #include "../../db/db_pool.h"
00033 #include "../../db/db_ut.h"
00034 #include "../../db/db_res.h"
00035 #include "../../db/db_query.h"
00036 #include "val.h"
00037 #include "ora_con.h"
00038 #include "res.h"
00039 #include "asynch.h"
00040 #include "dbase.h"
00041 
00042 
00043 #define  MAX_BIND_HANDLES 128
00044 
00045 char st_buf[STATIC_BUF_LEN];
00046 
00047 
00048 /*
00049  * Make error message. Always return negative value
00050  */
00051 int sql_buf_small(void)
00052 {
00053    LM_ERR("static buffer too small\n");
00054    return -11;
00055 }
00056 
00057 /*
00058  * Decode error
00059  */
00060 static char errbuf[512];
00061 
00062 static const char* db_oracle_errorinfo(ora_con_t* con)
00063 {
00064    sword errcd;
00065    if (OCIErrorGet(con->errhp, 1, NULL, &errcd,
00066          (OraText*)errbuf, sizeof(errbuf),
00067          OCI_HTYPE_ERROR) != OCI_SUCCESS) errbuf[0] = '\0';
00068    else switch (errcd) {
00069    case 28: /* your session has been killed */
00070    case 30: /* session ID does not exists */
00071    case 31: /* session marked for kill */
00072    case 41: /* active time limit exceeded session terminated */
00073    case 107:   /* failed to connect to oracle listener */
00074    case 115:   /* connection refused; dispatcher table is full */
00075    case 1033:  /* init/shutdown in progress */
00076    case 1034:  /* not available (startup) */
00077    case 1089:  /* server shutdown */
00078    case 1090:  /* shutdown wait after command */
00079    case 1092:  /* oracle instance terminated. Disconnection forced */
00080    case 1573:  /* shutdown instance, no futher change allowed */
00081    case 2049:  /* timeout: distributed transaction waiting lock */
00082    case 3113:  /* EOF on communication channel */
00083    case 3114:  /* not connected */
00084    case 3135:  /* lost connection */
00085    case 6033:  /* connect failed, partner rejected connection */
00086    case 6034:  /* connect failed, partner exited unexpectedly */
00087    case 6037:  /* connect failed, node unrecheable */
00088    case 6039:  /* connect failed */
00089    case 6042:  /* msgrcv failure (DNT) */
00090    case 6043:  /* msgsend failure (DNT) */
00091    case 6107:  /* network server not found */
00092    case 6108:  /* connect to host failed */
00093    case 6109:  /* msgrcv failure (TCP) */
00094    case 6110:  /* msgsend failure (TCP) */
00095    case 6114:  /* SID lookup failure */
00096    case 6124:  /* TCP timeout */
00097    case 6135:  /* connect rejected; server is stopping (TCP) */
00098    case 6144:  /* SID unavaliable (TCP) */
00099    case 6413:  /* connection not open */
00100    case 12150: /* tns can't send data, probably disconnect */
00101    case 12152: /* tns unable to send break message */
00102    case 12153: /* tns not connected */
00103    case 12161: /* tns internal error */
00104    case 12170: /* tns connect timeout */
00105    case 12224: /* tns no listener */
00106    case 12225: /* tns destination host unrecheable */
00107    case 12230: /* tns network error */
00108    case 12525: /* tns (internal) timeout */
00109    case 12521: /* tns can't resolve db name */
00110    case 12537: /* tns connection cloed */
00111    case 12541: /* tns not running */
00112    case 12543: /* tns destination host unrecheable */
00113    case 12547: /* tns lost contact */
00114    case 12560: /* tns protocol(transport) error */
00115    case 12561: /* tns unknown error */
00116    case 12608: /* tns send timeount */
00117    case 12609: /* tns receive timeount */
00118        LM_ERR("conneciom dropped\n");
00119        db_oracle_disconnect(con);
00120    default:
00121       break;
00122    }
00123 
00124    return errbuf;
00125 }
00126 
00127 const char* db_oracle_error(ora_con_t* con, sword status)
00128 {
00129    switch (status) {
00130       case OCI_SUCCESS:
00131          return "internal (success)";
00132 
00133       case OCI_SUCCESS_WITH_INFO:
00134       case OCI_ERROR:
00135          return db_oracle_errorinfo(con);
00136 
00137       case OCI_NEED_DATA:
00138          return "need data";
00139 
00140       case OCI_NO_DATA:
00141          return "no data";
00142 
00143       case OCI_INVALID_HANDLE:
00144          return "invalid handle";
00145 
00146       case OCI_STILL_EXECUTING:  // ORA-3123
00147          return "executing (logic)";
00148 
00149       case OCI_CONTINUE:
00150          return "continue (library)";
00151 
00152       default:
00153          snprintf(errbuf, sizeof(errbuf),
00154             "unknown status %u", status);
00155          return errbuf;
00156    }
00157 }
00158 
00159 
00160 /*
00161  * Initialize database module
00162  * No function should be called before this
00163  */
00164 db_con_t* db_oracle_init(const str* _url)
00165 {
00166    return db_do_init(_url, (void *)db_oracle_new_connection);
00167 }
00168 
00169 
00170 /*
00171  * Shut down database module
00172  * No function should be called after this
00173  */
00174 void db_oracle_close(db_con_t* _h)
00175 {
00176    db_do_close(_h, db_oracle_free_connection);
00177 }
00178 
00179 
00180 /*
00181  * Release a result set from memory
00182  */
00183 int db_oracle_free_result(db_con_t* _h, db_res_t* _r)
00184 {
00185    if (!_h || !_r) {
00186       LM_ERR("invalid parameter value\n");
00187       return -1;
00188    }
00189 
00190    if (db_free_result(_r) < 0)
00191    {
00192       LM_ERR("failed to free result structure\n");
00193       return -1;
00194    }
00195    return 0;
00196 }
00197 
00198 
00199 /*
00200  * Send an SQL query to the server
00201  */
00202 static int db_oracle_submit_query(const db_con_t* _h, const str* _s)
00203 {
00204    OCIBind* bind[MAX_BIND_HANDLES];
00205    OCIDate odt[sizeof(bind)/sizeof(bind[0])];
00206    str tmps;
00207    sword status;
00208    int pass;
00209    ora_con_t* con = CON_ORA(_h);
00210    query_data_t* pqd = con->pqdata;
00211    size_t hc = pqd->_n + pqd->_nw;
00212    OCIStmt *stmthp;
00213 
00214    if (hc >= sizeof(bind)/sizeof(bind[0])) {
00215       LM_ERR("too many bound. Rebuild with MAX_BIND_HANDLES >= %u\n",
00216          (unsigned)hc);
00217       return -1;
00218    }
00219    
00220    if (!pqd->_rs) {
00221       /*
00222        * This method is at ~25% faster as set OCI_COMMIT_ON_SUCCESS
00223        * in StmtExecute
00224        */
00225       tmps.len = snprintf(st_buf, sizeof(st_buf),
00226          "begin %.*s; commit write batch nowait; end;",
00227          _s->len, _s->s);
00228       if ((unsigned)tmps.len >= sizeof(st_buf))
00229          return sql_buf_small();
00230       tmps.s = st_buf;
00231       _s = &tmps;
00232    }
00233 
00234    pass = 1;
00235    if (!con->connected) {
00236       status = db_oracle_reconnect(con);
00237       if (status != OCI_SUCCESS) {
00238          LM_ERR("can't restore connection: %s\n", db_oracle_error(con, status));
00239          return -2;
00240       }
00241       LM_INFO("connection restored\n");
00242       --pass;
00243    }
00244 repeat:
00245    stmthp = NULL;
00246    status = OCIHandleAlloc(con->envhp, (dvoid**)(dvoid*)&stmthp,
00247           OCI_HTYPE_STMT, 0, NULL);
00248    if (status != OCI_SUCCESS)
00249       goto ora_err;
00250    status = OCIStmtPrepare(stmthp, con->errhp, (text*)_s->s, _s->len,
00251       OCI_NTV_SYNTAX, OCI_DEFAULT);
00252    if (status != OCI_SUCCESS)
00253       goto ora_err;
00254 
00255    if (hc) {
00256       bmap_t bmap;
00257       size_t pos = 1;
00258       int i;
00259 
00260       memset(bind, 0, hc*sizeof(bind[0]));
00261       for (i = 0; i < pqd->_n; i++) {
00262          if (db_oracle_val2bind(&bmap, &pqd->_v[i], &odt[pos]) < 0)
00263             goto bind_err;
00264          status = OCIBindByPos(stmthp, &bind[pos], con->errhp,
00265             pos, bmap.addr, bmap.size, bmap.type,
00266             NULL, NULL, NULL, 0, NULL, OCI_DEFAULT);
00267          if (status != OCI_SUCCESS)
00268             goto ora_err;
00269          ++pos;
00270       }
00271       for (i = 0; i < pqd->_nw; i++) {
00272          if (db_oracle_val2bind(&bmap, &pqd->_w[i], &odt[pos]) < 0) {
00273 bind_err:
00274             OCIHandleFree(stmthp, OCI_HTYPE_STMT);
00275             LM_ERR("can't map values\n");
00276             return -3;
00277          }
00278          status = OCIBindByPos(stmthp, &bind[pos], con->errhp,
00279             pos, bmap.addr, bmap.size, bmap.type,
00280             NULL, NULL, NULL, 0, NULL, OCI_DEFAULT);
00281          if (status != OCI_SUCCESS)
00282             goto ora_err;
00283          ++pos;
00284       }
00285    }
00286 
00287    // timelimited operation
00288    status = begin_timelimit(con, 0);
00289    if (status != OCI_SUCCESS) goto ora_err;
00290    do status = OCIStmtExecute(con->svchp, stmthp, con->errhp,
00291       !pqd->_rs, 0, NULL, NULL,
00292       pqd->_rs ? OCI_STMT_SCROLLABLE_READONLY : OCI_DEFAULT);
00293    while (wait_timelimit(con, status));
00294    if (done_timelimit(con, status)) goto stop_exec;
00295    switch (status)   {
00296    case OCI_SUCCESS_WITH_INFO:
00297       LM_WARN("driver: %s\n", db_oracle_errorinfo(con));
00298       //PASS THRU
00299    case OCI_SUCCESS:
00300       if (pqd->_rs)
00301          *pqd->_rs = stmthp;
00302       else
00303          OCIHandleFree(stmthp, OCI_HTYPE_STMT);
00304       return 0;
00305    default:
00306        pass = -pass;
00307        break;
00308    }
00309 
00310 ora_err:
00311    LM_ERR("driver: %s\n", db_oracle_error(con, status));
00312 stop_exec:
00313    if (stmthp)
00314       OCIHandleFree(stmthp, OCI_HTYPE_STMT);
00315    if (pass == -1 && !con->connected) {
00316       /* Attemtp to reconnect */
00317       if (db_oracle_reconnect(con) == OCI_SUCCESS) {
00318          LM_NOTICE("attempt repeat after reconnect\n");
00319          pass = 0;
00320          goto repeat;
00321       }
00322       LM_ERR("connection loss\n");
00323    }
00324    return -4;
00325 }
00326 
00327 
00328 /*
00329  * Query table for specified rows
00330  * _h: structure representing database connection
00331  * _k: key names
00332  * _op: operators
00333  * _v: values of the keys that must match
00334  * _c: column names to return
00335  * _n: number of key=values pairs to compare
00336  * _nc: number of columns to return
00337  * _o: order by the specified column
00338  */
00339 int db_oracle_query(const db_con_t* _h, const db_key_t* _k, const db_op_t* _op,
00340       const db_val_t* _v, const db_key_t* _c, int _n, int _nc,
00341       const db_key_t _o, db_res_t** _r)
00342 {
00343    query_data_t cb;
00344    OCIStmt* reshp;
00345    int rc;
00346 
00347    if (!_h || !CON_TABLE(_h) || !_r) {
00348       LM_ERR("invalid parameter value\n");
00349       return -1;
00350    }
00351 
00352    cb._rs = &reshp;
00353    cb._v  = _v;
00354    cb._n  = _n;
00355    cb._w  = NULL;
00356    cb._nw = 0;
00357    CON_ORA(_h)->pqdata = &cb;
00358    CON_ORA(_h)->bindpos = 0;
00359    rc = db_do_query(_h, _k, _op, _v, _c, _n, _nc, _o, _r,
00360       db_oracle_val2str, db_oracle_submit_query, db_oracle_store_result);
00361    CON_ORA(_h)->pqdata = NULL;   /* paranoid for next call */
00362    return rc;
00363 }
00364 
00365 
00366 /*
00367  * Execute a raw SQL query
00368  */
00369 int db_oracle_raw_query(const db_con_t* _h, const str* _s, db_res_t** _r)
00370 {
00371    query_data_t cb;
00372    OCIStmt* reshp;
00373    int len;
00374    const char *p;
00375 
00376    if (!_h || !_s || !_s->s) {
00377 badparam:
00378       LM_ERR("invalid parameter value\n");
00379       return -1;
00380    }
00381 
00382 
00383    memset(&cb, 0, sizeof(cb));
00384 
00385    p = _s->s;
00386    len = _s->len;
00387    while (len && *p == ' ') ++p, --len;
00388 #define _S_DIFF(p, l, S) (l <= sizeof(S)-1 || strncasecmp(p, S, sizeof(S)-1))
00389    if (!_S_DIFF(p, len, "select ")) {
00390       if (!_r) goto badparam;
00391       cb._rs = &reshp;
00392    } else {
00393       if (  _S_DIFF(p, len, "insert ")
00394           &&   _S_DIFF(p, len, "delete ")
00395           &&   _S_DIFF(p, len, "update "))
00396       {
00397          LM_ERR("unknown raw_query: '%.*s'\n", _s->len, _s->s);
00398          return -2;
00399       }
00400 #undef _S_DIFF
00401       if (_r) goto badparam;
00402       cb._rs = NULL;
00403    }
00404 
00405    len = db_do_raw_query(_h, _s, _r, db_oracle_submit_query, db_oracle_store_result);
00406    CON_ORA(_h)->pqdata = NULL;   /* paranoid for next call */
00407    return len;
00408 }
00409 
00410 
00411 /*
00412  * Insert a row into specified table
00413  * _h: structure representing database connection
00414  * _k: key names
00415  * _v: values of the keys
00416  * _n: number of key=value pairs
00417  */
00418 int db_oracle_insert(const db_con_t* _h, const db_key_t* _k, const db_val_t* _v,
00419       int _n)
00420 {
00421    query_data_t cb;
00422    int rc;
00423 
00424    if (!_h || !CON_TABLE(_h)) {
00425       LM_ERR("invalid parameter value\n");
00426       return -1;
00427    }
00428 
00429    cb._rs = NULL;
00430    cb._v  = _v;
00431    cb._n  = _n;
00432    cb._w  = NULL;
00433    cb._nw = 0;
00434    CON_ORA(_h)->pqdata = &cb;
00435    CON_ORA(_h)->bindpos = 0;
00436    rc = db_do_insert(_h, _k, _v, _n, db_oracle_val2str, db_oracle_submit_query);
00437    CON_ORA(_h)->pqdata = NULL;   /* paranoid for next call */
00438    return rc;
00439 }
00440 
00441 
00442 /*
00443  * Delete a row from the specified table
00444  * _h: structure representing database connection
00445  * _k: key names
00446  * _o: operators
00447  * _v: values of the keys that must match
00448  * _n: number of key=value pairs
00449  */
00450 int db_oracle_delete(const db_con_t* _h, const db_key_t* _k, const db_op_t* _o,
00451       const db_val_t* _v, int _n)
00452 {
00453    query_data_t cb;
00454    int rc;
00455 
00456    if (!_h || !CON_TABLE(_h)) {
00457       LM_ERR("invalid parameter value\n");
00458       return -1;
00459    }
00460 
00461    cb._rs = NULL;
00462    cb._v  = _v;
00463    cb._n  = _n;
00464    cb._w  = NULL;
00465    cb._nw = 0;
00466    CON_ORA(_h)->pqdata = &cb;
00467    CON_ORA(_h)->bindpos = 0;
00468    rc = db_do_delete(_h, _k, _o, _v, _n, db_oracle_val2str, db_oracle_submit_query);
00469    CON_ORA(_h)->pqdata = NULL;   /* paranoid for next call */
00470    return rc;
00471 }
00472 
00473 
00474 /*
00475  * Update some rows in the specified table
00476  * _h: structure representing database connection
00477  * _k: key names
00478  * _o: operators
00479  * _v: values of the keys that must match
00480  * _uk: updated columns
00481  * _uv: updated values of the columns
00482  * _n: number of key=value pairs
00483  * _un: number of columns to update
00484  */
00485 int db_oracle_update(const db_con_t* _h, const db_key_t* _k, const db_op_t* _o,
00486       const db_val_t* _v, const db_key_t* _uk, const db_val_t* _uv,
00487       int _n, int _un)
00488 {
00489    query_data_t cb;
00490    int rc;
00491    
00492    if (!_h || !CON_TABLE(_h)) {
00493       LM_ERR("invalid parameter value\n");
00494       return -1;
00495    }
00496 
00497    cb._rs = NULL;
00498    cb._v  = _uv;
00499    cb._n  = _un;
00500    cb._w  = _v;
00501    cb._nw = _n;
00502    CON_ORA(_h)->pqdata = &cb;
00503    CON_ORA(_h)->bindpos = 0;
00504    rc = db_do_update(_h, _k, _o, _v, _uk, _uv, _n, _un,
00505          db_oracle_val2str, db_oracle_submit_query);
00506    CON_ORA(_h)->pqdata = NULL;   /* paranoid for next call */
00507    return rc;
00508 }
00509 
00510 
00511 /*
00512  * Store name of table that will be used by
00513  * subsequent database functions
00514  */
00515 int db_oracle_use_table(db_con_t* _h, const str* _t)
00516 {
00517    return db_use_table(_h, _t);
00518 }

Generated on Mon May 21 20:00:25 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6