はじめに
だいぶ前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 の2種類があるようてすが後者のほうが推奨されるという記事を見ましたので後者にします。というより、前者はMindで使うには'MySQL'型のの構造体を用意する必要があって面倒そうでした。
それで、前回の解説で示したMindのサンプルで「mysql関数アドレス群を取得」という定義がありましたが、そこを mysql_real_connect に変更することにします。さら、今回使う mysql_init も追加することにします。
さて今回ですが、
前記の参考Webページ「C言語でmysqlを使う - Qiita」を見ると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() だけやってみるので、それに必要な宣言だけにすると以下となります。
int main(void){
MYSQL *conn = NULL;
char *sql_serv = "localhost";
char *user = "root";
char *passwd = "";
char *db_name = "db_test";
//~略~
上記宣言を解説します。
MYSQL *conn = NULL; //(* は・・へのポインタのこと)
※「MYSQL構造体へのポインタ変数 conn 初期値はNULL」と理解すると良い※
上は「MYSQL」という名前の(おそらく)構造体へのポインタを格納する変数定義です。つまりアドレスを格納するものなので、Mindであれば ○○は 変数 となります。
ちなみに、mysql_real_connect() ではなく mysql_connect() の場合は、
MYSQL conn; //(← *conn ではなく conn と書かれている) (今回は使わない)
となるようで、こちらだと構造体の実体定義になります。これだとMindでやっかいです(それと同じ構造体をMind側て定義する必要があるため)。ポインタ定義で済む mysql_real_connect() のほうか便利だと思いました。
次の、
char *sql_serv = "localhost";
は文字列定数を定義しています。Mindでは ○○は 文字列定数 「・・・」 に対応します。
文字列定数が全部で4個ありますがどれも同じようにします。
次に、C側処理本体で今回おこなうのは以下です。
// mysql接続
conn = mysql_init(NULL);
if( !mysql_real_connect(conn,sql_serv,user,passwd,db_name,0,NULL,0) ){
// error
exit(-1);
}
上記は2つのステップを記述していますが、最初に、
conn = mysql_init(NULL);
をMind記述にします。
接続ハンドルは 変数
MySQLを初期化とは (・ → ・)
$$NULLをつみ
mysql_initアドレスで
アドレス指定でAPI呼出し1
接続ハンドルに 入れ
接続ハンドルが ゼロ?
ならば ・・エラー処理・・
つぎに
。
「アドレス指定でAPI呼出し1」は引数1つをスタックに積み、さらに関数アドレスをスタックに積んでから実行することでAPIが呼び出されます。共有ライブラリからの戻り値はスタックに返されます。
(注:「アドレス指定でAPI呼出しn」の形の処理単語は多数存在しますが、いずれにもしても、スタックの最後に積むものは関数アドレスです
「$$NULL」という見慣れない単語があります。これは「0」と書くのと同じなのですが、数値としての0を積むのではなく、「値0のポインタを渡す」意図で書きたいときに使います。(Cでは型管理があるので0とNULLは同じではないのですがMindでは同じです)
次に mysql_initから戻された接続ハンドルがゼロ(NULL)の検査をしています。CサンプルではおこなっていませんでしたがAPI解説を見るとそのような戻りもあるようなので一応入れておきました。
話が飛びますが、
C側のソースでの変数「conn」をMindでは「接続ハンドル」にしました。英語系のプログラム言語ではこの conn のような短いシンボルがよく使われますが、簡略しすぎて意味不明になりがちなので(1文字の変数名よりはまだ良いですが‥)、やはりMindソースでは見て分かる変数名にしたいところです。ちなみに「接続ハンドル」は別のWebサイトで解説されていた用語を拝借しました。
次に以下のCソース、
if( !mysql_real_connect(conn,sql_serv,user,passwd,db_name,0,NULL,0) ){
// error
exit(-1);
}
上記をMind記述にします。
MySQLに接続とは (・ → ・)
ホスト名は 文字列定数 「localhost」
ユーザ名は 文字列定数 「myname」
パスワードは 文字列定数 「・・・」
db名は 文字列定数 「・・・」
Cホスト名は 文字列実体 長さ 80桁
Cユーザ名は 文字列実体 長さ 80桁
Cパスワードは 文字列実体 長さ 80桁
Cdb名は 文字列実体 長さ 80桁
戻値は 変数
(NULL終端文字列を作成)
ホスト名を Cホスト名に 入れ、 0を Cホスト名に 一文字追加し
ユーザ名を Cユーザ名に 入れ、 0を Cユーザ名に 一文字追加し
パスワードを Cパスワードに 入れ、 0を Cパスワードに 一文字追加し
db名を Cdb名に 入れ、 0を Cdb名に 一文字追加し ※訂正済
(APIの呼び出し)
接続ハンドルをつみ ※引数1
Cホスト名をつみ ※引数2
Cユーザ名をつみ ※引数3
Cパスワードをつみ ※引数4
Cdb名をつみ ※引数5
0と $$NULLと 0と ※引数6~8
mysql_real_connectアドレスで ※←関数アドレス
アドレス指定でAPI呼出し8し
戻値に 入れ
戻値が ゼロ?
ならば ・・エラー処理・・
終り
つぎに
。
まず、Mindの文字列をCに渡すにはC特有のNULL終端形式に変換する必要があります。共有ライブラリ内の関数に文字列を渡すシーンではすべてこの変換をかける必要があります。
NULL終端形式といっても簡単で、別途確保した文字列実体変数にまず文字列を代入したあと、0を <文字列実体>に 一文字追加する とするだけです。
一方、文字列のアドレスのほうですか、Mindの文字列情報は元々その整数部がアドレスをあらわしているので、アドレスについてだけいえばMindの文字列をそのまま渡せばよいです。
結果的に、Mindの文字列をCやAPIに渡すに必要なことはNULL終端をおこなうだけ‥と思えば良いです。
上記で文字列定数「ホスト名」に対して別の文字列実体変数「Cホスト名」を定義しているのはこのNULL終端形式を作るためのワークです。
なお、Mind側での文字列定数をNULL終端にする書き方もあります。たとえば、
ホスト名は 文字列定数 「localhost&00&」 (&00&はMind特有の十六進表記)
という書き方です。注意するのはこれを別の場面で(API呼び出し時ではなく普通のMindのプログラムとして)引用すると、末端のNULL文字も含めて参照することになる点です。しかしこの文字列定数がCやAPIのためだけに使われるのであれば問題ありません。そのことにさえ注意すれば、別に文字列実体を定義してNULL終端するコード書かなくて済むので便利な方法です。
あるいは、
ホスト名は 文字列定数 「localhost」
Cホスト名は 文字列定数 「localhost&00&」
という定義も良いかも知れません。好みで使い分けてください。
「アドレス指定でAPI呼出し8」は引数1~引数8をその順にスタックに積み、さらに関数アドレスをスタックに積んでから実行することでAPIが呼び出されます。Cの戻り値がスタックに返されます。
切断のためのAPIである mysql_close() はCでは以下のような簡単な呼び出しです。
mysql_close(conn);
Mindでは以下のようになります。
MySQLをクローズとは (・ → ・)
接続ハンドルと
mysql_closeアドレスで
アドレス指定でAPI呼出し1
(戻値を) 捨て ※←戻値が不要の場合も放置しないこと
。
改めて、ここまでの全体をまとめると以下のようになります。
モジュールハンドルは 変数。
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アドレスで
アドレス指定でAPI呼出し1
接続ハンドルに 入れ
接続ハンドルが ゼロ?
ならば 偽を 返し
終り
つぎに
真を 返すこと。
MySQLに接続とは (・ → 真偽)
ホスト名は 文字列定数 「localhost」
ユーザ名は 文字列定数 「myname」
パスワードは 文字列定数 「・・・」
db名は 文字列定数 「・・・」
Cホスト名は 文字列実体 長さ 80桁
Cユーザ名は 文字列実体 長さ 80桁
Cパスワードは 文字列実体 長さ 80桁
Cdb名は 文字列実体 長さ 80桁
戻値は 変数
(NULL終端文字列を作成)
ホスト名を Cホスト名に 入れ、 0を Cホスト名に 一文字追加し
ユーザ名を Cユーザ名に 入れ、 0を Cユーザ名に 一文字追加し
パスワードを Cパスワードに 入れ、 0を Cパスワードに 一文字追加し
Cdb名を Cdb名に 入れ、 0を Cdb名に 一文字追加し
(APIの呼び出し)
接続ハンドルをつみ ※引数1
Cホスト名をつみ ※引数2
Cユーザ名をつみ ※引数3
Cパスワードをつみ ※引数4
Cdb名をつみ ※引数5
0と $$NULLと 0と ※引数6~8
mysql_real_connectアドレスで ※←関数アドレス
アドレス指定でAPI呼出し8し
戻値に 入れ
戻値が ゼロ?
ならば 偽を 返し
終り
つぎに
真を 返すこと
。
MySQLをクローズとは (・ → ・)
接続ハンドルと
mysql_closeアドレスで
アドレス指定でAPI呼出し1
(戻値を) 捨て ※←戻値が不要の場合も放置しないこと
。
メインとは
「共有ライブラリをロードする」
MySQLの共有ライブラリをロードし 偽?
ならば ※ スタック=空 ※
「MySQLの共有ライブラリのロード失敗」で 重大エラー
終り
つぎに
「ロード成功」を 一行表示し
「MySQLの共有ライブラリをロードの後」で このメッセージでスタック検査し
「関数アドレス群を取得」を 一行表示し
mysql関数アドレス群を取得し
エラー?
ならば エラー文字列で 重大エラー
つぎに
「取得成功」を 一行表示し
「関数アドレス群を取得の後」で このメッセージでスタック検査し
MySQLを初期化し 偽? ※2017.04.23 ここから7行分抜けていたので追加
ならば ※ スタック=空 ※
「MySQLを初期化失敗」で 重大エラー
終り
つぎに
「MySQLを初期化成功」を 一行表示し
「MySQLを初期化の後」で このメッセージでスタック検査し
「MySQLに接続」を 一行表示し
MySQLに接続し 偽?
ならば ※ スタック=空 ※
「MySQLに接続失敗」で 重大エラー
終り
つぎに
「接続成功」を 一行表示し
「MySQLに接続の後」で このメッセージでスタック検査し
「MySQLをクローズ」を 一行表示し
MySQLをクローズし
「クローズ成功」を 一行表示し
「MySQLをクローズの後」で このメッセージでスタック検査し
「共有ライブラリを破棄する」を 一行表示し
MySQLの共有ライブラリを破棄し
「MySQLの共有ライブラリを破棄の後」で このメッセージでスタック検査し
。
先にも書きましたが、実際に動作確認したわけではないので、細かなミスがあるかも知れません。
Mindユーザーの @MindZanmai さんは下記のコードで接続できたようです。
ソースコード全文
mysql_closeは 数値 1。
mysql_initは 数値 2。
mysql_real_connectは 数値 3。
mysql_real_queryは 数値 4。
mysql_queryは 数値 5。
mysql_store_resultは 数値 6。
mysql_free_resultは 数値 7。
mysql_num_rowsは 数値 8。
mysql_num_fieldsは 数値 9。
mysql_errnoは 数値 10。
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アドレスで
アドレス指定でAPI呼出し1
接続ハンドルに 入れ
接続ハンドルが ゼロ?
ならば 偽を 返し
終り
つぎに
真を 返すこと。
MySQLに接続とは (・ → 真偽)
ホスト名は 文字列定数 「localhost」
ユーザ名は 文字列定数 「mind」
パスワードは 文字列定数 「*****」
db名は 文字列定数 「minddb」
Cホスト名は 文字列実体 長さ 80桁
Cユーザ名は 文字列実体 長さ 80桁
Cパスワードは 文字列実体 長さ 80桁
Cdb名は 文字列実体 長さ 80桁
戻値は 変数
(NULL終端文字列を作成)
ホスト名を Cホスト名に 入れ、 0を Cホスト名に 一文字追加し
ユーザ名を Cユーザ名に 入れ、 0を Cユーザ名に 一文字追加し
パスワードを Cパスワードに 入れ、 0を Cパスワードに 一文字追加し
db名を Cdb名に 入れ、 0を Cdb名に 一文字追加し
(APIの呼び出し)
接続ハンドルをつみ ※引数1
Cホスト名をつみ ※引数2
Cユーザ名をつみ ※引数3
Cパスワードをつみ ※引数4
Cdb名をつみ ※引数5
0と $$NULLと 0と ※引数6~8
mysqlアドレス(mysql_real_connect)で ※←関数アドレス
※mysql_real_connectアドレスで ※←関数アドレス
アドレス指定でAPI呼出し8し
戻値に 入れ
戻値が ゼロ?
ならば 偽を 返し
終り
つぎに
真を 返すこと
。
MySQLをクローズとは (・ → ・)
接続ハンドルと
mysqlアドレス(mysql_close)で
※mysql_closeアドレスで
アドレス指定でAPI呼出し1
(戻値を) 捨て ※←戻値が不要の場合も放置しないこと
。
メインとは
「共有ライブラリをロードする」を 一行表示し
MySQLの共有ライブラリをロードし 偽?
ならば
「ロード失敗」を 一行表示し
終り
つぎに
「ロード成功」を 一行表示し
「MySQLの共有ライブラリをロードの後」で このメッセージでスタック検査し
「関数アドレス群を取得」を 一行表示し
mysql関数アドレス群を取得し
「取得成功」を 一行表示し
「関数アドレス群を取得の後」で このメッセージでスタック検査し
「MySQLを初期化」を 一行表示し
MySQLを初期化し 偽?
ならば ※ スタック=空 ※
「MySQLの初期化失敗」で 重大エラー
終り
つぎに
「MySQL初期化成功」を 一行表示し
「MySQLを初期化の後」で このメッセージでスタック検査し
「MySQLに接続」を 一行表示し
MySQLに接続し 偽?
ならば ※ スタック=空 ※
「MySQLに接続失敗」で 重大エラー
終り
つぎに
「接続成功」を 一行表示し
「MySQLに接続の後」で このメッセージでスタック検査し
「MySQLをクローズ」を 一行表示し
MySQLをクローズし
「クローズ成功」を 一行表示し
「MySQLをクローズの後」で このメッセージでスタック検査し
「共有ライブラリを破棄する」を 一行表示し
MySQLの共有ライブラリを破棄する
「MySQLの共有ライブラリを破棄の後」で このメッセージでスタック検査し
。
おわりに
今回はここまでです。次回はMySQLへのクエリー処理について記述します。