OCILIB (C Driver for Oracle) 3.12.1
|
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-2013 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, 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 (res == TRUE && 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_ProcNotifyMessages 00225 * --------------------------------------------------------------------------------------------- */ 00226 00227 ub4 OCI_ProcNotifyMessages 00228 ( 00229 void *ctx, 00230 OCISubscription *subscrhp, 00231 void *payload, 00232 ub4 paylen, 00233 void *desc, 00234 ub4 mode 00235 ) 00236 { 00237 OCI_Dequeue *dequeue = (OCI_Dequeue *) ctx; 00238 00239 OCI_NOT_USED(paylen); 00240 OCI_NOT_USED(payload); 00241 OCI_NOT_USED(mode); 00242 OCI_NOT_USED(subscrhp); 00243 OCI_NOT_USED(desc); 00244 00245 OCI_CHECK(dequeue == NULL, OCI_SUCCESS); 00246 00247 dequeue->callback(dequeue); 00248 00249 return OCI_SUCCESS; 00250 } 00251 00252 /* --------------------------------------------------------------------------------------------- * 00253 * OCI_ProcNotifyChanges 00254 * --------------------------------------------------------------------------------------------- */ 00255 00256 ub4 OCI_ProcNotifyChanges 00257 ( 00258 void *ctx, 00259 OCISubscription *subscrhp, 00260 void *payload, 00261 ub4 paylen, 00262 void *desc, 00263 ub4 mode 00264 ) 00265 { 00266 OCI_Subscription *sub = (OCI_Subscription *) ctx; 00267 boolean res = TRUE; 00268 void *ostr = NULL; 00269 int osize = 0; 00270 ub4 type = 0; 00271 00272 OCI_NOT_USED(paylen); 00273 OCI_NOT_USED(payload); 00274 OCI_NOT_USED(mode); 00275 OCI_NOT_USED(subscrhp); 00276 00277 OCI_CHECK(sub == NULL, OCI_SUCCESS); 00278 00279 OCI_EventReset(&sub->event); 00280 00281 #if OCI_VERSION_COMPILE >= OCI_10_2 00282 00283 /* get database that generated the notification */ 00284 00285 OCI_CALL3 00286 ( 00287 res, sub->err, 00288 00289 OCIAttrGet((dvoid *) desc, (ub4) OCI_DTYPE_CHDES, (dvoid *) &ostr, (ub4 *) &osize, 00290 (ub4) OCI_ATTR_CHDES_DBNAME, sub->err) 00291 ) 00292 00293 if ((res == TRUE) && (osize > (int) sub->event.dbname_size)) 00294 { 00295 /* buffer is ANSI */ 00296 00297 sub->event.dbname = (dtext *) OCI_MemRealloc(sub->event.dbname, OCI_IPC_STRING, 00298 sizeof(dtext), (size_t) (osize + 1)); 00299 00300 sub->event.dbname_size = osize; 00301 } 00302 00303 OCI_CopyString(ostr, sub->event.dbname, &osize, sizeof(char), sizeof(dtext)); 00304 00305 /* get notification type */ 00306 00307 OCI_CALL3 00308 ( 00309 res, sub->err, 00310 00311 OCIAttrGet((dvoid *) desc, (ub4) OCI_DTYPE_CHDES, 00312 (dvoid *) &type, (ub4 *) NULL, 00313 (ub4) OCI_ATTR_CHDES_NFYTYPE, sub->err) 00314 ) 00315 00316 switch(type) 00317 { 00318 case OCI_EVENT_STARTUP: 00319 case OCI_EVENT_SHUTDOWN: 00320 case OCI_EVENT_SHUTDOWN_ANY: 00321 { 00322 if (sub->type & OCI_CNT_DATABASES) 00323 { 00324 sub->event.type = type; 00325 } 00326 00327 break; 00328 } 00329 case OCI_EVENT_DEREG: 00330 { 00331 sub->event.type = type; 00332 break; 00333 } 00334 case OCI_EVENT_OBJCHANGE: 00335 { 00336 if (sub->type & OCI_CNT_OBJECTS) 00337 { 00338 sub->event.type = type; 00339 } 00340 00341 break; 00342 } 00343 default: 00344 { 00345 break; 00346 } 00347 } 00348 00349 /* for object, much work to do for retrieving data */ 00350 00351 if (sub->event.type == OCI_EVENT_OBJCHANGE) 00352 { 00353 OCIColl *tables = 0; 00354 00355 /* get collection of modified tables */ 00356 00357 OCI_CALL3 00358 ( 00359 res, sub->err, 00360 00361 OCIAttrGet((dvoid *) desc, (ub4) OCI_DTYPE_CHDES, (dvoid *) &tables, 00362 (ub4 *) NULL, (ub4) OCI_ATTR_CHDES_TABLE_CHANGES, sub->err) 00363 ) 00364 00365 if (tables != NULL) 00366 { 00367 dvoid **tbl_elem = NULL; 00368 dvoid *tbl_ind = NULL; 00369 boolean tbl_exist = FALSE; 00370 sb4 nb_tables = 0; 00371 sb4 nb_rows = 0; 00372 sb4 i; 00373 00374 /* get number of tables in the collection */ 00375 00376 OCI_CALL3 00377 ( 00378 res, sub->err, 00379 00380 OCICollSize(sub->env, sub->err, tables, &nb_tables) 00381 ) 00382 00383 for (i = 0; i < nb_tables; i++) 00384 { 00385 nb_rows = 0; 00386 00387 /* partial reset of the event object */ 00388 00389 if (sub->event.objname != NULL) 00390 { 00391 sub->event.objname[0] = 0; 00392 } 00393 00394 if (sub->event.rowid != NULL) 00395 { 00396 sub->event.rowid[0] = 0; 00397 } 00398 00399 /* get table element */ 00400 00401 OCI_CALL3 00402 ( 00403 res, sub->err, 00404 00405 OCICollGetElem(sub->env, sub->err, tables, i, &tbl_exist, 00406 (dvoid**) (dvoid*) &tbl_elem, (dvoid**) &tbl_ind) 00407 ) 00408 00409 /* get table name */ 00410 00411 OCI_CALL3 00412 ( 00413 res, sub->err, 00414 00415 OCIAttrGet((dvoid *) *tbl_elem, 00416 (ub4) OCI_DTYPE_TABLE_CHDES, 00417 (dvoid *) &ostr, (ub4 *) &osize, 00418 (ub4) OCI_ATTR_CHDES_TABLE_NAME, 00419 sub->err) 00420 ) 00421 00422 if(osize > (int) sub->event.objname_size) 00423 { 00424 /* buffer is ANSI */ 00425 00426 sub->event.objname = (dtext *) OCI_MemRealloc(sub->event.objname, 00427 OCI_IPC_STRING, sizeof(dtext), 00428 (size_t) (osize + 1)); 00429 00430 sub->event.objname_size = osize; 00431 } 00432 00433 OCI_CopyString(ostr, sub->event.objname, &osize, sizeof(char), sizeof(dtext)); 00434 00435 /* get table modification type */ 00436 00437 OCI_CALL3 00438 ( 00439 res, sub->err, 00440 00441 OCIAttrGet((dvoid *) *tbl_elem, (ub4) OCI_DTYPE_TABLE_CHDES, 00442 (dvoid *) &sub->event.op, (ub4*) NULL, 00443 (ub4) OCI_ATTR_CHDES_TABLE_OPFLAGS, sub->err) 00444 ) 00445 00446 sub->event.op = sub->event.op & (~OCI_OPCODE_ALLROWS); 00447 sub->event.op = sub->event.op & (~OCI_OPCODE_ALLOPS); 00448 00449 /* if requested, get row details */ 00450 00451 if (sub->type & OCI_CNT_ROWS) 00452 { 00453 OCIColl *rows = 0; 00454 00455 /* get collection of modified rows */ 00456 00457 OCI_CALL3 00458 ( 00459 res, sub->err, 00460 00461 OCIAttrGet((dvoid *) *tbl_elem, (ub4) OCI_DTYPE_TABLE_CHDES, 00462 (dvoid *) &rows, (ub4 *) NULL, 00463 (ub4 ) OCI_ATTR_CHDES_TABLE_ROW_CHANGES, sub->err) 00464 ) 00465 00466 if (rows != NULL) 00467 { 00468 dvoid **row_elem = NULL; 00469 dvoid *row_ind = NULL; 00470 boolean row_exist = FALSE; 00471 sb4 j; 00472 00473 /* get number of rows */ 00474 00475 OCI_CALL3 00476 ( 00477 res, sub->err, 00478 00479 OCICollSize(sub->env, sub->err, rows, &nb_rows) 00480 ) 00481 00482 for (j = 0; j < nb_rows; j++) 00483 { 00484 /* partial reset of the event */ 00485 00486 if (sub->event.rowid != NULL) 00487 { 00488 sub->event.rowid[0] = 0; 00489 } 00490 00491 /* get row element */ 00492 00493 OCI_CALL3 00494 ( 00495 res, sub->err, 00496 00497 OCICollGetElem(sub->env, sub->err, rows, j, &row_exist, 00498 (dvoid**) (dvoid*) &row_elem, (dvoid**) &row_ind) 00499 ) 00500 00501 /* get rowid */ 00502 00503 OCI_CALL3 00504 ( 00505 res, sub->err, 00506 00507 OCIAttrGet((dvoid *) *row_elem, (ub4) OCI_DTYPE_ROW_CHDES, 00508 (dvoid *) &ostr, (ub4 *) &osize, 00509 (ub4) OCI_ATTR_CHDES_ROW_ROWID, sub->err) 00510 ) 00511 00512 /* get opcode */ 00513 00514 OCI_CALL3 00515 ( 00516 res, sub->err, 00517 00518 OCIAttrGet((dvoid *) *row_elem, (ub4) OCI_DTYPE_ROW_CHDES, 00519 &sub->event.op, (ub4*) NULL, 00520 (ub4) OCI_ATTR_CHDES_ROW_OPFLAGS, sub->err) 00521 ) 00522 00523 if(osize > (int) sub->event.rowid_size) 00524 { 00525 /* buffer is ANSI */ 00526 00527 sub->event.rowid = (dtext *) OCI_MemRealloc(sub->event.rowid, 00528 OCI_IPC_STRING, 00529 sizeof(dtext), 00530 (size_t) (osize + 1)); 00531 00532 sub->event.rowid_size = osize; 00533 } 00534 00535 OCI_CopyString(ostr, sub->event.rowid, &osize, 00536 sizeof(char), sizeof(dtext)); 00537 00538 sub->handler(&sub->event); 00539 } 00540 } 00541 } 00542 00543 if (nb_rows == 0) 00544 { 00545 sub->handler(&sub->event); 00546 } 00547 } 00548 } 00549 } 00550 else if (sub->event.type > 0) 00551 { 00552 sub->handler(&sub->event); 00553 } 00554 00555 #else 00556 00557 OCI_NOT_USED(ctx); 00558 OCI_NOT_USED(desc); 00559 OCI_NOT_USED(subscrhp); 00560 00561 OCI_NOT_USED(res); 00562 OCI_NOT_USED(type); 00563 OCI_NOT_USED(ostr); 00564 OCI_NOT_USED(osize); 00565 00566 #endif 00567 00568 return OCI_SUCCESS; 00569 } 00570 00571 /* --------------------------------------------------------------------------------------------- * 00572 * OCI_ProcFailOver 00573 * --------------------------------------------------------------------------------------------- */ 00574 00575 sb4 OCI_ProcFailOver 00576 ( 00577 dvoid *svchp, 00578 dvoid *envhp, 00579 dvoid *fo_ctx, 00580 ub4 fo_type, 00581 ub4 fo_event 00582 ) 00583 { 00584 OCI_Connection *cn = (OCI_Connection *) fo_ctx; 00585 sb4 ret = OCI_FOC_OK; 00586 00587 OCI_NOT_USED(envhp); 00588 OCI_NOT_USED(svchp); 00589 00590 if ((cn != NULL) && (cn->taf_handler != NULL)) 00591 { 00592 ret = (sb4) cn->taf_handler(cn, fo_type, fo_event); 00593 } 00594 00595 return ret; 00596 } 00597 00598 /* --------------------------------------------------------------------------------------------- * 00599 * OCI_ProcHAEvent 00600 * --------------------------------------------------------------------------------------------- */ 00601 00602 void OCI_ProcHAEvent 00603 ( 00604 dvoid *evtctx, 00605 dvoid *eventptr 00606 ) 00607 { 00608 OCI_List *list = OCILib.cons; 00609 OCI_Item *item = NULL; 00610 OCIServer *srvhp = NULL; 00611 00612 OCI_NOT_USED(evtctx); 00613 00614 #if OCI_VERSION_COMPILE >= OCI_10_2 00615 00616 if ((list == NULL) || (OCILib.ha_handler == NULL)) 00617 { 00618 return; 00619 } 00620 00621 if (OCILib.version_runtime >= OCI_10_2) 00622 { 00623 OCIEvent *eventhp = (OCIEvent *) eventptr; 00624 OCI_Timestamp *tmsp = NULL; 00625 sword ret; 00626 00627 ret = OCIAttrGet((dvoid **) eventhp, (ub4) OCI_HTYPE_SERVER, (dvoid *) &srvhp, 00628 (ub4 *) NULL, (ub4) OCI_ATTR_HA_SRVFIRST, OCILib.err); 00629 00630 while ((ret == OCI_SUCCESS) && (srvhp != NULL)) 00631 { 00632 if (list->mutex != NULL) 00633 { 00634 OCI_MutexAcquire(list->mutex); 00635 } 00636 00637 item = list->head; 00638 00639 /* for each item in the list, check the connection */ 00640 00641 while (item != NULL) 00642 { 00643 OCI_Connection *con = (OCI_Connection *) item->data; 00644 OCIDateTime *dth = NULL; 00645 00646 ub4 event = OCI_HA_STATUS_DOWN; 00647 ub4 source = OCI_HA_SOURCE_INSTANCE; 00648 00649 if ((con != NULL) && (con->svr == srvhp)) 00650 { 00651 boolean res = TRUE; 00652 00653 /* get event timestamp */ 00654 00655 OCI_CALL2 00656 ( 00657 res, con, 00658 00659 OCIAttrGet((dvoid **) eventhp, (ub4) OCI_HTYPE_SERVER, (dvoid *) &dth, 00660 (ub4 *) NULL, (ub4) OCI_ATTR_HA_TIMESTAMP, con->err) 00661 00662 ) 00663 00664 if (res == TRUE) 00665 { 00666 res = (OCI_TimestampInit(con, &tmsp, dth, OCI_TIMESTAMP) != NULL); 00667 } 00668 00669 /* get status */ 00670 00671 if (res == TRUE) 00672 { 00673 OCI_CALL2 00674 ( 00675 res, con, 00676 00677 OCIAttrGet((dvoid **) eventhp, (ub4) OCI_HTYPE_SERVER, (dvoid *) &event, 00678 (ub4 *) NULL, (ub4) OCI_ATTR_HA_STATUS, con->err) 00679 00680 ) 00681 } 00682 00683 /* get source */ 00684 00685 if (res == TRUE) 00686 { 00687 OCI_CALL2 00688 ( 00689 res, con, 00690 00691 OCIAttrGet((dvoid **) eventhp, (ub4) OCI_HTYPE_SERVER, (dvoid *) &source, 00692 (ub4 *) NULL, (ub4) OCI_ATTR_HA_SOURCE, con->err) 00693 00694 ) 00695 } 00696 00697 /* on success, call the user callback */ 00698 00699 if (res == TRUE) 00700 { 00701 OCILib.ha_handler(con, (unsigned int) source, (unsigned int) event, tmsp); 00702 } 00703 00704 item = item->next; 00705 } 00706 } 00707 00708 if (list->mutex != NULL) 00709 { 00710 OCI_MutexRelease(list->mutex); 00711 } 00712 00713 ret = OCIAttrGet((dvoid **) srvhp, (ub4) OCI_HTYPE_SERVER, (dvoid *) &srvhp, 00714 (ub4 *) NULL, (ub4) OCI_ATTR_HA_SRVNEXT, OCILib.err); 00715 00716 } 00717 00718 /* free temporary timestamp object */ 00719 00720 if (tmsp != NULL) 00721 { 00722 tmsp->hstate = OCI_OBJECT_FETCHED_DIRTY; 00723 OCI_TimestampFree(tmsp); 00724 } 00725 } 00726 00727 #else 00728 00729 OCI_NOT_USED(eventptr); 00730 OCI_NOT_USED(list); 00731 OCI_NOT_USED(item); 00732 OCI_NOT_USED(srvhp); 00733 00734 #endif 00735 00736 }