BookmarkSubscribeRSS Feed
bitcruncher
Obsidian | Level 7

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??






 



7 REPLIES 7
Tom
Super User Tom
Super User

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
Obsidian | Level 7
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
Tom
Super User Tom
Super User

@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

 

bitcruncher
Obsidian | Level 7
I used this work around, just interestd in whether RESOLVE should do this now ...

/*
work around RESOLVE oddity/defect
*/

if find(codeline,'/*') then
codeline = tranwrd(codeline, "/*", "~*");
codeline = resolve(codeline) ;
if find(codeline,'~*') then
codeline = tranwrd(codeline, "~*", "/*");

/*
end of work around RESOLVE oddity/defect
*/
Ksharp
Super User

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

 

bitcruncher
Obsidian | Level 7

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.

Tom
Super User Tom
Super User

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?

Catch up on SAS Innovate 2026

Dive into keynotes, announcements and breakthroughs on demand.

Explore Now →
How to Concatenate Values

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.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

Discussion stats
  • 7 replies
  • 426 views
  • 0 likes
  • 3 in conversation