デフォルトで、mysql_query()
と mysql_real_query()
はそれらのステートメント文字列引数を、実行すべき単一のステートメントとして解釈し、ユーザーはステートメントが結果セット (行のセット、SELECT
の場合) を生成するか、または影響を受ける行カウント (INSERT
、UPDATE
などの場合) を生成するかに従って、結果を処理します。
MySQL 5.6 はセミコロン (「;
」) 文字によって区切られた複数のステートメントを格納する文字列の実行もサポートします。この機能は、mysql_real_connect()
によってサーバーに接続するとき、または mysql_set_server_option()
の呼び出しによる接続後のいずれかに指定される特別なオプションによって有効化されます。
複数ステートメント文字列を実行すると、複数の結果セットまたは行カウントインジケータを生成できます。これらの結果の処理には、単一ステートメントの場合と異なるアプローチが必要です。最初のステートメントからの結果の処理後、それ以上の結果が存在するかどうかをチェックし、存在する場合は、それらを順番に処理する必要があります。複数結果の処理をサポートするため、C API には、mysql_more_results()
関数と mysql_next_result()
関数が含まれています。これらの関数は、それ以上の結果があるかぎり反復するループの最後で使用します。結果をこのように処理できないと、サーバーへの接続が切断される可能性があります。
複数結果の処理は、ストアドプロシージャーに対して CALL
ステートメントを実行する場合にも必要です。ストアドプロシージャーの結果にはこれらの特性があります。
-
プロシージャー内のステートメントは結果セットを生成することがあります (たとえば、それが
SELECT
ステートメントを実行する場合など)。これらの結果セットは、プロシージャーの実行とともに、それらが生成された順番で返されます。一般に、呼び出し元はプロシージャーが返す結果セットの数を知ることができません。プロシージャーの実行は、呼び出しごとに実行パスが異なるループや条件ステートメントによって異なることがあります。そのため、複数の結果を取得するように準備しておく必要があります。
プロシージャーからの最終結果は、結果セットを含まないステータス結果です。このステータスはプロシージャーが成功したか、エラーが発生したかを示します。
複数ステートメントおよび結果機能は、mysql_query()
または mysql_real_query()
と一緒にのみ使用できます。それらはプリペアドステートメントインタフェースと一緒に使用できません。プリペアドステートメントハンドルは単一のステートメントを含む文字列のみを操作するように定義されます。セクション23.7.8「C API プリペアドステートメント」を参照してください。
複数ステートメントの実行と結果の処理を有効にするには、次のオプションを使うことができます。
-
mysql_real_connect()
関数には 2 つのオプション値が関連するflags
引数があります。CLIENT_MULTI_RESULTS
により、クライアントプログラムは複数の結果を処理できます。結果セットを生成するストアドプロシージャーに対して、CALL
ステートメントを実行する場合、このオプションを有効にする必要があります。そうしないと、そのようなプロシージャーはエラー「エラー 1312 (0A000): PROCEDURE
を生成します。MySQL 5.6 では、proc_name
は指定されたコンテキストで結果セットを返すことができません」CLIENT_MULTI_RESULTS
はデフォルトで有効にされています。CLIENT_MULTI_STATEMENTS
により、mysql_query()
およびmysql_real_query()
はセミコロンで区切られた複数のステートメントを含むステートメント文字列を実行できます。このオプションにより、CLIENT_MULTI_RESULTS
も暗黙的に有効になるため、mysql_real_connect()
へのCLIENT_MULTI_STATEMENTS
のflags
引数は、CLIENT_MULTI_STATEMENTS | CLIENT_MULTI_RESULTS
の引数と同等になります。つまり、CLIENT_MULTI_STATEMENTS
は複数ステートメントの実行とすべての複数結果の処理を有効にするのに十分です。
サーバーへの接続が確立されたあと、
mysql_set_server_option()
関数を使用して、それをMYSQL_OPTION_MULTI_STATEMENTS_ON
またはMYSQL_OPTION_MULTI_STATEMENTS_OFF
の引数に渡すことによって、複数ステートメントの実行を有効または無効にできます。この関数によって複数ステートメントの実行を有効にすると、複数ステートメント文字列の「簡単な」結果の処理も有効になります。そこでは、各ステートメントが単一の結果を生成しますが、結果セットを生成するストアドプロシージャーの処理を許可するには十分でありません。
次の手順に、複数ステートメントの処理の推奨される戦略の概要を示します。
CLIENT_MULTI_STATEMENTS
をmysql_real_connect()
に渡して、複数ステートメントの実行と複数結果の処理を完全に有効にします。mysql_query()
またはmysql_real_query()
を呼び出し、それが成功したことを確認したあとに、ステートメント結果を処理するループに入ります。ループの反復ごとに、現在のステートメント結果を処理し、結果セットまたは影響を受けた行カウントを取得します。エラーが発生したら、ループを終了します。
ループの終わりに、
mysql_next_result()
を呼び出して、ほかの結果が存在するかどうかをチェックし、その場合は、取得を開始します。それ以上の結果がなくなったら、ループを終了します。
先述の戦略の 1 つの可能な実装を次に示します。ループの最終部分は、mysql_next_result()
がゼロ以外を返すかどうかの簡単なテストに単純化できます。示されているコードは、それ以上の結果がないこととエラーを区別し、それによって、後者の発生でメッセージを出力させることができます。
/* connect to server with the CLIENT_MULTI_STATEMENTS option */
if (mysql_real_connect (mysql, host_name, user_name, password,
db_name, port_num, socket_name, CLIENT_MULTI_STATEMENTS) == NULL)
{
printf("mysql_real_connect() failed\n");
mysql_close(mysql);
exit(1);
}
/* execute multiple statements */
status = mysql_query(mysql,
"DROP TABLE IF EXISTS test_table;\
CREATE TABLE test_table(id INT);\
INSERT INTO test_table VALUES(10);\
UPDATE test_table SET id=20 WHERE id=10;\
SELECT * FROM test_table;\
DROP TABLE test_table");
if (status)
{
printf("Could not execute statement(s)");
mysql_close(mysql);
exit(0);
}
/* process each statement result */
do {
/* did current statement return data? */
result = mysql_store_result(mysql);
if (result)
{
/* yes; process rows and free the result set */
process_result_set(mysql, result);
mysql_free_result(result);
}
else /* no result set or error */
{
if (mysql_field_count(mysql) == 0)
{
printf("%lld rows affected\n",
mysql_affected_rows(mysql));
}
else /* some error occurred */
{
printf("Could not retrieve result set\n");
break;
}
}
/* more results? -1 = no, >0 = error, 0 = yes (keep looping) */
if ((status = mysql_next_result(mysql)) > 0)
printf("Could not execute statement\n");
} while (status == 0);
mysql_close(mysql);