|
|
#include "config.h"
#include <string.h>
#include "daedef.h"
#include "pib.h"
#include "util.h"
#include "fmp.h"
#include "page.h"
#include "ssib.h"
#include "fucb.h"
#include "fcb.h"
#include "stapi.h"
#include "fdb.h"
#include "idb.h"
#include "fileint.h"
#include "recint.h"
#include "logapi.h"
#include "nver.h"
#include "dirapi.h"
#include "recapi.h"
#include "fileapi.h"
#include "dbapi.h"
#include "systab.h"
#include "bm.h"
DeclAssertFile; /* Declare file name for assert macros */
#ifdef DEBUG
//#define TRACE
#endif
//+API
// ErrIsamDeleteTable
// ========================================================================
// ERR ErrIsamDeleteTable( PIB *ppib, ULONG_PTR vdbid, CHAR *szName )
//
// Calls ErrFILEIDeleteTable to
// delete a file and all indexes associated with it.
//
// RETURNS JET_errSuccess or err from called routine.
//
// SEE ALSO ErrIsamCreateTable
//-
ERR VTAPI ErrIsamDeleteTable( PIB *ppib, ULONG_PTR vdbid, CHAR *szName ) { ERR err; DBID dbid = DbidOfVDbid (vdbid); CHAR szTable[(JET_cbNameMost + 1)]; OBJID objid; JET_OBJTYP objtyp;
/* ensure that database is updatable
/**/ CallR( VDbidCheckUpdatable( vdbid ) );
CheckPIB( ppib ); CheckDBID( ppib, dbid ); CallR( ErrCheckName( szTable, szName, (JET_cbNameMost + 1) ) ); #ifdef SYSTABLES
if ( FSysTabDatabase( dbid ) ) { err = ErrFindObjidFromIdName( ppib, dbid, objidTblContainer, szTable, &objid, &objtyp ); if ( err < 0 ) { return err; } else { if ( objtyp == JET_objtypQuery || objtyp == JET_objtypLink || objtyp == JET_objtypSQLLink ) { err = ErrIsamDeleteObject( (JET_SESID)ppib, vdbid, objid ); return err; } } } #endif /* SYSTABLES */
err = ErrFILEDeleteTable( ppib, dbid, szName ); return err; }
// ErrFILEDeleteTable
// ========================================================================
// ERR ErrFILEDeleteTable( PIB *ppib, DBID dbid, CHAR *szName )
//
// Deletes a file and all indexes associated with it.
//
// RETURNS JET_errSuccess or err from called routine.
//
// COMMENTS
// Acquires an exclusive lock on the file [FCBSetDelete].
// A transaction is wrapped around this function. Thus,
// any work done will be undone if a failure occurs.
// Transaction logging is turned off for temporary files.
//
// SEE ALSO ErrIsamCreateTable
//-
ERR ErrFILEDeleteTable( PIB *ppib, DBID dbid, CHAR *szTable ) { ERR err; FUCB *pfucb = pfucbNil; PGNO pgnoFDP; BOOL fSetDomainOperation = fFalse; FCB *pfcb; FCB *pfcbT;
CheckPIB( ppib ); CheckDBID( ppib, dbid );
CallR( ErrDIRBeginTransaction( ppib ) );
/* open cursor on database
/**/ Call( ErrDIROpen( ppib, pfcbNil, dbid, &pfucb ) );
/* seek to table without locking
/**/ Call( ErrFILESeek( pfucb, szTable ) ); Assert( ppib != ppibNil ); Assert( ppib->level < levelMax ); Assert( PcsrCurrent( pfucb ) != pcsrNil ); Assert( PcsrCurrent( pfucb )->csrstat == csrstatOnFDPNode ); pgnoFDP = PcsrCurrent( pfucb )->pgno;
/* abort if index is being built on file
/**/ if ( FFCBDenyDDL( pfucb->u.pfcb, ppib ) ) { err = JET_errWriteConflict; goto HandleError; }
/* get table FCB or sentinel FCB
/**/ pfcb = PfcbFCBGet( dbid, pgnoFDP ); /* wait for other domain operation
/**/ while ( pfcb != pfcbNil && FFCBDomainOperation( pfcb ) ) { BFSleep( cmsecWaitGeneric ); pfcb = PfcbFCBGet( dbid, pgnoFDP ); } if ( pfcb != pfcbNil ) { FCBSetDomainOperation( pfcb ); fSetDomainOperation = fTrue; }
/* handle error for above call
/**/ Call( ErrFCBSetDeleteTable( ppib, dbid, pgnoFDP ) ); if ( pfcb == pfcbNil ) { pfcb = PfcbFCBGet( dbid, pgnoFDP ); Assert( pfcb != pfcbNil ); }
FCBSetDenyDDL( pfucb->u.pfcb, ppib ); err = ErrVERFlag( pfucb, operDeleteTable, &pgnoFDP, sizeof(pgnoFDP) ); if ( err < 0 ) { FCBResetDenyDDL( pfucb->u.pfcb ); FCBResetDeleteTable( dbid, pgnoFDP ); goto HandleError; }
/* delete table FDP pointer node. This will recursively delete
/* table and free table space. Note that table space is defer
/* freed until commit to transaction level 0. This is done to
/* facillitate rollback.
/**/ Call( ErrDIRDelete( pfucb, fDIRVersion ) );
/* remove MPL entries for this table and all indexes
/**/ Assert( pfcb->pgnoFDP == pgnoFDP ); for ( pfcbT = pfcb; pfcbT != pfcbNil; pfcbT = pfcbT->pfcbNextIndex ) { Assert( dbid == pfcbT->dbid ); MPLPurgeFDP( dbid, pfcbT->pgnoFDP ); FCBSetDeletePending( pfcbT ); } DIRClose( pfucb ); pfucb = pfucbNil;
#ifdef SYSTABLES
/* remove table record from MSysObjects before committing.
/* Also remove associated columns and indexes in MSC/MSI.
/* Pass 0 for tblid; MSO case in STD figures it out.
/**/ if ( dbid != dbidTemp ) { Call( ErrSysTabDelete( ppib, dbid, itableSo, szTable, 0 ) ); } #endif /* SYSTABLES */
#ifdef TRACE
FPrintF2( "delete table at %d.%lu\n", pfcb->dbid, pfcb->pgnoFDP ); #endif
if ( fSetDomainOperation ) FCBResetDomainOperation( pfcb ); Call( ErrDIRCommitTransaction( ppib ) ); return err;
HandleError: if ( fSetDomainOperation ) FCBResetDomainOperation( pfcb ); if ( pfucb != pfucbNil ) DIRClose( pfucb ); CallS( ErrDIRRollback( ppib ) ); return err; }
//+API
// DeleteIndex
// ========================================================================
// ERR DeleteIndex( PIB *ppib, FUCB *pfucb, CHAR *szIndex )
//
// Deletes an index definition and all index entries it contains.
//
// PARAMETERS ppib PIB of user
// pfucb Exclusively opened FUCB on file
// szName name of index to delete
// RETURNS Error code from DIRMAN or
// JET_errSuccess Everything worked OK.
// -TableInvalid There is no file corresponding
// to the file name given.
// -TableNoSuchIndex There is no index corresponding
// to the index name given.
// -IndexMustStay The clustered index of a file may
// not be deleted.
// COMMENTS
// There must not be anyone currently using the file.
// A transaction is wrapped around this function. Thus,
// any work done will be undone if a failure occurs.
// Transaction logging is turned off for temporary files.
// SEE ALSO DeleteTable, CreateTable, CreateIndex
//-
ERR VTAPI ErrIsamDeleteIndex( PIB *ppib, FUCB *pfucb, CHAR *szName ) { ERR err; CHAR szIndex[ (JET_cbNameMost + 1) ]; BYTE rgbIndexNorm[ JET_cbKeyMost ]; DIB dib; KEY key; FCB *pfcb; FCB *pfcbIdx;
CheckPIB( ppib ); CheckTable( ppib, pfucb ); CallR( ErrCheckName( szIndex, szName, ( JET_cbNameMost + 1 ) ) );
/* ensure that table is updatable
/**/ CallR( FUCBCheckUpdatable( pfucb ) );
Assert( ppib != ppibNil ); Assert( pfucb != pfucbNil ); Assert( pfucb->u.pfcb != pfcbNil ); pfcb = pfucb->u.pfcb;
/* wait for other domain operation
/**/ while ( FFCBDomainOperation( pfcb ) ) { BFSleep( cmsecWaitGeneric ); } FCBSetDomainOperation( pfcb );
/* normalize index and set key to normalized index
/**/ SysNormText( szIndex, strlen( szIndex ), rgbIndexNorm, sizeof( rgbIndexNorm ), &key.cb ); key.pb = rgbIndexNorm;
err = ErrDIRBeginTransaction( ppib ); if ( err < 0 ) { FCBResetDomainOperation( pfcb ); return err; }
/* move to FDP root
/**/ DIRGotoFDPRoot( pfucb );
/* down to indexes, check against clustered index name
/**/ dib.pos = posDown; dib.pkey = (KEY *)pkeyIndexes; dib.fFlags = fDIRNull; Call( ErrDIRDown( pfucb, &dib ) ); if ( pfucb->lineData.cb != 0 && pfucb->lineData.cb == key.cb && memcmp( pfucb->lineData.pb, rgbIndexNorm, pfucb->lineData.cb ) == 0 ) { err = JET_errIndexMustStay; goto HandleError; }
/* down to index node
/**/ Assert( dib.pos == posDown ); dib.pkey = &key; Assert( dib.fFlags == fDIRNull ); Call( ErrDIRDown( pfucb, &dib ) ); if ( err == wrnNDFoundLess || err == wrnNDFoundGreater ) { err = JET_errIndexNotFound; goto HandleError; }
/* abort if DDL is being done on file
/**/ if ( FFCBDenyDDL( pfcb, ppib ) ) { err = JET_errWriteConflict; goto HandleError; } FCBSetDenyDDL( pfcb, ppib ); /* flag delete index
/**/ pfcbIdx = PfcbFCBFromIndexName( pfcb, szIndex ); if ( pfcbIdx == NULL ) { // NOTE: This case goes away when the data structures
// are versioned also.
// This case means basically, that another session
// has changed this index BUT has not committed to level 0
// BUT has changed the RAM data structures.
FCBResetDenyDDL( pfcb ); err = JET_errWriteConflict; goto HandleError; }
err = ErrFCBSetDeleteIndex( ppib, pfcb, szIndex ); if ( err < 0 ) { FCBResetDenyDDL( pfcb ); goto HandleError; } err = ErrVERFlag( pfucb, operDeleteIndex, &pfcbIdx, sizeof(pfcbIdx) ); if ( err < 0 ) { FCBResetDeleteIndex( pfcbIdx ); FCBResetDenyDDL( pfcb ); goto HandleError; }
/* purge MPL entries -- must be done after FCBSetDeletePending
/**/ MPLPurgeFDP( pfucb->dbid, pfcbIdx->pgnoFDP ); /* assert not deleting current non-clustered index
/**/ Assert( pfucb->pfucbCurIndex == pfucbNil || SysCmpText( szIndex, pfucb->pfucbCurIndex->u.pfcb->pidb->szName ) != 0 );
/* delete index node
/**/ Call( ErrDIRDelete( pfucb, fDIRVersion ) );
/* back up to file node
/**/ DIRUp( pfucb, 2 );
/* update index count and DDL time stamp
/**/ Call( ErrFILEIUpdateFDPData( pfucb, fDropIndexCount | fDDLStamp ) );
#ifdef SYSTABLES
/* remove index record from MSysIndexes before committing...
/**/ if ( FSysTabDatabase( pfucb->dbid ) ) { Call( ErrSysTabDelete( ppib, pfucb->dbid, itableSi, szIndex, pfucb->u.pfcb->pgnoFDP ) ); } #endif /* SYSTABLES */
Call( ErrDIRCommitTransaction( ppib ) );
/* set currency to before first
/**/ DIRBeforeFirst( pfucb ); #ifdef TRACE
FPrintF2( "delete index at %d.%lu\n", pfcbIdx->dbid, pfcbIdx->pgnoFDP ); #endif
FCBResetDomainOperation( pfcb ); return JET_errSuccess;
HandleError: CallS( ErrDIRRollback( ppib ) ); FCBResetDomainOperation( pfcb ); return err; }
ERR VTAPI ErrIsamDeleteColumn( PIB *ppib, FUCB *pfucb, CHAR *szName ) { ERR err; DIB dib; INT iidxseg; KEY key; CHAR szColumn[ (JET_cbNameMost + 1) ]; BYTE rgbColumnNorm[ JET_cbKeyMost ]; FCB *pfcb; LINE lineField; FIELDDEFDATA fdd; FCB *pfcbIndex;
CheckPIB( ppib ); CheckTable( ppib, pfucb ); CallR( ErrCheckName( szColumn, szName, (JET_cbNameMost + 1) ) );
/* ensure that table is updatable
/**/ CallR( FUCBCheckUpdatable( pfucb ) );
Assert( ppib != ppibNil ); Assert( pfucb != pfucbNil ); Assert( pfucb->u.pfcb != pfcbNil ); pfcb = pfucb->u.pfcb; // if ( !( FFCBDenyReadByUs( pfcb, ppib ) ) )
// return JET_errTableNotLocked;
/* normalize column name and set key
/**/ SysNormText( szColumn, strlen( szColumn ), rgbColumnNorm, sizeof( rgbColumnNorm ), &key.cb ); key.pb = rgbColumnNorm;
CallR( ErrDIRBeginTransaction( ppib ) );
/* abort if DDL is being done on file
/**/ if ( FFCBDenyDDL( pfcb, ppib ) ) { err = JET_errWriteConflict; goto HandleError; } FCBSetDenyDDL( pfcb, ppib ); err = ErrVERFlag( pfucb, operDeleteColumn, (VOID *)&pfcb->pfdb, sizeof(pfcb->pfdb) ); if ( err < 0 ) { FCBResetDenyDDL( pfcb ); } /* move to FDP root and update FDP timestamp
/**/ DIRGotoFDPRoot( pfucb ); Call( ErrFILEIUpdateFDPData( pfucb, fDDLStamp ) );
/* down to fields\rgbColumnNorm to find field id (and verify existance)
/**/ dib.pos = posDown; dib.pkey = (KEY *)pkeyFields; dib.fFlags = fDIRNull; Call( ErrDIRDown( pfucb, &dib ) ); dib.pkey = &key; err = ErrDIRDown( pfucb, &dib ); if ( err != JET_errSuccess ) { err = JET_errColumnNotFound; goto HandleError; } fdd = *(FIELDDEFDATA *)pfucb->lineData.pb;
/* search for column in use in indexes
/**/ for ( pfcbIndex = pfucb->u.pfcb; pfcbIndex != pfcbNil; pfcbIndex = pfcbIndex->pfcbNextIndex ) { if ( pfcbIndex->pidb != NULL ) { for ( iidxseg = 0; iidxseg < pfcbIndex->pidb->iidxsegMac; iidxseg++ ) { if ( pfcbIndex->pidb->rgidxseg[iidxseg] < 0 ) { if ( (FID)( -pfcbIndex->pidb->rgidxseg[iidxseg] ) == fdd.fid ) Call( JET_errColumnInUse ); } else { if ( (FID)pfcbIndex->pidb->rgidxseg[iidxseg] == fdd.fid ) Call( JET_errColumnInUse ); } } } }
Call( ErrDIRDelete( pfucb, fDIRVersion ) );
/* if fixed field, insert a placeholder for computing offsets
/**/ if ( fdd.fid <= fidFixedMost ) { BYTE bSav = *rgbColumnNorm;
fdd.bFlags = ffieldDeleted; // flag deleted fixed field
fdd.cbDefault = 0; // get rid of the default value
*rgbColumnNorm = ' '; // clobber the key
key.cb = 1; // (any value will work)
lineField.pb = (BYTE *)&fdd; // point to the field definition
lineField.cb = sizeof(fdd);
/* up to the FIELDS node
/**/ DIRUp( pfucb, 1 ); Call( ErrDIRInsert(pfucb, &lineField, &key, fDIRVersion | fDIRDuplicate ) ); *rgbColumnNorm = bSav; }
/* up to "FIELDS" node
/**/ DIRUp( pfucb, 1 );
/* rebuild FDB and default record value
/**/ Call( ErrDIRGet( pfucb ) ); Call( ErrFDBConstruct(pfucb, pfcb, fTrue /*fBuildDefault*/ ) );
/* set currencies at BeforeFirst and remove unused CSR
/**/ DIRUp( pfucb, 1 ); Assert( PcsrCurrent( pfucb ) != pcsrNil ); PcsrCurrent( pfucb )->csrstat = csrstatBeforeFirst; if ( pfucb->pfucbCurIndex != pfucbNil ) { Assert( PcsrCurrent( pfucb->pfucbCurIndex ) != pcsrNil ); PcsrCurrent( pfucb->pfucbCurIndex )->csrstat = csrstatBeforeFirst; }
#ifdef SYSTABLES
/* remove column record from MSysColumns before committing...
/**/ if ( FSysTabDatabase( pfucb->dbid ) ) { Call( ErrSysTabDelete( ppib, pfucb->dbid, itableSc, szColumn, pfucb->u.pfcb->pgnoFDP ) ); } #endif /* SYSTABLES */
Call( ErrDIRCommitTransaction( ppib ) );
return JET_errSuccess;
HandleError: CallS( ErrDIRRollback( ppib ) ); return err; }
|