MVS Version 9.4 (TS04.01M6P11072018)
BATCH and TSO
I have a program that scans SQL programs source code and resolves macro variables in text fields (ie that have an &xxxx in them where &xxxx is already a defined macro variable) . The output is written to a file. This isnt a normal resolve before data step, the point of the data step is to find such lines and resolve them, writing the SQL out for a another process. Resolve function is awesome and does near exactly what I want.
BUT
When the text starts with, '/*' resolve appears to blank the entire line. So the SQL in the file is missing a comment start.
%let mymvar = dummy ;
data step1;
length x $ 80 ;
x = '&mymvar' ;
output ;
x = ' /*' ;
output ;
x = '/*' ;
output ;
x = '/* this is a comment in SQL but without any macro variables' ;
output ;
run ;
data step2 ;
set step1 ;
x = resolve(x) ;
run ;
proc print data=step1; run ;
proc print data=step2; run ;
STEP 1 Output
Obs x
1 &mymvar
2 /*
3 /*
4 /* this is a comment in SQL but without any macro variables
STEP 2 OUTPUT
Obs x
1 dummy
2
3
4
I tried the comment open mid code
1 &mymvar
2 /*
3 /*
4 this is a comment in /* SQL but without any macro variables
and got this
Obs x
1 dummy
2
3
4 this is a comment in
So its clearly blanking anything from a comment onwards.
Note it is a comment that triggers this, not '/'
Why would RESOLVE remove any text from the start of a comment?? Anyone struck this before??
Because that is what SAS would do when presented that that string to interpret.
You can mask the *'s and it should help.
data test;
string1 = 'this has /* a comment */ in it';
string2 = resolve(string1);
string3 = resolve(tranwrd(string1,'*','%str(*)'));
put (string1-string3) (=/);
run;
Result
string1=this has /* a comment */ in it string2=this has in it string3=this has /* a comment */ in it
@bitcruncher wrote:
Thanks , yes I did that thats all good. To me RESOLVE shouldnt do this, its just a text string which could be from any language or any piece of text and the documentation is quite clear about the only function of RESOLVE being to resolve symbolics, not remove lines from a comment start. Anyway worked around and we both identified pretty well the same workaround which is good
But that is NOT what RESOLVE does. It does not just replace macro variable references. You can also call macro functions or user written macros or other macro code. For example %* macro comments are also removed.
73 data _null_; 74 input string1 $char80.; 75 string2=resolve(string1); 76 put (_n_ string1-string2) (=/); 77 cards4; _N_=1 string1=This has %* a comment; in it. string2=This has in it. _N_=2 string1=This has * a comment; in it. string2=This has * a comment; in it. _N_=3 string1=This has /* a comment */ in it. string2=This has in it. _N_=4 string1=This has %eval(2+3) words in it. string2=This has 5 words in it.
I suspect that rather than build something special for the RESOLVE() function it just calls the same block of code that does the normal macro processing which does ignore block comments.
Note you might want to look at PROC STREAM.
But I am not sure if it will do exactly what you want.
https://documentation.sas.com/doc/en/pgmsascdc/9.4_3.5/proc/n12zrkr08eiacmn17lcv4fmt79tb.htm
It really looks weird. But if you change this, the issue is gone.
/* ---> / *
Take Tom 's code for example:
data test; string1 = 'this has / * a comment */ in it'; string2 = resolve(string1); string3 = resolve(tranwrd(string1,'*','%str(*)')); put (string1-string3) (=/); run;
55 data test; 56 string1 = 'this has / * a comment */ in it'; 57 string2 = resolve(string1); 58 string3 = resolve(tranwrd(string1,'*','%str(*)')); 59 put (string1-string3) (=/); 60 run; string1=this has / * a comment */ in it string2=this has / * a comment */ in it string3=this has / * a comment */ in it
yes agreed, its triggered only by a '/*' comment (that we've seen so far) in the text string that we are doing RESOLVE on. And that text is each row of an existing Oracle query stored on mainframe.
The inputs are in production mainframe libraries which are being send (currently) via SAS/CONNECT to a SAS server which routes to Oracle
Going forward we wont have SAS/CONNECT anymore -- we are losing our middleman SAS server. So the identified solution to run these on the remote Oracle box is to resolve the symbolics into a file on mainframe and send that file to Oracle server where a script will trigger and execute the SQL (each day). We cannot change anything in that Oracle code member on the mainframe as there is a migration overlap period -- around 50 queries to change and need ability to run some parallel tests which start from the premise that the mainframe job must not change the oracle query code that currently has macro variables resolved on middleman SAS -- so that runs, but also takes that same query code member and creates the code ready to run with the new process, starting from that same Oracle query code.
Not sure why losing SAS/Connect should matter.
Can't you just send the code to Oracle from the SAS session you still have?
Also why does removing the comments matter?
Is it because the code blockas are using Oracle's modified comment syntax that allows you to give it hints for how to process the queries?
Dive into keynotes, announcements and breakthroughs on demand.
Explore Now →Learn how use the CAT functions in SAS to join values from multiple variables into a single value.
Find more tutorials on the SAS Users YouTube channel.
Ready to level-up your skills? Choose your own adventure.