/**************************************************************************** Desc: Close the database file and delete it. ****************************************************************************/ RCODE F_DbCheck::closeAndDeleteResultSetDb( void) { RCODE rc = NE_XFLM_OK; if (m_pResultSetDb) { if (m_pResultSetDb->getTransType() != XFLM_NO_TRANS) { m_pResultSetDb->transAbort(); } m_pResultSetDb->Release(); m_pResultSetDb = NULL; } if (RC_BAD( rc = gv_pXFlmDbSystem->dbRemove( m_szResultSetDibName, NULL, NULL, TRUE))) { goto Exit; } f_memset( m_szResultSetDibName, 0, sizeof( m_szResultSetDibName)); Exit: return rc; }
/**************************************************************************** Desc: ****************************************************************************/ RCODE TestBase::openTestState( const char * pszDibName) { RCODE rc = FERR_OK; CREATE_OPTS createOpts; if( RC_BAD( rc = gv_FlmSysData.pFileSystem->doesFileExist( pszDibName))) { // Create the database f_memset( &createOpts, 0, sizeof( CREATE_OPTS)); if( RC_BAD( rc = FlmDbCreate( pszDibName, NULL, NULL, NULL, NULL, &createOpts, &m_hDb))) { goto Exit; } } else { // Open the existing database if( RC_BAD( rc = FlmDbOpen( pszDibName, NULL, NULL, 0, NULL, &m_hDb))) { goto Exit; } } Exit: return( rc); }
/**************************************************************************** Desc: ****************************************************************************/ void FlagSet::init( FLMBYTE ** ppucElemArray, FLMUINT uiNumElems) { reset(); if( RC_BAD( f_alloc( sizeof( FLMBYTE *) * uiNumElems, &m_ppucElemArray))) { flmAssert( 0); } if( RC_BAD( f_alloc( sizeof( FLMBOOL) * uiNumElems, &m_pbFlagArray))) { flmAssert( 0); } f_memset( m_pbFlagArray, 0, sizeof( FLMBOOL) * uiNumElems); for( FLMUINT uiLoop = 0; uiLoop < uiNumElems; uiLoop++) { if( RC_BAD( f_alloc( f_strlen( (char *)ppucElemArray[ uiLoop]) + 1, &m_ppucElemArray[ uiLoop]))) { flmAssert( 0); } f_strcpy( (char *)m_ppucElemArray[uiLoop], (char *)ppucElemArray[uiLoop]); } m_uiNumElems = uiNumElems; }
/**************************************************************************** Desc: ****************************************************************************/ RCODE TestBase::initCleanTestState( const char * pszDibName) { RCODE rc = FERR_OK; CREATE_OPTS createOpts; // Create the database f_memset( &createOpts, 0, sizeof( CREATE_OPTS)); if ( RC_BAD( rc = FlmDbCreate( pszDibName, NULL, NULL, NULL, NULL, &createOpts, &m_hDb))) { if( rc == FERR_FILE_EXISTS) { if( RC_BAD( rc = FlmDbRemove( pszDibName, NULL, NULL, TRUE))) { goto Exit; } } if( RC_BAD( rc = FlmDbCreate( pszDibName, NULL, NULL, NULL, NULL, &createOpts, &m_hDb))) { goto Exit; } } Exit: return( rc); }
/**************************************************************************** Desc: ****************************************************************************/ FlagSet::FlagSet( const FlagSet& fs) { if( RC_BAD( f_alloc( sizeof( FLMBYTE *) * fs.m_uiNumElems, &m_ppucElemArray))) { flmAssert( 0); } if( RC_BAD( f_alloc( sizeof( FLMBOOL) * fs.m_uiNumElems, &m_pbFlagArray))) { flmAssert( 0); } f_memset( m_pbFlagArray, 0, sizeof( FLMBOOL) * fs.m_uiNumElems); for( FLMUINT uiLoop = 0; uiLoop < fs.m_uiNumElems; uiLoop++) { if( RC_BAD( f_alloc( f_strlen( (char *)fs.m_ppucElemArray[uiLoop]) + 1, &m_ppucElemArray[ uiLoop]))) { flmAssert( 0); } f_strcpy( (char *)m_ppucElemArray[uiLoop], (char *)fs.m_ppucElemArray[uiLoop]); } m_uiNumElems = fs.m_uiNumElems; }
RCODE FTKAPI F_DirHdl::openDir( const char * pszDirName, const char * pszPattern) { RCODE rc = NE_FLM_OK; m_rc = NE_FLM_OK; m_bFirstTime = TRUE; m_bFindOpen = FALSE; m_uiAttrib = 0; f_memset( &m_FindData, 0, sizeof( m_FindData)); f_strcpy( m_szDirectoryPath, pszDirName); if( pszPattern) { if( f_strlen( pszPattern) >= (FLMINT)sizeof( m_szPattern)) { rc = RC_SET( NE_FLM_MEM); goto Exit; } f_strcpy( m_szPattern, pszPattern); } else { m_szPattern[ 0] = 0; } Exit: return( rc); }
/******************************************************************** Desc: Output a label in the LABEL_COLUMN *********************************************************************/ void gigaOutputLabel( FLMUINT uiRow, const char * pszLabel, FLMBOOL bMutexLocked) { char szLabel [DATA_COLUMN - LABEL_COLUMN]; char * pszTmp; FLMUINT uiNumDots = sizeof( szLabel) - 1; f_memset( szLabel, '.', uiNumDots); szLabel [uiNumDots] = 0; pszTmp = &szLabel [0]; uiNumDots -= 2; while( *pszLabel && uiNumDots) { *pszTmp++ = (FLMBYTE)(*pszLabel++); uiNumDots--; } if( !bMutexLocked && gv_hWindowMutex != F_MUTEX_NULL) { f_mutexLock( gv_hWindowMutex); } FTXWinPrintStrXY( gv_pWindow, szLabel, LABEL_COLUMN, uiRow); if( !bMutexLocked && gv_hWindowMutex != F_MUTEX_NULL) { f_mutexUnlock( gv_hWindowMutex); } }
FINLINE FLMINT FTKAPI outputChar( char cChar, FLMUINT uiCount) { f_memset( m_pszDestBuffer, cChar, uiCount); m_pszDestBuffer += uiCount; return( (FLMINT)uiCount); }
/**************************************************************************** Desc: Make sure the vector array is allocated at least up to the element number that is passed in. ****************************************************************************/ RCODE F_DataVector::allocVectorArray( FLMUINT uiElementNumber) { RCODE rc = NE_XFLM_OK; if (uiElementNumber >= m_uiNumElements) { // May need to allocate a new vector array if (uiElementNumber >= m_uiVectorArraySize) { FLMUINT uiNewArraySize = uiElementNumber + 32; F_VECTOR_ELEMENT * pNewVector; if (m_pVectorElements == &m_VectorArray [0]) { if (RC_BAD( rc = f_alloc( uiNewArraySize * sizeof( F_VECTOR_ELEMENT), &pNewVector))) { goto Exit; } if (m_uiNumElements) { f_memcpy( pNewVector, m_pVectorElements, m_uiNumElements * sizeof( F_VECTOR_ELEMENT)); } } else { pNewVector = m_pVectorElements; if (RC_BAD( rc = f_realloc( uiNewArraySize * sizeof( F_VECTOR_ELEMENT), &pNewVector))) { goto Exit; } } m_pVectorElements = pNewVector; m_uiVectorArraySize = uiNewArraySize; } // Initialized everything between the old last element and // the new element, including the new element, to zeroes. f_memset( &m_pVectorElements [m_uiNumElements], 0, sizeof( F_VECTOR_ELEMENT) * (uiElementNumber - m_uiNumElements + 1)); m_uiNumElements = uiElementNumber + 1; } Exit: return( rc); }
/**************************************************************************** Desc: ****************************************************************************/ RCODE SortKeyTestImpl::createNameDoc( char * pszNames[ 2]) { RCODE rc = NE_XFLM_OK; ELEMENT_NODE_INFO pNameNodes[2]; f_memset( pNameNodes, 0, sizeof( pNameNodes)); if ( RC_BAD( rc = f_alloc( f_strlen( pszNames[0]) + 1, &pNameNodes[0].pvData))) { MAKE_FLM_ERROR_STRING( "f_alloc failed.", m_szDetails, rc); goto Exit; } f_strcpy( (char*)pNameNodes[0].pvData, pszNames[0]); pNameNodes[0].uiDataType = XFLM_TEXT_TYPE; pNameNodes[0].uiDataSize = f_strlen( pszNames[0]); pNameNodes[0].uiDictNum = FIRST_NAME_ID; if ( RC_BAD( rc = f_alloc( f_strlen( pszNames[1]) + 1, &pNameNodes[1].pvData))) { MAKE_FLM_ERROR_STRING( "f_alloc failed.", m_szDetails, rc); goto Exit; } f_strcpy( (char*)pNameNodes[1].pvData, pszNames[1]); pNameNodes[1].uiDataType = XFLM_TEXT_TYPE; pNameNodes[1].uiDataSize = f_strlen( pszNames[0]); pNameNodes[1].uiDictNum = LAST_NAME_ID; if ( RC_BAD( rc = createCompoundDoc( pNameNodes, 2, NULL))) { goto Exit; } Exit: if ( pNameNodes[0].pvData) { f_free( &pNameNodes[0].pvData); } if ( pNameNodes[1].pvData) { f_free( &pNameNodes[1].pvData); } return rc; }
/**************************************************************************** Desc: ****************************************************************************/ F_MultiFileHdl::F_MultiFileHdl( FLMUINT uiMaxFileSize) { m_bOpen = FALSE; m_szPath[ 0] = 0; m_ui64EOF = 0; m_pLockFileHdl = NULL; f_memset( m_pFileHdlList, 0, sizeof( FH_INFO) * F_MULTI_FHDL_LIST_SIZE); m_uiMaxFileSize = uiMaxFileSize; if( !m_uiMaxFileSize) { m_uiMaxFileSize = F_MULTI_FHDL_DEFAULT_MAX_FILE_SIZE; } }
/**************************************************************************** Desc: ****************************************************************************/ RCODE F_DbCheck::createAndOpenResultSetDb( void) { RCODE rc = NE_XFLM_OK; XFLM_CREATE_OPTS createOpts; if (m_pResultSetDb) { if (RC_BAD( rc = closeAndDeleteResultSetDb())) { goto Exit; } } f_memset( &createOpts, 0, sizeof( XFLM_CREATE_OPTS)); for (;;) { // Generate a random file name f_sprintf( m_szResultSetDibName, "%d.db", (int)m_pRandGen->getUINT32( 100, 20000)); if (RC_OK( rc = gv_pXFlmDbSystem->dbCreate( m_szResultSetDibName, NULL, NULL, NULL, NULL, &createOpts, TRUE, (IF_Db **)&m_pResultSetDb))) { break; } if (rc == NE_XFLM_FILE_EXISTS || rc == NE_FLM_IO_ACCESS_DENIED) { rc = NE_XFLM_OK; } else { goto Exit; } } // Shouldn't have an RFL object - don't want anything // logged by this database. flmAssert( !m_pResultSetDb->getDatabase()->m_pRfl); Exit: return rc; }
/******************************************************************** Desc: ? *********************************************************************/ FSTATIC void bldOutLabel( FLMUINT uiCol, FLMUINT uiRow, const char * pucLabel, const char * pucValue, FLMUINT uiNumValue, FLMBOOL bLogIt) { char szMsg[ 100]; FLMUINT uiLen = (FLMUINT)(VALUE_COLUMN - uiCol - 1); f_memset( szMsg, '.', uiLen); szMsg[ uiLen] = 0; f_conSetBackFore( FLM_BLACK, FLM_LIGHTGRAY); f_conStrOutXY( szMsg, uiCol, uiRow); f_conStrOutXY( pucLabel, uiCol, uiRow); if( pucValue != NULL) { bldOutValue( uiRow, pucValue); } else { bldOutNumValue( uiRow, uiNumValue); } if( (bLogIt) && (gv_bLoggingEnabled)) { f_strcpy( szMsg, pucLabel); f_strcpy( &szMsg[ f_strlen( szMsg)], ": "); if( pucValue != NULL) { f_strcpy( &szMsg[ f_strlen( szMsg)], pucValue); } else { f_sprintf( (char *)(&szMsg[ f_strlen( szMsg)]), "%u", (unsigned)uiNumValue); } bldLogString( szMsg); } }
/******************************************************************** Desc: This routine initializes a XFLM_DB_HDR structure. *********************************************************************/ void flmInitDbHdr( XFLM_CREATE_OPTS * pCreateOpts, FLMBOOL bCreatingDatabase, FLMBOOL bTempDb, XFLM_DB_HDR * pDbHdr) { FLMUINT uiMinRflFileSize; FLMUINT uiMaxRflFileSize; if (bCreatingDatabase) { f_memset( pDbHdr, 0, sizeof( XFLM_DB_HDR)); } // If pCreateOpts is non-NULL, copy it into the file header. f_strcpy( (char *)pDbHdr->szSignature, XFLM_DB_SIGNATURE); pDbHdr->ui8IsLittleEndian = XFLM_NATIVE_IS_LITTLE_ENDIAN; if (pCreateOpts) { pDbHdr->ui16BlockSize = (FLMUINT16)pCreateOpts->ui32BlockSize; pDbHdr->ui8DefaultLanguage = (FLMUINT8)pCreateOpts->ui32DefaultLanguage; if (pCreateOpts->bKeepRflFiles) { pDbHdr->ui8RflKeepFiles = 1; } if (pCreateOpts->bLogAbortedTransToRfl) { pDbHdr->ui8RflKeepAbortedTrans = 1; } if( (uiMinRflFileSize = (FLMUINT)pCreateOpts->ui32MinRflFileSize) == 0) { uiMinRflFileSize = XFLM_DEFAULT_MIN_RFL_FILE_SIZE; } if( (uiMaxRflFileSize = (FLMUINT)pCreateOpts->ui32MaxRflFileSize) == 0) { uiMaxRflFileSize = XFLM_DEFAULT_MAX_RFL_FILE_SIZE; } } else { // If pCreateOpts is NULL, initialize some default values. pDbHdr->ui16BlockSize = XFLM_DEFAULT_BLKSIZ; pDbHdr->ui8DefaultLanguage = XFLM_DEFAULT_LANG; uiMinRflFileSize = XFLM_DEFAULT_MIN_RFL_FILE_SIZE; uiMaxRflFileSize = XFLM_DEFAULT_MAX_RFL_FILE_SIZE; } // Make sure the RFL size limits are valid. // Maximum must be enough to hold at least one packet plus // the RFL header. Minimum must not be greater than the // maximum. NOTE: Minimum and maximum are allowed to be // equal, but in all cases, maximum takes precedence over // minimum. We will first NOT exceed the maximum. Then, // if possible, we will go above the minimum. if (uiMaxRflFileSize < RFL_MAX_PACKET_SIZE + 512) { uiMaxRflFileSize = RFL_MAX_PACKET_SIZE + 512; } if (uiMaxRflFileSize > gv_XFlmSysData.uiMaxFileSize) { uiMaxRflFileSize = gv_XFlmSysData.uiMaxFileSize; } if (uiMinRflFileSize > uiMaxRflFileSize) { uiMinRflFileSize = uiMaxRflFileSize; } pDbHdr->ui32RflMinFileSize = (FLMUINT32)uiMinRflFileSize; pDbHdr->ui32RflMaxFileSize = (FLMUINT32)uiMaxRflFileSize; // Only allow database to be created with current version number pDbHdr->ui32DbVersion = XFLM_CURRENT_VERSION_NUM; pDbHdr->ui8BlkChkSummingEnabled = 1; // Round block size up to nearest legal block size. pDbHdr->ui16BlockSize = (FLMUINT16)flmAdjustBlkSize( (FLMUINT)pDbHdr->ui16BlockSize); if (!bTempDb) { pDbHdr->ui32FirstLFBlkAddr = (FLMUINT32)FSBlkAddress(1, 0); } // If creating a database, initialize some more items. if (bCreatingDatabase) { // Set the logical EOF. if (!bTempDb) { pDbHdr->ui32LogicalEOF = pDbHdr->ui32FirstLFBlkAddr + (FLMUINT32)pDbHdr->ui16BlockSize; } else { pDbHdr->ui32LogicalEOF = (FLMUINT32)FSBlkAddress(1, 0); } pDbHdr->ui64CurrTransID = (FLMUINT64)0; pDbHdr->ui32RflCurrFileNum = 1; // Putting a zero in this value tells the RFL code that the // RFL file should be created - overwriting it if it already // exists. pDbHdr->ui32RflLastCPFileNum = 1; pDbHdr->ui32RflLastCPOffset = 512; pDbHdr->ui32RblEOF = pDbHdr->ui16BlockSize; // Set the database serial number f_createSerialNumber( pDbHdr->ucDbSerialNum); // Set the "current" RFL serial number - will be stamped into the RFL // file when it is first created. f_createSerialNumber( pDbHdr->ucLastTransRflSerialNum); // Set the "next" RFL serial number f_createSerialNumber( pDbHdr->ucNextRflSerialNum); // Set the incremental backup serial number and sequence number f_createSerialNumber( pDbHdr->ucIncBackupSerialNum); pDbHdr->ui32IncBackupSeqNum = 1; // Set the file size limits pDbHdr->ui32MaxFileSize = (FLMUINT32)gv_XFlmSysData.uiMaxFileSize; // Need at least two blocks to create a database! flmAssert( (FLMUINT)pDbHdr->ui32MaxFileSize >= (FLMUINT)pDbHdr->ui16BlockSize * 2); } }
/**************************************************************************** Desc: Returns the requested file handle ****************************************************************************/ RCODE F_MultiFileHdl::getFileHdl( FLMUINT uiFileNum, FLMBOOL bGetForWrite, IF_FileHdl ** ppFileHdl) { RCODE rc = NE_FLM_OK; IF_FileSystem * pFileSystem = f_getFileSysPtr(); FLMUINT uiSlot; IF_FileHdl * pTmpHdl; char szPath[ F_PATH_MAX_SIZE]; f_assert( m_bOpen); *ppFileHdl = NULL; uiSlot = uiFileNum % F_MULTI_FHDL_LIST_SIZE; pTmpHdl = m_pFileHdlList[ uiSlot].pFileHdl; if( pTmpHdl && m_pFileHdlList[ uiSlot].uiFileNum != uiFileNum) { if( RC_BAD( rc = pTmpHdl->flush())) { goto Exit; } pTmpHdl->closeFile(); pTmpHdl->Release(); pTmpHdl = NULL; f_memset( &m_pFileHdlList[ uiSlot], 0, sizeof( FH_INFO)); } if( !pTmpHdl) { dataFilePath( uiFileNum, szPath); if( RC_BAD( rc = pFileSystem->openFile( szPath, FLM_IO_RDWR, &pTmpHdl))) { if( rc == NE_FLM_IO_PATH_NOT_FOUND && bGetForWrite) { if( RC_BAD( rc = pFileSystem->createFile( szPath, FLM_IO_RDWR, &pTmpHdl))) { goto Exit; } } else { goto Exit; } } m_pFileHdlList[ uiSlot].pFileHdl = pTmpHdl; m_pFileHdlList[ uiSlot].uiFileNum = uiFileNum; f_assert( !m_pFileHdlList[ uiSlot].bDirty); } *ppFileHdl = m_pFileHdlList[ uiSlot].pFileHdl; if( bGetForWrite) { m_pFileHdlList[ uiSlot].bDirty = TRUE; } Exit: return( rc); }
/**************************************************************************** Desc: Retrieves the Checkpoint info for the database passed in. This assumes global mutex has already been locked. *****************************************************************************/ void F_Database::getCPInfo( XFLM_CHECKPOINT_INFO * pCheckpointInfo) { FLMUINT uiElapTime; FLMUINT uiCurrTime; flmAssert( pCheckpointInfo); f_memset( pCheckpointInfo, 0, sizeof( XFLM_CHECKPOINT_INFO)); if (m_pCPInfo) { pCheckpointInfo->bRunning = m_pCPInfo->bDoingCheckpoint; if (pCheckpointInfo->bRunning) { if (m_pCPInfo->uiStartTime) { uiCurrTime = FLM_GET_TIMER(); uiElapTime = FLM_ELAPSED_TIME( uiCurrTime, m_pCPInfo->uiStartTime); pCheckpointInfo->ui32RunningTime = (FLMUINT32)FLM_TIMER_UNITS_TO_MILLI( uiElapTime); } else { pCheckpointInfo->ui32RunningTime = 0; } pCheckpointInfo->bForcingCheckpoint = m_pCPInfo->bForcingCheckpoint; if (m_pCPInfo->uiForceCheckpointStartTime) { uiCurrTime = FLM_GET_TIMER(); uiElapTime = FLM_ELAPSED_TIME( uiCurrTime, m_pCPInfo->uiForceCheckpointStartTime); pCheckpointInfo->ui32ForceCheckpointRunningTime = (FLMUINT32)FLM_TIMER_UNITS_TO_MILLI( uiElapTime); } else { pCheckpointInfo->ui32ForceCheckpointRunningTime = 0; } pCheckpointInfo->ui32ForceCheckpointReason = (FLMUINT32)m_pCPInfo->iForceCheckpointReason; pCheckpointInfo->bWritingDataBlocks = m_pCPInfo->bWritingDataBlocks; pCheckpointInfo->ui32LogBlocksWritten = (FLMUINT32)m_pCPInfo->uiLogBlocksWritten; pCheckpointInfo->ui32DataBlocksWritten = (FLMUINT32)m_pCPInfo->uiDataBlocksWritten; } pCheckpointInfo->ui32BlockSize = (FLMUINT32)m_uiBlockSize; pCheckpointInfo->ui32DirtyCacheBytes = (FLMUINT32)(m_uiDirtyCacheCount * m_uiBlockSize); if (m_pCPInfo->uiStartWaitTruncateTime) { uiCurrTime = FLM_GET_TIMER(); uiElapTime = FLM_ELAPSED_TIME( uiCurrTime, m_pCPInfo->uiStartWaitTruncateTime); pCheckpointInfo->ui32WaitTruncateTime = (FLMUINT32)FLM_TIMER_UNITS_TO_MILLI( uiElapTime); } else { pCheckpointInfo->ui32WaitTruncateTime = 0; } } }
/*************************************************************************** Desc: This routine reads and verifies the information contained in the file header and log header of a FLAIM database. *****************************************************************************/ RCODE flmReadAndVerifyHdrInfo( XFLM_DB_STATS * pDbStats, IF_FileHdl * pFileHdl, XFLM_DB_HDR * pDbHdr, FLMUINT32 * pui32CalcCRC) { RCODE rc = NE_XFLM_OK; FLMUINT uiBytesRead; // Read the database header. f_memset( pDbHdr, 0, sizeof( XFLM_DB_HDR)); if (RC_BAD( rc = pFileHdl->read( (FLMUINT)0, sizeof( XFLM_DB_HDR), pDbHdr, &uiBytesRead))) { if (rc != NE_FLM_IO_END_OF_FILE) { if (pDbStats) { pDbStats->uiReadErrors++; } } else { if (pui32CalcCRC) { *pui32CalcCRC = calcDbHdrCRC( pDbHdr); } // Get what we can out of the header. if (hdrIsNonNativeFormat( pDbHdr)) { convertDbHdr( pDbHdr); } } goto Exit; } if (pui32CalcCRC) { *pui32CalcCRC = calcDbHdrCRC( pDbHdr); } if (uiBytesRead < sizeof( XFLM_DB_HDR)) { // Still get what we can out of the header. if (hdrIsNonNativeFormat( pDbHdr)) { convertDbHdr( pDbHdr); } rc = RC_SET( NE_XFLM_NOT_FLAIM); goto Exit; } else { // This routine will convert to native format if it is not // in native format. if (RC_BAD( rc = verifyDbHdr( pDbHdr))) { goto Exit; } } Exit: return( rc); }
/**************************************************************************** Desc: Constructor for F_Database object. ****************************************************************************/ F_Database::F_Database( FLMBOOL bTempDb) { m_krefPool.poolInit( DEFAULT_KREF_POOL_BLOCK_SIZE * 8); m_pNext = NULL; m_pPrev = NULL; m_pFirstQuery = NULL; m_pLastQuery = NULL; m_uiBlockSize = 0; m_uiDefaultLanguage = 0; m_uiMaxFileSize = 0; m_uiOpenIFDbCount = 0; m_bTempDb = bTempDb; m_pFirstDb = NULL; m_pszDbPath = NULL; m_pszDataDir = NULL; m_pSCacheList = NULL; m_pFirstNode = NULL; m_pLastNode = NULL; m_pLastDirtyNode = NULL; m_pPendingWriteList = NULL; m_pLastDirtyBlk = NULL; m_pFirstInLogList = NULL; m_pLastInLogList = NULL; m_uiLogListCount = 0; m_pFirstInNewList = NULL; m_pLastInNewList = NULL; m_uiNewCount = 0; m_uiDirtyCacheCount = 0; m_uiLogCacheCount = 0; m_ppBlocksDone = NULL; m_uiBlocksDoneArraySize = 0; m_uiBlocksDone = 0; m_pTransLogList = NULL; m_pOpenNotifies = NULL; m_pCloseNotifies = NULL; m_pDictList = NULL; m_bMustClose = FALSE; m_rcMustClose = NE_XFLM_OK; m_uiSigBitsInBlkSize = 0; if (!bTempDb) { m_uiFileExtendSize = XFLM_DEFAULT_FILE_EXTEND_SIZE; } else { m_uiFileExtendSize = 65536; } m_pRfl = NULL; f_memset( &m_lastCommittedDbHdr, 0, sizeof( m_lastCommittedDbHdr)); f_memset( &m_checkpointDbHdr, 0, sizeof( m_checkpointDbHdr)); f_memset( &m_uncommittedDbHdr, 0, sizeof( m_uncommittedDbHdr)); m_pBufferMgr = NULL; m_pCurrLogBuffer = NULL; m_uiCurrLogWriteOffset = 0; m_uiCurrLogBlkAddr = 0; m_pDbHdrWriteBuf = NULL; m_pucUpdBuffer = NULL; m_uiUpdBufferSize = 0; m_uiUpdByteCount = 0; m_uiUpdCharCount = 0; m_uiPendingType = XFLM_NODATA_TYPE; m_pPendingInput = NULL; m_pPendingBTree = NULL; m_pucBTreeTmpBlk = NULL; m_pucBTreeTmpDefragBlk = NULL; m_pucEntryArray = NULL; m_pucSortedArray = NULL; m_pucBtreeBuffer = NULL; m_pucReplaceStruct = NULL; m_pDatabaseLockObj = NULL; m_pWriteLockObj = NULL; m_pLockFileHdl = NULL; m_pLockNotifies = NULL; m_bBeingLocked = FALSE; m_pFirstReadTrans = NULL; m_pLastReadTrans = NULL; m_pFirstKilledTrans = NULL; m_uiFirstLogBlkAddress = 0; m_uiFirstLogCPBlkAddress = 0; m_uiLastCheckpointTime = 0; m_pCPThrd = NULL; m_pCPInfo = NULL; m_CheckpointRc = NE_XFLM_OK; m_uiBucket = 0; m_uiFlags = 0; m_bBackupActive = FALSE; m_pMaintThrd = NULL; m_hMaintSem = F_SEM_NULL; m_bAllowLimitedMode = FALSE; m_bInLimitedMode = FALSE; m_pszDbPasswd = NULL; m_pWrappingKey = NULL; m_bHaveEncKey = FALSE; m_rcLimitedCode = NE_XFLM_OK; m_hMutex = F_MUTEX_NULL; }
RCODE f_fileFindFirst( char * pszSearchPath, FLMUINT uiSearchAttrib, F_IO_FIND_DATA * pFindData, char * pszFoundPath, FLMUINT * puiFoundAttrib) { RCODE rc = NE_FLM_OK; char szTmpPath[ F_PATH_MAX_SIZE]; FSTATIC char pszWildCard[] = {'*',0}; int iRetVal; IF_FileSystem * pFileSystem = f_getFileSysPtr(); if( !pszSearchPath) { rc = RC_SET( NE_FLM_IO_PATH_NOT_FOUND); goto Exit; } f_strcpy( szTmpPath, pszSearchPath); if( RC_BAD( rc = pFileSystem->pathAppend( szTmpPath, pszWildCard))) { goto Exit; } f_memset( pFindData, 0, sizeof( F_IO_FIND_DATA)); if( uiSearchAttrib & F_IO_FA_DIRECTORY) { pFindData->mode_flag |= S_IFDIR; } if( uiSearchAttrib & F_IO_FA_RDONLY) { pFindData->mode_flag |= S_IREAD; } iRetVal = Find1( (char*)szTmpPath, pFindData); if( iRetVal != 0) { // If there were no more files found then return no more files // instead of mapping to error path not found or io error. // To return no more files ret_val is ENOENT (set in Find2) // and errno is not set if( iRetVal == ENOENT && errno == 0) { rc = RC_SET( NE_FLM_IO_NO_MORE_FILES); } else { rc = f_mapPlatformError( errno, NE_FLM_READING_FILE); } goto Exit; } // filter out ".." (PARENT) and "." (CURRENT) directories if( uiSearchAttrib & F_IO_FA_DIRECTORY ) { while( (f_strcmp( pFindData->name, "..") == 0) || (f_strcmp( pFindData->name, ".") == 0)) { if( (iRetVal = Find2( pFindData)) != 0) { // If there were no more files found then return no more files // instead of mapping to error path not found or io error. // To return no more files ret_val is ENOENT (set in Find2) // and errno is not set if( iRetVal == ENOENT && errno == 0) { rc = RC_SET( NE_FLM_IO_NO_MORE_FILES); } else { rc = f_mapPlatformError( errno, NE_FLM_READING_FILE); } goto Exit; } } } // Append the file name to the path name f_strcpy( pszFoundPath, pszSearchPath); if( RC_BAD( rc = pFileSystem->pathAppend( pszFoundPath, (char *)pFindData->name))) { goto Exit; } *puiFoundAttrib = (FLMUINT)ReturnAttributes( pFindData->FileStat.st_mode, pszFoundPath); // Save the search path in the NE_FLM_IO_FIND_DATA struct // for a find next call f_strcpy( pFindData->search_path, pszSearchPath); Exit: return( rc); }
/*************************************************************************** Desc: This routine begins a thread that will do checkpoints for the passed in database. It gives the thread its own FLAIM session and its own handle to the database. *****************************************************************************/ RCODE F_Database::startCPThread( void) { RCODE rc = NE_XFLM_OK; CP_INFO * pCPInfo = NULL; char szThreadName[ F_PATH_MAX_SIZE]; char szBaseName[ 32]; F_SuperFileClient * pSFileClient = NULL; // Allocate a CP_INFO structure that will be passed into the // thread when it is created. if (RC_BAD( rc = f_calloc( (FLMUINT)(sizeof( CP_INFO)), &pCPInfo))) { goto Exit; } pCPInfo->pDatabase = this; // Create a "wait" semaphore if( RC_BAD( rc = f_semCreate( &pCPInfo->hWaitSem))) { goto Exit; } // Allocate a super file handle. if( (pCPInfo->pSFileHdl = f_new F_SuperFileHdl) == NULL) { rc = RC_SET( NE_XFLM_MEM); goto Exit; } if( (pSFileClient = f_new F_SuperFileClient) == NULL) { rc = RC_SET( NE_XFLM_MEM); goto Exit; } if( RC_BAD( rc = pSFileClient->setup( m_pszDbPath, m_pszDataDir, m_uiMaxFileSize))) { goto Exit; } // Set up the super file if( RC_BAD( rc = pCPInfo->pSFileHdl->setup( pSFileClient, gv_XFlmSysData.pFileHdlCache, gv_XFlmSysData.uiFileOpenFlags, gv_XFlmSysData.uiFileCreateFlags))) { goto Exit; } f_memset( &pCPInfo->Stats, 0, sizeof( XFLM_STATS)); pCPInfo->bStatsInitialized = TRUE; // Generate the thread name if (RC_BAD( rc = gv_XFlmSysData.pFileSystem->pathReduce( m_pszDbPath, szThreadName, szBaseName))) { goto Exit; } f_sprintf( (char *)szThreadName, "Checkpoint (%s)", (char *)szBaseName); // Start the checkpoint thread. if (RC_BAD( rc = gv_XFlmSysData.pThreadMgr->createThread( &m_pCPThrd, flmCPThread, szThreadName, gv_XFlmSysData.uiCheckpointThreadGroup, 0, pCPInfo, NULL, 32000))) { goto Exit; } m_pCPInfo = pCPInfo; pCPInfo = NULL; Exit: if( pCPInfo) { flmFreeCPInfo( &pCPInfo); } if( pSFileClient) { pSFileClient->Release(); } return( rc); }
/*************************************************************************** Desc: Constructor for F_Db object. ****************************************************************************/ F_Db::F_Db( FLMBOOL bInternalOpen) { m_pDatabase = NULL; m_pDict = NULL; m_pNextForDatabase = NULL; m_pPrevForDatabase = NULL; m_pvAppData = NULL; m_uiThreadId = 0; m_bMustClose = FALSE; m_pSFileHdl = NULL; m_uiFlags = bInternalOpen ? FDB_INTERNAL_OPEN : 0; m_uiTransCount = 0; m_eTransType = XFLM_NO_TRANS; m_AbortRc = NE_XFLM_OK; m_ui64CurrTransID = 0; m_uiFirstAvailBlkAddr = 0; m_uiLogicalEOF = 0; m_uiUpgradeCPFileNum = 0; m_uiUpgradeCPOffset = 0; m_uiTransEOF = 0; f_memset( &m_TransStartTime, 0, sizeof( m_TransStartTime)); m_bHadUpdOper = FALSE; m_uiBlkChangeCnt = 0; m_pIxdFixups = NULL; m_pNextReadTrans = NULL; m_pPrevReadTrans = NULL; m_uiInactiveTime = 0; m_uiKilledTime = 0; m_bItemStateUpdOk = FALSE; m_pDeleteStatus = NULL; m_pIxClient = NULL; m_pIxStatus = NULL; m_pCommitClient = NULL; m_pStats = NULL; m_pDbStats = NULL; m_pLFileStats = NULL; m_uiLFileAllocSeq = 0; f_memset( &m_Stats, 0, sizeof( m_Stats)); m_bStatsInitialized = TRUE; m_pIxStartList = NULL; m_pIxStopList = NULL; m_pCachedBTree = NULL; m_pKeyColl = NULL; m_pOldNodeList = NULL; m_uiDirtyNodeCount = 0; m_hWaitSem = F_SEM_NULL; m_bKrefSetup = FALSE; m_pKrefTbl = NULL; m_uiKrefTblSize = 0; m_uiKrefCount = 0; m_uiTotalKrefBytes = 0; m_pucKrefKeyBuf = NULL; m_pKrefPool = NULL; m_bReuseKrefPool = FALSE; m_bKrefCompoundKey = FALSE; m_pKrefReset = NULL; m_tmpKrefPool.poolInit( DEFAULT_KREF_POOL_BLOCK_SIZE); m_tempPool.poolInit( XFLM_MAX_KEY_SIZE * 4); }
/**************************************************************************** Desc: This function handle the details of extracting the parameters needed to interpret the request and then generating the response HTML page ****************************************************************************/ RCODE F_FFilePage::display( FLMUINT uiNumParams, const char ** ppszParams) { RCODE rc = FERR_OK; #define GENERIC_SIZE_B 20 char szFrom[ GENERIC_SIZE_B]; char szBucket[ 4]; FLMUINT uiBucket; FFILE localFFile; FFILE * pFile; FLMBOOL bRefresh; void * pvAddress; char szAddress[GENERIC_SIZE_B]; char szLink[GENERIC_SIZE_B]; FLMBOOL bFlmLocked = FALSE; DATASTRUCT DataStruct; FLMBYTE * pszTemp = NULL; FLMBYTE * pszTemp1 = NULL; if( RC_BAD( rc = f_alloc( 150, &pszTemp))) { printErrorPage( rc, TRUE, (char *)"Failed to allocate temporary buffer"); goto Exit; } if( RC_BAD( rc = f_alloc( 150, &pszTemp1))) { printErrorPage( rc, TRUE, (char *)"Failed to allocate temporary buffer"); goto Exit; } // Initialize a few variables first... szFrom[0] = '\0'; szBucket[0] = '\0'; pFile = NULL; // Get the "From" parameter. We use this to determine everything else. if (RC_BAD( rc = ExtractParameter( uiNumParams, ppszParams, "From", sizeof( szFrom), szFrom))) { goto Exit; } f_mutexLock( gv_FlmSysData.hShareMutex); bFlmLocked = TRUE; if (!f_stricmp( szFrom, "FileHashTbl")) { // Get the hash bucket index if (RC_BAD( rc = ExtractParameter( uiNumParams, ppszParams, "Bucket", sizeof( szBucket), szBucket))) { goto Exit; } uiBucket = f_atoud( szBucket); pFile = (FFILE *)gv_FlmSysData.pFileHashTbl[uiBucket].pFirstInBucket; } else if ( (f_stricmp( szFrom, "SCacheBlock") == 0) || (f_stricmp( szFrom, "RCache") == 0) || (f_stricmp( szFrom, "FDB") == 0)) { // Get the FFile address and the Hash Bucket if (RC_BAD( rc = ExtractParameter( uiNumParams, ppszParams, "Bucket", sizeof( szBucket), szBucket))) { goto Exit; } uiBucket = f_atoud( szBucket); if (RC_BAD( rc = ExtractParameter( uiNumParams, ppszParams, "Address", sizeof( szAddress), szAddress))) { goto Exit; } pvAddress = (void *)f_atoud( szAddress); pFile = (FFILE *)gv_FlmSysData.pFileHashTbl[uiBucket].pFirstInBucket; while (pFile && (void *)pFile != pvAddress) { pFile = pFile->pNext; } } else if (f_stricmp( szFrom, "FlmSysData") == 0) { // Get the Link and the FFile address if (RC_BAD( rc = ExtractParameter( uiNumParams, ppszParams, "Link", sizeof( szLink), szLink))) { goto Exit; } if (RC_BAD( rc = ExtractParameter( uiNumParams, ppszParams, "Address", sizeof( szAddress), szAddress))) { goto Exit; } pvAddress = (void *)f_atoud( szAddress); if (f_stricmp( szLink, "pMrnuFile") == 0) { pFile = gv_FlmSysData.pMrnuFile; // Now let's make sure we are looking at the right FFile... while (pFile && (void *)pFile != pvAddress) { pFile = pFile->pNextNUFile; } } else if (f_stricmp( szLink, "pLrnuFile") == 0) { pFile = gv_FlmSysData.pLrnuFile; // Now let's make sure we are looking at the right FFile... while (pFile && (void *)pFile != pvAddress) { pFile = pFile->pPrevNUFile; } } } else if (f_stricmp( szFrom, "FFile") == 0) { // We need to get the Link, Bucket & Address if (RC_BAD(rc = ExtractParameter( uiNumParams, ppszParams, "Link", sizeof( szLink), szLink))) { goto Exit; } if (RC_BAD(rc = ExtractParameter( uiNumParams, ppszParams, "Address", sizeof( szAddress), szAddress))) { goto Exit; } pvAddress = (void *)f_atoud( szAddress); if (RC_BAD(rc = ExtractParameter( uiNumParams, ppszParams, "Bucket", sizeof( szBucket), szBucket))) { goto Exit; } uiBucket = f_atoud( szBucket); // First, let's get a reference to an FFile from the specified bucket if (gv_FlmSysData.pFileHashTbl[uiBucket].pFirstInBucket) { pFile = (FFILE *)gv_FlmSysData.pFileHashTbl[uiBucket].pFirstInBucket; } // Now let's make sure we are looking at the right FFile... while (pFile && (void *)pFile != pvAddress) { pFile = pFile->pNext; } // Now what link are we supposed to follow? if (f_stricmp( szLink, "pNext") == 0) { pFile = pFile->pNext; } else if (f_stricmp( szLink, "pPrev") == 0) { pFile = pFile->pPrev; } else if (f_stricmp( szLink, "pNextNUFile") == 0) { pFile = pFile->pNextNUFile; } else if (f_stricmp( szLink, "pPrevNUFile") == 0) { pFile = pFile->pPrevNUFile; } } // Gather additional data if present. Initialize the structure before // using it. f_memset( &DataStruct, 0, sizeof(DataStruct)); if (pFile) { f_memcpy( &localFFile, pFile, sizeof(localFFile)); if (pFile->pSCacheList) { DataStruct.SCacheBlkAddress = pFile->pSCacheList->uiBlkAddress; DataStruct.SCacheLowTransID = scaGetLowTransID( pFile->pSCacheList), DataStruct.SCacheHighTransID = pFile->pSCacheList->uiHighTransID; } if (pFile->pPendingWriteList) { DataStruct.PendingWriteBlkAddress = pFile->pPendingWriteList->uiBlkAddress; DataStruct.PendingWriteLowTransID = scaGetLowTransID( pFile->pPendingWriteList), DataStruct.PendingWriteHighTransID = pFile->pPendingWriteList->uiHighTransID; } if (pFile->pLastDirtyBlk) { DataStruct.LastDirtyBlkAddress = pFile->pLastDirtyBlk->uiBlkAddress; DataStruct.LastDirtyLowTransID = scaGetLowTransID( pFile->pLastDirtyBlk), DataStruct.LastDirtyHighTransID = pFile->pLastDirtyBlk->uiHighTransID; } if (pFile->pFirstRecord) { DataStruct.FirstRecordContainer = pFile->pFirstRecord->uiContainer; DataStruct.FirstRecordDrn = pFile->pFirstRecord->uiDrn; DataStruct.FirstRecordLowTransId = pFile->pFirstRecord->uiLowTransId; } if (pFile->pLastRecord) { DataStruct.LastRecordContainer = pFile->pLastRecord->uiContainer; DataStruct.LastRecordDrn = pFile->pLastRecord->uiDrn; DataStruct.LastRecordLowTransId = pFile->pLastRecord->uiLowTransId; } } f_mutexUnlock( gv_FlmSysData.hShareMutex); bFlmLocked = FALSE; stdHdr(); fnPrintf( m_pHRequest, HTML_DOCTYPE); fnPrintf( m_pHRequest, "<html>\n"); // Determine if we are being requested to refresh this page or not. if ((bRefresh = DetectParameter( uiNumParams, ppszParams, "Refresh")) == TRUE) { // Send back the page with a refresh command in the header f_sprintf( (char *)pszTemp, "%s/FFile?Refresh&From=%s&Bucket=%s", m_pszURLString, szFrom, szBucket); fnPrintf( m_pHRequest, "<HEAD>" "<META http-equiv=\"refresh\" content=\"5; url=%s\">" "<TITLE>FFile Structure</TITLE>\n", pszTemp); } else { fnPrintf( m_pHRequest, "<HEAD><TITLE>FFile Structure</TITLE>\n"); } printStyle(); fnPrintf( m_pHRequest, "</HEAD>\n"); fnPrintf( m_pHRequest, "<body>\n"); // If we are not to refresh this page, then don't include the // refresh meta command if (!bRefresh) { f_sprintf( (char *)pszTemp, "<A HREF=%s/FFile?Refresh&From=%s&Bucket=%s>Start Auto-refresh (5 sec.)</A>", m_pszURLString, szFrom, szBucket); } else { f_sprintf( (char *)pszTemp, "<A HREF=%s/FFile?From=%s&Bucket=%s>Stop Auto-refresh</A>", m_pszURLString, szFrom, szBucket); } // Prepare the refresh link. f_sprintf( (char *)pszTemp1, "<A HREF=%s/FFile?From=%s&Bucket=%s>Refresh</A>", m_pszURLString, szFrom, szBucket); // Show the table headings and the refresh option. if (pFile) { // Write out the table headings printTableStart( "FFile Structure", 4, 100); printTableRowStart(); printColumnHeading( "", JUSTIFY_LEFT, FLM_IMON_COLOR_PUTTY_1, 4, 1, FALSE); fnPrintf( m_pHRequest, "%s, ", pszTemp1); fnPrintf( m_pHRequest, "%s\n", pszTemp); printColumnHeadingClose(); printTableRowEnd(); // Write out the table headings. printTableRowStart(); printColumnHeading( "Byte Offset (hex)"); printColumnHeading( "Field Name"); printColumnHeading( "Field Type"); printColumnHeading( "Value"); printTableRowEnd(); write_data( (pFile ? &localFFile: NULL), (void *)pFile, &DataStruct); } else { // Write out an error page... fnPrintf( m_pHRequest, "<P>Unable to find the FFile structure that you requested." " This is probably because the state of the cache changed between " "the time that you displayed the previous page and the time that you " "clicked on the link that brought you here.\n" "<P>Click on your browser's \"Back\" button, then click \"Reload\" " "and then try the link again.\n"); } fnPrintf( m_pHRequest, "</body></html>\n"); fnEmit(); Exit: if (bFlmLocked) { f_mutexUnlock( gv_FlmSysData.hShareMutex); bFlmLocked = FALSE; } if (pszTemp) { f_free( &pszTemp); } if (pszTemp1) { f_free( &pszTemp1); } return( rc); }
/**************************************************************************** Name: insert Desc: *****************************************************************************/ RCODE F_DynamicList::insert( FLMUINT uiKey, F_DLIST_DISP_HOOK pDisplayHook, void * pvData, FLMUINT uiDataLen) { RCODE rc = NE_FLM_OK; DLIST_NODE * pTmp; DLIST_NODE * pNew = NULL; if( getNode( uiKey) != NULL) { rc = RC_SET( NE_FLM_EXISTS); goto Exit; } // Allocate the new node if( RC_BAD( rc = f_alloc( sizeof( DLIST_NODE), &pNew))) { goto Exit; } f_memset( pNew, 0, sizeof( DLIST_NODE)); // Set the members of the new node pNew->uiKey = uiKey; if( pDisplayHook) { pNew->pDispHook = pDisplayHook; } else { pNew->pDispHook = dlistDefaultDisplayHook; } if( uiDataLen) { if( RC_BAD( rc = f_alloc( uiDataLen, &pNew->pvData))) { goto Exit; } f_memcpy( pNew->pvData, pvData, uiDataLen); pNew->uiDataLen = uiDataLen; } // Find the insertion point if( !m_pFirst) { m_pFirst = m_pLast = m_pCur = pNew; } else { pTmp = m_pFirst; while( pTmp && pTmp->uiKey < uiKey) { pTmp = pTmp->pNext; } if( pTmp) { if( pTmp == m_pFirst) { pNew->pNext = m_pFirst; m_pFirst->pPrev = pNew; m_pFirst = pNew; } else { pNew->pNext = pTmp; pNew->pPrev = pTmp->pPrev; if( pTmp->pPrev) { pTmp->pPrev->pNext = pNew; } pTmp->pPrev = pNew; } } else { // Insert at end m_pLast->pNext = pNew; pNew->pPrev = m_pLast; m_pLast = pNew; } } m_bChanged = TRUE; Exit: if( RC_BAD( rc)) { if( pNew) { freeNode( pNew); } } return( rc); }
/**************************************************************************** Desc : Checks for physical corruption in a FLAIM database. DNote: The routine verifies the database by first reading through the database to count certain block types which are in linked lists. It then verifies the linked lists. It also verifies the B-TREEs in the database. The reason for the first pass is so that when we verify the linked lists, we can keep ourselves from getting into an infinite loop if there is a loop in the lists. ****************************************************************************/ RCODE F_DbCheck::dbCheck( const char * pszDbFileName, // [IN] Full path and file name of the database which // is to be checked. NULL can be passed as the value of // this parameter if pDb is non-NULL. const char * pszDataDir, // [IN] Directory for data files. const char * pszRflDir, // [IN] RFL directory. NULL can be passed as the value of // this parameter to indicate that the log files are located // in the same directory as the database or if pDb is non-NULL. const char * pszPassword, // [IN] Database password. Needed to open the database if the database // key has been wrapped in a password. NULL by default. FLMUINT uiFlags, // [IN] Check flags. Possible flags include: // // XFLM_ONLINE. This flag instructs the check to repair any // index corruptions it finds. The database must have been // opened in read/write mode in order for the check to // successfully repair corruptions. An update transaction // will be started whenever a corruption is repaired. // // XFLM_DO_LOGICAL_CHECK. This flag instructs the check to // perform a logical check of the databases's indexes // in addition to the structural check. // // XFLM_SKIP_DOM_LINK_CHECK. This flag instructs the check to skip // verifying the DOM links. This check can take quite a long time // to execute. // // XFLM_ALLOW_LIMITED_MODE. This flag instructs the check to allow // the database to be opened in limited mode if the database key is // wrapped in a password and the password we pass is incorrect // (or non-existent). IF_DbInfo ** ppDbInfo, // [IN] Pointer to a DB_INFO structure which is used to store // statistics collected during the database check. IF_DbCheckStatus * pDbCheckStatus // [IN] Status interface. Functions in this interface are called // periodically to iform the calling application of the progress // being made. This allows the application to monitor and/or display // the progress of the database check. NULL may be passed as the // value of this parameter if the callback feature is not needed. ) { RCODE rc = NE_XFLM_OK; FLMBYTE * pBlk = NULL; FLMUINT uiFileEnd; FLMUINT uiBlockSize; FLMUINT uiLoop; FLMUINT64 ui64TmpSize; FLMBOOL bStartOver; FLMBOOL bOkToCloseTrans = FALSE; FLMBOOL bAllowLimitedMode = ( uiFlags & XFLM_ALLOW_LIMITED_MODE) ? TRUE : FALSE; if (RC_BAD( rc = gv_pXFlmDbSystem->dbOpen( pszDbFileName, pszDataDir, pszRflDir, pszPassword, bAllowLimitedMode, (IF_Db **)&m_pDb))) { goto Exit; } if ((m_pDbInfo = f_new F_DbInfo) == NULL) { rc = RC_SET( NE_XFLM_MEM); goto Exit; } if (ppDbInfo) { *ppDbInfo = m_pDbInfo; (*ppDbInfo)->AddRef(); } m_pDbCheckStatus = pDbCheckStatus; m_LastStatusRc = NE_XFLM_OK; // Get the file size... if (uiFlags & XFLM_SKIP_DOM_LINK_CHECK) { m_bSkipDOMLinkCheck = TRUE; } // Initialize the information block and Progress structure. // Since we know that the check will start read transactions // during its processing, set the flag to indicate that the KRef table // should be cleaned up on exit if we are still in a read transaction. bOkToCloseTrans = TRUE; uiBlockSize = m_pDb->m_pDatabase->getBlockSize(); // Allocate memory to use for reading through the data blocks. if( RC_BAD( rc = f_alloc( uiBlockSize, &pBlk))) { goto Exit; } if ((m_pBtPool = f_new F_BtPool) == NULL) { rc = RC_SET( NE_XFLM_MEM); goto Exit; } if (RC_BAD( rc = m_pBtPool->btpInit())) { goto Exit; } // Setup the result set database. if( RC_BAD( rc = FlmAllocRandomGenerator( &m_pRandGen))) { goto Exit; } m_pRandGen->setSeed( 9768); if (RC_BAD( rc = createAndOpenResultSetDb())) { goto Exit; } Begin_Check: // Initialize all statistics in the DB_INFO structure. rc = NE_XFLM_OK; bStartOver = FALSE; m_pDbInfo->m_ui64FileSize = 0; m_pDbInfo->freeLogicalFiles(); m_bPhysicalCorrupt = FALSE; m_bIndexCorrupt = FALSE; m_uiFlags = uiFlags; m_bStartedUpdateTrans = FALSE; f_memset( &m_pDbInfo->m_AvailBlocks, 0, sizeof( BLOCK_INFO)); f_memset( &m_pDbInfo->m_LFHBlocks, 0, sizeof( BLOCK_INFO)); f_memset( &m_Progress, 0, sizeof( XFLM_PROGRESS_CHECK_INFO)); /* Get the dictionary information for the file. */ if (RC_BAD( rc = getDictInfo())) { goto Exit; } m_Progress.ui64BytesExamined = 0; for (uiLoop = 1; uiLoop <= MAX_DATA_BLOCK_FILE_NUMBER; uiLoop++) { if (RC_BAD( m_pDb->m_pSFileHdl->getFileSize( uiLoop, &ui64TmpSize))) { break; } m_Progress.ui64FileSize += ui64TmpSize; } // See if we have a valid end of file uiFileEnd = m_pDb->m_uiLogicalEOF; if (FSGetFileOffset( uiFileEnd) % uiBlockSize != 0) { if (RC_BAD( rc = chkReportError( FLM_BAD_FILE_SIZE, XFLM_LOCALE_NONE, 0, 0, 0xFF, (FLMUINT32)uiFileEnd, 0, 0, 0))) { goto Exit; } } else if (m_Progress.ui64FileSize < FSGetSizeInBytes( m_pDb->m_pDatabase-> getMaxFileSize(), uiFileEnd)) { m_Progress.ui64FileSize = FSGetSizeInBytes( m_pDb->m_pDatabase->getMaxFileSize(), uiFileEnd); } m_pDbInfo->m_ui64FileSize = m_Progress.ui64FileSize; // Verify the LFH blocks, B-Trees, and the AVAIL list. if( RC_BAD( rc = verifyLFHBlocks( &bStartOver))) { goto Exit; } if (bStartOver) { goto Begin_Check; } // Check the b-trees. if (RC_BAD( rc = verifyBTrees( &bStartOver))) { goto Exit; } if (bStartOver) { goto Begin_Check; } // Check the avail list. if (RC_BAD( rc = verifyAvailList( &bStartOver))) { goto Exit; } if (bStartOver) { goto Begin_Check; } Exit: if ((m_bPhysicalCorrupt || m_bIndexCorrupt) && !gv_pXFlmDbSystem->errorIsFileCorrupt( rc)) { rc = RC_SET( NE_XFLM_DATA_ERROR); } if (RC_OK( rc) && RC_BAD( m_LastStatusRc)) { rc = m_LastStatusRc; } if (m_pDb) { // Close down the transaction, if one is going if( bOkToCloseTrans && m_pDb->getTransType( ) == XFLM_READ_TRANS) { m_pDb->krefCntrlFree(); m_pDb->transAbort(); } } // Free memory, if allocated if (pBlk) { f_free( &pBlk); } // Close the FLAIM database we opened. if (m_pDb) { m_pDb->Release(); m_pDb = NULL; } return( rc); }
/**************************************************************************** Desc : Adds a value to the selection criteria of a given cursor. ****************************************************************************/ FLMEXP RCODE FLMAPI FlmCursorAddValue( HFCURSOR hCursor, QTYPES eValType, void * pVal, FLMUINT uiValLen ) { RCODE rc = FERR_OK; FLMUINT uiVal; void * pTmpVal = pVal; CURSOR * pCursor = (CURSOR *)hCursor; F_Pool pool; FLMBOOL bPoolInitialized = FALSE; if (!pCursor) { flmAssert( 0); rc = RC_SET( FERR_INVALID_PARM); goto Exit; } if (RC_BAD( rc = pCursor->rc)) { goto Exit; } // If a read operation has already been performed on this query, no // selection criteria may be added. if (pCursor->bOptimized) { rc = RC_SET( FERR_ILLEGAL_OP); goto Exit; } if (!( pCursor->QTInfo.uiExpecting & FLM_Q_OPERAND)) { rc = RC_SET( FERR_CURSOR_SYNTAX); goto Exit; } switch (eValType) { // Convert all string types to FLM_TEXT_VALUE // in order to handle pure unicode coming in. case FLM_UNICODE_VAL: case FLM_STRING_VAL: { NODE node; f_memset( &node, 0, sizeof(NODE)); pool.poolInit( 512); bPoolInitialized = TRUE; rc = (eValType == FLM_UNICODE_VAL) ? GedPutUNICODE( &pool, &node, (FLMUNICODE *) pVal) : GedPutNATIVE( &pool, &node, (const char *)pVal); if (RC_BAD( rc)) { goto Exit; } pTmpVal = GedValPtr( &node); uiValLen = GedValLen( &node); eValType = FLM_TEXT_VAL; break; } case FLM_BOOL_VAL: if (!pVal) { uiVal = FLM_UNK; } else { FLMBOOL bTrueFalse = (FLMBOOL)*(FLMBOOL *)pVal; uiVal = (bTrueFalse) ? FLM_TRUE : FLM_FALSE; } pTmpVal = &uiVal; eValType = FLM_BOOL_VAL; break; case FLM_INT32_VAL: case FLM_UINT32_VAL: case FLM_REC_PTR_VAL: case FLM_UINT64_VAL: case FLM_INT64_VAL: case FLM_TEXT_VAL: case FLM_BINARY_VAL: // pTmpVal is already pointing to pVal, and // eValType does not need to be changed. break; default: flmAssert( 0); rc = RC_SET( FERR_CURSOR_SYNTAX); break; } if (RC_OK( rc = flmCurMakeQNode( &pCursor->QueryPool, eValType, pTmpVal, uiValLen, pCursor->QTInfo.uiFlags, &(pCursor->QTInfo.pCurAtomNode)))) { if (pCursor->QTInfo.pCurOpNode) { flmCurLinkLastChild( pCursor->QTInfo.pCurOpNode, pCursor->QTInfo.pCurAtomNode); } pCursor->QTInfo.uiExpecting &= ~FLM_Q_OPERAND; pCursor->QTInfo.uiExpecting |= FLM_Q_OPERATOR; } Exit: if (pCursor) { pCursor->rc = rc; } if (bPoolInitialized) { pool.poolFree(); } return( rc); }
/**************************************************************************** Desc: Closes all data files associated with the object ****************************************************************************/ void F_MultiFileHdl::closeFile( FLMBOOL bDelete) { RCODE rc = NE_FLM_OK; FLMUINT uiLoop; IF_DirHdl * pDir = NULL; char szTmpPath[ F_PATH_MAX_SIZE]; IF_FileSystem * pFileSystem = f_getFileSysPtr(); if( !m_bOpen) { return; } for( uiLoop = 0; uiLoop < F_MULTI_FHDL_LIST_SIZE; uiLoop++) { if( m_pFileHdlList[ uiLoop].pFileHdl) { if( m_pFileHdlList[ uiLoop].bDirty) { (void)m_pFileHdlList[ uiLoop].pFileHdl->flush(); } m_pFileHdlList[ uiLoop].pFileHdl->closeFile(); m_pFileHdlList[ uiLoop].pFileHdl->Release(); f_memset( &m_pFileHdlList[ uiLoop], 0, sizeof( FH_INFO)); } } m_ui64EOF = 0; m_bOpen = FALSE; if( bDelete) { if( RC_OK( pFileSystem->openDir( m_szPath, "*.64", &pDir))) { // Remove all data files for( rc = pDir->next(); !RC_BAD( rc) ; rc = pDir->next()) { pDir->currentItemPath( szTmpPath); f_assert( f_strstr( szTmpPath, ".64") != 0); (void)pFileSystem->deleteFile( szTmpPath); } pDir->Release(); pDir = NULL; } // Release and delete the lock file (void)releaseLockFile( m_szPath, TRUE); // Remove the directory (void)pFileSystem->removeDir( m_szPath); } else { (void)releaseLockFile( m_szPath, FALSE); } }
/**************************************************************************** Desc : Return the status of the index. ****************************************************************************/ FLMEXP RCODE FLMAPI FlmIndexStatus( HFDB hDb, FLMUINT uiIndexNum, FINDEX_STATUS * pIndexStatus) { RCODE rc = FERR_OK; FLMBOOL bStartedAutoTrans = FALSE; FLMUINT uiLastDrnIndexed; FDB * pDb = (FDB *)hDb; F_BKGND_IX * pBackgroundIx; FLMBOOL bSuspended; FLMBOOL bMutexLocked = FALSE; flmAssert( pIndexStatus != NULL); if( IsInCSMode( hDb)) { fdbInitCS( pDb); rc = flmIndexStatusCS( pDb, uiIndexNum, pIndexStatus); goto Exit; } if( RC_BAD( rc = fdbInit( (FDB *)hDb, FLM_READ_TRANS, FDB_TRANS_GOING_OK, 0, &bStartedAutoTrans))) { goto Exit; } f_mutexLock( gv_FlmSysData.hShareMutex); bMutexLocked = TRUE; pBackgroundIx = flmBackgroundIndexGet( pDb->pFile, uiIndexNum, TRUE); if( pBackgroundIx) { f_memcpy( pIndexStatus, &pBackgroundIx->indexStatus, sizeof( FINDEX_STATUS)); f_mutexUnlock( gv_FlmSysData.hShareMutex); bMutexLocked = FALSE; flmAssert( pIndexStatus->uiIndexNum == uiIndexNum); } else { IXD * pIxd; FLMBOOL bTrackerIxSuspended; if( RC_BAD( rc = fdictGetIndex( pDb->pDict, pDb->pFile->bInLimitedMode, uiIndexNum,NULL, &pIxd, TRUE))) { goto Exit; } bSuspended = (pIxd->uiFlags & IXD_SUSPENDED) ? TRUE : FALSE; f_mutexUnlock( gv_FlmSysData.hShareMutex); bMutexLocked = FALSE; // Get the index state from the tracker if( RC_BAD( rc = flmGetIxTrackerInfo( pDb, uiIndexNum, NULL, &uiLastDrnIndexed, NULL, &bTrackerIxSuspended))) { if( rc == FERR_NOT_FOUND) { rc = RC_SET( FERR_BAD_IX); } goto Exit; } // Sanity check #ifdef FLM_DEBUG if( pDb->pFile->FileHdr.uiVersionNum >= FLM_FILE_FORMAT_VER_4_51 && bSuspended != bTrackerIxSuspended) { flmAssert( 0); } #endif // Populate the index status structure. f_memset( pIndexStatus, 0, sizeof( FINDEX_STATUS)); pIndexStatus->uiIndexNum = uiIndexNum; pIndexStatus->uiLastRecordIdIndexed = uiLastDrnIndexed; pIndexStatus->bSuspended = bSuspended; } Exit: if( bMutexLocked) { f_mutexUnlock( gv_FlmSysData.hShareMutex); } if( bStartedAutoTrans) { rc = flmEndAutoTrans( pDb, rc); } flmExit( FLM_INDEX_STATUS, pDb, rc); return( rc); }
/**************************************************************************** Desc: Reads data from the file ****************************************************************************/ RCODE F_MultiFileHdl::read( FLMUINT64 ui64Offset, // Offset to begin reading FLMUINT uiLength, // Number of bytes to read void * pvBuffer, // Buffer FLMUINT * puiBytesRead) // [out] Number of bytes read { RCODE rc = NE_FLM_OK; FLMUINT uiFileNum = getFileNum( ui64Offset); FLMUINT uiFileOffset = getFileOffset( ui64Offset); FLMUINT uiTmp; FLMUINT uiTotalBytesRead = 0; FLMUINT uiBytesToRead; FLMUINT uiMaxReadLen; IF_FileHdl * pFileHdl; // Handle the case of a 0-byte read if( !uiLength) { if( ui64Offset >= m_ui64EOF) { rc = RC_SET( NE_FLM_IO_END_OF_FILE); } goto Exit; } // Read the data file(s), moving to new files as needed. for( ;;) { if( ui64Offset >= m_ui64EOF) { rc = RC_SET( NE_FLM_IO_END_OF_FILE); goto Exit; } uiMaxReadLen = m_uiMaxFileSize - uiFileOffset; f_assert( uiMaxReadLen != 0); uiTmp = (uiLength >= uiMaxReadLen ? uiMaxReadLen : uiLength); uiBytesToRead = (((FLMUINT64)uiTmp > (FLMUINT64)(m_ui64EOF - ui64Offset)) ? (FLMUINT)(m_ui64EOF - ui64Offset) : uiTmp); if( RC_BAD( rc = getFileHdl( uiFileNum, FALSE, &pFileHdl))) { if( rc == NE_FLM_IO_PATH_NOT_FOUND) { // Handle the case of a sparse file by filling the unread // portion of the buffer with zeros. f_memset( pvBuffer, 0, uiBytesToRead); uiTmp = uiBytesToRead; rc = NE_FLM_OK; } else { goto Exit; } } else { if( RC_BAD( rc = pFileHdl->read( uiFileOffset, uiBytesToRead, pvBuffer, &uiTmp))) { if( rc == NE_FLM_IO_END_OF_FILE) { // Handle the case of a sparse file by filling the unread // portion of the buffer with zeros. f_memset( &(((FLMBYTE *)(pvBuffer))[ uiTmp]), 0, (FLMUINT)(uiBytesToRead - uiTmp)); uiTmp = uiBytesToRead; rc = NE_FLM_OK; } else { goto Exit; } } } uiTotalBytesRead += uiTmp; uiLength -= uiTmp; if( !uiLength) { break; } // Set up for next read pvBuffer = ((FLMBYTE *)pvBuffer) + uiTmp; ui64Offset += uiTmp; uiFileNum = getFileNum( ui64Offset); uiFileOffset = getFileOffset( ui64Offset); } Exit: *puiBytesRead = uiTotalBytesRead; return( rc); }
/**************************************************************************** Desc: This routine links a request into a notification list and then waits to be notified that the event has occurred. The mutex is assumed to protect the notify list. ****************************************************************************/ RCODE FLMAPI f_notifyWait( F_MUTEX hMutex, F_SEM hSem, void * pvData, F_NOTIFY_LIST_ITEM ** ppNotifyList) { RCODE rc = NE_FLM_OK; RCODE tmpRc; F_NOTIFY_LIST_ITEM stackNotify; F_NOTIFY_LIST_ITEM * pNotify = &stackNotify; f_assertMutexLocked( hMutex); f_assert( pNotify != *ppNotifyList); f_memset( &stackNotify, 0, sizeof( F_NOTIFY_LIST_ITEM)); pNotify->uiThreadId = f_threadId(); pNotify->hSem = F_SEM_NULL; if( hSem == F_SEM_NULL) { if( RC_BAD( rc = f_semCreate( &pNotify->hSem))) { goto Exit; } } else { pNotify->hSem = hSem; } pNotify->pRc = &rc; pNotify->pvData = pvData; pNotify->pNext = *ppNotifyList; *ppNotifyList = pNotify; // Unlock the mutex and wait on the semaphore f_mutexUnlock( hMutex); if( RC_BAD( tmpRc = f_semWait( pNotify->hSem, F_WAITFOREVER))) { rc = tmpRc; } // Free the semaphore if( hSem != pNotify->hSem) { f_semDestroy( &pNotify->hSem); } // Relock the mutex f_mutexLock( hMutex); Exit: 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); }