#include "config.h" #include #include "daedef.h" #include "pib.h" #include "util.h" #include "fmp.h" #include "ssib.h" #include "page.h" #include "fucb.h" #include "fcb.h" #include "stapi.h" #include "fdb.h" #include "idb.h" #include "nver.h" #include "dirapi.h" #include "logapi.h" #include "recapi.h" #include "spaceapi.h" #include "recint.h" DeclAssertFile; /* Declare file name for assert macros */ /**************************** INTERNAL STUFF ***************************/ typedef struct DFIPB { /*** DeleteFromIndexParameterBlock ***/ FUCB *pfucb; FUCB *pfucbIdx; // index's FUCB (can be pfucbNil) LINE lineRecord; // deleted data record SRID sridRecord; // SRID of deleted record BOOL fFreeFUCB; // free index FUCB? } DFIPB; ERR ErrRECIDeleteFromIndex( FCB *pfcbIdx, DFIPB *pdfipb ); //+API // ErrIsamDelete // ======================================================================== // ErrIsamDelete(ppib, pfucb) // PIB *ppib; // IN PIB of this user // FUCB *pfucb; // INOUT FUCB for file to delete from // Deletes the current record from data file. All indexes on the data // file are updated to reflect the deletion. // // PARAMETERS // ppib PIB of this user // pfucb FUCB for file to delete from // RETURNS // Error code, one of the following: // JET_errSuccess Everything went OK. // -NoCurrentRecord There is no current record // to delete. // SIDE EFFECTS // After the deletion, file currency is left just before // the next record. Index currency (if any) is left just // before the next index entry. If the deleted record was // the last in the file, the currencies are left after the // new last record. If the deleted record was the only record // in the entire file, the currencies are left in the // "beginning of file" state. On failure, the currencies are // returned to their initial states. // If there is a working buffer for SetField commands, // it is discarded. // COMMENTS // If the currencies are not ON a record, the delete will fail. // A transaction is wrapped around this function. Thus, any // work done will be undone if a failure occurs. // Index entries are not made for entirely-null keys. // For temporary files, transaction logging is deactivated // for the duration of the routine. //- ERR VTAPI ErrIsamDelete( PIB *ppib, FUCB *pfucb ) { ERR err; FCB *pfcbFile; // file's FCB FCB *pfcbIdx; // loop variable for each index on file DFIPB dfipb; // parameter to ErrRECIDeleteFromIndex CheckPIB( ppib ); CheckTable( ppib, pfucb ); CheckNonClustered( pfucb ); /* ensure that table is updatable /**/ CallR( FUCBCheckUpdatable( pfucb ) ); /* reset copy buffer status on record delete /**/ if ( FFUCBUpdatePrepared( pfucb ) ) { CallR( ErrIsamPrepareUpdate( ppib, pfucb, JET_prepCancel ) ); } /* efficiency variables /**/ pfcbFile = pfucb->u.pfcb; Assert( pfcbFile != pfcbNil ); CallR( ErrDIRBeginTransaction( ppib ) ); /* abort if index is being built on file /**/ if ( FFCBDenyDDL( pfcbFile, ppib ) ) { err = JET_errWriteConflict; goto HandleError; } /* refresh currency since pfucb->lineData may be invalid /**/ Call( ErrDIRGet( pfucb ) ); /* allocate working buffer if needed /**/ if ( pfucb->pbfWorkBuf == NULL ) { Call( ErrBFAllocTempBuffer( &pfucb->pbfWorkBuf ) ); } pfucb->lineWorkBuf.pb = (BYTE *)pfucb->pbfWorkBuf->ppage; Assert( pfucb->pbfWorkBuf != pbfNil ); /* copy record to be deleted into copy buffer /**/ LineCopy( &pfucb->lineWorkBuf, &pfucb->lineData ); /* cache record pointer for delete index and /* delete long value operations. /**/ dfipb.lineRecord = pfucb->lineWorkBuf; /* get SRID of record being deleted for updating indexes /**/ Assert( ppib->level < levelMax ); Assert( PcsrCurrent( pfucb ) != pcsrNil ); DIRGetBookmark( pfucb, &dfipb.sridRecord ); /* delete record /**/ Call( ErrDIRDelete( pfucb, fDIRVersion ) ); /* delete from non-clustered indexes /**/ dfipb.pfucb = pfucb; dfipb.fFreeFUCB = fFalse; for( pfcbIdx = pfcbFile->pfcbNextIndex; pfcbIdx != pfcbNil; pfcbIdx = pfcbIdx->pfcbNextIndex ) { dfipb.fFreeFUCB = pfcbIdx->pfcbNextIndex == pfcbNil; Call( ErrRECIDeleteFromIndex( pfcbIdx, &dfipb ) ); } // UNDONE: optimize record deletion by detecting presence of long values // on table basis. /* delete record long values /**/ Call( ErrRECAffectLongFields( pfucb, &dfipb.lineRecord, fDereference ) ); /* commit transaction if we started it and everything went OK /**/ Call( ErrDIRCommitTransaction( ppib ) ); return err; HandleError: /* if operation failed then rollback changes. /**/ Assert( err < 0 ); CallS( ErrDIRRollback( ppib ) ); return err; } //+INTERNAL // ErrRECIDeleteFromIndex // ======================================================================== // ErrRECIDeleteFromIndex( FCB *pfcbIdx, DFIPB *pdfipb ) // // Extracts key from data record, opens the index, deletes the key with // the given SRID, and closes the index. // // PARAMETERS // pfcbIdx FCB of index to delete from // pdfipb->ppib who is calling this routine // pdfipb->pfucbIdx pointer to index's FUCB. // pdfipb->lineRecord.cb length of deleted record // pdfipb->lineRecord.pb deleted record to extract key from // pdfipb->sridRecord SRID of deleted record // pdfipb->fFreeFUCB free index FUCB? // RETURNS // JET_errSuccess, or error code from failing routine // SIDE EFFECTS // If fFreeFUCB is fFalse, patipb->pfucbIdx should // be used in a subsequent ErrDIROpen. // SEE ALSO ErrRECDelete //- ERR ErrRECIDeleteFromIndex( FCB *pfcbIdx, DFIPB *pdfipb ) { ERR err; // error code of various utility KEY keyDead; // key extracted from old data record BYTE rgbDeadKeyBuf[ JET_cbKeyMost ]; // buffer for keyDead ULONG itagSequence; // used to extract keys BOOL fHasMultivalue; // index key has a tagged field? Assert( pfcbIdx != pfcbNil ); Assert( pfcbIdx->pfdb != pfdbNil ); Assert( pfcbIdx->pidb != pidbNil ); Assert( pdfipb != NULL ); Assert( !FLineNull( &pdfipb->lineRecord ) ); Assert( pdfipb->pfucb != pfucbNil ); /* open FUCB on this index /**/ CallR( ErrDIROpen( pdfipb->pfucb->ppib, pfcbIdx, 0, &pdfipb->pfucbIdx ) ); Assert( pdfipb->pfucbIdx != pfucbNil ); FUCBSetIndex( pdfipb->pfucbIdx ); FUCBSetNonClustered( pdfipb->pfucbIdx ); /* delete all keys from this index for dying data record /**/ fHasMultivalue = pfcbIdx->pidb->fidb & fidbHasMultivalue; keyDead.pb = rgbDeadKeyBuf; for ( itagSequence = 1; ; itagSequence++ ) { // Call( ErrDIRGet( pdfipb->pfucb ) ); // pdfipb->lineRecord = pdfipb->pfucb->lineData; Call( ErrRECExtractKey( pdfipb->pfucb, (FDB *)pfcbIdx->pfdb, pfcbIdx->pidb, &pdfipb->lineRecord, &keyDead, itagSequence ) ); Assert( err == wrnFLDNullKey || err == wrnFLDOutOfKeys || err == wrnFLDNullSeg || err == JET_errSuccess ); if ( err == wrnFLDOutOfKeys ) { Assert( itagSequence > 1 ); break; } /* record must honor index no NULL segment requirements /**/ Assert( !( pfcbIdx->pidb->fidb & fidbNoNullSeg ) || ( err != wrnFLDNullSeg && err != wrnFLDNullKey ) ); if ( err == wrnFLDNullKey ) { if ( pfcbIdx->pidb->fidb & fidbAllowAllNulls ) { /* move to DATA root and seek to index entry and delete it /**/ DIRGotoDataRoot( pdfipb->pfucbIdx ); Call( ErrDIRDownKeyBookmark( pdfipb->pfucbIdx, &keyDead, pdfipb->sridRecord ) ); Call( ErrDIRDelete( pdfipb->pfucbIdx, fDIRVersion ) ); } break; } else { if ( err == wrnFLDNullSeg && !( pfcbIdx->pidb->fidb & fidbAllowSomeNulls ) ) break; } DIRGotoDataRoot( pdfipb->pfucbIdx ); Call( ErrDIRDownKeyBookmark( pdfipb->pfucbIdx, &keyDead, pdfipb->sridRecord ) ); Call( ErrDIRDelete( pdfipb->pfucbIdx, fDIRVersion ) ); /* dont keep extracting for keys with no tagged segments /**/ if ( !fHasMultivalue ) break; } /* supress warnings /**/ Assert( err == wrnFLDNullKey || err == wrnFLDOutOfKeys || err == wrnFLDNullSeg || err == JET_errSuccess ); err = JET_errSuccess; HandleError: /* close the FUCB /**/ DIRClose( pdfipb->pfucbIdx ); Assert( err < 0 || err == JET_errSuccess ); return err; }