Function DbRSelect() Foundation

Returns the child work area of a relation.

Syntax
DbRSelect( <nRelation> | <cRelName> ) --> nWorkarea
Parameters
<nRelation>
<nRelation> is a positive integer specifying the ordinal position of the relation in a work area. It is the child work area of this relation that is returned. The relations are numbered in the order they were defined using DbSetRelation() or SET RELATION TO.
<cRelName>
Instead of the numeric ordinal, a string containing the name of the desired relation can be specified as first parameter.
Return

The return value of DbRSelect() is a positive integer indicating the child work area for the relation specified. If no relation exists or if a non-existing relation is referred to, the value zero is returned.

Description

The function DbRSelect() allows determination of the child work area whose record pointer is moved from a parent work area. The child work area is specified as an alias name passed to the command SET RELATION TO or the function DbSetRelation() when the relation between the two work areas is defined.

When the function is used without the alias operator, it returns the number of the child work area linked to the current work area.

The function DbRSelect() is generally used with DbRelation(), which returns the expression used to link the child work area in the specified relation.

Examples
DbRSelect()
// In the example, a link is produced between an invoice 
// file, an item file, and a customer file. The results 
// of the function DbRSelect() are displayed. 

PROCEDURE Main 
   USE Customer ALIAS Cust NEW EXCLUSIVE 
   INDEX ON CustNo TO CustNo 
   SET INDEX TO CustNo 

   USE InvItem ALIAS Items NEW EXCLUSIVE 
   INDEX ON ItemNo TO ItemNo 
   SET INDEX TO ItemNo 

   USE Invoice ALIAS Inv NEW 

   SET RELATION TO CustNo  INTO Cust , ; 
                TO ItemNo  INTO InvItem 

   ? Select()                    // result: 3 
   ? Alias()                     // result: Inv 

   ? DbRSelect(1)                // result: 1 
   ? Alias( DbRSelect(1) )       // result: CUST 

   ? DbRSelect(2)                // result: 2 
   ? Alias( DbRSelect(2) )       // result: ITEMS 

   SELECT Cust 
   ? Alias()                     // result: CUST 
   ? DbRSelect(1)                // result: 0 

   ? Inv->( DbRSelect(1) )       // result: 1 
   ? Inv->( DbRSelect(2) )       // result: 2 
   ? Inv->( DbRSelect(3) )       // result: 0 

   CLOSE DATABASES 
RETURN 
Cascading deletions

// The example shows how DbRSelect() and DbRelation() can be 
// used to create a deletion function that deletes all of 
// the dependent records in the child work areas when 
// the record in the parent work area is deleted. 

   PROCEDURE Main 
      USE Customer ALIAS Cust NEW EXCLUSIVE 
      INDEX ON LastName TO CustName 
      SET INDEX TO CustName 

      USE Invoice ALIAS Inv NEW EXCLUSIVE 
      INDEX ON CustNo TO CustNo 
      SET INDEX TO CustNo 

      SELECT Cust 
      SET RELATION TO CustNo INTO Inv 

      ? Cust->( LastRec() )         // result: 100 
      ? Inv->( LastRec() )          // result: 253 

      ? Cust->( DbSeek( "Miller") ) // result: .T. 
      ? Cust->( CascadeDelete() )   // result: 10 
                                    // a total of ten records 
                                    // were deleted 
      SELECT Cust 
      PACK 

      SELECT Inv 
      PACK 

      ? Cust->( LastRec() )         // result:  99 
                                    // one record was deleted 
                                    // from the Customer file 

      ? Inv->( LastRec() )          // result: 244 
                                    // nine records were deleted 
                                    // from the Invoice file 
      CLOSE DATABASES 
   RETURN 

// This function deletes the current record and cascades the 
// deletion operation through all dependent child work areas 
   FUNCTION CascadeDelete() 
      STATIC snTotal    := 0 
      STATIC snRecursion:= 0 
      LOCAL nDeleted    := 0 
      LOCAL nRelation   := 1 
      LOCAL aRelation   := {} 
      LOCAL nChildArea, cExpression, xValue, ; 
            n, nMax, nRecno 

   ** Go through all child work areas 
      DO WHILE .NOT. ( nChildArea := DbRSelect(nRelation) ) == 0 

      ** Child work area has no matching data 
         IF (nChildArea)->( Eof() ) 
            nRelation ++ 
            LOOP 
         ENDIF 

      ** Save information from child work area 
         cExpression := DbRelation( nRelation ) 
         xValue      := (nChildArea)->( &(cExpression) ) 

         AAdd( aRelation , ; 
                 { nChildArea , ;   // child work area number 
                   cExpression, ;   // linking expression 
                   xValue     , ;   // value of linking expression 
                  (nChildArea)->(RecNo()) ; // child record 
                 } ; 
             ) 

      ** Child work area is parent work area to other 
      ** work areas. Call function recursively. 
         IF .NOT. (nChildArea)->( DbRSelect(1) ) == 0 
            snRecursion++ 
            snTotal += (nChildArea)->( CascadeDelete() ) 
            snRecursion-- 
         ENDIF 

         nRelation ++               // next child work area 
      ENDDO 

      DbDelete()                    // delete record 
      nDeleted ++                   // in parent work area 

   ** Delete all records in the child work areas 
      nMax := Len( aRelation ) 

      FOR n:=1 TO nMax 
         nChildArea  := aRelation[n,1] 
         cExpression := aRelation[n,2] 
         xValue      := aRelation[n,3] 
         nRecno      := aRelation[n,4] 
         (nChildArea)->( DbGoto(nRecno) ) 

         DO WHILE (nChildArea)->( xValue == &(cExpression) ) 
            (nChildArea)->( DbDelete() ) 
            (nChildArea)->( DbSkip() ) 
            nDeleted ++ 
         ENDDO 
      NEXT 

   ** Total deleted records from the recursion, 
   ** and set STATIC variable back to 0, when there are 
   ** no more levels of recursion. 
      IF snRecursion == 0 
         nDeleted += snTotal 
         snTotal  := 0 
         DbGoto( RecNo() )          // position record pointer 
                                    // correctly again in all 
      ENDIF                         // child work areas 

   RETURN nDeleted 

Feedback

If you see anything in the documentation that is not correct, does not match your experience with the particular feature or requires further clarification, please use this form to report a documentation issue.