Interaction between Compute Services and Macro Processing

Macro-Generated RSUBMIT Blocks

Macros are compiled into macro program statements by the macro processor. A macro-generated RSUBMIT refers to an RSUBMIT/ENDRSUBMIT statement block that is contained within a macro definition. Here is the general structure of this block:
/* begin container macro */
%MACRO macro-name;
RSUBMIT;
  statements
ENDRSUBMIT;
%mend macro-name;
/* end container macro */
%macro-name
Macro processing within a macro-generated RSUBMIT might not always produce the results that you expect. Here are the types of statements that can be included in a macro-generated RSUBMIT/ENDRSUBMIT statement block:
  • macro definition
  • SAS statements that are not macro statements or macro definitions
  • macro statements
Only the macro definition statement and the SAS statement are always executed in the server session. Macro statements can be resolved and executed in the client session rather than in the server session.
For a macro-generated RSUBMIT block, include both the RSUBMIT and ENDRSUBMIT statements in the macro. A statement-style macro is inappropriate when including only the RSUBMIT statement in the macro definition. For details about statement-style macros, see SAS Macro Language: Reference.

Macro Definitions

When the macro processor encounters a macro definition in a macro-generated RSUBMIT statement, all the statements that follow the %MACRO statement are compiled into macro program statements until a %MEND statement is compiled. Then, the embedded macro definition is submitted remotely to the server session, and the macro is defined in the server session when the "container" macro is invoked.

SAS Statements That Are Not Macros or Macro Definitions

When the macro processor encounters statements that are not macro definitions or macro statements, such as SAS procedure statements or DATA steps, in a macro-generated RSUBMIT statement, these statements are compiled into macro program statements. When the macro is executed, these statements are submitted remotely to the server session for execution.

Macro Statements

Macro statements that you include in a macro-generated RSUBMIT statement might get resolved and executed in the client session rather than in the server session, regardless of your including the statements in an RSUBMIT/ENDRSUBMIT statement block. The macro processor in the client session resolves variables that are specified in the following statements:
  • %DO
  • %IF
  • %LET
  • %PUT
  • %SYSRPUT
The macro processor also compiles the variables into macro program statements, which the container macro executes in the client session. If you do not want the statements to execute in the client session, you can use various programming techniques to control the location where the statements execute.

Ensuring That the RSUBMIT Statements Are Executed in the Correct Session

Programming Techniques

To avoid possible macro processing confusion, you can use specific programming techniques to ensure that macro statements are processed in the server session or in the client session, whichever you choose.

%SYSLPUT Statement

To assign a value to a macro variable in a server session, use the %SYSLPUT macro statement. Using the %SYSLPUT statement to define a macro variable and then using a macro variable in the server session is better than attempting to remotely submit a %LET macro statement. Here is the syntax of the %SYSLPUT statement:
%SYSLPUT macvar = value</REMOTE=session-ID>;
Example:
%syslput remvar1=%sysfunc(date(),date9.);
The client session evaluates the value that is assigned to the server session macro variable REMVAR1. If the macro variable REMVAR1 does not exist, it is created. Using %SYSLPUT prevents the macro processor from interpreting a %LET statement that is in the macro-generated RSUBMIT statement in the client session.

%NRSTR Macro Quoting Function

If a special character or a mnemonic affects the way the macro processor constructs macro program statements, use the %NRSTR macro quoting function to mask the item during macro compilation (or during the compilation of a macro program statement in open code). %NRSTR can be used to mask the macro statements, which causes the macro processor to ignore the macro program statements in the client session and forces the macro statements to be executed in the server session.
Here is the syntax for the %NRSTR quoting function when used with a macro statement:
%NRSTR (%%) macro-statement;
Example:
%nrstr(%%)put abc=&abc one=&one time=&time;
%NRSTR prevents the macro processor from interpreting a macro statement that is in the RSUBMIT statement in the client session. %NRSTR causes the macro statement to be interpreted and executed in the server session. For details about macros, see SAS Macro Language: Reference.

Comment Delimiters to Disable or Enable SAS/CONNECT Executions

Instead of writing a macro that conditionally executes code using an RSUBMIT/ENDRSUBMIT block or a SIGNON statement, you can use simple macro variables and statements that insert or remove the comment delimiters - /* */ - from the RSUBMIT/ENDRSUBMIT block or the SIGNON statement. Using a simple macro to manage comment delimiters in code is an easy programming technique that is useful in testing environments.
Here is an example that uses a macro to insert comment delimiters before the RSUBMIT, ENDRSUBMIT, and SIGNON statements that disable SAS/CONNECT.
%global star slash;
   %let star=*;
   %let slash=/;

&star rsubmit;

          data x; x=1; run;

      &slash&star  endrsubmit; /* */

      &slash&star  signoff; /* */
