MySQL 8.0 リファレンスマニュアル


MySQL 8.0 リファレンスマニュアル  /  ストアドオブジェクト  /  ストアドプログラムの制約

25.8 ストアドプログラムの制約

これらの制約は、第25章「ストアドオブジェクトで説明している機能に適用されます。

ここに記載されている制約の中には、すべてのストアドルーチン、つまりストアドプロシージャーとストアドファンクションの両方に適用されるものがあります。 また、ストアドプロシージャーには適用されず、ストアドファンクションに固有の制約もいくつか存在します。

ストアドファンクションの制約は、トリガーにも適用されます。 トリガーに固有の制約もいくつかあります。

ストアドプロシージャーの制約は、イベントスケジューラのイベント定義の DO 句にも適用されます。 イベントに固有の制約もいくつかあります。

ストアドルーチンでは許可されていない SQL ステートメント

ストアドルーチンには自由に SQL ステートメントを含めることはできません。 次のステートメントは許可されていません。

  • LOCK TABLES および UNLOCK TABLES のロックステートメント。

  • ALTER VIEW

  • LOAD DATA

  • SQL 準備済みステートメント (PREPAREEXECUTEDEALLOCATE PREPARE) は、ストアドプロシージャーで使用できますが、ストアドファンクションやトリガーでは使用できません。 そのため、ストアドファンクションとトリガーは動的 SQL (この場合はステートメントを文字列として構築してから実行します) を使用できません。

  • 通常、SQL 準備済みステートメントで許可されていないステートメントは、ストアドプログラムでも許可されません。 準備済みステートメントとしてサポートされているステートメントのリストについては、セクション13.5「プリペアドステートメント」を参照してください。 例外は SIGNALRESIGNAL、および GET DIAGNOSTICS であり、これらは準備済みステートメントとして許可されていませんが、ストアドプログラムで許可されます。

  • ローカル変数はストアドプログラムの実行中にのみスコープ内にあるので、これらの参照は、ストアドプログラム内で作成された準備済みステートメントでは許可されていません。 準備済みステートメントのスコープは現在のセッションであり、ストアドプログラムではないので、ステートメントはプログラムの終了後に実行でき、この時点で変数はスコープ内に存在しなくなります。 たとえば、SELECT ... INTO local_var は準備済みステートメントとして使用できません。 この制約は、ストアドプロシージャーおよびストアドファンクションのパラメータにも適用されます。 セクション13.5.1「PREPARE ステートメント」を参照してください。

  • すべてのストアドプログラム (ストアドプロシージャーとストアドファンクション、トリガー、およびイベント) 内で、パーサーは、BEGIN [WORK]BEGIN ... END ブロックの開始として扱います。 このコンテキストでトランザクションを開始するには、代わりに START TRANSACTION を使用します。

ストアドファンクションの制約

次の追加ステートメントまたは操作は、ストアドファンクション内で許可されていません。 これらはストアドプロシージャーで許可されていますが、ストアドファンクションまたはトリガー内から呼び出されるストアドプロシージャーを除きます。 たとえば、ストアドプロシージャーで FLUSH を使用する場合、ストアドファンクションまたはトリガーからそのストアドプロシージャーを呼び出すことはできません。

  • 明示的または暗黙的なコミットまたはロールバックを実行するステートメント。 これらのステートメントのサポートは、SQL 標準では必要ありません。SQL 標準では、各 DBMS ベンダーがこれらのステートメントを許可するかどうかを決められると定めています。

  • 結果セットを返すステートメント。 これには、INTO var_list 句を含まない SELECT ステートメントや、SHOWEXPLAIN、および CHECK TABLE などのほかのステートメントも含まれます。 関数は、SELECT ... INTO var_list を使用するか、カーソルと FETCH ステートメントを使用すると、結果セットを処理できます。 セクション13.2.10.1「SELECT ... INTO ステートメント」およびセクション13.6.6「カーソル」を参照してください。

  • FLUSH ステートメント。

  • ストアドファンクションは再帰的に使用できません。

  • ストアドファンクションまたはトリガーは、そのストアドファンクションまたはトリガーを呼び出したステートメントによって (読み取りまたは書き込みに) すでに使用されているテーブルを変更できません。

  • ストアドファンクションで、一時テーブルを異なるエイリアスで複数回参照する場合、ストアドファンクション内の別々のステートメントで参照を行う場合でも、「表を再オープンできません: 'tbl_name'」 というエラーが発生します。

  • ストアドファンクションを呼び出す HANDLER ... READ ステートメントは、レプリケーションエラーを引き起こす可能性があり、許可されません。

