#include "config.h" #include #include "daedef.h" #include "pib.h" #include "util.h" #include "fmp.h" #include "page.h" #include "ssib.h" #include "fcb.h" #include "fucb.h" #include "stapi.h" DeclAssertFile; /* Declare file name for assert macros */ static CSR csrTemplate = { ulDBTimeMin, // page time stamp NULL, // parent currency pgnoNull, // pgno of node page sridNull, // bookmark of node sridNull, // item csrstatBeforeFirst, // status of csr relative to node itagNull, // node itag isridNull, // index of item in item list itagNull, // itag of father ibSonNull, // index of son in father son table }; ERR ErrFUCBAllocCSR( CSR **ppcsr ) { CSR *pcsr; pcsr = PcsrMEMAlloc( ); if ( !pcsr ) return JET_errOutOfMemory; *pcsr = csrTemplate; Assert( pcsr->csrstat == csrstatBeforeFirst ); Assert( pcsr->pgno == pgnoNull ); Assert( pcsr->itag == itagNull ); Assert( pcsr->itagFather == itagNull ); Assert( pcsr->ibSon == ibSonNull ); Assert( pcsr->isrid == isridNull ); Assert( pcsr->pcsrPath == NULL ); *ppcsr = pcsr; return JET_errSuccess; } //+api // ErrFUCBNewCSR // ======================================================================== // ERR ErrFUCBNewCSR( FUCB *pfucb ) // // Insert a null csr in the bottom of path of pfucb. // // PARAMETERS pfucb // // RETURNS JET_errOutOfMemory //- ERR ErrFUCBNewCSR( FUCB *pfucb ) { ERR err; CSR **ppcsr; CSR *pcsr; CallR( ErrFUCBAllocCSR( &pcsr ) ); ppcsr = &PcsrCurrent( pfucb ); pcsr->pcsrPath = *ppcsr; *ppcsr = pcsr; return JET_errSuccess; } //+api // FUCBFreeCSR // ======================================================================== // VOID FUCBFreeCSR( FUCB *pfucb ) // // Delete the csr in the bottom of path of pfucb. // // PARAMETERS pfucb // RETURNS JET_errOutOfMemory //- VOID FUCBFreeCSR( FUCB *pfucb ) { CSR **ppcsr = &PcsrCurrent( pfucb ); CSR *pcsr; *ppcsr = ( pcsr = *ppcsr )->pcsrPath; MEMReleasePcsr( pcsr ); return; } //+api // FUCBFreePath // ======================================================================== // VOID FUCBFreePath( CSR **ppcsr, CSR *pcsrMark ) // // Delete all the csr in the current path of pfucb. // // PARAMETERS pfucb // // RETURNS JET_errOutOfMemory //- VOID FUCBFreePath( CSR **ppcsr, CSR *pcsrMark ) { while ( *ppcsr != pcsrMark ) { CSR *pcsrTmp = *ppcsr; *ppcsr = pcsrTmp->pcsrPath; MEMReleasePcsr( pcsrTmp ); } return; } //+api // ErrFUCBOpen // ------------------------------------------------------------------------ // ERR ErrFUCBOpen( PIB *ppib, DBID dbid, FUCB **ppfucb ); // // Creates an open FUCB. At this point, no FCB is assigned yet. // // PARAMETERS ppib PIB of this user // dbid Database Id. // ppfucb Address of pointer to FUCB. If *ppfucb == NULL, // an FUCB is allocated and **ppfucb is set to its // address. Otherwise, *ppfucb is assumed to be // pointing at a closed FUCB, to be reused in the open. // // RETURNS JET_errSuccess if successful. // JET_errNoMoreCursors // ErrFUCBNewCSR: JET_errOutOfMemory. // // SIDE EFFECTS links the newly opened FUCB into the chain of open FUCBs // for this session. // // SEE ALSO ErrFUCBClose //- ERR ErrFUCBOpen( PIB *ppib, DBID dbid, FUCB **ppfucb ) { ERR err; FUCB *pfucb; /* if no fucb allocate new fucb and initialize it /* and allocate csr /* pib must be set before call to NewCSR /**/ pfucb = PfucbMEMAlloc( ); if ( pfucb == pfucbNil ) { err = JET_errNoMoreCursors; return err; } /* memset implicitly clears pointer cache /**/ Assert( pfucb->pfucbNext == (FUCB *)0xffffffff ); memset( (BYTE *)pfucb, '\0', sizeof( FUCB ) ); if ( FDBIDReadOnly( dbid ) ) FUCBResetUpdatable( pfucb ); else FUCBSetUpdatable( pfucb ); pfucb->dbid = dbid; SSIBSetDbid( &pfucb->ssib, dbid ); pfucb->ssib.pbf = PbfBFMostUsed(); pfucb->pbfEmpty = pbfNil; // set ppib before set NewCSR pfucb->ppib = ppib; pfucb->ssib.ppib = ppib; /* allocate a CSR for this fucb /**/ Call( ErrFUCBNewCSR( pfucb ) ); pfucb->levelOpen = ppib->level; /* link new FUCB into user chain, only when success is sure /* as unlinking NOT handled in error /**/ if ( *ppfucb == pfucbNil ) { *ppfucb = pfucb; // link the fucb now pfucb->pfucbNext = ( FUCB * )ppib->pfucb; ppib->pfucb = pfucb; return JET_errSuccess; } pfucb->pfucbCurIndex = pfucbNil; return JET_errSuccess; HandleError: MEMReleasePfucb( pfucb ); return err; } //+api // FUCBClose // ------------------------------------------------------------------------ // FUCBClose( FUCB *pfucb ) // // Closes an active FUCB, optionally returning it to the free FUCB pool. // All the pfucb->pcsr are freed. // // PARAMETERS pfucb FUCB to close. Should be open. pfucb->ssib should // hold no page. // // SIDE EFFECTS Unlinks the closed FUCB from the FUCB chain of its // associated PIB and FCB. // // SEE ALSO ErrFUCBOpen //- VOID FUCBClose( FUCB *pfucb ) { FUCB *pfucbPrev; FUCBFreePath( &PcsrCurrent( pfucb ), pcsrNil ); /* locate the pfucb in this thread and take it out of the fucb list /**/ pfucbPrev = (FUCB *)( (BYTE *)&pfucb->ppib->pfucb - (BYTE *)&( (FUCB *)0 )->pfucbNext ); while ( pfucbPrev->pfucbNext != pfucb ) { pfucbPrev = pfucbPrev->pfucbNext; Assert( pfucbPrev != pfucbNil ); } pfucbPrev->pfucbNext = pfucb->pfucbNext; /* set ppibNil to detect bogus reusage. /**/ #ifdef DEBUG pfucb->ppib = ppibNil; #endif /* release key buffer if one was allocated. /**/ if ( pfucb->pbKey != NULL ) { LFree( pfucb->pbKey ); pfucb->pbKey = NULL; } Assert( pfucb->pbfEmpty == pbfNil ); /* release the fucb /**/ MEMReleasePfucb( pfucb ); return; } VOID FUCBRemoveInvisible( CSR **ppcsr ) { CSR *pcsr; CSR *pcsrPrev; Assert( ppcsr && *ppcsr ); if ( (*ppcsr)->itag == itagNil) { CSR *pcsrT = *ppcsr; *ppcsr = (*ppcsr)->pcsrPath; MEMReleasePcsr( pcsrT ); } pcsrPrev = *ppcsr; pcsr = pcsrPrev->pcsrPath; while ( pcsr ) { if ( FCSRInvisible( pcsr ) ) { CSR *pcsrT = pcsrPrev->pcsrPath; pcsr = pcsrPrev->pcsrPath = pcsr->pcsrPath; MEMReleasePcsr( pcsrT ); } else { Assert( pcsr->itag != itagNil ); pcsrPrev = pcsr; pcsr = pcsr->pcsrPath; } } return; } VOID FUCBSetIndexRange( FUCB *pfucb, JET_GRBIT grbit ) { /* set limstat /**/ FUCBSetLimstat( pfucb ); if ( grbit & JET_bitRangeUpperLimit ) { FUCBSetUpper( pfucb ); } else { FUCBResetUpper( pfucb ); } if ( grbit & JET_bitRangeInclusive ) { FUCBSetInclusive( pfucb ); } else { FUCBResetInclusive( pfucb ); } return; } VOID FUCBResetIndexRange( FUCB *pfucb ) { FUCBResetLimstat( pfucb ); } ERR ErrFUCBCheckIndexRange( FUCB *pfucb ) { ERR err = JET_errSuccess; KEY keyLimit; INT cmp; Assert( pfucb->cbKey > 0 ); keyLimit.pb = pfucb->pbKey + 1; keyLimit.cb = pfucb->cbKey - 1; cmp = CmpPartialKeyKey( &pfucb->keyNode, &keyLimit ); if ( FFUCBUpper( pfucb ) ) { if ( FFUCBInclusive( pfucb ) && cmp > 0 || !FFUCBInclusive( pfucb ) && cmp >= 0 ) { PcsrCurrent( pfucb )->csrstat = csrstatAfterLast; FUCBResetLimstat( pfucb ); err = JET_errNoCurrentRecord; } } else { if ( FFUCBInclusive( pfucb ) && cmp < 0 || !FFUCBInclusive( pfucb ) && cmp <= 0 ) { PcsrCurrent( pfucb )->csrstat = csrstatBeforeFirst; FUCBResetLimstat( pfucb ); err = JET_errNoCurrentRecord; } } return err; }