はじめに
デバッグしている最中オブジェクトの中身が知りたいけど、処理を止めることが出来ない等で、開発時に苦労した経験がたくさんあります。
そんな時、オブジェクトの中身をグローバルに出力できたら便利だと思いませんか?
今回は、デバッグ時に役に立つコマンドをご紹介いたします。
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)
オブジェクトの中身を確認する事で、色々と参考になる情報が得られます。
是非ご活用下さい!