MindでMySQL(Linux)にクエリーする（2-MySQL接続編）

# はじめに

だいぶ前2017年ごろMindユーザーの @MindZanmai さんのご質問に回答して、MindでLinux上のMySQLにクエリーする方法を詳しくコメントに解説しておりまして、最近SQLServerへのクエリ記事を書かれている @mylifewithviolin さんのおすすめもあって記事にまとめておくことにしました。内容は少し古くなっていますが、MindのDB接続関連の情報は少ないので参考になれば幸いです。

今回はMySQLへの接続です。

# 参考情報

C言語側のAPIのプログラムとして参考にしたのは以下のサイトです。

全体としてのプログラム
C言語でmysqlを使う - Qiita
http://qiita.com/Ki4mTaria/items/778ff9186bb4958bb667

APIごとの解説
MySQL :: MySQL 5.6 リファレンスマニュアル
https://dev.mysql.com/doc/refman/5.6/ja/mysql-init.html
https://dev.mysql.com/doc/refman/5.6/ja/mysql-real-connect.html
https://dev.mysql.com/doc/refman/5.6/ja/mysql-query.html

# MySQLへの接続

まずMySQLに接続します。
mysql_connect と mysql_real_connect の２種類があるようてすが後者のほうが推奨されるという記事を見ましたので後者にします。というより、前者はMindで使うには'MySQL'型のの構造体を用意する必要があって面倒そうでした。

それで、前回の解説で示したMindのサンプルで「mysql関数アドレス群を取得」という定義がありましたが、そこを mysql_real_connect に変更することにします。さら、今回使う mysql_init も追加することにします。

さて今回ですが、
前記の参考Webページ「C言語でmysqlを使う - Qiita」を見るとC言語での接続例が書かれているので参考にさせていただきます。以下のようになっています。
まずここから。

```C
int main(void){
  MYSQL *conn     = NULL;
  MYSQL_RES *resp = NULL;
  MYSQL_ROW row;
  char sql_str[255];
  char *sql_serv  = "localhost";
  char *user      = "root";
  char *passwd    = "";
  char *db_name   = "db_test";
//～略～
```

C言語の int main() はMindでいう「メインとは」です。
今回は mysql_init() と mysql_real_connect() だけやってみるので、それに必要な宣言だけにすると以下となります。

```C
int main(void){
  MYSQL *conn     = NULL;
  char *sql_serv  = "localhost";
  char *user      = "root";
  char *passwd    = "";
  char *db_name   = "db_test";
//～略～
```

上記宣言を解説します。

```C
  MYSQL *conn     = NULL;　　//（* は・・へのポインタのこと）
```

　※「MYSQL構造体へのポインタ変数 conn 初期値はNULL」と理解すると良い※
 
上は「MYSQL」という名前の（おそらく）構造体へのポインタを格納する変数定義です。つまりアドレスを格納するものなので、Mindであれば ○○は　変数 となります。

ちなみに、mysql_real_connect() ではなく mysql_connect() の場合は、

```C
  MYSQL conn;　　//（← *conn ではなく conn と書かれている）　（今回は使わない）
```

となるようで、こちらだと構造体の実体定義になります。これだとMindでやっかいです（それと同じ構造体をMind側て定義する必要があるため）。ポインタ定義で済む mysql_real_connect() のほうか便利だと思いました。

次の、
```C
  char *sql_serv  = "localhost";
```

は文字列定数を定義しています。Mindでは ○○は　文字列定数　「・・・」 に対応します。
文字列定数が全部で４個ありますがどれも同じようにします。

次に、C側処理本体で今回おこなうのは以下です。

```C
  // mysql接続
  conn = mysql_init(NULL);
  if( !mysql_real_connect(conn,sql_serv,user,passwd,db_name,0,NULL,0) ){
    // error
    exit(-1);
  }
```

上記は２つのステップを記述していますが、最初に、

```C
  conn = mysql_init(NULL);
```

をMind記述にします。

