fbpx
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

VO Question: dbServer FieldGET issue 5 months 5 days ago #9247

  Jamal's Avatar Topic Author Jamal Offline Posts: 177
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 5 months 5 days ago #9248

  TimothyS's Avatar TimothyS Offline Posts: 32
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 5 months 5 days ago #9249

  Chris's Avatar Chris Offline Posts: 1460
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 5 months 5 days ago #9250

  Jamal's Avatar Topic Author Jamal Offline Posts: 177
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 5 months 4 days ago #9251

  lumberjack's Avatar lumberjack Offline Posts: 611
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
George, South Africa

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

VO Question: dbServer FieldGET issue 5 months 4 days ago #9252

  Jamal's Avatar Topic Author Jamal Offline Posts: 177
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 5 months 4 days ago #9253

  Karl-Heinz's Avatar Karl-Heinz Offline Posts: 392
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 5 months 4 days ago #9267

  Jamal's Avatar Topic Author Jamal Offline Posts: 177
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 5 months 4 days ago #9268

  Jamal's Avatar Topic Author Jamal Offline Posts: 177
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 1 week 5 days ago #11587

  Jamal's Avatar Topic Author Jamal Offline Posts: 177
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.
Attachments:

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

Last edit: by Jamal.

VO Question: dbServer FieldGET issue 1 week 4 days ago #11600

  ic2's Avatar ic2 Offline Posts: 575
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 2 days 10 hours ago #11727

  Jamal's Avatar Topic Author Jamal Offline Posts: 177
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 2 days 9 hours ago #11728

  wriedmann's Avatar wriedmann Offline Posts: 1854
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 2 days 9 hours ago #11729

  Jamal's Avatar Topic Author Jamal Offline Posts: 177
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 2 days 9 hours ago #11730

  wriedmann's Avatar wriedmann Offline Posts: 1854
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 2 days 9 hours ago #11731

  Jamal's Avatar Topic Author Jamal Offline Posts: 177
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 2 days 7 hours ago #11732

  Karl-Heinz's Avatar Karl-Heinz Offline Posts: 392
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 2 days 7 hours ago #11733

  robert's Avatar robert Offline Posts: 1311
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 2 days 6 hours ago #11735

  Jamal's Avatar Topic Author Jamal Offline Posts: 177
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