検索

クリアフィルター
記事
Megumi Kakechi · 2024年3月3日

ユーザではなくロールに対してSQL権限を割り当てる方法

これは InterSystems FAQ サイトの記事です。 ユーザに権限を与えたい場合、「GRANT」コマンドや「GrantPrivilegeメソッド」を使用しますが、ロールに対しても権限を与えることができます。 例えば、特定スキーマにのみ何でもできるロールを作成し、それを特定のユーザに割り当てるようなことが可能となります。 こちらの記事では、その方法をご紹介します。 (1) GrantPrivilegeメソッドを使用して「スキーマXXX に何でもできるロール」を作成し、(2) 該当ユーザに (1) のロールを割り当てる ★GRANT文を使う場合 GRANT <priv> ON SCHEMA <your schema> TO <role> 例:ロール testRole に、スキーマ XXX に対する、挿入/更新/参照/削除 の権限を付与します。 GRANT Insert,Update,Select,Delete ON SCHEMA XXX TO testRole ※その他、Alter, References, Execute, Use などの指定も可能です。 こちらは、まだ存在しないスキーマに対しても実行可能です。XXXスキーマにテーブルが登録されれば、自動的にそのテーブルに対して指定した権限が有効になります。 ★$SYSTEM.SQL.Security.GrantPrivilege() を使う場合 GrantPrivilegeメソッド: 例) ロール testRole に、スキーマ XXX に対する、挿入/更新/参照/削除 の権限を付与します set x= $SYSTEM.SQL.Security.GrantPrivilege("Insert,Update,Select,Delete","XXX","Schema","testRole") ※GrantPrivilegeメソッドは、指定されたユーザ (またはユーザのリスト) に特権を付与するメソッドとして周知されていますが、ロールに対して割り当てることも可能です。※その他、Alter, References, Execute, Use などの指定も可能です。※第1引数には、"*" (全指定) の設定も可能です。 まだ存在しないスキーマに対しても実行可能です。XXXスキーマにテーブルが登録されれば、自動的にそのテーブルに対して指定した権限が有効になります。 また逆に、指定のロールから権限を奪うのは、同じ引数で、RevokePrivilegeメソッドを実行してください。 set x=$SYSTEM.SQL.Security.RevokePrivilege(... 付与する権限を変更したい場合は、第1引数を変更します。たとえば "Insert,Update,Select" だけにすれば、挿入/更新/参照 だけが付与されます。 【注意】CREATE TABLE、DROP TABLE については制限があります。現バージョンでは、 CREATE TABLE (%CREATE_TABLE 権限) や DROP TABLE (%DROP_TABLE 権限) については、スキーマ単位で 有無の設定は出来ない仕様となっていますのでご注意ください。CREATE TABLE、DROP TABLE については、ネームスペース単位での権限を与えることが可能です。
記事
Hiroshi Sato · 2024年9月12日

PythonからIRISルーチンに引数を渡すサンプル

これは InterSystems FAQ サイトの記事です。 PythonからObjectScriptのルーチンを直接呼び出すことはできませんが、クラスメソッドを経由して間接的に呼び出すことができます。 しかし、Pythonの変数とObjectScriptのローカル変数は内部構造が異なるため、情報の交換には少し工夫が必要です。 簡単なサンプルでその方法について説明します。 まず、2つの変数を足し算する簡単なルーチン ^testを作ります。 TEST ; set sum = a + b 次にこの^testを呼び出すPythonのメソッドを含んだUser.testというクラスを作ります。 そしてpyという名前のPythonのメソッドを作成します。 先述の通りPythonからObjectScriptのルーチンを直接呼び出すことはできないので、ルーチンを間接的に呼び出すObjectScriptのメソッドを作成する必要があり、そのメソッドをPythonメソッドから呼び出すようにします。 渡したいデータが複数個ある場合、その数分引数を用意するのは面倒なため、Pythonの場合、情報をまとめて交換する際にdictionary(辞書)やlistという構造を使用することができます。 ここでは、dictionaryを使用する例を紹介します。 ClassMethod py() [ Language = python ] { import iris rtn = "^test" # 変数argのdictionary構造にa = 10, b = 20を設定 arg = {"a":10, "b":20} ret = iris.cls('User.test').callrtn(rtn, arg) # 戻り値のdictionary変数retにローカル変数sumの値が設定されている print (ret.get("sum")) } 次にルーチンを呼び出すためのクラスメソッドを定義します。 PythonのDictionary構造をObjectScriptで操作するためには、少し特別な処理が必要です。 ClassMethod callrtn(rtnname As %String, plist As %String) As %Integer [ ProcedureBlock = 0 ] { // python dictから変数を取得 set a = plist."get"("a") set b = plist."get"("b") // 2. ルーチンを実行する do @rtnname // 3. ローカル変数 ==> 戻り値 (python dict) kill rtnname,plist set ret = ##class(%SYS.Python).Builtins().dict() // 存在するローカル変数からdictionaryを生成する set %="%" for { // ローカル変数を順番に取得 set %=$Order(@%) quit:%="" //変数retは除く continue:%="ret" do ret.setdefault(%, @%) } quit ret } 2023.2以降のバージョンではarrayrefのサポートが追加されており、より直感的な処理が可能になりました。 ClassMethod py() [ Language = python ] { import iris rtn = "^test" arg = {"a":10, "b":20} ar = iris.arrayref(arg) ret = iris.cls('Test.pytest').callrtn(rtn,ar) print (ret.get("sum")) } ClassMethod callrtn(rtnname As %String, plist As %String) As %Integer [ ProcedureBlock = 0 ] { set a = plist("a") set b = plist("b") // ルーチン実行 do @rtnname //ローカル変数 ==> 戻り値(python dict) kill rtnname, plist set ret = ##class(%SYS.Python).Builtins().dict() set % = "%" for { set %=$order(@%) quit:%="" continue:%="ret" do ret.setdefault(%, @%) } quit ret }
記事
Megumi Kakechi · 2021年6月30日

管理ポータルのライセンス消費に関する仕様変更について(2012.1以降)

これは InterSystems FAQ サイトの記事です。 2012.1以降管理ポータルの使用もライセンスを消費する様にシステムを変更しました。 これはインターシステムズが定める製品のライセンスポリシーとシステムの動作をできるだけ合わせる一連の措置の1つとして行われました。 この変更に伴いライセンス使用に関わる思わぬトラブルが発生する可能性がありますので注意が必要です。 特にライセンスの解放が管理ポータルページの操作法によって異なるため、その違いを十分認識して対処する必要があります。 管理ポータルのライセンスの解放はページの切断の仕方により以下の様に変わります。 a) ポータルを開き何らかの操作を行った後にログアウトを行うとライセンスは即時解放されます。 b) ポータルのページを開いた後、他に何も操作せずにログアウトを行うと一定の待ち時間の後にライセンスの解放が行われます。 この待ち時間はライセンスの意図的な規約違反を防ぐための措置であるため、設定等で変更できないようになっています。 c) ポータルを開き、ブラウザのXボタンやAlt+F4等のショートカットでページを強制的に閉じた場合は、デフォルトでは8時間後にライセンスの解放が行われます。 ライセンスの解放の時間は以下の操作で変更することができます。 管理ポータル: [システム管理] > [セキュリティ] > [アプリケーション] > [ウェブ・アプリケーション] で /csp/sys/ 以下の全てのアプリケーションを編集してセッションタイムアウトをデフォルトの 28800 秒から変更します。 また、以下のドキュメントもあわせてご参照ください。CSP ライセンス使用 【ご参考】スタジオ、ターミナル、管理ポータルのライセンス消費ユーザをまとめる方法
記事
Megumi Kakechi · 2024年7月28日

SQLでレコードをSelectするとSQLエラー -114 が発生します

