OCILIB (C Driver for Oracle) 3.12.1
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-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: subscriptions.c, 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         if (res == TRUE)
00210         {
00211             /* allocate subcription handle */
00212 
00213             res = (OCI_SUCCESS == OCI_HandleAlloc(con->env,
00214                                                   (dvoid **) (void *) &sub->subhp,
00215                                                   OCI_HTYPE_SUBSCRIPTION, (size_t) 0,
00216                                                   (dvoid **) NULL));
00217         }
00218 
00219         if (res == TRUE)
00220         {
00221             ub4 attr   = 0;
00222             int osize  = -1;
00223             void *ostr = NULL;
00224 
00225             sub->con       = con;
00226             sub->env       = con->env;
00227             sub->port      = (ub4) port;
00228             sub->timeout   = (ub4) timeout;
00229             sub->handler   = handler;
00230             sub->type      = type;
00231             sub->name      = mtsdup(name);
00232             sub->event.sub = sub;
00233 
00234             /* set/get port number */
00235 
00236             if (sub->port > 0)
00237             {
00238                 OCI_CALL3
00239                 (
00240                     res, sub->err,
00241 
00242                     OCIAttrSet((dvoid *) sub->subhp, (ub4)  OCI_HTYPE_SUBSCRIPTION,
00243                                (dvoid *) &sub->port, (ub4) sizeof (sub->port),
00244                                (ub4) OCI_ATTR_SUBSCR_PORTNO, sub->err)
00245                 )
00246             }
00247             else
00248             {
00249                 OCI_CALL3
00250                 (
00251                     res, sub->err,
00252 
00253                     OCIAttrGet((dvoid *) sub->subhp, (ub4) OCI_HTYPE_SUBSCRIPTION,
00254                                (dvoid *) &sub->port, (ub4) 0,
00255                                (ub4) OCI_ATTR_SUBSCR_PORTNO, sub->err)
00256                 )
00257             }
00258 
00259             /* set timeout */
00260 
00261             if(sub->timeout > 0)
00262             {
00263                 OCI_CALL3
00264                 (
00265                     res, sub->err,
00266 
00267                     OCIAttrSet((dvoid *) sub->subhp, (ub4) OCI_HTYPE_SUBSCRIPTION,
00268                                (dvoid *) &sub->timeout, (ub4) sizeof (sub->timeout),
00269                                (ub4) OCI_ATTR_SUBSCR_TIMEOUT, sub->err)
00270                 )
00271             }
00272 
00273             /* name  */
00274 
00275             ostr = OCI_GetInputMetaString(sub->name, &osize);
00276 
00277             OCI_CALL3
00278             (
00279                 res, sub->err,
00280 
00281                 OCIAttrSet((dvoid *) sub->subhp, (ub4) OCI_HTYPE_SUBSCRIPTION,
00282                            (dvoid *) ostr, (ub4) osize,
00283                            (ub4) OCI_ATTR_SUBSCR_NAME, sub->err)
00284             )
00285 
00286             OCI_ReleaseMetaString(ostr);
00287 
00288             /* namespace for CDN */
00289 
00290             attr =  OCI_SUBSCR_NAMESPACE_DBCHANGE;
00291 
00292             OCI_CALL3
00293             (
00294                 res, sub->err,
00295 
00296                 OCIAttrSet((dvoid *) sub->subhp, (ub4) OCI_HTYPE_SUBSCRIPTION,
00297                            (dvoid *) &attr, (ub4) sizeof(attr),
00298                            (ub4) OCI_ATTR_SUBSCR_NAMESPACE, sub->err)
00299             )
00300 
00301             /* protocol for CDN */
00302 
00303             attr =  OCI_SUBSCR_PROTO_OCI;
00304 
00305             OCI_CALL3
00306             (
00307                 res, sub->err,
00308 
00309                 OCIAttrSet((dvoid *) sub->subhp, (ub4) OCI_HTYPE_SUBSCRIPTION,
00310                            (dvoid *) &attr, (ub4) sizeof(attr),
00311                            (ub4) OCI_ATTR_SUBSCR_RECPTPROTO, sub->err)
00312             )
00313 
00314             /* internal callback handler */
00315 
00316             OCI_CALL3
00317             (
00318                 res, sub->err,
00319 
00320                 OCIAttrSet((dvoid *) sub->subhp, (ub4) OCI_HTYPE_SUBSCRIPTION,
00321                            (dvoid *) OCI_ProcNotifyChanges, (ub4) 0,
00322                            (ub4) OCI_ATTR_SUBSCR_CALLBACK, sub->err)
00323             )
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