You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
560 lines
14 KiB
560 lines
14 KiB
#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;
|
|
}
|
|
|
|
|
|
|