From 537e33bf24d5d08c008a5aee541c77d62bb26c07 Mon Sep 17 00:00:00 2001 From: dsandersoremutah Date: Thu, 23 Mar 2006 17:37:47 +0000 Subject: [PATCH] First set of changes needed for bugzilla bug #145076. Added ability to keep a field id table for level one fields. git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@204 0109f412-320b-0410-ab79-c3e0c5ffbbe6 --- flaim/src/fdbcnfig.cpp | 23 ++ flaim/src/flaim.h | 136 +++++++- flaim/src/flaimsys.h | 2 +- flaim/src/flupdate.cpp | 8 +- flaim/src/frec.cpp | 676 +++++++++++++++++++++++++++++++++++++- flaim/src/fslfileu.cpp | 9 +- flaim/src/fsrecget.cpp | 6 + flaim/src/fsrefupd.cpp | 5 +- flaim/src/fstructs.h | 4 + flaim/src/fsv_hdlr.cpp | 1 + flaim/src/rcache.cpp | 46 ++- flaim/util/basic_test.cpp | 257 +++++++++++++++ 12 files changed, 1145 insertions(+), 28 deletions(-) diff --git a/flaim/src/fdbcnfig.cpp b/flaim/src/fdbcnfig.cpp index 9adedf7..169753c 100644 --- a/flaim/src/fdbcnfig.cpp +++ b/flaim/src/fdbcnfig.cpp @@ -149,6 +149,7 @@ FLMEXP RCODE FLMAPI FlmDbConfig( RCODE rc = FERR_OK; FDB * pDb = (FDB_p)hDb; FFILE * pFile = pDb->pFile; + LFILE * pLFile; FLMBOOL bDbInitialized = FALSE; FLMBOOL bStartedTrans = FALSE; FLMBOOL bDbLocked = FALSE; @@ -215,6 +216,7 @@ FLMEXP RCODE FLMAPI FlmDbConfig( } case FDB_RFL_FILE_LIMITS: + case FDB_ENABLE_FIELD_ID_TABLE: if( RC_BAD( rc = Wire.sendNumber( WIRE_VALUE_NUMBER1, (FLMUINT)Value1))) { @@ -638,6 +640,27 @@ Transmission_Error: pDb->fnCommit = (COMMIT_FUNC)((FLMUINT)Value1); pDb->pvCommitData = Value2; break; + + case FDB_ENABLE_FIELD_ID_TABLE: + if (pDb->pDict) + { + if (RC_BAD( rc = fdictGetContainer( pDb->pDict, (FLMUINT)Value1, + &pLFile))) + { + goto Exit; + } + pLFile->bMakeFieldIdTable = (FLMBOOL)Value2; + } + else if (pDb->pFile->pDictList) + { + if (RC_BAD( rc = fdictGetContainer( pDb->pFile->pDictList, + (FLMUINT)Value1, &pLFile))) + { + goto Exit; + } + pLFile->bMakeFieldIdTable = (FLMBOOL)Value2; + } + break; default: rc = RC_SET( FERR_NOT_IMPLEMENTED); diff --git a/flaim/src/flaim.h b/flaim/src/flaim.h index 495bd4d..c5e6e6b 100644 --- a/flaim/src/flaim.h +++ b/flaim/src/flaim.h @@ -2857,10 +2857,13 @@ FDB_SET_APP_DATA, ///< Allows an application to have the database object remember some data.\ pvValue1 contains a ///< pointer to the data to be remembered.\ An application may retrieve this pointer at any time ///< by calling FlmDbGetConfig() with the eDbGetConfigType::FDB_GET_APP_DATA option. - FDB_SET_COMMIT_CALLBACK ///< Set a callback function that is to be called whenever this database handle commits an + FDB_SET_COMMIT_CALLBACK, ///< Set a callback function that is to be called whenever this database handle commits an ///< update transaction.\ pvValue1 is a pointer to the callback ///< function - a ::COMMIT_FUNC.\ pvValue2 is a pointer to application data that will be passed into the ///< function whenever it is called. + FDB_ENABLE_FIELD_ID_TABLE ///< Enable the creating of a field ID table for level-one fields in cached records for a specific + ///< container.\ pvValue1 is a FLMUINT that holds the container number.\ pvValue2 is a FLMBOOL indicating + ///< whether the field id table is to be enabled or disabled. } eDbConfigType; #define F_SERIAL_NUM_SIZE 16 @@ -4538,6 +4541,69 @@ } FlmField; + /**************************************************************************** + Struct: FIELD_ID + ****************************************************************************/ + typedef struct FIELD_ID + { + FIELDLINK ui32FieldOffset; + FLMUINT16 ui16FieldId; + } FIELD_ID; + + FINLINE FLMUINT calcFieldIdTableByteSize( + FLMUINT uiTableItems) + { + return( FLM_ALIGN_SIZE + FLM_ALIGN_SIZE + FLM_ALIGN_SIZE + + sizeof( FIELD_ID) * uiTableItems); + } + + FINLINE void setFieldIdTableItemCount( + FLMBYTE * pucFieldIdTable, + FLMUINT uiItemCount) + { + *((FLMUINT *)(pucFieldIdTable + FLM_ALIGN_SIZE)) = uiItemCount; + } + + FINLINE void setFieldIdTableArraySize( + FLMBYTE * pucFieldIdTable, + FLMUINT uiTableArraySize) + { + *((FLMUINT *)(pucFieldIdTable + FLM_ALIGN_SIZE + FLM_ALIGN_SIZE)) = uiTableArraySize; + } + + FINLINE FLMUINT getFieldIdTableItemCount( + FLMBYTE * pucFieldIdTable) + { + if (!pucFieldIdTable) + { + return( 0); + } + else + { + return( *((FLMUINT *)(pucFieldIdTable + FLM_ALIGN_SIZE))); + } + } + + FINLINE FLMUINT getFieldIdTableArraySize( + FLMBYTE * pucFieldIdTable) + { + if (!pucFieldIdTable) + { + return( 0); + } + else + { + return( *((FLMUINT *)(pucFieldIdTable + FLM_ALIGN_SIZE + FLM_ALIGN_SIZE))); + } + } + + FINLINE FIELD_ID * getFieldIdTable( + FLMBYTE * pucFieldIdTable) + { + return( (FIELD_ID *)(pucFieldIdTable + + FLM_ALIGN_SIZE + FLM_ALIGN_SIZE + FLM_ALIGN_SIZE)); + } + /**************************************************************************** Desc: Class which provides the record interface that FLAIM uses to access and manipulate all records. @@ -4547,11 +4613,14 @@ { public: - #define RCA_READ_ONLY_FLAG 0x00000001 - #define RCA_CACHED 0x00000002 - #define RCA_OK_TO_DELETE 0x00000004 - #define RCA_OLD_VERSION 0x00000008 - #define RCA_HEAP_BUFFER 0x00000010 + #define RCA_READ_ONLY_FLAG 0x00000001 + #define RCA_CACHED 0x00000002 + #define RCA_OK_TO_DELETE 0x00000004 + #define RCA_OLD_VERSION 0x00000008 + #define RCA_HEAP_BUFFER 0x00000010 + #define RCA_ID_TABLE_HEAP_BUFFER 0x00000020 + #define RCA_FIELD_ID_TABLE_ENABLED 0x00000040 + #define RCA_NEED_TO_SORT_FIELD_ID_TABLE 0x00000080 FlmRecord(); @@ -5343,6 +5412,41 @@ setEncFlags( getFieldPointer( pvField), uiFlags); } + /// Determine if a record has a level one field ID table. + FINLINE FLMBOOL fieldIdTableEnabled( void) + { + return( (m_uiFlags & RCA_FIELD_ID_TABLE_ENABLED) + ? TRUE + : FALSE); + } + + /// Set a flag in the record that will cause it to generate a level + /// one field ID table. + FINLINE void enableFieldIdTable( void) + { + m_uiFlags |= RCA_FIELD_ID_TABLE_ENABLED; + } + + /// Create a level one field ID table in a record. + RCODE createFieldIdTable( + FLMBOOL bTruncateTable ///< Truncate the field id table after sorting? + ); + + FINLINE FLMBYTE * getFieldIdTbl( void) + { + return m_pucFieldIdTable; + } + + RCODE truncateFieldIdTable( void); + + void sortFieldIdTable( void); + + /// Find a level one field ID in a record. + void * findLevelOneField( + FLMUINT uiFieldID, ///< Field number of field to be found. + FLMBOOL bFindInclusive ///< OK to find next field after uiFieldID? + ); + void * locateFieldByPosition( FLMUINT uiPosition); @@ -5558,6 +5662,25 @@ RCODE remove( FlmField * pField); + RCODE addToFieldIdTable( + FLMUINT16 ui16FieldId, + FIELDLINK ui32FieldOffset); + + RCODE removeFromFieldIdTable( + FLMUINT16 ui16FieldId, + FIELDLINK ui32FieldOffset); + + FIELD_ID * findFieldId( + FLMUINT16 ui16FieldId, + FIELDLINK ui32FieldOffset, + FLMUINT * puiInsertPos); + + FINLINE FLMUINT fieldIdTableByteSize( void) + { + FLMUINT uiTableArraySize = getFieldIdTableArraySize( m_pucFieldIdTable); + return calcFieldIdTableByteSize( uiTableArraySize); + } + FLMUINT m_uiContainerID; FLMUINT m_uiRecordID; FLMUINT m_uiFlags; @@ -5569,6 +5692,7 @@ FLMBOOL m_bHolesInData; FLMUINT m_uiAvailFields; FIELDLINK m_uiFirstAvail; + FLMBYTE * m_pucFieldIdTable; friend struct FlmRecordExt; friend class F_Rfl; diff --git a/flaim/src/flaimsys.h b/flaim/src/flaimsys.h index 5400be7..74354af 100644 --- a/flaim/src/flaimsys.h +++ b/flaim/src/flaimsys.h @@ -1105,7 +1105,7 @@ void flmRcaReduceCache( RCODE flmRcaInsertRec( FDB * pDb, - FLMUINT uiContainer, + LFILE * pLFile, FLMUINT uiDrn, FlmRecord * pRecord); diff --git a/flaim/src/flupdate.cpp b/flaim/src/flupdate.cpp index fa49d7b..61a3b99 100644 --- a/flaim/src/flupdate.cpp +++ b/flaim/src/flupdate.cpp @@ -401,8 +401,7 @@ RCODE flmAddRecord( pRecord->setContainerID( pLFile->uiLfNum); if (bKeepInCache) { - if( RC_BAD( rc = flmRcaInsertRec( pDb, pLFile->uiLfNum, uiDrn, - pRecord))) + if( RC_BAD( rc = flmRcaInsertRec( pDb, pLFile, uiDrn, pRecord))) { // Remove the record that was added because of the error. @@ -578,7 +577,7 @@ FLMEXP RCODE FLMAPI FlmRecordModify( pRecord->setID( uiDrn); pRecord->setContainerID( uiContainer); - if( RC_BAD( rc = flmRcaInsertRec( pDb, uiContainer, uiDrn, pRecord))) + if( RC_BAD( rc = flmRcaInsertRec( pDb, pLFile, uiDrn, pRecord))) { goto Exit; } @@ -661,8 +660,7 @@ FLMEXP RCODE FLMAPI FlmRecordModify( pRecord->setID( uiDrn); pRecord->setContainerID( uiContainer); - if( RC_BAD( rc = flmRcaInsertRec( pDb, uiContainer, uiDrn, - pRecord))) + if( RC_BAD( rc = flmRcaInsertRec( pDb, pLFile, uiDrn, pRecord))) { if ( rc != FERR_MEM) { diff --git a/flaim/src/frec.cpp b/flaim/src/frec.cpp index dc0e1cb..8befc47 100644 --- a/flaim/src/frec.cpp +++ b/flaim/src/frec.cpp @@ -69,6 +69,7 @@ FlmRecord::FlmRecord() m_uiBufferSize = 0; m_uiFldTblSize = 0; m_uiFlags = 0; + m_pucFieldIdTable = NULL; clear(); } @@ -85,6 +86,12 @@ FlmRecord::~FlmRecord() gv_FlmSysData.RCacheMgr.pRecBufAlloc->freeBuf( m_uiBufferSize, &m_pucBuffer); } + if( m_pucFieldIdTable) + { + flmAssert( *((FlmRecord **)m_pucFieldIdTable) == this); + gv_FlmSysData.RCacheMgr.pRecBufAlloc->freeBuf( + fieldIdTableByteSize(), &m_pucFieldIdTable); + } } /***************************************************************************** @@ -128,6 +135,36 @@ FlmRecord * FlmRecord::copy( void) } } + if( m_pucFieldIdTable) + { + FLMUINT uiTableByteSize = fieldIdTableByteSize(); + + if( RC_BAD( rc = gv_FlmSysData.RCacheMgr.pRecBufAlloc->allocBuf( + uiTableByteSize, + &pNewRec, sizeof( FlmRecord *), &pNewRec->m_pucFieldIdTable, + &bHeapAlloc))) + { + goto Exit; + } + + f_memcpy( pNewRec->m_pucFieldIdTable + FLM_ALIGN_SIZE, + m_pucFieldIdTable + FLM_ALIGN_SIZE, + uiTableByteSize - FLM_ALIGN_SIZE); + + if( bHeapAlloc) + { + pNewRec->m_uiFlags |= RCA_ID_TABLE_HEAP_BUFFER; + } + if (m_uiFlags & RCA_NEED_TO_SORT_FIELD_ID_TABLE) + { + pNewRec->m_uiFlags |= RCA_NEED_TO_SORT_FIELD_ID_TABLE; + } + } + if (m_uiFlags & RCA_FIELD_ID_TABLE_ENABLED) + { + pNewRec->m_uiFlags |= RCA_FIELD_ID_TABLE_ENABLED; + } + pNewRec->m_uiBufferSize = m_uiBufferSize; pNewRec->m_uiContainerID = m_uiContainerID; pNewRec->m_uiRecordID = m_uiRecordID; @@ -192,6 +229,11 @@ RCODE FlmRecord::clear( m_uiFldTblSize = 0; } + if (m_pucFieldIdTable) + { + gv_FlmSysData.RCacheMgr.pRecBufAlloc->freeBuf( + fieldIdTableByteSize(), &m_pucFieldIdTable); + } m_uiFlags = 0; m_uiContainerID = 0; m_uiRecordID = 0; @@ -1019,6 +1061,13 @@ Exit: { pNewField->ui16FieldID = (FLMUINT16)uiFieldID; setFieldDataType( pNewField, uiDataType); + + if (getFieldLevel( pNewField) == 1 && + (m_uiFlags & RCA_FIELD_ID_TABLE_ENABLED)) + { + rc = addToFieldIdTable( (FLMUINT16)uiFieldID, + (FIELDLINK)((FLMUINT)(pNewField - getFieldTable()) + 1)); + } } if( ppvField) @@ -1102,6 +1151,14 @@ RCODE FlmRecord::insertLast( goto Exit; } + if (uiLevel == 1 && (m_uiFlags & RCA_FIELD_ID_TABLE_ENABLED)) + { + if (RC_BAD( rc = addToFieldIdTable( (FLMUINT16)uiFieldID, + (FIELDLINK)((FLMUINT)(pField - getFieldTable()) + 1)))) + { + goto Exit; + } + } if( ppvField) { *ppvField = getFieldVoid( pField); @@ -1668,6 +1725,30 @@ Exit: return( rc); } +/****************************************************************************** +Desc: Routine for comparing two FIELD_ID structures. +******************************************************************************/ +FINLINE FLMINT fieldIdCompare( + FIELD_ID * pFieldIdA, + FIELD_ID * pFieldIdB) +{ + if (pFieldIdA->ui16FieldId < pFieldIdB->ui16FieldId) + { + return( -1); + } + else if (pFieldIdA->ui16FieldId > pFieldIdB->ui16FieldId) + { + return( 1); + } + else if (pFieldIdA->ui32FieldOffset < pFieldIdB->ui32FieldOffset) + { + return( -1); + } + return( (pFieldIdA->ui32FieldOffset > pFieldIdB->ui32FieldOffset) + ? 1 + : 0); +} + /***************************************************************************** Desc: Return most all unused memory back to the system. This should be called by the Release method of the record object. @@ -1690,6 +1771,12 @@ RCODE FlmRecord::compactMemory( void) FLMUINT uiPicketFenceSize = 0; FlmRecord * pThis = this; FLMBOOL bHeapAlloc = FALSE; + FLMBYTE * pucNewFieldIdTable = NULL; + FLMBOOL bFieldIdHeapAlloc = FALSE; + FLMUINT uiFieldIdTableItemCount = 0; + FIELD_ID * pNewFieldIdTable = NULL; + FLMUINT uiLevelOneFldCount; + FLMBOOL bNeedToSortFieldIdTable; flmAssert( isCached()); flmAssert( getRefCount() == 1); @@ -1794,17 +1881,54 @@ RCODE FlmRecord::compactMemory( void) goto Exit; } + if (m_pucFieldIdTable) + { + uiFieldIdTableItemCount = getFieldIdTableItemCount( m_pucFieldIdTable); + if( RC_BAD( rc = gv_FlmSysData.RCacheMgr.pRecBufAlloc->allocBuf( + calcFieldIdTableByteSize( uiFieldIdTableItemCount), + &pThis, sizeof( FlmRecord *), &pucNewFieldIdTable, + &bFieldIdHeapAlloc))) + { + goto Exit; + } + + // Set the item count and table size in this new item table to be + // the same. + + setFieldIdTableItemCount( pucNewFieldIdTable, uiFieldIdTableItemCount); + setFieldIdTableArraySize( pucNewFieldIdTable, uiFieldIdTableItemCount); + pNewFieldIdTable = getFieldIdTable( pucNewFieldIdTable); + } + pNewFldTbl = (FlmField *)(pucNewBuf + FLM_ALIGN_SIZE); uiSlot = 0; uiNewDataOffset = 0; pucNewData = pucNewBuf + FLM_ALIGN_SIZE + (uiFields * sizeof( FlmField)); + uiLevelOneFldCount = 0; + bNeedToSortFieldIdTable = FALSE; pFld = getFieldPointer( root()); while( pFld) { uiLength = getFieldDataLength( pFld); pNewFld = &pNewFldTbl[ uiSlot]; f_memcpy( pNewFld, pFld, sizeof( FlmField)); + + if (pNewFieldIdTable && getFieldLevel( pFld) == 1) + { + FIELD_ID * pFieldId = pNewFieldIdTable + uiLevelOneFldCount; + + flmAssert( uiLevelOneFldCount < uiFieldIdTableItemCount); + pFieldId->ui16FieldId = pFld->ui16FieldID; + pFieldId->ui32FieldOffset = uiSlot + 1; + uiLevelOneFldCount++; + + if (uiLevelOneFldCount > 1 && !bNeedToSortFieldIdTable && + fieldIdCompare( pFieldId - 1, pFieldId) > 0) + { + bNeedToSortFieldIdTable = TRUE; + } + } if (!isEncryptedField(pFld)) { @@ -1926,8 +2050,30 @@ RCODE FlmRecord::compactMemory( void) { m_uiFlags &= ~RCA_HEAP_BUFFER; } - m_uiBufferSize = uiNewSize; + + if (m_pucFieldIdTable) + { + gv_FlmSysData.RCacheMgr.pRecBufAlloc->freeBuf( + fieldIdTableByteSize(), &m_pucFieldIdTable); + m_pucFieldIdTable = pucNewFieldIdTable; + pucNewFieldIdTable = NULL; + if( bFieldIdHeapAlloc) + { + m_uiFlags |= RCA_ID_TABLE_HEAP_BUFFER; + } + else + { + m_uiFlags &= ~RCA_ID_TABLE_HEAP_BUFFER; + } + if (bNeedToSortFieldIdTable) + { + // Need to set the flag, otherwise sortFieldIdTable() won't + // sort the table. + m_uiFlags |= RCA_NEED_TO_SORT_FIELD_ID_TABLE; + sortFieldIdTable(); + } + } m_uiFldTblOffset = uiFields; m_uiFldTblSize = uiFields; m_uiDataBufOffset = uiNewDataSize; @@ -1949,6 +2095,12 @@ Exit: gv_FlmSysData.RCacheMgr.pRecBufAlloc->freeBuf( uiNewSize, &pucNewBuf); } + if( pucNewFieldIdTable) + { + gv_FlmSysData.RCacheMgr.pRecBufAlloc->freeBuf( + calcFieldIdTableByteSize( uiFieldIdTableItemCount), + &pucNewFieldIdTable); + } flmAtomicDec( &m_refCnt, gv_FlmSysData.RCacheMgr.hMutex, TRUE); return( rc); @@ -2063,6 +2215,7 @@ RCODE FlmRecord::removeFields( RCODE rc = FERR_OK; FlmField * pCurField; FLMUINT uiFieldsRemoved = 0; + FlmField * pFieldTable = getFieldTable(); flmAssert( !isReadOnly()); flmAssert( !isCached()); @@ -2095,6 +2248,13 @@ RCODE FlmRecord::removeFields( pCurField = pFirstField; while( pCurField) { + if (getFieldLevel( pCurField) == 1 && + (m_uiFlags & RCA_FIELD_ID_TABLE_ENABLED)) + { + rc = removeFromFieldIdTable( (FLMUINT16)pCurField->ui16FieldID, + (FIELDLINK)((FLMUINT)(pCurField - pFieldTable) + 1)); + } + pCurField->uiPrev = 0; pCurField->ui32DataOffset = 0; pCurField->ui16FieldID = 0; @@ -4008,8 +4168,16 @@ Desc: *****************************************************************************/ FLMUINT FlmRecord::getTotalMemory( void) { - return( gv_FlmSysData.RCacheMgr.pRecBufAlloc->getTrueSize( - m_uiBufferSize, m_pucBuffer) + sizeof( FlmRecord)); + FLMUINT uiSize = sizeof( FlmRecord) + + gv_FlmSysData.RCacheMgr.pRecBufAlloc->getTrueSize( + m_uiBufferSize, m_pucBuffer); + + if (m_pucFieldIdTable) + { + uiSize += gv_FlmSysData.RCacheMgr.pRecBufAlloc->getTrueSize( + fieldIdTableByteSize(), m_pucFieldIdTable); + } + return( uiSize); } /***************************************************************************** @@ -4802,3 +4970,505 @@ Exit: return( rc); } + +/****************************************************************************** +Desc: Swap FIELD_ID structures in the array. +******************************************************************************/ +FINLINE void fieldIdSwap( + FIELD_ID * pFieldIdArray, + FLMUINT uiLeft, + FLMUINT uiRight) +{ + FIELD_ID tempId; + + tempId.ui16FieldId = pFieldIdArray [uiLeft].ui16FieldId; + tempId.ui32FieldOffset = pFieldIdArray [uiLeft].ui32FieldOffset; + pFieldIdArray [uiLeft].ui16FieldId = pFieldIdArray [uiRight].ui16FieldId; + pFieldIdArray [uiLeft].ui32FieldOffset = pFieldIdArray [uiRight].ui32FieldOffset; + pFieldIdArray [uiRight].ui16FieldId = tempId.ui16FieldId; + pFieldIdArray [uiRight].ui32FieldOffset = tempId.ui32FieldOffset; +} + +/****************************************************************************** +Desc: Quick-sort a field ID table. +******************************************************************************/ +FSTATIC void sortFieldIdArray( + FIELD_ID * pFieldIdArray, + FLMUINT uiLowerBounds, + FLMUINT uiUpperBounds) +{ + FLMUINT uiLBPos; + FLMUINT uiUBPos; + FLMUINT uiMIDPos; + FLMUINT uiLeftItems; + FLMUINT uiRightItems; + FIELD_ID * pCurEntry; + FLMINT iCompare; + +Iterate_Larger_Half: + + uiUBPos = uiUpperBounds; + uiLBPos = uiLowerBounds; + uiMIDPos = (uiUpperBounds + uiLowerBounds + 1) / 2; + pCurEntry = &pFieldIdArray[ uiMIDPos ]; + for( ;;) + { + while( (uiLBPos == uiMIDPos) // Don't compare with target + || ((iCompare = + fieldIdCompare( &pFieldIdArray[ uiLBPos], pCurEntry)) < 0)) + { + if( uiLBPos >= uiUpperBounds) break; + uiLBPos++; + } + + while( (uiUBPos == uiMIDPos) // Don't compare with target + || (((iCompare = + fieldIdCompare( pCurEntry, &pFieldIdArray[ uiUBPos])) < 0))) + { + if( !uiUBPos) break; + uiUBPos--; + } + + if( uiLBPos < uiUBPos ) // Interchange and continue loop. + { + + // Interchange [uiLBPos] with [uiUBPos]. + + fieldIdSwap( pFieldIdArray, uiLBPos, uiUBPos ); + uiLBPos++; // Scan from left to right. + uiUBPos--; // Scan from right to left. + } + else // Past each other - done + { + break; + } + } + // Check for swap( LB, MID ) - cases 3 and 4 + + if( uiLBPos < uiMIDPos ) + { + // Interchange [uiLBPos] with [uiMIDPos] + + fieldIdSwap( pFieldIdArray, uiMIDPos, uiLBPos ); + uiMIDPos = uiLBPos; + } + else if( uiMIDPos < uiUBPos ) + { + // Interchange [uUBPos] with [uiMIDPos] + + fieldIdSwap( pFieldIdArray, uiMIDPos, uiUBPos ); + uiMIDPos = uiUBPos; + } + + // Check the left piece. + + uiLeftItems = (uiLowerBounds + 1 < uiMIDPos ) + ? uiMIDPos - uiLowerBounds // 2 or more + : 0; + uiRightItems = (uiMIDPos + 1 < uiUpperBounds ) + ? uiUpperBounds - uiMIDPos // 2 or more + : 0; + + if (uiLeftItems < uiRightItems) + { + + // Recurse on the LEFT side and goto the top on the RIGHT side. + + if( uiLeftItems ) + { + sortFieldIdArray( pFieldIdArray, uiLowerBounds, uiMIDPos - 1 ); + } + uiLowerBounds = uiMIDPos + 1; + goto Iterate_Larger_Half; + } + else if (uiLeftItems) // Compute a truth table to figure out this check. + { + + // Recurse on the RIGHT side and goto the top for the LEFT side. + + if (uiRightItems) + { + sortFieldIdArray( pFieldIdArray, uiMIDPos + 1, uiUpperBounds); + } + uiUpperBounds = uiMIDPos - 1; + goto Iterate_Larger_Half; + } +} + +/****************************************************************************** +Desc: Sort the field ID table. +******************************************************************************/ +void FlmRecord::sortFieldIdTable( void) +{ + if (m_pucFieldIdTable) + { + if (getFieldIdTableItemCount( m_pucFieldIdTable) > 1) + { + sortFieldIdArray( getFieldIdTable( m_pucFieldIdTable), 0, + getFieldIdTableItemCount( m_pucFieldIdTable) - 1); + } + } + m_uiFlags &= (~(RCA_NEED_TO_SORT_FIELD_ID_TABLE)); +} + +/****************************************************************************** +Desc: Find a field ID to the field ID table. +******************************************************************************/ +FIELD_ID * FlmRecord::findFieldId( + FLMUINT16 ui16FieldId, + FIELDLINK ui32FieldOffset, + FLMUINT * puiInsertPos) +{ + FIELD_ID * pFieldId = NULL; + FIELD_ID * pFieldIdTable = getFieldIdTable( m_pucFieldIdTable); + FLMUINT uiTblSize; + FLMUINT uiLow; + FLMUINT uiMid; + FLMUINT uiHigh; + FLMINT iCmp; + + if (m_uiFlags & RCA_NEED_TO_SORT_FIELD_ID_TABLE) + { + sortFieldIdTable(); + } + + // Do binary search in the table + + if ((uiTblSize = getFieldIdTableItemCount( m_pucFieldIdTable)) == 0) + { + if (puiInsertPos) + { + *puiInsertPos = 0; + } + goto Exit; + } + uiHigh = --uiTblSize; + uiLow = 0; + for (;;) + { + uiMid = (uiLow + uiHigh) / 2; + if (ui16FieldId < pFieldIdTable [uiMid].ui16FieldId) + { + iCmp = -1; + } + else if (ui16FieldId > pFieldIdTable [uiMid].ui16FieldId) + { + iCmp = 1; + } + else if (!ui32FieldOffset) + { + iCmp = 0; + } + else if (ui32FieldOffset < pFieldIdTable [uiMid].ui32FieldOffset) + { + iCmp = -1; + } + else if (ui32FieldOffset > pFieldIdTable [uiMid].ui32FieldOffset) + { + iCmp = 1; + } + else + { + iCmp = 0; + } + if (iCmp == 0) + { + + // Found Match + + pFieldId = &pFieldIdTable [uiMid]; + if (puiInsertPos) + { + *puiInsertPos = uiMid; + } + goto Exit; + } + + // Check if we are done + + if (uiLow >= uiHigh) + { + + // Done, item not found + + if (puiInsertPos) + { + *puiInsertPos = (iCmp < 0) + ? uiMid + : uiMid + 1; + } + goto Exit; + } + + if (iCmp < 0) + { + if (uiMid == 0) + { + if (puiInsertPos) + { + *puiInsertPos = 0; + } + goto Exit; + } + uiHigh = uiMid - 1; + } + else + { + if (uiMid == uiTblSize) + { + if (puiInsertPos) + { + *puiInsertPos = uiMid + 1; + } + goto Exit; + } + uiLow = uiMid + 1; + } + } + +Exit: + + return( pFieldId); +} + +/****************************************************************************** +Desc: Add a field ID to the field ID table. +******************************************************************************/ +RCODE FlmRecord::addToFieldIdTable( + FLMUINT16 ui16FieldId, + FIELDLINK ui32FieldOffset) +{ + RCODE rc = FERR_OK; + FIELD_ID * pFieldId; + FLMUINT uiItemCount = getFieldIdTableItemCount( m_pucFieldIdTable); + FLMUINT uiTableSize = getFieldIdTableArraySize( m_pucFieldIdTable); + FLMBOOL bHeapAlloc; + FlmRecord * pThis = this; + + if (uiItemCount == uiTableSize) + { + FLMUINT uiNewByteSize; + + uiTableSize += 32; + + uiNewByteSize = calcFieldIdTableByteSize( uiTableSize); + + // Reallocate the table. + + if (!uiItemCount) + { + if( RC_BAD( rc = gv_FlmSysData.RCacheMgr.pRecBufAlloc->allocBuf( + uiNewByteSize, &pThis, sizeof( FlmRecord *), &m_pucFieldIdTable, + &bHeapAlloc))) + { + goto Exit; + } + } + else + { + if( RC_BAD( rc = gv_FlmSysData.RCacheMgr.pRecBufAlloc->reallocBuf( + fieldIdTableByteSize(), + uiNewByteSize, &pThis, sizeof( FlmRecord *), + &m_pucFieldIdTable, &bHeapAlloc))) + { + goto Exit; + } + } + if( bHeapAlloc) + { + m_uiFlags |= RCA_ID_TABLE_HEAP_BUFFER; + } + else + { + m_uiFlags &= ~RCA_ID_TABLE_HEAP_BUFFER; + } + setFieldIdTableArraySize( m_pucFieldIdTable, uiTableSize); + } + pFieldId = getFieldIdTable( m_pucFieldIdTable) + uiItemCount; + pFieldId->ui32FieldOffset = ui32FieldOffset; + pFieldId->ui16FieldId = ui16FieldId; + uiItemCount++; + setFieldIdTableItemCount( m_pucFieldIdTable, uiItemCount); + + // Table may no longer be sorted, in which case we need to set a flag + // indicating that it needs to be sorted. + + if (uiItemCount > 1 && !(m_uiFlags & RCA_NEED_TO_SORT_FIELD_ID_TABLE) && + fieldIdCompare( pFieldId - 1, pFieldId) > 0) + { + m_uiFlags |= RCA_NEED_TO_SORT_FIELD_ID_TABLE; + } + +Exit: + + return( rc); +} + +/****************************************************************************** +Desc: Remove a field ID from the field ID table. +******************************************************************************/ +RCODE FlmRecord::removeFromFieldIdTable( + FLMUINT16 ui16FieldId, + FIELDLINK ui32FieldOffset) +{ + RCODE rc = FERR_OK; + FLMUINT uiInsertPos; + FIELD_ID * pFieldId; + + if ((pFieldId = findFieldId( ui16FieldId, ui32FieldOffset, &uiInsertPos)) != NULL) + { + FLMUINT uiItemCount = getFieldIdTableItemCount( m_pucFieldIdTable); + FLMUINT uiTableSize = getFieldIdTableArraySize( m_pucFieldIdTable); + FIELD_ID * pFieldIdTable = getFieldIdTable( m_pucFieldIdTable); + + if (uiInsertPos < uiItemCount - 1) + { + f_memmove( pFieldId, &pFieldIdTable [uiInsertPos + 1], + sizeof( FIELD_ID) * (uiItemCount - uiInsertPos - 1)); + } + uiItemCount--; + if (!uiItemCount) + { + gv_FlmSysData.RCacheMgr.pRecBufAlloc->freeBuf( + fieldIdTableByteSize(), &m_pucFieldIdTable); + } + else + { + FLMBOOL bHeapAlloc; + FlmRecord * pThis = this; + + setFieldIdTableItemCount( m_pucFieldIdTable, uiItemCount); + if (uiTableSize > uiItemCount + 32) + { + if( RC_BAD( rc = gv_FlmSysData.RCacheMgr.pRecBufAlloc->reallocBuf( + fieldIdTableByteSize(), calcFieldIdTableByteSize( uiItemCount), + &pThis, sizeof( FlmRecord *), + &m_pucFieldIdTable, &bHeapAlloc))) + { + goto Exit; + } + setFieldIdTableArraySize( m_pucFieldIdTable, uiItemCount); + if( bHeapAlloc) + { + m_uiFlags |= RCA_ID_TABLE_HEAP_BUFFER; + } + else + { + m_uiFlags &= ~RCA_ID_TABLE_HEAP_BUFFER; + } + } + } + } + +Exit: + + return( rc); +} + +/****************************************************************************** +Desc: Find a level one field in the record. +******************************************************************************/ +void * FlmRecord::findLevelOneField( + FLMUINT uiFieldId, + FLMBOOL bFindInclusive) +{ + FLMUINT uiInsertPos; + FIELD_ID * pFieldId; + void * pvField = NULL; + + if (m_pucFieldIdTable) + { + if ((pFieldId = findFieldId( (FLMUINT16)uiFieldId, 0, &uiInsertPos)) != NULL) + { + pvField = (void *)((FLMUINT)pFieldId->ui32FieldOffset); + } + else if (bFindInclusive && + uiInsertPos < getFieldIdTableItemCount( m_pucFieldIdTable)) + { + pFieldId = getFieldIdTable( m_pucFieldIdTable) + uiInsertPos; + pvField = (void *)((FLMUINT)pFieldId->ui32FieldOffset); + } + } + else + { + flmAssert( m_uiFlags & RCA_FIELD_ID_TABLE_ENABLED); + } + return( pvField); +} + +/****************************************************************************** +Desc: Create the field ID table, if not already created. +******************************************************************************/ +RCODE FlmRecord::createFieldIdTable( + FLMBOOL bTruncateTable) +{ + RCODE rc = FERR_OK; + void * pvField; + + if (!(m_uiFlags & RCA_FIELD_ID_TABLE_ENABLED)) + { + m_uiFlags |= RCA_FIELD_ID_TABLE_ENABLED; + pvField = firstChild( root()); + while (pvField) + { + if (RC_BAD( rc = addToFieldIdTable( (FLMUINT16)getFieldID( pvField), + (FIELDLINK)((FLMUINT)pvField)))) + { + goto Exit; + } + pvField = nextSibling( pvField); + } + } + if (m_uiFlags & RCA_NEED_TO_SORT_FIELD_ID_TABLE) + { + sortFieldIdTable(); + } + if (bTruncateTable) + { + if (RC_BAD( rc = truncateFieldIdTable())) + { + goto Exit; + } + } + +Exit: + + return( rc); +} + +/****************************************************************************** +Desc: Truncate the field ID table, if not already truncated. +******************************************************************************/ +RCODE FlmRecord::truncateFieldIdTable( void) +{ + RCODE rc = FERR_OK; + FLMUINT uiItemCount = getFieldIdTableItemCount( m_pucFieldIdTable); + + if (uiItemCount != getFieldIdTableArraySize( m_pucFieldIdTable)) + { + FLMBOOL bHeapAlloc; + FlmRecord * pThis = this; + + if( RC_BAD( rc = gv_FlmSysData.RCacheMgr.pRecBufAlloc->reallocBuf( + fieldIdTableByteSize(), calcFieldIdTableByteSize( uiItemCount), + &pThis, sizeof( FlmRecord *), + &m_pucFieldIdTable, &bHeapAlloc))) + { + goto Exit; + } + setFieldIdTableArraySize( m_pucFieldIdTable, uiItemCount); + if( bHeapAlloc) + { + m_uiFlags |= RCA_ID_TABLE_HEAP_BUFFER; + } + else + { + m_uiFlags &= ~RCA_ID_TABLE_HEAP_BUFFER; + } + } + +Exit: + + return( rc); +} + diff --git a/flaim/src/fslfileu.cpp b/flaim/src/fslfileu.cpp index 627f913..9e820a1 100644 --- a/flaim/src/fslfileu.cpp +++ b/flaim/src/fslfileu.cpp @@ -1483,8 +1483,7 @@ RCODE flmSetIxTrackerInfo( pRecord->setID( uiIndexNum); pRecord->setContainerID( FLM_TRACKER_CONTAINER); - if( RC_BAD( rc = flmRcaInsertRec( pDb, FLM_TRACKER_CONTAINER, - uiIndexNum, pRecord))) + if( RC_BAD( rc = flmRcaInsertRec( pDb, pLFile, uiIndexNum, pRecord))) { goto Exit; } @@ -2367,8 +2366,7 @@ FSTATIC RCODE flmFreeIndexBlocks( goto Exit; } - if( RC_BAD( rc = flmRcaInsertRec( pDb, FLM_TRACKER_CONTAINER, - uiDrn, pRec))) + if( RC_BAD( rc = flmRcaInsertRec( pDb, pTrackerLFile, uiDrn, pRec))) { goto Exit; } @@ -2856,8 +2854,7 @@ FSTATIC RCODE flmModifyTrackerRec( pRecord->setID( uiDrn); pRecord->setContainerID( FLM_TRACKER_CONTAINER); - if( RC_BAD( rc = flmRcaInsertRec( pDb, FLM_TRACKER_CONTAINER, - uiDrn, pRecord))) + if( RC_BAD( rc = flmRcaInsertRec( pDb, pLFile, uiDrn, pRecord))) { goto Exit; } diff --git a/flaim/src/fsrecget.cpp b/flaim/src/fsrecget.cpp index d7d5885..251789d 100644 --- a/flaim/src/fsrecget.cpp +++ b/flaim/src/fsrecget.cpp @@ -251,6 +251,10 @@ RCODE FSReadElement( pRecord->setContainerID( pLFile->uiLfNum); pRecord->setID( uiDrn); + if (pLFile->bMakeFieldIdTable) + { + pRecord->enableFieldIdTable(); + } } // Check if out of fields in the tempoary field group. @@ -618,6 +622,8 @@ RCODE FSReadElement( flmAssert( 0); (*ppRecord)->Release(); } + + pRecord->sortFieldIdTable(); *ppRecord = pRecord; pRecord = NULL; diff --git a/flaim/src/fsrefupd.cpp b/flaim/src/fsrefupd.cpp index 3da4492..823ebdb 100644 --- a/flaim/src/fsrefupd.cpp +++ b/flaim/src/fsrefupd.cpp @@ -453,8 +453,7 @@ FSTATIC RCODE FSOutputIxCounts( // Put the record into record cache. - if( RC_BAD( rc = flmRcaInsertRec( pDb, FLM_TRACKER_CONTAINER, - pIxStats->uiIndexNum, + if( RC_BAD( rc = flmRcaInsertRec( pDb, pLFile, pIxStats->uiIndexNum, pTmpRec))) { @@ -478,7 +477,7 @@ FSTATIC RCODE FSOutputIxCounts( // Put the modified record into record cache. - if (RC_BAD( rc = flmRcaInsertRec( pDb, FLM_TRACKER_CONTAINER, + if (RC_BAD( rc = flmRcaInsertRec( pDb, pLFile, pIxStats->uiIndexNum, pTmpRec))) { diff --git a/flaim/src/fstructs.h b/flaim/src/fstructs.h index c46f4f8..4dda97d 100644 --- a/flaim/src/fstructs.h +++ b/flaim/src/fstructs.h @@ -1917,6 +1917,10 @@ typedef struct LFILE FLMUINT uiOffsetInBlk; // Offset within block of entry. FLMUINT uiLfNum; // Index number or container number. FLMUINT uiLfType; // Type of logical file. */ + FLMBOOL bMakeFieldIdTable; // Boolean that indicates whether or not + // for this container when we create + // records in cache we should create a + // field id table for the level-1 fields. IXD * pIxd; // If an index, points to the IXD. } LFILE; diff --git a/flaim/src/fsv_hdlr.cpp b/flaim/src/fsv_hdlr.cpp index aaf363d..2f38edd 100644 --- a/flaim/src/fsv_hdlr.cpp +++ b/flaim/src/fsv_hdlr.cpp @@ -1589,6 +1589,7 @@ RCODE fsvOpClassDatabase( break; case FDB_RFL_FILE_LIMITS: case FDB_FILE_EXTEND_SIZE: + case FDB_ENABLE_FIELD_ID_TABLE: if( RC_BAD( opRc = FlmDbConfig( hDb, (eDbConfigType)pWire->getType(), (void *)((FLMUINT)pWire->getNumber1()), (void *)((FLMUINT)pWire->getNumber2())))) diff --git a/flaim/src/rcache.cpp b/flaim/src/rcache.cpp index 318abc9..2dd585b 100644 --- a/flaim/src/rcache.cpp +++ b/flaim/src/rcache.cpp @@ -2260,12 +2260,13 @@ Desc: This routine inserts a record into the record cache. This is ONLY ****************************************************************************/ RCODE flmRcaInsertRec( FDB * pDb, - FLMUINT uiContainer, // Container record is in. + LFILE * pLFile, // Container record is in. FLMUINT uiDrn, // DRN of record FlmRecord * pRecord) // Record to be inserted. { RCODE rc = FERR_OK; FFILE_p pFile = pDb->pFile; + FLMUINT uiContainer = pLFile->uiLfNum; FLMBOOL bMutexLocked = FALSE; RCACHE * pRCache; RCACHE * pNewerRCache; @@ -2274,6 +2275,28 @@ RCODE flmRcaInsertRec( ? TRUE : FALSE; + if (pLFile->bMakeFieldIdTable && !pRecord->fieldIdTableEnabled()) + { + + // NOTE: createFieldIdTable will call sortFieldIdTable(). + + if (RC_BAD( rc = pRecord->createFieldIdTable( TRUE))) + { + goto Exit; + } + } + else + { + pRecord->sortFieldIdTable(); + if (getFieldIdTableItemCount( pRecord->getFieldIdTbl()) != + getFieldIdTableArraySize( pRecord->getFieldIdTbl())) + { + if (RC_BAD( rc = pRecord->truncateFieldIdTable())) + { + goto Exit; + } + } + } flmAssert( uiDrn != 0); // Lock the mutex @@ -2825,6 +2848,11 @@ void FlmRecordExt::relocateRec( flmAssert( *((FlmRecord **)pOldRec->m_pucBuffer) == pOldRec); *((FlmRecord **)pNewRec->m_pucBuffer) = pNewRec; } + if( pNewRec->m_pucFieldIdTable) + { + flmAssert( *((FlmRecord **)pOldRec->m_pucFieldIdTable) == pOldRec); + *((FlmRecord **)pNewRec->m_pucFieldIdTable) = pNewRec; + } // Find the record @@ -2864,7 +2892,7 @@ FLMBOOL FlmRecordExt::canRelocateRecBuffer( { FlmRecord * pRec = *((FlmRecord **)pvAlloc); - flmAssert( pRec->m_pucBuffer == pvAlloc); + flmAssert( pRec->m_pucBuffer == pvAlloc || pRec->m_pucFieldIdTable == pvAlloc); if( pRec->getRefCount() == 1 && pRec->isCached()) { @@ -2885,12 +2913,22 @@ void FlmRecordExt::relocateRecBuffer( flmAssert( pRec->getRefCount() == 1); flmAssert( pRec->isCached()); - flmAssert( pRec->m_pucBuffer == pvOldAlloc); flmAssert( pvNewAlloc < pvOldAlloc); // Update the buffer pointer in the record - pRec->m_pucBuffer = (FLMBYTE *)pvNewAlloc; + if (pRec->m_pucBuffer == pvOldAlloc) + { + pRec->m_pucBuffer = (FLMBYTE *)pvNewAlloc; + } + else if (pRec->m_pucFieldIdTable == pvOldAlloc) + { + pRec->m_pucFieldIdTable = (FLMBYTE *)pvNewAlloc; + } + else + { + flmAssert( 0); + } } /**************************************************************************** diff --git a/flaim/util/basic_test.cpp b/flaim/util/basic_test.cpp index ec88555..ad13cc8 100644 --- a/flaim/util/basic_test.cpp +++ b/flaim/util/basic_test.cpp @@ -126,6 +126,8 @@ public: RCODE resumeIndexTest( FLMUINT uiIndex); + RCODE sortedFieldsTest( void); + RCODE backupRestoreDbTest( void); RCODE compareRecords( @@ -2026,6 +2028,254 @@ Exit: return( rc); } +/*************************************************************************** +Desc: +****************************************************************************/ +RCODE IFlmTestImpl::sortedFieldsTest( void) +{ + RCODE rc = FERR_OK; + FLMBOOL bPassed = FALSE; + FlmRecord * pRec = NULL; + FlmRecord * pDataRec = NULL; + FlmRecord * pCopyRec = NULL; + void * pvField; + void * pvDataField; + FLMBOOL bTransActive = FALSE; + char szFieldName [100]; + FLMUINT uiFieldId; + FLMUINT uiTmp; + FLMUINT uiDrn; + + beginTest( "Sorted Fields Test"); + + // Modify to keep field id table for level one fields. + + if (RC_BAD( rc = FlmDbConfig( m_hDb, FDB_ENABLE_FIELD_ID_TABLE, + (void *)FLM_DATA_CONTAINER, (void *)TRUE))) + { + MAKE_ERROR_STRING( "calling FlmDbConfig", rc, m_szFailInfo); + goto Exit; + } + + // Create a dictionary record object + + if( (pDataRec = new FlmRecord) == NULL) + { + rc = RC_SET( FERR_MEM); + MAKE_ERROR_STRING( "allocating FlmRecord", rc, m_szFailInfo); + goto Exit; + } + if( RC_BAD( rc = pDataRec->insertLast( 0, FLM_FIELD_TAG, + FLM_TEXT_TYPE, &pvDataField))) + { + MAKE_ERROR_STRING( "calling insertLast", rc, m_szFailInfo); + goto Exit; + } + + // Start an update transaction + + if( RC_BAD( rc = FlmDbTransBegin( m_hDb, FLM_UPDATE_TRANS, 15))) + { + MAKE_ERROR_STRING( "calling FlmDbTransBegin", rc, m_szFailInfo); + goto Exit; + } + bTransActive = TRUE; + + // Create 300 IDs in the dictionary, 1001 to 1601, every other one + + for (uiFieldId = 1001; uiFieldId <= 1601; uiFieldId += 2) + { + if (pRec) + { + pRec->Release(); + pRec = NULL; + } + + // Create a dictionary record object + + if( (pRec = new FlmRecord) == NULL) + { + rc = RC_SET( FERR_MEM); + MAKE_ERROR_STRING( "allocating FlmRecord", rc, m_szFailInfo); + goto Exit; + } + + // Populate the record object with fields and values + // The first field of a record will be inserted at + // level zero (the first parameter of insertLast() + // specifies the level number). Subsequent fields + // will be inserted at a non-zero level. + + if( RC_BAD( rc = pRec->insertLast( 0, FLM_FIELD_TAG, + FLM_TEXT_TYPE, &pvField))) + { + MAKE_ERROR_STRING( "calling insertLast", rc, m_szFailInfo); + goto Exit; + } + f_sprintf( szFieldName, "Field_%u", (unsigned)uiFieldId); + if( RC_BAD( rc = pRec->setNative( pvField, szFieldName))) + { + MAKE_ERROR_STRING( "calling setNative", rc, m_szFailInfo); + goto Exit; + } + + if( RC_BAD( rc = pRec->insertLast( 1, FLM_TYPE_TAG, + FLM_TEXT_TYPE, &pvField))) + { + MAKE_ERROR_STRING( "calling insertLast", rc, m_szFailInfo); + goto Exit; + } + if( RC_BAD( rc = pRec->setNative( pvField, "number"))) + { + MAKE_ERROR_STRING( "calling setNative", rc, m_szFailInfo); + goto Exit; + } + + if( RC_BAD( rc = FlmRecordAdd( m_hDb, FLM_DICT_CONTAINER, + &uiFieldId, pRec, 0))) + { + MAKE_ERROR_STRING( "calling FlmRecordAdd", rc, m_szFailInfo); + goto Exit; + } + } + + // Add the fields to the record in reverse order. + + for (uiFieldId = 1601; uiFieldId >= 1001; uiFieldId -= 2) + { + if( RC_BAD( rc = pDataRec->insertLast( 1, uiFieldId, + FLM_NUMBER_TYPE, &pvDataField))) + { + MAKE_ERROR_STRING( "calling insertLast", rc, m_szFailInfo); + goto Exit; + } + if (RC_BAD( rc = pDataRec->setUINT( pvDataField, uiFieldId))) + { + MAKE_ERROR_STRING( "calling setUINT", rc, m_szFailInfo); + goto Exit; + } + } + + // Add the data record to the data container. + + uiDrn = 0; + if( RC_BAD( rc = FlmRecordAdd( m_hDb, FLM_DATA_CONTAINER, + &uiDrn, pDataRec, 0))) + { + MAKE_ERROR_STRING( "calling FlmRecordAdd", rc, m_szFailInfo); + goto Exit; + } + + if( RC_BAD( rc = FlmDbTransCommit( m_hDb))) + { + MAKE_ERROR_STRING( "calling FlmDbTransCommit", rc, m_szFailInfo); + goto Exit; + } + bTransActive = FALSE; + + // For each of the 300 field ids, get the field from the record, inclusive + + for (uiFieldId = 1000; uiFieldId <= 1600; uiFieldId += 2) + { + pvDataField = pDataRec->findLevelOneField( uiFieldId, TRUE); + if (!pvDataField) + { + rc = RC_SET( FERR_FAILURE); + f_sprintf( m_szFailInfo, "Could not find level one field #%u (incl)", (unsigned)uiFieldId); + goto Exit; + } + if (RC_BAD( rc = pDataRec->getUINT( pvDataField, &uiTmp))) + { + MAKE_ERROR_STRING( "calling getUINT", rc, m_szFailInfo); + goto Exit; + } + if (uiTmp != uiFieldId + 1) + { + rc = RC_SET( FERR_FAILURE); + f_sprintf( m_szFailInfo, "Incorrect value (%u) returned from level one field #%u (incl)", + (unsigned)uiTmp, (unsigned)uiFieldId); + goto Exit; + } + } + + // For each of the 300 field ids, get the field from the record. + // Also, delete each one as we go, and make sure they are deleted. + // We need to copy the record so that this can be done. + + if ((pCopyRec = pDataRec->copy()) == NULL) + { + rc = RC_SET( FERR_MEM); + MAKE_ERROR_STRING( "calling copy", rc, m_szFailInfo); + goto Exit; + } + + for (uiFieldId = 1001; uiFieldId <= 1601; uiFieldId += 2) + { + pvDataField = pCopyRec->findLevelOneField( uiFieldId, FALSE); + if (!pvDataField) + { + rc = RC_SET( FERR_FAILURE); + f_sprintf( m_szFailInfo, "Could not find level one field #%u", (unsigned)uiFieldId); + goto Exit; + } + if (RC_BAD( rc = pCopyRec->getUINT( pvDataField, &uiTmp))) + { + MAKE_ERROR_STRING( "calling getUINT", rc, m_szFailInfo); + goto Exit; + } + if (uiTmp != uiFieldId) + { + rc = RC_SET( FERR_FAILURE); + f_sprintf( m_szFailInfo, "Incorrect value (%u) returned from level one field #%u", + (unsigned)uiTmp, (unsigned)uiFieldId); + goto Exit; + } + + // Remove the field and make sure that the find fails. + + if (RC_BAD( rc = pCopyRec->remove( pvDataField))) + { + MAKE_ERROR_STRING( "calling remove", rc, m_szFailInfo); + goto Exit; + } + pvDataField = pCopyRec->findLevelOneField( uiFieldId, FALSE); + if (pvDataField) + { + rc = RC_SET( FERR_FAILURE); + f_sprintf( m_szFailInfo, "Should NOT have found level one field #%u", + (unsigned)uiFieldId); + goto Exit; + } + } + + bPassed = TRUE; + +Exit: + + if (pRec) + { + pRec->Release(); + } + + if (pDataRec) + { + pDataRec->Release(); + } + + if (pCopyRec) + { + pCopyRec->Release(); + } + + if (bTransActive) + { + (void)FlmDbTransAbort( m_hDb); + } + + endTest( bPassed); + return( rc); +} + /*************************************************************************** Desc: ****************************************************************************/ @@ -3013,7 +3263,14 @@ RCODE IFlmTestImpl::execute( void) { goto Exit; } + + // Sorted field test + if (RC_BAD( rc = sortedFieldsTest())) + { + goto Exit; + } + // Hot Backup/Restore test if (RC_BAD( rc = backupRestoreDbTest()))