これは InterSystems FAQ サイトの記事です。通常SQLCODE -114(一致する行が既に別のユーザにロックされています)のエラーはロックが競合した場合に発生します。 こちらはレコードロック競合があったり、ロック閾値を超える更新を行いテーブルロックに昇格した際に、そのテーブルレコードに対して別のプロセスよりSelectを行い共有ロックを取ろうとして失敗した(ロック待ちがタイムアウトとなった)場合に発生します。 Selectで共有ロックを取る場合というのは、IRIS の ISOLATION LEVEL がREAD COMMITTED(デフォルトはREAD UNCOMMITTED)で、Selectを行った場合です。 例:Sample.Personテーブルにテーブルロックがかかった状態で以下を実行する場合 USER>:sql SQL Command Line Shell ---------------------------------------------------- The command prefix is currently set to: <<nothing>>. Enter <command>, 'q' to quit, '?' for help. [SQL]USER>>set transaction isolation level read committed // Read Committed セット : [SQL]USER>>select Name from Sample.Person where Age < 10 2. select Name from Sample.Person where Age < 10 Name [SQLCODE: <-114>:<ひとつまたはそれ以上のマッチする行が別のユーザによりロックされています>] [%msg: <Unable to acquire shared lock on table Sample.Person for RowID value: 4>] 0 Rows(s) Affected こちらは、 他のプロセスが該当テーブルの該当IDをロックしている ロック閾値によるテーブルロックを行っている システムのロックテーブルが不足しているためのロックテーブルフル状態 のいずれかになっているものと考えられます。 ロックテーブルフルの場合、messages.log に「LOCK TABLE FULL!!!」のエラーが記録されます。 ロックテーブルフルの場合にロックテーブルサイズを変更する方法は、2023.1 より前のバージョンの場合は こちらの記事 をご覧ください。 2023.1以降のバージョンでは、ロックテーブルサイズは既定で 0 に設定されています。0 の場合は、構成されたグローバルバッファサイズ(データベースキャッシュサイズ)に基づき、最も効果的な設定値が自動構成されます。 【ご参考】SQLのUPDATEやDELETEで、ある程度の数のレコードを一括更新するとSQLエラー -110 が発生します
記事
Hiroshi Sato · 2022年10月14日

CachéでCache Directエミュレータを使っているアプリケーションをIRISのCache Directエミュレータに書き換える方法

IRISでは.Net Binding機能が非推奨になったため、VisM.OCXの置き換えのために用意していたCaché版Cache Directエミュレータ(.Net Binding機能を使用していたため)の使用も非推奨となりました。そこでIRISのNative API機能を使用して書き換えたものを作成し、OpenExchange(以下のFAQトピックを参照してください)に登録しています。 FAQのトピック Caché版Cache Directエミュレータを使っているアプリケーションをIRISに移行するためには、IRIS用のCache Directエミュレータに置き換えて、アプリケーションのコードをいくつか書き換える必要があります。 内容は、それぞれのプロジェクトに含まれるコンソールアプリケーションサンプル(consoleApp.cs)を比較することで大体理解できると思いますが、以下にその手順について説明します。 1. IRISの.Net Native API用のdllの参照設定を追加します。 Visual Studioのプロジェクト設定から参照の追加を選び、以下のファイルを追加してください。 c:\InterSystems\IRIS\dev\dotnet\bin\v4.6.2InterSystems.Data.IRISClient.dll 2. using句 Caché版の場合は、以下のusing句が使われていると思います。 using InterSystems.Data.CacheClient;using InterSystems.Data.CacheTypes; IRISでは、以下の様に変更します。 using InterSystems.Data.IRISClient;using InterSystems.Data.IRISClient.ADO; 3. 接続処理およびインスタンスの生成 Caché版の場合は、以下のような記述で接続、インスタンス生成処理を行っていると思います。 cacheDirectWapper cdw = new cacheDirectWapper("Server = localhost; Log File=cprovider.log;Port=1972; Namespace=USER; Password = SYS; User ID = _system;"); IRIS版でも同じ処理で接続、インスタンス生成できます。 IRIS版では先にIRISへの接続を確立後、その接続オブジェクトを使用して接続する方法もサポートしています。 IRISConnection irisconn = new IRISConnection();irisconn.ConnectionString = "Server = localhost; Log File=cprovider.log;Port=1972; Namespace=USER; Password = SYS; User ID = _system;";irisconn.Open();cacheDirectWapper cdw = new cacheDirectWapper(irisconn); 4. プロパティの参照 Caché版の場合には、.Net Bindingの仕様の制約によって、プロパティやメソッドの参照は、以下の様に2段階(.を2つ使用)になっていました。 cdw.cd.P0 = "ABC;DEF;GHI"; IRIS版の場合は、そのような制約がないので、直接1つの.で参照できるようになりました。 cdw.P0 = "ABC;DEF;GHI";
記事
Mihoko Iijima · 2021年6月28日

クラス定義でプロパティ名を変更するとそれまで参照できていたデータが参照できなくなる/参照時にエラーが発生する場合の対処方法

これは InterSystems FAQ サイトの記事です。 クラス定義の Property 定義文の名称を直接変更した場合、内部的には 元のプロパティを削除し、新しいプロパティを追加 したことになります。 このため、すでにデータを格納している永続クラスのプロパティ名をエディタで直接変更した場合、元のプロパティで設定されていた値にはアクセスができなくなります(新しいデータの格納位置が割り当てられます)。 また、変更したプロパティが必須(非ヌル)に指定されていた場合、データが存在しないために参照時にエラーが発生します。 以下の図は、左画面が変更前の状態、右画面がプロパティ名を変更してコンパイルを行った状態です。 基本的に、このような操作を行う場合は、あらかじめデータをエクスポートし、データの削除を行い、クラス定義の変更を行ってから、データを再インポートする方法が安全です。 または、スタジオのメニューの クラス > リファクタ > 名前変更 を利用してプロパティ名を変更します。(リファクタの名前変更メニューにより、クラス定義内のストレージやメソッド定義に対して、一括でプロパティ名を変更できます。) 変更対象のクラス定義を開き、修正したいプロパティ名を選択し、スタジオのメニューの クラス > リファクタ > 名前変更 を選択します。 変更対象の場所を目で確認しながら変更を許可することができます。変更を行った後は、クラス定義のコンパイルを行います。 VSCode または、リファクタメニューがない古いバージョンのスタジオでは、プロパティ名を修正した後、手動でストレージ定義を変更します。 方法:ストレージの定義で、新しいプロパティが元のプロパティと同じ格納位置をポイントするように手動で調整します。 詳細は、以下の通りです。 補足:<Value name="2"> の番号(例は2)は、システムにより任意の数が設定されます。
お知らせ
Seisuke Nakahashi · 2024年6月5日

IRIS 2024.1 日本語ドキュメント公開 & ランチャーからの参照方法

このたび InterSystems IRIS 2024.1 の日本語ドキュメントが完成しました。以下のURLでご参照いただけます。 IRIS 2024.1 IRIS for Health 2024.1 Health Connect 2024.1 Supply Chain Orchestrator 2024.1 ランチャーから日本語ドキュメントを参照したい IRIS for Windows で、ランチャーの [ドキュメント] をクリックしたときに、上記の日本語ドキュメントを表示させることが可能です。 ただし、このメニューのリンク先は http://localhost/<インスタンス名>/csp/docboook/DocBook.UI.Page.cls に固定されているため、日本語ドキュメントを表示させるには以下の手順にしたがい、IRISサーバ上に IIS および HTTPリダイレクト機能をインストールしたうえで、リダイレクトを設定する必要があります。 (1) IIS インストール (まだの場合)IRISサーバ上に、IISをインストールします。PowerShellを管理者モードで起動し、以下実行。再起動は不要。 Install-WindowsFeature -Name Web-Server -IncludeManagementTools (2) HTTPリダイレクト機能追加 (まだの場合)IRISサーバ上のIISに、リダイレクト機能を追加します。PowerShellを管理者モードで起動し、以下実行。要Windows再起動。 Enable-WindowsOptionalFeature -Online -FeatureName IIS-HttpRedirect (3) 日本語ドキュメントへのリダイレクト設定「http://localhost/<インスタンス名>/csp/docbook -> 日本語オンラインドキュメント」へのリダイレクトを設定します。コマンドプロンプトを管理者モードで起動し、以下3行実行。再起動不要。 ※1つめのappcmdの /path は /<インスタンス名>/csp/docbook にします。以下の例では、インスタンス名=IRIS です。※1つめのappcmdの /physicalPath は任意のフォルダで構いません。※2つめのappcmdの /destination は、表示したいドキュメントの docbookj までを指定します。IRIS for Health を表示する場合は以下になります。   /destination:https://docs.intersystems.com/irisforhealth20241/csp/docbookj cd C:\windows\system32\inetsrv appcmd add app /site.name:"Default Web Site" /path:/iris/csp/docbook /physicalPath:c:\temp appcmd set config "Default Web Site/iris/csp/docbook" /section:httpRedirect /enabled:true /destination:https://docs.intersystems.com/iris20241/csp/docbookj appcmdで作った仮想アプリケーション (ここでは /iris/csp/docbook) は、IISコンソール画面から参照できません。appcmd delete app "Default Web Site/iris/csp/docbook" を実行することで削除できます。 ぜひ日本語ドキュメントをご活用いただき、IRIS 製品をより便利にお使いください。
お知らせ
Seisuke Nakahashi · 2025年6月17日

IRIS 2025.1 日本語ドキュメント公開 & ランチャーからの参照方法

