af15e0698b
git-svn-id: svn://10.65.10.50/trunk@4679 c028cbd2-c16b-5b4b-a496-9718f37d4682
539 lines
17 KiB
C
Executable File
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 */
|