Progress
Language Reference


RUN Statement

Interfaces
OS
SpeedScript
All
All
Yes

Calls a Progress procedure. This procedure can be local to or remote from the current session, external from or internal to the current procedure, and either synchronous or asynchronous. When a local or remote procedure is called synchronously, the calling procedure resumes execution only after the called procedure completes execution. When a remote procedure is called asynchronously, the calling procedure resumes execution immediately after the remote request is sent to the AppServer.

The RUN statement can also call functions or routines that reside in the Windows Dynamic Link Libraries (DLLs) or in UNIX shared libraries. The called routine must first be declared like a Progress internal procedure. The procedure declaration must be in the same file as the RUN statement.

SYNTAX

RUN
  {     extern-proc-name
     |  VALUE ( extern-expression )
     |  path-name<<member-name>>
  }
  [ PERSISTENT [ SET proc-handle ] ]
  [ ON [ SERVER ] { server-handle | session-handle }
       [ TRANSACTION DISTINCT ]
       [ ASYNCHRONOUS 
            [ SET async-request-handle ]
            [ EVENT-PROCEDURE event-internal-procedure
                 [ IN procedure-context ] ]
       ]
  ]
  [ ( parameter [ , parameter ] ... ) ]
  [ argument ] ...
  [ NO-ERROR ] 

RUN
  { intern-proc-name | VALUE ( intern-expression) } 
  [ IN proc-handle ]
  [ ASYNCHRONOUS
       [ SET async-request-handle ]
       [ EVENT-PROCEDURE event-internal-procedure
           [ IN procedure-context ] ]
  ]
  [ ( parameter [ , parameter ] ... ) ]
  [ NO-ERROR ] 

extern-proc-name

The name of the (local or remote) external procedure to run. On UNIX, external procedure names are case sensitive; on Windows, they are not. If you specify a relative pathname, Progress searches the directories (and libraries, on platforms that support libraries) defined in the PROPATH environment variable. With extern-proc-name, you can specify a local or remote procedure.

VALUE ( extern-expression )

An expression that returns the name of the (local or remote) external procedure you want to run.

path-name<<member-name>>

The pathname of an r-code library and the name of an r-code file in that library. To specify an r-code file in a library, you must use the double angle brackets as shown. If you specify a relative library pathname, Progress searches the libraries defined in the PROPATH environment variable.

PERSISTENT [SET proc-handle ]

Specifies that the external procedure be run and created (instantiated) as a persistent procedure. You can return the handle to the persistent procedure in proc-handle , a field, variable, or output parameter defined with the HANDLE data type. If you do not specify proc-handle , you can find the procedure handle for this procedure using the FIRST-PROCEDURE and LAST-PROCEDURE attributes of the SESSION system handle. You can use PERSIST as an abbreviation for PERSISTENT.

A persistent procedure creates and maintains its context after it returns to the caller. Other external procedures can access this context through procedure triggers and internal procedures defined in the persistent procedure. Thus, a RUN statement that runs and creates a persistent procedure context is referred to as an instantiating RUN statement.

The order of the PERSISTENT option and the ON SERVER option is interchangeable.

ON [SERVER] server-handle

Tells Progress to run the procedure remotely in the Progress AppServer that the HANDLE variable, server-handle, refers to.

With the ASYNCHRONOUS option, server-handle causes the called procedure to run asynchronously in the remote session. Control returns immediately to the statement following the RUN statement. Execution of any specified event-internal-procedure. occurs in the context of an I/O blocking or PROCESS EVENTS statement.

The order of the PERSISTENT option and the ON SERVER option is interchangeable.

ON [SERVER] session-handle

Tells Progress to run the procedure locally in the current Progress session, specified by the value of the SESSION system handle (session-handle).

With the ASYNCHRONOUS option, session-handle causes the called procedure to run synchronously in the local session, followed immediately by execution of any specified event-internal-procedure. Only after execution of the specified event-internal-procedure does control return to the statement following the RUN statement.

NOTE: This order of execution is different than for a remote procedure call using the server-handle.

The order of the PERSISTENT option and the ON SERVER option is interchangeable.

TRANSACTION DISTINCT

Tells Progress not to propagate the calling procedure’s transaction to the Progress AppServer. Although the current version of Progress does not allow transaction propagation, future versions might. Thus, to accommodate this possibility without breaking current code, the current version of Progress allows you to specify this option with server-handle.

NOTE: It is an error to specify TRANSACTION DISTINCT with a session-handle.

ASYNCHRONOUS [ SET async-request-handle ]

