1 / 89

Macro Parameter Validation: Best Practices and Methods

Learn how to validate macro parameters, establish rules for valid values, and generate error messages for invalid inputs to enhance application reliability.

dagmara
Download Presentation

Macro Parameter Validation: Best Practices and Methods

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 3 Chapter 5: Passing and Processing Macro Parameters

  2. 3 Chapter 5: Passing and Processing Macro Parameters

  3. Objectives • Validate macro parameters.

  4. Parameter Validation • Up to this point, many of Orion Star’s applications have minimal parameter validation. The developers want to increase the amount of validation to reduce difficulties caused by user input. All macro applications should perform the following actions: • establish rules for valid values • Are null values valid? • What are valid values? • validate parameter values against valid values • generate error or warning message when invalid values are encountered and possibly terminate the macro

  5. Without Parameter Validation (Review) %macro printlst(country=AU,gender=F,type=CLUB); %upvalue proc print data=orion.customer_dim; var Customer_Name Customer_ID Customer_Age_Group Customer_Type; where Customer_Country = "&country" and Customer_Gender = "&gender" and upcase(Customer_Type) contains "&type"; title "Listing of Customer Names Subsetted By:"; title2 "Country=&country Gender=&gender Customer Type=&type"; run; title; %mend printlst; m205d01 The PRINTLST macro prints a subset of data based on the variables Country, Gender, and Type from orion.customer_dim. Without parameter validation, what potential problems might a user of this macro encounter?

  6. Without Parameter Validation (Review) * The CONTAINS operator selects observations that include the specified substring. The substring AL, null values, and blank values are found in the variable Customer_Type.

  7. Validation Against a Known List of Values • When a list of valid values is known, the macro applications should use one of these to validate parameter values: • the OR operator for equals conditions • the AND operator for not-equals conditions • the user-defined FIND macro • the IN operator The IN operator is new in SAS 9.2.

  8. Validation Using the OR and AND Operators %macro grplist(type); %let type=%upcase(&type); %if &type= or (&type ne GOLD and &type ne INTERNET and &type ne CATALOG) %then %do; %if &type = %then %put ERROR: A null value for TYPE is not valid.; %else %put ERROR: Value of TYPE: &type is not valid.; %put ERROR- Valid values are CATALOG, INTERNET or GOLD; %put ERROR- The macro will terminate now.; %return; %end; proc print data=orion.customer_dim; var Customer_Group Customer_Name Customer_Gender Customer_Age; where upcase(Customer_Group) contains "&type"; title "&type Customers"; run; title; %mend grplist; m205d02a

  9. Validation Using the OR and AND Operators 1922 %grplist() ERROR: A null value for TYPE is not valid. Valid values are CATALOG, INTERNET or GOLD The macro will terminate now. 1923 %grplist(silver) ERROR: Value of TYPE: SILVER is not valid. Valid values are CATALOG, INTERNET or GOLD The macro will terminate now. 1924 %grplist(catalog) NOTE: There were 8 observations read from the data set ORION.CUSTOMER_DIM. WHERE UPCASE(Customer_Group) contains 'CATALOG'; NOTE: PROCEDURE PRINT used (Total process time): real time 0.00 seconds cpu time 0.00 seconds Partial SAS Log

  10. Validation Using the FIND Macro %macro grplist(type); %let type=%upcase(&type); %if &type= or %find(GOLD INTERNET CATALOG ,&type)=0 %then %do; %if &type = %then %put ERROR: A null value for TYPE is not valid.; %else %put ERROR: Value of TYPE: &type is not valid.; %put ERROR- Valid values are CATALOG, INTERNET or GOLD; %put ERROR- The macro will terminate now.; %return; %end; proc print data=orion.customer_dim; var Customer_Group Customer_Name Customer_Gender Customer_Age; where upcase(Customer_Group) contains "&type"; title "&type Customers"; run; title; %mend grplist; m205d02b The FIND macro simplifies the %IF statement logic.

  11. Using the IN Operator Although similar in functionality to the DATA step IN operator, the macro IN operator is syntactically different.

  12. Incorrect Validation of Null Using the IN Operator %macro grplist(type)/minoperator; %let type=%upcase(&type); %if &type= or not(&type in GOLD INTERNET CATALOG) %then %do; %if &type = %then %put ERROR: A null value for TYPE is not valid.; %else %put ERROR: Value of TYPE: &type is not valid.; %put ERROR- Valid values are CATALOG, INTERNET or GOLD; %put ERROR- The macro will terminate now.; %return; %end; proc print data=orion.customer_dim; var Customer_Group Customer_Name Customer_Gender Customer_Age; where upcase(Customer_Group) contains "&type"; title "&type Customers"; run; title; %mend grplist; m205d02c

  13. Incorrect Validation of Null Using the IN Operator 2145 %grplist() SYMBOLGEN: Macro variable TYPE resolves to SYMBOLGEN: Macro variable TYPE resolves to ERROR: Operand missing for IN operator in argument to %EVAL function. ERROR: The macro GRPLIST will stop executing. %if = or not( in GOLD INTERNET CATALOG) %then %do; If the macro variables in the IN expression resolve to a null value, the macro processor generates the following errors: The IN operator does not recognize a null value as a valid value. If TYPE resolves to null, the %IF statement resolves to this statement:

  14. Validation of Null Using the IN Operator %if &type= %then %do; %put ERROR: A null value for TYPE is not valid.; %put ERROR- Valid values are CATALOG, INTERNET or GOLD; %put ERROR- The macro will terminate now.; %return; %end; %if not(&type in GOLD INTERNET CATALOG) %then %do; %put ERROR: Value of TYPE: &type is not valid.; %put ERROR- Valid values are CATALOG, INTERNET or GOLD; %put ERROR- The macro will terminate now.; %return; %end; m205d03 Testing for a null value must be done separately and prior to the %IF statement containing the IN operator.

  15. Validating NullUsing the IN Operator m205d03 This demonstration illustrates using the IN operator to test against a list of values.

  16. Validation Using a Dynamic List of Values %if not(&country in AU CA DE IL TR US ZA) %then %do; To reduce maintenance associated with parameter validation, the Orion Star programmers want to generate a data-driven list to replace the hardcoded values. The SQL procedure can be used to create the list of valid values dynamically and to save the result into a macro variable.

  17. The SQL Procedure INTO Clause (Review) proc sql noprint; select distinct country into :countrylist separated by ' ' from orion.customer; quit; 2241 %put Customer Countries: &countrylist; Customer Countries: AU CA DE IL TR US ZA m205d04 Partial SAS Log

  18. The SQL Procedure INTO Clause (Review) SELECT DISTINCTcol1, . . . INTO :mvarSEPARATED BY'delimiter', . . . FROM table-expression WHERE where-expression other clauses; The INTO clause can store the unique values of a specified column in a single macro variable. General form of the INTO clause to create a list of unique values in one macro variable:

  19. Validating Using a Dynamic List of Values m205d04 This demonstration illustrates using the SQL procedure to generate a data-driven list.

  20. Exercise This exercise reinforces the concepts discussed previously.

  21. 3 Chapter 5: Passing and Processing Macro Parameters

  22. Objectives • Generate repetitive macro calls using the following: • %DO loop • CALL EXECUTE routine • SQL procedure

  23. Data-Dependent Macro Calls %memlist(Orion Club members inactive) %memlist(Orion Club members low activity) %memlist(Orion Club members medium activity) %memlist(Orion Club members high activity) %memlist(Orion Club Gold members low activity) %memlist(Orion Club Gold members medium activity) %memlist(Orion Club Gold members high activity) %memlist(Internet/Catalog Customers) The Orion Star programmers need to call the MEMLIST macro for each value of Customer_Type. Because the value of Customer_Typecan change, they want to generate data-dependent macro calls as illustrated below:

  24. Data-Dependent Macro Calls • Three different methods can be used to generate data-dependent macro calls. • %DO loop • CALL EXECUTE routine • SQL procedure

  25. Method 1: %DO Loop %macro gencall; data _null_; set orion.customer_type end=final; call symputx(cats('type', _n_, Customer_Type,'L'); if final then call symputx('n',_n_,'L'); run; %do num=1 %to &n; %memlist(&&type&num) %end; %mend gencall; %gencall m205d05 Generally used to generate SAS code, the %DO loop can be used to generate data-dependent macro calls.

  26. Method 1: %DO Loop Partial Symbol Table Generate Macro Calls %memlist(&&type&num) %memlist(&type1) %memlist(Orion Club members inactive)

  27. Method 1: %DO Loop MPRINT(MEMLIST): proc print data=Orion.Customer_dim; MPRINT(MEMLIST): var Customer_Name Customer_ID Customer_Age_Group; MPRINT(MEMLIST): where Customer_Type="Orion Club members low activity"; MPRINT(MEMLIST): title "A List of Orion Club members low activity"; MPRINT(MEMLIST): run; MPRINT(MEMLIST): title; MPRINT(MEMLIST): proc print data=Orion.Customer_dim; MPRINT(MEMLIST): var Customer_Name Customer_ID Customer_Age_Group; MPRINT(MEMLIST): where Customer_Type="Orion Club members medium activity"; MPRINT(MEMLIST): title "A List of Orion Club members medium activity"; MPRINT(MEMLIST): run; MPRINT(MEMLIST): title; MPRINT(MEMLIST): proc print data=Orion.Customer_dim; MPRINT(MEMLIST): var Customer_Name Customer_ID Customer_Age_Group; MPRINT(MEMLIST): where Customer_Type="Orion Club members high activity"; MPRINT(MEMLIST): title "A List of Orion Club members high activity"; MPRINT(MEMLIST): run; Partial SAS Log

  28. Generating Code with the DATA Step CALL EXECUTE (argument); • The EXECUTE routine processes a text string during DATA step execution and can be used to generate data-driven macro calls. • General form of the CALL EXECUTE statement: • The value of argument can be one of the following: • a text expression, enclosed in quotation marks • the name of a character variable • a character expression that is resolved by the DATA step to a macro text expression

  29. Generating Code with the DATA Step 334 data new; 335 Dog='Paisley'; 336 call execute('proc print; run;') ; 337 run; NOTE: The data set WORK.NEW has 1 observations and 1 variables. NOTE: DATA statement used (Total process time): real time 0.01 seconds cpu time 0.01 seconds NOTE: CALL EXECUTE generated line. 1 + proc print; run; NOTE: There were 1 observations read from the data set WORK.NEW. NOTE: PROCEDURE PRINT used (Total process time): real time 0.00 seconds cpu time 0.00 seconds If argument is a text expression, it is inserted into the input stack as additional program code that will execute after the current DATA step. Partial SAS Log

  30. Executing Macro Code from a DATA Step • If the argument to the CALL EXECUTE routine resolves to a macro call, the macro executes immediately and DATA step execution pauses while the macro executes. • Macro language statements within the macro definition are executed. • All other SAS code generated by the macro is inserted into the input stack to execute after the current DATA step.

  31. Method 2: CALL EXECUTE Routine data _null_; set orion.customer_type(keep=Customer_Type) end=final; macrocall=catt('%memlist(', Customer_Type, ')'); call execute(macrocall) ; run; m205d06 Use the CALL EXECUTE routine to generate a macro call for each value of Customer_Type. The orion.customer_type data set contains one observation for each unique value of Customer_Type.

  32. Method 2: CALL EXECUTE Routine 858 data _null_; 859 set orion.customer_type(keep=Customer_Type) end=final; 860 macrocall=catt('%memlist(', Customer_Type, ')'); 861 call execute(macrocall) ; 862 run; MPRINT(MEMLIST): proc print data=Orion.Customer_dim; MPRINT(MEMLIST): var Customer_Name Customer_ID Customer_Age_Group; MPRINT(MEMLIST): where Customer_Type="Orion Club members inactive"; MPRINT(MEMLIST): title "A List of Orion Club members inactive"; MPRINT(MEMLIST): run; MPRINT(MEMLIST): title; MPRINT(MEMLIST): proc print data=Orion.Customer_dim; MPRINT(MEMLIST): var Customer_Name Customer_ID Customer_Age_Group; MPRINT(MEMLIST): where Customer_Type="Orion Club members low activity"; MPRINT(MEMLIST): title "A List of Orion Club members low activity"; MPRINT(MEMLIST): run; MPRINT(MEMLIST): title; MPRINT(MEMLIST): proc print data=Orion.Customer_dim; MPRINT(MEMLIST): var Customer_Name Customer_ID Customer_Age_Group; MPRINT(MEMLIST): where Customer_Type="Orion Club members medium activity"; MPRINT(MEMLIST): title "A List of Orion Club members medium activity"; MPRINT(MEMLIST): run; MPRINT(MEMLIST): title; Partial SAS Log

  33. Method 3: The SQL Procedure proc sql noprint; select distinct catt('%memlist(', customer_type, ')') into :mcalls separated by ' ' from orion.customer_type; quit; &mcalls *Resolution results in macro calls; m205d07 Use the INTO clause of PROC SQL to create a macro variable that contains a macro call for each value.

  34. Exercise This exercise reinforces the concepts discussed previously.

  35. 3 Chapter 5: Passing and Processing Macro Parameters

  36. Objectives • List and describe special characters. • Pass special characters. • Use special characters in functions. • Protect special characters in resolved values.

  37. Special Characters The macro language is a character-based language. Special characters can be misinterpreted by the macro processor when they appear in text strings, including these operators. blank , ; “ ‘ ( ) | + - * / < > = ¬ ^ ~ % & # The following mnemonics might also be misinterpreted: AND OR NOT EQ NE LE LT GE GT IN

  38. Comma: Argument Separator or Part of Text? %macro name(fullname); %let first=%scan(&fullname,2); %let last=%scan(&fullname,1); %let newname=&first &last; %put &newname; %mend name; %name(Taylor, Jenna) The comma will be misinterpreted as a separator instead of as part of the value. Commas are used as separators between parameter values in macro calls and as arguments in functions.

  39. Quotation Mark: Literal Delimiter or Part of Text? %macro unmatched(fullname); %let first=%scan(&fullname,2); %let last=%scan(&fullname,1); %let newname=&first &last; %put &newname; %mend unmatched; %unmatched(O'Malley, George) The apostrophe is treated as the beginning of a quoted string. An apostrophe or unmatched quotation mark is treated as the beginning of a quoted string, causing the windowing environment to stop responding.

  40. OR: Logical Operator or a Text Abbreviation? %macro operator(state); %if &state = OR %then %put State is Oregon; %else %put State is &state; %mend operator; %operator(PA) The %IF statement resolves to %if PA= OR %then, which is not allowed. The literal OR is interpreted as a logical operator that requires an expression on each side of the OR operator.

  41. Ampersand: Macro Trigger or Part of Text? %macro ampersand(company); %put &company; %mend ampersand; %ampersand(AT&T) The ampersand will be misinterpreted as a macro trigger. Macro triggers found in a macro call are resolved before the macro executes.

  42. Quoting Functions • Macro quoting functions resolve ambiguities by masking the significance of special characters and mnemonics so that the macro processor does not misinterpret them to be part of the syntax of a macro statement or expression. • The following are the most commonly used quoting functions: • %STR and %NRSTR • %SUPERQ • %BQUOTE

  43. Masking Special Characters Word Scanner Macro Processor The value of the macro variable should contain an ampersand and a percent sign as text. Input Stack %let xyz=%nrstr(&A+%B); ...

  44. Macro Processor Masking Special Characters Word Scanner % let xyz = % nrstr ( & A+ % B ) ; The word scanner identifies individual tokens. ...

  45. Masking Special Characters Word Scanner xyz = % nrstr ( & A+ % B ) ; Macro Processor %let The macro trigger %letredirects tokens to the macro processor. ...

  46. Masking Special Characters Word Scanner Macro Processor & A+ % B ) ; %let xyz=%nrstr( When %NRSTR is encountered, the macro processor masks special tokens that appear within the FUNCTION argument. ...

  47. Masking Special Characters Word Scanner Macro Processor ) ; %let xyz=%nrstr(&A+%B In effect, each individual character within a special token is treated as plain text. In reality, those tokens are stored as otherwise unused hexadecimal characters. ...

  48. Masking Special Characters Word Scanner Macro Processor ; %let xyz=%nrstr(&A+%B) Normal tokenization resumes after the %NRSTR is terminated with a right parenthesis. ...

  49. Masking Special Characters Word Scanner Macro Processor ; %let xyz=%nrstr(&A+%B) The macro processor will interpret this semicolon as the end of the %LET statement.

  50. Masking Special Characters %let xyz=%nrstr(&A+%B); The quoting functions mask special characters by converting them to hexadecimal values called delta characters. Becomes: 01 0F 41 15 10 42 02

More Related