【IRIS】特定の文字でインデックスを構築すると再作成コマンドで不具合が発生する

インデックスの再作成コマンド(%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で発生しているとの事なので、該当の関数を確認してみます。

%SYSTEM.SQL.Util.cls の関数「SetMapSelectability」

1131行目の「while $listnext(mapList,ptr,map)」でエラーが発生しています。

%BuildIndices(,1)を実行した時、この関数が内部で実行されます。
その際の各引数は、次の値を持ちます。

引数名データ型
pTablename%Library.Stringdeveloper_err.Index
pMapname%Library.String$lb(“IDKEY”,”文字列1Idx”)
pValue%Boolean1

念のため、ターミナルで関数の動作を確認します。

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 様に報告済みであり、近いうちに修正対応が行われると思います。
それまでは、日本語を含むインデックス名の使用には十分ご注意ください。
 →もしかすると、今回表面化していない影響が他にもあるかもしれません…

この記事が、同様の問題に直面している方々の参考となり、少しでもお役に立てれば幸いです。
最後までお読みいただき、ありがとうございました。