Esempio n. 1
0
/****************************************************************************
Desc : Suspend the selected index from doing any key updates on records
		 that are equal or higher than the next record ID value
		 in the container that the index references.  If the index is offline
		 then the background process will be suspended.  If the index is
		 online then it will be suspended.  If the index is already 
		 suspended FERR_OK will be returned.  A suspended index is not
		 persistant if the database goes down.  
Notes: An update transaction will be started if necessary.
****************************************************************************/
FLMEXP RCODE FLMAPI FlmIndexSuspend(
	HFDB			hDb,
	FLMUINT		uiIndexNum)
{
	RCODE			rc = FERR_OK;
	FDB *			pDb = (FDB *)hDb;
	IXD *			pIxd;
	FLMUINT		uiHighestRecId;
	FLMUINT		uiContainerNum;
	FLMBOOL		bSuspended;
	FLMBOOL		bStartedTrans = FALSE;
	LFILE *		pLFile;

	if( IsInCSMode( hDb))
	{
		fdbInitCS( pDb);

		CS_CONTEXT *		pCSContext = pDb->pCSContext;
		FCL_WIRE				Wire( pCSContext, pDb);

		if( !pCSContext->bConnectionGood)
		{
			rc = RC_SET( FERR_BAD_SERVER_CONNECTION);
			goto Transmission_Error;
		}

		if( RC_BAD( rc = Wire.sendOp(
			FCS_OPCLASS_INDEX, FCS_OP_INDEX_SUSPEND)))
		{
			goto Exit;
		}

		if (RC_BAD( rc = Wire.sendNumber( WIRE_VALUE_INDEX_ID, uiIndexNum)))
		{
			goto Transmission_Error;
		}

		if( RC_BAD( rc = Wire.sendTerminate()))
		{
			goto Transmission_Error;
		}

		// Read the response
	
		if (RC_BAD( rc = Wire.read()))
		{
			goto Transmission_Error;
		}

		if( RC_BAD( rc = Wire.getRCode()))
		{
			goto Exit;
		}

		goto Exit;

Transmission_Error:
		pCSContext->bConnectionGood = FALSE;
		goto Exit;
	}

	if (RC_BAD( rc = fdbInit( pDb, FLM_UPDATE_TRANS,
		FDB_TRANS_GOING_OK, FLM_AUTO_TRANS | FLM_NO_TIMEOUT, &bStartedTrans)))
	{
		goto Exit;
	}

	// See if the index is valid

	if( RC_BAD( rc = fdictGetIndex(
		pDb->pDict,
		pDb->pFile->bInLimitedMode,
		uiIndexNum, NULL, &pIxd, TRUE)))
	{
		goto Exit;
	}

	if( pIxd->uiFlags & IXD_UNIQUE)
	{
		// Can't suspend unique indexes
		rc = RC_SET( FERR_ILLEGAL_OP);
		goto Exit;
	}

	if( pIxd->uiFlags & IXD_SUSPENDED)
	{
		// Index is already suspended.
		goto Exit;
	}

	// Get the current index info from the tracker

	if( RC_BAD( rc = flmGetIxTrackerInfo( pDb,
		uiIndexNum, &uiContainerNum, &uiHighestRecId, NULL, &bSuspended)))
	{
		goto Exit;
	}
	flmAssert( !bSuspended);

	// Get information about the container(s) being indexed

	if( !(pIxd->uiFlags & IXD_OFFLINE))
	{
		if ((uiContainerNum = pIxd->uiContainerNum) == 0)
		{
			// The index was on-line and up-to-date.  For an index that
			// crosses all containers, we will suspend on the highest DRN of
			// the FLM_DATA_CONTAINER.

			uiContainerNum = FLM_DATA_CONTAINER;
		}

		if( RC_BAD( rc = fdictGetContainer( pDb->pDict, 
			uiContainerNum, &pLFile)))
		{
			goto Exit;
		}

		uiHighestRecId = 0;
		if( RC_BAD( rc = FSGetNextDrn( pDb, pLFile, FALSE, &uiHighestRecId)))
		{
			goto Exit;
		}

		// Decrement uiHighestRecId by 1 to correctly reflect the
		// last record that was indexed.

		flmAssert( uiHighestRecId != 0);
		uiHighestRecId--;
	}

	// There may be a background thread still assigned to the
	// index even though the index may be "on-line."  This is because
	// the background thread may have just commited a transaction that
	// transitioned the index from off-line to on-line, but the thread
	// has not yet exited (even though it will not do any more work
	// to update the index).  We want to wait for the thread to terminate
	// before our transaction is allowed to commit.  This is so that if
	// we immediately call resume, it won't find the yet-to-terminate
	// thread still running in the background.

	if( !(pDb->uiFlags & FDB_REPLAYING_RFL))
	{
		if( RC_BAD( rc = flmAddToStopList( pDb, uiIndexNum)))
		{
			goto Exit;
		}
	}

	flmAssert( uiContainerNum != 0xFFFFFFFF);

	if( RC_BAD( rc = flmSetIxTrackerInfo( pDb, 
		uiIndexNum, uiContainerNum, uiHighestRecId, 
		TRANS_ID_OFFLINE, TRUE)))
	{
		goto Exit;
	}

	// Create a new dictionary

	if( !(pDb->uiFlags & FDB_UPDATED_DICTIONARY))
	{
		if( RC_BAD( rc = fdictCloneDict( pDb)))
		{
			goto Exit;
		}

		// Get a pointer to the new IXD

		if( RC_BAD( rc = fdictGetIndex( pDb->pDict,
			pDb->pFile->bInLimitedMode,
			uiIndexNum, NULL, &pIxd, TRUE)))
		{
			goto Exit;
		}
	}

	// Update the IXDs flags so that the current update
	// transaction will see the correct state of the index.
	// Old read transactions will continue to use a prior
	// version of the dictionary.

	pIxd->uiFlags |= (IXD_SUSPENDED | IXD_OFFLINE);

	// Log the suspend packet to the RFL

	if( RC_BAD( rc = pDb->pFile->pRfl->logIndexSuspendOrResume( 
		uiIndexNum, RFL_INDEX_SUSPEND_PACKET)))
	{
		goto Exit;
	}

Exit:

	if( bStartedTrans)
	{
		rc = flmEndAutoTrans( pDb, rc);
	}

	flmExit( FLM_INDEX_SUSPEND, pDb, rc);
	return( rc);
}
Esempio n. 2
0
/****************************************************************************
Desc : Deletes a record from a container.
Notes: If an index definition record or a container definition record is
		 deleted from the dictionary container, the index B-TREE container or
		 container B-TREE will be deleted automatically when the transaction
		 commits.  Field definition records can only be deleted from the
		 dictionary using this routine if the field is not in use.  For more
		 information on deletion of field definitions, see the Dictionary Syntax
		 document.
****************************************************************************/
FLMEXP RCODE FLMAPI FlmRecordDelete(
	HFDB	 		hDb,
	FLMUINT		uiContainer,
	FLMUINT		uiDrn,
	FLMUINT		uiAutoTrans
	)
{
	RCODE				rc = FERR_OK;
	LFILE *			pLFile;
	FDB *				pDb = (FDB *)hDb;
	FLMBOOL			bStartedAutoTrans;
	FlmRecord *		pOldRecord;
	FlmRecord **	ppOldRecord;
	DB_STATS *		pDbStats = NULL;
	F_TMSTAMP		StartTime;

	if( uiContainer == FLM_TRACKER_CONTAINER)
	{
		rc = RC_SET( FERR_ILLEGAL_OP);
		goto Exit;
	}

	if (IsInCSMode( hDb))
	{
		fdbInitCS( pDb);
		rc = flmDoUpdateCS( pDb, FCS_OP_RECORD_DELETE, uiContainer,
									&uiDrn, NULL, uiAutoTrans);
		goto ExitCS;
	}

	bStartedAutoTrans = FALSE;
	pOldRecord = NULL;
	ppOldRecord = NULL;

	if( RC_BAD( rc = fdbInit( pDb, FLM_UPDATE_TRANS, FDB_TRANS_GOING_OK,
											uiAutoTrans, &bStartedAutoTrans)))
	{
		goto Exit;
	}

	if( (pDbStats = pDb->pDbStats) != NULL)
	{
		f_timeGetTimeStamp( &StartTime);
	}

	if( !uiDrn || uiDrn == (FLMUINT) DRN_LAST_MARKER)
	{
		rc = RC_SET( FERR_BAD_DRN);
		goto Exit;
	}

	if( RC_BAD(rc = fdictGetContainer( pDb->pDict, uiContainer, &pLFile)))
	{
		goto Exit;
	}

	if( gv_FlmSysData.UpdateEvents.pEventCBList)
	{
		// Do not have flmDeleteRecord fetch the old version of the record
		// unless an event callback is registered.
		
		ppOldRecord = &pOldRecord;
	}
	
	// NOTE: pLFile should NOT be used after this call, because flmDeleteRecord
	// could actually change its position in memory due to field changes.

	if (RC_BAD( rc = flmDeleteRecord( pDb, pLFile, uiDrn, ppOldRecord, FALSE)))
	{
		goto Exit;
	}

Exit:

	if( RC_OK( rc))
	{
		rc = pDb->pFile->pRfl->logUpdate( uiContainer, uiDrn, 
			uiAutoTrans, NULL, NULL);
	}

	if( pDbStats)
	{
		flmAddElapTime( &StartTime, &pDbStats->RecordDeletes.ui64ElapMilli);
		pDbStats->RecordDeletes.ui64Count++;
		pDbStats->bHaveStats = TRUE;
	}

	if( gv_FlmSysData.UpdateEvents.pEventCBList)
	{
		flmUpdEventCallback( pDb, F_EVENT_DELETE_RECORD, hDb, rc, uiDrn,
								uiContainer, NULL, pOldRecord);
	}

#ifdef FLM_DBG_LOG
	flmDbgLogUpdate( pDb->pFile->uiFFileId, 
		pDb->LogHdr.uiCurrTransID, uiContainer, uiDrn, rc, "RDel");
#endif

	// If started an automatic transaction, end it.

	if( bStartedAutoTrans)
	{
		rc = flmEndAutoTrans( pDb, rc);
	}

	if( pOldRecord)
	{
		pOldRecord->Release();
		pOldRecord = NULL;
	}

ExitCS:

	flmExit( FLM_RECORD_DELETE, pDb, rc);

	return( rc);
}
Esempio n. 3
0
/************************************************************************
Desc : Deletes a record from a container.
Notes: This is the internal call that corresponds to FlmRecordDelete.
		 It may also be called by the database checking code when
		 repairing an index.
*************************************************************************/
RCODE	flmDeleteRecord(
	FDB *				pDb,					// Operation context
	LFILE *			pLFile,				// LFILE of container to delete from.
	FLMUINT			uiDrn,				// DRN of the record to be deleted.
	FlmRecord **	ppOldRecord,		// Returns old record, if not null.
	FLMBOOL			bMissingKeysOK		// Is it OK for keys to be missing in the
												// indexes that are to be updated?
												// should we report when index entries
												// aren't found? TRUE=don't report,
												// FALSE=do report.
	)
{
	RCODE				rc = FERR_OK;
	FlmRecord *		pOldRecord = NULL;
	FLMUINT			uiContainer = pLFile->uiLfNum;
	FLMUINT			uiAction;
	FLMBOOL			bHadUniqueKeys;
	FLMBOOL			bProcessedKeys = FALSE;

	if( pDb->uiFlags & FDB_COMMITTING_TRANS)
	{
		flmAssert( 0);
		rc = RC_SET( FERR_ILLEGAL_TRANS_OP);
		goto Exit;
	}

	if( RC_BAD( rc = KrefCntrlCheck( pDb)))
	{
		goto Exit;
	}

	if( RC_BAD( rc = flmRcaRetrieveRec( pDb, NULL,
		uiContainer, uiDrn, FALSE, NULL, NULL, &pOldRecord)))
	{
		if (rc != FERR_NOT_FOUND)
		{
			goto Exit;
		}
		
		if( RC_BAD( rc = FSReadRecord( pDb, pLFile, uiDrn, 
			&pOldRecord, NULL, NULL)))
		{
			goto Exit;
		}
	}

	if( uiContainer == FLM_LOCAL_DICT_CONTAINER )
	{
		if( RC_OK( rc = flmLFileDictUpdate( pDb, &pLFile, 
			&uiDrn, NULL, pOldRecord, FALSE, FALSE, NULL)))
		{
			rc = flmRcaRemoveRec( pDb, uiContainer, uiDrn);
		}
		
		goto Exit;
	}

	// First read the record, then delete it's keys and then it.

	uiAction = (FLMUINT)((bMissingKeysOK)
							  ? (FLMUINT)(KREF_DEL_KEYS | KREF_MISSING_KEYS_OK)
							  : (FLMUINT)(KREF_DEL_KEYS));
	bProcessedKeys = TRUE;
	bHadUniqueKeys = FALSE;
	if( RC_BAD(rc = flmProcessRecFlds( pDb, NULL, uiContainer,
													uiDrn, pOldRecord, uiAction,
													TRUE,
													&bHadUniqueKeys)))
	{
		goto Exit;
	}
	
	// NOTE: The LFile table may have changed locations if the dictionary 
	// was updated because of a change in a field state
	
	if( RC_BAD( rc = fdictGetContainer( pDb->pDict, uiContainer, &pLFile)))
	{
		goto Exit;
	}
	
	if( RC_BAD( rc = KYProcessDupKeys( pDb, bHadUniqueKeys)))
	{
		goto Exit;
	}
	
	if( RC_BAD( rc = FSRecUpdate( pDb, pLFile, NULL, uiDrn, REC_UPD_DELETE)))
	{
		goto Exit;
	}

	// Remove the record from cache

	if( RC_BAD( rc = flmRcaRemoveRec( pDb, uiContainer, uiDrn)))
	{
		(void)FSRecUpdate( pDb, pLFile, pOldRecord, uiDrn, REC_UPD_ADD);
		goto Exit;
	}

	// Don't make this call until we are sure of success - because we want to
	// be able to back things out of KREF table.

	KYFinishCurrentRecord( pDb);

Exit:

	if (RC_BAD( rc) && bProcessedKeys)
	{
		KYAbortCurrentRecord( pDb);
	}

	if( ppOldRecord)
	{
		*ppOldRecord = pOldRecord;
	}
	else if( pOldRecord)
	{
		pOldRecord->Release();
	}

	// Add the BLOB entries to the blob list.
	
	rc = FB_OperationEnd( pDb, rc);
	return( rc);
}
Esempio n. 4
0
/****************************************************************************
Desc : Modifies a record within a container.
Notes: If an index definition record is modified in the dictionary container,
		 the index B-TREE will be deleted and rebuilt automatically when the
		 transaction commits.  If an index definition record is changed into
		 a field definition record or a container definition record, the index
		 will be automatically deleted when the transaction commits.  When a
		 non-unique index is changed to a unique index, or the fields in a
		 unique index are changed, FLAIM needs to verify that each key in the
		 proposed index is indeed a unique key.  However, this verification
		 does NOT occur until the dictionary transaction commits and the
		 index is actually rebuilt.  If FLAIM discovers that the keys in the
		 proposed index are not unique, the transaction commit will fail and
		 return FERR_NOT_UNIQUE.

		 If a container definition record is changed into a field definition
		 record, the container will be deleted automatically when the
		 transaction commits.  If a container definition record is changed
		 into an index definition record, the container will be automatically
		 deleted and the index will be automatically built when the transaction
		 commits.

		 Only the name and state of field definition records can be modified.
		 Changing a field type or changing a field definition record into an
		 index definition record is not allowed.  For information on changing
		 the state of a field, see the Dictionary Syntax document.
****************************************************************************/
FLMEXP RCODE FLMAPI FlmRecordModify(
	HFDB		   hDb,
	FLMUINT		uiContainer,
	FLMUINT		uiDrn,
	FlmRecord *	pRecord,
	FLMUINT		uiAutoTrans
	)
{
	RCODE			rc = FERR_OK;
	RCODE			rc1;
	FDB *			pDb = (FDB *)hDb;
	FlmRecord *	pOldRecord = NULL;
	LFILE *		pLFile;
	FLMBOOL		bStartedAutoTrans = FALSE;
	FLMBOOL		bProcessedKeys = FALSE;
	FLMBOOL		bLogCompleteIndexSet = FALSE;
	FLMBOOL		bHadUniqueKeys;
	DB_STATS *	pDbStats = NULL;
	F_TMSTAMP	StartTime;

	if( uiContainer == FLM_TRACKER_CONTAINER)
	{
		rc = RC_SET( FERR_ILLEGAL_OP);
		goto Exit;
	}

	if (IsInCSMode( hDb))
	{
		fdbInitCS( pDb);
		rc = flmDoUpdateCS( pDb, FCS_OP_RECORD_MODIFY, uiContainer,
									&uiDrn, pRecord, uiAutoTrans);
		goto ExitCS;
	}

	if( RC_BAD( rc = fdbInit( pDb, FLM_UPDATE_TRANS,
			FDB_TRANS_GOING_OK, uiAutoTrans, &bStartedAutoTrans)))
	{
		goto Exit;
	}

	if( pDb->uiFlags & FDB_COMMITTING_TRANS)
	{
		flmAssert( 0);
		rc = RC_SET( FERR_ILLEGAL_TRANS_OP);
		goto Exit;
	}

	if ((pDbStats = pDb->pDbStats) != NULL)
	{
		f_timeGetTimeStamp( &StartTime);
	}

	// Make sure we have a valid record

	if( !pRecord)
	{
		rc = RC_SET( FERR_INVALID_PARM);
		goto Exit;
	}

	// We cannot modify a record that is marked read-only.

	if( pRecord->isReadOnly())
	{
		flmAssert( 0);
		rc = RC_SET( FERR_ILLEGAL_OP);
		goto Exit;
	}

	if( !uiDrn || (uiDrn == (FLMUINT) DRN_LAST_MARKER))
	{
		rc = RC_SET( FERR_BAD_DRN);
		goto Exit;
	}

	if( RC_BAD( rc = fdictGetContainer( pDb->pDict, uiContainer, &pLFile)))
	{
		goto Exit;
	}

	if( RC_BAD( rc = KrefCntrlCheck( pDb)))
	{
		goto Exit;
	}

	// DICTIONARY RECORD MODIFY

	if( uiContainer == FLM_LOCAL_DICT_CONTAINER) 
	{
		if( RC_BAD( rc = flmRcaRetrieveRec( pDb, NULL,
			uiContainer, uiDrn, FALSE, NULL, NULL, &pOldRecord)))
		{

			// NOTE: Deliberately not reading in to cache if not found.

			if (rc != FERR_NOT_FOUND)
			{
				goto Exit;
			}
			if( RC_BAD( rc = FSReadRecord( pDb, pLFile, uiDrn, &pOldRecord, NULL, NULL)))
			{
				goto Exit;
			}
		}

		// Sanity check -- make sure that the new and old records point at
		// different objects.

		flmAssert( pRecord != pOldRecord);

		if( RC_BAD( rc = flmLFileDictUpdate( pDb, &pLFile, &uiDrn, 
				pRecord, pOldRecord,
				(uiAutoTrans & FLM_DO_IN_BACKGROUND) ? TRUE : FALSE, 
				(uiAutoTrans & FLM_SUSPENDED) ? TRUE : FALSE,
				&bLogCompleteIndexSet)))
		{
			goto Exit;
		}

		pRecord->setID( uiDrn);
		pRecord->setContainerID( uiContainer);
		if( RC_BAD( rc = flmRcaInsertRec( pDb, pLFile, uiDrn, pRecord)))
		{
			goto Exit;
		}

		goto Exit;
	}

	// First read the old record, and delete it's keys.
	// To do this we need to be able to read any purged fields and delete any
	// keys they build.

	if( RC_BAD( rc = flmRcaRetrieveRec( pDb, NULL,
		uiContainer, uiDrn, FALSE, NULL, NULL, &pOldRecord)))
	{

		// NOTE: Deliberately not reading in to cache if not found.

		if (rc != FERR_NOT_FOUND)
		{
			goto Exit;
		}
		
		if( RC_BAD( rc = FSReadRecord( pDb, pLFile, uiDrn, &pOldRecord, NULL, NULL)))
		{
			goto Exit;
		}
	}

	// Sanity check -- make sure that the new and old records point at
	// different objects.

	flmAssert( pRecord != pOldRecord);

	bProcessedKeys = TRUE;
	bHadUniqueKeys = FALSE;
	if( RC_BAD( rc = flmProcessRecFlds( pDb, NULL, uiContainer, uiDrn, pOldRecord,
													KREF_DEL_KEYS | KREF_IN_MODIFY,
													TRUE,		// Purged Field OK
													&bHadUniqueKeys)))
	{
		goto Exit;
	}

	if( RC_BAD( rc = flmProcessRecFlds( pDb, NULL, uiContainer, uiDrn, pRecord,
													KREF_ADD_KEYS | KREF_IN_MODIFY,
													FALSE,
													&bHadUniqueKeys)))
	{
		goto Exit;
	}
	
	// NOTE: The LFile table may have changed locations if the dictionary 
	// was update because of a change in a field state
	
	if( RC_BAD( rc = fdictGetContainer( pDb->pDict, uiContainer, &pLFile)))
	{
		goto Exit;
	}
	
	if( RC_BAD( rc = FSRecUpdate( pDb, pLFile, pRecord, uiDrn, REC_UPD_MODIFY)))
	{
		 goto Exit;
	}

	// Finish up the keys adding the unique keys to the indexes.

	if( RC_BAD( rc = KYProcessDupKeys( pDb, bHadUniqueKeys)))
	{
		// Undo the record that was modified - replace with original record.
		if( RC_BAD( rc1 = FSRecUpdate( pDb, pLFile, 
			pOldRecord, uiDrn, REC_UPD_MODIFY)))
		{
			rc = (rc == FERR_NOT_UNIQUE) ? rc1 : rc;
		}
		goto Exit;
	}

	// Insert record into cache
	
	pRecord->setID( uiDrn);
	pRecord->setContainerID( uiContainer);
	
	if( RC_BAD( rc = flmRcaInsertRec( pDb, pLFile, uiDrn, pRecord)))
	{
		if ( rc != FERR_MEM)
		{
			flmAssert( 0);
		}
		
		// Undo the record that was modified - replace with original record.
		
		FSRecUpdate( pDb, pLFile, pOldRecord, uiDrn, REC_UPD_MODIFY);
		goto Exit;
	}

	// Don't make this call until we are sure of success - because we want to
	// be able to back things out of KREF table.

	KYFinishCurrentRecord( pDb);

Exit:

	if( RC_BAD( rc) && bProcessedKeys)
	{
		KYAbortCurrentRecord( pDb);
	}

	// Add the BLOB entries to the blob list.
	
	rc = FB_OperationEnd( pDb, rc);

	if( RC_OK( rc))
	{
		if( RC_OK( rc = pDb->pFile->pRfl->logUpdate( 
				uiContainer, uiDrn, uiAutoTrans, pOldRecord, pRecord)) && 
			 bLogCompleteIndexSet &&
			 pDb->pFile->FileHdr.uiVersionNum <= FLM_FILE_FORMAT_VER_4_51)
		{
			// Log the fact that we indexed everything so the redo will also
			// index all data records in the container.

			rc = pDb->pFile->pRfl->logIndexSet( uiDrn, 0, 1, 0xFFFFFFFF);
		}
	}

	if( pDbStats)
	{
		flmAddElapTime( &StartTime, &pDbStats->RecordModifies.ui64ElapMilli);
		pDbStats->RecordModifies.ui64Count++;
		pDbStats->bHaveStats = TRUE;
	}

	if( gv_FlmSysData.UpdateEvents.pEventCBList)
	{
		flmUpdEventCallback( pDb, F_EVENT_MODIFY_RECORD, hDb, rc, uiDrn,
								uiContainer, pRecord, pOldRecord);
	}

#ifdef FLM_DBG_LOG
	flmDbgLogUpdate( pDb->pFile->uiFFileId, 
		pDb->LogHdr.uiCurrTransID, uiContainer, uiDrn, rc, "RMod");
#endif

	// If started an automatic transaction, end it.

	if( bStartedAutoTrans)
	{
		rc = flmEndAutoTrans( pDb, rc);
	}

	if( pOldRecord)
	{
		pOldRecord->Release();
		pOldRecord = NULL;
	}

ExitCS:

	flmExit( FLM_RECORD_MODIFY, pDb, rc);
	return( rc);
}
Esempio n. 5
0
/****************************************************************************
Desc:		Internal interface routine for database add operation.
			Must be in a valid transaction.
Note:		Internal name is used so that later we can call this within FLAIM.
****************************************************************************/
RCODE	flmAddRecord(
	FDB *	 		pDb,
	LFILE *		pLFile,
	FLMUINT *	puiDrn,						// Record Number to set AND return.
	FlmRecord * pRecord,						// Record to add, must NOT be NULL.
	FLMBOOL		bBatchProcessing,			// Set to TRUE if called by REBUILD.
	FLMBOOL		bDoInBackground,
	FLMBOOL		bCreateSuspended,
	FLMBOOL		bKeepInCache,
	FLMBOOL *	pbLogCompleteIndexSet)
{
	RCODE			rc = FERR_OK;
	FLMUINT		uiDrn = 0;
	FLMBOOL		bProcessedKeys = FALSE;
	FLMUINT		uiLfNum = pLFile->uiLfNum;
	FLMUINT		uiAddAppendFlags = REC_UPD_ADD;
	FLMBOOL		bHadUniqueKeys;

	if( puiDrn)
	{
		uiDrn = *puiDrn;
	}

	if( pDb->uiFlags & FDB_COMMITTING_TRANS)
	{
		flmAssert( 0);
		rc = RC_SET( FERR_ILLEGAL_TRANS_OP);
		goto Exit;
	}

	// Assert that the record is not read-only

	flmAssert( !pRecord->isReadOnly());

	// Set up for indexing.

	if( RC_BAD( rc = KrefCntrlCheck( pDb)))
	{
		goto Exit;
	}

	if( !pRecord)
	{
		rc = RC_SET( FERR_NULL_RECORD);
		goto Exit;
	}

	// If this is a dictionary record then one routine takes care of it.

	if( pLFile->uiLfNum == FLM_LOCAL_DICT_CONTAINER)
	{
		if( RC_OK( rc = flmLFileDictUpdate( pDb, &pLFile, &uiDrn,
					pRecord, NULL, bDoInBackground, bCreateSuspended,
					pbLogCompleteIndexSet)))
		{
			if( puiDrn)
			{
				*puiDrn = uiDrn;
			}
		}

		goto Exit;
	}
	else
	{
		if( !uiDrn || uiDrn == DRN_LAST_MARKER)
		{
			if( RC_BAD( rc = FSGetNextDrn( pDb, pLFile, FALSE, &uiDrn)))
			{
#ifdef FLM_DBG_LOG
				uiDrn = 0;
#endif
				goto Exit;
			}
			
			uiAddAppendFlags |= REC_UPD_NEW_RECORD;
		}
	}

	// Add the records keys, and then the record.  NOTE: If the bBatchProcessing
	// flag is set to TRUE, we are being called as part of a rebuild.  In this
	// case, we do NOT want BLOBs to be reprocessed.  Also, we do not want
	// the QF job list to be generated (it could get very large - and all of
	// the entries are stored in a single record).  So we set the
	// KREF_INDEXING_ONLY flag.  This flag will prohibit the processing of
	// BLOB data.  Also, it will prohibit constructing a QF job list.  Instead
	// of the QF job list, the entries will be fed directly to QuickFinder and
	// then processed when KYKeysCommit is called.

	bProcessedKeys = TRUE;
	bHadUniqueKeys = FALSE;
	if( RC_BAD( rc = flmProcessRecFlds( pDb, NULL, pLFile->uiLfNum, uiDrn, pRecord,
										(FLMUINT)((bBatchProcessing)
											? (KREF_ADD_KEYS | KREF_INDEXING_ONLY)
											: KREF_ADD_KEYS),
											FALSE, &bHadUniqueKeys)))
	{
		goto Exit;
	}
											
	// NOTE: The LFile table may have changed locations if the dictionary 
	// was update because of a change in a field state
	
	if( RC_BAD( rc = fdictGetContainer( pDb->pDict, uiLfNum, &pLFile)))
	{
		goto Exit;
	}

	if( RC_BAD(	rc = FSRecUpdate( pDb, pLFile, pRecord,
											uiDrn, uiAddAppendFlags)))
	{
		goto Exit;
	}

	if( puiDrn)
	{
		*puiDrn = uiDrn;
	}

	// Sort and check keys for uniqueness.
	
	if( RC_BAD( rc = KYProcessDupKeys( pDb, bHadUniqueKeys)))
	{
		// Remove the record that was added because of the error.

		RCODE		rc1 = FSRecUpdate( pDb, pLFile, NULL, uiDrn, REC_UPD_DELETE);
		if( RC_BAD(rc1))
		{
			rc = (rc == FERR_NOT_UNIQUE) ? rc1 : rc;
		}
		goto Exit;
	}

	// Insert record into cache

	pRecord->setID( uiDrn);
	pRecord->setContainerID( pLFile->uiLfNum);
	if (bKeepInCache)
	{
		if( RC_BAD( rc = flmRcaInsertRec( pDb, pLFile, uiDrn, pRecord)))
		{
			// Remove the record that was added because of the error.

			FSRecUpdate( pDb, pLFile, NULL, uiDrn, REC_UPD_DELETE);
			goto Exit;
		}
	}

	// Don't make this call until we are sure of success - because we want to
	// be able to back things out of KREF table.

	KYFinishCurrentRecord( pDb);

Exit:

	if( RC_BAD( rc) && bProcessedKeys)
	{
		KYAbortCurrentRecord( pDb);
	}
	
#ifdef FLM_DBG_LOG
	flmDbgLogUpdate( pDb->pFile->uiFFileId, pDb->LogHdr.uiCurrTransID, 
		uiLfNum, uiDrn, rc, "RAdd");
#endif

	return( rc);
}
Esempio n. 6
0
/****************************************************************************
Desc : Adds a record to a container.
Notes: If an index definition record is added to the dictionary container,
		 the index will be built automatically when the transaction commits.
		 When a unique index is added to the database, FLAIM needs to verify
		 that each key in the proposed index is indeed a unique key.  However,
		 this verification does NOT occur until the dictionary transaction
		 commits and the index is actually built.  If FLAIM discovers that the
		 keys in an index are not unique, the transaction commit will fail and
		 return an error.
****************************************************************************/
FLMEXP RCODE FLMAPI FlmRecordAdd(
	HFDB			hDb,
	FLMUINT		uiContainer,
	FLMUINT *	puiDrn,
	FlmRecord *	pRecord,
	FLMUINT		uiAutoTrans)
{
	RCODE			rc = FERR_OK;
	FLMUINT		uiDrn = 0;
	FDB *			pDb = (FDB *)hDb;
	LFILE *		pLFile;
	FLMBOOL		bStartedAutoTrans = FALSE;
	FLMBOOL		bLogCompleteIndexSet = FALSE;
	DB_STATS *	pDbStats = NULL;
	F_TMSTAMP	StartTime;

	if( puiDrn)
	{
		uiDrn = *puiDrn;
	}

	if( uiContainer == FLM_TRACKER_CONTAINER)
	{
		rc = RC_SET( FERR_ILLEGAL_OP);
		goto Exit;
	}

	if (IsInCSMode( hDb))
	{
		fdbInitCS( pDb);
		rc = flmDoUpdateCS( pDb, FCS_OP_RECORD_ADD, uiContainer,
									&uiDrn, pRecord, uiAutoTrans);
		goto ExitCS;
	}

	if( RC_BAD( rc = fdbInit( (FDB *)hDb, FLM_UPDATE_TRANS,
										FDB_TRANS_GOING_OK,
										uiAutoTrans, &bStartedAutoTrans)))
	{
		goto Exit;
	}

	if( (pDbStats = pDb->pDbStats) != NULL)
	{
		f_timeGetTimeStamp( &StartTime);
	}

	// Make sure we have a valid record

	if( !pRecord)
	{
		rc = RC_SET( FERR_INVALID_PARM);
		goto Exit;
	}

	// We cannot add a record that is marked read-only, because it
	// is probably already in the cache under a different record ID.

	if( pRecord->isReadOnly())
	{
		flmAssert( 0);
		rc = RC_SET( FERR_ILLEGAL_OP);
		goto Exit;
	}

	if( RC_BAD( rc = fdictGetContainer( pDb->pDict, uiContainer, &pLFile)))
	{
		goto Exit;
	}

	rc = flmAddRecord( pDb, pLFile, &uiDrn, pRecord, FALSE,
				(uiAutoTrans & FLM_DO_IN_BACKGROUND) ? TRUE : FALSE,
				(uiAutoTrans & FLM_SUSPENDED) ? TRUE : FALSE,
				(FLMBOOL)((uiAutoTrans & FLM_DONT_INSERT_IN_CACHE) ? FALSE : TRUE),
				&bLogCompleteIndexSet);

Exit:

	rc = FB_OperationEnd( pDb, rc);
	if( RC_OK( rc))
	{
		if( RC_OK( rc = pDb->pFile->pRfl->logUpdate( 
				uiContainer, uiDrn, uiAutoTrans, NULL, pRecord)) && 
			 bLogCompleteIndexSet &&
			 pDb->pFile->FileHdr.uiVersionNum <= FLM_FILE_FORMAT_VER_4_51)
		{

			// Log the fact that we indexed everything so the redo will also
			// index all data records in the container.

			rc = pDb->pFile->pRfl->logIndexSet( uiDrn, 0, 1, 0xFFFFFFFF);
		}
	}

	if( pDbStats)
	{
		flmAddElapTime( &StartTime, &pDbStats->RecordAdds.ui64ElapMilli);
		pDbStats->RecordAdds.ui64Count++;
		pDbStats->bHaveStats = TRUE;
	}

	if( gv_FlmSysData.UpdateEvents.pEventCBList)
	{
		flmUpdEventCallback( pDb, F_EVENT_ADD_RECORD, hDb, rc, uiDrn,
								uiContainer, pRecord, NULL);
	}

	// If started an automatic transaction end it.

	if( bStartedAutoTrans)
	{
		rc = flmEndAutoTrans( pDb, rc);
	}

ExitCS:

	if( puiDrn)
	{
		*puiDrn = uiDrn;
	}

	flmExit( FLM_RECORD_ADD, pDb, rc);
	return( rc);
}
Esempio n. 7
0
/****************************************************************************
Desc:		Returns the next DRN that record ADD would return.  The database
			must be in an existing update transaction.
****************************************************************************/
FLMEXP RCODE FLMAPI FlmReserveNextDrn(
	HFDB			hDb,
	FLMUINT		uiContainer,
	FLMUINT *	puiDrnRV)
{
	RCODE			rc;
	FDB *			pDb = (FDB *)hDb;
	LFILE *		pLFile;
	FLMBOOL		bIgnore;
	FLMUINT		uiDrn = 0;

	if (IsInCSMode( hDb))
	{
		fdbInitCS( pDb);

		CS_CONTEXT *	pCSContext = pDb->pCSContext;
		FCL_WIRE			Wire( pCSContext, pDb);

		// Send the request

		if( RC_BAD( rc = Wire.sendOp( 
			FCS_OPCLASS_RECORD, FCS_OP_RESERVE_NEXT_DRN)))
		{
			goto ExitCS;
		}

		if( uiContainer)
		{
			if (RC_BAD( rc = Wire.sendNumber(
				WIRE_VALUE_CONTAINER_ID, uiContainer)))
			{
				goto Transmission_Error;
			}
		}

		if( RC_BAD( rc = Wire.sendTerminate()))
		{
			goto Transmission_Error;
		}

		// Read the response

		if( RC_BAD( rc = Wire.read()))
		{
			goto Transmission_Error;
		}

		if( RC_BAD( rc = Wire.getRCode()))
		{
			goto ExitCS;
		}

		*puiDrnRV = Wire.getDrn();
		goto ExitCS;

Transmission_Error:
		pCSContext->bConnectionGood = FALSE;
		goto ExitCS;
	}

	bIgnore = FALSE;					// Set to shut up compiler.

	if( RC_BAD( rc = fdbInit( pDb, FLM_UPDATE_TRANS,
										FDB_TRANS_GOING_OK,	// byFlags
										0, 						// wAutoTrans
										&bIgnore)))				// bStartedAutoTrans
	{
		goto Exit;
	}

	if( pDb->uiFlags & FDB_COMMITTING_TRANS)
	{
		flmAssert( 0);
		rc = RC_SET( FERR_ILLEGAL_TRANS_OP);
		goto Exit;
	}

	if( RC_BAD( fdictGetContainer( pDb->pDict, uiContainer, &pLFile)))
	{
#ifdef FLM_DBG_LOG
		uiDrn = 0;
#endif
		goto Exit;
	}
	uiDrn = (FLMUINT) 0;					// Must initialize before call.
	if( RC_BAD( rc = FSGetNextDrn( pDb, pLFile, TRUE, &uiDrn)))
	{
#ifdef FLM_DBG_LOG
		uiDrn = 0;
#endif
		goto Exit;
	}

	*puiDrnRV = uiDrn;						// Set return value.

Exit:

	if (RC_OK( rc))
	{
		rc = pDb->pFile->pRfl->logUpdatePacket( 
			RFL_RESERVE_DRN_PACKET, uiContainer, *puiDrnRV, 0);
	}

	if( gv_FlmSysData.UpdateEvents.pEventCBList)
	{
		flmUpdEventCallback( pDb, F_EVENT_RESERVE_DRN, hDb, rc, *puiDrnRV,
								uiContainer, NULL, NULL);
	}

#ifdef FLM_DBG_LOG
	flmDbgLogUpdate( pDb->pFile->uiFFileId, pDb->LogHdr.uiCurrTransID,
			uiContainer, uiDrn, rc, "RDrn");
#endif

ExitCS:

	flmExit( FLM_RESERVE_NEXT_DRN, pDb, rc);

	return( rc);
}
Esempio n. 8
0
/********************************************************************
Desc: ?
*********************************************************************/
FLMINT ViewGetKey( void)
{
	RCODE				rc = FERR_OK;
	FlmRecord *		pKey = NULL;
	void *			pvFld;
	char				Prompt [80];
	FLMUINT			Num;
	FLMUINT			ValEntered;
	FLMUINT			Len;
	char				TempBuf [80];
	FLMUINT			NumFields;
	FLMUINT			i;
	FLMINT			GetOK;
	FLMBYTE			FieldName [80];
	FLMBYTE			FieldType [16];
	FLMINT			KeyEntered = FALSE;
	FLMBYTE			LFH[ LFH_SIZE];
	FLMUINT			FileOffset;
	LFILE *			pLFile = NULL;
	IXD *				pIxd;
	IFD *				pIfd;
	FLMUINT			uiRootBlkAddress;
	FLMBOOL			bTruncated;

	if (!gv_bViewHdrRead)
		ViewReadHdr();

	/* See if we can get dictionary information. */

	ViewGetDictInfo();
	if (gv_bViewHaveDictInfo)
	{

		/* Find the logical file */

		if ((RC_BAD( fdictGetIndex( ((FDB *)gv_hViewDb)->pDict,
				((FDB *)gv_hViewDb)->pFile->bInLimitedMode,
				gv_uiViewSearchLfNum, &pLFile, NULL))) &&
				(RC_BAD( fdictGetContainer( ((FDB *)gv_hViewDb)->pDict, 
				gv_uiViewSearchLfNum, &pLFile))))
		{
			pLFile = NULL;
		}
	}

	/* See if we have a valid logical file */

	if ((gv_uiViewSearchLfNum == FLM_DATA_CONTAINER) ||
			(gv_uiViewSearchLfNum == FLM_DICT_CONTAINER) ||
			(pLFile))
	{

		/* Get the LFH information for the logical file */

		if (!ViewGetLFH( gv_uiViewSearchLfNum, LFH, &FileOffset))
		{
			ViewShowError( "Could not get LFH for logical file");
			return( FALSE);
		}
		uiRootBlkAddress = FB2UD( &LFH [LFH_ROOT_BLK_OFFSET]);

		if (uiRootBlkAddress == 0xFFFFFFFF)
		{
			ViewShowError( "Logical file is empty");
			return( FALSE);
		}
	}
	else
	{
		ViewShowError( "Logical file not defined");
		return( FALSE);
	}

	if ((gv_uiViewSearchLfNum == FLM_DATA_CONTAINER) ||
		 (gv_uiViewSearchLfNum == FLM_DICT_CONTAINER) ||
		 ((pLFile) &&
		  (pLFile->uiLfType == LF_CONTAINER)))
	{
		if (gv_uiViewSearchLfNum == FLM_DICT_CONTAINER)
			f_strcpy( TempBuf, "Enter Dictionary Record Number: ");
		else if (gv_uiViewSearchLfNum == FLM_DATA_CONTAINER)
			f_strcpy( TempBuf, "Enter Data Container Record Number: ");
		else
			f_sprintf( (char *)TempBuf, 
				"Enter Record Number For Container %u: ", 
				(unsigned)gv_uiViewSearchLfNum);
		if ((!ViewGetNum( TempBuf, &Num, FALSE, 4,
										 0xFFFFFFFF, &ValEntered)) ||
				(!ValEntered))
			return( FALSE);
		f_UINT32ToBigEndian( (FLMUINT32)Num, gv_ucViewSearchKey);
		gv_uiViewSearchKeyLen = 4;
		return( TRUE);
	}

	/* At this point, we are dealing with an index. */

	if (gv_uiViewSearchLfNum == FLM_DICT_INDEX)
	{
		FLMUINT	 wTagType = 0;
		FLMUINT	 wElmLen;

		while (!wTagType)
		{
			if ((!ViewEditText( "Enter Type:", 
									TempBuf, sizeof( TempBuf), &ValEntered)) ||
				 (!ValEntered))
				return( FALSE);
			else if ((f_stricmp( TempBuf, "F") == 0) ||
						(f_stricmp( TempBuf, "FIELD") == 0))
			{
				wTagType = FLM_FIELD_TAG;
			}
			else if ((f_stricmp( TempBuf, "I") == 0) ||
						(f_stricmp( TempBuf, "INDEX") == 0))
			{
				wTagType = FLM_INDEX_TAG;
			}
			else if ((f_stricmp( TempBuf, "C") == 0) ||
						(f_stricmp( TempBuf, "CONTAINER") == 0))
			{
				wTagType = FLM_CONTAINER_TAG;
			}
			else if ((f_stricmp( TempBuf, "A") == 0) ||
						(f_stricmp( TempBuf, "AREA") == 0))
			{
				wTagType = FLM_AREA_TAG;
			}
			else
			{
				ViewShowError( "Illegal type, must be F)ield, I)ndex, C)ontainer, R)ecord, or A)rea");
				wTagType = 0;
			}
		}
		gv_ucViewSearchKey [0] = KY_CONTEXT_PREFIX;
		f_UINT16ToBigEndian( (FLMUINT16)wTagType, &gv_ucViewSearchKey [1]);
		gv_uiViewSearchKeyLen += KY_CONTEXT_LEN;
		gv_ucViewSearchKey [gv_uiViewSearchKeyLen++] = COMPOUND_MARKER;

		if (!ViewEditText( "Enter Name:", TempBuf, sizeof( TempBuf), &ValEntered))
			return( FALSE);

		/* Collate the name. */

		wElmLen = MAX_KEY_SIZ - gv_uiViewSearchKeyLen;
		if (RC_BAD( rc = KYCollateValue( &gv_ucViewSearchKey [gv_uiViewSearchKeyLen],
									&wElmLen,
									(const FLMBYTE *)TempBuf,
									(FLMUINT)f_strlen( TempBuf), FLM_TEXT_TYPE,
									MAX_KEY_SIZ,
									NULL, NULL,
									gv_ViewHdrInfo.FileHdr.uiDefaultLanguage,
									FALSE, FALSE, FALSE, &bTruncated)))
		{
			ViewShowRCError( "collating name", rc);
			return( FALSE);
		}
		gv_uiViewSearchKeyLen += wElmLen;
		return( TRUE);
	}
	else if (!pLFile)
	{
		ViewShowError( "Cannot get logical file information");
		return( FALSE);
	}
	else if (RC_BAD( fdictGetIndex( ((FDB *)gv_hViewDb)->pDict,
			((FDB *)gv_hViewDb)->pFile->bInLimitedMode,
			gv_uiViewSearchLfNum, &pLFile, &pIxd)))
	{
		ViewShowError( "Cannot get index field information");
		return( FALSE);
	}
	else
	{
		pIfd = pIxd->pFirstIfd;
		NumFields = pIxd->uiNumFlds;

		if (!(pIfd->uiFlags & IFD_COMPOUND))
		{
			NumFields = 1;
		}

		if( (pKey = f_new FlmRecord) == NULL)
		{
			rc = RC_SET( FERR_MEM);
			ViewShowRCError( "creating key", rc);
			goto Exit_False;
		}

		if (RC_BAD( rc = pKey->insertLast( 0, FLM_KEY_TAG,
										FLM_CONTEXT_TYPE, &pvFld)))
		{
			ViewShowRCError( "adding key tag", rc);
			goto Exit_False;
		}

		/* Ask for data for each field and link into key tree */

		i = 0;
		while (i < NumFields)
		{

			/* Get the name of the field and its type */

			f_sprintf( (char *)FieldName, "FIELD %u", (unsigned)pIfd->uiFldNum);
			switch( IFD_GET_FIELD_TYPE( pIfd))
			{
				case FLM_TEXT_TYPE:
					f_strcpy( (char *)FieldType, "TEXT");
					break;
				case FLM_NUMBER_TYPE:
					f_strcpy( (char *)FieldType, "NUMBER");
					break;
				case FLM_BINARY_TYPE:
					f_strcpy( (char *)FieldType, "BINARY");
					break;
				case FLM_CONTEXT_TYPE:
					f_strcpy( (char *)FieldType, "CONTEXT");
					break;
				default:
					f_sprintf( (char *)FieldType, "UNK: %u!",
						(unsigned)IFD_GET_FIELD_TYPE( pIfd));
					break;
			}
			if (pIfd->uiFlags & IFD_OPTIONAL)
				f_sprintf( (char *)Prompt, "%s (%s-OPTIONAL): ", FieldName, FieldType);
			else
				f_sprintf( (char *)Prompt, "%s (%s-REQUIRED): ", FieldName, FieldType);

			switch( IFD_GET_FIELD_TYPE( pIfd))
			{
				case FLM_TEXT_TYPE:
					if (!ViewEditText( Prompt, TempBuf, sizeof( TempBuf),
								&ValEntered))
						goto Exit_False;
					break;
				case FLM_NUMBER_TYPE:
				case FLM_CONTEXT_TYPE:
					if (!ViewGetNum( Prompt, &Num, FALSE, 4, 0xFFFFFFFF,
									&ValEntered))
						goto Exit_False;
					break;
				case FLM_BINARY_TYPE:
					Len = sizeof( TempBuf);
					if (!ViewEditBinary( Prompt, TempBuf, &Len, &ValEntered))
						goto Exit_False;
					break;
			}
			if (!ValEntered)
			{
				i++;
			}
			else
			{
				FLMUINT	uiDataType;

				/* See if the entered data can be converted to the */
				/* correct type */

				uiDataType = IFD_GET_FIELD_TYPE( pIfd);
				if (RC_BAD( rc = pKey->insertLast( 1, pIfd->uiFldNum,
													uiDataType, &pvFld)))
				{
					ViewShowRCError( "creating field", rc);
				}
				else
				{
					switch( IFD_GET_FIELD_TYPE( pIfd))
					{
						case FLM_TEXT_TYPE:
							rc = pKey->setNative( pvFld, TempBuf);
							break;
						case FLM_NUMBER_TYPE:
							rc = pKey->setUINT( pvFld, Num);
							break;
						case FLM_CONTEXT_TYPE:
							rc = pKey->setRecPointer( pvFld, Num);
							break;
						case FLM_BINARY_TYPE:
							rc = pKey->setBinary( pvFld, TempBuf, Len);
							break;
					}
					if (RC_BAD( rc))
					{
						ViewShowRCError( "putting data in field", rc);
					}
				}
				if (RC_OK(rc))
				{
					i++;
					pIfd++;
					KeyEntered = TRUE;
				}
			}
		}

		// If index is on all containers, prompt for container number.

		if (!pIxd->uiContainerNum)
		{
			f_strcpy( Prompt, "CONTAINER: ");
			if (!ViewGetNum( Prompt, &Num, FALSE, sizeof( Num), 0xFFFF,
									&ValEntered))
			{
				goto Exit_False;
			}
			if (ValEntered)
			{
				pKey->setContainerID( Num);
				KeyEntered = TRUE;
			}
		}

		/* Convert the key to binary format */

		if (!KeyEntered)
			goto Exit_False;

		if ((rc = FlmKeyBuild( gv_hViewDb, gv_uiViewSearchLfNum,
									pKey->getContainerID(), pKey, 0,
									gv_ucViewSearchKey, &gv_uiViewSearchKeyLen)) != FERR_OK)
			ViewShowRCError( "building key", rc);
		else
		{
			GetOK = TRUE;
			goto Exit_GetKey;
		}
	}

Exit_False:
	GetOK = FALSE;
Exit_GetKey:
	if (pKey)
	{
		pKey->Release();
	}
	return( GetOK);
}