git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@112 0109f412-320b-0410-ab79-c3e0c5ffbbe6
639 lines
14 KiB
C++
639 lines
14 KiB
C++
//-------------------------------------------------------------------------
|
|
// Desc: Retrieve keys from an index.
|
|
// Tabs: 3
|
|
//
|
|
// Copyright (c) 1998-2006 Novell, Inc. All Rights Reserved.
|
|
//
|
|
// This program is free software; you can redistribute it and/or
|
|
// modify it under the terms of version 2 of the GNU General Public
|
|
// License as published by the Free Software Foundation.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program; if not, contact Novell, Inc.
|
|
//
|
|
// To contact Novell about this file by physical or electronic mail,
|
|
// you may find current contact information at www.novell.com
|
|
//
|
|
// $Id: flkeyret.cpp 12329 2006-01-20 17:49:30 -0700 (Fri, 20 Jan 2006) ahodgkinson $
|
|
//-------------------------------------------------------------------------
|
|
|
|
#include "flaimsys.h"
|
|
|
|
FSTATIC RCODE flmKeyRetrieveCS(
|
|
FDB * pDb,
|
|
FLMUINT uiIndex,
|
|
FLMUINT uiContainer,
|
|
FlmRecord * pKeyTree,
|
|
FLMUINT uiRefDrn,
|
|
FLMUINT uiFlag,
|
|
FlmRecord ** ppRecordRV,
|
|
FLMUINT * puiDrnRV);
|
|
|
|
FSTATIC RCODE flmNextKey(
|
|
FDB * pDb,
|
|
LFILE * pLFile,
|
|
BTSK_p pStack,
|
|
FLMUINT * pudRefDrn);
|
|
|
|
|
|
/*API~***********************************************************************
|
|
Desc: Retrieves a key from an index based on a passed-in GEDCOM tree and DRN.
|
|
*END************************************************************************/
|
|
FLMEXP RCODE FLMAPI FlmKeyRetrieve(
|
|
HFDB hDb,
|
|
FLMUINT uiIndex,
|
|
FLMUINT uiContainer,
|
|
FlmRecord * pKeyTree,
|
|
FLMUINT uiRefDrn,
|
|
FLMUINT uiFlag,
|
|
FlmRecord ** ppRecordRV,
|
|
FLMUINT * puiDrnRV
|
|
)
|
|
{
|
|
BTSK stack[ BH_MAX_LEVELS];
|
|
FLMBOOL bStackInitialized = FALSE;
|
|
BTSK_p pStack = &stack[0];
|
|
DIN_STATE dinState;
|
|
FDB * pDb = (FDB *)hDb;
|
|
IXD_p pIxd = NULL;
|
|
LFILE * pLFile;
|
|
FLMBYTE * pSearchKeyBuf = NULL;
|
|
FLMBYTE * pKeyBuf = NULL;
|
|
void * pvMark = NULL;
|
|
FLMUINT uiFoundDrn = 0;
|
|
FLMUINT uiDomain;
|
|
FLMUINT uiElmDomain;
|
|
FLMUINT uiSearchKeyLen;
|
|
FLMBOOL bImplicitTrans = FALSE;
|
|
FLMBYTE pSmallBuf[8];
|
|
FLMUINT uiKeyRelPos;
|
|
RCODE rc;
|
|
|
|
// See if the database is being forced to close
|
|
|
|
if( RC_BAD( rc = flmCheckDatabaseState( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
pvMark = GedPoolMark( &(pDb->TempPool));
|
|
|
|
if( IsInCSMode( hDb))
|
|
{
|
|
fdbInitCS( pDb);
|
|
rc = flmKeyRetrieveCS( pDb, uiIndex, uiContainer,
|
|
pKeyTree, uiRefDrn, uiFlag,
|
|
ppRecordRV, puiDrnRV);
|
|
goto Exit_CS;
|
|
}
|
|
|
|
if( pKeyTree || (uiFlag & FO_LAST))
|
|
{
|
|
pSearchKeyBuf = (FLMBYTE *) GedPoolAlloc( &(pDb->TempPool),
|
|
MAX_KEY_SIZ + 4);
|
|
}
|
|
else
|
|
{
|
|
pSearchKeyBuf = pSmallBuf;
|
|
}
|
|
pKeyBuf = (FLMBYTE *) GedPoolAlloc( &pDb->TempPool, MAX_KEY_SIZ + 4);
|
|
if( !pSearchKeyBuf || !pKeyBuf)
|
|
{
|
|
rc = RC_SET( FERR_MEM);
|
|
goto Exit;
|
|
}
|
|
/* Initialize the OPC */
|
|
|
|
if( RC_BAD( rc = fdbInit( pDb, FLM_READ_TRANS,
|
|
FDB_TRANS_GOING_OK, 0, &bImplicitTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
if( RC_BAD( rc = fdictGetIndex(
|
|
pDb->pDict, pDb->pFile->bInLimitedMode,
|
|
uiIndex, &pLFile, &pIxd)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
if( RC_BAD( rc = KYFlushKeys( pDb)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if (uiFlag & (FO_LAST | FO_FIRST))
|
|
{
|
|
if (uiFlag & FO_FIRST)
|
|
{
|
|
pSearchKeyBuf[0] = 0;
|
|
uiSearchKeyLen = 1;
|
|
|
|
// Get rid of other bits that may have been set.
|
|
// Handle like FO_INCL from here on out.
|
|
// FO_FIRST takes precedence over other bits that
|
|
// may have been set.
|
|
|
|
uiFlag = FO_INCL;
|
|
}
|
|
else
|
|
{
|
|
f_memset( pSearchKeyBuf, 0xFF, MAX_KEY_SIZ);
|
|
uiSearchKeyLen = MAX_KEY_SIZ;
|
|
|
|
// Get rid of other bits that may have been set.
|
|
|
|
uiFlag = FO_LAST;
|
|
}
|
|
uiRefDrn = 0;
|
|
}
|
|
else if (pKeyTree)
|
|
{
|
|
if( RC_BAD( rc = KYTreeToKey( pDb, pIxd, pKeyTree,
|
|
uiContainer,
|
|
pSearchKeyBuf, &uiSearchKeyLen, 0)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pSearchKeyBuf[0] = 0;
|
|
uiSearchKeyLen = 1;
|
|
}
|
|
|
|
uiDomain = (FLMUINT)((uiRefDrn) ? DIN_DOMAIN( uiRefDrn) + 1
|
|
: 0);
|
|
|
|
FSInitStackCache( &stack[0], BH_MAX_LEVELS);
|
|
bStackInitialized = TRUE;
|
|
pStack->pKeyBuf = pKeyBuf;
|
|
|
|
/* Search the B-Tree for the key. */
|
|
|
|
if (RC_BAD( rc = FSBtSearch( pDb, pLFile, &pStack, pSearchKeyBuf,
|
|
uiSearchKeyLen, uiDomain)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
uiKeyRelPos = pStack->uiCmpStatus;
|
|
|
|
// Handle FO_LAST case - If FO_LAST bit was set, uiFlag will
|
|
// have been changed above to simply be equal to FO_LAST.
|
|
|
|
if (uiFlag == FO_LAST)
|
|
{
|
|
FLMUINT uiTmp;
|
|
DIN_STATE DinState;
|
|
|
|
if (pStack->uiBlkAddr == BT_END)
|
|
{
|
|
rc = RC_SET( FERR_BOF_HIT);
|
|
goto Exit;
|
|
}
|
|
|
|
// Should be positioned at end of data in the B-tree
|
|
|
|
flmAssert( uiKeyRelPos == BT_END_OF_DATA);
|
|
|
|
// Position to the last element in the block.
|
|
|
|
if (RC_BAD( rc = FSBtPrevElm( pDb, pLFile, pStack)))
|
|
{
|
|
if (rc == BT_END_OF_DATA)
|
|
{
|
|
rc = RC_SET( FERR_BOF_HIT);
|
|
}
|
|
goto Exit;
|
|
}
|
|
RESET_DINSTATE( DinState);
|
|
uiFoundDrn = FSRefLast( pStack, &DinState, &uiTmp);
|
|
goto Make_Key;
|
|
}
|
|
if( (uiKeyRelPos == BT_END_OF_DATA) ||
|
|
((uiFlag & (FO_EXACT | FO_KEY_EXACT)) && (uiKeyRelPos != BT_EQ_KEY)))
|
|
{
|
|
rc = (uiFlag & FO_EXACT)
|
|
? RC_SET( FERR_NOT_FOUND)
|
|
: RC_SET( FERR_EOF_HIT);
|
|
goto Exit;
|
|
}
|
|
|
|
// NOTE: dinState will be initialized by FSRefFirst - no
|
|
// need to memset prior to calling.
|
|
uiFoundDrn = FSRefFirst( pStack, &dinState, &uiElmDomain);
|
|
|
|
// Key positioning returns the first reference.
|
|
if( !uiRefDrn)
|
|
{
|
|
|
|
// If exclusive and NOT key exact
|
|
if( (uiFlag & (FO_EXCL | FO_KEY_EXACT)) == FO_EXCL)
|
|
{
|
|
if( uiKeyRelPos == BT_EQ_KEY)
|
|
{
|
|
if( RC_BAD( rc = flmNextKey( pDb, pLFile, pStack, &uiFoundDrn)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
}
|
|
// else already positioned to key and set uiFoundDrn.
|
|
// Cases are FO_INCL, (FO_KEY_EXACT | FO_INCL), (FO_KEY_EXACT | FO_EXCL)
|
|
}
|
|
else // uiRefDrn != 0
|
|
{
|
|
// Code below falls through with rc.
|
|
|
|
/*
|
|
Handles both cases of FO_KEY_EXACT being set or not set.
|
|
|
|
FO_KEY_EXACT cases.
|
|
Position to the exact key and FO flags act on the uiRefDrn value.
|
|
|
|
FO_EXACT - exact on uiRefDrn
|
|
FO_EXCL - Go exclusive of the input uiRefDrn or first ref if 0.
|
|
Returns FERR_NOT_FOUND when no more DRN references follow.
|
|
FO_INCL - Go inclusive of the current or next reference.
|
|
Returns FERR_NOT_FOUND when no more DRN references follow.
|
|
*/
|
|
|
|
if( uiFlag & FO_EXACT)
|
|
{
|
|
/*
|
|
Reading the current element, position to or after uiFoundDrn.
|
|
Anything but success means we did not find the exact DRN.
|
|
*/
|
|
|
|
uiFoundDrn = uiRefDrn;
|
|
if( RC_BAD( rc = FSRefSearch( pStack, &dinState, &uiFoundDrn)))
|
|
{
|
|
rc = RC_SET( FERR_NOT_FOUND);
|
|
}
|
|
}
|
|
else if (uiFlag & FO_EXCL)
|
|
{
|
|
if (uiKeyRelPos == BT_EQ_KEY)
|
|
{
|
|
/* Need to find reference and position to the next one */
|
|
|
|
uiFoundDrn = uiRefDrn;
|
|
rc = FSRefSearch( pStack, &dinState, &uiFoundDrn);
|
|
|
|
/*
|
|
SUCCESS means we found the DRN, need to position to
|
|
one past it. FERR_FAILURE means we are positioned
|
|
to a DRN that is SMALLER than the one we are
|
|
looking for or we are at the end of the reference set.
|
|
*/
|
|
|
|
if( RC_OK( rc))
|
|
{
|
|
if( (rc = FSRefNext( pDb, pLFile, pStack, &dinState,
|
|
&uiFoundDrn)) == FERR_BT_END_OF_DATA)
|
|
{
|
|
if (uiFlag & FO_KEY_EXACT)
|
|
{
|
|
rc = RC_SET( FERR_EOF_HIT);
|
|
}
|
|
else
|
|
{
|
|
rc = flmNextKey( pDb, pLFile, pStack, &uiFoundDrn);
|
|
}
|
|
}
|
|
}
|
|
else if( rc == FERR_FAILURE)
|
|
{
|
|
/*
|
|
If FSRefSearch returns a non-zero reference,
|
|
we are positioned on a DRN that is SMALLER
|
|
the one we searched for. Otherwise, we are
|
|
at the end of that key's reference set and we
|
|
need to go to the next key.
|
|
*/
|
|
|
|
if (uiFoundDrn)
|
|
{
|
|
rc = FERR_OK;
|
|
}
|
|
else if (uiFlag & FO_KEY_EXACT)
|
|
{
|
|
rc = RC_SET( FERR_EOF_HIT);
|
|
}
|
|
else
|
|
{
|
|
rc = flmNextKey( pDb, pLFile, pStack, &uiFoundDrn);
|
|
}
|
|
}
|
|
}
|
|
else if (uiFlag & FO_KEY_EXACT)
|
|
{
|
|
rc = RC_SET( FERR_EOF_HIT);
|
|
}
|
|
// else already positioned on the next key and uiFoundDrn is set.
|
|
}
|
|
else // FO_INCL
|
|
{
|
|
if (uiKeyRelPos == BT_EQ_KEY)
|
|
{
|
|
|
|
/* Need to find reference if possible. */
|
|
|
|
uiFoundDrn = uiRefDrn;
|
|
rc = FSRefSearch( pStack, &dinState, &uiFoundDrn);
|
|
|
|
/*
|
|
SUCCESS means we found the DRN. FERR_FAILURE means we
|
|
are either positioned past the DRN or we are at the
|
|
end of the key's reference set.
|
|
*/
|
|
|
|
if( rc == FERR_FAILURE)
|
|
{
|
|
/*
|
|
If FSRefSearch returns a non-zero reference,
|
|
we are positioned on a DRN that is SMALLER than
|
|
the one we searched for. Otherwise, we are
|
|
at the end of that key's reference set and we
|
|
need to go to the next key.
|
|
*/
|
|
|
|
if (uiFoundDrn)
|
|
{
|
|
rc = FERR_OK;
|
|
}
|
|
else if (uiFlag & FO_KEY_EXACT)
|
|
{
|
|
rc = RC_SET( FERR_EOF_HIT);
|
|
}
|
|
else
|
|
{
|
|
rc = flmNextKey( pDb, pLFile, pStack, &uiFoundDrn);
|
|
}
|
|
}
|
|
}
|
|
else if (uiFlag & FO_KEY_EXACT)
|
|
{
|
|
rc = RC_SET( FERR_EOF_HIT);
|
|
}
|
|
// else already positioned on the next key and uiFoundDrn is set.
|
|
}
|
|
}
|
|
|
|
/*
|
|
If everything went OK, render the key in GEDCOM form and return it together
|
|
with the reference DRN.
|
|
*/
|
|
|
|
Make_Key:
|
|
if( RC_OK( rc) && ppRecordRV)
|
|
{
|
|
|
|
/*
|
|
VISIT: We must build a fat tree and not a flat tree. (TRUE in last parm is fat)
|
|
Need to visit all of smi\fixcalls.cpp.
|
|
*/
|
|
if( RC_OK( rc = flmIxKeyOutput( pIxd,
|
|
pStack->pKeyBuf, pStack->uiKeyLen, ppRecordRV, TRUE)))
|
|
{
|
|
(*ppRecordRV)->setID( uiFoundDrn);
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
if( RC_OK(rc) && puiDrnRV)
|
|
{
|
|
*puiDrnRV = uiFoundDrn;
|
|
}
|
|
|
|
if( bStackInitialized)
|
|
{
|
|
FSReleaseStackCache( stack, BH_MAX_LEVELS, FALSE);
|
|
}
|
|
|
|
/* If we started an implicit transaction, abort it here */
|
|
|
|
if( bImplicitTrans)
|
|
{
|
|
(void)flmAbortDbTrans( pDb);
|
|
}
|
|
|
|
Exit_CS:
|
|
|
|
GedPoolReset( &(pDb->TempPool), pvMark);
|
|
flmExit( FLM_KEY_RETRIEVE, pDb, rc);
|
|
|
|
return( rc);
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
Name : flmKeyRetrieveCS
|
|
Area : RETRIEVAL
|
|
Desc: Retrieves a key from an index based on a passed-in GEDCOM tree and DRN.
|
|
VISIT: On reading data records and FO_EXCL, increment the DRN instead of
|
|
positioning to the DRN and then scanning to the next record.
|
|
*END************************************************************************/
|
|
FSTATIC RCODE flmKeyRetrieveCS(
|
|
FDB * pDb,
|
|
FLMUINT uiIndex,
|
|
FLMUINT uiContainer,
|
|
FlmRecord * pKeyTree,
|
|
FLMUINT uiRefDrn,
|
|
FLMUINT uiFlag,
|
|
FlmRecord ** ppRecordRV,
|
|
FLMUINT * puiDrnRV)
|
|
{
|
|
RCODE rc;
|
|
CS_CONTEXT * pCSContext = pDb->pCSContext;
|
|
FCL_WIRE Wire( pCSContext, pDb);
|
|
void * pvMark = GedPoolMark( &pCSContext->pool);
|
|
|
|
/*
|
|
Set the record object so that it can be re-used,
|
|
if possible
|
|
*/
|
|
|
|
if( ppRecordRV)
|
|
{
|
|
Wire.setRecord( *ppRecordRV);
|
|
if( *ppRecordRV)
|
|
{
|
|
(*ppRecordRV)->Release();
|
|
*ppRecordRV = NULL;
|
|
}
|
|
}
|
|
|
|
/*
|
|
Set the temporary pool
|
|
*/
|
|
|
|
Wire.setPool( &pCSContext->pool);
|
|
|
|
/*
|
|
Send the request
|
|
*/
|
|
|
|
if( RC_BAD( rc = Wire.sendOp( FCS_OPCLASS_RECORD, FCS_OP_KEY_RETRIEVE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( pCSContext->uiServerFlaimVer >= FLM_VER_4_50)
|
|
{
|
|
if( uiIndex)
|
|
{
|
|
if (RC_BAD( rc = Wire.sendNumber( WIRE_VALUE_INDEX_ID, uiIndex)))
|
|
{
|
|
goto Transmission_Error;
|
|
}
|
|
}
|
|
|
|
if( uiContainer)
|
|
{
|
|
if (RC_BAD( rc = Wire.sendNumber( WIRE_VALUE_CONTAINER_ID, uiContainer)))
|
|
{
|
|
goto Transmission_Error;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
|
|
// Older versions of server expect the index in the CONTAINER tag.
|
|
|
|
if( uiIndex)
|
|
{
|
|
if (RC_BAD( rc = Wire.sendNumber( WIRE_VALUE_CONTAINER_ID, uiIndex)))
|
|
{
|
|
goto Transmission_Error;
|
|
}
|
|
}
|
|
}
|
|
|
|
if( pKeyTree)
|
|
{
|
|
if (RC_BAD( rc = Wire.sendHTD( WIRE_VALUE_HTD, pKeyTree)))
|
|
{
|
|
goto Transmission_Error;
|
|
}
|
|
}
|
|
|
|
if( uiRefDrn)
|
|
{
|
|
if (RC_BAD( rc = Wire.sendNumber( WIRE_VALUE_DRN, uiRefDrn)))
|
|
{
|
|
goto Transmission_Error;
|
|
}
|
|
}
|
|
|
|
if( uiFlag)
|
|
{
|
|
if (RC_BAD( rc = Wire.sendNumber( WIRE_VALUE_FLAGS, uiFlag)))
|
|
{
|
|
goto Transmission_Error;
|
|
}
|
|
}
|
|
|
|
if( RC_BAD( rc = Wire.sendTerminate()))
|
|
{
|
|
goto Transmission_Error;
|
|
}
|
|
|
|
/* Read the response. */
|
|
|
|
if( RC_BAD( rc = Wire.read()))
|
|
{
|
|
goto Transmission_Error;
|
|
}
|
|
|
|
if( RC_BAD( rc = Wire.getRCode()))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( ppRecordRV)
|
|
{
|
|
if( (*ppRecordRV = Wire.getRecord()) != NULL)
|
|
{
|
|
(*ppRecordRV)->AddRef();
|
|
}
|
|
}
|
|
|
|
if( puiDrnRV)
|
|
{
|
|
*puiDrnRV = Wire.getDrn();
|
|
}
|
|
|
|
Exit:
|
|
|
|
GedPoolReset( &pCSContext->pool, pvMark);
|
|
return( rc);
|
|
|
|
Transmission_Error:
|
|
pCSContext->bConnectionGood = FALSE;
|
|
goto Exit;
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Go to the next key given a valid cursor. Get & position to reference
|
|
if you care about references
|
|
****************************************************************************/
|
|
FSTATIC RCODE flmNextKey(
|
|
FDB * pDb,
|
|
LFILE * pLFile,
|
|
BTSK_p pStack,
|
|
FLMUINT * puiRefDrn)
|
|
{
|
|
RCODE rc;
|
|
FLMBYTE * pCurElm;
|
|
|
|
/* The stack should be set up and is pointing to a valid block */
|
|
|
|
pStack->uiFlags = NO_STACK;
|
|
pStack->uiKeyBufSize = MAX_KEY_SIZ;
|
|
|
|
pCurElm = CURRENT_ELM( pStack);
|
|
|
|
/* Scan over the current record till 'does continue' flag NOT set */
|
|
|
|
while( BBE_NOT_LAST( pCurElm))
|
|
{
|
|
/* First go to the next element - rc may return FERR_BT_END_OF_DATA */
|
|
|
|
if( RC_BAD(rc = FSBtNextElm( pDb, pLFile, pStack)))
|
|
{
|
|
if( rc == FERR_BT_END_OF_DATA) /* b-tree corrupt if FERR_BT_END_OF_DATA */
|
|
rc = RC_SET( FERR_BTREE_ERROR);
|
|
goto Exit;
|
|
}
|
|
pCurElm = CURRENT_ELM( pStack);
|
|
}
|
|
|
|
/* Now go to the next element */
|
|
|
|
if( RC_BAD(rc = FSBtNextElm( pDb, pLFile, pStack)))
|
|
{
|
|
if( rc == FERR_BT_END_OF_DATA)
|
|
rc = RC_SET( FERR_EOF_HIT);
|
|
goto Exit;
|
|
}
|
|
if (puiRefDrn)
|
|
{
|
|
pCurElm = CURRENT_ELM( pStack);
|
|
(void) FSGetDomain( &pCurElm, BBE_KEY);
|
|
|
|
if( puiRefDrn)
|
|
{
|
|
*puiRefDrn = SENNextVal( &pCurElm);
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
return( rc);
|
|
}
|