00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
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
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*)¶m, 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:
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:
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
00145 case SQLT_VNU:
00146 case SQLT_NUM:
00147 len = 0;
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:
00166 case SQLT_BFLOAT:
00167 case SQLT_BDOUBLE:
00168 case SQLT_IBFLOAT:
00169 case SQLT_IBDOUBLE:
00170 case SQLT_PDN:
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
00178
00179 case SQLT_DATE:
00180 case SQLT_DAT:
00181 case SQLT_ODT:
00182 case SQLT_TIMESTAMP:
00183 case SQLT_TIMESTAMP_TZ:
00184 case SQLT_TIMESTAMP_LTZ:
00185
00186
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:
00194 case SQLT_BLOB:
00195
00196
00197
00198
00199 LM_DBG("use DB_BLOB result type");
00200 RES_TYPES(_r)[i] = DB_BLOB;
00201 goto dyn_str;
00202
00203 case SQLT_CHR:
00204 case SQLT_STR:
00205 case SQLT_VST:
00206 case SQLT_VCS:
00207 case SQLT_AFC:
00208 case SQLT_AVC:
00209
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;
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
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
00280
00281
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
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
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
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;
00427 return -3;
00428 }
00429
00430
00431
00432
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;
00458 }
00459
00460 rc = -1;
00461 if (_r) *_r = NULL;
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 }