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 件のコメント:
コメントを投稿