Handles Clean Up

jmac13

Member
Hi all,


I'm using handles (open edge 10.2b) in a procedure like this

Code:
 create buffer hanPointerToRealTable for table ipchrCreationTable.


just so i can point to a record im passing my question is do these handles hang about and need deleting.. I guess it’s good practise to delete them but does open edge get rid of them correctly with the procedure?

 
There is nothing like a garbage collection for handle-based dynamic objects. But, there is some sort of control which is called widget pools. There are different widget pools, named and unnamed ones, scoped to the session or a procedure.

You can deliberately create and delete named widget pools either scoped to the procedure in which you create them or scoped to the session (PERSISTENT).

All dynamics objects that you create go into the next unnamed widget pool unless you explicitly specify a widget pool. The next unnamed widget pool would be the one scoped to the procedure (or class) - but these are only created by the ABL when you explicitly tell it to do so (for example CREATE WIDGET-POOL at the beginning of the procedure, look into any .w that you have created with the AppBuilder - you will find it in the definition section). If no unnamed widget pool scoped to the procedure does exist then the next unnamed widget pool is the one scoped to the session itself.

Therefore: Unless you want dynamic objects to persist in the session it is good practice to include the CREATE WIDGET-POOL statement in every procedure - most prominently procedures running on an AppServer. Plus you can work with named widget-pools on purpose.

But - in the end it is your responsibility as a developer to take care of the objects you create. The rule is: You create them, you delete them no matter whether you use widget pools or not. If you don't you will wind up spending your time chasing down memory leaks.

Heavy Regards, RealHeavyDude.
 
cheers RHD I have used widget pools when ive created menu items on the fly before so that can delete them all at once.. so I'll look at trying to do that with handles..
is it also needed when you just a do a simple define variable hanFieldInfo as handle no-undo. with in a procedure?

another question on Handles if ive got a handle that is pointing at record how i can i use it help me do a for each... e.g.

if i use a buffer like this:
Code:
 define buffer bManpick for manpick.        
        
find    bManpick where        
          rowid(bManpick) = ipRowManPick        
         no-lock no-error.  
 
for each    manCert where        
                manCert.compno   = bManPick.compno   and        
                manCert.plantno    = bManPick.plantno   and        
                manCert.wordnum = bManPick.wordnum           
                exclusive-lock:


I can then do a for each on mancert and using fields from Manpick. Is there anyway using the Create buffer to do the same? so i can just say match up what you can to each other and find me some records?

cheers JMAC13
 
A handle is just a pointer to an object in memory. It is the object in memory you need to manage but it is good practice to assign null to a handle variable after you've deleted to object to which it pointed in the first place.

There are two flavors of handle-based objects:

  1. The static ones that you define at design time with the DEFINE statement and that get created for you by the ABL. Although you can grab the handle to them ( for example hBuffer = BUFFER myTablename:HANDLE ) the ABL manages their life cycle.
  2. The dynamic ones that you create at runtime when the ABL executes a CREATE statement. Theses are the ones which need to manage because the ABL does not do it for you. They were introduced in Progress V9.
Of course you can use the handle to a buffer object to build a dynamic query against it - in a nutshell (code in Firefox IDE - no syntax check :awink:):
CREATE BUFFER hBuffer FOR TABLE "myTable".
CREATE QUERY hQuery.
hQuery:SET-BUFFERS ( hBuffer ).
hQuery:QUERY-PREPARE ( "FOR EACH myTable NO-LOCK" ).
hQuery:QUERY-OPEN ().
hQuery:GET-FIRST ().
REPEAT WHILE NOT hQuery:QUERY-OFF-END:
DISPLAY hBuffer:BUFFER-FIELD ( "myFieldname" ):BUFFER-VALUE.
hQuery:GET-NEXT ( ).
END.
hQuery:QUERY-CLOSE ().
DELETE OBJECT hQuery.
DELETE OBJECT hBuffer.
ASSIGN hBuffer = ? hQuery = ?.
One word of advise: Before starting to use dynamics objects you should make yourself familiar with them otherwise you might wind up experiencing all sorts of undesirable behavior.

Heavy Regards, RealHeavyDude.
 
