1
0
mirror of https://github.com/sasjs/core.git synced 2026-01-11 02:50:06 +00:00

Merge pull request #167 from sasjs/issue166

feat: adding mddl_xx series of macros (and tests).  Closes #166
This commit is contained in:
Allan Bowe
2022-02-07 15:42:01 +02:00
committed by GitHub
19 changed files with 509 additions and 245 deletions

View File

@@ -31,19 +31,28 @@ Documentation: https://core.sasjs.io
## Components ## Components
### BASE library (SAS9/Viya) ### BASE library (All Platforms)
- OS independent - OS independent
- Not metadata aware - Works on all SAS Platforms
- No X command - No X command
- Prefixes: _mf_, _mp_ - Prefixes: _mf_, _mp_
#### FCMP library (SAS9/Viya) ### DDL library (All Platforms)
- OS independent
- Works on all SAS Platforms
- No X command
- Prefixes: _mddl_(lib)_ -> where lib can be "SAS" (in relation to a SAS component) or "DC" (in relation to a Data Controller component)
This library will not be used for storing data entries (such as formats or datalines). Where this becomes necessary in the future, a new repo will be created, in order to keep the NPM bundle size down (for the benefit of those looking to embed purely macros in their applications).
#### FCMP library (All Platforms)
- Function and macro names are identical, except for special cases - Function and macro names are identical, except for special cases
- Prefixes: _mcf_ - Prefixes: _mcf_
The fcmp macros are used to generate fcmp functions, and can be used with or The fcmp macros are used to generate fcmp functions, and can be used with or without the `proc fcmp` wrapper.
without the `proc fcmp` wrapper.
### META library (SAS9 only) ### META library (SAS9 only)
@@ -125,6 +134,7 @@ filename mc url "https://raw.githubusercontent.com/sasjs/core/main/all.sas";
- one macro per file - one macro per file
- prefixes: - prefixes:
- _mcf_ for macro compiled functions (proc fcmp) - _mcf_ for macro compiled functions (proc fcmp)
- _mddl_ for macros containing DDL (Data Definition Language)
- _mf_ for macro functions (can be used in open code). - _mf_ for macro functions (can be used in open code).
- _ml_ for macros that are used to compile LUA modules - _ml_ for macros that are used to compile LUA modules
- _mm_ for metadata macros (interface with the metadata server). - _mm_ for metadata macros (interface with the metadata server).
@@ -198,6 +208,7 @@ We are currently on major release v4. Breaking changes should be marked with th
* `insert_cmplib` option of mcf_xxx macros will be deprecated (the option is now checked automatically with value inserted only if needed) * `insert_cmplib` option of mcf_xxx macros will be deprecated (the option is now checked automatically with value inserted only if needed)
* mcf_xxx macros to have `wrap=` option defaulted to YES for convenience. Set this option explicitly to avoid issues. * mcf_xxx macros to have `wrap=` option defaulted to YES for convenience. Set this option explicitly to avoid issues.
* mp_getddl.sas to be renamed to mp_ds2ddl.sas (consistent with other ds2xxx macros). A wrapper macro is already in place, and you are able to use this immediately. The default for SHOWLOG will also be YES instead of NO. * mp_getddl.sas to be renamed to mp_ds2ddl.sas (consistent with other ds2xxx macros). A wrapper macro is already in place, and you are able to use this immediately. The default for SHOWLOG will also be YES instead of NO.
* mp_coretable.sas will be replaced by the standalone macros in the `ddl` folder (which are already available)
## Star Gazing ## Star Gazing

306
all.sas
View File

