OCILIB (C Driver for Oracle) 3.9.2
D:/Perso/dev/ocilib/ocilib/src/callback.c
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 }