トリガーの制約

トリガーの場合、さらに次の制約が適用されます。

  • トリガーは外部キーアクションでアクティブ化されません。

  • 行ベースのレプリケーションを使用している場合、レプリカのトリガーは、ソースで発生したステートメントによってアクティブ化されません。 レプリカのトリガーは、ステートメントベースレプリケーションを使用している場合にアクティブになります。 詳細は、セクション17.5.1.36「レプリケーションとトリガー」を参照してください。

  • RETURN ステートメントはトリガーでは許可されていません。トリガーは値を返すことができません。 すぐにトリガーを終了するには、LEAVE ステートメントを使用します。

  • トリガーは、mysql データベース内のテーブルでは許可されていません。 INFORMATION_SCHEMA または performance_schema テーブルでも許可されていません。 これらのテーブルは実際にはビューであり、トリガーはビューでは許可されません。

  • トリガーキャッシュは、ベースとなるオブジェクトのメタデータが変更された場合は検出しません。 トリガーがテーブルを使用し、トリガーがキャッシュにロードされたあとにそのテーブルに変更があった場合、トリガーは古いメタデータを使用して動作します。

ストアドルーチン内の名前競合

ルーチンパラメータ、ローカル変数、およびテーブルカラムに同じ識別子が使用される場合があります。 また、同じローカル変数名を、ネスト化されたブロックで使用することもできます。 例:

CREATE PROCEDURE p (i INT)
BEGIN
  DECLARE i INT DEFAULT 0;
  SELECT i FROM t;
  BEGIN
    DECLARE i INT DEFAULT 1;
    SELECT i FROM t;
  END;
END;

このような場合、識別子はあいまいになり、次の優先順位ルールが適用されます。

  • ローカル変数では、ルーチンパラメータやテーブルカラムが優先されます。

  • ルーチンパラメータでは、テーブルカラムが優先されます。

  • 内部ブロック内のローカル変数では、外部ブロック内のローカル変数が優先されます。

変数でテーブルカラムが優先される動作は、非標準です。

レプリケーションに関する考慮事項

ストアドルーチンを使用すると、レプリケーションの問題が生じることがあります。 この問題については、セクション25.7「ストアドプログラムバイナリロギング」で詳しく述べられています。

--replicate-wild-do-table=db_name.tbl_name オプションはテーブル、ビュー、およびトリガーに適用されます。 ストアドプロシージャーと関数、またはイベントには適用されません。 後者のオブジェクトで作用するステートメントをフィルタするには、1 つまたは複数の --replicate-*-db オプションを使用します。

デバッグに関する考慮事項

ストアドルーチンのデバッグ機能は存在しません。

SQL:2003 標準のサポート外の構文

MySQL ストアドルーチン構文は SQL:2003 標準に基づきます。 この標準の次の項目は現在サポートされていません。

  • UNDO ハンドラ

  • FOR ループ

ストアドルーチンの同時実行性に関する考慮事項

セッション間のやり取りの問題を防止するために、クライアントのステートメント発行時、サーバーではステートメントの実行に利用できるルーチンとトリガーのスナップショットが使用されます。 つまり、サーバーは、ステートメントの実行中に使用される可能性のあるプロシージャー、関数、およびトリガーのリストを算出してロードし、ステートメントの実行に進みます。 ステートメントの実行時は、ほかのセッションが実行するルーチンへの変更は認識されません。