@@ -3544,19 +3544,21 @@ run;
%mp_coretable(LOCKTABLE,libds=work.locktable) %mp_coretable(LOCKTABLE,libds=work.locktable)
@param [in] table_ref The type of table to create. Example values: @param [in] table_ref The type of table to create. Example values:
@li DIFFTABLE - Used to store changes to tables. Used by mp_storediffs.sas @li DIFFTABLE
and mp_stackdiffs.sas @li FILTER_DETAIL
@li FILTER_DETAIL - For storing detailed filter values. Used by @li FILTER_SUMMARY
mp_filterstore.sas. @li LOCKANYTABLE
@li FILTER_SUMMARY - For storing summary filter values. Used by @li MAXKEYTABLE
mp_filterstore.sas.
@li LOCKANYTABLE - For "locking" tables prior to multipass loads. Used by
mp_lockanytable.sas
@li MAXKEYTABLE - For storing the maximum retained key information. Used
by mp_retainedkey.sas
@param [in] libds= (0) The library.dataset reference used to create the table. @param [in] libds= (0) The library.dataset reference used to create the table.
If not provided, then the DDL is simply printed to the log. If not provided, then the DDL is simply printed to the log.
<h4> SAS Macros </h4>
@li mddl_dc_difftable.sas
@li mddl_dc_filterdetail.sas
@li mddl_dc_filtersummary.sas
@li mddl_dc_locktable.sas
@li mddl_dc_maxkeytable.sas
<h4> Related Macros </h4> <h4> Related Macros </h4>
@li mp_filterstore.sas @li mp_filterstore.sas
@li mp_lockanytable.sas @li mp_lockanytable.sas
@@ -3575,76 +3577,21 @@ run;
%let outds=%sysfunc(ifc(&libds=0,_data_,&libds)); %let outds=%sysfunc(ifc(&libds=0,_data_,&libds));
proc sql; proc sql;
%if &table_ref=DIFFTABLE %then %do; %if &table_ref=DIFFTABLE %then %do;
create table &outds( %mddl_dc_difftable(libds=&outds)
load_ref char(36) label='unique load reference',
processed_dttm num format=E8601DT26.6 label='Processed at timestamp',
libref char(8) label='Library Reference (8 chars)',
dsn char(32) label='Dataset Name (32 chars)',
key_hash char(32) label=
'MD5 Hash of primary key values (pipe seperated)',
move_type char(1) label='Either (A)ppended, (D)eleted or (M)odified',
is_pk num label='Is Primary Key Field? (1/0)',
is_diff num label=
'Did value change? (1/0/-1). Always -1 for appends and deletes.',
tgtvar_type char(1) label='Either (C)haracter or (N)umeric',
tgtvar_nm char(32) label='Target variable name (32 chars)',
oldval_num num format=best32. label='Old (numeric) value',
newval_num num format=best32. label='New (numeric) value',
oldval_char char(32765) label='Old (character) value',
newval_char char(32765) label='New (character) value',
constraint pk_mpe_audit
primary key(load_ref,libref,dsn,key_hash,tgtvar_nm)
);
%end; %end;
%else %if &table_ref=LOCKTABLE %then %do; %else %if &table_ref=LOCKTABLE %then %do;
create table &outds( %mddl_dc_locktable(libds=&outds)
lock_lib char(8),
lock_ds char(32),
lock_status_cd char(10) not null,
lock_user_nm char(100) not null ,
lock_ref char(200),
lock_pid char(10),
lock_start_dttm num format=E8601DT26.6,
lock_end_dttm num format=E8601DT26.6,
constraint pk_mp_lockanytable primary key(lock_lib,lock_ds));
%end; %end;
%else %if &table_ref=FILTER_SUMMARY %then %do; %else %if &table_ref=FILTER_SUMMARY %then %do;
create table &outds( %mddl_dc_filtersummary(libds=&outds)
filter_rk num not null,
filter_hash char(32) not null,
filter_table char(41) not null,
processed_dttm num not null format=E8601DT26.6,
constraint pk_mpe_filteranytable
primary key(filter_rk));
%end; %end;
%else %if &table_ref=FILTER_DETAIL %then %do; %else %if &table_ref=FILTER_DETAIL %then %do;
create table &outds( %mddl_dc_filterdetail(libds=&outds)
filter_hash char(32) not null,
filter_line num not null,
group_logic char(3) not null,
subgroup_logic char(3) not null,
subgroup_id num not null,
variable_nm varchar(32) not null,
operator_nm varchar(12) not null,
raw_value varchar(4000) not null,
processed_dttm num not null format=E8601DT26.6,
constraint pk_mpe_filteranytable
primary key(filter_hash,filter_line));
%end; %end;
%else %if &table_ref=MAXKEYTABLE %then %do; %else %if &table_ref=MAXKEYTABLE %then %do;
create table &outds( %mddl_dc_maxkeytable(libds=&outds)
keytable varchar(41) label='Base table in libref.dataset format',
keycolumn char(32) format=$32.
label='The Retained key field containing the key values.',
max_key num label=
'Integer representing current max RK or SK value in the KEYTABLE',
processed_dttm num format=E8601DT26.6
label='Datetime this value was last updated',
constraint pk_mpe_maxkeyvalues
primary key(keytable));
%end; %end;
%if &libds=0 %then %do; %if &libds=0 %then %do;
describe table &syslast; describe table &syslast;
drop table &syslast; drop table &syslast;
@@ -5779,6 +5726,7 @@ filename &outref temp;
<h4> SAS Macros </h4> <h4> SAS Macros </h4>
@li mddl_sas_cntlout.sas
@li mf_getuniquename.sas @li mf_getuniquename.sas
@li mf_getvalue.sas @li mf_getvalue.sas
@li mf_islibds.sas @li mf_islibds.sas
@@ -5840,36 +5788,14 @@ filename &outref temp;
%if "%substr(&libds,%length(&libds)-2,3)"="-FC" %then %do; %if "%substr(&libds,%length(&libds)-2,3)"="-FC" %then %do;
%let libds=%scan(&libds,1,-); /* chop off -FC extension */ %let libds=%scan(&libds,1,-); /* chop off -FC extension */
%let ds0=%mf_getuniquename(prefix=fmtds_); %let ds0=%mf_getuniquename(prefix=fmtds_);
%let libds=&ds0;
/* /*
There is no need to export the entire format catalog here - the validations There is no need to export the entire format catalog here - the validations
are done against the data model, not the data values. So we can simply are done against the data model, not the data values. So we can simply
hardcode the structure based on the cntlout dataset. hardcode the structure based on the cntlout dataset.
*/ */
proc sql; %mddl_sas_cntlout(libds=&ds0)
create table &ds0(
FMTNAME char(32)
,START char(16)
,END char(16)
,LABEL char(256)
,MIN num length=3
,MAX num length=3
,DEFAULT num length=3
,LENGTH num length=3
,FUZZ num
,PREFIX char(2)
,MULT num
,FILL char(1)
,NOEDIT num length=3
,TYPE char(1)
,SEXCL char(1)
,EEXCL char(1)
,HLO char(13)
,DECSEP char(1)
,DIG3SEP char(1)
,DATATYPE char(8)
,LANGUAGE char(8)
);
%let libds=&ds0;
%end; %end;
%mp_filtercheck(&queryds,targetds=&libds,abort=YES) %mp_filtercheck(&queryds,targetds=&libds,abort=YES)
@@ -7042,6 +6968,7 @@ https://support.sas.com/documentation/cdl/en/proc/61895/HTML/default/viewer.htm#
|`WHICHPATH `|`**OTHER** `|`**OTHER** `|`big fat problem if not path1 `|`1 `|`40 `|`28 `|`28 `|`1E-12 `|` `|`0 `|` `|`0 `|`N `|`N `|`N `|`O `|` `|` `|` `|` `| |`WHICHPATH `|`**OTHER** `|`**OTHER** `|`big fat problem if not path1 `|`1 `|`40 `|`28 `|`28 `|`1E-12 `|` `|`0 `|` `|`0 `|`N `|`N `|`N `|`O `|` `|` `|` `|` `|
<h4> SAS Macros </h4> <h4> SAS Macros </h4>
@li mddl_sas_cntlout.sas
@li mf_dedup.sas @li mf_dedup.sas
@li mf_getfmtlist.sas @li mf_getfmtlist.sas
@li mf_getfmtname.sas @li mf_getfmtname.sas
@@ -7096,30 +7023,7 @@ create table &outsummary as
%if "&outdetail" ne "0" %then %do; %if "&outdetail" ne "0" %then %do;
/* ensure base table always exists */ /* ensure base table always exists */
proc sql; %mddl_sas_cntlout(libds=&outdetail)
create table &outdetail(
FMTNAME char(32) label='Format name'
,START char(16) label='Starting value for format'
,END char(16) label='Ending value for format'
,LABEL char(256) label='Format value label'
,MIN num length=3 label='Minimum length'
,MAX num length=3 label='Maximum length'
,DEFAULT num length=3 label='Default length'
,LENGTH num length=3 label='Format length'
,FUZZ num label='Fuzz value'
,PREFIX char(2) label='Prefix characters'
,MULT num label='Multiplier'
,FILL char(1) label='Fill character'
,NOEDIT num length=3 label='Is picture string noedit?'
,TYPE char(1) label='Type of format'
,SEXCL char(1) label='Start exclusion'
,EEXCL char(1) label='End exclusion'
,HLO char(13) label='Additional information'
,DECSEP char(1) label='Decimal separator'
,DIG3SEP char(1) label='Three-digit separator'
,DATATYPE char(8) label='Date/time/datetime?'
,LANGUAGE char(8) label='Language for date strings'
);
/* grab the location of each format */ /* grab the location of each format */
%let fmtcnt=0; %let fmtcnt=0;
data _null_; data _null_;
@@ -12002,6 +11906,170 @@ ods package publish archive properties
ods package close; ods package close;
%mend mp_zip;/** %mend mp_zip;/**
@file
@brief Difftable DDL
@details Used to store changes to tables. Used by mp_storediffs.sas
and mp_stackdiffs.sas
**/
%macro mddl_dc_difftable(libds=WORK.DIFFTABLE);
proc sql;
create table &libds(
load_ref char(36) label='unique load reference',
processed_dttm num format=E8601DT26.6 label='Processed at timestamp',
libref char(8) label='Library Reference (8 chars)',
dsn char(32) label='Dataset Name (32 chars)',
key_hash char(32) label=
'MD5 Hash of primary key values (pipe seperated)',
move_type char(1) label='Either (A)ppended, (D)eleted or (M)odified',
is_pk num label='Is Primary Key Field? (1/0)',
is_diff num label=
'Did value change? (1/0/-1). Always -1 for appends and deletes.',
tgtvar_type char(1) label='Either (C)haracter or (N)umeric',
tgtvar_nm char(32) label='Target variable name (32 chars)',
oldval_num num format=best32. label='Old (numeric) value',
newval_num num format=best32. label='New (numeric) value',
oldval_char char(32765) label='Old (character) value',
newval_char char(32765) label='New (character) value',
constraint pk_mpe_audit
primary key(load_ref,libref,dsn,key_hash,tgtvar_nm)
);
%mend mddl_dc_difftable;/**
@file
@brief Filtertable DDL
@details For storing detailed filter values. Used by
mp_filterstore.sas.
**/
%macro mddl_dc_filterdetail(libds=WORK.FILTER_DETAIL);
proc sql;
create table &libds(
filter_hash char(32) not null,
filter_line num not null,
group_logic char(3) not null,
subgroup_logic char(3) not null,
subgroup_id num not null,
variable_nm varchar(32) not null,
operator_nm varchar(12) not null,
raw_value varchar(4000) not null,
processed_dttm num not null format=E8601DT26.6,
constraint pk_mpe_filteranytable
primary key(filter_hash,filter_line)
);
%mend mddl_dc_filterdetail;/**
@file
@brief Filtersummary DDL
@details For storing summary filter values. Used by
mp_filterstore.sas.
**/
%macro mddl_dc_filtersummary(libds=WORK.FILTER_SUMMARY);
proc sql;
create table &libds(
filter_rk num not null,
filter_hash char(32) not null,
filter_table char(41) not null,
processed_dttm num not null format=E8601DT26.6,
constraint pk_mpe_filteranytable
primary key(filter_rk)
);
%mend mddl_dc_filtersummary;/**
@file
@brief Locktable DDL
@details For "locking" tables prior to multipass loads. Used by
mp_lockanytable.sas
**/
%macro mddl_dc_locktable(libds=WORK.LOCKTABLE);
proc sql;
create table &libds(
lock_lib char(8),
lock_ds char(32),
lock_status_cd char(10) not null,
lock_user_nm char(100) not null ,
lock_ref char(200),
lock_pid char(10),
lock_start_dttm num format=E8601DT26.6,
lock_end_dttm num format=E8601DT26.6,
constraint pk_mp_lockanytable primary key(lock_lib,lock_ds)
);
%mend mddl_dc_locktable;/**
@file
@brief Maxkeytable DDL
@details For storing the maximum retained key information. Used
by mp_retainedkey.sas
**/
%macro mddl_dc_maxkeytable(libds=WORK.MAXKEYTABLE);
proc sql;
create table &libds(
keytable varchar(41) label='Base table in libref.dataset format',
keycolumn char(32) format=$32.
label='The Retained key field containing the key values.',
max_key num label=
'Integer representing current max RK or SK value in the KEYTABLE',
processed_dttm num format=E8601DT26.6
label='Datetime this value was last updated',
constraint pk_mpe_maxkeyvalues
primary key(keytable));
%mend mddl_dc_maxkeytable;/**
@file
@brief The CNTLOUT table generated by proc format
@details This table will actually change format depending on the data values,
therefore the max possible lengths are described here to enable consistency
when dealing with format data.
**/
%macro mddl_sas_cntlout(libds=WORK.CNTLOUT);
proc sql;
create table &libds(
FMTNAME char(32) label='Format name'
,START char(16) label='Starting value for format'
,END char(16) label='Ending value for format'
,LABEL char(256) label='Format value label'
,MIN num length=3 label='Minimum length'
,MAX num length=3 label='Maximum length'
,DEFAULT num length=3 label='Default length'
,LENGTH num length=3 label='Format length'
,FUZZ num label='Fuzz value'
,PREFIX char(2) label='Prefix characters'
,MULT num label='Multiplier'
,FILL char(1) label='Fill character'
,NOEDIT num length=3 label='Is picture string noedit?'
,TYPE char(1) label='Type of format'
,SEXCL char(1) label='Start exclusion'
,EEXCL char(1) label='End exclusion'
,HLO char(13) label='Additional information'
,DECSEP char(1) label='Decimal separator'
,DIG3SEP char(1) label='Three-digit separator'
,DATATYPE char(8) label='Date/time/datetime?'
,LANGUAGE char(8) label='Language for date strings'
);
%mend mddl_sas_cntlout;/**
@file mm_adduser2group.sas @file mm_adduser2group.sas
@brief Adds a user to a group @brief Adds a user to a group
@details Adds a user to a metadata group. The macro first checks whether the @details Adds a user to a metadata group. The macro first checks whether the

View File

@@ -16,19 +16,21 @@
%mp_coretable(LOCKTABLE,libds=work.locktable) %mp_coretable(LOCKTABLE,libds=work.locktable)
@param [in] table_ref The type of table to create. Example values: @param [in] table_ref The type of table to create. Example values:
@li DIFFTABLE - Used to store changes to tables. Used by mp_storediffs.sas @li DIFFTABLE
and mp_stackdiffs.sas @li FILTER_DETAIL
@li FILTER_DETAIL - For storing detailed filter values. Used by @li FILTER_SUMMARY
mp_filterstore.sas. @li LOCKANYTABLE
@li FILTER_SUMMARY - For storing summary filter values. Used by @li MAXKEYTABLE
mp_filterstore.sas.
@li LOCKANYTABLE - For "locking" tables prior to multipass loads. Used by
mp_lockanytable.sas
@li MAXKEYTABLE - For storing the maximum retained key information. Used
by mp_retainedkey.sas
@param [in] libds= (0) The library.dataset reference used to create the table. @param [in] libds= (0) The library.dataset reference used to create the table.
If not provided, then the DDL is simply printed to the log. If not provided, then the DDL is simply printed to the log.
<h4> SAS Macros </h4>
@li mddl_dc_difftable.sas
@li mddl_dc_filterdetail.sas
@li mddl_dc_filtersummary.sas
@li mddl_dc_locktable.sas
@li mddl_dc_maxkeytable.sas
<h4> Related Macros </h4> <h4> Related Macros </h4>
@li mp_filterstore.sas @li mp_filterstore.sas
@li mp_lockanytable.sas @li mp_lockanytable.sas
@@ -47,76 +49,21 @@
%let outds=%sysfunc(ifc(&libds=0,_data_,&libds)); %let outds=%sysfunc(ifc(&libds=0,_data_,&libds));
proc sql; proc sql;
%if &table_ref=DIFFTABLE %then %do; %if &table_ref=DIFFTABLE %then %do;
create table &outds( %mddl_dc_difftable(libds=&outds)
load_ref char(36) label='unique load reference',
processed_dttm num format=E8601DT26.6 label='Processed at timestamp',
libref char(8) label='Library Reference (8 chars)',
dsn char(32) label='Dataset Name (32 chars)',
key_hash char(32) label=
'MD5 Hash of primary key values (pipe seperated)',
move_type char(1) label='Either (A)ppended, (D)eleted or (M)odified',
is_pk num label='Is Primary Key Field? (1/0)',
is_diff num label=
'Did value change? (1/0/-1). Always -1 for appends and deletes.',
tgtvar_type char(1) label='Either (C)haracter or (N)umeric',
tgtvar_nm char(32) label='Target variable name (32 chars)',
oldval_num num format=best32. label='Old (numeric) value',
newval_num num format=best32. label='New (numeric) value',
oldval_char char(32765) label='Old (character) value',
newval_char char(32765) label='New (character) value',
constraint pk_mpe_audit
primary key(load_ref,libref,dsn,key_hash,tgtvar_nm)
);
%end; %end;
%else %if &table_ref=LOCKTABLE %then %do; %else %if &table_ref=LOCKTABLE %then %do;
create table &outds( %mddl_dc_locktable(libds=&outds)
lock_lib char(8),
lock_ds char(32),
lock_status_cd char(10) not null,
lock_user_nm char(100) not null ,
lock_ref char(200),
lock_pid char(10),
lock_start_dttm num format=E8601DT26.6,
lock_end_dttm num format=E8601DT26.6,
constraint pk_mp_lockanytable primary key(lock_lib,lock_ds));
%end; %end;
%else %if &table_ref=FILTER_SUMMARY %then %do; %else %if &table_ref=FILTER_SUMMARY %then %do;
create table &outds( %mddl_dc_filtersummary(libds=&outds)
filter_rk num not null,
filter_hash char(32) not null,
filter_table char(41) not null,
processed_dttm num not null format=E8601DT26.6,
constraint pk_mpe_filteranytable
primary key(filter_rk));
%end; %end;
%else %if &table_ref=FILTER_DETAIL %then %do; %else %if &table_ref=FILTER_DETAIL %then %do;
create table &outds( %mddl_dc_filterdetail(libds=&outds)
filter_hash char(32) not null,
filter_line num not null,
group_logic char(3) not null,
subgroup_logic char(3) not null,
subgroup_id num not null,
variable_nm varchar(32) not null,
operator_nm varchar(12) not null,
raw_value varchar(4000) not null,
processed_dttm num not null format=E8601DT26.6,
constraint pk_mpe_filteranytable
primary key(filter_hash,filter_line));
%end; %end;
%else %if &table_ref=MAXKEYTABLE %then %do; %else %if &table_ref=MAXKEYTABLE %then %do;
create table &outds( %mddl_dc_maxkeytable(libds=&outds)
keytable varchar(41) label='Base table in libref.dataset format',
keycolumn char(32) format=$32.
label='The Retained key field containing the key values.',
max_key num label=
'Integer representing current max RK or SK value in the KEYTABLE',
processed_dttm num format=E8601DT26.6
label='Datetime this value was last updated',
constraint pk_mpe_maxkeyvalues
primary key(keytable));
%end; %end;
%if &libds=0 %then %do; %if &libds=0 %then %do;
describe table &syslast; describe table &syslast;
drop table &syslast; drop table &syslast;

View File

@@ -50,6 +50,7 @@
<h4> SAS Macros </h4> <h4> SAS Macros </h4>
@li mddl_sas_cntlout.sas
@li mf_getuniquename.sas @li mf_getuniquename.sas
@li mf_getvalue.sas @li mf_getvalue.sas
@li mf_islibds.sas @li mf_islibds.sas
@@ -111,36 +112,14 @@
%if "%substr(&libds,%length(&libds)-2,3)"="-FC" %then %do; %if "%substr(&libds,%length(&libds)-2,3)"="-FC" %then %do;
%let libds=%scan(&libds,1,-); /* chop off -FC extension */ %let libds=%scan(&libds,1,-); /* chop off -FC extension */
%let ds0=%mf_getuniquename(prefix=fmtds_); %let ds0=%mf_getuniquename(prefix=fmtds_);
%let libds=&ds0;
/* /*
There is no need to export the entire format catalog here - the validations There is no need to export the entire format catalog here - the validations
are done against the data model, not the data values. So we can simply are done against the data model, not the data values. So we can simply
hardcode the structure based on the cntlout dataset. hardcode the structure based on the cntlout dataset.
*/ */
proc sql; %mddl_sas_cntlout(libds=&ds0)
create table &ds0(
FMTNAME char(32)
,START char(16)
,END char(16)
,LABEL char(256)
,MIN num length=3
,MAX num length=3
,DEFAULT num length=3
,LENGTH num length=3
,FUZZ num
,PREFIX char(2)
,MULT num
,FILL char(1)
,NOEDIT num length=3
,TYPE char(1)
,SEXCL char(1)
,EEXCL char(1)
,HLO char(13)
,DECSEP char(1)
,DIG3SEP char(1)
,DATATYPE char(8)
,LANGUAGE char(8)
);
%let libds=&ds0;
%end; %end;
%mp_filtercheck(&queryds,targetds=&libds,abort=YES) %mp_filtercheck(&queryds,targetds=&libds,abort=YES)

