MySQL 8.0 は、サーバー側の準備済みステートメントをサポートしています。 このサポートは、効率的なクライアント/サーバーバイナリプロトコルを利用します。 パラメータ値のためのプレースホルダを含む準備済みステートメントの使用には、次の利点があります。
ステートメントを実行のたびに解析するためのオーバーヘッドが少なくなります。 通常、データベースアプリケーションは、クエリーや削除の場合の
WHERE
、更新の場合のSET
、挿入の場合のVALUES
などの句でリテラルまたは変数値しか変更されていない、ほぼ同一の大量のステートメントを処理します。SQL インジェクション攻撃からの保護。 パラメータ値には、エスケープされていない SQL 引用符および区切り文字を含めることができます。
次の各セクションでは、プリペアドステートメントの特性の概要について説明します:
アプリケーションプログラムでの準備済みステートメント
サーバー側のプリペアドステートメントは、MySQL C API client library for C プログラム、MySQL Connector/J for Java プログラム、MySQL Connector/NET for .NET テクノロジを使用するプログラムなど、クライアントプログラミングインタフェースを介して使用できます。 たとえば、C API は、その準備済みステートメント API を構成する一連の関数呼び出しを提供しています。 C API Prepared Statement Interfaceを参照してください。 他の言語インタフェースでは、PHP 5.0 以上で使用可能な「mysqli
拡張機能」などの C クライアントライブラリにリンクすることで、バイナリプロトコルを使用するプリペアドステートメントをサポートできます。
SQL スクリプトでの準備済みステートメント
準備済みステートメントへの代替 SQL インタフェースを使用できます。 このインタフェースは、準備済みステートメント API 経由でのバイナリプロトコルの使用ほど効率的ではありませんが、SQL レベルで直接使用できるためプログラミングが必要ありません。
使用できるプログラミングインタフェースが存在しない場合でも使用できます。
mysql クライアントプログラムなどの、サーバーに SQL ステートメントを送信して実行させることのできる任意のプログラムから使用できます。
これは、クライアントが古いバージョンのクライアントライブラリを使用している場合でも使用できます。
準備済みステートメントのための SQL 構文は、次のような状況で使用されるように考慮されています。
準備済みステートメントのコーディングの前に、それがアプリケーションでどのように動作するかをテストする場合。
サポートしているプログラミング API にアクセスできないときに準備済みステートメントを使用する場合。
準備済みステートメントに関するアプリケーションの問題を対話的にトラブルシューティングする場合。
バグレポートを提出できるように、準備済みステートメントに関する問題を再現するテストケースを作成する場合。
PREPARE、EXECUTE、および DEALLOCATE PREPARE ステートメント
準備済みステートメントのための SQL 構文は、次の 3 つの SQL ステートメントに基づいています。
PREPARE
は、ステートメントを実行のために準備します (セクション13.5.1「PREPARE ステートメント」を参照してください)。EXECUTE
は、準備済みステートメントを実行します (セクション13.5.2「EXECUTE ステートメント」を参照してください)。DEALLOCATE PREPARE
は、準備済みステートメントを解放します (セクション13.5.3「DEALLOCATE PREPARE ステートメント」を参照してください)。
次の例は、2 辺の長さが与えられた三角形の斜辺を計算するステートメントを準備するための 2 つの同等の方法を示しています。
最初の例は、文字列リテラルを使用してステートメントのテキストを指定することによって準備済みステートメントを作成する方法を示しています。
mysql> PREPARE stmt1 FROM 'SELECT SQRT(POW(?,2) + POW(?,2)) AS hypotenuse';
mysql> SET @a = 3;
mysql> SET @b = 4;
mysql> EXECUTE stmt1 USING @a, @b;
+------------+
| hypotenuse |
+------------+
| 5 |
+------------+
mysql> DEALLOCATE PREPARE stmt1;
2 番目の例も同様ですが、ステートメントのテキストをユーザー変数として指定します。
mysql> SET @s = 'SELECT SQRT(POW(?,2) + POW(?,2)) AS hypotenuse';
mysql> PREPARE stmt2 FROM @s;
mysql> SET @a = 6;
mysql> SET @b = 8;
mysql> EXECUTE stmt2 USING @a, @b;
+------------+
| hypotenuse |
+------------+
| 10 |
+------------+
mysql> DEALLOCATE PREPARE stmt2;
次の追加の例は、クエリーを実行する対象となるテーブルの名前をユーザー変数として格納することによって、実行時にそのテーブルを選択する方法を示しています。
mysql> USE test;
mysql> CREATE TABLE t1 (a INT NOT NULL);
mysql> INSERT INTO t1 VALUES (4), (8), (11), (32), (80);
mysql> SET @table = 't1';
mysql> SET @s = CONCAT('SELECT * FROM ', @table);
mysql> PREPARE stmt3 FROM @s;
mysql> EXECUTE stmt3;
+----+
| a |
+----+
| 4 |
| 8 |
| 11 |
| 32 |
| 80 |
+----+
mysql> DEALLOCATE PREPARE stmt3;
準備済みステートメントは、そのステートメントが作成されたセッションに固有です。 以前に作成された準備済みステートメントを解放せずにセッションを終了した場合、そのステートメントはサーバーによって自動的に解放されます。
準備済みステートメントはまた、セッションに対してグローバルでもあります。 ストアドルーチン内で準備済みステートメントを作成した場合、そのステートメントはストアドルーチンが終了しても解放されません。
同時に作成される準備済みステートメントが多くなりすぎないようにするには、max_prepared_stmt_count
システム変数を設定します。 準備済みステートメントの使用を回避するには、この値を 0 に設定します。
プリペアドステートメントで許可される SQL 構文
次の SQL ステートメントは、準備済みステートメントとして使用できます。
ALTER TABLE
ALTER USER
ANALYZE TABLE
CACHE INDEX
CALL
CHANGE MASTER
CHECKSUM {TABLE | TABLES}
COMMIT
{CREATE | DROP} INDEX
{CREATE | RENAME | DROP} DATABASE
{CREATE | DROP} TABLE
{CREATE | RENAME | DROP} USER
{CREATE | DROP} VIEW
DELETE
DO
FLUSH {TABLE | TABLES | TABLES WITH READ LOCK | HOSTS | PRIVILEGES
| LOGS | STATUS | MASTER | SLAVE | USER_RESOURCES}
GRANT
INSERT
INSTALL PLUGIN
KILL
LOAD INDEX INTO CACHE
OPTIMIZE TABLE
RENAME TABLE
REPAIR TABLE
REPLACE
RESET {MASTER | SLAVE}
REVOKE
SELECT
SET
SHOW BINLOG EVENTS
SHOW CREATE {PROCEDURE | FUNCTION | EVENT | TABLE | VIEW}
SHOW {MASTER | BINARY} LOGS
SHOW {MASTER | SLAVE} STATUS
SLAVE {START | STOP}
TRUNCATE TABLE
UNINSTALL PLUGIN
UPDATE
その他のステートメントはサポートされていません。
診断ステートメントを準備できないことを示す SQL 標準に準拠するために、MySQL では準備済のステートメントとして次のものはサポートされていません:
SHOW WARNINGS
,SHOW COUNT(*) WARNINGS
SHOW ERRORS
,SHOW COUNT(*) ERRORS
warning_count
またはerror_count
システム変数への参照を含むステートメント。
通常、SQL 準備済みステートメントで許可されていないステートメントは、ストアドプログラムでも許可されません。 例外については、セクション25.8「ストアドプログラムの制約」に示されています。
プリペアドステートメントによって参照されているテーブルやビューのメタデータの変更が検出され、それが次に実行されるときに、ステートメントが自動再準備されます。 詳細については、セクション8.10.3「プリペアドステートメントおよびストアドプログラムのキャッシュ」を参照してください。
準備済みステートメントを使用する場合は、LIMIT
句の引数にプレースホルダを使用できます。 セクション13.2.10「SELECT ステートメント」を参照してください。
PREPARE
および EXECUTE
とともに使用される準備済み CALL
ステートメントでは、OUT
および INOUT
パラメータに対するプレースホルダのサポートが MySQL 8.0 から使用できます。 例および以前のバージョンでの回避方法については、セクション13.2.1「CALL ステートメント」を参照してください。 IN
パラメータには、バージョンには関係なくプレースホルダを使用できます。
準備済みステートメントのための SQL 構文は、ネストされた方法では使用できません。 つまり、PREPARE
に渡されるステートメント自体を、PREPARE
、EXECUTE
、または DEALLOCATE PREPARE
ステートメントにすることはできません。
準備済みステートメントのための SQL 構文は、準備済みステートメント API 呼び出しの使用とは異なります。 たとえば、mysql_stmt_prepare()
C API 関数を使用して、PREPARE
、EXECUTE
、または DEALLOCATE PREPARE
ステートメントを準備することはできません。
準備済みステートメントのための SQL 構文はストアドプロシージャー内で使用できますが、ストアドファンクションまたはトリガー内では使用できません。 ただし、PREPARE
と EXECUTE
で準備および実行される動的なステートメントにはカーソルを使用できません。 カーソルのステートメントはカーソル作成時にチェックされるため、そのステートメントを動的にすることはできません。
準備済みステートメントのための SQL 構文は、マルチステートメント (つまり、;
文字で区切られた 1 つの文字列内の複数のステートメント) をサポートしていません。
CALL
SQL ステートメントを使用して、準備済みステートメントを含むストアドプロシージャーを実行する C プログラムを記述するには、CLIENT_MULTI_RESULTS
フラグが有効になっている必要があります。 これは、各 CALL
によって、プロシージャー内で実行されるステートメントによって返される可能性のある結果セットに加えて、呼び出しステータスを示すための結果が返されるためです。
CLIENT_MULTI_RESULTS
は、mysql_real_connect()
を呼び出すときに、CLIENT_MULTI_RESULTS
フラグ自体を渡すことによって明示的に、または CLIENT_MULTI_STATEMENTS
を渡すことによって暗黙的に有効にする (これによって CLIENT_MULTI_RESULTS
も有効になります) ことができます。 詳細は、セクション13.2.1「CALL ステートメント」を参照してください。