ctRecordUpdateCallbackControl
Declaration
ctRecordUpdateCallbackControl() is used to add and delete callback function definitions. Its prototype is as follows:
NINT ctDECL ctRecordUpdateCallbackControl(pRUCBCTL prucbctl);
Description
A file can have one or more callback function definitions. Each callback function definition is identified by its name, which is a case-sensitive ASCII string. The callback functions are called in the order in which they were added.
These callbacks execute within the server process space. Programming errors will affect the entire database server process.
The synchronous callback types ( RUCBonrecupd, RUCBontrancmt ) occur in the context of the calling user. Most c-tree APIs cannot be safely called from these callbacks, as they may alter existing internal user state information. For advanced usage, information could be sent to another thread to make c-tree file calls if desired. ctThrd* APIs are useful in this regard to pass information to another thread.
The asynchronous callback types ( RUCBqueuethrd, RUCBqueueapp ) are more flexible, since they don't share the same state as the original operation. It should be safe to directly call c-tree file APIs, however, ensure you don't operate on the same file that is generating the callback.
More generally, within the server each thread has an implicit top level "connection" context that is single threaded, which we call OWNER. If you want to do something like have a pool of worker threads, you'll need to manage this using ctSetOWNER (faircom.com) or ctdbGetCtreeOWNER()/ctdbSetCtreeOWNER(). Only a single thread should be within a c-tree API call with a particular OWNER at the same time.
The RUCBCTL structure has the following definition:
typedef struct rucbctl {
COUNT version; /* version of this structure */
COUNT opcode; /* operation code */
LONG bufsiz; /* buffer size */
pVOID bufptr; /* input/output buffer */
#ifndef ct8P
LONG pad;
#endif
} RUCBCTL, *pRUCBCTL;
The RUCBACB structure, used when adding a callback definition, has the following definition:
/* Input buffer format for RUCBCTLaddcallback opcode. */
typedef struct rucbacb {
COUNT version; /* Version of this structure */
FILNO datno; /* Data file number */
LONG calltm; /* Time of function call */
LONG nfncnames; /* Number of function names */
LONG pad; /* Padding to ensure 8-byte alignment of next field */
pTEXT datnam; /* Data file name */
pTEXT cbname; /* Unique name to identify this callback */
pTEXT dllname; /* Name of callback DLL */
pTEXT params; /* Optional parameters */
ppTEXT fncnames; /* Callback function names */
#ifndef ct8P
LONG pad2[5];
#endif
} RUCBACB, *pRUCBACB;
The calltm member defines "when" a callback is executed. There are currently four possible values:
The RUCBDCB structure, used when deleting a callback definition, has the following definition:
/* Input buffer format for RUCBCTLdelcallback opcode. */
typedef struct rucbdcb {
COUNT version; /* Version of this structure */
FILNO datno; /* Data file number */
LONG pad; /* Padding for 8-byte pointer alignment */
pTEXT datnam; /* Data file name */
pTEXT cbname; /* Unique name to identify this callback */
#ifndef ct8P
LONG pad2[2];
#endif
} RUCBDCB, *pRUCBDCB;
Option to Update All Existing Records
The default when adding a callback is to not call it for existing records. An option can be specified to choose a new behavior of calling the callback for all existing records. This option, RUCBcallexist, is specified by OR'ing it into the calltm field of the RUCBACB structure when calling ctRecordUpdateCallbackControl().
Return Values
Value |
Symbolic Constant |
Explanation |
---|---|---|
0 |
NO_ERROR |
Successful operation. |
See c-tree Plus Error Codes for a complete listing of valid c-tree Plus error values.
Example
Follow these steps to use ctRecordUpdateCallbackControl() to add a callback function:
RUCBCTL rucbctl;
RUCBACB rucbacb;
pTEXT myCallbackFunctionNames[NbrRUCBFnc] = {
"rucbOpenFileCallback",
"rucbCloseFileCallback",
"rucbRecordUpdateCallback"
};
NINT rc;
memset(&rucbctl,0,sizeof(rucbctl));
rucbctl.verson = RUCBCTL_VERS_V01;
rucbctl.opcode = RUCBCTLaddcallback;
rucbctl.bufsiz = sizeof(rucbacb);
rucbctl.bufptr = &rucbacb;
memset(&rucbacb,0,sizeof(rucbacb));
rucbacb.verson = RUCBACB_VERS_V01;
rucbacb.opcode = RUCBCTLaddcallback;
/* datno of -1 instructs ctRecordUpdateCallbackControl() to open the file;
** otherwise it is the file number of an already-open data file. */
rucbacb.datno = -1;
rucbacb.datnam = "mydatafile.dat";
rucbacb.dllname = "ctuser.dll";
rucbacb.params = "my parameters";
rucbacb.fncnames = myCallbackFunctionNames;
rucbacb.nfncnames = NbrRUCBFnc;
rucbacb.cbname = "My First Callback";
/* This record update callback will be called on record update. */
rucbacb.calltm = RUCBonrecupd;
if ((rc = ctRecordUpdateCallbackControl(&rucbctl)) != NO_ERROR)
printf("Error: Failed to add record update callback function '%s': %d (%d)\n",
rucbacb.cbname,rc,sysiocod);
else
printf("Successfully added record update callback function '%s'.\n",
rucbacb.cbname);
To use ctRecordUpdateCallbackControl() to delete a callback function:
RUCBCTL rucbctl;
RUCBDCB rucbdcb;
NINT rc;
memset(&rucbctl,0,sizeof(rucbctl));
rucbctl.verson = RUCBCTL_VERS_V01;
rucbctl.opcode = RUCBCTLdelcallback;
rucbctl.bufsiz = sizeof(rucbdcb);
rucbctl.bufptr = &rucbdcb;
memset(&rucbdcb,0,sizeof(rucbdcb));
rucbdcb.verson = RUCBDCB_VERS_V01;
/* datno of -1 instructs ctRecordUpdateCallbackControl() to open the file;
** otherwise it is the file number of an already-open data file. */
rucbdcb.datno = -1;
rucbdcb.datnam = "mydatafile.dat";
rucbdcb.cbname = "My First Callback";
if ((rc = ctRecordUpdateCallbackControl(&rucbctl)) != NO_ERROR)
printf("Error: Failed to delete record update callback function '%s': %d (%d)\n",
rucbdcb.cbname,rc,sysiocod);
else
printf("Successfully deleted record update callback function '%s'.\n",
rucbdcb.cbname);