```mind
接続ハンドルは　変数

MySQLを初期化とは　（・　→　・）
　　　　$$NULLをつみ
　　　　　mysql_initアドレスで
　　　　　　アドレス指定でＡＰＩ呼出し１
　　　　接続ハンドルに　入れ
　　　　接続ハンドルが　ゼロ？
　　　　　　　　ならば　・・エラー処理・・
　　　　　　　　つぎに
　　　　。
```

　「アドレス指定でＡＰＩ呼出し１」は引数１つをスタックに積み、さらに関数アドレスをスタックに積んでから実行することでAPIが呼び出されます。共有ライブラリからの戻り値はスタックに返されます。
　（注：「アドレス指定でＡＰＩ呼出しｎ」の形の処理単語は多数存在しますが、いずれにもしても、スタックの最後に積むものは関数アドレスです

　「$$NULL」という見慣れない単語があります。これは「０」と書くのと同じなのですが、数値としての０を積むのではなく、「値０のポインタを渡す」意図で書きたいときに使います。（Cでは型管理があるので０とNULLは同じではないのですがMindでは同じです）

　次に mysql_initから戻された接続ハンドルがゼロ（NULL）の検査をしています。CサンプルではおこなっていませんでしたがAPI解説を見るとそのような戻りもあるようなので一応入れておきました。

話が飛びますが、
C側のソースでの変数「conn」をMindでは「接続ハンドル」にしました。英語系のプログラム言語ではこの conn のような短いシンボルがよく使われますが、簡略しすぎて意味不明になりがちなので（１文字の変数名よりはまだ良いですが‥）、やはりMindソースでは見て分かる変数名にしたいところです。ちなみに「接続ハンドル」は別のWebサイトで解説されていた用語を拝借しました。

次に以下のCソース、

```C
 if( !mysql_real_connect(conn,sql_serv,user,passwd,db_name,0,NULL,0) ){
    // error
    exit(-1);
  }
```

上記をMind記述にします。

```mind
MySQLに接続とは　（・　→　・）
　　　　　　　　ホスト名は　　　文字列定数　「localhost」
　　　　　　　　ユーザ名は　　　文字列定数　「myname」
　　　　　　　　パスワードは　　文字列定数　「・・・」
　　　　　　　　ｄｂ名は　　　　文字列定数　「・・・」
　　　　　　　　Ｃホスト名は　　文字列実体　長さ　８０桁
　　　　　　　　Ｃユーザ名は　　文字列実体　長さ　８０桁
　　　　　　　　Ｃパスワードは　文字列実体　長さ　８０桁
　　　　　　　　Ｃｄｂ名は　　　文字列実体　長さ　８０桁
　　　　　　　　戻値は　　　　　変数

　　（NULL終端文字列を作成）
　　　　ホスト名を　　Ｃホスト名に　　入れ、　０を　Ｃホスト名に　　一文字追加し
　　　　ユーザ名を　　Ｃユーザ名に　　入れ、　０を　Ｃユーザ名に　　一文字追加し
　　　　パスワードを　Ｃパスワードに　入れ、　０を　Ｃパスワードに　一文字追加し
　　　　ｄｂ名を　　　Ｃｄｂ名に　　　入れ、　０を　Ｃｄｂ名に　　　一文字追加し　※訂正済

　　（APIの呼び出し）
　　　　接続ハンドルをつみ　　　　　　　　※引数１
　　　　　Ｃホスト名をつみ　　　　　　　　※引数２
　　　　　　Ｃユーザ名をつみ　　　　　　　※引数３
　　　　　　　Ｃパスワードをつみ　　　　　※引数４
　　　　　　　　Ｃｄｂ名をつみ　　　　　　※引数５
　　　　　　　　　０と　$$NULLと　０と　　※引数６～８
　　　　　　　　　　mysql_real_connectアドレスで　　※←関数アドレス
　　　　　　　　　　　アドレス指定でＡＰＩ呼出し８し
　　　　戻値に　入れ
　　　　戻値が　ゼロ？
　　　　　　　　ならば　・・エラー処理・・
　　　　　　　　　　　　終り
　　　　　　　　つぎに
　　　　。
```