このたび InterSystems IRIS 2025.1 の日本語ドキュメントが完成しました。以下のURLでご参照いただけます。 IRIS 2025.1 https://docs.intersystems.com/iris20251/csp/docbookj/DocBook.UI.Page.cls IRIS for Health 2025.1 https://docs.intersystems.com/irisforhealth20251/csp/docbookj/DocBook.UI.Page.cls Health Connect 2025.1 https://docs.intersystems.com/healthconnect20251/csp/docbookj/DocBook.UI.Page.cls Supply Chain Orchestrator 2025.1 https://docs.intersystems.com/supplychain20251/csp/docbookj/DocBook.UI.Page.cls IRIS for Windows では、ランチャーの [ドキュメント] をクリックしたときに、好きな日本語ドキュメントを表示させることができます。 ランチャーのドキュメントリンク先は、デフォルトでは英語ドキュメントに飛ぶようになっています。ご希望の日本語ドキュメントを表示させるには、IRISサーバがIISを利用している場合は、IRISサーバ上で以下の(1)(2)を実行し、HTTPリダイレクト機能をインストール&リダイレクトを設定する必要があります。 (1) IIS HTTPリダイレクト機能追加 (まだの場合) IRISサーバ上のIISに、リダイレクト機能を追加します。[Windows の機能の有効化または無効化]→[インターネット インフォメーション サービス]→[World Wide Web サービス]→[HTTP 共通機能]→[HTTP リダイレクト]→[OK] (2) 日本語ドキュメントへのリダイレクト設定 IRISサーバ上でコマンドプロンプトを管理者モードで起動し、以下3行を実行してください。これにより、希望の日本語オンラインドキュメントへのリダイレクトが設定されます。 注意※2行目の /path は /<インスタンス名>/csp/docbook になります。以下の例では、インスタンス名=IRIS です。また、 /physicalPath は任意のフォルダで構いませんが、フォルダが存在している必要があります。※3行目の /destination は、表示したいドキュメントの docbookj までを指定します。以下の例では、IRIS for Health にリンクしています。 cd C:\windows\system32\inetsrv appcmd add app /site.name:"Default Web Site" /path:/iris/csp/docbook /physicalPath:c:\inetpub\docbook appcmd set config "Default Web Site/iris/csp/docbook" /section:httpRedirect /enabled:true /destination:https://docs.intersystems.com/irisforhealth20251/csp/docbookj IRISサーバが Apache を利用している場合は、こちら の手順をご覧ください。 なお、過去バージョンを含めた、日本語ドキュメント一覧は こちら からご確認いただけます。ぜひ日本語ドキュメントをご活用いただき、IRIS 製品をより便利にお使いください。
記事
Megumi Kakechi · 2025年1月7日

タスク履歴にある「有効期限切れになりました」メッセージの意味と対処法について

これは InterSystems FAQ サイトの記事です。こちらの記事では、タスク履歴の結果内容に、「タスクは 10 Apr 20xx 12:00:00AM 19 Aug 20xx 12:00:00AM から継続中 に有効期限切れになりました」のようなログがある場合、その意味と対処方法について説明します。 このログは、実行予定のタスクをチェックした際に、時間が対象タスクの有効期限を過ぎてしまったために、表示しているログになります。有効期限を指定していない場合(※)は、次回タスク予定時刻が有効期限になります。※有効期限の設定は、^TASKMGRユーティリティから行うことができます。 例えば、毎分実行予定のタスクスケジュールがあった場合、実行タスクの実行時間が1分を超える場合、仮に130秒とする場合、1分後と2分後に予定していたタスクスケジュールは実行することができなかったことになります。この場合、3分後のタスクスケジュール以降実行されることになり、実行されなかったタスクは、「タスクが次のスケジュール時刻を過ぎても実行を続けています」とログされ、次に正常に実行できたタスクの後に「タスクは YYYY-MM-DD hh:mm YYYY-MM-DD hh:mm から継続中 に有効期限切れになりました」のようにログされます(タスク履歴へ)。 タスクが何らかのエラー等が原因で終了した場合は、タスクは一時停止状態(Suspended)になり、再開(Resume)しなければ以後は動作しません。タスクを再開した場合、以前のタスクは有効期限が切れてしまったことになりますので、上記の例と同様に有効期限切れのログが残ります。 なお、「有効期限切れになりました」ログの原因を取り除かない限り、ログは出力し続けて同じ状態が続くことになります。このログが出力されるような場合は、タスクスケジュールの見直しや、実行タスクの見直し(エラー終了の場合)等で、原因を排除するようにしてください。 【ご参考】エラー解消後もジャーナル切り替えタスクの状態が Suspend Leave になっている場合の対処方法
記事
Toshihiko Minamoto · 2022年4月21日

ObjectScript Package Manager のユニットテストとテストカバレッジ

この記事では、ObjectScript Package Manager( を参照)を使用して、ユニットテストを実行するためのプロセスを説明します。テストカバレッジ測定( を使用)も含まれます。 ## ObjectScript でのユニットテスト ObjectScript でユニットテストを記述する方法については、素晴らしいドキュメントがすでに存在するため、ここでは繰り返しません。 ユニットテストのチュートリアルは、こちらをご覧ください: ユニットテストは、「/tests」など、ソースツリーの別の場所に含めるのがベストプラクティスです。 InterSystems 内では、デファクトスタンダードとして、/internal/testing/unit_tests/ を使用しています。テストは社内用/非配布用であり、ユニットテスト以外の種類のテストもあるため、これが意に適うためではありますが、単純なオープンソースプロジェクトでは、多少複雑になるかもしれません。 InterSystems の一部の GitHub リポジトリでは、この構造が使用されています。 ワークフローの観点では、VSCode では非常に簡単に行えます。ディレクトリを作成して、そこにクラスを配置するだけです。 より旧式のサーバー中心型のソース管理アプローチ(Studio で使用されているアプローチ)の場合、このパッケージを適切にマッピングする必要があります。このアプローチは、ソース管理拡張機能ごとに異なります。 ユニットテストクラスの命名規則の観点では、個人的には以下を気に入っています(私の所属するグループにおいてはベストプラクティスです)。 UnitTest.<テストされるパッケージ/クラス>[.<テストされるメソッド/機能>] たとえば、MyApplication.SomeClass クラスのメソッド Foo のユニットテストであれば、ユニットテストクラスは UnitTest.MyApplication.SomeClass.Foo と名付けられます。一方で、クラス全体のテストであれば、単に UnitTest.MyApplication.SomeClass となります。 ## ObjectScript Package Manager でのユニットテスト ObjectScript Package Manager でユニットテストを認識させるのは簡単です! 以下のように、module.xml に行を 1 つ追加するだけです( から抜粋。Open Exchange の @Peter.Steiwer による優れた数学パッケージのフォークです。これは単純なサンプルとして使用しています)。 `` ` ...` ` ` `` 上記は次のように解釈します。 * ユニットテストは、モジュールのルート配下にある「tests」ディレクトリにあります。 * ユニットテストは「UnitTest.Math」パッケージにあります。 テストされるクラスは「Math」パッケージに含まれるため、合理的です。 * ユニットテストは、パッケージライフサイクルの「test」フェーズで実行します。 (テストが実行できる「verify」フェーズもありますが、これについては後日お話しします。) ### ユニットテストの実行 上記で説明されたとおりにユニットテストを定義したら、Package Manager でそれを実行するための非常に便利なツールを使用することができます。 %UnitTest.Manager と同じように ^UnitTestRoot などを設定することも可能ですが、特に同じ環境で複数のプロジェクトの作業を行っている場合には、次のオプションを使用する方がはるかに簡単だと思います。 このすべては、上記にリストされている objectscript-math リポジトリのクローンを作成してから `zpm "load /path/to/cloned/repo/"` で読み込むか、「objectscript-math」を自分のパッケージ名(とテスト名)に入れ替えて独自のパッケージで実行することができます。 モジュールを再読み込みしてからすべてのユニットテストを実行する: `zpm "objectscript-math test"` ユニットテストのみを実行する(再読み込みなし): `zpm "objectscript-math test -only"` ユニットテストのみを実行し(再読み込みなし)、詳細出力を取得する: `zpm "objectscript-math test -only -verbose"` 再読み込みを行わずに特定のテストスイート(テストのディレクトリ、この場合は UnitTest/Math/Utils のすべてのテスト)のみを実行し、詳細出力を取得する: `zpm "objectscript-math test -only -verbose -DUnitTest.Suite=UnitTest.Math.Utils"` 再読み込みを行わずに特定のテストケース(この場合は UnitTest.Math.Utils.TestValidateRange)のみを実行し、詳細出力を取得する: `zpm "objectscript-math test -only -verbose -DUnitTest.Case=UnitTest.Math.Utils.TestValidateRange"` または、1 つのテストメソッドに存在する問題を解決するだけである場合は、以下のようにします。 `zpm "objectscript-math test -only -verbose -DUnitTest.Case=UnitTest.Math.Utils.TestValidateRange -DUnitTest.Method=TestpValueNull"` ObjectScript Package Manager を使ったテストカバレッジ測定 ユニットテストがあっても、それがうまく機能するのかを知るにはどうすればよいのでしょうか。 テストカバレッジを測定するだけでは、この疑問に完全に答えることはできませんが、少なくとも役には立ちます。 このことについては、2018 年の Global Summit でお話ししました。https://youtu.be/nUSeGHwN5pc をご覧ください。 最初に行うべきことは、テストカバレッジパッケージをインストールすることです。 `zpm "install testcoverage"` これには ObjectScript Package Manager によるインストール/実行は不要であることに注意してください。詳しくは、Open Exchange をご覧ください: とは言っても、ObjectScript Package Manager も使用するのであれば、テストカバレッジツールを最大限に活用することができます。 テストを実行する前に、テストでカバーしたいクラス/ルーチンを指定する必要があります。 非常に大型のコードベース(HealthShare など)においては、プロジェクト内のすべてのファイルに使用するテストカバレッジを測定して収集してしまうと、システムに装備されている以上のメモリが必要となる場合があるため、このステップは重要です。 (具体的には、行単位モニターの gmheap です。) ファイルのリストは、ユニットテストのルート内の coverage.list というファイルに出力されます。つまり、ユニットテストの別のサブディレクトリ(スイート)にそれぞれのリストが格納されるため、テストスイートが実行する間、追跡されるクラス/ルーチンがオーバーライドされます。 objectscript-math を使った単純な例については、 をご覧ください。[テストツールのユーザーガイド](https://github.com/intersystems/TestCoverage#user-guide)ではさらに詳しく説明されています。 テストカバレッジ測定を有効にしてユニットテストを実行する場合、コマンドにはもう 1 つ引数を追加します。テストを実行するために、%UnitTest.Manager の代わりに TestCoverage.Manager が使用することを指定するのです。 `zpm "objectscript-math test -only -DUnitTest.ManagerClass=TestCoverage.Manager"` 出力には、詳細モードでなくても、ユニットテストでカバーされたクラス/ルーチンの行と一部の集計された統計情報を確認できる URL が含まれます。 ## 今後の内容 このすべてのプロセスを CI で自動化してはどうでしょうか。 ユニットテストの結果とカバレッジのスコア/差をレポートするにはどうすればよいでしょうか。 こういったことも、実現可能です! Docker、Travis CI、および codecov.io を使用した簡単な例について、 をご覧ください。将来、いくつかの異なるアプローチを説明する記事を書く予定です。
記事
Mihoko Iijima · 2023年4月4日

