「unixODBC+FreeTDS+DBD::ODBCでSQL Serverに接続する」Part2

※前回の続きです。

設定ファイルをいじる

4.odbc.iniの編集

# vim /usr/local/etc/odbc.ini
--
[ODBC Data Sources]
<span style="color:#FF0000;">freetds = FreeTDS ODBC Driver

[freetds]
Driver = /usr/local/lib/libtdsodbc.so
Description = Microsoft SQL Server
Servername = mssql
Database = dbname

5.freetds.confの編集

# vim /usr/local/etc/freetds.conf
 --
[mssql]
        host = 192.168.XXX.XXX
        port = 1433
        tds version = 8.0
        charset = sjis
        client charset = UTF-8
       language = english

補足
host←SQL ServerをインストールしたホストのIPアドレスにすること
client charset←データに日本語を使わないなら「UTF-8」にしても良い
language←japaneseにするとエラーメッセージなどが日本語で表示されるが、
        環境によって文字化けする場合もあるのでenglishがお勧め。


【重要】
odbc.iniのServernameとfreetds.confのセクションをあわせます。


■接続テスト

# tsql -H 192.168.xxxx.xxx -p 1433 -U admin -P hogehoge
locale is "ja_JP.UTF-8"
locale charset is "UTF-8"
1> use test_db
2> go
1> select count(*) from hogehoge
2>go
1>exit

o(・∇・o)(o・∇・)o ヤッタ!つながった!!

これでDBIとfreetdsを使った接続は成功です!!

DBD::ODBC編

DBD::ODBCのインストール
#perl -MCPAN -e shell
cpan> install DBD::ODBC
--20:01:22--  ftp://ftp.perl.org/pub/CPAN/authors/id/M/MJ/MJEVANS/DBD-ODBC-1.15.tar.gz
  (試行: 9) => `-'
ftp.perl.org|163.143.1.21|:21 に接続しています... 接続しました。
anonymous としてログインしています...
サーバの応答にエラーがあるので、接続を終了します。
再試行しています。

あれ?失敗

■接続先URLを追加して実行(以下でいけるらしい)

cpan> o conf
cpan> o conf urllist push 追加したい url名
cpan> o conf commit

◎追加するURLは
http://search.cpan.org/CPAN/authors/id/M/MJ/MJEVANS/DBD-ODBC-1.15.tar.gz

cpan使っても一回install

#perl -MCPAN -e shell
cpan> install DBD::ODBC

◎警告はわさわさ出たけど入ったから次へ。


7.接続テストスクリプト作成

# vim odbc.pl
--
#!/usr/bin/perl

use strict;
use DBI;
use Data::Dumper;

my $dbh = DBI->connect('dbi:ODBC:freetds', 'username', 'passwd') or die $!;
my $sth = $dbh->prepare("select top 10 * from test_table") or die $dbh->errstr;
$sth->execute or die $dbh->errstr;
while (my $arrayref = $sth->fetchrow_arrayref) {
    print Dumper $arrayref;
}
$sth->finish;
$dbh->disconnect;

8.接続テストスクリプト実行

# perl odbc.pl
DBI connect('freetds','username',...) failed: [unixODBC][Driver Manager]Data source name not found, and no default driver specified (SQL-IM002) at odbc.pl line 7
Died at odbc.pl line 7.

エラー
データソースの設定がミスってますって怒られています。

ここからしばらくデバッグの経緯です。(省きたい人はすっとばしてください。)

■ドライバの一覧を確認してみます
odbc.pl に以下の記述を追加して実行

my @ary = DBI->available_drivers;
print Dumper(\@ary);

 ------実行結果-------
#perl odbc.pl
$VAR1 = [
          'DBM',
          'ExampleP',
          'File',
          'ODBC', ←いました。
          'Pg',
          'Proxy',
          'Sponge'
        ];


ODBCの一覧を見てみます

my @ary = DBI->data_sources('ODBC');
print Dumper(\@ary);

 ------実行結果-------
#perl odbc.pl
$VAR1 = [];

からっぽです。

■今どの設定ファイルみてるのかを調べる

#odbcinst -j
unixODBC 2.2.11
DRIVERS............: /etc/odbcinst.ini
SYSTEM DATA SOURCES: /etc/odbc.ini
USER DATA SOURCES..: /root/.odbc.ini

↑こんな結果です。

どうやら「/etc/odbc.ini」を見ているようです。
設定をこちらに書いてみます。

■再実行結果

#perl odbc.pl
$VAR1 = [
          'dbi:ODBC:freetds'
        ];

とれました。

■再度perl実行

# perl odbc.pl

できたーーーーー!!!
・゚・(つД`)・゚・値がとれましたー!!

↑ここまではasciiだけのテーブルが対象でした。

こっからは日本語の出力です。

SQLを日本語の入っているテーブルに変更して実行

my $sth = $dbh->prepare("select top 10 * from test_table<span style="color:#FF0000;">_jp</span>") or die $dbh->errstr;

何か途中で落ちる。。。

■カラムを指定して実行

my $sth = $dbh->prepare("select top 10 id,name from test_table_jp") or die $dbh->errstr;

無事日本語も表示されました。

(-ω-???????
どうやら型の中に「varchar(max)」があると落ちるようです。

http://www.mail-archive.com/dbi-users@perl.org/msg26962.html
↑パッチらしきものを発見

■diffにそってソースを修正後makeし直します。

vim /root/.cpan/build/DBD-ODBC-1.15/dbdimp.c

make clean
perl Makefile.PL
make
make test
make install

結果は同じでした。。。

デバッグに入ります。
まずはエラーを拾います。
http://www.rfs.jp/sb/perl/dbi/03.html
↑ここに「DBI->trace」こんなん載ってた。

デバッグレベルを変更します。

my $dbh = DBI->connect('dbi:ODBC:freetds', 'sa', '1ndivision',{PrintError=>0,AutoCommit=>0}) or die $!;
$dbh->trace(3);

デバッグ最強レベルまで上げる。

その結果。エラー文のような物がはかれました。
怪しい部分だけ抜き出します。

     now using col 1: type = CHAR (1), len = 20, display size = 21, prec = 20, scale = 0
     now using col 2: type = VARCHAR (12), len = 800, display size = 801, prec = 800, scale = 0
     now using col 3: type = LONG VARCHAR (-1), len = 258048, display size = 81, prec = 258048, scale = 0

col3がvarchar(max)部分になります。
display size が他のカラムに比べて少なすぎます。

ほかのカラムはlen+1 サイズになってるのに
varchar(max)のカラムはやたらと少ないです。

C言語経験者に頼る。。。。orz

「dbdimp.c」をデバッグする

case文にデバッグ入れ込んでみるとvarchar(max)の場合
「LONG VARCHAR」として判定されている事が判明!!

以下の関数部分を修正。

#vim /root/.cpan/build/DBD-ODBC-1.15/dbdimp.c

dbd_describe(h, imp_sth, more)関数の下部分のcase文の中にif文追加


          case SQL_LONGVARCHAR:
            if (fbh->ColDef <= 0) {
                fbh->ColDisplaySize = DBIc_LongReadLen(imp_sth)+1;
            }
            break;

修正しました。

#make install
#perl odbc.pl


now using col 3: type = LONG VARCHAR (-1), len = 258048, display size = 258049, prec = 258048, scale = 0


出ました!!!
fetchできちんと値が取れました!!!!

(^-^;)とりあえず出たので完了とします。。。