campo-sirio/cb5/r4relate.c

2302 lines
53 KiB
C
Raw Normal View History

/* r4relate.c (c)Copyright Sequiter Software Inc., 1992-1994. All rights reserved. */
#include "d4all.h"
#ifndef S4UNIX
#ifdef __TURBOC__
#pragma hdrstop
#endif
#endif
#include <time.h>
int S4FUNCTION f4flag_is_set_flip( F4FLAG *flag_ptr, unsigned long r )
{
if ( flag_ptr->flags == 0 )
return 1 ;
if ( flag_ptr->is_flip )
return ! f4flag_is_set( flag_ptr, r ) ;
else
return f4flag_is_set( flag_ptr, r ) ;
}
/* returns the position of the next flipped flag in the flag set - start at r */
unsigned long S4FUNCTION f4flag_get_next_flip( F4FLAG *f4, unsigned long r, char direction )
{
unsigned char c_flag ;
unsigned long low_val, on_val ;
char i ;
unsigned long high_val ;
c_flag = 0 ;
on_val = r ;
if ( f4->flags == 0 || r > f4->num_flags )
return 0 ;
low_val = (unsigned long)( r & 0x7 ) ;
high_val = (unsigned long)( r >> 3 ) ;
if ( (int)direction == -1 )
{
c_flag = (unsigned char)( f4->flags[high_val] ) ;
if ( f4->is_flip )
c_flag = (unsigned char) ~c_flag ;
c_flag = (unsigned char)( (unsigned char)( c_flag << ( 7 - low_val ) ) >> ( 7 - low_val )) ;
on_val += ( 7 - low_val ) ;
if ( c_flag == 0 )
for( ; c_flag == 0 ; on_val -= 8 )
{
if ( high_val-- <= 1 ) /* if was zero, or is now zero */
{
if ( f4->flags[0] == 0 )
return r ;
c_flag = f4->flags[0] ;
if ( f4->is_flip )
c_flag = (unsigned char) ~c_flag ;
on_val -= 8 ; /* for sure if high_val == 0, else?? */
break ;
}
c_flag = f4->flags[high_val] ;
if ( f4->is_flip )
c_flag = (unsigned char) ~c_flag ;
}
for( i = 7 ; (int)i >= 0 ; i--, on_val-- )
if ( c_flag & ( 0x01 << i ) )
break ;
return (r - on_val) ;
}
else
{
c_flag = (unsigned char)f4->flags[high_val] ;
if ( f4->is_flip )
c_flag = (unsigned char) ~c_flag ;
c_flag = (unsigned char) (c_flag >> low_val) ;
if ( c_flag == 0 )
{
on_val -= low_val ;
for( ; c_flag == 0 ; on_val += 8 )
{
if ( on_val >= f4->num_flags )
return (f4->num_flags - r + 1) ;
c_flag = f4->flags[++high_val] ;
if ( f4->is_flip )
c_flag = (unsigned char) ~c_flag ;
}
}
for( i = 0 ; i <= 7 ; i++, on_val++ )
if ( c_flag & ( 0x01 << i ) )
break ;
return (on_val - r) ;
}
}
int S4FUNCTION r4data_list_add( LIST4 *l4, DATA4 *data, RELATE4 *relate )
{
R4DATA_LIST *r4 ;
if ( relate->code_base->error_code < 0 )
return -1 ;
r4 = (R4DATA_LIST *)u4alloc_free( data->code_base, sizeof( R4DATA_LIST ) ) ;
if ( r4 == 0 )
return -1 ;
r4->data = data ;
r4->relate = relate ;
l4add( l4, r4 ) ;
return 0 ;
}
int S4FUNCTION r4data_list_find( LIST4 *l4, RELATE4 *r4 )
{
R4DATA_LIST *link ;
for ( link = 0 ;; )
{
link = (R4DATA_LIST *)l4next( l4, link ) ;
if ( link == 0 )
return 0 ;
if ( link->relate == r4 )
return 1 ;
}
}
void S4FUNCTION r4data_list_free( LIST4 *l4 )
{
R4DATA_LIST *r4data, *r4data2 ;
for ( r4data = (R4DATA_LIST *)l4first( l4 ) ; r4data ; )
{
r4data->relate->sort_type = 0 ;
r4data2 = (R4DATA_LIST *)l4next( l4, r4data ) ;
l4remove( l4, r4data ) ;
u4free( r4data ) ;
r4data = r4data2 ;
}
}
/* this function takes a completed sort list, and adds data members in the
following case:
If (r)elate must be added, r's siblings must also be added
Or, interpreted differently, if r is a relation, and any of it's children
must be added, then all of its children must be added.
*/
static int r4data_list_massage( LIST4 *l4 )
{
RELATE4 *relate_child ;
R4DATA_LIST *r4data ;
int add_children, relate_added ;
if ( l4->n_link == 0 ) /* no work required */
return 0 ;
r4data = 0 ;
for( ;; )
{
r4data = (R4DATA_LIST *)l4next( l4, r4data ) ;
if ( r4data == 0 )
break ;
relate_child = 0 ;
add_children = 0 ;
for( ;; )
{
relate_child = (RELATE4 *)l4next( &r4data->relate->slaves, relate_child ) ;
if ( relate_child == 0 )
break ;
if ( r4data_list_find( l4, relate_child ) )
{
add_children = 1 ;
break ;
}
}
if ( add_children == 1 )
{
relate_added = 0 ;
relate_child = 0 ;
for( ;; )
{
relate_child = (RELATE4 *)l4next( &r4data->relate->slaves, relate_child ) ;
if ( relate_child == 0 )
break ;
if ( r4data_list_find( l4, relate_child ) == 0 )
{
r4data_list_add( l4, relate_child->data, relate_child ) ;
relate_child->sort_type = relate4exact ;
relate_added = 1 ;
}
}
if ( relate_added == 1 )
r4data = 0 ; /* start at list top again to be sure none missed */
}
}
return 0 ;
}
/* 1 - database added, 0 - database not added, -1 - error */
/* check_type gives the caller's status in terms of whether we should be included */
int S4FUNCTION r4data_list_build( LIST4 *l4, RELATE4 *relate, EXPR4 *expr, int check_type )
{
int i ;
char must_add ;
E4INFO *info ;
RELATE4 *slave_on ;
if ( relate->code_base->error_code < 0 )
return -1 ;
must_add = 0 ;
/* 1st check if we must belong */
for( i = 0 ; i < expr->info_n ; i++ )
{
info = expr->info + i ;
if ( info->field_ptr )
{
if ( info->field_ptr->data == relate->data )
{
must_add = 1 ;
break ;
}
}
}
relate->sort_type = relate4exact ;
if ( must_add )
check_type = relate4exact ;
else
{
if ( relate->relation_type == relate4scan )
check_type = relate4scan ;
else
if ( check_type != relate4scan ) /* non-scan parent must be added, so we add ourselves too, in order to save work later */
must_add = 1 ;
}
/* if a child must be added, we must be too: */
for ( slave_on = 0 ;; )
{
slave_on = (RELATE4 *)l4next( &relate->slaves, slave_on ) ;
if ( slave_on == 0 )
break ;
if ( r4data_list_build( l4, slave_on, expr, check_type ) == 1 )
must_add = 1 ;
}
if ( must_add )
r4data_list_add( l4, relate->data, relate ) ;
else
if ( relate->relation_type == relate4scan )
relate->sort_type = relate4sort_skip ;
return must_add ;
}
int S4FUNCTION relate4blank_set( RELATE4 *relate, char direction )
{
RELATE4 *slave ;
int rc ;
if ( relate->code_base->error_code < 0 )
return -1 ;
relate->is_read = 1 ;
if ( direction == 1 )
{
if ( d4go_eof( relate->data ) < 0 )
return -1 ;
}
else
{
rc = d4top( relate->data ) ;
if ( rc )
return rc ;
rc = d4skip( relate->data, -1L ) ;
relate->data->rec_num = -1 ;
d4blank( relate->data ) ;
relate->data->record_changed = 0 ;
if ( relate->code_base->error_code < 0 )
return -1 ;
#ifndef S4SINGLE
if ( rc == r4locked || rc < 0 )
return rc ;
#endif
}
for( slave = 0 ;; )
{
slave = (RELATE4 *)l4next( &relate->slaves, slave ) ;
if ( slave == 0 )
return 0 ;
rc = relate4blank_set( slave, direction ) ;
if ( rc < 0 )
return rc ;
}
}
int S4FUNCTION relate4bottom( RELATE4 *relate )
{
RELATION4 *relation ;
int rc, rc2 ;
long rec ;
#ifdef S4VBASIC
if ( c4parm_check( relate->code_base, 1, E4_R4BOTTOM ) )
return -1 ;
#endif
#ifdef S4DEBUG
if ( relate == 0 )
e4severe( e4parm, E4_R4BOTTOM ) ;
#endif
if ( relate->code_base->error_code < 0 )
return -1 ;
relation = relate->relation ;
relate = &relation->relate ;
if ( relation->skip_backwards == 0 )
{
relate4sort_free( relation, 0 ) ;
relate4skip_enable( relate, 1 ) ;
}
rc = relate4top( relate ) ;
if ( rc )
return rc ;
relate4set_not_read( relate ) ;
if ( relation->in_sort == relate4sort_done )
{
if ( relate4sort_get_record( relation, relation->sort_rec_count ) == r4eof )
return r4eof ;
relation->sort_rec_on = relation->sort_rec_count ;
}
else
{
if ( d4bottom( relate->data ) < 0 )
return -1 ;
if ( relation->expr_source )
{
rec = d4recno( relate->data ) ;
#ifndef S4INDEX_OFF
if ( relate->data_tag )
while ( f4flag_is_set_flip( &relate->set, rec ) == 0 )
{
#ifdef S4HAS_DESCENDING
rc = (int)t4dskip( relate->data_tag, -1L ) ;
#else
rc = (int)t4skip( relate->data_tag, -1L ) ;
#endif
if ( rc != -1 )
{
if ( rc == 0 )
return r4bof ;
return rc ;
}
rec = t4recno( relate->data_tag ) ;
}
else
{
#endif
if ( f4flag_is_set_flip( &relate->set, rec ) == 0 )
{
rec = d4recno( relate->data ) - f4flag_get_next_flip( &relate->set, d4recno( relate->data), -1 ) ;
if ( rec == 0 )
return r4bof ;
}
#ifndef S4INDEX_OFF
}
#endif
d4go( relate->data, rec ) ;
}
relate4set_not_read( relate ) ;
}
rc = relate4read_rest( relate, -1 ) ;
if ( rc == relate4filter_record )
rc = relate4skip( relate, -1L ) ;
if ( rc < 0 || rc == r4terminate )
return rc ;
if ( relation->expr_source )
{
rc2 = log4true( &relation->log ) ;
if ( rc2 == r4terminate )
return r4terminate ;
if ( rc2 == 0 )
{
if ( relation->in_sort == relate4sort_skip ) /* must temporarily disable in order to get a matching scan if available */
{
relation->in_sort = 0 ;
rc = relate4skip( relate, -1L ) ;
relation->in_sort = relate4sort_skip ;
}
else
rc = relate4skip( relate, -1L ) ;
}
}
return rc ;
}
int S4FUNCTION relate4build_scan_list( RELATE4 *relate, RELATION4 *relation )
{
RELATE4 *relate_on ;
RELATE4LIST *ptr ;
if ( relate->code_base->error_code < 0 )
return -1 ;
for( relate_on = 0 ;; )
{
relate_on = (RELATE4 *)l4next(&relate->slaves,relate_on) ;
if ( relate_on == 0 )
break ;
if ( relate4build_scan_list( relate_on, relation ) < 0 )
return -1 ;
}
if ( relate->relation_type == relate4scan || relate == &relation->relate )
{
ptr = (RELATE4LIST *)mem4create_alloc( relate->code_base, &relation->relate_list_memory, 5, sizeof(RELATE4LIST), 5, 0 ) ;
if ( ptr == 0 )
return -1 ;
ptr->ptr = relate ;
l4add( &relation->relate_list, ptr ) ;
}
return 0 ;
}
void S4FUNCTION relate4changed( RELATE4 *relate )
{
RELATION4 *relation ;
int j ;
void *ptr ;
#ifdef S4DEBUG
if ( relate == 0 )
e4severe( e4parm, E4_R4CHANGED ) ;
#endif
if ( relate->code_base->error_code < 0 )
return ;
u4free( relate->scan_value ) ;
relate->scan_value = 0 ;
relation = relate->relation ;
relation->is_initialized = 0 ;
relate4sort_free( relation, 0 ) ;
for( ptr = 0 ;; )
{
ptr = l4last( &relation->relate_list) ;
if ( ptr == 0 )
break ;
l4remove( &relation->relate_list, ptr ) ;
mem4free( relation->relate_list_memory, ptr ) ;
}
u4free( relation->relate.set.flags ) ;
memset( (void *)&relation->relate.set, 0, sizeof( F4FLAG ) ) ;
if ( relation->log.expr != 0 )
{
for( j = relation->log.expr->info_n; --j >= 0; )
{
E4INFO_REPORT *info_ptr = relation->log.info_report + j ;
if ( info_ptr->data_list != 0 )
{
u4free( (void *)info_ptr->data_list->pointers ) ;
#ifdef S4DEBUG
info_ptr->data_list->pointers = 0 ;
#endif
mem4free( relation->data_list_memory, info_ptr->data_list ) ;
#ifdef S4DEBUG
info_ptr->data_list = 0 ;
#endif
}
}
expr4free( relation->log.expr ) ;
relation->log.expr = 0 ;
u4free( relation->log.info_report ) ;
relation->log.info_report = 0 ;
}
relation->in_sort = 0 ;
}
RELATE4 *S4FUNCTION relate4create_slave( RELATE4 *master, DATA4 *slave_data, char *master_expr, TAG4 *slave_tag )
{
RELATION4 *relation ;
RELATE4 *slave ;
char t1, t2 ;
int failed ;
if ( master == 0 )
return 0 ;
#ifdef S4VBASIC
if ( c4parm_check( master->code_base, 1, E4_R4CREATE_SLAVE ) )
return (RELATE4 *) 0 ;
#endif
if ( master->code_base->error_code < 0 )
return 0 ;
relation = master->relation ;
#ifdef S4DEBUG
if ( slave_data == 0 || master_expr == 0 )
e4severe( e4parm, E4_R4CREATE_SLAVE ) ;
/* check that the d4 doesn't belong to any existing relation */
if ( relate4lookup_relate( &relation->relate, slave_data ) != 0 )
{
e4( master->code_base, e4parm, E4_PARM_REL ) ;
return 0 ;
}
#endif
relate4changed( master ) ;
slave = (RELATE4 *)mem4create_alloc( master->code_base, &relation->relate_memory, 5, sizeof(RELATE4), 5, 0 ) ;
if ( slave == 0 )
return 0 ;
relate4init_relate( slave, master->relation, slave_data, master->code_base ) ;
slave->master_expr = expr4parse( master->data, master_expr ) ;
if ( slave->master_expr == 0 )
{
mem4free( relation->relate_memory, slave ) ;
return 0 ;
}
#ifndef S4INDEX_OFF
if ( slave_tag != 0 )
{
t1 = t4type( slave_tag ) ;
t2 = expr4type( slave->master_expr ) ;
if ( t1 != t2 ) /* check if types are compatible... */
{
failed = 1 ;
if ( t1 == r4date && t2 == r4date_doub )
failed = 0 ;
else
{
if ( t1 == r4date_doub && t2 == r4date )
failed = 0 ;
else
{
if ( t1 == r4num && t2 == r4num_doub )
failed = 0 ;
else
if ( t1 == r4num_doub && t2 == r4num )
failed = 0 ;
}
}
if ( failed == 1 )
{
if ( master->code_base->relate_error )
e4( master->code_base, e4relate, E4_RELATE_RCS ) ;
mem4free( relation->relate_memory, slave ) ;
return 0 ;
}
}
}
#endif
slave->data_tag = slave_tag ;
slave->master = master ;
l4add( &master->slaves, slave ) ;
relate4match_len( slave, -1 ) ; /* Set to maximum */
return slave ;
}
/* checks if the given dbf belongs to one of the relations in relation */
int S4FUNCTION relate4dbf_in_relation( RELATE4 *relate, DATA4 *dbf )
{
RELATE4 *relate_on ;
relate_on = &relate->relation->relate ;
while( relate_on->master )
relate_on = relate_on->master ;
do
{
if ( relate_on->data == dbf )
return 1 ;
} while( relate4next( &relate_on ) != 2 ) ;
return 0 ;
}
int S4FUNCTION relate4do( RELATE4 *relate )
{
int rc ;
#ifdef S4VBASIC
if ( c4parm_check( relate->code_base, 1, E4_R4DO ) )
return -1 ;
#endif
#ifdef S4DEBUG
if ( relate == 0 )
e4severe( e4parm, E4_R4DO ) ;
#endif
if ( relate->code_base->error_code < 0 )
return -1 ;
relate4set_not_read( relate ) ;
rc = relate4read_rest( relate, 0 ) ;
if ( rc == relate4filter_record ) /* no match is an error */
{
if ( relate->code_base->relate_error )
return e4( relate->code_base, e4lookup_err, relate->data->alias ) ;
return r4terminate ;
}
return rc ;
}
int S4FUNCTION relate4do_one( RELATE4 *relate )
{
int rc ;
#ifdef S4VBASIC
if ( c4parm_check( relate->code_base, 1, E4_R4DO_ONE ) )
return -1 ;
#endif
#ifdef S4DEBUG
if ( relate == 0 )
e4severe( e4parm, E4_R4DO_ONE ) ;
#endif
if ( relate->code_base->error_code < 0 )
return -1 ;
if ( relate->master == 0 ) /* no master, so we must be read */
return 0 ;
relate4set_not_read( relate ) ;
rc = relate4lookup( relate, 0 ) ;
relate->is_read = relate->master->is_read ; /* we are read if master is read */
if ( rc == relate4filter_record ) /* no match is an error */
{
if ( relate->code_base->relate_error )
return e4( relate->code_base, e4lookup_err, relate->data->alias ) ;
return r4terminate ;
}
return rc ;
}
int S4FUNCTION relate4eof( RELATE4 *relate )
{
#ifdef S4DEBUG
if ( relate == 0 )
e4severe( e4parm, E4_R4EOF ) ;
if ( relate->relation->is_initialized == 0 )
{
e4( relate->code_base, e4info, E4_INFO_REL ) ;
return -1 ;
}
#endif
if ( relate->relation->in_sort == relate4sort_done )
return relate->relation->sort_eof_flag ;
else
return d4eof( relate->relation->relate.data ) ;
}
int S4FUNCTION relate4error_action( RELATE4 *relate, int code )
{
int rc ;
if ( relate == 0 )
return -1 ;
#ifdef S4DEBUG
if ( code != relate4blank && code != relate4skip_rec && code != relate4terminate )
e4severe( e4parm, E4_INFO_IVE ) ;
#endif
rc = relate->error_action ;
relate->error_action = code ;
return rc ;
}
int S4FUNCTION relate4free( RELATE4 *relate, int close_files )
{
int rc = 0 ;
RELATION4 *relation ;
RELATE4 *relate_on ;
if ( relate == 0 )
return -1 ;
#ifdef S4VBASIC
if ( c4parm_check( relate->code_base, 1, E4_R4FREE ) )
return -1 ;
#endif
#ifndef S4SINGLE
relate4unlock( relate ) ;
#endif
relate4changed( relate ) ;
relation = relate->relation ;
relate = &relation->relate ;
if( close_files )
if( d4close( relate->data ) < 0 )
rc = -1 ;
for( relate_on = 0 ;; )
{
relate_on = (RELATE4 *)l4last( &relate->slaves ) ;
if ( relate_on == 0 )
break ;
if( relate4free_relate( relate_on, close_files ) < 0 )
rc = -1 ;
}
mem4release( relation->relate_memory ) ;
mem4release( relation->relate_list_memory ) ;
mem4release( relation->data_list_memory ) ;
relate4sort_free( relation, 1 ) ;
u4free( relation->expr_source ) ;
u4free( relation ) ;
return rc ;
}
int S4FUNCTION relate4free_relate( RELATE4 *relate, int close_files )
{
int rc = 0 ;
RELATE4 *relate_on ;
if ( relate->master == 0 )
return relate4free( relate, close_files ) ;
relate4changed( relate ) ;
if( close_files )
if( d4close( relate->data ) < 0 )
rc = -1 ;
for( ;; )
{
relate_on = (RELATE4 *)l4last( &relate->slaves) ;
if ( relate_on == 0 )
break ;
if( relate4free_relate( relate_on, close_files ) < 0 )
rc = -1 ;
}
expr4free( relate->master_expr ) ;
u4free( relate->scan_value ) ;
relate->scan_value = 0 ;
u4free( relate->set.flags ) ;
relate->set.flags = 0 ;
l4remove( &relate->master->slaves, relate ) ;
mem4free( relate->relation->relate_memory, relate ) ;
relate = 0 ;
return rc ;
}
RELATE4 *S4FUNCTION relate4init( DATA4 *master )
{
RELATION4 *relation ;
CODE4 *code_base ;
#ifdef S4VBASIC
if ( c4parm_check( master->code_base, 1, E4_R4INIT ) )
return (RELATE4 *) 0 ;
#endif
#ifdef S4DEBUG
if ( master == 0 )
e4severe( e4parm, E4_R4INIT ) ;
#endif
code_base = master->code_base ;
if ( code_base->error_code < 0 )
return 0 ;
relation = (RELATION4 *)u4alloc_er( code_base, sizeof( RELATION4 ) ) ;
if ( relation == 0 )
return 0 ;
relate4init_relate( &relation->relate, relation, master, code_base ) ;
relation->log.relation = relation ;
relation->log.code_base = code_base ;
relation->sort.file.hand = -1 ;
relation->sorted_file.hand = -1 ;
return &relation->relate ;
}
void S4FUNCTION relate4init_relate( RELATE4 *relate, RELATION4 *relation, DATA4 *data, CODE4 *code_ptr )
{
relate->code_base = code_ptr ;
relate->relation_type = relate4exact ;
relate->data = data ;
relate->error_action = relate4blank ;
relate->relation = relation ;
relate->data->count = d4reccount( relate->data ) ;
}
int S4FUNCTION relate4lock( RELATE4 *relate )
{
#ifdef S4SINGLE
return 0 ;
#else
CODE4 *code_base ;
int rc, old_attempts, count ;
DATA4 *data_on ;
if ( relate == 0 )
return -1 ;
#ifdef S4VBASIC
if ( c4parm_check( relate->code_base, 1, E4_R4LOCK ) )
return -1 ;
#endif
code_base = relate->code_base ;
if ( code_base->error_code < 0 )
return -1 ;
relate->relation->locked = 1 ;
count = old_attempts = code_base->lock_attempts ; /* take care of wait here */
code_base->lock_attempts = 1 ;
for(;;)
{
rc = 0 ;
for ( data_on = (DATA4 *)l4first( &code_base->data_list) ; data_on ; data_on = (DATA4 *)l4next( &code_base->data_list, data_on ) )
if ( relate4dbf_in_relation( relate, data_on ) )
{
rc = d4lock_all( data_on ) ;
if ( rc != 0 )
break ;
}
if ( rc != r4locked )
break ;
relate4unlock( relate ) ;
if ( count == 0 )
break ;
if ( count > 0 )
count-- ;
#ifdef S4TEMP
if ( d4display_quit( &display ) )
e4severe( e4result, E4_RESULT_EXI ) ;
#endif
u4delay_sec() ; /* wait a second */
}
code_base->lock_attempts = old_attempts ;
if ( code_base->error_code < 0 )
return -1 ;
return rc ;
#endif
}
/* direction : -1 = look backwards, 0 = lookup only, 1 = look forwards */
int S4FUNCTION relate4lookup( RELATE4 *relate, char direction )
{
int rc, len ;
long recno ;
char *ptr ;
#ifdef S4DEBUG
if ( relate == 0 )
e4severe( e4parm, E4_R4LOOKUP ) ;
#endif
if ( relate->code_base->error_code < 0 )
return -1 ;
if ( direction != 0 && relate->relation->is_initialized == 0 )
{
#ifdef S4DEBUG
e4( relate->code_base, e4info, E4_INFO_REL ) ;
#endif
return -1 ;
}
relate->is_read = 1 ;
if ( relate->master == 0 )
return 0 ;
d4tag_select( relate->data, relate->data_tag ) ;
#ifndef S4INDEX_OFF
if ( relate->data_tag == 0 )
{
#endif
recno = (long)expr4double( relate->master_expr ) ;
if ( relate->code_base->error_code < 0 )
return -1 ;
if ( direction != 0 )
if ( f4flag_is_set_flip( &relate->set, recno ) == 0 )
return relate4filter_record ;
rc = d4go( relate->data, recno ) ;
if ( rc < 0 )
return -1 ;
if ( rc != r4entry ) /* if not error, then return */
return 0 ;
if ( relate->relation_type == relate4approx )
{
d4go_eof( relate->data ) ;
return 0 ;
}
#ifndef S4INDEX_OFF
}
else
{
len = expr4key( relate->master_expr, &ptr ) ;
if ( len < 0 )
return -1 ;
len = (len < relate->match_len) ? len : relate->match_len ; /* min of len and match len */
if ( relate->relation_type == relate4scan )
{
#ifdef S4DEBUG
if ( relate->master == 0 )
e4severe( e4info, E4_RELATE_MEN ) ;
#endif
if ( relate->master->scan_value == 0 )
{
relate->master->scan_value_len = len ;
relate->master->scan_value = (char *)u4alloc_er( relate->code_base, len ) ;
if ( relate->master->scan_value == 0 )
return -1 ;
}
memcpy( relate->master->scan_value, ptr, len ) ;
}
rc = t4seek( relate->data_tag, ptr, len ) ;
if ( rc < 0 )
return -1 ;
if ( relate->relation_type == relate4approx || rc == 0 )
{
if ( t4eof( relate->data_tag) )
{
d4go_eof( relate->data ) ;
return 0 ;
}
if ( (int)direction < 0 && rc == 0 && relate->relation_type == relate4scan ) /* look for last one */
for( ;; )
{
#ifdef S4HAS_DESCENDING
if ( !t4dskip( relate->data_tag, 1L ) )
#else
if ( !t4skip( relate->data_tag, 1L ) )
#endif
break ;
if ( u4memcmp( t4key_data( relate->data_tag )->value, ptr, len ) )
{
#ifdef S4HAS_DESCENDING
t4dskip( relate->data_tag, -1L ) ;
#else
t4skip( relate->data_tag, -1L ) ;
#endif
break ;
}
}
recno = t4key_data( relate->data_tag )->num ;
if ( direction != 0 )
if ( f4flag_is_set_flip( &relate->set, recno ) == 0 )
return relate4filter_record ;
if ( d4go( relate->data, recno ) < 0 )
return -1 ;
return 0 ;
}
else
recno = t4key_data( relate->data_tag )->num ;
}
#endif
#ifdef S4CHANGE_BACK
if ( relate->relation_type == relate4scan ) /* no matching records, so filter */
return relate4filter_record ;
#endif
switch( relate->error_action ) /* if got here, must be error condition */
{
case relate4blank:
if ( d4go_eof( relate->data ) < 0 )
return -1 ;
if ( direction != 0 )
if ( f4flag_is_set_flip( &relate->set, recno ) == 0 )
return relate4filter_record ;
return 0 ;
case relate4skip_rec:
return relate4filter_record ;
case relate4terminate:
if ( relate->code_base->relate_error )
return e4( relate->code_base, e4lookup_err, relate->data->alias ) ;
return r4terminate ;
default:
#ifdef S4DEBUG
/* should never get this far */
e4severe( e4info, E4_RELATE_EAI ) ;
#endif
return -1 ;
}
}
RELATE4 *S4FUNCTION relate4lookup_relate( RELATE4 *relate, DATA4 *d4 )
{
RELATE4 *relate_return, *relate_on ;
if ( relate->data == d4 )
return relate ;
for( relate_on = 0 ;; )
{
relate_on = (RELATE4 *)l4next( &relate->slaves, relate_on) ;
if ( relate_on == 0 )
return 0 ;
relate_return = relate4lookup_relate( relate_on, d4 ) ;
if ( relate_return )
return relate_return ;
}
}
int S4FUNCTION relate4match_len( RELATE4 *relate, int match_len )
{
int len ;
#ifdef S4DEBUG
if ( relate == 0 )
e4severe( e4parm, E4_R4MATCH_LEN ) ;
#endif
if ( relate->code_base->error_code < 0 )
return -1 ;
len = expr4key_len( relate->master_expr ) ;
#ifdef S4CLIPPER
if ( match_len <= 0 )
match_len = len ;
#else
if ( match_len <= 0 )
{
relate->match_len = len ;
return match_len ;
}
#endif
#ifndef S4INDEX_OFF
#ifndef S4CLIPPER
if ( relate->data_tag )
if( expr4type( relate->data_tag->expr ) != r4str) /* make sure r4str only */
{
#ifdef S4DEBUG
e4( relate->code_base, e4relate, E4_RELATE_REL ) ;
#endif
return -1 ;
}
#endif
#endif
if ( match_len >= len )
match_len = len ;
#ifndef S4INDEX_OFF
if ( relate->data_tag )
{
len = expr4key_len( relate->data_tag->expr ) ;
if ( match_len >= len )
match_len = len ;
}
#endif
relate->match_len = match_len ;
relate4changed( relate ) ;
return match_len ;
}
int S4FUNCTION relate4next( RELATE4 **ptr_ptr )
{
RELATE4 *cur ;
void *next_link ;
int rc ;
#ifdef S4DEBUG
if ( ptr_ptr == 0 )
e4severe( e4parm, E4_R4NEXT ) ;
if ( *ptr_ptr == 0 )
e4severe( e4parm, E4_R4NEXT ) ;
#endif
cur = *ptr_ptr ;
rc = 1 ;
if ( cur->slaves.n_link > 0 )
{
*ptr_ptr = (RELATE4 *)l4first( &cur->slaves ) ;
return 1 ;
}
for(;;)
{
rc -- ;
if ( cur->master == 0 )
{
*ptr_ptr = 0 ;
return 2 ;
}
next_link = l4next( &cur->master->slaves, cur ) ;
if ( next_link )
{
*ptr_ptr = (RELATE4 *)next_link ;
return rc ;
}
cur = cur->master ;
}
}
int S4FUNCTION relate4next_record_in_scan( RELATE4 *relate )
{
long next_rec ;
int rc, save_code, len ;
B4KEY_DATA *key ;
char *ptr ;
#ifdef S4DEBUG
if ( relate == 0 )
e4severe( e4parm, E4_R4NEXT_RIS ) ;
#endif
if ( relate->code_base->error_code < 0 )
return -1 ;
if ( relate->relation->is_initialized == 0 )
{
#ifdef S4DEBUG
e4( relate->code_base, e4info, E4_INFO_REL ) ;
#endif
return -1 ;
}
if ( relate->relation->in_sort == relate4sort_skip && relate->sort_type == relate4sort_skip )
return r4eof ;
#ifndef S4INDEX_OFF
if ( relate->data_tag == 0 )
{
#endif
if ( d4bof( relate->data ) )
next_rec = 1 ;
else
next_rec = d4recno( relate->data ) + 1 ;
next_rec += f4flag_get_next_flip( &relate->set, next_rec, 1 ) ;
if ( next_rec > relate->data->count )
{
relate->data->count = d4reccount( relate->data ) ;
if ( next_rec > relate->data->count )
return r4eof ;
}
#ifndef S4INDEX_OFF
}
else
for(;;)
{
if ( d4bof( relate->data ) )
{
if ( relate->data->num_recs == 0 )
return r4eof ;
len = expr4key( relate->master_expr, &ptr ) ;
if ( len < 0 )
return -1 ;
len = (len < relate->match_len) ? len : relate->match_len ; /* min of len and match len */
rc = (int)t4seek( relate->data_tag, relate->master->scan_value, len ) ;
if ( rc < 0 )
return -1 ;
if ( rc == 0 )
rc = 1 ;
else
rc = 0 ;
}
else
#ifdef S4HAS_DESCENDING
rc = (int)t4dskip( relate->data_tag, 1 ) ;
#else
rc = (int)t4skip( relate->data_tag, 1 ) ;
#endif
if ( rc < 0 )
return -1 ;
if ( rc != 1 )
return r4eof ;
key = t4key_data( relate->data_tag) ;
next_rec = key->num ;
if ( relate->master )
if ( u4memcmp( key->value, relate->master->scan_value, relate->master->scan_value_len ) != 0 )
return r4eof ;
if ( f4flag_is_set_flip( &relate->set, next_rec ) )
break ;
}
#endif
save_code = relate->code_base->go_error ;
relate->code_base->go_error = 0 ;
rc = d4go( relate->data, next_rec ) ;
relate->code_base->go_error = save_code ;
if ( rc < 0 )
return -1 ;
if ( rc == r4entry )
return r4eof ;
relate->is_read = 1 ; /* we have updated this one */
return relate4skipped ;
}
int S4FUNCTION relate4next_scan_record( RELATION4 *relation )
{
RELATE4 *relate ;
int rc, rc2 ;
if ( relation->relate.code_base->error_code < 0 )
return -1 ;
relation->relate_list.selected = (void *)l4first( &relation->relate_list ) ;
for(;;)
{
relate = ((RELATE4LIST *)relation->relate_list.selected)->ptr ;
relate4set_not_read( relate ) ; /* This data file & its slaves */
if ( relation->in_sort == relate4sort_done )
if ( r4data_list_find( &relation->sort_data_list, relate ) )
return relate4sort_next_record( relation ) ;
rc = relate4next_record_in_scan( relate ) ;
if ( rc == relate4skipped )
return 0 ;
if ( rc < 0 )
return -1 ;
rc2 = relate4blank_set( relate, (char)1 ) ;
if ( rc2 == r4locked || rc2 < 0 ) /* error or locked */
return rc2 ;
if ( relate->master == 0 )
if ( d4eof( relate->data ) )
return r4eof ;
relation->relate_list.selected = l4next( &relation->relate_list, relation->relate_list.selected);
}
}
int S4FUNCTION relate4prev_record_in_scan( RELATE4 *relate )
{
long next_rec ;
int rc, save_code ;
B4KEY_DATA *key ;
#ifdef S4DEBUG
if ( relate == 0 )
e4severe( e4parm, E4_R4PREV_RIS ) ;
#endif
if ( relate->relation->is_initialized == 0 )
{
#ifdef S4DEBUG
e4( relate->code_base, e4info, E4_INFO_REL ) ;
#endif
return -1 ;
}
#ifndef S4INDEX_OFF
if ( relate->data_tag == 0 )
{
#endif
next_rec = d4recno( relate->data ) - 1 ;
next_rec -= f4flag_get_next_flip( &relate->set, next_rec, -1 ) ;
if ( next_rec <= 0 )
return r4bof ;
if ( next_rec > relate->data->count )
{
relate->data->count = d4reccount( relate->data ) ;
if ( next_rec > relate->data->count )
return r4eof ;
}
#ifndef S4INDEX_OFF
}
else
for(;;)
{
if ( relate4eof( relate ) ) /* if eof in relate, just leave on last tag entry */
rc = t4eof( relate->data_tag ) ? 0 : -1 ;
else
{
if ( d4eof( relate->data ) == 1 )
{
if ( relate->data->num_recs == 0 )
return r4bof ;
rc = (int)t4bottom( relate->data_tag ) ;
if ( rc < 0 )
return -1 ;
if ( rc == 0 )
rc = -1 ;
else
rc = 0 ;
}
else
#ifdef S4HAS_DESCENDING
rc = (int)t4dskip( relate->data_tag, -1L ) ;
#else
rc = (int)t4skip( relate->data_tag, -1L ) ;
#endif
}
if ( rc > 0 )
return -1 ;
if ( rc != -1L )
return r4bof ;
key = t4key_data( relate->data_tag) ;
next_rec = key->num ;
if ( relate->master )
if ( u4memcmp( key->value, relate->master->scan_value, relate->master->scan_value_len ) != 0 )
return r4bof ;
if ( f4flag_is_set_flip( &relate->set, next_rec ) )
break ;
}
#endif
save_code = relate->code_base->go_error ;
relate->code_base->go_error = 0 ;
rc = d4go( relate->data, next_rec ) ;
relate->code_base->go_error = save_code ;
if ( rc < 0 )
return -1 ;
if ( rc == r4entry )
return r4eof ;
relate->is_read = 1 ; /* we have updated this one */
return relate4skipped ;
}
int S4FUNCTION relate4prev_scan_record( RELATION4 *relation )
{
RELATE4 *relate ;
int rc, rc2 ;
if ( relation->relate.code_base->error_code < 0 )
return -1 ;
relate = ((RELATE4LIST *)l4last( &relation->relate_list ))->ptr ;
if ( relate4eof( relate ) ) /* at eof means we must read this record */
if ( relation->in_sort != relate4sort_done )
{
rc2 = relate->code_base->read_lock ; /* suspend the potential lock call... */
relate->code_base->read_lock = 0 ;
rc = relate4bottom( relate ) ;
relate->code_base->read_lock = rc2 ;
if ( rc == r4eof ) /* no records, so can't skip back */
return r4bof ;
else
return rc ;
}
relation->relate_list.selected = (void *)l4first( &relation->relate_list ) ;
for(;;)
{
relate = ((RELATE4LIST *)relation->relate_list.selected)->ptr ;
relate4set_not_read( relate ) ; /* This data file & its slaves */
if ( relation->in_sort == relate4sort_done )
if ( r4data_list_find( &relation->sort_data_list, relate ) )
return relate4sort_prev_record( relation ) ;
rc = relate4prev_record_in_scan(relate) ;
if ( rc == relate4skipped )
{
if ( relate4eof( relate ) )
{
if ( relate->relation->in_sort == relate4sort_done && relate->relation->sort_eof_flag == 1 )
{
relation->sort_rec_on-- ; /* move off eof on sort part */
relate->relation->sort_eof_flag = 0 ;
}
else
d4go( relate->relation->relate.data, d4reccount( relate->relation->relate.data ) ) ;
}
return 0 ;
}
if ( rc < 0 )
return -1 ;
rc2 = relate4blank_set( relate, (char)-1 ) ;
if ( rc2 == r4locked || rc2 < 0 ) /* error or locked */
return rc2 ;
if ( relate->master == 0 )
{
if ( d4bof(relate->data) )
return r4bof ;
if ( d4eof(relate->data) )
return r4eof ;
}
relation->relate_list.selected = l4next( &relation->relate_list, relation->relate_list.selected);
}
}
int S4FUNCTION relate4query_set( RELATE4 *relate, char *expr )
{
int len ;
if ( relate == 0 )
return -1 ;
#ifdef S4VBASIC
if ( c4parm_check( relate->code_base, 1, E4_R4QUERY_SET ) )
return -1 ;
#endif
if ( relate->code_base->error_code < 0 )
return -1 ;
relate4changed( relate ) ;
u4free( relate->relation->expr_source ) ;
relate->relation->expr_source = 0 ;
if ( expr == 0 )
return 0 ;
if ( expr[0] == 0 )
return 0 ;
len = strlen( expr ) + 1 ;
relate->relation->expr_source = (char *)u4alloc_er( relate->code_base, len ) ;
if ( relate->relation->expr_source == 0 )
return -1 ;
memcpy( relate->relation->expr_source, expr, len ) ;
return 0 ;
}
int S4FUNCTION relate4read_in( RELATE4 *relate )
{
int rc ;
if ( relate->code_base->error_code < 0 )
return -1 ;
if ( relate->is_read )
return 0 ;
if ( relate->master )
if ( relate->master->is_read == 0 )
{
rc = relate4read_in( relate->master ) ;
if ( rc == relate4filter_record || rc == r4terminate )
return rc ;
}
return relate4lookup( relate, 1 ) ;
}
int S4FUNCTION relate4read_rest( RELATE4 *relate, char direction )
{
RELATE4 *slave ;
int rc ;
int scan_done ;
#ifdef S4DEBUG
if ( relate == 0 )
e4severe( e4parm, E4_R4READ_REST ) ;
#endif
if ( relate->code_base->error_code < 0 )
return -1;
if ( relate->is_read == 0 )
{
rc = relate4lookup( relate, direction );
if ( rc < 0 || rc == relate4filter_record || rc == r4terminate )
return rc ;
}
scan_done = 0 ;
for( slave = 0 ;; )
{
slave = (RELATE4 *)l4next( &relate->slaves, slave ) ;
if ( slave == 0 )
return 0 ;
if ( slave->relation_type == relate4scan && scan_done == 1 )
{
relate4blank_set( slave, (char)(1 - direction) ) ;
slave->is_read = 1 ;
rc = relate4read_rest( slave, direction ) ;
}
else
{
rc = relate4read_rest( slave, direction ) ;
if ( slave->relation_type == relate4scan && rc == 0 )
if ( !d4eof( slave->data ) )
scan_done = 1 ;
}
if ( rc < 0 || rc == relate4filter_record || rc == r4terminate )
return rc ;
}
}
void S4FUNCTION relate4set_not_read( RELATE4 *relate )
{
RELATE4 *slave_on ;
if ( relate->is_read )
{
relate->is_read = 0 ;
for( slave_on = 0 ;; )
{
slave_on = (RELATE4 *)l4next(&relate->slaves,slave_on) ;
if ( slave_on == 0 )
return ;
relate4set_not_read( slave_on ) ;
}
}
}
int S4FUNCTION relate4skip( RELATE4 *relate, long num_skip )
{
int rc, sort_status, rc2 ;
#ifdef S4UNIX
int sign ;
#else
signed char sign ;
#endif
RELATION4 *relation ;
#ifdef S4REPORT
#ifdef S4WINDOWS
char countstring[22];
static long int scanreccount = 0, selectreccount = 0, sortreccount = 0;
HWND statwin;
#endif
#endif
#ifdef S4VBASIC
if ( c4parm_check( relate->code_base, 1, E4_R4SKIP ) )
return -1 ;
#endif
#ifdef S4DEBUG
if ( relate == 0 )
e4severe( e4parm, E4_R4SKIP ) ;
#endif
if ( relate->code_base->error_code < 0 )
return -1 ;
if ( relate->relation->is_initialized == 0 )
{
#ifdef S4DEBUG
e4( relate->code_base, e4info, E4_INFO_REL ) ;
#endif
return -1 ;
}
relation = relate->relation ;
relate = &relation->relate ;
if ( num_skip < 0 )
{
if ( relation->skip_backwards == 0 )
{
#ifdef S4DEBUG
e4describe( relate->code_base, e4info, E4_R4SKIP, E4_INFO_BAC, (char *)0 ) ;
#endif
return -1 ;
}
sign = -1 ;
}
else
sign = 1 ;
sort_status = 0 ;
rc = 0 ;
for( ; num_skip ; )
{
#ifdef S4REPORT
#ifdef S4WINDOWS
if(GetWindowWord(relate->code_base->hWnd,8) == 666)
statwin = relate->code_base->hWnd;
if( statwin )
{
if(GetWindowWord(statwin,6)==0)
{
SetWindowWord(statwin,6,1);
scanreccount = sortreccount = selectreccount = 0;
}
scanreccount++;
if( scanreccount < 20 || (scanreccount % 20) == 0 )
{
c4ltoa45(scanreccount,countstring,sizeof(countstring)-1);
countstring[21] = 0;
SendMessage((HWND)GetWindowWord(statwin,0),WM_SETTEXT,0,(LPARAM)((LPSTR)countstring));
}
}
#endif
#endif
if ( sign > 0 )
{
rc = relate4next_scan_record( relation ) ;
if ( rc == r4eof )
break ;
}
else
{
rc = relate4prev_scan_record( relation ) ;
if ( rc == r4bof )
break ;
}
#ifdef S4SINGLE
if ( rc < 0 )
#else
if ( rc < 0 || rc == r4locked )
#endif
break ;
rc = relate4read_rest( relate, sign ) ;
if ( rc == relate4filter_record )
continue ;
if ( rc < 0 || rc == r4terminate )
break ;
if ( relation->expr_source )
{
rc2 = log4true(&relation->log ) ;
if ( rc2 == r4terminate )
{
rc = r4terminate ;
break ;
}
if ( rc2 == 0 )
{
if ( relation->in_sort == relate4sort_skip ) /* must temporarily disable in order to get a matching scan if available */
{
sort_status = 1 ;
relation->in_sort = 0 ;
}
continue ;
}
}
num_skip -= sign ;
}
#ifdef S4WINDOWS
#ifdef S4REPORT
if(GetWindowWord(relate->code_base->hWnd,8) == 666)
statwin = relate->code_base->hWnd;
if( statwin )
{
selectreccount++;
if(selectreccount < 20 || (selectreccount % 20) == 0)
{
c4ltoa45(selectreccount,countstring,sizeof(countstring)-1);
countstring[21] = 0;
SendMessage((HWND)GetWindowWord(statwin,2),WM_SETTEXT,0,(LPARAM)((LPSTR)countstring));
}
if(relate->relation->in_sort)
{
sortreccount++;
if( sortreccount < 20 || (sortreccount % 20) == 0)
{
c4ltoa45(sortreccount,countstring,sizeof(countstring)-1);
countstring[21] = 0;
SendMessage((HWND)GetWindowWord(statwin,4),WM_SETTEXT,0,(LPARAM)((LPSTR)countstring));
}
}
}
#endif
#endif
if ( sort_status == 1 )
relation->in_sort = relate4sort_skip ;
return rc ;
}
int S4FUNCTION relate4skip_enable( RELATE4 *relate, int do_enable )
{
if ( relate == 0 )
return -1 ;
if ( relate->code_base->error_code < 0 )
return -1 ;
if ( relate->relation->skip_backwards != (char) do_enable )
{
relate->relation->skip_backwards = (char) do_enable ;
relate4changed( relate ) ;
}
return 0 ;
}
int S4FUNCTION relate4sort( RELATE4 *relate )
{
EXPR4 *sort_expr ;
int rc, i, len ;
long j, zero = 0L ;
char n_dbf, *sort_key ;
R4DATA_LIST *r4data ;
RELATION4 *relation ;
CODE4 *code_base ;
#ifdef S4DEBUG
if ( relate == 0 )
e4severe( e4parm, E4_R4SORT ) ;
#endif
code_base = relate->code_base ;
if ( code_base->error_code < 0 )
return -1 ;
relation = relate->relation ;
relate = &relation->relate ;
rc = 0 ;
sort_expr = expr4parse( relate->data, relation->sort_source ) ;
relation->in_sort = relate4sort_skip ;
relation->sort_done_flag = 0 ;
rc = relate4top( relate ) ;
if ( rc ) /* no records satisfy the relate, or error */
{
expr4free( sort_expr ) ;
return rc ;
}
len = expr4key( sort_expr, &sort_key ) ;
if ( len <= 0 )
{
expr4free( sort_expr ) ;
return -1 ;
}
#ifdef S4DEBUG
if ( relation->sort_data_list.n_link != 0 )
e4severe( e4parm, E4_PARM_NFD ) ;
#endif
if ( r4data_list_build( &relation->sort_data_list, relate, sort_expr, relate4exact ) < 0 )
{
expr4free( sort_expr ) ;
return -1 ;
}
if ( r4data_list_massage( &relation->sort_data_list ) < 0 )
{
expr4free( sort_expr ) ;
return -1 ;
}
n_dbf = (char) relation->sort_data_list.n_link ;
relation->sort_other_len = (unsigned)n_dbf * sizeof( long ) ;
relation->other_data = (char *)u4alloc( relation->sort_other_len ) ;
if ( relation->other_data == 0 )
return -1 ;
rc = sort4init_free( &relation->sort, code_base, len, relation->sort_other_len, relate ) ;
if ( rc )
{
expr4free( sort_expr ) ;
return rc ;
}
#ifndef S4FOX
#ifndef S4CLIPPER
switch( expr4type( sort_expr ) )
{
#ifdef S4NDX
case r4num:
case r4num_doub:
case r4date:
case r4date_doub:
relation->sort.cmp = t4cmp_doub ;
break ;
#endif
#ifdef S4MDX
case r4num:
/* if ( is_desc ) */
/* relation->sort.cmp = t4desc_bcd_cmp ; */
/* else */
relation->sort.cmp = c4bcd_cmp ;
break ;
case r4date:
/* if ( is_desc ) */
/* relation->sort.cmp = t4desc_cmp_doub ; */
/* else */
relation->sort.cmp = t4cmp_doub ;
break ;
/* case r4str: */
/* if ( is_desc ) */
/* relation->sort.cmp = t4desc_memcmp ; */
/* else */
/* relation->sort.cmp = u4memcmp ; */
#endif
default:
break ;
}
#endif
#endif
/* call relate4top() again in case free-ups occurred */
rc = relate4top( relate ) ;
if ( rc ) /* no records satisfy the relate, or error */
{
expr4free( sort_expr ) ;
return rc ;
}
for ( j = 0L, rc = 0 ; !rc ; j++, rc = relate4skip( relate, 1L ) )
{
for ( i = 0, r4data = 0 ;; i++ )
{
r4data = (R4DATA_LIST *)l4next( &relation->sort_data_list, r4data ) ;
if ( r4data == 0 )
break ;
if ( d4eof( r4data->data ) || d4bof( r4data->data ) ) /* relate4blank case */
memcpy( relation->other_data + i * sizeof(long), (void *)&zero, sizeof( long ) ) ;
else
memcpy( relation->other_data + i * sizeof(long), (void *)&r4data->data->rec_num, sizeof( long ) ) ;
}
if ( expr4key( sort_expr, &sort_key ) < 0 )
{
expr4free( sort_expr ) ;
u4free( relation->other_data ) ;
relation->other_data = 0 ;
return -1 ;
}
if ( sort4put( &relation->sort, j, sort_key, relation->other_data ) < 0 )
{
expr4free( sort_expr ) ;
u4free( relation->other_data ) ;
relation->other_data = 0 ;
return -1 ;
}
}
expr4free( sort_expr ) ;
if ( rc < 0 || rc == r4terminate )
{
u4free( relation->other_data ) ;
relation->other_data = 0 ;
return rc ;
}
relation->sort_rec_count = j ;
relation->in_sort = relate4sort_done ;
if ( relation->skip_backwards )
if ( file4temp( &relation->sorted_file, code_base, relation->sorted_file_name, 1 ) < 0 )
{
u4free( relation->other_data ) ;
relation->other_data = 0 ;
return -1 ;
}
if ( sort4get_init_free( &relation->sort, relate ) < 0 )
return -1 ;
relation->sort_rec_on = relation->sort_file_pos = relation->sort_rec_to = 0L ;
return 0 ;
}
void S4FUNCTION relate4sort_free( RELATION4 *relation, int delete_sort )
{
if ( relation == 0 )
return ;
sort4free( &relation->sort ) ;
u4free( relation->other_data ) ;
relation->other_data = 0 ;
if ( relation->sorted_file.hand >= 0 )
file4close( &relation->sorted_file ) ;
r4data_list_free( &relation->sort_data_list ) ;
relation->in_sort = 0 ;
if ( delete_sort )
{
u4free( relation->sort_source ) ;
relation->sort_source = 0 ;
}
}
int S4FUNCTION relate4sort_get_record( RELATION4 *relation, long num )
{
int len, i, rc ;
char *other, *key ;
R4DATA_LIST *link_on ;
long j, num_left ;
#ifdef S4UNIX
long long_ptr ;
#endif
if ( relation->relate.code_base->error_code < 0 )
return -1 ;
if ( num <= 0 )
return r4bof ;
relation->sort_eof_flag = 0 ;
num_left = num - relation->sort_rec_to ;
if ( num_left <= 0 ) /* already read, so just return from file */
{
if ( relation->skip_backwards == 0 )
return -1 ;
len = file4read( &relation->sorted_file, ( num - 1 ) * relation->sort_other_len, relation->other_data, relation->sort_other_len ) ;
if ( len != relation->sort_other_len ) /* free up and exit */
return -1 ;
other = relation->other_data ;
}
else
while ( num_left-- )
{
if ( relation->sort_done_flag == 1 ) /* sort is finished, therefore must be eof */
return r4eof ;
rc = sort4get( &relation->sort, &j, (void **)&key, (void **)&other ) ;
if ( rc ) /* no more items, or error */
{
sort4free( &relation->sort ) ;
if ( rc == 1 )
{
relation->sort_eof_flag = 1 ;
relation->sort_done_flag = 1 ;
return r4eof ;
}
else
return rc ;
}
relation->sort_rec_to++ ;
if ( relation->skip_backwards )
{
file4write( &relation->sorted_file, relation->sort_file_pos, other, relation->sort_other_len ) ;
relation->sort_file_pos += relation->sort_other_len ;
}
}
/* now read the database records in */
for ( i = 0, link_on = 0 ;; i++ )
{
link_on = (R4DATA_LIST *)l4next( &relation->sort_data_list, link_on ) ;
if ( link_on == 0 )
return 0 ;
#ifdef S4UNIX
memcpy( &long_ptr, (long *)other + i, sizeof(long_ptr) ) ;
if ( long_ptr == 0 ) /* relate4blank case */
d4go_eof( link_on->data ) ;
else
d4go( link_on->data, long_ptr ) ;
#else
if ( *((long *)other + i ) == 0 ) /* relate4blank case */
d4go_eof( link_on->data ) ;
else
d4go( link_on->data, *((long *)other + i ) ) ;
#endif
link_on->relate->is_read = 1 ;
}
}
int S4FUNCTION relate4sort_next_record( RELATION4 *relation )
{
int rc ;
if ( relation->relate.code_base->error_code < 0 )
return -1 ;
rc = relate4sort_get_record( relation, relation->sort_rec_on + 1 ) ;
if ( rc == 0 )
relation->sort_rec_on++ ;
if ( rc == r4eof )
relation->sort_rec_on = relation->sort_rec_count + 1 ;
return rc ;
}
int S4FUNCTION relate4sort_prev_record( RELATION4 *relation )
{
int rc ;
if ( relation->relate.code_base->error_code < 0 )
return -1 ;
rc = relate4sort_get_record( relation, relation->sort_rec_on - 1 ) ;
if ( rc == 0 )
relation->sort_rec_on-- ;
return rc ;
}
int S4FUNCTION relate4sort_set( RELATE4 *relate, char *expr )
{
RELATION4 *relation ;
int len ;
if ( relate == 0 )
return -1 ;
#ifdef S4VBASIC
if ( c4parm_check( relate->code_base, 1, E4_R4SORT_SET ) )
return -1 ;
#endif
if ( relate->code_base->error_code < 0 )
return -1 ;
relation = relate->relation ;
relate = &relation->relate ;
relate4changed( relate ) ;
u4free( relate->relation->sort_source ) ;
relate->relation->sort_source = 0 ;
if ( expr )
if ( expr[0] )
{
len = strlen( expr ) ;
relation->sort_source = (char *)u4alloc_er( relate->code_base, len + 1 ) ;
if ( relation->sort_source == 0 )
return -1 ;
memcpy( relation->sort_source, expr, len ) ;
}
return 0 ;
}
int S4FUNCTION relate4top( RELATE4 *relate )
{
RELATION4 *relation ;
int rc, rc2 ;
long rec ;
CODE4 *code_base ;
#ifndef S4OPTIMIZE_OFF
char has_opt ;
#endif
#ifdef S4VBASIC
if ( c4parm_check( relate->code_base, 1, E4_R4TOP ) )
return -1 ;
#endif
#ifdef S4DEBUG
if( relate == 0 )
e4severe( e4parm, E4_R4TOP ) ;
#else
if( relate == 0 )
return -1 ;
#endif
code_base = relate->code_base ;
if ( code_base->error_code < 0 )
return -1 ;
relation = relate->relation ;
relate = &relation->relate ;
rc = 0 ;
if ( relation->in_sort == relate4sort_done )
if ( relation->skip_backwards == 0 )
relate4changed( relate ) ;
relate->data_tag = d4tag_selected( relate->data ) ;
if ( relation->is_initialized == 0 )
{
#ifndef S4SINGLE
if ( code_base->read_lock )
rc = relate4lock( relate ) ;
#endif
#ifndef S4OPTIMIZE_OFF
has_opt = (char)code_base->has_opt ;
#endif
if ( rc < 0 )
return rc ;
relate->relation->bitmaps_freed = 0 ;
if ( relation->expr_source )
{
relation->log.expr = expr4parse( relate->data, relation->expr_source ) ;
if ( relation->log.expr == 0 )
return -1 ;
if ( log4bitmap_do( &relation->log ) < 0 )
relate->relation->bitmaps_freed = 1 ;
log4determine_evaluation_order( &relation->log ) ;
}
if ( relate4build_scan_list( relate, relation ) < 0 )
return -1 ;
relation->relate_list.selected = (void *)l4first( &relation->relate_list) ;
relation->is_initialized = 1 ;
if ( relation->sort_source )
{
rc = relate4sort( relate ) ;
if ( rc < 0 || rc == r4terminate )
return rc ;
}
#ifndef S4OPTIMIZE_OFF
if ( has_opt )
d4opt_restart( code_base ) ;
#endif
}
relate4set_not_read( relate ) ;
if ( relation->in_sort == relate4sort_done )
{
relation->sort_rec_on = 0 ;
rc = relate4sort_next_record( relation ) ;
}
else
rc = d4top( relate->data ) ;
if ( rc ) /* eof or error */
return rc ;
if ( relation->expr_source )
{
rec = d4recno( relate->data ) ;
if ( f4flag_is_set_flip( &relate->set, rec ) == 0 )
{
#ifndef S4INDEX_OFF
if ( relate->data_tag )
while ( f4flag_is_set_flip( &relate->set, rec ) == 0 )
{
#ifdef S4HAS_DESCENDING
rc = (int)t4dskip( relate->data_tag, 1L ) ;
#else
rc = (int)t4skip( relate->data_tag, 1L ) ;
#endif
if ( rc != 1 )
{
if ( rc == 0 )
{
d4go_eof( relate->data ) ;
return r4eof ;
}
return rc ;
}
rec = t4recno( relate->data_tag ) ;
}
else
{
#endif
rec = f4flag_get_next_flip( &relate->set, 1L, 1 ) + 1L ;
if ( rec > relate->data->count )
{
relate->data->count = d4reccount( relate->data ) ;
if ( rec > relate->data->count )
{
d4go_eof( relate->data ) ;
return r4eof ;
}
}
#ifndef S4INDEX_OFF
}
#endif
}
d4go( relate->data, rec ) ;
}
rc = relate4read_rest( relate, 1 ) ;
if ( rc == relate4filter_record )
return relate4skip( relate, 1L ) ;
if ( rc < 0 || rc == r4terminate )
return rc ;
if ( relation->expr_source )
{
rc2 = log4true( &relation->log ) ;
if ( rc2 == r4terminate )
return r4terminate ;
if ( rc2 == 0 )
{
if ( relation->in_sort == relate4sort_skip ) /* must temporarily disable in order to get a matching scan if available */
{
relation->in_sort = 0 ;
rc = relate4skip( relate, 1L ) ;
relation->in_sort = relate4sort_skip ;
}
else
rc = relate4skip( relate, 1L ) ;
}
}
return rc ;
}
int S4FUNCTION relate4type( RELATE4 *relate, int relate_type )
{
int rc ;
if ( relate == 0 )
return -1 ;
#ifdef S4DEBUG
if ( relate_type != relate4exact && relate_type != relate4scan && relate_type != relate4approx )
e4severe( e4parm, E4_INFO_IVT ) ;
#endif
rc = relate->relation_type ;
if ( rc != relate_type )
{
relate->relation_type = relate_type ;
relate4changed( relate ) ;
}
return rc ;
}
int S4FUNCTION relate4unlock( RELATE4 *relate )
{
#ifndef S4SINGLE
DATA4 *data_on ;
#ifdef S4DEBUG
if ( relate == 0 )
e4severe( e4parm, E4_R4UNLOCK ) ;
#endif
if ( !relate->relation->locked )
return 0 ;
for ( data_on = (DATA4 *)l4first( &relate->code_base->data_list) ; data_on ; data_on = (DATA4 *)l4next( &relate->code_base->data_list, data_on ) )
if ( relate4dbf_in_relation( relate, data_on ) )
d4unlock( data_on ) ;
relate->relation->locked = 0 ;
#endif
return 0 ;
}
#ifdef S4VB_DOS
RELATE4 *S4FUNCTION relate4create_slave_v( RELATE4 *master, DATA4 *slave, char *master_expr, TAG4 *slave_tag)
{
return relate4create_slave(master, slave, c4str(master_expr), slave_tag) ;
}
char * relate4master_expr_v( RELATE4 *r4 )
{
#ifdef S4VBASIC
if ( c4parm_check( r4->code_base, 1, "relate4masterExpr():" ) ) return 0 ;
#endif
return v4str(r4->master_expr->source) ;
}
int S4FUNCTION relate4query_set_v ( RELATE4 *relate, char *expr )
{
return relate4query_set( relate, c4str(expr) ) ;
}
int S4FUNCTION relate4sort_set_v ( RELATE4 *relate, char *expr )
{
return relate4sort_set( relate, c4str(expr) ) ;
}
#endif