*DECK DB$MDPF 
USETEXT UTMPTTX 
USETEXT MDDEFTX 
USETEXT MDBCMTX 
      FUNC DB$MDPF ((NEWPFN), (NEWID), (NEWPN)) B;
      BEGIN 
 #
  *   DB$MDPF - VALIDATE PF UNIQUENESS           PAGE  1
  *   M. D. SAXE                                 DATE  02/06/76 
  *   J. G. SERPA - MDU 2.3 ENHANCEMENTS         DATE  07/16/80 
  *   R. L. MCALLESTER - TABLE SEGMENTATION      DATE  05/30/84 
  
  DC  PURPOSE 
  
      SEARCHES THRU THE PFN TABLE LOOKING FOR DUPLICATE PFNS
  
  DC  ENTRY CONDITIONS
  
      NEWPFN - CURRENT PFN BEING PROCESSED. LEFT JUSTIFIED WITH ZERO
               FILL 
      NEWID  - ID OF PFN
      NEWPN  - PACK/SET/FAMILY WHERE PFN RESIDES(REFERRED TO AS PACK) 
               INCLUDES FLAGS 
  
  DC  EXIT CONDITIONS 
  
      DB$MDPF = TRUE, IF THE NEW PFN/ID/PACK IS ADDED TO THE PFN TABLE
      DB$MDPF = FALSE, IF A DUPLICATE PFN/ID/PACK IS FOUND
  
  DC  CALLING ROUTINES
  
      DB$MDPR                REPLACE A PFN ENTRY
      DB$SRDM 
        DB$SR06              BUILD ADT, AIT, KIT, PIT AND VIT 
                               FOR A MASTER VERSION AREA
  
      DB$SR07                BUILD AND VERIFY A SCHEMA ENTRY
      DB$SR71                REPLACE AREA PERMANENT FILE INFORMATION
      DB$SR88                CREATE PIT ENTRY AND UDATE THE VIT 
                               FOR A NON-MASTER VERSION AREA
  
  DC  CALLED ROUTINES 
  
# 
      XREF FUNC DB$MDPS B;   # SEARCH THE PFN TABLE                    #
      XREF PROC DB$MVG;      # GROW A VARIABLE LENGTH TABLE            #
      XREF PROC DB$MV1A;     # ALLOCATE A VARIABLE LENGTH TABLE        #
      XREF PROC DB$UAWS;     # ALLOCATES SPACE IN MANAGED MEMORY.      #
# 
  DC  DESCRIPTION 
* 
*     THE PFN IS MAINTAINED IN ALPHABETIC SEQUENCE. 
*     EACH NEW ENTRY IS INSERTED INTO THE TABLE IN ITS SEQUENTIAL 
*     POSITION. 
*     WHEN THE TABLE REACHES THE MAXIMUM SIZE LIMIT, IT IS SPLIT AND
*     WRITTEN TO THE DISK AS TWO SEPARATE DISK SEGMENTS.
*     WHEN THESE FIRST TWO SEGMENTS ARE WRITTEN TO THE DISK, AN INDEX 
*     TABLE IS CREATED IN MEMORY. 
*     THIS FIRST INDEX CONSISTS OF JUST ONE ENTRY, THE FIRST ENTRY OF 
*     THE SECOND SEGMENT. 
*     COMPARISON WITH THAT ENTRY TELLS IMMEDIATELY IF A NEW ENTRY 
*     SHOULD BE ADDED TO THE FIRST OR SECOND SEGMENT. 
*     THERE IS NEVER ANY REASON TO CREATE AN INDEX ENTRY FOR THE FIRST
*     SEGMENT.
* 
*     EACH SEGMENT GROWS INDEPENDENTLY AND WHEN IT REACHES THE LIMIT
*     IT WILL AGAIN BE SPLIT, CREATING A NEW INDEX ENTRY FOR THE NEW
*     SEGMENT THAT IT HAS SPAWNED.
 #
