MySQL 5.6 は、組み込み (ネイティブ) 関数、ユーザー定義関数 (UDF)、およびストアドファンクションをサポートします。このセクションでは、組み込み関数名が関数呼び出しとして使用されているか、識別子として使用されているかをサーバーで認識する方法と、指定された名前で異なる型の関数が存在する場合に使用する関数をサーバーが特定する方法について説明します。
組み込み関数名の構文解析
パーサーは組み込み関数名を構文解析するためのデフォルトのルールを使用します。これらのルールは IGNORE_SPACE
SQL モードを有効にすることで変更できます。
パーサーは、組み込み関数の名前である単語を検出すると、その名前が関数呼び出しを示しているのか、それともテーブル名やカラム名などの識別子の式以外の参照であるのかを判別する必要があります。たとえば、次のステートメントでは count
に対する最初の参照は関数呼び出しですが、2 番目の参照はテーブル名です。
SELECT COUNT(*) FROM mytable;
CREATE TABLE count (i INT);
パーサーは、式であると予想される対象を解析しているときにのみ、組み込み関数の名前を、関数呼び出しを示している名前として認識する必要があります。つまり、式以外のコンテキストでは、関数名は識別子として許可されます。
ただし、組み込み関数の中には構文解析や実装に関する特別な考慮事項を含んでいるものがあるため、パーサーはデフォルトで次のルールに従って、その名前が関数呼び出しとして使用されているのか、それとも式以外のコンテキストで識別子として使用されているのかを判別します。
式の中で関数呼び出しとして名前を使用するには、名前とそれに続く括弧文字「
(
」の間に空白が存在しないことが必要です。反対に、関数名を識別子として使用するには、括弧文字を直後に続けないでください。
名前と括弧の間に空白を入れずに関数呼び出しを記述するという要件は、特別な考慮事項を持つ組み込み関数にのみ適用されます。COUNT
がこのような名前の 1 つです。後続の空白によって解釈が決まる関数名の正確な一覧は、sql/lex.h
ソースファイルの sql_functions[]
配列に表示されます。MySQL 5.1 よりも前のバージョンでは、このような関数名が多数 (約 200) あるため、空白なしという要件をすべての関数呼び出しに適用させる方法がもっとも簡単であると考えられます。MySQL 5.1 以降では、パーサーの改善によって、影響を受ける関数名の数は約 30 にまで減少しています。
sql_functions[]
配列に一覧表示されていない関数には、空白は関係ありません。それらは式のコンテキストで使用されるときにのみ関数呼び出しとして解釈され、それ以外では識別子として自由に使用できます。ASCII
がこのような名前の 1 つです。ただし、このような影響を受けない関数名に対する解釈は、式のコンテキストによって変わることがあります。つまり、
は、指定の名前が単独で使用される場合は組み込み関数として解釈されますが、単独ではない場合、func_name
()
はユーザー定義関数またはストアドファンクション (その名前の関数が存在する場合) として解釈されます。
func_name
()
IGNORE_SPACE
SQL モードは、空白の有無で区別される関数名をパーサーで扱う方法を変更するために使用できます。
-
IGNORE_SPACE
が無効になっていると、名前と後続の括弧の間に空白がない場合、パーサーはその名前を関数呼び出しと解釈します。これは、関数名が式以外のコンテキストで使用されているときにも行われます。mysql> CREATE TABLE count(i INT); ERROR 1064 (42000): You have an error in your SQL syntax ... near 'count(i INT)'
エラーを取り除き、名前が識別子として扱われるようにするには、名前のあとに続く空白を使うか、引用符で囲んだ識別子として記述してください (あるいはこの両方)。
CREATE TABLE count (i INT); CREATE TABLE `count`(i INT); CREATE TABLE `count` (i INT);
-
IGNORE_SPACE
が有効になっていると、パーサーは関数名と後続の括弧の間に空白は存在しないという要件を緩和します。このことで、関数呼び出しの記述がより自由に行えるようになります。たとえば、次のどちらの関数呼び出しも有効です。SELECT COUNT(*) FROM mytable; SELECT COUNT (*) FROM mytable;
ただし、
IGNORE_SPACE
を有効にした場合、影響を受ける関数名をパーサーが予約語として扱うという副作用も生じます (セクション9.3「予約語」を参照してください)。つまり、名前のあとに続く空白は、それが識別子として使用されることを示すものではなくなります。後続の空白の有無を問わず、名前は関数呼び出しとして使用できますが、引用符で囲まれていないかぎり、式以外のコンテキストでは構文エラーが発生します。たとえば、IGNORE_SPACE
が有効になっていると、パーサーがcount
を予約語として解釈するため、次のステートメントはどちらも構文エラーが表示されて失敗します。CREATE TABLE count(i INT); CREATE TABLE count (i INT);
式以外のコンテキストで関数名を使用するには、これを引用符で囲まれた識別子として記述します。
CREATE TABLE `count`(i INT); CREATE TABLE `count` (i INT);
IGNORE_SPACE
SQL モードを有効にするには、次のステートメントを使用します。
SET sql_mode = 'IGNORE_SPACE';
IGNORE_SPACE
は、ANSI
などのほかの特定のコンポジットモードの値に含められている場合にも有効になります。
SET sql_mode = 'ANSI';
どのコンポジットモードが IGNORE_SPACE
を有効にするかを調べるには、セクション5.1.7「サーバー SQL モード」を参照してください。
IGNORE_SPACE
設定における SQL コードの依存関係を最小にするには、以下のガイドラインを使用してください。
組み込み関数と同じ名前の UDF またはストアドファンクションは作成しないでください。
-
式以外のコンテキストでは関数名を使用しないでください。たとえば、これらのステートメントは、
count
(IGNORE_SPACE
の影響を受ける関数名の 1 つ) を使用するため、IGNORE_SPACE
が有効であれば、名前に続く空白の有無によらずこれらのステートメントは失敗します。CREATE TABLE count(i INT); CREATE TABLE count (i INT);
式以外のコンテキストで関数名を使用する必要がある場合は、これを引用符で囲まれた識別子として記述します。
CREATE TABLE `count`(i INT); CREATE TABLE `count` (i INT);
MySQL 5.1.13 では、IGNORE_SPACE
の影響を受ける関数名の数がおよそ 200 から 30 に大幅に減少しました。MySQL 5.1.13 以降、IGNORE_SPACE
設定の影響を引き続き受けるのは、次の関数だけです。
ADDDATE |
BIT_AND |
BIT_OR |
BIT_XOR |
CAST |
COUNT |
CURDATE |
CURTIME |
DATE_ADD |
DATE_SUB |
EXTRACT |
GROUP_CONCAT |
MAX |
MID |
MIN |
NOW |
POSITION |
SESSION_USER |
STD |
STDDEV |
STDDEV_POP |
STDDEV_SAMP |
SUBDATE |
SUBSTR |
SUBSTRING |
SUM |
SYSDATE |
SYSTEM_USER |
TRIM |
VARIANCE |
VAR_POP |
VAR_SAMP |
MySQL の以前のバージョンでは、sql/lex.h
ソースファイルの sql_functions[]
配列の内容を確認して、どの関数が IGNORE_SPACE
に影響を受けるかを確認してください。
非互換性に関する警告: MySQL 5.1.13 では IGNORE_SPACE
の影響を受ける関数名の数を抑えることでパーサー操作に一貫性をもたらしました。ただし、次の条件に依存する旧 SQL コードの非互換性の可能性も生じます。
IGNORE_SPACE
は無効になっています。関数名に続く空白の有無は、同じ名前を持つ組み込み関数とストアドファンクション (たとえば、
PI()
とPI ()
など) を区別するために使用されます。
MySQL 5.1.13 以降に IGNORE_SPACE
の影響を受けなくなった関数に対しては、その方法は機能しません。前述の非互換性の影響を受けるコードがある場合は、次のどちらのアプローチも使用できます。
ストアドファンクションに組み込み関数と競合する名前が存在する場合、空白の有無にかかわらず、スキーマ名修飾子を持つストアドファンクションを参照してください。たとえば、
またはschema_name
.PI()
と記述します。schema_name
.PI ()または、競合しない名前を使用するようにストアドファンクションの名前を変更し、新しい名前を使用するように関数の呼び出しを変更します。
関数名の解決
次のルールは、関数の作成と呼び出しのために、サーバーで関数名の参照を解決する方法について記述します。
-
組み込み関数とユーザー定義関数
組み込み関数と同じ名前で UDF を作成しようとした場合、エラーが発生します。
-
組み込み関数とストアドファンクション
組み込み関数と同名のストアドファンクションを作成することは可能ですが、このストアドファンクションを呼び出すにはスキーマ名で修飾する必要があります。たとえば、
test
スキーマ内でPI
という名のストアドファンクションを作成する場合、サーバーがPI()
を組み込み関数の参照として解決するため、test.PI()
として呼び出します。サーバーは、ストアドファンクション名が組み込み関数名と一致しない場合、警告を作成します。この警告はSHOW WARNINGS
で表示できます。 -
ユーザー定義関数とストアドファンクション
ユーザー定義関数とストアドファンクションは同じ名前空間を共有します。したがって、同名の UDF とストアドファンクションを作成することはできません。
前述の関数名の解決ルールは、新しい組み込み関数を実装する MySQL のバージョンへのアップグレードに影響を及ぼします。
指定の名前のユーザー定義関数がすでに作成されており、同じ名前で新しい組み込み関数を実装するバージョンに MySQL をアップグレードすると、この UDF にはアクセスできなくなります。これを修正するには、
DROP FUNCTION
を使用して UDF を削除してから、CREATE FUNCTION
を使用して競合しない別の名前で UDF を再作成します。新しいバージョンの MySQL で、既存のストアドファンクションと同じ名前で組み込み関数を実装する場合、ストアドファンクションの名前を競合しない名前に変更するか、スキーマ修飾子を使用するように関数の呼び出しを変更する (つまり、
構文を使用する) という 2 つの選択肢があります。schema_name
.func_name
()