雑多なブログ

音楽や語学、プログラム関連の話題について書いています

MySQL: プリペアドステートメントのプレースホルダーの数は65535まで。

MySQLで大量にインサートするために、複数行を1つのINSERTで追加しようとしたら、次のエラーが発生してINSERTに失敗した。

SQLSTATE[HY000]: General error: 1390 Prepared statement contains too many placeholders ....

プリペアドステートメントを使って、1つのクエリーで使用可能なプレースホルダーの上限は、65535 のようだ。

ネットには、同様の上限にひっかかってエラーが発生している事象の報告は多々見受けられた。しかし、エビデンスに基づいた情報が見つからなかったので頑張って調べてみた。

そうすると、stackoverflowでMySQLのソースを提示している情報を見つけた。実際にMySQLのソースを見てみると、それっぽい感じがする・・・

sql_prepare.cc

static bool init_param_array(Prepared_statement *stmt) {
  LEX *lex = stmt->lex;
  if ((stmt->param_count = lex->param_list.elements)) {
    if (stmt->param_count > (uint)UINT_MAX16) {
      /* Error code to be defined in 5.0 */
      my_error(ER_PS_MANY_PARAM, MYF(0));
      return true;
    }

https://github.com/mysql/mysql-server/blob/8.0/sql/sql_prepare.cc

ここで、比較に使用している UINT_MAX16 の定義がどういった内容なのか、不明なのでこちらの定義も、同じgithubリポジトリ内のソースを検索してみる。

そうすると、下記の定義が見つかった。

include/my_inttypes.h
#define UINT_MAX24 0x00FFFFFF
#define INT_MIN16 (~0x7FFF)
#define INT_MAX16 0x7FFF
#define UINT_MAX16 0xFFFF
#define INT_MIN8 (~0x7F)

0xFFFF65535 である。

これで今後は自信を持って、プレースホルダーを使う事ができる。
しかし、65535個もプレースホルダーを同時に使う機会はそうそうないような気もする・・・・

ちなみに、エラーメッセージの定義を確認してみた。 エラーメッセージは、sql_prepare.cc の my_error(ER_PS_MANY_PARAM, MYF(0)); で行っているが、ここで指定されている定数?に対応するエラーメッセージは、messages_to_clients.txt で定義されていた。

ER_PS_MANY_PARAM
        eng "Prepared statement contains too many placeholders"
        ger "Vorbereitete Anweisung enthält zu viele Platzhalter"

https://github.com/mysql/mysql-server/blob/8.0/share/messages_to_clients.txt

それにしても、公式のドキュメントにすら情報がないのはしんどい。