MySQL 5.1ではビルトイン(既存の)ファンクション、ユーザによって定義されたファンクション(UDFs)、そして保存されたファンクションがサポートされます。このセクションでは、サーバが、ビルトインファンクション名をファンクション呼び出しもしくは識別子として認識するかどうか、また既存名によって異なる型のファンクションが存在する場合に、サーバがどのファンクションを使用するかを決定します。
ビルトインファンクション名の構文解析
パーサがビルトインファンクション名を解析するには、デフォルトルールにのっとって行われます。これらのルールは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
を有効化することは、パーサが影響を受けるファンクション名を予約語として扱うという副作用もあります。(項8.3. 「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
を有効化するかを調べるには項4.2.6. 「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
()