TWOPHASE.C

/*Demo of Two-Phase Commit Service 
**
**This example uses the two-phase commit service
**to perform a simultaneous update on two servers.
**In this example, one of the servers participating
**in the distributed transaction also functions as
**the commit service.
**
**In this particular example, the same update is
**performed on both servers. You can, however, use
**the commit server to perform completely different
**updates on each server.
**
*/

#if defined(DBNTWIN32)
#include <windows.h>
#endif

#include <stdio.h>
#include <sqlfront.h>
#include <sqldb.h>

charcmdbuf[256];
charxact_string[128];

/* Forward declarations of the error handler and message handler.
*/
int err_handler(DBPROCESS*, int, int, int, char*, char*);
int msg_handler(DBPROCESS*, DBINT, int, int, char*);
void abortall (DBPROCESS * dbproc_server1, DBPROCESS * dbproc_server2, DBPROCESS * dbproc_commit, DBINT commid);

void main(argv,argc)
int argc;
char *argv[];
{

DBPROCESS*dbproc_server1;
DBPROCESS*dbproc_server2;
DBPROCESS*dbproc_commit;
LOGINREC*login;
DBINTcommid;

RETCODEret_server1;
RETCODEret_server2;

// set error/msg handlers for this program
dbmsghandle((DBMSGHANDLE_PROC)msg_handler);
dberrhandle((DBERRHANDLE_PROC)err_handler);


/* Open connections with the servers and the commit service. */
printf("Demo of Two Phase Commit\n");
login = dblogin();
DBSETLUSER(login, "user");
DBSETLPWD(login, "my_passwd");
DBSETLAPP(login, "example");
DBSETLVERSION(login, DBVER60);

dbproc_server1 = dbopen (login, "my_server1");
dbproc_server2 = dbopen (login, "my_server2");
dbproc_commit = open_commit (login, "my_commitsrv");

if (dbproc_server1 == NULL ||
dbproc_server2 == NULL ||
dbproc_commit== NULL)
{
printf (" Connections failed!\n");
exit (ERREXIT);
}

/* Use the "pubs" database. */
dbuse(dbproc_server1, "pubs");
dbuse(dbproc_server2, "pubs");

/* Start the distributed transaction on the commit service. */
commid = start_xact(dbproc_commit, "demo", "test", 2);

/* Build the transaction name. */
build_xact_string ("test", "my_commitsrv", commid, xact_string);

/* Build the first command buffer. */
sprintf(cmdbuf, "BEGIN TRANSACTION %s", xact_string);

/* Begin the transactions on the different servers. */
dbcmd(dbproc_server1, cmdbuf);
dbsqlexec(dbproc_server1);
dbcmd(dbproc_server2, cmdbuf);
dbsqlexec(dbproc_server2);

dbcancel(dbproc_server1);
dbcancel(dbproc_server2);

/* Do various updates. */
sprintf(cmdbuf, " update titles set price = $1.50 where");
strcat(cmdbuf, " title_id = 'BU1032'");
dbcmd(dbproc_server1, cmdbuf);
ret_server1 = dbsqlexec(dbproc_server1);
dbcmd(dbproc_server2, cmdbuf);
ret_server2 =dbsqlexec(dbproc_server2);
if (ret_server1 == FAIL || ret_server2 == FAIL)
{
/* Some part of the transaction failed. */
printf(" Transaction aborted -- dbsqlexec failed\n");
abortall(dbproc_server1, dbproc_server2, dbproc_commit, commid);
}

dbcancel(dbproc_server1);
dbcancel(dbproc_server2);

/* Find out if all servers can commit the transaction. */
sprintf(cmdbuf, "PREPARE TRANSACTION");
dbcmd(dbproc_server1, cmdbuf);
dbcmd(dbproc_server2, cmdbuf);
ret_server1 = dbsqlexec(dbproc_server1);
ret_server2 = dbsqlexec(dbproc_server2);
if (ret_server1 == FAIL || ret_server2 == FAIL)
{
/* One or both of the servers failed to prepare. */
printf(" Transaction aborted -- PREPARE failed\n");
abortall(dbproc_server1, dbproc_server2, dbproc_commit, commid);
}

dbcancel(dbproc_server1);
dbcancel(dbproc_server2);

/* Commit the transaction. */
if (commit_xact(dbproc_commit, commid) == FAIL)
{
/* The commit server failed to record the commit. */
printf( " Transaction aborted -- commit_xact failed\n");
abortall(dbproc_server1, dbproc_server2, dbproc_commit, commid);
exit(ERREXIT);
}

/* The transaction has successfully committed.Inform the servers.
*/
sprintf(cmdbuf, "COMMIT TRANSACTION");
dbcmd(dbproc_server1, cmdbuf);
if (dbsqlexec(dbproc_server1) != FAIL)
remove_xact(dbproc_commit, commid, 1);
dbcmd(dbproc_server2, cmdbuf);
if (dbsqlexec(dbproc_server2) != FAIL)
remove_xact(dbproc_commit, commid, 1);

/* Close the connection to the commit server. */
close_commit(dbproc_commit);

printf( "We made it!\n");
dbexit();
exit(STDEXIT);
}

/* Function to abort the distributed transaction. */

void abortall( dbproc_server1, dbproc_server2, dbproc_commit, commid )
DBPROCESS*dbproc_server1;
DBPROCESS*dbproc_server2;
DBPROCESS*dbproc_commit;
DBINTcommid;
{
/* Some part of the transaction failed. */

/* Inform the commit server of the failure. */
abort_xact(dbproc_commit, commid);

/* Roll back the transactions on the different servers. */
sprintf(cmdbuf, "ROLLBACK TRANSACTION");
dbcmd(dbproc_server1, cmdbuf);
if (dbsqlexec(dbproc_server1) != FAIL)
remove_xact(dbproc_commit, commid, 1);
dbcmd(dbproc_server2, cmdbuf);
if (dbsqlexec(dbproc_server2) != FAIL)
remove_xact(dbproc_commit, commid, 1);

dbexit();
exit(ERREXIT);
}
/* Message and error handling functions. */
int msg_handler(dbproc,msgno,msgstate, severity, msgtext)
DBPROCESS*dbproc;
DBINTmsgno;
intmsgstate;
intseverity;
char*msgtext;
{
/*Msg 5701 is just a USE DATABASE message, so skip it.*/
if (msgno == 5701)
return (0);
/*Print any severity 0 message as is, without extra stuff.*/
if (severity == 0)
{
printf ("%s\n",msgtext);
return (0);
}

printf("SQL Server message %ld, severity %d:\n\t%s\n",
msgno, severity, msgtext);

if (severity >>= 16)
{
printf("Program Terminated! Fatal SQL Server error.\n");
exit(ERREXIT);
}
return (0);
}

int err_handler(dbproc, severity, dberr, oserr, dberrstr, oserrstr)
DBPROCESS*dbproc;
intseverity;
intdberr;
intoserr;
char*dberrstr;
char*oserrstr;
{
if ((dbproc == NULL) || (DBDEAD(dbproc)))
return (INT_EXIT);
else
{
printf ("DB-LIBRARY error: \n\t%s\n", dberrstr);

if (oserr != DBNOERR)
printf ("Operating system error:\n\t%s\n", oserrstr);
}
return (INT_CANCEL);
}