OK, so here's an interesting bit of code. I think it illustrates what I'm seeing. Notice that the macro variable &x gets assigned four different values. Note in particular the value of &x after the 3rd data step inside the macro.
Here's the code:
OPTIONS noSYMBOLGEN noSOURCE noSOURCE2;
%macro TestDoSubl;
/*%macro TestDoSubl(x=);*/
%local rc;
%PUT NOTE: Entering macro. x=&x;
%LET x=DynamicValue;
%put NOTE: Before Dosubl 1: x=&x;
data _null_;
PUT "NOTE: inside data step 1 before DOSUBL x= &x";
%put NOTE: Macro put inside data step 1 before DOSUBL x=&x;
rc=dosubl("DATA _NULL_;%put NOTE: Inside inner DOSUBL 1: x=&x;RUN;");
PUT "NOTE: inside data step 1 after DOSUBL x= &x";
run;
%put NOTE: After Dosubl 1: x=&x;
%LET x=NewDynamicValue;
%put NOTE: Before Dosubl 2: x=&x;
data _null_;
PUT "NOTE: inside data step 2 before DOSUBL x= &x";
rc=dosubl("");
PUT "NOTE: inside data step 3 after DOSUBL x= &x";
run;
%put NOTE: After Dosubl 2: x=&x;
%put NOTE: Before Dosubl 3: x=&x;
data _null_;
PUT "NOTE: inside data step 2 before DOSUBL x= &x";
rc=dosubl("");
PUT "NOTE: inside data step 3 after DOSUBL x= &x";
run;
%put NOTE: After Dosubl 3: x=&x;
%mend TestDoSubl;
%let x=GlobalValue;
%put NOTE: Before Dosubl invoked macro execution complete: x=&x;
DATA _NULL_;
rc=DOSUBL('%TestDoSubl;');
/* rc=DOSUBL('%TestDoSubl(x=LocalValue);');*/
RUN;
%put NOTE: After Dosubl invoked macro execution complete: x=&x;
And here's the log:
NOTE: Before Dosubl invoked macro execution complete: x=GlobalValue
NOTE: Entering macro. x=GlobalValue
NOTE: Before Dosubl 1: x=DynamicValue
NOTE: Macro put inside data step 1 before DOSUBL x=DynamicValue
NOTE: Inside inner DOSUBL 1: x=DynamicValue
NOTE: inside data step 1 before DOSUBL x= DynamicValue
NOTE: DATA statement used (Total process time):
real time 0.00 seconds
cpu time 0.00 seconds
NOTE: inside data step 1 after DOSUBL x= DynamicValue
NOTE: DATA statement used (Total process time):
real time 0.00 seconds
cpu time 0.00 seconds
NOTE: After Dosubl 1: x=GlobalValue
NOTE: Before Dosubl 2: x=NewDynamicValue
NOTE: inside data step 2 before DOSUBL x= NewDynamicValue
NOTE: inside data step 3 after DOSUBL x= NewDynamicValue
NOTE: DATA statement used (Total process time):
real time 0.11 seconds
cpu time 0.00 seconds
NOTE: After Dosubl 2: x=GlobalValue
NOTE: Before Dosubl 3: x=GlobalValue
NOTE: inside data step 2 before DOSUBL x= GlobalValue
NOTE: inside data step 3 after DOSUBL x= GlobalValue
NOTE: DATA statement used (Total process time):
real time 0.00 seconds
cpu time 0.01 seconds
NOTE: After Dosubl 3: x=DynamicValue
NOTE: DATA statement used (Total process time):
real time 0.62 seconds
cpu time 0.02 seconds
NOTE: After Dosubl invoked macro execution complete: x=DynamicValue
Note that after the 3rd DATA step in the macro the value of &x is the value that was set before the first DATA step in the macro. So, it's not that the global macro variable is always returned after a DATA step is returned. The confusion/collision is more than that.
Jim
Yes, it's confusing. I added some %PUT _user_ statements, and I think that shows something (I'm not sure what). with this code:
%macro TestDoSubl;
%local rc;
%PUT NOTE: Entering macro. x=&x;
%put _user_;
%put;%put;%put;
%LET x=DynamicValue;
%put NOTE: Before Dosubl 1: x=&x;
%put _user_;
%put;
data _null_;
rc=dosubl("");
run;
%put NOTE: After Dosubl 1: x=&x;
%put _user_;
%put;
%put;%put;%put;
%LET x=NewDynamicValue;
%put NOTE: Before Dosubl 2: x=&x;
%put _user_;
%put;
data _null_;
rc=dosubl("");
run;
%put NOTE: After Dosubl 2: x=&x;
%put _user_;
%put;
%put;%put;%put;
%put NOTE: Before Dosubl 3: x=&x;
%put _user_;
data _null_;
rc=dosubl("");
run;
%put NOTE: After Dosubl 3: x=&x;
%put _user_;
%put;
%mend TestDoSubl;
%let x=GlobalValue;
DATA _NULL_;
rc=DOSUBL('%TestDoSubl;');
RUN;
I get:
NOTE: Entering macro. x=GlobalValue TESTDOSUBL RC GLOBAL X GlobalValue GLOBAL X GlobalValue NOTE: Before Dosubl 1: x=DynamicValue TESTDOSUBL RC GLOBAL X DynamicValue GLOBAL X GlobalValue NOTE: After Dosubl 1: x=GlobalValue TESTDOSUBL X GlobalValue TESTDOSUBL RC GLOBAL X DynamicValue GLOBAL X GlobalValue NOTE: Before Dosubl 2: x=NewDynamicValue TESTDOSUBL X NewDynamicValue TESTDOSUBL RC GLOBAL X DynamicValue GLOBAL X GlobalValue NOTE: After Dosubl 2: x=GlobalValue TESTDOSUBL X GlobalValue TESTDOSUBL RC GLOBAL X DynamicValue GLOBAL X GlobalValue NOTE: Before Dosubl 3: x=GlobalValue TESTDOSUBL X GlobalValue TESTDOSUBL RC GLOBAL X DynamicValue GLOBAL X GlobalValue NOTE: After Dosubl 3: x=DynamicValue TESTDOSUBL X DynamicValue TESTDOSUBL RC GLOBAL X DynamicValue GLOBAL X GlobalValue
What I see see above is that every time DOSUBL is called above, the value of one of the two global macro variables named X gets copied to the local macro variable X.
But I'm not going to pretend that I understand the inner workings of how DOSUBL moves macro variables back and forth between the main session and the side session. I'm not even sure why the above creates a local macro variable X. Having seen some of the collisions that can occur has led me to stay away from using DOSUBL for production work. But I'm hopeful that in time the good folks at SAS will resolve these scoping issues, and either officially document how DOSUBL transfers macro variables (and system options, and datasets, and other constructs) back and forth between the main session and side session, or write it up in UG papers. There is clearly a lot of power and potential in the idea of a side-session.
I just ran my code at home where I'm running SAS 9.4 M3. Everything works fine. Everything also worked fine with SAS 9.3 M1 on my PC at work. It's only on my work AIX machine running SAS 9.3 M2 that I'm seeing the problem. It seems pretty clear this is a bug, perhaps limited only to SAS 9.3 M2.
NOTE: Starting primary execution. The value of Debug=*
SYSVLONG4=9.04.01M3P06242015
NOTE: The value of Debug before invoking macro, Debug=*
NOTE: The value of Debug before the 1st Data step=
NOTE: Executing 1st Debug Logic
NOTE: Executing 1st Regular Logic
NOTE: The value of Debug inside the 1st Data step=
NOTE: DATA statement used (Total process time):
real time 0.03 seconds
cpu time 0.03 seconds
NOTE: The value of Debug after the 1st Data step=
NOTE: The value of Debug before the 2nd Data step=*
NOTE: Executing 2nd Regular Logic
NOTE: The value of Debug inside the 2nd Data step=*
NOTE: DATA statement used (Total process time):
real time 0.05 seconds
cpu time 0.02 seconds
NOTE: The value of Debug after the 2nd Data step=*
NOTE: The value of Debug before the 3rd Data step=*
NOTE: Executing 3rd Regular Logic
NOTE: The value of Debug inside the 3rd Data step=*
NOTE: DATA statement used (Total process time):
real time 0.01 seconds
cpu time 0.01 seconds
NOTE: The value of Debug after the 3rd Data step=*
NOTE: The value of Debug after invoking macro, Debug=*
NOTE: DATA statement used (Total process time):
real time 0.18 seconds
cpu time 0.08 seconds
NOTE: Ending primary execution. The value of Debug=*
NOTE: __________________________________________________________________________________________________
For production work, I think I'd probably stay away from DOSUBL on SAS 9.3 and only use DOSUBL with SAS 9.4. 9.4 M3 is clearly working. I don't know about earlier versions of 9.4 though.
Jim
OK, here's the code I think you mean. There aren't any time stamps displayed at least in my view of communities.sas.com.
OPTIONS noSYMBOLGEN noSOURCE noSOURCE2;
%macro TestDoSubl;
%local rc;
%PUT NOTE: Entering macro. x=&x;
%put _user_;
%PUT NOTE- ;
%PUT NOTE- ;
%LET x=DynamicValue;
%put NOTE: Before Dosubl 1: x=&x;
%put _user_;
%put;
data _null_;
rc=dosubl("");
run;
%put NOTE: After Dosubl 1: x=&x;
%put _user_;
%PUT NOTE- ;
%PUT NOTE- ;
%LET x=NewDynamicValue;
%put NOTE: Before Dosubl 2: x=&x;
%put _user_;
%PUT NOTE- ;
data _null_;
rc=dosubl("");
run;
%put NOTE: After Dosubl 2: x=&x;
%put _user_;
%PUT NOTE- ;
%PUT NOTE- ;
%put NOTE: Before Dosubl 3: x=&x;
%put _user_;
data _null_;
rc=dosubl("");
run;
%put NOTE: After Dosubl 3: x=&x;
%put _user_;
%PUT NOTE- ;
%PUT NOTE- ;
%mend TestDoSubl;
%PUT NOTE- ;
%PUT NOTE- ;
%PUT NOTE: __________________________________________________________________________________________________;
%let x=GlobalValue;
%PUT NOTE: Before TestDoSubl macro. x=&x;
%PUT NOTE- &=SYSVLONG4;
DATA _NULL_;
rc=DOSUBL('%TestDoSubl;');
RUN;
%PUT NOTE: After TestDoSubl macro. x=&x;
%PUT NOTE: __________________________________________________________________________________________________;
%PUT NOTE- ;
%PUT NOTE- ;
I've modified the code slightly because SAS web studio is freaking verbose. The big ______________ lines help separate out all the background noise that SAS web studio puts into the log.
And here's the output. Everything is as I would expect. In other words, I think that they have in fact fixed the bugs that were in 9.3 M2.
NOTE: __________________________________________________________________________________________________
NOTE: Before TestDoSubl macro. x=GlobalValue
SYSVLONG4=9.04.01M3P06242015
NOTE: Entering macro. x=GlobalValue
TESTDOSUBL RC
GLOBAL GRAPHINIT
GLOBAL GRAPHTERM
GLOBAL OLDPREFS /folders/myfolders/.wepreferences
GLOBAL OLDSNIPPETS /folders/myfolders/.mysnippets
GLOBAL OLDTASKS /folders/myfolders/.mytasks
GLOBAL RETURNCODE 0
GLOBAL STUDIODIR /folders/myfolders/.sasstudio
GLOBAL STUDIODIRNAME .sasstudio
GLOBAL STUDIOPARENTDIR /folders/myfolders
GLOBAL USERDIR /folders/myfolders
GLOBAL X GlobalValue
GLOBAL _BASEURL http:192.168.142.128SASStudio
GLOBAL _CLIENTAPP SAS Studio
GLOBAL _CLIENTAPPVERSION 3.4
GLOBAL _EXECENV SASStudio
GLOBAL _SASPROGRAMFILE foldersmyfoldersSAS_CodeDOSUBL_Test_Program3.sas
GLOBAL _SASWSTEMP_ foldersmyfolders.imagesaf7d42bf86784eacbcd1746bb34e87c0
GLOBAL _SASWS_ foldersmyfolders
NOTE: Before Dosubl 1: x=DynamicValue
TESTDOSUBL RC
GLOBAL GRAPHINIT
GLOBAL GRAPHTERM
GLOBAL OLDPREFS /folders/myfolders/.wepreferences
GLOBAL OLDSNIPPETS /folders/myfolders/.mysnippets
GLOBAL OLDTASKS /folders/myfolders/.mytasks
GLOBAL RETURNCODE 0
GLOBAL STUDIODIR /folders/myfolders/.sasstudio
GLOBAL STUDIODIRNAME .sasstudio
GLOBAL STUDIOPARENTDIR /folders/myfolders
GLOBAL USERDIR /folders/myfolders
GLOBAL X DynamicValue
GLOBAL _BASEURL http:192.168.142.128SASStudio
GLOBAL _CLIENTAPP SAS Studio
GLOBAL _CLIENTAPPVERSION 3.4
GLOBAL _EXECENV SASStudio
GLOBAL _SASPROGRAMFILE foldersmyfoldersSAS_CodeDOSUBL_Test_Program3.sas
GLOBAL _SASWSTEMP_ foldersmyfolders.imagesaf7d42bf86784eacbcd1746bb34e87c0
GLOBAL _SASWS_ foldersmyfolders
NOTE: DATA statement used (Total process time):
real time 0.02 seconds
cpu time 0.01 seconds
NOTE: After Dosubl 1: x=DynamicValue
TESTDOSUBL RC
GLOBAL GRAPHINIT
GLOBAL GRAPHTERM
GLOBAL OLDPREFS /folders/myfolders/.wepreferences
GLOBAL OLDSNIPPETS /folders/myfolders/.mysnippets
GLOBAL OLDTASKS /folders/myfolders/.mytasks
GLOBAL RETURNCODE 0
GLOBAL STUDIODIR /folders/myfolders/.sasstudio
GLOBAL STUDIODIRNAME .sasstudio
GLOBAL STUDIOPARENTDIR /folders/myfolders
GLOBAL USERDIR /folders/myfolders
GLOBAL X DynamicValue
GLOBAL _BASEURL http:192.168.142.128SASStudio
GLOBAL _CLIENTAPP SAS Studio
GLOBAL _CLIENTAPPVERSION 3.4
GLOBAL _EXECENV SASStudio
GLOBAL _SASPROGRAMFILE foldersmyfoldersSAS_CodeDOSUBL_Test_Program3.sas
GLOBAL _SASWSTEMP_ foldersmyfolders.imagesaf7d42bf86784eacbcd1746bb34e87c0
GLOBAL _SASWS_ foldersmyfolders
NOTE: Before Dosubl 2: x=NewDynamicValue
TESTDOSUBL RC
GLOBAL GRAPHINIT
GLOBAL GRAPHTERM
GLOBAL OLDPREFS /folders/myfolders/.wepreferences
GLOBAL OLDSNIPPETS /folders/myfolders/.mysnippets
GLOBAL OLDTASKS /folders/myfolders/.mytasks
GLOBAL RETURNCODE 0
GLOBAL STUDIODIR /folders/myfolders/.sasstudio
GLOBAL STUDIODIRNAME .sasstudio
GLOBAL STUDIOPARENTDIR /folders/myfolders
GLOBAL USERDIR /folders/myfolders
GLOBAL X NewDynamicValue
GLOBAL _BASEURL http:192.168.142.128SASStudio
GLOBAL _CLIENTAPP SAS Studio
GLOBAL _CLIENTAPPVERSION 3.4
GLOBAL _EXECENV SASStudio
GLOBAL _SASPROGRAMFILE foldersmyfoldersSAS_CodeDOSUBL_Test_Program3.sas
GLOBAL _SASWSTEMP_ foldersmyfolders.imagesaf7d42bf86784eacbcd1746bb34e87c0
GLOBAL _SASWS_ foldersmyfolders
NOTE: DATA statement used (Total process time):
real time 0.02 seconds
cpu time 0.02 seconds
NOTE: After Dosubl 2: x=NewDynamicValue
TESTDOSUBL RC
GLOBAL GRAPHINIT
GLOBAL GRAPHTERM
GLOBAL OLDPREFS /folders/myfolders/.wepreferences
GLOBAL OLDSNIPPETS /folders/myfolders/.mysnippets
GLOBAL OLDTASKS /folders/myfolders/.mytasks
GLOBAL RETURNCODE 0
GLOBAL STUDIODIR /folders/myfolders/.sasstudio
GLOBAL STUDIODIRNAME .sasstudio
GLOBAL STUDIOPARENTDIR /folders/myfolders
GLOBAL USERDIR /folders/myfolders
GLOBAL X NewDynamicValue
GLOBAL _BASEURL http:192.168.142.128SASStudio
GLOBAL _CLIENTAPP SAS Studio
GLOBAL _CLIENTAPPVERSION 3.4
GLOBAL _EXECENV SASStudio
GLOBAL _SASPROGRAMFILE foldersmyfoldersSAS_CodeDOSUBL_Test_Program3.sas
GLOBAL _SASWSTEMP_ foldersmyfolders.imagesaf7d42bf86784eacbcd1746bb34e87c0
GLOBAL _SASWS_ foldersmyfolders
NOTE: Before Dosubl 3: x=NewDynamicValue
TESTDOSUBL RC
GLOBAL GRAPHINIT
GLOBAL GRAPHTERM
GLOBAL OLDPREFS /folders/myfolders/.wepreferences
GLOBAL OLDSNIPPETS /folders/myfolders/.mysnippets
GLOBAL OLDTASKS /folders/myfolders/.mytasks
GLOBAL RETURNCODE 0
GLOBAL STUDIODIR /folders/myfolders/.sasstudio
GLOBAL STUDIODIRNAME .sasstudio
GLOBAL STUDIOPARENTDIR /folders/myfolders
GLOBAL USERDIR /folders/myfolders
GLOBAL X NewDynamicValue
GLOBAL _BASEURL http:192.168.142.128SASStudio
GLOBAL _CLIENTAPP SAS Studio
GLOBAL _CLIENTAPPVERSION 3.4
GLOBAL _EXECENV SASStudio
GLOBAL _SASPROGRAMFILE foldersmyfoldersSAS_CodeDOSUBL_Test_Program3.sas
GLOBAL _SASWSTEMP_ foldersmyfolders.imagesaf7d42bf86784eacbcd1746bb34e87c0
GLOBAL _SASWS_ foldersmyfolders
NOTE: DATA statement used (Total process time):
real time 0.01 seconds
cpu time 0.01 seconds
NOTE: After Dosubl 3: x=NewDynamicValue
TESTDOSUBL RC
GLOBAL GRAPHINIT
GLOBAL GRAPHTERM
GLOBAL OLDPREFS /folders/myfolders/.wepreferences
GLOBAL OLDSNIPPETS /folders/myfolders/.mysnippets
GLOBAL OLDTASKS /folders/myfolders/.mytasks
GLOBAL RETURNCODE 0
GLOBAL STUDIODIR /folders/myfolders/.sasstudio
GLOBAL STUDIODIRNAME .sasstudio
GLOBAL STUDIOPARENTDIR /folders/myfolders
GLOBAL USERDIR /folders/myfolders
GLOBAL X NewDynamicValue
GLOBAL _BASEURL http:192.168.142.128SASStudio
GLOBAL _CLIENTAPP SAS Studio
GLOBAL _CLIENTAPPVERSION 3.4
GLOBAL _EXECENV SASStudio
GLOBAL _SASPROGRAMFILE foldersmyfoldersSAS_CodeDOSUBL_Test_Program3.sas
GLOBAL _SASWSTEMP_ foldersmyfolders.imagesaf7d42bf86784eacbcd1746bb34e87c0
GLOBAL _SASWS_ foldersmyfolders
NOTE: DATA statement used (Total process time):
real time 0.20 seconds
cpu time 0.09 seconds
NOTE: After TestDoSubl macro. x=NewDynamicValue
NOTE: _________________________________________________________________________________________________
Jim
Timestamp tip: hover over the post "time" (which might be in friendly form, like "yesterday" or "a week ago") to get the exact day/time of posting.
Sorry, by 10:00pm last night I was typing on my phone, which showed the time stramps....
Could you try this block?
%macro TestDoSubl(x=);
%local rc;
%put Before Dosubl: x=&x;
data _null_;
rc=dosubl("");
run;
%put After Dosubl: x=&x;
%mend TestDoSubl;
%let x=GlobalValue;
%TestDoSubl(x=LocalValue)
If the After Dosubl %PUT statement returns LocalValue, I would be thrilled. If it still returns GlobalValue (i.e. a collision), then perhaps this confirms that your bug is different than my bug (i.e. if your bug is fixed in 9.4M3 but mine is not).
@Quentin wrote:
Sorry, by 10:00pm last night I was typing on my phone, which showed the time stramps....
Could you try this block?
%macro TestDoSubl(x=); %local rc; %put Before Dosubl: x=&x; data _null_; rc=dosubl(""); run; %put After Dosubl: x=&x; %mend TestDoSubl; %let x=GlobalValue; %TestDoSubl(x=LocalValue)
If the After Dosubl %PUT statement returns LocalValue, I would be thrilled. If it still returns GlobalValue (i.e. a collision), then perhaps this confirms that your bug is different than my bug (i.e. if your bug is fixed in 9.4M3 but mine is not).
Here's what get I know you're not asking me.
33 %macro TestDoSubl(x=);
34 %local rc;
35
36 %put Before Dosubl: x=&x;
37
38 data _null_;
39 rc=dosubl("");
40 run;
41
42 %put After Dosubl: x=&x;
43
44 %mend TestDoSubl;
45 %put NOTE: &=SYSVLONG4;
NOTE: SYSVLONG4=9.04.01M3P06242015
46 %let x=GlobalValue;
47 %TestDoSubl(x=LocalValue)
Before Dosubl: x=LocalValue
NOTE: DATA statement used (Total process time):
real time 0.09 seconds
cpu time 0.02 seconds
After Dosubl: x=GlobalValue
Thanks @data_null__, happy to have an answer from you. Even though I'm not happy with the result (bug still there), it's what I expected based on previous reports. Perhpas I'll look for a polite way to bring this up during Rick Langston and @ArtC's Ask The Experts session in Vegas....
The result that @data_null__ got doesn't surprise me. My results, if you look at the below log snippet, were identical.
NOTE: Entering macro. x=GlobalValue
I wouild think the "work around" if you want to call it that, would be simply to code the following inside the Macro, yes?
%LOCAL x;
Jim
Ah. I see what you're saying. I didn't pay attention to the way in which the macro was being invoked. Hmm. Yeah, that doesn't seem quite right... I'll have to play with that a bit more on my 9.4 at home this evening if I get a chance.
Jim
SAS Innovate 2025 is scheduled for May 6-9 in Orlando, FL. Sign up to be first to learn about the agenda and registration!
What’s the difference between SAS Enterprise Guide and SAS Studio? How are they similar? Just ask SAS’ Danny Modlin.
Find more tutorials on the SAS Users YouTube channel.
Ready to level-up your skills? Choose your own adventure.