2012/05/08

MySQL でフェッチしながら他の SQL を実行

MySQL でフェッチしながら他の SQL を実行しようとするとよく "Commands out of sync; you can't run thiscommand now" というエラーになる。

大きな検索結果のときどうすりゃいいんだろう? というのがかねてからの疑問だった。

MySQL のクライレアント API を理解するために SWIG を使って Common Lisp から API をたたいてみた。

;; swig でコードを生成する。
(quicklisp:quickload :trivial-shell)
(with-open-file (out "/tmp/input.i" :direction :output :if-exists :supersede)
(write-string "%module input
%include \"/usr/include/mysql/mysql.h\""
out))
(trivial-shell:shell-command "swig -cffi /tmp/input.i")

;; libmysqlclient をロードする
(quicklisp:quickload :cffi)
(cffi:define-foreign-library libmysqlclient
((:not :windows) (:default "libmysqlclient"))
(:windows (:default "libmysql")))
(cffi:use-foreign-library libmysqlclient)

;; swig で生成したコードをロード
(load "/tmp/input.lisp")

;; MySQL に接続
(mysql_server_init -1 (cffi-sys:null-pointer) (cffi-sys:null-pointer))
(setf mysql (mysql_init (cffi-sys:null-pointer)))
(setf connection (mysql_real_connect mysql "localhost" "root" "" "outing_development" 0 "/var/run/mysqld/mysqld.sock" 0))
(mysql_set_character_set mysql "utf8")

;; クエリー行実 mysql_store_result
(mysql_query connection "select * from regions")
(setf result (mysql_store_result connection))
(loop for row = (mysql_fetch_row result)
until (cffi-sys:null-pointer-p row)
do (loop for i below (mysql_num_fields result)
do (format t "~a " (cffi:mem-aref row :string i))
finally (terpri)))
(mysql_free_result result)

;; クエリー行実 mysql_use_result
(mysql_query connection "select * from regions")
(setf result (mysql_use_result mysql))
(loop for row = (mysql_fetch_row result) ; このループを最後まで回らないと "Commands out of sync; you can't run this command now"
until (cffi-sys:null-pointer-p row)
do (loop for i below (mysql_num_fields result)
do (format t "~a " (cffi:mem-aref row :string i))
finally (terpri)))
(mysql_free_result result)

;; おしまい
(mysql_close connection)
(mysql_server_end)

mysql_fetch_row を使った場合は最後(null が返っくる)まで mysql_fetch_row をしないと "Commands out of sync; you can't run this command now" というエラーになる。ここに書いてある。

Common Lisp でコード書かなくてもマニュアルを読めばよかったんだけど、隠れた動機というやつかな。

で、結局のところフェッチしながら他の SQL を実行するにはどうすればいいか? よくわからん。

Rails の find_each なんかは何回かに分けて mysql_store_result している感じなんだろうか?

そんなことより、SWIG 使えば C のコードを一行も書かずに Common Lisp だけで C の API をたたけて実にすばらしい。

0 件のコメント: