Microsoftが提供しているSQL ServerのDockerイメージを使うと、デフォルト設定では無料のSQL Server Developer Editionのコンテナを起動できる。
このコンテナに対してRustからクエリを発行したい。Rustでは、SQL ServerのクライアントとしてPrismaが開発しているTiberiusというcrateがあるので、これを使う。
今回は0.12.2を使う。
SQL Serverのコンテナを起動する
version: '3' services: db: image: mcr.microsoft.com/mssql/server:2022-latest environment: ACCEPT_EULA: Y MSSQL_SA_PASSWORD: yourStrong(!)Password ports: - '1433:1433' volumes: - sqlvolume:/var/opt/mssql volumes: sqlvolume:
ACCEPT_EULA
があるとライセンス条項に同意したことになるMYSQL_SA_PASSWORD
が管理者(sa
)のパスワード。強めのパスワードポリシーがある- この記事では"yourStrong(!)Password"にしておく
- ボリュームをマウントしたい場合は/var/opt/mssqlへ
これで起動する。mssql/serverのイメージはamd64アーキテクチャにしか対応していないので、AppleシリコンのmacOSかつDocker Desktopを使う場合、Docker Desktopの"Use Rosetta for x86/amd64 emulation on Apple Silicon"を有効にする必要がある1。
sqlcmdから接続確認してもよい。
$ sqlcmd -U sa -P "yourStrong(!)Password" 1>
Tiberiusから接続する
ここから先は、すでにtestデータベースにproductsテーブルがあることにする。
create table products ( id int identity(1,1) primary key, name varchar(255) not null, price decimal(10,2) not null );
TiberiusからSQL Serverのコンテナに接続する。macOSでRustのコードを実行する場合、tiberius crateのfeatureとしてrustlsを有効化する必要があることに注意2。デフォルトのnative-tlsを使うとDB接続時にスタックしてしまう現象が見られた。
具体的には、tiberius crateデフォルトのfeatureをすべて無効化して、rustlsをfeatureとして追加する。Cargo.tomlに次のように設定を追加すればよい(デフォルトで有効なfeatureであるtds73も再度追加している)。
[dependencies] tiberius = { version = "0.12.2", default-features = false, features = ["tds73", "rustls"] } # ...
また、今回は非同期ランタイムとしてTokioを使う。cargo add tokio tokio-util
しておく。
SQL Serverのコンテナに接続するコードは次のとおり。
use tiberius::{AuthMethod, Client, Config}; use tokio::net::TcpStream; use tokio_util::compat::TokioAsyncWriteCompatExt; #[tokio::main] async fn main() -> anyhow::Result<()> { // 接続設定を作る。デフォルトでlocalhost:1433に接続する let mut config = Config::new(); config.database("test"); config.authentication(AuthMethod::sql_server("sa", "yourStrong(!)Password")); config.trust_cert(); // TLS証明書を検証しない // TCP接続する let tcp = TcpStream::connect(config.get_addr()).await?; tcp.set_nodelay(true)?; // DBに接続する let mut client = Client::connect(config, tcp.compat_write()).await?; // INSERT client .query( "insert into products (name, price) values (@P1, @P2)", &[&"Mac Studio", &1999], ) .await?; // SELECT let stream = client.query("select top 1 * from products", &[]).await?; let row = stream.into_row().await?.unwrap(); println!("{:#?}", row); Ok(()) }
注意点としては、開発用なのでTLS証明書を検証しない設定でないと接続に失敗する。DB設定の作成時にtiberius::Config::trust_cert
を呼んでおけばよい。
このコードを実行すると、次のように出力される。
Row { columns: [ Column { name: "id", column_type: Int4, }, Column { name: "name", column_type: BigVarChar, }, Column { name: "price", column_type: Decimaln, }, ], data: TokenRow { data: [ I32( Some( 15, ), ), String( Some( "Mac Studio", ), ), Numeric( Some( 1999.00, ), ), ], }, result_index: 0, }
- https://github.com/microsoft/mssql-docker/issues/668#issuecomment-1436802153↩
- TiberiusのREADMEによると、"For some reasons the Security Framework on macOS does not work with SQL Server TLS settings, and on Apple platforms if needing TLS it is recommended to use rustls instead of native-tls"とのこと↩