【IRIS/Cache】オブジェクトの中身を見よう

はじめに

デバッグしている最中オブジェクトの中身が知りたいけど、処理を止めることが出来ない等で、開発時に苦労した経験がたくさんあります。

そんな時、オブジェクトの中身をグローバルに出力できたら便利だと思いませんか?
今回は、デバッグ時に役に立つコマンドをご紹介いたします。

d $system.OBJ.Dump([object])

身も蓋もない名前のコマンドですが、実行するとその中身を参照することが出来ます。

d $system.OBJ.Dump(obj)
SAMPLE>s obj = ##class(developer.data.Sample).%OpenId(1)
 
SAMPLE>d $system.OBJ.Dump(obj)
+----------------- general information ---------------
|      oref value: 5
|      class name: developer.data.Sample
|           %%OID: $lb("1","developer.data.Sample")
| reference count: 1
+----------------- attribute values ------------------
|       %Concurrency = 1  <Set>
|               code = "B659"
|           document = "Assistant Product Specialist"
|                flg = 0
|               name = "Young,William F."
|             number = 418003358
+-----------------------------------------------------

クラス名、各プロパティの値等が確認できます。

オブジェクトであれば何でもDump出来るので、引数の型を記載する時などに、クラス名をド忘れした場合も超有能です(笑

こんなのも取れちゃいます。

SAMPLE>s json={"test":"mytest","doument":"ドキュメント","count":2 }
 
SAMPLE>d $system.OBJ.Dump(json)
+----------------- general information ---------------
|      oref value: 6
|      class name: %Library.DynamicObject
| reference count: 1
+----------------- JSON value ------------------------
| {"test":"mytest","doument":"ドキュメント","count":2}
+-----------------------------------------------------

writeを防止する

ただそのまま実行するだけだと、writeするだけで記録として取得することが出来ません。

これではデバッグが難しいですし、writeする事で余計な不具合を誘発する可能性もあります。
その場合、^SPOOLを使用すると解決します。

ClassMethod dump(obj As %Persistent)
{
	OPEN 2:(1:1)
	USE 2 d $system.OBJ.Dump(obj)
	CLOSE 2
	m ^Sample = ^SPOOL
}

では、関数を実行して「^Sample」を確認してみましょう。
引数には、「developer.data.Sample.cls」のオブジェクトを使用しています。

^Sample(1,1)="+----------------- general information ---------------"_$c(13,10)
^Sample(1,2)="|      oref value: 5"_$c(13,10)
^Sample(1,3)="|      class name: developer.data.Sample"_$c(13,10)
^Sample(1,4)="|           %%OID: $lb(""1"",""developer.data.Sample"")"_$c(13,10)
^Sample(1,5)="| reference count: 2"_$c(13,10)
^Sample(1,6)="+----------------- attribute values ------------------"_$c(13,10)
^Sample(1,7)="|       %Concurrency = 1  <Set>"_$c(13,10)
^Sample(1,8)="|               code = ""B659"""_$c(13,10)
^Sample(1,9)="|           document = ""Assistant Product Specialist"""_$c(13,10)
^Sample(1,10)="|                flg = 0"_$c(13,10)
^Sample(1,11)="|               name = ""Young,William F."""_$c(13,10)
^Sample(1,12)="|             number = 418003358"_$c(13,10)
^Sample(1,13)="+-----------------------------------------------------"_$c(13,10)
^Sample(1,2147483647)="{66942,34834{14{"

ターミナルへの出力を防止しつつ、グローバルに記録する事が出来ました。

これで、オブジェクトの中身を気楽に覗けるようになりましたね。

終わりに

デバッグ時にオブジェクトの中身を覗く事で、正常に動作しているのかより正確に確認できるようになります。

特に取り方を忘れた時などは、かなり有効ですよ。
%Execute()からの戻り値「tre」から、クエリプランを取得する方法は・・・

SAMPLE>s stm = ##class(%SQL.Statement).%New()
 
SAMPLE>d stm.%Prepare("EXPLAIN select name from developer_data.Sample where code='B659'")
 
SAMPLE>s tre = stm.%Execute()
 
SAMPLE>
 
SAMPLE>d $system.OBJ.Dump(tre)
+----------------- general information ---------------
|      oref value: 2
|      class name: %sqlcq.SAMPLE.cls7
| reference count: 2
+----------------- attribute values ------------------
|     %CurrentResult = "2@%sqlcq.SAMPLE.cls7"
|      %CursorNumber = 1
|  %ExtendedMetadata = $lb($lb("","%Library.String",10))
|           %Message = ""
|       %Metadata(0) = lb(1,"Plan",12,50,"0",2,"Plan","","",0,$c(0,1,0,1,0,0,1,1,0,0,0,0,0))
|      (%NextColumn) = 2
|           %Objects = ""
| %OutputColumnCount = 0
|        %Parameters = ""
|          %ROWCOUNT = 0
|             %ROWID = ""
| %ResultColumnCount = 1
|           %SQLCODE = 0
|      (%SelectMode) = 0
|     %StatementType = 1
|           %routine = ""
|        CursorState = 1
|        (StackInfo) = $lb("%SQL",$lb("ikeda","Sample-Server:1972"),$lb("DynamicStatement",0,0),"cvTnsutKmNV3puUKUSrxeOLm8QA=",0,$lb(),225565.508884,"",,"SAMPLE","%sqlcq.SAMPLE.cls7")
|(UF0cselectnamefromdeve) = "<plans>"_$c(13,10)_" <plan>"_$c(13,10)_" <sql>"_$c(13,10)_" select name from developer_data.Sample where code='B659' /*#OPTIONS {""DynamicSQL"":1} */"_$c(13,10)_" </sql>"_$c(13,10)_" <cost value=""451.41""/>"_$c(13,10)_" Read index map developer_data.Sample.idx, using the given %SQLUPPER(code), and looping on ID."_$c(13,10)_" For each row:"_$c(13,10)_"     Read master map developer_data.Sample.IDKEY, using the given idkey value."_$c(13,10)_"     Output the row."_$c(13,10)_" </plan>"_$c(13,10)_"</plans>"
|              (c02) = 0
|       (cShowPlan3) = "ShowPlan"
|         (commands) = 46036
|(cselectnamefromdevelop) = "select name from developer_data.Sample where code='B659' /*#OPTIONS {""DynamicSQL"":1} */"
|    (isolationMode) = 0
|       (querystats) = ""
|           (rowcnt) = 0
|         (rowlimit) = 9223372036854775807
|             (time) = .030272
+----------------- swizzled references ---------------
|   i%%PrivateTables = ""  <Set>
|   r%%PrivateTables = ""  <Set>
|    (i%%ProcCursor) = ""
|    (r%%ProcCursor) = ""
|          (i%%rsmd) = ""
|          (r%%rsmd) = ""
+--------------- calculated references ---------------
| %StatementTypeName   <Get>
|               Plan   <Get>  [ Aliases - plan,PLAN ]
+-----------------------------------------------------

「%ResultColumnCount=1」だから、↓のコードで全部取得できるんだ・・・とか。

 s txt = tre.%GetData(1)

オブジェクトの中身を確認する事で、色々と参考になる情報が得られます。
是非ご活用下さい!