af15e0698b
git-svn-id: svn://10.65.10.50/trunk@4679 c028cbd2-c16b-5b4b-a496-9718f37d4682
1196 lines
36 KiB
C
Executable File
1196 lines
36 KiB
C
Executable File
/* d4write.c (c)Copyright Sequiter Software Inc., 1988-1996. All rights reserved. */
|
|
|
|
#include "d4all.h"
|
|
#ifndef S4UNIX
|
|
#ifdef __TURBOC__
|
|
#pragma hdrstop
|
|
#endif /* __TURBOC__ */
|
|
#endif /* S4UNIX */
|
|
|
|
#ifndef S4OFF_WRITE
|
|
#ifdef S4CLIENT
|
|
|
|
int S4FUNCTION d4writeLow( DATA4 *d4, const long recIn, const int unlock )
|
|
{
|
|
int rc ;
|
|
CODE4 *c4 ;
|
|
CONNECTION4 *connection ;
|
|
CONNECTION4WRITE_INFO_IN info ;
|
|
CONNECTION4WRITE_INFO_OUT *out ;
|
|
long rec ;
|
|
#ifndef S4OFF_MEMO
|
|
CONNECTION4MEMO memo ;
|
|
F4MEMO *mfield ;
|
|
int i ;
|
|
#endif
|
|
|
|
#ifdef S4VBASIC
|
|
if ( c4parm_check( d4, 2, E92601 ) )
|
|
return 0 ;
|
|
#endif /* S4VBASIC */
|
|
|
|
if ( recIn == -1 )
|
|
rec = d4recNo( d4 ) ;
|
|
else
|
|
rec = recIn ;
|
|
|
|
#ifdef E4PARM_HIGH
|
|
if ( d4 == 0 )
|
|
return error4( 0, e4parm_null, E92601 ) ;
|
|
if ( rec == 0 || rec < -1 || d4->codeBase == 0 )
|
|
return error4( d4->codeBase, e4parm, E92601 ) ;
|
|
#ifdef E4ANALYZE
|
|
if ( d4->dataFile == 0 )
|
|
return error4( d4->codeBase, e4parm, E92601 ) ;
|
|
if ( d4->dataFile->connection == 0 )
|
|
return error4( d4->codeBase, e4parm, E92601 ) ;
|
|
#endif
|
|
#endif
|
|
|
|
c4 = d4->codeBase ;
|
|
if ( error4code( c4 ) < 0 )
|
|
return e4codeBase ;
|
|
|
|
if ( d4->readOnly == 1 )
|
|
return error4describe( c4, e4write, E80606, d4alias( d4 ), 0, 0 ) ;
|
|
|
|
/* ensure the record is being written to a valid position */
|
|
if ( rec > d4recCount( d4 ) + d4lockTestAppend( d4 ) )
|
|
return error4describe( c4, e4write, E82601, d4alias( d4 ), 0, 0 ) ;
|
|
|
|
memset( &info, 0, sizeof( CONNECTION4WRITE_INFO_IN ) ) ;
|
|
connection = d4->dataFile->connection ;
|
|
connection4assign( connection, CON4WRITE, data4clientId( d4 ), data4serverId( d4 ) ) ;
|
|
#ifndef S4OFF_MEMO
|
|
for ( i = 0 ; i < d4->dataFile->nFieldsMemo ; i++ )
|
|
{
|
|
mfield = d4->fieldsMemo + i ;
|
|
if ( mfield->isChanged == 1 )
|
|
info.numMemoFields++ ;
|
|
}
|
|
#endif
|
|
info.recNo = rec ;
|
|
info.unlock = unlock ;
|
|
connection4addData( connection, &info, sizeof( CONNECTION4WRITE_INFO_IN ), 0 ) ;
|
|
connection4addData( connection, d4->record, dfile4recWidth( d4->dataFile ), 0 ) ;
|
|
#ifndef S4OFF_MEMO
|
|
for ( i = 0 ; i < d4->dataFile->nFieldsMemo ; i++ )
|
|
{
|
|
mfield = d4->fieldsMemo + i ;
|
|
if ( mfield->isChanged == 1 )
|
|
{
|
|
memo.fieldNum = i ;
|
|
memo.memoLen = mfield->len ;
|
|
connection4addData( connection, &memo, sizeof( CONNECTION4MEMO ), 1 ) ;
|
|
if ( mfield->len > 0 )
|
|
connection4addData( connection, mfield->contents, mfield->len, 1 ) ;
|
|
}
|
|
}
|
|
#endif
|
|
rc = connection4repeat( connection, -2, -1, -1, d4 ) ;
|
|
if ( rc == r4locked )
|
|
return rc ;
|
|
if ( rc < 0 )
|
|
return connection4error( connection, c4, rc, E92601 ) ;
|
|
if ( connection4len( connection ) != sizeof( CONNECTION4WRITE_INFO_OUT ) )
|
|
return error4( c4, e4packetLen, E92601 ) ;
|
|
out = (CONNECTION4WRITE_INFO_OUT *)connection4data( connection ) ;
|
|
if ( out->recordLocked == 1 )
|
|
d4localLockSet( d4, d4recNo( d4 ) ) ;
|
|
|
|
if ( rc > 0 ) /* eg. r4entry or r4locked */
|
|
return rc ;
|
|
d4->recordChanged = 0 ;
|
|
return 0 ;
|
|
}
|
|
|
|
#else
|
|
static int d4unwriteKeys( DATA4 *, const long ) ;
|
|
|
|
int S4FUNCTION d4writeLow( DATA4 *d4, const long recIn, const int unlock )
|
|
{
|
|
long rec ;
|
|
int rc, finalRc, old ;
|
|
CODE4 *c4 ;
|
|
#ifndef S4OFF_TRAN
|
|
int hasTran ;
|
|
unsigned long len ;
|
|
TRAN4 *trans = 0 ;
|
|
long connectionId = 0L ;
|
|
long recNo ;
|
|
#ifndef S4OFF_MEMO
|
|
unsigned int ptrLen ;
|
|
char *ptr, *tempRecord ;
|
|
#ifdef S4MFOX
|
|
long type ;
|
|
#endif
|
|
long entry ;
|
|
unsigned long tempLong ;
|
|
unsigned long zero = 0L ;
|
|
#endif
|
|
#endif
|
|
#ifndef S4OFF_MEMO
|
|
int i ;
|
|
#endif
|
|
|
|
#ifdef S4VBASIC
|
|
if ( c4parm_check( d4, 2, E92601 ) )
|
|
return 0 ;
|
|
#endif /* S4VBASIC */
|
|
|
|
#ifdef E4PARM_HIGH
|
|
if ( d4 == 0 )
|
|
return error4( 0, e4parm_null, E92601 ) ;
|
|
if ( recIn < -1 || recIn == 0 || d4->codeBase == 0 )
|
|
return error4( d4->codeBase, e4parm, E92601 ) ;
|
|
#endif
|
|
|
|
if ( recIn == -1 )
|
|
rec = d4recNo( d4 ) ;
|
|
else
|
|
rec = recIn ;
|
|
|
|
c4 = d4->codeBase ;
|
|
if ( error4code( c4 ) < 0 )
|
|
return e4codeBase ;
|
|
|
|
if ( d4->readOnly == 1 )
|
|
return error4describe( c4, e4write, E80606, d4alias( d4 ), 0, 0 ) ;
|
|
|
|
old = d4->recordChanged ;
|
|
d4->recordChanged = 0 ;
|
|
|
|
/* set lock before transaction handling since cannot otherwise rollback */
|
|
#ifndef S4OFF_MULTI
|
|
#ifdef S4SERVER
|
|
rc = dfile4lock( d4->dataFile, data4clientId( d4 ), data4serverId( d4 ), rec ) ;
|
|
#else
|
|
rc = d4lock( d4, rec ) ;
|
|
#endif
|
|
if ( rc )
|
|
{
|
|
d4->recordChanged = old ;
|
|
return rc ;
|
|
}
|
|
#endif /* S4OFF_MULTI */
|
|
|
|
/* ensure the record is being written to a valid position */
|
|
#ifdef S4OFF_MULTI
|
|
if ( rec > d4recCount( d4 ) + 1 )
|
|
#else
|
|
if ( rec > d4recCount( d4 ) + dfile4lockTestAppend( d4->dataFile, data4clientId( d4 ), data4serverId( d4 ) ) )
|
|
#endif
|
|
{
|
|
d4->recordChanged = old ;
|
|
return error4( c4, e4write, E82601 ) ;
|
|
}
|
|
|
|
#ifndef S4OFF_TRAN
|
|
hasTran = 0 ;
|
|
if ( d4->logVal != LOG4TRANS )
|
|
if ( code4transEnabled( c4 ) )
|
|
if ( ( code4tranStatus( c4 ) == r4inactive ) ) /* start a mini-transaction */
|
|
{
|
|
rc = code4tranStartSingle( c4 ) ;
|
|
if ( rc != 0 )
|
|
{
|
|
d4->recordChanged = old ;
|
|
return rc ;
|
|
}
|
|
hasTran = 1 ;
|
|
}
|
|
#endif
|
|
/* 0. Validate memo id's */
|
|
/* 1. Update Keys */
|
|
/* 2. Update Memo Information */
|
|
/* 3. Update Data FILE4 */
|
|
|
|
#ifndef S4OFF_MEMO
|
|
#ifndef S4OFF_MULTI
|
|
if ( d4->dataFile->nFieldsMemo > 0 )
|
|
if ( ( rc = d4validateMemoIds( d4 ) ) != 0 )
|
|
{
|
|
d4->recordChanged = old ;
|
|
#ifndef S4OFF_TRAN
|
|
if ( hasTran )
|
|
code4tranRollbackSingle( c4 ) ;
|
|
#endif
|
|
return rc ;
|
|
}
|
|
#endif /* S4OFF_MULTI */
|
|
#endif /* S4OFF_MEMO */
|
|
|
|
#ifndef S4OFF_TRAN
|
|
if ( code4transEnabled( c4 ) )
|
|
if ( code4tranStatus( c4 ) == r4active )
|
|
{
|
|
trans = code4trans( c4 ) ;
|
|
#ifndef S4STAND_ALONE
|
|
connectionId = connection4id( c4->currentClient->connection ) ;
|
|
#endif
|
|
recNo = d4recNo( d4 ) ;
|
|
rc = tran4set( trans, trans->currentTranStatus, -1L, connectionId, TRAN4WRITE,
|
|
sizeof( recNo ) + 2 * dfile4recWidth( d4->dataFile ), data4clientId( d4 ), data4serverId( d4 ) ) ;
|
|
if ( rc < 0 )
|
|
{
|
|
if ( hasTran )
|
|
code4tranRollbackSingle( c4 ) ;
|
|
d4->recordChanged = old ;
|
|
return 0 ;
|
|
}
|
|
if ( tran4putData( trans, &recNo, sizeof( recNo ) ) == e4memory )
|
|
{
|
|
if ( hasTran )
|
|
code4tranRollbackSingle( c4 ) ;
|
|
d4->recordChanged = old ;
|
|
return 0 ;
|
|
}
|
|
if ( d4readOld( d4, rec ) < 0 )
|
|
{
|
|
d4->recordChanged = old ;
|
|
return -1 ;
|
|
}
|
|
if ( tran4putData( trans, d4->recordOld, dfile4recWidth( d4->dataFile ) ) == e4memory )
|
|
{
|
|
if ( hasTran )
|
|
code4tranRollbackSingle( c4 ) ;
|
|
d4->recordChanged = old ;
|
|
return 0 ;
|
|
}
|
|
if ( tran4putData( trans, d4record( d4 ), dfile4recWidth( d4->dataFile ) ) == e4memory )
|
|
{
|
|
if ( hasTran )
|
|
code4tranRollbackSingle( c4 ) ;
|
|
d4->recordChanged = old ;
|
|
return 0 ;
|
|
}
|
|
len = trans->header.dataLen ;
|
|
#ifndef S4OFF_MEMO
|
|
/* First cycle through the fields to be flushed */
|
|
ptr = 0 ;
|
|
ptrLen = 0 ;
|
|
|
|
for ( i = 0; i < d4->dataFile->nFieldsMemo; i++ )
|
|
{
|
|
if ( d4->fieldsMemo[i].isChanged == 1 )
|
|
{
|
|
tempRecord = d4->record ;
|
|
d4->record = d4->recordOld ;
|
|
entry = f4long( d4->fieldsMemo[i].field ) ;
|
|
d4->record = tempRecord ;
|
|
|
|
if ( entry == 0 )
|
|
{
|
|
if ( tran4putData( trans, &zero, sizeof( zero ) ) == e4memory )
|
|
{
|
|
rc = e4memory ;
|
|
break ;
|
|
}
|
|
len += sizeof( zero ) ;
|
|
}
|
|
else
|
|
{
|
|
#ifdef S4MFOX
|
|
rc = memo4fileRead( &d4->dataFile->memoFile, entry, &ptr, &ptrLen, &type ) ;
|
|
#else
|
|
rc = memo4fileRead( &d4->dataFile->memoFile, entry, &ptr, &ptrLen ) ;
|
|
#endif
|
|
if ( rc < 0 )
|
|
break ;
|
|
tempLong = ptrLen;
|
|
if ( tran4putData( trans, &tempLong, sizeof( tempLong ) ) == e4memory )
|
|
{
|
|
rc = e4memory ;
|
|
break ;
|
|
}
|
|
len += sizeof( tempLong ) ;
|
|
if ( ptrLen > 0 )
|
|
{
|
|
if ( tran4putData( trans, ptr, ptrLen ) == e4memory )
|
|
{
|
|
rc = e4memory ;
|
|
break ;
|
|
}
|
|
len += ptrLen ;
|
|
}
|
|
}
|
|
tempLong = d4->fieldsMemo[i].len;
|
|
if ( tran4putData( trans, &tempLong, sizeof( tempLong ) ) == e4memory )
|
|
{
|
|
rc = e4memory ;
|
|
break ;
|
|
}
|
|
len += sizeof( tempLong ) ;
|
|
if ( d4->fieldsMemo[i].len )
|
|
{
|
|
if ( tran4putData( trans, d4->fieldsMemo[i].contents, d4->fieldsMemo[i].len ) == e4memory )
|
|
{
|
|
rc = e4memory ;
|
|
break ;
|
|
}
|
|
len += d4->fieldsMemo[i].len ;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( tran4putData( trans, &zero, sizeof( zero ) ) == e4memory )
|
|
{
|
|
rc = e4memory ;
|
|
break ;
|
|
}
|
|
if ( tran4putData( trans, &zero, sizeof( zero ) ) == e4memory )
|
|
{
|
|
rc = e4memory ;
|
|
break ;
|
|
}
|
|
len += 2 * sizeof( zero ) ;
|
|
}
|
|
}
|
|
|
|
u4free( ptr ) ;
|
|
ptr = 0 ;
|
|
ptrLen = 0 ;
|
|
if ( rc < 0 )
|
|
{
|
|
if ( hasTran )
|
|
code4tranRollbackSingle( c4 ) ;
|
|
d4->recordChanged = old ;
|
|
return error4stack( c4, (short)rc, E92601 ) ;
|
|
}
|
|
trans->header.dataLen = (unsigned short int)len ;
|
|
#endif /* S4OFF_MEMO */
|
|
|
|
rc = tran4lowAppend( trans, 0 ) ;
|
|
if ( rc != 0 )
|
|
{
|
|
if ( hasTran )
|
|
code4tranRollbackSingle( c4 ) ;
|
|
d4->recordChanged = old ;
|
|
return rc ;
|
|
}
|
|
}
|
|
#endif /* S4OFF_TRAN */
|
|
|
|
#ifndef S4INDEX_OFF
|
|
rc = d4writeKeys( d4, rec ) ;
|
|
#endif
|
|
d4->recordChanged = old ;
|
|
#ifndef S4INDEX_OFF
|
|
if ( rc )
|
|
{
|
|
#ifndef S4OFF_TRAN
|
|
if ( hasTran )
|
|
code4tranRollbackSingle( c4 ) ;
|
|
#endif
|
|
return rc ;
|
|
}
|
|
#endif
|
|
|
|
finalRc = 0 ;
|
|
|
|
#ifndef S4OFF_MEMO
|
|
/* First cycle through the fields to be flushed */
|
|
for ( i = 0; i < d4->dataFile->nFieldsMemo; i++ )
|
|
{
|
|
rc = f4memoUpdate( d4->fieldsMemo[i].field) ;
|
|
if ( rc < 0 )
|
|
{
|
|
#ifndef S4OFF_TRAN
|
|
if ( hasTran )
|
|
code4tranRollbackSingle( c4 ) ;
|
|
#endif
|
|
return error4stack( c4, (short)rc, E92601 ) ;
|
|
}
|
|
if ( rc > 0 )
|
|
finalRc = rc ;
|
|
}
|
|
#endif /* S4OFF_MEMO */
|
|
|
|
rc = d4writeData( d4, rec ) ;
|
|
if ( rc < 0 )
|
|
d4unwriteKeys( d4, rec ) ;
|
|
#ifndef S4OFF_TRAN
|
|
if ( rc < 0 )
|
|
if ( code4transEnabled( c4 ) )
|
|
if ( code4tranStatus( c4 ) == r4active )
|
|
{
|
|
rc = tran4set( trans, trans->currentTranStatus, -1L,
|
|
connectionId, TRAN4VOID, (unsigned int)0, data4clientId( d4 ), data4serverId( d4 ) ) ;
|
|
if ( rc < 0 )
|
|
{
|
|
if ( hasTran )
|
|
code4tranRollbackSingle( c4 ) ;
|
|
return rc ;
|
|
}
|
|
return tran4lowAppend( trans, "\0" ) ;
|
|
}
|
|
#else
|
|
if ( rc < 0 )
|
|
return rc ;
|
|
#endif
|
|
|
|
#ifndef S4OFF_TRAN
|
|
if ( hasTran )
|
|
code4tranCommitSingle( c4 ) ;
|
|
#endif
|
|
|
|
if ( unlock ) /* unlock records (unless entire file is locked)... */
|
|
{
|
|
#ifdef S4SERVER
|
|
if ( dfile4lockTestFile( d4->dataFile, data4clientId( d4 ), data4serverId( d4 ) ) == 0 )
|
|
return dfile4unlockData( d4->dataFile, data4clientId( d4 ), data4serverId( d4 ) ) ;
|
|
#else
|
|
#ifndef S4OFF_TRAN
|
|
if ( code4transEnabled( c4 ) )
|
|
if ( code4tranStatus( c4 ) == r4active )
|
|
return 0 ;
|
|
#endif
|
|
#ifndef S4OFF_MULTI
|
|
if ( d4lockTestFile( d4 ) == 0 )
|
|
{
|
|
rc = d4unlock( d4 ) ;
|
|
if ( rc == r4active ) /* just a transactional notification */
|
|
return 0 ;
|
|
return rc ;
|
|
}
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
return finalRc ;
|
|
}
|
|
|
|
int d4writeData( DATA4 *data, const long rec )
|
|
{
|
|
#ifndef S4OFF_MULTI
|
|
int rc ;
|
|
#endif
|
|
|
|
#ifdef E4PARM_HIGH
|
|
if ( data == 0 )
|
|
return error4( 0, e4parm_null, E92602 ) ;
|
|
if ( rec < 1 || data->codeBase == 0 )
|
|
return error4( data->codeBase, e4parm, E92602 ) ;
|
|
#endif
|
|
|
|
if ( error4code( data->codeBase ) < 0 )
|
|
return e4codeBase ;
|
|
|
|
#ifndef S4OFF_MULTI
|
|
#ifdef S4SERVER
|
|
rc = dfile4lock( data->dataFile, data4clientId( data ), data4serverId( data ), rec ) ;
|
|
#else
|
|
rc = d4lock( data, rec ) ;
|
|
#endif
|
|
if ( rc )
|
|
return rc ;
|
|
#endif /* S4OFF_MULTI */
|
|
|
|
data->recordChanged = 0 ;
|
|
return dfile4writeData( data->dataFile, rec, data->record ) ;
|
|
}
|
|
|
|
int dfile4writeData( DATA4FILE *d4, const long rec, const char *record )
|
|
{
|
|
#ifdef E4PARM_LOW
|
|
if ( d4 == 0 )
|
|
return error4( 0, e4parm_null, E91102 ) ;
|
|
if ( rec < 1 || d4->c4 == 0 )
|
|
return error4( d4->c4, e4parm, E91102 ) ;
|
|
#endif
|
|
|
|
if ( error4code( d4->c4 ) < 0 )
|
|
return e4codeBase ;
|
|
|
|
d4->fileChanged = 1 ;
|
|
return file4write( &d4->file, dfile4recordPosition(d4, rec), record, d4->recWidth ) ;
|
|
}
|
|
|
|
#ifndef S4OFF_TRAN
|
|
/* search the removed list for the specified keys/char combination.
|
|
if recno is 0, then the matching character entry is returned */
|
|
TAG4KEY_REMOVED *t4keyFind( TAG4 *tag, long recno, char *key )
|
|
{
|
|
TAG4KEY_REMOVED *found ;
|
|
|
|
for ( found = 0 ; ; )
|
|
{
|
|
found =(TAG4KEY_REMOVED *)l4next( &tag->removedKeys, found ) ;
|
|
if ( found == 0 )
|
|
break ;
|
|
if ( recno == 0 )
|
|
{
|
|
if ( c4memcmp( key, found->key, (unsigned int)tag->tagFile->header.keyLen ) == 0 )
|
|
return found ;
|
|
}
|
|
else
|
|
if ( found->recno == recno )
|
|
if ( c4memcmp( key, found->key, (unsigned int)tag->tagFile->header.keyLen ) == 0 )
|
|
return found ;
|
|
}
|
|
|
|
return 0 ;
|
|
}
|
|
#endif
|
|
|
|
int d4writeKeys( DATA4 *d4, const long rec )
|
|
{
|
|
#ifdef S4INDEX_OFF
|
|
return 0 ;
|
|
#else
|
|
unsigned char newKeyBuf[I4MAX_KEY_SIZE] ;
|
|
unsigned char *tempPtr ;
|
|
char *saveRecBuffer ;
|
|
unsigned char *oldKey ;
|
|
int rc, rc2, saveError, keyLen, oldKeyAdded, addNewKey ;
|
|
TAG4 *tagOn ;
|
|
TAG4FILE *tagFileOn ;
|
|
CODE4 *c4 ;
|
|
#ifndef S4OFF_MULTI
|
|
int indexLocked ;
|
|
#endif
|
|
#ifndef S4OFF_TRAN
|
|
TAG4KEY_REMOVED *removed ;
|
|
#endif
|
|
#ifdef S4FOX
|
|
int newKeyLen ;
|
|
#endif
|
|
|
|
#ifdef E4PARM_HIGH
|
|
if ( d4 == 0 )
|
|
return error4( 0, e4parm_null, E92604 ) ;
|
|
if ( rec < 1 || d4->codeBase == 0 )
|
|
return error4( d4->codeBase, e4parm, E92604 ) ;
|
|
#endif
|
|
|
|
c4 = d4->codeBase ;
|
|
d4->bofFlag = d4->eofFlag = 0 ;
|
|
|
|
#ifdef S4CB51
|
|
#ifndef S4OFF_MULTI
|
|
#ifdef S4SERVER
|
|
rc = dfile4lock( d4->dataFile, data4clientId( d4 ), data4serverId( d4 ), rec, d4 ) ;
|
|
#else
|
|
rc = d4lock( d4, rec ) ;
|
|
#endif
|
|
if ( rc )
|
|
return rc ;
|
|
#endif /* S4OFF_MULTI */
|
|
#endif
|
|
|
|
#ifdef N4OTHER
|
|
if ( d4->dataFile->tagfiles.nLink > 0 )
|
|
#else
|
|
if ( d4->dataFile->indexes.nLink > 0 )
|
|
#endif
|
|
{
|
|
if ( d4readOld( d4, rec ) < 0 )
|
|
return -1 ;
|
|
if ( u4memcmp( d4->recordOld, d4->record, dfile4recWidth( d4->dataFile )) == 0 )
|
|
return 0 ;
|
|
}
|
|
|
|
saveRecBuffer = d4->record ;
|
|
rc = 0 ;
|
|
#ifndef S4OFF_MULTI
|
|
#ifdef S4SERVER
|
|
indexLocked = dfile4lockTestIndex( d4->dataFile, data4serverId( d4 ) ) ? 2 : 0 ; /* 2 means was user locked */
|
|
#else
|
|
indexLocked = d4lockTestIndex( d4 ) ? 2 : 0 ; /* 2 means was user locked */
|
|
#endif
|
|
#endif
|
|
|
|
for( tagOn = 0 ;; )
|
|
{
|
|
tagOn = d4tagNext( d4, tagOn ) ;
|
|
if ( tagOn == 0 )
|
|
break ;
|
|
|
|
tagFileOn = tagOn->tagFile ;
|
|
oldKeyAdded = addNewKey = 1 ;
|
|
tagOn->added = tagOn->removed = 0 ;
|
|
|
|
rc2 = expr4context( tagFileOn->expr, d4 ) ;
|
|
if ( rc2 < 0 )
|
|
{
|
|
rc = rc2 ;
|
|
break ;
|
|
}
|
|
if ( tagFileOn->filter != 0 )
|
|
{
|
|
rc2 = expr4context( tagFileOn->filter, d4 ) ;
|
|
if ( rc2 < 0 )
|
|
{
|
|
rc = rc2 ;
|
|
break ;
|
|
}
|
|
}
|
|
keyLen = tfile4exprKey( tagFileOn, &tempPtr ) ;
|
|
if ( keyLen < 0 )
|
|
{
|
|
rc = -1 ;
|
|
break ;
|
|
}
|
|
#ifdef E4ANALYZE
|
|
if ( keyLen != tagFileOn->header.keyLen || keyLen > I4MAX_KEY_SIZE)
|
|
return error4( c4, e4index, E92604 ) ;
|
|
#endif
|
|
|
|
memcpy( (void *)newKeyBuf, tempPtr, (unsigned int)keyLen ) ;
|
|
#ifdef S4FOX
|
|
newKeyLen = keyLen ;
|
|
#endif
|
|
|
|
if ( tagFileOn->filter )
|
|
addNewKey = expr4true( tagFileOn->filter ) ;
|
|
|
|
d4->record = d4->recordOld ;
|
|
|
|
rc2 = expr4context( tagFileOn->expr, d4 ) ;
|
|
if ( rc2 < 0 )
|
|
{
|
|
rc = rc2 ;
|
|
break ;
|
|
}
|
|
if ( tagFileOn->filter != 0 )
|
|
{
|
|
rc2 = expr4context( tagFileOn->filter, d4 ) ;
|
|
if ( rc2 < 0 )
|
|
{
|
|
rc = rc2 ;
|
|
break ;
|
|
}
|
|
}
|
|
if ( tagFileOn->filter )
|
|
oldKeyAdded = expr4true( tagFileOn->filter ) ;
|
|
keyLen = tfile4exprKey( tagOn->tagFile, &oldKey ) ;
|
|
|
|
d4->record = saveRecBuffer ;
|
|
|
|
if ( keyLen < 0 )
|
|
{
|
|
rc = keyLen ;
|
|
break ;
|
|
}
|
|
if ( oldKeyAdded == addNewKey )
|
|
#ifdef S4FOX
|
|
if ( u4keycmp( (void *)newKeyBuf, oldKey, (unsigned int)keyLen, (unsigned int)newKeyLen, 0, &tagFileOn->vfpInfo ) == 0 )
|
|
#else
|
|
if ( u4memcmp( (void *)newKeyBuf, oldKey, (unsigned int)keyLen ) == 0 )
|
|
#endif
|
|
continue ;
|
|
|
|
#ifndef S4OFF_MULTI
|
|
if ( indexLocked == 0 )
|
|
{
|
|
indexLocked = 1 ;
|
|
#ifdef S4SERVER
|
|
rc = dfile4lockIndex( d4->dataFile, data4serverId( d4 ) ) ;
|
|
#else
|
|
rc = d4lockIndex( d4 ) ;
|
|
#endif
|
|
if ( rc )
|
|
break ;
|
|
}
|
|
#endif /* S4OFF_MULTI */
|
|
|
|
if ( oldKeyAdded )
|
|
{
|
|
tagOn->removed = 1 ;
|
|
#ifndef S4OFF_TRAN
|
|
if ( code4tranStatus( c4 ) == r4active && ( t4unique( tagOn ) == r4unique ||
|
|
t4unique( tagOn ) == e4unique
|
|
#ifdef S4FOX
|
|
|| t4unique( tagOn ) == r4candidate
|
|
#endif
|
|
) ) /* save the entry due to transactions */
|
|
{
|
|
removed = (TAG4KEY_REMOVED *)u4allocFree( c4, (long)sizeof( LINK4 ) + (long)sizeof( long ) + tagFileOn->header.keyLen ) ;
|
|
if ( removed == 0 )
|
|
{
|
|
rc = e4memory ;
|
|
break ;
|
|
}
|
|
removed->recno = rec ;
|
|
memcpy( removed->key, oldKey, (unsigned int)tagFileOn->header.keyLen ) ;
|
|
l4addBefore( &tagOn->removedKeys, l4first( &tagOn->removedKeys ), removed ) ;
|
|
}
|
|
else
|
|
{
|
|
#endif
|
|
rc2 = expr4context( tagFileOn->expr, d4 ) ;
|
|
if ( rc2 < 0 )
|
|
{
|
|
rc = rc2 ;
|
|
break ;
|
|
}
|
|
if ( tagFileOn->filter != 0 )
|
|
{
|
|
rc2 = expr4context( tagFileOn->filter, d4 ) ;
|
|
if ( rc2 < 0 )
|
|
{
|
|
rc = rc2 ;
|
|
break ;
|
|
}
|
|
}
|
|
|
|
if ( tfile4remove( tagFileOn, oldKey, rec ) < 0 )
|
|
{
|
|
rc = -1 ;
|
|
break ;
|
|
}
|
|
#ifndef S4OFF_TRAN
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#ifndef S4OFF_TRAN
|
|
if ( code4tranStatus( c4 ) == r4rollback && ( t4unique( tagOn ) == r4unique ||
|
|
t4unique( tagOn ) == e4unique
|
|
#ifdef S4FOX
|
|
|| t4unique( tagOn ) == r4candidate
|
|
#endif
|
|
) ) /* remove the removal due to transactions */
|
|
{
|
|
removed = t4keyFind( tagOn, rec,(char *)newKeyBuf ) ;
|
|
if ( removed != 0 ) /* means the record really was not deleted, so just remove from the list of to-be-removed */
|
|
{
|
|
l4remove( &tagOn->removedKeys, removed ) ;
|
|
u4free( removed ) ;
|
|
addNewKey = 0 ;
|
|
}
|
|
/* else: removed is null when, within the same transaction,
|
|
a record alteration is made to replace the key that was to
|
|
be removed. At that point, the key was actually removed,
|
|
so it must now be added back */
|
|
}
|
|
#endif
|
|
if ( addNewKey )
|
|
{
|
|
tagOn->added = 1 ;
|
|
rc2 = expr4context( tagFileOn->expr, d4 ) ;
|
|
if ( rc2 < 0 )
|
|
{
|
|
rc = rc2 ;
|
|
break ;
|
|
}
|
|
if ( tagFileOn->filter != 0 )
|
|
{
|
|
rc2 = expr4context( tagFileOn->filter, d4 ) ;
|
|
if ( rc2 < 0 )
|
|
{
|
|
rc = rc2 ;
|
|
break ;
|
|
}
|
|
}
|
|
#ifndef S4OFF_TRAN
|
|
/* if a unique tag, first check if the record may have instead been pre-deleted */
|
|
if ( t4unique( tagOn ) != 0 )
|
|
{
|
|
removed = t4keyFind( tagOn, 0L, (char *)newKeyBuf ) ;
|
|
if ( removed != 0 ) /* re-adding a key that was removed, so really remove this entry from the tag file first */
|
|
{
|
|
if ( tfile4remove( tagFileOn, removed->key, removed->recno ) < 0 )
|
|
{
|
|
rc = -1 ;
|
|
break ;
|
|
}
|
|
l4remove( &tagOn->removedKeys, removed ) ;
|
|
u4free( removed ) ;
|
|
}
|
|
}
|
|
#endif
|
|
rc = tfile4add( tagFileOn, newKeyBuf, rec, t4unique( tagOn ) ) ;
|
|
if ( rc == r4unique || rc == e4unique )
|
|
{
|
|
saveError = error4set( c4, 0 ) ;
|
|
|
|
#ifndef S4OFF_TRAN
|
|
if ( code4tranStatus( c4 ) == r4active && ( t4unique( tagOn ) == r4unique ||
|
|
t4unique( tagOn ) == e4unique
|
|
#ifdef S4FOX
|
|
|| t4unique( tagOn ) == r4candidate
|
|
#endif
|
|
) ) /* just remove from the removed list */
|
|
{
|
|
removed =(TAG4KEY_REMOVED *)l4first( &tagOn->removedKeys ) ;
|
|
if ( removed == 0 )
|
|
{
|
|
error4( c4, e4info, E92604 ) ;
|
|
error4set( c4, 0 ) ;
|
|
rc = e4info ;
|
|
break ;
|
|
}
|
|
l4remove( &tagOn->removedKeys, removed ) ;
|
|
u4free( removed ) ;
|
|
}
|
|
else
|
|
#endif
|
|
if ( oldKeyAdded )
|
|
{
|
|
rc2 = expr4context( tagFileOn->expr, d4 ) ;
|
|
if ( rc2 < 0 )
|
|
{
|
|
rc = rc2 ;
|
|
break ;
|
|
}
|
|
if ( tagFileOn->filter != 0 )
|
|
{
|
|
rc2 = expr4context( tagFileOn->filter, d4 ) ;
|
|
if ( rc2 < 0 )
|
|
{
|
|
rc = rc2 ;
|
|
break ;
|
|
}
|
|
}
|
|
if ( tfile4add( tagFileOn, (unsigned char *)oldKey, rec, t4unique( tagOn ) ) < 0 )
|
|
{
|
|
rc = -1 ;
|
|
break ;
|
|
}
|
|
}
|
|
|
|
/* Remove the keys which were just added */
|
|
for(;;)
|
|
{
|
|
tagOn = d4tagPrev( d4, tagOn ) ;
|
|
if ( tagOn == 0 )
|
|
break ;
|
|
tagFileOn = tagOn->tagFile ;
|
|
|
|
if ( tagOn->added )
|
|
{
|
|
d4->record = saveRecBuffer ;
|
|
|
|
rc2 = expr4context( tagFileOn->expr, d4 ) ;
|
|
if ( rc2 < 0 )
|
|
{
|
|
rc = rc2 ;
|
|
break ;
|
|
}
|
|
if ( tagFileOn->filter != 0 )
|
|
{
|
|
rc2 = expr4context( tagFileOn->filter, d4 ) ;
|
|
if ( rc2 < 0 )
|
|
{
|
|
rc = rc2 ;
|
|
break ;
|
|
}
|
|
}
|
|
|
|
rc2 = tfile4removeCalc( tagFileOn, rec ) ;
|
|
if ( rc2 < 0 )
|
|
{
|
|
rc = rc2 ;
|
|
break ;
|
|
}
|
|
}
|
|
|
|
if ( tagOn->removed )
|
|
{
|
|
d4->record = d4->recordOld ;
|
|
|
|
rc2 = expr4context( tagFileOn->expr, d4 ) ;
|
|
if ( rc2 < 0 )
|
|
{
|
|
rc = rc2 ;
|
|
break ;
|
|
}
|
|
if ( tagFileOn->filter != 0 )
|
|
{
|
|
rc2 = expr4context( tagFileOn->filter, d4 ) ;
|
|
if ( rc2 < 0 )
|
|
{
|
|
rc = rc2 ;
|
|
break ;
|
|
}
|
|
}
|
|
rc2 = t4addCalc( tagOn, rec ) ;
|
|
if ( rc2 < 0 )
|
|
{
|
|
d4->record = saveRecBuffer ;
|
|
rc = rc2 ;
|
|
break ;
|
|
}
|
|
}
|
|
}
|
|
|
|
d4->record = saveRecBuffer ;
|
|
|
|
error4set( c4, (short)saveError ) ;
|
|
if ( saveError < 0 )
|
|
rc = saveError ;
|
|
break ;
|
|
}
|
|
if ( rc < 0 ) /* can't generate e4unique, so just set to -1 */
|
|
{
|
|
rc = -1 ;
|
|
break ;
|
|
}
|
|
rc = 0 ;
|
|
}
|
|
}
|
|
#ifndef S4OFF_MULTI
|
|
if ( indexLocked == 1 )
|
|
dfile4unlockIndex( d4->dataFile, data4serverId( d4 ) ) ;
|
|
#endif
|
|
|
|
d4->recNumOld = -1 ;
|
|
return rc ;
|
|
#endif /* S4OFF_INDEX */
|
|
}
|
|
|
|
static int d4unwriteKeys( DATA4 *d4, const long rec )
|
|
{
|
|
#ifdef S4INDEX_OFF
|
|
return 0 ;
|
|
#else
|
|
unsigned char newKeyBuf[I4MAX_KEY_SIZE] ;
|
|
char *saveRecBuffer ;
|
|
unsigned char *oldKey, *tempPtr ;
|
|
int rc2, rc, keyLen, oldKeyAdded, addNewKey ;
|
|
#ifndef S4OFF_MULTI
|
|
int indexLocked ;
|
|
#endif
|
|
TAG4 *tagOn ;
|
|
TAG4FILE *tagFileOn ;
|
|
#ifndef S4OFF_TRAN
|
|
TAG4KEY_REMOVED *removed ;
|
|
#endif
|
|
#ifdef S4FOX
|
|
int newKeyLen ;
|
|
#endif
|
|
|
|
#ifdef E4PARM_HIGH
|
|
if ( d4 == 0 )
|
|
return error4( 0, e4parm_null, E92605 ) ;
|
|
if ( rec < 1 || d4->codeBase == 0 )
|
|
return error4( d4->codeBase, e4parm, E92605 ) ;
|
|
#endif
|
|
|
|
#ifdef N4OTHER
|
|
if ( d4->dataFile->tagfiles.nLink > 0 )
|
|
#else
|
|
if ( d4->dataFile->indexes.nLink > 0 )
|
|
#endif
|
|
if ( u4memcmp( d4->recordOld, d4->record, dfile4recWidth( d4->dataFile )) == 0 )
|
|
return 0 ;
|
|
|
|
saveRecBuffer = d4->record ;
|
|
|
|
rc = 0 ;
|
|
#ifndef S4OFF_MULTI
|
|
#ifdef S4SERVER
|
|
indexLocked = dfile4lockTestIndex( d4->dataFile, data4serverId( d4 ) ) ? 2 : 0 ; /* 2 means was user locked */
|
|
#else
|
|
indexLocked = d4lockTestIndex( d4 ) ? 2 : 0 ; /* 2 means was user locked */
|
|
#endif
|
|
#endif
|
|
|
|
for( tagOn = 0 ;; )
|
|
{
|
|
tagOn = d4tagNext( d4, tagOn ) ;
|
|
if ( tagOn == 0 )
|
|
break ;
|
|
|
|
tagFileOn = tagOn->tagFile ;
|
|
rc2 = expr4context( tagFileOn->expr, d4 ) ;
|
|
if ( rc2 < 0 )
|
|
{
|
|
rc = rc2 ;
|
|
break ;
|
|
}
|
|
if ( tagFileOn->filter != 0 )
|
|
{
|
|
rc2 = expr4context( tagFileOn->filter, d4 ) ;
|
|
if ( rc2 < 0 )
|
|
{
|
|
rc = rc2 ;
|
|
break ;
|
|
}
|
|
}
|
|
|
|
oldKeyAdded = addNewKey = 1 ;
|
|
|
|
keyLen = tfile4exprKey( tagFileOn, &tempPtr ) ;
|
|
if ( keyLen < 0 )
|
|
{
|
|
rc = keyLen ;
|
|
break ;
|
|
}
|
|
#ifdef E4ANALYZE
|
|
if ( keyLen != tagFileOn->header.keyLen || keyLen > I4MAX_KEY_SIZE)
|
|
return error4( d4->codeBase, e4index, E92605 ) ;
|
|
#endif
|
|
|
|
memcpy( (void *)newKeyBuf, tempPtr, (unsigned int)keyLen ) ;
|
|
#ifdef S4FOX
|
|
newKeyLen = keyLen ;
|
|
#endif
|
|
|
|
if ( tagFileOn->filter )
|
|
addNewKey = expr4true( tagFileOn->filter ) ;
|
|
|
|
d4->record = d4->recordOld ;
|
|
|
|
rc2 = expr4context( tagFileOn->expr, d4 ) ;
|
|
if ( rc2 < 0 )
|
|
{
|
|
rc = rc2 ;
|
|
break ;
|
|
}
|
|
if ( tagFileOn->filter != 0 )
|
|
{
|
|
rc2 = expr4context( tagFileOn->filter, d4 ) ;
|
|
if ( rc2 < 0 )
|
|
{
|
|
rc = rc2 ;
|
|
break ;
|
|
}
|
|
}
|
|
|
|
if ( tagFileOn->filter )
|
|
oldKeyAdded = expr4true( tagFileOn->filter ) ;
|
|
keyLen = tfile4exprKey( tagFileOn, &oldKey ) ;
|
|
|
|
d4->record = saveRecBuffer ;
|
|
|
|
if ( keyLen < 0 )
|
|
{
|
|
rc = keyLen ;
|
|
break ;
|
|
}
|
|
if ( oldKeyAdded == addNewKey )
|
|
#ifdef S4FOX
|
|
if ( u4keycmp( (void *)newKeyBuf, oldKey, (unsigned int)keyLen, (unsigned int)newKeyLen, 0, &tagFileOn->vfpInfo ) == 0 )
|
|
#else
|
|
if ( u4memcmp( (void *)newKeyBuf, oldKey, (unsigned int)keyLen ) == 0 )
|
|
#endif
|
|
continue ;
|
|
|
|
#ifndef S4OFF_MULTI
|
|
if ( indexLocked == 0 )
|
|
{
|
|
indexLocked = 1 ;
|
|
#ifdef S4SERVER
|
|
rc = dfile4lockIndex( d4->dataFile, data4serverId( d4 ) ) ;
|
|
#else
|
|
rc = d4lockIndex( d4 ) ;
|
|
#endif
|
|
if ( rc )
|
|
break ;
|
|
}
|
|
#endif /* S4OFF_MULTI */
|
|
|
|
if ( oldKeyAdded )
|
|
{
|
|
#ifndef S4OFF_TRAN
|
|
if ( code4tranStatus( d4->codeBase ) == r4active && ( t4unique( tagOn ) == r4unique ||
|
|
t4unique( tagOn ) == e4unique
|
|
#ifdef S4FOX
|
|
|| t4unique( tagOn ) == r4candidate
|
|
#endif
|
|
) ) /* save the entry due to transactions */
|
|
{
|
|
for ( removed = 0 ;; )
|
|
{
|
|
removed = (TAG4KEY_REMOVED *)l4next( &tagOn->removedKeys, removed ) ;
|
|
/* if a reindex occurs, then the list will be empty,
|
|
so follow regular procedures. Otherwise the key should
|
|
be on the removed list */
|
|
if ( removed == 0 )
|
|
break ;
|
|
if ( c4memcmp( removed->key, oldKey, (unsigned int)tagFileOn->header.keyLen ) == 0 && ( removed->recno == rec ) )
|
|
{
|
|
l4remove( &tagOn->removedKeys, removed ) ;
|
|
u4free( removed ) ;
|
|
break ;
|
|
}
|
|
}
|
|
if ( rc < 0 )
|
|
break ;
|
|
}
|
|
else
|
|
{
|
|
#endif
|
|
rc2 = expr4context( tagFileOn->expr, d4 ) ;
|
|
if ( rc2 < 0 )
|
|
{
|
|
rc = rc2 ;
|
|
break ;
|
|
}
|
|
if ( tagFileOn->filter != 0 )
|
|
{
|
|
rc2 = expr4context( tagFileOn->filter, d4 ) ;
|
|
if ( rc2 < 0 )
|
|
{
|
|
rc = rc2 ;
|
|
break ;
|
|
}
|
|
}
|
|
if ( tfile4add( tagFileOn, oldKey, rec, t4unique( tagOn ) ) < 0 )
|
|
{
|
|
rc = -1 ;
|
|
break ;
|
|
}
|
|
#ifndef S4OFF_TRAN
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#ifndef S4OFF_TRAN
|
|
if ( code4tranStatus( d4->codeBase ) == r4rollback && ( t4unique( tagOn ) == r4unique ||
|
|
t4unique( tagOn ) == e4unique
|
|
#ifdef S4FOX
|
|
|| t4unique( tagOn ) == r4candidate
|
|
#endif
|
|
) ) /* remove the removal due to transactions */
|
|
{
|
|
rc = -1 ;
|
|
break ;
|
|
}
|
|
else
|
|
#endif
|
|
if ( addNewKey )
|
|
{
|
|
rc2 = expr4context( tagFileOn->expr, d4 ) ;
|
|
if ( rc2 < 0 )
|
|
{
|
|
rc = rc2 ;
|
|
break ;
|
|
}
|
|
if ( tagFileOn->filter != 0 )
|
|
{
|
|
rc2 = expr4context( tagFileOn->filter, d4 ) ;
|
|
if ( rc2 < 0 )
|
|
{
|
|
rc = rc2 ;
|
|
break ;
|
|
}
|
|
}
|
|
rc = tfile4remove( tagFileOn, newKeyBuf, rec ) ;
|
|
if ( rc == r4unique || rc == e4unique )
|
|
{
|
|
rc = -1 ;
|
|
break ;
|
|
}
|
|
if ( rc < 0 )
|
|
{
|
|
rc = -1 ;
|
|
break ;
|
|
}
|
|
rc = 0 ;
|
|
}
|
|
}
|
|
#ifndef S4OFF_MULTI
|
|
if ( indexLocked == 1 )
|
|
dfile4unlockIndex( d4->dataFile, data4serverId( d4 ) ) ;
|
|
#endif
|
|
|
|
d4->recNumOld = -1 ;
|
|
return rc ;
|
|
#endif /* S4OFF_INDEX */
|
|
}
|
|
#endif /* S4CLIENT */
|
|
#endif /* S4OFF_WRITE */
|