/* 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 */