PythonからNativeAPIを利用してIRISに接続する AWS Lambda関数を作成するまでの流れ

開発者の皆さん、こんにちは。 Python Native APIを利用すると、IRISにあるグローバル変数の参照/更新をPythonから行えたり、メソッドやルーチンをPythonから実行することができます。 この記事では「AWS Lambda の IRIS Python Native API IRIS」の記事を参考に、NativeAPIを利用してPythonからIRISに接続するAWS Lambda関数を作成する流れで必要となる、レイヤー作成と関数用コードの作成例をご紹介します。 ※ 事前にAWSのEC2インスタンス(Ubuntu 20.04を選択)にIRISをインストールした環境を用意した状態からの例でご紹介します。 「AWS Lambda の IRIS Python Native API IRIS」の記事では、レイヤーとコードをまとめたZipを用意してLambda関数を作成していますがこの記事ではレイヤーとコード用Zipをそれぞれ用意して作成する流れでご紹介します。 NativeAPIについて詳しくは、「【はじめての InterSystems IRIS】セルフラーニングビデオ:アクセス編:Python の NativeAPI に挑戦」をご参照ください。 AWS Lambda関数のレイヤー作成、関数作成の流れは、別の記事:「PyODBC経由でIRISに接続するAWS Lambda関数を作成するまでの流れ」 と同様のため、この記事では詳細な作成手順について割愛しています。詳細な流れは記事をご参照ください。 以下の流れでご紹介します。 Native API レイヤー用Zipの作成 サンプルのクラス定義のインポート 関数の作成とテスト実行 CloudformationのYAML例 例で使用しているコード一式はこちらにあります👉https://github.com/Intersystems-jp/iris-native-lambda 1. Native API レイヤー用Zipの作成 Native API用モジュールのレイヤーを以下の手順で作成します。 レイヤー作成用の任意ディレクトリを用意し、その下に python ディレクトリを用意します。 mkdir python cd python wget https://github.com/intersystems/quickstarts-python/raw/master/Solutions/nativeAPI_wheel/irisnative-1.0.0-cp34-abi3-linux_x86_64.whl unzip irisnative-1.0.0-cp34-abi3-linux_x86_64.whl cd .. zip -r9 ../iris_native_lambda.zip * この流れで作成したZipの例:iris_native_lambda.zip 2.サンプルのクラス定義のインポート Native APIでは、IRIS内のメソッドやルーチンをPythonから実行できるのでサンプルでは Test.Utils に用意したメソッドを実行しています。 Pythonのサンプルスクリプト:index.pyを試す場合は事前にインポートしてください。 インポートは管理ポータルから、またはVSCodeから、またはUtils.clsをIRISをインストールした環境に転送後、ユーティリティからインポートすることができます。 管理ポータルからインポートする場合 http://IPアドレス:52773/csp/sys/UtilHome.csp にアクセスし、システムエクスプローラ→クラス→ネームスペース:USER→インポートボタン をクリックします。 Utils.clsをファイルに指定してインポートを行ってください。 VSCodeを利用する場合 VSCodeにObjectScriptエクステンションをインストール後、IRISに接続しUtils.cls保存します(Ctrl+S)。 詳細は VSCode を使ってみよう!をご参照ください。 Utils.clsをIRISをインストールした環境に転送後、ユーティリティからインポートする場合 Utils.cls を /usr/irissys/mgr/user ディレクトリに配置した状態での実行例です。 IRISにログインします(USERネームスペースにログインしています)。 iris session IRIS インポート用ユーティリティを利用してインポートを実施します。 do $system.OBJ.Load("/usr/irissys/mgr/user/Utils.cls","ck") 実行例は以下の通りです。 USER>do $system.OBJ.Load("/usr/irissys/mgr/user/Utils.cls","ck") Load started on 03/27/2023 09:36:21 Loading file /usr/irissys/mgr/user/Utils.cls as udl Compiling class Test.Utils Compiling routine Test.Utils.1 Load finished successfully. USER> インポートしたクラス:Test.Utilsには以下のクラスメソッドが用意されています。(全メソッド、JSON文字列を戻り値で返すように作成しています) メソッド名 内容 Hello() IRISのバージョンと実行時の日付時刻を戻り値で返します。 CreateDummyTbl() テスト実行に使用するTest.Personテーブルの作成とサンプルデータ(2レコード)を作成します。 GetPerson() Test.PersonテーブルのSELECTの結果を返します。 CreateDummyGlo() Pythonからグローバル変数の操作例に使用するサンプルグローバル ^KION を作成します。 3. 関数の作成とテスト実行 1.Native API レイヤー用Zipの作成 の手順で作成したレイヤー用Zip:iris_native_lambda.zipと、Pythonスクリプトのサンプルコード:index.py と 接続情報を記載するファイル:connection.config をZipにしたファイル:iris_native_code.zipを利用してAWS Lambda関数を作成します。 Lambda 関数作成とテスト実行の流れついては、開発者コミュニティの記事:PyODBC経由でIRISに接続するAWS Lambda関数を作成するまでの流れ:(6) レイヤーの作成以降をご参照ください。 確認:IRISへの接続情報について サンプルのpythonスクリプト:index.py では、以下いずれかの方法でIRISに接続できるように記述しています。 環境変数を使用する場合 index.pyには、lambda関数作成時に設定する環境変数を利用するように記述しています(19~23行目) 。 なお、環境変数は、Lambda関数登録後、画面で追加/変更できます。 connection.config を使用する index.py の10行目と12~16行目のコメントを外し19~23行目をコメント化して利用します。接続するIRISの情報に合わせて connection.config を変更してください。 メモ:Lambda関数に設定する環境変数例は以下の通りです。 テスト実行の引数例 ※引数に指定するJSONのプロパティに指定が不要な場合は、"none" を設定してください。 TestlUtilsクラスのHello()メソッドを実行する場合の引数例 { "method": "Hello", "function":"none", "args": "none" } 以下のような戻り値が返ります。 "{\"message\":\"こんにちは!今の時間は:2023年3月27日 10:16:05です\",\"status\":1,\"payload\":\"IRIS for UNIX (Ubuntu Server 20.04 LTS for x86-64) 2022.1.2 (Build 574U) Fri Jan 13 2023 15:03:40 EST\"}" Test.Personテーブルの作成とダミーデータの登録する場合の引数例 (TestlUtilsクラスのCreateDummyTbl()メソッドを実行する場合) { "method": "CreateDummyTbl", "function":"none", "args": "none" } 以下の戻り値が返ります。 "{\"Message\":\"登録完了\"}" Test.PersonテーブルのSELECTの結果を取得する場合の引数例 (Test.UtilsクラスのGetPetPerson()メソッド実行する場合) { "method": "GetPerson", "function":"none", "args": "none" } 以下の戻り値が返ります。 "[{\"Name\":\"山田\",\"Email\":\"taro@mail.com\"},{\"Name\":\"斉藤\",\"Email\":\"saito@mail.com\"}]" ^KIONグローバル変数を設定する例 (Test.UtilsクラスのCreateDummyGlo()メソッドを実行する場合の引数例) { "method": "CreateDummyGlo", "function":"none", "args": "none" } 以下の戻り値が返ります。 "{\"Message\":\"登録完了\"}" index.pyのFunctionを動かす例 (^KION全データ取得する get_globaldata()関数を実行する例) { "method":"none", "function":"getglobal", "args":"none" } 以下の戻り値が返ります。 "[[\"久留米\", 14, 19], [\"大阪\", 12, 18], [\"奈良\", 10, 18], [\"愛知\", 13, 15], [\"新潟\", 6, 12], [\"東京\", 14, 19], [\"沖縄\", 21, 26]]" index.pyのFunctionを動かす例 (^KIONにデータを追加するset_kiondata()関数を実行する場合の引数例) { "method":"none", "function": "setglobal", "args": {"area":"長野","min":5,"max":10} } 正しくデータ登録できたかどうかは、get_globaldata()関数を再度実行すると確認できます。 以下、get_globaldata()関数を再実行した場合の戻り値の例です。 "[[\"久留米\", 14, 19], [\"大阪\", 12, 18], [\"奈良\", 10, 18], [\"愛知\", 13, 15], [\"新潟\", 6, 12], [\"東京\", 14, 19], [\"沖縄\", 21, 26], [\"長野\", 5, 10]]" 4. CloudformationのYAML例 例:cloudformation.yml 実行の流れについては、「[PyODBC経由でIRISに接続するAWS Lambda関数を作成するまでの流れ]の」3. 1,2の流れをCloudformationで行う例と同様です。
記事
Toshihiko Minamoto · 2024年3月28日

