なぜだか急に pg gem の実装が気になった。
# コネクション張って SELECT するだけのコード require 'pg' conn = PG.connect(dbname: 'hoge') conn.exec('SELECT * FROM fuga') do |result| result.each do |row| puts row end end
👆 のコードを実行した時に何が起こっているかを追う。
バージョン
pg 1.2.3
PG.connect
PG.connect
の定義は lib/pg.rb にある。
はいはい PG::Connection
のインスタンスを返してるのね。って PG::Connection クラス 見てみたらインスタンスメソッド一つもないし、example コード の PG::Connection.open
も定義されてない。
ここでハマってしまったが、結論から言うと全て ext/
以下の C 言語のコードで定義されていた。
実装的には ext/pg_connection.c にあった。
まず .open
含むいくつかの特異メソッドは .new
の alias だった。
alias 張るのに使われてる SINGLETON_ALIAS
は自前で定義したマクロだった。(内部的にはrb_define_alias 使ってる)
alias 張られてるクラスの rb_cPGconn
が PG::Connection
なのではと思って読んでたら、ビンゴ。
rb_cPGconn
変数代入してるとこ 見ると、 rb_define_class_under で rb_mPG
に所属する定数として定義されていて、rb_mPG
変数代入してるとこ(C 拡張の初期化時に呼ばれる)を見ると、rb_define_module でモジュール PG
として定義されていた。
で initialize の処理は rb_define_method で pgconn_init として定義されていた。
pgconn_init これが読みたかったんだよう 😭(ドキュメントもバッチリ書いてある…)
とりあえずいろいろやって conn オブジェクトを返してるね。(ここまで読んで満足してる)
conn.exec
ここ で pgconn_async_exec
として定義されてる。
pgconn_async_exec これが読みたかry
大事そうな処理としては postgres にクエリ投げてるっぽい pgconn_send_query と非同期に結果取得してるっぽい pgconn_get_last_result かな。
pgconn_get_last_result
で PG::Result
が返る。(PG::Result
の定義は ここ っぽいけど力尽きました)
所感
- 途中から PostgreSQL とか pg gem とかどうでもよくなってた
- ruby の C API の読み方がちょっと分かって良かった