Renamed version4 to flaim and version5 to xflaim
git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@7 0109f412-320b-0410-ab79-c3e0c5ffbbe6
This commit is contained in:
999
flaim/src/flupdate.cpp
Normal file
999
flaim/src/flupdate.cpp
Normal file
@@ -0,0 +1,999 @@
|
||||
//-------------------------------------------------------------------------
|
||||
// Desc: Record add, modify, and delete routines.
|
||||
// Tabs: 3
|
||||
//
|
||||
// Copyright (c) 1991-1992,1994-2006 Novell, Inc. All Rights Reserved.
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of version 2 of the GNU General Public
|
||||
// License as published by the Free Software Foundation.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, contact Novell, Inc.
|
||||
//
|
||||
// To contact Novell about this file by physical or electronic mail,
|
||||
// you may find current contact information at www.novell.com
|
||||
//
|
||||
// $Id: flupdate.cpp 12266 2006-01-19 14:45:33 -0700 (Thu, 19 Jan 2006) dsanders $
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
#include "flaimsys.h"
|
||||
|
||||
FSTATIC RCODE flmDoUpdateCS(
|
||||
FDB * pDb,
|
||||
FLMUINT uiOp,
|
||||
FLMUINT uiContainer,
|
||||
FLMUINT * puiDrn,
|
||||
FlmRecord * pRecord,
|
||||
FLMUINT uiAutoTrans);
|
||||
|
||||
/****************************************************************************
|
||||
Desc: Internal routine for doing updates via client/server
|
||||
****************************************************************************/
|
||||
FSTATIC RCODE flmDoUpdateCS(
|
||||
FDB * pDb,
|
||||
FLMUINT uiOp,
|
||||
FLMUINT uiContainer,
|
||||
FLMUINT * puiDrn,
|
||||
FlmRecord * pRecord,
|
||||
FLMUINT uiAutoTrans)
|
||||
{
|
||||
RCODE rc = FERR_OK;
|
||||
CS_CONTEXT *pCSContext = pDb->pCSContext;
|
||||
FCL_WIRE Wire( pCSContext, pDb);
|
||||
|
||||
// Send a request to do the update
|
||||
|
||||
if (RC_BAD( rc = Wire.sendOp( FCS_OPCLASS_RECORD, uiOp)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
if (uiContainer)
|
||||
{
|
||||
if (RC_BAD( rc = Wire.sendNumber( WIRE_VALUE_CONTAINER_ID, uiContainer)))
|
||||
{
|
||||
goto Transmission_Error;
|
||||
}
|
||||
}
|
||||
|
||||
if (*puiDrn)
|
||||
{
|
||||
if (RC_BAD( rc = Wire.sendNumber( WIRE_VALUE_DRN, *puiDrn)))
|
||||
{
|
||||
goto Transmission_Error;
|
||||
}
|
||||
}
|
||||
|
||||
if (pRecord)
|
||||
{
|
||||
if (RC_BAD( rc = Wire.sendRecord( WIRE_VALUE_RECORD, pRecord)))
|
||||
{
|
||||
goto Transmission_Error;
|
||||
}
|
||||
}
|
||||
|
||||
if (uiAutoTrans)
|
||||
{
|
||||
if (RC_BAD( rc = Wire.sendNumber( WIRE_VALUE_AUTOTRANS, uiAutoTrans)))
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
if (uiOp == FCS_OP_RECORD_ADD)
|
||||
{
|
||||
*puiDrn = Wire.getDrn();
|
||||
}
|
||||
|
||||
Exit:
|
||||
return( rc);
|
||||
|
||||
Transmission_Error:
|
||||
pCSContext->bConnectionGood = FALSE;
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
Desc : Outputs an update event callback.
|
||||
*************************************************************************/
|
||||
void flmUpdEventCallback(
|
||||
FDB * pDb,
|
||||
FEventType eEventType,
|
||||
HFDB hDb,
|
||||
RCODE rc,
|
||||
FLMUINT uiDrn,
|
||||
FLMUINT uiContainer,
|
||||
FlmRecord * pNewRecord,
|
||||
FlmRecord * pOldRecord)
|
||||
{
|
||||
FLM_UPDATE_EVENT UpdEvent;
|
||||
|
||||
UpdEvent.uiThreadId = f_threadId();
|
||||
UpdEvent.hDb = hDb;
|
||||
UpdEvent.uiTransID = (FLMUINT)( (pDb->uiTransType)
|
||||
? pDb->LogHdr.uiCurrTransID
|
||||
: 0);
|
||||
UpdEvent.rc = rc;
|
||||
UpdEvent.uiDrn = uiDrn;
|
||||
UpdEvent.uiContainer = uiContainer;
|
||||
UpdEvent.pNewRecord = pNewRecord;
|
||||
UpdEvent.pOldRecord = pOldRecord;
|
||||
flmDoEventCallback( F_EVENT_UPDATES, eEventType, &UpdEvent, NULL);
|
||||
}
|
||||
|
||||
/*API~***********************************************************************
|
||||
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.
|
||||
*END************************************************************************/
|
||||
RCODE FlmRecordAdd(
|
||||
HFDB hDb,
|
||||
FLMUINT uiContainer,
|
||||
FLMUINT * puiDrn,
|
||||
FlmRecord * pRecord,
|
||||
FLMUINT uiAutoTrans
|
||||
)
|
||||
{
|
||||
RCODE rc = FERR_OK;
|
||||
FDB * pDb = (FDB *)hDb;
|
||||
LFILE * pLFile;
|
||||
FLMBOOL bStartedAutoTrans = FALSE;
|
||||
FLMBOOL bLogCompleteIndexSet = FALSE;
|
||||
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_ADD, uiContainer,
|
||||
puiDrn, 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, puiDrn, 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, *puiDrn, uiAutoTrans, NULL, pRecord)) &&
|
||||
bLogCompleteIndexSet &&
|
||||
pDb->pFile->FileHdr.uiVersionNum <= FLM_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( *puiDrn, 0, 1, 0xFFFFFFFF);
|
||||
}
|
||||
}
|
||||
|
||||
if( pDbStats)
|
||||
{
|
||||
flmAddElapTime( &StartTime, &pDbStats->RecordAdds.ui64ElapMilli);
|
||||
pDbStats->RecordAdds.ui64Count++;
|
||||
pDbStats->bHaveStats = TRUE;
|
||||
}
|
||||
|
||||
if( gv_FlmSysData.EventHdrs[ F_EVENT_UPDATES].pEventCBList)
|
||||
{
|
||||
flmUpdEventCallback( pDb, F_EVENT_ADD_RECORD, hDb, rc, *puiDrn,
|
||||
uiContainer, pRecord, NULL);
|
||||
}
|
||||
|
||||
// If started an automatic transaction end it.
|
||||
|
||||
if( bStartedAutoTrans)
|
||||
{
|
||||
rc = flmEndAutoTrans( pDb, rc);
|
||||
}
|
||||
|
||||
ExitCS:
|
||||
|
||||
flmExit( FLM_RECORD_ADD, pDb, rc);
|
||||
return( rc);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
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 = *puiDrn;
|
||||
FLMBOOL bProcessedKeys = FALSE;
|
||||
FLMUINT uiLfNum = pLFile->uiLfNum;
|
||||
FLMUINT uiAddAppendFlags = REC_UPD_ADD;
|
||||
FLMBOOL bHadUniqueKeys;
|
||||
|
||||
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)))
|
||||
{
|
||||
*puiDrn = uiDrn; // Set return value
|
||||
}
|
||||
goto Exit; // all done.
|
||||
}
|
||||
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;
|
||||
}
|
||||
*puiDrn = uiDrn; // Set return value.
|
||||
|
||||
// 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->uiLfNum, 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);
|
||||
}
|
||||
|
||||
/*API~***********************************************************************
|
||||
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.
|
||||
*END************************************************************************/
|
||||
RCODE 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, uiContainer, 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, uiContainer, 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_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.EventHdrs [F_EVENT_UPDATES].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);
|
||||
}
|
||||
|
||||
/*API~***********************************************************************
|
||||
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.
|
||||
*END************************************************************************/
|
||||
RCODE 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.EventHdrs [F_EVENT_UPDATES].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.EventHdrs [F_EVENT_UPDATES].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);
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
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);
|
||||
}
|
||||
Reference in New Issue
Block a user