12 Replies Latest reply on Nov 5, 2010 10:59 AM by philmodjunk

    Get(LastError) clobbered by OnRecordLoad script trigger

    MattHirons

      Summary

      Get(LastError) clobbered by OnRecordLoad script trigger

      Product

      FileMaker Pro

      Version

      11.0v2

      Operating system version

      All

      Description of the issue

      The value of Get(LastError) is clobbered by an OnRecordLoad script trigger.

      For example,
      PerformFind[]
      << OnRecordLoad >> script trigger fires here
      If [Get(LastError) = 401]
        Do Something
      End If

      PerformFind generates a 401 error.  The OnRecordLoad script trigger fires after the PerformFind step.  The trigger script does not generate an error, so Get(LastError) is 0 at the end.  When context switches back to the original script, Get(LastError) is still 0, causing existing script functionality to change unexpectedly.  What should happen is that the value of Get(LastError) is restored upon returning from the script trigger.

      Steps to reproduce the problem

      Create a script (script1) with at least one step in it, such as Set Variable[$$count; Value:1]

      Set script1 as the OnRecordLoad script trigger.

      Create another script (script2) with the following steps:
      Set Error Capture [On]
      PerformFind[Restore]  <--make sure this find returns 0 records
      If [Get(LastError) = 401]
        Show Custom Dialog ["notice"; "no records found"]
      End If

      Execute script2.

      Expected result

      The PerformFind[] step generates a 401 error.
      Get(LastError) returns 401.
      A dialog is displayed informing us that no records have been found.

      Actual result

      The PerformFind[] step generates a 401 error.
      Get(LastError) returns 0.
      No dialog is displayed.

        • 1. Re: Get(LastError) clobbered by OnRecordLoad script trigger
          davidhead

          Hi MattHirons

          This is expected behaviour given the nature of the OnRecordLoad trigger. This would be exactly the same as if you had a Perform Script step at that point in your script.

          To accurately test for an error that may have occurred in the Perform Find script step (and suppress any associated dialogs) , I would suggest that you use a variable to store the error:

          Set Error Capture [On]
          PerformFind[]
          Set Variable [$lasterror; Value: Get(LastError)]
          Set Error Capture [Off]
          If [$lasterror = 401]
            Do Something
          End If

          TS_Oz, FileMaker Inc.

          • 2. Re: Get(LastError) clobbered by OnRecordLoad script trigger
            MattHirons

            Unless I have something set somewhere that is affecting my FileMaker behavior, you've just made my point even clearer. As FileMaker developers, we expect that Get(LastError) is only, but always available on the very next line of our scripts.

            The problem here is that when you have an OnRecordLoad layout script trigger set up, it is called BEFORE the next step.  Before the Set Variable.  So by the time it gets done executing the script trigger, Get(LastError) has lost it's value, and that error value is not restored when context switches back to the script.

            I created a brand new database with just the information I listed in the original bug report and it displays this behavior.  It is very easy to reproduce.  If you want, I can send you the test file that I created.

            Thanks for taking a look at this,

            Matt

            • 3. Re: Get(LastError) clobbered by OnRecordLoad script trigger
              philmodjunk

              One work around is to create a second utility layout that refers to the same table occurrence as the layout where your script is currently performing the find. You can switch to this layout and perform your find then switch back. This will keep the On record load trigger from interfering.

              • 4. Re: Get(LastError) clobbered by OnRecordLoad script trigger
                davidhead

                Hi Matt

                I am very confident that this can be reproduced as it is expected behaviour. 

                You said "we expect that Get(LastError) is only, but always available on the very next line of our scripts". Well that is what is happening here. However, perhaps you do not know that there is a unified script stack and only ever one "last error". What this means is that the last error is from the last run script step. In your case, this means the last step of the triggered script. And that error is available on the very next line of the next script. 

                I have demonstrated to you how, with good programming, you can trap the error for later use when you need it. This technique is also used in other circumstances where any state in a script may change and needs to be remembered for future use. This is not a workaround: it is a programming technique that accounts for the standard behaviour of the environment.

                TS_Oz, FileMaker Inc.

                • 5. Re: Get(LastError) clobbered by OnRecordLoad script trigger
                  philmodjunk

                  TS_Oz, please download and test this demo file that uses your script and please show us why it doesn't trap the error message:

                  http://www.4shared.com/file/moP-gIFB/ScriptTriggerTest.html

                  • 6. Re: Get(LastError) clobbered by OnRecordLoad script trigger
                    hschlossberg

                    Given the nature of this issue, TS_Oz's workaround would not work.  Going to an alternate layout that has no script triggers is a valid way to handle this issue.  While the current behavior might be expected by FMI's engineers, it doesn't seem to me to necessarily be desirable.

                    I would have been nice to have been given the option to temporarily turn off all script triggers while a script is running.

                    • 7. Re: Get(LastError) clobbered by OnRecordLoad script trigger
                      davidhead

                      Hi Phil

                      I was wrong in my knowledge of exactly when the OnRecordLoad script would be triggered. My technique will not work in this case.

                      For others who are following this, it triggers as soon as the find is performed when the resulting record (or even in this case, no record) loads. This means that the last error is carried to the triggered script and is gone by the time the originating script runs my Set Variable script step.

                      Why is this so? OnRecordLoad is a “post”-processing trigger so it happens after the records are loaded. That would appear to be a good thing for this situation. However, the found records are loaded as part of the Perform Find script step - it both finds and loads the found records. There is therefore no opportunity to deal with the resulting error (including trapping it in a variable) before the trigger is fired.

                      So the question is what changes could be made to the FileMaker environment to allow such an error to be dealt with when there is an OnRecordLoad script trigger in place? And is this the only trigger which will produce this sort of problem?

                      One suggestion might be to be able to maintain an error stack where all errors that occur are stacked until all running scripts end. That stack could be queried for specific errors. Do you think that would be useful?

                      Howard's suggestion is interesting. I would encourage Howard to submit it as a feature request with a well-reasoned case. So you are thinking a script step such as SetScriptTriggers [Off]? Interesting.

                      TS_Oz, FileMaker Inc.

                      • 8. Re: Get(LastError) clobbered by OnRecordLoad script trigger
                        davidhead

                        Another thing: with Phil's suggestion of performing the find on a utility layout where there are no script triggers.

                        Would it be reasonable to suggest that a good development habit is to have a utility (table view) layout for each table where such operations are performed? Just to be safe?

                        In my solutions, I will always have what I call a developer layout for each table. This is used to see the data and check things from a developer's standpoint. But it is also used when I need to do other things on sets of records. When programming, I always know it is there (with a standard name) and I can always easily navigate there and back in confidence.

                        TS_Oz, FileMaker Inc.

                        • 9. Re: Get(LastError) clobbered by OnRecordLoad script trigger
                          hschlossberg

                          Thanks for your responses, Oz.  I'm not sure how useful an error stack would be unless there was a way of identifying the steps that triggered those error results.  

                          I'm having trouble imagining a reason that last errors should carry from one script to another.  I'd think we should deal with potential errors within the same script or else we can pass any errors back to a calling script with the Exit Script step.

                          I would recommend against using a table view layout for a variety of reasons, the biggest one being that it can easily slow down your scripts.  The reason is that a table view has to load all data from all fields (displayed or not0 from all records in a table view, whereas a form view only has to load all fields from the current record.  Even better, I've been utilizing completely blank layouts for my script utilities so that no record data has to be loaded.  

                          • 10. Re: Get(LastError) clobbered by OnRecordLoad script trigger
                            davidhead

                            Great comments Howard. Thanks.

                            I suppose you could say that the errors don't really "carry from one script to another". Rather, there is a single script stack used by all running scripts. So what you would like to see is an error stack for each running script.

                            True comments about the layouts with no fields too. So, let's say that in the normal course of use, they are blank layouts in form view. A developer could switch to table view when needed and that view has fields that have been added via the Modify button. I like that.

                            TS_Oz, FileMaker Inc.

                            • 11. Re: Get(LastError) clobbered by OnRecordLoad script trigger
                              MattHirons

                              Thanks for everyone's responses on this issue.  The way I imagine this working is that when the triggered script "interrupts" the originating script, the LastError value is pushed onto a stack.  The triggered script would not see the error.  When the triggered script exits, the LastError value is popped off the stack able to be seen by the originating script again.  So, if the triggered script itself generates an error, that value is lost when the script exits, unless you pass it back as a script result.

                              I haven't tested any other trigger types, but there are probably others that would have the same issue.

                              We've started to create blank and/or developer layouts to be used with scripts, and that is a good workaround (and probably even a preferred way of doing it).  However, for legacy scripts that depend on Get(LastError), I think some method of saving its value is required.

                              A SetScriptTriggers[Off] step is interesting, I'm still trying to wrap my head around the possible consequences of that.

                              • 12. Re: Get(LastError) clobbered by OnRecordLoad script trigger
                                philmodjunk

                                With scripted finds, you can also use Get ( foundcount ) to check for successful results rather than LastError, though that doesn't allow you to distinguish between no records match criteria and Invalid search criteria errors.

                                I've suggested before in the forum and FileMaker Inc.'s suggestion form that FileMaker should implement much better, more consistent error handling.

                                1. All errors should halt script execution with a dialog that gives you an option to terminate the script.
                                2. All such error dialogs should be disabled when Set error capture is turned on.
                                3. And some errors such as Go to record [ next ; exit after last ] on the last record should not be flagged as errors in the first place.
                                4. It should also be possible to set up an error handler such as one finds with On Error in visual basic that allows us to create code to handle the error gracefully by trapping all errors and then returning execution back to the appropriate point in the script after the error has been dealt with.