I言語システム開発の入門編 8/9 (承認機能の追加)


(8)承認機能の追加。
((★注意:I言語のI520090620(V5.3)以降を必ずインストール下さい,それ以前では問題があって動きません))
承認機能の場合は,色々の解決策がありますので,ここに示すのはほんの一例です。
まず,どのような仕様にするか決めます。
「仕様」
①めったに有ることではないので,承認が必要になった時点で承認者にはメールを送り承認を促す。
②承認者のテーブルを作るが,I言語の持っている認証システム用テーブルも使う。
③承認済みの場合は,市実表を更新出来ないようにする。
【テータ名】----------【データ型】{【I言語の型】}
①ZZZY承認者     CHAR(8){I} (とりあえずZZZZ_I_SECURITY_TABLEのZZZZ_PERSONに合わせる)
(I言語の型が{I}は「ファイル名に出来る半角文字全て」で,とりあえずZZZZ_PERSONに合わせています)
②ZZZYメールアドレス CHAR(160){,L}(メールアドレスは正しくは160文字では足らな場合もありますが, I言語では1項目最大80文字までしか入力出来ません, 今回は取りあえず2項目でメールアドレスを構成するものとします)
(I言語の型が{,L}は型1が空白は「汎用機(EBCDIC)互換半角文字」で,型2がLは英小文字を入力可とします)
(I言語では型1が「!」以外は英小文字も,半角カナも入力できません)
【テーブル名】-------------【主キー】(【従属項目】)
①ZZZY承認者実表    ZZZY承認者{ZZZYメールアドレス}(新規)
②ZZZY市実表       ZZZYし{ZZZY市,ZZZY都道府県,ZZZY承認者}(ZZZY承認者を最後に追加,データ名登録時登録位置注意)
☆すでに,データ辞書とテーブルに関する作成方法は説明したので,作成をした事として以後を説明します。

◎(8.1)最初に承認者を登録するプログラムを「ZZZY承認者実表」使ってZZZZ300138に「承認者 更新処理」で作ってテスト実行して下さい。
この画面ではメールアドレスが80文字しか入力できません,そこで,2項目に分け160文字入力にしてみます。

◎(8.2)修正および作成したプログラムを説明します。
700 DATA={N }?_T?.?&.DATA&~~メールアドレス?
「N」を追加しました。これはこの項目を画面には表示しない事を意味します。,
1010 SQL=,?_SUBSTR?(X1.~~メールアドレス,1,80)
これでX1.~~メールアドレスの1から80文字目までを受信します。
(「?_SUBSTR?」は文字列を抜き出す関数がRDBMSで異なるためシステム変数で対応しています)
(注意:この方法は,全角文字が有る場合は問題が出ます,今回は全角文字無しです)
1020 SQL=,?_SUBSTR?(X1.~~メールアドレス,81,160)
これでX1.~~メールアドレスの81から160文字目までを受信します。
1910 DATA={*}メールアドレス1{80,,,L}メールアドレス1/2
_DATA_COUNTを2のままとしたかったので,最後にDATA=をもってきました。
800行より上に書いた場合は「800 REPEAT=_DATA_COUNT-2」とすれば動きます。
「*」はこの項目を更新処理対象としない意味です。
{80,,,L}のLは英小文字を認める意味です,I言語では型1が「!」以外は英小文字と,半角カナは通常では入力できません。
ここでメールアドレスの前の部分を設定します。
1920 DATA={*}メールアドレス2{80,,,L}メールアドレス2/2
ここでメールアドレスの後の部分を設定します。
1930 =SET{X1.~~メールアドレス=メールアドレス1+メールアドレス2};
X1.~~メールアドレスに値を設定し,更新出来るようにします。
「+」は文字列を結合する意味です。

◎(8.3)これでメールアドレスが160文字分正しく更新出来るようになりました。