View File

@@ -40,6 +40,7 @@ https://support.sas.com/documentation/cdl/en/proc/61895/HTML/default/viewer.htm#
|`WHICHPATH `|`**OTHER** `|`**OTHER** `|`big fat problem if not path1 `|`1 `|`40 `|`28 `|`28 `|`1E-12 `|` `|`0 `|` `|`0 `|`N `|`N `|`N `|`O `|` `|` `|` `|` `| |`WHICHPATH `|`**OTHER** `|`**OTHER** `|`big fat problem if not path1 `|`1 `|`40 `|`28 `|`28 `|`1E-12 `|` `|`0 `|` `|`0 `|`N `|`N `|`N `|`O `|` `|` `|` `|` `|
<h4> SAS Macros </h4> <h4> SAS Macros </h4>
@li mddl_sas_cntlout.sas
@li mf_dedup.sas @li mf_dedup.sas
@li mf_getfmtlist.sas @li mf_getfmtlist.sas
@li mf_getfmtname.sas @li mf_getfmtname.sas
@@ -94,30 +95,7 @@ create table &outsummary as
%if "&outdetail" ne "0" %then %do; %if "&outdetail" ne "0" %then %do;
/* ensure base table always exists */ /* ensure base table always exists */
proc sql; %mddl_sas_cntlout(libds=&outdetail)
create table &outdetail(
FMTNAME char(32) label='Format name'
,START char(16) label='Starting value for format'
,END char(16) label='Ending value for format'
,LABEL char(256) label='Format value label'
,MIN num length=3 label='Minimum length'
,MAX num length=3 label='Maximum length'
,DEFAULT num length=3 label='Default length'
,LENGTH num length=3 label='Format length'
,FUZZ num label='Fuzz value'
,PREFIX char(2) label='Prefix characters'
,MULT num label='Multiplier'
,FILL char(1) label='Fill character'
,NOEDIT num length=3 label='Is picture string noedit?'
,TYPE char(1) label='Type of format'
,SEXCL char(1) label='Start exclusion'
,EEXCL char(1) label='End exclusion'
,HLO char(13) label='Additional information'
,DECSEP char(1) label='Decimal separator'
,DIG3SEP char(1) label='Three-digit separator'
,DATATYPE char(8) label='Date/time/datetime?'
,LANGUAGE char(8) label='Language for date strings'
);
/* grab the location of each format */ /* grab the location of each format */
%let fmtcnt=0; %let fmtcnt=0;
data _null_; data _null_;

