/* PROGRAM: dsmTransaction - commit or rollback a transaction or savepoint. * * RETURNS: DSM_S_SUCCESS * DSM_S_BADSAVE - invalid savepoint passed. * DSM_S_TRANSACTION_ALREADY_STARTED - transaction already started. * DSM_S_NO_TRANSACTION - a transaction operation request * was issued prior to a start request. * DSM_S_INVALID_TRANSACTION_CODE - invalid transaction code. * DSM_S_FAILURE */ dsmStatus_t dsmTransaction( dsmContext_t *pcontext, /* IN/OUT database context */ dsmTxnSave_t *pSavePoint, /* IN/OUT savepoint */ dsmTxnCode_t txnCode) /* IN function code */ { int returnCode; int forceAbort; dbcontext_t *pdbcontext = pcontext->pdbcontext; usrctl_t *pusr = pcontext->pusrctl; pdbcontext->inservice++; if (pdbcontext->prlctl == (RLCTL *)NULL) { /* Logging disabled */ if (pdbcontext->dbcode != PROCODET) { /* Not a temp-table database */ return DSM_S_SUCCESS; } } SETJMP_ERROREXIT(pcontext, returnCode) /* Ensure error exit address set */ if ((returnCode = dsmThreadSafeEntry(pcontext)) != DSM_S_SUCCESS) { /* If the user is marked to die it was decided to allow the * transaction operation to completed for 4gl compatibility */ if ( ( (returnCode == DSM_S_USER_TO_DIE) && (pcontext->pdbcontext->accessEnv == DSM_4GL_ENGINE) ) == 0 ) { returnCode = dsmEntryProcessError(pcontext, returnCode, (TEXT *)"dsmTransaction"); goto done; } } returnCode = DSM_S_SUCCESS; /* assume success */ if( txnCode == DSMTXN_START ) { /* Check to make sure that we are not trying to start a transaction on a task that already has a transaction */ if (pusr->uc_task) { returnCode = DSM_S_TRANSACTION_ALREADY_STARTED; goto done; } /* Transaction begin starts an implicit savepoint of 1 */ tmstrt(pcontext); } else if ( txnCode == DSMTXN_COMMIT ) { /* Check to make sure a transaction start was issued prior */ if (pusr->uc_task == 0) { returnCode = DSM_S_NO_TRANSACTION; goto done; } returnCode = tmend(pcontext, TMACC, NULL, 1 ); } else if ( txnCode == DSMTXN_SAVE ) { /* Make sure a transaction begin has been executed */ if ( !pSavePoint || (*pSavePoint < (DSMTXN_SAVE_MINIMUM + 1)) ) { returnCode = DSM_S_BADSAVE; goto done; } /* Mark the savepoint specified by the user */ returnCode = tmMarkSavePoint(pcontext, pSavePoint); } else if ( txnCode == DSMTXN_ABORT || txnCode == DSMTXN_FORCE || txnCode == DSMTXN_UNSAVE ) { if( txnCode == DSMTXN_FORCE ) forceAbort = 1; else forceAbort = 0; /* Check to make sure a transaction start was issued prior */ if (pusr->uc_task == 0) { returnCode = DSM_S_NO_TRANSACTION; goto done; } /* Rollback the transaction and unmark the savepoint */ if (pdbcontext->accessEnv == DSM_SQL_ENGINE) { if (!pSavePoint || (*pSavePoint > pcontext->pusrctl->uc_savePoint) ) { returnCode = DSM_S_BADSAVE; goto done; } tmrej(pcontext, forceAbort, pSavePoint); } else tmrej(pcontext, forceAbort, (dsmTxnSave_t *)PNULL); if( !pSavePoint ) { /* savepoint pointer should not be null */ returnCode = DSM_S_BADSAVE; goto done; } if( *pSavePoint == 0 ) returnCode = tmend(pcontext, TMREJ, NULL, 1); } else if ( txnCode == DSMTXN_ABORTED ) { /* Check to make sure a transaction start was issued prior */ if (pusr->uc_task == 0) { returnCode = DSM_S_NO_TRANSACTION; goto done; } returnCode = tmend(pcontext, TMREJ, NULL, 1 ); } else if ( txnCode == DSMTXN_PHASE1 ) { /* Check to make sure a transaction start was issued prior */ if (pusr->uc_task == 0) { returnCode = DSM_S_NO_TRANSACTION; goto done; } returnCode = tmend(pcontext, PHASE1, NULL, 1 ); } else if (txnCode == DSMTXN_PHASE1Q2) { /* Check to make sure a transaction start was issued prior */ if (pusr->uc_task == 0) { returnCode = DSM_S_NO_TRANSACTION; goto done; } returnCode = tmend(pcontext, PHASE1q2,NULL, 1); } else { /* Indicate that an invalid txnCode was passed to dsmTransaction */ returnCode = DSM_S_INVALID_TRANSACTION_CODE; } done: dsmThreadSafeExit(pcontext); pdbcontext->inservice--; return((dsmStatus_t) returnCode); } /* end dsmTransaction */
/* PROGRAM: dbxaEnd - End an association with a global transaction RETURNS: */ dsmStatus_t dbxaEnd(dsmContext_t *pcontext, dbxaTransaction_t *pxaTran, LONG flags) { dsmStatus_t returnCode = DSM_S_SUCCESS; usrctl_t *pusr = pcontext->pusrctl; if(pxaTran->trid != pcontext->pusrctl->uc_task) { /* Maybe we're ending a suspended association */ if(pcontext->pusrctl->uc_task == 0 && pxaTran->numSuspended) { /* That must be what it is */ ; } else { returnCode = DSM_S_XAER_NOTA; goto done; } } if(pxaTran->flags & DSM_XA_PREPARED) { returnCode = DSM_S_XAER_PROTO; goto done; } switch (flags) { case DSM_TMSUCCESS: { MT_LOCK_TXT(); pxaTran->referenceCount--; if(pusr->uc_task) pusr->uc_task = 0; else pxaTran->numSuspended--; pxaTran->lastRLblock = pusr->uc_lastBlock; pxaTran->lastRLoffset = pusr->uc_lastOffset; MT_UNLK_TXT(); break; } case DSM_TMSUSPEND: { pusr->uc_task = 0; MT_LOCK_TXT(); pxaTran->lastRLblock = pusr->uc_lastBlock; pxaTran->lastRLoffset = pusr->uc_lastOffset; pxaTran->numSuspended++; MT_UNLK_TXT(); break; } case DSM_TMFAIL: { MT_LOCK_TXT(); pxaTran->referenceCount--; pxaTran->flags |= DSM_XA_ROLLBACK_ONLY; MT_UNLK_TXT(); tmrej(pcontext,0,NULL); tmend(pcontext,TMREJ,NULL,1); break; } default: { returnCode = DSM_S_XAER_INVAL; } } done: return returnCode; }