Porównanie zawartości bibliotek
Aby szybko porównać zawartość dwóch bibliotek na serwerze AS/400 wystarczy kilka komend CL i znajomość Query lub SQL’a. Ale gdy do porównania jest kilkadziesiÄ…t bibliotek to warto zastanowić siÄ™ nad stworzeniem prostego narzÄ™dzia które wykona tÄ… pracÄ™ za nas, a czas poÅ›wiÄ™cony na jego stworzenie nie bÄ™dzie wiele dÅ‚uższy niż „rÄ™czne” wykonywanie tego zadania.
Stając ostatnio przed takim zadaniem postanowiłem stworzyć komendę, która po podaniu nazw dwóch bibliotek porówna ich zawartość i zwróci wynik w postaci listy obiektów które są w jednej z bibliotek, a nie ma ich w drugiej. Rzecz dotyczyła porównania plików ekranowych i wydrukowych (tak zwanych display files i printer files), ale dodając możliwość wyboru typu obiektu oraz jego atrybutu, komenda staje się bardziej uniwersalna i tak została przygotowana.
NarzÄ™dzie jest proste, pozwala na podanie dwóch nazw bibliotek oraz ewentualnie typu porównywanych obiektów – domyÅ›lnie brane sÄ… pod uwagÄ™ wszystkie obiekty w bibliotece. Komenda sÅ‚użąca do uruchomienia funkcji może wyglÄ…dać nastÄ™pujÄ…co:
CMDÂ Â Â Â Â Â Â PROMPT('Library compare')Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â PARMÂ Â Â Â Â Â KWD(LIBFROM) TYPE(*CHAR) LEN(10) RSTD(*NO) + Â Â Â Â Â Â Â Â Â Â Â Â CHOICE('Name, *LIBL') +Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â PROMPT('Source library')Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â PARMÂ Â Â Â Â Â KWD(LIBTO) TYPE(*CHAR) LEN(10) RSTD(*NO) + Â Â Â Â Â Â Â Â Â Â Â Â Â CHOICE('Name, *LIBL') +Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â PROMPT('Destination library')Â Â Â Â Â Â Â Â Â Â Â Â PARMÂ Â Â Â Â Â KWD(OBJTYPE) TYPE(*CHAR) LEN(10) RSTD(*NO) + Â Â Â Â Â Â Â Â Â Â Â Â DFT(*ALL) CHOICE('*ALL, *type') +Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â PROMPT('Object type')Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â PARMÂ Â Â Â Â Â KWD(OBJATTR) TYPE(*CHAR) LEN(10) RSTD(*NO) + Â Â Â Â Â Â Â Â Â Â Â Â DFT(*ALL) CHOICE('*ALL, attribute') +Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â PROMPT('Object attribute')Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â
Program w języku CL, który zrealizuje opisaną funkcjonalność działa następująco:
- na podstawie parametrów wejściowych przekazanych z komendy, tworzone są w bibliotece QTEMP pliki robocze ze spisem obiektów w każdej z bibliotek;
/* pliki robocze ze spisem obiektów z obu bibliotek */      DSPOBJD   OBJ(&LIBFROM/*ALL) OBJTYPE(&OBJTYPE) +                  OUTPUT(*OUTFILE) OUTFILE(QTEMP/&LIBFROM)    MONMSG    MSGID(CPF2123) EXEC(GOTO CMDLBL(ERRFIN))     Â
- nastÄ™pnie tworzona jest kwerenda w jÄ™zyku SQL która na podstawie zawartoÅ›ci obu zbiorów wybierze te obiekty, które sÄ… w bibliotece źródÅ‚owej a nie ma ich w bibliotece docelowej i utworzy z nich zbiór bazy danych; przy tworzeniu zapytania korzystam z LEFT OUTER JOIN którego sposób dziaÅ‚ania Å›wietnie wyjaÅ›nia poradnik ”A Visual Explanation of SQL Join”;
/* parametr z kwerendÄ… SQL - LEFT OUTER JOIN */Â Â Â Â Â Â Â Â Â Â Â CHGVARÂ Â Â Â VAR(&PARM1) VALUE('create table QTEMP/CMPLIBS + Â Â Â Â Â Â Â Â Â as (select ' *CAT &LIBFROM *TCAT +Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â '.ODOBNM, ' *CAT &LIBFROM *TCAT '.ODOBTP, + Â Â Â Â Â Â Â Â Â Â Â ' *CAT &LIBFROM *TCAT '.ODOBAT from +Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â QTEMP/' *CAT &LIBFROM *TCAT ' left outer +Â Â Â Â Â Â Â Â Â Â Â Â join QTEMP/' *CAT &LIBTO *CAT ' on ' *CAT + Â Â Â Â Â Â Â Â Â Â Â &LIBFROM *TCAT '.ODOBNM = ' *CAT &LIBTO +Â Â Â Â Â Â Â Â Â Â Â Â Â *TCAT '.ODOBNM and ' *CAT &LIBFROM *TCAT +Â Â Â Â Â Â Â Â Â Â Â '.ODOBTP = ' *CAT &LIBTO *TCAT '.ODOBTP +Â Â Â Â Â Â Â Â Â Â Â Â where ' *CAT &LIBTO *TCAT '.ODOBNM is +Â Â Â Â Â Â Â Â Â Â Â Â Â null and ' *CAT &LIBTO *TCAT '.ODOBTP is +Â Â Â Â Â Â Â Â Â Â Â Â null ' *CAT +Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â &PARM2 *TCAT &PARM3 *TCAT ' ) with data')Â Â Â
- jeśli na ekranie komendy wprowadzony został typ wybieranych obiektów i atrybut, do zapytania dołączany jest odpowiedni fragment;
/* parametr z fragmentem kwerendy SQL dotyczÄ…cej wyboru typu obiektu */Â Â Â IFÂ Â Â Â Â Â Â Â COND(&OBJTYPE *NE '*ALL') THEN(CHGVAR +Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â VAR(&PARM2) VALUE(' and ' *CAT &LIBFROM +Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â *TCAT '.ODOBTP =' *CAT '''' *CAT &OBJTYPE +Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â *TCAT ''''))Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â /* parametr z fragmentem kwerendy SQL dotyczÄ…cej wyboru atrybutu obiektu */ IFÂ Â Â Â Â Â Â Â COND(&OBJATR *NE '*ALL') THEN(CHGVAR +Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â VAR(&PARM3) VALUE(' and ' *CAT &LIBFROM +Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â *TCAT '.ODOBAT =' *CAT '''' *CAT &OBJATR +Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â *TCAT ''''))Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â Â
- nastÄ™pnie wystarczy uruchomić utworzone zapytanie – mechanizm i możliwość wykorzystania komendy RUNSQL opisany jest w jednym ze starszych wpisów – i wynik przesÅ‚ać na wyjÅ›cie – do moich potrzeb wystarczyÅ‚a prezentacja na ekranie;
/* uruchomienie kwerendy SQL */                            RUNSQL    SQL(&PARM1) COMMIT(*NONE) NAMING(*SYS) MONMSG    MSGID(SQL9010)                        /* prezentacja wyników na ekranie za pomocÄ… RUNQRY */      RUNQRY    QRYFILE((QTEMP/CMPLIBS))            Â
Ten przykład może być dowodem na to, że w szybki i prosty sposób można tworzyć własne narzędzia i komendy do automatyzacji czynności wykonywanych na co dzień.
Komendę wraz z programem CL i źródłami można pobrać tutaj:
CMPLIBS (643,5 KiB, 872 hits)