Renamed version4 to flaim and version5 to xflaim
git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@7 0109f412-320b-0410-ab79-c3e0c5ffbbe6
This commit is contained in:
965
flaim/src/fqget.cpp
Normal file
965
flaim/src/fqget.cpp
Normal file
@@ -0,0 +1,965 @@
|
||||
//-------------------------------------------------------------------------
|
||||
// Desc: Query record retrieval
|
||||
// Tabs: 3
|
||||
//
|
||||
// Copyright (c) 1996-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: fqget.cpp 12329 2006-01-20 17:49:30 -0700 (Fri, 20 Jan 2006) ahodgkinson $
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
#include "flaimsys.h"
|
||||
|
||||
FSTATIC RCODE flmCurCSTestRec(
|
||||
CURSOR_p pCursor,
|
||||
FLMUINT uiDrn,
|
||||
FlmRecord * pTestRec,
|
||||
FLMBOOL * pbIsMatchRV);
|
||||
|
||||
/****************************************************************************
|
||||
Desc: Makes a SET_DEL from a record.
|
||||
****************************************************************************/
|
||||
RCODE flmCurMakeKeyFromRec(
|
||||
FDB * pDb,
|
||||
IXD_p pIxd,
|
||||
POOL * pPool,
|
||||
FlmRecord * pRec,
|
||||
FLMBYTE ** ppucKeyBuffer,
|
||||
FLMUINT * puiKeyLen)
|
||||
{
|
||||
REC_KEY * pKey = NULL;
|
||||
RCODE rc = FERR_OK;
|
||||
|
||||
// Set up CDL table and other KREF stuff in FDB.
|
||||
|
||||
if (RC_BAD( rc = KrefCntrlCheck( pDb)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Parse the keys from the record, and verify that the record contains
|
||||
// only one key.
|
||||
|
||||
rc = flmGetRecKeys( pDb, pIxd, pRec, pRec->getContainerID(),
|
||||
TRUE, pPool, &pKey);
|
||||
|
||||
KYAbortCurrentRecord( pDb);
|
||||
|
||||
if (RC_BAD( rc))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
else if (!pKey)
|
||||
{
|
||||
rc = RC_SET( FERR_NOT_FOUND);
|
||||
goto Exit;
|
||||
}
|
||||
if (pKey->pNextKey)
|
||||
{
|
||||
rc = RC_SET( FERR_ILLEGAL_OP);
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Now allocate a key buffer to hold the key.
|
||||
|
||||
if (!(*ppucKeyBuffer))
|
||||
{
|
||||
if ((*ppucKeyBuffer = (FLMBYTE *)GedPoolCalloc(
|
||||
pPool, MAX_KEY_SIZ)) == NULL)
|
||||
{
|
||||
rc = RC_SET( FERR_MEM);
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
|
||||
// We pass in pRec->getContainerID(), because every key we generate
|
||||
// came from pRec, and we want to use its container number.
|
||||
|
||||
if (RC_BAD( rc = KYTreeToKey( pDb, pIxd, pKey->pKey,
|
||||
pRec->getContainerID(),
|
||||
*ppucKeyBuffer,
|
||||
puiKeyLen, 0)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
Exit:
|
||||
|
||||
while (pKey)
|
||||
{
|
||||
pKey->pKey->Release();
|
||||
pKey->pKey = NULL;
|
||||
pKey = pKey->pNextKey;
|
||||
}
|
||||
return( rc);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Desc: Sets a query's position from a passed-in DRN.
|
||||
****************************************************************************/
|
||||
RCODE flmCurSetPosFromDRN(
|
||||
CURSOR_p pCursor,
|
||||
FLMUINT uiDRN
|
||||
)
|
||||
{
|
||||
RCODE rc = FERR_OK;
|
||||
FlmRecord * pRec = NULL;
|
||||
POOL * pTempPool;
|
||||
FDB_p pDb = NULL;
|
||||
IXD_p pIxd;
|
||||
LFILE * pLFile;
|
||||
SUBQUERY_p pSubQuery;
|
||||
FLMBOOL bPositioned;
|
||||
FLMBYTE * pucKeyBuffer = NULL;
|
||||
FLMUINT uiKeyLen;
|
||||
|
||||
pDb = pCursor->pDb;
|
||||
if (RC_BAD( rc = flmCurDbInit( pCursor)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
pTempPool = &pDb->TempPool;
|
||||
|
||||
// Read the record associated with the DRN, and construct an index key
|
||||
|
||||
rc = flmRcaRetrieveRec( pDb, NULL, pCursor->uiContainer, uiDRN,
|
||||
FALSE, NULL, NULL, &pRec);
|
||||
|
||||
if (rc == FERR_NOT_FOUND)
|
||||
{
|
||||
if (RC_BAD( rc = fdictGetContainer( pDb->pDict,
|
||||
pCursor->uiContainer, &pLFile)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
if (RC_BAD( rc = FSReadRecord( pDb, pLFile, uiDRN,
|
||||
&pRec, NULL, NULL)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
else if (RC_BAD( rc))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Optimize the subqueries as necessary
|
||||
|
||||
if (!pCursor->bOptimized)
|
||||
{
|
||||
if (RC_BAD( rc = flmCurPrep( pCursor)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
|
||||
// Go through the subquery list to find the sub-query into which the
|
||||
// DRN falls.
|
||||
|
||||
bPositioned = FALSE;
|
||||
for( pSubQuery = pCursor->pSubQueryList;
|
||||
pSubQuery && !bPositioned;
|
||||
pSubQuery = pSubQuery->pNext)
|
||||
{
|
||||
FLMUINT uiResult;
|
||||
|
||||
// See if the record satisifies this sub-query's criteria.
|
||||
// If not, we cannot position into this sub-query.
|
||||
|
||||
if (RC_BAD( rc = flmCurEvalCriteria( pCursor, pSubQuery, pRec,
|
||||
FALSE, &uiResult)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Found a sub-query where this DRN passes. Set this sub-query to
|
||||
// be the current sub-query on certain conditions.
|
||||
|
||||
if (uiResult == FLM_TRUE)
|
||||
{
|
||||
switch (pSubQuery->OptInfo.eOptType)
|
||||
{
|
||||
case QOPT_USING_INDEX:
|
||||
if (RC_BAD( rc = fdictGetIndex( pDb->pDict,
|
||||
pDb->pFile->bInLimitedMode,
|
||||
pSubQuery->OptInfo.uiIxNum,
|
||||
NULL, &pIxd)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// If we cannot create a key for this index, go to the next
|
||||
// subquery.
|
||||
|
||||
if (RC_BAD( rc = flmCurMakeKeyFromRec( pDb, pIxd, pTempPool,
|
||||
pRec, &pucKeyBuffer, &uiKeyLen)))
|
||||
{
|
||||
if (rc == FERR_NOT_FOUND || rc == FERR_ILLEGAL_OP)
|
||||
{
|
||||
rc = FERR_OK;
|
||||
break;
|
||||
}
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Position to the key and drn - If we can't just go to the
|
||||
// next subquery.
|
||||
|
||||
if (RC_BAD( rc = pSubQuery->pFSIndexCursor->positionTo( pDb,
|
||||
pucKeyBuffer, uiKeyLen, uiDRN)))
|
||||
{
|
||||
if (rc == FERR_NOT_FOUND ||
|
||||
rc == FERR_EOF_HIT ||
|
||||
rc == FERR_BOF_HIT)
|
||||
{
|
||||
rc = FERR_OK;
|
||||
break;
|
||||
}
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Retrieve the current key and DRN from the index cursor.
|
||||
|
||||
rc = pSubQuery->pFSIndexCursor->currentKey( pDb,
|
||||
&pSubQuery->pRec, &pSubQuery->uiDrn);
|
||||
if (RC_BAD( rc))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
bPositioned = TRUE;
|
||||
pSubQuery->uiCurrKeyMatch = FLM_UNK;
|
||||
pSubQuery->bFirstReference = FALSE;
|
||||
|
||||
// These should have been set by the call to currentKey.
|
||||
|
||||
flmAssert( pSubQuery->pRec->getContainerID() ==
|
||||
pCursor->uiContainer);
|
||||
flmAssert( pSubQuery->pRec->getID() == pSubQuery->uiDrn);
|
||||
|
||||
pSubQuery->bRecIsAKey = TRUE;
|
||||
break;
|
||||
case QOPT_USING_PREDICATE:
|
||||
// Can't position in a predicate - go to next sub-query.
|
||||
break;
|
||||
case QOPT_SINGLE_RECORD_READ:
|
||||
bPositioned = TRUE;
|
||||
pSubQuery->uiDrn = uiDRN;
|
||||
break;
|
||||
case QOPT_PARTIAL_CONTAINER_SCAN:
|
||||
case QOPT_FULL_CONTAINER_SCAN:
|
||||
rc = pSubQuery->pFSDataCursor->positionTo( pDb, uiDRN);
|
||||
if (RC_BAD( rc))
|
||||
{
|
||||
if (rc == FERR_NOT_FOUND ||
|
||||
rc == FERR_EOF_HIT ||
|
||||
rc == FERR_BOF_HIT)
|
||||
{
|
||||
rc = FERR_OK;
|
||||
break;
|
||||
}
|
||||
goto Exit;
|
||||
}
|
||||
bPositioned = TRUE;
|
||||
break;
|
||||
default:
|
||||
flmAssert( 0);
|
||||
break;
|
||||
}
|
||||
if (bPositioned)
|
||||
{
|
||||
pCursor->uiLastRecID = uiDRN;
|
||||
pCursor->pCurrSubQuery = pSubQuery;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!bPositioned)
|
||||
{
|
||||
rc = RC_SET( FERR_NOT_FOUND);
|
||||
}
|
||||
|
||||
Exit:
|
||||
|
||||
if (pRec)
|
||||
{
|
||||
pRec->Release();
|
||||
}
|
||||
flmExit( FLM_CURSOR_CONFIG, pDb, rc);
|
||||
|
||||
return( pCursor->rc = rc);
|
||||
}
|
||||
|
||||
/*API~***********************************************************************
|
||||
Desc: Given a cursor and two DRNs, this API does the following:
|
||||
*END************************************************************************/
|
||||
RCODE FlmCursorCompareDRNs(
|
||||
HFCURSOR hCursor,
|
||||
FLMUINT uiDRN1,
|
||||
FLMUINT uiDRN2,
|
||||
FLMUINT uiTimeLimit,
|
||||
FLMINT * piCmpResult,
|
||||
FLMBOOL * pbTimedOut,
|
||||
FLMUINT * puiCount)
|
||||
{
|
||||
RCODE rc = FERR_OK;
|
||||
CURSOR_p pCursor = (CURSOR *)hCursor;
|
||||
FDB_p pDb = NULL;
|
||||
POOL * pTempPool;
|
||||
FLMBYTE * pucKey1;
|
||||
FLMUINT uiKey1Len;
|
||||
FLMBYTE * pucKey2;
|
||||
FLMUINT uiKey2Len;
|
||||
FlmRecord * pRec1 = NULL;
|
||||
FlmRecord * pRec2 = NULL;
|
||||
IXD_p pIxd;
|
||||
FSIndexCursor * pTmpFSIndexCursor = NULL;
|
||||
FSIndexCursor * pSaveFSIndexCursor = NULL;
|
||||
FLMUINT uiSaveTimeLimit = 0;
|
||||
LFILE * pLFile;
|
||||
FLMUINT uiIndexNum;
|
||||
FLMINT iCmp;
|
||||
|
||||
// Verify that return params are non-NULL.
|
||||
|
||||
flmAssert( piCmpResult != NULL);
|
||||
flmAssert( pbTimedOut != NULL);
|
||||
flmAssert( puiCount != NULL);
|
||||
flmAssert( pCursor != NULL);
|
||||
|
||||
if (!pCursor)
|
||||
{
|
||||
flmAssert( 0);
|
||||
rc = RC_SET( FERR_INVALID_PARM);
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
if (pCursor->pCSContext)
|
||||
{
|
||||
rc = RC_SET( FERR_NOT_IMPLEMENTED);
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// If the two DRNs are equal, there is no need to read the records to compare
|
||||
// their keys. Furthermore, if they are in the cursor's result set, the
|
||||
// return count will be 2, otherwise it will be 0.
|
||||
|
||||
if (uiDRN1 == uiDRN2)
|
||||
{
|
||||
*piCmpResult = 0;
|
||||
if (uiTimeLimit)
|
||||
{
|
||||
FLMBOOL bInRSet;
|
||||
|
||||
if (RC_BAD( rc = FlmCursorTestDRN( hCursor, uiDRN1, &bInRSet)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
if (bInRSet)
|
||||
{
|
||||
*puiCount = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
*puiCount = 0;
|
||||
}
|
||||
*pbTimedOut = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
*pbTimedOut = TRUE;
|
||||
rc = FERR_OK;
|
||||
}
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
*puiCount = 0;
|
||||
*pbTimedOut = (FLMBOOL)((!uiTimeLimit)
|
||||
? TRUE
|
||||
: FALSE);
|
||||
|
||||
// Read the records associated with the two DRNs, and construct index keys
|
||||
// from them to determine the directional relationship between them.
|
||||
|
||||
pDb = pCursor->pDb;
|
||||
if (RC_BAD( rc = flmCurDbInit( pCursor)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
pTempPool = &pDb->TempPool;
|
||||
|
||||
// Get the records corresponding to the two DRNs.
|
||||
|
||||
rc = flmRcaRetrieveRec( pDb, NULL, pCursor->uiContainer, uiDRN1,
|
||||
FALSE, NULL, NULL, &pRec1);
|
||||
if (rc == FERR_NOT_FOUND)
|
||||
{
|
||||
if (RC_BAD( rc = fdictGetContainer( pDb->pDict,
|
||||
pCursor->uiContainer, &pLFile)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
if (RC_BAD( rc = FSReadRecord( pDb, pLFile, uiDRN1,
|
||||
&pRec1, NULL, NULL)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
else if (RC_BAD( rc))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Retrieve the 2nd record.
|
||||
|
||||
rc = flmRcaRetrieveRec( pDb, NULL, pCursor->uiContainer, uiDRN2,
|
||||
FALSE, NULL, NULL, &pRec2);
|
||||
if (rc == FERR_NOT_FOUND)
|
||||
{
|
||||
if (RC_BAD( rc = fdictGetContainer( pDb->pDict,
|
||||
pCursor->uiContainer, &pLFile)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
if (RC_BAD( rc = FSReadRecord( pDb, pLFile, uiDRN2,
|
||||
&pRec2, NULL, NULL)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
else if (RC_BAD( rc))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// At this point, both DRNs have been found. Now generate keys from each
|
||||
// of the records and perform the following actions:
|
||||
// 1) Verify that only one key exists in each record. If there is more
|
||||
// than one key, no clear comparison can be made.
|
||||
// 2) Compare the two keys and set *piCmpResult as follows:
|
||||
// <0 First Key < Second Key
|
||||
// 0 First Key = Second Key
|
||||
// >0 First Key > Second Key
|
||||
|
||||
// If necessary, optimize the query here. NOTE: this should be done only if
|
||||
// FLAIM is to choose an index for the query.
|
||||
|
||||
if (!pCursor->bOptimized && pCursor->uiIndexNum == FLM_SELECT_INDEX)
|
||||
{
|
||||
if (RC_BAD( rc = flmCurPrep( pCursor)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
|
||||
if (pCursor->bOptimized)
|
||||
{
|
||||
|
||||
// If there are multiple subqueries, that means there are
|
||||
// multiple indexes. Set uiIndexNum to zero in this
|
||||
// case so that we will return FERR_NOT_IMPLEMENTED
|
||||
// below.
|
||||
|
||||
if (!pCursor->pSubQueryList ||
|
||||
pCursor->pSubQueryList->pNext ||
|
||||
pCursor->pSubQueryList->OptInfo.eOptType != QOPT_USING_INDEX)
|
||||
{
|
||||
uiIndexNum = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
uiIndexNum = pCursor->pSubQueryList->OptInfo.uiIxNum;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uiIndexNum = pCursor->uiIndexNum;
|
||||
}
|
||||
|
||||
// Index number of zero means that the user either did not set an
|
||||
// index, or no index was selected, or multiple indexes were
|
||||
// selected - all of which disqualify this query from being able
|
||||
// to compare to DRNs.
|
||||
|
||||
if (!uiIndexNum)
|
||||
{
|
||||
rc = RC_SET( FERR_NOT_IMPLEMENTED);
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
if( RC_BAD( rc = fdictGetIndex(
|
||||
pDb->pDict, pDb->pFile->bInLimitedMode,
|
||||
uiIndexNum, NULL, &pIxd)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
pucKey1 = NULL;
|
||||
if (RC_BAD( rc = flmCurMakeKeyFromRec( pDb, pIxd, pTempPool,
|
||||
pRec1, &pucKey1, &uiKey1Len)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
pucKey2 = NULL;
|
||||
if (RC_BAD( rc = flmCurMakeKeyFromRec( pDb, pIxd, pTempPool,
|
||||
pRec2, &pucKey2, &uiKey2Len)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
if (uiKey1Len > uiKey2Len)
|
||||
{
|
||||
if ((iCmp = f_memcmp( pucKey1, pucKey2, uiKey2Len)) == 0)
|
||||
{
|
||||
iCmp = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
iCmp = ( (iCmp > 0) ? 1 : -1);
|
||||
}
|
||||
}
|
||||
else if (uiKey1Len < uiKey2Len)
|
||||
{
|
||||
if ((iCmp = f_memcmp( pucKey1, pucKey2, uiKey1Len)) == 0)
|
||||
{
|
||||
iCmp = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
iCmp = ( (iCmp > 0) ? 1 : -1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((iCmp = f_memcmp( pucKey1, pucKey2, uiKey2Len)) != 0)
|
||||
{
|
||||
iCmp = ( (iCmp > 0) ? 1 : -1);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
// Keys are equal, compare DRNs.
|
||||
|
||||
iCmp = (FLMINT)((uiDRN1 > uiDRN2)
|
||||
? (FLMINT)-1
|
||||
: (FLMINT)((uiDRN1 < uiDRN2)
|
||||
? (FLMINT)1
|
||||
: (FLMINT)0));
|
||||
}
|
||||
}
|
||||
*piCmpResult = iCmp;
|
||||
|
||||
// If time limit is zero, don't need to do the count.
|
||||
|
||||
if (!uiTimeLimit)
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// If keys are equal, simply return a count of two.
|
||||
|
||||
if (!iCmp)
|
||||
{
|
||||
*puiCount = 2;
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Optimize the subqueries as necessary
|
||||
|
||||
if (!pCursor->bOptimized)
|
||||
{
|
||||
if (RC_BAD( rc = flmCurPrep( pCursor)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
|
||||
// Create a new temporary index cursor.
|
||||
|
||||
if ((pTmpFSIndexCursor = f_new FSIndexCursor) == NULL)
|
||||
{
|
||||
rc = RC_SET( FERR_MEM);
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Count the entries between the two keys/references.
|
||||
|
||||
if (iCmp > 0)
|
||||
{
|
||||
if (RC_BAD( rc = pTmpFSIndexCursor->setupKeys( pDb, pIxd,
|
||||
pucKey1, uiKey1Len, uiDRN1,
|
||||
pucKey2, uiKey2Len, uiDRN2, FALSE)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (RC_BAD( rc = pTmpFSIndexCursor->setupKeys( pDb, pIxd,
|
||||
pucKey1, uiKey1Len, uiDRN1,
|
||||
pucKey2, uiKey2Len, uiDRN2, FALSE)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
|
||||
// Intersect the temporary index cursor's key range with the
|
||||
// cursor's key range(es).
|
||||
|
||||
pSaveFSIndexCursor = pCursor->pSubQueryList->pFSIndexCursor;
|
||||
uiSaveTimeLimit = pCursor->uiTimeLimit;
|
||||
if (RC_BAD( rc = pTmpFSIndexCursor->intersectKeys( pDb, pSaveFSIndexCursor)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Set the query's index cursor to the temporary index cursor and count
|
||||
// the entries between them.
|
||||
|
||||
if (uiTimeLimit == FLM_NO_LIMIT)
|
||||
{
|
||||
pCursor->uiTimeLimit = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
FLM_SECS_TO_TIMER_UNITS( uiTimeLimit, pCursor->uiTimeLimit);
|
||||
}
|
||||
|
||||
// Perform the count operation.
|
||||
|
||||
pCursor->pSubQueryList->pFSIndexCursor = pTmpFSIndexCursor;
|
||||
if (RC_BAD( rc = flmCurSearch( FLM_CURSOR_REC_COUNT, pCursor, TRUE,
|
||||
TRUE, puiCount, NULL, NULL, NULL)))
|
||||
{
|
||||
if (rc == FERR_EOF_HIT)
|
||||
{
|
||||
rc = FERR_OK;
|
||||
}
|
||||
else if (rc == FERR_TIMEOUT)
|
||||
{
|
||||
rc = FERR_OK;
|
||||
*pbTimedOut = TRUE;
|
||||
}
|
||||
goto Exit;
|
||||
}
|
||||
Exit:
|
||||
|
||||
if (pRec1)
|
||||
{
|
||||
pRec1->Release();
|
||||
}
|
||||
|
||||
if (pRec2)
|
||||
{
|
||||
pRec2->Release();
|
||||
}
|
||||
|
||||
if (pTmpFSIndexCursor)
|
||||
{
|
||||
pTmpFSIndexCursor->Release();
|
||||
pTmpFSIndexCursor = NULL;
|
||||
}
|
||||
|
||||
// Restore saved index cursor if necessary.
|
||||
|
||||
if (pSaveFSIndexCursor)
|
||||
{
|
||||
pCursor->pSubQueryList->pFSIndexCursor = pSaveFSIndexCursor;
|
||||
pCursor->uiTimeLimit = uiSaveTimeLimit;
|
||||
}
|
||||
flmExit( FLM_CURSOR_COMPARE_DRNS, pDb, rc);
|
||||
|
||||
return( pCursor->rc = rc);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Desc: Does FlmCursorTestRec and FlmCursorTestDRN over the client/server
|
||||
line.
|
||||
****************************************************************************/
|
||||
FSTATIC RCODE flmCurCSTestRec(
|
||||
CURSOR_p pCursor,
|
||||
FLMUINT uiDrn,
|
||||
FlmRecord * pTestRec,
|
||||
FLMBOOL * pbIsMatchRV
|
||||
)
|
||||
{
|
||||
RCODE rc = FERR_OK;
|
||||
CS_CONTEXT_p pCSContext = pCursor->pCSContext;
|
||||
FCL_WIRE Wire( pCSContext);
|
||||
|
||||
// If there is no VALID id for the cursor, get one.
|
||||
|
||||
if (pCursor->uiCursorId == FCS_INVALID_ID)
|
||||
{
|
||||
if (RC_BAD( rc = flmInitCurCS( pCursor)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
|
||||
// Send a request to test the record or DRN.
|
||||
|
||||
if (RC_BAD( rc = Wire.sendOp(
|
||||
FCS_OPCLASS_ITERATOR, FCS_OP_ITERATOR_TEST_REC)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
if (RC_BAD( rc = Wire.sendNumber(
|
||||
WIRE_VALUE_ITERATOR_ID, pCursor->uiCursorId)))
|
||||
{
|
||||
goto Transmission_Error;
|
||||
}
|
||||
|
||||
if (pTestRec)
|
||||
{
|
||||
if (RC_BAD( rc = Wire.sendRecord( WIRE_VALUE_RECORD, pTestRec)))
|
||||
{
|
||||
goto Transmission_Error;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (RC_BAD( rc = Wire.sendNumber( WIRE_VALUE_DRN, uiDrn)))
|
||||
{
|
||||
goto Transmission_Error;
|
||||
}
|
||||
}
|
||||
|
||||
if (RC_BAD( rc = Wire.sendTerminate()))
|
||||
{
|
||||
goto Transmission_Error;
|
||||
}
|
||||
|
||||
// Read the response.
|
||||
|
||||
if (RC_BAD( rc = Wire.read()))
|
||||
{
|
||||
goto Transmission_Error;
|
||||
}
|
||||
|
||||
*pbIsMatchRV = Wire.getBoolean();
|
||||
rc = Wire.getRCode();
|
||||
|
||||
Exit:
|
||||
|
||||
return( rc);
|
||||
|
||||
Transmission_Error:
|
||||
|
||||
pCSContext->bConnectionGood = FALSE;
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
|
||||
/*API~***********************************************************************
|
||||
Name : FlmCursorTestRec
|
||||
Area : CURSOR
|
||||
Desc : Checks a record that has been retrieved from the database to see if
|
||||
satisfies the cursor selection criteria.
|
||||
IMPORTANT NOTE: pRec's containerID better be set to the container it
|
||||
came from, because flmCurEvalCriteria verifies that the record's
|
||||
container number matches the cursor's container number.
|
||||
*END************************************************************************/
|
||||
RCODE FlmCursorTestRec(
|
||||
HFCURSOR hCursor,
|
||||
// [IN] Handle to a cursor.
|
||||
FlmRecord * pRec,
|
||||
// [IN] Pointer to the record to be checked.
|
||||
FLMBOOL * pbIsMatch
|
||||
// [OUT] If *pbIsMatch == TRUE, then the record is a match.
|
||||
// Otherwise, the record did not meet the criteria and is not a match.
|
||||
)
|
||||
{
|
||||
RCODE rc = FERR_OK;
|
||||
FDB_p pDb = NULL;
|
||||
CURSOR_p pCursor = (CURSOR *)hCursor;
|
||||
SUBQUERY_p pSubQuery;
|
||||
|
||||
flmAssert( pCursor != NULL);
|
||||
*pbIsMatch = FALSE;
|
||||
|
||||
if (pCursor->pCSContext)
|
||||
{
|
||||
rc = flmCurCSTestRec( pCursor, 0, pRec, pbIsMatch);
|
||||
goto Exit2;
|
||||
}
|
||||
|
||||
// Make sure that we don't have partially finished
|
||||
// query criteria.
|
||||
|
||||
if (pCursor->QTInfo.uiNestLvl ||
|
||||
((pCursor->QTInfo.uiExpecting & FLM_Q_OPERAND) &&
|
||||
pCursor->QTInfo.pTopNode))
|
||||
{
|
||||
rc = RC_SET( FERR_CURSOR_SYNTAX);
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Optimize the subqueries as necessary
|
||||
|
||||
if (!pCursor->bOptimized)
|
||||
{
|
||||
if (RC_BAD( rc = flmCurPrep( pCursor)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
|
||||
flmAssert( pCursor->pDb != NULL);
|
||||
|
||||
pDb = pCursor->pDb;
|
||||
if (RC_BAD( rc = flmCurDbInit( pCursor)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Evaluate the record against all sub-queries until
|
||||
// we find a TRUE.
|
||||
// IMPORTANT NOTE: pRec's containerID better be set to the container it
|
||||
// came from, because flmCurEvalCriteria verifies that the record's
|
||||
// container number matches the cursor's container number.
|
||||
|
||||
flmAssert( pRec->getContainerID() != 0);
|
||||
|
||||
pSubQuery = pCursor->pSubQueryList;
|
||||
while (pSubQuery)
|
||||
{
|
||||
FLMUINT uiResult;
|
||||
|
||||
if (RC_BAD( rc = flmCurEvalCriteria( pCursor, pSubQuery,
|
||||
pRec, FALSE, &uiResult)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
if (uiResult == FLM_TRUE)
|
||||
{
|
||||
*pbIsMatch = TRUE;
|
||||
break;
|
||||
}
|
||||
pSubQuery = pSubQuery->pNext;
|
||||
}
|
||||
|
||||
Exit:
|
||||
|
||||
if (pDb)
|
||||
{
|
||||
fdbExit( pDb);
|
||||
}
|
||||
|
||||
Exit2:
|
||||
|
||||
return( rc);
|
||||
}
|
||||
|
||||
/*API~***********************************************************************
|
||||
Name : FlmCursorTestDRN
|
||||
Area : CURSOR
|
||||
Desc : Retrieves the record identified by the passed-in DRN and checks it to
|
||||
see if it satisfies the cursor selection criteria.
|
||||
Notes: This function is designed for use with cursors having only one
|
||||
associated source. Multiple sources are not supported.
|
||||
*END************************************************************************/
|
||||
RCODE
|
||||
// FERR_NOT_IMPLEMENTED - The source list associated with the cursor
|
||||
// is either empty or contains more than one source.
|
||||
FlmCursorTestDRN(
|
||||
HFCURSOR hCursor,
|
||||
// [IN] Handle to a cursor.
|
||||
FLMUINT uiDrn,
|
||||
// [IN] DRN of the record to be checked.
|
||||
FLMBOOL * pbIsMatch
|
||||
// [OUT] If *pbIsMatch == TRUE, then the record is a match.
|
||||
// Otherwise, the record did not meet the criteria and is not a match.
|
||||
)
|
||||
{
|
||||
RCODE rc = FERR_OK;
|
||||
FDB_p pDb = NULL;
|
||||
CURSOR_p pCursor = (CURSOR *)hCursor;
|
||||
SUBQUERY_p pSubQuery;
|
||||
FlmRecord * pRec = NULL;
|
||||
|
||||
flmAssert( pCursor != NULL);
|
||||
*pbIsMatch = FALSE;
|
||||
if (pCursor->pCSContext)
|
||||
{
|
||||
rc = flmCurCSTestRec( pCursor, uiDrn, NULL, pbIsMatch);
|
||||
goto Exit2;
|
||||
}
|
||||
|
||||
flmAssert( pCursor->pDb != NULL);
|
||||
if (RC_OK( rc = FlmRecordRetrieve( (HFDB)pCursor->pDb,
|
||||
pCursor->uiContainer,
|
||||
uiDrn, FO_EXACT, &pRec, NULL)))
|
||||
{
|
||||
|
||||
// Optimize the subqueries as necessary
|
||||
|
||||
if (!pCursor->bOptimized)
|
||||
{
|
||||
if (RC_BAD( rc = flmCurPrep( pCursor)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
|
||||
pDb = pCursor->pDb;
|
||||
if (RC_BAD(rc = flmCurDbInit( pCursor)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Evaluate the record against all sub-queries until
|
||||
// we find a TRUE.
|
||||
|
||||
pSubQuery = pCursor->pSubQueryList;
|
||||
while (pSubQuery)
|
||||
{
|
||||
FLMUINT uiResult;
|
||||
|
||||
if (RC_BAD( rc = flmCurEvalCriteria( pCursor, pSubQuery,
|
||||
pRec, FALSE, &uiResult)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
if (uiResult == FLM_TRUE)
|
||||
{
|
||||
*pbIsMatch = TRUE;
|
||||
break;
|
||||
}
|
||||
pSubQuery = pSubQuery->pNext;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Exit:
|
||||
|
||||
if (pDb)
|
||||
{
|
||||
fdbExit( pDb);
|
||||
}
|
||||
|
||||
if (pRec)
|
||||
{
|
||||
pRec->Release();
|
||||
}
|
||||
|
||||
Exit2:
|
||||
return( rc);
|
||||
}
|
||||
Reference in New Issue
Block a user