LISTSERV at the University of Georgia
Menubar Imagemap
Home Browse Manage Request Manuals Register
Previous messageNext messagePrevious in topicNext in topicPrevious by same authorNext by same authorPrevious page (December 2007, week 2)Back to main SAS-L pageJoin or leave SAS-L (or change settings)ReplyPost a new messageSearchProportional fontNon-proportional font
Date:         Mon, 10 Dec 2007 01:32:32 -0800
Reply-To:     chris@OVIEW.CO.UK
Sender:       "SAS(r) Discussion" <SAS-L@LISTSERV.UGA.EDU>
From:         chris@OVIEW.CO.UK
Organization: http://groups.google.com
Subject:      Re: Q: SAS Macro question
Comments: To: sas-l@uga.edu
Content-Type: text/plain; charset=ISO-8859-1

Hi Patrick,

Here's a solution that works for your test case - but see the caveats following it:

data test; do x = 1 to 10; output; end; run;

%macro AddSteps; proc print data=work.test; run; %mend;

%macro SetOptions; /* some options */ label='My DS'); if _n_ = 1 then call execute('%addsteps'); * %mend;

data work.test(%SetOptions) ; set test; run;

How it works: the SetOptions macro is modified to close the dataset options early by including the closing bracket (parenthesis) and semi- colon. It then inserts a CALL EXECUTE statement that will only be executed once, based on checking _N_. It then inserts a single asterisk, effectively starting a new comment, so that the original closing bracket following the SetOptions call doesn't cause an error.

The final data step resolves to:

data work.test(label='My DS'); if _n_ = 1 then call execute('%addsteps'); *) ; set test; run;

So far so good, but this is a very fragile solution. In your case, where you can't or don't want to modify all cases where SetOptions is called, it's unlikely to be sufficiently robust. For example, it will cause an error in a case like this:

data test1 (%setoptions) test2 (%setoptions);

More dangerously, in this case:

data test (%setoptions compress=no);

it won't cause an error, but will silently suppress the 'compress=no' option, causing possible problems later on.

The weakness of the method is that it's using a code injection technique to force data step statements in where they shouldn't be allowed. The ideal solution would involve a purely macro-language way to call CALL EXECUTE, but I can't find such a way at the moment....

Interestingly, every clinical reporting system I've ever worked on (including those validated for FDA use) is vulnerable to code injection attacks using this sort of technique.

HTH,

Chris. -------------------------------------------------------- Elvis SAS Log Analyser - http://www.oview.co.uk/elvis Recover runnable SAS code from your log's MPRINT lines. --------------------------------------------------------

On 10 Dec, 04:22, Patrick <patrick.mat...@gmx.ch> wrote: > Hi all > > Just posting that again in the hope to get an answer. > > Can anyone of you think of a solution for the following under SAS > 9.1.3 SP4, Unix or Windows? > > What I have: > - A bunch of programs. > - I have to add some checks after certain steps (proc's or datasteps) > within this programs. > - All steps after which I have to add code are calling the same macro > in the same way. > - This macro does nothing else than generating some data set options > - > eg: data test(%SetOptions); > > What I try to achieve: > - Not to make direct changes to the script of all the programs (DI > jobs, sometimes with user written code, sometimes within loops...) > - Change the %SetOptions macro in a way that it does the job for me. > > Where I am: > - call execute() is behaving close to what I need. But as much as I > understand it, that won't be the solution. > - doubting that there is a solution at all for what I try to achieve. > > Below is a code example to illustrate what I try to do. The example > doesn't work - and I understand also why. It's just outlining the > idea. > > Any idea for a solution or info why it can't be done at all would be > highly appreciated. > > Patrick > > Example: > %macro AddSteps; > proc print data=work.test; > run; > %mend; > > %macro SetOptions; > /* some options */ > label='My DS' > /* how to call macro so that it executes after current step > boundary? */ > call execute('%AddSteps'); /* ' */ > %mend; > > data work.test(%SetOptions) ; > a=1; > output; > run;


Back to: Top of message | Previous page | Main SAS-L page