まず、Mindの文字列をCに渡すにはC特有のNULL終端形式に変換する必要があります。共有ライブラリ内の関数に文字列を渡すシーンではすべてこの変換をかける必要があります。
NULL終端形式といっても簡単で、別途確保した文字列実体変数にまず文字列を代入したあと、０を　＜文字列実体＞に　一文字追加する とするだけです。
一方、文字列のアドレスのほうですか、Mindの文字列情報は元々その整数部がアドレスをあらわしているので、アドレスについてだけいえばMindの文字列をそのまま渡せばよいです。
結果的に、Mindの文字列をCやAPIに渡すに必要なことはNULL終端をおこなうだけ‥と思えば良いです。
上記で文字列定数「ホスト名」に対して別の文字列実体変数「Ｃホスト名」を定義しているのはこのNULL終端形式を作るためのワークです。

なお、Mind側での文字列定数をNULL終端にする書き方もあります。たとえば、

```mind
　　　　ホスト名は　　　文字列定数　「localhost&00&」　（&00&はMind特有の十六進表記）
```

という書き方です。注意するのはこれを別の場面で（API呼び出し時ではなく普通のMindのプログラムとして）引用すると、末端のNULL文字も含めて参照することになる点です。しかしこの文字列定数がCやAPIのためだけに使われるのであれば問題ありません。そのことにさえ注意すれば、別に文字列実体を定義してNULL終端するコード書かなくて済むので便利な方法です。
あるいは、

```mind
　　　　ホスト名は　　　文字列定数　「localhost」
　　　　Ｃホスト名は　　文字列定数　「localhost&00&」
```
という定義も良いかも知れません。好みで使い分けてください。

　「アドレス指定でＡＰＩ呼出し８」は引数１～引数８をその順にスタックに積み、さらに関数アドレスをスタックに積んでから実行することでAPIが呼び出されます。Cの戻り値がスタックに返されます。

　切断のためのAPIである mysql_close() はCでは以下のような簡単な呼び出しです。

```C
  mysql_close(conn);
```

Mindでは以下のようになります。

```mind
MySQLをクローズとは　（・　→　・）
　　　　接続ハンドルと
　　　　　mysql_closeアドレスで
　　　　　　アドレス指定でＡＰＩ呼出し１
　　　　(戻値を)　捨て　　　　　　※←戻値が不要の場合も放置しないこと
　　　　。
```

改めて、ここまでの全体をまとめると以下のようになります。