Here is an example that uses a macro to remove comment delimiters before the SIGNON statement that enables SAS/CONNECT.
global star slash;
   %let star=*;
   %let slash=/;

   signon runconn sascmd="!sascmd -noautoexec";
   %syslput slash=;
   %syslput star=;
You could include both versions of code in separate autoexec files in order to execute code in a SAS session or in a SAS/CONNECT server session, as necessary.

Examples

Client Session Execution: Macro Statement in RSUBMIT

/* In this macro, %LET is a macro statement that will be interpreted  */
/* by the client session and not submitted remotely.                    */
/* If REMVAR1 is not already defined in the server session,           */
/* this example will produce an error.                                */
%macro example;
%global remvar1;

rsubmit;
  data x; x=1; run;
  %let remvar1=%sysfunc(date(),date9.);
  data a; x="&remvar1"; run;
endrsubmit;

%mend;
%example;

Server Session Execution: %SYSLPUT to Mask Client Session Macro Processing

/* In this macro, the %SYSLPUT statement is used to assign a value to a   
 */
/* macro variable in the server session, to avoid having the client session */
/* macro processor interpret a %LET statement in the RSUBMIT block.         */
/* %SYSLPUT can also be issued outside the macro definition.                */

%macro example1;

%syslput remvar1=&sysfunc(date(),date9.);
rsubmit;
  data a; x="&remvar1"; run;
endrsubmit;

%mend;
%example1;

Server Session Execution: %NRSTR to Mask Client Session Macro Processing

/* In this macro, %NRSTR is used with the %LET macro statement          
*/
/* to "hide" it from the client session macro processor and allow it     */
/* to be submitted remotely.                                               */

%macro example2;

rsubmit;
   %nrstr(%%)let remvar1=%sysfunc(date(),date9.);
   data a; x="&remvar1"; run;
endrsubmit;
%mend;
%example2;

Server Session Execution: Macro Definition in an RSUBMIT Block

/* This shows a macro definition embedded in an RSUBMIT block.           
*/
/* The entire ONREMOTE macro definition is remotely submitted               */
/* and none of the statements in the ONREMOTE macro are interpreted       */
/* by the macro processor in the client session.                          */

%macro example3;

rsubmit;
  %macro onremote;
  %global abc;
     %put this is on the server;
     %let abc=value;
  %mend;
  %onremote;
endrsubmit;
%mend;
%example3;

Local Execution: %IF Allows Conditional Processing Based on Client Macro Variable

/* In this macro example, %IF is interpreted by the              */
/* macro processor in the client session in order to determine   */
/* whether to execute PROC DOWNLOAD.                             */
%macro example4;
%global localvar2;
rsubmit;
  data remds;
    x=1;
  run;
  %if &localvar2 eq getit %then %do;
     proc download;
       run;
  %end;
endrsubmit;
%mend;
%let localvar2=getit;
%example4;                    /* download occurs         */
%let localvar2=;
%example4;                    /* download does not occur */

Client and Server Session Execution: %PUT Statement Defined in Nested Macros

/* The following macro shows how embedded macros work.  The         */
/* %PUT statements indicate where the macros are defined and        */
/* where they should be invoked.                                    */
/* The macro ONREMOTE is defined to the server session because it   */
/* is in an RSUBMIT/ENDRSUBMIT block.  Therefore, its invocation    */
/* must be remotely submitted.  The macro ONLOCAL is defined to       */
/* the client session and its invocation is locally submitted.      */
%macro embeddedmacros;
rsubmit;
  %macro onremote;
    %put on the remote side;
  %mend;
endrsubmit;
%macro onlocal;
  %put on the local side;
%mend;
rsubmit;
  %onremote;
endrsubmit;
%onlocal;
%mend;

%embeddedmacros;

Server Session Execution: No Macros or Macro Statements in Macro-Generated RSUBMIT

/* This macro shows that everything in the RSUBMIT/ENDRSUBMIT block     */
/* is executed by the server session because there are no macro         */
/* statements in the macro-generated RSUBMIT to be interpreted by       */
/* the macro processor in the client session.                           */

%macro do-x;
rsubmit;

data x;
  date="04 July 03";
  put date=;
run;
endrsubmit;
%mend;
%do-x;

Server Session Execution: %NRSTR to Mask Local Macro Processing

/* This macro uses SYMPUT in an RSUBMIT, and                           */
/* uses %NRSTR to "hide" the %PUT statement from the macro processor   */
/* in the client session, so that it can be executed by the            */
/* server session.                                                     */
%macro nullds;
rsubmit;
  data _null_;
    call symput('abc','abc');
    call symput('one','1');
    call symput('date',"%sysfunc(date(),date9.)");
  run;