View File

@@ -84,7 +84,7 @@ options noquotelenmax;
""" """
f = open('all.sas', "w") # r / r+ / rb / rb+ / w / wb f = open('all.sas', "w") # r / r+ / rb / rb+ / w / wb
f.write(header) f.write(header)
folders=['base','meta','metax','server','viya','lua','fcmp'] folders=['base','ddl','meta','metax','server','viya','lua','fcmp']
for folder in folders: for folder in folders:
filenames = [fn for fn in Path('./' + folder).iterdir() if fn.match("*.sas")] filenames = [fn for fn in Path('./' + folder).iterdir() if fn.match("*.sas")]
filenames.sort() filenames.sort()

34
ddl/mddl_dc_difftable.sas Normal file
View File

@@ -0,0 +1,34 @@
/**
@file
@brief Difftable DDL
@details Used to store changes to tables. Used by mp_storediffs.sas
and mp_stackdiffs.sas
**/
%macro mddl_dc_difftable(libds=WORK.DIFFTABLE);
proc sql;
create table &libds(
load_ref char(36) label='unique load reference',
processed_dttm num format=E8601DT26.6 label='Processed at timestamp',
libref char(8) label='Library Reference (8 chars)',
dsn char(32) label='Dataset Name (32 chars)',
key_hash char(32) label=
'MD5 Hash of primary key values (pipe seperated)',
move_type char(1) label='Either (A)ppended, (D)eleted or (M)odified',
is_pk num label='Is Primary Key Field? (1/0)',
is_diff num label=
'Did value change? (1/0/-1). Always -1 for appends and deletes.',
tgtvar_type char(1) label='Either (C)haracter or (N)umeric',
tgtvar_nm char(32) label='Target variable name (32 chars)',
oldval_num num format=best32. label='Old (numeric) value',
newval_num num format=best32. label='New (numeric) value',
oldval_char char(32765) label='Old (character) value',
newval_char char(32765) label='New (character) value',
constraint pk_mpe_audit
primary key(load_ref,libref,dsn,key_hash,tgtvar_nm)
);
%mend mddl_dc_difftable;

