Exemplo n.º 1
0
/****************************************************************************
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);
}
Exemplo n.º 2
0
/****************************************************************************
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);
}
Exemplo n.º 5
0
/****************************************************************************
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);
}
Exemplo n.º 6
0
/*****************************************************************************
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);
}