/* i4addtag.c (c)Copyright Sequiter Software Inc., 1990-1994. All rights reserved. */ #include "d4all.h" #ifndef S4UNIX #ifdef __TURBOC__ #pragma hdrstop #endif #endif #ifndef S4INDEX_OFF #ifndef S4OFF_WRITE #ifdef S4NDX int S4FUNCTION i4get_last_key( TAG4 *t4, char *key_data, long for_block ) { int rc = 0 ; B4BLOCK *temp_block ; #ifdef S4DEBUG if ( for_block <= 0 || t4 == 0 || key_data == 0 ) e4severe( e4parm, E4_I4GET_LAST_KEY ) ; #endif /* must get block for_block, then find the last key */ temp_block = b4alloc( t4, for_block ) ; if ( temp_block == 0 ) return -1 ; if ( file4read_all( &t4->file, I4MULTIPLY * for_block, &temp_block->n_keys, B4BLOCK_SIZE ) < 0 ) return -1 ; b4go_eof( temp_block ) ; if ( b4leaf( temp_block ) ) rc = 2 ; else rc = b4get_last_key( temp_block, key_data ) ; b4free( temp_block ) ; return rc ; } #endif #ifndef N4OTHER #ifdef S4FOX /* (temporary) fix for FoxPro multi-user compatibility swaps parent and right blocks */ #ifndef S4SINGLE static long t4swap( B4BLOCK *parent, B4BLOCK *left ) { long temp_fb ; #ifdef S4BYTE_SWAP S4LONG long_val ; #endif temp_fb = left->file_block ; left->file_block = parent->file_block ; parent->file_block = temp_fb ; /* now update neighbours */ if ( left->header.right_node != -1 ) { #ifdef S4BYTE_SWAP long_val = x4reverse_long( (void *)&left->file_block ) ; file4write( &parent->tag->index->file, left->header.right_node + 2*sizeof(short), &long_val, sizeof( left->header.left_node ) ) ; #else file4write( &parent->tag->index->file, left->header.right_node + 2*sizeof(short), &left->file_block, sizeof( left->header.left_node ) ) ; #endif } if ( left->header.left_node != -1 ) { #ifdef S4BYTE_SWAP long_val = x4reverse_long( (void *)&left->file_block ) ; file4write( &parent->tag->index->file, left->header.left_node + 2*sizeof(short), &long_val, sizeof( left->header.right_node ) ) ; #else file4write( &parent->tag->index->file, left->header.left_node + 2*sizeof(short), &left->file_block, sizeof( left->header.right_node ) ) ; #endif } if ( parent->header.right_node != -1 ) { #ifdef S4BYTE_SWAP long_val = x4reverse_long( (void *)&parent->file_block ) ; file4write( &parent->tag->index->file, parent->header.right_node + 2*sizeof(short), &long_val, sizeof( parent->header.left_node ) ) ; #else file4write( &parent->tag->index->file, parent->header.right_node + 2*sizeof(short), &parent->file_block, sizeof( parent->header.left_node ) ) ; #endif } if ( parent->header.left_node != -1 ) { #ifdef S4BYTE_SWAP long_val = x4reverse_long( (void *)&parent->file_block ) ; file4write( &parent->tag->index->file, parent->header.left_node + 2*sizeof(short), &long_val, sizeof( parent->header.right_node ) ) ; #else file4write( &parent->tag->index->file, parent->header.left_node + 2*sizeof(short), &parent->file_block, sizeof( parent->header.right_node ) ) ; #endif } return left->file_block ; } #endif #endif int S4FUNCTION t4add( TAG4 *t4, unsigned char *key_info, long rec ) { CODE4 *c4 ; INDEX4 *i4 ; B4BLOCK *old_block, *root_block, *new_block ; int rc ; long old_file_block, extend_block ; #ifdef S4FOX int key_on ; long rec1 = 0L ; long rec2 = 0L ; unsigned char *temp_key ; int do_insert, update_reqd ; #else int is_branch ; #endif #ifdef S4DEBUG if ( t4 == 0 || key_info == 0 || rec < 1 ) e4severe( e4parm, E4_T4ADD ) ; #endif c4 = t4->code_base ; i4 = t4->index ; if ( c4->error_code < 0 ) return -1 ; #ifdef S4FOX rc = t4go( t4, (char *)key_info, rec ) ; #else rc = t4seek( t4, (char *)key_info, t4->header.key_len ) ; #endif if ( rc < 0 ) return -1 ; #ifdef S4FOX if ( rc == 0 && t4->unique_error == e4unique ) { e4( c4, e4unique, i4->file.name ) ; return e4unique ; } #endif #ifdef S4FOX if ( (t4->header.type_code & 0x01) && rc == r4found ) #else if ( t4->header.unique && rc == 0 ) #endif { switch ( t4->unique_error ) { case e4unique: return e4( c4, e4unique, i4->file.name ) ; case r4unique: return r4unique ; case r4unique_continue: return r4unique_continue ; default: break ; } } if ( t4->filter && !t4->has_keys ) { file4write(&t4->index->file, t4->header_offset+sizeof(t4->header)+222, (char *) "\0", (int) 1 ) ; t4->has_keys = (char)1 ; #ifdef S4MDX t4->had_keys = (char)0 ; #endif } old_block = t4block(t4) ; old_file_block = 0 ; #ifdef S4FOX do_insert = 1 ; update_reqd = 0 ; for( ;; ) { if ( do_insert == 1 ) { i4->tag_index->header.version = i4->version_old+1 ; if ( old_block == 0 ) { /* Must create a new root block */ extend_block = i4extend(i4) ; if ( extend_block < 0 ) return (int)extend_block ; root_block = b4alloc( t4, extend_block) ; if ( root_block == 0 ) return -1 ; root_block->header.left_node = -1 ; root_block->header.right_node = -1 ; root_block->header.node_attribute = 1 ; l4add( &t4->blocks, root_block ) ; #ifndef S4SINGLE if ( t4->index->file.is_exclusive == 0 ) { old_file_block = t4swap( root_block, (B4BLOCK *)l4last( &t4->saved ) ) ; if ( old_file_block < 0 ) return -1 ; } #endif b4top( root_block ) ; b4insert( root_block, temp_key, rec, rec2, 1 ) ; b4insert( root_block, key_info, old_file_block, rec1, 1 ) ; rec1 = 0L ; rec2 = 0L ; t4->header.root = root_block->file_block ; t4->root_write = 1 ; return 0 ; } if ( (rc = b4insert( old_block, key_info, rec, rec1, 0 )) != 1 ) { if ( rc == 0 ) { if ( b4leaf( old_block ) ) { temp_key = key_info ; rec2 = rec ; } if ( old_block->key_on == old_block->header.n_keys - 1 ) update_reqd = 1 ; do_insert = 0 ; continue ; } else return rc ; } else { l4pop( &t4->blocks ) ; key_on = old_block->key_on ; /* The new block's end key gets added to the block just up */ new_block= t4split( t4, old_block ) ; if ( new_block == 0 ) return -1 ; l4add( &t4->saved, old_block ) ; if ( key_on < old_block->header.n_keys ) { b4go( old_block, key_on ) ; b4insert( old_block, key_info, rec, rec1, 0 ) ; } else { b4go( new_block, key_on - old_block->header.n_keys ) ; b4insert( new_block, key_info, rec, rec1, 0 ) ; if ( new_block->key_on == new_block->header.n_keys - 1 ) update_reqd = 1 ; } #ifdef S4INDEX_VERIFY if ( b4verify( old_block ) == -1 ) e4describe( t4->code_base, e4index, t4->alias, "t4split()-old after split", "" ) ; if ( b4verify( new_block ) == -1 ) e4describe( t4->code_base, e4index, t4->alias, "t4split()-new after split", "" ) ; #endif /* Now add to the block just up */ b4go_eof( old_block ) ; old_block->key_on-- ; key_info = b4key_key( old_block, old_block->key_on ) ; old_file_block = old_block->file_block ; rec1 = b4recno( old_block, old_block->key_on ) ; rec = new_block->file_block ; if ( b4flush(new_block) < 0 ) return -1 ; b4go_eof( new_block ) ; new_block->key_on-- ; temp_key = (unsigned char *)c4->saved_key ; memcpy( (void *)temp_key, (void *)b4key_key( new_block, new_block->key_on ), t4->header.key_len ) ; rec2 = b4recno( new_block, new_block->key_on ) ; if( new_block->key_on == new_block->header.n_keys - 1 ) update_reqd = 1 ; b4free( new_block ) ; } } else l4add( &t4->saved, l4pop( &t4->blocks ) ) ; old_block = (B4BLOCK *)t4->blocks.last_node ; if ( old_block == 0 ) { if ( do_insert == 0 ) return 0 ; } else if ( update_reqd ) /* may have to update a parent block */ { b4br_replace( old_block, (char *)temp_key, rec2 ) ; if ( old_block->key_on != old_block->header.n_keys - 1 ) /* done reqd updates */ update_reqd = 0 ; } } #else /* if not S4FOX */ i4->changed = 1 ; t4->changed = 1 ; t4->header.version++ ; for(;;) { if ( old_block == 0 ) { /* Must create a new root block */ extend_block = i4extend(i4) ; if ( extend_block < 0 ) return (int) extend_block ; root_block = b4alloc( t4, extend_block) ; if ( root_block == 0 ) return -1 ; l4add( &t4->blocks, root_block ) ; b4insert( root_block, key_info, old_file_block ) ; b4insert( root_block, key_info, rec ) ; root_block->n_keys-- ; t4->header.root = root_block->file_block ; t4->root_write = 1 ; return 0 ; } if ( old_block->n_keys < old_block->tag->header.keys_max ) { b4insert( old_block, key_info, rec ) ; return 0 ; } l4pop( &t4->blocks ) ; is_branch = b4leaf( old_block ) ? 0 : 1 ; /* NNNNOOOO N - New, O - Old */ /* The new block's end key gets added to the block just up */ new_block= t4split( t4, old_block ) ; if ( new_block == 0 ) return -1 ; l4add( &t4->saved, new_block ) ; new_block->n_keys -= (short)is_branch ; if ( new_block->key_on < (new_block->n_keys+is_branch) ) b4insert( new_block, key_info, rec ) ; else b4insert( old_block, key_info, rec ) ; #ifdef S4INDEX_VERIFY if ( b4verify( old_block ) == -1 ) e4describe( t4->code_base, e4index, t4->alias, "t4split()-old after split", "" ) ; if ( b4verify( new_block ) == -1 ) e4describe( t4->code_base, e4index, t4->alias, "t4split()-new after split", "" ) ; #endif /* Now add to the block just up */ new_block->key_on = b4lastpos(new_block) ; key_info = b4key_key( new_block, new_block->key_on ) ; rec = new_block->file_block ; old_file_block = old_block->file_block ; if ( b4flush(old_block) < 0 ) return -1 ; b4free( old_block ) ; old_block = (B4BLOCK *) t4->blocks.last_node ; } #endif } int S4FUNCTION t4add_calc( TAG4 *t4, long rec ) { int len ; char *ptr ; #ifdef S4DEBUG if ( t4 == 0 || rec < 1 ) e4severe( e4parm, E4_T4ADD_CALC ) ; #endif if ( t4->code_base->error_code < 0 ) return -1 ; if ( t4->filter ) if ( !expr4true( t4->filter ) ) return 0; len = t4expr_key( t4, &ptr ) ; if ( len < 0 ) return -1 ; #ifdef S4DEBUG if ( len != t4->header.key_len ) e4severe( e4result, E4_T4ADD_CALC ) ; #endif return t4add( t4, (unsigned char *)ptr, rec ) ; } #endif /* ifndef N4OTHER */ #ifdef N4OTHER #ifdef S4NDX int S4FUNCTION t4add( TAG4 *t4, unsigned char *key_info, long rec ) { CODE4 *c4 ; INDEX4 *i4 ; B4BLOCK *old_block, *root_block, *new_block, *wch_block ; int rc, is_branch ; long old_file_block, extend_block ; char key_data[I4MAX_KEY_SIZE+1] ; /* temporary storage for the key data (max size 100) */ char key2_data[I4MAX_KEY_SIZE+1] ; B4KEY_DATA *at_new ; #ifdef S4DEBUG if ( t4 == 0 || key_info == 0 || rec < 1 ) e4severe( e4parm, E4_T4ADD ) ; #endif c4 = t4->code_base ; i4 = t4->index ; if ( c4->error_code < 0 ) return -1 ; rc = t4go( t4, (char *)key_info, rec ) ; if ( rc < 0 ) return -1 ; if ( rc == 0 && t4->unique_error == e4unique ) { e4( c4, e4unique, i4->file.name ) ; return e4unique ; } if ( rc == r4found || rc == 0 ) { switch ( t4->unique_error ) { case e4unique: return e4( c4, e4unique, i4->file.name ) ; case r4unique: return r4unique ; case r4unique_continue: return r4unique_continue ; default: break ; } } old_block = t4block( t4 ) ; old_file_block = 0 ; t4->header.version = t4->header.old_version + 1 ; for(;;) { if ( old_block == 0 ) { /* Must create a new root block */ extend_block = t4extend( t4 ) ; if ( extend_block < 0 ) return (int)extend_block ; root_block = b4alloc( t4, extend_block ) ; if ( root_block == 0 ) return -1 ; l4add( &t4->blocks, root_block ) ; i4get_last_key( t4, key_data, old_file_block ) ; b4insert( root_block, key_data, 0L, old_file_block ) ; b4append( root_block, rec ) ; t4->header.root = root_block->file_block ; t4->root_write = 1 ; return 0 ; } if ( b4room( old_block ) ) { if ( b4leaf( old_block ) ) b4insert( old_block, key_info, rec, 0L ) ; else { b4get_last_key( old_block, key_data ) ; if ( old_block->key_on >= old_block->n_keys ) /*insert at end done different */ { b4insert( old_block, key_data, 0L, old_file_block ) ; b4append( old_block, rec ) ; } else { at_new = b4key( old_block, old_block->key_on ) ; at_new->pointer = rec ; b4insert( old_block, key_data, 0L, old_file_block ) ; } } return 0 ; } l4pop( &t4->blocks ) ; is_branch = b4leaf( old_block ) ? 0 : 1 ; /* NNNNOOOO N - New, O - Old */ /* The new block's end key gets added to the block just up */ new_block= t4split( t4, old_block ) ; if ( new_block == 0 ) return -1 ; l4add( &t4->saved, new_block ) ; /* which block should do the insertion ? */ if ( old_block->key_on < (old_block->n_keys + is_branch) ) wch_block = old_block ; else wch_block = new_block ; if ( b4leaf( wch_block ) ) b4insert( wch_block, key_info, rec, 0L ) ; else { b4get_last_key( wch_block, key_data ) ; if ( wch_block->key_on >= wch_block->n_keys ) /* insert at end done different */ { b4insert( wch_block, key_data, 0L, old_file_block ) ; b4append( wch_block, rec ) ; } else { at_new = b4key( wch_block, wch_block->key_on ) ; at_new->pointer = rec ; b4insert( wch_block, key_data, 0L, old_file_block ) ; } } #ifdef S4INDEX_VERIFY if ( b4verify( old_block ) == -1 ) e4describe( t4->code_base, e4index, t4->alias, "t4split()-old after split", "" ) ; if ( b4verify( new_block ) == -1 ) e4describe( t4->code_base, e4index, t4->alias, "t4split()-new after split", "" ) ; #endif /* Now add to the block just up */ new_block->key_on = b4lastpos(new_block) ; key_info = b4key_key( new_block, new_block->key_on ) ; rec = new_block->file_block ; if( !b4leaf( new_block ) ) if ( b4get_last_key( new_block, key2_data ) != 4) key_info = (unsigned char *)key2_data ; old_block->key_on = b4lastpos( old_block ) ; memcpy( key_data, b4key_key( old_block, old_block->key_on ), t4->header.key_len ) ; old_file_block = old_block->file_block ; if ( b4flush( old_block ) < 0 ) return -1 ; b4free( old_block ) ; old_block = (B4BLOCK *) t4->blocks.last_node ; } } #else #ifdef S4CLIPPER int S4FUNCTION t4add( TAG4 *t4, unsigned char *key_info, long rec ) { CODE4 *c4 ; INDEX4 *i4 ; B4BLOCK *old_block, *root_block, *new_block, *wch_block ; int rc, is_branch ; long old_file_block, extend_block, new_file_block ; B4KEY_DATA *at_new ; unsigned char old_key_ptr[ I4MAX_KEY_SIZE ] ; unsigned char key_data[I4MAX_KEY_SIZE+1] ; /* temporary storage for the key data (max size 100) */ int old_desc, inc_pos ; #ifndef S4SINGLE int d_set ; #ifdef S4DEBUG_DEV long findVal ; int trc ; #endif #endif #ifdef S4DEBUG if ( t4 == 0 || key_info == 0 || rec < 1 ) e4severe( e4parm, E4_T4ADD ) ; #endif c4 = t4->code_base ; i4 = t4->index ; if ( c4->error_code < 0 ) return -1 ; old_desc = t4->header.descending ; t4descending( t4, 0 ) ; rc = t4seek( t4, (char *)key_info, t4->header.key_len ) ; #ifndef S4SINGLE if ( rc == 0 && t4->unique_error == 0 ) { for( d_set = 0, inc_pos = t4->header.key_len - 1 ; d_set == 0 && inc_pos >=0 ; inc_pos-- ) if ( key_info[inc_pos] != 0xFF ) { key_info[inc_pos]++ ; d_set = 1 ; if ( t4seek( t4, (char *)key_info, t4->header.key_len ) < 0 ) return -1 ; key_info[inc_pos]-- ; #ifdef S4DEBUG_DEV findVal = t4recno( t4 ) ; #endif } #ifdef S4DEBUG_DEV rc = t4seek( t4, (char *)key_info, t4->header.key_len ) ; if ( rc != 0 || t4->unique_error != 0 ) findVal = -2L ; for(;;) { if ( (*t4->cmp)( t4key_data( t4 )->value, key_info, t4->header.key_len ) == 0 ) { trc = t4skip( t4, 1L ) ; if ( trc == 0L ) { b4go_eof( t4block( t4 ) ) ; break ; } } else break ; } if ( t4recno( t4 ) != findVal ) e4severe( e4index, "i4addtag() - record number mismatch" ) ; #endif } #endif t4descending( t4, old_desc ) ; if ( rc < 0 ) return -1 ; if ( rc == 0 ) { switch ( t4->unique_error ) { case e4unique: return e4( c4, e4unique, i4->file.name ) ; case r4unique: return r4unique ; case r4unique_continue: return r4unique_continue ; default: break ; } } old_block = t4block(t4) ; old_file_block = 0 ; new_file_block = 0 ; t4->header.version = (short)(t4->header.old_version + 1L) ; while( !b4leaf( old_block ) ) { rc = t4down( t4 ) ; if ( rc < 0 || rc == 2 ) return -1 ; old_block = t4block( t4 ) ; if ( b4leaf( old_block ) ) old_block->key_on = b4lastpos( old_block ) + 1 ; else old_block->key_on = b4lastpos( old_block ) ; } for(;;) { if ( old_block == 0 ) { /* Must create a new root block */ extend_block = t4extend( t4 ) ; if ( extend_block < 0 ) return (int) extend_block ; root_block = b4alloc( t4, extend_block) ; if ( root_block == 0 ) return -1 ; l4add( &t4->blocks, root_block ) ; b4insert( root_block, key_info, rec, old_file_block ) ; t4->header.root = root_block->file_block * 512 ; /* line order here so that the index validation works */ b4append( root_block, new_file_block ) ; t4->root_write = 1 ; return 0 ; } if ( b4room( old_block ) ) { if ( b4leaf( old_block ) ) b4insert( old_block, key_info, rec, 0L ) ; else /* update the current pointer, add the new branch */ { #ifdef S4DEBUG if ( old_block->n_keys == 0 ) e4severe( e4info, E4_T4ADD ) ; /* { b4insert( old_block, key_info, rec, old_file_block ) ; at_new = b4key( old_block, 1 ) ; at_new->pointer = new_file_block * 512 ; } else { ... } */ #endif at_new = b4key( old_block, old_block->key_on ) ; at_new->pointer = new_file_block * 512 ; b4insert( old_block, key_info, rec, old_file_block ) ; } return 0 ; } l4pop( &t4->blocks ) ; is_branch = b4leaf( old_block ) ? 0 : 1 ; /* NNNNOOOO N - New, O - Old */ /* The new block's end key gets added to the block just up */ if ( old_block->key_on < (t4->header.keys_half + is_branch) ) { new_block= t4split( t4, old_block, 0 ) ; if ( new_block == 0 ) return -1 ; wch_block = old_block ; } else { new_block= t4split( t4, old_block, 1 ) ; if ( new_block == 0 ) return -1 ; wch_block = new_block ; } if ( b4leaf( wch_block ) ) { b4insert( wch_block, key_info, rec, 0L ) ; if ( new_block->n_keys <= t4->header.keys_half ) /* add a key from the old block!, must have info in new_block because old_block gets deleted below */ { #ifdef S4DEBUG if ( old_block->n_keys <= t4->header.keys_half ) /* impossible */ e4severe( e4info, E4_INFO_CIF ) ; #endif old_block->key_on = old_block->n_keys - 1 ; memcpy( key_data, b4key_key( old_block, old_block->key_on ), t4->header.key_len ) ; key_info = key_data ; rec = b4key( old_block, old_block->key_on )->num ; b4remove( old_block ) ; new_block->key_on = 0 ; b4insert( new_block, key_info, rec, 0 ) ; } new_block->key_on = 0 ; memcpy( key_data, b4key_key( new_block, new_block->key_on ), t4->header.key_len ) ; key_info = key_data ; rec = b4key( new_block, new_block->key_on )->num ; b4remove( new_block ) ; } else { /* now get the key to place upwards */ if ( wch_block->n_keys == 0 ) /* treat like a root block */ { #ifdef S4DEBUG if ( wch_block == old_block ) e4severe( e4info, "t4add - split distribution incorrect" ) ; #endif b4insert( wch_block, key_info, rec, old_file_block ) ; b4append( wch_block, new_file_block ) ; } else { if ( wch_block->key_on > wch_block->n_keys && wch_block == old_block ) { at_new = b4key( new_block, 0 ) ; at_new->pointer = new_file_block * 512 ; } else { at_new = b4key( wch_block, wch_block->key_on ) ; at_new->pointer = new_file_block * 512 ; } b4insert( wch_block, key_info, rec, old_file_block ) ; } memcpy( old_key_ptr, b4key_key( old_block, b4lastpos( old_block )), t4->header.key_len ) ; key_info = old_key_ptr ; rec = b4key( old_block, b4lastpos( old_block ) )->num ; } #ifdef S4INDEX_VERIFY if ( b4verify( old_block ) == -1 ) e4describe( t4->code_base, e4index, t4->alias, "t4split()-old after split", "" ) ; if ( b4verify( new_block ) == -1 ) e4describe( t4->code_base, e4index, t4->alias, "t4split()-new after split", "" ) ; #endif l4add( &t4->saved, new_block ) ; new_file_block = new_block->file_block ; old_file_block = old_block->file_block ; if ( b4flush( old_block ) < 0 ) return -1 ; b4free( old_block ) ; old_block = (B4BLOCK *) t4->blocks.last_node ; } } #endif /* ifdef S4CLIPPER */ #endif /* ifdef S4NDX */ int S4FUNCTION t4add_calc( TAG4 *t4, long rec ) { char *ptr ; #ifdef S4DEBUG if ( t4 == 0 || rec < 1 ) e4severe( e4parm, E4_T4ADD_CALC ) ; #endif if ( t4->code_base->error_code < 0 ) return -1 ; #ifdef S4CLIPPER if ( t4->filter ) if ( !expr4true( t4->filter ) ) return 0; #endif if ( t4expr_key( t4, &ptr ) < 0 ) return -1 ; return t4add( t4, (unsigned char *)ptr, rec ) ; } #endif /* ifdef N4OTHER */ #endif /* S4OFF_WRITE */ #endif /* S4INDEX_OFF */