150 行未満のコードで IRIS クロスファンクショナルアプリを作成する

ローコードへの挑戦 こんな状況を思い浮かべてください。「ウィジェットダイレクト」というウィジェットとウィジェットアクセサリーを販売する一流のネットショップで楽しく勤務しています。先日、上司から一部の顧客がウィジェット商品にあまり満足していないという残念な話を聞き、苦情を追跡するヘルプデスクアプリケーションが必要となりました。さらに面白いことに、上司はコードのフットプリントを最小限に抑えることを希望しており、InterSystems IRIS を使って 150 行未満のコードでアプリケーションを提供するという課題をあなたに与えました。これは実際に可能なのでしょうか? 免責事項: この記事は、非常に基本的なアプリケーションの構築を記すものであり、簡潔さを維持するために、セキュリティやエラー処理などの重要な部分は省略されています。このアプリケーションは参考としてのみ使用し、本番アプリケーションには使用しないようにしてください。この記事ではデータプラットフォームとして IRIS 2023.1 を使用していますが、それ以前のバージョンでは記載されているすべての機能が提供されているとは限りません。 ステップ 1 - データモデルの定義 クリーンなネームスペースを新規に定義することから始めましょう。CODE と DATA データベースを使用します。 すべてを 1 つのデータベースで賄うことはできますが、分割してデータのリフレッシュを実行できるようにすると便利です。 このヘルプデスクシステムには 3 つの基本クラスが必要です。スタッフアドバイザーユーザーアカウント(UserAccount) と顧客連絡先ユーザーアカウント(UserAccount)間のやり取りを文書化するアクション(Actions)を含められる Ticket オブジェクトです。 19 行のコードで完全なデータモデルができました!2 つのクラスはデータベースに保存できるように Persistent(永続)に設定し、%JSON.Adapter を継承しています。この継承によって、JSON フォーマットでのオブジェクトのインポートとエクスポートを非常に簡単に行うことができます。テストとして、最初のユーザーをターミナルにセットアップし、保存してから JSONExport が正しく動作することを確認します。 すべてうまくいったようです。上司から、スタッフと顧客のリストが含まれる csv ファイルを渡されました。これを解析して読み込むコードを書くことは可能ですが、簡単に行う方法はないものでしょうか? ステップ 2 - データの読み込み InterSystems IRIS には、CSV ファイルから簡単にデータを読み込み、ヘッダーの解析やフィールド名の変更のオプションも使用できる SQL のLOAD DATA ステートメントが備わっています。使い方も単純です。では、それを使用してユーザーテーブルを読み込んでみましょう。 ヘッダーラベルを使ってこのデータを抽出し、データベースに読み込みます。 1 つのコマンドで全 300 行のデータがインポートされました。この 4 行のコードを加えると、合計 23 行のコードが記述したことになります。これらのレコードが正しいことを、基本的な SQL の SELECT を使って素早く確認してみましょう。 最初のデータを得られました。では、フロントエンドを接続できる基本的な API を作成しましょう。この API は、JSON を送受信する REST サービスとして作成します。 ステップ 3 - REST API の作成 InterSystems IRIS には、%CSP.REST クラスの継承を通じてネイティブの RESTサポートが備わっています。そこで、REST.Dispatch クラスを作成して %CSP.REST を継承することにします。このクラスは、URL と動詞をメソッドにマッピングする XData UrlMap と、これらの URL から呼び出されるメソッドの 2 つのセクションで構成されます。 ここで作成する実用最低限のツールには、スタッフまたは顧客のユーザーリストの取得、発行された最近のチケットの取得、ID 番号による単一のチケットの取得、および新しいチケットの作成の 4 つの演算が必要です。ここで使用する動詞を定義してからメソッドを定義します。 GetUserList は、直接 JSON にデータを出力する基本的な埋め込み SQL カーソルです。その後で、ネイティブの JSON 機能を使ってこれを解析し、JSON 配列にプッシュして、レスポンス本文として送信することができます。URL から直接クエリにスタッフ変数を渡して、データのコンテキストを変更します。 TicketSummary はほぼ同じですが、クエリは TICKET テーブルにアクセスします。 TicketSummary は最もシンプルなサービスです。ID でオブジェクトを開き、組み込みの %JSONExport を出力に書き込みます。オブジェクトが読み込みに失敗する場合、エラーパケットを出力します。 最後に、UploadTicket は最も複雑なメソッドです。 リクエストオブジェクトからペイロードを読み取り、JSON に解析してから %JSONImport を使って Ticket の新しいインスタンスに適用します。また、入力を待つ代わりに現在の時間から OpenDate と OpenTime も設定します。正しく保存できたら、オブジェクトの JSON 表現を呼び出すか、読み込み失敗する場合はエラーを返します。 このサービスにより、さらに 60 行のコードが全体に追加されました。これで、このアプリケーションの合計コード行数は、89 行になりました。 次は、セキュリティ > アプリケーションに Web アプリケーションを作成する必要があります。これには REST タイプのアプリケーションに設定し、クラス名を今作成したディスパッチクラスとして設定する必要があります(このアプリケーションがコードとデータにアクセスできるように適切なセキュリティロールを付与する必要があることに注意してください)。保存すると、REST サービスを定義した URL から呼び出せるようになります。 UserList を呼び出して確認してみましょう。 これで、データを作成する準備ができました。REST クライアントを使用して、ペイロードをチケット作成サービスに送信してみましょう。Keyword、Description、Advisor、および Contact を提供すると、作成したチケットの JSON が OpenDate と TicketId と共に返されます。 これで実用最低限のツールが完成しました。任意のフロントエンドフォームビルダーを使用して、REST サービス経由でチケット情報を送受信できるようになりました。 ステップ 4 - 相互運用性の要件 たった 89 行のコードで基本的なチケット管理アプリケーションが完成しました。上司も絶対に驚いたのでは?確かにそうですが、上司から悪い知らせを受けました。要件を逃しているというのです。ウィジェットダイレクトにはフランス語圏での特別な契約があり、フランス語によるチケットはすべて初回レビューを行う Mme Bettie Francis(ベティー・フランシス)を通過しなければならないのです。幸いにも、Robert Luman の Python 自然言語サポートに関する優れた記事を読み、テキストサンプルを受け入れて言語を識別できる REST サービスを作成したことのある同僚がいました。InterSystems IRIS 相互運用性を使用してこのサービスを呼び出し、テキストがフランス語であればアドバイザーを自動的にフランシスさんに更新するようにすることはできるでしょうか? まずは、リクエストを送受信できるように、メッセージクラスを作成することから始めましょう。チケット ID とサンプルテキストを格納するリクエストと、言語コードと説明を返すレスポンスが必要です。 それぞれ Ens.Request と Ens.Response を継承します。 さて、さらに 6 行が追加され、合計 95 行のコードとなりました。次に演算を作成する必要があります。同僚のサービスにリクエストを送信して回答を取得する演算です。Outbount Operation を Server と URL のプロパティで定義し、これらを SETTINGS パラメーターに含めてユーザー構成に公開します。こうすることで、サーバーのパスが変更した場合に簡単にリクエストを更新できます。HTTPRequest をセットアップするヘルパーメソッドを作成してから、それを使用してサービスを呼び出し、レスポンスを作成します。 27 行のコードが追加され 100 行を超え、合計 122 行となりました。次に、このクラスを Ensemble 本番環境内にセットアップする必要があります。相互運用性の本番構成に移動し、「演算」ヘッダーの下にある「追加」を押します。クラス名と表示名で演算をセットアップしましょう。 次に、それをクリックして設定を開き、サーバー名と URL を入力して演算を有効にします。 次に、チケット ID を取り、入力されたユーザーアカウント ID をアドバイザーに設定する 2 つ目の演算が必要です。メッセージと演算クラスが必要ですが、この場合レスポンスは返さず、演算はフィードバックなしでタスクを実行します。 さらに 12 行が追加され、合計 134 行になりました。言語サービスを追加した方法でこの演算を本番環境に追加しますが、この場合、構成を設定する必要はありません。 次に、サービスを呼び出し、レスポンスを評価し、オプションとしてフランス語アドバイザーの演算を呼び出すルーターが必要です。「相互運用性」>「ビルド」>「ビジネスプロセス」に移動し、ビジュアルルールビルダーを開きます。リクエストとレスポンスのコンテキストを設定してから、呼び出しの項目を追加します。作成したメッセージクラスに入力と出力を設定したら、リクエストビルダーを使って入力をマッピングします。「非同期」フラグのチェックがオフになっていることを確認してください。レスポンスを待ってから処理を進めるためです。 次に「If」項目を追加して、返される言語コードを評価します。「fr」であれば、FrenchAdvisor 演算を呼び出すようにします。 フランシスさんのユーザー ID は 11 であるため、AdvisorUpdate メッセージを FrenchAdvisor サービスに供給するように呼び出しオブジェクトを設定し、ビルダーを使って、TicketID と固定値 11 を Advisor パラメーターに渡します。 「プロセス」ヘッダーの下にある「追加」をクリックし、クラスを選択して表示名「FrenchRouter」を指定したら、本番にこれを追加します。 これでルーティングが設定されました。 後は、新しいチケットをスキャンして、ルーターでの処理に送信するサービスが必要です。SQL アダプターに従ってサービスクラスを定義します(さらに 8 行のコードが追加されます)。 次に、演算オブジェクトとプロセスオブジェクトと同じようにして、これを本番に追加します。SQL アダプターのセットアップが必要です。ODBC DSN を介してローカルデータベースへの接続情報を提供し、CallInterval 設定に設定されたタイマーでチケットをクエリするためにサービスが使用する基本的な SQL クエリを指定します。このクエリはクエリに一意のキーを定義し、送信済みのレコードが再送信されないようにする「キーフィールド名」設定と組み合わされます。 この設定により、新しいチケットをスキャンし、テキストを外部サービスに渡して言語を解析し、オプションとしてこのレスポンスに応じてアドバイザーをリセットする処理が完成しました。では試してみましょう!英語のリクエストを送信してみましょう。これは TicketID 70 で返されます。数秒待ってから、GetTicket REST サービスを介してこのレコードにアクセスすると、アドバイザーは元のリクエストから変わっていないのがわかります。 では、フランス語のテキストを使ってみましょう。 チケット ID 71 をリクエストすると、期待どおり、アドバイザーはフランシスさんに変更されています! これは相互運用性内で、ビジュアルトレースでメッセージの場所を探し、演算が期待どおりに呼び出されたことを確認すればわかります。 この時点でのコード行数は 142 行であり、データを永続させ、LOAD DATA でデータを読み込み、データの表示と編集を行える基本的な REST API と、外部 REST サービスへの呼び出しに基づいて意思決定サポートを提供する高度な統合エンジンを備えた InterSystems IRIS アプリケーションが出来上がりました。これ以上のことを求める人はきっといないですよね? ステップ 5 - 更なる要求: 分析 このアプリケーションは大成功をおさめ、データもさらに増えています。この貴重データを利用するには専門知識が必要であり、ウィジェットダイレクトの経営陣はインサイトを希望しています。データへの対話型アクセスを提供できるでしょうか? InterSystems IRIS Analytics を使用すると、高度なデータ操作ツールを素早く簡単に利用できます。まずは、内部 Web アプリケーションに対し、Analytics サポートを有効化する必要があります。 これにより、ネームスペースの分析セクションを使用できるようになります。「分析」>「アーキテクト」を開きましょう。「新規」を選択してフォームに入力し、Ticket クラスの分析キューブを作成します。 次に、ビジュアルビルダーを使って、次元と、基本的なドリルダウンのリストをセットアップします。このビューはドラッグアンドドロップで操作します。リストは、ユーザーがデータポイントを調査する際に表示されるコンテンツをカスタマイズするためのビジュアルエディターででも作成できます。 基本のセットアップが完了したら、キューブを保存、コンパイル、ビルドできます。これによりすべてのインデックスがセットアップされ、アナライザーでの分析用にキューブが有効化されます。アナライザーを開いてデータを操作してみましょう。例では、アドバイザーを年と四半期の階層に対して比較されており、保存されている連絡先でフィルターされています。セルをクリックすると双眼鏡のアイコンが表示されるため、それをクリックすると作成したドリルダウンリストが呼び出されます。それを使用してさらに分析し、エクスポートすることができます。 まとめ たった 142 行のコードで、基本的ではありながらも機能性のあるモダンなバックエンドアプリケーションを作成しました。アプリケーション間の通信と高度な分析が可能なツールもサポートされています。これは過剰に単純化した実装であり、IRIS でデータベースアプリケーションを構築するために必要最低限の例としてのみ使用してください。この記事の冒頭で述べたように、このコードは本番対応かつ実用できるものではありません。開発者は InterSystems IRIS ドキュメントとベストプラクティスを参考にしながら、自分のコードを堅牢かつ安全で、スケーラブルにしてください(このコードベースはどれにも該当しません)。それでは、コーディングをお楽しみください! 翻訳していただきありがとうございます!
記事
Megumi Kakechi · 2023年5月8日