◎(8.4)今度は承認者をZZZZ_I_SECURITY_TABLEに有るZZZZ_PERSONのみとします。
プログラムを説明します。
110 TABLE=&X2,?_MP_ZZZZ?_I_SECURITY_TABLE
ZZZZ_I_SECURITY_TABLEを使用するのでTABLEで指定して定義情報を受け取れる様にします。
&X2で別名をX2で設定しています。
メニューの許可と異なるので_Mは使えません,「_MP_+許可」を使って宣言します。
510 =SET{W.ZZZZ_PERSON=X1.~~承認者,W.ZZZZ_PERSON_NAME=};
データ有りの確認を前回はSQL_SETで行いましたが今回はPROGRAMで行うため,初期値を設定しています。
520 =PROGRAM{?&X2.TABLE?}{W.ZZZZ_PERSON}{W.ZZZZ_PERSON_NAME}{0};
{0}でSELECTします,これでW.ZZZZ_PERSONの同じ情報をSELECTしZZZZ_PERSON_NAMEが設定されます。
530 =IF{_PROGRAM_COUNT!=1}ERROR{該当承認者無し};
_PROGRAM_COUNTにSELECTした件数が設定されるので1以外は「該当承認者無し」エラーとします。
540 =SET{X2.ZZZZ_PERSON_NAME=W.ZZZZ_PERSON_NAME};
SELECTされたのでZZZZ_PERSON_NAMEを表示します。
550 DATA={*O}X2.?&X2.DATA&ZZZZ_PERSON_NAME?
検索でZZZZ_PERSON_NAMEを表示する場所を確保します。
{*O}の*はテーブル更新対象では無い事を意味しています。O(OUTPUT)は入力しない事を意味しています。
1210 SQL=LEFT JOIN ?&X2.TABLE? X2 ON X1.ZZZY承認者=X2.ZZZZ_PERSON
1220 SQL=AND X2.Z_CANCEL IS NULL
検索時LEFT JOINでテーブルを結合しZZZZ_PERSON_NAMEを表示します。
LEFT JOINとするのはZZZZ_I_SECURITY_TABLEですでに削除されている使用者でも表示する為です。

◎(8.5)テスト実行してみると画面が上がらないで上記エラーとなります。
これはZZZZ_I_SECURITY_TABLEが無いためプログラム解析時点で異常終了しています。
I言語のインストールではZZZZ_I_で始まるテーブルは本番環境のみにインストールされます,よって, テスト環境には無いためこのような事になってしまいました, そこで,このテーブルを本番からテスト用データベースにコピーします。

◎(8.6)本番環境からコピーするので,ZZZZ010413の「本番からテストへテーブルコピー」を起動します。
ZZZZから始まるテーブルを扱うので使用者は許可ZZZZの管理者である必要があります,そこで使用者'ZZZZZZZZ'でパスワードを入れます。
(メニューの承認がAの場合は都度使用者とパスワードを入れる必要があります)
名前に'ZZZZ_I_SECURITY_T’と入れて[Enter]で検索し,'←','0'

◎(8.7)内容は変更しないので'↓'で最後に行き'YES'「Enter]でコピー完了です。

◎(8.8)再度テスト実行すると今度は拒否されましたと出ました。
これはインストールソフトがテストでもZZZ_I_SECURITY_TABLEを使うであろう事を想定していなかったために起きた事件です, 現インストールではこの問題は解決しないので, 個別に対応する必要がありますが,ZZZZ_I_SECURITY_TABLEは本番で使われているので,開発メニューからは触れません,そこで, 管理メニューで許可ZZZZの管理者が対応する必要があります。
状況説明:ZZZZ_はI言語システム用テーブルでその中でもZZZZ_I_が付いているものは,本番用のみ作られています, 権限はPUBLICに読み込み権限があり,全ての利用者が読む事ができます,本来はテーブル情報にPUBULIC指定ありを設定すべきですが, インストールソフトはこれをしないでテーブルに直接PUBLIC権限を与えているため,今回のようにコーピーした場合はPUBLIC権限が付きません, そこで,テーブル情報にPUBLIC権限を付けます。

◎(8.9)ZZZZ010426「本番テーブルの更新(新規不可)」に行き,使用者'ZZZZZZZZ'で入り,名前に'ZZZZ_I_SECURITY_T'をいれ[Enter]で検索後,
'←','3’,'1'(インデックス),'PUBLIC','↓’,[Enter]で修正します。これで,テスト用テーブルにもPUBLIC権限が付与されて正しく動きます。
I言語でのPUBLIC権限とはそのデータベースを扱える全てのログインIDに対しSELECT権限を与えます。
★このように,I言語と言えどもデータベース上で色々の問題が出ますので,難しいですが,ある程度は知っておくべき事が有りますので説明します。
まず,データベースには大きく3種類の物が登録されます。(SQL Serverのみで他のRDBMSでは大きく違います)
①データベース---テーブルを作る器です。SQL Serverでは全部で8個作られます。(SQL Server以外は1個です)
②ログインID---データベースに接続する時ログインIDを使用して接続します。I言語では全部で16個作られます。
③バックアップデバイス---データベースをバックアップ(保存)する器です。I言語では全部で16個作られます。 (これは開発には直接関係はないので,ここでの説明は省きます)
まずはデータベースから見てみます。

