/**************************************************************************** Desc: ****************************************************************************/ FLMBOOL FlagSet::removeElemContaining( FLMBYTE * pszSubString) { FLMBOOL bElemExisted = FALSE; for( FLMUINT uiLoop = 0; uiLoop < m_uiNumElems; ) { if( containsSubstring( m_ppucElemArray[ uiLoop], pszSubString)) { bElemExisted = TRUE; if( uiLoop < m_uiNumElems - 1) { f_memmove( &m_ppucElemArray[ uiLoop], &m_ppucElemArray[ uiLoop + 1], (m_uiNumElems - (uiLoop + 1)) * sizeof( FLMBYTE *)); f_memmove( &m_pbFlagArray[ uiLoop], &m_pbFlagArray[ uiLoop + 1], (m_uiNumElems - (uiLoop + 1)) * sizeof( FLMBYTE *)); } m_uiNumElems--; } else { uiLoop++; } } return( bElemExisted); }
/**************************************************************************** Desc: ****************************************************************************/ FLMBOOL FlagSet::removeElem( FLMBYTE * pElem) { FLMBOOL bElemExisted = FALSE; for( FLMUINT uiLoop = 0; uiLoop < m_uiNumElems; uiLoop++) { if( f_strcmp( (char *)pElem, (char *)m_ppucElemArray[ uiLoop]) == 0) { bElemExisted = TRUE; if( uiLoop < m_uiNumElems - 1) { f_free( &m_ppucElemArray[ uiLoop]); f_memmove( &m_ppucElemArray[ uiLoop], &m_ppucElemArray[ uiLoop + 1], (m_uiNumElems - ( uiLoop + 1)) * sizeof( FLMBYTE *)); f_memmove( &m_pbFlagArray[ uiLoop], &m_pbFlagArray[ uiLoop + 1], (m_uiNumElems - ( uiLoop + 1)) * sizeof( FLMBYTE *)); } m_uiNumElems--; } } return( bElemExisted); }
/**************************************************************************** Desc: Insert the entry into the buffer. ****************************************************************************/ RCODE F_BtreeBlk::insertEntry( void * pvEntry, FLMUINT uiChildAddr) { RCODE rc = NE_FLM_OK; FLMBYTE * pucCurEntry; FLMUINT uiShiftBytes; // Always shift down if( entryCount() >= m_uiNumSlots) { rc = RC_SET( NE_FLM_FAILURE); goto Exit; } flmAssert( m_uiPosition != DYNSSET_POSITION_NOT_SET); pucCurEntry = ENTRY_POS( m_uiPosition); if ((uiShiftBytes = (entryCount() - m_uiPosition) * (m_uiEntrySize + m_uiEntryOvhd)) != 0) { // Big hairy assert. Finds coding bugs and corruptions. flmAssert( m_uiPosition * (m_uiEntrySize + m_uiEntryOvhd) + uiShiftBytes < DYNSSET_BLOCK_SIZE - sizeof( FixedBlkHdr)); f_memmove( pucCurEntry + m_uiEntrySize + m_uiEntryOvhd, pucCurEntry, uiShiftBytes); } f_memcpy( pucCurEntry, pvEntry, m_uiEntrySize); if( m_uiEntryOvhd) { UD2FBA( (FLMUINT32)uiChildAddr, &pucCurEntry[m_uiEntrySize]); } entryCount( entryCount() + 1); m_uiPosition++; m_bDirty = TRUE; Exit: return( rc); }
/**************************************************************************** Desc: Move first half of entries into new block. Reset previous block to point to new block. Add new last entry in new block to parent. Fixup prev/next linkages. ****************************************************************************/ RCODE F_BtreeBlk::split( F_BtreeRoot * pRoot, FLMBYTE * pucCurEntry, // (in) Contains entry to insert FLMUINT uiCurBlkAddr, // (in) Blk addr if non-leaf FLMBYTE * pucParentEntry, // (out) Entry to insert into parent. FLMUINT * puiNewBlkAddr) // (out) New blk addr to insert into parent. { RCODE rc = NE_FLM_OK; F_BtreeBlk * pPrevBlk; F_BtreeBlk * pNewBlk = NULL; FLMBYTE * pucEntry = NULL; FLMBYTE * pucMidEntry; FLMBYTE * pucChildAddr; FLMUINT uiChildAddr; FLMUINT uiPrevBlkAddr; FLMUINT uiMid; FLMUINT uiPos; FLMUINT uiMoveBytes; FLMBOOL bInserted = FALSE; // Allocate a new block for the split. if (RC_BAD( rc = pRoot->newBlk( &pNewBlk, blkType() ))) { goto Exit; } pNewBlk->AddRef(); // Pin the block - may get flushed out. // the last half into the new block, but that would force the parent // entry to be changed. This may take a little longer, but it is much // more easier to code. // Call search entry once just to setup for insert. (void) pNewBlk->searchEntry( ENTRY_POS( 0)); // get the count and move more then half into the new block. uiMid = (entryCount() + 5) >> 1; uiChildAddr = FBTREE_END; for (uiPos = 0; uiPos < uiMid; uiPos++) { pucEntry = ENTRY_POS( uiPos); if (blkType() != ACCESS_BTREE_LEAF) { pucChildAddr = pucEntry + m_uiEntrySize; uiChildAddr = (FLMUINT)FB2UD(pucChildAddr); } // m_uiPosition automatically gets incremented. if (RC_BAD( rc = pNewBlk->insertEntry( pucEntry, uiChildAddr))) { RC_UNEXPECTED_ASSERT( rc); goto Exit; } } if (m_uiPosition < uiMid) { // Insert this entry now bInserted = TRUE; (void) pNewBlk->searchEntry( pucCurEntry); if (RC_BAD( rc = pNewBlk->insertEntry( pucCurEntry, uiCurBlkAddr))) { goto Exit; } } // Let caller insert into parent entry. This rids us of recursion. f_memcpy( pucParentEntry, pucEntry, m_uiEntrySize); // Move the rest down pucEntry = ENTRY_POS( 0); pucMidEntry = ENTRY_POS( uiMid); entryCount( entryCount() - uiMid); uiMoveBytes = entryCount() * (m_uiEntrySize + m_uiEntryOvhd); flmAssert( uiMoveBytes < DYNSSET_BLOCK_SIZE - sizeof( FixedBlkHdr)); f_memmove( pucEntry, pucMidEntry, uiMoveBytes); if( !bInserted) { // m_uiPosition -= uiMid; (void) searchEntry( pucCurEntry); if (RC_BAD( rc = insertEntry( pucCurEntry, uiCurBlkAddr))) { goto Exit; } } // VISIT: Could position stack to point to current element to insert. // Fixup the prev/next block linkages. if (prevBlk() != FBTREE_END) { if (RC_BAD( rc = pRoot->readBlk( prevBlk(), blkType(), &pPrevBlk ))) { goto Exit; } pPrevBlk->nextBlk( pNewBlk->blkAddr()); uiPrevBlkAddr = pPrevBlk->blkAddr(); } else { uiPrevBlkAddr = FBTREE_END; } pNewBlk->prevBlk( uiPrevBlkAddr); pNewBlk->nextBlk( blkAddr()); prevBlk( pNewBlk->blkAddr()); *puiNewBlkAddr = pNewBlk->blkAddr(); Exit: if (pNewBlk) { pNewBlk->Release(); } return( rc); }
/**************************************************************************** Desc: Build a text key. ****************************************************************************/ FSTATIC RCODE flmAddTextKeyPiece( SQL_PRED * pPred, F_INDEX * pIndex, FLMUINT uiKeyComponent, ICD * pIcd, F_DataVector * pFromSearchKey, FLMBYTE * pucFromKey, FLMUINT * puiFromKeyLen, F_DataVector * pUntilSearchKey, FLMBYTE * pucUntilKey, FLMUINT * puiUntilKeyLen, FLMBOOL * pbCanCompareOnKey, FLMBOOL * pbFromIncl, FLMBOOL * pbUntilIncl) { RCODE rc = NE_SFLM_OK; FLMBYTE * pucFromKeyLenPos; FLMBYTE * pucUntilKeyLenPos; FLMUINT uiLanguage = pIndex->uiLanguage; FLMUINT uiFromCollationLen = 0; FLMUINT uiUntilCollationLen = 0; FLMUINT uiCharCount; FLMUINT uiFromCaseLen; FLMUINT uiUntilCaseLen; FLMBOOL bFromOriginalCharsLost = FALSE; FLMBOOL bUntilOriginalCharsLost = FALSE; FLMBOOL bIsDBCS = (uiLanguage >= FLM_FIRST_DBCS_LANG && uiLanguage <= FLM_LAST_DBCS_LANG) ? TRUE : FALSE; FLMBOOL bCaseInsensitive = (FLMBOOL)((pPred->uiCompareRules & FLM_COMP_CASE_INSENSITIVE) ? TRUE : FALSE); FLMBOOL bDoFirstSubstring = (FLMBOOL)((pIcd->uiFlags & ICD_SUBSTRING) ? TRUE : FALSE); FLMBOOL bDoMatchBegin = FALSE; FLMBOOL bTrailingWildcard = FALSE; const FLMBYTE * pucFromUTF8Buf = NULL; FLMUINT uiFromBufLen = 0; const FLMBYTE * pucUntilUTF8Buf = NULL; FLMUINT uiUntilBufLen = 0; FLMUINT uiWildcardPos; FLMBOOL bFromDataTruncated; FLMBOOL bUntilDataTruncated; FLMUINT uiFromFlags = 0; FLMUINT uiUntilFlags = 0; FLMUINT uiCompareRules; FLMBOOL bAscending = (pIcd->uiFlags & ICD_DESCENDING) ? FALSE: TRUE; F_BufferIStream bufferIStream; FLMUINT uiFromKeyLen = *puiFromKeyLen; FLMUINT uiUntilKeyLen = *puiUntilKeyLen; FLMUINT uiFromComponentLen; FLMUINT uiUntilComponentLen; FLMUINT uiFromSpaceLeft; FLMUINT uiUntilSpaceLeft; // Leave room for the component length pucFromKeyLenPos = pucFromKey + uiFromKeyLen; pucUntilKeyLenPos = pucUntilKey + uiUntilKeyLen; pucFromKey = pucFromKeyLenPos + 2; pucUntilKey = pucUntilKeyLenPos + 2; uiFromSpaceLeft = SFLM_MAX_KEY_SIZE - uiFromKeyLen - 2; uiUntilSpaceLeft = SFLM_MAX_KEY_SIZE - uiUntilKeyLen - 2; switch (pPred->eOperator) { // The difference between MATCH and EQ_OP is that EQ does // not support wildcards embedded in the search key. case SQL_MATCH_OP: flmAssert( pPred->pFromValue->eValType == SQL_UTF8_VAL); pucFromUTF8Buf = pPred->pFromValue->val.str.pszStr; uiFromBufLen = pPred->pFromValue->val.str.uiByteLen; uiCompareRules = pIcd->uiCompareRules; if (RC_BAD( rc = flmUTF8FindWildcard( pucFromUTF8Buf, &uiWildcardPos, &uiCompareRules))) { goto Exit; } // If there is no wildcard, uiWildcardPos will be FLM_MAX_UINT if (uiWildcardPos != FLM_MAX_UINT) { // If wildcard is in position 0, it is NOT // a match begin. if (uiWildcardPos) { bDoMatchBegin = TRUE; uiFromBufLen = uiWildcardPos; } } if (!(pIcd->uiFlags & ICD_SUBSTRING)) { // Index is NOT a substring index if (!bDoMatchBegin) { // Wildcard was at the beginning, will have // to search the index from first to last pucFromUTF8Buf = NULL; } else { bTrailingWildcard = TRUE; } } else { FLMBOOL bNotUsingFirstOfString; // If this is a substring index look for a // better 'contains' string to search for. // We don't like "A*BCDEFG" searches. bTrailingWildcard = bDoMatchBegin; uiCompareRules = pIcd->uiCompareRules; if (RC_BAD( rc = flmSelectBestSubstr( &pucFromUTF8Buf, &uiFromBufLen, &uiCompareRules, &bTrailingWildcard, &bNotUsingFirstOfString))) { goto Exit; } if (bNotUsingFirstOfString) { bDoMatchBegin = bTrailingWildcard; *pbCanCompareOnKey = FALSE; bDoFirstSubstring = FALSE; } else if (bTrailingWildcard) { bDoMatchBegin = TRUE; } if (RC_BAD( rc = flmCountCharacters( pucFromUTF8Buf, uiFromBufLen, 2, &uiCompareRules, &uiCharCount))) { goto Exit; } // Special case: Single character contains/MEnd in a substr ix. if (!bIsDBCS && uiCharCount < 2) { pucFromUTF8Buf = NULL; } } pucUntilUTF8Buf = pucFromUTF8Buf; uiUntilBufLen = uiFromBufLen; break; case SQL_RANGE_OP: if (bAscending) { if (pPred->pFromValue) { flmAssert( pPred->pFromValue->eValType == SQL_UTF8_VAL); pucFromUTF8Buf = pPred->pFromValue->val.str.pszStr; uiFromBufLen = pPred->pFromValue->val.str.uiByteLen; } else { // Should have been done up above // pucFromUTF8Buf = NULL; // uiFromBufLen = 0; } if (pPred->pUntilValue) { flmAssert( pPred->pUntilValue->eValType == SQL_UTF8_VAL); pucUntilUTF8Buf = pPred->pUntilValue->val.str.pszStr; uiUntilBufLen = pPred->pUntilValue->val.str.uiByteLen; } else { // Should have been done up above. // pucUntilUTF8Buf = NULL; // uiUntilBufLen = 0; } if (!pPred->bInclFrom) { uiFromFlags |= EXCLUSIVE_GT_FLAG; } if (!pPred->bInclUntil) { uiUntilFlags |= EXCLUSIVE_LT_FLAG; } } else { if (pPred->pUntilValue) { flmAssert( pPred->pUntilValue->eValType == SQL_UTF8_VAL); pucFromUTF8Buf = pPred->pUntilValue->val.str.pszStr; uiFromBufLen = pPred->pUntilValue->val.str.uiByteLen; } else { // Should have been done up above // pucFromUTF8Buf = NULL; // uiFromBufLen = 0; } if (pPred->pFromValue) { flmAssert( pPred->pFromValue->eValType == SQL_UTF8_VAL); pucUntilUTF8Buf = pPred->pFromValue->val.str.pszStr; uiUntilBufLen = pPred->pFromValue->val.str.uiByteLen; } else { // Should have been done up above. // pucUntilUTF8Buf = NULL; // uiUntilBufLen = 0; } if (!pPred->bInclUntil) { uiFromFlags |= EXCLUSIVE_GT_FLAG; } if (!pPred->bInclFrom) { uiUntilFlags |= EXCLUSIVE_LT_FLAG; } } break; case SQL_NE_OP: // Set up to do full index scan. // Buffers should already be NULL. // pucFromUTF8Buf = NULL; // pucUntilUTF8Buf = NULL; break; case SQL_APPROX_EQ_OP: // Set up to do full index scan. // Buffers should already be NULL // pucFromUTF8Buf = NULL; // pucUntilUTF8Buf = NULL; // Cannot compare on the key if index is upper case, // even if the bCaseInsensitive flag is set. if (pIcd->uiCompareRules & FLM_COMP_CASE_INSENSITIVE) { *pbCanCompareOnKey = FALSE; } break; default: // Every predicate should have been converted to one of the above // cases, or should be handled by another routine. rc = RC_SET_AND_ASSERT( NE_SFLM_QUERY_SYNTAX); goto Exit; } // If index is case insensitive, but search is case sensitive // we must NOT do a key match - we would fail things we should // not be failing. if ((pIcd->uiCompareRules & FLM_COMP_CASE_INSENSITIVE) && !bCaseInsensitive) { *pbCanCompareOnKey = FALSE; } if (!pucFromUTF8Buf) { uiFromComponentLen = KEY_LOW_VALUE; } else { if (RC_BAD( rc = bufferIStream.openStream( (const char *)pucFromUTF8Buf, uiFromBufLen))) { goto Exit; } // Add ICD_ESC_CHAR to the icd flags because // the search string must have BACKSLASHES and '*' escaped. uiFromComponentLen = uiFromSpaceLeft; bFromDataTruncated = FALSE; if (RC_BAD( rc = KYCollateValue( pucFromKey, &uiFromComponentLen, &bufferIStream, SFLM_STRING_TYPE, pIcd->uiFlags | ICD_ESC_CHAR, pIcd->uiCompareRules, pIcd->uiLimit, &uiFromCollationLen, &uiFromCaseLen, uiLanguage, bDoFirstSubstring, FALSE, &bFromDataTruncated, &bFromOriginalCharsLost))) { goto Exit; } bufferIStream.closeStream(); if (bFromDataTruncated) { *pbCanCompareOnKey = FALSE; // Save the original data into pFromSearchKey so the comparison // routines can do a comparison on the full value if // necessary. if (RC_BAD( rc = pFromSearchKey->setUTF8( uiKeyComponent, pucFromUTF8Buf, uiFromBufLen))) { goto Exit; } uiFromFlags |= (SEARCH_KEY_FLAG | TRUNCATED_FLAG); } else if (bFromOriginalCharsLost) { *pbCanCompareOnKey = FALSE; } if (pucFromUTF8Buf != pucUntilUTF8Buf) { // Handle scenario of a case-sensitive index, but search is // case-insensitive. if (uiFromComponentLen && (bIsDBCS || (!(pIcd->uiCompareRules & FLM_COMP_CASE_INSENSITIVE) && bCaseInsensitive))) { setFromCaseByte( pucFromKey, &uiFromComponentLen, uiFromCaseLen, bIsDBCS, bAscending, (uiFromFlags & EXCLUSIVE_GT_FLAG) ? TRUE : FALSE); } } } // Do the until key now if (!pucUntilUTF8Buf) { uiUntilComponentLen = KEY_HIGH_VALUE; } else if (pucFromUTF8Buf == pucUntilUTF8Buf) { // Handle case where from and until buffers are the same. // This should only be possible in the equality case or match begin // case, in which cases neither the EXCLUSIVE_LT_FLAG or the // EXCLUSIVE_GT_FLAG should be set. flmAssert( uiFromBufLen == uiUntilBufLen); flmAssert( !(uiFromFlags & (EXCLUSIVE_GT_FLAG | EXCLUSIVE_LT_FLAG))); flmAssert( !(uiUntilFlags & (EXCLUSIVE_GT_FLAG | EXCLUSIVE_LT_FLAG))); // Need to collate the until key from the original data if // the from key was truncated or there is not enough room in // the until key. Otherwise, we can simply copy // the from key into the until key - a little optimization. if (uiUntilSpaceLeft >= uiFromComponentLen && !bFromDataTruncated) { if ((uiUntilComponentLen = uiFromComponentLen) != 0) { f_memcpy( pucUntilKey, pucFromKey, uiFromComponentLen); } uiUntilCaseLen = uiFromCaseLen; uiUntilCollationLen = uiFromCollationLen; bUntilOriginalCharsLost = bFromOriginalCharsLost; bUntilDataTruncated = FALSE; } else { if (RC_BAD( rc = bufferIStream.openStream( (const char *)pucUntilUTF8Buf, uiUntilBufLen))) { goto Exit; } // Add ICD_ESC_CHAR to the icd flags because // the search string must have BACKSLASHES and '*' escaped. uiUntilComponentLen = uiUntilSpaceLeft; bUntilDataTruncated = FALSE; if (RC_BAD( rc = KYCollateValue( pucUntilKey, &uiUntilComponentLen, &bufferIStream, SFLM_STRING_TYPE, pIcd->uiFlags | ICD_ESC_CHAR, pIcd->uiCompareRules, pIcd->uiLimit, &uiUntilCollationLen, &uiUntilCaseLen, uiLanguage, bDoFirstSubstring, FALSE, &bUntilDataTruncated, &bUntilOriginalCharsLost))) { goto Exit; } bufferIStream.closeStream(); if (bUntilDataTruncated) { // Save the original data into pUntilSearchKey so the comparison // routines can do a comparison on the full value if // necessary. if (RC_BAD( rc = pUntilSearchKey->setUTF8( uiKeyComponent, pucUntilUTF8Buf, uiUntilBufLen))) { goto Exit; } *pbCanCompareOnKey = FALSE; uiUntilFlags |= (SEARCH_KEY_FLAG | TRUNCATED_FLAG); } else if (bUntilOriginalCharsLost) { *pbCanCompareOnKey = FALSE; } } if (bDoMatchBegin) { if (bAscending) { // Handle scenario of a case-sensitive index, but search is // case-insensitive. if (uiFromComponentLen && (bIsDBCS || (!(pIcd->uiCompareRules & FLM_COMP_CASE_INSENSITIVE) && bCaseInsensitive))) { setFromCaseByte( pucFromKey, &uiFromComponentLen, uiFromCaseLen, bIsDBCS, bAscending, FALSE); } // Fill everything after the collation values in the until // key with high values (0xFF) f_memset( &pucUntilKey[ uiUntilCollationLen], 0xFF, uiUntilSpaceLeft - uiUntilCollationLen); uiUntilComponentLen = uiUntilSpaceLeft; } else { if (uiUntilComponentLen && (bIsDBCS || (!(pIcd->uiCompareRules & FLM_COMP_CASE_INSENSITIVE) && bCaseInsensitive))) { // NOTE: Always inclusive because this is a matchbegin. setUntilCaseByte( pucUntilKey, &uiUntilComponentLen, uiUntilCaseLen, bIsDBCS, bAscending, FALSE); } // Fill rest of from key with high values after collation values. f_memset( &pucFromKey[ uiFromCollationLen], 0xFF, uiFromSpaceLeft - uiFromCollationLen); uiFromComponentLen = uiFromSpaceLeft; } } else { if (bDoFirstSubstring) { FLMUINT uiBytesToRemove = (bIsDBCS) ? 2 : 1; if (bAscending) { // Get rid of the first substring byte in the until // key. f_memmove( &pucUntilKey [uiUntilCollationLen], &pucUntilKey [uiUntilCollationLen + uiBytesToRemove], uiUntilComponentLen - uiUntilCollationLen - uiBytesToRemove); uiUntilComponentLen -= uiBytesToRemove; } else { // Descending order - put the string without the // first-substring-marker into the from key instead of // the until key. f_memmove( &pucFromKey [uiFromCollationLen], &pucFromKey [uiFromCollationLen + uiBytesToRemove], uiFromComponentLen - uiFromCollationLen - uiBytesToRemove); uiFromComponentLen -= uiBytesToRemove; } // Handle scenario of a case-sensitive index, but search is // case-insensitive. if (bIsDBCS || (!(pIcd->uiCompareRules & FLM_COMP_CASE_INSENSITIVE) && bCaseInsensitive)) { setFromCaseByte( pucFromKey, &uiFromComponentLen, uiFromCaseLen, bIsDBCS, bAscending, FALSE); setUntilCaseByte( pucUntilKey, &uiUntilComponentLen, uiUntilCaseLen, bIsDBCS, bAscending, FALSE); } } } } else // pucFromUTF8Buf != pucUntilUTF8Buf { if (RC_BAD( rc = bufferIStream.openStream( (const char *)pucUntilUTF8Buf, uiUntilBufLen))) { goto Exit; } // Add ICD_ESC_CHAR to the icd flags because // the search string must have BACKSLASHES and '*' escaped. uiUntilComponentLen = uiUntilSpaceLeft; bUntilDataTruncated = FALSE; if (RC_BAD( rc = KYCollateValue( pucUntilKey, &uiUntilComponentLen, &bufferIStream, SFLM_STRING_TYPE, pIcd->uiFlags | ICD_ESC_CHAR, pIcd->uiCompareRules, pIcd->uiLimit, &uiUntilCollationLen, &uiUntilCaseLen, uiLanguage, bDoFirstSubstring, FALSE, &bUntilDataTruncated, &bUntilOriginalCharsLost))) { goto Exit; } bufferIStream.closeStream(); if (bUntilDataTruncated) { // Save the original data into pUntilSearchKey so the comparison // routines can do a comparison on the full value if // necessary. if (RC_BAD( rc = pUntilSearchKey->setUTF8( uiKeyComponent, pucUntilUTF8Buf, uiUntilBufLen))) { goto Exit; } *pbCanCompareOnKey = FALSE; uiUntilFlags |= (SEARCH_KEY_FLAG | TRUNCATED_FLAG); } else if (bUntilOriginalCharsLost) { *pbCanCompareOnKey = FALSE; } if (uiUntilComponentLen && (bIsDBCS || (!(pIcd->uiCompareRules & FLM_COMP_CASE_INSENSITIVE) && bCaseInsensitive))) { setUntilCaseByte( pucUntilKey, &uiUntilComponentLen, uiUntilCaseLen, bIsDBCS, bAscending, (uiUntilFlags & EXCLUSIVE_LT_FLAG) ? TRUE : FALSE); } } UW2FBA( (FLMUINT16)(uiFromKeyLen | uiFromFlags), pucFromKeyLenPos); UW2FBA( (FLMUINT16)(uiUntilKeyLen | uiUntilFlags), pucUntilKeyLenPos); // Set the FROM and UNTIL key length return values. uiFromKeyLen += 2; if (uiFromComponentLen != KEY_LOW_VALUE) { uiFromKeyLen += uiFromComponentLen; if (!(uiFromFlags & EXCLUSIVE_GT_FLAG)) { *pbFromIncl = TRUE; } } uiUntilKeyLen += 2; if (uiUntilComponentLen != KEY_HIGH_VALUE) { uiUntilKeyLen += uiUntilComponentLen; if (!(uiUntilFlags & EXCLUSIVE_LT_FLAG)) { *pbUntilIncl = TRUE; } } Exit: return( rc); }
/***************************************************************************** Desc: Add a node to the node list. If it is already there, it is ok. ******************************************************************************/ RCODE F_NodeList::addNode( FLMUINT uiCollection, FLMUINT64 ui64Document, FLMUINT64 ui64NodeId) { RCODE rc = NE_XFLM_OK; FLMUINT uiInsertPos; // Cannot allow collection or document to be zero flmAssert( uiCollection && ui64Document); if( m_uiLastCollection == uiCollection && m_ui64LastDocument == ui64Document && m_ui64LastNodeId == ui64NodeId) { goto Exit; } if( !findNode( uiCollection, ui64Document, ui64NodeId, &uiInsertPos)) { // Have we reached the limit of the number of documents we will // keep pending in a transaction? if( m_uiNumNodes == MAX_PENDING_NODES) { rc = RC_SET( NE_XFLM_TOO_MANY_PENDING_NODES); goto Exit; } // See if we need to allocate the table if( !m_pNodeTbl) { if (RC_BAD( rc = f_alloc( sizeof( NODE_LIST_ITEM) * MAX_PENDING_NODES, &m_pNodeTbl))) { goto Exit; } m_uiNodeTblSize = MAX_PENDING_NODES; } flmAssert( uiInsertPos <= m_uiNumNodes); // Make room for the new node ID if( uiInsertPos < m_uiNumNodes) { f_memmove( &m_pNodeTbl[ uiInsertPos+1], &m_pNodeTbl[ uiInsertPos], sizeof( NODE_LIST_ITEM) * (m_uiNumNodes - uiInsertPos)); } m_pNodeTbl[ uiInsertPos].uiCollection = uiCollection; m_pNodeTbl[ uiInsertPos].ui64Document = ui64Document; m_pNodeTbl[ uiInsertPos].ui64NodeId = ui64NodeId; m_uiNumNodes++; } // Save collection and document id - this is an optimization // that will keep us from calling findNode too much if // we are working inside the same document. m_uiLastPosition = uiInsertPos; m_uiLastCollection = uiCollection; m_ui64LastDocument = ui64Document; m_ui64LastNodeId = ui64NodeId; Exit: return( rc); }