並列性を最大にするために、ストアドファンクションでは、その副作用を最小限に抑える必要があります。特に、ストアドファンクション内のテーブルを更新することにより、そのテーブルでの並列操作が減少することがあります。 ストアドファンクションは、実行前にテーブルロックを取得して、ステートメントが実行する順序とログに表示されるときの順序の不一致によるバイナリログの不整合を回避します。 ステートメントベースのバイナリロギングが使用される場合、関数内で実行されるステートメントではなく、関数を呼び出すステートメントが記録されます。 その結果、ベースとなる同じテーブルを更新するストアドファンクションは、並列で実行しません。 対照的に、ストアドプロシージャーはテーブルレベルのロックを取得しません。 ストアドプロシージャー内で実行されたすべてのステートメントは、ステートメントベースのバイナリロギングの場合でも、バイナリログに書き込まれます。 セクション25.7「ストアドプログラムバイナリロギング」を参照してください。

イベントスケジューラの制約

次の制限は、イベントスケジューラに固有のものです。

  • イベント名は大文字と小文字を区別せずに処理されます。 たとえば、anEventAnEvent という名前の 2 つのイベントを同じデータベース内に含めることはできません。

  • イベント名が変数によって指定されている場合、ストアドプログラム内からイベントを作成、変更、または削除することはできません。 イベントは、ストアドルーチンやトリガーを作成、変更、削除することもできません。

  • LOCK TABLES ステートメントの有効時は、イベントでの DDL ステートメントは禁止されています。

  • YEARQUARTERMONTH、および YEAR_MONTH の間隔を使用したイベントのタイミングは、月で解決されます。ほかの間隔を使用したタイミングは秒で解決されます。 同時に行われるようにスケジュール設定されたイベントは、指定の順序で実行できません。 さらに、丸め、スレッドアプリケーションの特性、およびイベントを作成しその実行を信号で伝えるためにゼロ以外の時間長が必要になるため、イベントが 1、2 秒ほど遅れる場合があります。 ただし、INFORMATION_SCHEMA.EVENTS テーブルの LAST_EXECUTED カラムに表示される時間は、常に実際のイベント実行時間の 1 秒以内に正確です。 (Bug #16522 も参照してください。)

  • イベントの本体に含まれるステートメントの各実行は、新しい接続で行われます。したがって、これらのステートメントは、SHOW STATUS によって表示される Com_selectCom_insert などのサーバーステートメント数に対する特定のユーザーセッションには影響しません。 ただし、このような数はグローバルスコープで更新されます。 (Bug #16422)

  • イベントは、Unix エポックの最後の時間以降をサポートしません。この時間は 2038 年の年頭あたりになります。 このような日付はイベントスケジューラで特に許可されません。 (Bug #16396)

  • CREATE EVENT および ALTER EVENT ステートメントの ON SCHEDULE 句でのストアドファンクション、ユーザー定義関数、およびテーブルの参照はサポートされていません。 このような種類の参照は許可されていません。 (詳細は Bug #22830 を参照してください。)

NDB Cluster 内のストアドルーチンとトリガー

ストアドプロシージャ、ストアドファンクション、トリガーおよびスケジュール済イベントはすべて、NDB ストレージエンジンを使用するテーブルでサポートされますが、これらはクラスタ SQL ノードとして機能する MySQL Servers 間で自動的に伝播されないことに注意する必要があります。 これは、ストアドルーチンおよびトリガー定義が、クラスタノード間でコピーされない InnoDB テーブルを使用して mysql システムデータベース内のテーブルに格納されるためです。

MySQL Cluster テーブルと対話するストアドルーチンまたはトリガーは、ストアドルーチンまたはトリガーを使用するクラスタに参加する各 MySQL Server で適切な CREATE PROCEDURECREATE FUNCTION、または CREATE TRIGGER ステートメントを実行して再作成する必要があります。 同様に、既存のストアドルーチンまたはトリガーに対する変更は、クラスタにアクセスする各 MySQL Server で適切な ALTER ステートメントまたは DROP ステートメントを使用して、すべてのクラスタ SQL ノードで明示的に実行する必要があります。

警告

NDB ストレージエンジンを使用するように mysql データベーステーブルを変換して、ここで説明した問題を回避しないでください。 mysql データベースでのシステムテーブルの変更はサポートされていません」では、望ましくない結果が生成される可能性があります。


関連キーワード:  ステートメント, トリガー, テーブル, 制約, ストアドファンクション, ストアドルーチン, 実行, イベント, 許可, ストアドプログラム