View File

@@ -0,0 +1,27 @@
/**
@file
@brief Filtertable DDL
@details For storing detailed filter values. Used by
mp_filterstore.sas.
**/
%macro mddl_dc_filterdetail(libds=WORK.FILTER_DETAIL);
proc sql;
create table &libds(
filter_hash char(32) not null,
filter_line num not null,
group_logic char(3) not null,
subgroup_logic char(3) not null,
subgroup_id num not null,
variable_nm varchar(32) not null,
operator_nm varchar(12) not null,
raw_value varchar(4000) not null,
processed_dttm num not null format=E8601DT26.6,
constraint pk_mpe_filteranytable
primary key(filter_hash,filter_line)
);
%mend mddl_dc_filterdetail;

View File

@@ -0,0 +1,22 @@
/**
@file
@brief Filtersummary DDL
@details For storing summary filter values. Used by
mp_filterstore.sas.
**/
%macro mddl_dc_filtersummary(libds=WORK.FILTER_SUMMARY);
proc sql;
create table &libds(
filter_rk num not null,
filter_hash char(32) not null,
filter_table char(41) not null,
processed_dttm num not null format=E8601DT26.6,
constraint pk_mpe_filteranytable
primary key(filter_rk)
);
%mend mddl_dc_filtersummary;