ヘルスモニタでのチェック頻度およびアラート通知条件の確認と変更方法

これは InterSystems FAQ サイトの記事です。 InterSystems IRIS では、柔軟でユーザ拡張可能な監視ツールである「システムモニタ」をお使いいただくことが可能です。 システムモニタには、以下の3つのインスタンス監視ツールがあります。 システムモニタ:システムの状態およびリソースを監視・固定パラメータに基づいて通知 (アラートおよび警告) を生成 ヘルスモニタ:主要なシステムメトリックおよびユーザ定義メトリックをサンプリング&ユーザ変更可能パラメータおよび規定の通常値と比較し、該当しきい値を超えた場合に通知を生成 ※ヘルスモニタは既定では無効となっています。 起動するには、^%SYSMONMGR を使用してヘルスモニタを有効にする必要があります。  ただし、システムモニタのサブスクライバクラスは、ヘルスモニタが有効でなくても動作します。 アプリケーションモニタ:重要なシステムメトリックをサンプリング&ユーザが作成したアラート定義を使用して評価 messages.logに、以下のようなログが記録される場合があります。 [SYSTEM MONITOR] DBLatency(c:\xxx\) Warning: DBLatency = 1510 ( Warnvalue is 1000).※このメッセージの意味については こちらの記事 をご覧ください。 このメッセージはシステムモニタのインスタンス監視ツールであるヘルスモニタにより出力されています。システムモニタは色々なリソースの使用状況を監視する機能です。メッセージ中のDBLatency は、データベースの読み取り I/O 速度(ディスク I/O 応答速度)を監視し出力しているものです。 ご参考ドキュメントIRIS ヘルス・モニタ このシステムモニタよりコンソールログへメッセージが出力されますが、メッセージの重要度が 0 のものは、インフォメーションのメッセージになります。 センサオブジェクトで設定された最大値や警告値を超えた場合は、メッセージの重要度が 1 Warning , 2 Alert のものを出力します。 Alertの場合:ある期間のセンサの読み取り値が 3 回連続してセンサの最大値を上回った場合にアラート (深刻度 2 の通知) を生成Warningの場合:ある期間のセンサの読み取り値が 5 回連続してセンサの警告値を上回った場合にワーニング (深刻度 1 の通知) を生成 ヘルスモニタのセンサーオブジェクトの設定(最大値等の変更)は、^%SYSMONMGR ユーティリティを使用して行えます。※システムモニタのセンサオブジェクト設定は固定パラメータであるため変更はできません。 変更例) DBLatencyのログ出力のしきい値を、 Alert (深刻度 2 の通知):3000 から 4000 へ Warning (深刻度 1 の通知):1000 から 2000 へに変更します。 センサオブジェクトの設定を行う前に システムモニタを停止する必要があります。 %SYS>do ^%SYSMONMGR 1) Start/Stop System Monitor 2) Set System Monitor Options 3) Configure System Monitor Classes 4) View System Monitor State 5) Manage Application Monitor 6) Manage Health Monitor 7) View System Data 8) Exit Option? 1 1) Start System Monitor 2) Stop System Monitor 3) Exit Option? 2 Stopping System Monitor... System Monitor stopped 1) Start System Monitor 2) Stop System Monitor 3) Exit Option? センサオブジェクトのしきい値の変更を行います。 %SYS>do ^%SYSMONMGR 1) Start/Stop System Monitor 2) Set System Monitor Options 3) Configure System Monitor Classes 4) View System Monitor State 5) Manage Application Monitor 6) Manage Health Monitor 7) View System Data 8) Exit Option? 6 1) Enable/Disable Health Monitor 2) View Alerts Records 3) Configure Health Monitor Classes 4) Set Health Monitor Options 5) Exit Option? 3 1) Activate/Deactivate Rules 2) Configure Periods 3) Configure Charts 4) Edit Sensor Objects 5) Reset Defaults 6) Exit Option? 4 1) List Sensor Objects 2) Edit Sensor Object 3) Exit Option? 2 Sensor? ? Num Sensor Threshold : 9) DBLatency 10) DBReads 11) DBWrites 12) DiskPercentFull : Sensor? 9 DBLatency Base? 1000 => Alert Value? 3000 => 4000 <-- Alert(2) メッセージ出力レベルを 4000 に変更 Setting Max Multiplier and Warn Multiplier to 0. Enter a Warn Value Warn Value? 1000 => 2000 <-- Warming(1) メッセージ出力レベルを 2000 に変更 Sensor object DBLatency updated. Base 750 MaxMult 0 AlertValue 4000 WarnMult 0 WarnValue 2000 1) List Sensor Objects 2) Edit Sensor Object 3) Exit Option? <-- このあと全て <Enter> で抜ける システムモニタを再開することで、設定したセンサオブジェクトの値が有効になります。 %SYS>do ^%SYSMONMGR 1) Start/Stop System Monitor : Option? 1 1) Start System Monitor 2) Stop System Monitor 3) Exit Option? 1 Starting System Monitor... System Monitor started 1) Start System Monitor 2) Stop System Monitor 3) Exit Option? <-- このあと全て <Enter> で抜ける ※変更可能なセンサオブジェクトの一覧は こちら をご覧ください。 Caché 用に作成された資料になりますが、以下で^%SYSMONMGRユーティリティについて詳しく説明をしています(IRISでも根本機能は同じです)。ぜひ参考になさってください。モニタリングツールによるシステム監視(P.8~)
記事
Mihoko Iijima · 2023年10月3日

