Home page Home page Home page Home page
Pixel Header R1 C1 Pixel
Pixel Header R2 C1 Pixel
Pixel Header R3 C1 Pixel
By Sprezz | Sunday 10 February 2013 05:29 | 2 Comments
Putting the finishing touches to an order entry system this week, we were frustrated by the apparent unwillingness of one symbolic to update, whilst those around it had no such qualms.

Looking at the dictionary items nothing stood out; they were all multivalued, they all derived their values based upon the code entry. So we decided to go for the sledgehammer to crack a nut approach and added a quickevent to the POSCHANGED event. Column 4 doesn't want to update - we'll tell it to update every single time the user moves cells.

This was sort of successful - but not entirely. Sometimes it worked, sometimes the price column was the only one updated.

In the Sprezz world, "Sort of" doesn't cut it. So just as we were about to start coding a POSCHANGED in the commuter routine to update ALL of the columns we reviewed our options. As is often the way when discussing problems rather than thinking about problems the solution becamse obvious. RTI have optimised the semantic logic layer in such a way that the only symbolics recalculated by default are those that rely on the column that has just changed.

How do they do that?

We can't know the exact mechanism but it's safe to guess that they look at the formula for the symbolic in some way and see if it references the changed column. They doubtless do this once at Window compilation time then cache the results. And what was the formula of the non-updating column?

Because the calculation was reused elsewhere, we'd moved it off into a function - which worked well BUT confused the semantic logic layer as now, as far as it was concerned, the formula was NOT dependent on the code column. The initial solution - as inelegant as it seems, was simply to ensure that the formula contained a reference to the code column so -

et voila now all the symbolics update without any further user intervention.

But that still didn't really satisfy us  ΜΆΜΆ  why should we have to pollute our dictionary items just to make dependencies within the window work? Especially as we have an increasing tendency on new systems to move all symbolic calculations into a control commuter for the table. So we decided to work out how OI was dealing with these dependencies and manipulate them ourselves on the form CREATE event.

The first place to look when trying to establish this sort of information is always the additional features documentation provided by Revelation - or the SYSPROG Inserts as they're more commonly known - OIWIN_EQUATES in this case. Opening this, the area that we're specifically interested in is the equates for the Control Semantics which are associated with the Control Map. Scanning this we come to the rubric "* list of controls to send recalcs to on change" next to column position 14 - CS_RECALC$.

Given that we're dealing with an edit table here, the information is going to be somewhat nested! We could have several data columns which in turn are depended upon by several other symbolics.  Describing the structure in English first - column X of controlSemantics@ contains the controlSemantic information for the control we have located at X in the controlMap@.

Value14 of controlSemantics@ contains a subvalued list of information - each subvalue corresponding to the equivalent data column in the edit table. So if the data control that was depended upon was in column 3 of the data table, the corresponding information would be in controlSemantics@. Now there could be multiple columns dependent on this data column so their details would be text mark delimited. So the details of the first dependent column would be in controlSemantics@ the second in controlSemantics@ etc. Finally the identification of the data that is dependent consists on the control name value, and in the case of an edit table the column value. In the case of an edit control that is not multivalued this is always 1. The two values are in turn delimited by sub text marks. So if the control in question were dependent on the 3rd column of the editable and it was the EDT_PRODUCTS control column 4 then the structure would be

controlSemantics@< X, 14, 3, 4, 1> = "ENQUIRIES.EDT_PRODUCTS"
controlSemantics@< X, 14, 3, 4, 2> = "4"

So finally a code sample showing how we achieved the result we wanted without having to change our dictionary columns.

    ensure controlSemantics@ is updated to adjust the selling price
    when the product code changes. The product code is tn column 2 of
    the edit table and the selling price is In column 4

  Equ editTable$    To atWindow : ".EDT_PRODUCTS"
  Equ sellingPrice$ To editTable$ : @Stm : 4
  Equ codeColumn$   To 2

  Locate editTable$ In controlMap@ using @Fm setting controlPos Then

    dependsInfo = controlSemantics@< controlPos, CS_RECALC$ >
    colInfo     = dependsInfo<0, 0, codeColumn$>
    Locate sellingPrice$ In colInfo using @Tm setting thereAlready Else
      colInfo := @Tm : sellingPrice$
      dependsInfo<0, 0, codeColumn$> = colInfo
      controlSemantics@< controlPos, CS_RECALC$ > = dependsInfo


This worked perfectly and lent itself to encapsulation in a function to tweak recalculation dependencies as we saw fit.
By Sprezz | Saturday 2 February 2013 17:03 | 0 Comments
An accusation once (correctly) levelled at your author is that he frequently neglects to read the ReadMe files that accompany each upgrade of OpenInsight. Despite having made this oversight the subject of a New Year's Resolution it seems that they still aren't being read with quite the right degree of attention otherwise this little snippet might have been noticed in the 9.2.1 readme...

   RTI_LOAD_DATABASE - Can Load a different DBT programmatically.
   Call RTI_Load_Database("MYDB") to load MYDB.DBT

This will swap the DBT without all the initialisation we mentioned in our last blog post. It will even leave the inheritance chain in @APPID intact so that you can load a database which doesn't inherit from the existing database. In fact the only thing that changes is @DBID which changes to the new database value.

As if that weren't enough (and thanks to RTI for this information) there is an additional boolean parameter to the routine (the second parameter) that will leave @DBID at its previous value. To quote the RTI source "a flag named buseAppIdforDBid. If true, then @DBID will remain as @APPID, preventing some problems".

So depending on desired behaviour it may be even quicker to use RTI_LOAD_DATABASE in place of SWAP_DATABASE. The performance improvements just keep on coming :).
Pixel Footer R1 C1 Pixel