OCILIB (C Driver for Oracle) 3.9.2
|
00001 /* 00002 +-----------------------------------------------------------------------------------------+ 00003 | | 00004 | OCILIB - C Driver for Oracle | 00005 | | 00006 | (C Wrapper for Oracle OCI) | 00007 | | 00008 | Website : http://www.ocilib.net | 00009 | | 00010 | Copyright (c) 2007-2011 Vincent ROGIER <vince.rogier@ocilib.net> | 00011 | | 00012 +-----------------------------------------------------------------------------------------+ 00013 | | 00014 | This library is free software; you can redistribute it and/or | 00015 | modify it under the terms of the GNU Lesser General Public | 00016 | License as published by the Free Software Foundation; either | 00017 | version 2 of the License, or (at your option) any later version. | 00018 | | 00019 | This library is distributed in the hope that it will be useful, | 00020 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 00021 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 00022 | Lesser General Public License for more details. | 00023 | | 00024 | You should have received a copy of the GNU Lesser General Public | 00025 | License along with this library; if not, write to the Free | 00026 | Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 00027 | | 00028 +-----------------------------------------------------------------------------------------+ 00029 */ 00030 00031 /* --------------------------------------------------------------------------------------------- * 00032 * $Id: callback.c, v 3.9.2 2011-07-13 00:00 Vincent Rogier $ 00033 * --------------------------------------------------------------------------------------------- */ 00034 00035 #include "ocilib_internal.h" 00036 00037 /* ********************************************************************************************* * 00038 * PRIVATE FUNCTIONS 00039 * ********************************************************************************************* */ 00040 00041 /* --------------------------------------------------------------------------------------------- * 00042 * OCI_ProcInBind 00043 * --------------------------------------------------------------------------------------------- */ 00044 00045 sb4 OCI_ProcInBind 00046 ( 00047 dvoid *ictxp, 00048 OCIBind *bindp, 00049 ub4 iter, 00050 ub4 index, 00051 dvoid **bufpp, 00052 ub4 *alenp, 00053 ub1 *piecep, 00054 dvoid **indp 00055 ) 00056 { 00057 OCI_Bind * bnd = (OCI_Bind *) ictxp; 00058 sb2 *ind = (sb2 *) bnd->buf.inds; 00059 ub4 i = 0; 00060 00061 /* those checks may be not necessary but they keep away compilers warning 00062 away if the warning level is set to maximum ! 00063 */ 00064 00065 OCI_NOT_USED(index); 00066 OCI_NOT_USED(bindp); 00067 00068 /* check objects and bounds */ 00069 00070 OCI_CHECK(bnd == NULL, OCI_ERROR); 00071 OCI_CHECK(iter >= bnd->buf.count, OCI_ERROR); 00072 00073 /* indicators must be set to -1 depending on datatype, 00074 so let's do it for all */ 00075 00076 for (i = 0; i < bnd->buf.count; i++, ind++) 00077 { 00078 *ind = -1; 00079 } 00080 00081 /* setup bind index because OCI_RegisterXXX() might not have been called 00082 in the same order than the variables in the returning clause */ 00083 00084 if (iter == 0) 00085 { 00086 bnd->dynpos = bnd->stmt->dynidx++; 00087 } 00088 00089 /* we do not need to do anything here except setting indicators */ 00090 00091 *bufpp = (dvoid *) 0; 00092 *alenp = (ub4 ) 0; 00093 *indp = (dvoid *) bnd->buf.inds; 00094 *piecep = (ub1 ) OCI_ONE_PIECE; 00095 00096 return OCI_CONTINUE; 00097 } 00098 00099 /* --------------------------------------------------------------------------------------------- * 00100 * OCI_ProcOutBind 00101 * --------------------------------------------------------------------------------------------- */ 00102 00103 sb4 OCI_ProcOutBind 00104 ( 00105 dvoid *octxp, 00106 OCIBind *bindp, 00107 ub4 iter, 00108 ub4 index, 00109 dvoid **bufpp, 00110 ub4 **alenp, 00111 ub1 *piecep, 00112 dvoid **indp, 00113 ub2 **rcodep 00114 ) 00115 { 00116 OCI_Bind * bnd = (OCI_Bind *) octxp; 00117 OCI_Define *def = NULL; 00118 OCI_Resultset *rs = NULL; 00119 boolean res = TRUE; 00120 ub4 rows = 0; 00121 00122 /* those checks may be not necessary but they keep away compilers warning 00123 away if the warning level is set to maximum ! 00124 */ 00125 00126 OCI_NOT_USED(bindp); 00127 00128 /* check objects and bounds */ 00129 00130 OCI_CHECK(bnd == NULL, OCI_ERROR); 00131 OCI_CHECK(iter >= bnd->buf.count, OCI_ERROR); 00132 00133 /* update statmement status */ 00134 00135 bnd->stmt->status |= OCI_STMT_EXECUTED; 00136 00137 /* create resultset on the first row processed for each iteration */ 00138 00139 if (index == 0) 00140 { 00141 bnd->stmt->nb_rs = bnd->stmt->nb_iters; 00142 bnd->stmt->cur_rs = 0; 00143 00144 /* allocate resultset handles array */ 00145 00146 if (bnd->stmt->rsts == NULL) 00147 { 00148 bnd->stmt->rsts = (OCI_Resultset **) OCI_MemAlloc(OCI_IPC_RESULTSET_ARRAY, 00149 sizeof(*bnd->stmt->rsts), 00150 (size_t) bnd->stmt->nb_rs, TRUE); 00151 00152 if (bnd->stmt->rsts == NULL) 00153 { 00154 res = FALSE; 00155 } 00156 } 00157 00158 /* create resultset as needed */ 00159 00160 if (bnd->stmt->rsts[iter] == NULL) 00161 { 00162 OCI_CALL1 00163 ( 00164 res, bnd->stmt->con, bnd->stmt, 00165 00166 OCIAttrGet(bnd->buf.handle, (ub4) OCI_HTYPE_BIND, (void *) &rows, (ub4 *) NULL, 00167 (ub4) OCI_ATTR_ROWS_RETURNED, bnd->stmt->con->err) 00168 ) 00169 00170 if (res == TRUE) 00171 { 00172 bnd->stmt->rsts[iter] = OCI_ResultsetCreate(bnd->stmt, rows); 00173 00174 if (bnd->stmt->rsts[iter] != NULL) 00175 { 00176 bnd->stmt->rsts[iter]->row_count = rows; 00177 } 00178 } 00179 } 00180 } 00181 00182 OCI_CHECK(bnd->stmt->rsts == NULL, OCI_ERROR); 00183 00184 rs = bnd->stmt->rsts[iter]; 00185 00186 OCI_CHECK(rs == NULL, OCI_ERROR); 00187 00188 /* ok.. let's Oracle update its buffers */ 00189 00190 if (res == TRUE) 00191 { 00192 /* update pointers contents */ 00193 00194 def = &rs->defs[bnd->dynpos]; 00195 00196 switch (def->col.type) 00197 { 00198 case OCI_CDT_CURSOR: 00199 case OCI_CDT_TIMESTAMP: 00200 case OCI_CDT_INTERVAL: 00201 case OCI_CDT_LOB: 00202 case OCI_CDT_FILE: 00203 { 00204 *bufpp = def->buf.data[index]; 00205 break; 00206 } 00207 default: 00208 { 00209 *bufpp = (((ub1*)def->buf.data) + (size_t) (def->col.bufsize * index)); 00210 break; 00211 } 00212 } 00213 00214 *alenp = (ub4 *) (((ub1 *) def->buf.lens) + (size_t) ((ub4) def->buf.sizelen * index)); 00215 *indp = (dvoid *) (((ub1 *) def->buf.inds) + (size_t) ((ub4) sizeof(sb2) * index)); 00216 *piecep = (ub1 ) OCI_ONE_PIECE; 00217 *rcodep = (ub2 *) NULL; 00218 } 00219 00220 return ((res == TRUE) ? OCI_CONTINUE : OCI_ERROR); 00221 } 00222 00223 /* --------------------------------------------------------------------------------------------- * 00224 * OCI_ProcNotify 00225 * --------------------------------------------------------------------------------------------- */ 00226 00227 ub4 OCI_ProcNotify 00228 ( 00229 void *ctx, 00230 OCISubscription *subscrhp, 00231 void *payload, 00232 ub4 paylen, 00233 void *desc, 00234 ub4 mode 00235 ) 00236 { 00237 OCI_Subscription *sub = (OCI_Subscription *) ctx; 00238 boolean res = TRUE; 00239 void *ostr = NULL; 00240 int osize = 0; 00241 ub4 type = 0; 00242 00243 OCI_NOT_USED(paylen); 00244 OCI_NOT_USED(payload); 00245 OCI_NOT_USED(mode); 00246 OCI_NOT_USED(subscrhp); 00247 00248 OCI_CHECK(sub == NULL, OCI_SUCCESS); 00249 00250 OCI_EventReset(&sub->event); 00251 00252 #if OCI_VERSION_COMPILE >= OCI_10_2 00253 00254 /* get database that generated the notification */ 00255 00256 OCI_CALL3 00257 ( 00258 res, sub->err, 00259 00260 OCIAttrGet((dvoid *) desc, (ub4) OCI_DTYPE_CHDES, (dvoid *) &ostr, (ub4 *) &osize, 00261 (ub4) OCI_ATTR_CHDES_DBNAME, sub->err) 00262 ) 00263 00264 if ((res == TRUE) && (osize > (int) sub->event.dbname_size)) 00265 { 00266 /* buffer is ANSI */ 00267 00268 sub->event.dbname = (dtext *) OCI_MemRealloc(sub->event.dbname, OCI_IPC_STRING, 00269 sizeof(dtext), (size_t) (osize + 1)); 00270 00271 sub->event.dbname_size = osize; 00272 } 00273 00274 OCI_CopyString(ostr, sub->event.dbname, &osize, sizeof(char), sizeof(dtext)); 00275 00276 /* get notification type */ 00277 00278 OCI_CALL3 00279 ( 00280 res, sub->err, 00281 00282 OCIAttrGet((dvoid *) desc, (ub4) OCI_DTYPE_CHDES, 00283 (dvoid *) &type, (ub4 *) NULL, 00284 (ub4) OCI_ATTR_CHDES_NFYTYPE, sub->err) 00285 ) 00286 00287 switch(type) 00288 { 00289 case OCI_EVENT_STARTUP: 00290 case OCI_EVENT_SHUTDOWN: 00291 case OCI_EVENT_SHUTDOWN_ANY: 00292 { 00293 if (sub->type & OCI_CNT_DATABASES) 00294 { 00295 sub->event.type = type; 00296 } 00297 00298 break; 00299 } 00300 case OCI_EVENT_DEREG: 00301 { 00302 sub->event.type = type; 00303 break; 00304 } 00305 case OCI_EVENT_OBJCHANGE: 00306 { 00307 if (sub->type & OCI_CNT_OBJECTS) 00308 { 00309 sub->event.type = type; 00310 } 00311 00312 break; 00313 } 00314 default: 00315 { 00316 break; 00317 } 00318 } 00319 00320 /* for object, much work to do for retrieving data */ 00321 00322 if (sub->event.type == OCI_EVENT_OBJCHANGE) 00323 { 00324 OCIColl *tables = 0; 00325 sb4 nb_tables = 0; 00326 sb4 i; 00327 00328 /* get collection of modified tables */ 00329 00330 OCI_CALL3 00331 ( 00332 res, sub->err, 00333 00334 OCIAttrGet((dvoid *) desc, (ub4) OCI_DTYPE_CHDES, (dvoid *) &tables, 00335 (ub4 *) NULL, (ub4) OCI_ATTR_CHDES_TABLE_CHANGES, sub->err) 00336 ) 00337 00338 if (tables != NULL) 00339 { 00340 dvoid **elem_tbl = NULL; 00341 dvoid *ind_tbl = NULL; 00342 boolean exist = FALSE; 00343 sb4 nb_rows = 0; 00344 00345 /* get number of tables in the collection */ 00346 00347 OCI_CALL3 00348 ( 00349 res, sub->err, 00350 00351 OCICollSize(sub->env, sub->err, tables, &nb_tables) 00352 ) 00353 00354 for(i = 0; i < nb_tables; i++) 00355 { 00356 nb_rows = 0; 00357 00358 /* partial reset of the event object */ 00359 00360 if (sub->event.objname != NULL) 00361 { 00362 sub->event.objname[0] = 0; 00363 } 00364 00365 if (sub->event.rowid != NULL) 00366 { 00367 sub->event.rowid[0] = 0; 00368 } 00369 00370 /* get table element */ 00371 00372 OCI_CALL3 00373 ( 00374 res, sub->err, 00375 00376 OCICollGetElem(sub->env, sub->err, tables, i, &exist, 00377 (dvoid**) (dvoid*) &elem_tbl, (dvoid**) &ind_tbl) 00378 ) 00379 00380 /* get table name */ 00381 00382 OCI_CALL3 00383 ( 00384 res, sub->err, 00385 00386 OCIAttrGet((dvoid *) *elem_tbl, 00387 (ub4) OCI_DTYPE_TABLE_CHDES, 00388 (dvoid *) &ostr, (ub4 *) &osize, 00389 (ub4) OCI_ATTR_CHDES_TABLE_NAME, 00390 sub->err) 00391 ) 00392 00393 if(osize > (int) sub->event.objname_size) 00394 { 00395 /* buffer is ANSI */ 00396 00397 sub->event.objname = (dtext *) OCI_MemRealloc(sub->event.objname, 00398 OCI_IPC_STRING, sizeof(dtext), 00399 (size_t) (osize + 1)); 00400 00401 sub->event.objname_size = osize; 00402 } 00403 00404 OCI_CopyString(ostr, sub->event.objname, &osize, sizeof(char), sizeof(dtext)); 00405 00406 /* get table modification type */ 00407 00408 OCI_CALL3 00409 ( 00410 res, sub->err, 00411 00412 OCIAttrGet((dvoid *) *elem_tbl, (ub4) OCI_DTYPE_TABLE_CHDES, 00413 (dvoid *) &sub->event.op, (ub4*) NULL, 00414 (ub4) OCI_ATTR_CHDES_TABLE_OPFLAGS, sub->err) 00415 ) 00416 00417 sub->event.op = sub->event.op & (~OCI_OPCODE_ALLROWS); 00418 sub->event.op = sub->event.op & (~OCI_OPCODE_ALLOPS); 00419 00420 /* if requested, get row details */ 00421 00422 if (sub->type & OCI_CNT_ROWS) 00423 { 00424 OCIColl *rows = 0; 00425 00426 /* get collection of modified rows */ 00427 00428 OCI_CALL3 00429 ( 00430 res, sub->err, 00431 00432 OCIAttrGet((dvoid *) *elem_tbl, (ub4) OCI_DTYPE_TABLE_CHDES, 00433 (dvoid *) &rows, (ub4 *) NULL, 00434 (ub4 ) OCI_ATTR_CHDES_TABLE_ROW_CHANGES, sub->err) 00435 ) 00436 00437 if (rows != NULL) 00438 { 00439 dvoid **elem_row = NULL; 00440 dvoid *ind_row = NULL; 00441 boolean exist = FALSE; 00442 sb4 j; 00443 00444 /* get number of rows */ 00445 00446 OCI_CALL3 00447 ( 00448 res, sub->err, 00449 00450 OCICollSize(sub->env, sub->err, rows, &nb_rows) 00451 ) 00452 00453 for (j = 0; j < nb_rows; j++) 00454 { 00455 /* partial reset of the event */ 00456 00457 if (sub->event.rowid != NULL) 00458 { 00459 sub->event.rowid[0] = 0; 00460 } 00461 00462 /* get row element */ 00463 00464 OCI_CALL3 00465 ( 00466 res, sub->err, 00467 00468 OCICollGetElem(sub->env, sub->err, rows, j, &exist, 00469 (dvoid**) (dvoid*) &elem_row, (dvoid**) &ind_row) 00470 ) 00471 00472 /* get rowid */ 00473 00474 OCI_CALL3 00475 ( 00476 res, sub->err, 00477 00478 OCIAttrGet((dvoid *) *elem_row, (ub4) OCI_DTYPE_ROW_CHDES, 00479 (dvoid *) &ostr, (ub4 *) &osize, 00480 (ub4) OCI_ATTR_CHDES_ROW_ROWID, sub->err) 00481 ) 00482 00483 /* get opcode */ 00484 00485 OCI_CALL3 00486 ( 00487 res, sub->err, 00488 00489 OCIAttrGet((dvoid *) *elem_row, (ub4) OCI_DTYPE_ROW_CHDES, 00490 &sub->event.op, (ub4*) NULL, 00491 (ub4) OCI_ATTR_CHDES_ROW_OPFLAGS, sub->err) 00492 ) 00493 00494 if(osize > (int) sub->event.rowid_size) 00495 { 00496 /* buffer is ANSI */ 00497 00498 sub->event.rowid = (dtext *) OCI_MemRealloc(sub->event.rowid, 00499 OCI_IPC_STRING, 00500 sizeof(dtext), 00501 (size_t) (osize + 1)); 00502 00503 sub->event.rowid_size = osize; 00504 } 00505 00506 OCI_CopyString(ostr, sub->event.rowid, &osize, 00507 sizeof(char), sizeof(dtext)); 00508 00509 sub->handler(&sub->event); 00510 } 00511 } 00512 } 00513 00514 if (nb_rows == 0) 00515 { 00516 sub->handler(&sub->event); 00517 } 00518 } 00519 } 00520 } 00521 else if (sub->event.type > 0) 00522 { 00523 sub->handler(&sub->event); 00524 } 00525 00526 #else 00527 00528 OCI_NOT_USED(ctx); 00529 OCI_NOT_USED(desc); 00530 OCI_NOT_USED(subscrhp); 00531 00532 OCI_NOT_USED(res); 00533 OCI_NOT_USED(type); 00534 OCI_NOT_USED(ostr); 00535 OCI_NOT_USED(osize); 00536 00537 #endif 00538 00539 return OCI_SUCCESS; 00540 } 00541 00542 /* --------------------------------------------------------------------------------------------- * 00543 * OCI_ProcFailOver 00544 * --------------------------------------------------------------------------------------------- */ 00545 00546 sb4 OCI_ProcFailOver 00547 ( 00548 dvoid *svchp, 00549 dvoid *envhp, 00550 dvoid *fo_ctx, 00551 ub4 fo_type, 00552 ub4 fo_event 00553 ) 00554 { 00555 OCI_Connection *cn = (OCI_Connection *) fo_ctx; 00556 sb4 ret = OCI_FOC_OK; 00557 00558 OCI_NOT_USED(envhp); 00559 OCI_NOT_USED(svchp); 00560 00561 if ((cn != NULL) && (cn->taf_handler != NULL)) 00562 { 00563 ret = (sb4) cn->taf_handler(cn, fo_type, fo_event); 00564 } 00565 00566 return ret; 00567 } 00568 00569 /* --------------------------------------------------------------------------------------------- * 00570 * OCI_ProcHAEvent 00571 * --------------------------------------------------------------------------------------------- */ 00572 00573 void OCI_ProcHAEvent 00574 ( 00575 dvoid *evtctx, 00576 dvoid *eventptr 00577 ) 00578 { 00579 sword ret = OCI_SUCCESS; 00580 OCIServer *srvhp = NULL; 00581 OCI_List *list = OCILib.cons; 00582 OCI_Item *item = NULL; 00583 boolean res = TRUE; 00584 00585 OCI_NOT_USED(evtctx); 00586 00587 #if OCI_VERSION_COMPILE >= OCI_10_2 00588 00589 if ((list == NULL) || (OCILib.ha_handler == NULL)) 00590 { 00591 return; } 00592 00593 00594 if (OCILib.version_runtime >= OCI_10_2) 00595 { 00596 OCIEvent *eventhp = (OCIEvent *) eventptr; 00597 00598 ret = OCIAttrGet((dvoid **) eventhp, (ub4) OCI_HTYPE_SERVER, (dvoid *) &srvhp, 00599 (ub4 *) NULL, (ub4) OCI_ATTR_HA_SRVFIRST, OCILib.err); 00600 00601 while ((ret == OCI_SUCCESS) && (srvhp != NULL)) 00602 { 00603 if (list->mutex != NULL) 00604 { 00605 OCI_MutexAcquire(list->mutex); 00606 } 00607 00608 item = list->head; 00609 00610 /* for each item in the list, check the connection */ 00611 00612 while (item != NULL) 00613 { 00614 OCI_Connection *tmp = (OCI_Connection *) item->data; 00615 OCI_Connection *con = NULL; 00616 OCI_Timestamp *tmsp = NULL; 00617 OCIDateTime *dth = NULL; 00618 00619 ub4 event = OCI_HA_STATUS_DOWN; 00620 ub4 source = OCI_HA_SOURCE_INSTANCE; 00621 00622 if ((tmp != NULL) && (tmp->svr == srvhp)) 00623 { 00624 con = tmp; 00625 00626 /* get event timestamp */ 00627 00628 OCI_CALL2 00629 ( 00630 res, con, 00631 00632 OCIAttrGet((dvoid **) eventhp, (ub4) OCI_HTYPE_SERVER, (dvoid *) &dth, 00633 (ub4 *) NULL, (ub4) OCI_ATTR_HA_TIMESTAMP, con->err) 00634 00635 ) 00636 00637 if (res == TRUE) 00638 { 00639 res = (OCI_TimestampInit(con, &tmsp, dth, OCI_TIMESTAMP) != NULL); 00640 } 00641 00642 /* get status */ 00643 00644 if (res == TRUE) 00645 { 00646 OCI_CALL2 00647 ( 00648 res, con, 00649 00650 OCIAttrGet((dvoid **) eventhp, (ub4) OCI_HTYPE_SERVER, (dvoid *) &event, 00651 (ub4 *) NULL, (ub4) OCI_ATTR_HA_STATUS, con->err) 00652 00653 ) 00654 } 00655 00656 /* get source */ 00657 00658 if (res == TRUE) 00659 { 00660 OCI_CALL2 00661 ( 00662 res, con, 00663 00664 OCIAttrGet((dvoid **) eventhp, (ub4) OCI_HTYPE_SERVER, (dvoid *) &source, 00665 (ub4 *) NULL, (ub4) OCI_ATTR_HA_SOURCE, con->err) 00666 00667 ) 00668 } 00669 00670 /* on success, call the user callback */ 00671 00672 if (res == TRUE) 00673 { 00674 OCILib.ha_handler(con, (unsigned int) source, (unsigned int) event, tmsp); 00675 } 00676 00677 item = item->next; 00678 } 00679 } 00680 00681 if (list->mutex != NULL) 00682 { 00683 OCI_MutexRelease(list->mutex); 00684 } 00685 00686 ret = OCIAttrGet((dvoid **) srvhp, (ub4) OCI_HTYPE_SERVER, (dvoid *) &srvhp, 00687 (ub4 *) NULL, (ub4) OCI_ATTR_HA_SRVNEXT, OCILib.err); 00688 00689 } 00690 } 00691 #else 00692 00693 OCI_NOT_USED(eventptr); 00694 00695 #endif 00696 00697 }