```mind
モジュールハンドルは　変数。

MySQLの共有ライブラリをロードとは　（・　→　真偽）
     "/usr/～～/～.so"で　モジュールをロードし　モジュールハンドルに　入れ
     モジュールハンドルが　ゼロ以外を　返すこと。

MySQLの共有ライブラリを破棄とは　（・　→　・）
     モジュールハンドルが　ゼロ以外
          ならば　モジュールハンドルで　モジュールを解放し
               モジュールハンドルを　クリアする　　※←二度呼ばれることに備え

          つぎに。

mysql_initアドレスは　　　　　変数。
mysql_real_connectアドレスは　変数。
mysql_closeアドレスは 　　　　変数。
※mysql_・・・アドレスは　　　変数。
※mysql_・・・アドレスは　　　変数。

mysql関数アドレス群を取得とは　（・　→　・）
　　（エラーリターンがあるので「エラー？」で調べよ）
　　　　モジュールハンドルと　"mysql_init"で　モジュールの関数アドレスを得て
　　　　mysql_initアドレスに　入れ
　　　　エラー？
　　　　　　　　ならば　終り
　　　　　　　　つぎに
　　　　モジュールハンドルと　"mysql_real_connect"で　モジュールの関数アドレスを得て
　　　　mysql_real_connectアドレスに　入れ
　　　　エラー？
　　　　　　　　ならば　終り
　　　　　　　　つぎに
　　　　モジュールハンドルと　"mysql_close"で　モジュールの関数アドレスを得て
　　　　mysql_closeアドレスに　入れ
　　　　エラー？
　　　　　　　　ならば　終り
　　　　　　　　つぎに
※　　（当初は上だけで良いです。本格的に実験するには他の関数群も取得してください）
※　　　　モジュールハンドルと　"・・・"で　モジュールの関数アドレスを得て
※　　　　～略～
※　　　　モジュールハンドルと　"・・・"で　モジュールの関数アドレスを得て
※　　　　～略～
※　　　　モジュールハンドルと　"・・・"で　モジュールの関数アドレスを得て
※　　　　～略～
　　　　。

接続ハンドルは　変数。

MySQLを初期化とは　（・　→　真偽）
　　　　$$NULLをつみ
　　　　　mysql_initアドレスで
　　　　　　アドレス指定でＡＰＩ呼出し１
　　　　接続ハンドルに　入れ
　　　　接続ハンドルが　ゼロ？
　　　　　　　　ならば　偽を　返し
　　　　　　　　　　　　終り
　　　　　　　　つぎに
　　　　真を　返すこと。

MySQLに接続とは　（・　→　真偽）
　　　　　　　　ホスト名は　　　文字列定数　「localhost」
　　　　　　　　ユーザ名は　　　文字列定数　「myname」
　　　　　　　　パスワードは　　文字列定数　「・・・」
　　　　　　　　ｄｂ名は　　　　文字列定数　「・・・」
　　　　　　　　Ｃホスト名は　　文字列実体　長さ　８０桁
　　　　　　　　Ｃユーザ名は　　文字列実体　長さ　８０桁
　　　　　　　　Ｃパスワードは　文字列実体　長さ　８０桁
　　　　　　　　Ｃｄｂ名は　　　文字列実体　長さ　８０桁
　　　　　　　　戻値は　　　　　変数

　　（NULL終端文字列を作成）
　　　　ホスト名を　　Ｃホスト名に　　入れ、　０を　Ｃホスト名に　　一文字追加し
　　　　ユーザ名を　　Ｃユーザ名に　　入れ、　０を　Ｃユーザ名に　　一文字追加し
　　　　パスワードを　Ｃパスワードに　入れ、　０を　Ｃパスワードに　一文字追加し
　　　　Ｃｄｂ名を　　Ｃｄｂ名に　　　入れ、　０を　Ｃｄｂ名に　　　一文字追加し

　　（APIの呼び出し）
　　　　接続ハンドルをつみ　　　　　　　　※引数１
　　　　　Ｃホスト名をつみ　　　　　　　　※引数２
　　　　　　Ｃユーザ名をつみ　　　　　　　※引数３
　　　　　　　Ｃパスワードをつみ　　　　　※引数４
　　　　　　　　Ｃｄｂ名をつみ　　　　　　※引数５
　　　　　　　　　０と　$$NULLと　０と　　※引数６～８
　　　　　　　　　　mysql_real_connectアドレスで　　※←関数アドレス
　　　　　　　　　　　アドレス指定でＡＰＩ呼出し８し
　　　　戻値に　入れ
　　　　戻値が　ゼロ？
　　　　　　　　ならば　偽を　返し
　　　　　　　　　　　　終り
　　　　　　　　つぎに
　　　　真を　返すこと
　　　　。

MySQLをクローズとは　（・　→　・）
　　　　接続ハンドルと
　　　　　mysql_closeアドレスで
　　　　　　アドレス指定でＡＰＩ呼出し１
　　　　(戻値を)　捨て　　　　　　※←戻値が不要の場合も放置しないこと
　　　　。


メインとは
　　　　「共有ライブラリをロードする」
　　　　MySQLの共有ライブラリをロードし　偽？
　　　　　　　　ならば　※ スタック=空 ※
　　　　　　　　　　　　「MySQLの共有ライブラリのロード失敗」で　重大エラー
　　　　　　　　　　　　終り
　　　　　　　　つぎに
　　　　「ロード成功」を　一行表示し
　　　　「MySQLの共有ライブラリをロードの後」で　このメッセージでスタック検査し

　　　　「関数アドレス群を取得」を　一行表示し
　　　　mysql関数アドレス群を取得し
　　　　エラー？
　　　　　　　　ならば　エラー文字列で　重大エラー
　　　　　　　　つぎに
　　　　「取得成功」を　一行表示し
　　　　「関数アドレス群を取得の後」で　このメッセージでスタック検査し

　　　　MySQLを初期化し　偽？　　　　※2017.04.23 ここから7行分抜けていたので追加
　　　　　　　　ならば　※ スタック=空 ※
　　　　　　　　　　　　「MySQLを初期化失敗」で　重大エラー
　　　　　　　　　　　　終り
　　　　　　　　つぎに
　　　　「MySQLを初期化成功」を　一行表示し
　　　　「MySQLを初期化の後」で　このメッセージでスタック検査し

　　　　「MySQLに接続」を　一行表示し
　　　　MySQLに接続し　偽？
　　　　　　　　ならば　※ スタック=空 ※
　　　　　　　　　　　　「MySQLに接続失敗」で　重大エラー
　　　　　　　　　　　　終り
　　　　　　　　つぎに
　　　　「接続成功」を　一行表示し
　　　　「MySQLに接続の後」で　このメッセージでスタック検査し

　　　　「MySQLをクローズ」を　一行表示し
　　　　MySQLをクローズし
　　　　「クローズ成功」を　一行表示し
　　　　「MySQLをクローズの後」で　このメッセージでスタック検査し

　　　　「共有ライブラリを破棄する」を　一行表示し
　　　　MySQLの共有ライブラリを破棄し
　　　　「MySQLの共有ライブラリを破棄の後」で　このメッセージでスタック検査し
　　　　。
```