Cheers RHD.. as i thought with the static and the dynamic handles. I understand what you've done with the code above you're just going through the table via the handle... but i was trying to get records from a table mancert by using fields in my handle. As they have some of the same fields i want to use those fields to get the record
 
Now you've lost me. I don't see any handle involved in the piece of code you've posted.

Is it that you don't know how to reference fields from a dynamic buffer - if that's the case have a look into the DISPLAY statement that was included in my code example. I should mention that there is also a shortcut:

Instead of
hBuffer:BUFFER-FIELD ( "fieldName" ):BUFFER-VALUE
you could also write
hbuffer::fieldName
Heavy Regards, RealHeavyDude.
 
sorry RHD I'll try do a better job of explaining..

Below I've got a handle been passed through that is point to table spechdr in this procedure i want to go round pltCustCert where
pltCustCert.compno = spechdr.compno and
pltCustCert.plantno = spechdr.platno and
pltCustCert.custslno = spechdr.custslno

and 2 other conditions that are not from spechdr so i want to able to say match what i can from spechdr fields and these other condtions.


Code:
define input parameter iphanSpechdr as handle no-undo.

define variable intSpecNo as integer no-undo.
define variable intCustslno as integer no-undo.
define variable hanPltCustCert as handle     no-undo.
define variable chrAssignValues as character no-undo.
define variable intCompno as integer no-undo.
define variable intPlantno as integer no-undo.
if not valid-handle(iphanSpechdr) then
    return.

assign intCompno     = iphanSpechdr:buffer-field ("compno"):buffer-value
       intSpecNo     = iphanSpechdr:buffer-field ("specno"):buffer-value 
       intPlantNo    = int(substring(string(intSpecNo,"999999999":u),1,3))   
       intCustslno   = iphanSpechdr:buffer-field ("custslno"):buffer-value.

assign hanPltCustCert  = buffer pltCustCert:handle 
       chrAssignValues = "specNo," + string(intSpecNo).

for each pltCustCert where     
         pltCustCert.compno   = intCompno   and     
         pltCustCert.plantno  = intPlantNo  and     
         pltCustCert.custslno = intCustslno and     
         pltCustCert.active                 and     
         pltCustCert.custdel  = 0 no-lock:
 
Sorry, maybe I don't see you point - is this a question or statement ... because I see you have all the bits & pieces in your code that you need.

Heavy Regards, RealHeavyDude.
 
a Question.. I've had to define variables for the matching fields is there anyway to say

for each mancert where mancert = hanPltCustCert and pltCustCert.active and pltCustCert.custdel = 0.

so i dont have to define a variable for each field i want to match.. I just want to generically say match all you can from the handle and some other conditions
 
There is no such functionality "match what you can" that I am aware of in the OpenEdge product. One always needs to specify a syntactically correct query ( WHERE clause ). The database engine will then execute the query but does not adjust the query along the way when it would recognize - but how could it? - that there could possibly made other matches. You must understand that whatever you have access to in the ABL layer (be it buffers or variables) does not matter to the database engine in that respect - it will always execute the given query.

Maybe one could come up with a solution in the ABL but I don't think you will get it to perform.

Heavy Regards, RealHeavyDude.
 
Ok cheers RHD.. i was just thinking down lines of that because of buffer-copy/buffer-compare etc as that copies what it can from one record to another matching the fields.

Thanks for your help Hopeful I'll get some good use out of the handles its just in our code at the moment we passing RowID to stuff and finding the record again which thought its a bit of a waste of time. Thought buffer-objects would be a better way
 
Now you've lost me again. I was thinking you are talking about "magically" building a query. The buffer-copy is completely different animal. AFAIK it works only on identical buffers.

Heavy Regards, RealHeavyDude.
 
BUFFER-COPY( ) method

"This method copies any common fields, determined by name, data type, and extent-matching, from the source buffer to the receiving buffer. If there are fields in one buffer that do not exist in the other, they are ignored. This method is used to accommodate temp-tables of joins."

but ur right RHD cant really do it like that for query.. was just thinking out loud... kind of doing a OF with in a for each but in that case the tables have to match....Thanks again for all ur input Cheers
 
Back
Top