Specifies that the remote procedure is to be called as an asynchronous request. By default, the remote procedure is called synchronously. The handle to the asynchronous request is returned in async-request-handle, which must be a field, variable, or parameter defined with the HANDLE data type. If you specify ASYNCHRONOUS but do not specify SET async-request-handle, you can find the handle for the asynchronous request using the LAST-ASYNC-REQUEST attribute of the server-handle specified by the ON option. You can also locate the asynchronous request handle by walking the chain between the FIRST-ASYNC-REQUEST and LAST-ASYNC-REQUEST attributes of server-handle, searching on the PROCEDURE-NAME attribute of each request handle.

EVENT-PROCEDURE event-internal-procedure

Specifies a quoted string or character expression representing the name of an internal procedure that resides within procedure-context. When the response from the asynchronous request is received (that is, a PROCEDURE-COMPLETE event occurs), the specified internal procedure is called during subsequent execution of a PROCESS EVENTS or I/O-blocking statement (such as WAIT-FOR). The specified event-internal-procedure processes any parameters and errors returned from the asynchronous request. If not specified, no event procedure is executed when the PROCEDURE-COMPLETE event occurs for the asynchronous request.

For information on how the event-internal-procedure handles parameters from the asynchronous request, see the parameter option. For information on how the event-internal-procedure handles errors from the asynchronous request, see the NO-ERROR option.

IN procedure-context

A handle to an active procedure that contains the internal procedure specified by event-internal-procedure. If not specified, THIS-PROCEDURE is used as the procedure-context value.

parameter

A run-time parameter to pass to the called procedure. This is the syntax for parameter.

SYNTAX
[ INPUT ] { expression | TABLE temp-table-name |
        TABLE-HANDLE temp-table-handle } 

OUTPUT
  {     field
     |  variable
     |  TABLE temp-table-name [ APPEND ]
     |  TABLE-HANDLE temp-table-handle [ APPEND ]
     |  param-name AS data-type
  } 

INPUT-OUTPUT
  {     field
     |  variable
     |  TABLE temp-table-name [ APPEND ]
     |  TABLE-HANDLE temp-table-handle [ APPEND ]
  } 

BUFFER buffer 

An expression is a constant, field name, variable name, or expression. A temp-table is the name of a temporary table. Progress assumes INPUT if you do not supply a keyword. OUTPUT and INPUT-OUTPUT parameters must be record fields, program variables, temporary tables or temporary table handles.

APPEND determines whether or not to append the traveling temporary table data to the stationary temporary table data.

FOR temp-table-handle APPEND is used only with the DEFINE INPUT PARAMETER statement. To APPEND output parameter data, the APPEND keyword is added to the RUN statement.

You can pass temporary table and temp-table handle parameters to both local and remote procedures. For more information on temporary table parameters, see the Progress Programming Handbook .

Parameters must be defined in the called procedure. (See the DEFINE PARAMETER Statement reference entry.) They must be passed in the same order as they are defined, and they must have compatible data types. Progress attempts to convert values for data types that do not match. If Progress cannot convert the value for a mismatched data type, the RUN statement fails with an error condition.

For OUTPUT parameters of an asynchronous remote procedure call only, you can specify param-name AS data-type as a prototype. The param-name is an arbitrary place-holder name and data-type must specify the Progress data type of the corresponding OUTPUT parameter in the asynchronous remote procedure. You can also specify OUTPUT parameters for an asynchronous remote procedure using a local field, variable, or TABLE temp-table-name. However, note that the asynchronous remote procedure does not return any values to OUTPUT or INPUT-OUTPUT parameters on the RUN statement. These parameters are place holders only for values returned by the remote procedure to the specified event-internal-procedure.

Any specified event-internal-procedure can define only INPUT parameters and must define one INPUT parameter for each OUTPUT or INPUT-OUTPUT parameter defined in the asynchronous remote procedure. Each event-internal-procedure INPUT parameter must match the corresponding remote procedure OUTPUT or INPUT-OUTPUT parameter in order and data type. (As with other procedures, Progress attempts to convert the values for data types that do not match.) The asynchronous remote procedure returns the values of these parameters to the INPUT parameters of the event-internal-procedure after the remote procedure completes execution and the client session processes the associated PROCEDURE-COMPLETE event.

You cannot pass BUFFER parameters to a remote procedure. However, you can pass temp-table (TABLE and TABLE-HANDLE) parameters to a remote procedure.

If you are running an internal procedure declared as a Windows dynamic link library (DLL) or UNIX shared library routine, you must match any RETURN parameter specified by a DEFINE PARAMETER statement with a corresponding OUTPUT parameter in the RUN statement. If the internal procedure does not specify the RETURN parameter, do not specify the corresponding OUTPUT parameter in the RUN statement.

