Rails5からrails db
を使ってSQL Serverに接続したかったので調べて試した結果をメモ。
結果としては接続はできた。
ただしSQL Server側がDatabaseの切り替えをサポートしていないので接続先のデータベースが指定できないということもあり実用性無し。
そのためtsql
コマンドで接続することに変更した。
環境
OS : CentOS7.3
ruby : 2.4.2
Rails : 5.1.4
DB : SQL Server(Azure)のtest-database(事前に作成済み)
FreeTSDのインストール
レポジトリにあるFreeTDS(0.9系)を使うと接続時にwarning: TinyTds: :use_utf16 option not supported in this version of FreeTDS.
という警告が出る。
それを回避するにはバージョンが1.0以上のFreeTDSをインストールしないと駄目なのでソースからビルドする。
$ cd /usr/local/src
$ wget ftp://ftp.freetds.org/pub/freetds/stable/freetds-1.00.9.tar.gz
$ tar zxvf freetds-1.00.9.tar.gz
$ cd freetds-1.00.9
$ ./configure --prefix=/usr/local/freetds
$ make
$ make install
$ vi /etc/profile.d/freetds.sh
export PATH="/usr/local/freetds/bin:${PATH}"
export LD_LIBRARY_PATH="/usr/local/freetds/lib:${LD_LIBRARY_PATH}"
$ exec ${SHELL} -l
$ tsql -C
Compile-time settings (established with the "configure" script)
Version: freetds v1.00.9
freetds.conf directory: /usr/local/freetds/etc
MS db-lib source compatibility: no
Sybase binary compatibility: no
Thread safety: yes
iconv library: yes
TDS version: auto
iODBC: no
unixodbc: no
SSPI "trusted" logins: no
Kerberos: no
OpenSSL: yes
GnuTLS: no
MARS: no
sqshのインストール
rails db
で接続するにはsqsh
というコマンドが必要なのでこれもソースからインストールする。
$ SYBASE=/usr/local/freetds
$ export SYBASE
$ cd /usr/local/src
$ wget https://jaist.dl.sourceforge.net/project/sqsh/sqsh/sqsh-2.5/sqsh-2.5.16.1.tgz
$ tar zxvf sqsh-2.5.16.1.tgz
$ cd sqsh-2.5/
三箇所ほどソースに手を加えないとエラーでこけるので以下のように修正する。
まず一箇所目。
修正前
/* 860行目付近 */
#if !defined(CS_TDS_50)
/* Then we use freetds which uses enum instead of defines */
else if (strcmp(tds_version, "7.0") == 0)
version = CS_TDS_70;
else if (strcmp(tds_version, "8.0") == 0)
version = CS_TDS_80;
修正後
#if !defined(CS_TDS_50)
/* Then we use freetds which uses enum instead of defines */
else if (strcmp(tds_version, "7.0") == 0)
version = CS_TDS_70;
#else if (strcmp(tds_version, "8.0") == 0)
# version = CS_TDS_80;
else if (strcmp(tds_version, "7.1") == 0)
version = CS_TDS_71;
else if (strcmp(tds_version, "7.2") == 0)
version = CS_TDS_72;
else if (strcmp(tds_version, "7.3") == 0)
version = CS_TDS_73;
続いて二箇所目。
修正前
/* 1260行目付近 */
#if !defined(CS_TDS_50)
case CS_TDS_70:
env_set( g_env, "tds_version", "7.0" );
case CS_TDS_80:
env_set( g_env, "tds_version", "8.0" );
break;
修正後
#if !defined(CS_TDS_50)
case CS_TDS_70:
env_set( g_env, "tds_version", "7.0" );
break;
#case CS_TDS_80:
# env_set( g_env, "tds_version", "8.0" );
# break;
case CS_TDS_71:
env_set( g_env, "tds_version", "7.1" );
break;
case CS_TDS_72:
env_set( g_env, "tds_version", "7.2" );
break;
case CS_TDS_73:
env_set( g_env, "tds_version", "7.3" );
break;
ラスト
修正前
/* 664行目付近 */
/*
* Take the existing format and strip it down according to the
* type of date that we are processing and replace the ms
* field if it exists.
*/
#if defined(CS_BIGDATETIME_TYPE) && defined(CS_BIGTIME_TYPE)
if (dt_fmt->datatype == CS_BIGDATETIME_TYPE || dt_fmt->datatype == CS_BIGTIME_TYPE)
fmt = dsp_datetime_strip( dt_fmt->datatype, conv_fmt, (int) dr.datesecfrac );
else
#endif
fmt = dsp_datetime_strip( dt_fmt->datatype, conv_fmt, (int) dr.datemsecond );
修正後
/* 修正後 */
/*
* Take the existing format and strip it down according to the
* type of date that we are processing and replace the ms
* field if it exists.
*/
fmt = dsp_datetime_strip( dt_fmt->datatype, conv_fmt, (int) dr.datemsecond );
修正を終えたらビルドしてインストールする。
$ ./configure --prefix=/usr/local/sqsh
$ make clean
$ make
$ make install
$ vi /etc/profile.d/sqsh.sh
export PATH="/usr/local/sqsh/bin:${PATH}"
$ exec ${SHELL} -l
$ sqsh -v
sqsh-2.5.16.1
これでRailsで接続する準備が出来た。
Rails側の環境構築
プロジェクトを作成する際にはsqlserverを指定する。
必要なgemは一緒にインストールされるのでGemfileは編集しなくもOK。
ただしfreetdsのインストール先を設定する必要あり。
SQL Serverへの接続はactiverecord-sqlserver-adapterとtiny_tdsが使われる。
$ rails new Sample -d sqlserver -B -T --api
$ cd Sample
$ bundle config build.tiny_tds -- --with-freetds-dir=/usr/local/freetds
$ bundle install --path vendor/bundle
database.ymlを編集する。
default: &default
adapter: sqlserver
username: rails
password: <%= ENV['DB_PASSWORD'] %>
host: hostname or IP
port: 1433 # ポート番号に変更が無いなら省略可
azure: true # Azure上のSQL Serverにつなぐには必要らしい
development:
<<: *default
database: test-database
接続確認
準備できたので接続できるか試す
$ rails db
sqsh-2.5.16.1 Copyright (C) 1995-2001 Scott C. Gray
Portions Copyright (C) 2004-2014 Michael Peppler and Martin Wesdorp
This is free software with ABSOLUTELY NO WARRANTY
For more information type '\warranty'
Msg 40508, Level 16, State 1
Server 'XXXXXXXXXXXXXX', Line 1
USE statement is not supported to switch between databases. Use a new connection to connect to a different database.
[5] XXXXXXXXXXXXXX.master.1>
接続はできたっぽいけどtest-databaseには接続できていないっぽい?masterってなんだ・・・。
軽く調べた限りではSQLServer(Azure)側がUSEコマンドをサポートしてないのが原因っぽい。
DB側が未サポートなのはどうにもならないので別の方法で接続することに変更。
tsqlコマンドで接続確認
rails db
じゃあ接続できないのでFreeTDSのtsql
を使って接続する。
まずfreetds.confに接続先の情報を追記
[conn-test]
host = hostname or IP
port = 1433
tds version = 7.0
続いてtsqlコマンドを実行。
$ tsql -S conn-test -U "ユーザ名" -D "test-database"
Password:
locale is "en_US.UTF-8"
locale charset is "UTF-8"
using default charset "UTF-8"
Setting test-database as default database in login packet
1>
接続できた。やったね。