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
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;
|
|
}
|
|
|