WindowsでNimからPostgreSQLにアクセスする


libpq.dllはどこに?

開発PCにDockerがインストールされている環境では、PostgreSQL等のDBサーバーを立ち上げるのは比較的簡単です。

DBサーバーを立ち上げることは簡単になったものの、WindowsからPostgreSQLにアクセスする場合、Nimであればdb_postgresモジュールを使えばアクセスできるわけではなく、db_postgresが、libpq.dllというDLLファイルに依存しており、このファイルが無いことには、PostgreSQLにはアクセスできません。

import db_postgres
let db = open("localhost:5432","user","password","database_name")

# Error
# could not load: libpq.dll

libpq.dllだけを落としてきてもダメ

今どきでは、libpq.dllを検索するとダウンロードサイトがいくつかヒットします。
ですが、Windows32ビット版だったりなど、なかなかうまく行きません。

結局のところ、PostgreSQLをダウンロードせよ

PostgreSQLの本体はインストールしたくないけど、クライアントツールのインストールさえできれば、DLLが手に入りそうなので、諦めて本家(https://www.enterprisedb.com/downloads/postgres-postgresql-downloads) から、PostgreSQLのインストーラをダンロードします(およそ200MBくらい)。

Let's インストール

ダウンロードしたファイルはExe形式になっているのでこれを実行し、インストーラを起動します。

コマンドラインツールだけを選択しインストール

PostgreSQL自体はDockerで導入するので、CommandLine Toolsをチェックし、インストールを継続します。

libpq.dllはどこに?(その2)

インストールされたフォルダを確認すると、C:\Program Files\PostgreSQL\11\binフォルダに、念願のlibpq.dllが入っています。

libpq.dllだけをコピって使おうとしてもやっぱりダメ

nimソースのあるフォルダにlibpq.dllファイルをコピーし、先のコードを実行しても、まだlibpq.dllが無いと怒られます。
この理由はlibpq.dllが更に他のDLL(binフォルダに配置されていたDLL)に依存しているからです。

これは、dependency walkerというツールを使うと確認できます。

そのために取れる手段としては、以下の2つのうちのどれかとなります。
* インストール先のbinフォルダへPathを通す
* binフォルダ内のすべてのdllファイルを(nimインストール先のbin)コピーする

まとめ的な何か

PostgreSQLのインストール先\binにパスを通し、以下のソースを実行してみます。

pgsample.nim
import db_postgres

const host_port = "localhost:5432"
const user_name = "username"
const password  = "password"
const db_name   = "postgres"

block:
  let db = open(host_port,user_name,password,db_name)
  echo "opened"
  defer:
    db.close 
    echo "closed"
  for x in db.fastRows(sql"select current_schema()") :
    echo x

結果はこちら。

opened
@["public"]
closed

この手の方法はその他DB(Oracle/MySQL)でも同様で、クライアントツール等のインストールを行い必要なDLLへのパスを通すなどの作業は必要です。
当初はlibpq.dllだけが必要ならそれだけ落としてこれば良いかと思って始まった勘違いの旅路でした。