[pgsql-jp: 26091] Re: 7.2 ODBC ドライバでSQL_DESC_OCTET_LENGTHを取得すると 0 になる。

Hiroshi Inoue Inoue @ tpf.co.jp
2002年 5月 23日 (木) 18:41:26 JST


井上です。

> こんにちは。
> 加倉です。
> 
> お返事ありがとう御座います。
> 
> > > ■現象
> > > - VARCHAR(40) の列の OCTET LENGTH に 0 が返される。
> > > - OCTET_LENGTH の取得は SQLColAttribute で SQL_DESC_OCTET_LENGTH
> > > を指定しています。
> > >  SQLRETURN は SQL_SUCCESS が返されています。
> > > ※参考までに、Column Size, Display Size は各々 40 と 40 が返されて
> > > います。
> >
> > 問題がいくつかありそうです。
> >
> > 1)SQL_DESC_OCTET_LENGTHはODBC3.Xで追加された項目ですが、
> >  普通にコンパイルしてもODBC2.50対応のドライバしか作成
> >  されません。値の0とSQL_SUCCESSはドライバマネージャー
> >  が返しているのではないかと思われます。
> 
> unixODBC の SQLColAttribute のソースを確認してみました。
> (gdb でのトレースと、ソースの確認)
> 
> unixODBC では ODBC 3 の Field Itentifier を 2 の形式に変換しようとして
> ますが、OCTET_LENGTH は変換対象がないので、そのまま OCTET_LENGTH を
> PostgreSQL の Driver の SQLColAttributes (Attribute ではなく Attributes)
> に渡して呼び出しています。
> PostgreSQL の PGAPI_ColAttributes のソースも目視で確認しました。
> PGAPI_Colattributes は対応する field type (field identifier) がない場合
> 値の 0 と SQL_SUCCESS を返しています。
> field type の場合わけを switch 文で行っていますが、switch 文に default
> ラベルがなく、無条件に成功してしまうようです。

なるほどこれはチョンボですね。最新のソースではエラーに
なります。最新のソースは
 http://developer.postgresql.org/cvsweb.cgi/pgsql/src/interfaces/odbc/
で確認することが可能です。
 
> > 2) PostgreSQL7.2.xに付属のソースではOCTET_LENGTHに対応
> >  する実装がありません。
> 
> 確かに確認しました。
> 
> > 1)についてはODBCVER=0x0300を定義すればODBC3.0対応の
> >  ドライバが作成されるかもしれません。残念ながら
> >  unixODBCで試したことはないので保証はできません。
> 
> PostgreSQL のソースでは、SQLColAttribute も PGAPI_ColAttributes が呼び出
> されているようなので結果は同じになると思われます。

最新のソースでは
#ifdef (ODBCVER >= 0x0300) 以下
  ODBC3.X用にいくつか追加されています。
 
> > 2)については最新の開発中ソースを使用する必要があります。
> >  ちなみに最新の実装では
> >
> > > ■加倉の認識
> > > - PostgreSQL 7.2.1 では VARCHAR は文字単位になっているので
> > > 、OCTET LENGTH (転送に必
> > >  要なバッファのバイトサイズ)は、EUC_JP の場合 2(または3)×
> > > ColumnSize が戻らなけれ
> >
> > はマルチバイト付のコンパイルの場合、無条件に3XColumnSizeが
> > 返ります。ただし254(正確にはMax Varchar Size)を超えたら
> > 254にしてしまいます。(VAR)CHARが文字単位というのはODBC
> > ドライバにとっては厄介な変更で仕方なくこうしてあります。
> 
> なぜ OCTET_LENGTH が Max Varchar Size を超えたら 254 バイトに丸められて
> しまうのですか?(不勉強ですみません。)
> MSDN の以下の URL では、OCTET LENGTH は可変長文字列は最大バイト数を返すと
> 書かれていますが?
> http://msdn.microsoft.com/library/default.asp?url=/library/en-us/odbc/htm/odbcsqlcolattribute.asp
> ここでいう最大バイト数とは取得するのに必要な転送バッファの最大サイズを意
> 味しているのだと思いますがどうでしょう。転送バッファの最大サイズなら、254
> で丸める意味はないとおもいますが。
> OCTET_LENGTH で最大バイト数が分からないと、VARCHAR 型のデータは SQLBindCol
> ではデータを取得しずらくなってしまいます。

確かにおっしゃるとおりなのですが、ODBCでは254を境に
SQL_VARCHARからSQL_LONGVARCHARへと別の扱いになって
しまいます。そして不幸なことにSQL_LONGVARCHARを
SQL_VARCHARほどうまく扱えないアプリが多いのです。
VARCHARだから最大文字数に達するデータがあるかどうか
もあやしい。3倍になるのは最悪のシナリオに過ぎずす
べてasciiなら1倍ですんでしまう。7.1からの単純コン
バージョンなら元々バイト数も足りているはずである。
そもそも7.1迄はそうだったのだし文字数とバイト数を
区別しないユーザーもいるだろう。等々を勘案して現在
の内容にしています。たいしたものをうまないこういう
所で悩まなければならないのにはいつもうんざりする
のですが。
 
> 参考までに、SQLServer のドライバでは NVARCHAR 型(unicodeです)の場合は、
> 2×ColumnSize をそのまま返すようです。特に値の丸めは行われていません。

Unicodeの場合は文字数とバイト数の対応が明確なのですっきり
しています。PostgreSQLでもunicode対応のものはSQLServerと
同じ計算をします。

regards,
Hiroshi Inoue
	http://w2422.nsk.ne.jp/~inoue/



pgsql-jp メーリングリストの案内