By the way, notice every object you create is bound to the current datasession at it's creation. The only and obvious exceptions are a form with private datasession creating a new datasession it itself also lives in and a session class when set to create a priavte datasession (which is the default, as thats the intent of that class).
So let's demonstrate: That also means an object you create without a parent, i.e. you create it with CREATEOBJECT or NEWOBJECT instead of ADDOBJECT, will be in the datasession of whatever code makes these CREATEOBJECT or NEWOBJECT calls. It doesn't set Parent object property nor do objects need to have a datasessionid prpoerty to be part of a datasession, that's standard behavior, nothing you need to program. There's no compliaction in needing to care about this with code that switches to the correct session, the session is an automatic separation from the rest regarding anything about workareas.
So here's a demo of that concept. What you should notice is that Set("Datasession") - which reports the current datasesion id - only depends on what was the session id when the object was created, not what is the current session at time of calling it.
Code:
Clear
? "General code is in session id", Set("Datasession")
oDemoform = CreateObject("privatesessionform") && shows its datasession id and the custom objects (same) session id.
oDemoform.ShowSessionId() && still shows its datasession id, not 1, the session id of the code calling the method.
? "General code still is in session id", Set("Datasession") && to show the general code session still is 1 and has not switched session
goCustom.ShowSessionId() && showing the custom obnject session calling from genral code instead of calling from inside the form, session is still the same as the form
oCustom = CreateObject("mycustom","custom2") && creating a second object from the genreal session 1
oCustom.ShowSessionId() && will show to be part of session 1
oDemoform.ShowSessionOf(oCustom) && ...also when the form makes that call
Define Class PrivateSessionForm as form
Datasession = 2 && private datasession
Procedure Init()
? this.Name + " is in session id", This.DataSessionId && not every class has that property, though. But every object lives in a datasession
Public goCustom && for sake of simple demonstration of an object without parent you can access here and in general code.
goCustom = CreateObject("mycustom","custom1")
goCustom.ShowSessionId()
EndProc
Procedure ShowSessionOf(oObject)
oObject.ShowSessionId()
Endproc
Procedure ShowSessionId()
? This.Name + " is in session id", Set("Datasession")
EndProc
EndDefine
Define class MyCustom as Custom
Procedure Init(cName)
This.Name = cName
EndProc
Procedure ShowSessionId()
? This.Name + " is in session id", Set("Datasession")
EndProc
Enddefine
Expected outcome:
View attachment 2153
Notice no matter from where and in which session the call to a ShowSession method is done, the session is always the one that was the session when creating the object. General code is always in session 1, custom1 in the same session as the form (2 or higher, depends on whether you have further private session forms running before running this demo code), custom2 is in session 1, as general code created custom2, that's also the case when the ShowSessionOf(oObject) method of the form calls custom2s ShowSessionId method. So the session is not the session of the caller, but of the creator or that of creation time. What happens, if the form is destroyed and custom1 still is kept existing? Experiment to find out.
What can be concluded from this is that you could even let a private datasession form create a timer as child object of screen or in a goTimer public variable or however you create your timer now, just put that timer creation into the private form code. In init, for example, to keep it simple. The timer does not need to be a child object of the form and any code which addresses the timer object can stay as is, of you have a goTimer variable, that can be kept. If you add it to the _screen, that can stay as is, even if the private form init calls _screen.addobject() and makes the timer an object of the screen It will still be created in the private datasession of the form and not the session of the screen, as the form create the timer object and does that in the form datasession.
And after you change that, the timer can't affect anything in any session. You can even now use a dbf or cursor as a permanent timer workarea that you also can be sure won't be affected by application code unless it closes all workareas of all existing datasessions. But CLOSE DATA ALL, for example, is only acting in one session and will keep timer workareas untouched. So even such extreme code doesn't harm the timer. And so you can keep the SQLEXEC result and don't care about, you can use workareas to add logging of timer events or monitor anything you want in workareas of the timer without effecting any other code and without needing to maintain where which workarea is by what alias name in which session id, you will have your own private session "inherited" by the forms private session. Don't show the form, don't use it for anything so you don't introduce a possible side effect of the timer with what you show in that form, so don't make it part of the application main form, just use a separate private datasession form for creating the timer.
Also: You don't need a form class, you can also make it a scx form with private datasession and call it with DO FORM ... NOSHOW, perhaps LINKED to a variable not going out of scope, so that session is existing all the time and the timer therefore also lives in that separate "world".
In essence: Creating an general purpose application timer from within a private datasession is general advice for a sideeffect free timer. Even when it uses workareas and not only for your SQLEXEC scenario. The only way you may cause side effects from the timer to other datasessions or application code from other datasessions affecting the timer is when you switch sessions in code and are irresponsible with how you do that. So if you would act responsible with anything that intentionally switches data sessions to act on them, too, don't touch the session of the timer, and you're good with that, too.