PostgreSQL 可以讓使用者自行定義的函數除了 SQL 和 C 之外還能用其他語言編寫。這些其他語言通常稱為程序語言(PL)。對於用程序語言編寫的函數,資料庫伺服器並沒有關於如何解釋函數原始程式碼的能力。所以相關的任務會被傳遞給一個瞭解語言細節的特殊處理程序來處理。處理程序可以自己完成內容過濾,語法分析,程序執行等所有工作,也可以作為 PostgreSQL 與現有程序語言實作之間的「粘合劑」。處理程序本身是一個 C 語言函數,編譯成一個共享物件並按需要載入,就像任何其他 C 函數一樣。
目前標準的 PostgreSQL 發行版中有四種可用的程序語言:PL/pgSQL(第 43 章),PL/Tcl(第 44 章),PL/Perl(第 45 章)和 PL/Python(第 46 章)。 還有其他可用的程序語言未包含在主要發行版中。附錄 H 包含相關的其他訊息。此外,使用者可以定義其他語言;第 56 章介紹了開發新程序語言的基礎知識。
A procedural language must be “installed” into each database where it is to be used. But procedural languages installed in the database template1
are automatically available in all subsequently created databases, since their entries in template1
will be copied by CREATE DATABASE
. So the database administrator can decide which languages are available in which databases and can make some languages available by default if desired.
For the languages supplied with the standard distribution, it is only necessary to execute CREATE EXTENSION
language_name
to install the language into the current database. The manual procedure described below is only recommended for installing languages that have not been packaged as extensions.
Manual Procedural Language Installation
A procedural language is installed in a database in five steps, which must be carried out by a database superuser. In most cases the required SQL commands should be packaged as the installation script of an “extension”, so that CREATE EXTENSION
can be used to execute them.
The shared object for the language handler must be compiled and installed into an appropriate library directory. This works in the same way as building and installing modules with regular user-defined C functions does; see Section 38.10.5. Often, the language handler will depend on an external library that provides the actual programming language engine; if so, that must be installed as well.
The handler must be declared with the command
The special return type of language_handler
tells the database system that this function does not return one of the defined SQL data types and is not directly usable in SQL statements.
Optionally, the language handler can provide an “inline” handler function that executes anonymous code blocks (DO commands) written in this language. If an inline handler function is provided by the language, declare it with a command like
Optionally, the language handler can provide a “validator” function that checks a function definition for correctness without actually executing it. The validator function is called by CREATE FUNCTION
if it exists. If a validator function is provided by the language, declare it with a command like
Finally, the PL must be declared with the command
The optional key word TRUSTED
specifies that the language does not grant access to data that the user would not otherwise have. Trusted languages are designed for ordinary database users (those without superuser privilege) and allows them to safely create functions and procedures. Since PL functions are executed inside the database server, the TRUSTED
flag should only be given for languages that do not allow access to database server internals or the file system. The languages PL/pgSQL, PL/Tcl, and PL/Perl are considered trusted; the languages PL/TclU, PL/PerlU, and PL/PythonU are designed to provide unlimited functionality and should not be marked trusted.
Example 42.1 shows how the manual installation procedure would work with the language PL/Perl.
Example 42.1. Manual Installation of PL/Perl
The following command tells the database server where to find the shared object for the PL/Perl language's call handler function:
PL/Perl has an inline handler function and a validator function, so we declare those too:
The command:
then defines that the previously declared functions should be invoked for functions and procedures where the language attribute is plperl
.\
In a default PostgreSQL installation, the handler for the PL/pgSQL language is built and installed into the “library” directory; furthermore, the PL/pgSQL language itself is installed in all databases. If Tclsupport is configured in, the handlers for PL/Tcl and PL/TclU are built and installed in the library directory, but the language itself is not installed in any database by default. Likewise, the PL/Perl and PL/PerlU handlers are built and installed if Perl support is configured, and the PL/PythonU handler is installed if Python support is configured, but these languages are not installed by default.
本節討論一些實作的細節,這些細節通常對於 PL/pgSQL 使用者來說很重要。
PL/pgSQL 函數中的 SQL 語句和表示式可以引用函數的變數和參數。在後端處理時,PL/pgSQL 會將查詢參數代換為資料內容的引用。僅在語法上允許使用參數或欄位引用的位置代換參數。有一個極端的情況,請參考以下不良程式風格的範例:
從語法上講,第一個出現的 foo 必須是一個資料表名稱,因此即使該函數具有一個名為 foo 的變數,也不能將其代換。第二個出現的 foo 必須是資料表的欄位名稱,因此也不會被代換。 只有第三次出現的 foo 才可以引用該函數的變數。
提醒 版本 9.0 之前的 PostgreSQL 會在所有這三種情況下都嘗試代換該變數,從而導致語法錯誤。
由於變數的名稱在語法上與資料表欄位的名稱沒有差別,因此在引用資料表的語句中可能存在歧義:給予的名稱是要引用資料表欄位還是變數? 我們將前面的範例更改為
在這裡,dest 和 src 必須是資料表名稱,col 必須是 dest 的欄位,但是 foo 和 bar 可能合理地是函數的變數或 src 的欄位。
預設情況下,如果 SQL 語句中的名稱可以引用變數或資料表欄位,則 PL/pgSQL 將回報錯誤。您可以透過重新命名變數或欄位,限定引用或告訴 PL/pgSQL 偏好哪種解釋來解決此問題。
最簡單的解決方案是重新命名變數或欄位。常見的命名規則是對 PL/pgSQL 變數使用與對欄位名不同的命名約定。例如,如果您一致地命名函數變數 v_something,而您的欄位名稱都不以 v_ 開頭,就絕對不會發生衝突。
或者,您可以限定模糊的引用以使其變得清楚。在上面的範例中,src.foo 將是對資料表欄位的明確引用。要建立對變數的明確引用,請在帶標籤的區塊中對其進行宣告,並使用該區塊的標籤(請參閱第 42.2 節)。例如,
即使在 src 中有欄位 foo,block.foo 也還是會被認定為變數。函數參數以及諸如 FOUND 之類的特殊變數可以透過函數名稱來限定,因為它們是在標有函數名稱的外部區塊中隱含宣告的。
有時在大量的 PL/pgSQL 程式中修復所有模棱兩可的引用是不切實際的。在這種情況下,您可以指定 PL/pgSQL 應該將歧義引用解析為變數(與 PostgreSQL 9.0 之前的 PL/pgSQL 行為相容)或資料表欄位(與 Oracle 這樣的系統相容)。
要在系統範圍內變更行為,請將組態參數 plpgsql.variable_conflict 設定為 error、use_variable 或 use_column(其中 error 是預設設定)之一。 此參數影響 PL/pgSQL 函數中語句的後續編譯,但不影響目前連線中已編譯的語句。由於變更此設定可能會導致 PL/pgSQL 函數的行為發生意外變更,因此只能由超級使用者變更。
您還可以透過在函數內容的開頭插入以下特殊命令之一來達到逐個函數的設定行為:
這些命令僅影響它們所在的函數,並覆蓋 plpgsql.variable_conflict 的設定。範例如下
在 UPDATE 指令中,無論使用者是否具有這些名稱的欄位,curtime、comment 和 id 將引用該函數的變數和參數。注意,我們必須在 WHERE 子句中限定對 users.id 的引用,以使其引用資料表欄位。但是我們不必將引用的註釋限定為 UPDATE 列表中的標的,因為在語法上必須是使用者的欄位。我們可以這樣撰寫相同的函數,而毋需依賴 variable_conflict 設定:
給予 EXECUTE 或其等效的指令字串中不會發生變數代換。如果您需要在這樣的命令中插入變化的值,則應在建構字串的過程中進行,或使用 USING,如第 42.5.4 節中所示。
目前,變數代換僅在 SELECT、INSERT、UPDATE 和 DELETE 指令中有作用,因為主要的 SQL 引擎僅在這些指令中允許查詢參數。要在其他語句類型(通常稱為工具程序語句 utility statements)中使用非常數的名稱或值,必須將工具程序語句建構為字串再使用 EXECUTE。
The PL/pgSQL 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 PL/pgSQL statement structure, but individual SQL expressions and SQL commands used in the function are not translated immediately.
As each expression and SQL command is first executed in the function, the PL/pgSQL interpreter parses and analyzes the command to create a prepared statement, using the SPI manager's SPI_prepare
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.)
PL/pgSQL (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, PL/pgSQL 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 generic 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 PL/pgSQL variables referenced in it. If it is, generating a plan each time is a net win. See PREPARE for more information about the behavior of prepared statements.
Because PL/pgSQL saves prepared statements and sometimes execution plans in this way, SQL commands that appear directly in a PL/pgSQL 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 PL/pgSQL EXECUTE
statement — at the price of performing new parse analysis and constructing a new execution plan on every execution.
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. EXECUTE
can be used to get around this problem when necessary.
If the same function is used as a trigger for more than one table, PL/pgSQL 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 key
even if it happens to have different types in different tables.
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:
and:
In the case of logfunc1
, the PostgreSQL main parser knows when analyzing the INSERT
that the string 'now'
should be interpreted as timestamp
, because the target column of logtable
is of that type. Thus, 'now'
will be converted to a timestamp
constant when the INSERT
is analyzed, and then used in all invocations of logfunc1
during the lifetime of the session. Needless to say, this isn't what the programmer wanted. A better idea is to use the now()
or current_timestamp
function.
In the case of logfunc2
, the PostgreSQL main parser does not know what type 'now'
should become and therefore it returns a data value of type text
containing the string now
. During the ensuing assignment to the local variable curtime
, the PL/pgSQL interpreter casts this string to the timestamp
type by calling the text_out
and timestamp_in
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 now()
function would still be a better idea.
In this section and the following ones, we describe all the statement types that are explicitly understood by PL/pgSQL. Anything not recognized as one of these statement types is presumed to be an SQL command and is sent to the main database engine to execute, as described in Section 42.5.2 and Section 42.5.3.
An assignment of a value to a PL/pgSQL variable is written as:
As explained previously, the expression in such a statement is evaluated by means of an SQL SELECT
command sent to the main database engine. The expression must yield a single value (possibly a row value, if the variable is a row or record variable). The target variable can be a simple variable (optionally qualified with a block name), a field of a row or record variable, or an element of an array that is a simple variable or field. Equal (=
) can be used instead of PL/SQL-compliant :=
.
If the expression's result data type doesn't match the variable's data type, the value will be coerced as though by an assignment cast (see Section 10.4). If no assignment cast is known for the pair of data types involved, the PL/pgSQL interpreter will attempt to convert the result value textually, that is by applying the result type's output function followed by the variable type's input function. Note that this could result in run-time errors generated by the input function, if the string form of the result value is not acceptable to the input function.
Examples:
For any SQL command that does not return rows, for example INSERT
without a RETURNING
clause, you can execute the command within a PL/pgSQL function just by writing the command.
Any PL/pgSQL variable name appearing in the command text is treated as a parameter, and then the current value of the variable is provided as the parameter value at run time. This is exactly like the processing described earlier for expressions; for details see Section 42.11.1.
When executing a SQL command in this way, PL/pgSQL may cache and re-use the execution plan for the command, as discussed in Section 42.11.2.
Sometimes it is useful to evaluate an expression or SELECT
query but discard the result, for example when calling a function that has side-effects but no useful result value. To do this in PL/pgSQL, use the PERFORM
statement:
This executes query
and discards the result. Write the query
the same way you would write an SQL SELECT
command, but replace the initial keyword SELECT
with PERFORM
. For WITH
queries, use PERFORM
and then place the query in parentheses. (In this case, the query can only return one row.) PL/pgSQL variables will be substituted into the query just as for commands that return no result, and the plan is cached in the same way. Also, the special variable FOUND
is set to true if the query produced at least one row, or false if it produced no rows (see Section 42.5.5).
One might expect that writing SELECT
directly would accomplish this result, but at present the only accepted way to do it is PERFORM
. A SQL command that can return rows, such as SELECT
, will be rejected as an error unless it has an INTO
clause as discussed in the next section.
An example:
The result of a SQL command yielding a single row (possibly of multiple columns) can be assigned to a record variable, row-type variable, or list of scalar variables. This is done by writing the base SQL command and adding an INTO
clause. For example,
where target
can be a record variable, a row variable, or a comma-separated list of simple variables and record/row fields. PL/pgSQL variables will be substituted into the rest of the query, and the plan is cached, just as described above for commands that do not return rows. This works for SELECT
, INSERT
/UPDATE
/DELETE
with RETURNING
, and utility commands that return row-set results (such as EXPLAIN
). Except for the INTO
clause, the SQL command is the same as it would be written outside PL/pgSQL.
Note that this interpretation of SELECT
with INTO
is quite different from PostgreSQL's regular SELECT INTO
command, wherein the INTO
target is a newly created table. If you want to create a table from a SELECT
result inside a PL/pgSQL function, use the syntax CREATE TABLE ... AS SELECT
.
If a row or a variable list is used as target, the query's result columns must exactly match the structure of the target as to number and data types, or else a run-time error occurs. When a record variable is the target, it automatically configures itself to the row type of the query result columns.
The INTO
clause can appear almost anywhere in the SQL command. Customarily it is written either just before or just after the list of select_expressions
in a SELECT
command, or at the end of the command for other command types. It is recommended that you follow this convention in case the PL/pgSQL parser becomes stricter in future versions.
If STRICT
is not specified in the INTO
clause, then target
will be set to the first row returned by the query, or to nulls if the query returned no rows. (Note that “the first row” is not well-defined unless you've used ORDER BY
.) Any result rows after the first row are discarded. You can check the special FOUND
variable (see Section 42.5.5) to determine whether a row was returned:
If the STRICT
option is specified, the query must return exactly one row or a run-time error will be reported, either NO_DATA_FOUND
(no rows) or TOO_MANY_ROWS
(more than one row). You can use an exception block if you wish to catch the error, for example:
Successful execution of a command with STRICT
always sets FOUND
to true.
For INSERT
/UPDATE
/DELETE
with RETURNING
, PL/pgSQL reports an error for more than one returned row, even when STRICT
is not specified. This is because there is no option such as ORDER BY
with which to determine which affected row should be returned.
If print_strict_params
is enabled for the function, then when an error is thrown because the requirements of STRICT
are not met, the DETAIL
part of the error message will include information about the parameters passed to the query. You can change the print_strict_params
setting for all functions by setting plpgsql.print_strict_params
, though only subsequent function compilations will be affected. You can also enable it on a per-function basis by using a compiler option, for example:
On failure, this function might produce an error message such as
The STRICT
option matches the behavior of Oracle PL/SQL's SELECT INTO
and related statements.
To handle cases where you need to process multiple result rows from a SQL query, see Section 42.6.6.
Oftentimes you will want to generate dynamic commands inside your PL/pgSQL functions, that is, commands that will involve different tables or different data types each time they are executed. PL/pgSQL's normal attempts to cache plans for commands (as discussed in Section 42.11.2) will not work in such scenarios. To handle this sort of problem, the EXECUTE
statement is provided:
where command-string
is an expression yielding a string (of type text
) containing the command to be executed. The optional target
is a record variable, a row variable, or a comma-separated list of simple variables and record/row fields, into which the results of the command will be stored. The optional USING
expressions supply values to be inserted into the command.
No substitution of PL/pgSQL variables is done on the computed command string. Any required variable values must be inserted in the command string as it is constructed; or you can use parameters as described below.
Also, there is no plan caching for commands executed via EXECUTE
. Instead, the command is always planned each time the statement is run. Thus the command string can be dynamically created within the function to perform actions on different tables and columns.
The INTO
clause specifies where the results of a SQL command returning rows should be assigned. If a row or variable list is provided, it must exactly match the structure of the query's results (when a record variable is used, it will configure itself to match the result structure automatically). If multiple rows are returned, only the first will be assigned to the INTO
variable. If no rows are returned, NULL is assigned to the INTO
variable(s). If no INTO
clause is specified, the query results are discarded.
If the STRICT
option is given, an error is reported unless the query produces exactly one row.
The command string can use parameter values, which are referenced in the command as $1
, $2
, etc. These symbols refer to values supplied in the USING
clause. This method is often preferable to inserting data values into the command string as text: it avoids run-time overhead of converting the values to text and back, and it is much less prone to SQL-injection attacks since there is no need for quoting or escaping. An example is:
Note that parameter symbols can only be used for data values — if you want to use dynamically determined table or column names, you must insert them into the command string textually. For example, if the preceding query needed to be done against a dynamically selected table, you could do this:
A cleaner approach is to use format()
's %I
specification for table or column names (strings separated by a newline are concatenated):
Another restriction on parameter symbols is that they only work in SELECT
, INSERT
, UPDATE
, and DELETE
commands. In other statement types (generically called utility statements), you must insert values textually even if they are just data values.
An EXECUTE
with a simple constant command string and some USING
parameters, as in the first example above, is functionally equivalent to just writing the command directly in PL/pgSQL and allowing replacement of PL/pgSQL variables to happen automatically. The important difference is that EXECUTE
will re-plan the command on each execution, generating a plan that is specific to the current parameter values; whereas PL/pgSQL may otherwise create a generic plan and cache it for re-use. In situations where the best plan depends strongly on the parameter values, it can be helpful to use EXECUTE
to positively ensure that a generic plan is not selected.
SELECT INTO
is not currently supported within EXECUTE
; instead, execute a plain SELECT
command and specify INTO
as part of the EXECUTE
itself.
The PL/pgSQL EXECUTE
statement is not related to the EXECUTE SQL statement supported by the PostgreSQL server. The server's EXECUTE
statement cannot be used directly within PL/pgSQL functions (and is not needed).
When working with dynamic commands you will often have to handle escaping of single quotes. The recommended method for quoting fixed text in your function body is dollar quoting. (If you have legacy code that does not use dollar quoting, please refer to the overview in Section 42.12.1, which can save you some effort when translating said code to a more reasonable scheme.)
Dynamic values require careful handling since they might contain quote characters. An example using format()
(this assumes that you are dollar quoting the function body so quote marks need not be doubled):
It is also possible to call the quoting functions directly:
This example demonstrates the use of the quote_ident
and quote_literal
functions (see Section 9.4). For safety, expressions containing column or table identifiers should be passed through quote_ident
before insertion in a dynamic query. Expressions containing values that should be literal strings in the constructed command should be passed through quote_literal
. These functions take the appropriate steps to return the input text enclosed in double or single quotes respectively, with any embedded special characters properly escaped.
Because quote_literal
is labeled STRICT
, it will always return null when called with a null argument. In the above example, if newvalue
or keyvalue
were null, the entire dynamic query string would become null, leading to an error from EXECUTE
. You can avoid this problem by using the quote_nullable
function, which works the same as quote_literal
except that when called with a null argument it returns the string NULL
. For example,
If you are dealing with values that might be null, you should usually use quote_nullable
in place of quote_literal
.
As always, care must be taken to ensure that null values in a query do not deliver unintended results. For example the WHERE
clause
will never succeed if keyvalue
is null, because the result of using the equality operator =
with a null operand is always null. If you wish null to work like an ordinary key value, you would need to rewrite the above as
(At present, IS NOT DISTINCT FROM
is handled much less efficiently than =
, so don't do this unless you must. See Section 9.2 for more information on nulls and IS DISTINCT
.)
Note that dollar quoting is only useful for quoting fixed text. It would be a very bad idea to try to write this example as:
because it would break if the contents of newvalue
happened to contain $$
. The same objection would apply to any other dollar-quoting delimiter you might pick. So, to safely quote text that is not known in advance, you must use quote_literal
, quote_nullable
, or quote_ident
, as appropriate.
Dynamic SQL statements can also be safely constructed using the format
function (see Section 9.4.1). For example:
%I
is equivalent to quote_ident
, and %L
is equivalent to quote_nullable
. The format
function can be used in conjunction with the USING
clause:
This form is better because the variables are handled in their native data type format, rather than unconditionally converting them to text and quoting them via %L
. It is also more efficient.\
A much larger example of a dynamic command and EXECUTE
can be seen in Example 42.10, which builds and executes a CREATE FUNCTION
command to define a new function.
There are several ways to determine the effect of a command. The first method is to use the GET DIAGNOSTICS
command, which has the form:
This command allows retrieval of system status indicators. CURRENT
is a noise word (but see also GET STACKED DIAGNOSTICS
in Section 42.6.8.1). Each item
is a key word identifying a status value to be assigned to the specified variable
(which should be of the right data type to receive it). The currently available status items are shown in Table 42.1. Colon-equal (:=
) can be used instead of the SQL-standard =
token. An example:
The second method to determine the effects of a command is to check the special variable named FOUND
, which is of type boolean
. FOUND
starts out false within each PL/pgSQL function call. It is set by each of the following types of statements:
A SELECT INTO
statement sets FOUND
true if a row is assigned, false if no row is returned.
A PERFORM
statement sets FOUND
true if it produces (and discards) one or more rows, false if no row is produced.
UPDATE
, INSERT
, and DELETE
statements set FOUND
true if at least one row is affected, false if no row is affected.
A FETCH
statement sets FOUND
true if it returns a row, false if no row is returned.
A MOVE
statement sets FOUND
true if it successfully repositions the cursor, false otherwise.
A FOR
or FOREACH
statement sets FOUND
true if it iterates one or more times, else false. FOUND
is set this way when the loop exits; inside the execution of the loop, FOUND
is not modified by the loop statement, although it might be changed by the execution of other statements within the loop body.
RETURN QUERY
and RETURN QUERY EXECUTE
statements set FOUND
true if the query returns at least one row, false if no row is returned.
Other PL/pgSQL statements do not change the state of FOUND
. Note in particular that EXECUTE
changes the output of GET DIAGNOSTICS
, but does not change FOUND
.
FOUND
is a local variable within each PL/pgSQL function; any changes to it affect only the current function.
Sometimes a placeholder statement that does nothing is useful. For example, it can indicate that one arm of an if/then/else chain is deliberately empty. For this purpose, use the NULL
statement:
For example, the following two fragments of code are equivalent:
Which is preferable is a matter of taste.
In Oracle's PL/SQL, empty statement lists are not allowed, and so NULL
statements are required for situations such as this. PL/pgSQL allows you to just write nothing, instead.\
Name | Type | Description |
---|---|---|
ROW_COUNT
bigint
the number of rows processed by the most recent SQL command
PG_CONTEXT
text
line(s) of text describing the current call stack (see Section 42.6.9)
Functions written in PL/pgSQL are defined to the server by executing CREATE FUNCTION commands. Such a command would normally look like, say,
The function body is simply a string literal so far as CREATE FUNCTION
is concerned. It is often helpful to use dollar quoting (see Section 4.1.2.4) to write the function body, rather than the normal single quote syntax. Without dollar quoting, any single quotes or backslashes in the function body must be escaped by doubling them. Almost all the examples in this chapter use dollar-quoted literals for their function bodies.
PL/pgSQL is a block-structured language. The complete text of a function body must be a block. A block is defined as:
Each declaration and each statement within a block is terminated by a semicolon. A block that appears within another block must have a semicolon after END
, as shown above; however the final END
that concludes a function body does not require a semicolon.
A common mistake is to write a semicolon immediately after BEGIN
. This is incorrect and will result in a syntax error.
A label
is only needed if you want to identify the block for use in an EXIT
statement, or to qualify the names of the variables declared in the block. If a label is given after END
, it must match the label at the block's beginning.
All key words are case-insensitive. Identifiers are implicitly converted to lower case unless double-quoted, just as they are in ordinary SQL commands.
Comments work the same way in PL/pgSQL code as in ordinary SQL. A double dash (--
) starts a comment that extends to the end of the line. A /*
starts a block comment that extends to the matching occurrence of */
. Block comments nest.
Any statement in the statement section of a block can be a subblock. Subblocks can be used for logical grouping or to localize variables to a small group of statements. Variables declared in a subblock mask any similarly-named variables of outer blocks for the duration of the subblock; but you can access the outer variables anyway if you qualify their names with their block's label. For example:
There is actually a hidden “outer block” surrounding the body of any PL/pgSQL function. This block provides the declarations of the function's parameters (if any), as well as some special variables such as FOUND
(see Section 42.5.5). The outer block is labeled with the function's name, meaning that parameters and special variables can be qualified with the function's name.
It is important not to confuse the use of BEGIN
/END
for grouping statements in PL/pgSQL with the similarly-named SQL commands for transaction control. PL/pgSQL's BEGIN
/END
are only for grouping; they do not start or end a transaction. See Section 42.8 for information on managing transactions in PL/pgSQL. Also, a block containing an EXCEPTION
clause effectively forms a subtransaction that can be rolled back without affecting the outer transaction. For more about that see Section 42.6.8.