25
ddl/mddl_dc_locktable.sas Normal file
View File

@@ -0,0 +1,25 @@
/**
@file
@brief Locktable DDL
@details For "locking" tables prior to multipass loads. Used by
mp_lockanytable.sas
**/
%macro mddl_dc_locktable(libds=WORK.LOCKTABLE);
proc sql;
create table &libds(
lock_lib char(8),
lock_ds char(32),
lock_status_cd char(10) not null,
lock_user_nm char(100) not null ,
lock_ref char(200),
lock_pid char(10),
lock_start_dttm num format=E8601DT26.6,
lock_end_dttm num format=E8601DT26.6,
constraint pk_mp_lockanytable primary key(lock_lib,lock_ds)
);
%mend mddl_dc_locktable;

View File

@@ -0,0 +1,24 @@
/**
@file
@brief Maxkeytable DDL
@details For storing the maximum retained key information. Used
by mp_retainedkey.sas
**/
%macro mddl_dc_maxkeytable(libds=WORK.MAXKEYTABLE);
proc sql;
create table &libds(
keytable varchar(41) label='Base table in libref.dataset format',
keycolumn char(32) format=$32.
label='The Retained key field containing the key values.',
max_key num label=
'Integer representing current max RK or SK value in the KEYTABLE',
processed_dttm num format=E8601DT26.6
label='Datetime this value was last updated',
constraint pk_mpe_maxkeyvalues
primary key(keytable));
%mend mddl_dc_maxkeytable;