先にも書きましたが、実際に動作確認したわけではないので、細かなミスがあるかも知れません。

Mindユーザーの @MindZanmai さんは下記のコードで接続できたようです。

<details><summary>ソースコード全文</summary>

```mind
mysql_closeは　数値　１。
mysql_initは　数値　２。
mysql_real_connectは　数値　３。
mysql_real_queryは　数値　４。
mysql_queryは　数値　５。
mysql_store_resultは　数値　６。
mysql_free_resultは　数値　７。
mysql_num_rowsは　数値　８。
mysql_num_fieldsは　数値　９。
mysql_errnoは　数値　１０。

mysql関数名は　文字列定数配列
    "mysql_close"
    "mysql_init"
    "mysql_real_connect"
    "mysql_real_query"
    "mysql_query"
    "mysql_store_result"
    "mysql_free_result"
    "mysql_num_rows"
    "mysql_num_fields"
    "mysql_errno"
。
mysqlアドレスは　50個の　変数。

モジュールハンドルは　変数。
MySQLのモジュール名は　”/usr/lib/mysql/libmysqlclient.so.16”。

MySQLの共有ライブラリをロードとは　（・　→　真偽）
    MySQLのモジュール名で　モジュールをロードし　モジュールハンドルに　入れ
    モジュールハンドルが　ゼロ以外を　返すこと。

MySQLの共有ライブラリを破棄とは　（・　→　・）
    モジュールハンドルが　ゼロ以外
        ならば
            モジュールハンドルで　モジュールを解放し
            モジュールハンドルを　クリアする
        つぎに。

mysql関数アドレス群を取得とは　（・　→　・）
    mysql関数名の　要素数で　回数指定し
        モジュールハンドルと　mysql関数名（回数）で　モジュールの関数アドレスを得て
        mysqlアドレス（回数）に　入れ
        エラー？
            ならば　
            mysql関数名（回数）を　表示し
            ”アドレス取得失敗”を　一行表示し
        つぎに
    繰り返す
。

接続ハンドルは　変数。

MySQLを初期化とは　（・　→　真偽）
　　　　$$NULLをつみ
　　　　　mysqlアドレス（mysql_init）で
　　　　　※mysql_initアドレスで
　　　　　　アドレス指定でＡＰＩ呼出し１
　　　　接続ハンドルに　入れ
　　　　接続ハンドルが　ゼロ？
　　　　　　　　ならば　偽を　返し
　　　　　　　　　　　　終り
　　　　　　　　つぎに
　　　　真を　返すこと。

MySQLに接続とは　（・　→　真偽）
　　　　　　　　ホスト名は　　　文字列定数　「localhost」
　　　　　　　　ユーザ名は　　　文字列定数　「mind」
　　　　　　　　パスワードは　　文字列定数　「*****」
　　　　　　　　ｄｂ名は　　　　文字列定数　「minddb」
　　　　　　　　Ｃホスト名は　　文字列実体　長さ　８０桁
　　　　　　　　Ｃユーザ名は　　文字列実体　長さ　８０桁
　　　　　　　　Ｃパスワードは　文字列実体　長さ　８０桁
　　　　　　　　Ｃｄｂ名は　　　文字列実体　長さ　８０桁
　　　　　　　　戻値は　　　　　変数

　　（NULL終端文字列を作成）
　　　　ホスト名を　　Ｃホスト名に　　入れ、　０を　Ｃホスト名に　　一文字追加し
　　　　ユーザ名を　　Ｃユーザ名に　　入れ、　０を　Ｃユーザ名に　　一文字追加し
　　　　パスワードを　Ｃパスワードに　入れ、　０を　Ｃパスワードに　一文字追加し
　　　　ｄｂ名を　　Ｃｄｂ名に　　　入れ、　０を　Ｃｄｂ名に　　　一文字追加し

　　（APIの呼び出し）
　　　　接続ハンドルをつみ　　　　　　　　※引数１
　　　　　Ｃホスト名をつみ　　　　　　　　※引数２
　　　　　　Ｃユーザ名をつみ　　　　　　　※引数３
　　　　　　　Ｃパスワードをつみ　　　　　※引数４
　　　　　　　　Ｃｄｂ名をつみ　　　　　　※引数５
　　　　　　　　　０と　$$NULLと　０と　　※引数６～８
　　　　　　　　　　mysqlアドレス（mysql_real_connect）で　　※←関数アドレス
　　　　　　　　　　※mysql_real_connectアドレスで　　※←関数アドレス
　　　　　　　　　　　アドレス指定でＡＰＩ呼出し８し
　　　　戻値に　入れ
　　　　戻値が　ゼロ？
　　　　　　　　ならば　偽を　返し
　　　　　　　　　　　　終り
　　　　　　　　つぎに
　　　　真を　返すこと
　　　　。

MySQLをクローズとは　（・　→　・）
　　　　接続ハンドルと
　　　　　mysqlアドレス（mysql_close）で
　　　　　※mysql_closeアドレスで
　　　　　　アドレス指定でＡＰＩ呼出し１
　　　　(戻値を)　捨て　　　　　　※←戻値が不要の場合も放置しないこと
　　　　。

メインとは
    「共有ライブラリをロードする」を　一行表示し
    MySQLの共有ライブラリをロードし　偽？
        ならば
            「ロード失敗」を　一行表示し
            終り
        つぎに
    「ロード成功」を　一行表示し
    「MySQLの共有ライブラリをロードの後」で　このメッセージでスタック検査し

    「関数アドレス群を取得」を　一行表示し
    mysql関数アドレス群を取得し
    「取得成功」を　一行表示し
　　　　「関数アドレス群を取得の後」で　このメッセージでスタック検査し

　　　　「MySQLを初期化」を　一行表示し
    MySQLを初期化し　偽？
　　　　　　　　ならば　※ スタック=空 ※
　　　　　　　　　　　　「MySQLの初期化失敗」で　重大エラー
　　　　　　　　　　　　終り
　　　　　　　　つぎに
　　　　「MySQL初期化成功」を　一行表示し
    「MySQLを初期化の後」で　このメッセージでスタック検査し

　　　　「MySQLに接続」を　一行表示し
　　　　MySQLに接続し　偽？
　　　　　　　　ならば　※ スタック=空 ※
　　　　　　　　　　　　「MySQLに接続失敗」で　重大エラー
　　　　　　　　　　　　終り
　　　　　　　　つぎに
　　　　「接続成功」を　一行表示し
　　　　「MySQLに接続の後」で　このメッセージでスタック検査し

　　　　「MySQLをクローズ」を　一行表示し
　　　　MySQLをクローズし
　　　　「クローズ成功」を　一行表示し
　　　　「MySQLをクローズの後」で　このメッセージでスタック検査し

    「共有ライブラリを破棄する」を　一行表示し
    MySQLの共有ライブラリを破棄する
　　　　「MySQLの共有ライブラリを破棄の後」で　このメッセージでスタック検査し
　　　　。
```

</details>

# おわりに

今回はここまでです。次回はMySQLへのクエリー処理について記述します。