Back

Tip 35. A Datastore that Destroys Itself.

A problem I have come across in my use of datastores is that if you do not destroy them then you cause memory leaks and the application can either GPF or fail to close properly.

You can double check that you DESTROY all your datastores, but I decided to try to use the autoinstantiate option.

You cannot select this option if you create a user object based on a datastore, so I created a non visual object and set the autoinstantiate option and added the following code.

I called my object nvo_datastore.

//---------------------------------------------------------------------------
// Instance Variables
//---------------------------------------------------------------------------
datastore ds

//---------------------------------------------------------------------------
//      Event Name : constructor
//         Purpose : 
//            Sets : None
// Override/Extend : Extend
//---------------------------------------------------------------------------
ds = CREATE datastore

//---------------------------------------------------------------------------
//      Event Name : Destructor
//         Purpose : 
//            Sets : None
// Override/Extend : Extend
//---------------------------------------------------------------------------
DESTROY ds

//---------------------------------------------------------------------------
//  Function Name : initialise
//     Parameters : string      as_dataobject
//                  transaction atrans
//        Purpose : Setup Datastore
//        Returns : SetTransObject Return
//           Sets : None
//---------------------------------------------------------------------------
IF IsValid(ds) THEN
   ds.DataObject = as_dataobject
   RETURN ds.SetTransObject(atrans)
END IF

//---------------------------------------------------------------------------
//  Function Name : of_dynamic_ds
//     Parameters : transaction atrans
//					string as_sqlsyntax
//					ref string as_error
//        Purpose : Dynamic Datastore function.
//        Returns : Success (-1/0) or Row count
//           Sets : None
//---------------------------------------------------------------------------

string	ls_dw_syntax, ls_presentation
long	ll_row_count

IF as_sqlsyntax = "" THEN
	RETURN 0
END IF

ls_presentation = "style(type=Grid Horizontal_spread=10 Detail_top_margin=0 detail_bottom_margin=0 ) "
ls_presentation += "column(border=0 font.face='Arial' font.height=-8) " 
ls_presentation += "text(border=2 font.face='Arial' font.height=-9 font.weight=700 alignment=2)"

ls_dw_syntax = SyntaxFromSQL(atrans, as_sqlsyntax, ls_presentation, as_error)

IF as_error <> "" THEN
	atrans.sqlerrtext = as_sqlsyntax + "~r~n" + as_error
	RETURN -1
END IF

if ds.Create(ls_dw_syntax, as_error) < 0 THEN
	atrans.sqlerrtext = as_sqlsyntax + "~r~n" + as_error
	RETURN -1
END IF

ds.SetTransObject(atrans)
ll_row_count = ds.retrieve()

RETURN ll_row_count
To use the object you simply create a variable of the nvo user object type. The initialise() function is use to setup the data window name and the transaction object. You can then treat it like a normal datastore by references the variable then the datastore ( .ds ) within.
//---------------------------------------------------------------------------
// Some Code
//---------------------------------------------------------------------------
long   ll_row, ll_row_count

nvo_datastore lnvo_datastore

lnvo_datastore.initialise("ds_customer_orders", SQLCA)
lnvo_datastore.ds.Retrieve(ls_cust_code)

ll_row_count = lnvo_datastore.ds.RowCount()

FOR ll_row = 1 TO ll_row_count
   // Do something   
NEXT
The code for the of_dynamic_ds function was sent to by Jan Hink as a solution to the to one of the disadvantages of Using Datastores Instead of Cursors.

I've incorperated it into the datastore object as well as adding a standalone version. See Dynamic Datawindow Function.
Here is an example of the datastore object using a dynamic datawindow.
//---------------------------------------------------------------------------
// Some Code
//---------------------------------------------------------------------------
string    ls_cust_code, ls_customer_name, ls_town, 
string	  ls_sqlsyntax, ls_error
long      ll_row, ll_row_count

nvo_datastore lnvo_datastore

ls_sqlsyntax = "SELECT customers.cust_code, customers.customer_name, customers.town"
ls_sqlsyntax += " FROM customers ORDER BY cust_code"
	
ll_row_count = lnvo_datastore.of_dynamic_ds(SQLCA, ls_sqlsynax, ls_error)

FOR ll_row = 1 TO ll_row_count
   ls_cust_code = lds_datastore.GetItemString(ll_row, "cust_code")
   ls_customer_name = lds_datastore.GetItemString(ll_row, "customer_name")
   ls_town = lds_datastore.GetItemString(ll_row, "town")

   // Loop code
NEXT

DESTROY lds_datastore
See Also Use Datastores Instead of Cursors.
and Dynamic Datawindow Function

Added before 01 Jan 2000

Back