MySQL は、組込み (ネイティブ) 関数、ユーザー定義関数 (UDF) およびストアドファンクションをサポートしています。 このセクションでは、組み込み関数名が関数呼び出しとして使用されているか、識別子として使用されているかをサーバーで認識する方法と、指定された名前で異なる型の関数が存在する場合に使用する関数をサーバーが特定する方法について説明します。
パーサーは組み込み関数名を構文解析するためのデフォルトのルールを使用します。 これらのルールは IGNORE_SPACE
SQL モードを有効にすることで変更できます。
パーサーは、組み込み関数の名前である単語を検出すると、その名前が関数呼び出しを示しているのか、それともテーブル名やカラム名などの識別子の式以外の参照であるのかを判別する必要があります。 たとえば、次のステートメントでは count
に対する最初の参照は関数呼び出しですが、2 番目の参照はテーブル名です。
SELECT COUNT(*) FROM mytable;
CREATE TABLE count (i INT);
パーサーは、式であると予想される対象を解析しているときにのみ、組み込み関数の名前を、関数呼び出しを示している名前として認識する必要があります。 つまり、式以外のコンテキストでは、関数名は識別子として許可されます。
ただし、組み込み関数の中には構文解析や実装に関する特別な考慮事項を含んでいるものがあるため、パーサーはデフォルトで次のルールに従って、その名前が関数呼び出しとして使用されているのか、それとも式以外のコンテキストで識別子として使用されているのかを判別します。
式の中で関数呼び出しとして名前を使用するには、名前とそれに続く括弧文字
(
の間に空白が存在しないことが必要です。反対に、関数名を識別子として使用するには、括弧文字を直後に続けないでください。
名前と括弧の間に空白を入れずに関数呼び出しを記述するという要件は、特別な考慮事項を持つ組み込み関数にのみ適用されます。 COUNT
がこのような名前の 1 つです。 sql/lex.h
ソースファイルには、次の空白によって解釈が決定されるこれらの特殊関数の名前がリストされます: symbols[]
配列の SYM_FN()
マクロによって定義された名前。
次のリストに、IGNORE_SPACE
設定の影響を受け、sql/lex.h
ソースファイルに特殊としてリストされる MySQL 8.0 の関数の名前を示します。 非ヒットスペース要件をすべての関数コールに適用するのが最も簡単な場合があります。
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
sql/lex.h
で特殊としてリストされていない関数の場合、空白は関係ありません。 それらは式のコンテキストで使用されるときにのみ関数呼び出しとして解釈され、それ以外では識別子として自由に使用できます。 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.11「サーバー 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);
次のルールは、関数の作成と呼び出しのために、サーバーで関数名の参照を解決する方法について記述します。
-
組み込み関数とユーザー定義関数
組み込み関数と同じ名前で UDF を作成しようとした場合、エラーが発生します。
-
組み込み関数とストアドファンクション
組み込み関数と同名のストアドファンクションを作成することは可能ですが、このストアドファンクションを呼び出すにはスキーマ名で修飾する必要があります。 たとえば、
test
スキーマにPI
という名前のストアドファンクションを作成した場合、サーバーは組込み関数への参照として修飾子なしでPI()
を解決するため、それをtest.PI()
として起動します。 ストアドファンクション名が組込み関数名と競合する場合、サーバーは警告を生成します。 この警告はSHOW WARNINGS
で表示できます。 -
ユーザー定義関数とストアドファンクション
ユーザー定義関数とストアドファンクションは同じ名前空間を共有します。したがって、同名の UDF とストアドファンクションを作成することはできません。
前述の関数名の解決ルールは、新しい組み込み関数を実装する MySQL のバージョンへのアップグレードに影響を及ぼします。
指定の名前のユーザー定義関数がすでに作成されており、同じ名前で新しい組み込み関数を実装するバージョンに MySQL をアップグレードすると、この UDF にはアクセスできなくなります。 これを修正するには、
DROP FUNCTION
を使用して UDF およびCREATE FUNCTION
を削除し、競合しない別の名前で UDF を再作成します。 次に、影響を受けるコードを変更して新しい名前を使用します。新しいバージョンの MySQL で、既存のストアドファンクションと同じ名前で組み込み関数を実装する場合、ストアドファンクションの名前を競合しない名前に変更するか、スキーマ修飾子を使用するように関数の呼び出しを変更する (つまり、
構文を使用する) という 2 つの選択肢があります。 いずれの場合も、影響を受けるコードを適宜変更します。schema_name
.func_name
()