Kbase P118804: SHARED dataset not showing expected records when passing datasets BY-REFERENCE
Autor |
  Progress Software Corporation - Progress |
Acesso |
  Público |
Publicação |
  19/11/2009 |
|
Status: Verified
SYMPTOM(s):
Using SHARED ProDataSet
Passing ProDataSet parameter to procedure that defines dataset as NEW SHARED
Other procedures defining ProDataSet as SHARED do not return the expected data
Passing ProDataSet BY-REFERENCE
Passing ProDataSet by value does give expected results
FACT(s) (Environment):
OpenEdge 10.0x
OpenEdge 10.1x
All Supported Operating Systems
CAUSE:
This is expected behavior.
To understand the behavior, it is important to understand that references to an object and the actual object itself are two different things.
The syntax for SHARED objects/variables, for passing parameters BY-REFERENCE and for passing parameters using the BIND syntax all set references to objects in a different way, and this behavior is due to the interaction of the different techniques (or rather, the lack thereof).
Passing by-reference redirects the object reference in the called procedure only; any object reference that points to the original object in the called procedure remains unchanged.
Consider the following example:
Using 3 procedures:
- UsesShared.p: Defines the ProDataSet dTest1 as SHARED. It contains an internal procedure doMoreStuff; this internal procedures does not accept parameters, it does have references to the dTest1 dataset.
- DefinesNewShared.p: Defines a proDataSet dTest1 as NEW SHARED, then loads UsesShared.p persistently. It contains an internal procedure doStuff which will call an internal procedure doMoreStuff in UsesShared.p. The internal procedure doStuff has an input parameter for dTest1.
- Caller.p: Loads the DefinesNewShared.p persistently, then passes a (non-shared) proDataSet dTest2 to internal procedure in DefinesNewShared.p.
The ProDataSets have an identical schema, and all references to the ProDataSets are static.
What happens when caller.p is run, regardless of how the dataset is passed:
1. DefinesNewShared.p is loaded persistently. This uses the DEFINE NEW SHARED syntax, so at this point the SHARED dataset dTest1 is instantiated.
2. UsesShared.p is loaded persistently. This uses the DEFINE SHARED syntax, so any reference to dTest1 is bound to the SHARED dTest1 at this point.
When caller.p does not use BY-REFERENCE syntax:
3a. The dTest2 is passed in to DefinesNewShared.p by value, which means that the records are copied from non-shared dTest2 into shared dTest1.
4a. At the end of the call chain, the doMoreStuff internal procedure will be able to find the records because it is referring to a dataset that contains them.
When caller.p does use BY-REFERENCE syntax:
3b. The non-shared dTest is passed into DefinesNewShared.p by reference. Which means that the references to dTest1 in DefinesNewShared.p are redirected to dTest2 instead. However, nothing is done with UsesShared.p at this point, so references to dTest1 there still point to the SHARED dTest1.
4b. At the end of the call chain, the doMoreStuff internal procedure will be looking at dTest1, which does not contain the same records as dTest2. Therefore it is unable to find the expected data.
In OpenEdge 10.1A and later:
The same issue can be seen if instead of the SHARED syntax the REFERENCE-ONLY / BIND syntax is used.
While the BIND syntax uses a significantly different implementation model on determining which actual instance of an object is being used, it behaves the same when parameters are being passed around (points 3a,4a,3b and 4b above).
FIX:
When passing by reference, ensure the code is written properly to ensure all procedures in the call chain accept the dataset by-reference instead of relying on shared objects.
Note that for this to work as expected, no SHARED definitions may exist in the 4GL code. Incompatibility between the SHARED and BY-REFERENCE models prevents this.
Note also that this does open up the possibility of using the REFERENCE-ONLY syntax on the DEFINE <object> statements, which will improve performance on procedure startup.
A less efficient but easier to implement option is to ensure that any procedure defining a dataset as NEW SHARED qualifies all parameter definitions for that dataset with the BY-VALUE option, to ensure no passing by reference takes place.
While this ensures the existing code will continue to behave as expected, any potential performance benefits from passing by-reference are lost.