38
ddl/mddl_sas_cntlout.sas Normal file
View File

@@ -0,0 +1,38 @@
/**
@file
@brief The CNTLOUT table generated by proc format
@details This table will actually change format depending on the data values,
therefore the max possible lengths are described here to enable consistency
when dealing with format data.
**/
%macro mddl_sas_cntlout(libds=WORK.CNTLOUT);
proc sql;
create table &libds(
FMTNAME char(32) label='Format name'
,START char(16) label='Starting value for format'
,END char(16) label='Ending value for format'
,LABEL char(256) label='Format value label'
,MIN num length=3 label='Minimum length'
,MAX num length=3 label='Maximum length'
,DEFAULT num length=3 label='Default length'
,LENGTH num length=3 label='Format length'
,FUZZ num label='Fuzz value'
,PREFIX char(2) label='Prefix characters'
,MULT num label='Multiplier'
,FILL char(1) label='Fill character'
,NOEDIT num length=3 label='Is picture string noedit?'
,TYPE char(1) label='Type of format'
,SEXCL char(1) label='Start exclusion'
,EEXCL char(1) label='End exclusion'
,HLO char(13) label='Additional information'
,DECSEP char(1) label='Decimal separator'
,DIG3SEP char(1) label='Three-digit separator'
,DATATYPE char(8) label='Date/time/datetime?'
,LANGUAGE char(8) label='Language for date strings'
);
%mend mddl_sas_cntlout;