Note that for external procedures, the parenthesized list of run-time parameters must precede any compile-time arguments.

argument

A constant, field name, variable name, or expression that you want to pass as a compile-time argument to the external procedure you are running.

When you pass arguments to an external procedure, Progress converts those arguments to character format. Progress recompiles the called procedure, substitutes arguments, and then runs the procedure. You cannot precompile a procedure to which you pass arguments. (If you use shared variables instead of arguments, the procedure can be precompiled. This yields more efficient code.)

Note that you cannot pass compile-time arguments in a call to an internal procedure.

NO-ERROR

Specifies that any ERROR conditions that occur in the attempt to run the procedure are suppressed. This does not mean that all errors produced by the called procedure are suppressed; only errors caused by the RUN statement itself. Also, if a specified local or synchronous remote procedure performs a RETURN ERROR, an ERROR is raised for the RUN statement. After the RUN statement completes, you can check the ERROR-STATUS system handle for information on any errors that occurred.

For an asynchronous remote procedure, the result depends on where the errors occur. If the errors occur during the send phase of the asynchronous request, this raises the ERROR condition on the RUN statement in the client (which you can suppress with NO-ERROR). If the errors occur during execution of the remote request and are returned by the AppServer, this results in an implied NO-ERROR on the RUN statement, and you must check the ERROR-STATUS system handle as well as the attributes of the asynchronous request handle (async-request-handle) for any error returns in the specified event-internal-procedure. If the asynchronous remote procedure returns an unhandled STOP condition, ERROR-STATUS:ERROR and async-request-handle:ERROR are both set to FALSE and async-request-handle:STOP is set to TRUE.

The RUN statement returns ERROR or STOP for a variety of events depending on the type of procedure that is executed:

intern-proc-name

The name of the (local or remote) internal procedure you want to run. The procedure must be declared in the same procedure file as the RUN statement that calls it unless you specify the IN proc-handle option or use a super procedure. If you do not specify the IN proc-handle option and there is no internal procedure declared by the specified name, Progress tries to run an external procedure with the specified name. If the internal procedure is remote, you must specify the IN proc-handle option to identify the remote persistent procedure that defines the internal procedure on a Progress AppServer.

VALUE ( intern-expression )

An expression that evaluates to the name of the internal procedure you want to run.

IN proc-handle

Specifies the handle of the external procedure that declares the internal procedure you want to run. You can specify proc-handle as a field, variable, parameter, or expression that specifies a valid procedure handle or proxy (remote) persistent procedure handle.

EXAMPLES

The following procedure displays a simple menu. The user’s selection is stored in the selection variable. The INDEX function returns an integer value that indicates the position of the user’s selection in a string of characters ("12345"). If the value in the selection variable is not in the list of values, the INDEX function returns a 0. The VALIDATE statement ensures that the INDEX function did not return a zero. If it did, VALIDATE displays the message “Not a valid choice.”

r-run.p
DEFINE VARIABLE selection AS CHARACTER
LABEL "Enter Program Choice" FORMAT "x(1)".
DEFINE VARIABLE programs AS CHARACTER 
FORMAT "x(15)" EXTENT 5.

/* Create the procedures custrpt.p, custedit.p, ordrpt.p, and ordedit.p.*/
programs[1] = "custrpt.p".
programs[2] = "custedit.p".
programs[3] = "ordrpt.p".
programs[4] = "ordedit.p".
programs[5] = "r-exit.p".

REPEAT:
  FORM HEADER TODAY "MASTER MENU" AT 35 STRING(TIME,"hh:mm") to 79.
  FORM SKIP(3)
   "1 - Customer Listing"  AT 30
   "2 - Customer Update" AT 30
   "3 - Order Listing"  AT 30
   "4 - Order Update"   AT 30
   "5 - Quit System"    AT 30
   selection COLON 28 AUTO-RETURN WITH SIDE-LABELS NO-BOX 1 DOWN.    

UPDATE selection
  VALIDATE(INDEX("12345",selection) NE 0,
      "Not a valid choice").
  HIDE ALL.
  RUN VALUE(programs[INDEX("12345",selection)]).
END. 

In the RUN statement, the INDEX function returns the position of the user’s selection in a character string. Suppose you chose option 2 from the menu. That option occupies the second position in the "12345" character string. Therefore, the INDEX function returns the number two (2). Using this number, the RUN statement reads, RUN VALUE(programs[2]). According to the assignments at the top of the procedure, the value of programs[2] is custedit.p. Now the RUN statement reads, RUN custedit.p, and the r-run.p procedure runs the custedit.p procedure.

