This section discusses some implementation details that are frequently important for <application>PL/pgSQL</application> users to know. 本節では、PL/pgSQL利用者の知識として重要な、実装の詳細を述べます。
SQL statements and expressions within a <application>PL/pgSQL</application> function can refer to variables and parameters of the function. Behind the scenes, <application>PL/pgSQL</application> substitutes query parameters for such references. Query parameters will only be substituted in places where they are syntactically permissible. As an extreme case, consider this example of poor programming style: PL/pgSQL関数内のSQL文および式は変数および関数のパラメータを参照することができます。 背後では、PL/pgSQLはこうした参照を問い合わせパラメータに置き換えます。 文法的に許されているところでのみ問い合わせパラメータは置換されます。 極端な場合として、以下のよろしくないプログラミングスタイルの例を考えてみましょう。
INSERT INTO foo (foo) VALUES (foo(foo));
The first occurrence of <literal>foo</literal> must syntactically be a table
name, so it will not be substituted, even if the function has a variable
named <literal>foo</literal>. The second occurrence must be the name of a
column of that table, so it will not be substituted either. Likewise
the third occurrence must be a function name, so it also will not be
substituted for. Only the last occurrence is a candidate to be a
reference to a variable of the <application>PL/pgSQL</application>
function.
最初に現れるfoo
の場所は文法的にはテーブル名でなければなりません。
このため関数がfoo
という名前の変数を持っていたとしても、置換されません。
2番目の場所はそのテーブルの列名でなければなりません。このためこれも置換されません。
同様に、3番目の場所は関数名でなければなりません。このためこれも置換されません。
最後の場所のみがPL/pgSQLの関数の変数参照の候補です。
Another way to understand this is that variable substitution can only insert data values into an SQL command; it cannot dynamically change which database objects are referenced by the command. (If you want to do that, you must build a command string dynamically, as explained in <xref linkend="plpgsql-statements-executing-dyn"/>.) これを理解する別の方法は、変数の置換はSQLコマンドへデータ値を挿入できるだけだということです。コマンドが参照するデータベースオブジェクトを動的には変更できません。 (そのようにしたければ、41.5.4に書かれているように、コマンド文字列を動的に構成しなければなりません。)
Since the names of variables are syntactically no different from the names of table columns, there can be ambiguity in statements that also refer to tables: is a given name meant to refer to a table column, or a variable? Let's change the previous example to 変数名は文法的にはテーブル列名と違いがありませんので、テーブルを参照する文の中であいまいさが出る可能性があります。 与えられた名前はテーブル列を意味するのでしょうか、それとも変数なのでしょうか。 前の例を次のように変えてみましょう。
INSERT INTO dest (col) SELECT foo + bar FROM src;
Here, <literal>dest</literal> and <literal>src</literal> must be table names, and
<literal>col</literal> must be a column of <literal>dest</literal>, but <literal>foo</literal>
and <literal>bar</literal> might reasonably be either variables of the function
or columns of <literal>src</literal>.
ここでは、dest
およびsrc
はテーブル名でなければなりません。
また、col
はdest
の列でなければなりませんが、foo
およびbar
は理論上関数の変数かもしれませんし、src
の列かもしれません。
By default, <application>PL/pgSQL</application> will report an error if a name in an SQL statement could refer to either a variable or a table column. You can fix such a problem by renaming the variable or column, or by qualifying the ambiguous reference, or by telling <application>PL/pgSQL</application> which interpretation to prefer. デフォルトでPL/pgSQLはSQL文における名前が変数かテーブル列のいずれかを参照可能な場合にエラーを報告します。 変数または列の名前を変更することやあいまいな参照を修飾すること、PL/pgSQLにどちらを優先して解釈するかを通知することで、こうした問題を解消することができます。
The simplest solution is to rename the variable or column.
A common coding rule is to use a
different naming convention for <application>PL/pgSQL</application>
variables than you use for column names. For example,
if you consistently name function variables
<literal>v_<replaceable>something</replaceable></literal> while none of your
column names start with <literal>v_</literal>, no conflicts will occur.
最も簡単な解法は変数名または列名を変更することです。
一般的なコーディング法として、列の命名とPL/pgSQL変数の命名とで規約を分ける方法があります。
例えば、一貫して関数の変数はv_
という名前とし、列名はsomething
v_
で始まらないようにすれば、競合は起こりません。
Alternatively you can qualify ambiguous references to make them clear.
In the above example, <literal>src.foo</literal> would be an unambiguous reference
to the table column. To create an unambiguous reference to a variable,
declare it in a labeled block and use the block's label
(see <xref linkend="plpgsql-structure"/>). For example,
その他、あいまいな参照を明確にするために修飾することができます。
上の例では、src.foo
によりテーブル列への参照についてあいまいさが解消します。
あいまい性のない変数参照を行うためには、ラベル付けしたブロック内で変数を宣言し、そのブロックのラベルを使用します(41.2参照)。
以下に例を示します。
<<block>> DECLARE foo int; BEGIN foo := ...; INSERT INTO dest (col) SELECT block.foo + bar FROM src;
Here <literal>block.foo</literal> means the variable even if there is a column
<literal>foo</literal> in <literal>src</literal>. Function parameters, as well as
special variables such as <literal>FOUND</literal>, can be qualified by the
function's name, because they are implicitly declared in an outer block
labeled with the function's name.
ここでblock.foo
はsrc
にfoo
列があったとしても、変数を意味することになります。
FOUND
などの特別な変数を含め、関数パラメータを関数名で修飾することができます。
これらは暗黙的に関数名をラベル名とした上位ブロック内で宣言されているためです。
Sometimes it is impractical to fix all the ambiguous references in a large body of <application>PL/pgSQL</application> code. In such cases you can specify that <application>PL/pgSQL</application> should resolve ambiguous references as the variable (which is compatible with <application>PL/pgSQL</application>'s behavior before <productname>PostgreSQL</productname> 9.0), or as the table column (which is compatible with some other systems such as <productname>Oracle</productname>). PL/pgSQLの大規模な本体コードにおける、すべてのあいまいな参照を修正することが現実的ではない場合があります。 こうした場合、PL/pgSQLにあいまいな参照を変数として解決すべき(この動作はPostgreSQL 9.0より前のPL/pgSQLの動作と互換性を持ちます)、または、テーブル列参照として解決すべき(Oracleなどの他のシステムと互換性を持ちます)と指定することができます。
To change this behavior on a system-wide basis, set the configuration
parameter <literal>plpgsql.variable_conflict</literal> to one of
<literal>error</literal>, <literal>use_variable</literal>, or
<literal>use_column</literal> (where <literal>error</literal> is the factory default).
This parameter affects subsequent compilations
of statements in <application>PL/pgSQL</application> functions, but not statements
already compiled in the current session.
Because changing this setting
can cause unexpected changes in the behavior of <application>PL/pgSQL</application>
functions, it can only be changed by a superuser.
システム全体に対してこの動作を変更するためにはplpgsql.variable_conflict
設定パラメータをerror
、use_variable
、use_column
のいずれかに設定します(error
が標準配布におけるデフォルトです)。
このパラメータは以降のPL/pgSQL関数の文のコンパイルに影響しますが、現在のセッションでコンパイル済みの文には影響を与えません。
この設定を変更することで、PL/pgSQLの動作において予期できない変化が発生することがありますので、これはスーパーユーザのみが変更することができます。
You can also set the behavior on a function-by-function basis, by inserting one of these special commands at the start of the function text: また、関数テキストの先頭に以下の特殊なコマンドの1つをいれることで、関数単位で動作を設定することもできます。
#variable_conflict error #variable_conflict use_variable #variable_conflict use_column
These commands affect only the function they are written in, and override
the setting of <literal>plpgsql.variable_conflict</literal>. An example is
これらのコマンドを記述した関数に対してのみ、コマンドは影響を与え、plpgsql.variable_conflict
の設定を上書きします。
以下に例を示します。
CREATE FUNCTION stamp_user(id int, comment text) RETURNS void AS $$ #variable_conflict use_variable DECLARE curtime timestamp := now(); BEGIN UPDATE users SET last_modified = curtime, comment = comment WHERE users.id = id; END; $$ LANGUAGE plpgsql;
In the <literal>UPDATE</literal> command, <literal>curtime</literal>, <literal>comment</literal>,
and <literal>id</literal> will refer to the function's variable and parameters
whether or not <literal>users</literal> has columns of those names. Notice
that we had to qualify the reference to <literal>users.id</literal> in the
<literal>WHERE</literal> clause to make it refer to the table column.
But we did not have to qualify the reference to <literal>comment</literal>
as a target in the <literal>UPDATE</literal> list, because syntactically
that must be a column of <literal>users</literal>. We could write the same
function without depending on the <literal>variable_conflict</literal> setting
in this way:
UPDATE
コマンドにおいて、curtime
、comment
およびid
は、users
に同名の列があるか否かに関わらず、関数の変数またはパラメータを参照します。
テーブル列を参照させるためにWHERE
句においてusers.id
と参照を修飾する必要があったことに注意して下さい。
しかしUPDATE
リストの対象としてのcomment
への参照は修飾させる必要がありませんでした。
これは文法的にusers
の列でなければならないためです。
以下のようにvariable_conflict
の設定に依存せずに同じ関数を作成することもできます。
CREATE FUNCTION stamp_user(id int, comment text) RETURNS void AS $$ <<fn>> DECLARE curtime timestamp := now(); BEGIN UPDATE users SET last_modified = fn.curtime, comment = stamp_user.comment WHERE users.id = stamp_user.id; END; $$ LANGUAGE plpgsql;
Variable substitution does not happen in a command string given
to <command>EXECUTE</command> or one of its variants. If you need to
insert a varying value into such a command, do so as part of
constructing the string value, or use <literal>USING</literal>, as illustrated in
<xref linkend="plpgsql-statements-executing-dyn"/>.
変数置換はEXECUTE
コマンドまたはその亜種におけるコマンド文字列の中では起こりません。
そのようなコマンドに可変値を挿入する時は、41.5.4に述べたように、文字列の値を構成するものの一部とするかUSING
を使用してください。
Variable substitution currently works only in <command>SELECT</command>,
<command>INSERT</command>, <command>UPDATE</command>,
<command>DELETE</command>, and commands containing one of
these (such as <command>EXPLAIN</command> and <command>CREATE TABLE
... AS SELECT</command>),
because the main SQL engine allows query parameters only in these
commands. To use a non-constant name or value in other statement
types (generically called utility statements), you must construct
the utility statement as a string and <command>EXECUTE</command> it.
今のところ変数置換は、SELECT
とINSERT
とUPDATE
とDELETE
コマンドと(EXPLAIN
やCREATE TABLE ... AS SELECT
のような)このうちの1つを含むコマンドの中だけで作動します。
メインSQLエンジンが問い合わせパラメータをこれらのコマンドでしか許可しないからです。
他の種類の文(通常ユーティリティ文といいます)において可変名または可変値を使用するには、文字列としてユーティリティ文を構成しEXECUTE
してください。
The <application>PL/pgSQL</application> interpreter parses the function's source text and produces an internal binary instruction tree the first time the function is called (within each session). The instruction tree fully translates the <application>PL/pgSQL</application> statement structure, but individual <acronym>SQL</acronym> expressions and <acronym>SQL</acronym> commands used in the function are not translated immediately. PL/pgSQLインタプリタは、初めてその関数が(各セッションで)呼び出された時に、関数のソーステキストを解析し、バイナリ形式の命令ツリーを内部で作成します。 この命令ツリーは完全にPL/pgSQL文構造に変換されますが、関数内部の個々のSQL式とSQLコマンドは即座に変換されません。
As each expression and <acronym>SQL</acronym> command is first
executed in the function, the <application>PL/pgSQL</application> interpreter
parses and analyzes the command to create a prepared statement,
using the <acronym>SPI</acronym> manager's
<function>SPI_prepare</function> function.
Subsequent visits to that expression or command
reuse the prepared statement. Thus, a function with conditional code
paths that are seldom visited will never incur the overhead of
analyzing those commands that are never executed within the current
session. A disadvantage is that errors
in a specific expression or command cannot be detected until that
part of the function is reached in execution. (Trivial syntax
errors will be detected during the initial parsing pass, but
anything deeper will not be detected until execution.)
各式やSQLコマンドが初めてその関数で実行される時に、PL/pgSQLインタプリタはSPIマネージャのSPI_prepare
関数を使用して、プリペアドステートメントを作成するためにコマンドを解析します。
その後にその式やコマンドが行われる時には、そのプリペアドステートメントを再利用します。
こうして、めったに分岐されない条件付きコードパスを持つ関数では、現在のセッションで実行されないそれらのコマンドの解析によるオーバーヘッドを背負いこむことはありません。
欠点は特定の式や問い合わせのエラーが、関数の該当部分が実行されるまで検出されないことです。
(典型的な構文エラーは、最初の解釈において検出されますが、それより深いエラーは、実行の時まで検出されません)。
<application>PL/pgSQL</application> (or more precisely, the SPI manager) can furthermore attempt to cache the execution plan associated with any particular prepared statement. If a cached plan is not used, then a fresh execution plan is generated on each visit to the statement, and the current parameter values (that is, <application>PL/pgSQL</application> variable values) can be used to optimize the selected plan. If the statement has no parameters, or is executed many times, the SPI manager will consider creating a <firstterm>generic</firstterm> plan that is not dependent on specific parameter values, and caching that for re-use. Typically this will happen only if the execution plan is not very sensitive to the values of the <application>PL/pgSQL</application> variables referenced in it. If it is, generating a plan each time is a net win. See <xref linkend="sql-prepare"/> for more information about the behavior of prepared statements. PL/pgSQLは(正確にはSPIマネージャは)さらに特定のプリペアドステートメントに関する実行計画のキャッシュを試行できます。 キャッシュした実行計画が使用されなかった場合、プリペアドステートメントが呼び出される度に新しい実行計画が作成され、選択した実行計画を最適にするために、最新のパラメータ値(すなわちPL/pgSQLの変数値)が使用されます。 プリペアドステートメントがパラメータを持たないか何回も使用される場合、SPIマネージャは特定のパラメータ値に依存しない一般的な実行計画の作成を考え、再使用のためにキャッシュします。 典型的には、これは参照したPL/pgSQLの変数値が、実行計画にさほど影響しない場合にだけ起こります。 それならば、毎回の実行計画の作成の方が優れています。 プリペアドステートメントに関する詳細はPREPAREを参照してください。
Because <application>PL/pgSQL</application> saves prepared statements
and sometimes execution plans in this way,
SQL commands that appear directly in a
<application>PL/pgSQL</application> function must refer to the
same tables and columns on every execution; that is, you cannot use
a parameter as the name of a table or column in an SQL command. To get
around this restriction, you can construct dynamic commands using
the <application>PL/pgSQL</application> <command>EXECUTE</command>
statement — at the price of performing new parse analysis and
constructing a new execution plan on every execution.
このようにPL/pgSQLはプリペアドステートメントおよび時には実行計画を保存しますので、PL/pgSQL関数内に直接現れるSQLコマンドは実行の度に同じテーブルとフィールドを参照しなければなりません。
つまり、SQLコマンドにて、テーブルやフィールドの名前としてパラメータを使用することができません。
実行の度に新しく実行計画を作成して解析する無駄を覚悟で、PL/pgSQLのEXECUTE
文を使った動的問い合わせを構成することで、この制限を回避できます。
The mutable nature of record variables presents another problem in this
connection. When fields of a record variable are used in
expressions or statements, the data types of the fields must not
change from one call of the function to the next, since each
expression will be analyzed using the data type that is present
when the expression is first reached. <command>EXECUTE</command> can be
used to get around this problem when necessary.
レコード変数の変わりやすいという性質はこの接続において別の問題となります。
レコード変数のフィールドが式や文の中で使用される場合、そのフィールドのデータ型を関数を呼び出す度に変更してはいけません。
それぞれの式が最初に実行された時のデータ型を使用して、その式が解析されているからです。
必要な場合EXECUTE
を使用してこの問題を回避することができます。
If the same function is used as a trigger for more than one table,
<application>PL/pgSQL</application> prepares and caches statements
independently for each such table — that is, there is a cache
for each trigger function and table combination, not just for each
function. This alleviates some of the problems with varying
data types; for instance, a trigger function will be able to work
successfully with a column named <literal>key</literal> even if it happens
to have different types in different tables.
同一の関数が2つ以上のテーブルのトリガとして使用される場合、PL/pgSQLはテーブルごとのプリペアドステートメントをキャッシュします。
すなわち、各々のトリガ関数とテーブルの組ごとにキャッシュするのであり、トリガ関数ごとではありません。
このため、データ型の変更に伴う問題の一部を軽減します。
例えば、別のテーブルにある異なったデータ型であっても、key
と命名した列に対してトリガ関数は有効に作動します。
Likewise, functions having polymorphic argument types have a separate statement cache for each combination of actual argument types they have been invoked for, so that data type differences do not cause unexpected failures. 同様に、多様型の引数を持った関数は、実際に呼び出す引数の型の組み合わせごとに別々のプリペアドステートメントをキャッシュします。 そのため、データ型の差異が原因で予期しない失敗が起こることはありません。
Statement caching can sometimes have surprising effects on the interpretation of time-sensitive values. For example there is a difference between what these two functions do: プリペアドステートメントのキャッシュにより、時間に依存する値の解釈の結果に違いが現れることがあります。 例えば、以下の2つの関数の結果は異なります。
CREATE FUNCTION logfunc1(logtxt text) RETURNS void AS $$ BEGIN INSERT INTO logtable VALUES (logtxt, 'now'); END; $$ LANGUAGE plpgsql;
and: および
CREATE FUNCTION logfunc2(logtxt text) RETURNS void AS $$ DECLARE curtime timestamp; BEGIN curtime := 'now'; INSERT INTO logtable VALUES (logtxt, curtime); END; $$ LANGUAGE plpgsql;
In the case of <function>logfunc1</function>, the
<productname>PostgreSQL</productname> main parser knows when
analyzing the <command>INSERT</command> that the
string <literal>'now'</literal> should be interpreted as
<type>timestamp</type>, because the target column of
<classname>logtable</classname> is of that type. Thus,
<literal>'now'</literal> will be converted to a <type>timestamp</type>
constant when the
<command>INSERT</command> is analyzed, and then used in all
invocations of <function>logfunc1</function> during the lifetime
of the session. Needless to say, this isn't what the programmer
wanted. A better idea is to use the <literal>now()</literal> or
<literal>current_timestamp</literal> function.
logfunc1
の場合では、PostgreSQLのメインパーサは、INSERT
を解析する時に、logtable
の対象列の型から'now'
をtimestamp
と解釈しなければならないことを把握しています。
こうして、パーサはINSERT
が解析された時点で'now'
をtimestamp
定数に変換し、その定数値をその後のセッションの有効期間におけるlogfunc1
の全ての呼び出しで使用します。
言うまでもありませんが、これはプログラマが意図した動作ではありません。
now()
またはcurrent_timestamp
関数の使用が優れています。
In the case of <function>logfunc2</function>, the
<productname>PostgreSQL</productname> main parser does not know
what type <literal>'now'</literal> should become and therefore
it returns a data value of type <type>text</type> containing the string
<literal>now</literal>. During the ensuing assignment
to the local variable <varname>curtime</varname>, the
<application>PL/pgSQL</application> interpreter casts this
string to the <type>timestamp</type> type by calling the
<function>textout</function> and <function>timestamp_in</function>
functions for the conversion. So, the computed time stamp is updated
on each execution as the programmer expects. Even though this
happens to work as expected, it's not terribly efficient, so
use of the <literal>now()</literal> function would still be a better idea.
logfunc2
の場合では、PostgreSQLのメインパーサは'now'
の型を決定することができません。
そのため、now
という文字列を持つtext
型のデータ値を返します。
curtime
ローカル変数に代入する時に、PL/pgSQLインタプリタはこの文字列をtextout
とtimestamp_in
関数を変換に使用してtimestamp
型にキャストします。
ですから、演算されたタイムスタンプは、プログラマが意図した通り、実行の度に更新されます。
この方法でたまたま意図した通り動くけれど、それほど効率的ではありません。
ですから、now()
関数の使用の方が優れています。