diff --git a/flaim/src/flaim.h b/flaim/src/flaim.h index 4a46711..eb469c2 100644 --- a/flaim/src/flaim.h +++ b/flaim/src/flaim.h @@ -2084,6 +2084,7 @@ #define FLM_USE_DEFAULT_VALUE 0x20 #define FLM_SINGLE_VALUED 0x40 + #define FLM_ROOTED_PATH 0x80 // Predefined values for special fields @@ -5440,6 +5441,11 @@ FLMBOOL bFindInclusive ///< OK to find next field after uiFieldID? ); + /// Find a level one field ID in a record. + void * nextLevelOneField( + void * pvLastLevelOneField ///< Last level one field that was found. + ); + void * locateFieldByPosition( FLMUINT uiPosition); @@ -6754,4 +6760,145 @@ } } + /**************************************************************************** + Random Generation Functions + ****************************************************************************/ + + #define MAX_RANDOM 2147483646L + + typedef struct + { + FLMINT32 i32Seed; + } f_randomGenerator; + + /* + Call f_randomSetSeed to initialize your random-number generator. Then + call f_randomLong, f_randomChoice, or f_randomTruth to access the series of + random values. + + Initialize your generator with f_randomSetSeed( &r, SOME_CONSTANT) to get a + reproducible sequence of pseudo-random numbers. Using different constant + seeds will give you independent sequences. The constant can be any number + between 1 and MAX_RANDOM, inclusive. + + Call f_randomLong to get a number randomly distributed between 1 and + MAX_RANDOM. This is the basic call, but is usually not as convenient as + the subsequent functions, all of which call f_randomLong and process the + result into a more useable form. + + 1 <= f_randomLong(&r) <= MAX_RANDOM + + Call f_randomChoice to get a number uniformly distributed across a + specified range of integer values. + + lo <= f_randomChoice(&r, lo, hi) <= hi + + Call f_randomTruth(&r, n) to get a boolean value which is true n percent + of the time (0 <= n <= 100). + + 0 <= f_randomTrue(&r, n) <= 1 + */ + + FLMEXP void FLMAPI f_randomize( + f_randomGenerator * pRand); + + FLMEXP void FLMAPI f_randomSetSeed( + f_randomGenerator * pRand, + FLMINT32 i32seed); + + FLMEXP FLMINT32 FLMAPI f_randomLong( + f_randomGenerator * pRand); + + FLMEXP FLMINT32 FLMAPI f_randomChoice( + f_randomGenerator * pRand, + FLMINT32 lo, + FLMINT32 hi); + + FLMEXP FLMINT FLMAPI f_randomTruth( + f_randomGenerator * pRand, + FLMINT iPercentageTrue); + + /**************************************************************************** + Time, date, timestamp functions + ****************************************************************************/ + typedef struct + { + FLMUINT16 year; + FLMBYTE month; + FLMBYTE day; + } F_DATE, * F_DATE_p; + + typedef struct + { + FLMBYTE hour; + FLMBYTE minute; + FLMBYTE second; + FLMBYTE hundredth; + } F_TIME, * F_TIME_p; + + typedef struct + { + FLMUINT16 year; + FLMBYTE month; + FLMBYTE day; + FLMBYTE hour; + FLMBYTE minute; + FLMBYTE second; + FLMBYTE hundredth; + } F_TMSTAMP, * F_TMSTAMP_p; + + FLMEXP void FLMAPI f_timeGetSeconds( + FLMUINT * puiSeconds); + + FLMEXP void FLMAPI f_timeGetTimeStamp( + F_TMSTAMP * pTimeStamp); + + FLMEXP FLMINT FLMAPI f_timeGetLocalOffset( void); + + FLMEXP void FLMAPI f_timeSecondsToDate( + FLMUINT uiSeconds, + F_TMSTAMP * pTimeStamp); + + FLMEXP void FLMAPI f_timeDateToSeconds( + F_TMSTAMP * pTimeStamp, + FLMUINT * puiSeconds); + + FLMEXP FLMINT FLMAPI f_timeCompareTimeStamps( + F_TMSTAMP * pTimeStamp1, + F_TMSTAMP * pTimeStamp2, + FLMUINT uiCompareFlag); + + #define COMPARE_DATE_AND_TIME 0 + #define COMPARE_DATE_ONLY 1 + #define COMPARE_TIME_ONLY 2 + + #if defined( FLM_UNIX) + FLMEXP FLMUINT FLMAPI f_timeGetMilliTime(); + #endif + + // Get the current time as platform-dependent timer units. + FLMEXP FLMUINT FLMAPI f_getCurrTimeAsTimerUnits( void); + + // Convert seconds to platform-dependent timer units. + FLMEXP FLMUINT FLMAPI f_secondsToTimerUnits( + FLMUINT uiSeconds); + + // Convert platform-dependent timer units to seconds. + FLMEXP FLMUINT FLMAPI f_timerUnitsToSeconds( + FLMUINT uiTimerUnits); + + // Convert milliseconds to platform-dependent timer units. + FLMEXP FLMUINT FLMAPI f_milliSecondsToTimerUnits( + FLMUINT uiMilliSeconds); + + // Convert platform-dependent timer units to milli-seconds. + FLMEXP FLMUINT FLMAPI f_timerUnitsToMilliSeconds( + FLMUINT uiTimerUnits); + + // Return elapsed time (as platform-dependent timer units). Input + // parameters must be passed in as platform-dependent timer units. + FLMEXP FLMUINT FLMAPI f_elapsedTimeTimerUnits( + FLMUINT uiEarlierTimeTimerUnits, + FLMUINT uiLaterTimeTimerUnits); + #endif diff --git a/flaim/src/fqeval.cpp b/flaim/src/fqeval.cpp index 0344821..e97957f 100644 --- a/flaim/src/fqeval.cpp +++ b/flaim/src/fqeval.cpp @@ -29,6 +29,16 @@ extern FQ_OPERATION * FQ_DoOperation[]; FSTATIC FLMUINT flmCurEvalTrueFalse( FQATOM_p pElm); +FSTATIC RCODE flmCurGetAtomFromRec( + FDB * pDb, + POOL * pPool, + FQATOM_p pTreeAtom, + FlmRecord * pRecord, + QTYPES eFldType, + FLMBOOL bGetAtomVals, + FQATOM_p pResult, + FLMBOOL bHaveKey); + FSTATIC RCODE flmFieldIterate( FDB * pDb, POOL * pPool, @@ -391,7 +401,7 @@ Desc: Given a list of FQATOMs containing alternate field paths, finds those contents of those paths. Ret: ****************************************************************************/ -RCODE flmCurGetAtomFromRec( +FSTATIC RCODE flmCurGetAtomFromRec( FDB * pDb, POOL * pPool, FQATOM_p pTreeAtom, @@ -403,17 +413,22 @@ RCODE flmCurGetAtomFromRec( { RCODE rc = FERR_OK; FQATOM_p pTmpResult = NULL; - FQATOM_p pTmpQAtom; - void * pField; + void * pvField; + void * pvLastLevelOneField; FLMUINT * puiFldPath; FLMUINT uiCurrFieldPath[ GED_MAXLVLNUM + 1]; - FLMUINT uiSlot; + FLMUINT uiFieldLevel; FLMUINT uiTmp; - FLMUINT uiFldNum; + FLMUINT uiLeafFldNum; FLMUINT uiRecFldNum; FLMBOOL bFound; FLMBOOL bSavedInvisTrans; FLMUINT uiResult; + FLMBOOL bPathFromRoot; + FLMBOOL bUseFieldIdLookupTable; + FLMUINT * puiPToCPath; + FLMUINT uiHighestLevel; + FLMUINT uiLevelOneFieldId; pResult->eType = NO_TYPE; if (pTreeAtom->val.QueryFld.puiFldPath [0] == FLM_MISSING_FIELD_TAG) @@ -425,162 +440,240 @@ RCODE flmCurGetAtomFromRec( goto Exit; } - for (pTmpQAtom = pTreeAtom; pTmpQAtom; pTmpQAtom = pTmpQAtom->pNext) + flmAssert( !pTreeAtom->pNext); + puiFldPath = pTreeAtom->val.QueryFld.puiFldPath; + puiPToCPath = pTreeAtom->val.QueryFld.puiPToCPath; + uiLevelOneFieldId = puiPToCPath [1]; + + // We are only going to do the path to root optimation if + // the field path is specified as having to be from the root (FLM_ROOTED_PATH) + // and it goes down to at least level 1 in the tree, and our record + // has a field id table in it. + + bPathFromRoot = (!bHaveKey && + (pTreeAtom->uiFlags & FLM_ROOTED_PATH)) + ? TRUE + : FALSE; + bUseFieldIdLookupTable = (bPathFromRoot && + pRecord->fieldIdTableEnabled() && + uiLevelOneFieldId) + ? TRUE + : FALSE; + if (*puiFldPath == FLM_RECID_FIELD) { - puiFldPath = pTmpQAtom->val.QueryFld.puiFldPath; - if (*puiFldPath == FLM_RECID_FIELD) + pResult->eType = FLM_UINT32_VAL; + pResult->val.uiVal = pRecord->getID(); + goto Exit; + } + pvField = pRecord->root(); + uiFieldLevel = 0; + if (bPathFromRoot) + { + // Determine the highest level we need to go down to in the record. + + uiHighestLevel = 1; + while (puiPToCPath [uiHighestLevel + 1]) + { + uiHighestLevel++; + } + if (puiPToCPath [0] != pRecord->getFieldID( pvField)) { - pResult->eType = FLM_UINT32_VAL; - pResult->val.uiVal = pRecord->getID(); goto Exit; } - pField = pRecord->root(); + if (bUseFieldIdLookupTable) + { + if ((pvLastLevelOneField = + pRecord->findLevelOneField( uiLevelOneFieldId, FALSE)) == NULL) + { + goto Exit; + } + uiCurrFieldPath [0] = puiPToCPath [0]; + pvField = pvLastLevelOneField; + uiFieldLevel = 1; + } + } + uiLeafFldNum = puiFldPath[ 0]; + for (;;) + { + uiRecFldNum = pRecord->getFieldID( pvField); + uiCurrFieldPath[ uiFieldLevel] = uiRecFldNum; + + // When we are doing path from root, we only need to traverse + // back up when we are on a field that is exactly at the highest level + // we can go down to in the tree - no need to check any others. + // If we are not doing bPathFromRoot, we check all node paths. + + if (uiRecFldNum == uiLeafFldNum && + (!bPathFromRoot || uiFieldLevel == uiHighestLevel)) + { + bFound = TRUE; + + // We already know that puiFldPath[0] matches - it is the same + // as uiLeafFldNum. Traverse back up the tree and see if + // the rest of the path matches. + + for (uiTmp = 1; puiFldPath[ uiTmp]; uiTmp++) + { + if (!uiFieldLevel) + { + bFound = FALSE; + break; + } + uiFieldLevel--; + if (puiFldPath[ uiTmp] != uiCurrFieldPath[ uiFieldLevel]) + { + bFound = FALSE; + break; + } + } + + // Found field in proper path. Get the value if requested, + // otherwise set the result to FLM_TRUE and exit. If a + // callback is set, do that first to see if it is REALLY + // found. + + if (bFound && pTreeAtom->val.QueryFld.fnGetField) + { + CB_ENTER( pDb, &bSavedInvisTrans); + rc = pTreeAtom->val.QueryFld.fnGetField( + pTreeAtom->val.QueryFld.pvUserData, pRecord, + (HFDB)pDb, pTreeAtom->val.QueryFld.puiFldPath, + FLM_FLD_VALIDATE, NULL, &pvField, &uiResult); + CB_EXIT( pDb, bSavedInvisTrans); + if (RC_BAD( rc)) + { + goto Exit; + } + if (uiResult == FLM_FALSE) + { + bFound = FALSE; + } + else if (uiResult == FLM_UNK) + { + if (bHaveKey) + { + + // bHaveKey means we are evaluating a key. There + // should only be one occurrence of the field in the + // key in this case. If the callback does not know + // if the field really exists, we must defer judgement + // on this one until we can fetch the record. Hence, + // we force the result to be UNKNOWN. Note that it + // must be set to UNKNOWN, even if this is a field exists + // predicate (!bGetAtomVals). If we set it to NO_TYPE + // and fall through to exist, it would get converted to + // a FLM_BOOL_VAL of FALSE, which is NOT what we + // want. + + pResult->eType = FLM_UNKNOWN; + pResult->uiFlags = pTreeAtom->uiFlags & + ~(FLM_IS_RIGHT_TRUNCATED_DATA | + FLM_IS_LEFT_TRUNCATED_DATA); + if (pvField) + { + if (pRecord->isRightTruncated( pvField)) + { + pResult->uiFlags |= FLM_IS_RIGHT_TRUNCATED_DATA; + } + if (pRecord->isLeftTruncated( pvField)) + { + pResult->uiFlags |= FLM_IS_LEFT_TRUNCATED_DATA; + } + } + + // Better not be multiple results in this case because + // we are evaluating a key. + + flmAssert( pResult->pNext == NULL); + pResult->pNext = NULL; + goto Exit; + } + else + { + bFound = FALSE; + } + } + } + + if (bFound) + { + if (!bGetAtomVals) + { + pResult->eType = FLM_BOOL_VAL; + pResult->val.uiBool = FLM_TRUE; + goto Exit; + } + if (!pTmpResult) + { + pTmpResult = pResult; + } + else if (pTmpResult->eType) + { + if ((pTmpResult->pNext = + (FQATOM_p)GedPoolCalloc( pPool, sizeof( FQATOM))) == NULL) + { + rc = RC_SET( FERR_MEM); + goto Exit; + } + pTmpResult = pTmpResult->pNext; + } + pTmpResult->uiFlags = pTreeAtom->uiFlags; + if ((rc = flmCurGetAtomVal( pRecord, pvField, pPool, eFldType, + pTmpResult)) == FERR_CURSOR_SYNTAX) + { + goto Exit; + } + } + } + + // Get the next field to process. If bPathFromRoot is set, we will skip + // any fields that are at too high of levels in the record. + // If bUseFieldIdLookupTable is set, it means + // that when we get back up to level one fields, we should call the + // API to get the next level one field. + for (;;) { - uiRecFldNum = pRecord->getFieldID( pField); - uiSlot = pRecord->getLevel( pField); - uiCurrFieldPath[ uiSlot] = uiRecFldNum; - uiFldNum = puiFldPath[ 0]; - if (uiRecFldNum == uiFldNum) + if ((pvField = pRecord->next( pvField)) == NULL) { - bFound = TRUE; - for (uiTmp = 0; puiFldPath[ uiTmp]; uiSlot--, uiTmp++) - { - if (!uiSlot) - { - if ((puiFldPath[ uiTmp + 1]) || - (puiFldPath[ uiTmp] != uiCurrFieldPath[ uiSlot])) - { - bFound = FALSE; - } - break; - } - if (puiFldPath[ uiTmp] != uiCurrFieldPath[ uiSlot]) - { - bFound = FALSE; - break; - } - } - - // Found field in proper path. Get the value if requested, - // otherwise set the result to FLM_TRUE and exit. If a - // callback is set, do that first to see if it is REALLY - // found. - - if (bFound && pTreeAtom->val.QueryFld.fnGetField) - { - CB_ENTER( pDb, &bSavedInvisTrans); - rc = pTreeAtom->val.QueryFld.fnGetField( - pTreeAtom->val.QueryFld.pvUserData, pRecord, - (HFDB)pDb, pTreeAtom->val.QueryFld.puiFldPath, - FLM_FLD_VALIDATE, NULL, &pField, &uiResult); - CB_EXIT( pDb, bSavedInvisTrans); - if (RC_BAD( rc)) - { - goto Exit; - } - if (uiResult == FLM_FALSE) - { - bFound = FALSE; - } - else if (uiResult == FLM_UNK) - { - if (bHaveKey) - { - - // bHaveKey means we are evaluating a key. There - // should only be one occurrence of the field in the - // key in this case. If the callback does not know - // if the field really exists, we must defer judgement - // on this one until we can fetch the record. Hence, - // we force the result to be UNKNOWN. Note that it - // must be set to UNKNOWN, even if this is a field exists - // predicate (!bGetAtomVals). If we set it to NO_TYPE - // and fall through to exist, it would get converted to - // a FLM_BOOL_VAL of FALSE, which is NOT what we - // want. - - pResult->eType = FLM_UNKNOWN; - pResult->uiFlags = pTreeAtom->uiFlags & - ~(FLM_IS_RIGHT_TRUNCATED_DATA | - FLM_IS_LEFT_TRUNCATED_DATA); - if (pField) - { - if (pRecord->isRightTruncated( pField)) - { - pResult->uiFlags |= FLM_IS_RIGHT_TRUNCATED_DATA; - } - if (pRecord->isLeftTruncated( pField)) - { - pResult->uiFlags |= FLM_IS_LEFT_TRUNCATED_DATA; - } - } - - // Better not be multiple results in this case because - // we are evaluating a key. - - flmAssert( pResult->pNext == NULL); - pResult->pNext = NULL; - goto Exit; - } - else - { - bFound = FALSE; - } - } - } - - if (bFound) - { - if (!bGetAtomVals) - { - pResult->eType = FLM_BOOL_VAL; - pResult->val.uiBool = FLM_TRUE; - goto Exit; - } - if (!pTmpResult) - { - pTmpResult = pResult; - } - else if (pTmpResult->eType) - { - if ((pTmpResult->pNext = - (FQATOM_p)GedPoolCalloc( pPool, sizeof( FQATOM))) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - pTmpResult = pTmpResult->pNext; - } - pTmpResult->uiFlags = pTreeAtom->uiFlags; - if ((rc = flmCurGetAtomVal( pRecord, pField, pPool, eFldType, - pTmpResult)) == FERR_CURSOR_SYNTAX) - { - goto Exit; - } - } - } - - // If the end of the record has been reached, and the last field - // value searched for was not found, unlink it from the result list. - - if ((pField = pRecord->next( pField)) == NULL) - { - if (pTmpResult && pTmpResult != pResult && - pTmpResult->eType == NO_TYPE) - { - FQATOM_p pTmp; - - for (pTmp = pResult; - pTmp && pTmp->pNext != pTmpResult; - pTmp = pTmp->pNext) - { - ; - } - pTmp->pNext = NULL; - } break; } + uiFieldLevel = pRecord->getLevel( pvField); + if (!bPathFromRoot) + { + break; + } + if (uiFieldLevel > uiHighestLevel) + { + continue; + } + if (bUseFieldIdLookupTable && uiFieldLevel == 1) + { + pvLastLevelOneField = pvField = pRecord->nextLevelOneField( + pvLastLevelOneField); + } + break; + } + + // If the end of the record has been reached, and the last field + // value searched for was not found, unlink it from the result list. + + if (!pvField) + { + if (pTmpResult && pTmpResult != pResult && + pTmpResult->eType == NO_TYPE) + { + FQATOM_p pTmp; + + for (pTmp = pResult; + pTmp && pTmp->pNext != pTmpResult; + pTmp = pTmp->pNext) + { + ; + } + pTmp->pNext = NULL; + } + break; } } @@ -1298,7 +1391,7 @@ Get_Operand: { if (RC_BAD( rc = flmCurGetAtomFromRec( pDb, pTmpPool, pTmpQNode->pQAtom, pRecord, eFldType, - TRUE, pTmpQAtom, bHaveKey))) + TRUE, pTmpQAtom, bHaveKey))) { goto Exit; } diff --git a/flaim/src/fqstack.cpp b/flaim/src/fqstack.cpp index 16221a5..cfe6198 100644 --- a/flaim/src/fqstack.cpp +++ b/flaim/src/fqstack.cpp @@ -495,7 +495,9 @@ void flmCurLinkLastChild( } /**************************************************************************** -Desc: Put a value in an FQATOM node - so we can call it from SMI. +Desc: Put a value in an FQATOM node - so we can call it from SMI. Can + only be used for values, not field paths. Cannot be used for + unknown values. ****************************************************************************/ RCODE flmPutValInAtom( void * pAtom, @@ -527,9 +529,6 @@ RCODE flmPutValInAtom( pQAtom->val.pucBuf = (FLMBYTE *)pvVal; pQAtom->uiBufLen = uiValLen; break; - case FLM_FLD_PATH: - pQAtom->val.QueryFld.puiFldPath = (FLMUINT *)pvVal; - break; case FLM_UNKNOWN: break; default: @@ -553,6 +552,7 @@ RCODE flmCurMakeQNode( FQNODE_p * ppQNode) { FLMUINT * puiTmpPath; + FLMUINT * puiPToCPath; FLMUINT * puiFldPath; FLMUINT uiTmpLen = uiValLen; FLMBYTE * pTmpBuf; @@ -622,19 +622,22 @@ RCODE flmCurMakeQNode( } if ((puiTmpPath = (FLMUINT *)GedPoolCalloc( pPool, - (FLMUINT)((FLMUINT)(uiPathCnt + 1) * + (FLMUINT)((FLMUINT)(uiPathCnt + 1) * 2 * (FLMUINT)sizeof( FLMUINT)))) == NULL) { rc = RC_SET( FERR_MEM); goto Exit; } + puiPToCPath = &puiTmpPath [uiPathCnt + 1]; puiFldPath = (FLMUINT *)pVal; for (uiCnt = 0; uiCnt < uiPathCnt; uiCnt++) { puiTmpPath[ uiPathCnt - uiCnt - 1] = puiFldPath[ uiCnt]; + puiPToCPath [uiCnt] = puiFldPath [uiCnt]; } pQAtom->val.QueryFld.puiFldPath = puiTmpPath; + pQAtom->val.QueryFld.puiPToCPath = puiPToCPath; break; case FLM_BINARY_VAL: if ((pTmpBuf = (FLMBYTE *)GedPoolCalloc( pPool, uiTmpLen)) == NULL) diff --git a/flaim/src/fquery.h b/flaim/src/fquery.h index 566f04f..4dd7410 100644 --- a/flaim/src/fquery.h +++ b/flaim/src/fquery.h @@ -145,6 +145,7 @@ Structures used for the query tree and other stuff typedef struct FlmQueryField { FLMUINT * puiFldPath; // In child-to-parent order. + FLMUINT * puiPToCPath; // In parent-to-child order. CURSOR_GET_FIELD_CB fnGetField; FLMBOOL bValidateOnly; void * pvUserData; @@ -414,16 +415,6 @@ RCODE flmCurGetAtomVal( QTYPES eFldType, FQATOM_p pResult); -RCODE flmCurGetAtomFromRec( - FDB * pDb, - POOL * pPool, - FQATOM_p pTreeAtom, - FlmRecord * pRecord, - QTYPES eFldType, - FLMBOOL bGetAtomVals, - FQATOM_p pResult, - FLMBOOL bHaveKey); - RCODE flmCurEvalCriteria( CURSOR_p pCursor, SUBQUERY_p pSubQuery, diff --git a/flaim/src/frec.cpp b/flaim/src/frec.cpp index 4791b48..612b04e 100644 --- a/flaim/src/frec.cpp +++ b/flaim/src/frec.cpp @@ -5176,6 +5176,18 @@ FIELD_ID * FlmRecord::findFieldId( // Found Match + // If ui32FieldOffset was not set, we need to + // backtrack to find the lowest one that matches + + if (!ui32FieldOffset) + { + while (uiMid && pFieldIdTable [uiMid-1].ui16FieldId == ui16FieldId) + { + uiMid--; + } + } + + pFieldId = &pFieldIdTable [uiMid]; if (puiInsertPos) { @@ -5396,6 +5408,47 @@ void * FlmRecord::findLevelOneField( return( pvField); } +/****************************************************************************** +Desc: Find a level one field in the record. +******************************************************************************/ +void * FlmRecord::nextLevelOneField( + void * pvLastLevelOneField) +{ + FLMUINT16 ui16FieldId = (FLMUINT16)getFieldID( pvLastLevelOneField); + FIELDLINK ui32FieldOffset = (FIELDLINK)((FLMUINT)pvLastLevelOneField); + FLMUINT uiInsertPos; + FIELD_ID * pFieldId; + void * pvField = NULL; + + if (m_pucFieldIdTable) + { + if ((pFieldId = findFieldId( ui16FieldId, ui32FieldOffset, + &uiInsertPos)) != NULL) + { + + // See if there is a next field in the array. + + if (uiInsertPos + 1 < getFieldIdTableItemCount( m_pucFieldIdTable)) + { + + // See if the next field in the array has the same field ID as + // the one we're looking for. + + pFieldId = getFieldIdTable( m_pucFieldIdTable) + uiInsertPos + 1; + if (pFieldId->ui16FieldId == ui16FieldId) + { + 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. ******************************************************************************/ diff --git a/flaim/src/ftk.h b/flaim/src/ftk.h index f47b857..f7754b3 100644 --- a/flaim/src/ftk.h +++ b/flaim/src/ftk.h @@ -1005,90 +1005,6 @@ } #endif - /**************************************************************************** - Desc: Random numbers - ****************************************************************************/ - - #define MAX_RANDOM 2147483646L - - typedef struct - { - FLMINT32 i32Seed; - } f_randomGenerator; - - void f_randomize( - f_randomGenerator * pRand); - - void f_randomSetSeed( - f_randomGenerator * pRand, - FLMINT32 i32seed); - - FLMINT32 f_randomLong( - f_randomGenerator * pRand); - - FLMINT32 f_randomChoice( - f_randomGenerator * pRand, - FLMINT32 lo, - FLMINT32 hi); - - FLMINT f_randomTruth( - f_randomGenerator * pRand, - FLMINT iPercentageTrue); - - /**************************************************************************** - Desc: Time, date, timestamp functions - ****************************************************************************/ - typedef struct - { - FLMUINT16 year; - FLMBYTE month; - FLMBYTE day; - } F_DATE, * F_DATE_p; - - typedef struct - { - FLMBYTE hour; - FLMBYTE minute; - FLMBYTE second; - FLMBYTE hundredth; - } F_TIME, * F_TIME_p; - - typedef struct - { - FLMUINT16 year; - FLMBYTE month; - FLMBYTE day; - FLMBYTE hour; - FLMBYTE minute; - FLMBYTE second; - FLMBYTE hundredth; - } F_TMSTAMP, * F_TMSTAMP_p; - - void f_timeGetSeconds( - FLMUINT * puiSeconds); - - void f_timeGetTimeStamp( - F_TMSTAMP * pTimeStamp); - - FLMINT f_timeGetLocalOffset( void); - - void f_timeSecondsToDate( - FLMUINT uiSeconds, - F_TMSTAMP * pTimeStamp); - - void f_timeDateToSeconds( - F_TMSTAMP * pTimeStamp, - FLMUINT * puiSeconds); - - FLMINT f_timeCompareTimeStamps( - F_TMSTAMP * pTimeStamp1, - F_TMSTAMP * pTimeStamp2, - FLMUINT uiFlag); - - #if defined( FLM_UNIX) - unsigned f_timeGetMilliTime(); - #endif - /********************************************************************** Desc: Atomic Increment, Decrement, Exchange Note: Some of this code is derived from the Ximian source code contained diff --git a/flaim/src/ftkrand.cpp b/flaim/src/ftkrand.cpp index fc5a166..c35a5e2 100644 --- a/flaim/src/ftkrand.cpp +++ b/flaim/src/ftkrand.cpp @@ -59,7 +59,7 @@ implementation is correct. /************************************************************************* Desc: Set the seed from the date and time *************************************************************************/ -void f_randomize( +FLMEXP void FLMAPI f_randomize( f_randomGenerator * pRand) { FLMUINT uiTime; @@ -73,7 +73,7 @@ void f_randomize( /************************************************************************* Desc: initialize the seed to a known value *************************************************************************/ -void f_randomSetSeed( +FLMEXP void FLMAPI f_randomSetSeed( f_randomGenerator * pRand, FLMINT32 ui32Seed) { @@ -153,7 +153,7 @@ Note: generator since it would continue to generate nothing but zero from that point on (it IS a multiplicative generator, after all). *************************************************************************/ -FLMINT32 f_randomLong( +FLMEXP FLMINT32 FLMAPI f_randomLong( f_randomGenerator * generator) { #define M 2147483647 @@ -214,7 +214,7 @@ Note: The distance (range) between lo and hi must be no greater than Therefore, f_randomChoice uses a better but slower algorithm if the range is >= 1 Meg (2**20). *************************************************************************/ -FLMINT32 f_randomChoice( +FLMEXP FLMINT32 FLMAPI f_randomChoice( f_randomGenerator * r, FLMINT32 lo, /* lowest allowed return value */ FLMINT32 hi /* highest allowed return value */ @@ -258,7 +258,7 @@ Example: life_force[ i] = 0; *************************************************************************/ -FLMINT f_randomTruth( +FLMEXP FLMINT FLMAPI f_randomTruth( f_randomGenerator * pRand, FLMINT iPercentageTrue /* 1 <= int <= 100 */ ) diff --git a/flaim/src/ftktime.cpp b/flaim/src/ftktime.cpp index 5690022..e33a91d 100644 --- a/flaim/src/ftktime.cpp +++ b/flaim/src/ftktime.cpp @@ -73,7 +73,7 @@ static FLMUINT f_timeLeapYearsSince1970( /**************************************************************************** Desc: Gets the number of seconds since 1980 or 1970. ****************************************************************************/ -void f_timeGetSeconds( +FLMEXP void FLMAPI f_timeGetSeconds( FLMUINT * puiSeconds) { #if defined( FLM_WIN) @@ -93,7 +93,7 @@ void f_timeGetSeconds( /**************************************************************************** Desc: Gets the time stamp from the system clock. ****************************************************************************/ -void f_timeGetTimeStamp( +FLMEXP void FLMAPI f_timeGetTimeStamp( F_TMSTAMP * pTimeStamp) { #if defined( FLM_WIN) @@ -136,7 +136,7 @@ void f_timeGetTimeStamp( /**************************************************************************** Desc: Returns the local time bias in seconds ****************************************************************************/ -FLMINT f_timeGetLocalOffset( void) +FLMEXP FLMINT FLMAPI f_timeGetLocalOffset( void) { FLMINT iOffset = 0; @@ -217,7 +217,7 @@ static FLMUINT f_timeLeapYearsSince1970( /**************************************************************************** Desc: Convert from seconds to the F_TMSTAMP structure. ****************************************************************************/ -void f_timeSecondsToDate( +FLMEXP void FLMAPI f_timeSecondsToDate( FLMUINT uiSeconds, F_TMSTAMP * date) { @@ -273,7 +273,7 @@ void f_timeSecondsToDate( /**************************************************************************** Desc: Convert a time stamp to the number of seconds. ****************************************************************************/ -void f_timeDateToSeconds( +FLMEXP void FLMAPI f_timeDateToSeconds( F_TMSTAMP * pTimeStamp, // [in] - time stamp of date FLMUINT * puiSeconds) // [out] - seconds of time stamp { @@ -281,7 +281,7 @@ void f_timeDateToSeconds( FLMUINT uiDays = 0; // is date past max? - if( f_timeCompareTimeStamps( pTimeStamp, &maxdate, 0) > 0) + if( f_timeCompareTimeStamps( pTimeStamp, &maxdate, COMPARE_DATE_AND_TIME) > 0) { *pTimeStamp = maxdate; } @@ -309,12 +309,12 @@ void f_timeDateToSeconds( /**************************************************************************** Desc: Compare two time stamps ****************************************************************************/ -FLMINT f_timeCompareTimeStamps( +FLMEXP FLMINT FLMAPI f_timeCompareTimeStamps( F_TMSTAMP * pTimeStamp1, F_TMSTAMP * pTimeStamp2, - FLMUINT flag) + FLMUINT uiCompareFlag) { - if( flag != 2) /* not comparing times only */ + if( uiCompareFlag != COMPARE_TIME_ONLY) /* not comparing times only */ { if( pTimeStamp1->year != pTimeStamp2->year) { @@ -329,7 +329,7 @@ FLMINT f_timeCompareTimeStamps( return((pTimeStamp1->day < pTimeStamp2->day) ? -1 : 1); } } - if( flag != 1) + if( uiCompareFlag != COMPARE_DATE_ONLY) { if( pTimeStamp1->hour != pTimeStamp2->hour) { @@ -351,7 +351,7 @@ FLMINT f_timeCompareTimeStamps( Desc: Get the current time in milliseconds. ****************************************************************************/ #if defined( FLM_UNIX) -unsigned f_timeGetMilliTime() +FLMEXP FLMUINT FLMAPI f_timeGetMilliTime() { #ifdef FLM_SOLARIS static hrtime_t epoch = 0; @@ -360,7 +360,7 @@ unsigned f_timeGetMilliTime() if (!epoch) epoch = now; - return( (unsigned)((now - epoch) / (1000 * 1000))); + return( (FLMUINT)((now - epoch) / (1000 * 1000))); #else static int epoch = 0; struct timeval tv; @@ -369,7 +369,74 @@ unsigned f_timeGetMilliTime() if (!epoch) epoch = tv.tv_sec; - return (tv.tv_sec - epoch) * 1000 + tv.tv_usec / 1000; + return( (FLMUINT)((tv.tv_sec - epoch) * 1000 + tv.tv_usec / 1000)); #endif } #endif + +/**************************************************************************** +Desc: Get the current time as platform-dependent timer units. +****************************************************************************/ +FLMEXP FLMUINT FLMAPI f_getCurrTimeAsTimerUnits( void) +{ + return( FLM_GET_TIMER()); +} + +/**************************************************************************** +Desc: Convert seconds to platform-dependent timer units. +****************************************************************************/ +FLMEXP FLMUINT FLMAPI f_secondsToTimerUnits( + FLMUINT uiSeconds) +{ + FLMUINT uiTimerUnits; + + FLM_SECS_TO_TIMER_UNITS( uiSeconds, uiTimerUnits); + return( uiTimerUnits); +} + +/**************************************************************************** +Desc: Convert platform-dependent timer units to seconds. +****************************************************************************/ +FLMEXP FLMUINT FLMAPI f_timerUnitsToSeconds( + FLMUINT uiTimerUnits) +{ + FLMUINT uiSeconds; + + FLM_TIMER_UNITS_TO_SECS( uiTimerUnits, uiSeconds); + return( uiSeconds); +} + +/**************************************************************************** +Desc: Convert milliseconds to platform-dependent timer units. +****************************************************************************/ +FLMEXP FLMUINT FLMAPI f_milliSecondsToTimerUnits( + FLMUINT uiMilliSeconds) +{ + FLMUINT uiTimerUnits; + + FLM_MILLI_TO_TIMER_UNITS( uiMilliSeconds, uiTimerUnits); + return( uiTimerUnits); +} + +/**************************************************************************** +Desc: Convert platform-dependent timer units to milli-seconds. +****************************************************************************/ +FLMEXP FLMUINT FLMAPI f_timerUnitsToMilliSeconds( + FLMUINT uiTimerUnits) +{ + FLMUINT uiMilliSeconds; + + FLM_TIMER_UNITS_TO_MILLI( uiTimerUnits, uiMilliSeconds); + return( uiMilliSeconds); +} + +/**************************************************************************** +Desc: Return elapsed time (as platform-dependent timer units). Input + parameters must be passed in as platform-dependent timer units. +****************************************************************************/ +FLMEXP FLMUINT FLMAPI f_elapsedTimeTimerUnits( + FLMUINT uiEarlierTimeTimerUnits, + FLMUINT uiLaterTimeTimerUnits) +{ + return( FLM_ELAPSED_TIME( uiLaterTimeTimerUnits, uiEarlierTimeTimerUnits)); +} diff --git a/flaim/util/basic_test.cpp b/flaim/util/basic_test.cpp index ad13cc8..d839510 100644 --- a/flaim/util/basic_test.cpp +++ b/flaim/util/basic_test.cpp @@ -126,7 +126,12 @@ public: RCODE resumeIndexTest( FLMUINT uiIndex); - RCODE sortedFieldsTest( void); + RCODE sortedFieldsTest( + FLMUINT * puiDrn); + + RCODE sortedFieldsQueryTest( + FLMUINT uiDrn, + FLMBOOL bDoRootedFieldPaths); RCODE backupRestoreDbTest( void); @@ -2031,7 +2036,8 @@ Exit: /*************************************************************************** Desc: ****************************************************************************/ -RCODE IFlmTestImpl::sortedFieldsTest( void) +RCODE IFlmTestImpl::sortedFieldsTest( + FLMUINT * puiDrn) { RCODE rc = FERR_OK; FLMBOOL bPassed = FALSE; @@ -2044,7 +2050,9 @@ RCODE IFlmTestImpl::sortedFieldsTest( void) char szFieldName [100]; FLMUINT uiFieldId; FLMUINT uiTmp; - FLMUINT uiDrn; + FLMUINT uiCount; + FLMUINT uiLoop1; + FLMUINT uiLoop2; beginTest( "Sorted Fields Test"); @@ -2065,7 +2073,7 @@ RCODE IFlmTestImpl::sortedFieldsTest( void) MAKE_ERROR_STRING( "allocating FlmRecord", rc, m_szFailInfo); goto Exit; } - if( RC_BAD( rc = pDataRec->insertLast( 0, FLM_FIELD_TAG, + if( RC_BAD( rc = pDataRec->insertLast( 0, PERSON_TAG, FLM_TEXT_TYPE, &pvDataField))) { MAKE_ERROR_STRING( "calling insertLast", rc, m_szFailInfo); @@ -2143,24 +2151,60 @@ RCODE IFlmTestImpl::sortedFieldsTest( void) for (uiFieldId = 1601; uiFieldId >= 1001; uiFieldId -= 2) { - if( RC_BAD( rc = pDataRec->insertLast( 1, uiFieldId, - FLM_NUMBER_TYPE, &pvDataField))) + // Add three instances of each field. + + for (uiCount = 1; uiCount <= 3; uiCount++) { - 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; + 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; + } + + // Under each field add 25 sub-fields, and under those add 5 sub-fields + + for (uiLoop1 = 0; uiLoop1 < 25; uiLoop1++) + { + if( RC_BAD( rc = pDataRec->insertLast( 2, 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; + } + for (uiLoop2 = 0; uiLoop2 < 5; uiLoop2++) + { + if( RC_BAD( rc = pDataRec->insertLast( 3, 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; + *puiDrn = 0; if( RC_BAD( rc = FlmRecordAdd( m_hDb, FLM_DATA_CONTAINER, - &uiDrn, pDataRec, 0))) + puiDrn, pDataRec, 0))) { MAKE_ERROR_STRING( "calling FlmRecordAdd", rc, m_szFailInfo); goto Exit; @@ -2181,9 +2225,24 @@ RCODE IFlmTestImpl::sortedFieldsTest( void) if (!pvDataField) { rc = RC_SET( FERR_FAILURE); - f_sprintf( m_szFailInfo, "Could not find level one field #%u (incl)", (unsigned)uiFieldId); + f_sprintf( m_szFailInfo, "Could not find next level one after field #%u", + (unsigned)uiFieldId); goto Exit; } + + // Verify that we got the expected field ID. + + uiTmp = pDataRec->getFieldID( pvDataField); + if (uiTmp != uiFieldId + 1) + { + rc = RC_SET( FERR_FAILURE); + f_sprintf( m_szFailInfo, "Incorrect field ID (%u) returned from level one field #%u (incl)", + (unsigned)uiTmp, (unsigned)(uiFieldId + 1)); + goto Exit; + } + + // Verify that we got the expected field value. + if (RC_BAD( rc = pDataRec->getUINT( pvDataField, &uiTmp))) { MAKE_ERROR_STRING( "calling getUINT", rc, m_szFailInfo); @@ -2193,9 +2252,66 @@ RCODE IFlmTestImpl::sortedFieldsTest( void) { rc = RC_SET( FERR_FAILURE); f_sprintf( m_szFailInfo, "Incorrect value (%u) returned from level one field #%u (incl)", - (unsigned)uiTmp, (unsigned)uiFieldId); + (unsigned)uiTmp, (unsigned)(uiFieldId + 1)); goto Exit; } + + // Get the next level one fields with the same ID. Should be two more. + // Set uiCount to one because we have already retrieved one of them. + + uiCount = 1; + for (;;) + { + pvDataField = pDataRec->nextLevelOneField( pvDataField); + if (!pvDataField) + { + if (uiCount != 3) + { + rc = RC_SET( FERR_FAILURE); + f_sprintf( m_szFailInfo, "Could not get next level one field with same ID as #%u", + (unsigned)(uiFieldId + 1)); + goto Exit; + } + break; + } + else + { + uiCount++; + if (uiCount > 3) + { + rc = RC_SET( FERR_FAILURE); + f_sprintf( m_szFailInfo, "Too many instances of level one fields with ID #%u", + (unsigned)(uiFieldId + 1)); + goto Exit; + } + + // Verify that we got the expected field ID. + + uiTmp = pDataRec->getFieldID( pvDataField); + if (uiTmp != uiFieldId + 1) + { + rc = RC_SET( FERR_FAILURE); + f_sprintf( m_szFailInfo, "Incorrect field ID (%u) returned from instance #%u of level one field #%u", + (unsigned)uiTmp, (unsigned)uiCount, (unsigned)(uiFieldId + 1)); + goto Exit; + } + + // Verify that we got the expected field value. + + 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 instance #%u of level one field #%u", + (unsigned)uiTmp, (unsigned)uiCount, (unsigned)(uiFieldId + 1)); + goto Exit; + } + } + } } // For each of the 300 field ids, get the field from the record. @@ -2211,33 +2327,57 @@ RCODE IFlmTestImpl::sortedFieldsTest( void) for (uiFieldId = 1001; uiFieldId <= 1601; uiFieldId += 2) { - pvDataField = pCopyRec->findLevelOneField( uiFieldId, FALSE); - if (!pvDataField) + + // Should be three instances to delete. + + for (uiCount = 1; uiCount <= 3; uiCount++) { - 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; + pvDataField = pCopyRec->findLevelOneField( uiFieldId, FALSE); + if (!pvDataField) + { + rc = RC_SET( FERR_FAILURE); + f_sprintf( m_szFailInfo, "Could not find instance #%u of level one field #%u", + (unsigned)uiCount, (unsigned)uiFieldId); + goto Exit; + } + + // Verify that we got the expected field ID. + + uiTmp = pCopyRec->getFieldID( pvDataField); + if (uiTmp != uiFieldId) + { + rc = RC_SET( FERR_FAILURE); + f_sprintf( m_szFailInfo, "Incorrect field ID (%u) returned from instance #%u of level one field #%u", + (unsigned)uiTmp, (unsigned)uiCount, (unsigned)uiFieldId); + goto Exit; + } + + // Verify that we got the expected field value. + + 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 instance #%u of level one field #%u", + (unsigned)uiTmp, (unsigned)uiCount, (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; + } } - // Remove the field and make sure that the find fails. + // All instances should be gone now. - if (RC_BAD( rc = pCopyRec->remove( pvDataField))) - { - MAKE_ERROR_STRING( "calling remove", rc, m_szFailInfo); - goto Exit; - } pvDataField = pCopyRec->findLevelOneField( uiFieldId, FALSE); if (pvDataField) { @@ -2276,6 +2416,115 @@ Exit: return( rc); } +/*************************************************************************** +Desc: +****************************************************************************/ +RCODE IFlmTestImpl::sortedFieldsQueryTest( + FLMUINT uiDrn, + FLMBOOL bDoRootedFieldPaths) +{ + RCODE rc = FERR_OK; + FLMBOOL bPassed = FALSE; + HFCURSOR hCursor = HFCURSOR_NULL; + FLMUINT uiFieldPath [10]; + FLMUINT uiFlags; + FLMUINT32 ui32Value; + FLMUINT uiLoop; + FlmRecord * pRec = NULL; + FLMBOOL bTransActive = FALSE; + char szTest [100]; + + f_sprintf( szTest, "Sorted Fields Query Test, %s", + (char *)(bDoRootedFieldPaths ? (char *)"Rooted" : (char *)"Non-Rooted")); + beginTest( szTest); + + // Initialize a cursor + + if (RC_BAD( rc = FlmCursorInit( m_hDb, FLM_DATA_CONTAINER, &hCursor))) + { + MAKE_ERROR_STRING( "calling FlmCursorInit", rc, m_szFailInfo); + goto Exit; + } + + // Add a field path - use a field number right in the middle. + + uiFieldPath [0] = PERSON_TAG; + uiFieldPath [1] = 1301; + uiFieldPath [2] = 1301; + uiFieldPath [3] = 1301; + uiFieldPath [4] = 0; + uiFlags = (bDoRootedFieldPaths) ? FLM_ROOTED_PATH : 0; + if (RC_BAD( rc = FlmCursorAddFieldPath( hCursor, uiFieldPath, uiFlags))) + { + MAKE_ERROR_STRING( "calling FlmCursorAddFieldPath", rc, m_szFailInfo); + goto Exit; + } + + // Add the equals operator. + + if (RC_BAD( rc = FlmCursorAddOp( hCursor, FLM_EQ_OP, FALSE))) + { + MAKE_ERROR_STRING( "calling FlmCursorAddOp", rc, m_szFailInfo); + goto Exit; + } + + // Add the value we are comparing to. + + ui32Value = 1301; + if (RC_BAD( rc = FlmCursorAddValue( hCursor, FLM_UINT32_VAL, &ui32Value, 4))) + { + MAKE_ERROR_STRING( "calling FlmCursorAddValue", rc, m_szFailInfo); + goto Exit; + } + + // Start a read transaction + + if( RC_BAD( rc = FlmDbTransBegin( m_hDb, FLM_READ_TRANS, 0))) + { + MAKE_ERROR_STRING( "calling FlmDbTransBegin", rc, m_szFailInfo); + goto Exit; + } + bTransActive = TRUE; + + // Do the query 250 times. Get a timing to print out. + + for (uiLoop = 0; uiLoop < 250; uiLoop++) + { + if (RC_BAD( rc = FlmCursorFirst( hCursor, &pRec))) + { + MAKE_ERROR_STRING( "calling FlmCursorFirst", rc, m_szFailInfo); + goto Exit; + } + if (pRec->getID() != uiDrn) + { + rc = RC_SET( FERR_FAILURE); + f_sprintf( m_szFailInfo, "Got incorrect record back from query"); + goto Exit; + } + } + bPassed = TRUE; + +Exit: + + if (hCursor != HFCURSOR_NULL) + { + FlmCursorFree( &hCursor); + } + + if (pRec) + { + pRec->Release(); + } + + if (bTransActive) + { + (void)FlmDbTransAbort( m_hDb); + } + + endTest( bPassed); + return( rc); +} + /*************************************************************************** Desc: ****************************************************************************/ @@ -3266,7 +3515,19 @@ RCODE IFlmTestImpl::execute( void) // Sorted field test - if (RC_BAD( rc = sortedFieldsTest())) + if (RC_BAD( rc = sortedFieldsTest( &uiDrn))) + { + goto Exit; + } + + // Sorted field query test - first time using rooted field path. + // Second time not using rooted field path. + + if (RC_BAD( rc = sortedFieldsQueryTest( uiDrn, TRUE))) + { + goto Exit; + } + if (RC_BAD( rc = sortedFieldsQueryTest( uiDrn, FALSE))) { goto Exit; } diff --git a/flaim/util/flmunittest.cpp b/flaim/util/flmunittest.cpp index 2366aff..e4f3390 100644 --- a/flaim/util/flmunittest.cpp +++ b/flaim/util/flmunittest.cpp @@ -912,6 +912,7 @@ void TestBase::beginTest( m_pszTestName = pszTestName; display( m_pszTestName); display( " ... "); + m_uiStartTime = f_getCurrTimeAsTimerUnits(); } /**************************************************************************** @@ -1083,15 +1084,18 @@ void TestBase::logTestResults( Desc: ****************************************************************************/ void TestBase::displayTestResults( - FLMBOOL bPassed) + FLMBOOL bPassed, + FLMUINT uiElapsedMilli) { - if (bPassed) + char szResult [60]; + + f_sprintf( szResult, "%s (%u.%03u secs)", + (char *)(bPassed ? (char *)"PASS" : (char *)"FAIL"), + (unsigned)(uiElapsedMilli / 1000), (unsigned)(uiElapsedMilli % 1000)); + + displayLine( szResult); + if (!bPassed) { - displayLine( "PASS"); - } - else - { - displayLine( "FAIL"); displayLine( m_szFailInfo); } } @@ -1102,7 +1106,11 @@ Desc: void TestBase::endTest( FLMBOOL bPassed) { - displayTestResults( bPassed); + FLMUINT uiEndTime = f_getCurrTimeAsTimerUnits(); + FLMUINT uiElapsedMilli = f_timerUnitsToMilliSeconds( + f_elapsedTimeTimerUnits( m_uiStartTime, uiEndTime)); + + displayTestResults( bPassed, uiElapsedMilli); if (m_bLog) { logTestResults( bPassed); diff --git a/flaim/util/flmunittest.h b/flaim/util/flmunittest.h index 4064566..9a1abba 100644 --- a/flaim/util/flmunittest.h +++ b/flaim/util/flmunittest.h @@ -386,6 +386,7 @@ protected: HFDB m_hDb; char m_szFailInfo [100]; const char * m_pszTestName; + FLMUINT m_uiStartTime; void beginTest( const char * pszTestName); @@ -406,7 +407,8 @@ protected: FLMBOOL bPassed); void displayTestResults( - FLMBOOL bPassed); + FLMBOOL bPassed, + FLMUINT uiElapsedMilli); RCODE initCleanTestState( const char * pszDibName);