5つの便利なSQL関数のご紹介

開発者の皆さん、こんにちは! この記事では、Muhammad Waseem さんが(US開発者コミュニティに)投稿された「SQLのスキルを次のレベルに引き上げることのできる5つの便利なSQL関数」の記事についてご紹介します。 ✅ SQLに関わらず、IRIS/Caché全般で日頃利用されている便利な機能、使い方、関数などなどありましたら、ぜひコミュニティで共有いただければと思います。 ✅ 現在「技術文書ライティングコンテスト」開催中です! 🎁 参加賞/特賞 🏆ありますので、ぜひチャレンジしてみてください! 以下、Muhammad さんの記事です。 この記事では、5つの便利なSQL関数の説明を実行例と共にご紹介します👇 COALESCE RANK DENSE_RANK ROW_NUMBER Function to Get Running Totals まずは、COALESCE関数から始めてみましょう #COALESCE COALESCE関数は表現式をのリストを左から右に順番に評価し、NULLではない最初の表現式の値を返します。すべての表現式がNULLの場合、NULLが返ります。 以下の例文では、Nullではない最初の値である "intersystems" を返します。 SELECT COALESCE(NULL, NULL, NULL,'intersystems', NULL,'sql') 以下例のテーブルを作成します。 CREATE TABLE EXPENSES( TDATE DATE NOT NULL, EXPENSE1 NUMBER NULL, EXPENSE2 NUMBER NULL, EXPENSE3 NUMBER NULL, TTYPE CHAR(30) NULL) 関数のテストをするため、以下のようにダミーデータを登録します。 INSERT INTO sqluser.expenses (tdate, expense1,expense2,expense3,ttype ) SELECT {d'2023-01-01'}, 500,400,NULL,'Present' UNION ALL SELECT {d'2023-01-01'}, NULL,50,30,'SuperMarket' UNION ALL SELECT {d'2023-01-01'}, NULL,NULL,30,'Clothes' UNION ALL SELECT {d'2023-01-02'}, NULL,50,30 ,'Present' UNION ALL SELECT {d'2023-01-02'}, 300,500,NULL,'SuperMarket' UNION ALL SELECT {d'2023-01-02'}, NULL,400,NULL,'Clothes' UNION ALL SELECT {d'2023-01-03'}, NULL,NULL,350 ,'Present' UNION ALL SELECT {d'2023-01-03'}, 500,NULL,NULL,'SuperMarket' UNION ALL SELECT {d'2023-01-04'}, 200,100,NULL,'Clothes' UNION ALL SELECT {d'2023-01-06'}, NULL,NULL,100,'SuperMarket' UNION ALL SELECT {d'2023-01-06'}, NULL,100,NULL,'Clothes' データを確認してみます。 テストデータの作成が終わったら、COALESCE関数を使用して、EXPENSE1、EXPENSE2、EXPENSE3のカラムからNULLではない最初の値を取得してみましょう。 SELECT TDATE, COALESCE(EXPENSE1,EXPENSE2,EXPENSE3), TTYPE FROM sqluser.expenses ORDER BY 2 #RANK vs DENSE_RANK vs ROW_NUMBER 関数 RANK()— 同じウィドウフレーム内の各行に1から始まるランキングを表す整数を割り当てます。ウィンドウ関数フィールドに同じ値を含む複数の行が存在する場合、ランキングの整数に重複値を含めることができます。 ROW_NUMBER() — 同じウィンドウフレーム内の各行に1から始まる一意な連続した整数を割り当てます。ウィンドウ関数フィールドに同じ値を含む複数の行が存在する場合、各行に一意の連続した整数が割り当てられます。 DENSE_RANK() — 重複したランク(順位)があってもその後の順位は飛ばさない関数。 SQLでは、行にランキングの整数値を割り当てる方法がいくつかあります。先ほどと同じ例をもう1度考えてみましょう。 以下実行例では、どこに一番お金をかけているかを調べています。様々な方法があります。ROW_NUMBER() 、RANK()、DENSE_RANK()をすべて使用できます。この3つの関数を使用して前述したテーブルを順番に並べます。次のクエリを使用して3つの関数の主な違いを確認してみましょう。 クエリは以下の通りです。 3つの関数の主な違いは、同じランキングになった場合の扱い方です。違いは以下の通りです。 ROW_NUMBER()- 1から始まる各行に一意な番号を返します。同値の場合、2番目の基準が定義されていなければ、任意に番号を割り当てます。 RANK()- 1から始まる各行の一意な番号を返しますが、同値の場合は同じ番号を割り当てます。重複した順位には「ずれ」が生じます。 DENSE_RANK() - 重複したランク(順位)があってもその後の順位は飛ばさない関数。 #合計の計算 合計の計算は、特に成長を視覚化する場合に最も便利なウィンドウ関数の1つです。ウィンドウ関数の SUM()を使用して、累積集計を計算することができます。 これを行うためには、集約関数 SUM() 使用して変数を合計します。以下の例ではTDATEカラムを順番に並べて合計を算出しています。 実行例は以下の通りです。 上記結果の通り、日付が経過するにつれ、使用された金額の累積合計を確認できます(結果の「Window_3」カラムが累積集計の結果です)。 まとめ SQLは素晴らしいです。上記例で使用した関数は、データ分析、データサイエンス、その他データに関連するあらゆる分野で役に立つでしょう。だからこそ、SQLのスキルを向上させ続けていきましょう。
記事
Hiroshi Sato · 2020年10月5日

Caché .Net BindingアプリケーションをIRISの.Net Native APIを利用して書き換える方法(その3)

