3926 lines
		
	
	
		
			108 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			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
 |