
インデックスの再作成コマンド(%BuildIndices)で発生した、不具合の報告になります。
状況
※ 2025年5月時点で最新のバージョン、IRIS 2025でも発生を確認しています。
cache2018では確認できていません。
■簡単なサンプル
Class developer.err.Index Extends (%Persistent, %Populate)
{
Index 文字列1Idx On 文字列1;
Property 文字列1 As %String;
}
パット見、日本語のプロパティと日本語のインデックスで構成された、ごくごく普通のデータクラスです。
この何の変哲もないデータクラスに対し、インデックスの再作成を実行すると、下記結果になります。
d ##class(developer.err.Index).%BuildIndices(,1)
//
// while $listnext(mapList,ptr,map) {
// ^
// <WIDE CHAR>SetMapSelectability+13^%SYSTEM.SQL.Util.1
えぇ・・・
インデックスの再作成ができない!
マジスカ…
他の挙動をざっくり確認する
%Saveは問題なく実行可能。
s obj=##class(developer.err.Index).%New()
s obj.文字列1 = "サンプル"
w obj.%Save() // 1が返る
当然インデックスも生成されています。
^developer.err.IndexI(“文字列1Idx”,” サンプル”,1) = “”
他にも動作を確認してみました。
// データ取得
s obj=##class(developer.err.Index).%OpenId(1)
w obj.文字列1 // 「サンプル」が返る
// SQL実行
:sql
select * from developer_err.Index where 文字列1='サンプル'
2. select * from developer_err.Index where 文字列1='サンプル'
ID 文字列1
1 サンプル
1 Rows(s) Affected
statement prepare time(s)/globals/cmds/disk: 0.1290s/35,645/179,974/7ms
execute time(s)/globals/cmds/disk: 0.0006s/2/555/0ms
cached query class: %sqlcq.SAMPLE.cls11
---------------------------------------------------------------------------
// レコード削除
w ##class(developer.err.Index).%DeleteId(1) // 1が返る
通常の操作では、問題なさそうです。
インデックスも正常に参照するようです。
<plans>
<plan>
<sql>
select * from developer_err.Index where 文字列1='サンプル' /*#OPTIONS {""DynamicSQL"":1} */
</sql>
<cost value=""454.4""/>
Read index map developer_err.Index.文字列1Idx, using the given %SQLUPPER(文字列1), and looping on ID.
For each row:
Read master map developer_err.Index.IDKEY, using the given idkey value.
Output the row.
</plan>
</plans>
なんでインデックス再作成だけ、エラーになるんでしょうね。
原因の確認
SetMapSelectability+13で発生しているとの事なので、該当の関数を確認してみます。

1131行目の「while $listnext(mapList,ptr,map)」でエラーが発生しています。
%BuildIndices(,1)を実行した時、この関数が内部で実行されます。
その際の各引数は、次の値を持ちます。
引数名 | データ型 | 値 |
---|---|---|
pTablename | %Library.String | developer_err.Index |
pMapname | %Library.String | $lb(“IDKEY”,”文字列1Idx”) |
pValue | %Boolean | 1 |
念のため、ターミナルで関数の動作を確認します。
w $SYSTEM.SQL.Util.SetMapSelectability("developer_err.Index",$lb("IDKEY","文字列1Idx"),1)
//
// while $listnext(mapList,ptr,map) {
// ^
// <WIDE CHAR>SetMapSelectability+13^%SYSTEM.SQL.Util.1
同じエラーが発生しました。
この関数がエラーの発生源で間違いないですね。
引数の値も確認できたので、原因を絞り込んでみましょう。
原因発見!
変数「mapList」は、$$$UPPER(pMapname)の戻り値が格納されます(1128行目)。
原因はこのマクロにあるとみて間違い無いでしょう。

マクロの中身を確認します。
インクルードファイル「%msql.inc」を確認すると、UPPERは「$zu(28, %s, 5)」となっています。
つまり、この$zutilコマンドが問題と思われます。
早速、ターミナルで挙動を確認してみましょう。
s dt = $lb("IDKEY","文字列1Idx")
s cnv = $zu(28, dt, 5)
w $lg(cnv,1),",",$lg(cnv,2)
// IDKEY,
// W $LG(cnv,1),",",$LG(cnv,2)
// ^
// <WIDE CHAR>
上記結果を見ると、「”文字列1Idx”」で<WIDE CHAR>エラーが発生しているようです。
こいつが犯人で間違いないです。
次は、問題を特定すべく、少し分解して確認してみます。
// <WIDE CHAE>エラー
s dt = $lb("文字列1Idx")
s cnv = $zu(28, dt, 5)
w $lg(cnv,1) // エラー発生
// 正常に返る
s dt = "文字列1Idx"
s cnv = $zu(28, dt, 5)
w cnv // 文字列1IDX
// 文が鬱に変わる
s dt = $lb("文字列1Idx") // 1を半角に変更
s cnv = $zu(28, dt, 5)
w $lg(cnv,1) // 䖇字列1IDX
この結果を見ると、%List型 + 特定の文字 + $zu(28,%s,5)がダメそうですね。
また、文→鬱に変わる謎現象まで確認できました。
カンベンシテヨ
$zutilの挙動として、%Listを丸ごと変換するのではなく、%List内の各要素毎に変換すれば、この問題は解決するんだろうなぁ・・・
他に対象文字を探す
大体の原因が分かったので、どの文字が該当するのか確認してみたいと思います。
ターミナルで下記を実行してみました。
cnvChk ;
f asc=1:1:66000 {
s str = $c(asc)
s chk = $zcvt(str,"U") // 大文字変換
s chg = $zu(28, $lb(str), 5) // $$$UPPER()
try {
s chg = $lg(chg,1)
w:(chk'=chg)&&(str'=chg) !,asc,":",str,"(",chk,")",",",chg
}catch e{
w !,asc,":",str,":エラー"
}
}
d cnvChk
【結果】
対象の文字が多すぎて表示しきれません!
ちょくちょくエラーが表示されつつ、65279(BOM)以降から全滅している感じです。
誤変換が行われる文字も多いのですが、漢字が別の漢字に化けていたりしているのが確認できました。
その対象数も結構多いなぁ・・・
インデックス名称は、英数字で構築した方が事故が起きなくて良いですね。
完全日本語化はまだ早いようです。
おわりに
いかがだったでしょうか。
昨今、日本語を用いてテーブルやインデックスを定義するケースが、じわじわと増えてきているように感じます。
その一方で、思わぬところに落とし穴があることも、今回の件で実感しています。
→過去にも、日本語でjobコマンドが動かないとか、チョイチョイありましたよね。
この問題については ISJ 様に報告済みであり、近いうちに修正対応が行われると思います。
それまでは、日本語を含むインデックス名の使用には十分ご注意ください。
→もしかすると、今回表面化していない影響が他にもあるかもしれません…
この記事が、同様の問題に直面している方々の参考となり、少しでもお役に立てれば幸いです。
最後までお読みいただき、ありがとうございました。