%nrstr(%%)put abc=&abc one=&one date=&date;
endrsubmit;
%mend;
%nullds;

Frequently Asked Questions

Will %SYSFUNC Be Evaluated in the Client Session or the Server Session?

Whether %SYSFUNC is evaluated in the client or the server session depends on how %SYSFUNC is used. If it is used in a %LET or a %PUT macro statement, %SYSFUNC is executed in the client session. However, you can use %NRSTR in your macro definition to mask the %LET and %PUT statements, which causes the %LET, %PUT, and %SYSFUNC macros to be executed in the server session. In the following example, %SYSFUNC executes in the remote session because %NRSTR is used.
%macro remotesysfunc;
  rsubmit;
    %nrstr(%%)let current="%sysfunc(time(),time.)";
    %nrstr(%%)put current=&current;
  endrsubmit;
%mend;
%remotesysfunc;
In the next example, %SYSFUNC is not part of a macro statement; it is part of the DATA step. Therefore, including it in an RSUBMIT block causes it to be executed in a server session.
%macro dssysfunc;
rsubmit;
  data x;
    time="%sysfunc(time(),time.)";
    put time=;
  run;
endrsubmit;
%mend;
%dssysfunc;

Does %SYSLPUT Affect the Current Session or All Sessions?

I don't want %SYSLPUT to affect all my sessions because I am passing an ID to my server session.
%SYSLPUT affects either the server session that is specified by using the /REMOTE= option or the current server session. The current session is the one that you have most recently accessed. You can find out which server session is current by examining the value that is specified in the CONNECTREMOTE system option, as follows:
%put %sysfunc(getoption(connectremote));
or
proc options option=connectremote;
run; 
For example, suppose the output from the %PUT statement shows unixhost, but you want to define the macro for your Windows computer winhost:
%syslput currentds=ds2008/remote=winhost;
As another example, two server sessions are created and the macro variable FLAG must be set in both sessions. The /REMOTE= option is used in the %SYSLPUT statements to direct the correct value to the correct server session.
signon task1 sascmd="sas";
signon task2 sascmd="sas";

%syslput flag=1/remote=task1;
/* NOTE: Without the /REMOTE= option in the previous statement,
the FLAG variable would be defined in the TASK2 session,
because it was the session most recently accessed with the
previous SIGNON statement. */
rsubmit task1;
  %put flag on task1 is &flag;
endrsubmit;
%syslput flag=2/remote=task2;
/* NOTE: Without the /REMOTE= option in the previous statement,
the FLAG variable would be defined in the TASK1 session,
because it was the session most recently accessed with
the previous RSUBMIT statement. */
rsubmit task2;
  %put flag on task2 is &flag
endrsubmit;

What Session Are Macro Variables Set in When Using the CALL SYMPUT Routine?

Macro variables are set in the server session when you use the CALL SYMPUT routine in a DATA _NULL_ DATA step because the DATA step CALL SYMPUT statements are not macro statements. Here is a sample macro that creates the macro variables in the server session:
%macro nullds;
rsubmit;
  data _null_;
    call symput('abc','abc');
    call symput('one','1');
    call symput('time',"%sysfunc(putn(%sysfunc(time()),time.))");
  run;
  %nrstr(%%)put abc=&abc one=&one time=&time;
 endrsubmit;
 %mend;
 %nullds;

How Do I Know What Session a Macro Is Executed In?

Why does a macro always execute in a client session but sometimes not in a server session?
Even if all the following conditions are met, a macro might not execute in the server session, as expected.
  • SAS is run in line mode.
  • The macro is the last line of an RSUBMIT block.
  • The macro invocation does not end with a semicolon (;).
For example, you can invoke the MYDATE macro (without a semicolon) in a client session, as follows:
%mydate
If you execute SAS in full-screen or DMS mode, invoking MYDATE (with or without the semicolon) in a remote submit will execute correctly.
However, if you execute SAS in line mode, and if MYDATE is defined in the server session and you are remotely submitting the invocation of MYDATE as the final line in an RSUBMIT block, you must use the semicolon to delimit the macro invocation, as follows:
RSUBMIT;
   %MACRO MYDATE;
      %PUT &SYSDATE;
   %MEND MYDATE;
   %MYDATE;           /* must use semicolon here */
ENDRSUBMIT;
When you execute SAS in line mode, the RSUBMIT statement indicates that all subsequent statements are to be processed in the server session. SAS/CONNECT searches the beginning of each statement for the occurrence of the ENDRSUBMIT statement, which indicates that statement processing in the server session should end. The semicolon delimits the end of each statement, except a comment. If the semicolon is omitted, the beginning of the next statement cannot be detected, which causes the ENDRSUBMIT statement to be ignored. The ENDRSUBMIT statement will be sent to the server session along with the macro invocation. The client session will continue to search for an ENDRSUBMIT statement.
In order to execute the remote submit block, including the macro invocation, enter another ENDRSUBMIT statement. Issuing the second ENDRSUBMIT causes the remote submit block to execute. Although the second ENDRSUBMIT is successful, the first ENDRSUBMIT produces the following error message:
Statement is not valid or it is used out of proper order.

