501 lines
15 KiB
C
501 lines
15 KiB
C
|
/* r4log.c (c)Copyright Sequiter Software Inc., 1992-1994. All rights reserved. */
|
||
|
|
||
|
#include "d4all.h"
|
||
|
#ifdef __TURBOC__
|
||
|
#pragma hdrstop
|
||
|
#endif
|
||
|
|
||
|
int S4FUNCTION e4is_constant( E4INFO *info_ptr )
|
||
|
{
|
||
|
int pos ;
|
||
|
|
||
|
if ( info_ptr->function_i == E4DOUBLE || info_ptr->function_i == E4STRING ||
|
||
|
( info_ptr->function_i >= E4LOG_LOW && info_ptr->function_i <= E4LOG_HIGH ) )
|
||
|
return 1 ;
|
||
|
|
||
|
if ( info_ptr->function_i == E4STOD || info_ptr->function_i == E4CTOD ) /* might be a constant */
|
||
|
{
|
||
|
for ( pos = info_ptr->num_entries - 1 ; pos >= 0 ; pos -- )
|
||
|
if ( (info_ptr-pos)->field_ptr != 0 || (info_ptr-pos)->function_i >= E4CALC_FUNCTION )
|
||
|
return 0 ;
|
||
|
return 1 ;
|
||
|
}
|
||
|
|
||
|
return 0 ;
|
||
|
}
|
||
|
|
||
|
/* returns true if there is a tag that matches the desired condition type,
|
||
|
AND if there is no filter on that tag */
|
||
|
int S4FUNCTION e4is_tag( E4INFO_REPORT *report_ptr, EXPR4 *expr, E4INFO *info_ptr, DATA4 *data )
|
||
|
{
|
||
|
#ifndef S4INDEX_OFF
|
||
|
TAG4 *tag_on ;
|
||
|
int is_same, i ;
|
||
|
E4INFO *info_on, *tag_info ;
|
||
|
|
||
|
for( tag_on = 0;; )
|
||
|
{
|
||
|
tag_on = d4tag_next( data, tag_on ) ;
|
||
|
if ( tag_on == 0 )
|
||
|
break ;
|
||
|
#ifdef S4NDX
|
||
|
if ( t4unique( tag_on ) != r4unique_continue ) /* if unique, can't filter */
|
||
|
#else
|
||
|
if ( tag_on->filter == 0 && ( t4unique( tag_on ) != r4unique_continue ) ) /* if unique a filter, than cannot bitmap optimize */
|
||
|
#endif
|
||
|
{
|
||
|
tag_info = tag_on->expr->info + tag_on->expr->info_n -1 ;
|
||
|
if ( tag_info->num_entries == info_ptr->num_entries )
|
||
|
{
|
||
|
is_same = 1 ;
|
||
|
info_on = info_ptr ;
|
||
|
for( i = 0; i < info_ptr->num_entries && is_same; i++, info_on--, tag_info-- )
|
||
|
{
|
||
|
if ( memcmp( (void *)info_on, (void *)tag_info, sizeof(E4INFO)
|
||
|
- sizeof(info_on->i1) - sizeof(info_on->result_pos)
|
||
|
- sizeof(info_on->function_i) - sizeof(info_on->function))
|
||
|
!= 0 )
|
||
|
{
|
||
|
is_same = 0 ;
|
||
|
break ;
|
||
|
}
|
||
|
|
||
|
switch( info_on->function_i )
|
||
|
{
|
||
|
case E4DOUBLE:
|
||
|
case E4STRING:
|
||
|
case E4CTOD:
|
||
|
case E4DTOC:
|
||
|
case E4DTOC+1:
|
||
|
/* Compare Constant */
|
||
|
if( memcmp( tag_on->expr->constants + tag_info->i1, expr->constants + info_on->i1, tag_info->len ) != 0 )
|
||
|
is_same = 0 ;
|
||
|
break ;
|
||
|
|
||
|
default:
|
||
|
is_same = (info_on->i1 == tag_info->i1) ;
|
||
|
break ;
|
||
|
}
|
||
|
if( info_on->function_i != tag_info->function_i )
|
||
|
if( info_on->function_i > E4LAST_FIELD
|
||
|
|| tag_info->function_i > E4LAST_FIELD )
|
||
|
is_same = 0 ;
|
||
|
}
|
||
|
if( is_same )
|
||
|
{
|
||
|
report_ptr->tag = tag_on ;
|
||
|
return 1 ;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
return 0 ;
|
||
|
}
|
||
|
|
||
|
int S4FUNCTION data_list4add( DATA4LIST *list, CODE4 *code_base, RELATE4 *new_pointer )
|
||
|
{
|
||
|
if ( code_base->error_code < 0 )
|
||
|
return -1 ;
|
||
|
if ( new_pointer == 0 )
|
||
|
return 0 ;
|
||
|
if ( data_list4is_in( list, new_pointer ) )
|
||
|
return 0 ;
|
||
|
if( list->pointers_tot <= list->pointers_used )
|
||
|
{
|
||
|
list->pointers_tot += 5 ;
|
||
|
if ( u4alloc_again( code_base, (char **)&list->pointers, &list->mem_allocated, list->pointers_tot * sizeof(RELATE4 *)) < 0 )
|
||
|
return -1 ;
|
||
|
}
|
||
|
list->pointers[list->pointers_used++] = new_pointer ;
|
||
|
return 0 ;
|
||
|
}
|
||
|
|
||
|
int S4FUNCTION data_list4expand_from_db_tree( DATA4LIST *list, CODE4 *code_base )
|
||
|
{
|
||
|
int i ;
|
||
|
RELATE4 *relate_parent ;
|
||
|
|
||
|
for( i = list->pointers_used-1; i >= 0; i-- )
|
||
|
{
|
||
|
relate_parent = list->pointers[i]->master ;
|
||
|
while( relate_parent != 0 )
|
||
|
{
|
||
|
if ( data_list4add( list, code_base, relate_parent ) < 0 )
|
||
|
return -1 ;
|
||
|
relate_parent = relate_parent->master ;
|
||
|
}
|
||
|
}
|
||
|
if ( code_base->error_code < 0 )
|
||
|
return -1 ;
|
||
|
return 0 ;
|
||
|
}
|
||
|
|
||
|
int S4FUNCTION data_list4is_in( DATA4LIST *list, RELATE4 *new_pointer )
|
||
|
{
|
||
|
int i ;
|
||
|
for( i = 0 ; i < list->pointers_tot ; i++ )
|
||
|
if ( list->pointers[i] == new_pointer )
|
||
|
return 1 ;
|
||
|
return 0 ;
|
||
|
}
|
||
|
|
||
|
int S4FUNCTION data_list4read_records( DATA4LIST *data_list )
|
||
|
{
|
||
|
RELATE4 *cur ;
|
||
|
int i, rc ;
|
||
|
|
||
|
if ( data_list == 0 )
|
||
|
return 0 ;
|
||
|
|
||
|
for( i = data_list->pointers_used-1 ; i >= 0 ; i-- )
|
||
|
{
|
||
|
cur = data_list->pointers[i] ;
|
||
|
rc = relate4read_in( cur ) ;
|
||
|
if ( rc == relate4filter_record || rc == r4terminate )
|
||
|
return rc ;
|
||
|
if ( rc < 0 )
|
||
|
return -1 ;
|
||
|
}
|
||
|
return 0 ;
|
||
|
}
|
||
|
|
||
|
void S4FUNCTION data_list4remove( DATA4LIST *this_list, DATA4LIST *remove_list )
|
||
|
{
|
||
|
int i ;
|
||
|
|
||
|
#ifdef S4DEBUG
|
||
|
if ( this_list == 0 || remove_list == 0 )
|
||
|
e4severe( e4parm, E4_DATA_LIST4REM ) ;
|
||
|
#endif
|
||
|
|
||
|
for( i = 0; i < this_list->pointers_used; i++ )
|
||
|
if( data_list4is_in( remove_list, this_list->pointers[i]) )
|
||
|
this_list->pointers[i--] = this_list->pointers[--this_list->pointers_used] ;
|
||
|
}
|
||
|
|
||
|
int S4FUNCTION log4add_to_list( L4LOGICAL *log, E4INFO *info_ptr, DATA4LIST *list )
|
||
|
{
|
||
|
int num_parms, i ;
|
||
|
|
||
|
if ( info_ptr->function_i <= E4LAST_FIELD )
|
||
|
if ( data_list4add( list, log->code_base, relate4lookup_relate( (RELATE4 *)&log->relation->relate, f4data(info_ptr->field_ptr)) ) < 0 )
|
||
|
return -1 ;
|
||
|
|
||
|
if ( info_ptr->num_entries == 1 )
|
||
|
return 0 ;
|
||
|
|
||
|
num_parms = info_ptr->num_parms ;
|
||
|
info_ptr-- ;
|
||
|
|
||
|
for ( i = 0; i < num_parms; i++ )
|
||
|
{
|
||
|
if ( log4add_to_list( log, info_ptr, list ) < 0 )
|
||
|
return -1 ;
|
||
|
info_ptr -= info_ptr->num_entries ;
|
||
|
}
|
||
|
if ( log->code_base->error_code < 0 )
|
||
|
return -1 ;
|
||
|
return 0 ;
|
||
|
}
|
||
|
|
||
|
static int log4build_database_lists( L4LOGICAL *log )
|
||
|
{
|
||
|
int last_pos, pos, i ;
|
||
|
E4INFO *info_last ;
|
||
|
|
||
|
log->info_report = (E4INFO_REPORT *)u4alloc_er( log->code_base, (long)sizeof(E4INFO_REPORT) * log->expr->info_n ) ;
|
||
|
if ( log->info_report == 0 )
|
||
|
return -1 ;
|
||
|
|
||
|
last_pos = log->expr->info_n - 1 ;
|
||
|
info_last = (E4INFO *)log->expr->info + last_pos ;
|
||
|
|
||
|
if ( info_last->function_i == E4AND )
|
||
|
{
|
||
|
pos = last_pos - 1 ;
|
||
|
|
||
|
for ( i = 0; i < info_last->num_parms; i++ )
|
||
|
{
|
||
|
if ( log->info_report[pos].data_list == 0 )
|
||
|
{
|
||
|
log->info_report[pos].data_list = (DATA4LIST *)mem4create_alloc( log->code_base,
|
||
|
&log->relation->data_list_memory, 5, sizeof(DATA4LIST), 5, 0 ) ;
|
||
|
if ( log->info_report[pos].data_list == 0 )
|
||
|
return -1 ;
|
||
|
}
|
||
|
if ( log4add_to_list( log, log->expr->info+pos, log->info_report[pos].data_list ) < 0 )
|
||
|
return -1 ;
|
||
|
pos -= log->expr->info[pos].num_entries ;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if ( log->info_report[last_pos].data_list == 0 )
|
||
|
{
|
||
|
log->info_report[last_pos].data_list = (DATA4LIST *)mem4create_alloc( log->code_base,
|
||
|
&log->relation->data_list_memory, 5, sizeof( DATA4LIST ), 5, 0 ) ;
|
||
|
if ( log->info_report[last_pos].data_list == 0 )
|
||
|
return -1 ;
|
||
|
}
|
||
|
log4add_to_list( log, info_last, log->info_report[last_pos].data_list ) ;
|
||
|
}
|
||
|
|
||
|
if ( log->code_base->error_code < 0 )
|
||
|
return -1 ;
|
||
|
return 0 ;
|
||
|
}
|
||
|
|
||
|
int S4FUNCTION log4bitmap_do( L4LOGICAL *log )
|
||
|
{
|
||
|
if ( log->code_base->error_code < 0 )
|
||
|
return -1 ;
|
||
|
|
||
|
log4build_database_lists( log ) ;
|
||
|
#ifndef S4INDEX_OFF
|
||
|
if ( bitmap4evaluate( log, log->expr->info_n - 1 ) < 0 )
|
||
|
return -1 ;
|
||
|
#endif
|
||
|
if ( log->code_base->error_code < 0 )
|
||
|
return -1 ;
|
||
|
return 0 ;
|
||
|
}
|
||
|
|
||
|
int S4FUNCTION log4determine_evaluation_order( L4LOGICAL *log )
|
||
|
{
|
||
|
/* Expand Lists due to Database Tree */
|
||
|
int i, pos, num_left, cur_smallest_pos, cur_smallest_num, cur_pos ;
|
||
|
int num_compare, last_pos = log->expr->info_n -1 ;
|
||
|
E4INFO *info_last, *info_ptr ;
|
||
|
E4INFO_REPORT *report_last, *report, *cur_report ;
|
||
|
|
||
|
info_last = (E4INFO *)log->expr->info + last_pos ;
|
||
|
report_last = log->info_report + last_pos ;
|
||
|
|
||
|
if ( info_last->function_i != E4AND )
|
||
|
return data_list4expand_from_db_tree( report_last->data_list, log->code_base ) ;
|
||
|
|
||
|
info_ptr = info_last-1 ;
|
||
|
report = report_last-1 ;
|
||
|
for ( i = 0; i < info_last->num_parms; i++ )
|
||
|
{
|
||
|
if ( data_list4expand_from_db_tree(report->data_list, log->code_base) < 0 )
|
||
|
return -1 ;
|
||
|
|
||
|
report -= info_ptr->num_entries ;
|
||
|
info_ptr -= info_ptr->num_entries ;
|
||
|
}
|
||
|
|
||
|
/* Change the evaluation orders by repeatedly determining the
|
||
|
list with the smallest number of entries and puting it at the end.
|
||
|
The idea is that we want the conditions which causes the fewest
|
||
|
additional database records to be read in, to be evaluated first.
|
||
|
*/
|
||
|
pos = last_pos - 1 ; /* Position currently being made into the fewest. */
|
||
|
|
||
|
for( num_left = info_last->num_parms; num_left > 1; num_left-- )
|
||
|
{
|
||
|
report = log->info_report + pos ;
|
||
|
info_ptr = (E4INFO *)log->expr->info + pos ;
|
||
|
|
||
|
/* Now determine which is the entry with the fewest data files. */
|
||
|
cur_smallest_pos = pos ;
|
||
|
cur_smallest_num = report->data_list->pointers_used ;
|
||
|
|
||
|
cur_pos = pos - info_ptr->num_entries ;
|
||
|
for( num_compare = num_left-1; num_compare > 0; num_compare-- )
|
||
|
{
|
||
|
cur_report = log->info_report + cur_pos ;
|
||
|
|
||
|
if ( cur_report->data_list->pointers_used < cur_smallest_num )
|
||
|
{
|
||
|
cur_smallest_num = cur_report->data_list->pointers_used ;
|
||
|
cur_smallest_pos = cur_pos ;
|
||
|
}
|
||
|
|
||
|
cur_pos -= log->expr->info[cur_pos].num_entries ;
|
||
|
}
|
||
|
|
||
|
if( pos != cur_smallest_pos )
|
||
|
if ( log4swap_entries( log, pos, cur_smallest_pos ) < 0 )
|
||
|
return -1 ;
|
||
|
|
||
|
/* The next step is to remove the data list for the first evaluated
|
||
|
condition from the data list of the rest of the conditions. */
|
||
|
cur_pos = pos - info_ptr->num_entries ;
|
||
|
for( i = num_left-1; i > 0; i-- )
|
||
|
{
|
||
|
cur_report = log->info_report + cur_pos ;
|
||
|
data_list4remove( cur_report->data_list, report->data_list ) ;
|
||
|
cur_pos -= log->expr->info[cur_pos].num_entries ;
|
||
|
}
|
||
|
|
||
|
pos -= info_ptr->num_entries ;
|
||
|
}
|
||
|
if ( log->code_base->error_code < 0 )
|
||
|
return -1 ;
|
||
|
return 0 ;
|
||
|
}
|
||
|
|
||
|
int S4FUNCTION log4swap_entries( L4LOGICAL *log, int a, int b )
|
||
|
{
|
||
|
int large_entries, small_entries ;
|
||
|
char *save_buf ;
|
||
|
E4INFO *a_ptr, *b_ptr, *small, *large, *middle ;
|
||
|
E4INFO_REPORT *small2, *large2, *middle2 ;
|
||
|
int small_pos, large_pos, middle_pos, middle_entries, move_positions ;
|
||
|
|
||
|
if ( log->code_base->error_code < 0 )
|
||
|
return -1 ;
|
||
|
|
||
|
a_ptr = log->expr->info + a ;
|
||
|
b_ptr = log->expr->info + b ;
|
||
|
|
||
|
if ( a_ptr->num_entries > b_ptr->num_entries )
|
||
|
{
|
||
|
small = b_ptr ;
|
||
|
large = a_ptr ;
|
||
|
small_pos = b ;
|
||
|
large_pos = a ;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
small = a_ptr ;
|
||
|
large = b_ptr ;
|
||
|
small_pos = a ;
|
||
|
large_pos = b ;
|
||
|
}
|
||
|
|
||
|
/* make copies of large and small entries because the info may be later
|
||
|
lost as swaps take place... */
|
||
|
large_entries = large->num_entries ;
|
||
|
small_entries = small->num_entries ;
|
||
|
save_buf = (char *)u4alloc_free( log->code_base, sizeof(E4INFO) * large_entries ) ;
|
||
|
if ( save_buf == 0 )
|
||
|
return e4( log->code_base, e4memory, E4_INFO_EXP ) ;
|
||
|
|
||
|
move_positions = large_entries - small_entries ;
|
||
|
if ( small_pos < large_pos )
|
||
|
{
|
||
|
middle_pos = small_pos + 1 ;
|
||
|
middle_entries = large_pos - small_pos - large_entries ;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
middle_pos = large_pos + 1 ;
|
||
|
middle_entries = small_pos - large_pos - small_entries ;
|
||
|
move_positions = -move_positions ;
|
||
|
}
|
||
|
middle = log->expr->info + middle_pos ;
|
||
|
|
||
|
memcpy( save_buf, (void *)(large - large_entries + 1), sizeof(E4INFO) * large_entries ) ;
|
||
|
if ( large_pos > small_pos ) /* want to move small to end of large pos... */
|
||
|
{
|
||
|
memcpy( (void *)(large - small_entries + 1 ), (void *)(small - small_entries + 1),
|
||
|
sizeof(E4INFO) *small_entries ) ;
|
||
|
memmove( (void *)(middle + move_positions), middle, sizeof(E4INFO) * middle_entries ) ;
|
||
|
memcpy( (void *)(small - small_entries + 1), save_buf, sizeof(E4INFO) * large_entries ) ;
|
||
|
}
|
||
|
else /* want to move small to start of large pos... */
|
||
|
{
|
||
|
memcpy( (void *)(large - large_entries + 1 ), (void *)(small - small_entries + 1),
|
||
|
sizeof(E4INFO) *small_entries ) ;
|
||
|
memmove( (void *)(middle + move_positions), middle, sizeof(E4INFO) * middle_entries ) ;
|
||
|
memcpy( (void *)(small - large_entries + 1), save_buf, sizeof(E4INFO) * large_entries ) ;
|
||
|
}
|
||
|
|
||
|
large2 = log->info_report + large_pos ;
|
||
|
small2 = log->info_report + small_pos ;
|
||
|
middle2 = log->info_report + middle_pos ;
|
||
|
|
||
|
memcpy( save_buf, (void *)(large2 - large_entries + 1), sizeof(E4INFO_REPORT) * large_entries ) ;
|
||
|
if ( large_pos > small_pos ) /* want to move small to end of large pos... */
|
||
|
{
|
||
|
memcpy( (void *)(large2 - small_entries + 1), (void *)(small2 - small_entries + 1),
|
||
|
sizeof(E4INFO_REPORT) *small_entries ) ;
|
||
|
memmove( middle2 + move_positions, middle2, sizeof(E4INFO_REPORT) * middle_entries ) ;
|
||
|
memcpy( (void *)(small2 - small_entries + 1), save_buf, sizeof(E4INFO_REPORT) * large_entries ) ;
|
||
|
}
|
||
|
else /* want to move small to start of large pos... */
|
||
|
{
|
||
|
memcpy( (void *)(large2 - large_entries + 1), (void *)(small2 - small_entries + 1),
|
||
|
sizeof(E4INFO_REPORT) *small_entries ) ;
|
||
|
memmove( middle2 + move_positions, middle2, sizeof(E4INFO_REPORT) * middle_entries ) ;
|
||
|
memcpy( (void *)(small2 - large_entries + 1), save_buf, sizeof(E4INFO_REPORT) * large_entries ) ;
|
||
|
}
|
||
|
|
||
|
u4free( save_buf ) ;
|
||
|
|
||
|
return 0 ;
|
||
|
}
|
||
|
|
||
|
/* Must read in records, as appropriate, to evaluate the different parts of */
|
||
|
/* the expression. */
|
||
|
int S4FUNCTION log4true( L4LOGICAL *log )
|
||
|
{
|
||
|
int cur_pos, rc, i, *result_ptr ;
|
||
|
E4INFO *info_ptr ;
|
||
|
E4INFO_REPORT *info_report_ptr ;
|
||
|
int n_parms = 1 ;
|
||
|
cur_pos = log->expr->info_n - 1 ;
|
||
|
|
||
|
if( log->expr->info[cur_pos].function_i == E4AND )
|
||
|
{
|
||
|
n_parms = log->expr->info[cur_pos].num_parms ;
|
||
|
cur_pos-- ;
|
||
|
}
|
||
|
|
||
|
/* Go through each of the & sub-expressions and evaluate them, first */
|
||
|
/* reading in the appropriate database records for the sub-expression. */
|
||
|
|
||
|
for( i = 0; i < n_parms; i++ )
|
||
|
{
|
||
|
info_ptr = log->expr->info + cur_pos ;
|
||
|
info_report_ptr = log->info_report + cur_pos ;
|
||
|
|
||
|
rc = data_list4read_records( info_report_ptr->data_list ) ;
|
||
|
if ( rc == relate4filter_record )
|
||
|
return 0 ;
|
||
|
if ( rc == r4terminate )
|
||
|
return rc ;
|
||
|
if ( rc < 0 )
|
||
|
return -1 ;
|
||
|
|
||
|
if ( log->expr->info[cur_pos].num_parms < 2 )
|
||
|
{
|
||
|
if ( expr4execute( log->expr, cur_pos, (void **)&result_ptr ) < 0 )
|
||
|
return -1 ;
|
||
|
if ( *result_ptr == 0 )
|
||
|
return 0 ;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
#ifdef S4TEST
|
||
|
#ifdef S4DEBUG
|
||
|
/* in debug case, if tag, the result must always be true if we get here... */
|
||
|
if ( log->code_base->bitmap_disable == 0 && !log->relation->bitmaps_freed ) /* then do check */
|
||
|
{
|
||
|
if ( expr4execute( log->expr, cur_pos, (void **)&result_ptr ) < 0 )
|
||
|
return -1 ;
|
||
|
if ( ( (info_report_ptr-1)->tag || (info_report_ptr-2)->tag ) )
|
||
|
if ( *result_ptr == 0 )
|
||
|
e4severe( e4info, E4_LOG4TRUE ) ;
|
||
|
}
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
if ( ( (info_report_ptr-1)->tag == 0 && (info_report_ptr-2)->tag == 0 ) || log->relation->bitmaps_freed )
|
||
|
{
|
||
|
if ( expr4execute( log->expr, cur_pos, (void **)&result_ptr ) < 0 )
|
||
|
return -1 ;
|
||
|
if ( *result_ptr == 0 )
|
||
|
return 0 ;
|
||
|
}
|
||
|
}
|
||
|
cur_pos -= info_ptr->num_entries ;
|
||
|
}
|
||
|
if ( log->code_base->error_code < 0 )
|
||
|
return -1 ;
|
||
|
return 1 ;
|
||
|
}
|