[pending]Common LispでどうやってMySQLと接続するのか調べてみる。

Common Lispで
どうやってデータベース(MySQL)とのやり取りをするんだろうかわからなかったので、

https://github.com/fukamachi/cl-dbi

のソースコードから学んでいきます。

## 注意
Lispに関してはまだまだ初心者ですので、間違いがあればぜひご指摘ください。すごく喜びます。

読み進めると、どんどん雑になっているのが分かると思います。
補足などのリクエストもぜひお願いします。


# cl-dbiとは
CL-DBI - Database independent interface for Common Lisp

つまりデータベースと簡単にやりとりできるすばらしいライブラリ。

(#追記　いろんなデータベースとやりとりできることがすごく便利でした。)

では、さっそくとりかかっていきます。


# 読むファイルを決める
Lispではsourceをsrcに、
テストをtにいれる(はず)なので
srcを読み込んでいきます。

すべて読むと効率が悪いので、
メインのファイルを読んでいきます。(dbi.lisp、driver.lisp、mysql.lisp)

```
src/
  dbd/
    mysql/
      error.lisp
    ココ→mysql.lisp
    postgres.lisp
    sqlite3.lisp
  ココ→dbi.lisp
  ココ→driver.lisp
  error.lisp
　test.lisp
```
 
# dbi.lisp

dbi.driverからimportしてるメソッドが
prepare、execute、commit、rollebackがあるので、
driverの方ではクエリを実行したりするのかなと予想をつけます。

さらにimportしたものも、exportしているので
このファイルがメインのファイルだろうなと推測します。


メイン処理を読み始めて最初に目に入るのが、

```cl
@export
(defun connect (driver-name &rest params &key database-name &allow-other-keys)
  "Open a connection to the database which corresponds to `driver-name`."
...
```
この@export。

LispではS式を採用しておりカッコに囲まれているため、
この@exportはいびつです。

調べてみると、これはアノテーションと呼ばれる技法であり
マクロが呼ばれる前の任意のタイミングで評価するリードマクロであることが分かります。
http://blog.8arrow.org/entry/20120419/1334852535

つまり記事を参考にすると、上の記述は

```cl
(progn
   (export #'connect)
   (defun connect ...)
```
のように解釈されるということです。

### connect関数
こちらでは適切なdriveを探し、
そのdriveからmake-instanceし、
make-connectionを行ってます。

##### make-instance
とは、[CLOS](https://ja.wikibooks.org/wiki/Lisp/%E5%9F%BA%E6%9C%AC%E3%81%8B%E3%82%89%E3%81%95%E3%82%89%E3%81%AB%E4%B8%80%E6%AD%A9%E9%80%B2%E3%82%93%E3%81%A7/CLOS)においてdefclassで定義した
クラスのオブジェクトを作成するメソッドで、driverのオブジェクトを作成しています。



### make-connection関数
こちらはdriverファイルに定義されているので、ファイルを移動します。

```cl

(defgeneric make-connection (driver &key)
  (:documentation "Create a instance of `<dbi-connection>` for the `driver`.
This method must be implemented in each drivers.")
```
defgenericは確か総称関数とばれるもののはずですが、忘れたので調べます。

[こちら](https://ja.wikipedia.org/wiki/Common_Lisp_Object_System)を参考に調べてみると、

```
(defgeneric who-are-u()
)

(defmethod who-are-u ((a person-class))
  (format nil "your person")
)

(defmethod who-are-u ((a animal-class))
  (format nil "your animal")
)
```
のように、引数のクラス?によって
あらかじめdefgenericで定義していた
関数のふるまいを変更することができるようです。引数のクラスが何を継承しているかで
また更にいろいろな処理を事前、事後に走らせることができて便利ですね。

ぱっと思いつくものだと、
コールバックなどにつかえるのかな、なんて思いました。

さて、コードに戻ります。
make-connectionの中では
:documentationと
:methodが続きメイン処理が
ないように見えますが、

どうやら:methodとはdefmethodと
[同義](https://stackoverflow.com/questions/29639620/use-of-method-option-in-defgeneric)で、デフォルトの定義となるようです。

つまりこの総称関数のメイン処理は

```
@ignore driver
``` 

になります。
けど、driverとは先ほど
make-instanceなはずなので、??となります。

ちなみに`<dbi-driver>`は

```cl

(defclass <dbi-driver> () ()
  (:documentation "Base class for DB driver."))
```
クラスみたいですね。

どうやらクラスは<class-name>となってるみたいで凄くわかりやすいです。
僕もまねしようと思います。

さて行き詰りましたが、

先ほど定義されていた
make-connection の実態が
なんであるのかが気になります。

ただインスタンスを返すメソッドであれば、接続は確立されないはず。。

いったん、make-connectionが
どのように使われているのか調べてみます。ソースコードを検索してみると。。。

# src/dbd/mysql.lisp
にも定義されていました。

```cl
(defmethod make-connection ((driver <dbd-mysql>) &key host database-name username password port socket client-flag)
  (make-instance '<dbd-mysql-connection>
```

なるほど、driverとはMySqlなどのRDMSであり、
それによってふるまい方を変えているのですね。(それが総称関数を使うことのメリットですね。忘れていました。すごくわかりやすい。)

どのようにこのファイルを読み込んでいるのか、僕の知識不足で分かっていないですが、
driver.lispが各RDMSの抽象層であることがわかりました。

mysql.lisp内で定義されている
make-connectionを見ると、

```cl
(defmethod make-connection ((driver <dbd-mysql>) &key host database-name username password port socket client-flag)
  (make-instance '<dbd-mysql-connection>
     :database-name database-name
　　　:handle (connect :host host
```
どうやら、ここでは`<dbd-mysql-connection>`のオブジェクトを作成しています。


ここのhandleで使われているconnect関数が実は
cl-mysqlの関数であり、MySQLとのコネクションを作成してる
みたいなので、cl-mysqlに移動します。

...

# cl-mysql

https://github.com/hackinghat/cl-mysql

Common Lisp MySQL library

10年前のコードみたいですね。
(そんな昔のコードを読むことができて、おぉっとなりました。)

さてconnect関数を探していくと、

https://github.com/hackinghat/cl-mysql/blob/master/pool.lisp#L283

にありました。

# connect

```cl
(defun connect (&key host user password database port socket
...
 (setf *last-database* (make-instance 'connection-pool
...
```

ここではconnection-poolのオブジェクトを作成されていますね。

connection-poolクラスには、定義しか書かれていないので
実際にどのような処理が走ってるのかよくわかりません。

少しソースコードを探索すると、

```cl
(defmethod initialize-instance :after ((self connection-pool) &rest initargs)
  "The connection arrays need to be set-up after the pool is created."
```

どうやらconnection-poolのオブジェクトを作成する前に
initialize-instance関数が実行されるようです。

# initialize-instance
http://clhs.lisp.se/Body/f_init_i.htm
http://www.nct9.ne.jp/m_hiroi/clisp/clisp07.html#chap0702

この関数の中でも総称関数を使った技法があります。

```cl
(defmethod initialize-instance :after ((self connection-pool) &rest initargs)
  "The connection arrays need to be set-up after the pool is created."
  (declare (ignore initargs))
  (setf (connections self) (make-array (max-connections self)
...
```

最後に書かれているsetfですが、実はこれは
普通のsetfではありません。

```cl
(defmethod (setf max-connections) ((max-connect number) (pool connection-pool))
...
 (with-lock (pool-lock pool)
    (setf (slot-value pool 'max-connections) max-connect))
  (pool-notify pool)
```
この定義によりmax-connectionsが引数に渡った時の
setfを再定義しており、この書き方をすることによって
setfに渡すクラスによって、どの変数に定義するするのか
事前に決めることができます。

そして最大接続数と残りの可能な接続数を
設定した後に、

connect-upto-minimumというメイン処理に進みます。

# connect-upto-minimum

```cl
(loop for i from 0 to (1- (- min n))
     do (connect-to-server self))
```

シンプルですね。
connect-to-serverを見に行きます。

# connect-to-server
```cl

(defmethod connect-to-server ((self connection-pool))
  "Create a new single connection and add it to the pool."
  (let* ((mysql (mysql-init (null-pointer)))
	 (connection (mysql-real-connect mysql
 ...
    (error-if-null mysql connection)
    (add-connection self (make-instance 'connection
					:pointer  connection
					:owner-pool self
					:in-use nil))))
```

ここでは、connection変数をmysql-real-connectを使って
作成し、その変数を使ってconnectionのオブジェクトを作成して
既存のコネクションらの可変長配列に追加しているようです。

ここででてくるmysql-real-connectが僕が探していた関数です。
(長かった。。)

# mysql-real-connect

system.lispの中にあるので、
定義を見てみると、、、

```cl

(defmysqlfun ("mysql_real_connect" mysql-real-connect) :pointer
...
  (client-flag :unsigned-long))
```


どうやらマクロでさらに定義されているみたいです。

# defmysqlfun

```cl
(defmacro defmysqlfun ((name internal-name) return-type &body args)
...
  (let* ((n name)
	 (int-name internal-name)
	 (int-libname (intern (string-upcase
...
`(defcfun (,n ,int-name) ,return-type
	   ,mysql-doc-ref
	   ,@args))))
```

渡した"mysql-real-connect"を,
defcfunを使って定義しています。

このdefcfunの定義はソースにのっていないので、
調べてみると、

# defcfun

https://masatoi.hateblo.jp/entry/20160805/1470385802

C言語のライブラリ(限定しないかもしれない)を使うために
cffiとライブラリがあるようで、
それを使ってC言語のmysql-real-connect関数を呼び出しているのですね。

つまり、実際にどのようにコネクションを作っているのかは、
さらにこのC言語のmysql-real-connect関数を読み解かなければ
ならない。。。orz


残念ながら僕はCをサクサク読めないので、
今回は一旦ここまでとして、また気が向いたら↑を
読んでいきたいと思います。


今回ではCLOSを使った書き方をいっぱい学べました。
OSSを読むといっぱい勉強できるので楽しいです。

次はlackを読んでいこうかな。

また気が向いたら書きます。
それでは。