Go to the first, previous, next, last section, table of contents.

# 9 Extending MySQL

## 9.1 MySQL への新しい関数の追加

There are two ways to add new functions to MySQL:

- ユーザ定義関数(UDF:user-definable function)インタフェースを通して関数を追 加できます。 ユーザ定義関数は、`CREATE FUNCTION` と `DROP FUNCTION` ステー トメントを使用して、動的に追加、削除されます。 「9.1.1 `CREATE FUNCTION/DROP FUNCTION` Syntax」節参照.
- ネイティブ(ビルトイン) MySQL 関数として関数を追加できます。 ネイティブ関数は `mysqld` サーバに統合され、恒久的に有効になります。

それぞれの方法には、有利な点と不利な点があります:

- ユーザ定義関数を書く場合、サーバ自身に追加するオブジェクトファイルをイン ストールする必要があります。関数をサーバに統合する場合あそれを行なう必要 はありません。
- UDF をバイナリ MySQL 配布に追加することができます。ネイティブ関 数はソース配布の変更が必要です。
- MySQL 配布をアップグレードする場合、前にインストールされた UDF の使用を継続できます。ネイティブ関数では、アップグレードの度に変更を繰り 返す必要があります。

新しい関数を追加するためにどちらの方法を使用しても、`ABS()` や `SOUNDEX()` のようなネイティブ関数と同じように使用することができま す。

### 9.1.1 `CREATE FUNCTION/DROP FUNCTION` Syntax

    CREATE [AGGREGATE] FUNCTION function_name RETURNS {STRING|REAL|INTEGER}
           SONAME shared_library_name

    DROP FUNCTION function_name

A user-definable function (UDF) is a way to extend MySQL with a new function that works like native (built in) MySQL functions such as `ABS()` and `CONCAT()`.

`AGGREGATE` is a new option for MySQL Version 3.23. An `AGGREGATE` function works exactly like a native MySQL `GROUP` function like `SUM` or `COUNT()`.

`CREATE FUNCTION` saves the function's name, type, and shared library name in the `mysql.func` system table. You must have the insert and delete privileges for the `mysql` database to create and drop functions.

All active functions are reloaded each time the server starts, unless you start `mysqld` with the `--skip-grant-tables` option. In this case, UDF initialization is skipped and UDFs are unavailable. (An active function is one that has been loaded with `CREATE FUNCTION` and not removed with `DROP FUNCTION`.)

For instructions on writing user-definable functions, see 「9.1 MySQL への新しい関数の追加」節. For the UDF mechanism to work, functions must be written in C or C++, your operating system must support dynamic loading and you must have compiled `mysqld` dynamically (not statically).

### 9.1.2 新しいユーザ定義関数の追加

UDF 機構が動作するためには、関数は C か C++ で書かれる必要があり、OS が 動的ローディングをサポートする必要があります。MySQL ソース配布 は ``sql/udf_example.cc'` を含んでいて、これは５つの新しい関数を定義 しています。UDF の呼び出し方法がどのように働くかはこのファイルを参考にし てください。

