/* 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