git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@1009 0109f412-320b-0410-ab79-c3e0c5ffbbe6
948 lines
20 KiB
C++
948 lines
20 KiB
C++
//-------------------------------------------------------------------------
|
|
// Desc: Query record retrieval
|
|
// Tabs: 3
|
|
//
|
|
// Copyright (c) 1996-2007 Novell, Inc. All Rights Reserved.
|
|
//
|
|
// This library is free software; you can redistribute it and/or
|
|
// modify it under the terms of the GNU Lesser General Public
|
|
// License as published by the Free Software Foundation; version 2.1
|
|
// of the License.
|
|
//
|
|
// This library 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
|
|
// Library Lesser General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Lesser General Public
|
|
// License along with this library; 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$
|
|
//------------------------------------------------------------------------------
|
|
|
|
#include "flaimsys.h"
|
|
|
|
FSTATIC RCODE flmCurCSTestRec(
|
|
CURSOR * pCursor,
|
|
FLMUINT uiDrn,
|
|
FlmRecord * pTestRec,
|
|
FLMBOOL * pbIsMatchRV);
|
|
|
|
/****************************************************************************
|
|
Desc: Makes a SET_DEL from a record.
|
|
****************************************************************************/
|
|
RCODE flmCurMakeKeyFromRec(
|
|
FDB * pDb,
|
|
IXD * pIxd,
|
|
F_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( RC_BAD( rc = pPool->poolCalloc( MAX_KEY_SIZ, (void **)ppucKeyBuffer)))
|
|
{
|
|
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 * pCursor,
|
|
FLMUINT uiDRN
|
|
)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
FlmRecord * pRec = NULL;
|
|
F_Pool * pTempPool;
|
|
FDB * pDb = NULL;
|
|
IXD * pIxd;
|
|
LFILE * pLFile;
|
|
SUBQUERY * 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);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Given a cursor and two DRNs, this API does the following:
|
|
****************************************************************************/
|
|
FLMEXP RCODE FLMAPI FlmCursorCompareDRNs(
|
|
HFCURSOR hCursor,
|
|
FLMUINT uiDRN1,
|
|
FLMUINT uiDRN2,
|
|
FLMUINT uiTimeLimit,
|
|
FLMINT * piCmpResult,
|
|
FLMBOOL * pbTimedOut,
|
|
FLMUINT * puiCount)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
CURSOR * pCursor = (CURSOR *)hCursor;
|
|
FDB * pDb = NULL;
|
|
F_Pool * pTempPool;
|
|
FLMBYTE * pucKey1;
|
|
FLMUINT uiKey1Len;
|
|
FLMBYTE * pucKey2;
|
|
FLMUINT uiKey2Len;
|
|
FlmRecord * pRec1 = NULL;
|
|
FlmRecord * pRec2 = NULL;
|
|
IXD * 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
|
|
{
|
|
pCursor->uiTimeLimit = FLM_SECS_TO_TIMER_UNITS( 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 * pCursor,
|
|
FLMUINT uiDrn,
|
|
FlmRecord * pTestRec,
|
|
FLMBOOL * pbIsMatchRV
|
|
)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
CS_CONTEXT * 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;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
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.
|
|
****************************************************************************/
|
|
FLMEXP RCODE FLMAPI FlmCursorTestRec(
|
|
HFCURSOR hCursor,
|
|
FlmRecord * pRec,
|
|
FLMBOOL * pbIsMatch)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
FDB * pDb = NULL;
|
|
CURSOR * pCursor = (CURSOR *)hCursor;
|
|
SUBQUERY * 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);
|
|
}
|
|
|
|
/****************************************************************************
|
|
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.
|
|
****************************************************************************/
|
|
FLMEXP RCODE FLMAPI FlmCursorTestDRN(
|
|
HFCURSOR hCursor,
|
|
FLMUINT uiDrn,
|
|
FLMBOOL * pbIsMatch)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
FDB * pDb = NULL;
|
|
CURSOR * pCursor = (CURSOR *)hCursor;
|
|
SUBQUERY * 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);
|
|
}
|