◎(8.10)データベース名一覧を見るためZZZZ010412「SQLを実行」を起動します。ここで全てを見るため必ず'ZZZZZZZZ'の使用者で入ります (メニューの認証が「A]の場合は,必ず使用者を要求してきます) (尚,この作業はSAのパスワードを知っている必要があります)
[Enter]で「」,「LOGIN」(SAでログインする為),「SQL=」(SELECTで検索する場合使用)を'0'で選択します。

◎(8.11)SAで接続するため’Tab'2回でS_PASSWORDに行き「AS」のパスワードを入れ[Enter]で検索します。

◎(8.12)[Enter],'←','2','100','','SELECT NAME FROM MASTER.SYS.DATABASES WHERE NAME LIKE 'I_?_SYSTEM?_%' ORDER BY 1’,[Enter]で作成後, '0'で選択します。

◎(8.13)データベースの一覧が見えました,名前の内訳を説明をします。
①I_:I言語で作るものにはすべて「I_」で始まります。
②ABC:システム名でシステム別に作ります。
③REAL/TEST:REALが本番用でTESTがテスト用です。
④MAST/WORK:MASTがマスタ用でI言語で「テーブル 更新」で作るテーブルはここに作られます,WORKは一時作業で作るテーブル用です。
⑤ZZZZ/ZZZY:許可の単位でデータベースを分けています。
このようにデーターベースを複数持つ事で,管理しやすくしています。

◎(8.14)次はログインIDの一覧を調べます。
'←'、'200'、「Enter]で検索,'←','2','200','','SELECT NAME FROM MASTER.SYS.SYSLOGINS WHERE NAME LIKE 'I_?_SYSTEM?_%' ORDER BY 1',[Enter]で作成後, '0'で選択します。

◎(8.15)ログインIDの一覧です内訳です。
データベースのMASTとWORKの部分はなく,その場所に,DBO,INP,LNK,OUTが有ります。
①DBO:DB Ownerの意味でデータベースの管理者用です。I言語自身がログインする場合は許可ZZZZのDBOを使用します。
プログラムの中でDBO_を命令の先頭に付加した場合はその命令のみ,その許可のDBOでログインし直します。
このログインIDにはDB_OWNERと呼ぶロールを付与しており,そのデータベースの全ての操作が出来る設定になっています。
②INP:INPUTの略でメニューの処理種類を「INPUT」とした場合このログインID付きで接続します。
③OUT:OUTPUTの略でメニューの処理種類を「OUTPUT」とした場合このログインID付きで接続します。
④LNK:リンクサーバーを使用して接続する場合のみこのログインIDを使用します,つまり,リンクサーバーの設定以外では使用しません。
このようにプログラムがログインするIDをI言語が使い分けるので,テーブルの権限の設定が重要になります。
それでは,具体的にどのように権限が設定されているのか確認してみます。

◎(8.16)ZZZZ010211の「テスト テーブル内容 表示,消滅」を起動し,ZZZZの管理者'ZZZZZZZZZZ'を使用者としてパスワード入り,名前に'ZZZZ_SYS_MAST%GRANT'と入力し検索します。
'←','0'で選択します。

◎(8.17)SQLに'WHERE ZZZZ_NAME=N'ZZZY市実表'’と入力し[Enter]します,これで,権限がどのように設定されているのか分かります。
SがSELECT,IがINSERT,UがUPDATE権限です,DはDELETE権限ですがどこにも設定されていないのがI言語の特徴です, つまりDELETEは通常の状態では実行できません,また,許可が自分自身とZZZZのみに与えらてているので, 何もしないとZZZZ以外の他の許可からは一切使えないようになっています。
また,OUTはOUTPUTで検索用ですのでSELECT権限しかありません。

◎(8.18)それでは先ほどPUBLICを指定したZZZZ_I_SECURITY_TABLEを見てみます。
[Esc]で戻って,'↓','0'で次を選択しSQLに'WHERE ZZZZ_NAME=N'ZZZZ_I_SECURITY_TABLE'’と入力し[Enter]します。
今度はZZZY分がないので少ないですが,PUBLICが増えています,PUBLICは全てのログインID共通の設定と同じ事ですので, PUBLICでどのログインIDでもSELECTが実行できます。
ほかに,LNKや他の許可にもSELECT権限を与えられるようになっていますが,ここでは説明を省きます。

◎(8.19)これで承認者 更新のプログラムは完成しましたので実際にZZZZZZZYを承認者として登録します。

