Leaked source code of windows server 2003
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.
 
 
 
 
 
 

798 lines
19 KiB

#include "config.h"
#include <stdlib.h>
#include <string.h>
#include "daedef.h"
#include "util.h"
#include "pib.h"
#include "page.h"
#include "ssib.h"
#include "fmp.h"
#include "fucb.h"
#include "stapi.h"
#include "dirapi.h"
#include "fcb.h"
#include "fdb.h"
#include "idb.h"
#include "scb.h"
#include "recapi.h"
#include "recint.h"
#include "nver.h"
#include "logapi.h"
#include "fileint.h"
#include "sortapi.h"
#include "fileapi.h"
DeclAssertFile; /* Declare file name for assert macros */
CRIT critTempDBName;
static ULONG ulTempNum = 0;
ULONG NEAR
ulTempNameGen()
{ ULONG ulNum;
SgSemRequest(critTempDBName);
ulNum = ulTempNum++;
SgSemRelease(critTempDBName);
return(ulNum);
}
/*=================================================================
ErrIsamSortMaterialize
Description: Converts a SORT file into a temporary file so that it
may be accessed using the normal file access functions.
/* 1. create temporary table
/* 2. use DIR operations to convert SORT data to FILE data
/* 3. fake SORT cursor to be FILE cursor
/* 4. close SORT cursor and return SORT resources
/**/
/*
Parameters: FUCB *pfucbSort pointer to the FUCB for the sort file
Return Value: standard error return
Errors/Warnings:
<List of any errors or warnings, with any specific circumstantial
comments supplied on an as-needed-only basis>
Side Effects:
=================================================================*/
ERR VTAPI
ErrIsamSortMaterialize( PIB *ppib, FUCB *pfucbSort, BOOL fIndex )
{
ERR err;
INT crun;
INT irun;
INT cPages;
RUN *rgrun;
FUCB *pfucbTable = pfucbNil;
FCB *pfcbTable;
FCB *pfcbSort;
FDB *pfdb;
IDB *pidb;
BYTE szName[JET_cbNameMost+1];
CheckPIB( ppib );
CheckSort( ppib, pfucbSort );
Assert( ppib->level < levelMax );
Assert( pfucbSort->ppib == ppib );
Assert( !( FFUCBIndex( pfucbSort ) ) );
/* causes remaining runs to be flushed to disk
/**/
if ( FSCBInsert( pfucbSort->u.pscb ) )
{
CallR( ErrSORTEndRead( pfucbSort ) );
}
CallR( ErrDIRBeginTransaction( ppib ) );
crun = pfucbSort->u.pscb->crun;
if ( crun > 0 )
{
rgrun = pfucbSort->u.pscb->rgrun;
for (irun = 0, cPages=0; irun < crun; irun++)
{
cPages += rgrun[irun].cbfRun;
}
}
else
{
cPages = 4;
}
/* generate temporary file name
/**/
sprintf(szName, "TEMP%lu", ulTempNameGen());
/* create table
/**/
Call( ErrFILECreateTable( ppib, dbidTemp, szName, 16, 100, &pfucbTable ) );
/* move to DATA root
/**/
DIRGotoDataRoot( pfucbTable );
pfcbSort = &(pfucbSort->u.pscb->fcb);
pfcbTable = pfucbTable->u.pfcb;
err = ErrSORTFirst( pfucbSort );
if ( fIndex )
{
while ( err >= 0 )
{
Call( ErrDIRInsert( pfucbTable,
&pfucbSort->lineData,
&pfucbSort->keyNode,
fDIRVersion | fDIRBackToFather ) );
err = ErrSORTNext( pfucbSort );
}
}
else
{
DBK dbk = 0;
BYTE rgbDbk[4];
KEY keyDbk;
keyDbk.cb = sizeof(DBK);
keyDbk.pb = rgbDbk;
while ( err >= 0 )
{
keyDbk.pb[0] = (BYTE)(dbk >> 24);
keyDbk.pb[1] = (BYTE)((dbk >> 16) & 0xff);
keyDbk.pb[2] = (BYTE)((dbk >> 8) & 0xff);
keyDbk.pb[3] = (BYTE)(dbk & 0xff);
dbk++;
Call( ErrDIRInsert( pfucbTable,
&pfucbSort->lineData,
&keyDbk,
fDIRVersion | fDIRBackToFather ) );
err = ErrSORTNext(pfucbSort);
}
pfcbTable->dbkMost = dbk;
}
if ( err < 0 && err != JET_errNoCurrentRecord )
{
goto HandleError;
}
Call( ErrDIRCommitTransaction( ppib ) );
/* convert sort cursor into table cursor by changing flags.
/**/
Assert( pfcbTable->pfcbNextIndex == pfcbNil );
Assert( pfcbTable->dbid == dbidTemp );
pfcbTable->cbDensityFree = 0;
pfcbTable->wFlags = fFCBTemporaryTable | fFCBClusteredIndex;
/* switch sort and table FDP so FDP preserved and ErrFILECloseTable.
/**/
pfdb = (FDB *)pfcbSort->pfdb;
pfcbSort->pfdb = pfcbTable->pfdb;
pfcbTable->pfdb = pfdb;
/* switch sort and table IDB so IDB preserved and ErrFILECloseTable,
/* only if fIndex.
/**/
if ( fIndex )
{
pidb = pfcbSort->pidb;
pfcbSort->pidb = pfcbTable->pidb;
pfcbTable->pidb = pidb;
}
/* convert sort cursor flags to table flags, with fFUCBOrignallySort
/**/
Assert( pfucbSort->dbid == dbidTemp );
Assert( pfucbSort->pfucbCurIndex == pfucbNil );
FUCBSetIndex( pfucbSort );
FUCBResetSort( pfucbSort );
/* release SCB and close table cursor
/**/
SORTClosePscb( pfucbSort->u.pscb );
FCBLink( pfucbSort, pfcbTable );
CallS( ErrFILECloseTable( ppib, pfucbTable ) );
pfucbTable = pfucbNil;
/* move to the first record ignoring error if table empty
/**/
err = ErrIsamMove( ppib, pfucbSort, JET_MoveFirst, 0 );
if ( err < 0 )
{
if ( err != JET_errNoCurrentRecord )
goto HandleError;
}
Assert( err == JET_errSuccess || err == JET_errNoCurrentRecord );
return err;
HandleError:
if ( pfucbTable != pfucbNil )
CallS( ErrFILECloseTable( ppib, pfucbTable ) );
CallS( ErrDIRRollback( ppib ) );
return err;
}
/*=================================================================
ErrIsamMove
Description:
Retrieves the first, last, (nth) next, or (nth) previous
record from the specified file.
Parameters:
PIB *ppib PIB of user
FUCB *pfucb FUCB for file
LONG crow number of rows to move
JET_GRBIT grbit options
Return Value: standard error return
Errors/Warnings:
<List of any errors or warnings, with any specific circumstantial
comments supplied on an as-needed-only basis>
Side Effects:
=================================================================*/
ERR VTAPI ErrIsamMove( PIB *ppib, FUCB *pfucb, LONG crow, JET_GRBIT grbit )
{
ERR err = JET_errSuccess;
FUCB *pfucb2ndIdx; // FUCB for secondary index (if any)
FUCB *pfucbIdx; // FUCB of selected index (pri or sec)
SRID srid; // bookmark of record
DIB dib; // Information block for DirMan
CheckPIB( ppib );
CheckTable( ppib, pfucb );
CheckNonClustered( pfucb );
if ( FFUCBUpdatePrepared( pfucb ) )
{
CallR( ErrIsamPrepareUpdate( ppib, pfucb, JET_prepCancel ) );
}
#ifdef INPAGE
/* check to see if search can cross page boundary
/* and set flag accordingly.
/**/
if ( grbit & JET_bitMoveInPage )
dib.fFlags = fDIRInPage;
else
dib.fFlags = fDIRNull;
#else
Assert( ( grbit & JET_bitMoveInPage ) == 0 );
dib.fFlags = fDIRNull;
#endif
// Get secondary index FUCB if any
pfucb2ndIdx = pfucb->pfucbCurIndex;
if ( pfucb2ndIdx == pfucbNil )
pfucbIdx = pfucb;
else
pfucbIdx = pfucb2ndIdx;
if ( crow == JET_MoveLast )
{
DIRResetIndexRange( pfucb );
dib.pos = posLast;
dib.fFlags |= fDIRPurgeParent;
/* move to DATA root
/**/
DIRGotoDataRoot( pfucbIdx );
err = ErrDIRDown( pfucbIdx, &dib );
}
else if ( crow > 0 )
{
LONG crowT = crow;
if ( ( grbit & JET_bitMoveKeyNE ) != 0 )
dib.fFlags |= fDIRNeighborKey;
// Move forward number of rows given
while ( crowT-- > 0 )
{
err = ErrDIRNext( pfucbIdx, &dib );
if (err < 0)
break;
}
}
else if ( crow == JET_MoveFirst )
{
DIRResetIndexRange( pfucb );
dib.pos = posFirst;
dib.fFlags |= fDIRPurgeParent;
/* move to DATA root
/**/
DIRGotoDataRoot( pfucbIdx );
err = ErrDIRDown( pfucbIdx, &dib );
}
else if ( crow == 0 )
{
err = ErrDIRGet( pfucb );
}
else
{
LONG crowT = crow;
if ( ( grbit & JET_bitMoveKeyNE ) != 0)
dib.fFlags |= fDIRNeighborKey;
while ( crowT++ < 0 )
{
err = ErrDIRPrev( pfucbIdx, &dib );
if ( err < 0 )
break;
}
}
/* if the movement was successful and a non-clustered index is
/* in use, then position clustered index to record.
/**/
if ( err == JET_errSuccess && pfucb2ndIdx != pfucbNil && crow != 0 )
{
Assert( pfucb2ndIdx->lineData.pb != NULL );
Assert( pfucb2ndIdx->lineData.cb >= sizeof(SRID) );
srid = PcsrCurrent( pfucb2ndIdx )->item;
DIRDeferGotoBookmark( pfucb, srid );
Assert( PgnoOfSrid( srid ) != pgnoNull );
}
if ( err == JET_errSuccess )
return err;
if ( err == JET_errPageBoundary )
return JET_errNoCurrentRecord;
if ( crow > 0 )
{
PcsrCurrent(pfucbIdx)->csrstat = csrstatAfterLast;
PcsrCurrent(pfucb)->csrstat = csrstatAfterLast;
}
else if ( crow < 0 )
{
PcsrCurrent(pfucbIdx)->csrstat = csrstatBeforeFirst;
PcsrCurrent(pfucb)->csrstat = csrstatBeforeFirst;
}
switch ( err )
{
case JET_errRecordNotFound:
err = JET_errNoCurrentRecord;
case JET_errNoCurrentRecord:
case JET_errRecordDeleted:
break;
default:
PcsrCurrent( pfucbIdx )->csrstat = csrstatBeforeFirst;
if ( pfucb2ndIdx != pfucbNil )
PcsrCurrent( pfucb2ndIdx )->csrstat = csrstatBeforeFirst;
}
return err;
}
/*=================================================================
ErrIsamSeek
Description:
Retrieve the record specified by the given key or the
one just after it (SeekGT or SeekGE) or the one just
before it (SeekLT or SeekLE).
Parameters:
PIB *ppib PIB of user
FUCB *pfucb FUCB for file
JET_GRBIT grbit grbit
Return Value: standard error return
Errors/Warnings:
<List of any errors or warnings, with any specific circumstantial
comments supplied on an as-needed-only basis>
Side Effects:
=================================================================*/
ERR VTAPI ErrIsamSeek( PIB *ppib, FUCB *pfucb, JET_GRBIT grbit )
{
ERR err = JET_errSuccess;
KEY key; // key
KEY *pkey = &key; // pointer to the input key
FUCB *pfucb2ndIdx; // pointer to index FUCB (if any)
BOOL fFoundLess;
SRID srid; // bookmark of record
JET_GRBIT grbitMove = 0;
CheckPIB( ppib );
CheckTable( ppib, pfucb );
CheckNonClustered( pfucb );
if ( ! ( FKSPrepared( pfucb ) ) )
{
return(JET_errKeyNotMade);
}
/* Reset copy buffer status
/**/
if ( FFUCBUpdatePrepared( pfucb ) )
{
CallR( ErrIsamPrepareUpdate( ppib, pfucb, JET_prepCancel ) );
}
/* reset index range limit
/**/
DIRResetIndexRange( pfucb );
/* ignore segment counter
/**/
pkey->pb = pfucb->pbKey + 1;
pkey->cb = pfucb->cbKey - 1;
pfucb2ndIdx = pfucb->pfucbCurIndex;
if ( pfucb2ndIdx == pfucbNil )
{
err = ErrDIRDownFromDATA( pfucb, pkey );
}
else
{
Assert( FFUCBNonClustered( pfucb2ndIdx ) );
err = ErrDIRDownFromDATA( pfucb2ndIdx, pkey );
/* if the movement was successful and a non-clustered index is
/* in use, then position clustered index to record.
/**/
if ( err == JET_errSuccess )
{
Assert(pfucb2ndIdx->lineData.pb != NULL);
Assert(pfucb2ndIdx->lineData.cb >= sizeof(SRID));
srid = PcsrCurrent( pfucb2ndIdx )->item;
DIRDeferGotoBookmark( pfucb, srid );
Assert( PgnoOfSrid( srid ) != pgnoNull );
}
}
if ( err == JET_errSuccess && ( grbit & JET_bitSeekEQ ) != 0 )
{
/* found equal on seek equal. If index range grbit is
/* set then set index range upper inclusive.
/**/
if ( grbit & JET_bitSetIndexRange )
{
CallR( ErrIsamSetIndexRange( ppib, pfucb, JET_bitRangeInclusive | JET_bitRangeUpperLimit ) );
}
/* reset key status.
/**/
KSReset( pfucb );
return err;
}
/* reset key status.
/**/
KSReset( pfucb );
/* remember if found less.
/**/
fFoundLess = ( err == wrnNDFoundLess );
if ( err == wrnNDFoundLess || err == wrnNDFoundGreater )
{
err = JET_errRecordNotFound;
}
else if ( err < 0 )
{
PcsrCurrent( pfucb )->csrstat = csrstatBeforeFirst;
if ( pfucb2ndIdx != pfucbNil )
{
PcsrCurrent( pfucb2ndIdx )->csrstat = csrstatBeforeFirst;
}
}
#define bitSeekAll (JET_bitSeekEQ | JET_bitSeekGE | JET_bitSeekGT | \
JET_bitSeekLE | JET_bitSeekLT)
/* adjust currency for seek request.
/**/
switch ( grbit & bitSeekAll )
{
case JET_bitSeekEQ:
return err;
case JET_bitSeekGE:
if ( err != JET_errRecordNotFound )
return err;
err = ErrIsamMove( ppib, pfucb, +1L, grbitMove );
if ( err == JET_errNoCurrentRecord )
return JET_errRecordNotFound;
else
return JET_wrnSeekNotEqual;
case JET_bitSeekGT:
if ( err < 0 && err != JET_errRecordNotFound )
return err;
if ( err >= 0 || fFoundLess )
grbitMove |= JET_bitMoveKeyNE;
err = ErrIsamMove( ppib, pfucb, +1L, grbitMove );
if ( err == JET_errNoCurrentRecord )
return JET_errRecordNotFound;
else
return err;
case JET_bitSeekLE:
if ( err != JET_errRecordNotFound )
return err;
err = ErrIsamMove( ppib, pfucb, JET_MovePrevious, grbitMove );
if ( err == JET_errNoCurrentRecord )
return JET_errRecordNotFound;
else
return JET_wrnSeekNotEqual;
case JET_bitSeekLT:
if ( err < 0 && err != JET_errRecordNotFound )
return err;
if ( err >= 0 || !fFoundLess )
grbitMove |= JET_bitMoveKeyNE;
err = ErrIsamMove( ppib, pfucb, JET_MovePrevious, grbitMove );
if ( err == JET_errNoCurrentRecord )
return JET_errRecordNotFound;
else
return err;
}
return err;
}
ERR VTAPI
ErrIsamGotoBookmark( PIB *ppib, FUCB *pfucb, BYTE *pbBookmark, ULONG cbBookmark )
{
ERR err;
LINE key;
CheckPIB( ppib );
CheckTable( ppib, pfucb );
Assert( FFUCBIndex( pfucb ) );
CheckNonClustered( pfucb );
if ( cbBookmark != sizeof(SRID) )
return JET_errInvalidBookmark;
Assert( cbBookmark == sizeof(SRID) );
/* reset copy buffer status
/**/
if ( FFUCBUpdatePrepared( pfucb ) )
{
CallR( ErrIsamPrepareUpdate( ppib, pfucb, JET_prepCancel ) );
}
/* reset index range limit
/**/
DIRResetIndexRange( pfucb );
/* get node, and return error if this node is not there for caller.
/**/
DIRGotoBookmark( pfucb, *(SRID *)pbBookmark );
Call( ErrDIRGet( pfucb ) );
/* bookmark must be for node in table cursor is on
/**/
Assert( PgnoPMPgnoFDPOfPage( pfucb->ssib.pbf->ppage ) == pfucb->u.pfcb->pgnoFDP );
/* goto bookmark record build key for secondary index
/* to bookmark record
/**/
if ( pfucb->pfucbCurIndex != pfucbNil )
{
/* get non-clustered index cursor
/**/
FUCB *pfucbIdx = pfucb->pfucbCurIndex;
/* allocate goto bookmark resources
/**/
if ( pfucb->pbKey == NULL )
{
pfucb->pbKey = LAlloc( 1L, JET_cbKeyMost );
if ( pfucb->pbKey == NULL )
return JET_errOutOfMemory;
}
/* make key for record for non-clustered index
/**/
key.pb = pfucb->pbKey;
Call( ErrRECExtractKey( pfucb, (FDB *)pfucb->u.pfcb->pfdb, pfucbIdx->u.pfcb->pidb, &pfucb->lineData, &key, 1 ) );
Assert( err != wrnFLDOutOfKeys );
/* record must honor index no NULL segment requirements
/**/
Assert( !( pfucbIdx->u.pfcb->pidb->fidb & fidbNoNullSeg ) ||
( err != wrnFLDNullSeg && err != wrnFLDNullKey ) );
/* if item is not index,
/* then move before first instead of seeking
/**/
if ( ( err == wrnFLDNullKey && !( pfucbIdx->u.pfcb->pidb->fidb & fidbAllowAllNulls ) ) ||
( err == wrnFLDNullSeg && !( pfucbIdx->u.pfcb->pidb->fidb & fidbAllowSomeNulls ) ) )
{
/* This assumes that NULLs sort low.
/**/
DIRBeforeFirst( pfucbIdx );
err = JET_errNoCurrentRecord;
}
else
{
/* move to DATA root
/**/
DIRGotoDataRoot( pfucbIdx );
/* seek on secondary key
/**/
Call( ErrDIRDownKeyBookmark( pfucbIdx, &key, *(SRID *)pbBookmark ) );
Assert( err == JET_errSuccess );
/* item must be same as bookmark and
/* clustered cursor must be on record.
/**/
Assert( pfucbIdx->lineData.pb != NULL );
Assert( pfucbIdx->lineData.cb >= sizeof(SRID) );
Assert( PcsrCurrent( pfucbIdx )->csrstat == csrstatOnCurNode );
Assert( PcsrCurrent( pfucbIdx )->item == *(SRID *)pbBookmark );
}
}
HandleError:
KSReset( pfucb );
return err;
}
ERR VTAPI
ErrIsamGotoPosition( PIB *ppib, FUCB *pfucb, JET_RECPOS *precpos )
{
ERR err;
FUCB *pfucb2ndIdx;
SRID srid;
CheckPIB( ppib );
CheckTable( ppib, pfucb );
CheckNonClustered( pfucb );
/* Reset copy buffer status
/**/
if ( FFUCBUpdatePrepared( pfucb ) )
{
CallR( ErrIsamPrepareUpdate( ppib, pfucb, JET_prepCancel ) );
}
/* reset index range limit
/**/
DIRResetIndexRange( pfucb );
/* reset key stat
/**/
KSReset( pfucb );
/* set non clustered index pointer, may be null
/**/
pfucb2ndIdx = pfucb->pfucbCurIndex;
if ( pfucb2ndIdx == pfucbNil )
{
/* move to DATA root
/**/
DIRGotoDataRoot( pfucb );
err = ErrDIRGotoPosition( pfucb, precpos->centriesLT, precpos->centriesTotal );
}
else
{
/* move to DATA root
/**/
DIRGotoDataRoot( pfucb2ndIdx );
err = ErrDIRGotoPosition( pfucb2ndIdx, precpos->centriesLT, precpos->centriesTotal );
/* if the movement was successful and a non-clustered index is
/* in use, then position clustered index to record.
/**/
if ( err == JET_errSuccess )
{
Assert( pfucb2ndIdx->lineData.pb != NULL );
Assert( pfucb2ndIdx->lineData.cb >= sizeof(SRID) );
srid = PcsrCurrent( pfucb2ndIdx )->item;
DIRDeferGotoBookmark( pfucb, srid );
Assert( PgnoOfSrid( srid ) != pgnoNull );
}
}
/* if no records then return JET_errRecordNotFound
/* otherwise return error from called routine
/**/
if ( err < 0 )
{
PcsrCurrent( pfucb )->csrstat = csrstatBeforeFirst;
if ( pfucb2ndIdx != pfucbNil )
{
PcsrCurrent( pfucb2ndIdx )->csrstat = csrstatBeforeFirst;
}
}
else
{
Assert (err==JET_errSuccess || err==wrnNDFoundLess || err==wrnNDFoundGreater );
err = JET_errSuccess;
}
return err;
}
ERR VTAPI ErrIsamSetIndexRange( PIB *ppib, FUCB *pfucb, JET_GRBIT grbit )
{
ERR err;
FUCB *pfucbIdx;
/* ppib is not used in this function.
/**/
NotUsed( ppib );
/* must be on index
/**/
if ( pfucb->u.pfcb->pidb == pidbNil && pfucb->pfucbCurIndex == pfucbNil )
return JET_errNoCurrentIndex;
/* key must be prepared
/**/
if ( ! ( FKSPrepared( pfucb ) ) )
return JET_errKeyNotMade;
/* get cursor for current index. If non-clustered index,
/* then copy index range key to non-clustered index.
/**/
if ( pfucb->pfucbCurIndex != pfucbNil )
{
pfucbIdx = pfucb->pfucbCurIndex;
if ( pfucbIdx->pbKey == NULL )
{
pfucbIdx->pbKey = LAlloc( 1L, JET_cbKeyMost );
if ( pfucbIdx->pbKey == NULL )
return JET_errOutOfMemory;
}
pfucbIdx->cbKey = pfucb->cbKey;
memcpy( pfucbIdx->pbKey, pfucb->pbKey, pfucbIdx->cbKey );
}
else
pfucbIdx = pfucb;
/* set index range and check current position.
/**/
DIRSetIndexRange( pfucbIdx, grbit );
err = ErrDIRCheckIndexRange( pfucbIdx );
/* reset key status.
/**/
KSReset( pfucb );
return err;
}