Why Does the Error “Apparent symbolic reference USER1 not resolved” Occur?

This error occurs when a macro variable has not been defined in the SAS session where it is used. This error can occur in a server session when a %LET statement executes in the client session. You can use %NRSTR and %SYSLPUT to ensure that the macro is defined in the server session. You can also put the %LET statement in a macro definition so that the macro variable will be defined in the server session when the macro is invoked.
In the following code example, all the %LET statements are specified in an RSUBMIT block. The &USER1 macro variable is assigned in the client session rather than in the server session, as intended. This problem can be fixed by using the %SYSLPUT or %NRSTR statements. The &USER2 macro variable is assigned in the server session because it is contained in a macro definition in the RSUBMIT block.
%macro client;
   RSUBMIT;
      %let user1 = %sysget(LOGNAME);

      %macro remote;
         %global user2;
         %let user2 = %sysget(LOGNAME);
      %mend remote;
      %remote

      data _null_;
        put "user 1 = &user1";
        put "     2 = &user2";
        run;
   ENDRSUBMIT;
%mend client;
%client
The %LET statement for USER1 is executed in the client session, but the DATA step is executed in the server session. If the USER1 macro variable has not been previously defined, the following error message will be displayed:
Apparent symbolic reference USER1 not resolved.
You can set the MLOGIC system option to trace macro processing and to write trace output to the SAS log. Statements that generate a log message are processed in the client session. Statements that do not generate a log message are processed in the server session. For details about MLOGIC, see SAS Macro Language: Reference.

How Do I Avoid Spacing Problems When Using Semicolons in Macro Values?

My macro-generated RSUBMIT contains several %LET statements whose semicolons are followed with spaces. How can I include semicolons in my macro values and have the value concatenated correctly?
Here is the code:
%MACRO SETPATH;
    rsubmit;
      %nrstr(%%let PATH1 = c:\winnt\system32%%str(;);)
      %nrstr(%%let PATH2 = c:\winnt%%str(;);)
      %nrstr(%%let PATH3 = c:\bin;)
      %nrstr(%%let PATH  = &PATH1.&PATH2&.&PATH3)
      %nrstr(%%put PATH  = &PATH)
    endrsubmit;
    %MEND;
    %SETPATH
Here is the content of the SAS log:
NOTE: Remote submit to MAINPC commencing.
    1     %let PATH1 = c:\winnt\system32%str(;
    2    );
    3     %let PATH2 = c:\winnt%str(;
    4    );
    5     %let PATH3 = c:\bin;
    6     %let PATH = &PATH1.&PATH2&.&PATH3;
    7     %put PATH = &PATH;
    PATH = c:\winnt\system32; c:\winnt; c:\bin
    NOTE: Remote submit to MAINPC complete. 
Notice that the semicolons in the PATH macro variables are followed by extraneous spaces.
Because a semicolon is used to terminate a SAS statement, an %STR(;) statement within an %NRSTR statement causes problems when SAS/CONNECT parses the lines and buffers them before sending them to the server session.
To recover from the problem, modify the macro by using %SYSLPUT to submit the SEMICOLON macro variable to the server session. Execution of &SEMICOLON in the server session causes a semicolon to be appended to each %LET statement. Here is the modified code:
 %MACRO SETPATH;
   %syslput semicolon=%nrstr(;);
   rsubmit;
      %nrstr(%%let PATH1 = c:\winnt\system32&SEMICOLON;)
      %nrstr(%%let PATH2 = c:\winnt&SEMICOLON;)
      %nrstr(%%let PATH3 = c:\bin;)
      %nrstr(%%let PATH  = &PATH1.&PATH2&.&&PATH3;)
      %nrstr(%%put PATH  = &PATH;)
   endrsubmit;
   %MEND;
   %SETPATH
Using the SEMICOLON macro variable, the %SETPATH macro prints the &PATH macro value without spaces.
Here is the log:
NOTE: Remote submit to MAINPC commencing.
   8     %let PATH1 = c:\winnt\system32&SEMICOLON
   9     %let PATH2 = c:\winnt&SEMICOLON
   10    %let PATH3 = c:\bin;
   11    %let PATH = &PATH1.&PATH2&.&PATH3;
   12    %put PATH = &PATH;
   PATH = c:\winnt\system32;c:\winnt;c:\bin
   NOTE: Remote submit to MAINPC complete.