#     FORMAL PARAMETERS                                                #
      ITEM NEWPFN U;         # CURRENT PERMANENT FILE NAME, LEFT JUSTIF#
                             # IED WITH ZERO FILL.                     #
      ITEM NEWID U;          # CURRENT PFN ID, LEFT JUSTIFIED WITH ZERO#
                             # FILL.                                   #
      ITEM NEWPN;            # CURRENT PACK NAME, LEFT JUSTIFIED, ZERO #
                             # FILLED. INCLUDES FLAGS                  #
  
#     LOCAL VARIABLES                                                  #
  
      ITEM I;                      # INDUCTION VARIABLE                #
      ITEM J;                      # INDUCTION VARIABLE                #
      ITEM SEGORD;                 # NEXT SEGMENT TO BE LOADED         #
  
      BASED ARRAY PFNTABLE [0] S; 
        BEGIN 
*CALL MDPFNDCLS 
        END 
  
  
  
#     B E G I N   D B $ M D P F   E X E C U T A B L E   C O D E .      #
  
  
# 
*     SEARCH THE PFN TABLE FOR THE INSERTION POSITION.
# 
      IF DB$MDPS(J,NEWPFN,NEWID,NEWPN)
      THEN
        BEGIN                      # DUPLICATE PFN/UN/PACK FOUND       #
        DB$MDPF = FALSE;
        RETURN; 
  
        END 
# 
*     ADJUST THE PFN TABLE TO ACCOMODATE THE PFN, ID AND PACK.
*     INSERT THE NEW ENTRY. 
# 
      IF PFXL EQ 0
      THEN                         # THERE IS NO INDEX TABLE.          #
                                   # PFN IS IN ITS INITIAL GROWTH      #
                                   # STAGE BEFORE THE FIRST OVERFLOW.  #
  
        BEGIN                      # ALLOCATE SPACE FOR THE NEW ENTRY. #
        DB$UAWS(LOC(PFUNCBBP),DFPFUNENT); 
        END 
  
# 
*     SET PFN BASED ARRAY TO POINT TO THE FIRST PFN ENTRY 
# 
      P<TLC> = B<42,18>PFUNCBBP;
      P<PFNTABLE> = LOC(TLC) + TLCHLEN[0] + DFMDPFNHD;
# 
*     IF THE NEW ENTRY IS TO BE INSERTED AHEAD OF OTHERS, MOVE THE
*     OTHERS TO MAKE ROOM.
# 
      FOR I = TLCDSWL[0] -DFPFUNENT STEP -DFPFUNENT UNTIL J 
      DO
        BEGIN 
        MDPFN1WRD[I+DFPFUNENT] = MDPFN1WRD[I];
        MDPFN2WRD[I+DFPFUNENT] = MDPFN2WRD[I];
        MDPFN3WRD[I+DFPFUNENT] = MDPFN3WRD[I];
        END 
  
# 
*     INSERT THE NEW ENTRY. 
*       STORE THE ID OF THE SCHEMA CURRENTLY BEING PROCESSED. 
*       STORE THE PERMANENT FILE NAME, ID AND PACK NAME OF THE FILE 
*       CURRENTLY BEING PROCESSED.
# 
      MDPFNSCHID[J] = SCINPRG;
      MDPFNAME[J] = B<0,42>NEWPFN;
      MDPFNID[J] = B<0,42>NEWID;
      MDPFN3WRD[J] = NEWPN; 
  
      TLCDSMF[0] = TRUE;           # SET THE MODIFIED FLAG             #
  
                                   # UP THE DISK SEGMENT WORD LENGTH   #
      TLCDSWL[0] = TLCDSWL + DFPFUNENT; 
  
