In Omnis Classic, detecting whether a datafile needs reorganisation after a schema change is not as simple as checking whether a field exists.

Classic does not provide runtime error trapping, schema introspection, or safe field existence checks. Probing missing fields can trigger hard runtime errors, and doing a full reorganisation on every startup is not practical for large datafiles.

The best approach is to ask Omnis Classic itself whether an update or reorganisation is required, but with one important caveat for shared datafiles.

The Key Insight

Omnis Classic already knows whether a reorganisation is required.
The trick is to ask it without actually doing the work.

Classic provides two operations that can be run in Test only mode:

These perform fast, metadata level checks and return a Boolean result (in #F), without touching records.

Shared Datafile Gotcha (False Positives)

If the datafile is shared by multiple libraries, a top level Test only can report that an update is required because another library has changed a table that your current library does not even include.

In that situation you can get a false positive: your library is fine, but the shared datafile contains tables that need work for someone else.

Practical fix

Use the global test only check as a quick first pass, then if it reports that something needs updating, run a table by table scan and only count tables that your library actually knows about (and cares about).

Practical Solution

This pattern is fast, safe, and handles shared datafiles.

Step 1: Quick global check

;  
Update data dictionary (Test only)
Calculate LB_Needs_Update as #F
If not(LB_Needs_Update)
  Reorganize data (Test only)
  Calculate LB_Needs_Update as #F
End If
;  
If LB_Needs_Update
  Call procedure WAg_Update/$tables2Update (LL_Tables) {$tables2Update}
  Calculate LB_Needs_Update as LL_Tables.$linecount
End If
;  
Calculate #F as LB_Needs_Update
Quit procedure
;  
Local variable LB_Needs_Update (Boolean) = kFalse
;  
Local variable LL_Tables (List)

Step 2: Determine which tables actually need work

$tables2Update builds a list of tables that require conversion, dictionary update, or reorganisation, then returns only the relevant ones to the caller.

Key flags in the working list:

Core idea: for each table, run the Test only operations on that specific table, mark the required actions, then at the end merge out only the flagged rows and return them.

;  
Other parameters are optional
Parameter PF_Files (Field name)
;  
Call procedure MAg_SQL/4 {Close SQL}
;  
Begin reversible block
  Clear range of fields #1D0 to #4D0
  Calculate #S5 as ""
End reversible block

Calculate LC_CURR_DATA_FILE as $root.$cdata().$name
Set current list LL_Files
Define list (Store long data) {#S5,#S4,#1D0,#2D0,#3D0,#4D0}

Build file list

Calculate LL_Slots as $cdata.$slots.$makelist($ref.$name)
Set current list LL_Slots
Redefine list {LLC_Slot_Name}

Set current list LL_Files
For each line in list from 1 to #LN step 1
  Working message (Repeat count) {PLEASE WAIT: Checking the data files//   { [#LN] }}
  Load from list

  If mid(#S5,1,1)="#"     ;; Ignore the special in house Tables
  
  Else

    If $clib.$files.[lst(#S5)].$datahead.$filemode=kReadwrite|$clib.$files.[lst(#S5)].$datahead.$filemode=kReadonly

      ;; Optional: ensure Unique Locks for larger files
      If not($cdata.$slots.[#S5].$uniquelocks)&$cdata.$slots.[#S5].$recordcount>200
        Calculate #F as $cdata.$slots.[#S5].$uniquelocks.$assign(kTrue)
      End If

      Convert old data (Test only) {[lst(#S5)]}
      If flag true
        Calculate LL_Files(nam(#1),LL_Files.$line) as 1
      End If

      Update data dictionary (Test only) {[lst(#S5)]}
      If #F|totc(LL_Slots,LLC_Slot_Name=#S5)=0
        Calculate LL_Files(nam(#2),LL_Files.$line) as 1
      End If

      Reorganize data (Test only) {[lst(#S5)]}
      If flag true
        Calculate LL_Files(nam(#3),LL_Files.$line) as 1
      End If

      Calculate LL_Files(nam(#1),LL_Files.$line) as $root.$datas.[//LC_CURR_DATA_FILE].$slots.[#S5].$recordcount()

    Else If $clib.$files.[lst(#S5)].$datahead.$filemode=kMemory
      If $cdata.$slots.[#S5].$disksize>0
        Delete data {[#S5]}
      End If
    End If

  End If

End For

Set search as calculation {#1|#2|#3}
Set current list FL_Files
Merge list LL_Files (Clear list,Use search)

Calculate PF_Files as FL_Files
Quit procedure
;  
Local variable LC_CURR_DATA_FILE (Character   1000) = ""
;  
Local variable LL_Files (List)
Local variable LL_Slots (List)
Local variable LLC_Slot_Name (Character   10000000) = ""

How to Read the Result

In the startup check:

Summary