The following two external procedures, r-runper.p and r-perprc.p, illustrate the PERSISTENT and IN proc-handle options of the RUN statement. The first procedure, a non-persistent control procedure, sets up a window to run and manage the second procedure as a persistent procedure.

r-runper.p 
DEFINE VARIABLE phand AS HANDLE.
DEFINE VARIABLE nhand AS HANDLE.
DEFINE VARIABLE whand AS WIDGET-HANDLE.
DEFINE BUTTON bStart LABEL "Start Customer Query".
DEFINE BUTTON bRecall LABEL "Recall All Hidden Queries".
DEFINE BUTTON bExit LABEL "Exit".
DEFINE FRAME ControlFrame SKIP (.5) 
    SPACE (2) bStart bRecall bExit SPACE (2) SKIP (.5).

ON CHOOSE OF bStart IN FRAME ControlFrame RUN r-perprc.p PERSISTENT.

ON CHOOSE OF bRecall IN FRAME ControlFrame DO:
    phand = SESSION:FIRST-PROCEDURE.
    DO WHILE VALID-HANDLE(phand):
        IF phand:PRIVATE-DATA = "Customer Browse" THEN
            RUN recall-query IN phand.
        phand = phand:NEXT-SIBLING.
    END.
END.

ON CHOOSE OF bExit IN FRAME ControlFrame DO:
    phand = SESSION:FIRST-PROCEDURE.
    DO WHILE VALID-HANDLE(phand):
        nhand = phand:NEXT-SIBLING.
        IF phand:PRIVATE-DATA = "Customer Browse" THEN
            RUN destroy-query IN phand.
        phand = nhand.
    END.
    APPLY "RETURN" TO THIS-PROCEDURE.
END.

SESSION:SYSTEM-ALERT-BOXES = TRUE.
CREATE WINDOW whand
    ASSIGN
        TITLE = "Customer Query Control"
        SCROLL-BARS = FALSE
        MESSAGE-AREA = FALSE
        MAX-HEIGHT-CHARS = FRAME ControlFrame:HEIGHT-CHARS
        MAX-WIDTH-CHARS = FRAME ControlFrame:WIDTH-CHARS.
CURRENT-WINDOW = whand.
ENABLE ALL WITH FRAME ControlFrame.
WAIT-FOR RETURN OF THIS-PROCEDURE. 

r-perprc.p
DEFINE QUERY custq FOR customer.
DEFINE BROWSE custb QUERY custq
    DISPLAY name balance credit-limit phone WITH 10 DOWN.
DEFINE BUTTON bName LABEL "Query on Name".
DEFINE BUTTON bBalance LABEL "Query on Balance".
DEFINE BUTTON bCredit LABEL "Query on Credit".
DEFINE BUTTON bHide LABEL "Hide Query".
DEFINE BUTTON bCancel LABEL "Cancel".

DEFINE FRAME CustFrame custb SKIP
    bName bBalance bCredit bHide bCancel.
    
DEFINE VARIABLE custwin AS WIDGET-HANDLE.

ON CHOOSE OF bName IN FRAME CustFrame DO:
    custwin:TITLE = "Customers by Name".
    OPEN QUERY custq FOR EACH customer BY name.
END.        

ON CHOOSE OF bBalance IN FRAME CustFrame DO:
    custwin:TITLE = "Customers by Balance".
    OPEN QUERY custq FOR EACH customer BY balance DESCENDING.
END.  

ON CHOOSE OF bCredit IN FRAME CustFrame DO:
    custwin:TITLE = "Customers by Credit".
    OPEN QUERY custq FOR EACH customer BY credit-limit DESCENDING.
END.  

ON VALUE-CHANGED OF BROWSE custb DO:
    IF customer.balance >= (customer.credit-limit * 0.75) THEN DO:
        BELL.
        MESSAGE "Evaluate" customer.name "for credit increase.".
    END.
END.

IF THIS-PROCEDURE:PERSISTENT THEN DO:
    THIS-PROCEDURE:PRIVATE-DATA = "Customer Browse".
    CREATE WIDGET-POOL.
END.

CREATE WINDOW custwin
    ASSIGN
        TITLE = "Customer Browser"
        SCROLL-BARS = FALSE
        MAX-HEIGHT-CHARS = FRAME CustFrame:HEIGHT-CHARS
        MAX-WIDTH-CHARS = FRAME CustFrame:WIDTH-CHARS. 
THIS-PROCEDURE:CURRENT-WINDOW = custwin.

ENABLE ALL WITH FRAME CustFrame.

