which included commits to RCS files with non-trunk default branches. git-svn-id: svn://10.65.10.50/trunk@976 c028cbd2-c16b-5b4b-a496-9718f37d4682
		
			
				
	
	
		
			501 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			501 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
| /* 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 ;
 | |
| }
 |