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:
- Update data dictionary (Test only)
- Reorganise data (Test only)
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:
#1D0needs conversion from older files#2D0needs dictionary update#3D0needs reorganisation#4D0record count (optional, but useful for reporting)
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:
- If
#FiskFalse, no action is required. - If
#FiskTrue, you have one or more tables that require conversion, dictionary update, or reorganisation. - In a shared datafile scenario, the table list avoids false positives by restricting the result to tables your library knows about.
Summary
- Use Test only checks to avoid slow startup and risky field probing.
- Beware of shared datafiles: global checks can produce false positives.
- If a global check reports a mismatch, follow up with a table by table scan and only act on tables that matter to your current library.