【罠】ORACLEのsubstr関数の仕様が紛らわしい件【注意】
文字列を扱うアプリを作ることが多いのでsubstr関数にはお世話になっています。ORACLEにはsubstrとsubstrbという2種類の関数があって前者がキャラクター単位、後者がバイト単位で文字列を切り出せます。
それはそれとして……。
ORACLEを使ったことがある人ならご存じとは思いますが、ORACLEでは一般的には文字列をvarchar2という型で定義します。しかし他にも方法はあります。clobと言う型です。キャラクターベースのラージオブジェクトってやつです。varchar2が4000バイト(PL/SQLの内部変数や32767バイト)しかもてないのに対して、clobなら2ギガバイトまで大丈夫です。
そのclobにもsubstr関数があるのですよ。dbms_lob.substrって関数。dbms_lobってのはパッケージ名で、関数をひとまとめにしておく機能みたいなものと説明すればいいのかな。dbmsで始まるやつはシステムが用意している物です。他にもあるけど。
さて、ここからが本題。マニュアルをみてみましょう。
- SQLのsubstr関数マニュアル (むろんオラクル公式サイト)
- DBMS_LOBのsubstr関数マニュアル (当然オラクル公式サイト)
ゴシゴシ……
よく見えない。見えてないだけ??
かみ砕いて書くとsubstr関数は
substr('元の文字列',何文字目から?,何文字分とりだすの?)
となっています。
substr('元の文字列だよ',3,5)
って書くとたぶん「文字列だよ」って返ってくるんだと思う。検証してないから嘘ついたらごめん。
それに対しdbms_lob.substrは
dbms_lob.substr(lobのお名前入れてね♪,何文字欲しいの?,何文字目から?)
ってなってます。lobをテキストで表現するのはつらいから模式的に書くと
dbms_lob.substr('元の文字列だよ。ほんとはlobだよ。',3,5)
って書くと、「列だよ」って返ってくるのかな?それとも1文字ずれるのか?まぁやってみればわかるけれど自宅に環境ないのでね。
substrだから同じように使えると頭から思いこんで使っちゃうとはまるんだよね(笑)。ってか、はまったんだ。ずいぶん前にだけど(笑)。
おそらくちゃんとマニュアル読みなさいと言われるだけなんですけど、substr関数は頻繁に使うので仕様を覚えていたのが罠だったんですね。dbms_log.substrって関数があったんでsubstrって関数と同じように使えるのかなぁと思っちゃったんだよね。
名前は一緒だけど、内部仕様は全然違うだろうし当然作った人も作ったタイミングも違うでしょう。さらには何らかの事情もあるかも知れません。
でも、この罠はきつかった。すっかり思いこんでいるからマニュアル見ても間違えに気づかないの。instrとかにも同じ罠があったような気がします。
最近自分が書いた記事に救われたのでこの一件も書いておくことにしました。
でもね。問題を解決しようとしてGoogleに聞いたら一番上に自分のサイトが出てくると絶望的な気持ちになれるんだぜ……。