RUN statement options for remote procedures
- Last Updated: January 27, 2016
- 5 minute read
- OpenEdge
- Version 13.0
- Documentation
You can use various options on the RUN statement to execute
remote procedures:
- Run a synchronous external procedure, using the
ON[SERVER] handle-variable [TRANSACTION DISTINCT]option, as shown:DEFINE VARIABLE hAppSrv AS HANDLE NO-UNDO. CREATE SERVER hAppSrv. hAppSrv:CONNECT(...). . . . RUN order.p ON SERVER hAppSrv TRANSACTION DISTINCT.With a small change, this example can execute a remote procedure or a local procedure, depending on whether
hAppSrvcontains a server handle value or the value of theSESSIONsystem handle. Thus, with the same statement, you can run order.p remotely (with a server handle) or locally (with theSESSIONhandle), and determine the choice at run time, as shown:DEFINE VARIABLE hAppSrv AS HANDLE NO-UNDO. CREATE SERVER hAppSrv. IF NOT hAppSrv:CONNECT(...) THEN hAppSrv = SESSION. . . . RUN order.p ON SERVER hAppSrv. - Run a remote persistent procedure, using the
ON SERVERandPERSISTENT SEThandle-variable options, as shown:DEFINE VARIABLE hAppSrv AS HANDLE NO-UNDO. DEFINE VARIABLE hOrder AS HANDLE NO-UNDO. CREATE SERVER hAppSrv. hAppSrv:CONNECT(...). . . . RUN order.p PERSISTENT SET hOrderON SERVER hAppSrv TRANSACTION DISTINCT.A synchronous remote persistent procedure executes similarly to the same persistent procedure run locally. The server session creates the context for the persistent procedure as it starts to execute, and that context persists after it returns until the end of the client connection or until the persistent procedure is explicitly deleted (see Deleting remote persistent procedures.) Once a remote persistent procedure context is instantiated, you can execute any remote internal procedure or user-defined function that is defined within that remote persistent procedure.
The execution context for a remote persistent procedure is managed almost exclusively within the server session where the persistent procedure is instantiated. However, the persistent procedure handle (
hOrderin the example), as a proxy procedure handle, provides some additional access to the remote context from the client, allowing the client to delete the persistent procedure remotely. For more information on proxy procedure handles, see Understanding proxy procedure handles. - Run a remote external procedure over a session-free or
unbound session-managed connection, using the
ON SERVERoption and eitherSINGLE-RUN SEThandle-variable (as shown below) orSINGLETON SEThandle-variableDEFINE VARIABLE hAppSrv AS HANDLE NO-UNDO. DEFINE VARIABLE serverHandle AS HANDLE NO-UNDO. CREATE SERVER hAppSrv. serverHandle:CONNECT(...). . . . RUN aproc.p SINGLE-RUN SET procHandle ON SERVER serverHandle. RUN internalProcA IN procHandle (INPUT argIn1, OUTPUT argout1). RUN internalProcB IN procHandle. (INPUT argin2, OUTPUT argout2). DELETE PROCEDURE procHandle.Although the preceding example illustrates the use of the
SINGLE-RUNoption,SINGLETONcan be substituted with no other syntax differences. The purpose of both options is to allow the client to access internal procedures and user-defined functions found in the specified external procedure, without causing the client to be bound to the server session as it is whenRUN PERSISTENTis used. Single-run and singleton operations offer the potential for greater server throughput (since the lack of binding increases the availability of sessions) and improved application performance (because the number of messages that the client must send to the PAS for OpenEdge instance is minimized).In the case of both
SINGLE-RUNandSINGLETON, the remote external procedure is not instantiated, and no message is sent to the server, until the first internal procedure or user-defined function is called (RUN internal procAin the preceding example). On each such call to an internal procedure or user-defined function, the client session sends the server a message with the names of both the external procedure and the internal procedure or function; these are the only messages generated. Note that if server access is being controlled by a PAS for OpenEdge export list, procedures run using theSINGLE-RUNandSINGLETONoptions should be added using theEXPORT( )method. See Controlling PAS for OpenEdge entry points for more information.The difference between
SINGLE-RUNandSINGLETONlies in how the client session deals with the remote external procedure instance(s) created on the server. In the single-run case, a new instance of the external procedure is created with each call into that procedure, and the instance is deleted after execution of the call. In the singleton case, once the external procedure is instantiated in a server session on the first call to an internal procedure or user-defined function, that instance remains in session memory until it is explicitly deleted or the session ends. This singleton instance is used for all subsequent calls into the remote procedure running in this server session, whether the calls come from the client that originally caused the instantiation or from a different client.The following restrictions apply to the use of theSINGLE-RUNandSINGLETONoptions:- The remote external procedure
cannot run asynchronously; the use of the
ASYNCHRONOUSoption with theSINGLE-RUNorSINGLETONoption raises an error. However, its internal procedures can run asynchronously. - The external procedure cannot have input or output parameters.
DELETE PROCEDUREonly deletes the proxy handle on the client for a procedure run with theSINGLE-RUNorSINGLETONoption. This is because a single-run procedure is deleted automatically by the session when the request completes, and a singleton procedure can be running on more than one server session where it is separately instantiated, and where it can be deleted using ABL code running in the session.
- The remote external procedure
cannot run asynchronously; the use of the
- Run a synchronous internal procedure or user-defined
function using the
INhandle-variable option, as shown:DEFINE VARIABLE hAppSrv AS HANDLE NO-UNDO. DEFINE VARIABLE hProc AS HANDLE NO-UNDO. FUNCTION fnOrders RETURNS LOGICAL IN hProc. CREATE SERVER hAppSrv. hAppSrv:CONNECT(...). RUN order.p PERSISTENT SET hProc ON SERVER hAppSrv TRANSACTION DISTINCT. . . . RUN GetOrders IN hProc. IF fnOrders THEN DISPLAY "Orders Found!"In this example, both the
GetOrdersprocedure andfnOrdersuser-defined function are defined in the remote persistent procedure specified by the proxy procedure handle,hProc.For session-free and unbound session-managed connections, the same functionality is available by using the
INhandle-variable option withRUN SINGLE-RUNorRUN SINGLETON (provided the external procedure associated with handle-variable does not have parameters). These options are preferable toRUN PERSISTENTbecause they do not bind the client to the server session executing the request.Note that running a synchronous remote internal procedure or invoking a remote user-defined function is syntactically identical to running it locally. OpenEdge automatically determines the right server connection and remote procedure or function to execute from the specified proxy procedure handle.
- Pass
INPUT,OUTPUT, andINPUT-OUTPUTvariable,TEMP-TABLE, or ProDataSet parameters, but notBUFFERparameters. - Run a procedure (internal or external) asynchronously,
using the
ASYNCHRONOUSoption, as shown:DEFINE VARIABLE hAppSrv AS HANDLE NO-UNDO. DEFINE VARIABLE hAsync AS HANDLE NO-UNDO. DEFINE VARIABLE hAsync2 AS HANDLE NO-UNDO. DEFINE VARIABLE hProc AS HANDLE NO-UNDO. DEFINE TEMP-TABLE ttOrder... FUNCTION fnHighVolume RETURNS LOGICAL IN hProc. CREATE SERVER hAppSrv. hAppSrv:CONNECT(...). RUN order.p PERSISTENT SET hProc ON SERVER hAppSrv TRANSACTION DISTINCT ASYNCHRONOUS SET hAsync. DO WHILE NOT hAsync:COMPLETE: PROCESS EVENTS. IF hAsync:COMPLETE THEN RUN GetOrders IN hProc ASYNCHRONOUS SET hAsync2 EVENT-PROCEDURE GetOrderRecords IN THIS-PROCEDURE (INPUT-OUTPUT TABLE ttOrder). ELSE /* Order module not ready, so work on other stuff while waiting. */ . . . END. WAIT-FOR CLOSE OF THIS-PROCEDURE. PROCEDURE GetOrderRecords: DEFINE INPUT PARAMETER TABLE FOR ttOrder. DEFINE VARIABLE lSee AS LOGICAL NO-UNDO. IF fnHighVolume THEN DISPLAY "Orders > 100: Call in extra help!". MESSAGE "Do you want to see the orders?" UPDATE lSee. IF lSee THEN ... /* Display ttOrder. */ RETURN. END.This example asynchronously instantiates a remote persistent procedure, order.p, and when available, asynchronously calls the
GetOrdersremote internal procedure defined in order.p to return aTEMP-TABLEparameter with order information. While waiting for the persistent procedure, order.p, to become available, the procedure does an unspecified amount of work. This part of the example is procedural, using thePROCESS EVENTSstatement to handle thePROCEDURE-COMPLETEevent each time through the loop. The status of the request is checked by testing theCOMPLETEattribute of the asynchronous request handle (hAsync).After the example runs
GetOrdersasynchronously, the example blocks using theWAIT-FORstatement to handle thePROCEDURE-COMPLETEevent for theGetOrdersrequest. WhenGetOrderscompletes, the associated event procedure,GetOrderRecords, executes.GetOrderRecordsreturns theTEMP-TABLEparameter and executes the remote user-defined functionfnHighVolume(also defined in order.p) to provide warning of heavy order traffic. Note that the remote user-defined function is (and can only be) called synchronously.Note: An external procedure called withRUN SINGLE-RUNorRUN SINGLETONcannot run asynchronously. That is, including theASYNCHRONOUSoption withSINGLE-RUNorSINGLETONraises an error. However, internal procedures defined in a single-run or singleton procedure can run asynchronously. The syntax shown in the preceding example for asynchronously runningGetOrdersis also valid in the context of a single-run or singleton procedure.Clearly, the handling of asynchronous requests is more complex than for synchronous requests. While this example is partly procedural, you typically handle all asynchronous requests in an event-driven context using a blocking I/O statement, such as the
WAIT-FORstatement. For more information on how to manage asynchronous requests, see Managing asynchronous requests.However, note that you cannot use compile-time (preprocessor) arguments when running a remote procedure.