For `mysqld` to be able to use UDF functions, you should configure MySQL with `--with-mysqld-ldflags=-rdynamic` The reason is that to on many platforms (including Linux) you can load a dynamic library (with `dlopen()`) from a static linked program, which you would get if you are using `--with-mysqld-ldflags=-all-static` If you want to use an UDF that needs to access symbols from `mysqld` (like the `methaphone` example in ``sql/udf_example.cc'` that uses `default_charset_info`), you must link the program with `-rdynamic`. (see `man dlopen`).

SQL ステートメントで使用したいそれぞれの関数について、対応する C (または C++) 関数を定義すべきです。下の説明では、名前 ``xxx'' がサンプル関数名と して使用されています。SQL と C/C++ 使用法を distinquish するために、 `XXX()` (大文字) は SQL 関数呼び出しを表わし、`xxx()` (小文字) は C/C++ 関数呼び出しを表わします。

`XXX()` のインタフェースを実装するために書く C/C++ 関数は:

`xxx()` (必要)
  メイン関数。これは関数結果が計算されるところです。SQL 型と C/C++ 関数の 戻り値型の対応は次に示します:

  SQL type | C/C++ type
  `STRING` | `char *`
  `INTEGER` | `long long`
  `REAL` | `double`

`xxx_init()` (オプション)
  `xxx()` の初期化関数。これは次のように使用されます:
  - `XXX()` の引数の数のチェック
  - 引数が要求される型かどうかのチェック、また、メイン関数が呼ばれる時に望む 型に引数を強制するように MySQL に伝える
  - メイン関数が必要とするメモリの割り当て
  - 結果の最大長の指定
  - (`REAL` 関数では) 小数部の最大桁数の指定
  - 結果が `NULL` になり得るかどうかの指定
`xxx_deinit()` (オプション)
  `xxx()` の終了関数(deinitialization function)。これは初期化関数によっ て割り当てられたメモリを解放すべきです。

SQL ステートメントが `XXX()` を呼び出すとき、MySQL は引数 チェックやメモリ割り当てのように、必要なセットアップを行なわせるために、 初期化関数 `xxx_init()` を呼び出します。`xxx_init()` がエラー を返す場合、SQL ステートメントはエラーメッセージと共に異常終了し、メイン 関数と終了関数は呼び出されません。そうでなければ、メイン関数 `xxx()` が各行毎に呼び出されます。全ての行が処理された後、終了関数 `xxx_deinit()` が、必要な掃除を行なうために、呼び出されます。

全ての関数はスレッド安全でなくてはいけません(メイン関数だけでなく、初期 化関数と終了関数も同様です)。これは変更されうるグローバル変数や静的変数 を割り当てることは許されないことを意味します！ メモリが必要な場合は、 `xxx_init()` で割り当て、`xxx_deinit()` でそれを解放すべきです。

#### 9.1.2.1 UDF Calling Sequences

メイン関数は下に示すように宣言されるべきです。戻り値型と引数は、 `CREATE FUNCTION` ステートメントで、SQL 関数 `XXX()` の戻り値 を`STRING`, `INTEGER`, `REAL` のどれに宣言するかに依存し て異なることに注意してください:

`STRING` 関数では:

    char *xxx(UDF_INIT *initid, UDF_ARGS *args,
                  char *result, unsigned long *length,
                  char *is_null, char *error);

`INTEGER` 関数では:

    long long xxx(UDF_INIT *initid, UDF_ARGS *args,
                  char *is_null, char *error);

`REAL` 関数では:

    double xxx(UDF_INIT *initid, UDF_ARGS *args,
                  char *is_null, char *error);

初期化と終了関数は次のように宣言します

    my_bool xxx_init(UDF_INIT *initid, UDF_ARGS *args, char *message);

    void xxx_deinit(UDF_INIT *initid);

`initid` 引数は３つの関数全てに渡されます。これは `UDF_INIT` 構造体を示し、関数間で情報を伝達するために使用されます。`UDF_INIT` 構造体のメンバは下に一覧します。初期化関数は変更したい全てのメンバを埋め るべきです。(メンバにデフォルトを使用するには、未変更のままにしてくださ い。)

`my_bool maybe_null`
  `xxx()` が `NULL` を返す場合、`xxx_init()` は `maybe_null` を `1` に設定すべきです。デフォルト値は、引数のい ずれかが `maybe_null` として宣言された場合、`1` です。
`unsigned int decimals`
  小数部の桁数。デフォルト値はメイン関数に渡される引数の小数部の最大桁数で す。(例えば、関数に `1.34`, `1.345`, `1.3` が渡された場合、 デフォルトは 3 です。`1.345` が 3 桁の小数部を持つためです。)
`unsigned int max_length`
  文字列結果の最大長。デフォルト値は関数の戻り値型に依存して異なります。文 字列関数では、デフォルトは最も長い引数の長さです。整数関数では、デフォル トは 21 桁です。実数関数では、デフォルトは 13 に `initid->decimals` で示される小数部の桁数を加えたものです。(数値関数では、長さは符号と小数 点文字を含みます。)
`char *ptr`
  それ自身の目的のために関数が使用できるポインタです。例えば、関数は割り当 てたメモリを関数間で伝達するために、`initid->ptr` を使用できます。 `xxx_init()` では、メモリを獲得し、このポインタに割り当てます:

      initid->ptr = allocated_memory;

  `xxx()` と `xxx_deinit()` では、`initid->ptr` を参照して、 メモリを使用または解放します。

#### 9.1.2.2 引数処理

`args` 引数は次に示すメンバを持つ `UDF_ARGS` 構造体へのポイン タです:

`unsigned int arg_count`
  引数の数。関数が特定の引数の数で呼び出されることを期待する場合は、初期化 関数でこの値をチェックしてください。例えば:

      if (args->arg_count != 2)
      {
          strcpy(message,"XXX() requires two arguments");
          return 1;
      }

`enum Item_result *arg_type`
  引数の型。可能な型の値は `STRING_RESULT`, `INT_RESULT`, `REAL_RESULT` です。 引数が与えられた型であることと、そうでない場合エラーを返すことを確実にす るために、初期化関数で `arg_type` 配列をチェックしてください。例えば:

      if (args->arg_type[0] != STRING_RESULT ||
          args->arg_type[1] != INT_RESULT)
      {
          strcpy(message,"XXX() requires a string and an integer");
          return 1;
      }

  関数の引数が特定の型を要求するための代案として、初期化関数を使用して、 `arg_type` 要素を求める型に設定できます。これは MySQL に `xxx()` の各呼び出しにこれらの型を引数に強制するようにさせます。例 えば、最初の２つの引数に文字列と整数を強制するように指定するには、 `xxx_init()` で次を行なってください:

      args->arg_type[0] = STRING_RESULT;
      args->arg_type[1] = INT_RESULT;

`char **args`
  `args->args` は、関数が呼ばれる時の引数の一般的な特性について、情報 を初期化関数に伝達します。定数引数 `i` について、 `args->args[i]` は引数値のをポイントします。(値への正しいアクセス方 法については後述。)非定数引数について、`args->args[i]` は `0` です。定数引数は定数だけを使用する表現で、`3`, `4*7-2`, `SIN(3.14)` などです。非定数引数は行から行に変更される値を参照する 表現で、項目名や非定数引数で呼び出される関数などです。 メイン関数のそれぞれの呼び出しについて、`args->args` は現在処理され ている行に渡される実際の引数を含んでいます。 関数は次のように引数 `i` を参照できます:
  - `STRING_RESULT` 型の引数は、バイナリデータまたは任意の長さのデータ の処理を許すため、文字列ポインタ＋長さとして与えられます。文字列内容は `args->args[i]` として有効で、文字列長は `args->lengths[i]` で す。文字列は NULL 終端とみなすべきではありません。
  - `INT_RESULT` 型の引数について、`args->args[i]` を `long long` 値にキャストする必要があります:

        long long int_val;
        int_val = *((long long*) args->args[i]);

  - For an argument of type `REAL_RESULT`, you must cast `args->args[i]` to a `double` value:

        double    real_val;
        real_val = *((double*) args->args[i]);

`unsigned long *lengths`
  初期化関数では、`lengths` 配列は各引数についての最大文字列長を示し ます。メイン関数の各呼び出しについては、`lengths` は、現在処理され ている行に渡される任意の文字列引数の実際の長さを含んでいます。 `INT_RESULT`, `REAL_RESULT` 型の引数については、`lengths` はまだ引数の最大長を含んでいます(初期化関数については)。

#### 9.1.2.3 戻り値とエラー処理

初期化関数は、エラーが無い場合は `0` を、そうでなければ `1` を 返すべきです。エラーが発生する場合は、`xxx_init()` は NULL 終端エラー メッセージを `message` パラメータに格納すべきです。このメッセージは クライアントに返されます。メッセージバッファは `MYSQL_ERRMSG_SIZE` 文字長ですが、80 文字より小さく保つように試みるべきです。標準的な端末画 面の幅にフィットするようにです。

メイン関数 `xxx()` の返す値は `long long` と `double` 関 数については関数値です。文字列関数については、`result` と `length` 引数で文字列が返されます。`result` は少なくとも 255 バイト長のバッファです。これらに内容と戻り値の長さを設定してください。例 えば:

    memcpy(result, "result string", 13);
    *length = 13;

あなたの文字列関数が 255 バイトよりも長い文字列を返す必要がある場合、 `xxx_init()` 関数または `xxx()` 関数内で `malloc()` で領域 を割り当て、`xxx_deinit()` 関数でそれを解放する必要があります。将来の `xxx()` 呼び出しによって再利用されるように、割り当てたメモリを `UDF_INIT` 構造体の `ptr` スロットに格納できます。 「9.1.2.1 UDF Calling Sequences」節参照.

メイン関数で `NULL` 値の戻り値を示すには、`is_null` を `1` に設定してください:

    *is_null = 1;

To indicate an error return in the main function, set the `error` parameter to `1`:

    *error = 1;

`xxx()` が任意の行について `*error` に `1` を設定する場合、 関数値は現在の行についてと、その後の `XXX()` が呼び出されるステート メントによって処理される任意の行について `NULL` です。(`xxx()` は続く行については呼び出しさえされません。) 注意: 3.22.10 より 前の MySQL バージョンでは、`*error` と `*is_null` の 両方に設定すべきです:

    *error = 1;
    *is_null = 1;

#### 9.1.2.4 ユーザ定義関数のコンパイルとインストール

UDF を実装するファイルはサーバが動作するホスト上でコンパイルされインストー ルされないければなりません。この処理はサンプル UDF ファイル ``udf_example.cc'` について次に説明します。これは MySQL ソー ス配布に含まれています。このファイルは次の関数を含みます:

- `metaphon()` は文字列引数の metaphon 文字列を返します。これは時には soundex 文字列ですが、さらに英語用に調整されています。
- `myfunc_double()` は引数の文字の ASCII 値の合計を引数の長さの合計で 割った値を返します。
- `myfunc_int()` は引数の長さの合計を返します。
- `sequence([const int])` returns an sequence starting from the given number or 1 if no number has been given.
- `lookup()` はホスト名の IP 番号を返します。
- `reverse_lookup()` は IP 番号のホスト名を返します。この関数は文字列 `"xxx.xxx.xxx.xxx"` または４つの数値とともに呼ばれます。

動的ロード可能ファイルは、次のような何らかのコマンドを使用して、共有オブ ジェクトファイルとしてコンパイルされるべきです:

    shell> gcc -shared -o udf_example.so myfunc.cc

MySQL ソースツリーの ``sql'` ディレクトリ内で次のコマンドを 実行することにより、システムのコンパイラオプションを簡単に正しく見つけ出 すことができます:

    shell> make udf_example.o

`make` が表示するものに似たコンパイルコマンドを実行すべきですが、行 末近くの `-c` オプションを取り除いて、`-o udf_example.so` を行 末につけてください。(いくつかのシステムでは、コマンドに `-c` を残す 必要があります。)

UDF を含む共有オブジェクトをコンパイルすると、それをインストールしてその ことを MySQL に知らせる必要があります。``udf_example.cc'` か らの共有オブジェクトのコンパイルは、``udf_example.so'` のような何かの ファイル名を提供します(実際の名前はプラットフォームによって変わります)。 このファイルを ``/usr/lib'` のような `ld` が探すどこかのディレク トリにコピーしてください。多くのシステムでは、`LD_LIBRARY` または `LD_LIBRARY_PATH` 環境変数を設定して、UDF 関数ファイルがあるディレ クトリを示すことができます。`dlopen` マニュアルページはシステム上で 使用すべき変数を教えてくれます。これを `mysql.server` または `safe_mysqld` に設定し、`mysqld` を再起動すべきです。

ライブラリがインストールされた後、`mysqld` に新しい関数について次の コマンドで通知すべきです:

    mysql> CREATE FUNCTION metaphon RETURNS STRING SONAME "udf_example.so";
    mysql> CREATE FUNCTION myfunc_double RETURNS REAL SONAME "udf_example.so";
    mysql> CREATE FUNCTION myfunc_int RETURNS INTEGER SONAME "udf_example.so";
    mysql> CREATE FUNCTION lookup RETURNS STRING SONAME "udf_example.so";
    mysql> CREATE FUNCTION reverse_lookup RETURNS STRING SONAME "udf_example.so";

関数は `DROP FUNCTION` を使用して削除できます:

    mysql> DROP FUNCTION metaphon;
    mysql> DROP FUNCTION myfunc_double;
    mysql> DROP FUNCTION myfunc_int;
    mysql> DROP FUNCTION lookup;
    mysql> DROP FUNCTION reverse_lookup;

`CREATE FUNCTION` と `DROP FUNCTION` ステートメントは `mysql` データベース内のシステムテーブル `func` を更新します。 関数の名前、型、共有ライブラリ名はテーブルに保存されます。作成と破棄機能 のためには、`mysql` データベースに insert と delete 権限を持つ必要があります。

既に生成してある関数を追加するために `CREATE FUNCTION` を使用すべき ではありません。関数の再インストールが必要な場合は、`DROP FUNCTION` でそれを削除し、それから `CREATE FUNCTION` で再インストールすべきで す。例えば、関数の新しいバージョンの再コンパイルをした場合、 `mysqld` が新しいバージョンを得るために、これを行なう必要があるでしょ う。そうでなければ、サーバは古いバージョンの使用を継続します。

`mysqld` を `--skip-grant-tables` オプションで起動しなくても、 有効な関数はサーバの開始毎に再読み込みされます。この場合、UDF 初期化は飛 ばされ、UDF が無効になります。(有効な関数は `CREATE FUNCTION` でロー ドされているもので、`DROP FUNCTION` で削除されていないものです。)

### 9.1.3 新しいネイティブ関数の追加

ネイティブ関数を追加するためのプロシジャを以下に示します。バイナリ配布に はネイティブ関数を追加できないことに注意してください。プロシジャは MySQL ソースコードの変更を必要とするためです。MySQL を ソース配布から自分でコンパイルする必要があります。また、MySQL の他のバージョンに移行する場合(例えば、新しいバージョンがリリースされた 時)、新しいバージョンでこのプロシジャを繰り返す必要があります。

新しいネイティブ MySQL 関数を追加するためには、次のステップに従っ てください:

1. `sql_functions[]` 配列内で関数名を定義している ``lex.h'` に１行 追加してください。
2. If the function prototype is simple (just takes zero, one, two or three arguments), you should in lex.h specify SYM(FUNC_ARG#) (where # is the number of arguments) as the second argument in the `sql_functions[]` array and add a function that creates a function object in ``item_create.cc'`. Take a look at `"ABS"` and `create_funcs_abs()` for an example of this. If the function prototype is complicated (for example takes a variable number of arguments), you should add two lines to ``sql_yacc.yy'`. 一つは、`yacc` が定義す べきプリプロセッサシンボルを指示します(これはファイルの先頭に追加すべき です)。それから関数パラメータを定義し、これらのパラメータとともに ``item'' を `simple_expr` パース規則に追加します。例えば、これがど のように動作するかを見るには、``sql_yacc.yy'` 内の `ATAN` の 全ての出来事をチェックしてください。
3. ``item_func.h'` 内で、関数が数値または文字列のどちらを返すかに依存し て、`Item_num_func` または `Item_str_func` から継承するクラス を宣言してください。
4. ``item_func.cc'` 内で、数値または文字列のどちらの関数を定義するかに依 存して、次の宣言の一つを追加してください:

       double   Item_func_newname::val()
       longlong Item_func_newname::val_int()
       String  *Item_func_newname::Str(String *str)

   If you inherit your object from any of the standard items (like `Item_num_func` you probably only have to define one of the above functions and let the parent object take care of the other functions. For example, the `Item_str_func` class defines a `val()` function that executes `atof()` on the value returned by `::str()`.
5. おそらく次のオブジェクト関数も定義すべきです

       void Item_func_newname::fix_length_and_dec()

   この関数は与えられた引数に基づいて少なくとも `max_length` を計算す べきです。`max_length` は関数が返し得る文字の最大数です。この関数は、 メイン関数が `NULL` 値を返すことがない場合は、`maybe_null = 0` も設定すべきです。関数は、引数の `maybe_null` 変数をチェックするこ とで、関数の任意の引数が `NULL` を返しうるかどうかをチェックできま す。 You can take a look at `Item_func_mod::fix_length_and_dec` for a typical example of how to do this.

全ての関数はスレッド安全である必要があります (In other words, don't use any global or static variables in the functions without protecting them with mutexes).

If you want to return `NULL`, from `::val()`, `::val_int()` or `::str()` you should set `null_value` to 1 and return 0.

`::str()` オブジェクト関数については、次のいくつかの追加検討事項があ ります:

- `String *str` 引数は、結果を保持するために使用される文字列バッファ を提供します。 (For more information about the `String` type, take a look at the ``sql_string.h'` file.)
- The `::str()` function should return the string that holds the result or `(char*) 0` if the result is `NULL`.
- 全ての現在の文字列関数は、絶対に必要でない限り、メモリ割り当てを避けるよ うに試みてください！

## 9.2 MySQLにプロシージャを追加する

MySQL ではC++で書かれたプロシージャを定義することが できます。 これらのプロシージャを使うとデータが クライアントに送信される前にクエリー内でデータにアクセス、 修正することが可能です。 データの修正は列単位、あるいは グループ単位(`GROUP BY`)で行えます。

プロシージャを使って何ができるかをご覧いただくために、 MySQL バージョン3.23を使ったサンプルを用意しました。

さらに Contrib ディレクトリにある 'mylua' を参考にされることをお薦めします。 「D Contributed Programs」節参照。 myluaではLUA言語を使って、 ランタイム時にプロシージャを `mysqld` にロードすることができます。

### 9.2.1 プロシージャ分析

`analyse([max elements,[max memory]])`

このプロシージャは ``sql/sql_analyse.cc'` によって定義されています。 クエリーの結果を調べ、 分析結果を返します：

- `max elements` (デフォルト値は256)とは、 一つの行において `analyse` プロシージャが認識する値の数(重複するものは除く)の 最大値です。 最大エレメント数は `analyse` プロシージャがその行に 最適なデータ型が `ENUM` 型であるかどうかを判別するために使 われます。
- `max memory`(デフォルト値は8192)とは、 `analyse` プロシージャが 1つの行に含まれる重複しない全ての値を探し出す際に、 1つの行に 割り当てるメモリーの最大サイズです。

    SELECT ... FROM ... WHERE ... PROCEDURE ANALYSE([max elements,[max memory]])

### 9.2.2 プロシージャの記述

今のところ、 この項目にはソースコードしかありません。

プロシージャに関する全ての情報は以下のファイルにありますのでご覧下さい：

- ``sql/sql_analyse.cc'`
- ``sql/procedure.h'`
- ``sql/procedure.cc'`
- ``sql/sql_select.cc'`

## 9.3 MySQL Internals

This chapter describes a lot of things that you need to know when working on the MySQL code. If you plan to contribute to MySQL development, want to have access to the bleeding-edge in-between versions code, or just want to keep track of development, follow the instructions in 「2.3.4 開発ソースツリーからのインストール」節参照. If you are interested in MySQL internals, you should also subscribe to internals@lists.mysql.com. This is a relatively low traffic list, in comparison with mysql@lists.mysql.com.

### 9.3.1 MySQL Threads

The MySQL server creates the following threads:

- The TCP/IP connection thread handles all connection requests and creates a new dedicated thread to handle the authentication and and SQL query processing for each connection.
- On Windows NT there is a named pipe handler thread that does the same work as the TCP/IP connection thread on named pipe connect requests.
- The signal thread handles all signals. This thread also normally handles alarms and calls `process_alarm()` to force timeouts on connections that have been idle too long.
- If `mysqld` is compiled with `-DUSE_ALARM_THREAD`, a dedicated thread that handles alarms is created. This is only used on some systems where there are problems with `sigwait()` or if one wants to use the `thr_alarm()` code in ones application without a dedicated signal handling thread.
- If one uses the `--flush_time=#` option, a dedicated thread is created to flush all tables at the given interval.
- Every connection has its own thread.
- Every different table on which one uses `INSERT DELAYED` gets its own thread.
- If you use `--master-host`, a slave replication thread will be started to read and apply updates from the master.

`mysqladmin processlist` only shows the connection, `INSERT DELAYED`, and replication threads.

### 9.3.2 MySQL Test Suite

Until recently, our main full-coverage test suite was based on proprietary customer data and for that reason has not been publicly available. The only publicly available part of our testing process consisted of the `crash-me` test, a Perl DBI/DBD benchmark found in the `sql-bench` directory, and miscellaneous tests located in `tests` directory. The lack of a standardized publicly available test suite has made it difficult for our users, as well developers, to do regression tests on the MySQL code. To address this problem, we have created a new test system that is included in the source and binary distributions starting in Version 3.23.29.

The current set of test cases doesn't test everything in MySQL, but it should catch most obvious bugs in the SQL processing code, OS/library issues, and is quite thorough in testing replication. Our eventual goal is to have the tests cover 100% of the code. We welcome contributions to our test suite. You may especially want to contribute tests that examine the functionality critical to your system, as this will ensure that all future MySQL releases will work well with your applications.

#### 9.3.2.1 Running the MySQL Test Suite

The test system consist of a test language interpreter (`mysqltest`), a shell script to run all tests(`mysql-test-run`), the actual test cases written in a special test language, and their expected results. To run the test suite on your system after a build, type `make test` or `mysql-test/mysql-test-run` from the source root. If you have installed a binary distribution, `cd` to the install root (eg. `/usr/local/mysql`), and do `scripts/mysql-test-run`. All tests should succeed. If not, you should try to find out why and report the problem if this is a bug in MySQL. 「9.3.2.3 Reporting Bugs in the MySQL Test Suite」節参照.

If you have a copy of `mysqld` running on the machine where you want to run the test suite you do not have to stop it, as long as it is not using ports `9306` and `9307`. If one of those ports is taken, you should edit `mysql-test-run` and change the values of the master and/or slave port to one that is available.

You can run one individual test case with `mysql-test/mysql-test-run test_name`.

If one test fails, you should test running `mysql-test-run` with the `--force` option to check if any other tests fails.

#### 9.3.2.2 Extending the MySQL Test Suite

You can use the `mysqltest` language to write your own test cases. Unfortunately, we have not yet written full documentation for it - we plan to do this shortly. You can, however, look at our current test cases and use them as an example. The following points should help you get started:

- The tests are located in `mysql-test/t/*.test`
- A test case consists of `;` terminated statements and is similar to the input of `mysql` command line client. A statement by default is a query to be sent to MySQL server, unless it is recognized as internal command ( eg. `sleep` ).
- All queries that produce results, e.g. `SELECT`, `SHOW`, `EXPLAIN`, etc., must be preceded with `@/path/to/result/file`. The file must contain the expected results. An easy way to generate the result file is to run `mysqltest -r < t/test-case-name.test` from `mysql-test` directory, and then edit the generated result files, if needed, to adjust them to the expected output. In that case, be very careful about not adding or deleting any invisible characters - make sure to only change the text and/or delete lines. If you have to insert a line, make sure the fields are separated with a hard tab, and there is a hard tab at the end. You may want to use `od -c` to make sure your text editor has not messed anything up during edit. We, of course, hope that you will never have to edit the output of `mysqltest -r` as you only have to do it when you find a bug.
- To be consistent with our setup, you should put your result files in `mysql-test/r` directory and name them `test_name.result`. If the test produces more than one result, you should use `test_name.a.result`, `test_name.b.result`, etc.
- If a statement returns an error, you should on the line before the statement specify with the `--error error-number`. The error number can be a list of possible error numbers separated with `','`.
- If you are writing a replication test case, you should on the first line of the test file, put `source include/master-slave.inc;`. To switch between master and slave, use `connection master;` and `connection slave;`. If you need to do something on an alternate connection, you can do `connection master1;` for the master, and `connection slave1;` for the slave.
- If you need to do something in a loop, you can use something like this:

      let $1=1000;
      while ($1)
      {
       # do your queries here
       dec $1;
      }

- To sleep between queries, use the `sleep` command. It supports fractions of a second, so you can do `sleep 1.3;`, for example, to sleep 1.3 seconds.
- To run the slave with additional options for your test case, put them in the command-line format in `mysql-test/t/test_name-slave.opt`. For the master, put them in `mysql-test/t/test_name-master.opt`.
- If you have a question about the test suite, or have a test case to contribute, e-mail to internals@lists.mysql.com. As the list does not accept attachments, you should ftp all the relevant files to: ftp://support.mysql.com/pub/mysql/Incoming

#### 9.3.2.3 Reporting Bugs in the MySQL Test Suite

If your MySQL version doesn't pass the test suite you should do the following:

- Don't send a bug report before you have found out as much as possible of what when wrong! When you do it, please use the `mysqlbug` script so that we can get information about your system and `MySQL` version. 「1.2.22.3 バグや問題を報告する方法」節参照.
- Make sure to include the output of `mysql-test-run`, as well as contents of all `.reject` files in `mysql-test/r` directory.
- If a test in the test suite fails, check if the test fails also when run by its own:

      cd mysql-test
      mysql-test-run --local test-name

  If this fails, then you should configure MySQL with `--with-debug` and run `mysql-test-run` with the `--debug` option. If this also fails send the trace file ``var/tmp/master.trace'` to ftp://support.mysql.com/pub/mysql/secret so that we can examine it. Please remember to also include a full description of your system, the version of the mysqld binary and how you compiled it.
- Try also to run `mysql-test-run` with the `--force` option to see if there is any other test that fails.
- If you have compiled MySQL yourself, check our manual for how to compile MySQL on your platform or, preferable, use one of the binaries we have compiled for you at http://www.mysql.com/downloads/. All our standard binaries should pass the test suite !
- If you get an error, like `Result length mismatch` or `Result content mismatch` it means that the output of the test didn't match exactly the expected output. This could be a bug in MySQL or that your mysqld version produces slight different results under some circumstances. Failed test results are put in a file with the same base name as the result file with the `.reject` extension. If your test case is failing, you should do a diff on the two files. If you cannot see how they are different, examine both with `od -c` and also check their lengths.
- If a test fails totally, you should check the logs file in the `mysql-test/var/log` directory for hints of what went wrong.
- If you have compiled MySQL with debugging you can try to debug this by running `mysql-test-run` with the `--gdb` and/or `--debug` options. 「G.1.2 Creating trace files」節参照. If you have not compiled MySQL for debugging you should probably do that. Just specify the `--with-debug` options to `configure`! 「2.3 MySQL ソースディストリビューションのインストール」節参照.

Go to the first, previous, next, last section, table of contents.