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
を有効にすることには、パーサーが影響を受ける関数名を予約語として扱うという副作用もあります
(項5.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
を有効にするかを調べるにはServer SQL Modesを参照してください。
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);
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
()
あるいは、ストアドファンクションの名前を衝突しない名前に変更し、新しい名前を使用するようにその関数の呼び出しを変更してください。
ファンクション名の解像度
次の規則はファンクション作成と起動のためにサーバーがどのようにファンクション名を参照するかについて述べられています。
組み込み関数とユーザー定義関数
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
()