はじめに
だいぶ前2017年ごろMindユーザーの @MindZanmai さんのご質問に回答して、MindでLinux上のMySQLにクエリーする方法を詳しくコメントに解説しておりまして、最近SQLServerへのクエリ記事を書かれている @mylifewithviolin さんのおすすめもあって記事にまとめておくことにしました。内容は少し古くなっていますが、MindのDB接続関連の情報は少ないので参考になれば幸いです。
今回はクエリの発行を書いてみました。
参考情報
C記述の側は以下の方のWebページを参考にさせていただきました(前回記事の参考ページと違います)。
C言語でMySQLへ接続 - 日常メモ
http://d.hatena.ne.jp/graySpace/20141011/1413014403
上記のプログラム中で、クエリ発行に関する部分は以下になります。
//~略~
MYSQL *conn;
MYSQL_RES *res;
MYSQL_ROW row;
//~略~
// クエリ発行
if (mysql_query(conn, "show tables")) {
fprintf(stderr, "%s\n", mysql_error(conn));
exit(1);
}
res = mysql_use_result(conn);
// 結果表示
while ((row = mysql_fetch_row(res)) != NULL) {
printf("%s\n", row[0]);
}
mysql_free_result(res);
// 切断
mysql_close(conn);
クエリ発行
まず、Cの次の行。
if (mysql_query(conn, "show tables")) {
これは簡単でMindでは以下のように書けばいいはずです。
CSQL文は 文字列実体 長さ ・・
"show tables"を CSQL文に 入れ、 0を CSQL文に 一文字追加し
接続ハンドルをつみ ※←引数1
CSQL文をつみ ※←引数2
mysql_queryアドレスで ※←関数アドレス
アドレス指定でAPI呼出し2し
戻値に 入れ
戻値が ゼロ以外
ならば ・・エラー処理・・
終り
つぎに
次に、Cの次の部分です。
MYSQL_RES *res;
上記で「res」の定義は前回の解説でも書きましたが以下のように考えます。
Cの側が MYSQL_RES res のように「」を挟んでいます。このタイプは簡単で、アドレスを記憶する変数に過ぎないためMindでは以下のように書けばよいです。
結果セットは 変数
次に、Cの次の部分。
res = mysql_use_result(conn);
上記はMindでは以下のように書けばいいはずです。
接続ハンドルをつみ ※←引数1
mysql_use_resultアドレスで ※←関数アドレス
アドレス指定でAPI呼出し1し
結果セットに 入れ
結果セットが ゼロ?
ならば ・・エラー処理・・
終り
つぎに
次にCの次の部分です。
MYSQL_ROW row;
//~略~
上記で「row」の定義は以下のように考えます。
Cの側が MYSQL_ROW row は途中に「*」を挟んで【いない】ので要注意です。やっかいですが、データ型 MYSQL_ROW はどのような定義なのかを調べる必要があります。
以下のWebページに mysql.h の中身の解説がありました。
MySQL: include/mysql.h File Reference
https://dev.mysql.com/doc/dev/mysql-server/8.0.0/include_2mysql_8h.html
上記によると問題の MYSQL_ROW は以下のようなものらしいです。
typedef char ** MYSQL_ROW
Cの場合 char * が文字列を格納する変数となりますが、これにもう1つ * が付いているので、文字列変数の配列を示しています。結果として「row」は【文字列変数へのポインタを配列状にしたものへのポインタ】のようです。
配列の実体は確保する必要はないため、Mindの側では型紙を使います。以下のようになるかと思います。
行データ型は 型紙
C列データは 変数
全体は
100個の C列データ。
上記には文字列を表すデータ型が書いてありませんが、Cでは文字列といってもその先頭アドレスでしか管理されていないのでこのようになります。
次にCの次の部分です。
while ((row = mysql_fetch_row(res)) != NULL) {
上ではループ構文と結果判定を含めて一気に書かれていて見ずらいですが要点だけ書くと以下となります。
まずCの次の箇所。
row = mysql_fetch_row(res);
上を翻訳してMindでは以下のようにします。
結果セットをつみ ※←引数1
mysql_fetch_rowアドレスで ※←関数アドレス
アドレス指定でAPI呼出し1し
行データアドレスに 入れ
先のC記述をもう少し範囲を広げると以下となります。
// 結果表示
while ((row = mysql_fetch_row(res)) != NULL) {
printf("%s\n", row[0]);
}
Mindでは以下のようにすれば良いと思います。
ここから
結果セットをつみ ※←引数1
mysql_fetch_rowアドレスで ※←関数アドレス
アドレス指定でAPI呼出し1し
行データアドレスに 入れ
行データアドレスが ゼロ?
ならば 打ち切り
つぎに
行データアドレスの C列データ(1)を Mind文字列に変換し 一行表示し
※ ↑親構造の ↑型紙要素(Mindでは配列要素を1から数える) ※
繰り返し
上記で使っている「Mind文字列に変換」という処理単語は、C形式の文字列(NULL終端形式の文字列)をMindの文字列(アドレス+カウントのパック値)に変換するものです。Mind形式に変換してしまえば「表示」など普通の処理に渡せます。
最後に今回のMySQL関連記事の全体を通したMindのプログラムは以下のようになります。
(1) 関数アドレスを記憶する変数の追加
※↓今回追加分
mysql_queryアドレスは 変数。
mysql_use_resultアドレスは 変数。
mysql_free_resultアドレスは 変数。
mysql_fetch_rowアドレスは 変数。
(2) 「mysql関数アドレス群を取得」に上記分の取得を追加
mysql関数アドレス群を取得とは (・ → ・)
~略~
~略~
・・・今回追加の関数アドレスの取得処理追加・・・
・・・今回追加の関数アドレスの取得処理追加・・・
・・・今回追加の関数アドレスの取得処理追加・・・
・・・今回追加の関数アドレスの取得処理追加・・・
。
(3) SQL文の発行
行データ型は 型紙
C列データは 変数
全体は
100個の C列データ。
SQL文の発行テストとは (・ → ・)
CSQL文は 文字列実体 長さ 512 ※←この値は十分な長さを指定のこと
結果セットは 変数
結果セットは 変数
戻値は 変数
行データアドレスは 変数
エラークリアし
"show tables"を CSQL文に 入れ、 0を CSQL文に 一文字追加し
接続ハンドルをつみ ※←引数1
CSQL文をつみ ※←引数2
mysql_queryアドレスで ※←関数アドレス
アドレス指定でAPI呼出し2し
戻値に 入れ
戻値が ゼロ以外
ならば 「mysql_query()の発行でエラー」を エラー登録し
終り
つぎに
接続ハンドルをつみ ※←引数1
mysql_use_resultアドレスで ※←関数アドレス
アドレス指定でAPI呼出し1し
結果セットに 入れ
結果セットが ゼロ?
ならば 「mysql_use_result()の発行でエラー」を エラー登録し
終り
つぎに
ここから
結果セットをつみ ※←引数1
mysql_fetch_rowアドレスで ※←関数アドレス
アドレス指定でAPI呼出し1し
行データアドレスに 入れ
行データアドレスが ゼロ?
ならば 打ち切り
つぎに
行データアドレスの C列データ(1)を Mind文字列に変換し 一行表示し
※ ↑親構造の ↑型紙要素(Mindでは配列要素を1から数える) ※
繰り返し
結果セットをつみ ※←引数1
mysql_free_resultアドレスで ※←関数アドレス
アドレス指定でAPI呼出し1し
(結果を) 捨て
。
(4) メイン部分の追加
メインとは (・ → ・)
~略~
~略~
「MySQLに接続の後」で このメッセージでスタック検査し
「SQL文の発行テスト」を 一行表示し
SQL文の発行テストし
エラー?
ならば 「エラー:」を 表示し エラー文字列を 一行表示し
つぎに
「テスト終り」を 一行表示し
「SQL文の発行テストの後」で このメッセージでスタック検査し
「MySQLをクローズ」を 一行表示し
~略~
~略~
。
おわりに
3回にわけてMindからMySQLへ接続しクエリーを処理する方法について解説しました。思えばずいぶん長いコメントを書いたものです(^^;