OCILIB (C Driver for Oracle) 3.9.1
D:/Perso/dev/ocilib/ocilib/src/subscription.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: subscriptions.c, v 3.9.1 2011-07-08 00:00 Vincent Rogier $
00033  * --------------------------------------------------------------------------------------------- */
00034 
00035 #include "ocilib_internal.h"
00036 
00037 /* ********************************************************************************************* *
00038  *                             PRIVATE FUNCTIONS
00039  * ********************************************************************************************* */
00040 
00041 /* --------------------------------------------------------------------------------------------- *
00042  * OCI_SubscriptionClose
00043  * --------------------------------------------------------------------------------------------- */
00044 
00045 boolean OCI_SubscriptionClose
00046 (
00047     OCI_Subscription *sub
00048 )
00049 {
00050     boolean res = TRUE;
00051 
00052     OCI_CHECK_PTR(OCI_IPC_NOTIFY, sub, FALSE);
00053 
00054 #if OCI_VERSION_COMPILE >= OCI_10_2
00055 
00056     /* deregister the subscription if connection still alive */
00057 
00058     if (sub->subhp != NULL)
00059     {
00060         OCI_Connection * con = NULL;
00061 
00062         if (sub->con == NULL)
00063         {
00064             con = OCI_ConnectionCreate(sub->saved_db, sub->saved_user,
00065                                        sub->saved_pwd, OCI_SESSION_DEFAULT);
00066 
00067             sub->con = con;
00068         }
00069 
00070         if (sub->con != NULL)
00071         {
00072             OCI_CALL3
00073             (
00074                 res, sub->err,
00075 
00076                 OCISubscriptionUnRegister(sub->con->cxt, sub->subhp,
00077                                           sub->err,(ub4) OCI_DEFAULT)
00078             )
00079         }
00080 
00081         if (con != NULL)
00082         {
00083             OCI_ConnectionFree(con);
00084         }
00085     }
00086 
00087     /* free OCI handle */
00088 
00089     OCI_HandleFree((dvoid *) sub->subhp, OCI_HTYPE_SUBSCRIPTION);
00090 
00091     /* close error handle */
00092 
00093     if (sub->err != NULL)
00094     {
00095         OCI_HandleFree(sub->err, OCI_HTYPE_ERROR);
00096     }
00097 
00098 #endif
00099 
00100     /* free event data */
00101 
00102     OCI_FREE(sub->event.dbname);
00103     OCI_FREE(sub->event.objname);
00104     OCI_FREE(sub->event.rowid);
00105 
00106     /* free strings */
00107 
00108     OCI_FREE(sub->saved_db);
00109     OCI_FREE(sub->saved_user);
00110     OCI_FREE(sub->saved_pwd);
00111     OCI_FREE(sub->name);
00112 
00113     return res;
00114 }
00115 
00116 /* --------------------------------------------------------------------------------------------- *
00117  * OCI_SubscriptionDetachConnection
00118  * --------------------------------------------------------------------------------------------- */
00119 
00120 boolean OCI_SubscriptionDetachConnection
00121 (
00122     OCI_Connection *con
00123 )
00124 {
00125     OCI_List *list = OCILib.subs;
00126     OCI_Item *item = NULL;
00127 
00128     OCI_CHECK(list == NULL, FALSE);
00129 
00130     if (list->mutex != NULL)
00131     {
00132         OCI_MutexAcquire(list->mutex);
00133     }
00134 
00135     item = list->head;
00136 
00137     /* for each item in the list, check the connection */
00138 
00139     while (item != NULL)
00140     {
00141         OCI_Subscription * sub = (OCI_Subscription *) item->data;
00142 
00143         if ((sub != NULL) && (sub->con == con))
00144         {
00145             sub->con = NULL;
00146 
00147             sub->saved_db   = mtsdup(con->db);
00148             sub->saved_user = mtsdup(con->user);
00149             sub->saved_pwd  = mtsdup(con->pwd);
00150         }
00151 
00152         item = item->next;
00153     }
00154 
00155     if (list->mutex != NULL)
00156     {
00157         OCI_MutexRelease(list->mutex);
00158     }
00159 
00160     return TRUE;
00161 }
00162 
00163 /* ********************************************************************************************* *
00164  *                            PUBLIC FUNCTIONS
00165  * ********************************************************************************************* */
00166 
00167 /* --------------------------------------------------------------------------------------------- *
00168  * OCI_SubscriptionCreate
00169  * --------------------------------------------------------------------------------------------- */
00170 
00171 OCI_Subscription * OCI_API OCI_SubscriptionRegister
00172 (
00173     OCI_Connection *con,
00174     const mtext    *name,
00175     unsigned int    type,
00176     POCI_NOTIFY     handler,
00177     unsigned int    port,
00178     unsigned int    timeout
00179 )
00180 {
00181     OCI_Subscription *sub = NULL;
00182     OCI_Item *item        = NULL;
00183     boolean res           = TRUE;
00184 
00185     OCI_CHECK_INITIALIZED(NULL);
00186     OCI_CHECK_DATABASE_NOTIFY_ENABLED(NULL);
00187 
00188     OCI_CHECK_PTR(OCI_IPC_CONNECTION, con, NULL);
00189     OCI_CHECK_PTR(OCI_IPC_PROC, handler, NULL);
00190     OCI_CHECK_PTR(OCI_IPC_STRING, name, NULL);
00191 
00192 #if OCI_VERSION_COMPILE >= OCI_10_2
00193 
00194     /* create subscription object */
00195 
00196     item = OCI_ListAppend(OCILib.subs, sizeof(*sub));
00197 
00198     if (item != NULL)
00199     {
00200         sub = (OCI_Subscription *) item->data;
00201 
00202         /* allocate error handle */
00203 
00204         res = (OCI_SUCCESS == OCI_HandleAlloc(con->env,
00205                                               (dvoid **) (void *) &sub->err,
00206                                               OCI_HTYPE_ERROR, (size_t) 0,
00207                                               (dvoid **) NULL));
00208 
00209         /* allocate subcription handle */
00210 
00211         res = (OCI_SUCCESS == OCI_HandleAlloc(con->env,
00212                                               (dvoid **) (void *) &sub->subhp,
00213                                               OCI_HTYPE_SUBSCRIPTION, (size_t) 0,
00214                                               (dvoid **) NULL));
00215 
00216         if (res == TRUE)
00217         {
00218             ub4 attr   = 0;
00219             int osize  = -1;
00220             void *ostr = NULL;
00221 
00222             sub->con       = con;
00223             sub->env       = con->env;
00224             sub->port      = (ub4) port;
00225             sub->timeout   = (ub4) timeout;
00226             sub->handler   = handler;
00227             sub->type      = type;
00228             sub->name      = mtsdup(name);
00229             sub->event.sub = sub;
00230 
00231             /* set/get port number */
00232 
00233             if (sub->port > 0)
00234             {
00235                 OCI_CALL3
00236                 (
00237                     res, sub->err,
00238 
00239                     OCIAttrSet((dvoid *) con->env, (ub4) OCI_HTYPE_ENV,
00240                                (dvoid *) &sub->port, (ub4) sizeof (sub->port),
00241                                (ub4) OCI_ATTR_SUBSCR_PORTNO, sub->err)
00242                 )
00243             }
00244             else
00245             {
00246                 OCI_CALL3
00247                 (
00248                     res, sub->err,
00249 
00250                     OCIAttrGet((dvoid *) con->env, (ub4) OCI_HTYPE_ENV,
00251                                (dvoid *) &sub->port, (ub4) 0,
00252                                (ub4) OCI_ATTR_SUBSCR_PORTNO, sub->err)
00253                 )
00254             }
00255 
00256             /* set/get timeout */
00257 
00258             if(sub->timeout > 0)
00259             {
00260                 OCI_CALL3
00261                 (
00262                     res, sub->err,
00263 
00264                     OCIAttrSet((dvoid *) sub->subhp, (ub4) OCI_HTYPE_SUBSCRIPTION,
00265                                (dvoid *) &sub->timeout, (ub4) sizeof (sub->timeout),
00266                                (ub4) OCI_ATTR_SUBSCR_TIMEOUT, sub->err)
00267                 )
00268             }
00269 
00270             /* name  */
00271 
00272             ostr = OCI_GetInputMetaString(sub->name, &osize);
00273 
00274             OCI_CALL3
00275             (
00276                 res, sub->err,
00277 
00278                 OCIAttrSet((dvoid *) sub->subhp, (ub4) OCI_HTYPE_SUBSCRIPTION,
00279                            (dvoid *) ostr, (ub4) osize,
00280                            (ub4) OCI_ATTR_SUBSCR_NAME, sub->err)
00281             )
00282 
00283             OCI_ReleaseMetaString(ostr);
00284 
00285             /* namespace for CDN */
00286 
00287             attr =  OCI_SUBSCR_NAMESPACE_DBCHANGE;
00288 
00289             OCI_CALL3
00290             (
00291                 res, sub->err,
00292 
00293                 OCIAttrSet((dvoid *) sub->subhp, (ub4) OCI_HTYPE_SUBSCRIPTION,
00294                            (dvoid *) &attr, (ub4) sizeof(attr),
00295                            (ub4) OCI_ATTR_SUBSCR_NAMESPACE, sub->err)
00296             )
00297 
00298 /* On MSVC, casting a function pointer to a data pointer generates a warning.
00299    As there is no other to way to do regarding the OCI API, let's disable this
00300    warning just the time to set the callback attribute to the subscription handle */
00301 
00302         #ifdef _MSC_VER
00303 
00304             #pragma warning(disable: 4054)
00305    
00306         #endif
00307 
00308             /* internal callback handler */
00309 
00310             OCI_CALL3
00311             (
00312                 res, sub->err,
00313 
00314                 OCIAttrSet((dvoid *) sub->subhp, (ub4) OCI_HTYPE_SUBSCRIPTION,
00315                            (dvoid *) OCI_ProcNotify, (ub4) 0,
00316                            (ub4) OCI_ATTR_SUBSCR_CALLBACK, sub->err)
00317             )
00318 
00319         #ifdef _MSC_VER
00320 
00321             #pragma warning(default: 4054)
00322             
00323         #endif
00324 
00325             /* RowIds handling */
00326 
00327             if (sub->type & OCI_CNT_ROWS)
00328             {
00329                 attr = TRUE;
00330 
00331                 OCI_CALL3
00332                 (
00333                     res, sub->err,
00334 
00335                     OCIAttrSet((dvoid *) sub->subhp, (ub4) OCI_HTYPE_SUBSCRIPTION,
00336                                (dvoid *) &attr, (ub4) sizeof(attr),
00337                                (ub4) OCI_ATTR_CHNF_ROWIDS, sub->err)
00338                 )
00339             }
00340 
00341             /* set subsription context pointer to our subscription structure */
00342 
00343             OCI_CALL3
00344             (
00345                 res, sub->err,
00346 
00347                 OCIAttrSet((dvoid *) sub->subhp, (ub4) OCI_HTYPE_SUBSCRIPTION,
00348                            (dvoid *) sub, (ub4) 0,
00349                            (ub4) OCI_ATTR_SUBSCR_CTX, sub->err)
00350             )
00351 
00352             /* all attributes set, let's register the subscription ! */
00353 
00354             OCI_CALL3
00355             (
00356                 res, sub->err,
00357 
00358                 OCISubscriptionRegister(sub->con->cxt, &sub->subhp, (ub2) 1,
00359                                         sub->err,(ub4) OCI_DEFAULT)
00360 
00361             )
00362         }
00363     }
00364     else
00365     {
00366         res = FALSE;
00367     }
00368 
00369     if (res == FALSE)
00370     {
00371         OCI_SubscriptionClose(sub);
00372         OCI_ListRemove(OCILib.subs, sub);
00373         OCI_FREE(sub);
00374     }
00375 
00376 #else
00377 
00378     res = FALSE;
00379 
00380     OCI_NOT_USED(name);
00381     OCI_NOT_USED(type);
00382     OCI_NOT_USED(handler);
00383     OCI_NOT_USED(port);
00384     OCI_NOT_USED(timeout);
00385     OCI_NOT_USED(con);
00386     OCI_NOT_USED(item);
00387 
00388 #endif
00389 
00390     OCI_RESULT(res);
00391 
00392     return sub;
00393 }
00394 
00395 /* --------------------------------------------------------------------------------------------- *
00396  * OCI_SubscriptionUnregister
00397  * --------------------------------------------------------------------------------------------- */
00398 
00399 boolean OCI_API OCI_SubscriptionUnregister
00400 (
00401     OCI_Subscription *sub
00402 )
00403 {
00404     boolean res = TRUE;
00405 
00406     OCI_CHECK_PTR(OCI_IPC_NOTIFY, sub, FALSE);
00407 
00408     res = OCI_SubscriptionClose(sub);
00409 
00410     OCI_ListRemove(OCILib.subs, sub);
00411 
00412     OCI_FREE(sub);
00413 
00414     OCI_RESULT(res);
00415 
00416     return res;
00417 }
00418 
00419 /* --------------------------------------------------------------------------------------------- *
00420  * OCI_SubscriptionAddStatement
00421  * --------------------------------------------------------------------------------------------- */
00422 
00423 boolean OCI_API OCI_SubscriptionAddStatement
00424 (
00425     OCI_Subscription *sub,
00426     OCI_Statement    *stmt
00427 )
00428 {
00429     boolean res = TRUE;
00430 
00431     OCI_CHECK_PTR(OCI_IPC_NOTIFY, sub, FALSE);
00432     OCI_CHECK_PTR(OCI_IPC_STATEMENT, stmt, FALSE);
00433 
00434     OCI_CHECK_STMT_STATUS(stmt, OCI_STMT_PREPARED, FALSE);
00435 
00436 #if OCI_VERSION_COMPILE >= OCI_10_2
00437 
00438     /* register the statement query if provided */
00439 
00440     if (sub->type & OCI_CNT_OBJECTS)
00441     {
00442         OCI_CALL3
00443         (
00444             res, sub->err,
00445 
00446             OCIAttrSet((dvoid *) stmt->stmt, (ub4) OCI_HTYPE_STMT,
00447                        (dvoid *) sub->subhp, (ub4) 0,
00448                        (ub4) OCI_ATTR_CHNF_REGHANDLE, sub->err)
00449         )
00450 
00451         res = res && OCI_Execute(stmt) && (OCI_GetResultset(stmt) != NULL);
00452     }
00453 
00454 #endif
00455 
00456     OCI_RESULT(res);
00457 
00458     return res;
00459 }
00460 
00461 /* --------------------------------------------------------------------------------------------- *
00462  * OCI_SubscriptionGetName
00463  * --------------------------------------------------------------------------------------------- */
00464 
00465 const mtext * OCI_API OCI_SubscriptionGetName
00466 (
00467     OCI_Subscription *sub
00468 )
00469 {
00470     OCI_CHECK_PTR(OCI_IPC_NOTIFY, sub, NULL);
00471 
00472     OCI_RESULT(TRUE);
00473 
00474     return sub->name;
00475 }
00476 
00477 /* --------------------------------------------------------------------------------------------- *
00478  * OCI_SubscriptionGetPort
00479  * --------------------------------------------------------------------------------------------- */
00480 
00481 unsigned int OCI_API OCI_SubscriptionGetPort
00482 (
00483     OCI_Subscription *sub
00484 )
00485 {
00486     OCI_CHECK_PTR(OCI_IPC_NOTIFY, sub, 0);
00487 
00488     OCI_RESULT(TRUE);
00489 
00490     return sub->port;
00491 }
00492 
00493 /* --------------------------------------------------------------------------------------------- *
00494  * OCI_SubscriptionGetTimeout
00495  * --------------------------------------------------------------------------------------------- */
00496 
00497 unsigned int OCI_API OCI_SubscriptionGetTimeout
00498 (
00499     OCI_Subscription *sub
00500 )
00501 {
00502     OCI_CHECK_PTR(OCI_IPC_NOTIFY, sub, 0);
00503 
00504     OCI_RESULT(TRUE);
00505 
00506     return sub->timeout;
00507 }
00508