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:
886
flaim/src/kyget.cpp
Normal file
886
flaim/src/kyget.cpp
Normal file
@@ -0,0 +1,886 @@
|
||||
//-------------------------------------------------------------------------
|
||||
// Desc: Get index keys from a record.
|
||||
// Tabs: 3
|
||||
//
|
||||
// Copyright (c) 1992-2001,2003-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: kyget.cpp 12329 2006-01-20 17:49:30 -0700 (Fri, 20 Jan 2006) ahodgkinson $
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
#include "flaimsys.h"
|
||||
|
||||
typedef struct CMP_KEY_ELM * CMP_KEY_ELM_p;
|
||||
|
||||
typedef struct CMP_KEY_ELM
|
||||
{
|
||||
const FLMBYTE * pValue;
|
||||
FLMUINT uiValueLen;
|
||||
FLMUINT uiType;
|
||||
FLMUINT uiTagNum;
|
||||
CMP_KEY_ELM_p pParent;
|
||||
FLMBOOL bFirstSubstring;
|
||||
FLMBOOL bSubstringComponent;
|
||||
} CMP_KEY_ELM;
|
||||
|
||||
FSTATIC RCODE flmKeyAdd(
|
||||
FDB_p pDb,
|
||||
IXD_p pIxd,
|
||||
FlmRecord * pRecord,
|
||||
FLMUINT uiContainerNum,
|
||||
POOL * pPool,
|
||||
FLMBOOL bRemoveDups,
|
||||
REC_KEY ** ppKeyList);
|
||||
|
||||
FSTATIC RCODE flmGetFieldKeys(
|
||||
FDB_p pDb,
|
||||
IXD_p pIxd,
|
||||
FlmRecord * pRecord,
|
||||
FLMUINT uiContainerNum,
|
||||
void ** ppPathFlds,
|
||||
FLMUINT uiLeafFieldLevel,
|
||||
void * pvField,
|
||||
FLMBOOL bRemoveDups,
|
||||
POOL * pPool,
|
||||
REC_KEY ** ppKeyList,
|
||||
FLMBOOL * bHasCmpKeys);
|
||||
|
||||
FSTATIC RCODE flmBuildCompoundKey(
|
||||
FDB_p pDb,
|
||||
IXD_p pIxd,
|
||||
CMP_KEY_ELM_p pCmpKeyElm,
|
||||
FLMBOOL bRemoveDups,
|
||||
POOL * pPool,
|
||||
FLMUINT uiContainerNum,
|
||||
REC_KEY ** ppKeyList);
|
||||
|
||||
FSTATIC RCODE flmGetCmpKeyElement(
|
||||
FDB_p pDb,
|
||||
IXD_p pIxd,
|
||||
IFD_p pIfd,
|
||||
FLMUINT uiCdlEntry,
|
||||
FLMUINT uiCompoundPos,
|
||||
CMP_KEY_ELM_p pParent,
|
||||
FLMBOOL bRemoveDups,
|
||||
POOL * pPool,
|
||||
REC_KEY ** ppKeyList,
|
||||
FlmRecord * pRecord,
|
||||
FLMUINT uiContainerNum,
|
||||
FLD_CONTEXT * pFldContext);
|
||||
|
||||
FSTATIC RCODE flmGetCompoundKeys(
|
||||
FDB_p pDb,
|
||||
IXD_p pIxd,
|
||||
FLMBOOL bRemoveDups,
|
||||
POOL * pPool,
|
||||
FlmRecord * pRecord,
|
||||
FLMUINT uiContainerNum,
|
||||
REC_KEY ** ppKeyList);
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
Desc: This routine adds a key to a key list.
|
||||
*****************************************************************************/
|
||||
FSTATIC RCODE flmKeyAdd(
|
||||
FDB_p pDb,
|
||||
IXD_p pIxd,
|
||||
FlmRecord * pRecord,
|
||||
FLMUINT uiContainerNum,
|
||||
POOL * pPool,
|
||||
FLMBOOL bRemoveDups,
|
||||
REC_KEY ** ppKeyList)
|
||||
{
|
||||
RCODE rc = FERR_OK;
|
||||
REC_KEY * pTempRecKey;
|
||||
FLMBYTE Key1Buf [MAX_KEY_SIZ];
|
||||
FLMUINT uiKey1Len;
|
||||
FLMBYTE Key2Buf [MAX_KEY_SIZ];
|
||||
FLMUINT uiKey2Len;
|
||||
|
||||
/* First see if the key is already in the list. */
|
||||
|
||||
pTempRecKey = *ppKeyList;
|
||||
if( pTempRecKey && bRemoveDups)
|
||||
{
|
||||
if( RC_BAD( rc = KYTreeToKey( pDb, pIxd, pRecord, uiContainerNum,
|
||||
Key1Buf, &uiKey1Len, 0)))
|
||||
goto Exit;
|
||||
|
||||
while (pTempRecKey != NULL)
|
||||
{
|
||||
|
||||
/* Build the collated keys for each key tree in *ppKeyList */
|
||||
|
||||
if( RC_BAD( rc = KYTreeToKey( pDb, pIxd, pTempRecKey->pKey,
|
||||
uiContainerNum,
|
||||
Key2Buf, &uiKey2Len, 0)))
|
||||
goto Exit;
|
||||
|
||||
/*
|
||||
If the key was found, return success - don't add to list.
|
||||
Also, free up the memory pool back to where the key
|
||||
started.
|
||||
*/
|
||||
|
||||
if (KYKeyCompare( Key1Buf, uiKey1Len, Key2Buf, uiKey2Len) == BT_EQ_KEY)
|
||||
{
|
||||
// Should return FERR_OK.
|
||||
goto Exit;
|
||||
}
|
||||
pTempRecKey = pTempRecKey->pNextKey;
|
||||
}
|
||||
}
|
||||
|
||||
if ((pTempRecKey = (REC_KEY *)GedPoolAlloc( pPool,
|
||||
sizeof(REC_KEY))) == NULL)
|
||||
{
|
||||
rc = RC_SET( FERR_MEM);
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
pTempRecKey->pKey = pRecord;
|
||||
pRecord->AddRef();
|
||||
pTempRecKey->pNextKey = *ppKeyList;
|
||||
*ppKeyList = pTempRecKey;
|
||||
Exit:
|
||||
return( rc);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
Desc: This routine gets all of the keys for a field and either saves them
|
||||
as an element for a compound key, or saves them into the key list.
|
||||
*****************************************************************************/
|
||||
FSTATIC RCODE flmGetFieldKeys(
|
||||
FDB_p pDb,
|
||||
IXD_p pIxd,
|
||||
FlmRecord * pRecord,
|
||||
FLMUINT uiContainerNum,
|
||||
void ** ppPathFlds,
|
||||
FLMUINT uiLeafFieldLevel,
|
||||
void * pvField,
|
||||
FLMBOOL bRemoveDups,
|
||||
POOL * pPool,
|
||||
REC_KEY ** ppKeyList,
|
||||
FLMBOOL * pbHasCmpKeys)
|
||||
{
|
||||
RCODE rc = FERR_OK;
|
||||
IFD_p pIfd;
|
||||
FlmRecord * pFieldRecord = NULL;
|
||||
void * pvRootContext;
|
||||
void * pvValueField;
|
||||
const FLMBYTE * pExportPtr = NULL;
|
||||
FLMBYTE * pImportDataPtr;
|
||||
FLMUINT uiCounter;
|
||||
FLMUINT uiTagNum;
|
||||
FLMUINT uiExportLen;
|
||||
FLMUINT uiFieldType;
|
||||
FLMUINT * puiFieldPath;
|
||||
FLMUINT uiLevel;
|
||||
FLMUINT uiLanguage = pIxd->uiLanguage;
|
||||
FLMBYTE * pbyTmpBuf = NULL;
|
||||
|
||||
uiTagNum = pRecord->getFieldID( pvField);
|
||||
|
||||
// See if the field is defined in this index.
|
||||
|
||||
pIfd = pIxd->pFirstIfd;
|
||||
for (uiCounter = 0; uiCounter < pIxd->uiNumFlds; uiCounter++, pIfd++ )
|
||||
{
|
||||
if (pIfd->uiFldNum == uiTagNum)
|
||||
{
|
||||
if (flmCheckIfdPath( pIfd, pRecord, ppPathFlds, uiLeafFieldLevel,
|
||||
pvField, &pvRootContext))
|
||||
{
|
||||
break; // Found one that matches.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If the field is not part of the index, return. */
|
||||
|
||||
if( uiCounter == pIxd->uiNumFlds)
|
||||
goto Exit; /* Should return FERR_OK. */
|
||||
|
||||
/* At this point, we know the field is part of the index. */
|
||||
|
||||
pExportPtr = pRecord->getDataPtr( pvField);
|
||||
uiExportLen = pRecord->getDataLength( pvField);
|
||||
uiFieldType = pRecord->getDataType( pvField);
|
||||
|
||||
/*
|
||||
VISIT:
|
||||
Scott thinks we should treat all keys like a compound key and get rid of the
|
||||
flmKeyAdd() call above.
|
||||
*/
|
||||
|
||||
if (pIfd->uiFlags & IFD_COMPOUND)
|
||||
{
|
||||
rc = KYCmpKeyAdd2Lst( pDb, pIxd, pIfd, pvField, pvRootContext);
|
||||
*pbHasCmpKeys = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( (pFieldRecord = f_new FlmRecord) == NULL)
|
||||
{
|
||||
rc = RC_SET( FERR_MEM);
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
pFieldRecord->setContainerID( uiContainerNum);
|
||||
|
||||
// Build a record with just this field in it.
|
||||
puiFieldPath = pIfd->pFieldPathPToC;
|
||||
for( uiLevel = 0; *puiFieldPath; puiFieldPath++)
|
||||
{
|
||||
if( RC_BAD( rc = pFieldRecord->insertLast( uiLevel++,
|
||||
*puiFieldPath, FLM_CONTEXT_TYPE, &pvValueField)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
|
||||
if (pIfd->uiFlags & IFD_CONTEXT)
|
||||
{
|
||||
/* Create the field and put it into the key list. */
|
||||
|
||||
rc = flmKeyAdd( pDb, pIxd, pFieldRecord, uiContainerNum,
|
||||
pPool, bRemoveDups, ppKeyList);
|
||||
}
|
||||
else if ((pIfd->uiFlags & (IFD_EACHWORD|IFD_SUBSTRING)) &&
|
||||
(uiFieldType == FLM_TEXT_TYPE))
|
||||
{
|
||||
const FLMBYTE * pText = pExportPtr;
|
||||
FLMUINT uiTextLen = uiExportLen;
|
||||
FLMUINT uiKeyLen;
|
||||
FLMBOOL bReturn;
|
||||
FLMBOOL bFirstSubstring = (pIfd->uiFlags & IFD_SUBSTRING)
|
||||
? TRUE : FALSE;
|
||||
|
||||
if (!pbyTmpBuf)
|
||||
{
|
||||
if (RC_BAD( rc = f_alloc( MAX_KEY_SIZ, &pbyTmpBuf)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
|
||||
/* Get each word out of the key and save as a separate key. */
|
||||
|
||||
for( pText = pExportPtr;;)
|
||||
{
|
||||
bReturn = (pIfd->uiFlags & IFD_EACHWORD)
|
||||
? (FLMBOOL) KYEachWordParse( &pText, &uiTextLen,
|
||||
pIfd->uiLimit,
|
||||
pbyTmpBuf, &uiKeyLen)
|
||||
: (FLMBOOL) KYSubstringParse( &pText, &uiTextLen,
|
||||
pIfd->uiFlags, pIfd->uiLimit,
|
||||
pbyTmpBuf, &uiKeyLen);
|
||||
if( !bReturn)
|
||||
break;
|
||||
|
||||
if (!pFieldRecord)
|
||||
{
|
||||
if( (pFieldRecord = f_new FlmRecord) == NULL)
|
||||
{
|
||||
rc = RC_SET( FERR_MEM);
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
pFieldRecord->setContainerID( uiContainerNum);
|
||||
puiFieldPath = pIfd->pFieldPathPToC;
|
||||
|
||||
for( uiLevel = 0; *puiFieldPath; puiFieldPath++)
|
||||
{
|
||||
if (RC_BAD( rc = pFieldRecord->insertLast( uiLevel++,
|
||||
*puiFieldPath, FLM_CONTEXT_TYPE, &pvValueField)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( RC_BAD( rc = pFieldRecord->allocStorageSpace( pvValueField,
|
||||
FLM_TEXT_TYPE,
|
||||
uiKeyLen,
|
||||
0, 0, 0,
|
||||
&pImportDataPtr,
|
||||
NULL)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
f_memcpy( pImportDataPtr, pbyTmpBuf, uiKeyLen);
|
||||
|
||||
if( (pIfd->uiFlags & IFD_SUBSTRING) && !bFirstSubstring)
|
||||
{
|
||||
pFieldRecord->setLeftTruncated( pvValueField, TRUE);
|
||||
}
|
||||
if( RC_BAD( rc = flmKeyAdd( pDb, pIxd, pFieldRecord,
|
||||
uiContainerNum, pPool, bRemoveDups, ppKeyList)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
pFieldRecord->Release();
|
||||
pFieldRecord = NULL;
|
||||
|
||||
if( (pIfd->uiFlags & IFD_SUBSTRING) &&
|
||||
uiTextLen == 1 &&
|
||||
!(uiLanguage >= FIRST_DBCS_LANG &&
|
||||
uiLanguage <= LAST_DBCS_LANG))
|
||||
{
|
||||
break;
|
||||
}
|
||||
bFirstSubstring = FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Oct98 - Accept zero length fields. */
|
||||
/* Copy the field and put it into the key list. */
|
||||
|
||||
if( RC_BAD( rc = pFieldRecord->allocStorageSpace(
|
||||
pvValueField,
|
||||
pRecord->getDataType( pvField),
|
||||
uiExportLen,
|
||||
0, 0, 0, &pImportDataPtr, NULL)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
f_memcpy( pImportDataPtr, pExportPtr, uiExportLen);
|
||||
|
||||
if( RC_BAD( rc = flmKeyAdd( pDb, pIxd, pFieldRecord,
|
||||
uiContainerNum, pPool, bRemoveDups, ppKeyList)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Exit:
|
||||
|
||||
if (pFieldRecord)
|
||||
{
|
||||
pFieldRecord->Release();
|
||||
}
|
||||
|
||||
if (pbyTmpBuf)
|
||||
{
|
||||
f_free( &pbyTmpBuf);
|
||||
}
|
||||
return( rc);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
Desc: This routine builds a compound key and saves it into the key list.
|
||||
*****************************************************************************/
|
||||
FSTATIC RCODE flmBuildCompoundKey(
|
||||
FDB_p pDb,
|
||||
IXD_p pIxd,
|
||||
CMP_KEY_ELM_p pCmpKeyElm,
|
||||
FLMBOOL bRemoveDups,
|
||||
POOL * pPool,
|
||||
FLMUINT uiContainerNum,
|
||||
REC_KEY ** ppKeyList)
|
||||
{
|
||||
RCODE rc = FERR_OK;
|
||||
FlmRecord * pRecord = NULL;
|
||||
FLMBYTE * pImportDataPtr;
|
||||
|
||||
// Build fields for each value in the list.
|
||||
|
||||
while (pCmpKeyElm)
|
||||
{
|
||||
if (pCmpKeyElm->uiTagNum != 0)
|
||||
{
|
||||
void * pvValueField;
|
||||
FLMUINT uiExportLen = pCmpKeyElm->uiValueLen;
|
||||
|
||||
if (!pRecord)
|
||||
{
|
||||
if( (pRecord = f_new FlmRecord) == NULL)
|
||||
{
|
||||
rc = RC_SET( FERR_MEM);
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
pRecord->setContainerID( uiContainerNum);
|
||||
}
|
||||
|
||||
// VISIT: Add full path of each key.
|
||||
if( RC_BAD( rc = pRecord->insertLast( 0,
|
||||
pCmpKeyElm->uiTagNum, pCmpKeyElm->uiType, &pvValueField)))
|
||||
goto Exit;
|
||||
|
||||
// VISIT: Don't know what type.
|
||||
|
||||
if( RC_BAD( rc = pRecord->allocStorageSpace( pvValueField,
|
||||
pCmpKeyElm->uiType,
|
||||
uiExportLen,
|
||||
0, 0, 0,
|
||||
&pImportDataPtr,
|
||||
NULL)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
if( uiExportLen)
|
||||
{
|
||||
f_memcpy( pImportDataPtr, pCmpKeyElm->pValue, uiExportLen);
|
||||
}
|
||||
|
||||
if( pCmpKeyElm->bSubstringComponent &&
|
||||
!pCmpKeyElm->bFirstSubstring)
|
||||
{
|
||||
pRecord->setLeftTruncated( pvValueField, TRUE);
|
||||
}
|
||||
}
|
||||
pCmpKeyElm = pCmpKeyElm->pParent;
|
||||
}
|
||||
|
||||
/* Add the key to the key list. */
|
||||
|
||||
if( pRecord)
|
||||
{
|
||||
if (RC_BAD( rc = flmKeyAdd( pDb, pIxd, pRecord, uiContainerNum,
|
||||
pPool, bRemoveDups, ppKeyList)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
|
||||
Exit:
|
||||
|
||||
if (pRecord)
|
||||
{
|
||||
pRecord->Release();
|
||||
}
|
||||
|
||||
return( rc);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
Desc: This routine gets an element of a compound key and links it to
|
||||
the previous element in the compound key.
|
||||
Note: This routine recursively calls itself.
|
||||
The code is very similar to KYCmpKeyElmBld() in kycompnd.cpp.
|
||||
*****************************************************************************/
|
||||
FSTATIC RCODE flmGetCmpKeyElement(
|
||||
FDB_p pDb,
|
||||
IXD_p pIxd,
|
||||
IFD_p pIfd,
|
||||
FLMUINT uiCdlEntry,
|
||||
FLMUINT uiCompoundPos,
|
||||
CMP_KEY_ELM_p pParent,
|
||||
FLMBOOL bRemoveDups,
|
||||
POOL * pPool,
|
||||
REC_KEY ** ppKeyList,
|
||||
FlmRecord * pRecord,
|
||||
FLMUINT uiContainerNum,
|
||||
FLD_CONTEXT * pFldContext)
|
||||
{
|
||||
RCODE rc = FERR_OK;
|
||||
CDL_p * ppCdlTbl = pDb->KrefCntrl.ppCdlTbl;
|
||||
CDL_p pCdl = ppCdlTbl [uiCdlEntry];
|
||||
CMP_KEY_ELM CmpKeyElm;
|
||||
void * pvField;
|
||||
void * pSaveParentAnchor;
|
||||
FLMBYTE * pbyTmpBuf = NULL;
|
||||
IFD_p pNextIfdPiece;
|
||||
FLMUINT uiNextCdlEntry;
|
||||
FLMUINT uiNextPiecePos; // 0 if this is the last piece.
|
||||
FLMUINT uiLanguage = pIxd->uiLanguage;
|
||||
FLMBOOL bBuiltKeyPiece;
|
||||
|
||||
/* If there are no values, see if we are on the last IFD. */
|
||||
|
||||
CmpKeyElm.pParent = pParent;
|
||||
CmpKeyElm.pValue = NULL;
|
||||
CmpKeyElm.uiType = 0;
|
||||
CmpKeyElm.uiValueLen = 0;
|
||||
CmpKeyElm.uiTagNum = 0;
|
||||
CmpKeyElm.bFirstSubstring = FALSE;
|
||||
CmpKeyElm.bSubstringComponent = FALSE;
|
||||
|
||||
// New 05/06/96
|
||||
// Determine the next IFD compound piece.
|
||||
|
||||
for( pNextIfdPiece = (IFD_p)NULL,
|
||||
uiNextCdlEntry = uiCdlEntry + 1,
|
||||
uiNextPiecePos = 0
|
||||
; ((pIfd+uiNextPiecePos)->uiFlags & IFD_LAST) == 0
|
||||
; )
|
||||
{
|
||||
if ((pIfd+uiNextPiecePos)->uiCompoundPos !=
|
||||
(pIfd+uiNextPiecePos+1)->uiCompoundPos)
|
||||
{
|
||||
pNextIfdPiece = pIfd + uiNextPiecePos + 1;
|
||||
uiNextCdlEntry = uiCdlEntry + uiNextPiecePos + 1;
|
||||
break;
|
||||
}
|
||||
if( !pCdl)
|
||||
{
|
||||
pIfd++;
|
||||
pCdl = ppCdlTbl [++uiCdlEntry];
|
||||
uiNextCdlEntry = uiCdlEntry + 1;
|
||||
}
|
||||
else
|
||||
uiNextPiecePos++;
|
||||
}
|
||||
|
||||
pSaveParentAnchor = pFldContext->pParentAnchor;
|
||||
bBuiltKeyPiece = FALSE;
|
||||
|
||||
/* Loop through all of the values in this IFD. */
|
||||
|
||||
while (pCdl || !bBuiltKeyPiece)
|
||||
{
|
||||
|
||||
// Restore context values for each iteration.
|
||||
pFldContext->pParentAnchor = pSaveParentAnchor;
|
||||
|
||||
/*
|
||||
If there is a field to process, verify that its path is
|
||||
relative to the previous non-null compound pieces.
|
||||
*/
|
||||
if( pCdl)
|
||||
{
|
||||
pvField = pCdl->pField;
|
||||
|
||||
// Validate the current and previous root contexts.
|
||||
|
||||
if( KYValidatePathRelation( pRecord, pCdl->pRootContext, pvField,
|
||||
pFldContext, uiCompoundPos) == FERR_FAILURE)
|
||||
{
|
||||
// This field didn't pass the test, get the next field.
|
||||
goto Next_CDL_Node;
|
||||
}
|
||||
|
||||
CmpKeyElm.pValue = pRecord->getDataPtr( pvField);
|
||||
CmpKeyElm.uiValueLen = pRecord->getDataLength( pvField);
|
||||
CmpKeyElm.uiType = pRecord->getDataType( pvField);
|
||||
CmpKeyElm.uiTagNum = pRecord->getFieldID( pvField);
|
||||
CmpKeyElm.bFirstSubstring = FALSE;
|
||||
CmpKeyElm.bSubstringComponent = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
pvField = NULL;
|
||||
}
|
||||
if (pRecord &&
|
||||
(pIfd->uiFlags & (IFD_EACHWORD|IFD_SUBSTRING)) &&
|
||||
CmpKeyElm.uiType == FLM_TEXT_TYPE &&
|
||||
pRecord->getDataLength( pvField))
|
||||
{
|
||||
const FLMBYTE * pText = pRecord->getDataPtr( pvField);
|
||||
FLMUINT uiTextLen = pRecord->getDataLength( pvField);
|
||||
FLMUINT uiKeyLen;
|
||||
FLMBOOL bReturn;
|
||||
FLMBOOL bFirstSubstring = (pIfd->uiFlags & IFD_SUBSTRING)
|
||||
? TRUE : FALSE;
|
||||
|
||||
if (!pbyTmpBuf)
|
||||
{
|
||||
if (RC_BAD( rc = f_alloc( MAX_KEY_SIZ, &pbyTmpBuf)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
|
||||
for(;;)
|
||||
{
|
||||
bReturn = (pIfd->uiFlags & IFD_EACHWORD)
|
||||
? (FLMBOOL) KYEachWordParse( &pText, &uiTextLen,
|
||||
pIfd->uiLimit,
|
||||
pbyTmpBuf, &uiKeyLen)
|
||||
: (FLMBOOL) KYSubstringParse( &pText, &uiTextLen,
|
||||
pIfd->uiFlags, pIfd->uiLimit,
|
||||
pbyTmpBuf, &uiKeyLen);
|
||||
if( !bReturn)
|
||||
break;
|
||||
|
||||
CmpKeyElm.pValue = pbyTmpBuf;
|
||||
CmpKeyElm.uiValueLen = uiKeyLen;
|
||||
CmpKeyElm.uiType = FLM_TEXT_TYPE;
|
||||
CmpKeyElm.bFirstSubstring = bFirstSubstring;
|
||||
CmpKeyElm.bSubstringComponent =
|
||||
(pIfd->uiFlags & IFD_SUBSTRING) ? TRUE : FALSE;
|
||||
if (pIfd->uiFlags & IFD_LAST)
|
||||
rc = flmBuildCompoundKey( pDb, pIxd, &CmpKeyElm,
|
||||
bRemoveDups, pPool, uiContainerNum, ppKeyList);
|
||||
else
|
||||
rc = flmGetCmpKeyElement( pDb, pIxd, (pIfd + 1),
|
||||
uiCdlEntry + 1, uiCompoundPos + 1,
|
||||
&CmpKeyElm, bRemoveDups, pPool, ppKeyList,
|
||||
pRecord, uiContainerNum, pFldContext);
|
||||
if (RC_BAD( rc))
|
||||
goto Exit;
|
||||
|
||||
if( (pIfd->uiFlags & IFD_SUBSTRING) &&
|
||||
uiTextLen == 1 &&
|
||||
!(uiLanguage >= FIRST_DBCS_LANG &&
|
||||
uiLanguage <= LAST_DBCS_LANG))
|
||||
{
|
||||
break;
|
||||
}
|
||||
bFirstSubstring = FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CmpKeyElm.bSubstringComponent = FALSE;
|
||||
if (pIfd->uiFlags & IFD_CONTEXT)
|
||||
CmpKeyElm.uiValueLen = 0;
|
||||
if (pIfd->uiFlags & IFD_LAST)
|
||||
{
|
||||
rc = flmBuildCompoundKey( pDb, pIxd, &CmpKeyElm, bRemoveDups,
|
||||
pPool, uiContainerNum, ppKeyList);
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = flmGetCmpKeyElement( pDb, pIxd, pNextIfdPiece,
|
||||
uiNextCdlEntry, uiCompoundPos+1, &CmpKeyElm,
|
||||
bRemoveDups, pPool, ppKeyList, pRecord, uiContainerNum,
|
||||
pFldContext);
|
||||
}
|
||||
|
||||
if (RC_BAD( rc))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
bBuiltKeyPiece = TRUE;
|
||||
|
||||
Next_CDL_Node:
|
||||
/* Go to next cdl. */
|
||||
if (pCdl)
|
||||
pCdl = pCdl->pNext;
|
||||
|
||||
// If the CDL list is empty, goto the next IFD if same uiCompoundPos.
|
||||
|
||||
while ((!pCdl)
|
||||
&& ((pIfd->uiFlags & IFD_LAST) == 0)
|
||||
&& (pIfd->uiCompoundPos == (pIfd+1)->uiCompoundPos))
|
||||
{
|
||||
pIfd++;
|
||||
pCdl = ppCdlTbl [++uiCdlEntry];
|
||||
}
|
||||
/*
|
||||
Here is the tough part of the new compound indexing strategy (Aug98).
|
||||
If all nodes failed the validate field path test and this piece of
|
||||
the compound key is required, then goto exit NOW which will not
|
||||
build any key with the previous built key pieces.
|
||||
*/
|
||||
|
||||
if( !pCdl && !bBuiltKeyPiece && ((pIfd->uiFlags & IFD_OPTIONAL) == 0))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
Exit:
|
||||
if (pbyTmpBuf)
|
||||
{
|
||||
f_free( &pbyTmpBuf);
|
||||
}
|
||||
return( rc);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
Desc: This routine builds all of the compound keys whose elements have
|
||||
been previously saved off of the index's IFD structures.
|
||||
Note: Already knows that there are compound keys.
|
||||
*****************************************************************************/
|
||||
FSTATIC RCODE flmGetCompoundKeys(
|
||||
FDB_p pDb,
|
||||
IXD_p pIxd,
|
||||
FLMBOOL bRemoveDups,
|
||||
POOL * pPool,
|
||||
FlmRecord * pRecord,
|
||||
FLMUINT uiContainerNum,
|
||||
REC_KEY ** ppKeyList)
|
||||
{
|
||||
RCODE rc = FERR_OK;
|
||||
IFD_p pFirstIfd;
|
||||
IFD_p pIfd;
|
||||
CDL_p * ppCdlTbl = pDb->KrefCntrl.ppCdlTbl;
|
||||
FLMUINT uiFirstCdlEntry;
|
||||
FLMUINT uiCdlEntry;
|
||||
FLMUINT wIfdCnt;
|
||||
FLMBOOL bBuildCmpKeys = TRUE;
|
||||
|
||||
pFirstIfd = pIxd->pFirstIfd;
|
||||
uiFirstCdlEntry = (FLMUINT) (pFirstIfd - pDb->pDict->pIfdTbl);
|
||||
|
||||
// Make sure we have all of the required fields for key generation.
|
||||
|
||||
for (wIfdCnt = 0, pIfd = pFirstIfd, uiCdlEntry = uiFirstCdlEntry;
|
||||
wIfdCnt < pIxd->uiNumFlds;
|
||||
pIfd++, wIfdCnt++, uiCdlEntry++)
|
||||
{
|
||||
|
||||
/*
|
||||
If field is not optional and no data list found,
|
||||
there are no compound keys to build.
|
||||
*/
|
||||
FLMUINT uiCompoundPos;
|
||||
FLMBOOL bHitFound;
|
||||
|
||||
// Loop on each compound field piece looking for REQUIRED field
|
||||
// without any data.
|
||||
|
||||
bHitFound = (pIfd->uiFlags & IFD_OPTIONAL) ? TRUE : FALSE;
|
||||
uiCompoundPos = pIfd->uiCompoundPos;
|
||||
for(;;)
|
||||
{
|
||||
if (!bHitFound)
|
||||
{
|
||||
if (ppCdlTbl [uiCdlEntry])
|
||||
{
|
||||
bHitFound = TRUE; // Loop through all ixds
|
||||
}
|
||||
}
|
||||
if ((pIfd->uiFlags & IFD_LAST)
|
||||
|| ((pIfd+1)->uiCompoundPos != uiCompoundPos))
|
||||
break;
|
||||
pIfd++;
|
||||
uiCdlEntry++;
|
||||
wIfdCnt++;
|
||||
}
|
||||
if( !bHitFound)
|
||||
{
|
||||
bBuildCmpKeys = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Build the individual compound keys. */
|
||||
|
||||
if (bBuildCmpKeys)
|
||||
{
|
||||
FLD_CONTEXT fldContext;
|
||||
|
||||
f_memset( &fldContext, 0, sizeof(FLD_CONTEXT));
|
||||
rc = flmGetCmpKeyElement( pDb, pIxd, pFirstIfd,
|
||||
uiFirstCdlEntry, 0, NULL, bRemoveDups, pPool, ppKeyList, pRecord,
|
||||
uiContainerNum, &fldContext);
|
||||
}
|
||||
|
||||
return( rc);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
Desc: This routine builds all of the keys in a record for a particular
|
||||
index in the database.
|
||||
*****************************************************************************/
|
||||
RCODE flmGetRecKeys(
|
||||
FDB_p pDb,
|
||||
IXD_p pIxd,
|
||||
FlmRecord * pRecord,
|
||||
FLMUINT uiContainerNum,
|
||||
FLMBOOL bRemoveDups,
|
||||
POOL * pPool,
|
||||
REC_KEY ** ppKeyList)
|
||||
{
|
||||
RCODE rc = FERR_OK;
|
||||
void * pvField;
|
||||
FlmRecord * pTmpRec = NULL;
|
||||
FLMUINT uiFieldCount;
|
||||
FLMUINT uiSaveFieldID = pRecord->getFieldID( pRecord->root());
|
||||
FLMBOOL bResetID = FALSE;
|
||||
FLMBOOL bHasCmpKeys = FALSE;
|
||||
FLMBOOL bDictIx = FALSE;
|
||||
void * pathFlds[ GED_MAXLVLNUM + 1];
|
||||
FLMUINT uiLeafFieldLevel;
|
||||
|
||||
*ppKeyList = NULL;
|
||||
|
||||
if( pIxd->uiIndexNum == FLM_DICT_INDEX)
|
||||
{
|
||||
bDictIx = TRUE;
|
||||
|
||||
/*
|
||||
Temporary convert the record's tag number to FLM_NAME_TAG so
|
||||
that we will generate the appropriate name key.
|
||||
*/
|
||||
|
||||
if ((uiSaveFieldID >= FLM_DICT_FIELD_NUMS) &&
|
||||
(uiSaveFieldID <= FLM_LAST_DICT_FIELD_NUM))
|
||||
{
|
||||
if( pRecord->isReadOnly())
|
||||
{
|
||||
if( (pTmpRec = pRecord->copy()) == NULL)
|
||||
{
|
||||
rc = RC_SET( FERR_MEM);
|
||||
goto Exit;
|
||||
}
|
||||
pRecord = pTmpRec;
|
||||
}
|
||||
|
||||
pRecord->setFieldID( pRecord->root(), FLM_NAME_TAG);
|
||||
bResetID = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Process all fields in the tree. */
|
||||
|
||||
uiFieldCount = 256;
|
||||
for( pvField = pRecord->root(); pvField; pvField = pRecord->next( pvField))
|
||||
{
|
||||
// Is if field is indexed before building the keys.
|
||||
|
||||
uiLeafFieldLevel = (FLMINT)pRecord->getLevel( pvField);
|
||||
pathFlds[ uiLeafFieldLevel] = pvField;
|
||||
if( RC_BAD( rc = flmGetFieldKeys( pDb, pIxd, pRecord, uiContainerNum,
|
||||
pathFlds, uiLeafFieldLevel,
|
||||
pvField, bRemoveDups,
|
||||
pPool, ppKeyList, &bHasCmpKeys)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
/* Release the CPU periodically to prevent CPU hog problems. */
|
||||
|
||||
if( uiFieldCount-- == 0)
|
||||
{
|
||||
f_yieldCPU();
|
||||
uiFieldCount = 128;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* If OK, get the compound keys. */
|
||||
|
||||
if (bHasCmpKeys)
|
||||
{
|
||||
if (RC_BAD( rc = flmGetCompoundKeys( pDb, pIxd, bRemoveDups,
|
||||
pPool, pRecord, uiContainerNum, ppKeyList)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
|
||||
Exit:
|
||||
|
||||
if( pTmpRec)
|
||||
{
|
||||
pTmpRec->Release();
|
||||
}
|
||||
else if( bResetID)
|
||||
{
|
||||
pRecord->setFieldID( pRecord->root(), uiSaveFieldID);
|
||||
}
|
||||
|
||||
return( rc);
|
||||
}
|
||||
Reference in New Issue
Block a user