Use a DBPROCESS structure to save a pointer to user-allocated data.
void dbsetuserdata(dbproc, ptr) DBPROCESS *dbproc; BYTE *ptr;
A pointer to the DBPROCESS structure that provides the connection for a particular front-end/server process. It contains all the information that DB-Library uses to manage communications and data between the front end and server.
A generic BYTE pointer to the user’s private data space.
None.
This routine saves, in a DBPROCESS structure, a pointer to user-allocated data. The application can access the data later with the dbgetuserdata routine.
dbsetuserdata allows the application to associate user data with a particular DBPROCESS. This avoids the necessity of using global variables for this purpose. One use for this routine is to handle deadlock, as shown in the example below. This routine is particularly useful when the application has multiple DBPROCESS structures.
The application must allocate the data that ptr points to. DB-Library never manipulates this data; it merely saves the pointer to it for later use by the application.
Here is an example of using this routine to handle deadlock, a situation which occurs occasionally in high-volume applications. See the Adaptive Server Enterprise System Administration Guide. This program fragment sends updates to the server. It reruns the transaction when its message handler detects deadlock.
...
/*
** Deadlock detection:
** In the DBPROCESS structure, we save a pointer to
** a DBBOOL variable. The message handler sets the
** variable when deadlock occurs. The result
** processing logic checks the variable and resends
** the transaction in case of deadlock.
*/
/*
** Allocate the space for the DBBOOL variable
** and save it in the DBPROCESS structure.
*/
dbsetuserdata(dbproc, malloc(sizeof(DBBOOL)));
/* Initialize the variable to FALSE */
*((DBBOOL *) dbgetuserdata(dbproc)) = FALSE;
...
/* Run queries and check for deadlock */
deadlock:
/*
** Did we get here using deadlock?
** If so, the server has already aborted the
** transaction. We’ll just start it again. In a
** real application, the deadlock handling may need
** to be somewhat more sophisticated. For
** instance, you may want to keep a counter and
** retry the transaction just a fixed number
** of times.
*/
if (*((DBBOOL *) dbgetuserdata(dbproc)) == TRUE)
{
/* Reset the variable to FALSE */
*((DBBOOL *) dbgetuserdata(dbproc)) = FALSE;
}
/* Start the transaction */
dbcmd(dbproc, "begin transaction ");
/* Run the first update command */
dbcmd(dbproc, "update ......");
dbsqlexec(dbproc);
while (dbresults(dbproc) != NO_MORE_RESULTS)
{
/* application code */
}
/* Did we deadlock? */
if (*((DBBOOL *) dbgetuserdata(dbproc)) == TRUE)
goto deadlock;
/* Run the second update command. */
dbcmd(dbproc, "update ......");
dbsqlexec(dbproc);
while (dbresults(dbproc) != NO_MORE_RESULTS)
{
/* application code */
}
/* Did we deadlock? */
if (*((DBBOOL *) dbgetuserdata(dbproc)) == TRUE)
goto deadlock;
/* No deadlock -- Commit the transaction */
dbcmd(dbproc, "commit transaction");
dbsqlexec(dbproc);
dbresults(dbproc);
...
/*
** SERVERMSGS
** This is the server message handler. Assume that
** the dbmsghandle() routine installed it earlier in
** the program.
*/
servermsgs(dbproc, msgno, msgstate, severity, msgtext,
srvname, procname, line)
DBPROCESS *dbproc;
DBINT msgno;
int msgstate;
int severity;
char *msgtext;
char *srvname;
char *procname;
DBUSMALLINT line;
{
/* Is this a deadlock message? */
if (msgno == 1205)
{
/* Set the deadlock indicator */
*((DBBOOL *) dbgetuserdata(dbproc)) = TRUE;
return (0);
}
/* Normal message handling code here */
}