Try OpenEdge Now
skip to main content
ProDataSets
Advanced Events and Attributes : Successive loading of ProDataSet data : Forcing the ProDataSet to be passed BY-VALUE
 

Forcing the ProDataSet to be passed BY-VALUE

You might notice that there is an extra keyword on the ProDataSet parameter at the top of fetchOrders, as shown:
DEFINE OUTPUT PARAMETER DATASET FOR dsOrder BY-VALUE.
Why is this here? After all, as you learned earlier, passing ProDataSets by value (that is, by copying the data from one procedure to the other) is the default behavior, and you have to explicitly specify BY-REFERENCE in the RUN statement to pass the ProDataSet by simply pointing the called procedure at the same instance the calling procedure is using.
To answer the question, let us look at a sketch of how the ProDataSet definitions are used in these two procedures, the window procedure that represents the client and the support procedure that represents the server code, as shown in the following figure.
Figure 12. Use of ProDataSet definitions
Here are the steps these procedures go through using the default behavior of passing the ProDataSet by value:
1. The ProDataSet that is going to supply the data to the client is defined in orderSupport.p. The SET-CALLBACK-PROCEDURE methods that attach its behavior to it all point to that definition by using the local ProDataSet handle or one of its buffer handles.
2. When the client procedure calls fetchOrders, the ProDataSet parameter in fetchOrdersfetchOrders also references the local ProDataSet dsOrder whose definition it shares.
3. When fetchOrdersfetchOrders does a FILL, that FILL also references the local ProDataSet dsOrder.
4. Because the FILL callback events have been attached to that local instance of dsOrder, they all execute correctly to prepare the query, attach Data-Sources, and take other actions as part of the FILL.
5. When fetchOrders returns ProDataSet dsOrder as OUTPUT, it again refers to the local ProDataSet, which is copied back to the window procedure's own instance of ProDataSet dsOrder.
In this way, the ProDataSet in (enclosed in the dotted line) maintains its integrity. All the behavior that has been attached to it executes properly. This is always how a procedure call like this operates when the application is actually distributed. If the window procedure truly executes in a client session and the support procedure in an AppServer session, then the ProDataSet is always copied back to the client from the server. Given this expectation, the way you have set up the server procedure is entirely appropriate.
However, you also want to code your procedures so that even when they are all run in the same session, even if only for initial testing purposes, they run correctly. Because ProDataSets are passed by value by default, the default behavior in a strictly local situation is also correct. The potential problem lies in the fact that orderSupport.p depends on the ProDataSet always being passed by value.
The following figure shows what happens if the client procedure in the same session decides to ask for the OUTPUT DATASET dsOrder BY-REFERENCE.
Figure 13. ProDataSet in an AppServer session
The following describes the execution flow in the above figure:
1. The SET-CALLBACK-PROCEDURE methods still act on the ProDataSet instance in orderSupport.p.
2. When the window procedure runs fetchOrders locally with the ProDataSet passed BY-REFERENCE, it is forcing the support procedure to use its instance of dsOrder in order to avoid copying the ProDataSet back.
3. Because the AVM adjusts the parameter reference to dsOrder in fetchOrders to point to the ProDataSet in the caller, the FILL is done relative to the ProDataSet in the window procedure PickOrder.w.
4. Unfortunately, the callback procedures are still attached to the (now unused) ProDataSet instance in orderSupport.p. Therefore they do not run when the FILL happens because the FILL is on a different instance of the ProDataSet.
5. When fetchOrders returns, it does not copy anything back to PickOrder.w because the BY-REFERENCE qualifier tells the AVM to use the caller's instance of the ProDataSet. Because the fill events never fire to prepare the query and attach the Data-Sources, nothing happened and there is no data on the client.
The design of orderSupport.p in this case requires that the ProDataSet be passed by value. For this reason, you can assure that the calls will be made properly by forcing the parameter to be passed by value by using the BY-VALUE keyword on the parameter definition in the called procedure. Then everything works properly even if a local caller tries to use BY-REFERENCE. The qualifier is simply overridden by the definition in the called procedure, without error.
As with the earlier discussion about when and how to use BY-REFERENCE, the implications of its use can seem confusing. The best guideline is to pass ProDataSets BY-REFERENCE when you expect that the procedure call will always, or at least sometimes, be made locally (within the same session) in the deployed application (where performance counts), and when you have structured your procedures such that you will not have references to the wrong ProDataSet instance, as could happen in the second example here. Passing a ProDataSet BY-REFERENCE can be a valuable optimization, but it is only an optimization, and you must always make sure that sharing the same ProDataSet instance will not have unintended consequences.
Now, let us return to completing the example.