git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@7 0109f412-320b-0410-ab79-c3e0c5ffbbe6
610 lines
12 KiB
C++
610 lines
12 KiB
C++
//-------------------------------------------------------------------------
|
|
// Desc: Query record retrieval
|
|
// Tabs: 3
|
|
//
|
|
// Copyright (c) 1994-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: fqread.cpp 12329 2006-01-20 17:49:30 -0700 (Fri, 20 Jan 2006) ahodgkinson $
|
|
//-------------------------------------------------------------------------
|
|
|
|
#include "flaimsys.h"
|
|
|
|
FSTATIC RCODE flmCurCSPerformRead(
|
|
CURSOR_p pCursor,
|
|
eFlmFuncs eFlmFuncId,
|
|
FlmRecord ** ppRecordRV,
|
|
FLMUINT * puiDrnRV,
|
|
FLMUINT * puiCountRV);
|
|
|
|
FSTATIC RCODE flmCurGetDRNRec(
|
|
CURSOR_p pCursor,
|
|
FLMUINT uiDRN,
|
|
FlmRecord ** ppRecord);
|
|
|
|
/****************************************************************************
|
|
Desc: Gets the requested record, DRN, or count over the CS line.
|
|
****************************************************************************/
|
|
FSTATIC RCODE flmCurCSPerformRead(
|
|
CURSOR_p pCursor,
|
|
eFlmFuncs eFlmFuncId,
|
|
FlmRecord ** ppRecordRV,
|
|
FLMUINT * puiDrnRV,
|
|
FLMUINT * puiCountRV)
|
|
{
|
|
CS_CONTEXT_p pCSContext = pCursor->pCSContext;
|
|
FCL_WIRE Wire( pCSContext);
|
|
void * pvMark = GedPoolMark( &pCSContext->pool);
|
|
RCODE rc = FERR_OK;
|
|
FLMUINT uiCSOp = 0;
|
|
|
|
// 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;
|
|
}
|
|
}
|
|
|
|
Wire.setFDB( pCursor->pDb);
|
|
|
|
// Set the temporary pool
|
|
|
|
Wire.setPool( &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;
|
|
}
|
|
}
|
|
|
|
// Map Function ID to CS Op
|
|
switch (eFlmFuncId)
|
|
{
|
|
case FLM_CURSOR_REC_COUNT:
|
|
uiCSOp = FCS_OP_ITERATOR_COUNT;
|
|
break;
|
|
case FLM_CURSOR_FIRST:
|
|
uiCSOp = FCS_OP_ITERATOR_FIRST;
|
|
break;
|
|
case FLM_CURSOR_LAST:
|
|
uiCSOp = FCS_OP_ITERATOR_LAST;
|
|
break;
|
|
case FLM_CURSOR_NEXT:
|
|
uiCSOp = FCS_OP_ITERATOR_NEXT;
|
|
break;
|
|
case FLM_CURSOR_PREV:
|
|
uiCSOp = FCS_OP_ITERATOR_PREV;
|
|
break;
|
|
case FLM_CURSOR_FIRST_DRN:
|
|
uiCSOp = FCS_OP_ITERATOR_FIRST;
|
|
break;
|
|
case FLM_CURSOR_LAST_DRN:
|
|
uiCSOp = FCS_OP_ITERATOR_LAST;
|
|
break;
|
|
case FLM_CURSOR_NEXT_DRN:
|
|
uiCSOp = FCS_OP_ITERATOR_NEXT;
|
|
break;
|
|
case FLM_CURSOR_PREV_DRN:
|
|
uiCSOp = FCS_OP_ITERATOR_PREV;
|
|
break;
|
|
default:
|
|
flmAssert( 0); // Unsupported flaim function hit.
|
|
}
|
|
|
|
// Send a request to perform the read.
|
|
|
|
if (RC_BAD( rc = Wire.sendOp( FCS_OPCLASS_ITERATOR, uiCSOp)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if (RC_BAD( rc = Wire.sendNumber(
|
|
WIRE_VALUE_ITERATOR_ID, pCursor->uiCursorId)))
|
|
{
|
|
goto Transmission_Error;
|
|
}
|
|
|
|
if (puiDrnRV && !ppRecordRV)
|
|
{
|
|
if (RC_BAD( rc = Wire.sendNumber(
|
|
WIRE_VALUE_FLAGS, FCS_ITERATOR_DRN_FLAG)))
|
|
{
|
|
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 (puiCountRV)
|
|
{
|
|
*puiCountRV = (FLMUINT)Wire.getCount();
|
|
}
|
|
|
|
if (ppRecordRV)
|
|
{
|
|
if ((*ppRecordRV = Wire.getRecord()) != NULL)
|
|
{
|
|
(*ppRecordRV)->AddRef();
|
|
}
|
|
}
|
|
|
|
if (puiDrnRV)
|
|
{
|
|
if (ppRecordRV && *ppRecordRV)
|
|
{
|
|
*puiDrnRV = (*ppRecordRV)->getID();
|
|
}
|
|
else
|
|
{
|
|
*puiDrnRV = Wire.getDrn();
|
|
}
|
|
}
|
|
|
|
rc = Wire.getRCode();
|
|
|
|
Exit:
|
|
|
|
GedPoolReset( &pCSContext->pool, pvMark);
|
|
return( rc);
|
|
|
|
Transmission_Error:
|
|
pCSContext->bConnectionGood = FALSE;
|
|
goto Exit;
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Gets the requested record.
|
|
****************************************************************************/
|
|
RCODE flmCurPerformRead(
|
|
eFlmFuncs eFlmFuncId,
|
|
HFCURSOR hCursor,
|
|
FLMBOOL bReadForward,
|
|
FLMBOOL bFirstRead,
|
|
FLMUINT * puiSkipCount,
|
|
FlmRecord ** ppRecord,
|
|
FLMUINT * puiDrn
|
|
)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
FLMUINT uiDrn = 0;
|
|
CURSOR * pCursor = (CURSOR *)hCursor;
|
|
|
|
if (!pCursor)
|
|
{
|
|
flmAssert( 0);
|
|
rc = RC_SET( FERR_INVALID_PARM);
|
|
goto Exit;
|
|
}
|
|
|
|
// Make sure the record is clear.
|
|
|
|
if (ppRecord && *ppRecord)
|
|
{
|
|
(*ppRecord)->Release();
|
|
*ppRecord = NULL;
|
|
}
|
|
|
|
if (pCursor->bEliminateDups)
|
|
{
|
|
if( pCursor->pDRNSet && (bFirstRead || !pCursor->bOptimized))
|
|
{
|
|
pCursor->pDRNSet->Release();
|
|
pCursor->pDRNSet = NULL;
|
|
}
|
|
}
|
|
|
|
if (!bFirstRead)
|
|
{
|
|
if (pCursor->ReadRc == FERR_EOF_HIT)
|
|
{
|
|
if (bReadForward)
|
|
{
|
|
rc = pCursor->ReadRc;
|
|
goto Save_RecId;
|
|
}
|
|
else
|
|
{
|
|
bFirstRead = TRUE;
|
|
}
|
|
}
|
|
else if (pCursor->ReadRc == FERR_BOF_HIT)
|
|
{
|
|
if (!bReadForward)
|
|
{
|
|
rc = pCursor->ReadRc;
|
|
goto Save_RecId;
|
|
}
|
|
else
|
|
{
|
|
bFirstRead = TRUE;
|
|
}
|
|
}
|
|
|
|
// No read has been performed yet - or the last
|
|
// read returned an error besides eof or bof.
|
|
|
|
else if (!pCursor->uiLastRecID)
|
|
{
|
|
bFirstRead = TRUE;
|
|
}
|
|
}
|
|
|
|
pCursor->ReadRc = FERR_OK;
|
|
|
|
if (pCursor->pCSContext)
|
|
{
|
|
rc = flmCurCSPerformRead( pCursor, eFlmFuncId,
|
|
ppRecord, &uiDrn, NULL);
|
|
}
|
|
else
|
|
{
|
|
// Optimize the query if necessary.
|
|
|
|
if (!pCursor->bOptimized)
|
|
{
|
|
bFirstRead = TRUE;
|
|
if (RC_BAD( rc = flmCurPrep( pCursor)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// If this is an empty query, return EOF or BOF.
|
|
|
|
if (pCursor->bEmpty)
|
|
{
|
|
pCursor->rc =
|
|
rc = (RCODE)((bReadForward)
|
|
? RC_SET( FERR_EOF_HIT)
|
|
: RC_SET( FERR_BOF_HIT));
|
|
}
|
|
else
|
|
{
|
|
pCursor->rc = rc = flmCurSearch( eFlmFuncId, pCursor, bFirstRead,
|
|
bReadForward, NULL,
|
|
puiSkipCount, ppRecord, &uiDrn);
|
|
}
|
|
}
|
|
|
|
if (RC_BAD( rc))
|
|
{
|
|
if (rc == FERR_EOF_HIT || rc == FERR_BOF_HIT)
|
|
{
|
|
pCursor->ReadRc = rc;
|
|
}
|
|
uiDrn = 0;
|
|
}
|
|
|
|
Save_RecId:
|
|
|
|
// Set a flag indicating that this cursor has been repositioned.
|
|
|
|
pCursor->bUsePrcntPos = FALSE;
|
|
pCursor->uiLastRecID = uiDrn;
|
|
|
|
Exit:
|
|
if (puiDrn)
|
|
{
|
|
*puiDrn = uiDrn;
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Gets the requested record given a DRN.
|
|
****************************************************************************/
|
|
FSTATIC RCODE flmCurGetDRNRec(
|
|
CURSOR_p pCursor,
|
|
FLMUINT uiDRN,
|
|
FlmRecord ** ppRecord)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
FDB_p pDb = NULL;
|
|
LFILE * pLFile;
|
|
|
|
if (pCursor->pCSContext)
|
|
{
|
|
HFDB hDb = (HFDB)pCursor->pDb;
|
|
FLMUINT uiContainer = pCursor->uiContainer;
|
|
FCL_WIRE Wire( pCursor->pCSContext);
|
|
|
|
Wire.setFDB( (FDB *)hDb);
|
|
for (;;)
|
|
{
|
|
rc = FlmRecordRetrieve( hDb, uiContainer, uiDRN, FO_EXACT, ppRecord, NULL);
|
|
if (rc != FERR_OLD_VIEW)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (RC_BAD( rc = Wire.doTransOp( FCS_OP_TRANSACTION_RESET,
|
|
FLM_READ_TRANS, 0, 0)))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
goto Exit;
|
|
}
|
|
|
|
pDb = pCursor->pDb;
|
|
if (RC_BAD( rc = flmCurDbInit( pCursor)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
rc = flmRcaRetrieveRec( pDb, NULL, pCursor->uiContainer,
|
|
uiDRN, FALSE, NULL, NULL, ppRecord);
|
|
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,
|
|
ppRecord, NULL, NULL)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
if (pDb)
|
|
{
|
|
fdbExit( pDb);
|
|
}
|
|
return( rc);
|
|
}
|
|
|
|
/*API~***********************************************************************
|
|
Name : FlmCursorCurrent
|
|
Area : CURSOR
|
|
Desc : Retrieves the record currently pointed to by a cursor.
|
|
*END************************************************************************/
|
|
RCODE FlmCursorCurrent(
|
|
HFCURSOR hCursor,
|
|
// [IN] Handle to a cursor.
|
|
FlmRecord ** ppRecord
|
|
// [OUT] Pointer to a FlmRecord. *ppRecord will be non-NULL if the
|
|
// call is successful. Otherwise, *ppRecord will be NULL.
|
|
)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
CURSOR_p pCursor = (CURSOR *)hCursor;
|
|
|
|
if (!pCursor)
|
|
{
|
|
flmAssert( 0);
|
|
rc = RC_SET( FERR_INVALID_PARM);
|
|
goto Exit;
|
|
}
|
|
*ppRecord = NULL;
|
|
|
|
if (pCursor->uiLastRecID == 0)
|
|
{
|
|
if (RC_OK( rc = pCursor->ReadRc))
|
|
{
|
|
rc = RC_SET( FERR_BOF_HIT);
|
|
}
|
|
}
|
|
else if (RC_OK( pCursor->rc))
|
|
{
|
|
if (RC_BAD( rc = flmCurGetDRNRec( pCursor, pCursor->uiLastRecID,
|
|
ppRecord)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
rc = pCursor->rc;
|
|
}
|
|
|
|
Exit:
|
|
return( rc);
|
|
}
|
|
|
|
/*API~***********************************************************************
|
|
Name : FlmCursorCurrentDRN
|
|
Area : CURSOR
|
|
Desc : Retrieves the DRN of the current record in a set defined by a cursor.
|
|
*END************************************************************************/
|
|
RCODE FlmCursorCurrentDRN(
|
|
HFCURSOR hCursor,
|
|
// [IN] Handle to a cursor.
|
|
FLMUINT * puiDrn
|
|
// [OUT] Pointer to a DRN. If the call is successful, the value
|
|
// of *puiDrn will be the DRN of the current record.
|
|
)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
CURSOR_p pCursor = (CURSOR *)hCursor;
|
|
|
|
if (!pCursor)
|
|
{
|
|
flmAssert( 0);
|
|
rc = RC_SET( FERR_INVALID_PARM);
|
|
goto Exit;
|
|
}
|
|
|
|
*puiDrn = 0;
|
|
|
|
if (!pCursor->uiLastRecID)
|
|
{
|
|
if (RC_OK( rc = pCursor->ReadRc))
|
|
{
|
|
rc = RC_SET( FERR_BOF_HIT);
|
|
}
|
|
}
|
|
else if (RC_OK( pCursor->rc))
|
|
{
|
|
*puiDrn = pCursor->uiLastRecID;
|
|
rc = FERR_OK;
|
|
}
|
|
else
|
|
{
|
|
rc = pCursor->rc;
|
|
}
|
|
|
|
Exit:
|
|
return( rc);
|
|
}
|
|
|
|
/*API~***********************************************************************
|
|
Desc : Positions the cursor to a next or previous item at an offset relative
|
|
to the current item and retrieves that item from the database.
|
|
Notes: Requests that position beyond the end of the result set will
|
|
cause an EOF_HIT error to be returned. Likewise, requests that
|
|
position before the beginning of the result set will cause a
|
|
BOF_HIT error to be returned. Passing a relative position of 0 is
|
|
invalid and will cause ILLEGAL_OP to be returned.
|
|
*END************************************************************************/
|
|
RCODE FlmCursorMoveRelative(
|
|
HFCURSOR hCursor,
|
|
FLMINT * piPosition,
|
|
FlmRecord ** ppRecord
|
|
)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
FLMINT iPosition;
|
|
FLMUINT uiTmpPos;
|
|
|
|
if ((iPosition = *piPosition) == 0)
|
|
{
|
|
flmAssert( 0);
|
|
rc = RC_SET( FERR_ILLEGAL_OP);
|
|
goto Exit;
|
|
}
|
|
|
|
uiTmpPos = (FLMUINT)((iPosition < 0)
|
|
? (FLMUINT)(-iPosition)
|
|
: (FLMUINT)iPosition);
|
|
|
|
rc = flmCurPerformRead( FLM_CURSOR_MOVE_RELATIVE, hCursor,
|
|
(FLMBOOL)((iPosition > 0) ? TRUE : FALSE), FALSE,
|
|
&uiTmpPos, ppRecord, NULL);
|
|
|
|
*piPosition = (FLMINT)((iPosition < 0)
|
|
? (FLMINT)(iPosition + uiTmpPos)
|
|
: (FLMINT)(iPosition - uiTmpPos));
|
|
Exit:
|
|
return( rc);
|
|
}
|
|
|
|
/*API~***********************************************************************
|
|
Name : FlmCursorRecCount
|
|
Area : CURSOR
|
|
Desc : Returns the number of records in a set defined by a cursor.
|
|
*END************************************************************************/
|
|
RCODE FlmCursorRecCount(
|
|
HFCURSOR hCursor,
|
|
// [IN] Handle to a cursor.
|
|
FLMUINT * puiCount
|
|
// [OUT] Pointer to a FLMUINT. If the call is successful, the value
|
|
// of *puiCount will be number of records in the set defined by the
|
|
// cursor.
|
|
)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
CURSOR_p pCursor = (CURSOR *)hCursor;
|
|
RCODE TmpRc;
|
|
FDB * pDb = NULL;
|
|
FLMBOOL bSavedPosition = FALSE;
|
|
|
|
if (!pCursor)
|
|
{
|
|
flmAssert( 0);
|
|
rc = RC_SET( FERR_INVALID_PARM);
|
|
goto Exit;
|
|
}
|
|
*puiCount = 0;
|
|
|
|
if (pCursor->pCSContext)
|
|
{
|
|
rc = flmCurCSPerformRead( pCursor, FLM_CURSOR_REC_COUNT,
|
|
NULL, NULL, puiCount);
|
|
goto Exit2;
|
|
}
|
|
|
|
pDb = pCursor->pDb;
|
|
if( RC_BAD( rc = flmCurDbInit( pCursor)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Optimize the subqueries as necessary
|
|
|
|
if (!pCursor->bOptimized)
|
|
{
|
|
if (RC_BAD( rc = flmCurPrep( pCursor)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// Save current position so we can restore it after doing the count.
|
|
|
|
bSavedPosition = TRUE;
|
|
rc = flmCurSearch( FLM_CURSOR_REC_COUNT, pCursor, TRUE, TRUE,
|
|
puiCount, NULL, NULL, NULL);
|
|
if (rc == FERR_EOF_HIT)
|
|
{
|
|
rc = FERR_OK;
|
|
}
|
|
|
|
Exit:
|
|
|
|
// Restore saved cursor settings if necessary.
|
|
|
|
if (bSavedPosition)
|
|
{
|
|
if (RC_BAD( TmpRc = flmCurRestorePosition( pCursor)))
|
|
{
|
|
if (RC_OK( rc))
|
|
{
|
|
rc = TmpRc;
|
|
}
|
|
}
|
|
}
|
|
|
|
flmExit( FLM_CURSOR_REC_COUNT, pDb, rc);
|
|
pCursor->rc = rc;
|
|
Exit2:
|
|
return( rc);
|
|
}
|