View File

@@ -2,13 +2,15 @@
"$schema": "https://raw.githubusercontent.com/sasjs/utils/main/src/types/sasjsconfig-schema.json", "$schema": "https://raw.githubusercontent.com/sasjs/utils/main/src/types/sasjsconfig-schema.json",
"macroFolders": [ "macroFolders": [
"base", "base",
"ddl",
"fcmp", "fcmp",
"meta", "meta",
"metax", "metax",
"server", "server",
"viya", "viya",
"lua", "lua",
"tests/crossplatform" "tests/crossplatform",
"tests/ddl"
], ],
"docConfig": { "docConfig": {
"displayMacroCore": false, "displayMacroCore": false,

View File

@@ -0,0 +1,19 @@
/**
@file
@brief Difftable DDL test
<h4> SAS Macros </h4>
@li mddl_dc_difftable.sas
@li mf_existds.sas
@li mp_assert.sas
**/
%mddl_dc_difftable(libds=WORK.DIFFTABLE)
%mp_assert(
iftrue=(%mf_existds(WORK.DIFFTABLE)=1),
desc=Checking table was created,
outds=work.test_results
)

View File

@@ -0,0 +1,18 @@
/**
@file
@brief Filtertable DDL test
<h4> SAS Macros </h4>
@li mddl_dc_filterdetail.sas
@li mf_existds.sas
@li mp_assert.sas
**/
%mddl_dc_filterdetail(libds=WORK.TEST)
%mp_assert(
iftrue=(%mf_existds(WORK.TEST)=1),
desc=Checking table was created,
outds=work.test_results
)

View File

@@ -0,0 +1,18 @@
/**
@file
@brief Filtersummary DDL test
<h4> SAS Macros </h4>
@li mddl_dc_filtersummary.sas
@li mf_existds.sas
@li mp_assert.sas
**/
%mddl_dc_filtersummary(libds=WORK.TEST)
%mp_assert(
iftrue=(%mf_existds(WORK.TEST)=1),
desc=Checking table was created,
outds=work.test_results
)

View File

@@ -0,0 +1,18 @@
/**
@file
@brief Locktable DDL test
<h4> SAS Macros </h4>
@li mddl_dc_locktable.sas
@li mf_existds.sas
@li mp_assert.sas
**/
%mddl_dc_locktable(libds=WORK.TEST)
%mp_assert(
iftrue=(%mf_existds(WORK.TEST)=1),
desc=Checking table was created,
outds=work.test_results
)

View File

@@ -0,0 +1,18 @@
/**
@file
@brief Maxkeytable DDL test
<h4> SAS Macros </h4>
@li mddl_dc_maxkeytable.sas
@li mf_existds.sas
@li mp_assert.sas
**/
%mddl_dc_maxkeytable(libds=WORK.TEST)
%mp_assert(
iftrue=(%mf_existds(WORK.TEST)=1),
desc=Checking table was created,
outds=work.test_results
)

View File

@@ -0,0 +1,18 @@
/**
@file
@brief mddl_sas_cntlout ddl test
<h4> SAS Macros </h4>
@li mddl_sas_cntlout.sas
@li mf_existds.sas
@li mp_assert.sas
**/
%mddl_sas_cntlout(libds=WORK.TEST)
%mp_assert(
iftrue=(%mf_existds(WORK.TEST)=1),
desc=Checking table was created,
outds=work.test_results
)