IF THIS-PROCEDURE:PERSISTENT THEN DO:
    ON CHOOSE OF bCancel IN FRAME CustFrame DO:
        RUN destroy-query.
    END.
    ON CHOOSE OF bHide IN FRAME CustFrame DO:
        custwin:VISIBLE = FALSE.
    END.
END.
ELSE DO: 
    WAIT-FOR CHOOSE OF bHide, bCancel IN FRAME CustFrame.
END.

PROCEDURE recall-query:
    custwin:VISIBLE = TRUE.
END.

PROCEDURE destroy-query:
    DELETE PROCEDURE THIS-PROCEDURE NO-ERROR.
    DELETE WIDGET-POOL.
END. 

The control procedure, r-runper.p, runs r-perprc.p each time you choose the Start Customer Query button. Each time it runs, r-perprc.p creates (instantiates) an additional context instance for the persistent procedure, including an additional window to open customer queries. When you choose the Recall All Hidden Queries button from the control window, r-runper.p calls the recall-query internal procedure in each instance of r-perprc.p to redisplay its window. Similarly, when you choose the Exit button, r-runper.p calls the destroy-query internal procedure in each instance of r-perprc.p to delete its context instance; r-runper.p then applies the RETURN event to itself to terminate by completing the WAIT-FOR statement.

The r-perprc.p procedure sets up a customer query that you can re-open three different ways: by name, by balance ,or by credit. Each instance of r-perprc.p maintains a separate query for its own local customer buffer. Note that by testing and setting attributes of the THIS-PROCEDURE system handle, r-perprc.p can run either persistently or non-persistently. The basic difference is how the procedure maintains its own context. For example, when running persistently, it defines a trigger on the bCancel button to run its own deletion procedure, destroy-query, to terminate; when running non-persistently, it completes a WAIT-FOR statement with the bCancel button to terminate.

The following example shows how you might implement an asynchronous request. The procedure r-async.p runs persistently from a user-interface trigger, perhaps in response to a menu choice. This procedure, in turn, sends a request to run runReport.p on an AppServer, which provides an inventory report for the specified date.

When r-async.p returns, the user-interface trigger ends and the application returns to its WAIT-FOR state. The user continues to use the application in the normal way while the inventory report runs on the AppServer.

When runReport.p finishes running, a PROCEDURE-COMPLETE event occurs. This event causes the internal procedure reportDone to run automatically within the context of the application’s WAIT-FOR statement. Whatever the user is doing in the application, reportDone displays an alert box indicating whether or not the inventory report completed successfully and the number of lines (numLines) that were output for the report. (The bolded 4GL indicates the code required to support asynchronous requests to run runReport.p.)

r-async.p 
DEFINE INPUT PARAMETER invDate AS DATE. 
DEFINE VAR sh AS WIDGET-HANDLE. /* Server handle */
DEFINE VAR ah AS WIDGET-HANDLE. /* Asynchronous request handle */

CREATE SERVER sh.
sh:CONNECT("-AppService Inventory -H myhost").
RUN runReport.p 
    ON SERVER sh 
    ASYNCHRONOUS SET ah EVENT-PROCEDURE "reportDone" IN THIS-PROCEDURE
    (invDate, OUTPUT numLines AS INT).
RETURN.

PROCEDURE reportDone:
    DEFINE INPUT PARAMETER numLines AS INT.
    IF ah:ERROR OR ah:STOP THEN DO:
        MESSAGE "An error occurred when running your" SKIP
                "Inventory report for " invDate "." SKIP
                "The error is: " ERROR-STATUS:GET-MESSAGE(1)
                VIEW-AS ALERT-BOX.
    END.
    ELSE DO:
        MESSAGE "Your Inventory report for " invDate SKIP
                "has completed successfully." SKIP
                numLines " report lines were generated"
                VIEW-AS ALERT-BOX.
    END.
    sh:DISCONNECT().
    DELETE OBJECT sh.
    DELETE OBJECT THIS-PROCEDURE. /* Persistent proc no longer needed */
END. 

NOTES

SEE ALSO

{ } Argument Reference, { } Include File Reference, APPLY Statement, Asynchronous Request Object Handle, CODEBASE-LOCATOR System Handle, COMPILE Statement, CREATE SERVER Statement, DEFINE PARAMETER Statement, DELETE PROCEDURE Statement, ON Statement, PROCEDURE Statement, RUN STORED-PROCEDURE Statement, THIS-PROCEDURE System Handle, VALID-HANDLE Function, Widget Phrase


Copyright © 2004 Progress Software Corporation
www.progress.com
Voice: (781) 280-4000
Fax: (781) 280-4095