UbuntuでFreeTDSとtdsppからSQLServerに接続する
久しぶりに FreeTDS を扱う機会を得たので、FreeTDS そのものというか、ODBC を使わずに、C++ で SQL Server on Linux に接続してみたくなりました。
とは言っても、直接 DB-Library / CT-Library を扱うつもりはなく、FreeTDS の Wikipedia にリンクが貼ってある C++ wrapper な TDS++ (tdspp) 経由です。
GitHub に TDS7.4 対応済みのものを見つけたので、これを試してみます。
1. 環境
- Ubuntu Desktop 18.04.4 LTS 日本語Remix (Linux Kernel 5.3.0-42-generic)
- SQL Server 2019 (RTM-CU3) (KB4538853) - 15.0.4023.6 (X64) on Linux
- g++ 7.5.0
- NorthwindJ データベース ※Node.js と Qt5 から正常に接続できる事を確認済み。
以降の内容は、あくまで tdspp の評価が目的です。常用するつもりはありません。
2. 準備
(1) パッケージ追加 ※未導入の場合
まずは、FreeTDS のヘッダとライブラリを用意します。
$ sudo apt install freetds-dev
私の環境では、バージョン 1.00.82-2ubuntu0.1 が導入されました。
(2) 作業ディレクトリ
$ cd ~
$ mkdir work
$ cd work
(3) リポジトリのクローン
GitHub から tdspp のリポジトリを取ってきます。
$ git clone https://github.com/calanor/tdspp.git
Cloning into 'tdspp'...
remote: Enumerating objects: 78, done.
remote: Total 78 (delta 0), reused 0 (delta 0), pack-reused 78
Unpacking objects: 100% (78/78), done.
$ cd tdspp
これでコンパイル環境は~/work/tdspp/
になります。
3. ソース修正
tdspp そのものは修正しない方針で進めます。
(1) Makefile の修正
些細な事ですが、Makefile に不備があるので、先に修正します。
install
の最下行の一つ前にある、@ln 〜
の行をコメントアウトします。
install:: $(LIB)
@ls -l $(LIB)
@echo "Installing $(SONAME) into $(PREFIX)"
@mkdir -p $(PREFIX)/lib/
@mkdir -p $(PREFIX)/include/$(LIBNAME)
install -o root -g bin -m 644 $(STRIPFLAG) $(LIB) $(PREFIX)/lib/
# @ln -fs $(PREFIX)/lib/$(LIB) $(PREFIX)/lib/$(SONAME)
install -o root -g bin -m 644 *.hh $(PREFIX)/include/$(LIBNAME)
※LIB のコメントを入れ替えても良いですが、今回は評価だけなので、これで済ませます。
(2) main.cc の修正
データベースへの接続情報を実際の環境に合わせます。
4. ライブラリ作成とインストール
(1) コンパイル
./configure は存在しないので、そのまま make します。
$ make
g++ -o tdspp.o -I/usr/local/include -c -Wall -ansi -fPIC -std=c++11 tdspp.cc
g++ -o query.o -I/usr/local/include -c -Wall -ansi -fPIC -std=c++11 query.cc
g++ -o field.o -I/usr/local/include -c -Wall -ansi -fPIC -std=c++11 field.cc
g++ -o libtds++.so -Wall -ansi -fPIC -std=c++11 -I/usr/local/include -L/usr/local/lib -lct -shared -ldl tdspp.o query.o field.o
$
make が成功すれば、カレントディレクトリにlibtds++.so
が作られます。
(2) インストール
ヘッダとライブラリを OS 環境にインストールします。
$ sudo make install
.......
Installing libtds++.so into /usr/local
install -o root -g bin -m 644 -s libtds++.so /usr/local/lib/
install -o root -g bin -m 644 *.hh /usr/local/include/tds++
$
(3) ライブラリの設定
/etc/ld.so.conf
に/usr/include/lib
を追加してsudo ldconfig
しますが、後で削除する予定なので、今回は何もしません。
その代わりに、サンプルを実行する環境で、一時的に LD_LIBRARY_PATH を設定します。
$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib
5. サンプルの実行
(1) コンパイルと実行結果
$ make main
g++ -g -std=c++11 main.cc -o main -L/usr/local/lib -ltds++ -lct
$ ./main
| datetime_type | right_now | integer_type | float_type |
Results:
| Mar 23 2020 08:19PM | Mar 23 2020 08:19PM | 1 | 0.1 |
(2) ロケール設定を追加してみる
main.cc にロケール設定を追加します。
(3) リコンパイルと実行結果
$ make main
g++ -g -std=c++11 main.cc -o main -L/usr/local/lib -ltds++ -lct
$ ./main
| datetime_type | right_now | integer_type | float_type |
Results:
| 3月 23 2020 08:25午後 | 3月 23 2020 08:25午後 | 1 | 0.1 |
日本語ロケールを考慮した、想定通りの結果です。
6. ちょっとだけ遊んでみた
日本語を含むクエリ文字列を実行して、int, nvarchar, datetime のデータ型を処理してみます。
(1) ソース修正
main.cc の中身を入れ替えます。
datetime 型は tdspp で考慮されていないデータ型なので、文字列で受けて強引に処理してます。
(2) コンパイルと実行結果
$ make main
g++ -g -std=c++11 main.cc -o main -L/usr/local/lib -ltds++ -lct
$ ./main
SELECT TOP 5 社員コード,氏名,CONVERT(nvarchar, 誕生日, 111) AS 誕生日 FROM 社員
結果:
| 105 | 森上 偉久馬 | 1967-10-25 |
| 107 | 葛城 孝史 | 1961-02-03 |
| 110 | 加藤 泰江 | 1968-02-02 |
| 204 | 川村 匡 | 1957-12-08 |
| 207 | 松沢 誠一 | 1965-03-30 |
日本語を含むクエリ文字列でも問題なく処理できたので、概ね満足です。
7. 補足
(1) tdspp のヘッダとライブラリの削除
make clean では削除されません。
そして、make uninstall 等も実装されていないので、手動で削除します。
$ sudo rm -r /usr/local/include/tds++/
$ sudo rm /usr/local/lib/libtds++.so
(2) 所感
本格的に tdspp を利用するなら、tdspp にも手を加えないとです。
C と DB-Library だけの時代と比べたら天国だとしても、やっぱり手間ですね。
クエリを工夫すれば、ある程度までは unixODBC 無し / ODBC ドライバ無しでも何とかなりそうだけど...
基本的には ODBC なので、もうこのパターンでコーディングする機会はほぼないかな。