◎(8.20)次はZZZZ300131で「承認 処理」を作ります、ZZZZ010221の「テスト 全 プログラム 更新」での「ZZZZY市実表」 からプログラムを作り承認機能に変更します。
プログラムの説明をします。
110 CONTROL=1,2
CONTROL=はI言語に対し細かな指示を与えます。承認は修正処理ですので、「1」で削除の抑止、「2」で作成の抑止を指示しています。
120 BEGIN
ここから下に書いた命令群をプログラムの開始で実行する指定です。
130 =SET{未承認='YES'};
通常では未承認分を検索し承認するので、「未承認」に’YES'を初期値として転送します。
140 SET={,*}未承認{3}{YES,NO};
未承認分のみ(YES)か全て(NO)を指定できる項目を設定します。
{,*}の「*」は検索用SQLの条件としては使用しない事を意味しています。
150 =SET{W.ZZZY承認者=_PERSON,W.未承認=};
PROGRAMで使用するデータに初期値を与えます。
_PERSONはI言語の認証で使われた使用者でこの人が認証する事になります。
160 =PROGRAM{?_M?承認者実表}{W.ZZZY承認者}{}{0};
{0}で検索処理を実行します。
170 =IF{_PROGRAM_COUNT!=1}ERROR{あなたは承認できません!};
検索データが無い場合は「あなたは承認できません!」でエラーとします。
180 =IF{_DATA='YES'}SET{W.未承認='AND X1.~~承認者='' '''};
未承認が「YES」の場合はW.未承認に~~承認者が空白の条件を設定します。
引用符(')の中の引用符は2個で1個と見なします。
900 DATA={O }?_T?.?&.DATA&~~市?
1100 DATA={O }?_T?.?&.DATA&~~都道府県?
~~市と~~都道府県は修正しないので表示のみでOを付加します。
(I言語ではデータが変更されなければSQL文でそのデータを変更する部分は作られないので、更新対象としない意味の*は不要です)
1310 CHECK1=,?_PERSON?
CHECK1=は値一致および範囲一致(最小値、最大値)をカンマ区切りで指定出来ます。
今回は未承認の空白か、使用者のみ入力できるように「,?_PERSON?」と指定しています。
2210 SQL=?W.未承認?
?W.未承認?を検索の条件に付加します。
これで、「承認 処理」は完成しました。

◎(8.21)次はZZZZ300121の「市 更新処理」を修正します。
2310 START
STARTは更新の1,2,3の入力直後に実行するプログラム用です。
2320 =IF{_START!=2}IF{X1.~~承認者!=}ERROR{承認済です!};
_STARTは1,2,3のどれかの値です。
_STARTは2以外かつX1.承認者が空白以外のときは承認済みですので、処理出来ないようにエラー表示します。
2330 =IF{_START=1}EXIT{};
_STARTが1の時はメールアドレス不要なので次に行きます。
2340 =SQL_SET{W.~~メールアドレス}{SELECT ~~メールアドレス FROM
2350 =?_M?承認者実表 WHERE Z_CANCEL IS NULL}
メールアドレスを受信します。(尚、今回はメールアドレスは1個のみを想定しました)
2360 = ERROR{承認者実表に登録情報がありません};
メールアドレスが無い場合はエラーとします。
2910 DATA={*O}?_T?.?&.DATA&~~承認者?
~~承認者は無かったので追加します。
{*O}の*は更新対象で無い事を意味し,OはOUTOUTで入力しない意味です。
2920 STOP_AFTER
STOP_AFTERは更新処理後に実行される処理用です。(更新処理前はSTOP_BEFOREです)
2930 =IF{_START=1}EXIT{};
削除の場合はメール不要ですのでそのまま終了します。
2940 =SMTP{SMTP.MIS.JANIS.OR.JP}{25}{?W.~~メールアドレス?}
2950 ={HARASAWA@MIS.JANIS.OR.JP}{市承認依頼の件}
2960 ={市(?X1.~~し?,?X1.~~市?,?X1.~~都道府県?)
2970 =の承認をよろしくお願いします。};
これでメールを出します。一応確認の画面が出ますので、送信するか、送信しないか選べますが、更新処理は行われます。
★注意:今回は説明が長くなるのでメールサーバーやメールアドレスをプログラムに直接書きましたが、このような事はしないで、 情報は全てプログラムではなくテーブルに持って下さい。
これで、承認機能の追加は全て完了です。
次へ(9/9,インターネットでの公開)
All Rights Reserved, Copyright (C) 2009-2010 Nobumichi Harasawa.