campo-sirio/cb/source/r4relate.c
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

3926 lines
108 KiB
C
Executable File

/* r4relate.c (c)Copyright Sequiter Software Inc., 1988-1996. All rights reserved. */
#include "d4all.h"
#ifdef __TURBOC__
#pragma hdrstop
#endif
#ifdef S4CLIENT
static int relate4clientInit( RELATE4 * ) ;
#else
static int relate4currentIsChild( RELATE4 * ) ;
static int relate4parent( RELATE4 *, RELATE4 * ) ;
static int relate4nextRelationList( RELATION4 *, int ) ;
static int relate4prevRecordInScan( RELATE4 * ) ;
static int relate4prevRelationList( RELATION4 *, int ) ;
#endif
static int relate4initRelate( RELATE4 *, RELATION4 *, DATA4 *, CODE4 *, int ) ;
static int relate4lookup( RELATE4 *, const char ) ;
static int relate4readRest( RELATE4 *, char ) ;
static void relate4setNotRead( RELATE4 * ) ;
static void relate4sortFree( RELATION4 *, const int ) ;
static int relate4sortGetRecord( RELATION4 *, const long ) ;
static int relate4sortNextRecord( RELATION4 * ) ;
static int relate4sortPrevRecord( RELATION4 * ) ;
#ifndef S4CLIENT
static int relate4topInit( RELATE4 * ) ;
static int f4flagIsSetFlip( F4FLAG *flagPtr, const unsigned long r )
{
if ( flagPtr->flags == 0 )
return 1 ;
if ( flagPtr->isFlip )
return ! f4flagIsSet( flagPtr, r ) ;
else
return f4flagIsSet( flagPtr, r ) ;
}
/* returns the position of the next flipped flag in the flag set - start at r */
static unsigned long f4flagGetNextFlip( F4FLAG *f4, const unsigned long r, const char direction )
{
unsigned char cFlag ;
unsigned long lowVal, onVal, highVal ;
char i ;
#ifdef E4PARM_LOW
if ( direction != -1 && direction != 1 )
return error4( 0, e4parm, E90812 ) ;
#endif
onVal = r ;
if ( f4->flags == 0 || r > f4->numFlags )
return 0 ;
lowVal = (unsigned long)( r & 0x7 ) ;
highVal = (unsigned long)( r >> 3 ) ;
if ( (int)direction == -1 )
{
cFlag = (unsigned char)( f4->flags[highVal] ) ;
if ( f4->isFlip )
cFlag = (unsigned char) ~cFlag ;
cFlag = (unsigned char)( (unsigned char)( cFlag << ( 7 - lowVal ) ) >> ( 7 - lowVal )) ;
onVal += ( 7 - lowVal ) ;
if ( cFlag == 0 )
for( ; cFlag == 0 ; onVal -= 8 )
{
if ( highVal-- <= 1 ) /* if was zero, or is now zero */
{
if ( f4->flags[0] == 0 )
return r ;
cFlag = f4->flags[0] ;
if ( f4->isFlip )
cFlag = (unsigned char) ~cFlag ;
onVal -= 8 ; /* for sure if highVal == 0, else?? */
break ;
}
cFlag = f4->flags[highVal] ;
if ( f4->isFlip )
cFlag = (unsigned char) ~cFlag ;
}
for( i = 7 ; (int)i >= 0 ; i--, onVal-- )
if ( cFlag & ( 0x01 << i ) )
break ;
return (r - onVal) ;
}
else
{
cFlag = (unsigned char)f4->flags[highVal] ;
if ( f4->isFlip )
cFlag = (unsigned char) ~cFlag ;
cFlag = (unsigned char) (cFlag >> lowVal) ;
if ( cFlag == 0 )
{
onVal -= lowVal ;
for( ; cFlag == 0 ; onVal += 8 )
{
if ( onVal >= f4->numFlags )
return (f4->numFlags - r + 1) ;
cFlag = f4->flags[++highVal] ;
if ( f4->isFlip )
cFlag = (unsigned char) ~cFlag ;
}
}
for( i = 0 ; i <= 7 ; i++, onVal++ )
if ( cFlag & ( 0x01 << i ) )
break ;
return (onVal - r) ;
}
}
int r4dataListAdd( LIST4 *l4, DATA4 *data, RELATE4 *relate )
{
R4DATA_LIST *r4 ;
CODE4 *c4 ;
c4 = relate->codeBase ;
if ( error4code( c4 ) < 0 )
return -1 ;
if ( c4->relateDataListMemory == 0 )
{
c4->relateDataListMemory = mem4create( c4, 10, sizeof( R4DATA_LIST ), 10, 0 ) ;
if ( c4->relateDataListMemory == 0 )
return 0 ;
}
r4 = (R4DATA_LIST *)mem4alloc( c4->relateDataListMemory ) ;
if ( r4 == 0 )
return -1 ;
r4->data = data ;
r4->relate = relate ;
l4add( l4, r4 ) ;
return 0 ;
}
int r4dataListFind( LIST4 *l4, RELATE4 *r4 )
{
R4DATA_LIST *link ;
for ( link = 0 ;; )
{
link = (R4DATA_LIST *)l4next( l4, link ) ;
if ( link == 0 )
return 0 ;
if ( link->relate == r4 )
return 1 ;
}
}
void r4dataListFree( LIST4 *l4 )
{
R4DATA_LIST *r4data, *r4data2 ;
for ( r4data = (R4DATA_LIST *)l4first( l4 ) ; r4data ; )
{
r4data->relate->sortType = 0 ;
r4data2 = (R4DATA_LIST *)l4next( l4, r4data ) ;
l4remove( l4, r4data ) ;
mem4free( r4data->relate->codeBase->relateDataListMemory, r4data ) ;
r4data = r4data2 ;
}
}
/* this function takes a completed sort list, and adds data members in the
following case:
If (r)elate must be added, r's siblings must also be added
Or, interpreted differently, if r is a relation, and any of it's children
must be added, then all of its children must be added.
*/
static int r4dataListMassage( LIST4 *l4 )
{
RELATE4 *relateChild ;
R4DATA_LIST *r4data ;
int addChildren, relateAdded ;
if ( l4->nLink == 0 ) /* no work required */
return 0 ;
r4data = 0 ;
for( ;; )
{
r4data = (R4DATA_LIST *)l4next( l4, r4data ) ;
if ( r4data == 0 )
break ;
relateChild = 0 ;
addChildren = 0 ;
for( ;; )
{
relateChild = (RELATE4 *)l4next( &r4data->relate->slaves, relateChild ) ;
if ( relateChild == 0 )
break ;
if ( r4dataListFind( l4, relateChild ) )
{
addChildren = 1 ;
break ;
}
}
if ( addChildren == 1 )
{
relateAdded = 0 ;
relateChild = 0 ;
for( ;; )
{
relateChild = (RELATE4 *)l4next( &r4data->relate->slaves, relateChild ) ;
if ( relateChild == 0 )
break ;
if ( r4dataListFind( l4, relateChild ) == 0 )
{
r4dataListAdd( l4, relateChild->data, relateChild ) ;
relateChild->sortType = relate4exact ;
relateAdded = 1 ;
}
}
if ( relateAdded == 1 )
r4data = 0 ; /* start at list top again to be sure none missed */
}
}
return 0 ;
}
/* 1 - database added, 0 - database not added, -1 - error */
/* checkType gives the caller's status in terms of whether we should be included */
int r4dataListBuild( LIST4 *l4, RELATE4 *relate, EXPR4 *expr, int checkType )
{
int i ;
char mustAdd ;
E4INFO *info ;
RELATE4 *slaveOn ;
if ( error4code( relate->codeBase ) < 0 )
return -1 ;
mustAdd = 0 ;
/* 1st check if we must belong */
for( i = 0 ; i < expr->infoN ; i++ )
{
info = expr->info + i ;
if ( info->fieldPtr )
{
if ( info->fieldPtr->data == relate->data )
{
mustAdd = 1 ;
break ;
}
}
}
relate->sortType = relate4exact ;
if ( mustAdd )
checkType = relate4exact ;
else
{
if ( relate->relationType == relate4scan )
checkType = relate4scan ;
else
if ( checkType != relate4scan ) /* non-scan parent must be added, so we add ourselves too, in order to save work later */
mustAdd = 1 ;
}
/* if a child must be added, we must be too: */
for ( slaveOn = 0 ;; )
{
slaveOn = (RELATE4 *)l4next( &relate->slaves, slaveOn ) ;
if ( slaveOn == 0 )
break ;
if ( r4dataListBuild( l4, slaveOn, expr, checkType ) == 1 )
mustAdd = 1 ;
}
if ( mustAdd )
r4dataListAdd( l4, relate->data, relate ) ;
else
if ( relate->relationType == relate4scan )
relate->sortType = relate4sortSkip ;
return mustAdd ;
}
/* direction : -1 = look backwards, 0 = lookup only, 1 = look forwards */
static int relate4blankSet( RELATE4 *relate, const char direction )
{
RELATE4 *slave ;
CODE4 *c4 ;
int rc ;
#ifdef E4PARM_LOW
if ( direction < -1 || direction > 1 )
return error4( 0, e4parm, E94417 ) ;
#endif
c4 = relate->codeBase ;
if ( error4code( c4 ) < 0 )
return -1 ;
relate->isRead = 1 ;
if ( direction >= 0 )
{
if ( d4goEof( relate->data ) < 0 )
return -1 ;
}
else
{
rc = d4top( relate->data ) ;
if ( rc )
return rc ;
rc = d4skip( relate->data, -1L ) ;
relate->data->recNum = -1 ;
d4blank( relate->data ) ;
relate->data->recordChanged = 0 ;
if ( error4code( c4 ) < 0 )
return -1 ;
#ifdef S4SINGLE
if ( rc < 0 )
#else
if ( rc == r4locked || rc < 0 )
#endif
return rc ;
}
for( slave = 0 ;; )
{
slave = (RELATE4 *)l4next( &relate->slaves, slave ) ;
if ( slave == 0 )
return 0 ;
rc = relate4blankSet( slave, direction ) ;
if ( rc < 0 )
return rc ;
}
}
#endif
#ifdef S4CLIENT
int relate4unpack( RELATION4 *relation, CONNECTION4 *connection )
{
CONNECTION4RELATION_DATA_OUT *info ;
RELATE4 *relate ;
unsigned int pos ;
long recCount, len ;
const char *data ;
#ifndef S4MEMO_OFF
int i ;
#endif
len = connection4len( connection ) ;
data = connection4data( connection ) ;
if ( len < sizeof( CONNECTION4RELATION_DATA_OUT ) )
return error4( relation->relate.codeBase, e4packetLen, E94425 ) ;
info = (CONNECTION4RELATION_DATA_OUT *)data ;
if ( info->relationId != relation->relationId )
return error4( relation->relate.codeBase, e4connection, E84305 ) ;
pos = sizeof( CONNECTION4RELATION_DATA_OUT ) ;
for( relate = &relation->relate ;; )
{
#ifndef S4MEMO_OFF
if ( relate->data->dataFile->nFieldsMemo > 0 )
{
for ( i = 0; i < relate->data->dataFile->nFieldsMemo; i++ )
f4memoReset( relate->data->fieldsMemo[i].field ) ;
}
#endif
if ( len < (long)pos + (long)dfile4recWidth( relate->data->dataFile ) + (long)sizeof( relate->data->recNum ) + (long)sizeof(long) )
return error4( relation->relate.codeBase, e4packetLen, E94425 ) ;
memcpy( &relate->data->recNum, data + pos, sizeof( relate->data->recNum ) ) ;
pos += sizeof( relate->data->recNum ) ;
recCount = *((long *)( data + pos )) ;
pos += sizeof( long ) ;
if ( recCount < 0 )
return error4( relation->relate.codeBase, e4result, E84305 ) ;
if ( relate->data->recNum > recCount )
relate->data->eofFlag = 1 ;
else
relate->data->eofFlag = 0 ;
if ( recCount == 0 || relate->data->recNum == 0 )
relate->data->bofFlag = 1 ;
else
relate->data->bofFlag = 0 ;
memcpy( relate->data->record, data + pos, dfile4recWidth( relate->data->dataFile ) ) ;
pos += dfile4recWidth( relate->data->dataFile ) ;
if ( relate4next( &relate ) == 2 )
break ;
}
if ( len != (long)pos )
return error4( relation->relate.codeBase, e4packetLen, E94425 ) ;
return 0 ;
}
#endif
int S4FUNCTION relate4bottom( RELATE4 *relate )
{
RELATION4 *relation ;
int rc, rc2 ;
CODE4 *c4 ;
#ifdef S4CLIENT
CONNECTION4 *connection ;
CONNECTION4RELATE_BOTTOM_INFO_IN info ;
#else
#ifndef S4OFF_MULTI
int oldReadLock ;
#endif
long rec ;
#endif
#ifdef S4VBASIC
if ( c4parm_check( relate, 5, E94401 ) )
return -1 ;
#endif
#ifdef E4PARM_LOW
if ( relate == 0 )
return error4( 0, e4parm_null, E94401 ) ;
#endif
c4 = relate->codeBase ;
if ( error4code( c4 ) < 0 )
return e4codeBase ;
relation = relate->relation ;
relate = &relation->relate ;
#ifdef S4CLIENT
if ( relation->isInitialized == 0 )
{
rc = relate4clientInit( relate ) ;
if ( rc != 0 )
return rc ;
}
#ifdef S4CB51
#ifndef S4OFF_MULTI
if ( c4->readLock )
{
rc = relate4lock( relate ) ;
if ( rc != 0 )
return rc ;
}
#endif
#endif
#ifdef E4ANALYZE
if ( relate->data == 0 )
return error4( c4, e4parm, E94401 ) ;
if ( relate->data->dataFile == 0 )
return error4( c4, e4parm, E94401 ) ;
#endif
connection = relate->data->dataFile->connection ;
#ifdef E4ANALYZE
if ( connection == 0 )
return error4( c4, e4parm, E94401 ) ;
#endif
connection4assign( connection, CON4RELATE_BOTTOM, 0, 0 ) ;
info.relationId = relation->relationId ;
connection4addData( connection, &info, sizeof( CONNECTION4RELATE_BOTTOM_INFO_IN ), 0 ) ;
connection4send( connection ) ;
rc = connection4receive( connection ) ;
if ( rc < 0 )
return error4stack( c4, rc, E94401 ) ;
rc = connection4status( connection ) ;
if ( rc < 0 )
return connection4error( connection, c4, rc, E94401 ) ;
rc2 = relate4unpack( relation, connection ) ;
if ( rc2 < 0 )
return error4stack( c4, rc, E94401 ) ;
return rc ;
#else
#ifndef S4OFF_MULTI
oldReadLock = c4->readLock ;
c4->readLock = 0 ;
#endif
if ( relation->skipBackwards == 0 )
{
relate4sortFree( relation, 0 ) ;
relate4skipEnable( relate, 1 ) ;
}
for ( ;; ) /* used to minimize return code areas, just break out... */
{
rc = relate4topInit( relate ) ;
if ( rc != 0 )
break ;
relate4setNotRead( relate ) ;
relation->currentRelateLevel = 0 ;
relate4prevRelationList( relation, 1 ) ;
if ( relation->inSort == relate4sortDone )
{
if ( relate4sortGetRecord( relation, relation->sortRecCount ) == r4eof )
{
rc = r4eof ;
break ;
}
else
relation->sortRecOn = relation->sortRecCount ;
}
else
{
rc = d4bottom( relate->data ) ;
if ( rc != 0 )
break ;
if ( relation->exprSource )
{
rec = d4recNo( relate->data ) ;
#ifndef S4INDEX_OFF
if ( relate->dataTag )
{
while ( f4flagIsSetFlip( &relate->set, (unsigned long)rec ) == 0 )
{
#ifdef S4HAS_DESCENDING
rc = (int)tfile4dskip( relate->dataTag->tagFile, -1L ) ;
#else
rc = (int)tfile4skip( relate->dataTag->tagFile, -1L ) ;
#endif
if ( rc != -1 )
{
if ( rc == 0 )
rc = r4eof ;
break ;
}
rec = tfile4recNo( relate->dataTag->tagFile ) ;
}
if ( rc == r4eof )
break ;
}
else
{
#endif
if ( f4flagIsSetFlip( &relate->set, (unsigned long)rec ) == 0 )
{
rec = d4recNo( relate->data ) - f4flagGetNextFlip( &relate->set, (unsigned long)d4recNo( relate->data), (char)-1 ) ;
if ( rec == 0 )
{
rc = r4eof ;
break ;
}
}
#ifndef S4INDEX_OFF
}
#endif
rc = d4go( relate->data, rec ) ;
if ( rc < 0 )
break ;
}
relate4setNotRead( relate ) ;
}
rc = relate4readRest( relate, -1 ) ;
if ( rc == relate4filterRecord )
rc = relate4skip( relate, -1L ) ;
if ( rc < 0 || rc == r4terminate )
break ;
if ( relation->exprSource )
{
rc2 = log4true( &relation->log ) ;
if ( rc2 == r4terminate )
{
rc = r4terminate ;
break ;
}
if ( rc2 == 0 )
{
if ( relation->inSort == relate4sortSkip ) /* must temporarily disable in order to get a matching scan if available */
{
relation->inSort = 0 ;
rc = relate4skip( relate, -1L ) ;
relation->inSort = relate4sortSkip ;
}
else
rc = relate4skip( relate, -1L ) ;
}
}
if ( rc == r4bof )
rc = r4eof ;
break ;
}
#ifndef S4OFF_MULTI
c4->readLock = oldReadLock ;
#endif
return rc ;
#endif
}
#ifndef S4CLIENT
static int relate4buildScanList( RELATE4 *master, RELATE4 *relate, RELATION4 *relation )
{
RELATE4 *relateOn ;
RELATE4LIST *ptr ;
if ( error4code( relate->codeBase ) < 0 )
return -1 ;
for( relateOn = 0 ;; )
{
relateOn = (RELATE4 *)l4next( &relate->slaves, relateOn ) ;
if ( relateOn == 0 )
break ;
if ( relate4buildScanList( relate, relateOn, relation ) < 0 )
return -1 ;
}
if ( master != 0 ) /* cannot have a scan without a base master */
if ( relate->relationType == relate4scan || relate == &relation->relate )
{
ptr = (RELATE4LIST *)mem4createAlloc( relate->codeBase, &relate->codeBase->relateListMemory, 5, sizeof(RELATE4LIST), 5, 0 ) ;
if ( ptr == 0 )
return -1 ;
ptr->ptr = relate ;
l4add( &master->relateList, ptr ) ;
}
return 0 ;
}
#endif
static void relate4freeRelateList( RELATE4 *relate )
{
RELATE4 *slaveOn ;
void *ptr ;
for( ;; )
{
ptr = l4pop( &relate->relateList ) ;
if ( ptr == 0 )
break ;
mem4free( relate->codeBase->relateListMemory, ptr ) ;
}
for ( slaveOn = 0 ;; )
{
slaveOn = (RELATE4 *)l4next( &relate->slaves, slaveOn ) ;
if ( slaveOn == 0 )
return ;
relate4freeRelateList( slaveOn ) ;
}
}
int S4FUNCTION relate4changed( RELATE4 *relate )
{
RELATION4 *relation ;
CODE4 *c4 ;
#ifndef S4CLIENT
int j ;
#endif
#ifdef E4PARM_HIGH
if ( relate == 0 )
return error4( 0, e4parm_null, E94402 ) ;
#endif
c4 = relate->codeBase ;
if ( error4code( c4 ) < 0 )
return -1 ;
#ifndef S4CLIENT
u4free( relate->scanValue ) ;
relate->scanValue = 0 ;
#endif
relation = relate->relation ;
#ifdef S4CLIENT
if ( relation->isInitialized != 0 )
relation->needsFreeing = 1 ;
#endif
relation->isInitialized = 0 ;
relate4sortFree( relation, 0 ) ;
relate4freeRelateList( &(relation->relate) ) ;
#ifndef S4CLIENT
u4free( relation->relate.set.flags ) ;
memset( (void *)&relation->relate.set, 0, sizeof( F4FLAG ) ) ;
if ( relation->log.expr != 0 )
{
for( j = relation->log.expr->infoN; --j >= 0; )
{
E4INFO_REPORT *info_ptr = relation->log.infoReport + j ;
if ( info_ptr->relateDataList != 0 )
{
u4free( (info_ptr->relateDataList->pointers) ) ;
mem4free( c4->dataListMemory, info_ptr->relateDataList ) ;
}
}
expr4free( relation->log.expr ) ;
relation->log.expr = 0 ;
u4free( relation->log.infoReport ) ;
relation->log.infoReport = 0 ;
}
if ( relation->log.bufLen != 0 )
{
u4free( relation->log.buf ) ;
relation->log.bufLen = 0 ;
relation->log.bufPos = 0 ;
}
relation->inSort = 0 ;
#endif
return 0 ;
}
RELATE4 *S4FUNCTION relate4createSlave( RELATE4 *master, DATA4 *slaveData, char *masterExpr, TAG4 *slaveTag )
{
RELATION4 *relation ;
RELATE4 *slave ;
CODE4 *c4 ;
int rc ;
#ifdef S4SERVER
LIST4 *oldList ;
#endif
if ( master == 0 )
return 0 ;
#ifdef S4VBASIC
if ( c4parm_check( master, 5, E94403 ) )
return (RELATE4 *) 0 ;
#endif
c4 = master->codeBase ;
if ( error4code( c4 ) < 0 )
return 0 ;
#ifdef E4PARM_LOW
if ( slaveData == 0 || masterExpr == 0 )
{
error4( c4, e4parm_null, E94403 ) ;
return 0 ;
}
#endif
relation = master->relation ;
#ifdef E4MISC
/* check that the d4 doesn't belong to any existing relation */
if ( relate4lookupRelate( &relation->relate, slaveData ) != 0 )
{
error4( c4, e4parm, E84403 ) ;
return 0 ;
}
#endif
relate4changed( master ) ;
slave = (RELATE4 *)mem4createAlloc( c4, &c4->relateMemory, 5, sizeof(RELATE4), 5, 0 ) ;
if ( slave == 0 )
return 0 ;
#ifdef S4SERVER
rc = relate4initRelate( slave, relation, slaveData, c4, 0 ) ;
#else
rc = relate4initRelate( slave, relation, slaveData, c4, 1 ) ;
#endif
if ( rc < 0 )
{
mem4free( c4->relateMemory, slave ) ;
return 0 ;
}
#ifdef S4SERVER
oldList = tran4dataList( code4trans( c4 ) ) ;
tran4dataListSet( code4trans( c4 ), &relation->localDataList ) ;
#endif
slave->masterExpr = expr4parseLow( master->data, masterExpr, 0 ) ;
#ifdef S4VFP_KEY
if ( slaveTag != 0 )
slave->masterExpr->vfpInfo = &slaveTag->tagFile->vfpInfo ;
#endif
#ifdef S4SERVER
tran4dataListSet( code4trans( c4 ), oldList ) ;
#endif
if ( slave->masterExpr == 0 )
{
mem4free( c4->relateMemory, slave ) ;
return 0 ;
}
#ifndef S4CLIENT
#ifndef S4INDEX_OFF
if ( slaveTag != 0 )
if ( tfile4type( slaveTag->tagFile ) != expr4type( slave->masterExpr ) )
{
#ifndef S4SERVER
error4( c4, e4relate, E84404 ) ;
#endif
mem4free( c4->relateMemory, slave ) ;
return 0 ;
}
#endif
#endif
slave->dataTag = slaveTag ;
slave->master = master ;
l4add( &master->slaves, slave ) ;
relate4matchLen( slave, -1 ) ; /* Set to maximum */
return slave ;
}
#ifdef S4CLIENT
int S4FUNCTION relate4doAll( RELATE4 *relate )
{
CONNECTION4RELATE_DO_INFO_IN info ;
CONNECTION4 *connection ;
int rc, rc2 ;
CODE4 *c4 ;
#ifdef E4PARM_HIGH
if ( relate == 0 )
return error4( 0, e4parm_null, E94404 ) ;
#endif
c4 = relate->codeBase ;
#ifdef E4PARM_HIGH
if ( relate->master != 0 )
return error4( c4, e4parm, E84402 ) ;
#endif
if ( relate->relation->isInitialized == 0 ) /* need to initialize on server first */
{
rc = relate4clientInit( relate ) ;
if ( rc != 0 )
return rc ;
}
connection = relate->data->dataFile->connection ;
#ifdef E4ANALYZE
if ( connection == 0 )
return error4( c4, e4struct, E94404 ) ;
#endif
connection4assign( connection, CON4RELATE_DO, 0, 0 ) ;
info.relationId = relate->relation->relationId ;
info.relateId = relate->id ;
info.masterStartPos = d4recNo( relate->data ) ;
connection4addData( connection, &info, sizeof( CONNECTION4RELATE_DO_INFO_IN ), 0 ) ;
connection4send( connection ) ;
rc = connection4receive( connection ) ;
if ( rc < 0 )
return error4stack( c4, rc, E94404 ) ;
rc = connection4status( connection ) ;
if ( rc < 0 )
return connection4error( connection, c4, rc, E94404 ) ;
rc2 = relate4unpack( relate->relation, relate->data->dataFile->connection ) ;
if ( rc2 < 0 )
return error4stack( c4, rc, E94404 ) ;
return rc ;
}
int S4FUNCTION relate4doOne( RELATE4 *relate )
{
CONNECTION4RELATE_DO_ONE_INFO_IN info ;
CONNECTION4RELATE_DO_ONE_INFO_OUT *out ;
CONNECTION4 *connection ;
int rc, saveRc ;
CODE4 *c4 ;
#ifdef E4PARM_HIGH
if ( relate == 0 )
return error4( 0, e4parm_null, E94405 ) ;
if ( relate->master == 0 )
return error4( relate->codeBase, e4parm, E84405 ) ;
#endif
c4 = relate->codeBase ;
if ( relate->relation->isInitialized == 0 ) /* need to initialize on server first */
{
rc = relate4clientInit( relate ) ;
if ( rc != 0 )
return rc ;
}
connection = relate->data->dataFile->connection ;
#ifdef E4ANALYZE
if ( connection == 0 )
return error4( 0, e4struct, E94405 ) ;
#endif
connection4assign( connection, CON4RELATE_DO_ONE, 0, 0 ) ;
info.relationId = relate->relation->relationId ;
info.relateId = relate->id ;
info.masterStartPos = d4recNo( relate->master->data ) ;
connection4addData( connection, &info, sizeof( CONNECTION4RELATE_DO_ONE_INFO_IN ), 0 ) ;
connection4send( connection ) ;
rc = connection4receive( connection ) ;
if ( rc < 0 )
return error4stack( c4, rc, E94405 ) ;
rc = connection4status( connection ) ;
if ( rc < 0 )
return connection4error( connection, c4, rc, E94405 ) ;
saveRc = rc ;
if ( saveRc != r4terminate )
{
if ( saveRc == r4eof ) /* end of file */
{
saveRc = 0 ;
rc = d4goEof( relate->data ) ;
if ( rc < 0 )
return error4stack( c4, rc, E94405 ) ;
}
else
{
if ( connection4len( connection ) != sizeof( CONNECTION4RELATE_DO_ONE_INFO_OUT ) )
return error4stack( c4, e4packetLen, E94405 ) ;
out = (CONNECTION4RELATE_DO_ONE_INFO_OUT *)connection4data( connection ) ;
rc = d4go( relate->data, out->recNo ) ;
if ( rc < 0 )
return error4stack( c4, rc, E94405 ) ;
}
}
return saveRc ;
}
#ifdef S4CB51
static int relate4dbfInRelation( RELATE4 *relate, const DATA4 *dbf )
{
RELATE4 *relateOn ;
relateOn = &relate->relation->relate ;
while( relateOn->master )
relateOn = relateOn->master ;
do
{
if ( relateOn->data == dbf )
return 1 ;
} while( relate4next( &relateOn ) != 2 ) ;
return 0 ;
}
#endif /* S4CB51 */
#else
/* checks if the given dbf belongs to one of the relations in relation */
#ifdef S4CB51
static int relate4dbfInRelation( RELATE4 *relate, const DATA4 *dbf )
{
RELATE4 *relateOn ;
relateOn = &relate->relation->relate ;
while( relateOn->master )
relateOn = relateOn->master ;
do
{
if ( relateOn->data == dbf )
return 1 ;
} while( relate4next( &relateOn ) != 2 ) ;
return 0 ;
}
#endif /* S4CB51 */
int S4FUNCTION relate4doAll( RELATE4 *relate )
{
int rc ;
CODE4 *c4 ;
#ifndef S4OFF_MULTI
int oldReadLock ;
#endif
#ifdef S4VBASIC
if ( c4parm_check( relate, 5, E94405 ) )
return -1 ;
#endif
#ifdef E4PARM_HIGH
if ( relate == 0 )
return error4( 0, e4parm_null, E94405 ) ;
#endif
c4 = relate->codeBase ;
#ifdef E4ANALYZE
if ( relate->master != 0 )
return error4( c4, e4struct, E84402 ) ;
#endif
if ( error4code( c4 ) < 0 )
return e4codeBase ;
#ifndef S4OFF_MULTI
oldReadLock = c4->readLock ;
c4->readLock = 0 ;
#endif
relate4setNotRead( relate ) ;
rc = relate4readRest( relate, 0 ) ;
#ifndef S4OFF_MULTI
c4->readLock = oldReadLock ;
#endif
if ( rc == relate4filterRecord ) /* no match is an error */
{
#ifndef S4SERVER
if ( c4->errRelate )
return error4describe( c4, e4lookupErr, E94404, relate->data->alias, 0, 0 ) ;
#endif
return r4terminate ;
}
return rc ;
}
int S4FUNCTION relate4doOne( RELATE4 *relate )
{
int rc ;
CODE4 *c4 ;
#ifndef S4OFF_MULTI
int oldReadLock ;
#endif
#ifdef S4VBASIC
if ( c4parm_check( relate, 5, E94405 ) )
return -1 ;
#endif
#ifdef E4PARM_HIGH
if ( relate == 0 )
return error4( 0, e4parm_null, E94405 ) ;
#endif
c4 = relate->codeBase ;
#ifdef E4PARM_HIGH
if ( relate->master == 0 )
return error4( c4, e4parm, E84405 ) ;
#endif
if ( error4code( c4 ) < 0 )
return e4codeBase ;
if ( relate->master == 0 ) /* no master, so we must be read */
return 0 ;
#ifndef S4OFF_MULTI
oldReadLock = c4->readLock ;
c4->readLock = 0 ;
#endif
relate4setNotRead( relate ) ;
rc = relate4lookup( relate, 0 ) ;
#ifndef S4OFF_MULTI
c4->readLock = oldReadLock ;
#endif
relate->isRead = relate->master->isRead ; /* we are read if master is read */
if ( rc == relate4filterRecord ) /* no match is an error */
{
#ifndef S4SERVER
if ( c4->errRelate )
return error4describe( c4, e4info, E94405, relate->data->alias, 0, 0 ) ;
#endif
return r4terminate ;
}
return rc ;
}
#endif
int S4FUNCTION relate4eof( RELATE4 *relate )
{
#ifdef E4PARM_HIGH
if ( relate == 0 )
return error4( 0, e4parm_null, E94406 ) ;
#endif
#ifdef E4MISC
if ( relate->relation->isInitialized == 0 )
{
error4( relate->codeBase, e4info, E84406 ) ;
return -1 ;
}
#endif
#ifndef S4CLIENT
if ( relate->relation->inSort == relate4sortDone )
return relate->relation->sortEofFlag ;
else
#endif
return d4eof( relate->relation->relate.data ) ;
}
int S4FUNCTION relate4errorAction( RELATE4 *relate, const int code )
{
int rc ;
#ifdef E4PARM_HIGH
if ( relate == 0 )
return error4( 0, e4parm_null, E94407 ) ;
if ( code != relate4blank && code != relate4skipRec && code != relate4terminate )
return error4( relate->codeBase, e4parm, E84407 ) ;
#endif
rc = relate->errorAction ;
relate->errorAction = code ;
return rc ;
}
int S4FUNCTION relate4freeRelate( RELATE4 *relate, const int closeFiles )
{
int rc ;
RELATE4 *relateOn ;
CODE4 *c4 ;
#ifdef S4SERVER
LIST4 *oldList ;
#endif
rc = 0 ;
if ( relate->master == 0 )
return relate4free( relate, closeFiles ) ;
c4 = relate->codeBase ;
relate4changed( relate ) ;
if( closeFiles )
{
#ifdef S4SERVER
oldList = tran4dataList( code4trans( c4 ) ) ;
tran4dataListSet( code4trans( c4 ), &relate->relation->localDataList ) ;
#endif
if( d4close( relate->data ) < 0 )
rc = -1 ;
#ifdef S4SERVER
tran4dataListSet( code4trans( c4 ), oldList ) ;
#endif
relate->data = 0 ;
}
for( ;; )
{
relateOn = (RELATE4 *)l4last( &relate->slaves) ;
if ( relateOn == 0 )
break ;
if( relate4freeRelate( relateOn, closeFiles ) < 0 )
rc = -1 ;
}
expr4free( relate->masterExpr ) ;
u4free( relate->scanValue ) ;
relate->scanValue = 0 ;
#ifndef S4CLIENT
u4free( relate->set.flags ) ;
relate->set.flags = 0 ;
#endif
l4remove( &relate->master->slaves, relate ) ;
mem4free( c4->relateMemory, relate ) ;
relate = 0 ;
return rc ;
}
int S4FUNCTION relate4free( RELATE4 *relate, const int closeFiles )
{
int rc ;
RELATION4 *relation ;
RELATE4 *relateOn ;
CODE4 *c4 ;
#ifdef S4CLIENT
CONNECTION4RELATE_FREE_INFO_IN info ;
CONNECTION4 *connection ;
#endif
#ifdef S4SERVER
LIST4 *oldList ;
#endif
if ( relate == 0 )
return -1 ;
rc = 0 ;
#ifdef S4VBASIC
if ( c4parm_check( relate, 5, E94408 ) )
return -1 ;
#endif
#ifdef S4CB51
#ifndef S4SINGLE
relate4unlock( relate ) ;
#endif
#endif
relate4changed( relate ) ;
relation = relate->relation ;
relate = &relation->relate ;
c4 = relate->codeBase ;
#ifdef S4CLIENT
#ifdef E4ANALYZE
if ( relate->data == 0 )
return error4( c4, e4struct, E94408 ) ;
if ( relate->data->dataFile == 0 )
return error4( c4, e4struct, E94408 ) ;
#endif
if ( relation->relationId != 0 ) /* if not freed on the server */
{
connection = relate->data->dataFile->connection ;
#ifdef E4ANALYZE
if ( connection == 0 )
return error4( c4, e4struct, E94408 ) ;
#endif
connection4assign( connection, CON4RELATE_FREE, 0, 0 ) ;
info.relationId = relation->relationId ;
connection4addData( connection, &info, sizeof( CONNECTION4RELATE_FREE_INFO_IN ), 0 ) ;
connection4send( connection ) ;
rc = connection4receive( connection ) ;
if ( rc < 0 )
return error4stack( c4, rc, E94408 ) ;
rc = connection4status( connection ) ;
if ( rc != 0 )
return connection4error( connection, c4, rc, E94408 ) ;
}
#endif
#ifdef S4SERVER
if( closeFiles || relate->freeData == 1 )
#else
if( closeFiles )
#endif
{
#ifdef S4SERVER
oldList = tran4dataList( code4trans( c4 ) ) ;
tran4dataListSet( code4trans( c4 ), &relation->localDataList ) ;
#endif
if( d4close( relate->data ) < 0 )
rc = -1 ;
#ifdef S4SERVER
tran4dataListSet( code4trans( c4 ), oldList ) ;
#endif
relate->data = 0 ;
}
for( relateOn = 0 ;; )
{
relateOn = (RELATE4 *)l4last( &relate->slaves ) ;
if ( relateOn == 0 )
break ;
if( relate4freeRelate( relateOn, closeFiles ) < 0 )
rc = -1 ;
}
/* mem4release( relation->relateMemory ) ; */
/* mem4release( relation->relateListMemory ) ; */
/* mem4release( relation->relateDataListMemory ) ; */
relate4sortFree( relation, 1 ) ;
u4free( relation->exprSource ) ;
mem4free( c4->relationMemory, relation ) ;
return rc ;
}
#ifdef S4SERVER
static DATA4 *relate4dataOpen( RELATE4 *relate, DATA4 *oldData )
{
DATA4 *d4 ;
int oldAccessMode, oldReadOnly ;
CODE4 *c4 ;
#ifdef E4PARM_LOW
if ( relate == 0 || oldData == 0 )
{
error4( 0, e4parm_null, E94427 ) ;
return 0 ;
}
#endif
c4 = relate->codeBase ;
relate->dataOld = oldData ;
oldAccessMode = c4->accessMode ;
c4->accessMode = OPEN4DENY_NONE ;
oldReadOnly = c4->readOnly ;
c4->readOnly = 1 ;
d4 = d4openClone( oldData ) ;
if ( d4 == 0 )
{
error4( c4, e4info, E94409 ) ;
return 0 ;
}
#ifdef S4SERVER
d4->trans = &c4->currentClient->trans ;
/* l4add( tran4dataList( &c4->currentClient->trans ), d4 ) ;*/
#endif
c4->accessMode = oldAccessMode ;
c4->readOnly = oldReadOnly ;
return d4 ;
}
#endif /* S4SERVER */
RELATE4 *S4FUNCTION relate4init( DATA4 *master )
{
RELATION4 *relation ;
CODE4 *c4 ;
int rc ;
#ifdef S4VBASIC
if ( c4parm_check( master, 5, E94410 ) )
return (RELATE4 *) 0 ;
#endif
#ifdef E4PARM_HIGH
if ( master == 0 )
{
error4( 0, e4parm_null, E94410 ) ;
return 0 ;
}
#endif
c4 = master->codeBase ;
if ( error4code( c4 ) < 0 )
return 0 ;
if ( c4->relationMemory == 0 )
{
c4->relationMemory = mem4create( c4, 5, sizeof( RELATION4 ), 5, 0 ) ;
if ( c4->relationMemory == 0 )
return 0 ;
}
relation = (RELATION4 *)mem4alloc( c4->relationMemory ) ;
if ( relation == 0 )
return 0 ;
#ifndef S4CLIENT
relation->log.relation = relation ;
relation->log.codeBase = c4 ;
relation->sort.file.hand = -1 ;
relation->sortedFile.hand = -1 ;
#endif
rc = relate4initRelate( &relation->relate, relation, master, c4, 1 ) ;
if ( rc < 0 )
{
mem4free( c4->relationMemory, relation ) ;
return 0 ;
}
#ifdef S4SERVER
relation->relate.freeData = 1 ;
#endif
return &relation->relate ;
}
#ifdef P4ARGS_USED
#pragma argsused
#endif
static int relate4initRelate( RELATE4 *relate, RELATION4 *relation, DATA4 *data, CODE4 *c4, int doOpen )
{
#ifdef S4SERVER
LIST4 *oldList ;
#endif
relate->codeBase = c4 ;
relate->relationType = relate4exact ;
#ifdef E4ANALYZE
if ( relate->data != 0 )
error4( relate->codeBase, e4info, E84406 ) ;
#endif
#ifndef S4SERVER
relate->data = data ;
#else
if ( doOpen == 0 )
relate->data = data ;
else
{
oldList = tran4dataList( code4trans( c4 ) ) ;
tran4dataListSet( code4trans( c4 ), &relation->localDataList ) ;
relate->data = relate4dataOpen( relate, data ) ;
tran4dataListSet( code4trans( c4 ), oldList ) ;
}
#endif
relate->errorAction = relate4blank ;
relate->relation = relation ;
if ( relate->data == 0 )
return error4( c4, e4info, E94410 ) ;
relate->data->count = d4recCount( relate->data ) ;
return 0 ;
}
#ifdef P4ARGS_USED
#pragma argsused
#endif
int S4FUNCTION relate4lockAdd( RELATE4 *relate )
{
#ifdef S4OFF_MULTI
return 0 ;
#else
int rc ;
RELATE4 *relateOn ;
#ifdef E4PARM_HIGH
if ( relate == 0 )
return error4( 0, e4parm_null, E94411 ) ;
#endif
#ifdef S4VBASIC
if ( c4parm_check( relate, 5, E94411 ) )
return -1 ;
#endif
if ( error4code( relate->codeBase ) < 0 )
return e4codeBase ;
rc = 0 ;
for( relateOn = &relate->relation->relate ;; )
{
if ( relateOn == 0 )
break ;
rc = d4lockAddFile( relateOn->data ) ;
if ( rc != 0 )
break ;
if ( relate4next( &relateOn ) == 2 )
break ;
}
return rc ;
#endif
}
#ifdef S4CB51
/* new form does not allow combining lockAdds spaced around relate4locks()
if required to do that, S4OLD_RELATE_LOCK code will allow */
int S4FUNCTION relate4lock( RELATE4 *relate )
{
int rc ;
rc = relate4lockAdd( relate ) ;
if ( rc < 0 )
return rc ;
rc = code4lock( relate->codeBase ) ;
if ( rc == 0 )
relate->relation->locked = 1 ;
return rc ;
}
#endif
#ifdef S4CLIENT
#ifdef S4CB51
#ifdef S4OLD_RELATE_LOCK
int S4FUNCTION relate4lock( RELATE4 *relate )
{
CONNECTION4 *connection ;
CONNECTION4RELATE_LOCK_INFO_IN info ;
CONNECTION4RELATE_LOCK_INFO_OUT *out ;
CONNECTION4RELATE_LOCK_SUB_DATA *subData ;
int rc, count ;
CODE4 *c4 ;
DATA4 *data ;
#ifdef E4PARM_HIGH
if ( relate == 0 )
return error4( 0, e4parm_null, E94411 ) ;
#endif
c4 = relate->codeBase ;
/* must ensure that client relation is registered before requesting a lock */
if ( relate->relation->isInitialized == 0 || relate->dataTag != relate->data->tagSelected )
{
relate->dataTag = relate->data->tagSelected ;
rc = relate4clientInit( relate ) ;
if ( rc != 0 )
return rc ;
}
connection = relate->data->dataFile->connection ;
#ifdef E4ANALYZE
if ( connection == 0 )
{
error4( c4, e4struct, E94411 ) ;
return 0 ;
}
#endif
connection4assign( connection, CON4RELATE_LOCK, 0, 0 ) ;
info.relationId = relate->relation->relationId ;
connection4addData( connection, &info, sizeof( CONNECTION4RELATE_LOCK_INFO_IN ), 0 ) ;
rc = connection4repeat( connection, -2, -1, -1, 0 ) ;
if ( rc == r4locked )
return r4locked ;
if ( rc < 0 )
return connection4error( connection, c4, rc, E94411 ) ;
if ( rc == 0 ) /* add locks */
{
if ( connection4len( connection ) < sizeof(CONNECTION4RELATE_LOCK_INFO_OUT) )
return error4( c4, e4packetLen, E94411 ) ;
out = (CONNECTION4RELATE_LOCK_INFO_OUT *)connection4data( connection ) ;
if ( connection4len( connection ) != (long)sizeof(CONNECTION4RELATE_LOCK_INFO_OUT) + out->count * sizeof( CONNECTION4RELATE_LOCK_SUB_DATA ) )
return error4( c4, e4packetLen, E94411 ) ;
subData = (CONNECTION4RELATE_LOCK_SUB_DATA *)( (char *)connection4data( connection ) + sizeof( CONNECTION4RELATE_LOCK_INFO_OUT ) ) ;
for( count = out->count ; count > 0 ; count-- )
{
data = tran4data( code4trans( c4 ), subData->serverId, subData->clientId ) ;
if ( data == 0 )
return error4( c4, e4info, E94411 ) ;
if ( data->dataFile->fileLock != 0 )
{
#ifdef E4MISC
if ( data->dataFile->fileLock != data )
return error4( c4, e4info, E94411 ) ;
#endif
}
else
data->dataFile->fileLock = data ;
subData++ ;
}
}
return rc ;
}
#endif /* S4OLD_RELATE_LOCK */
#endif /* S4CB51 */
#else
#ifdef S4OLD_RELATE_LOCK
int S4FUNCTION relate4lock( RELATE4 *relate )
{
#ifdef S4SINGLE
return 0 ;
#else
CODE4 *c4 ;
int rc, oldAttempts, count ;
RELATE4 *relateOn ;
#ifdef S4SERVER
RELATE4 *relateSkip ;
DATA4 *dataTemp ;
#endif
#ifdef E4PARM_HIGH
if ( relate == 0 )
return error4( 0, e4parm_null, E94411 ) ;
#endif
#ifdef S4VBASIC
if ( c4parm_check( relate, 5, E94411 ) )
return -1 ;
#endif
c4 = relate->codeBase ;
if ( error4code( c4 ) < 0 )
return e4codeBase ;
relate->relation->locked = 1 ;
count = oldAttempts = c4->lockAttempts ; /* take care of wait here */
c4->lockAttempts = 1 ;
for( ;; )
{
rc = 0 ;
for( relateOn = &relate->relation->relate ;; )
{
if ( relateOn == 0 )
break ;
#ifdef S4SERVER
if ( relateOn->dataOld->dataFile->fileServerLock == data4serverId( relateOn->dataOld ) ) /* check for duplicate lock */
{
dataTemp = tran4data( code4trans( c4 ), relateOn->dataOld->dataFile->fileServerLock, relateOn->dataOld->dataFile->fileClientLock ) ;
if ( dataTemp == 0 )
rc = r4locked ;
else
{
/* check for data in relation via relate search */
for ( relateSkip = &relate->relation->relate ;; )
{
if ( relateSkip == 0 )
{
rc = r4locked ;
break ;
}
if ( relateSkip->dataOld == dataTemp )
break ;
if ( relate4next( &relateSkip ) == 2 )
break ;
}
}
}
else
rc = dfile4lockAll( relateOn->dataOld->dataFile, data4clientId( relateOn->dataOld ), data4serverId( relateOn->dataOld ), relateOn->dataOld ) ;
#else
rc = d4lockAll( relateOn->data ) ;
#endif
if ( rc != 0 )
break ;
if ( relate4next( &relateOn ) == 2 )
break ;
}
if ( rc != r4locked )
break ;
relate4unlock( relate ) ;
if ( count == 0 )
break ;
if ( count > 0 )
count-- ;
#ifdef S4TEMP
if ( d4displayQuit( &display ) )
{
rc = error4( c4, e4result, E84409 ) ;
break ;
}
#endif
u4delayHundredth( c4->lockDelay ) ; /* wait a second & try lock again */
}
c4->lockAttempts = oldAttempts ;
if ( error4code( c4 ) < 0 )
return error4code( c4 ) ;
return rc ;
#endif
}
#endif /* S4OLD_RELATE_LOCK */
/* direction : -1 = look backwards, 0 = lookup only, 1 = look forwards */
static int relate4lookup( RELATE4 *relate, const char direction )
{
int rc ;
long recno ;
CODE4 *c4 ;
RELATION4 *relation ;
#ifndef S4SERVER
int oldGoError ;
#endif
#ifndef S4INDEX_OFF
char *ptr ;
int len ;
#endif
#ifdef E4PARM_LOW
if ( relate == 0 )
return error4( 0, e4parm_null, E94412 ) ;
if ( direction < -1 || direction > 1 )
return error4( 0, e4parm, E94417 ) ;
#endif
c4 = relate->codeBase ;
if ( error4code( c4 ) < 0 )
return e4codeBase ;
relation = relate->relation ;
#ifdef E4MISC
if ( direction != 0 && relation->isInitialized == 0 )
return error4( c4, e4struct, E84406 ) ;
#endif
relate->isRead = 1 ;
if ( relate->master == 0 )
return 0 ;
#ifndef S4INDEX_OFF
d4tagSelect( relate->data, relate->dataTag ) ;
if ( relate->dataTag == 0 )
{
#endif
recno = (long)expr4double( relate->masterExpr ) ;
if ( error4code( c4 ) < 0 )
return -1 ;
if ( direction != 0 )
if ( f4flagIsSetFlip( &relate->set, (unsigned long)recno ) == 0 )
return relate4filterRecord ;
#ifndef S4SERVER
oldGoError = c4->errGo ;
c4->errGo = 0 ;
#endif
rc = d4go( relate->data, recno ) ;
#ifndef S4SERVER
c4->errGo = oldGoError ;
if ( rc < 0 )
return error4stack( c4, rc, E94412 ) ;
#endif
if ( rc != r4entry ) /* if not error, then return */
return 0 ;
if ( relate->relationType == relate4approx )
{
d4goEof( relate->data ) ;
return 0 ;
}
#ifndef S4INDEX_OFF
}
else
{
len = expr4key( relate->masterExpr, &ptr ) ;
if ( len < 0 )
return -1 ;
len = (len < relate->matchLen) ? len : relate->matchLen ; /* min of len and match len */
if ( relate->relationType == relate4scan )
{
#ifdef E4ANALYZE
if ( relate->master == 0 )
return error4( c4, e4struct, E84410 ) ;
#endif
if ( relate->master->scanValue == 0 )
{
relate->master->scanValueLen = len ;
relate->master->scanValue = (char *)u4allocEr( c4, (long)len ) ;
if ( relate->master->scanValue == 0 )
return -1 ;
}
memcpy( relate->master->scanValue, ptr, (unsigned int)len ) ;
}
rc = tfile4seek( relate->dataTag->tagFile, ptr, len ) ;
if ( rc < 0 )
return -1 ;
if ( relate->relationType == relate4approx || rc == 0 )
{
if ( tfile4eof( relate->dataTag->tagFile) )
{
d4goEof( relate->data ) ;
return 0 ;
}
if ( (int)direction < 0 && rc == 0 && relate->relationType == relate4scan ) /* look for last one */
for( ;; )
{
#ifdef S4HAS_DESCENDING
if ( !tfile4dskip( relate->dataTag->tagFile, 1L ) )
#else
if ( !tfile4skip( relate->dataTag->tagFile, 1L ) )
#endif
break ;
#ifdef S4FOX
if ( u4keycmp( tfile4keyData( relate->dataTag->tagFile )->value, ptr, (unsigned int)len, (unsigned int)relate->dataTag->tagFile->header.keyLen, 0, &relate->dataTag->tagFile->vfpInfo ) )
#else
if ( u4memcmp( tfile4keyData( relate->dataTag->tagFile )->value, ptr, (unsigned int)len ) )
#endif
{
#ifdef S4HAS_DESCENDING
tfile4dskip( relate->dataTag->tagFile, -1L ) ;
#else
tfile4skip( relate->dataTag->tagFile, -1L ) ;
#endif
break ;
}
}
recno = tfile4keyData( relate->dataTag->tagFile )->num ;
if ( direction != 0 )
if ( f4flagIsSetFlip( &relate->set, (unsigned long)recno ) == 0 )
return relate4filterRecord ;
if ( d4go( relate->data, recno ) < 0 )
return -1 ;
return 0 ;
}
else
recno = tfile4keyData( relate->dataTag->tagFile )->num ;
}
#endif
switch( relate->errorAction ) /* if got here, must be error condition */
{
case relate4blank:
if ( d4goEof( relate->data ) < 0 )
return -1 ;
if ( direction != 0 )
if ( f4flagIsSetFlip( &relate->set, (unsigned long)recno ) == 0 )
return relate4filterRecord ;
return 0 ;
case relate4skipRec:
/* if a scan, and a failure, then, if the current relation set is
below the current position, move it to above the current position */
if ( relate->relationType == relate4scan )
{
if ( relate != &relation->relate )
while ( relate4currentIsChild( relate ) )
relate4nextRelationList( relation, 0 ) ;
}
return relate4filterRecord ;
case relate4terminate:
#ifndef S4SERVER
if ( c4->errRelate )
return error4describe( c4, e4lookupErr, E94412, relate->data->alias, 0, 0 ) ;
#endif
return r4terminate ;
default: /* should never get this far */
return error4( c4, e4info, E84411 ) ;
}
}
#endif
RELATE4 *relate4lookupRelate( RELATE4 *relate, const DATA4 *d4 )
{
RELATE4 *relateReturn, *relateOn ;
if ( relate->data == d4 )
return relate ;
for( relateOn = 0 ;; )
{
relateOn = (RELATE4 *)l4next( &relate->slaves, relateOn) ;
if ( relateOn == 0 )
return 0 ;
relateReturn = relate4lookupRelate( relateOn, d4 ) ;
if ( relateReturn )
return relateReturn ;
}
}
int S4FUNCTION relate4matchLen( RELATE4 *relate, const int matchLenIn )
{
int len, matchLen ;
#ifdef E4PARM_HIGH
if ( relate == 0 )
return error4( 0, e4parm_null, E94413 ) ;
#endif
if ( error4code( relate->codeBase ) < 0 )
return e4codeBase ;
matchLen = matchLenIn ;
len = expr4keyLen( relate->masterExpr ) ;
#ifdef S4CLIPPER
if ( matchLen <= 0 )
matchLen = len ;
#else
if ( matchLen <= 0 )
{
relate->matchLen = len ;
return len ;
}
#endif
#ifndef S4CLIENT
#ifndef S4INDEX_OFF
#ifndef S4CLIPPER
#ifdef E4MISC
if ( relate->dataTag )
if( expr4type( relate->dataTag->tagFile->expr ) != r4str ) /* make sure r4str only */
return error4( relate->codeBase, e4relate, E84412 ) ;
#endif
#endif
#endif
#endif
if ( matchLen >= len )
matchLen = len ;
#ifndef S4CLIENT
#ifndef S4INDEX_OFF
if ( relate->dataTag )
{
len = expr4keyLen( relate->dataTag->tagFile->expr ) ;
if ( matchLen >= len )
matchLen = len ;
}
#endif
#endif
relate->matchLen = matchLen ;
relate4changed( relate ) ;
return matchLen ;
}
/* r4same = 0, r4down = 1, r4complete = 2 */
int S4FUNCTION relate4next( RELATE4 **ptrPtr )
{
RELATE4 *cur ;
void *nextLink ;
int rc ;
#ifdef E4PARM_HIGH
if ( ptrPtr == 0 )
return error4( 0, e4parm_null, E94414 ) ;
if ( *ptrPtr == 0 )
return error4( 0, e4parm_null, E94414 ) ;
#endif
cur = *ptrPtr ;
rc = r4down ;
if ( cur->slaves.nLink > 0 )
{
*ptrPtr = (RELATE4 *)l4first( &cur->slaves ) ;
return r4down ;
}
for(;;)
{
rc -- ;
if ( cur->master == 0 )
{
*ptrPtr = 0 ;
return r4complete ;
}
nextLink = l4next( &cur->master->slaves, cur ) ;
if ( nextLink )
{
*ptrPtr = (RELATE4 *)nextLink ;
return rc ;
}
cur = cur->master ;
}
}
#ifndef S4CLIENT
static int relate4nextRecordInScan( RELATE4 *relate )
{
long nextRec ;
int rc ;
DATA4 *d4 ;
#ifndef S4SERVER
int saveCode ;
#endif
#ifndef S4INDEX_OFF
B4KEY_DATA *key ;
#endif
#ifndef S4INDEX_OFF
char *ptr ;
int len ;
#endif
#ifdef E4PARM_LOW
if ( relate == 0 )
return error4( 0, e4parm_null, E94415 ) ;
#endif
if ( error4code( relate->codeBase ) < 0 )
return e4codeBase ;
#ifdef E4MISC
if ( relate->relation->isInitialized == 0 )
return error4( relate->codeBase, e4info, E84406 ) ;
#endif
if ( relate->relation->inSort == relate4sortSkip && relate->sortType == relate4sortSkip )
return r4eof ;
d4 = relate->data ;
#ifndef S4INDEX_OFF
if ( relate->dataTag == 0 )
{
#endif
if ( d4bof( d4 ) )
nextRec = 1 ;
else
nextRec = d4recNo( d4 ) + 1 ;
nextRec += f4flagGetNextFlip( &relate->set, (unsigned long)nextRec, (char)1 ) ;
if ( d4recCountLessEq( d4, nextRec ) == 0 )
return r4eof ;
#ifndef S4INDEX_OFF
}
else
for(;;)
{
if ( d4bof( d4 ) )
{
if ( d4recCountLessEq( d4, 1L ) == 0L ) /* count == 0 */
return r4eof ;
if ( relate->masterExpr == 0 ) /* top relate, bof */
return r4bof ;
len = expr4key( relate->masterExpr, &ptr ) ;
if ( len < 0 )
return -1 ;
len = (len < relate->matchLen) ? len : relate->matchLen ; /* min of len and match len */
rc = (int)tfile4seek( relate->dataTag->tagFile, relate->master->scanValue, len ) ;
if ( rc < 0 )
return -1 ;
if ( rc == 0 )
rc = 1 ;
else
rc = 0 ;
}
else
#ifdef S4HAS_DESCENDING
rc = (int)tfile4dskip( relate->dataTag->tagFile, 1L ) ;
#else
rc = (int)tfile4skip( relate->dataTag->tagFile, 1L ) ;
#endif
if ( rc < 0 )
return -1 ;
if ( rc != 1 )
return r4eof ;
key = tfile4keyData( relate->dataTag->tagFile) ;
nextRec = key->num ;
if ( relate->master )
{
#ifdef S4FOX
if ( u4keycmp( key->value, relate->master->scanValue, (unsigned int)relate->master->scanValueLen,
(unsigned int)relate->dataTag->tagFile->header.keyLen, 0, &relate->dataTag->tagFile->vfpInfo ) )
#else
if ( u4memcmp( key->value, relate->master->scanValue, (unsigned int)relate->master->scanValueLen ) )
#endif
return r4eof ;
}
if ( f4flagIsSetFlip( &relate->set, (unsigned long)nextRec ) )
break ;
}
#endif
#ifndef S4SERVER
saveCode = relate->codeBase->errGo ;
relate->codeBase->errGo = 0 ;
#endif
rc = d4go( d4, nextRec ) ;
#ifndef S4SERVER
relate->codeBase->errGo = saveCode ;
#endif
if ( rc < 0 )
return -1 ;
if ( rc == r4entry )
return r4eof ;
relate->isRead = 1 ; /* we have updated this one */
return relate4skipped ;
}
/* returns 1 if the current relation set is a child (or is itself) of the input relation */
static int relate4currentIsChild( RELATE4 *parent )
{
RELATE4 *relateOn ;
relateOn = parent->relation->currentRelateLevel ;
if ( relateOn == parent )
return 1 ;
for ( relateOn = 0 ;; ) /* now recursively check all the descendents */
{
relateOn = (RELATE4 *)l4next( &parent->slaves, relateOn ) ;
if ( relateOn == 0 )
return 0 ;
if ( relate4currentIsChild( relateOn ) == 1 )
return 1 ;
}
}
/* returns 1 if the parent is above the child at any level (grandparent, etc) */
static int relate4parent( RELATE4 *parent, RELATE4 *child )
{
RELATE4 *slaveOn, *masterOn ;
for ( slaveOn = child ;; )
{
masterOn = slaveOn->master ;
if ( masterOn == 0 )
return 0 ;
if ( masterOn == parent )
return 1 ;
slaveOn = slaveOn->master ; /* go up one level */
}
}
/* returns 1 if done, 0 if positioned to a new relate */
/* if setup is true, it just does positional work (for relate4top), no reads */
static int relate4nextRelationList( RELATION4 *relation, int setup )
{
RELATE4 *relateOn, *master ;
int rc, rc2 ;
relateOn = relation->currentRelateLevel ;
if ( relateOn == 0 ) /* means get the first one */
relateOn = &relation->relate ;
else
if ( setup != 1 )
{
/* first see if we are part of a scan ourselves, and if so that we are scanned */
if ( relateOn->relationType == relate4scan || relateOn == &relation->relate ) /* the master is an implicit scan */
{
relate4setNotRead( relateOn ) ; /* This data file & its slaves */
if ( relation->inSort == relate4sortDone )
if ( r4dataListFind( &relation->sortDataList, relateOn ) )
return relate4sortNextRecord( relation ) ;
rc = relate4nextRecordInScan( relateOn ) ;
if ( rc == relate4skipped )
return 0 ;
rc2 = relate4blankSet( relateOn, (char)1 ) ;
if ( rc2 == r4locked || rc2 < 0 ) /* error or locked */
return rc2 ;
if ( relateOn->master == 0 )
if ( d4eof( relateOn->data ) )
return r4eof ;
/* are our siblings also scanned? */
/* we are scanned, so fall through and check out our master */
}
if ( relateOn->master == 0 )
{
relation->currentRelateLevel = 0 ;
return r4eof ;
}
master = relateOn->master ;
/* try our masters next slave */
relateOn = (RELATE4 *)l4next( &master->slaves, relateOn ) ;
if ( relateOn == 0 ) /* no more slaves, try the master itself */
{
relation->currentRelateLevel = master ;
return relate4continue ; /* either do ourselves or go up further */
}
}
/* we need to go down our own slave list to the bottom level and start seek */
while ( relateOn->slaves.nLink != 0 )
relateOn = (RELATE4 *)l4first( &relateOn->slaves ) ;
/* at the bottom, so try ourselves */
relation->currentRelateLevel = relateOn->master ;
if ( setup == 1 )
return relate4continue ;
if ( relateOn->master == 0 ) /* done/ eof */
return r4eof ;
if ( relateOn->relationType == relate4scan )
return relate4continue ;
/* otherwise try our current masters other slaves--i.e. just go get next */
return relate4nextRelationList( relation, setup ) ;
}
static int relate4nextScanRecord( RELATION4 *relation )
{
RELATE4 *relate ;
int rc, rc2, tryMatches ;
LIST4 *relateList ;
if ( error4code( relation->relate.codeBase ) < 0 )
return -1 ;
rc = 0 ;
for ( ;; )
{
if ( relation->currentRelateLevel == 0 )
relation->currentRelateLevel = &relation->relate ;
for ( ;; )
{
relateList = &relation->currentRelateLevel->relateList ;
tryMatches = 1 ;
if ( d4eof( relation->currentRelateLevel->data ) ) /* we are at eof, so all children cannot match */
tryMatches = 0 ;
else
{
if ( relation->currentRelateLevel->master != 0 )
if ( d4eof( relation->currentRelateLevel->master->data ) ) /* means no matches possible */
tryMatches = 0 ;
}
if ( tryMatches == 1 && l4numNodes( relateList ) )
{
if ( relateList->selected == 0 )
relateList->selected = (LINK4 *)l4first( relateList ) ;
for( ;; )
{
if ( relateList->selected == 0 ) /* finished with matches for this list */
break ;
relate = ((RELATE4LIST *)relateList->selected)->ptr ;
relate4setNotRead( relate ) ; /* This data file & its slaves */
if ( relation->inSort == relate4sortDone )
if ( r4dataListFind( &relation->sortDataList, relate ) )
return relate4sortNextRecord( relation ) ;
rc = relate4nextRecordInScan( relate ) ;
if ( rc == relate4skipped )
return 0 ;
if ( rc < 0 )
return rc ;
rc2 = relate4blankSet( relate, (char)1 ) ;
if ( rc2 == r4locked || rc2 < 0 ) /* error or locked */
return rc2 ;
if ( relate->master == 0 )
if ( d4eof( relate->data ) )
return r4eof ;
relateList->selected =(LINK4 *)l4next( relateList, relateList->selected ) ;
}
}
rc = relate4nextRelationList( relation, 0 ) ;
if ( rc != relate4continue )
return rc ;
}
/*
for ( ;; )
{
if ( d4eof( relation->relate.data ) )
{
rc = r4eof ;
break ;
}
if ( relation->inSort == relate4sortDone )
if ( r4dataListFind( &relation->sortDataList, &relation->relate ) )
{
relate4setNotRead( &relation->relate ) ;
return relate4sortNextRecord( relation ) ;
}
rc = relate4nextRecordInScan( &relation->relate ) ;
if ( rc < 0 )
return rc ;
if ( rc != relate4skipped )
{
rc = r4bof ;
break ;
}
relate4setNotRead( &relation->relate ) ;
rc = relate4lookup( &relation->relate, 1 ) ;
if ( rc != 0 )
continue ;
rc = relate4readRest( &relation->relate, 1 ) ;
if ( rc == 0 || rc < 0 || rc == r4terminate )
return rc ;
rc = 0 ;
}
if ( rc != 0 )
break ;
*/
}
/* d4goEof( relation->relate.data ) ; */
/* return r4eof ; */
}
/* returns 1 if done, 0 if positioned to a new relate */
/* if setup is true, it just does positional work (for relate4top), no reads */
static int relate4prevRelationList( RELATION4 *relation, int setup )
{
RELATE4 *relateOn, *master ;
int rc, rc2 ;
relateOn = relation->currentRelateLevel ;
if ( relateOn == 0 ) /* means get the first one */
relateOn = &relation->relate ;
else
if ( setup != 1 )
{
/* first see if we are part of a scan ourselves, and if so that we are scanned */
if ( relateOn->relationType == relate4scan || relateOn == &relation->relate ) /* the master is an implicit scan */
{
relate4setNotRead( relateOn ) ; /* This data file & its slaves */
if ( relation->inSort == relate4sortDone )
if ( r4dataListFind( &relation->sortDataList, relateOn ) )
return relate4sortPrevRecord( relation ) ;
rc = relate4prevRecordInScan( relateOn ) ;
if ( rc == relate4skipped )
{
if ( relate4eof( relateOn ) )
{
if ( relation->inSort == relate4sortDone && relation->sortEofFlag == 1 )
{
relation->sortRecOn-- ; /* move off eof on sort part */
relation->sortEofFlag = 0 ;
}
else
{
rc = d4go( relation->relate.data, d4recCount( relation->relate.data ) ) ;
if ( rc < 0 )
return rc ;
}
}
return 0 ;
}
if ( rc < 0 )
return rc ;
rc2 = relate4blankSet( relateOn, (char)-1 ) ;
if ( rc2 == r4locked || rc2 < 0 ) /* error or locked */
return rc2 ;
if ( relateOn->master == 0 )
{
if ( d4bof( relateOn->data ) )
return r4bof ;
if ( d4eof( relateOn->data ) )
return r4eof ;
}
/* are our siblings also scanned? */
/* we are scanned, so fall through and check out our master */
}
if ( relateOn->master == 0 )
{
relation->currentRelateLevel = 0 ;
return r4bof ;
}
master = relateOn->master ;
/* try our masters prev slave */
relateOn = (RELATE4 *)l4prev( &master->slaves, relateOn ) ;
if ( relateOn == 0 ) /* no more slaves, try the master itself */
{
relation->currentRelateLevel = master ;
return relate4continue ; /* either do ourselves or go up further */
}
}
/* we need to go down our own slave list to the bottom level and start seek */
while ( relateOn->slaves.nLink != 0 )
relateOn = (RELATE4 *)l4last( &relateOn->slaves ) ;
/* at the bottom, so try ourselves */
relation->currentRelateLevel = relateOn->master ;
if ( setup == 1 )
return relate4continue ;
if ( relateOn->master == 0 ) /* done / bof */
return r4bof ;
if ( relateOn->relationType == relate4scan )
return relate4continue ;
/* otherwise try our current masters other slaves--i.e. just go get next */
return relate4prevRelationList( relation, setup ) ;
}
static int relate4prevRecordInScan( RELATE4 *relate )
{
long nextRec ;
int rc ;
DATA4 *d4 ;
#ifndef S4SERVER
int saveCode ;
#endif
#ifndef S4INDEX_OFF
B4KEY_DATA *key ;
#ifdef S4HAS_DESCENDING
unsigned short int oldDesc ;
int len ;
char *ptr ;
#endif
#endif
#ifdef E4PARM_LOW
if ( relate == 0 )
return error4( 0, e4parm_null, E94416 ) ;
#endif
#ifdef E4MISC
if ( relate->relation->isInitialized == 0 )
return error4( relate->codeBase, e4info, E84406 ) ;
#endif
d4 = relate->data ;
#ifndef S4INDEX_OFF
if ( relate->dataTag == 0 )
{
#endif
nextRec = d4recNo( d4 ) - 1 ;
nextRec -= f4flagGetNextFlip( &relate->set, (unsigned long)nextRec, (char)-1 ) ;
if ( nextRec <= 0 )
return r4bof ;
if ( d4recCountLessEq( d4, nextRec ) == 0 )
return r4eof ;
#ifndef S4INDEX_OFF
}
else
for(;;)
{
if ( relate4eof( relate ) ) /* if eof in relate, just leave on last tag entry */
rc = tfile4eof( relate->dataTag->tagFile ) ? 0 : -1 ;
else
{
if ( d4eof( d4 ) == 1 )
{
if ( d4recCountLessEq( d4, 1L ) == 0L ) /* count == 0 */
return r4bof ;
if ( relate->masterExpr == 0 ) /* top relate, bof */
return r4eof ;
#ifdef S4HAS_DESCENDING
len = expr4key( relate->masterExpr, &ptr ) ;
if ( len < 0 )
return -1 ;
len = (len < relate->matchLen) ? len : relate->matchLen ; /* min of len and match len */
oldDesc = relate->dataTag->tagFile->header.descending ;
tfile4descending( relate->dataTag->tagFile, ((unsigned short int)(1 - oldDesc)) ) ; /* invert the descending */
rc = (int)tfile4seek( relate->dataTag->tagFile, relate->master->scanValue, len ) ;
tfile4descending( relate->dataTag->tagFile, oldDesc ) ;
#else
/* need to find the last matching entry, without seek */
rc = (int)tfile4bottom( relate->dataTag->tagFile ) ;
if ( rc == 0 )
{
rc = -1 ;
while ( rc == -1 )
{
key = tfile4keyData( relate->dataTag->tagFile) ;
if ( u4memcmp( key->value, relate->master->scanValue, (unsigned int)relate->master->scanValueLen ) == 0 )
{
rc = 0 ;
break ;
}
if ( u4memcmp( key->value, relate->master->scanValue, (unsigned int)relate->master->scanValueLen ) < 0 )
return r4bof ;
rc = (int)tfile4skip( relate->dataTag->tagFile, -1L ) ;
}
}
#endif
if ( rc < 0 )
return -1 ;
if ( rc == 0 )
rc = -1 ;
else
rc = 0 ;
}
else
#ifdef S4HAS_DESCENDING
rc = (int)tfile4dskip( relate->dataTag->tagFile, -1L ) ;
#else
rc = (int)tfile4skip( relate->dataTag->tagFile, -1L ) ;
#endif
}
if ( rc > 0 )
return -1 ;
if ( rc != -1L )
return r4bof ;
key = tfile4keyData( relate->dataTag->tagFile) ;
nextRec = key->num ;
if ( relate->master )
#ifdef S4FOX
if ( u4keycmp( key->value, relate->master->scanValue, (unsigned int)relate->master->scanValueLen,
(unsigned int)relate->dataTag->tagFile->header.keyLen, 0, &relate->dataTag->tagFile->vfpInfo ) )
#else
if ( u4memcmp( key->value, relate->master->scanValue, (unsigned int)relate->master->scanValueLen ) )
#endif
return r4bof ;
if ( f4flagIsSetFlip( &relate->set, (unsigned long)nextRec ) )
break ;
}
#endif
#ifndef S4SERVER
saveCode = relate->codeBase->errGo ;
relate->codeBase->errGo = 0 ;
#endif
rc = d4go( d4, nextRec ) ;
#ifndef S4SERVER
relate->codeBase->errGo = saveCode ;
#endif
if ( rc < 0 )
return -1 ;
if ( rc == r4entry )
return r4eof ;
relate->isRead = 1 ; /* we have updated this one */
return relate4skipped ;
}
static int relate4prevScanRecord( RELATION4 *relation )
{
RELATE4 *relate ;
int rc, rc2, tryMatches ;
LIST4 *relateList ;
if ( error4code( relation->relate.codeBase ) < 0 )
return -1 ;
rc = 0 ;
for ( ;; )
{
if ( relation->currentRelateLevel == 0 )
relation->currentRelateLevel = &relation->relate ;
for ( ;; )
{
relateList = &relation->currentRelateLevel->relateList ;
tryMatches = 1 ;
if ( d4eof( relation->currentRelateLevel->data ) ) /* we are at eof, so all children cannot match */
tryMatches = 0 ;
else
{
if ( relation->currentRelateLevel->master != 0 )
if ( d4eof( relation->currentRelateLevel->master->data ) ) /* means no matches possible */
tryMatches = 0 ;
}
if ( tryMatches == 1 && l4numNodes( relateList ) )
{
if ( relateList->selected == 0 )
relateList->selected = (LINK4 *)l4last( relateList ) ;
for (;; )
{
if ( relateList->selected == 0 ) /* finished with matches for this list */
break ;
relate = ((RELATE4LIST *)l4last( relateList ))->ptr ;
if ( relate4eof( relate ) ) /* at eof means we must read this record */
if ( relation->inSort != relate4sortDone )
{
rc = relate4bottom( relate ) ;
if ( rc == r4eof ) /* no records, so can't skip back */
return r4bof ;
else
return rc ;
}
relate = ((RELATE4LIST *)relateList->selected)->ptr ;
relate4setNotRead( relate ) ; /* This data file & its slaves */
if ( relation->inSort == relate4sortDone )
if ( r4dataListFind( &relation->sortDataList, relate ) )
return relate4sortPrevRecord( relation ) ;
rc = relate4prevRecordInScan(relate) ;
if ( rc == relate4skipped )
{
if ( relate4eof( relate ) )
{
if ( relation->inSort == relate4sortDone && relation->sortEofFlag == 1 )
{
relation->sortRecOn-- ; /* move off eof on sort part */
relation->sortEofFlag = 0 ;
}
else
{
rc = d4go( relation->relate.data, d4recCount( relation->relate.data ) ) ;
if ( rc < 0 )
return rc ;
}
}
return 0 ;
}
if ( rc < 0 )
return rc ;
rc2 = relate4blankSet( relate, (char)-1 ) ;
if ( rc2 == r4locked || rc2 < 0 ) /* error or locked */
return rc2 ;
if ( relate->master == 0 )
{
if ( d4bof(relate->data) )
return r4bof ;
if ( d4eof(relate->data) )
return r4eof ;
}
relateList->selected =(LINK4 *)l4prev( relateList, relateList->selected ) ;
}
}
rc = relate4prevRelationList( relation, 0 ) ;
if ( rc != relate4continue )
return rc ;
}
/*
for ( ;; )
{
if ( d4bof( relation->relate.data ) || d4eof( relation->relate.data ) )
{
rc = r4bof ;
break ;
}
if ( relation->inSort == relate4sortDone )
if ( r4dataListFind( &relation->sortDataList, &relation->relate ) )
{
relate4setNotRead( &relation->relate ) ;
return relate4sortPrevRecord( relation ) ;
}
rc = relate4prevRecordInScan( &relation->relate ) ;
if ( rc < 0 )
return rc ;
if ( rc != relate4skipped )
{
rc = r4bof ;
break ;
}
relate4setNotRead( &relation->relate ) ;
rc = relate4lookup( &relation->relate, -1 ) ;
if ( rc != 0 )
continue ;
rc = relate4readRest( &relation->relate, -1 ) ;
if ( rc == 0 || rc < 0 || rc == r4terminate )
return rc ;
rc = 0 ;
}
if ( rc != 0 )
break ;
*/
}
/* return r4bof ; */
}
#endif
int S4FUNCTION relate4querySet( RELATE4 *relate, const char *expr )
{
int len ;
if ( relate == 0 )
return -1 ;
#ifdef S4VBASIC
if ( c4parm_check( relate, 5, E94428 ) )
return -1 ;
#endif
if ( error4code( relate->codeBase ) < 0 )
return -1 ;
relate4changed( relate ) ;
u4free( relate->relation->exprSource ) ;
relate->relation->exprSource = 0 ;
if ( expr == 0 )
return 0 ;
if ( expr[0] == 0 )
return 0 ;
len = strlen( expr ) + 1 ;
relate->relation->exprSource = (char *)u4allocEr( relate->codeBase, (long)len ) ;
if ( relate->relation->exprSource == 0 )
return -1 ;
memcpy( relate->relation->exprSource, expr, (unsigned int)len ) ;
return 0 ;
}
#ifndef S4CLIENT
int relate4readIn( RELATE4 *relate )
{
int rc ;
if ( error4code( relate->codeBase ) < 0 )
return -1 ;
if ( relate->isRead )
return 0 ;
if ( relate->master )
if ( relate->master->isRead == 0 )
{
rc = relate4readIn( relate->master ) ;
if ( rc == relate4filterRecord || rc == r4terminate )
return rc ;
}
return relate4lookup( relate, 1 ) ;
}
/* direction : -1 = look backwards, 0 = lookup only, 1 = look forwards */
static int relate4readRest( RELATE4 *relate, char direction )
{
RELATE4 *slave ;
int rc, scanDone ;
#ifdef E4PARM_LOW
if ( relate == 0 )
return error4( 0, e4parm_null, E94417 ) ;
if ( direction < -1 || direction > 1 )
return error4( 0, e4parm, E94417 ) ;
#endif
#ifdef E4ANALYZE
if ( error4code( relate->codeBase ) < 0 )
return e4codeBase ;
#endif
rc = 0 ;
if ( relate->isRead == 0 )
{
rc = relate4lookup( relate, direction );
if ( rc < 0 || rc == relate4filterRecord || rc == r4terminate )
return rc ;
}
scanDone = 0 ;
for( slave = 0 ;; )
{
if ( direction == 1 )
slave = (RELATE4 *)l4next( &relate->slaves, slave ) ;
else
slave = (RELATE4 *)l4prev( &relate->slaves, slave ) ;
if ( slave == 0 )
break ;
if ( slave->isRead == 0 )
if ( slave->relationType == relate4scan )
{
/* if the currentRelateLevel is an upward master of ourselves,
then make our master the currentRelateLevel so that the next
skip will scan through us */
if ( relate4parent( slave->relation->currentRelateLevel, slave->master ) )
slave->relation->currentRelateLevel = slave->master ;
if ( direction == 1 )
{
d4top( slave->data ) ;
#ifndef S4OFF_INDEX
tfile4top( slave->dataTag->tagFile ) ;
#endif
}
else
{
d4bottom( slave->data ) ;
#ifndef S4OFF_INDEX
tfile4bottom( slave->dataTag->tagFile ) ;
#endif
}
}
}
for( slave = 0 ;; )
{
if ( direction == 1 )
slave = (RELATE4 *)l4next( &relate->slaves, slave ) ;
else
slave = (RELATE4 *)l4prev( &relate->slaves, slave ) ;
if ( slave == 0 )
return 0 ;
if ( slave->relationType == relate4scan && scanDone == 1 )
{
if ( slave->isRead == 0 )
{
relate4blankSet( slave, (char)(-direction) ) ; /* do reverse of direction */
slave->isRead = 1 ;
rc = relate4readRest( slave, direction ) ;
}
}
else
{
rc = relate4readRest( slave, direction ) ;
if ( slave->relationType == relate4scan && rc == 0 )
{
switch ( direction )
{
case -1:
if ( !d4bof( slave->data ) )
scanDone = 1 ;
break ;
case 1:
if ( !d4eof( slave->data ) )
scanDone = 1 ;
break ;
default:
break ;
}
}
}
if ( rc < 0 || rc == relate4filterRecord || rc == r4terminate )
return rc ;
}
}
static void relate4setNotRead( RELATE4 *relate )
{
RELATE4 *slaveOn ;
if ( relate->isRead )
{
relate->isRead = 0 ;
for( slaveOn = 0 ;; )
{
slaveOn = (RELATE4 *)l4next(&relate->slaves,slaveOn) ;
if ( slaveOn == 0 )
return ;
relate4setNotRead( slaveOn ) ;
}
}
}
#endif
int S4FUNCTION relate4skip( RELATE4 *relate, const long numSkip )
{
int rc ;
long numskip ;
RELATION4 *relation ;
CODE4 *c4 ;
#ifdef S4CLIENT
CONNECTION4RELATE_SKIP_INFO_IN info ;
CONNECTION4 *connection ;
int saveRc ;
#else
int sortStatus, rc2 ;
signed char sign ;
#ifdef S4REPORT
#ifdef S4WINDOWS
char countstring[22];
static long int scanrecCount = 0, selectrecCount = 0, sortrecCount = 0;
HWND statwin;
#endif
#endif
#ifndef S4SINGLE
int oldReadLock ;
#endif
#endif
#ifdef S4VBASIC
if ( c4parm_check( relate, 5, E94418 ) )
return -1 ;
#endif
#ifdef E4PARM_HIGH
if ( relate == 0 )
return error4( 0, e4parm_null, E94418 ) ;
#endif
c4 = relate->codeBase ;
if ( error4code( c4 ) < 0 )
return e4codeBase ;
numskip = numSkip ;
relation = relate->relation ;
if ( relation->isInitialized == 0 )
return error4( c4, e4info, E84406 ) ;
relate = &relation->relate ;
#ifdef S4CLIENT
#ifdef E4ANALYZE
if ( relate->data == 0 )
return error4( c4, e4struct, E94418 ) ;
if ( relate->data->dataFile == 0 )
return error4( c4, e4struct, E94418 ) ;
#endif
connection = relate->data->dataFile->connection ;
#ifdef E4ANALYZE
if ( connection == 0 )
return error4( c4, e4struct, E94418 ) ;
#endif
connection4assign( connection, CON4RELATE_SKIP, 0, 0 ) ;
info.relationId = relation->relationId ;
info.numSkips = numskip ;
connection4addData( connection, &info, sizeof( CONNECTION4RELATE_SKIP_INFO_IN ), 0 ) ;
connection4send( connection ) ;
saveRc = connection4receive( connection ) ;
if ( saveRc < 0 )
return error4stack( c4, saveRc, E94418 ) ;
saveRc = connection4status( connection ) ;
if ( saveRc < 0 )
return connection4error( connection, c4, saveRc, E94418 ) ;
rc = relate4unpack( relation, relate->data->dataFile->connection ) ;
if ( rc < 0 )
return error4stack( c4, rc, E94418 ) ;
return saveRc ;
#else
if ( numskip < 0 )
{
if ( relation->skipBackwards == 0 )
return error4( c4, e4info, E84417 ) ;
sign = -1 ;
}
else
sign = 1 ;
sortStatus = 0 ;
rc = 0 ;
#ifndef S4SINGLE
/* suspend auto read locking from within the relate */
oldReadLock = c4->readLock ;
c4->readLock = 0 ;
#endif
for( ; numskip ; )
{
#ifdef S4REPORT
#ifdef S4WINDOWS
if( GetWindowWord( c4->hWnd, 8 ) == 666 )
statwin = c4->hWnd ;
if ( statwin )
{
if ( GetWindowWord( statwin, 6 ) == 0 )
{
SetWindowWord( statwin, 6, 1 ) ;
scanrecCount = sortrecCount = selectrecCount = 0 ;
}
scanrecCount++ ;
if ( scanrecCount < 20 || ( scanrecCount % 20 ) == 0 )
{
c4ltoa45( scanrecCount, countstring, sizeof( countstring ) -1 ) ;
countstring[21] = 0 ;
SendMessage( (HWND)GetWindowWord( statwin, 0 ), WM_SETTEXT, 0, (LPARAM)((LPSTR)countstring ) ) ;
}
}
#endif
#endif
if ( sign > 0 )
{
rc = relate4nextScanRecord( relation ) ;
if ( rc == r4eof )
break ;
}
else
{
rc = relate4prevScanRecord( relation ) ;
if ( rc == r4bof )
break ;
}
#ifdef S4SINGLE
if ( rc < 0 || rc == r4terminate )
#else
if ( rc < 0 || rc == r4locked || rc == r4terminate )
#endif
break ;
rc = relate4readRest( relate, sign ) ;
if ( rc == relate4filterRecord )
continue ;
if ( rc < 0 || rc == r4terminate )
break ;
if ( relation->exprSource )
{
rc2 = log4true(&relation->log ) ;
if ( rc2 == r4terminate )
{
rc = r4terminate ;
break ;
}
if ( rc2 == 0 )
{
if ( relation->inSort == relate4sortSkip ) /* must temporarily disable in order to get a matching scan if available */
{
sortStatus = 1 ;
relation->inSort = 0 ;
}
continue ;
}
}
numskip -= sign ;
}
#ifndef S4SINGLE
/* suspend auto read locking from within the relate */
c4->readLock = oldReadLock ;
#endif
#ifdef S4WINDOWS
#ifdef S4REPORT
if(GetWindowWord( c4->hWnd, 8 ) == 666 )
statwin = c4->hWnd;
if ( statwin )
{
selectrecCount++;
if ( selectrecCount < 20 || (selectrecCount % 20) == 0 )
{
c4ltoa45(selectrecCount,countstring,sizeof(countstring)-1);
countstring[21] = 0;
SendMessage((HWND)GetWindowWord(statwin,2),WM_SETTEXT,0,(LPARAM)((LPSTR)countstring));
}
if ( relation->inSort )
{
sortrecCount++;
if( sortrecCount < 20 || (sortrecCount % 20) == 0)
{
c4ltoa45(sortrecCount,countstring,sizeof(countstring)-1);
countstring[21] = 0;
SendMessage((HWND)GetWindowWord(statwin,4),WM_SETTEXT,0,(LPARAM)((LPSTR)countstring));
}
}
}
#endif
#endif
if ( sortStatus == 1 )
relation->inSort = relate4sortSkip ;
return rc ;
#endif
}
int S4FUNCTION relate4skipEnable( RELATE4 *relate, const int doEnable )
{
if ( relate == 0 )
return -1 ;
if ( error4code( relate->codeBase ) < 0 )
return -1 ;
if ( relate->relation->skipBackwards != (char) doEnable )
{
relate->relation->skipBackwards = (char) doEnable ;
relate4changed( relate ) ;
}
return 0 ;
}
static void relate4sortFree( RELATION4 *relation, const int deleteSort )
{
if ( relation == 0 )
return ;
#ifndef S4CLIENT
sort4free( &relation->sort ) ;
u4free( relation->otherData ) ;
relation->otherData = 0 ;
if ( relation->sortedFile.hand >= 0 )
file4close( &relation->sortedFile ) ;
r4dataListFree( &relation->sortDataList ) ;
relation->inSort = 0 ;
#endif
if ( deleteSort )
{
u4free( relation->sortSource ) ;
relation->sortSource = 0 ;
}
}
#ifndef S4CLIENT
static int relate4sort( RELATE4 *relate )
{
EXPR4 *sortExpr ;
int rc, i, len ;
long j, zero ;
char nDbf, *sortKey ;
R4DATA_LIST *r4data ;
RELATION4 *relation ;
CODE4 *c4 ;
#ifdef S4SERVER
LIST4 *oldList ;
#endif
zero = 0L ;
#ifdef E4PARM_LOW
if ( relate == 0 )
return error4( 0, e4parm_null, E94419 ) ;
#endif
c4 = relate->codeBase ;
#ifdef E4ANALYZE
if ( error4code( c4 ) < 0 )
return e4codeBase ;
#endif
relation = relate->relation ;
relate = &relation->relate ;
rc = 0 ;
#ifdef S4SERVER
oldList = tran4dataList( code4trans( c4 ) ) ;
tran4dataListSet( code4trans( c4 ), &relation->localDataList ) ;
#endif
sortExpr = expr4parseLow( relate->data, relation->sortSource, 0 ) ;
#ifdef S4SERVER
tran4dataListSet( code4trans( c4 ), oldList ) ;
#endif
relation->inSort = relate4sortSkip ;
relation->sortDoneFlag = 0 ;
rc = relate4top( relate ) ;
if ( rc ) /* no records satisfy the relate, or error */
{
expr4free( sortExpr ) ;
return rc ;
}
len = expr4key( sortExpr, &sortKey ) ;
if ( len <= 0 )
{
expr4free( sortExpr ) ;
return -1 ;
}
#ifdef E4ANALYZE
if ( relation->sortDataList.nLink != 0 )
return error4( c4, e4struct, E84413 ) ;
#endif
if ( r4dataListBuild( &relation->sortDataList, relate, sortExpr, relate4exact ) < 0 )
{
expr4free( sortExpr ) ;
return -1 ;
}
if ( r4dataListMassage( &relation->sortDataList ) < 0 )
{
expr4free( sortExpr ) ;
return -1 ;
}
nDbf = (char)relation->sortDataList.nLink ;
relation->sortOtherLen = (int)(nDbf * sizeof( long )) ;
relation->otherData = (char *)u4alloc( (long)relation->sortOtherLen ) ;
if ( relation->otherData == 0 )
return -1 ;
rc = sort4initFree( &relation->sort, c4, len, relation->sortOtherLen, relate ) ;
if ( rc )
{
expr4free( sortExpr ) ;
return rc ;
}
#ifndef S4FOX
#ifndef S4CLIPPER
switch( expr4type( sortExpr ) )
{
#ifdef S4NDX
case r4num:
case r4num_doub:
case r4date:
case r4date_doub:
relation->sort.cmp = (S4CMP_FUNCTION *)t4cmpDoub ;
break ;
#endif
#ifdef S4MDX
case r4num:
relation->sort.cmp = (S4CMP_FUNCTION *)c4bcdCmp ;
break ;
case r4date:
relation->sort.cmp = (S4CMP_FUNCTION *)t4cmpDoub ;
break ;
#endif
default:
break ;
}
#endif
#endif
/* call relate4top() again in case free-ups occurred */
rc = relate4top( relate ) ;
if ( rc ) /* no records satisfy the relate, or error */
{
expr4free( sortExpr ) ;
return rc ;
}
for ( j = 0L, rc = 0 ; !rc ; j++, rc = relate4skip( relate, 1L ) )
{
for ( i = 0, r4data = 0 ;; i++ )
{
r4data = (R4DATA_LIST *)l4next( &relation->sortDataList, r4data ) ;
if ( r4data == 0 )
break ;
if ( d4eof( r4data->data ) || d4bof( r4data->data ) ) /* relate4blank case */
memcpy( relation->otherData + i * sizeof(long), (void *)&zero, sizeof( long ) ) ;
else
memcpy( relation->otherData + i * sizeof(long), (void *)&r4data->data->recNum, sizeof( long ) ) ;
}
if ( expr4key( sortExpr, &sortKey ) < 0 )
{
expr4free( sortExpr ) ;
u4free( relation->otherData ) ;
relation->otherData = 0 ;
return -1 ;
}
if ( sort4put( &relation->sort, j, sortKey, relation->otherData ) < 0 )
{
expr4free( sortExpr ) ;
u4free( relation->otherData ) ;
relation->otherData = 0 ;
return -1 ;
}
}
expr4free( sortExpr ) ;
if ( rc < 0 || rc == r4terminate )
{
u4free( relation->otherData ) ;
relation->otherData = 0 ;
return rc ;
}
relation->sortRecCount = j ;
relation->inSort = relate4sortDone ;
if ( relation->skipBackwards )
if ( file4tempLow( &relation->sortedFile, c4, 1 ) < 0 )
{
u4free( relation->otherData ) ;
relation->otherData = 0 ;
return -1 ;
}
if ( sort4getInitFree( &relation->sort, relate ) < 0 )
return -1 ;
relation->sortRecOn = relation->sortFilePos = relation->sortRecTo = 0L ;
return 0 ;
}
static int relate4sortGetRecord( RELATION4 *relation, const long num )
{
int len, i, rc ;
char *key ;
char *other = 0 ;
R4DATA_LIST *linkOn ;
long j, numLeft ;
#ifdef S4DATA_ALIGN
long longPtr ;
#endif
if ( error4code( relation->relate.codeBase ) < 0 )
return -1 ;
if ( num <= 0 )
return r4bof ;
relation->sortEofFlag = 0 ;
numLeft = num - relation->sortRecTo ;
if ( numLeft <= 0 ) /* already read, so just return from file */
{
if ( relation->skipBackwards == 0 )
return -1 ;
len = file4read( &relation->sortedFile, ( num - 1 ) * relation->sortOtherLen, relation->otherData, (unsigned int)relation->sortOtherLen ) ;
if ( len != relation->sortOtherLen ) /* free up and exit */
return -1 ;
other = relation->otherData ;
}
else
while ( numLeft-- )
{
if ( relation->sortDoneFlag == 1 ) /* sort is finished, therefore must be eof */
return r4eof ;
rc = sort4get( &relation->sort, &j, (void **)&key, (void **)&other ) ;
if ( rc ) /* no more items, or error */
{
sort4free( &relation->sort ) ;
if ( rc == 1 )
{
relation->sortEofFlag = 1 ;
relation->sortDoneFlag = 1 ;
return r4eof ;
}
else
return rc ;
}
relation->sortRecTo++ ;
if ( relation->skipBackwards )
{
file4write( &relation->sortedFile, relation->sortFilePos, other, (unsigned int)relation->sortOtherLen ) ;
relation->sortFilePos += relation->sortOtherLen ;
}
}
/* now read the database records in */
for ( i = 0, linkOn = 0 ;; i++ )
{
linkOn = (R4DATA_LIST *)l4next( &relation->sortDataList, linkOn ) ;
if ( linkOn == 0 )
return 0 ;
/* note that the sort positions all blanks to eof whereas in non-sort it is not
consistent whether it is positioned bof or eof. For sort it doesn't matter
because further skips all go through the sort, therefore we already know the
record order thus it doesn't need to be calculated. This is a small efficience. */
#ifdef S4DATA_ALIGN
memcpy( &longPtr, (void *)(other + i*sizeof(longPtr)), sizeof(longPtr) ) ;
if ( longPtr == 0 ) /* relate4blank case */
rc = d4goEof( linkOn->data ) ;
else
rc = d4go( linkOn->data, longPtr ) ;
#else
if ( *((long *)(other) + i ) == 0 ) /* relate4blank case */
rc = d4goEof( linkOn->data ) ;
else
rc = d4go( linkOn->data, *((long *)(other) + i ) ) ;
#endif
if ( rc < 0 )
return rc ;
linkOn->relate->isRead = 1 ;
}
}
static int relate4sortNextRecord( RELATION4 *relation )
{
int rc ;
if ( error4code( relation->relate.codeBase ) < 0 )
return -1 ;
rc = relate4sortGetRecord( relation, relation->sortRecOn + 1 ) ;
if ( rc == 0 )
relation->sortRecOn++ ;
if ( rc == r4eof )
relation->sortRecOn = relation->sortRecCount + 1 ;
return rc ;
}
static int relate4sortPrevRecord( RELATION4 *relation )
{
int rc ;
if ( error4code( relation->relate.codeBase ) < 0 )
return -1 ;
rc = relate4sortGetRecord( relation, relation->sortRecOn - 1 ) ;
if ( rc == 0 )
relation->sortRecOn-- ;
return rc ;
}
#endif
int S4FUNCTION relate4sortSet( RELATE4 *relate, const char *expr )
{
RELATION4 *relation ;
int len ;
if ( relate == 0 )
return -1 ;
#ifdef S4VBASIC
if ( c4parm_check( relate, 5, E94429 ) )
return -1 ;
#endif
if ( error4code( relate->codeBase ) < 0 )
return -1 ;
relation = relate->relation ;
relate = &relation->relate ;
relate4changed( relate ) ;
u4free( relation->sortSource ) ;
relation->sortSource = 0 ;
if ( expr )
if ( expr[0] )
{
len = strlen( expr ) ;
relation->sortSource = (char *)u4allocEr( relate->codeBase, (long)len + 1L ) ;
if ( relation->sortSource == 0 )
return -1 ;
memcpy( relation->sortSource, expr, (unsigned int)len ) ;
}
return 0 ;
}
#ifdef S4CLIENT
static int relate4add( CONNECTION4 *connection, RELATE4 *relate, unsigned int *relatePos, unsigned int *flexPos, char *relateData )
{
int len, savePos ;
RELATE4 *slaveOn ;
CONNECTION4RELATE *info ;
TAG4 *tag ;
/* add this relate's info */
savePos = *relatePos ;
info = (CONNECTION4RELATE *)( relateData + *relatePos ) ;
info->matchLen = relate->matchLen ;
info->relationType = relate->relationType ;
info->errorAction = relate->errorAction ;
info->numSlaves = relate->slaves.nLink ;
info->clientId = data4clientId( relate->data ) ;
tag = relate->dataTag ;
if ( tag == 0 )
info->dataTagName.offset = 0 ;
else
{
len = strlen( tag->tagFile->alias ) + 1 ;
info->dataTagName.offset = *flexPos ;
connection4addData( connection, tag->tagFile->alias, len, 0 ) ;
*flexPos += len ;
}
if ( relate->masterExpr == 0 )
info->masterExpr.offset = 0 ;
else
{
len = strlen( relate->masterExpr->source ) + 1 ;
info->masterExpr.offset = *flexPos ;
connection4addData( connection, relate->masterExpr->source, len, 0 ) ;
*flexPos += len ;
}
if ( relate->data == 0 )
info->dataAccessName.offset = 0 ;
else
{
len = strlen( dfile4name( relate->data->dataFile ) ) + 1 ;
info->dataAccessName.offset = *flexPos ;
connection4addData( connection, dfile4name( relate->data->dataFile ), len, 0 ) ;
*flexPos += len ;
}
*relatePos += sizeof( CONNECTION4RELATE ) ;
/* and do it's slaves: */
for ( slaveOn = 0 ;; )
{
slaveOn = (RELATE4 *)l4next( &relate->slaves, slaveOn ) ;
if ( slaveOn == 0 )
break ;
relate4add( connection, slaveOn, relatePos, flexPos, relateData ) ;
}
return 0 ;
}
static int relate4clientInit( RELATE4 *master )
{
CONNECTION4RELATE_INIT_INFO_IN info ;
CONNECTION4RELATE_INIT_INFO_OUT *out ;
int rc, relateCount, i ;
RELATE4 *relateOn ;
CONNECTION4 *connection ;
unsigned int relatePos, flexPos, exprLen, sortLen ;
char *relateData ;
CODE4 *c4 ;
#ifdef E4PARM_LOW
if ( master == 0 )
return error4( 0, e4parm_null, E94421 ) ;
#endif
c4 = master->codeBase ;
connection = master->data->dataFile->connection ;
relateCount = 1 ;
memset( &info, 0, sizeof( CONNECTION4RELATE_INIT_INFO_IN ) ) ;
for( relateOn = master ;; relateCount++ )
{
if ( relate4next( &relateOn ) == 2 )
break ;
#ifdef E4MISC
if ( relateOn->data != 0 )
{
if ( connection == 0 )
connection = relateOn->data->dataFile->connection ;
else
if ( connection != relateOn->data->dataFile->connection ) /* multi-servers not supported on relations */
return error4( c4, e4notSupported, E84414 ) ;
}
#endif
}
#ifdef E4ANALYZE
if ( connection == 0 )
return error4( c4, e4struct, E94421 ) ;
#endif
if ( relateCount == 0 || connection == 0 )
return error4( c4, e4relate, E84415 ) ;
if ( master->relation->needsFreeing == 1 )
info.relationId = master->relation->relationId ;
else
info.relationId = 0 ;
info.relateOffset = sizeof( CONNECTION4RELATE_INIT_INFO_IN ) ;
info.flexOffset = info.relateOffset + relateCount * sizeof( CONNECTION4RELATE ) ;
info.relation.skipBackwards = master->relation->skipBackwards ;
info.bitmapDisable = master->relation->bitmapDisable ;
info.masterClientId = master->data->clientId ;
if ( master->relation->exprSource == 0 )
{
info.relation.exprSource.offset = 0 ;
exprLen = 0 ;
}
else
{
exprLen = strlen( master->relation->exprSource ) + 1 ;
info.relation.exprSource.offset = info.flexOffset ;
}
if ( master->relation->sortSource == 0 )
{
info.relation.sortSource.offset = 0 ;
sortLen = 0 ;
}
else
{
sortLen = strlen( master->relation->sortSource ) + 1 ;
info.relation.sortSource.offset = info.flexOffset + exprLen ;
}
connection4assign( connection, CON4RELATE_INIT, 0, 0 ) ;
connection4addData( connection, &info, sizeof( CONNECTION4RELATE_INIT_INFO_IN ), 0 ) ;
relateData = (char *)u4allocFree( c4, relateCount * sizeof( CONNECTION4RELATE ) ) ;
if ( relateData == 0 )
return error4stack( c4, e4memory, E94421 ) ;
connection4addData( connection, relateData, relateCount * sizeof( CONNECTION4RELATE ), 0 ) ;
if ( exprLen != 0 )
connection4addData( connection, master->relation->exprSource, exprLen, 0 ) ;
if ( sortLen != 0 )
connection4addData( connection, master->relation->sortSource, sortLen, 0 ) ;
relatePos = 0 ;
flexPos = info.flexOffset + exprLen + sortLen ;
rc = relate4add( connection, master, &relatePos, &flexPos, relateData ) ;
if ( rc < 0 )
{
u4free( relateData ) ;
return error4stack( c4, rc, E94421 ) ;
}
connection4send( connection ) ;
u4free( relateData ) ;
rc = connection4receive( connection ) ;
if ( rc < 0 )
return error4stack( c4, rc, E94421 ) ;
rc = connection4status( connection ) ;
if ( rc < 0 )
return connection4error( connection, c4, rc, E84401 ) ;
if ( rc != 0 )
return rc ;
if ( connection4len( connection ) != (long)sizeof( CONNECTION4RELATE_INIT_INFO_OUT ) + relateCount * (long)sizeof( relateOn->id ) )
return error4stack( c4, e4packetLen, E94421 ) ;
out = (CONNECTION4RELATE_INIT_INFO_OUT *)connection4data( connection ) ;
master->relation->relationId = out->relationId ;
#ifdef E4ANALYZE
if ( sizeof( relateOn->id ) != sizeof( unsigned short int ) )
return error4( c4, e4struct, E94421 ) ;
#endif
out++ ; /* go to the end of out for the variable length data */
for( relateOn = master, i = 0 ;; i++ )
{
if ( relateOn == 0 )
break ;
relateOn->id = *((unsigned short int *)(((char *)out) + i * sizeof( relateOn->id ) ) ) ;
rc = relate4next( &relateOn ) ;
if ( rc == 2 )
break ;
}
master->relation->isInitialized = 1 ;
return 0 ;
}
#endif
#ifndef S4CLIENT
static int relate4topInit( RELATE4 *relate )
{
RELATION4 *relation ;
int rc ;
CODE4 *c4 ;
#ifndef S4OPTIMIZE_OFF
int has_opt ;
#endif
#ifdef S4SERVER
LIST4 *oldList ;
#endif
#ifdef S4VBASIC
if ( c4parm_check( relate, 5, E94422 ) )
return -1 ;
#endif
#ifdef E4PARM_HIGH
if( relate == 0 )
return error4( 0, e4parm_null, E94422 ) ;
#endif
c4 = relate->codeBase ;
if ( error4code( c4 ) < 0 )
return e4codeBase ;
relation = relate->relation ;
relate = &relation->relate ;
rc = 0 ;
if ( relation->inSort == relate4sortDone )
if ( relation->skipBackwards == 0 )
relate4changed( relate ) ;
relate->dataTag = relate->data->tagSelected ;
if ( relation->isInitialized == 0 )
{
#ifndef S4OPTIMIZE_OFF
has_opt = (char)c4->hasOpt ;
#endif
if ( rc < 0 )
return rc ;
relation->bitmapsFreed = 0 ;
if ( relation->exprSource )
{
#ifdef S4SERVER
oldList = tran4dataList( code4trans( c4 ) ) ;
tran4dataListSet( code4trans( c4 ), &relation->localDataList ) ;
#endif
relation->log.expr = expr4parseLow( relate->data, relation->exprSource, 0 ) ;
#ifdef S4SERVER
tran4dataListSet( code4trans( c4 ), oldList ) ;
#endif
if ( relation->log.expr == 0 )
return -1 ;
if ( log4bitmapDo( &relation->log ) < 0 )
relation->bitmapsFreed = 1 ;
log4determineEvaluationOrder( &relation->log ) ;
}
if ( relate4buildScanList( 0, relate, relation ) < 0 )
return -1 ;
/* relation->relateList.selected = (LINK4 *)l4first( &relation->relateList) ;*/
relation->isInitialized = 1 ;
if ( relation->sortSource )
{
rc = relate4sort( relate ) ;
if ( rc < 0 || rc == r4terminate )
return rc ;
}
#ifndef S4OPTIMIZE_OFF
if ( has_opt )
code4optRestart( c4 ) ;
#endif
}
return 0 ;
}
#endif
int S4FUNCTION relate4top( RELATE4 *relate )
{
RELATION4 *relation ;
int rc ;
CODE4 *c4 ;
DATA4 *d4 ;
#ifdef S4CLIENT
CONNECTION4RELATE_TOP_INFO_IN info ;
CONNECTION4 *connection ;
int saveRc ;
#else
long rec ;
int rc2 ;
#ifndef S4OFF_MULTI
int oldReadLock ;
#endif
#endif
#ifdef S4VBASIC
if ( c4parm_check( relate, 5, E94422 ) )
return -1 ;
#endif
#ifdef E4PARM_HIGH
if( relate == 0 )
return error4( 0, e4parm_null, E94422 ) ;
#endif
c4 = relate->codeBase ;
if ( error4code( c4 ) < 0 )
return e4codeBase ;
relation = relate->relation ;
relate = &relation->relate ;
d4 = relate->data ;
rc = 0 ;
#ifdef S4CLIENT
#ifdef E4ANALYZE
if ( d4 == 0 )
return error4( c4, e4struct, E94422 ) ;
if ( d4->dataFile == 0 )
return error4( c4, e4struct, E94422 ) ;
#endif
if ( relation->isInitialized == 0 || relate->dataTag != d4->tagSelected )
{
relate->dataTag = d4->tagSelected ;
rc = relate4clientInit( relate ) ;
if ( rc != 0 )
return rc ;
}
#ifdef S4CB51
#ifndef S4OFF_MULTI
if ( c4->readLock )
{
rc = relate4lock( relate ) ;
if ( rc != 0 )
return rc ;
}
#endif
#endif
connection = d4->dataFile->connection ;
#ifdef E4ANALYZE
if ( connection == 0 )
return error4( c4, e4struct, E94422 ) ;
#endif
connection4assign( connection, CON4RELATE_TOP, 0, 0 ) ;
info.relationId = relation->relationId ;
connection4addData( connection, &info, sizeof( CONNECTION4RELATE_TOP_INFO_IN ), 0 ) ;
connection4send( connection ) ;
saveRc = connection4receive( connection ) ;
if ( saveRc < 0 )
return error4stack( c4, saveRc, E94422 ) ;
saveRc = connection4status( connection ) ;
if ( saveRc < 0 )
return connection4error( connection, c4, saveRc, E94422 ) ;
rc = relate4unpack( relation, d4->dataFile->connection ) ;
if ( rc != 0 )
return error4stack( c4, rc, E94422 ) ;
return saveRc ;
#else
#ifndef S4OFF_MULTI
oldReadLock = c4->readLock ;
c4->readLock = 0 ;
#endif
for ( ;; ) /* used to minimize return code areas, just break out... */
{
rc = relate4topInit( relate ) ;
if ( rc != 0 )
break ;
relate4setNotRead( relate ) ;
relation->currentRelateLevel = 0 ;
relate4nextRelationList( relation, 1 ) ;
if ( relation->inSort == relate4sortDone )
{
relation->sortRecOn = 0 ;
rc = relate4sortNextRecord( relation ) ;
}
else
rc = d4top( d4 ) ;
if ( rc ) /* eof or error */
break ;
if ( relation->exprSource )
{
rec = d4recNo( d4 ) ;
if ( f4flagIsSetFlip( &relate->set, (unsigned long)rec ) == 0 )
{
#ifndef S4INDEX_OFF
if ( relate->dataTag )
{
while ( f4flagIsSetFlip( &relate->set, (unsigned long)rec ) == 0 )
{
#ifdef S4HAS_DESCENDING
rc = (int)tfile4dskip( relate->dataTag->tagFile, 1L ) ;
#else
rc = (int)tfile4skip( relate->dataTag->tagFile, 1L ) ;
#endif
if ( rc != 1 )
{
if ( rc == 0 )
{
d4goEof( d4 ) ;
rc = r4eof ;
}
break ;
}
rec = tfile4recNo( relate->dataTag->tagFile ) ;
}
if ( rc == r4eof )
break ;
}
else
{
#endif
rec = f4flagGetNextFlip( &relate->set, 1L, 1 ) + 1L ;
if ( d4recCountLessEq( d4, rec ) == 0 )
{
d4goEof( d4 ) ;
rc = r4eof ;
break ;
}
#ifndef S4INDEX_OFF
}
#endif
}
rc = d4go( d4, rec ) ;
if ( rc != 0 )
break ;
}
rc = relate4readRest( relate, 1 ) ;
if ( rc == relate4filterRecord )
{
rc = relate4skip( relate, 1L ) ;
break ;
}
if ( rc < 0 || rc == r4terminate )
break ;
if ( relation->exprSource )
{
rc2 = log4true( &relation->log ) ;
if ( rc2 == r4terminate )
{
rc = r4terminate ;
break ;
}
if ( rc2 == 0 )
{
if ( relation->inSort == relate4sortSkip ) /* must temporarily disable in order to get a matching scan if available */
{
relation->inSort = 0 ;
rc = relate4skip( relate, 1L ) ;
relation->inSort = relate4sortSkip ;
}
else
rc = relate4skip( relate, 1L ) ;
}
}
break ;
}
#ifndef S4OFF_MULTI
c4->readLock = oldReadLock ;
#endif
return rc ;
#endif
}
int S4FUNCTION relate4type( RELATE4 *relate, int relateType )
{
int rc ;
#ifdef E4PARM_HIGH
if ( relate == 0 )
return error4( 0, e4parm_null, E94423 ) ;
if ( relateType != relate4exact && relateType != relate4scan && relateType != relate4approx )
return error4( relate->codeBase, e4parm, E84416 ) ;
#endif
rc = relate->relationType ;
if ( rc != relateType )
{
relate->relationType = relateType ;
relate4changed( relate ) ;
}
return rc ;
}
#ifdef S4CB51
int S4FUNCTION relate4unlock( RELATE4 *relate )
{
#ifndef S4SINGLE
DATA4 *dataOn ;
#ifdef E4PARM_HIGH
if ( relate == 0 )
return error4( 0, e4parm_null, E94424 ) ;
#endif
if ( !relate->relation->locked )
return 0 ;
for ( dataOn = (DATA4 *)l4first( tran4dataList( code4trans( relate->codeBase ) ) ) ;
dataOn ; dataOn = (DATA4 *)l4next( tran4dataList ( code4trans( relate->codeBase ) ), dataOn ) )
if ( relate4dbfInRelation( relate, dataOn ) )
d4unlock( dataOn ) ;
relate->relation->locked = 0 ;
#endif
return 0 ;
}
#endif
#ifdef S4VB_DOS
RELATE4 *S4FUNCTION relate4createSlave_v( RELATE4 *master, DATA4 *slave, char *masterExpr, TAG4 *slaveTag )
{
return relate4createSlave( master, slave, c4str( masterExpr ), slaveTag ) ;
}
char * relate4masterExpr_v( RELATE4 *r4 )
{
#ifdef S4VBASIC
if ( c4parm_check( r4, 5, "relate4masterExpr():" ) ) return 0 ;
#endif
return v4str(r4->masterExpr->source) ;
}
int S4FUNCTION relate4querySet_v ( RELATE4 *relate, char *expr )
{
return relate4querySet( relate, c4str(expr) ) ;
}
int S4FUNCTION relate4sortSet_v ( RELATE4 *relate, char *expr )
{
return relate4sortSet( relate, c4str( expr ) ) ;
}
#endif