MySQL 5.1ではビルトイン(既存の)ファンクション、ユーザ定義関数(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を有効化することは、パーサが影響を受ける関数名を予約語として扱うという副作用もあります。(「MySQLでの予約語の扱い」を参照してください)これは名前の後に続く余白には識別子として認識されないことを意味します。後続の余白の有無を問わず、名前は関数呼び出しとして使用できますが、引用符で囲まれない場合は、非表現テキスト内での構文エラーを引き起こします。例えば、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を有効化するかを調べるには「SQL モード」を参照してください。
IGNORE_SPACE設定におけるSQLコードの依存性を最小化するには、これらのガイドラインを使用してください。
UDFもしくはビルトイン関数と同名のストアドファンクションの作成を避けてください。
非表現コンテキスト内の関数名使用を避けてください。例えば、これらのステートメントはcount
(IGNORE_SPACEに影響を受ける関数名のひとつ)を使用するため、IGNORE_SPACE
が有効であれば後続名に対する余白の有無によらず、これらは無効となります。
CREATE TABLE count(i INT); CREATE TABLE count (i INT);
非表現コンテキストで関数名を使用するには、引用符で囲まれた識別子として記述してください。
CREATE TABLE `count`(i INT); CREATE TABLE `count` (i INT);
IGNORE_SPACEに影響を受ける関数名の数はMySQL
5.1.13では約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
()
また、ストアド関数名を、コンフリクトを引き起こさない名前に付け替え、新しい名前を使用するために関数の起動を変更してください。
関数名の名前解決
次のルールは関数作成と起動のためにサーバがどのように関数名を参照するかについて述べられています。
ビルトイン関数とユーザ定義関数
MySQL
5.1.14より後では、ビルトイン関数と同名のUDFを作成する際に、エラーが発生します。5.1.14前では、UDFはビルトイン関数と同名で作成はできましたが、パーサがビルトイン関数を参照する関数の起動を解除するため、UDFの起動はできませんでした。例えば、ABSと名づけられたUDFを作成する場合、ABS()を参照するとビルトイン関数が起動されます。
ビルトイン関数とストアドファンクション
ビルトイン関数と同名のストアドファンクションを作成することは可能ですが、ストアドファンクションを起動させるにはスキーマ名で資格を与えなければいけません。例えば、testスキーマ内でPIという名のストアドファンクションを作成する場合、サーバがPI()をビルトイン関数参照として解釈するため、test.PI()として起動されます。5.1.14より、ストアド関数名がビルトイン関数名と衝突する場合、サーバから警告が発せられます。この警告はSHOW
WARNINGSで表示できます。
ユーザ定義関数とストアドファンクション
ユーザ定義関数とストアドファンクションは同じネームスペースを共有します。したがって、同名でUDFとストアドファンクションを作成することはできません。
前置関数名を解除するには、新しいビルトイン関数を実行するためのMySQLバージョンアップグレードを実行してください。
すでにユーザによって定義された関数が提供名で作成され、同名の新ビルトイン関数が実行されるようにMySQLがアップグレードされた場合、UDFはアクセス不可となります。これを修正するには、DROP
FUNCTIONを使用してUDFを無効にし、次にCREATE
FUNCTIONを使ってコンフリクトを引き起こさないような異なる名前でUDFを再作成してください。
MySQLの新バージョンで、既存のストアドファンクションと同名のビルトイン関数を起動する場合、2つの方法があります。コンフリクトを引き起こさないようにストアド関数名を変えるか、スキーマ修飾語が使用されるよう、ファンクションの呼び名を変えてください。(つまり、構文を使用してください。)
schema_nameまたはfunc_name()
