campo-sirio/cb/source/i4addtag.c
alex af15e0698b Codebase
git-svn-id: svn://10.65.10.50/trunk@4679 c028cbd2-c16b-5b4b-a496-9718f37d4682
1997-06-16 13:01:08 +00:00

1035 lines
31 KiB
C
Executable File

/* i4addtag.c (c)Copyright Sequiter Software Inc., 1988-1996. All rights reserved. */
#include "d4all.h"
#ifndef S4UNIX
#ifdef __TURBOC__
#pragma hdrstop
#endif
#endif
#ifndef S4CLIENT
#ifndef S4INDEX_OFF
#ifndef S4OFF_WRITE
#ifdef S4NDX
int i4getLastKey( TAG4FILE *t4, char *keyData, long forBlock )
{
int rc = 0 ;
B4BLOCK *tempBlock ;
#ifdef E4PARM_LOW
if ( forBlock <= 0 || t4 == 0 || keyData == 0 )
return error4( 0, e4parm, E95401 ) ;
#endif
/* must get block forBlock, then find the last key */
tempBlock = b4alloc( t4, forBlock ) ;
if ( tempBlock == 0 )
return -1 ;
if ( file4readAll( &t4->file, I4MULTIPLY * forBlock, &tempBlock->nKeys, B4BLOCK_SIZE ) < 0 )
return -1 ;
b4goEof( tempBlock ) ;
if ( b4leaf( tempBlock ) )
rc = 2 ;
else
rc = b4getLastKey( tempBlock, keyData ) ;
b4free( tempBlock ) ;
return rc ;
}
#endif
#ifndef N4OTHER
#ifdef S4FOX
/* (temporary) fix for FoxPro multi-user compatibility
swaps parent and right blocks */
#ifndef S4OFF_MULTI
static long tfile4swap( B4BLOCK *parent, B4BLOCK *left )
{
long tempFb ;
#ifdef S4BYTE_SWAP
S4LONG longVal ;
#endif
tempFb = left->fileBlock ;
left->fileBlock = parent->fileBlock ;
parent->fileBlock = tempFb ;
/* now update neighbours */
if ( left->header.rightNode != -1 )
{
#ifdef S4BYTE_SWAP
longVal = x4reverseLong( (void *)&left->fileBlock ) ;
file4write( &parent->tag->indexFile->file, left->header.rightNode + 2*sizeof(short),
&longVal, sizeof( left->header.leftNode ) ) ;
#else
file4write( &parent->tag->indexFile->file, left->header.rightNode + 2*sizeof(short),
&left->fileBlock, sizeof( left->header.leftNode ) ) ;
#endif
}
if ( left->header.leftNode != -1 )
{
#ifdef S4BYTE_SWAP
longVal = x4reverseLong( (void *)&left->fileBlock ) ;
file4write( &parent->tag->indexFile->file, left->header.leftNode + 2*sizeof(short),
&longVal, sizeof( left->header.rightNode ) ) ;
#else
file4write( &parent->tag->indexFile->file, left->header.leftNode + 2*sizeof(short),
&left->fileBlock, sizeof( left->header.rightNode ) ) ;
#endif
}
if ( parent->header.rightNode != -1 )
{
#ifdef S4BYTE_SWAP
longVal = x4reverseLong( (void *)&parent->fileBlock ) ;
file4write( &parent->tag->indexFile->file, parent->header.rightNode + 2*sizeof(short),
&longVal, sizeof( parent->header.leftNode ) ) ;
#else
file4write( &parent->tag->indexFile->file, parent->header.rightNode + 2*sizeof(short),
&parent->fileBlock, sizeof( parent->header.leftNode ) ) ;
#endif
}
if ( parent->header.leftNode != -1 )
{
#ifdef S4BYTE_SWAP
longVal = x4reverseLong( (void *)&parent->fileBlock ) ;
file4write( &parent->tag->indexFile->file, parent->header.leftNode + 2*sizeof(short),
&longVal, sizeof( parent->header.rightNode ) ) ;
#else
file4write( &parent->tag->indexFile->file, parent->header.leftNode + 2*sizeof(short),
&parent->fileBlock, sizeof( parent->header.rightNode ) ) ;
#endif
}
return left->fileBlock ;
}
#endif
#endif
/* errUnique must be 0 if the tag is not unique, otherwise must contain unique error */
static int tfile4addDo( TAG4FILE *t4, const unsigned char *keyInfo, const long recIn, short int errUnique )
{
CODE4 *c4 ;
INDEX4FILE *i4 ;
B4BLOCK *oldBlock, *rootBlock, *newBlock ;
int rc ;
long oldFileBlock, extendBlock, rec ;
#ifdef S4FOX
int keyOn, didAdd ;
long rec1 = 0L ;
long rec2 = 0L ;
const unsigned char *tempKey = 0 ;
int doInsert, updateReqd ;
#else
int isBranch ;
#endif
rec = recIn ;
#ifdef E4PARM_LOW
if ( t4 == 0 )
return error4( 0, e4parm_null, E95402 ) ;
if ( keyInfo == 0 || rec < 1 )
return error4( t4->codeBase, e4parm_null, E95402 ) ;
#endif
c4 = t4->codeBase ;
i4 = t4->indexFile ;
if ( error4code( c4 ) < 0 )
return e4codeBase ;
#ifdef S4FOX
if ( t4->expr != 0 )
switch( errUnique ) /* ensure not a null add if r4/e4 candidate */
{
case r4candidate:
if ( expr4nullLow( t4->expr, 1 ) == 1 )
return r4unique ;
break ;
case e4candidate:
if ( expr4nullLow( t4->expr, 1 ) == 1 )
return error4describe( c4, e4unique, E95402, tfile4alias( t4 ), i4->file.name, 0 ) ;
break ;
default:
break ;
}
rc = tfile4go( t4, keyInfo, rec, 1 ) ;
#else
rc = tfile4seek( t4, keyInfo, t4->header.keyLen ) ;
#endif
if ( rc < 0 )
return error4stack( c4, rc, E95402 ) ;
#ifdef S4FOX
if ( rc == 0 )
{
switch( errUnique )
{
case e4unique:
case e4candidate:
return error4describe( c4, e4unique, E95402, tfile4alias( t4 ), i4->file.name, 0 ) ;
case r4candidate :
return r4unique ;
default:
break ;
}
}
if ( errUnique && rc == r4found )
#else
if ( errUnique && rc == 0 )
#endif
{
switch ( errUnique )
{
#ifdef S4FOX
case e4candidate:
#endif
case e4unique:
return error4describe( c4, e4unique, E95402, tfile4alias( t4 ), i4->file.name, 0 ) ;
#ifdef S4FOX
case r4candidate:
#endif
case r4unique:
return r4unique ;
case r4uniqueContinue:
return r4uniqueContinue ;
default:
break ;
}
}
if ( t4->filter && !t4->hasKeys )
{
file4write(&t4->indexFile->file, t4->headerOffset+sizeof(t4->header)+222, (char *) "\0", (int) 1 ) ;
t4->hasKeys = (char)1 ;
#ifdef S4MDX
t4->hadKeys = (char)0 ;
#endif
}
oldBlock = tfile4block( t4 ) ;
oldFileBlock = 0 ;
#ifdef S4FOX
doInsert = 1 ;
updateReqd = 0 ;
didAdd = 1 ;
for( ;; )
{
if ( doInsert == 1 )
{
i4->tagIndex->header.version = i4->versionOld + 1 ;
if ( oldBlock == 0 )
{
/* Must create a new root block */
extendBlock = index4extend( i4 ) ;
if ( extendBlock < 0 )
return (int)extendBlock ;
rootBlock = b4alloc( t4, extendBlock) ;
if ( rootBlock == 0 )
return -1 ;
rootBlock->header.leftNode = -1 ;
rootBlock->header.rightNode = -1 ;
rootBlock->header.nodeAttribute = 1 ;
l4add( &t4->blocks, rootBlock ) ;
#ifndef S4OFF_MULTI
if ( t4->indexFile->file.lowAccessMode != OPEN4DENY_RW )
{
oldFileBlock = tfile4swap( rootBlock, (B4BLOCK *)l4last( &t4->saved ) ) ;
if ( oldFileBlock < 0 )
return -1 ;
}
#endif
b4top( rootBlock ) ;
b4insert( rootBlock, tempKey, rec, rec2, 1 ) ;
b4insert( rootBlock, keyInfo, oldFileBlock, rec1, 1 ) ;
t4->header.root = rootBlock->fileBlock ;
t4->rootWrite = 1 ;
if ( didAdd == 0 )
return 1 ;
return 0 ;
}
if ( (rc = b4insert( oldBlock, keyInfo, rec, rec1, 0 )) != 1 )
{
if ( rc == 0 )
{
if ( b4leaf( oldBlock ) )
{
tempKey = keyInfo ;
rec2 = rec ;
}
if ( oldBlock->keyOn == oldBlock->header.nKeys - 1 )
updateReqd = 1 ;
doInsert = 0 ;
continue ;
}
else
return rc ;
}
else
{
l4pop( &t4->blocks ) ;
keyOn = oldBlock->keyOn ;
/* The new block's end key gets added to the block just up */
newBlock= tfile4split( t4, oldBlock ) ;
if ( newBlock == 0 )
return -1 ;
l4add( &t4->saved, oldBlock ) ;
if ( keyOn < oldBlock->header.nKeys )
{
b4go( oldBlock, (long)keyOn ) ;
rc = b4insert( oldBlock, keyInfo, rec, rec1, 0 ) ;
}
else
{
b4go( newBlock, (long)(keyOn - oldBlock->header.nKeys) ) ;
rc = b4insert( newBlock, keyInfo, rec, rec1, 0 ) ;
if ( rc == 0 ) /* if there was room to insert and on the key, need to change the upper block entry */
if ( newBlock->keyOn == newBlock->header.nKeys - 1 )
updateReqd = 1 ;
}
if ( rc == 1 ) /* was not possible to insert the key */
didAdd = 0 ;
#ifdef E4INDEX_VERIFY
rc = b4verify( oldBlock ) ;
if ( rc < 0 )
return error4stack( t4->codeBase, rc, E91642 ) ;
rc = b4verify( newBlock ) ;
if ( rc < 0 )
return error4stack( t4->codeBase, rc, E91642 ) ;
#endif
/* Now add to the block just up */
b4goEof( oldBlock ) ;
oldBlock->keyOn-- ;
keyInfo = b4keyKey( oldBlock, oldBlock->keyOn ) ;
oldFileBlock = oldBlock->fileBlock ;
rec1 = b4recNo( oldBlock, oldBlock->keyOn ) ;
rec = newBlock->fileBlock ;
rc = b4flush(newBlock) ;
if ( rc < 0 )
return error4stack( t4->codeBase, rc, E91642 ) ;
b4goEof( newBlock ) ;
newBlock->keyOn-- ;
tempKey = (unsigned char *)c4->savedKey ;
memcpy( (void *)tempKey, (void *)b4keyKey( newBlock, newBlock->keyOn ), (unsigned int)t4->header.keyLen ) ;
rec2 = b4recNo( newBlock, newBlock->keyOn ) ;
if( newBlock->keyOn == newBlock->header.nKeys - 1 )
updateReqd = 1 ;
b4free( newBlock ) ;
}
}
else
l4add( &t4->saved, l4pop( &t4->blocks ) ) ;
oldBlock = (B4BLOCK *)t4->blocks.lastNode ;
if ( oldBlock == 0 )
{
if ( doInsert == 0 )
{
if ( didAdd == 0 )
return 1 ;
return 0 ;
}
}
else
if ( updateReqd ) /* may have to update a parent block */
{
if ( b4brReplace( oldBlock, tempKey, rec2 ) < 0 )
return -1 ;
if ( oldBlock->keyOn != oldBlock->header.nKeys - 1 ) /* done reqd updates */
updateReqd = 0 ;
}
}
#else /* if not S4FOX */
i4->changed = 1 ;
t4->changed = 1 ;
t4->header.version++ ;
for(;;)
{
if ( oldBlock == 0 )
{
/* Must create a new root block */
extendBlock = index4extend(i4) ;
if ( extendBlock < 0 )
return (int) extendBlock ;
rootBlock = b4alloc( t4, extendBlock) ;
if ( rootBlock == 0 )
return -1 ;
l4add( &t4->blocks, rootBlock ) ;
b4insert( rootBlock, keyInfo, oldFileBlock ) ;
b4insert( rootBlock, keyInfo, rec ) ;
rootBlock->nKeys-- ;
t4->header.root = rootBlock->fileBlock ;
t4->rootWrite = 1 ;
return 0 ;
}
if ( oldBlock->nKeys < oldBlock->tag->header.keysMax )
{
b4insert( oldBlock, keyInfo, rec ) ;
return 0 ;
}
l4pop( &t4->blocks ) ;
isBranch = b4leaf( oldBlock ) ? 0 : 1 ;
/* NNNNOOOO N - New, O - Old */
/* The new block's end key gets added to the block just up */
newBlock= tfile4split( t4, oldBlock ) ;
if ( newBlock == 0 )
return -1 ;
l4add( &t4->saved, newBlock ) ;
newBlock->nKeys -= (short)isBranch ;
if ( newBlock->keyOn < (newBlock->nKeys+isBranch) )
b4insert( newBlock, keyInfo, rec ) ;
else
b4insert( oldBlock, keyInfo, rec ) ;
#ifdef E4INDEX_VERIFY
rc = b4verify( oldBlock ) ;
if ( rc < 0 )
return error4stack( t4->codeBase, rc, E91642 ) ;
rc = b4verify( newBlock ) ;
if ( rc < 0 )
return error4stack( t4->codeBase, rc, E91642 ) ;
#endif
/* Now add to the block just up */
newBlock->keyOn = b4lastpos(newBlock) ;
keyInfo = b4keyKey( newBlock, newBlock->keyOn ) ;
rec = newBlock->fileBlock ;
oldFileBlock = oldBlock->fileBlock ;
if ( b4flush(oldBlock) < 0 )
return -1 ;
b4free( oldBlock ) ;
oldBlock = (B4BLOCK *) t4->blocks.lastNode ;
}
#endif
}
int tfile4add( TAG4FILE *t4, const unsigned char *keyInfo, const long recIn, short int errUnique )
{
#ifdef S4FOX
int rc ;
#endif
#ifdef S4FOX
/* in fox case the tfile4add might not actually add the key */
for( ;; )
{
rc = tfile4addDo( t4, keyInfo, recIn, errUnique ) ;
if ( rc != 1 )
return rc ;
}
#else
return tfile4addDo( t4, keyInfo, recIn, errUnique ) ;
#endif
}
int t4addCalc( TAG4 *t4, long rec )
{
int len ;
unsigned char *ptr ;
TAG4FILE *tfile ;
#ifndef S4OFF_TRAN
TAG4KEY_REMOVED *removed ;
#endif
#ifdef E4PARM_LOW
if ( t4 == 0 || rec < 1 )
return error4( 0, e4parm, E95403 ) ;
#endif
tfile = t4->tagFile ;
if ( error4code( tfile->codeBase ) < 0 )
return e4codeBase ;
if ( tfile->filter )
if ( !expr4true( tfile->filter ) )
return 0;
len = tfile4exprKey( tfile, (unsigned char **)&ptr ) ;
if ( len < 0 )
return error4stack( tfile->codeBase, len, E95403 ) ;
#ifdef E4ANALYZE
if ( len != tfile->header.keyLen )
return error4describe( tfile->codeBase, e4index, E95403, tfile4alias( tfile ), 0, 0 ) ;
#endif
#ifndef S4OFF_TRAN
if ( code4tranStatus( tfile->codeBase ) == r4active && ( t4unique( t4 ) == r4unique ||
t4unique( t4 ) == e4unique
#ifdef S4FOX
|| t4unique( t4 ) == r4candidate
#endif
) ) /* just remove from the removed list */
{
removed = t4keyFind( t4, rec,(char *)ptr ) ;
/* if found it means it is already there, so just remove from list */
if ( removed != 0 )
{
l4remove( &t4->removedKeys, removed ) ;
u4free( removed ) ;
return 0 ;
}
removed = t4keyFind( t4, 0L, (char *)ptr ) ;
if ( removed != 0 )
{
if ( tfile4remove( tfile, removed->key, removed->recno ) < 0 )
return -1 ;
l4remove( &t4->removedKeys, removed ) ;
u4free( removed ) ;
}
}
#endif
return tfile4add( tfile, (unsigned char *)ptr, rec, t4unique( t4 ) ) ;
}
#endif /* ifndef N4OTHER */
#ifdef N4OTHER
#ifdef S4NDX
int tfile4add( TAG4FILE *t4, unsigned char *keyInfo, long rec, short int errUnique )
{
CODE4 *c4 ;
INDEX4 *i4 ;
B4BLOCK *oldBlock, *rootBlock, *newBlock, *wchBlock ;
int rc, isBranch ;
long oldFileBlock, extendBlock ;
char keyData[I4MAX_KEY_SIZE+1] ; /* temporary storage for the key data (max size 100) */
char key2data[I4MAX_KEY_SIZE+1] ;
B4KEY_DATA *atNew ;
#ifdef E4PARM_LOW
if ( t4 == 0 )
return error4( 0, e4parm_null, E95402 ) ;
if ( keyInfo == 0 || rec < 1 )
return error4( t4->codeBase, e4parm_null, E95402 ) ;
#endif
c4 = t4->codeBase ;
i4 = t4->index ;
if ( error4code( c4 ) < 0 )
return e4codeBase ;
rc = tfile4go( t4, (char *)keyInfo, rec, 1 ) ;
if ( rc < 0 )
return error4stack( c4, rc, E95402 ) ;
if ( rc == 0 && t4unique( t4 ) == e4unique )
return error4describe( c4, e4unique, E95402, tfile4alias( t4 ), i4->file.name, 0 ) ;
if ( rc == r4found || rc == 0 )
{
switch ( t4unique( t4 ) )
{
case e4unique:
return error4describe( c4, e4unique, E95402, tfile4alias( t4 ), i4->file.name, 0 ) ;
case r4unique:
return r4unique ;
case r4uniqueContinue:
return r4uniqueContinue ;
default:
break ;
}
}
oldBlock = tfile4block( t4 ) ;
oldFileBlock = 0 ;
t4->header.version = t4->header.oldVersion + 1 ;
for(;;)
{
if ( oldBlock == 0 )
{
/* Must create a new root block */
extendBlock = tfile4extend( t4 ) ;
if ( extendBlock < 0 )
return (int)extendBlock ;
rootBlock = b4alloc( t4, extendBlock ) ;
if ( rootBlock == 0 )
return -1 ;
l4add( &t4->blocks, rootBlock ) ;
i4getLastKey( t4, keyData, oldFileBlock ) ;
b4insert( rootBlock, keyData, 0L, oldFileBlock ) ;
b4append( rootBlock, rec ) ;
t4->header.root = rootBlock->fileBlock ;
t4->rootWrite = 1 ;
return 0 ;
}
if ( b4room( oldBlock ) )
{
if ( b4leaf( oldBlock ) )
b4insert( oldBlock, keyInfo, rec, 0L ) ;
else
{
b4getLastKey( oldBlock, keyData ) ;
if ( oldBlock->keyOn >= oldBlock->nKeys ) /*insert at end done different */
{
b4insert( oldBlock, keyData, 0L, oldFileBlock ) ;
b4append( oldBlock, rec ) ;
}
else
{
atNew = b4key( oldBlock, oldBlock->keyOn ) ;
atNew->pointer = rec ;
b4insert( oldBlock, keyData, 0L, oldFileBlock ) ;
}
}
return 0 ;
}
l4pop( &t4->blocks ) ;
isBranch = b4leaf( oldBlock ) ? 0 : 1 ;
/* NNNNOOOO N - New, O - Old */
/* The new block's end key gets added to the block just up */
newBlock= tfile4split( t4, oldBlock ) ;
if ( newBlock == 0 )
return -1 ;
l4add( &t4->saved, newBlock ) ;
/* which block should do the insertion ? */
if ( oldBlock->keyOn < (oldBlock->nKeys + isBranch) )
wchBlock = oldBlock ;
else wchBlock = newBlock ;
if ( b4leaf( wchBlock ) )
b4insert( wchBlock, keyInfo, rec, 0L ) ;
else
{
b4getLastKey( wchBlock, keyData ) ;
if ( wchBlock->keyOn >= wchBlock->nKeys ) /* insert at end done different */
{
b4insert( wchBlock, keyData, 0L, oldFileBlock ) ;
b4append( wchBlock, rec ) ;
}
else
{
atNew = b4key( wchBlock, wchBlock->keyOn ) ;
atNew->pointer = rec ;
b4insert( wchBlock, keyData, 0L, oldFileBlock ) ;
}
}
#ifdef E4INDEX_VERIFY
rc = b4verify( oldBlock ) ;
if ( rc < 0 )
return error4stack( t4->codeBase, rc, E91642 ) ;
rc = b4verify( newBlock ) ;
if ( rc < 0 )
return error4stack( t4->codeBase, rc, E91642 ) ;
#endif
/* Now add to the block just up */
newBlock->keyOn = b4lastpos(newBlock) ;
keyInfo = b4keyKey( newBlock, newBlock->keyOn ) ;
rec = newBlock->fileBlock ;
if( !b4leaf( newBlock ) )
if ( b4getLastKey( newBlock, key2data ) != 4)
keyInfo = (unsigned char *)key2data ;
oldBlock->keyOn = b4lastpos( oldBlock ) ;
memcpy( keyData, b4keyKey( oldBlock, oldBlock->keyOn ), t4->header.keyLen ) ;
oldFileBlock = oldBlock->fileBlock ;
if ( b4flush( oldBlock ) < 0 )
return -1 ;
b4free( oldBlock ) ;
oldBlock = (B4BLOCK *) t4->blocks.lastNode ;
}
}
#else
#ifdef S4CLIPPER
int tfile4add( TAG4FILE *t4, unsigned char *keyInfo, const long recNum, short int errUnique )
{
CODE4 *c4 ;
B4BLOCK *oldBlock, *rootBlock, *newBlock, *wchBlock ;
int rc ;
long oldFileBlock, extendBlock, newFileBlock, rec ;
B4KEY_DATA *atNew ;
unsigned char oldKeyPtr[ I4MAX_KEY_SIZE ] ;
unsigned char keyData[I4MAX_KEY_SIZE+1] ; /* temporary storage for the key data (max size 100) */
unsigned short int oldDesc ;
#ifndef S4OFF_MULTI
int dSet, incPos ;
#ifdef E4ANALYZE_ALL
long findVal ;
int trc ;
#endif
#endif
#ifdef E4PARM_LOW
if ( t4 == 0 )
return error4( 0, e4parm_null, E95402 ) ;
if ( keyInfo == 0 || recNum < 1 )
return error4( t4->codeBase, e4parm_null, E95402 ) ;
#endif
rec = recNum ;
c4 = t4->codeBase ;
if ( error4code( c4 ) < 0 )
return e4codeBase ;
oldDesc = t4->header.descending ;
tfile4descending( t4, 0 ) ;
rc = tfile4seek( t4, (char *)keyInfo, t4->header.keyLen ) ;
#ifndef S4OFF_MULTI
/* for run-time multi-user compatibility with Clipper, must perform
the insertion at the end of the list of keys. This is slower than
CodeBase's insertion at the beginning (i.e. S4OFF_MULTI is defined) */
if ( rc == 0 && errUnique == 0 )
{
for( dSet = 0, incPos = t4->header.keyLen - 1 ; dSet == 0 && incPos >=0 ; incPos-- )
if ( keyInfo[incPos] != 0xFF )
{
keyInfo[incPos]++ ;
dSet = 1 ;
if ( tfile4seek( t4, (char *)keyInfo, t4->header.keyLen ) < 0 )
return -1 ;
keyInfo[incPos]-- ;
#ifdef E4ANALYZE_ALL
findVal = tfile4recNo( t4 ) ;
#endif
}
#ifdef E4ANALYZE_ALL
rc = tfile4seek( t4, (char *)keyInfo, t4->header.keyLen ) ;
if ( rc != 0 || errUnique != 0 )
findVal = -2L ;
for(;;)
{
if ( (*t4->cmp)( tfile4keyData( t4 )->value, keyInfo, t4->header.keyLen ) == 0 )
{
trc = tfile4skip( t4, 1L ) ;
if ( trc == 0L )
{
b4goEof( tfile4block( t4 ) ) ;
break ;
}
}
else
break ;
}
if ( tfile4recNo( t4 ) != findVal )
return error4( c4, e4index, E85402 ) ;
#endif
}
#endif
tfile4descending( t4, oldDesc ) ;
if ( rc < 0 )
return error4stack( c4, rc, E95402 ) ;
if ( rc == 0 )
{
switch ( errUnique )
{
case e4unique:
#ifdef N4OTHER
return error4describe( c4, e4unique, E95402, tfile4alias( t4 ), t4->file.name, 0 ) ;
#else
return error4describe( c4, e4unique, E95402, tfile4alias( t4 ), t4->indexFile->file.name, 0 ) ;
#endif
case r4unique:
return r4unique ;
case r4uniqueContinue:
return r4uniqueContinue ;
default:
break ;
}
}
oldBlock = tfile4block(t4) ;
oldFileBlock = 0 ;
newFileBlock = 0 ;
t4->header.version = (short)(t4->header.oldVersion + 1L) ;
while( !b4leaf( oldBlock ) )
{
rc = tfile4down( t4 ) ;
if ( rc < 0 || rc == 2 )
return -1 ;
oldBlock = tfile4block( t4 ) ;
if ( b4leaf( oldBlock ) )
oldBlock->keyOn = b4lastpos( oldBlock ) + 1 ;
else
oldBlock->keyOn = b4lastpos( oldBlock ) ;
}
for(;;)
{
if ( oldBlock == 0 )
{
/* Must create a new root block */
extendBlock = tfile4extend( t4 ) ;
if ( extendBlock < 0 )
return (int) extendBlock ;
rootBlock = b4alloc( t4, extendBlock) ;
if ( rootBlock == 0 )
return -1 ;
l4add( &t4->blocks, rootBlock ) ;
/* need to set root first so that b4insert() will record that current
block is the root block, which is vital to its functioning */
t4->header.root = rootBlock->fileBlock * 512 ;
b4insert( rootBlock, keyInfo, rec, oldFileBlock ) ;
b4append( rootBlock, newFileBlock ) ;
t4->rootWrite = 1 ;
return 0 ;
}
if ( b4room( oldBlock ) )
{
if ( b4leaf( oldBlock ) )
b4insert( oldBlock, keyInfo, rec, 0L ) ;
else /* update the current pointer, add the new branch */
{
#ifdef E4ANALYZE
if ( oldBlock->nKeys == 0 )
return error4( t4->codeBase, e4index, E95402 ) ;
#endif
atNew = b4key( oldBlock, oldBlock->keyOn ) ;
atNew->pointer = newFileBlock * 512 ;
b4insert( oldBlock, keyInfo, rec, oldFileBlock ) ;
}
return 0 ;
}
l4pop( &t4->blocks ) ;
/* NNNNOOOO N - New, O - Old */
/* The new block's end key gets added to the block just up */
if ( oldBlock->keyOn < (t4->header.keysHalf + ( b4leaf( oldBlock ) ? 0 : 1 ) ) )
{
newBlock= tfile4split( t4, oldBlock, 0 ) ;
if ( newBlock == 0 )
return -1 ;
wchBlock = oldBlock ;
}
else
{
newBlock= tfile4split( t4, oldBlock, 1 ) ;
if ( newBlock == 0 )
return -1 ;
wchBlock = newBlock ;
}
if ( b4leaf( wchBlock ) )
{
b4insert( wchBlock, keyInfo, rec, 0L ) ;
if ( newBlock->nKeys <= t4->header.keysHalf ) /* add a key from the old block!, must have info in newBlock because oldBlock gets deleted below */
{
#ifdef E4ANALYZE
if ( oldBlock->nKeys <= t4->header.keysHalf ) /* impossible */
#ifdef N4OTHER
return error4describe( t4->codeBase, e4index, E81601, tfile4alias( t4 ), t4->file.name, 0 ) ;
#else
return error4describe( t4->codeBase, e4index, E81601, tfile4alias( t4 ), t4->indexFile->file.name, 0 ) ;
#endif
#endif
oldBlock->keyOn = oldBlock->nKeys - 1 ;
memcpy( keyData, b4keyKey( oldBlock, oldBlock->keyOn ), t4->header.keyLen ) ;
keyInfo = keyData ;
rec = b4key( oldBlock, oldBlock->keyOn )->num ;
b4remove( oldBlock ) ;
newBlock->keyOn = 0 ;
b4insert( newBlock, keyInfo, rec, 0 ) ;
}
newBlock->keyOn = 0 ;
memcpy( keyData, b4keyKey( newBlock, newBlock->keyOn ), t4->header.keyLen ) ;
keyInfo = keyData ;
rec = b4key( newBlock, newBlock->keyOn )->num ;
b4remove( newBlock ) ;
}
else
{
/* now get the key to place upwards */
if ( wchBlock->nKeys == 0 ) /* treat like a root block */
{
if ( wchBlock == oldBlock ) /* not a problem if number of keys very small ?? */
{
if ( wchBlock->keyOn == 1 ) /* at end, so must combine with new block alterations */
{
wchBlock->nKeys = 1 ; /* now reset to the proper value */
/* don't actually need to do an insert, just set the file block value */
/* but need to copy values in so that later copy for data gives correct results */
memcpy( b4keyKey( oldBlock, 1), keyData, t4->header.keyLen ) ;
b4key( oldBlock, 1 )->num = rec ;
atNew = b4key( oldBlock, 1 ) ;
atNew->pointer = oldFileBlock * 512 ;
atNew = b4key( newBlock, 0 ) ; /* currently set to old value, reset to new */
atNew->pointer = newFileBlock * 512 ;
}
else /* simple insert */
{
wchBlock->nKeys = 1 ; /* to get a proper insert */
b4insert( wchBlock, keyInfo, rec, oldFileBlock ) ;
atNew = b4key( wchBlock, 1 ) ;
atNew->pointer = newFileBlock * 512 ;
memcpy( oldKeyPtr, b4keyKey( oldBlock, 1 ), t4->header.keyLen ) ;
keyInfo = oldKeyPtr ;
rec = b4key( oldBlock, 1 )->num ;
wchBlock->nKeys = 1 ; /* now reset to the proper value */
}
}
else
{
b4insert( wchBlock, keyInfo, rec, oldFileBlock ) ;
b4append( wchBlock, newFileBlock ) ;
}
}
else
{
if ( wchBlock->keyOn > wchBlock->nKeys && wchBlock == oldBlock )
{
atNew = b4key( newBlock, 0 ) ;
atNew->pointer = newFileBlock * 512 ;
}
else
{
atNew = b4key( wchBlock, wchBlock->keyOn ) ;
atNew->pointer = newFileBlock * 512 ;
}
b4insert( wchBlock, keyInfo, rec, oldFileBlock ) ;
}
memcpy( oldKeyPtr, b4keyKey( oldBlock, b4lastpos( oldBlock )), t4->header.keyLen ) ;
keyInfo = oldKeyPtr ;
rec = b4key( oldBlock, b4lastpos( oldBlock ) )->num ;
}
#ifdef E4INDEX_VERIFY
rc = b4verify( oldBlock ) ;
if ( rc < 0 )
return error4stack( t4->codeBase, rc, E91642 ) ;
rc = b4verify( newBlock ) ;
if ( rc < 0 )
return error4stack( t4->codeBase, rc, E91642 ) ;
#endif
l4add( &t4->saved, newBlock ) ;
newFileBlock = newBlock->fileBlock ;
oldFileBlock = oldBlock->fileBlock ;
if ( b4flush( oldBlock ) < 0 )
return -1 ;
b4free( oldBlock ) ;
oldBlock = (B4BLOCK *) t4->blocks.lastNode ;
}
}
#endif /* ifdef S4CLIPPER */
#endif /* ifdef S4NDX */
int t4addCalc( TAG4 *t4, long rec )
{
int rc ;
char *ptr ;
TAG4FILE *tfile ;
#ifndef S4OFF_TRAN
TAG4KEY_REMOVED *removed ;
#endif
#ifdef E4PARM_LOW
if ( t4 == 0 || rec < 1 )
return error4( 0, e4parm, E95403 ) ;
#endif
tfile = t4->tagFile ;
if ( error4code( tfile->codeBase ) < 0 )
return e4codeBase ;
#ifdef S4CLIPPER
if ( tfile->filter )
if ( !expr4true( tfile->filter ) )
return 0;
#endif
rc = tfile4exprKey( tfile, (unsigned char **)&ptr ) ;
if ( rc < 0 )
return error4stack( tfile->codeBase, rc, E95403 ) ;
#ifndef S4OFF_TRAN
if ( code4tranStatus( tfile->codeBase ) == r4active && ( t4unique( t4 ) == r4unique ||
t4unique( t4 ) == e4unique
#ifdef S4FOX
|| t4unique( t4 ) == r4candidate
#endif
) ) /* just remove from the removed list */
{
removed = t4keyFind( t4, 0L, ptr ) ;
if ( removed != 0 )
{
if ( tfile4remove( tfile, removed->key, removed->recno ) < 0 )
return -1 ;
l4remove( &t4->removedKeys, removed ) ;
u4free( removed ) ;
return 0 ;
}
}
#endif
return tfile4add( tfile, (unsigned char *)ptr, rec, t4unique( t4 ) ) ;
}
#endif /* ifdef N4OTHER */
#endif /* S4OFF_WRITE */
#endif /* S4INDEX_OFF */
#endif