ここで紹介するサンプルは、以下のGitHubから入手可能です。 IRIS .Netサンプル jpegファイルを読んで、IRISデータベースに格納するサンプル 上記GitHub上のinsertbinary\insertbinary\binread.csというファイル名です。 処理内容は、ファイルシステム上のjpeg形式のファイルを読み込んで、BLOB形式でIRISデータベースに格納します。 Caché ではADO.NET Managed Providerを使用して実装していましたが、それをIRISのInterSystems Managed Provider for .NETを使用して書き換えました。(名前が変わっていますが、ADO.NETに関しては、機能はほとんど同じです) 従って、厳密に言うと.Net Native APIを使用していませんが、コネクションオブジェクトの使用方法は共通なので、この部分は、Native APIを使用していると言うこともできます。 Caché での実装は、以下の通りです。 // binread.csusing System;using System.IO;CacheCommand spCache;CacheConnection cnCache;CacheDataAdapter daCache;CacheTransaction txCache=null;DataSet dsCache;DataTable dtCache;DataRow drCache;class BinaryRead { static void Main(string[] args) { //存在するファイルを指定する FileStream fs = new FileStream( @"c:\temp\picture\xxx.jpeg", FileMode.Open, FileAccess.Read) int fileSize = (int)fs.Length; // ファイルのサイズ byte[] buf = new byte[fileSize]; // データ格納用配列 int readSize; // Readメソッドで読み込んだバイト数 int remain = fileSize; // 読み込むべき残りのバイト数 int bufPos = 0; // データ格納用配列内の追加位置 readSize = fs.Read(buf, 0, fs.Length) string cacheConnectString = "Server = localhost;Port=1972;Namespace=User;Password=SYS;User ID = _SYSTEM;"; cnCache = new CacheConnection(cacheConnectString); cnCache.Open(); spCache = new CacheCommand("Insert into MyApp.Person2(Name, Picture) Values(?, ?)", cnCache, txCache); CacheParameter pName = new CacheParameter(); pName.ParameterName = "Name"; pName.CacheDbType = CacheDbType.NVarChar; pName.Direction = ParameterDirection.Input; pName.Value = "Hoge Hoge; CacheParameter pPicture = new CacheParameter(); pDOB.ParameterName = "Picture"; pName.CacheDbType = CacheDbType.LONGVARBINARY; pDOB.Direction = ParameterDirection.Input; pDOB.Value = buf; spCache.ExecuteNonQuery(); fs.Dispose(); cnCache.close(); }} IRISで書き換えたソースは以下の通りです。 // binread.csusing System;using System.IO;using System.Data;using InterSystems.Data.IRISClient;using InterSystems.Data.IRISClient.ADO;namespace binaryfileread { class binaryfileread { [STAThread] static void Main(string[] args) { IRISCommand spIRIS; IRISConnection cnIRIS; IRISTransaction txIRIS = null; //存在するファイルを指定する FileStream fs = new FileStream( @"c:\temp\test.jpeg", FileMode.Open, FileAccess.Read); int fileSize = (int)fs.Length; // ファイルのサイズ byte[] buf = new byte[fileSize]; // データ格納用配列 long readSize; // Readメソッドで読み込んだバイト数 int remain = fileSize; // 読み込むべき残りのバイト数 readSize = fs.Read(buf, 0, (int)fs.Length); string IRISConnectString = "Server = localhost;Port=1972;Namespace=User;Password=SYS;User ID = _SYSTEM;"; cnIRIS = new IRISConnection(IRISConnectString); cnIRIS.Open(); spIRIS = new IRISCommand("Insert into MyApp.Person2(Name, Picture) Values(?, ?)", cnIRIS, txIRIS); IRISParameter pName = new IRISParameter(); pName.ParameterName = "Name"; pName.IRISDbType = IRISDbType.NVarChar; pName.Direction = ParameterDirection.Input; pName.Value = "Hoge Hoge"; spIRIS.Parameters.Add(pName); IRISParameter pPicture = new IRISParameter(); pPicture.ParameterName = "Picture"; pPicture.IRISDbType = IRISDbType.LongVarBinary; pPicture.Direction = ParameterDirection.Input; pPicture.Value = buf; spIRIS.Parameters.Add(pPicture); spIRIS.ExecuteNonQuery(); fs.Dispose(); cnIRIS.Close(); } }} CachéとIRISでは、ADO.NETに関しては、関数等の名前がCacheからIRISに変更になっているという違いがあります。 参照の変更 まず以前の参照を削除します。 Visual Studioのソリューションエクスプローラーの所で参照をクリックします。 表示されるInterSystems.Data.CacheClientを削除します。(右クリックして削除を選ぶ) 次にプロジェクトメニューから参照の追加をクリックして、以下の2つのファイルを選択します。(プロジェクトの.Net Frameworkバージョンに合わせて、それに対応するファイルを選択する以下の例は、v4.5を選択) c:\InterSystems\IRIS\dev\dotnet\bin\v4.5 InterSystems.Data.IRISClient.dll jpegファイルを読んで、フォーム上にそのjpegファイルの内容を表示するサンプル 上記GitHub上の\VBImage\VBImage\Forms1.vbというファイル名です。 処理内容は、ファイルシステム上のjpeg形式のファイルを読み込んで、VB.NETのフォーム上のPictureオブジェクトとして表示します。 Caché では.NET Managed Providerの.Net Bindingを使用して実装していましたが、それをIRISの.Net Native APIを使用して書き換えました。 Caché での実装は以下の通りです。 Imports InterSystems.Data.CacheClientImports InterSystems.Data.CacheTypesImports System.DrawingPublic Class Form1 Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Dim cn As CacheConnection cn = New CacheConnection("Server=127.0.0.1;Port=1972;Namespace=User;Username=_system;Password=SYS") cn.Open() Dim img As System.IO.FileStream img = New System.IO.FileStream("C:\temp\test.jpg", System.IO.FileMode.Open, IO.FileAccess.Read) Dim f As User.Fax ' NEW ----------- f = New User.Fax(cn) img.CopyTo(f.pic) f.memo = "abcde" f.Save() f.Dispose() MsgBox("Done!") cn.Close() End Sub  Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Button2.Click Dim cn As CacheConnection cn = New CacheConnection("Server=127.0.0.1;Port=1972;Namespace=User;Username=_system;Password=SYS") cn.Open() Dim f As User.Fax f = User.Fax.OpenId(cn, 1) PictureBox1.Image = Image.FromStream(f.pic) cn.Close() End SubEnd Class IRISで書き換えたソースです。 Imports InterSystems.Data.IRISClientImports InterSystems.Data.IRISClient.ADOImports System.DrawingImports System.IOPublic Class Form1 Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Dim cn As IRISConnection cn = New IRISConnection("Server=127.0.0.1;Port=1972;Namespace=User;Username=_system;Password=SYS") cn.Open() Dim iris As IRIS Dim irisobject As IRISObject Dim memstream As New MemoryStream Dim str As String Dim buf As Byte() Dim pic As IRISObject iris = IRIS.CreateIRIS(cn) irisobject = iris.ClassMethodObject("User.Fax", "%New") Dim img As System.IO.FileStream img = New System.IO.FileStream("C:\temp\test.jpg", System.IO.FileMode.Open, IO.FileAccess.Read) buf = New Byte(img.Length) {} img.Read(buf, 0, img.Length) str = System.Text.Encoding.GetEncoding("ISO-8859-1").GetString(buf) pic = irisobject.GetObject("pic") pic.InvokeVoid("Write", str) irisobject.InvokeIRISStatusCode("%Save") 'Dim f As User.Fax ' NEW ----------- 'f = New User.Fax(cn) 'img.CopyTo(f.pic) 'f.memo = "abcde" 'f.Save() 'f.Dispose() MsgBox("Done!") cn.Close() End Sub Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Button2.Click Dim cn As IRISConnection Dim iris As IRIS Dim irisobject As IRISObject Dim pic As IRISObject Dim memorystream As New MemoryStream Dim buf As Byte() Dim str As String Dim len As Long cn = New IRISConnection("Server=127.0.0.1;Port=1972;Namespace=User;Username=_system;Password=SYS") cn.Open() iris = IRIS.CreateIRIS(cn) irisobject = iris.ClassMethodObject("User.Fax", "%OpenId", 1) pic = irisobject.GetObject("pic") len = pic.InvokeLong("SizeGet") str = pic.InvokeString("Read", len) buf = System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(str) memorystream.Write(buf, 0, len) PictureBox1.Image = Image.FromStream(MemoryStream) cn.Close() End SubEnd Class 良くコードを見るとわかりますが、IRIS版のほうが処理がかなり長くなっています。 結論を言うとこのケースはIRIS .Net Native APIを使用して書き換えるのは得策ではありません。ADO.NETを使用したほうが簡単に処理できます。 上記GitHub上の\VBImageADO配下にADO.NETで書き換えたサンプルも用意しましたので、ご参考下さい。