Welcome, Guest
Username: Password: Remember me
Visual Objects

Please use this forum to post questions about Visual Objects and Vulcan.NET
  • Page:
  • 1

TOPIC:

VO Question: dbServer FieldGET issue 11 Jun 2019 21:09 #9247

  • Jamal
  • Jamal's Avatar
  • Topic Author


  • Posts: 309
  • Using VO 2.08 SP4b (2838), I have the following code which sometimes fails to find a field in the dbf file. Thus wPos returns 0.
    The same happens in various DBF files in a random fashion and I cannot pinpoint exactly what is causing it. I am passing a SYMBOL for the field name such as oSrv:FieldGet(#MYFIELD). Is IsSymbol() the problem or is it FieldPosSym() ?
    Since this is random and I cannot replicate it, I am baffled. Any idea on what is causing this issue or a possible workaround?
    METHOD FIELDGET(uField) CLASS _SpeciallDBServer
    	LOCAL uRetVal as USUAL
    	LOCAL wPos AS DWORD
    	LOCAL dwCurrentWorkArea as DWORD    
    	LOCAL oError as USUAL
    	
    	BEGIN SEQUENCE
    		VODBSelect( wWorkArea, @dwCurrentWorkArea )      
    		
                    IF  IsSymbol( uField )
                           wPos := FieldPosSym( uField) 
    
    		ELSEIF IsString( uField ) 
    			wPos := FieldPos( AsString(uField) )
    			
    		ELSEIF IsNumeric( uField )
    			wPos := uField
    			IF wPos > wFieldCount
    				wPos := 0
    			ENDIF		
    		ENDIF
    		
    		IF wPos = 0
    			InfoBox{,"Utility", "Invalid field: " + AsString(uField) + " in " + AsString(self:name) + _chr(10) + Psz2String(ProcName(2)) + _chr(10) + AsString(ProcLine(2))}:show()    
    		ELSE
    			(wWorkArea)->VODBFieldGet( wPos, @uRetVal )
    		ENDIF    
    		
    		__DBSSetSelect( dwCurrentWorkArea )  //SE-060527    
    		
    	RECOVER USING oError
    		oErrorInfo := oError
    		__DBSSetSelect( dwCurrentWorkArea )  //SE-060527
    		uRetVal := nil
    	END SEQUENCE
    	
    	
    	RETURN uRetVal     

    Please Log in or Create an account to join the conversation.

    VO Question: dbServer FieldGET issue 12 Jun 2019 02:01 #9248

    • TimothyS
    • TimothyS's Avatar


  • Posts: 55
  • Suspect the problem could be in the workarea. You might want to do a few checks to see if you have the right workarea.

    Please Log in or Create an account to join the conversation.

    VO Question: dbServer FieldGET issue 12 Jun 2019 02:18 #9249

    • Chris
    • Chris's Avatar


  • Posts: 3980
  • Or maybe sometimes for some reason the wrong symbol is being passed. I would add some debug code after the "IF IsSymbol( uField )" line that prints the symbol, workarea and return value of wPos. And if wPos == 0, maybe I would also print the names of all the fields just after.
    XSharp Development Team
    chris(at)xsharp.eu

    Please Log in or Create an account to join the conversation.

    VO Question: dbServer FieldGET issue 12 Jun 2019 03:17 #9250

    • Jamal
    • Jamal's Avatar
    • Topic Author


  • Posts: 309
  • Hi Timothy & Chris,

    The workarea and fieldname are correct based on what is displayed using:
    IF wPos = 0
    	InfoBox{,"Utility", "Invalid field: " + AsString(uField) + " in " + AsString(self:name) + _chr(10) + Psz2String(ProcName(2)) + _chr(10) + AsString(ProcLine(2))}:show()    
    ELSE
    	(wWorkArea)->VODBFieldGet( wPos, @uRetVal )
    ENDIF 

    The self:name (for the dbf name) and uField are displayed correctly via the InfoBox when wPos is zero.

    Jamal

    Please Log in or Create an account to join the conversation.

    Last edit: by Jamal.

    VO Question: dbServer FieldGET issue 12 Jun 2019 07:08 #9251

    • lumberjack
    • lumberjack's Avatar


  • Posts: 721
  • Jamal,

    Jamal wrote: Using VO 2.08 SP4b (2838), I have the following code which sometimes fails to find a field in the dbf file. Thus wPos returns 0 for the field name such as oSrv:FieldGet(#MYFIELD). Is IsSymbol() the problem or is it FieldPosSym() ?
    Since this is random and I cannot replicate it, I am baffled.

    METHOD FIELDGET(uField) CLASS _SpeciallDBServer
    	LOCAL uRetVal as USUAL
    	LOCAL wPos AS DWORD
    	LOCAL dwCurrentWorkArea as DWORD    
    	LOCAL oError as USUAL
    	BEGIN SEQUENCE
    		VODBSelect( wWorkArea, @dwCurrentWorkArea )      
                    IF  IsSymbol( uField )
                           wPos := FieldPosSym( uField) 
    		ELSEIF IsString( uField ) 
    			wPos := FieldPos( AsString(uField) )
    		ELSEIF IsNumeric( uField )
    			wPos := uField
    			IF wPos > wFieldCount
    				wPos := 0
    			ENDIF		
    		ENDIF
    		IF wPos = 0
    			InfoBox{,"Utility", "Invalid field: " + AsString(uField) + " in " + AsString(self:name) + _chr(10) + Psz2String(ProcName(2)) + _chr(10) + AsString(ProcLine(2))}:show()    
    		ELSE
    			(wWorkArea)->VODBFieldGet( wPos, @uRetVal )
    		ENDIF    
    		__DBSSetSelect( dwCurrentWorkArea )  //SE-060527    
    	END SEQUENCE
    	RETURN uRetVal     

    Is your _SpeciallDbServer class inheriting from DbServer? It just look strange why you would want to select a different workarea (wWorkArea and dwCurrentWorkArea) seeing that DbServer manages its workarea internally?
    ______________________
    Johan Nel
    Boshof, South Africa

    Please Log in or Create an account to join the conversation.

    VO Question: dbServer FieldGET issue 12 Jun 2019 08:02 #9252

    • Jamal
    • Jamal's Avatar
    • Topic Author


  • Posts: 309
  • Johan,

    I am just "improving" the dbServer and overriding the FIELDGET() which does the same thing; nothing strange about that. Please look at the VO RDD CLASS SDK, FIELDGET() method. Without the
    VODBSelect( self:wWorkArea, @dwCurrentWorkArea )

    the FIELDGET() will fail.

    Jamal

    Please Log in or Create an account to join the conversation.

    VO Question: dbServer FieldGET issue 12 Jun 2019 09:50 #9253

    • Karl-Heinz
    • Karl-Heinz's Avatar


  • Posts: 774
  • Hi Jamal,

    when i switched from 2.5b3 to 2.8 i noticed several strange DBF access problems. The solution was to use DbSetRestoreWorkarea( TRUE ) - the default setting of this global setting is FALSE. As you see, within the __DBSSetSelect() func VODBSetSelect() is only called if __glRestoreWorkarea is set to TRUE.

    FUNCTION __DBSSetSelect(dwNew AS DWORD) AS DWORD PASCAL
       //SE-060527
       IF __glRestoreWorkarea
          RETURN VODBSetSelect(LONGINT(dwNew))
       ENDIF
       RETURN dwNew
    
    STATIC GLOBAL __glRestoreWorkarea := FALSE AS LOGIC //SE-060527
    
    FUNCTION DbSetRestoreWorkarea(lEnable := NIL AS USUAL) AS LOGIC PASCAL
       //SE-060527
       LOCAL lOldValue AS LOGIC
    
       lOldValue := __glRestoreWorkarea
    
       IF IsLogic(lEnable)
          __glRestoreWorkarea := lEnable
       ENDIF
    
       RETURN lOldValue
    

    Don´t know if it helps in your case, but i would give it a try.

    BTW. The DBsetRestoreWorkarea() func is documented in the Whatsnew28.rtf

    regards
    Karl-Heinz

    Please Log in or Create an account to join the conversation.

    VO Question: dbServer FieldGET issue 12 Jun 2019 18:11 #9267

    • Jamal
    • Jamal's Avatar
    • Topic Author


  • Posts: 309
  • Hi Karl,

    Thanks! It is funny I was looking at DbSetRestoreWorkarea() function yesterday and its source in the X# master lib. However, I am not sure if this will help, since I am setting the workarea before accessing the DBF functions and __DBSSetSelect(..) is coming after. On error, I am going to dump the field list into a log file and see what what is returned.

    Jamal

    Please Log in or Create an account to join the conversation.

    Last edit: by Jamal.

    VO Question: dbServer FieldGET issue 12 Jun 2019 18:38 #9268

    • Jamal
    • Jamal's Avatar
    • Topic Author


  • Posts: 309
  • I modified the code to force an alias to be used via (self:wWorkArea)->
    wPos := (self:wWorkArea)->FieldPos( AsString(uField)

    Will wait to see if any clients have issues or if it solves it.

    Jamal

    Please Log in or Create an account to join the conversation.

    Last edit: by Jamal. Reason: self:wWorkArea used

    VO Question: dbServer FieldGET issue 05 Nov 2019 00:57 #11587

    • Jamal
    • Jamal's Avatar
    • Topic Author


  • Posts: 309
  • I know it has been sometime since posting this topic!

    By accident, I think I may have found the real reason for the mystery! It was bBrowser AutoRefresh feature after not touching anything on the bBrowser by sitting idle for about 10 minutes. The use of SetTimer()/KillTimer() combination in bBrowser even with AutoRefreshTime set to 0, caused the DBF workarea to get really screwed up after about 10 minutes of idle time and then FIELDGET() crashed.

    I was able to replicate the issue several times. Commenting out the SetTimer()/KillTimer() in the Assign AutoRerfreshTime(...) method code resolved the issue; basically, I just disabled this feature!

    I am going to implement my refresh routine and see how it goes by implementing a simple timer function which is not part of the bBrowser's EventHandler().

    Edit: so I created my timer to call oBrowser:Refresh() now that always points:
    bBrowser:StabilizeServer() line 26 which is: self:oServer:Skip(1). See screenshot:



    I'll email bBrowser support. Hope Joachim responds.

    Please Log in or Create an account to join the conversation.

    Last edit: by Jamal.

    VO Question: dbServer FieldGET issue 05 Nov 2019 15:36 #11600

    • ic2
    • ic2's Avatar


  • Posts: 1666
  • Hello Jamal,

    Good detective work!

    Please keep us posted about what Joachim replies.

    Dick

    Please Log in or Create an account to join the conversation.

    VO Question: dbServer FieldGET issue 14 Nov 2019 18:57 #11727

    • Jamal
    • Jamal's Avatar
    • Topic Author


  • Posts: 309
  • Hi All,

    Joachim just replied and could not duplicate the issue.

    In the mean time I think I may have found out the culprit: it has to do with multi-threading and DBF workarea gets all mixed up.

    Disclaimer: I am no multi-threading expert, my conclusions may not be accurate.

    I was creating a timer using code like the incomplete sample below. When the timer kicked in, the OpenDBFCallBack() is called. This function only opens another DBF, checks some values, closes dbServer and returns, but somehow, this affected bBrowser dbServer workarea in another unrelated datawindow1 where a bBrowser:refresh() was called by its refresh timer. The workarea got overwritten and no longer the same and thus FIELDGET("SOMEFIELD") crashed because my code that handles bBrowser on DataWindow1 innocently thinks it is still working with the same original workarea and its same dbf structure.

    Here the a sample code:

    _dll FUNCTION CreateTimerQueue() as ptr PASCAL:Kernel32.CreateTimerQueue
    function Test() as void pascal 
     	local hTimer as ptr
     	local arg := 1234 as int
           local gDoneEvent as ptr   
           LOCAL gTimerQueue as ptr
    
     	gDoneEvent := CreateEvent(null_ptr, true, FALSE, null_ptr)
    
     	// Create the timer queue.
     	gTimerQueue := CreateTimerQueue()
    
     	// Set a timer to call the timer routine every 5 minutes.
           //  Time in milliseconds. Multiply the time value by 60000. 5 MINUTES = 5*60000 
     	CreateTimerQueueTimer( @hTimer, gTimerQueue, @OpenDBFCallBack(), @arg , 1*60000, 1*60000, 0)
    
    	return
    
    function OpenDBFCallBack() as void pascal
    // open dbf server, check some values
    // close dbServer and return
    return
    

    Note: even before using the above CreateTimerQueueTimer(), I had issues with bBrowser sometimes failing with similar issues.

    I had DbSetRestoreWorkarea(false) in the Start() of my app. I will do more tests to see if setting it to True makes a difference.

    Jamal

    Please Log in or Create an account to join the conversation.

    VO Question: dbServer FieldGET issue 14 Nov 2019 19:41 #11728

    • wriedmann
    • wriedmann's Avatar


  • Posts: 3366
  • Hi Jamal,
    if you are not using multithreading in your application, then this is not the cause.
    In VO both the RDDs and the Garbage Collector are no thread safe, but according to the Microsoft docs docs.microsoft.com/de-de/windows/win32/sync/using-timer-queues this call does not creates an own thread.
    There must be something other that confused the runtime and make it close the wrong server.
    Wolfgang
    Wolfgang Riedmann
    Meran, South Tyrol, Italy

    www.riedmann.it - docs.xsharp.it

    Please Log in or Create an account to join the conversation.

    VO Question: dbServer FieldGET issue 14 Nov 2019 19:59 #11729

    • Jamal
    • Jamal's Avatar
    • Topic Author


  • Posts: 309
  • Hi Wolfgang,

    You most likely right. If you notice I wrote:
    Note: even before using the above CreateTimerQueueTimer(), I had issues with bBrowser sometimes failing with similar issues.

    But my feeling is that it has to do with the way VO is handling works areas and may be the DbSetRestoreWorkarea(false) is the cause. I can't rule anything out at this point.

    Jamal

    Please Log in or Create an account to join the conversation.

    VO Question: dbServer FieldGET issue 14 Nov 2019 20:10 #11730

    • wriedmann
    • wriedmann's Avatar


  • Posts: 3366
  • Hi Jamal,

    yes, I have noted that.
    But in my applications (and I'm using bBrowser heavily) I had never this issue.
    Do you are using a hybrid approach somewhere (mixed functions and servers9?
    Wolfgang
    Wolfgang Riedmann
    Meran, South Tyrol, Italy

    www.riedmann.it - docs.xsharp.it

    Please Log in or Create an account to join the conversation.

    VO Question: dbServer FieldGET issue 14 Nov 2019 20:33 #11731

    • Jamal
    • Jamal's Avatar
    • Topic Author


  • Posts: 309
  • Hi Wolfgang,

    It use mostly dbServer methods in my apps, and if I overrode any dbServer methods (for speed) I write for example:
    METHOD FIELDPUT( uField, uValue ) CLASS _JamalDBServer
    
    	LOCAL wPos as DWORD
    	LOCAL dwCurrentWorkArea as DWORD
    
    	
    	VODBSelect( wWorkArea, @dwCurrentWorkArea ) // select workrea
    	
    	wPos := __GetFldPos( uField, wFieldCount )
    	
    	VODBFieldPut( wPos, uValue )
    	
    	__DBSSetSelect( dwCurrentWorkArea )  //SE-060527  - restore workarea
    
    	RETURN uValue   

    Jamal

    Please Log in or Create an account to join the conversation.

    Last edit: by Jamal.

    VO Question: dbServer FieldGET issue 14 Nov 2019 21:48 #11732

    • Karl-Heinz
    • Karl-Heinz's Avatar


  • Posts: 774
  • Hi Jamal,

    take a look at the __DBSSetSelect() sources. If you don´t use the DbSetRestoreWorkarea(TRUE) setting, the global var __glRestoreWorkarea never becomes true. So either use DbSetRestoreWorkarea(TRUE) or restore the workarea within your FieldPut()

    FUNCTION __DBSSetSelect(dwNew AS DWORD) AS DWORD PASCAL
       //SE-060527
       IF __glRestoreWorkarea    <---------------------------------------
          RETURN VODBSetSelect(LONGINT(dwNew))
       ENDIF
       RETURN dwNew

    regards
    Karl-Heinz

    Please Log in or Create an account to join the conversation.

    VO Question: dbServer FieldGET issue 14 Nov 2019 22:19 #11733

    • robert
    • robert's Avatar


  • Posts: 3595
  • Jamal, Karl-Heinz,

    I suggest to set DbSetRestoreWorkarea(TRUE) .
    In fact I will make that the default for the next build.
    In VO switching workareas (especially when there are many fields) can be quite expensive. The runtime removes the fieldnames from the active table from the memvar/fields list and then adds the fields of the new area.
    We added this setting as optimization.
    But in X# things work differently, so there is no need anymore to suppress workarea switching. See
    github.com/X-Sharp/XSharpPublic/blob/mas...RDD/CoreDb.prg#L1694
    to see what we are doing: we are only changing the active workarea number.

    Robert
    XSharp Development Team
    The Netherlands

    Please Log in or Create an account to join the conversation.

    VO Question: dbServer FieldGET issue 14 Nov 2019 23:19 #11735

    • Jamal
    • Jamal's Avatar
    • Topic Author


  • Posts: 309
  • Hi Karl, Robert,

    I will use DbSetRestoreWorkarea(TRUE) from now on in my VO apps.

    Hopefully, this cures the issues.

    Jamal

    Please Log in or Create an account to join the conversation.

    Last edit: by Jamal.
    • Page:
    • 1