# 
*     IF THE DISK SEGMENT HAS REACHED THE MAXIMUM TABLE LIMIT,
*     SPLIT IT AND DUMP IT SO THAT THERE WILL BE ROOM FOR ANY MORE
*     ENTRIES THAT ARE TO BE PUT INTO IT. 
* 
*     THE ACTUAL SPLIT IS DONE BY DB$UAWS.
*     DB$UAWS USUALLY REDUCES THE TLCUSED PARAMETER TO REFLECT THE
*     REDUCTION OF MEMORY REQUIREMENTS WHEN IT WRITES ANOTHER SEGMENT 
*     TO DISK.
*     IN THIS CASE, THE LENGTH OF THE NEW SEGMENT IS REQUESTED AS NEW 
*     MEMORY. 
*     IN THAT WAY THE MAXIMUM TABLE SIZE IS RETAINED. 
*     THIS RETAINS SPACE FOR READING IN ANY OF THE TABLE SEGMENTS 
*     AS THEIR GROWTH AGAIN APPROACHES THE MAXIMUM. 
* 
*     DB$UAWS CONSIDERS ALL TABLES TO BE ORGANIZED AS PILES INSTEAD 
*     OF INDEXED SEQUENTIAL.
*     THEREFORE IT ALWAYS ASSIGNS THE NEW SEGMENT AS THE LAST ONE.
*     THIS LEAVES IT TO BE RE-ORDERED UPON RETURN.
# 
      IF TLCDSWL[0] + DFMDPFNHD GQ TLCTMXL[0] 
      THEN
        BEGIN 
        TLCDSWL[0] = TLCBSBW[0] - DFMDPFNHD;
        SEGORD = TLCDSOR[0];
        IF SEGORD EQ 0             # IF THERE ARE NO SEGMENTS          #
        THEN
          BEGIN 
          SEGORD = DFTLCHL; 
          END 
        ELSE
          BEGIN 
          TLCSLEN[SEGORD] = TLCDSWL[0]; 
          END 
        DB$UAWS(LOC(PFUNCBBP),TLCDSWL[0]);
  
                                   # MERGE IN THE NEW SEGMENT DESCRIPTR#
  
        SEGORD = SEGORD + 1;       # ITS NEW ORDINAL                   #
        I = TLCHLEN[0] -1;
        J = TLCWORD[I];            # SAVE THE DESCRIPTOR               #
        FOR I = I-1  STEP -1 UNTIL SEGORD 
        DO
          BEGIN                    # MOVE INTERVENING DESRIPTORS       #
          TLCWORD[I+1] = TLCWORD[I];
          END 
        TLCWORD[SEGORD] = J;       # INSERT THE NEW DESCRIPTOR         #
        TLCDSOR[0] = SEGORD;
        TLCDSWL[0] = TLCSLEN[SEGORD]; 
  
        IF PFXL EQ 0               # IF THERE IS NO INDEX              #
        THEN                       # CREATE ONE.                       #
          BEGIN 
          PFXA = DFTLCPAD * DFPFUNENT;
          DB$MV1A(PFXA,P<PFX>); 
          END 
        PFXL = PFXL + DFPFUNENT;   # INCREASE INDEX LENGTH.            #
        IF PFXL GR PFXA            # IF IT IS NEEDED                   #
        THEN                       # ALLOCATE MORE INDEX SPACE.        #
          BEGIN 
          DB$MVG(P<PFX>,DFTLCPAD * DFPFUNENT);
          PFXA = PFXA +(DFTLCPAD * DFPFUNENT);
          END 
                                   # RESTORE PFN TABLE POINTER         #
        P<TLC> = B<42,18>PFUNCBBP;
        P<PFNTABLE> = LOC(TLC) + TLCHLEN[0] + DFMDPFNHD;
  
                                   # SET SUBSCRIPT FOR INDEX INSERTION #
        J = (SEGORD - DFTLCHL -1) * DFPFUNENT;
  
                                   # MOVE OTHERS OUT OF THE WAY        #
        FOR I = PFXL - 2*DFPFUNENT STEP - DFPFUNENT UNTIL J 
        DO
          BEGIN 
          PXPFW1[I+DFPFUNENT] = PXPFW1[I];
          PXPFW2[I+DFPFUNENT] = PXPFW2[I];
          PXPFW3[I+DFPFUNENT] = PXPFW3[I];
          END 
                                   # INSERT THE NEW INDEX ENTRY        #
        PXPFW1[J] = MDPFN1WRD[0]; 
        PXPFW2[J] = MDPFN2WRD[0]; 
        PXPFW3[J] = MDPFN3WRD[0]; 
        END 
  
      DB$MDPF = TRUE; 
      PFUNCNT = PFUNCNT + 1;
      RETURN; 
      END 
      TERM; 
