+ linkend="plpgsql-statements-executing-dyn">. The list below gives
+ you an overview over the needed levels of quotation marks in
+ various situations. Keep this chart handy.
+
+
+
+
+ 1 quotation mark
+
+ To begin/end function bodies, for example:
+CREATE FUNCTION foo() RETURNS integer AS '...'
+ LANGUAGE plpgsql;
+
+
+
+
+
+
+ 2 quotation marks
+
+ For string literals inside the function body, for example:
+a_output := ''Blah'';
+SELECT * FROM users WHERE f_name=''foobar'';
+
+ The second line is interpreted as
+SELECT * FROM users WHERE f_name='foobar';
+
+
+
+
+
+
+ 4 quotation marks
+
+ When you need a single quote in a string inside the function
+ body, for example:
+a_output := a_output || '' AND name LIKE ''''foobar'''' AND xyz''
+
+ The value of a_output would then be:
+ AND name LIKE 'foobar' AND xyz.
+
+
+
+
+
+ 6 quotation marks
+
+ When a single quote in a string inside the function body is
+ adjacent to the end of that string constant, for example:
+a_output := a_output || '' AND name LIKE ''''foobar''''''
+
+ The value of a_output would then be:
+ AND name LIKE 'foobar'.
+
+
+
+
+
+ 10 quotation marks
+
+ When you want two single quotes in a string constant (which
+ accounts for 8 quotes) and this is adjacent to the end of that
+ string constant (2 more). You will probably only need that if
+ you are writing a function that generates other functions. For
+ example:
+a_output := a_output || '' if v_'' ||
+ referrer_keys.kind || '' like ''''''''''
+ || referrer_keys.key_string || ''''''''''
+ then return '''''' || referrer_keys.referrer_type
+ || ''''''; end if;'';
+
+ The value of a_output would then be:
+if v_... like ''...'' then return ''...''; end if;
+
+
+
+
+
+
+
- structured language. The complete text of a function
- definition must be a block>. A block is defined as:
+
PL/pgSQL is a block-structured language.
+ The complete text of a function definition must be a
+ block>. A block is defined as:
- <<label>>
+ <<label>>
DECLARE
declarations
BEGIN
- Any statement> in the statement section of a block
- can be a sub-block>. Sub-blocks can be used for
+ Each declaration and each statement within a block is terminated
+ by a semicolon.
+
+
+ All key words and identifiers can be written in mixed upper and
+ lower case. Identifiers are implicitly converted to lower-case
+ unless double-quoted.
+
+
+ There are two types of comments in
PL/pgSQL>. A double dash (--)
+ starts a comment that extends to the end of the line. A /*
+ starts a block comment that extends to the next occurrence of */.
+ Block comments cannot be nested, but double dash comments can be
+ enclosed into a block comment and a double dash can hide
+ the block comment delimiters /* and */.
+
+
+ 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.
block are initialized to their default values every time the
block is entered, not only once per function call. For example:
-CREATE FUNCTION somefunc() RETURNS INTEGER AS '
+CREATE FUNCTION somefunc() RETURNS integer AS '
DECLARE
- quantity INTEGER := 30;
+ quantity integer := 30;
BEGIN
- RAISE NOTICE ''Quantity here is %'',quantity; -- Quantity here is 30
- quantity := 50;
- --
- -- Create a sub-block
- --
- DECLARE
- quantity INTEGER := 80;
- BEGIN
- RAISE NOTICE ''Quantity here is %'',quantity; -- Quantity here is 80
- END;
-
- RAISE NOTICE ''Quantity here is %'',quantity; -- Quantity here is 50
-
- RETURN quantity;
+ RAISE NOTICE ''Quantity here is %'', quantity; -- Quantity here is 30
+ quantity := 50;
+ --
+ -- Create a subblock
+ --
+ DECLARE
+ quantity integer := 80;
+ BEGIN
+ RAISE NOTICE ''Quantity here is %'', quantity; -- Quantity here is 80
+ END;
+
+ RAISE NOTICE ''Quantity here is %'', quantity; -- Quantity here is 50
+
+ RETURN quantity;
END;
-' LANGUAGE 'plpgsql';
+' LANGUAGE plpgsql;
- It is important not to confuse the use of BEGIN/END for
+ It is important not to confuse the use of BEGIN>/END> for
grouping statements in
PL/pgSQL> with the database commands for
- transaction control.
PL/pgSQL>'s BEGIN/END are only for grouping;
+ transaction control.
PL/pgSQL>'s BEGIN>/END> are only for grouping;
they do not start or end a transaction. Functions and trigger procedures
are always executed within a transaction established by an outer query
--- they cannot start or commit transactions, since
PostgreSQL does not have nested transactions.
-
-
-
Lexical Details
-
- Each statement and declaration within a block is terminated
- by a semicolon.
-
-
- All keywords and identifiers can be written in mixed upper- and
- lower-case. Identifiers are implicitly converted to lower-case
- unless double-quoted.
-
-
- There are two types of comments in
PL/pgSQL>. A double dash --
- starts a comment that extends to the end of the line. A /*
- starts a block comment that extends to the next occurrence of */.
- Block comments cannot be nested, but double dash comments can be
- enclosed into a block comment and a double dash can hide
- the block comment delimiters /* and */.
-
-
Declarations
- All variables, rows and records used in a block must be declared in the
+ All variables used in a block must be declared in the
declarations section of the block.
- (The only exception is that the loop variable of a FOR loop iterating
+ (The only exception is that the loop variable of a FOR> loop iterating
over a range of integer values is automatically declared as an integer
variable.)
PL/pgSQL> variables can have any SQL data type, such as
- INTEGER, VARCHAR and
- CHAR.
+ integer, varchar, and
+ char.
Here are some examples of variable declarations:
-user_id INTEGER;
-quantity NUMERIC(5);
-url VARCHAR;
+user_id integer;
+quantity numeric(5);
+url varchar;
myrow tablename%ROWTYPE;
-myfield tablename.fieldname%TYPE;
+myfield tablename.columnname%TYPE;
arow RECORD;
name CONSTANT type NOT NULL { DEFAULT | := } expression ;
-
-
- The DEFAULT clause, if given, specifies the initial value assigned
- to the variable when the block is entered. If the DEFAULT clause
+ The DEFAULT> clause, if given, specifies the initial value assigned
+ to the variable when the block is entered. If the DEFAULT> clause
is not given then the variable is initialized to the
-
-
- The CONSTANT option prevents the variable from being assigned to,
+ The CONSTANT> option prevents the variable from being assigned to,
so that its value remains constant for the duration of the block.
- If NOT NULL
- is specified, an assignment of a NULL value results in a run-time
- error. All variables declared as NOT NULL
- must have a non-NULL default value specified.
+ If NOT NULL>
+ is specified, an assignment of a null value results in a run-time
+ error. All variables declared as NOT NULL>
+ must have a nonnull default value specified.
The default value is evaluated every time the block is entered. So,
- for example, assigning 'now' to a variable of type
+ for example, assigning 'now' to a variable of type
timestamp causes the variable to have the
- time of the current function call, not when the function was
+ time of the current function call, not the time when the function was
precompiled.
Examples:
-quantity INTEGER DEFAULT 32;
+quantity integer DEFAULT 32;
url varchar := ''http://mysite.com'';
-user_id CONSTANT INTEGER := 10;
+user_id CONSTANT integer := 10;
Aliases for Function Parameters
-name ALIAS FOR $n;
+name ALIAS FOR $n;
-
Parameters passed to functions are named with the identifiers
$1, $2,
- etc. Optionally, aliases can be declared for $n
+ etc. Optionally, aliases can be declared for $n
parameter names for increased readability. Either the alias or the
numeric identifier can then be used to refer to the parameter value.
Some examples:
-CREATE FUNCTION sales_tax(REAL) RETURNS REAL AS '
+CREATE FUNCTION sales_tax(real) RETURNS real AS '
DECLARE
subtotal ALIAS FOR $1;
BEGIN
- return subtotal * 0.06;
+ RETURN subtotal * 0.06;
END;
-' LANGUAGE 'plpgsql';
+' LANGUAGE plpgsql;
-CREATE FUNCTION instr(VARCHAR,INTEGER) RETURNS INTEGER AS '
+CREATE FUNCTION instr(varchar, integer) RETURNS integer AS '
DECLARE
v_string ALIAS FOR $1;
index ALIAS FOR $2;
BEGIN
- -- Some computations here
+ -- some computations here
END;
-' LANGUAGE 'plpgsql';
+' LANGUAGE plpgsql;
-CREATE FUNCTION use_many_fields(tablename) RETURNS TEXT AS '
+CREATE FUNCTION use_many_fields(tablename) RETURNS text AS '
DECLARE
in_t ALIAS FOR $1;
BEGIN
RETURN in_t.f1 || in_t.f3 || in_t.f5 || in_t.f7;
END;
-' LANGUAGE 'plpgsql';
+' LANGUAGE plpgsql;
+
+
Copying Types
+
+
+variable%TYPE
+
+
+ %TYPE provides the data type of a variable or
+ table column. You can use this to declare variables that will hold
+ database values. For example, let's say you have a column named
+ user_id in your users
+ table. To declare a variable with the same data type as
+ users.user_id> you write:
+user_id users.user_id%TYPE;
+
+
+
+ By using %TYPE you don't need to know the data
+ type of the structure you are referencing, and most importantly,
+ if the data type of the referenced item changes in the future (for
+ instance: you change the type of user_id>
+ from integer to real), you may not need
+ to change your function definition.
+
+
+
Row Types
name tablename%ROWTYPE;
-
A variable of a composite type is called a row>
- variable (or row-type> variable). Such a variable can hold a
- whole row of a SELECT or FOR
- query result, so long as that query's column set matches the declared
- type of the variable. The individual fields of the row value are
- accessed using the usual dot notation, for example
+ variable (or row-type> variable). Such a variable
+ can hold a whole row of a SELECT> or FOR>
+ query result, so long as that query's column set matches the
+ declared type of the variable.
+ tablename must be an existing table or
+ view name in the database. The individual fields of the row value
+ are accessed using the usual dot notation, for example
rowvar.field.
Parameters to a function can be
composite types (complete table rows). In that case, the
- corresponding identifier $n will be a row variable, and fields can
+ corresponding identifier $n> will be a row variable, and fields can
be selected from it, for example $1.user_id.
- Only the user-defined attributes of a table row are accessible in a
- row-type variable, not OID or other system attributes (because the
+ Only the user-defined columns of a table row are accessible in a
+ row-type variable, not the OID or other system columns (because the
row could be from a view). The fields of the row type inherit the
table's field size or precision for data types such as
- char(n).
+ char(n>).
+
+
+ Here is an example of using composite types:
-CREATE FUNCTION use_two_tables(tablename) RETURNS TEXT AS '
+CREATE FUNCTION use_two_tables(tablename) RETURNS text AS '
DECLARE
in_t ALIAS FOR $1;
use_t table2name%ROWTYPE;
SELECT * INTO use_t FROM table2name WHERE ... ;
RETURN in_t.f1 || use_t.f3 || in_t.f5 || use_t.f7;
END;
-' LANGUAGE 'plpgsql';
+' LANGUAGE plpgsql;
-
Records
+
Record Types
Record variables are similar to row-type variables, but they have no
predefined structure. They take on the actual row structure of the
- row they are assigned during a SELECT or FOR command. The substructure
+ row they are assigned during a SELECT> or FOR> command. The substructure
of a record variable can change each time it is assigned to.
A consequence of this is that until a record variable is first assigned
- to, it has no> substructure, and any attempt to access a
+ to, it has no substructure, and any attempt to access a
field in it will draw a run-time error.
-
-
Attributes
-
- Using the %TYPE and %ROWTYPE
- attributes, you can declare variables with the same
- data type or structure as another database item (e.g: a
- table field).
-
-
-
-
-
- variable%TYPE
-
-
- %TYPE provides the data type of a
- variable or database column. You can use this to
- declare variables that will hold database
- values. For example, let's say you have a column
- named user_id in your
- users table. To declare a variable with
- the same data type as users>.user_id> you write:
-user_id users.user_id%TYPE;
-
-
-
- By using %TYPE you do not need to know
- the data type of the structure you are referencing,
- and most important, if the data type of the
- referenced item changes in the future (e.g: you
- change your table definition of user_id from INTEGER to
- REAL), you may not need to change your function
- definition.
-
-
-
-
-
-
- table%ROWTYPE
-
-
- %ROWTYPE provides the composite data type corresponding
- to a whole row of the specified table.
- table must be an existing
- table or view name of the database.
-
-
-DECLARE
- users_rec users%ROWTYPE;
- user_id users.user_id%TYPE;
-BEGIN
- user_id := users_rec.user_id;
- ...
-
-CREATE FUNCTION does_view_exist(INTEGER) RETURNS bool AS '
- DECLARE
- key ALIAS FOR $1;
- table_data cs_materialized_views%ROWTYPE;
- BEGIN
- SELECT INTO table_data * FROM cs_materialized_views
- WHERE sort_key=key;
-
- IF NOT FOUND THEN
- RETURN false;
- END IF;
- RETURN true;
- END;
-' LANGUAGE 'plpgsql';
-
-
-
-
-
-
-
RENAME
+
RENAME>
statements are processed using the server's regular
SQL executor. Expressions that appear to
contain constants may in fact require run-time evaluation
- (e.g. 'now' for the timestamp
+ (e.g., 'now' for the timestamp
type) so it is impossible for the
PL/pgSQL parser to identify real
- constant values other than the NULL keyword. All expressions are
+ constant values other than the key word NULL>. All expressions are
evaluated internally by executing a query
SELECT expression
- using the
SPI manager.
In the expression,
+ using the
SPI manager.
For evaluation,
occurrences of
PL/pgSQL variable
- identifiers are replaced by parameters and the actual values from
+ identifiers are replaced by parameters, and the actual values from
the variables are passed to the executor in the parameter array.
This allows the query plan for the SELECT to
- be prepared just once and then re-used for subsequent
+ be prepared just once and then reused for subsequent
evaluations.
is a difference between what these two functions do:
-CREATE FUNCTION logfunc1 (TEXT) RETURNS TIMESTAMP AS '
+CREATE FUNCTION logfunc1(text) RETURNS timestamp AS '
DECLARE
logtxt ALIAS FOR $1;
BEGIN
INSERT INTO logtable VALUES (logtxt, ''now'');
RETURN ''now'';
END;
-' LANGUAGE 'plpgsql';
+' LANGUAGE plpgsql;
and
-CREATE FUNCTION logfunc2 (TEXT) RETURNS TIMESTAMP AS '
+CREATE FUNCTION logfunc2(text) RETURNS timestamp AS '
DECLARE
logtxt ALIAS FOR $1;
curtime timestamp;
INSERT INTO logtable VALUES (logtxt, curtime);
RETURN curtime;
END;
-' LANGUAGE 'plpgsql';
+' LANGUAGE plpgsql;
+
- In the case of logfunc1(), the
+ In the case of logfunc1, the
PostgreSQL main parser knows when
- preparing the plan for the INSERT, that the string
+ preparing the plan for the INSERT, that the string
'now' should be interpreted as
- timestamp because the target field of logtable
+ timestamp because the target column of logtable
is of that type. Thus, it will make a constant from it at this
time and this constant value is then used in all invocations of
- logfunc1() during the lifetime of the
- backend. Needless to say that this isn't what the
+ logfunc1 during the lifetime of the
+ session. Needless to say that this isn't what the
programmer wanted.
- In the case of logfunc2(), the
+ 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
+ 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()
+ text_out and timestamp_in
functions for the conversion. So, the computed time stamp is updated
on each execution as the programmer expects.
types that are explicitly understood by
Anything not recognized as one of these statement types is presumed
- to be an SQL query, and is sent to the main database engine to execute
- (after substitution
for any
PL/pgSQL variables
+ to be an SQL command and is sent to the main database engine to execute
+ (after substitution
of any
PL/pgSQL variables
used in the statement). Thus,
- for example, SQL INSERT>, UPDATE>, and
- DELETE> commands may be considered to be statements of
-
PL/pgSQL. But they are not specifically
+ for example, the SQL commands INSERT>, UPDATE>, and
+ DELETE> may be considered to be statements of
+
PL/pgSQL, but they are not specifically
listed here.
-
SELECT INTO
+
SELECT INTO
- The result of a SELECT command yielding multiple columns (but
+ The result of a SELECT command yielding multiple columns (but
only one row) can be assigned to a record variable, row-type
variable, or list of scalar variables. This is done by:
where target can be a record variable, a row
variable, or a comma-separated list of simple variables and
- record/row fields. Note that this is quite different from
-
PostgreSQL>'s normal interpretation of SELECT INTO, which is that 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.)
+ record/row fields.
+
+
+ Note that this is quite different from
+
PostgreSQL>'s normal interpretation of
+ SELECT INTO, where 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 selected values
- must exactly match the structure of the target(s), or a run-time error
+ must exactly match the structure of the target, or 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.
- Except for the INTO clause, the SELECT statement is the same as a normal
- SQL SELECT query and can use the full power of SELECT.
+ Except for the INTO> clause, the SELECT>
+ statement is the same as a normal SQL SELECT> command
+ and can use its full power.
- If the SELECT query returns zero rows, null values are assigned to the
- target(s). If the SELECT query returns multiple rows, the first
+ If the query returns zero rows, null values are assigned to the
+ target(s). If the query returns multiple rows, the first
row is assigned to the target(s) and the rest are discarded.
(Note that the first row> is not well-defined unless you've
- used ORDER BY.)
+ used ORDER BY>.)
- At present, the INTO clause can appear almost anywhere in the SELECT
- query, but it is recommended to place it immediately after the SELECT
- keyword as depicted above. Future versions of
+ At present, the INTO> clause can appear almost anywhere in the SELECT
+ statement, but it is recommended to place it immediately after the SELECT
+ key word as depicted above. Future versions of
PL/pgSQL may be less forgiving about
- placement of the INTO clause.
+ placement of the INTO clause.
- You can use FOUND immediately after a SELECT
- INTO statement to determine whether the assignment was successful
- (that is, at least one row was was returned by the SELECT
- statement). For example:
+ You can use FOUND immediately after a SELECT
+ INTO statement to determine whether the assignment was successful
+ (that is, at least one row was was returned by the query). For example:
-SELECT INTO myrec * FROM EMP WHERE empname = myname;
+SELECT INTO myrec * FROM emp WHERE empname = myname;
IF NOT FOUND THEN
RAISE EXCEPTION ''employee % not found'', myname;
END IF;
-
- Alternatively, you can use the IS NULL (or ISNULL>) conditional to
- test for whether a RECORD/ROW result is null. Note that there is no
- way to tell whether any additional rows might have been discarded.
+ To test for whether a record/row result is null, you can use the
+ IS NULL conditional. There is, however, no
+ way to tell whether any additional rows might have been
+ discarded. Here is an example that handles the case where no
+ rows have been returned:
DECLARE
users_rec RECORD;
IF users_rec.homepage IS NULL THEN
-- user entered no homepage, return "http://"
-
RETURN ''http://'';
END IF;
END;
-
Executing an expression or query with no result
+
Executing an Expression or Query With No Result
Sometimes one wishes to evaluate an expression or query but
PERFORM query;
- This executes a SELECT
- <replaceable>query and discards the
+ This executes query, which must be a
+ <command>SELECT statement, and discards the
result.
PL/pgSQL variables are
substituted in the query as usual. Also, the special variable
FOUND is set to true if the query produced at
- least one row, or false if it produced no rows.
+ least one row or false if it produced no rows.
- One might expect that SELECT with no INTO
- clause would accomplish this result, but at present the only
- accepted way to do it is PERFORM.
-
-
+ One might expect that SELECT with no
+ INTO> clause would accomplish this result, but at
+ present the only accepted way to do it is
+ PERFORM.
+
+
An example:
- -queries">
-
Executing dynamic queries
+
+
Executing Dynamic Commands
- Oftentimes you will want to generate dynamic queries inside your
-
PL/pgSQL functions, that is,
queries
+ 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 queries will not work in such
+ normal attempts to cache plans for commands will not work in such
scenarios. To handle this sort of problem, the
EXECUTE statement is provided:
-EXECUTE query-string;
+EXECUTE command-string;
- where query-string is an expression
+ where command-string is an expression
yielding a string (of type
- text) containing the query
+ text) containing the command
to be executed. This string is fed literally to the SQL engine.
Note in particular that no substitution of
PL/pgSQL>
- variables is done on the query string. The values of variables must
- be inserted in the query string as it is constructed.
+ variables is done on the command string. The values of variables must
+ be inserted in the command string as it is constructed.
- When working with dynamic queries you will have to face
+ When working with dynamic commands you will have to face
escaping of single quotes in
PL/pgSQL>. Please refer to the
- table in
- for a detailed explanation that will save you some effort.
+ overview in ,
+ which can save you some effort.
- Unlike all other queries in
PL/pgSQL>, a
- query run by an
- EXECUTE statement is not prepared and saved
- just once during the life of the server. Instead, the
- query is prepared each time the
- statement is run. The query-string can
- be dynamically created within the procedure to perform actions on
- variable tables and fields.
+ Unlike all other commands in
PL/pgSQL>, a command
+ run by an EXECUTE statement is not prepared
+ and saved just once during the life of the session. Instead, the
+ command is prepared each time the statement is run. The command
+ string can be dynamically created within the function to perform
+ actions on variable tables and columns.
- The results from SELECT queries are discarded
+ The results from SELECT commands are discarded
by EXECUTE, and SELECT INTO
is not currently supported within EXECUTE.
So, the only way to extract a result from a dynamically-created
- SELECT is to use the FOR-IN-EXECUTE form
+ SELECT is to use the FOR-IN-EXECUTE> form
described later.
An example:
-
EXECUTE ''UPDATE tbl SET ''
- || quote_ident(fieldname)
+ || quote_ident(colname)
|| '' = ''
|| quote_literal(newvalue)
|| '' WHERE ...'';
-
This example shows use of the functions
- quote_ident(TEXT) and
- quote_literal(TEXT).
- Variables containing field and table identifiers should be
- passed to function quote_ident().
- Variables containing literal elements of the dynamic query
+ quote_ident(text) and
+ quote_literal(text).
+ Variables containing column and table identifiers should be
+ passed to function quote_ident.
+ Variables containing values that act as value literals in the constructed command
string should be passed to
- quote_literal(). Both take the
+ quote_literal. Both take the
appropriate steps to return the input text enclosed in single
or double quotes and with any embedded special characters
properly escaped.
- Here is a much larger example of a dynamic query and
+ Here is a much larger example of a dynamic command and
EXECUTE:
-CREATE FUNCTION cs_update_referrer_type_proc() RETURNS INTEGER AS '
+CREATE FUNCTION cs_update_referrer_type_proc() RETURNS integer AS '
DECLARE
- referrer_keys RECORD; -- Declare a generic record to be used in a FOR
+ referrer_keys RECORD; -- declare a generic record to be used in a FOR
a_output varchar(4000);
BEGIN
- a_output := ''CREATE FUNCTION cs_find_referrer_type(varchar,varchar,varchar)
- RETURNS VARCHAR AS ''''
+ a_output := ''CREATE FUNCTION cs_find_referrer_type(varchar, varchar, varchar)
+ RETURNS varchar AS ''''
DECLARE
v_host ALIAS FOR $1;
v_domain ALIAS FOR $2;
v_url ALIAS FOR $3;
BEGIN '';
- --
-- Notice how we scan through the results of a query in a FOR loop
-- using the FOR <record> construct.
- --
FOR referrer_keys IN SELECT * FROM cs_referrer_keys ORDER BY try_order LOOP
a_output := a_output || '' IF v_'' || referrer_keys.kind || '' LIKE ''''''''''
|| referrer_keys.referrer_type || ''''''; END IF;'';
END LOOP;
- a_output := a_output || '' RETURN NULL; END; '''' LANGUAGE ''''plpgsql'''';'';
+ a_output := a_output || '' RETURN NULL; END; '''' LANGUAGE plpgsql;'';
- -- This works because we are not substituting any variables
- -- Otherwise it would fail. Look at PERFORM for another way to run functions
-
EXECUTE a_output;
END;
-' LANGUAGE 'plpgsql';
+' LANGUAGE plpgsql;
-
Obtaining result status
+
Obtaining the Result Status
There are several ways to determine the effect of a command. The
- first method is to use the <literal>GET DIAGNOSTICS>,
+ first method is to use the <command>GET DIAGNOSTICS>,
which has the form:
This command allows retrieval of system status indicators. Each
- item is a keyword identifying a state
+ item is a key word identifying a state
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 ROW_COUNT>, the number of rows
- processed by the last
SQL query sent down to
- the
SQL engine
; and
RESULT_OID>,
+ processed by the last
SQL command sent down to
+ the
SQL engine
, and
RESULT_OID>,
the OID of the last row inserted by the most recent
-
SQL query. Note that
RESULT_OID>
- is only useful after an INSERT query.
+
SQL command. Note that
RESULT_OID>
+ is only useful after an INSERT command.
+
-
+ An example:
- GET DIAGNOSTICS var_integer = ROW_COUNT;
+GET DIAGNOSTICS var_integer = ROW_COUNT;
-
- There is a special variable named FOUND of
+ The second method to determine the effects of a command is the
+ special variable named FOUND of
type boolean. FOUND starts out
false within each
PL/pgSQL function.
It is set by each of the following types of statements:
-
Returning from a function
+
Returning From a Function
There are two commands available that allow you to return data
RETURN>
RETURN expression;
- RETURN with an expression is used to return
- from a
PL/pgSQL> function that does not return a
- set. The function terminates and the value of
- expression is returned to the caller.
+ RETURN with an expression terminates the
+ function and returns the value of
+ expression to the caller. This form
+ is to be used for
PL/pgSQL> functions that does
+ not return a set.
- To return a composite (row) value, you must write a record or row
- variable as the expression. When
- returning a scalar type, any expression can be used.
- The expression's result will be automatically cast into the
- function's return type as described for assignments.
+ When returning a scalar type, any expression can be used. The
+ expression's result will be automatically cast into the
+ function's return type as described for assignments. To return a
+ composite (row) value, you must write a record or row variable
+ as the expression.
without hitting a RETURN statement, a run-time
error will occur. Note that if you have declared the function to
return void, a RETURN statement
- must still be specified; however, the expression following
- RETURN is optional, and will be ignored in
+ must still be specified; the expression following
+ RETURN is, however, optional and will be ignored in
any case.
When a
PL/pgSQL> function is declared to return
- SETOF sometype>, the procedure
+ SETOF sometype>>, the procedure
to follow is slightly different. In that case, the individual
items to return are specified in RETURN NEXT
commands, and then a final RETURN command
finished executing. RETURN NEXT can be used
with both scalar and composite data types; in the later case, an
entire table
of results will be returned.
+
+
Functions that use RETURN NEXT should be
called in the following fashion:
SELECT * FROM some_func();
- That is, the function is used as a table source in a FROM
+ That is, the function is used as a table source in a FROM
clause.
have no argument, causes control to exit the function.
- For more information on using set-returning functions in
-
PostgreSQL, refer to XXX.
-
-
The current implementation of RETURN NEXT
allow users to allow users to define set-returning functions
that do not have this limitation. Currently, the point at
which data begins being written to disk is controlled by the
- SORT_MEM> configuration variable. Administrators
+ sort_mem> configuration variable. Administrators
who have sufficient memory to store larger result sets in
memory should consider increasing this parameter.
-
IF ... THEN ... ELSE IF> and>
+
IF ... THEN ... ELSE IF>>
IF ... THEN ... ELSIF ... THEN ... ELSE>>
IF-THEN>
IF boolean-expression THEN
statements
END IF;
IF-THEN statements are the simplest form of
IF. The statements between
THEN and END IF will be
executed if the condition is true. Otherwise, they are
skipped.
+
+ Example:
IF v_user_id <> 0 THEN
UPDATE users SET email = v_email WHERE user_id = v_user_id;
IF-THEN-ELSE>
IF boolean-expression THEN
statements
END IF;
IF-THEN-ELSE statements add to
IF-THEN by letting you specify an
alternative set of statements that should be executed if the
- condition evaluates to FALSE.
+ condition evaluates to false.
+
+ Examples:
-IF parentid IS NULL or parentid = ''''
-THEN
- return fullname;
+IF parentid IS NULL OR parentid = ''''
+THEN
+ RETURN fullname;
ELSE
- return hp_true_filename(parentid) || ''/'' || fullname;
+ RETURN hp_true_filename(parentid) || ''/'' || fullname;
END IF;
+
-
IF v_count > 0 THEN
- INSERT INTO users_count(count) VALUES(v_count);
- return ''t'';
-ELSE
- return ''f'';
+ INSERT INTO users_count (count) VALUES (v_count);
+ RETURN ''t'';
+ELSE
+ RETURN ''f'';
END IF;
IF demo_row.sex = ''m'' THEN
- pretty_sex := ''man'';
+ pretty_sex := ''man'';
ELSE
- IF demo_row.sex = ''f'' THEN
- pretty_sex := ''woman'';
- END IF;
+ IF demo_row.sex = ''f'' THEN
+ pretty_sex := ''woman'';
+ END IF;
END IF;
IF statement inside the
ELSE part of an outer IF
statement. Thus you need one END IF
- statement for each nested IF and one for the parent
+ statement for each nested IF and one for the parent
IF-ELSE. This is workable but grows
tedious when there are many alternatives to be checked.
+ Hence the next form.
IF-THEN-ELSIF-ELSE>
IF boolean-expression THEN
statements
END IF;
IF-THEN-ELSIF-ELSE> provides a more convenient
method of checking many alternatives in one statement.
Formally it is equivalent to nested
ELSIF number < 0 THEN
result := ''negative'';
ELSE
- -- hmm, the only other possibility is that number IS NULL
+ -- hmm, the only other possibility is that number is null
result := ''NULL'';
END IF;
-
- The final ELSE statement is optional.
-
-
Simple Loops
- With the LOOP, EXIT, WHILE and FOR statements, you can arrange
- for your
PL/pgSQL function to repeat
- a series of commands.
+ With the LOOP>, EXIT>, WHILE>,
+ and FOR> statements, you can arrange for your
+
PL/pgSQL function to repeat a series
+ of commands.
-
LOOP
+
LOOP>
-<<label>>
+<<label>>
LOOP
statements
END LOOP;
- LOOP defines an unconditional loop that is repeated indefinitely
- until terminated by an EXIT or RETURN
- statement. The optional label can be used by EXIT statements in
+ LOOP> defines an unconditional loop that is repeated indefinitely
+ until terminated by an EXIT> or RETURN
+ statement. The optional label can be used by EXIT> statements in
nested loops to specify which level of nesting should be
terminated.
-
EXIT
+
EXIT>
EXIT label WHEN expression ;
If no label is given,
the innermost loop is terminated and the
- statement following END LOOP is executed next.
+ statement following END LOOP> is executed next.
If label is given, it
must be the label of the current or some outer level of nested loop
or block. Then the named loop or block is terminated and control
continues with the statement after the loop's/block's corresponding
- END.
+ END>.
- If WHEN is present, loop exit occurs only if the specified condition
- is true, otherwise control passes to the statement after EXIT.
+ If WHEN> is present, loop exit occurs only if the specified condition
+ is true, otherwise control passes to the statement after EXIT>.
BEGIN
-- some computations
IF stocks > 100000 THEN
- EXIT; -- illegal. Can't use EXIT outside of a LOOP
+ EXIT; -- invalid; cannot use EXIT outside of LOOP
END IF;
END;
-
WHILE
+
WHILE>
-<<label>>
+<<label>>
WHILE expression LOOP
statements
END LOOP;
- The WHILE statement repeats a
+ The WHILE> statement repeats a
sequence of statements so long as the condition expression
evaluates to true. The condition is checked just before
each entry to the loop body.
-
FOR (integer for-loop)
+
FOR> (integer variant)
-<<label>>
+<<label>>
FOR name IN REVERSE expression .. expression LOOP
statements
END LOOP;
- This form of FOR creates a loop that iterates over a range of integer
+ This form of FOR> creates a loop that iterates over a range of integer
values. The variable
name is automatically defined as type
- integer and exists only inside the loop. The two expressions giving
+ integer> and exists only inside the loop. The two expressions giving
the lower and upper bound of the range are evaluated once when entering
- the loop. The iteration step is normally 1, but is -1 when REVERSE is
+ the loop. The iteration step is normally 1, but is -1 when REVERSE> is
specified.
- Some examples of integer FOR loops:
+ Some examples of integer FOR> loops:
FOR i IN 1..10 LOOP
- -- some expressions here
-
- RAISE NOTICE ''i is %'',i;
+ -- some expressions here
+ RAISE NOTICE ''i is %'', i;
END LOOP;
FOR i IN REVERSE 10..1 LOOP
Looping Through Query Results
- Using a different type of FOR loop, you can iterate through
+ Using a different type of FOR> loop, you can iterate through
the results of a query and manipulate that data
accordingly. The syntax is:
-<<label>>
-FOR record | row IN select_query LOOP
+<<label>>
+FOR record_or_row IN query LOOP
statements
END LOOP;
- The record or row variable is successively assigned all the rows
- resulting from the SELECT query and the loop
+ The record or row variable is successively assigned each row
+ resulting from the query (a SELECT command) and the loop
body is executed for each row. Here is an example:
-
-
-CREATE FUNCTION cs_refresh_mviews () RETURNS INTEGER AS '
+CREATE FUNCTION cs_refresh_mviews() RETURNS integer AS '
DECLARE
- mviews RECORD;
+ mviews RECORD;
BEGIN
- PERFORM cs_log(''Refreshing materialized views...'');
+ PERFORM cs_log(''Refreshing materialized views...'');
- FOR mviews IN SELECT * FROM cs_materialized_views ORDER BY sort_key LOOP
+ FOR mviews IN SELECT * FROM cs_materialized_views ORDER BY sort_key LOOP
- -- Now "mviews" has one record from cs_materialized_views
+ -- Now "mviews" has one record from cs_materialized_views
- PERFORM cs_log(''Refreshing materialized view '' || quote_ident(mviews.mv_name) || ''...'');
- EXECUTE ''TRUNCATE TABLE '' || quote_ident(mviews.mv_name);
- EXECUTE ''INSERT INTO '' || quote_ident(mviews.mv_name) || '' '' || mviews.mv_query;
- END LOOP;
+ PERFORM cs_log(''Refreshing materialized view '' || quote_ident(mviews.mv_name) || ''...'');
+ EXECUTE ''TRUNCATE TABLE '' || quote_ident(mviews.mv_name);
+ EXECUTE ''INSERT INTO '' || quote_ident(mviews.mv_name) || '' '' || mviews.mv_query;
+ END LOOP;
- PERFORM cs_log(''Done refreshing materialized views.'');
- RETURN 1;
-end;
-' LANGUAGE 'plpgsql';
+ PERFORM cs_log(''Done refreshing materialized views.'');
+ RETURN 1;
+END;
+' LANGUAGE plpgsql;
- If the loop is terminated by an EXIT statement, the last
+ If the loop is terminated by an EXIT> statement, the last
assigned row value is still accessible after the loop.
- The FOR-IN-EXECUTE statement is another way to iterate over
+ The FOR-IN-EXECUTE> statement is another way to iterate over
records:
-<<label>>
-FOR record | row IN EXECUTE text_expression LOOP
+<<label>>
+FOR record_or_row IN EXECUTE text_expression LOOP
statements
END LOOP;
This is like the previous form, except that the source
SELECT statement is specified as a string
- expression, which is evaluated and re-planned on each entry to
- the FOR loop. This allows the programmer to choose the speed of
- a pre-planned query or the flexibility of a dynamic query, just
+ expression, which is evaluated and replanned on each entry to
+ the FOR> loop. This allows the programmer to choose the speed of
+ a preplanned query or the flexibility of a dynamic query, just
as with a plain EXECUTE statement.
The
PL/pgSQL> parser presently distinguishes the
- two kinds of FOR loops (integer or record-returning) by checking
- whether the target variable mentioned just after FOR has been
- declared as a record/row variable. If not, it's presumed to be
- an integer FOR loop. This can cause rather nonintuitive error
+ two kinds of FOR> loops (integer or query result) by checking
+ whether the target variable mentioned just after FOR> has been
+ declared as a record or row variable. If not, it's presumed to be
+ an integer FOR> loop. This can cause rather nonintuitive error
messages when the true problem is, say, that one has
- misspelled the FOR variable name.
+ misspelled the variable name after the FOR>.
the query result a few rows at a time. One reason for doing this is
to avoid memory overrun when the result contains a large number of
rows. (However,
PL/pgSQL> users do not normally need
- to worry about that, since FOR loops automatically use a cursor
+ to worry about that, since FOR> loops automatically use a cursor
internally to avoid memory problems.) A more interesting usage is to
return a reference to a cursor that it has created, allowing the
caller to read the rows. This provides an efficient way to return
Another way is to use the cursor declaration syntax,
which in general is:
-name CURSOR ( arguments ) FOR select_query ;
+name CURSOR ( arguments ) FOR query ;
(FOR> may be replaced by IS> for
- arguments, if any, are a
- comma-separated list of name
- datatype pairs that define names to be
+ arguments, if specified, is a
+ comma-separated list of pairs name
+ datatype that define names to be
replaced by parameter values in the given query. The actual
values to substitute for these names will be specified later,
when the cursor is opened.
DECLARE
curs1 refcursor;
- curs2 CURSOR FOR SELECT * from tenk1;
- curs3 CURSOR (key int) IS SELECT * from tenk1 where unique1 = key;
+ curs2 CURSOR FOR SELECT * FROM tenk1;
+ curs3 CURSOR (key integer) IS SELECT * FROM tenk1 WHERE unique1 = key;
All three of these variables have the data type refcursor>,
but the first may be used with any query, while the second has
Before a cursor can be used to retrieve rows, it must be
opened>. (This is the equivalent action to the SQL
command
DECLARE CURSOR>.) PL/pgSQL> has
- four forms of the OPEN statement, two of which use unbound cursor
- variables and the other two use bound cursor variables.
+ three forms of the OPEN> statement, two of which use unbound cursor
+ variables and the other uses a bound cursor variable.
-
OPEN FOR SELECT
+
OPEN FOR SELECT
OPEN unbound-cursor FOR SELECT ...;
The cursor variable is opened and given the specified query to
execute. The cursor cannot be open already, and it must have been
declared as an unbound cursor (that is, as a simple
is treated in the same way as other SELECT
statements in
PL/pgSQL>: PL/pgSQL>
variable names are substituted, and the query plan is cached for
- possible re-use.
+ possible reuse.
+
+ An example:
OPEN curs1 FOR SELECT * FROM foo WHERE key = mykey;
-
OPEN FOR EXECUTE
+
OPEN FOR EXECUTE
OPEN unbound-cursor FOR EXECUTE query-string;
The cursor variable is opened and given the specified query to
execute. The cursor cannot be open already, and it must have been
declared as an unbound cursor (that is, as a simple
expression in the same way as in the EXECUTE
command. As usual, this gives flexibility so the query can vary
from one run to the next.
+
+ An example:
OPEN curs1 FOR EXECUTE ''SELECT * FROM '' || quote_ident($1);
-
Opening a bound cursor
+
Opening a Bound Cursor
OPEN bound-cursor ( argument_values ) ;
This form of OPEN is used to open a cursor
variable whose query was bound to it when it was declared. The
cursor cannot be open already. A list of actual argument value
expressions must appear if and only if the cursor was declared to
take arguments. These values will be substituted in the query.
- The query plan for a bound cursor is always considered cacheable
- --- there is no equivalent of EXECUTE in this case.
+ The query plan for a bound cursor is always considered cacheable;
+ there is no equivalent of EXECUTE in this case.
+
+ Examples:
OPEN curs2;
OPEN curs3(42);
opened the cursor to begin with. You can return a refcursor>
value out of a function and let the caller operate on the cursor.
(Internally, a refcursor> value is simply the string name
- of a Portal containing the active query for the cursor. This name
+ of a so-called portal containing the active query for the cursor. This name
can be passed around, assigned to other refcursor> variables,
- and so on, without disturbing the Portal.)
+ and so on, without disturbing the portal.)
- All Portals are implicitly closed at transaction end. Therefore
- a refcursor> value is useful to reference an open cursor
+ All portals are implicitly closed at transaction end. Therefore
+ a refcursor> value is usable to reference an open cursor
only until the end of the transaction.
-
FETCH
+
FETCH>
FETCH cursor INTO target;
FETCH retrieves the next row from the
cursor into a target, which may be a row variable, a record
variable, or a comma-separated list of simple variables, just like
SELECT INTO. As with SELECT
INTO, the special variable FOUND may
be checked to see whether a row was obtained or not.
+
+ An example:
FETCH curs1 INTO rowvar;
-FETCH curs2 INTO foo,bar,baz;
+FETCH curs2 INTO foo, bar, baz;
-
CLOSE
+
CLOSE>
CLOSE cursor;
CLOSE closes the Portal underlying an open
cursor. This can be used to release resources earlier than end of
transaction, or to free up the cursor variable to be opened again.
+
+ An example:
CLOSE curs1;
Returning Cursors
-
PL/pgSQL> functions can return cursors to the
caller. This is used to return multiple rows or columns from
- the function. The function opens the cursor and returns the
+ the function. To do this, the function opens the cursor and returns the
cursor name to the caller. The caller can then
- FETCH rows from the cursor. The cursor can
+ fetch rows from the cursor. The cursor can
be closed by the caller, or it will be closed automatically
when the transaction closes.
-
CREATE FUNCTION reffunc(refcursor) RETURNS refcursor AS '
BEGIN
- OPEN $1 FOR SELECT col FROM test;
- RETURN $1;
+ OPEN $1 FOR SELECT col FROM test;
+ RETURN $1;
END;
-' LANGUAGE 'plpgsql';
+' LANGUAGE plpgsql;
BEGIN;
SELECT reffunc('funccursor');
CREATE FUNCTION reffunc2() RETURNS refcursor AS '
DECLARE
- ref refcursor;
+ ref refcursor;
BEGIN
- OPEN ref FOR SELECT col FROM test;
- RETURN ref;
+ OPEN ref FOR SELECT col FROM test;
+ RETURN ref;
END;
-' LANGUAGE 'plpgsql';
+' LANGUAGE plpgsql;
BEGIN;
SELECT reffunc2();
- reffunc2
- --------------------
- <unnamed cursor 1>
- (1 row)
+ reffunc2
+--------------------
+ <unnamed cursor 1>
+(1 row)
FETCH ALL IN "<unnamed cursor 1>";
COMMIT;
raise errors.
-RAISE level 'format' , variable ...;
+RAISE level 'format' , variable , ...;
Possible levels are DEBUG (write the message to
NOTICE and WARNING (write
the message to the server log and send it to the client, with
respectively higher priorities), and EXCEPTION
- (raise an error and abort the current transaction). Whether error
+ (raise an error and abort the current transaction). Whether
messages of a particular priority are reported to the client,
written to the server log, or both is controlled by the
- and
- configuration variables. See
+ and
+ configuration variables. See
for more information.
Inside the format string, % is replaced by the
- next optional argument's external representation. Write
+ next optional argument's string representation. Write
%% to emit a literal %. Note
that the optional arguments must presently be simple variables,
not expressions, and the format must be a simple string literal.
-->
- Examples:
+ In this example, the value of v_job_id> will replace the
+ % in the string.
-RAISE NOTICE ''Calling cs_create_job(%)'',v_job_id;
+RAISE NOTICE ''Calling cs_create_job(%)'', v_job_id;
-
- In this example, the value of v_job_id will replace the
- % in the string.
+ This example will abort the transaction with the given error message.
-RAISE EXCEPTION ''Inexistent ID --> %'',user_id;
+RAISE EXCEPTION ''Inexistent ID --> %'', user_id;
- This will abort the transaction with the given error message.
-
-
Exceptions
-
PostgreSQL does not have a very smart
exception handling model. Whenever the parser, planner/optimizer
or executor decide that a statement cannot be processed any longer,
the whole transaction gets aborted and the system jumps back
- into the main loop to get the next query from the client application.
+ into the main loop to get the next command from the client application.
It is possible to hook into the error mechanism to notice that this
happens. But currently it is impossible to tell what really
- caused the abort (input/output conversion error, floating-point
- error, parse error). And it is possible that the database backend
+ caused the abort (data type format error, floating-point
+ error, parse error, etc.). And it is possible that the database server
is in an inconsistent state at this point so returning to the upper
executor or issuing more commands might corrupt the whole database.
function and where (line number and type of statement) this
happened. The error always stops execution of the function.
-
Data type RECORD; variable holding the new
- database row for INSERT/UPDATE operations in ROW level
- triggers. This variable is NULL in STATEMENT level triggers.
+ database row for INSERT>/UPDATE> operations in row-level
+ triggers. This variable is null in statement-level triggers.
Data type RECORD; variable holding the old
- database row for UPDATE/DELETE operations in ROW level
- triggers. This variable is NULL in STATEMENT level triggers.
+ database row for UPDATE>/DELETE> operations in row-level
+ triggers. This variable is null in statement-level triggers.
Data type text; a string of
- INSERT, UPDATE or
+ INSERT, UPDATE, or
DELETE telling for which operation the
- trigger is fired.
+ trigger was fired.
Data type array of text; the arguments from
the CREATE TRIGGER statement.
- The index counts from 0 and can be given as an expression. Invalid
- indices (< 0 or >= tg_nargs>) result in a null value.
+ The index counts from 0. Invalid
+ indices (less than 0 or greater than or equal to tg_nargs>) result in a null value.
- A trigger function must return either NULL or a record/row value
+ A trigger function must return either null or a record/row value
having exactly the structure of the table the trigger was fired
- for. The return value of a BEFORE or AFTER STATEMENT level
- trigger, or an AFTER ROW level trigger is ignored; it may as well
- return NULL. However, any of these types of triggers can still
+ for. The return value of a BEFORE> or AFTER> statement-level
+ trigger or an AFTER> row-level trigger is ignored; it may as well
+ be null. However, any of these types of triggers can still
abort the entire trigger operation by raising an error.
- ROW level triggers fired BEFORE may return NULL to signal the
+ Row-level triggers fired BEFORE> may return null to signal the
trigger manager to skip the rest of the operation for this row
- (ie, subsequent triggers are not fired, and the
- INSERT/UPDATE/DELETE does not occur for this row). If a non-NULL
+ (i.e., subsequent triggers are not fired, and the
+ INSERT>/UPDATE>/DELETE> does not occur for this row). If a nonnull
value is returned then the operation proceeds with that row value.
- Note that returning a row value different from the original value
- of NEW alters the row that will be inserted or updated. It is
- possible to replace single values directly in NEW and return that,
+ Returning a row value different from the original value
+ of NEW> alters the row that will be inserted or updated. It is
+ possible to replace single values directly in NEW> and return NEW>,
or to build a complete new record/row to return.
-
-
A PL/pgSQL Trigger Procedure Example
+ shows an example of a
+ trigger procedure in
PL/pgSQL.
+
+
+
+
A PL/pgSQL Trigger Procedure
This example trigger ensures that any time a row is inserted or updated
in the table, the current user name and time are stamped into the
row. And it ensures that an employee's name is given and that the
salary is a positive value.
+
CREATE TABLE emp (
last_user text
);
-CREATE FUNCTION emp_stamp () RETURNS TRIGGER AS '
+CREATE FUNCTION emp_stamp() RETURNS trigger AS '
BEGIN
-- Check that empname and salary are given
- IF NEW.empname ISNULL THEN
- RAISE EXCEPTION ''empname cannot be NULL value'';
+ IF NEW.empname IS NULL THEN
+ RAISE EXCEPTION ''empname cannot be null'';
END IF;
- IF NEW.salary ISNULL THEN
- RAISE EXCEPTION ''% cannot have NULL salary'', NEW.empname;
+ IF NEW.salary IS NULL THEN
+ RAISE EXCEPTION ''% cannot have null salary'', NEW.empname;
END IF;
-- Who works for us when she must pay for it?
- IF NEW.salary < 0 THEN
+ IF NEW.salary < 0 THEN
RAISE EXCEPTION ''% cannot have a negative salary'', NEW.empname;
END IF;
NEW.last_user := current_user;
RETURN NEW;
END;
-' LANGUAGE 'plpgsql';
+' LANGUAGE plpgsql;
CREATE TRIGGER emp_stamp BEFORE INSERT OR UPDATE ON emp
FOR EACH ROW EXECUTE PROCEDURE emp_stamp();
-
-
-
-
-
-
-
-
-
Examples
-
- Here are only a few functions to demonstrate how easy it is to
- functions. For more complex examples the programmer
- might look at the regression test for
PL/pgSQL>.
-
-
- One painful detail in writing functions in
-
PL/pgSQL is the handling of single
- quotes. The function's source text in CREATE FUNCTION>
- must be a literal string. Single quotes inside of literal strings
- must be either doubled or quoted with a backslash. We are still
- looking for an elegant alternative. In the meantime, doubling the
- single quotes as in the examples below should be used. Any
- solution for this in future versions of
-
PostgreSQL will be forward compatible.
-
-
- For a detailed explanation and examples of how to escape single
- quotes in different situations, please see .
-
-
-
-
A Simple PL/pgSQL Function to Increment an Integer
-
- The following two
PL/pgSQL functions are identical to their
- counterparts from the C language function discussion. This
- function receives an integer and increments it by
- one, returning the incremented value.
-
-
-CREATE FUNCTION add_one (integer) RETURNS INTEGER AS '
- BEGIN
- RETURN $1 + 1;
- END;
-' LANGUAGE 'plpgsql';
-
-
-
-
-
A Simple PL/pgSQL Function to Concatenate Text
-
- This function receives two text parameters and
- returns the result of concatenating them.
-
-
-CREATE FUNCTION concat_text (TEXT, TEXT) RETURNS TEXT AS '
- BEGIN
- RETURN $1 || $2;
- END;
-' LANGUAGE 'plpgsql';
-
-
-
-
-
A PL/pgSQL Function on Composite Type
-
- In this example, we take EMP> (a table) and an
- integer as arguments to our function, which returns
- a boolean. If the salary> field of the EMP> table is
- NULL, we return f>. Otherwise we compare with
- that field with the integer passed to the function
- and return the boolean result of the comparison (t
- or f). This is the
PL/pgSQL equivalent to the example from the C
- functions.
-
-
-CREATE FUNCTION c_overpaid (EMP, INTEGER) RETURNS BOOLEAN AS '
- DECLARE
- emprec ALIAS FOR $1;
- sallim ALIAS FOR $2;
- BEGIN
- IF emprec.salary ISNULL THEN
- RETURN ''f'';
- END IF;
- RETURN emprec.salary > sallim;
- END;
-' LANGUAGE 'plpgsql';
-
-
-
- February 2001
-
- Roberto
- Mello
-
-
-
-
-
-
Porting from Oracle PL/SQL
-
-
Author
-
-
-
- This section explains differences between
Oracle>'s PL/SQL and
-
PostgreSQL>'s PL/pgSQL languages in the hopes of helping developers
- port applications from Oracle to
PostgreSQL>. Most of the code here
- module that I ported to
PostgreSQL> when I took an
- internship with
OpenForce
- Inc. in the Summer of 2000.
+ This section explains differences between
+ language and Oracle's
PL/SQL language,
+ to help developers that port applications from Oracle to
-
PL/pgSQL is similar to PL/SQL in many aspects. It is a block
- structured, imperative language (all variables have to be
- declared). PL/SQL has many more features than its
PostgreSQL>
- counterpart, but
PL/pgSQL allows for a great deal of functionality
- and it is being improved constantly.
-
-
-
-
Main Differences
-
- Some things you should keep in mind when porting from
+
PL/pgSQL is similar to PL/SQL in many
+ aspects. It is a block-structured, imperative language, and all
+ variables have to be declared. Assignments, loops, conditionals
+ are similar. The main differences you should keep in mind when
+ porting from
PL/SQL> to
-
No default parameters in
PostgreSQL>.
+
There are no default values for parameters in
PostgreSQL>.
- Assignments, loops and conditionals are similar.
+ No need for cursors in
PL/pgSQL>, just put the
+ query in the
FOR statement. (See
+ linkend="plpgsql-porting-ex2">.)
- No need for cursors in
PostgreSQL>, just put the query in the FOR
- statement (see example below)
+ In
PostgreSQL> you need to escape single
+ quotes in the function body. See .
- In
PostgreSQL> you need to escape single
- quotes. See .
+ Instead of packages, use schemas to organize your functions
+ into groups.
-
-
Quote Me on That: Escaping Single Quotes
-
- In
PostgreSQL> you need to escape single quotes inside your
- function definition. This can lead to quite amusing code at
- times, especially if you are creating a function that generates
- other function(s), as in
- .
- One thing to keep in mind
- when escaping lots of single quotes is that, except for the
- beginning/ending quotes, all the others will come in even
- quantity.
-
-
- gives the scoop. (You'll
- love this little chart.)
-
-
-
-
Single Quotes Escaping Chart
-
-
-
- |
- No. of Quotes
- Usage
- Example
- Result
-
-
-
-
- |
- 1
- To begin/terminate function bodies
-CREATE FUNCTION foo() RETURNS INTEGER AS '...'
-LANGUAGE 'plpgsql';
-
- as is
-
-
- |
- 2
- In assignments, SELECT statements, to delimit strings, etc.
-a_output := ''Blah'';
-SELECT * FROM users WHERE f_name=''foobar'';
-
- SELECT * FROM users WHERE f_name='foobar';
-
-
- |
- 4
-
- When you need two single quotes in your resulting string
- without terminating that string.
-
-a_output := a_output || '' AND name
- LIKE ''''foobar'''' AND ...''
-
- AND name LIKE 'foobar' AND ...
-
-
- |
- 6
-
- When you want double quotes in your resulting string
- and terminate that string.
-
-a_output := a_output || '' AND name
- LIKE ''''foobar''''''
-
-
- AND name LIKE 'foobar'
-
-
-
- |
- 10
-
- When you want two single quotes in the resulting string
- (which accounts for 8 quotes) and
- terminate that string (2 more). You will probably only need
- that if you were using a function to generate other functions
- (like in ).
-
-a_output := a_output || '' if v_'' ||
- referrer_keys.kind || '' like ''''''''''
- || referrer_keys.key_string || ''''''''''
- then return '''''' || referrer_keys.referrer_type
- || ''''''; end if;'';
-
-
- if v_<...> like ''<...>'' then return ''<...>''; end if;
-
-
-
-
-
-
-
+
+
Porting Examples
- >
-
- Porting Functions
- title>
+ shows how to port a simple
+ function from
PL/SQL> to PL/pgSQL>.
+ para>
-
-
- A Simple Function
-
+
+
Porting a Simple Function from PL/SQL> to PL/pgSQL>
- Here is an
Oracle function:
+ Here is an
Oracle PL/SQL> function:
CREATE OR REPLACE FUNCTION cs_fmt_browser_version(v_name IN varchar, v_version IN varchar)
RETURN varchar IS
RETURN v_name || '/' || v_version;
END;
/
-SHOW ERRORS;
+show errors;
IN, OUT, and
- INOUT parameters passed to functions. The
+ INOUT parameters passed to functions.
INOUT, for example, means that the
parameter will receive a value and return
- another.
PostgreSQL> only has <quote>IN>
- parameters and functions can return only a single value.
+ another.
PostgreSQL> only has <literal>IN>
+ parameters.
The RETURN key word in the function
prototype (not the function body) becomes
-
RETURNS in
PostgreSQL>.
+ RETURNS in PostgreSQL.
- On
PostgreSQL> functions are created using single quotes as
- delimiters, so you have to escape single quotes inside your
- functions (which can be quite annoying at times; see
- linkend="plpgsql-quote">).
+ In
PostgreSQL>, functions are created using
+ single quotes as the delimiters of the function body, so you
+ have to escape single quotes inside the function body.
- So let's see how this function would look when ported to
+ This is how this function would look when ported to
-CREATE OR REPLACE FUNCTION cs_fmt_browser_version(VARCHAR, VARCHAR)
-RETURNS VARCHAR AS '
+CREATE OR REPLACE FUNCTION cs_fmt_browser_version(varchar, varchar)
+RETURNS varchar AS '
DECLARE
v_name ALIAS FOR $1;
v_version ALIAS FOR $2;
END IF;
RETURN v_name || ''/'' || v_version;
END;
-' LANGUAGE 'plpgsql';
+' LANGUAGE plpgsql;
+
+ shows how to port a
+ function that creates another function and how to handle to
+ ensuing quoting problems.
+
-
-
- A Function that Creates Another Function
-
+
+
Porting a Function that Creates Another Function from PL/SQL> to PL/pgSQL>
The following procedure grabs rows from a
SELECT statement and builds a large function
with the results in IF statements, for the
- sake of efficiency. Notice particularly the differences in
- cursors, FOR loops, and the need to escape
- single quotes in
PostgreSQL>.
+ sake of efficiency. Notice particularly the differences in the
+ cursor and the FOR loop,
+
+ This is the Oracle version:
CREATE OR REPLACE PROCEDURE cs_update_referrer_type_proc IS
CURSOR referrer_keys IS
EXECUTE IMMEDIATE a_output;
END;
/
-show errors
+show errors;
Here is how this function would end up in
PostgreSQL>:
-CREATE FUNCTION cs_update_referrer_type_proc() RETURNS INTEGER AS '
+CREATE FUNCTION cs_update_referrer_type_proc() RETURNS integer AS '
DECLARE
referrer_keys RECORD; -- Declare a generic record to be used in a FOR
a_output varchar(4000);
BEGIN
- a_output := ''CREATE FUNCTION cs_find_referrer_type(VARCHAR,VARCHAR,VARCHAR)
- RETURNS VARCHAR AS ''''
+ a_output := ''CREATE FUNCTION cs_find_referrer_type(varchar, varchar, varchar)
+ RETURNS varchar AS ''''
DECLARE
v_host ALIAS FOR $1;
v_domain ALIAS FOR $2;
v_url ALIAS FOR $3;
BEGIN '';
- --
-- Notice how we scan through the results of a query in a FOR loop
-- using the FOR <record> construct.
- --
FOR referrer_keys IN SELECT * FROM cs_referrer_keys ORDER BY try_order LOOP
a_output := a_output || '' IF v_'' || referrer_keys.kind || '' LIKE ''''''''''
|| referrer_keys.referrer_type || ''''''; END IF;'';
END LOOP;
- a_output := a_output || '' RETURN NULL; END; '''' LANGUAGE ''''plpgsql'''';'';
+ a_output := a_output || '' RETURN NULL; END; '''' LANGUAGE plpgsql;'';
- -- This works because we are not substituting any variables
- -- Otherwise it would fail. Look at PERFORM for another way to run functions
+ -- EXECUTE will work because we are not substituting any variables.
+ -- Otherwise it would fail. Look at PERFORM for another way to run functions.
EXECUTE a_output;
END;
-' LANGUAGE 'plpgsql';
+' LANGUAGE plpgsql;
-
-
- A Procedure with a lot of String Manipulation and OUT> Parameters
-
+ shows how to port a function
+ with OUT> parameters and string manipulation.
+
PostgreSQL> does not have an
+ instr function, but you can work around it
+ using a combination of other functions. In
+ linkend="plpgsql-porting-appendix"> there is a
+
PL/pgSQL implementation of
+ instr that you can use to make your porting
+ easier.
+
+
+
+
Porting a Procedure With String Manipulation and
+
OUT> Parameters from PL/SQL> to
The following
Oracle PL/SQL procedure is used to parse a URL and
- return several elements (host, path and query). It is an
- procedure because in
PL/pgSQL functions only one value can be returned
- (see ). In
+ return several elements (host, path, and query).
+
PL/pgSQL functions can return only one value. In
PostgreSQL>, one way to work around this is to split the procedure
in three different functions: one to return the host, another for
- the path and another for the query.
+ the path, and another for the query.
+ This is the Oracle version:
CREATE OR REPLACE PROCEDURE cs_parse_url(
v_url IN VARCHAR,
v_host OUT VARCHAR, -- This will be passed back
v_path OUT VARCHAR, -- This one too
v_query OUT VARCHAR) -- And this one
-is
+IS
a_pos1 INTEGER;
a_pos2 INTEGER;
-begin
+BEGIN
v_host := NULL;
v_path := NULL;
v_query := NULL;
- a_pos1 := instr(v_url, '//');
-- PostgreSQL> doesn't have an instr function
+ a_pos1 := instr(v_url, '//');
IF a_pos1 = 0 THEN
RETURN;
/
show errors;
+
- Here is how this procedure could be translated for
PostgreSQL>:
+ Here is how the
PL/pgSQL> function that returns
+ the host part could look like:
-CREATE OR REPLACE FUNCTION cs_parse_url_host(VARCHAR) RETURNS VARCHAR AS '
-DECLARE
- v_url ALIAS FOR $1;
- v_host VARCHAR;
- v_path VARCHAR;
- a_pos1 INTEGER;
- a_pos2 INTEGER;
- a_pos3 INTEGER;
+CREATE OR REPLACE FUNCTION cs_parse_url_host(varchar) RETURNS varchar AS '
+DECLARE
+ v_url ALIAS FOR $1;
+ v_host varchar;
+ v_path varchar;
+ a_pos1 integer;
+ a_pos2 integer;
+ a_pos3 integer;
BEGIN
v_host := NULL;
- a_pos1 := instr(v_url,''//'');
+ a_pos1 := instr(v_url, ''//'');
IF a_pos1 = 0 THEN
RETURN ''''; -- Return a blank
END IF;
- a_pos2 := instr(v_url,''/'',a_pos1 + 2);
+ a_pos2 := instr(v_url,''/'',a_pos1 + 2);
IF a_pos2 = 0 THEN
v_host := substr(v_url, a_pos1 + 2);
v_path := ''/'';
v_host := substr(v_url, a_pos1 + 2, a_pos2 - a_pos1 - 2 );
RETURN v_host;
END;
-' LANGUAGE 'plpgsql';
+' LANGUAGE plpgsql;
-
-
PostgreSQL> does not have an instr function,
- so you can work around it using a combination of other functions.
- I got tired of doing this and created my own
- instr functions that behave exactly like
-
Oracle's (it makes life easier). See the
- linkend="plpgsql-porting-appendix"> for the code.
-
-
-
-
-
-
- Procedures
-
-
-
Oracle procedures give a little more
- flexibility to the developer because nothing needs to be
- explicitly returned, but it can be through the use of
- INOUT> or OUT> parameters.
+ shows how to port a procedure
+ that uses numerous features that are specific to Oracle.
- An example:
+
+
Porting a Procedure from PL/SQL> to PL/pgSQL>
+
+ The Oracle version:
CREATE OR REPLACE PROCEDURE cs_create_job(v_job_id IN INTEGER) IS
BEGIN
LOCK TABLE cs_jobs IN EXCLUSIVE MODE;
- SELECT count(*) INTO a_running_job_count
- FROM cs_jobs
- WHERE end_stamp IS NULL;
+ SELECT count(*) INTO a_running_job_count FROM cs_jobs WHERE end_stamp IS NULL;
IF a_running_job_count > 0 THEN
COMMIT; -- free lock
Procedures like this can be easily converted into
PostgreSQL>
- functions returning an INTEGER. This procedure in
+ functions returning an integer. This procedure in
particular is interesting because it can teach us some things:
- There is no
pragma statement in
PostgreSQL>.
+ There is no
PRAGMA statement in
PostgreSQL>.
- You also cannot have transactions in
PL/pgSQL procedures. The
+ You also cannot have transactions in
PL/pgSQL functions. The
entire function (and other functions called from therein) is
- executed in a transaction and
PostgreSQL> rolls back the results if
- something goes wrong. Therefore only one
- BEGIN statement is allowed.
+ executed in one transaction and
PostgreSQL> rolls back the transaction if
+ something goes wrong.
-
So let's see one of the ways we could port this procedure to
PL/pgSQL>:
+
This is how we could port this procedure to
PL/pgSQL>:
-CREATE OR REPLACE FUNCTION cs_create_job(INTEGER) RETURNS INTEGER AS '
+CREATE OR REPLACE FUNCTION cs_create_job(integer) RETURNS integer AS '
DECLARE
v_job_id ALIAS FOR $1;
- a_running_job_count INTEGER;
- a_num INTEGER;
- -- PRAGMA AUTONOMOUS_TRANSACTION;
+ a_running_job_count integer;
+ a_num integer;
BEGIN
LOCK TABLE cs_jobs IN EXCLUSIVE MODE;
- SELECT count(*) INTO a_running_job_count
- FROM cs_jobs
- WHERE end_stamp IS NULL;
+ SELECT count(*) INTO a_running_job_count FROM cs_jobs WHERE end_stamp IS NULL;
IF a_running_job_count > 0
THEN
- -- COMMIT; -- free lock
RAISE EXCEPTION ''Unable to create a new job: a job is currently running.'';
END IF;
DELETE FROM cs_active_job;
INSERT INTO cs_active_job(job_id) VALUES (v_job_id);
- SELECT count(*) into a_num
- FROM cs_jobs
- WHERE job_id=v_job_id;
+ SELECT count(*) INTO a_num FROM cs_jobs WHERE job_id=v_job_id;
IF NOT FOUND THEN -- If nothing was returned in the last query
-- This job is not in the table so lets insert it.
- INSERT INTO cs_jobs(job_id, start_stamp) VALUES (v_job_id, sysdate());
+ INSERT INTO cs_jobs(job_id, start_stamp) VALUES (v_job_id, current_timestamp);
RETURN 1;
ELSE
RAISE NOTICE ''Job already running.'';
RETURN 0;
END;
-' LANGUAGE 'plpgsql';
+' LANGUAGE plpgsql;
+
-
-
- Packages
-
-
-
- I haven't done much with packages myself, so if there are
- mistakes here, please let me know.
-
-
-
- Packages are a way
Oracle gives you to
- encapsulate PL/SQL statements and functions into one entity, like
- Java classes, where you define methods and objects. You can access
- these objects/methods with a .
- (dot). Here is an example of an
Oracle
- package from ACS 4 (the
- url="http://www.arsdigita.com/doc/">ArsDigita Community
- System):
-
-CREATE OR REPLACE PACKAGE BODY acs
-AS
- FUNCTION add_user (
- user_id IN users.user_id%TYPE DEFAULT NULL,
- object_type IN acs_objects.object_type%TYPE DEFAULT 'user',
- creation_date IN acs_objects.creation_date%TYPE DEFAULT sysdate,
- creation_user IN acs_objects.creation_user%TYPE DEFAULT NULL,
- creation_ip IN acs_objects.creation_ip%TYPE DEFAULT NULL,
- ...
- ) RETURN users.user_id%TYPE
- IS
- v_user_id users.user_id%TYPE;
- v_rel_id membership_rels.rel_id%TYPE;
- BEGIN
- v_user_id := acs_user.new (user_id, object_type, creation_date,
- creation_user, creation_ip, email, ...
- RETURN v_user_id;
- END;
-END acs;
-/
-show errors
-
-
+
+
Other Things to Watch For
- We port this to
PostgreSQL> by creating the
- different objects of the
Oracle package
- as functions with a standard naming convention. We have to pay
- attention to some other details, like the lack of default
- parameters in
PostgreSQL> functions. The above
- package would become something like this:
-
-CREATE FUNCTION acs__add_user(INTEGER,INTEGER,VARCHAR,TIMESTAMP,INTEGER,INTEGER,...)
-RETURNS INTEGER AS '
-DECLARE
- user_id ALIAS FOR $1;
- object_type ALIAS FOR $2;
- creation_date ALIAS FOR $3;
- creation_user ALIAS FOR $4;
- creation_ip ALIAS FOR $5;
- ...
- v_user_id users.user_id%TYPE;
- v_rel_id membership_rels.rel_id%TYPE;
-BEGIN
- v_user_id := acs_user__new(user_id,object_type,creation_date,creation_user,creation_ip, ...);
- ...
-
- RETURN v_user_id;
-END;
-' LANGUAGE 'plpgsql';
-
+ This section explains a few other things to watch for when porting
+ Oracle
PL/SQL> functions to PostgreSQL.
-
-
-
-
- Other Things to Watch For
-
-
EXECUTE
+
EXECUTE
- The
PostgreSQL> version of EXECUTE works
- nicely, but you have to remember to use
- quote_literal(TEXT) and
-
quote_string(TEXT) as described in
- linkend="plpgsql-statements-executing-dyn-queries">. Constructs of the type
- EXECUTE ''SELECT * from $1''; will not work
- unless you use these functions.
+ The
PL/pgSQL> version of
+ EXECUTE works similar to the
+
PL/SQL> version, but you have to remember to use
+ quote_literal(text) and
+
quote_string(text) as described in
+ linkend="plpgsql-statements-executing-dyn">. Constructs of the
+ type EXECUTE ''SELECT * FROM $1''; will not
+ work unless you use these functions.
Optimizing PL/pgSQL Functions
-
PostgreSQL> gives you two function creation modifiers to optimize
- execution: iscachable (function always returns
- the same result when given the same arguments) and
- isstrict (function returns NULL if any
- argument is NULL). Consult the CREATE
- FUNCTION reference for details.
+
PostgreSQL> gives you two function creation
+ modifiers to optimize execution: the volatility (whether the
+ function always returns the same result when given the same
+ arguments) and the strictness
(whether the
+ function returns null if any argument is null). Consult the description of
+ CREATE FUNCTION for details.
- To make use of these optimization attributes, you have to use the
- <literal>WITH modifier in your CREATE
- FUNCTION statement. Something like:
+ To make use of these optimization attributes, your
+ <command>CREATE FUNCTION statement could look something
+ like this:
-CREATE FUNCTION foo(...) RETURNS INTEGER AS '
+CREATE FUNCTION foo(...) RETURNS integer AS '
...
-' LANGUAGE 'plpgsql'
-WITH (isstrict, iscachable);
+' LANGUAGE plpgsql STRICT IMMUTABLE;
-
- Appendix
-
-
-
-
- Code for my instr functions
-
+
Appendix
-
- This function should probably be integrated into the core.
-
+ This section contains the code for an Oracle-compatible
+ instr function that you can use to simplify
+ your porting efforts.
+
--
-- instr functions that mimic Oracle's counterpart
--- Syntax: instr(string1,string2,[n],[m]) where [] denotes optional params.
+-- Syntax: instr(string1, string2, [n], [m]) where [] denotes optional parameters.
--
--- Searches string1 beginning at the nth character for the mth
--- occurrence of string2. If n is negative, search backwards. If m is
--- not passed, assume 1 (search starts at first character).
---
--- Licensed under the GPL v2 or later.
+-- Searches string1 beginning at the nth character for the mth occurrence
+-- of string2. If n is negative, search backwards. If m is not passed,
+-- assume 1 (search starts at first character).
--
-CREATE FUNCTION instr(VARCHAR,VARCHAR) RETURNS INTEGER AS '
+CREATE FUNCTION instr(varchar, varchar) RETURNS integer AS '
DECLARE
pos integer;
BEGIN
- pos:= instr($1,$2,1);
+ pos:= instr($1, $2, 1);
RETURN pos;
END;
-' LANGUAGE 'plpgsql';
+' LANGUAGE plpgsql;
-CREATE FUNCTION instr(VARCHAR,VARCHAR,INTEGER) RETURNS INTEGER AS '
+CREATE FUNCTION instr(varchar, varchar, varchar) RETURNS integer AS '
DECLARE
string ALIAS FOR $1;
string_to_search ALIAS FOR $2;
beg_index ALIAS FOR $3;
pos integer NOT NULL DEFAULT 0;
- temp_str VARCHAR;
- beg INTEGER;
- length INTEGER;
- ss_length INTEGER;
+ temp_str varchar;
+ beg integer;
+ length integer;
+ ss_length integer;
BEGIN
IF beg_index > 0 THEN
+ temp_str := substring(string FROM beg_index);
+ pos := position(string_to_search IN temp_str);
- temp_str := substring(string FROM beg_index);
- pos := position(string_to_search IN temp_str);
-
- IF pos = 0 THEN
- RETURN 0;
- ELSE
- RETURN pos + beg_index - 1;
- END IF;
+ IF pos = 0 THEN
+ RETURN 0;
+ ELSE
+ RETURN pos + beg_index - 1;
+ END IF;
ELSE
- ss_length := char_length(string_to_search);
- length := char_length(string);
- beg := length + beg_index - ss_length + 2;
+ ss_length := char_length(string_to_search);
+ length := char_length(string);
+ beg := length + beg_index - ss_length + 2;
- WHILE beg > 0 LOOP
- temp_str := substring(string FROM beg FOR ss_length);
- pos := position(string_to_search IN temp_str);
+ WHILE beg > 0 LOOP
+ temp_str := substring(string FROM beg FOR ss_length);
+ pos := position(string_to_search IN temp_str);
+
+ IF pos > 0 THEN
+ RETURN beg;
+ END IF;
- IF pos > 0 THEN
- RETURN beg;
- END IF;
+ beg := beg - 1;
+ END LOOP;
- beg := beg - 1;
- END LOOP;
- RETURN 0;
+ RETURN 0;
END IF;
END;
-' LANGUAGE 'plpgsql';
+' LANGUAGE plpgsql;
---
--- Licensed under the GPL v2 or later.
---
-CREATE FUNCTION instr(VARCHAR,VARCHAR,INTEGER,INTEGER) RETURNS INTEGER AS '
+
+CREATE FUNCTION instr(varchar, varchar, integer, integer) RETURNS integer AS '
DECLARE
string ALIAS FOR $1;
string_to_search ALIAS FOR $2;
beg_index ALIAS FOR $3;
occur_index ALIAS FOR $4;
pos integer NOT NULL DEFAULT 0;
- occur_number INTEGER NOT NULL DEFAULT 0;
- temp_str VARCHAR;
- beg INTEGER;
- i INTEGER;
- length INTEGER;
- ss_length INTEGER;
+ occur_number integer NOT NULL DEFAULT 0;
+ temp_str varchar;
+ beg integer;
+ i integer;
+ length integer;
+ ss_length integer;
BEGIN
IF beg_index > 0 THEN
beg := beg_index;
RETURN 0;
END IF;
END;
-' LANGUAGE 'plpgsql';
+' LANGUAGE plpgsql;
-
-
+
PL/Python - Python Procedural Language
createlang plpython dbname>.
+
+ If a language is installed into template1>, all subsequently
+ created databases will have the language installed automatically.
+
+
+
Users of source packages must specially enable the build of
- PL/Python during the installation process (refer to the
- installation instructions for more information). Users of binary
+ PL/Python during the installation process. (Refer to the
+ installation instructions for more information.) Users of binary
packages might find PL/Python in a separate subpackage.
PL/Python Functions
- The Python code you write gets transformed into a function. E.g.,
+ The Python code you write gets transformed into a Python function. E.g.,
CREATE FUNCTION myfunc(text) RETURNS text
AS 'return args[0]'
- LANGUAGE 'plpython';
+ LANGUAGE plpython;
gets transformed into
If you do not provide a return value, Python returns the default
- None which may or may not be what you want. The
+ None. The
language module translates Python's None into the
SQL null value.
myfunc example, args[0]> contains
whatever was passed in as the text argument. For
myfunc2(text, integer), args[0]>
- would contain the text variable and
- args[1] the integer variable.
+ would contain the text argument and
+ args[1] the integer argument.
TD["level"]> contains one of ROW>,
STATEMENT>, and UNKNOWN>.
TD["name"]> contains the trigger name, and
- TD["relid"]> contains the relation ID of the table on
+ TD["relid"]> contains the OID of the table on
which the trigger occurred. If the trigger was called with
arguments they are available in TD["args"][0]> to
TD["args"][(n-1)]>.
- If the TD["when"] is BEFORE>, you may
+ If TD["when"] is BEFORE>, you may
return None or "OK" from the
Python function to indicate the row is unmodified,
"SKIP"> to abort the event, or "MODIFY"> to
optional limit argument causes that query to be run and the result
to be returned in a result object. The result object emulates a
list or dictionary object. The result object can be accessed by
- row number and field name. It has these additional methods:
- nrows() which returns the number of rows
+ row number and column name. It has these additional methods:
+ nrows which returns the number of rows
returned by the query, and status which is the
- SPI_exec return variable. The result object
+ SPI_exec() return value. The result object
can be modified.
returns up to 5 rows from my_table. If
my_table has a column
- my_field, it would be accessed as
+ my_column, it would be accessed as
-foo = rv[i]["my_field"]
+foo = rv[i]["my_column"]
- The second function plpy.prepare is called
- with a query string and a list of argument types if you have bind
- variables in the query. For example:
+ The second function, plpy.prepare, prepares the
+ execution plan for a query. It is called with a query string and a
+ list of parameter types, if you have parameter references in the
+ query. For example:
plan = plpy.prepare("SELECT last_name FROM my_users WHERE first_name = $1", [ "text" ])
text is the type of the variable you will be
- passing as $1. After preparing a statement, you
+ passing for $1. After preparing a statement, you
use the function plpy.execute to run it:
rv = plpy.execute(plan, [ "name" ], 5)
- The limit argument is optional in the call to
- plpy.execute.
+ The third argument is the limit and is optional.
in the immediate termination of that function by the server; it is
not possible to trap error conditions using Python try
... catch constructs. For example, a syntax error in an
- SQL statement passed to the plpy.execute() call
+ SQL statement passed to the plpy.execute call
will terminate the function. This behavior may be changed in a
future release.
When you prepare a plan using the PL/Python module it is
automatically saved. Read the SPI documentation (
linkend="spi">) for a description of what this means.
-
-
In order to make effective use of this across function calls
one needs to use one of the persistent storage dictionaries
- SD or GD, see
- . For example:
+ SD or GD (see
+ ). For example:
-CREATE FUNCTION usesavedplan ( ) RETURNS TRIGGER AS '
- if SD.has_key("plan"):
- plan = SD["plan"]
- else:
- plan = plpy.prepare("SELECT 1")
- SD["plan"] = plan
- # rest of function
-' LANGUAGE 'plpython';
+CREATE FUNCTION usesavedplan() RETURNS trigger AS '
+ if SD.has_key("plan"):
+ plan = SD["plan"]
+ else:
+ plan = plpy.prepare("SELECT 1")
+ SD["plan"] = plan
+ # rest of function
+' LANGUAGE plpython;
trigger procedures.
- This package was originally written by Jan Wieck.
-
-
Tcl interpreter. In addition to the limited command set of safe Tcl, only
a few commands are available to access the database via SPI and to raise
messages via elog()>. There is no way to access internals of the
- database backend or to gain OS-level access under the permissions of the
-
PostgreSQL user ID, as a C function can do.
+ database server or to gain OS-level access under the permissions of the
+
PostgreSQL server process, as a C function can do.
Thus, any unprivileged database user may be
permitted to use this language.
- The other, implementation restriction is that Tcl procedures cannot
+ The other, implementation restriction is that Tcl functions cannot
be used to create input/output functions for new data types.
Sometimes it is desirable to write Tcl functions that are not restricted
- to safe Tcl --- for example, one might want a Tcl function that sends
- mail. To handle these cases, there is a variant of
PL/Tcl> called PL/TclU>
+ to safe Tcl. For example, one might want a Tcl function that sends
+
email. To handle these cases, there is a variant of
PL/Tcl> called PL/TclU>
(for untrusted Tcl). This is the exact same language except that a full
Tcl interpreter is used.
If PL/TclU> is used, it must be
installed as an untrusted procedural language so that only
library directory if Tcl/Tk support is specified
in the configuration step of the installation procedure. To install
PL/Tcl> and/or PL/TclU> in a particular database, use the
- <filename>createlang script, for example
+ <command>createlang program, for example
createlang pltcl dbname> or
createlang pltclu dbname>.
-
-
Description
-
-
+
PL/Tcl Functions and Arguments
- To create a function in the
PL/Tcl> language, use the standard syntax
+ To create a function in the
PL/Tcl> language, use the standard syntax:
CREATE FUNCTION funcname (argument-types) RETURNS return-type AS '
# PL/Tcl function body
-' LANGUAGE 'pltcl';
-
+' LANGUAGE pltcl;
+
-
PL/TclU> is the same, except that the language should be specified as
+
PL/TclU> is the same, except that the language has to be specified as
pltclu>.
The body of the function is simply a piece of Tcl script.
When the function is called, the argument values are passed as
- variables $1 ... $n to the
+ variables $1 ... $n to the
Tcl script. The result is returned
from the Tcl code in the usual way, with a return
- statement. For example, a function
+ statement.
+
+
+ For example, a function
returning the greater of two integer values could be defined as:
-CREATE FUNCTION tcl_max (integer, integer) RETURNS integer AS '
+CREATE FUNCTION tcl_max(integer, integer) RETURNS integer AS '
if {$1 > $2} {return $1}
return $2
-' LANGUAGE 'pltcl' WITH (isStrict);
-
+' LANGUAGE pltcl STRICT;
+
- Note the clause WITH (isStrict)>, which saves us from
- having to think about NULL input values: if a NULL is passed, the
- function will not be called at all, but will just return a NULL
+ Note the clause STRICT>, which saves us from
+ having to think about null input values: if a null value is passed, the
+ function will not be called at all, but will just return a null
result automatically.
- In a non-strict function,
- if the actual value of an argument is NULL, the corresponding
- $n variable will be set to an empty string.
- To detect whether a particular argument is NULL, use the function
+ In a nonstrict function,
+ if the actual value of an argument is null, the corresponding
+ $n variable will be set to an empty string.
+ To detect whether a particular argument is null, use the function
argisnull>. For example, suppose that we wanted tcl_max
- with one null and one non-null argument to return the non-null
- argument, rather than NULL:
+ with one null and one nonnull argument to return the nonnull
+ argument, rather than null:
-CREATE FUNCTION tcl_max (integer, integer) RETURNS integer AS '
+CREATE FUNCTION tcl_max(integer, integer) RETURNS integer AS '
if {[argisnull 1]} {
if {[argisnull 2]} { return_null }
return $2
if {[argisnull 2]} { return $1 }
if {$1 > $2} {return $1}
return $2
-' LANGUAGE 'pltcl';
-
+' LANGUAGE pltcl;
+
- Composite-type arguments are passed to the procedure as Tcl arrays.
- The element names of the array are the attribute names of the composite
- type. If an attribute in the passed row
- has the NULL value, it will not appear in the array! Here is
- an example that defines the overpaid_2 function (as found in the
- older
PostgreSQL documentation) in PL/Tcl:
-
-CREATE FUNCTION overpaid_2 (EMP) RETURNS bool AS '
+ Composite-type arguments are passed to the function as Tcl
+ arrays. The element names of the array are the attribute names
+ of the composite type. If an attribute in the passed row has the
+ null value, it will not appear in the array. Here is an example:
+
+CREATE TABLE employee (
+ name text,
+ salary integer,
+ age integer
+);
+
+CREATE FUNCTION overpaid(employee) RETURNS boolean AS '
if {200000.0 < $1(salary)} {
return "t"
}
return "t"
}
return "f"
-' LANGUAGE 'pltcl';
-
+' LANGUAGE pltcl;
+
- There is not currently any support for returning a composite-type
+ There is currently no support for returning a composite-type
result value.
- 2>
+ 1>
- 2>
+ 1 id="pltcl-data">
Data Values in PL/Tcl
- The argument values supplied to a PL/Tcl function's script are simply
+ The argument values supplied to a PL/Tcl function's code are simply
the input arguments converted to text form (just as if they had been
- displayed by a SELECT statement). Conversely, the return>
+ displayed by a SELECT> statement). Conversely, the return>
command will accept any string that is acceptable input format for
the function's declared return type. So, the PL/Tcl programmer can
manipulate data values as if they were just text.
- 2>
+ 1>
- 2>
+ 1 id="pltcl-global">
Global Data in PL/Tcl
Sometimes it
- is useful to have some global status data that is held between two
- calls to a procedure or is shared between different procedures.
+ is useful to have some global data that is held between two
+ calls to a function or is shared between different functions.
This is easily done since
- all PL/Tcl procedures executed in one backend share the same
+ all PL/Tcl functions executed in one session share the same
safe Tcl interpreter. So, any global Tcl variable is accessible to
- all PL/Tcl procedure calls, and will persist for the duration of the
- SQL
client connection. (Note that
PL/TclU> functions likewise share
+ all PL/Tcl function calls and will persist for the duration of the
+ SQL
session. (Note that
PL/TclU> functions likewise share
global data, but they are in a different Tcl interpreter and cannot
communicate with PL/Tcl functions.)
- To help protect PL/Tcl procedures from unintentionally interfering
+ To help protect PL/Tcl functions from unintentionally interfering
with each other, a global
- array is made available to each procedure via the upvar>
- command. The global name of this variable is the procedure's internal
- name and the local name is GD>. It is recommended that
+ array is made available to each function via the upvar>
+ command. The global name of this variable is the function's internal
+ name, and the local name is GD>. It is recommended that
GD> be used
- for private status data of a procedure. Use regular Tcl global variables
+ for private data of a function. Use regular Tcl global variables
only for values that you specifically intend to be shared among multiple
- procedures.
+ functions.
An example of using GD> appears in the
spi_execp example below.
- 2>
+ 1>
- 2>
+ 1 id="pltcl-dbaccess">
Database Access from PL/Tcl
The following commands are available to access the database from
- the body of a PL/Tcl procedure:
-
+ the body of a PL/Tcl function:
- spi_exec ?-count n? ?-array name? query ?loop-body?
+ spi_exec ?-count n? ?-array name? command ?loop-body?
- Execute an SQL query given as a string. An error in the query
- causes an error to be raised. Otherwise, the command's return value
+ Executes an SQL command given as a string. An error in the command
+ causes an error to be raised. Otherwise, the return value of spi_exec
is the number of rows processed (selected, inserted, updated, or
- deleted) by the query, or zero if the query is a utility
- statement. In addition, if the query is a SELECT statement, the
+ deleted) by the command, or zero if the command is a utility
+ statement. In addition, if the command is a SELECT> statement, the
values of the selected columns are placed in Tcl variables as
described below.
The optional -count> value tells
spi_exec the maximum number of rows
- to process in the query. The effect of this is comparable to
- setting up the query as a cursor and then saying FETCH n>.
+ to process in the command. The effect of this is comparable to
+ setting up a query as a cursor and then saying FETCH n>>.
- If the query is a SELECT> statement, the values of the statement's
+ If the command is a SELECT> statement, the values of the
result columns are placed into Tcl variables named after the columns.
If the -array> option is given, the column values are
- instead stored into the named associative array, with the SELECT
+ instead stored into the named associative array, with the
column names used as array indexes.
- If the query is a SELECT statement and no loop-body>
+ If the command is a SELECT> statement and no loop-body>
script is given, then only the first row of results are stored into
- Tcl variables; remaining rows, if any, are ignored. No store occurs
+ Tcl variables; remaining rows, if any, are ignored. No storing occurs
if the
- SELECT returns no rows (this case can be detected by checking the
- result of spi_exec). For example,
+ query returns no rows. (This case can be detected by checking the
+ result of spi_exec.) For example,
spi_exec "SELECT count(*) AS cnt FROM pg_proc"
-
+
will set the Tcl variable $cnt> to the number of rows in
the pg_proc> system catalog.
If the optional loop-body> argument is given, it is
a piece of Tcl script that is executed once for each row in the
- SELECT result (note: loop-body> is ignored if the given
- query is not a SELECT). The values of the current row's fields
+ query result. (loop-body> is ignored if the given
+ command is not a SELECT>.) The values of the current row's columns
are stored into Tcl variables before each iteration. For example,
spi_exec -array C "SELECT * FROM pg_class" {
elog DEBUG "have table $C(relname)"
}
-
+
- will print a DEBUG log message for every row of pg_class. This
+ will print a log message for every row of pg_class>. This
feature works similarly to other Tcl looping constructs; in
particular continue> and break> work in the
usual way inside the loop body.
- If a field of a SELECT result is NULL, the target
+ If a column of a query result is null, the target
variable for it is unset> rather than being set.
Prepares and saves a query plan for later execution. The saved plan
- will be retained for the life of the current backend.
+ will be retained for the life of the current session.
- The query may use arguments>, which are placeholders for
+ The query may use parameters, that is, placeholders for
values to be supplied whenever the plan is actually executed.
- In the query string, refer to arguments
- by the symbols $1 ... $n.
- If the query uses arguments, the names of the argument types
+ In the query string, refer to parameters
+ by the symbols $1 ... $n.
+ If the query uses parameters, the names of the parameter types
must be given as a Tcl list. (Write an empty list for
- typelist if no arguments are used.)
- Presently, the argument types must be identified by the internal
- type names shown in pg_type; for example int4> not
+ typelist if no parameters are used.)
+ Presently, the parameter types must be identified by the internal
+ type names shown in the system table pg_type>; for example int4> not
integer>.
spi_execp> ?-count n? ?-array name? ?-nulls string? queryid ?value-list? ?loop-body?
- Execute a query previously prepared with spi_prepare>.
+ Executes a query previously prepared with spi_prepare>.
queryid is the ID returned by
- spi_prepare>. If the query references arguments,
- a value-list must be supplied: this
- is a Tcl list of actual values for the arguments. This must be
- the same length as the argument type list previously given to
+ spi_prepare>. If the query references parameters,
+ a value-list must be supplied. This
+ is a Tcl list of actual values for the parameters. The list must be
+ the same length as the parameter type list previously given to
spi_prepare>. Omit value-list
- if the query has no arguments.
+ if the query has no parameters.
The optional value for -nulls> is a string of spaces and
'n'> characters telling spi_execp
- which of the arguments are null values. If given, it must have exactly the
+ which of the parameters are null values. If given, it must have exactly the
same length as the value-list. If it
- is not given, all the argument values are non-NULL.
+ is not given, all the parameter values are nonnull.
- Except for the way in which the query and its arguments are specified,
+ Except for the way in which the query and its parameters are specified,
spi_execp> works just like spi_exec>.
The -count>, -array>, and
loop-body options are the same,
Here's an example of a PL/Tcl function using a prepared plan:
CREATE FUNCTION t1_count(integer, integer) RETURNS integer AS '
if {![ info exists GD(plan) ]} {
# prepare the saved plan on the first call
}
spi_execp -count 1 $GD(plan) [ list $1 $2 ]
return $cnt
-' LANGUAGE 'pltcl';
-
+' LANGUAGE pltcl;
+
Note that each backslash that Tcl should see must be doubled when
we type in the function, since the main parser processes
- backslashes too in CREATE FUNCTION. We need backslashes inside
+ backslashes, too, in CREATE FUNCTION>. We need backslashes inside
the query string given to spi_prepare> to ensure that
- the $n> markers will be passed through to
+ the $n> markers will be passed through to
spi_prepare> as-is, and not
replaced by Tcl variable substitution.
Returns the OID of the row inserted by the last
- spi_exec>'d or spi_execp>'d query,
- if that query was a single-row INSERT. (If not, you get zero.)
+ spi_exec> or spi_execp>,
+ if the command was a single-row INSERT>. (If not, you get zero.)
Duplicates all occurrences of single quote and backslash characters
in the given string. This may be used to safely quote strings
- that are to be inserted into SQL queries given
+ that are to be inserted into SQL commands given
to spi_exec or
spi_prepare.
- For example, think about a query string like
+ For example, think about an SQL command string like
"SELECT '$val' AS ret"
- where the Tcl variable val actually contains
+ where the Tcl variable val> actually contains
doesn't. This would result
- in the final query string
+ in the final command string
SELECT 'doesn't' AS ret
which would cause a parse error during
spi_exec or
spi_prepare.
- The submitted query should contain
+ The submitted command should contain
SELECT 'doesn''t' AS ret
- which can be formed in PL/Tcl as
+ which can be formed in PL/Tcl using
"SELECT '[ quote $val ]' AS ret"
One advantage of spi_execp is that you don't
- have to quote argument values like this, since the arguments are never
- parsed as part of an SQL query string.
+ have to quote parameter values like this, since the parameters are never
+ parsed as part of an SQL command string.
elog> level msg
- Emit a log or error message. Possible levels are
+ Emits a log or error message. Possible levels are
DEBUG>, LOG>, INFO>,
NOTICE>, WARNING>, ERROR>, and
FATAL>. Most simply emit the given message just like
- the elog> backend C function. ERROR>
+ the elog> C function. ERROR>
raises an error condition: further execution of the function is
abandoned, and the current transaction is aborted.
FATAL> aborts the transaction and causes the current
- backend to shut down (there is probably no good reason to use
+ session to shut down. (There is probably no good reason to use
this error level in PL/Tcl functions, but it's provided for
- completeness).
+ completeness.)
+
- 2>
+ 1>
- 2>
+ 1 id="pltcl-trigger">
Trigger Procedures in PL/Tcl
- Trigger procedures can be written in PL/Tcl. As is customary in
-
PostgreSQL, a procedure that's to be called
+ Trigger procedures can be written in PL/Tcl.
+
PostgreSQL requires that a procedure that is to be called
as a trigger must be declared as a function with no arguments
and a return type of trigger>.
- <replaceable class="Parameter">$TG_namee>
+ <varname>$TG_namee>
- The name of the trigger from the CREATE TRIGGER statement.
+ The name of the trigger from the CREATE TRIGGER statement.
- <replaceable class="Parameter">$TG_relide>
+ <varname>$TG_relide>
The object ID of the table that caused the trigger procedure
- <replaceable class="Parameter">$TG_relattse>
+ <varname>$TG_relattse>
- A Tcl list of the table field names, prefixed with an empty list
- element. So looking up a
n element name in the list with
Tcl>'s
+ A Tcl list of the table column names, prefixed with an empty list
+ element. So looking up a
column name in the list with
Tcl>'s
lsearch> command returns the element's number starting
- with 1 for the first column, the same way the fields are customarily
+ with 1 for the first column, the same way the columns are customarily
- <replaceable class="Parameter">$TG_whene>
+ <varname>$TG_whene>
The string BEFORE> or AFTER> depending on the
- <replaceable class="Parameter">$TG_levele>
+ <varname>$TG_levele>
The string ROW> or STATEMENT> depending on the
- <replaceable class="Parameter">$TG_ope>
+ <varname>$TG_ope>
- The string INSERT>, UPDATE> or
+ The string INSERT>, UPDATE>, or
DELETE> depending on the type of trigger call.
- <replaceable class="Parameter">$NEWe>
+ <varname>$NEWe>
- An associative array containing the values of the new table row for
- INSERT/UPDATE actions, or empty for DELETE. The array is indexed
- by field name. Fields that are NULL will not appear in the array!
+ An associative array containing the values of the new table
+ row for INSERT> or UPDATE> actions, or
+ empty for DELETE>. The array is indexed by column
+ name. Columns that are null will not appear in the array.
- <replaceable class="Parameter">$OLDe>
+ <varname>$OLDe>
- An associative array containing the values of the old table row for
- UPDATE/DELETE actions, or empty for INSERT. The array is indexed
- by field name. Fields that are NULL will not appear in the array!
+ An associative array containing the values of the old table
+ row for UPDATE> or DELETE> actions, or
+ empty for INSERT>. The array is indexed by column
+ name. Columns that are null will not appear in the array.
- <replaceable class="Parameter">$argse>
+ <varname>$argse>
A Tcl list of the arguments to the procedure as given in the
- CREATE TRIGGER statement. These arguments are also accessible as
- $1 ... $n in the procedure body.
+ CREATE TRIGGER statement. These arguments are also accessible as
+ $1 ... $n in the procedure body.
The return value from a trigger procedure can be one of the strings
OK> or SKIP>, or a list as returned by the
array get> Tcl command. If the return value is OK>,
- the operation (INSERT/UPDATE/DELETE) that fired the trigger will proceed
+ the operation (INSERT>/UPDATE>/DELETE>) that fired the trigger will proceed
normally. SKIP> tells the trigger manager to silently suppress
the operation for this row. If a list is returned, it tells PL/Tcl to
return a modified row to the trigger manager that will be inserted
- instead of the one given in $NEW (this works for INSERT/UPDATE
- only). Needless to say that all this is only meaningful when the trigger
- is BEFORE and FOR EACH ROW; otherwise the return value is ignored.
+ instead of the one given in $NEW>. (This works for INSERT> and UPDATE>
+ only.) Needless to say that all this is only meaningful when the trigger
+ is BEFORE> and FOR EACH ROW>; otherwise the return value is ignored.
Here's a little example trigger procedure that forces an integer value
in a table to keep track of the number of updates that are performed on the
row. For new rows inserted, the value is initialized to 0 and then
- incremented on every update operation:
+ incremented on every update operation.
-CREATE FUNCTION trigfunc_modcount() RETURNS TRIGGER AS '
+CREATE FUNCTION trigfunc_modcount() RETURNS trigger AS '
switch $TG_op {
INSERT {
set NEW($1) 0
}
}
return [array get NEW]
-' LANGUAGE 'pltcl';
+' LANGUAGE pltcl;
CREATE TABLE mytab (num integer, description text, modcnt integer);
CREATE TRIGGER trig_mytab_modcount BEFORE INSERT OR UPDATE ON mytab
FOR EACH ROW EXECUTE PROCEDURE trigfunc_modcount('modcnt');
-
+
Notice that the trigger procedure itself does not know the column
name; that's supplied from the trigger arguments. This lets the
- trigger procedure be re-used with different tables.
+ trigger procedure be reused with different tables.
- 2>
+ 1>
- 2>
-
Modules and the unknown> command
+ 1 id="pltcl-unknown">
+
Modules and the unknown> command
- PL/Tcl has support for auto-loading Tcl code when used.
+ PL/Tcl has support for autoloading Tcl code when used.
It recognizes a special table, pltcl_modules>, which
is presumed to contain modules of Tcl code. If this table
exists, the module unknown> is fetched from the table
While the unknown> module could actually contain any
initialization script you need, it normally defines a Tcl
- <quote>unknown> procedure that is invoked whenever Tcl does
+ <function>unknown> procedure that is invoked whenever Tcl does
not recognize an invoked procedure name.
PL/Tcl>'s standard version
of this procedure tries to find a module in pltcl_modules>
that will define the required procedure. If one is found, it is
support scripts to maintain these tables:
pltcl_loadmod>, pltcl_listmod>,
pltcl_delmod>, as well as source for the standard
- unknown module share/unknown.pltcl>. This module
+ unknown> module in share/unknown.pltcl>. This module
must be loaded
into each database initially to support the autoloading mechanism.
must be readable by all, but it is wise to make them owned and
writable only by the database administrator.
- 2>
+ 1>
- 2>
+ 1 id="pltcl-procnames">
Tcl Procedure Names
differ. Tcl, however, requires all procedure names to be distinct.
PL/Tcl deals with this by making the internal Tcl procedure names contain
the object
- ID of the procedure's pg_proc> row as part of their name. Thus,
+ ID of the function from the system table pg_proc> as part of their name. Thus,
PostgreSQL functions with the same name
- and different argument types will be different Tcl procedures too. This
+ and different argument types will be different Tcl procedures, too. This
is not normally a concern for a PL/Tcl programmer, but it might be visible
when debugging.
-
-
-
+
+
PyGreSQL - Python Interface
API at
url="http://www.python.org/topics/database/DatabaseAPI-2.0.html"
>http://www.python.org/topics/database/DatabaseAPI-2.0.html.
-
-
A tutorial-like introduction to the
DB-API can be
found at
url="http://www2.linuxjournal.com/lj-issues/issue49/2605.html"
- >http://www2.linuxjournal.com/lj-issues/issue49/2605.html
+ >http://www2.linuxjournal.com/lj-issues/issue49/2605.html.
- pgqueryobject that handles query results.
+ pgqueryobject, which handles query results.
- If you want to see a simple example of the use of some of these
- functions, see
- >http://www.druid.net/rides where you can find a link at the
+ If you want to see a simple example of the use this module,
+ see
where you can find a link at the
bottom to the actual
Python code for the
page.
INV_WRITE
- large objects access modes, used by
+ Large objects access modes, used by
(pgobject.)locreate and
- (pglarge.)open.
+ (pglarge.)open
SEEK_END
- positional flags, used by (pglarge.)seek.
+ Positional flags, used by (pglarge.)seek
__version__
- constants that give the current version
+ Constants that give the current version
to handle general connection parameters without heavy code in your
programs. You can prompt the user for a value, put it in the
default variable, and forget it, without having to modify your
- environment. The support for default variables can be disabled by
+ environment. The support for default variables can be disabled at build time by
setting the option in the Python
Setup> file. Methods relative to this are specified by the tag [DV].
- All variables are set to None at module
+ All default values are set to None at module
initialization, specifying that standard environment variables
should be used.
-
Name of connected database (string/None>).
+
Name of connected database (string/None>)
-
Name of the server host (string/None>).
+
Name of the server host (string/None>)
-
Port used by the database server (integer/-1).
+
Port used by the database server (integer/-1)
- Options for the server (string/None>).
+ Options for the server (string/None>)
- File or tty for optional debug output from backend
- (string/None>).
+ File or TTY for optional debug output from server
+ (string/None>)
-
PostgreSQL user (string/
None>).
+
PostgreSQL user (string/
None>)
-
Password for user (string/None>).
+
Password for user (string/None>)
This method opens a connection to a specified database on a given
-
PostgreSQL server. You can use
- key words here, as described in the
-
Python tutorial. The names of the
+
PostgreSQL server. The arguments can be
+ given using key words here. The names of the
key words are the name of the parameters given in the syntax
line. For a precise description of the parameters, please refer
- to
the PostgreSQL user manual.
+ to .
Procedural Languages
-
-
Introduction
-
PostgreSQL allows users to add new
programming languages to be available for writing functions and
could serve as glue
between
PostgreSQL and an existing implementation
of a programming language. The handler itself is a special
- programming language function compiled into a shared object and
+ C language function compiled into a shared object and
loaded on demand.
available in the standard
PostgreSQL
distribution, which can serve as examples.
-
Installing Procedural Languages
A procedural language must be installed
into each
database where it is to be used. But procedural languages installed in
- the template1 database are automatically available in all
+ the database template1> are automatically available in all
subsequently created databases. So the database administrator can
- decide which languages are available in which databases, and can make
+ decide which languages are available in which databases and can make
some languages available by default if he chooses.
For the languages supplied with the standard distribution, the
- shell script createlang may be used instead
- of carrying out the details by hand. For example, to install
PL/pgSQL
- into the template1 database, use
+ program createlang may be used to install the
+ language instead of carrying out the details by hand. For
+ example, to install the language
+
PL/pgSQL into the database
+ template1>, use
createlang plpgsql template1
The manual procedure described below is only recommended for
- installing custom languages that <filename>createlang>
+ installing custom languages that <command>createlang>
does not know about.
- A procedural language is installed in the database in three
- steps, which must be carried out by a database superuser.
+ A procedural language is installed in a database in three steps,
+ which must be carried out by a database superuser. The
+
createlang programm automates
+ linkend="xplang-install-cr1"> and
+ linkend="xplang-install-cr2">.
The handler must be declared with the command
-CREATE FUNCTION handler_function_name ()
- RETURNS LANGUAGE_HANDLER AS
- 'path-to-shared-object' LANGUAGE C;
+CREATE FUNCTION handler_function_name()
+ RETURNS language_handler
+ AS 'path-to-shared-object'
+ LANGUAGE C;
- The special return type of LANGUAGE_HANDLER tells
- the database that this function does not return one of
+ 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
CREATE TRUSTED PROCEDURAL LANGUAGE language-name
HANDLER handler_function_name;
- The optional key word TRUSTED tells whether
+ The optional key word TRUSTED specifies that
ordinary database users that have no superuser privileges should
be allowed to use this language to create functions and trigger
procedures. Since PL functions are executed inside the database
- In a default
PostgreSQL installation,
- the handler for the
PL/pgSQL language
- is built and installed into the library
- directory. If
Tcl/Tk> support is configured in, the handlers for
-
PL/Tcl> and PL/TclU> are also built and installed in the same
- location. Likewise, the
PL/Perl> and PL/PerlU> handlers are built
- and installed if Perl support is configured, and
PL/Python> is
- installed if Python support is configured. The
-
createlang script automates
- linkend="xplang-install-cr1"> and
- linkend="xplang-install-cr2"> described above.
+ shows how the manual
+ installation procedure would work with the language
-
+ id="xplang-install-example">
Manual Installation of PL/pgSQL
shared object for the
PL/pgSQL language's call handler function.
-CREATE FUNCTION plpgsql_call_handler () RETURNS LANGUAGE_HANDLER AS
+CREATE FUNCTION plpgsql_call_handler() RETURNS language_handler AS
'$libdir/plpgsql' LANGUAGE C;
+ In a default
PostgreSQL installation,
+ the handler for the
PL/pgSQL language
+ is built and installed into the library
+ directory. If
Tcl/Tk> support is configured in, the handlers for
+
PL/Tcl> and PL/TclU> are also built and installed in the same
+ location. Likewise, the
PL/Perl> and PL/PerlU> handlers are built
+ and installed if Perl support is configured, and
PL/Python> is
+ installed if Python support is configured.
+
+