Main block references ignored in internal procedures
- Last Updated: March 30, 2020
- 4 minute read
- OpenEdge
- Version 12.2
- Documentation
When the called procedure is a persistent procedure, its
ProDataSet definition will naturally be in the main block of the
procedure, that is, outside of any internal procedure. A ProDataSet
definition is in fact not even allowed in an internal procedure.
However, if its internal procedures are ever passed a ProDataSet
parameter BY-REFERENCE, it is important that you
not reference the ProDataSet handle in any way in the main block
if you expect the effect of that reference to be visible in the
internal procedures. This case is insidious enough to merit a specific
example and diagram.
Here is a simple procedure that defines
the dsOrder ProDataSet, runs another procedure
persistent, and then runs an internal procedure to fill the ProDataSet:
|
Here is the procedure it runs. It defines its
own instance of the ProDataSet and then uses its handle to attach
three Data-Sources. Inside the internal procedure fillProc,
it fills the ProDataSet and returns it as an OUTPUT parameter,
as shown:
|
If you run the main procedure refCaller.p, you get the following error:

What happened? All three Data-Sources were attached in the main block, so why can the AVM not see them?
The reason is that the instance of dsOrder defined
in the main block, the one whose handle was used to attach the Data-Sources,
is not the one used by the internal procedure. Because the ProDataSet
is passed in by reference, fillProc is pointing
to the instance of dsOrder defined in refCaller.p, which
has no Data-Sources. A few messages confirm this.
Here we display the ProDataSet handle in the calling procedure:
|
Also, in the main block of the persistent procedure refCallee.p:
|
And, in the internal procedure fillProc:
|
Run refCaller.p again and you can see the proof. When refCallee.p is first run, it gets a handle for its own ProDataSet. For example:

Next, the calling procedure displays the handle of its copy of the ProDataSet:

Now
it runs fillProc:

You
can see that fillProc's ProDataSet has the same
handle as the one in the calling procedure refCaller.p. In
fact, it is the same ProDataSet, the one with no Data-Sources.
If you change the persistent procedure to do all its work in the internal procedure, then everything works, as shown:
|
The following figure shows how the ProDataSet
is filled in the called program and passed back as an OUTPUT parameter
to the calling program.

Procedure refCallee.p has
a definition of dsOrder, but the ProDataSet instance
this represents is replaced by the one from refCaller.p when
its ProDataSet is passed BY-REFERENCE. All internal
references to hDset are therefore invalid because
they point to a ProDataSet instance that is not being used. This
teaches two important lessons, as described in the following design
tips.
REFERENCE-ONLY option to
these definitions would improve the performance of these procedures
by avoiding the instantiation of the called routine's objects. It
would also avoid the run-time errors by telling ABL at compile time
that the called procedure's ProDataSet is not actually being used.