alex af15e0698b Codebase
git-svn-id: svn://10.65.10.50/trunk@4679 c028cbd2-c16b-5b4b-a496-9718f37d4682
1997-06-16 13:01:08 +00:00

539 lines
17 KiB
C
Executable File

/* r4log.c (c)Copyright Sequiter Software Inc., 1988-1996. All rights reserved. */
#include "d4all.h"
#ifdef __TURBOC__
#pragma hdrstop
#endif
#ifndef S4CLIENT
static int dataList4isIn( DATA4LIST *, const RELATE4 * ) ;
static int log4swapEntries( L4LOGICAL *, const int, const int ) ;
int e4isConstant( E4INFO *infoPtr )
{
int pos ;
if ( infoPtr->functionI == E4DOUBLE || infoPtr->functionI == E4STRING ||
( infoPtr->functionI >= E4LOG_LOW && infoPtr->functionI <= E4LOG_HIGH ) )
return 1 ;
if ( infoPtr->functionI == E4STOD || infoPtr->functionI == E4CTOD ) /* might be a constant */
{
for ( pos = infoPtr->numEntries - 1 ; pos >= 0 ; pos -- )
if ( (infoPtr-pos)->fieldPtr != 0 || (infoPtr-pos)->functionI >= 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 */
#ifdef P4ARGS_USED
#pragma argsused
#endif
int e4isTag( E4INFO_REPORT *reportPtr, EXPR4 *expr, E4INFO *infoPtr, DATA4 *data )
{
#ifndef S4INDEX_OFF
TAG4 *tagOn ;
int isSame, i ;
E4INFO *infoOn, *tagInfo ;
for( tagOn = 0;; )
{
tagOn = d4tagNext( data, tagOn ) ;
if ( tagOn == 0 )
break ;
#ifdef S4NDX
if ( t4unique( tagOn ) != r4uniqueContinue ) /* if unique, can't filter */
#else
if ( tagOn->tagFile->filter == 0 && ( t4unique( tagOn ) != r4uniqueContinue ) ) /* if unique a filter, than cannot bitmap optimize */
#endif
{
tagInfo = tagOn->tagFile->expr->info + tagOn->tagFile->expr->infoN -1 ;
if ( tagInfo->numEntries == infoPtr->numEntries )
{
isSame = 1 ;
infoOn = infoPtr ;
for( i = 0; i < infoPtr->numEntries && isSame; i++, infoOn--, tagInfo-- )
{
/* verify the general info structure */
if ((infoOn->len != tagInfo->len) || (infoOn->numEntries != tagInfo->numEntries) || (infoOn->numParms != tagInfo->numParms))
{
isSame = 0 ;
break ;
}
/* general match, so ensure a field match if appropriate */
if ( infoOn->fieldPtr == 0 )
{
if ( tagInfo->fieldPtr != 0 )
{
isSame = 0 ;
break ;
}
}
else
{
if ( tagInfo->fieldPtr == 0 )
{
isSame = 0 ;
break ;
}
if ( c4memcmp( infoOn->fieldPtr, tagInfo->fieldPtr, sizeof( tagInfo->fieldPtr->name )
+ sizeof( tagInfo->fieldPtr->len ) + sizeof( tagInfo->fieldPtr->dec )
+ sizeof( tagInfo->fieldPtr->type ) + sizeof( tagInfo->fieldPtr->offset ) ) )
{
isSame = 0 ;
break ;
}
}
switch( infoOn->functionI )
{
case E4DOUBLE:
case E4STRING:
case E4CTOD:
case E4DTOC:
case E4DTOC+1:
/* Compare Constant */
if( c4memcmp( tagOn->tagFile->expr->constants + tagInfo->i1, expr->constants + infoOn->i1, (unsigned int)tagInfo->len ) != 0 )
isSame = 0 ;
break ;
default:
isSame = (infoOn->i1 == tagInfo->i1) ;
break ;
}
if( infoOn->functionI != tagInfo->functionI )
if( infoOn->functionI > E4LAST_FIELD
|| tagInfo->functionI > E4LAST_FIELD )
isSame = 0 ;
}
if( isSame )
{
reportPtr->tag = tagOn->tagFile ;
return 1 ;
}
}
}
}
#endif
return 0 ;
}
static int dataList4add( DATA4LIST *list, CODE4 *codeBase, RELATE4 *newPointer )
{
if ( error4code( codeBase ) < 0 )
return -1 ;
if ( newPointer == 0 )
return 0 ;
if ( dataList4isIn( list, newPointer ) )
return 0 ;
if( list->pointersTot <= list->pointersUsed )
{
list->pointersTot += 5 ;
if ( u4allocAgain( codeBase, (char **)&list->pointers, &list->memAllocated, list->pointersTot * sizeof(RELATE4 *)) < 0 )
return -1 ;
}
list->pointers[list->pointersUsed++] = newPointer ;
return 0 ;
}
static int dataList4expandFromDbTree( DATA4LIST *list, CODE4 *codeBase )
{
int i ;
RELATE4 *relateParent ;
for( i = list->pointersUsed-1; i >= 0; i-- )
{
relateParent = list->pointers[i]->master ;
while( relateParent != 0 )
{
if ( dataList4add( list, codeBase, relateParent ) < 0 )
return -1 ;
relateParent = relateParent->master ;
}
}
if ( error4code( codeBase ) < 0 )
return -1 ;
return 0 ;
}
static int dataList4isIn( DATA4LIST *list, const RELATE4 *newPointer )
{
int i ;
for( i = 0 ; i < list->pointersTot ; i++ )
if ( list->pointers[i] == newPointer )
return 1 ;
return 0 ;
}
static int dataList4readRecords( DATA4LIST *dList )
{
RELATE4 *cur ;
int i, rc ;
if ( dList == 0 )
return 0 ;
for( i = dList->pointersUsed-1 ; i >= 0 ; i-- )
{
cur = dList->pointers[i] ;
rc = relate4readIn( cur ) ;
if ( rc == relate4filterRecord || rc == r4terminate )
return rc ;
if ( rc < 0 )
return -1 ;
}
return 0 ;
}
static int dataList4remove( DATA4LIST *thisList, DATA4LIST *removeList )
{
int i ;
#ifdef E4PARM_LOW
if ( thisList == 0 || removeList == 0 )
return error4( 0, e4parm_null, E96001 ) ;
#endif
for( i = 0; i < thisList->pointersUsed; i++ )
if( dataList4isIn( removeList, thisList->pointers[i]) )
thisList->pointers[i--] = thisList->pointers[--thisList->pointersUsed] ;
return 0 ;
}
static int log4addToList( L4LOGICAL *log, E4INFO *infoPtr, DATA4LIST *list )
{
int numParms, i ;
if ( infoPtr->functionI <= E4LAST_FIELD )
if ( dataList4add( list, log->codeBase, relate4lookupRelate( (RELATE4 *)&log->relation->relate, f4data(infoPtr->fieldPtr)) ) < 0 )
return -1 ;
if ( infoPtr->numEntries == 1 )
return 0 ;
numParms = infoPtr->numParms ;
infoPtr-- ;
for ( i = 0; i < numParms; i++ )
{
if ( log4addToList( log, infoPtr, list ) < 0 )
return -1 ;
infoPtr -= infoPtr->numEntries ;
}
if ( error4code( log->codeBase ) < 0 )
return -1 ;
return 0 ;
}
int log4buildDatabaseLists( L4LOGICAL *log )
{
int lastPos, pos, i ;
E4INFO *infoLast ;
log->infoReport = (E4INFO_REPORT *)u4allocEr( log->codeBase, (long)sizeof(E4INFO_REPORT) * log->expr->infoN ) ;
if ( log->infoReport == 0 )
return -1 ;
lastPos = log->expr->infoN - 1 ;
infoLast = (E4INFO *)log->expr->info + lastPos ;
if ( infoLast->functionI == E4AND )
{
pos = lastPos - 1 ;
for ( i = 0; i < infoLast->numParms; i++ )
{
if ( log->infoReport[pos].relateDataList == 0 )
{
log->infoReport[pos].relateDataList = (DATA4LIST *)mem4createAlloc( log->codeBase,
&log->codeBase->dataListMemory, 5, sizeof(DATA4LIST), 5, 0 ) ;
if ( log->infoReport[pos].relateDataList == 0 )
return -1 ;
}
if ( log4addToList( log, log->expr->info+pos, log->infoReport[pos].relateDataList ) < 0 )
return -1 ;
pos -= log->expr->info[pos].numEntries ;
}
}
else
{
if ( log->infoReport[lastPos].relateDataList == 0 )
{
log->infoReport[lastPos].relateDataList = (DATA4LIST *)mem4createAlloc( log->codeBase,
&log->codeBase->dataListMemory, 5, sizeof( DATA4LIST ), 5, 0 ) ;
if ( log->infoReport[lastPos].relateDataList == 0 )
return -1 ;
}
log4addToList( log, infoLast, log->infoReport[lastPos].relateDataList ) ;
}
if ( error4code( log->codeBase ) < 0 )
return -1 ;
return 0 ;
}
int log4bitmapDo( L4LOGICAL *log )
{
if ( error4code( log->codeBase ) < 0 )
return -1 ;
log4buildDatabaseLists( log ) ;
#ifndef S4INDEX_OFF
if ( bitmap4evaluate( log, log->expr->infoN - 1 ) < 0 )
return -1 ;
#endif
if ( error4code( log->codeBase ) < 0 )
return -1 ;
return 0 ;
}
int log4determineEvaluationOrder( L4LOGICAL *log )
{
/* Expand Lists due to Database Tree */
int i, pos, numLeft, curSmallestPos, curSmallestNum, curPos ;
int numCompare, lastPos = log->expr->infoN -1 ;
E4INFO *infoLast, *infoPtr ;
E4INFO_REPORT *reportLast, *report, *curReport ;
infoLast = (E4INFO *)log->expr->info + lastPos ;
reportLast = log->infoReport + lastPos ;
if ( infoLast->functionI != E4AND )
return dataList4expandFromDbTree( reportLast->relateDataList, log->codeBase ) ;
infoPtr = infoLast-1 ;
report = reportLast-1 ;
for ( i = 0; i < infoLast->numParms; i++ )
{
if ( dataList4expandFromDbTree(report->relateDataList, log->codeBase) < 0 )
return -1 ;
report -= infoPtr->numEntries ;
infoPtr -= infoPtr->numEntries ;
}
/* 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 = lastPos - 1 ; /* Position currently being made into the fewest. */
for( numLeft = infoLast->numParms; numLeft > 1; numLeft-- )
{
report = log->infoReport + pos ;
infoPtr = (E4INFO *)log->expr->info + pos ;
/* Now determine which is the entry with the fewest data files. */
curSmallestPos = pos ;
curSmallestNum = report->relateDataList->pointersUsed ;
curPos = pos - infoPtr->numEntries ;
for( numCompare = numLeft-1; numCompare > 0; numCompare-- )
{
curReport = log->infoReport + curPos ;
if ( curReport->relateDataList->pointersUsed < curSmallestNum )
{
curSmallestNum = curReport->relateDataList->pointersUsed ;
curSmallestPos = curPos ;
}
curPos -= log->expr->info[curPos].numEntries ;
}
if( pos != curSmallestPos )
if ( log4swapEntries( log, pos, curSmallestPos ) < 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. */
curPos = pos - infoPtr->numEntries ;
for( i = numLeft-1; i > 0; i-- )
{
curReport = log->infoReport + curPos ;
dataList4remove( curReport->relateDataList, report->relateDataList ) ;
curPos -= log->expr->info[curPos].numEntries ;
}
pos -= infoPtr->numEntries ;
}
if ( error4code( log->codeBase ) < 0 )
return -1 ;
return 0 ;
}
static int log4swapEntries( L4LOGICAL *log, const int a, const int b )
{
int largeEntries, smallEntries ;
char *saveBuf ;
E4INFO *aPtr, *bPtr, *small1, *large1, *middle1;
E4INFO_REPORT *small2, *large2, *middle2 ;
int smallPos, largePos, middlePos, middleEntries, movePositions ;
if ( error4code( log->codeBase ) < 0 )
return -1 ;
aPtr = log->expr->info + a ;
bPtr = log->expr->info + b ;
if ( aPtr->numEntries > bPtr->numEntries )
{
small1= bPtr ;
large1= aPtr ;
smallPos = b ;
largePos = a ;
}
else
{
small1= aPtr ;
large1= bPtr ;
smallPos = a ;
largePos = b ;
}
/* make copies of large and small entries because the info may be later
lost as swaps take place... */
largeEntries = large1->numEntries ;
smallEntries = small1->numEntries ;
saveBuf = (char *)u4allocFree( log->codeBase, (long)sizeof(E4INFO) * largeEntries ) ;
if ( saveBuf == 0 )
return error4( log->codeBase, e4memory, E86001 ) ;
movePositions = largeEntries - smallEntries ;
if ( smallPos < largePos )
{
middlePos = smallPos + 1 ;
middleEntries = largePos - smallPos - largeEntries ;
}
else
{
middlePos = largePos + 1 ;
middleEntries = smallPos - largePos - smallEntries ;
movePositions = -movePositions ;
}
middle1= log->expr->info + middlePos ;
memcpy( saveBuf, (void *)(large1- largeEntries + 1), sizeof(E4INFO) * largeEntries ) ;
if ( largePos > smallPos ) /* want to move small to end of large pos... */
{
memcpy( (void *)(large1- smallEntries + 1 ), (void *)(small1- smallEntries + 1),
sizeof(E4INFO) *smallEntries ) ;
c4memmove( (void *)(middle1+ movePositions), middle1, sizeof(E4INFO) * middleEntries ) ;
memcpy( (void *)(small1- smallEntries + 1), saveBuf, sizeof(E4INFO) * largeEntries ) ;
}
else /* want to move small to start of large pos... */
{
memcpy( (void *)(large1- largeEntries + 1 ), (void *)(small1- smallEntries + 1),
sizeof(E4INFO) *smallEntries ) ;
c4memmove( (void *)(middle1+ movePositions), middle1, sizeof(E4INFO) * middleEntries ) ;
memcpy( (void *)(small1- largeEntries + 1), saveBuf, sizeof(E4INFO) * largeEntries ) ;
}
large2 = log->infoReport + largePos ;
small2 = log->infoReport + smallPos ;
middle2 = log->infoReport + middlePos ;
memcpy( saveBuf, (void *)(large2 - largeEntries + 1), sizeof(E4INFO_REPORT) * largeEntries ) ;
if ( largePos > smallPos ) /* want to move small to end of large pos... */
{
memcpy( (void *)(large2 - smallEntries + 1), (void *)(small2 - smallEntries + 1),
sizeof(E4INFO_REPORT) *smallEntries ) ;
c4memmove( middle2 + movePositions, middle2, sizeof(E4INFO_REPORT) * middleEntries ) ;
memcpy( (void *)(small2 - smallEntries + 1), saveBuf, sizeof(E4INFO_REPORT) * largeEntries ) ;
}
else /* want to move small to start of large pos... */
{
memcpy( (void *)(large2 - largeEntries + 1), (void *)(small2 - smallEntries + 1),
sizeof(E4INFO_REPORT) *smallEntries ) ;
c4memmove( middle2 + movePositions, middle2, sizeof(E4INFO_REPORT) * middleEntries ) ;
memcpy( (void *)(small2 - largeEntries + 1), saveBuf, sizeof(E4INFO_REPORT) * largeEntries ) ;
}
u4free( saveBuf ) ;
return 0 ;
}
/* Must read in records, as appropriate, to evaluate the different parts of */
/* the expression. */
int log4true( L4LOGICAL *log )
{
int curPos, rc, i, *resultPtr ;
E4INFO *infoPtr ;
E4INFO_REPORT *infoReportPtr ;
int nParms = 1 ;
curPos = log->expr->infoN - 1 ;
if( log->expr->info[curPos].functionI == E4AND )
{
nParms = log->expr->info[curPos].numParms ;
curPos-- ;
}
/* Go through each of the & sub-expressions and evaluate them, first */
/* reading in the appropriate database records for the sub-expression. */
if ( expr4context( log->expr, log->expr->data ) < 0 )
return -1 ;
for( i = 0; i < nParms; i++ )
{
infoPtr = log->expr->info + curPos ;
infoReportPtr = log->infoReport + curPos ;
rc = dataList4readRecords( infoReportPtr->relateDataList ) ;
if ( rc == relate4filterRecord )
return 0 ;
if ( rc == r4terminate )
return rc ;
if ( rc < 0 )
return -1 ;
if ( log->expr->info[curPos].numParms < 2 )
{
if ( expr4execute( log->expr, curPos, (void **)&resultPtr ) < 0 )
return -1 ;
if ( *resultPtr == 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->codeBase->bitmap_disable == 0 && !log->relation->bitmapsFreed ) /* then do check */
{
if ( expr4execute( log->expr, curPos, (void **)&resultPtr ) < 0 )
return -1 ;
if ( ( (infoReportPtr-1)->tag || (infoReportPtr-2)->tag ) )
if ( *resultPtr == 0 )
return error4( log->codeBase, e4info, E96002 ) ;
}
#endif
#endif
if ( ( (infoReportPtr-1)->tag == 0 && (infoReportPtr-2)->tag == 0 ) || log->relation->bitmapsFreed )
{
if ( expr4execute( log->expr, curPos, (void **)&resultPtr ) < 0 )
return -1 ;
if ( *resultPtr == 0 )
return 0 ;
}
}
curPos -= infoPtr->numEntries ;
}
if ( error4code( log->codeBase ) < 0 )
return -1 ;
return 1 ;
}
#endif /* S4CLIENT */