debug – Anvil of Time https://anvil-of-time.com Nature Forges Everything on the Anvil of Time Tue, 09 Mar 2021 18:30:11 +0000 en-US hourly 1 PowerBuilder – Window Object information service https://anvil-of-time.com/powerbuilder/powerbuilder-window-information-service/ Fri, 15 Oct 2010 01:20:20 +0000 http://anvil-of-time.com/wordpress/?p=447 Here is an easy to implement service geared towards developers who are working on complex, many layered applications. In its basic form it shows the current window object, which pbl it is located in, all the various ancestors of the window, their pbl locations, all datawindows and datawindow objects on the window, and the sql statements for those datawindow objects.

The only dependency in the window is the pfc resize service. This can easily be stripped out if needed.

To implement the service, add the following to the window/ancestor window event (rbuttondown for example):

openwithparm(w_window_info,THIS)

The screenshot is an example output.

Download the exports of the window and datawindow object from here.

]]>
PowerBuilder – Things to Avoid https://anvil-of-time.com/powerbuilder/powerbuilder-things-to-avoid/ Fri, 03 Sep 2010 01:16:10 +0000 http://anvil-of-time.com/wordpress/?p=337 “Give someone enough rope and he’ll hang himself”

There are a number of things to avoid in Powerbuilder since they are either resource hogs or make maintenance/debugging a real pain. In no particular order.

Code in the Other event
I worked for awhile on a large accounting application, a commercially available product, written in PB back in version 6.5 days which had some ancestor code in the Other event. I don’t remember exactly why the code was there but it makes debugging almost impossible since it is fired so frequently. From the 11.5 help file,
“The Other event is no longer useful, because you can define your own user events. You should avoid using it, because it slows performance while it checks every Windows message.”
This is an understatement if there ever was one.

RetrieveRow datawindow event
Again from the 11.5 help file, “If you want to guard against potentially large queries, you can have code in the RetrieveRow event check the row argument and decide whether the user has reached a maximum limit. When row exceeds the limit, you can return 1 to abort the retrieval (in which case the retrieval cannot be resumed). A script in the RetrieveRow event (even a comment) can significantly increase the time it takes to complete a query.”

Do not follow this advise for limiting large queries. A much more useful way to achieve this is by altering the datawindow object SQL in the sqlpreview event. Add an instance variable and set that to the record limit you want to enforce. Here is the syntax for SQL Server, Oracle, and MySQL.

SQL Server:
SELECT TOP 10 partNo, partDesc, categoryNo 
FROM partMaster

ORACLE:
SELECT partNo, partDesc, categoryNo
FROM partMaster 
WHERE ROWNUM <= 10

MySQL:
SELECT partNo, partDesc, categoryNo
FROM partMaster
LIMIT 10

So just take apart the sql string, insert the syntax in the proper place, and then let the datawindow do its thing.

Breakpoints in Mousemove
Forget about even trying this. Put a couple of text controls on your window and populate the text property with the X,Y coordinates or whatever else you are looking for.

Global Functions in Datawindow expressions
These can really send the processor utilization on the PC upwards of 100% depending upon what is being done. If you have no alternative try to limit the calls to the function by means of a flag. Add an additional column (‘checkstatus’) to the datawindow retrieve with the default value of ‘Y’. Then in the expression calling the global function put something like:

if(checkstatus[0] <> 'Y', gf_fix_global_warming,0)

Make sure the ‘false’ portion of the expression is the same datatype as the return from the global function. Now when you want the datawindow row to call the function you modify the value in checkstatus with:

dw_1.setitem(row,'checkstatus','N')
dw1.setretraw(TRUE) // this may or may not be needed

And afterwards modify the value back to ‘Y’ so the global is not called again until it needs to.

Large data retrievals in Timers
If you are coding a dashboard type window where data modifications are monitored in near real time, be very careful with the SQL which gets called. Even if the SQL is very efficient and tuned, if it is called every five seconds it can send the cpu utilization on the database server skyward. Try to narrow down the number of columns you update frequently to as few as possible and put these in a separate datastore. The main datawindow retrieve can be called at a longer interval with updates to the display being made based on the smaller datastore retrieve.

Naming global, instance, and local variables the same
Believe it or not I once worked on an application where the global, instance, and local variable names were exactly the same. The folly of doing this should be obvious.

Using database cursors to manipulate data instead of datastores
If you are modifying data in a series of rows and using a cursor in PB to do so, stop. There are very good reasons to use cursors within PB but straightforward updates is best done with a datastore.

Not providing context for error messages
Although it may be meaningless to an end user, putting the object and method name in your error messages are invaluable to the support staff. If you want to get really fancy you can log these things somewhere to provide as much additional information as possible.

March 2010 update:  Modern security standards frown on this last issue.  Just make sure the error is logged via some mechanism for easier troubleshooting.

]]>
PowerBuilder – Watch expressions in Debug https://anvil-of-time.com/powerbuilder/powerbuilder-watch-expressions-in-debug/ Wed, 14 Apr 2010 01:20:16 +0000 http://anvil-of-time.com/2010/04/13/powerbuilder-watch-expressions-in-debug/ There is an easy way to see the contents of a datawindow/datastore while in debug mode – through the use of watch expressions.  Once you are stopped at a breakpoint, say after a retrieve, insert the following watch expression:

The watch window should show a “1” indicating the successful execution of the expression.  Open up the file in excel and you will see the contents of the datawindow including column headers.  Note that the watch is evaluated after each line stepped through in the debugger so you probably will want to remove it after you have obtained the information you want. If you have the file open in Excel and continue debugging, the watch will fail (showing a -1) but otherwise there is no problem.

You can use this technique with any valid powerscript expression including

dwname.getitemstring(1,”mycol”) < make sure row and column designations are correct
dwname.object.datawindow.data < only shows a small chunk of the datawindow data.
gf_myfunc(parm1,parm2) < shows the return value of the function

Beware of out of bounds, null values, and unknown row/column type errors as they can close PB completely and can prevent you from running the debugger again until you clear them out of the Watch tab.

Updated March 2021

]]>