Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
P
Postgres FD Implementation
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Abuhujair Javed
Postgres FD Implementation
Commits
883ac5ca
Commit
883ac5ca
authored
Dec 30, 2004
by
Tom Lane
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
More minor updates and copy-editing.
parent
1fbdb6bc
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
513 additions
and
394 deletions
+513
-394
doc/src/sgml/plhandler.sgml
doc/src/sgml/plhandler.sgml
+7
-1
doc/src/sgml/plperl.sgml
doc/src/sgml/plperl.sgml
+104
-77
doc/src/sgml/plpgsql.sgml
doc/src/sgml/plpgsql.sgml
+76
-62
doc/src/sgml/plpython.sgml
doc/src/sgml/plpython.sgml
+19
-14
doc/src/sgml/pltcl.sgml
doc/src/sgml/pltcl.sgml
+181
-165
doc/src/sgml/spi.sgml
doc/src/sgml/spi.sgml
+56
-33
doc/src/sgml/xfunc.sgml
doc/src/sgml/xfunc.sgml
+8
-16
doc/src/sgml/xplang.sgml
doc/src/sgml/xplang.sgml
+62
-26
No files found.
doc/src/sgml/plhandler.sgml
View file @
883ac5ca
<!--
<!--
$PostgreSQL: pgsql/doc/src/sgml/plhandler.sgml,v 1.
2 2003/11/29 19:51:37 pgsq
l Exp $
$PostgreSQL: pgsql/doc/src/sgml/plhandler.sgml,v 1.
3 2004/12/30 21:45:36 tg
l Exp $
-->
-->
<chapter id="plhandler">
<chapter id="plhandler">
...
@@ -154,6 +154,12 @@ CREATE LANGUAGE plsample
...
@@ -154,6 +154,12 @@ CREATE LANGUAGE plsample
</programlisting>
</programlisting>
</para>
</para>
<para>
The procedural languages included in the standard distribution
are good references when trying to write your own call handler.
Look into the <filename>src/pl</> subdirectory of the source tree.
</para>
</chapter>
</chapter>
<!-- Keep this comment at the end of the file
<!-- Keep this comment at the end of the file
...
...
doc/src/sgml/plperl.sgml
View file @
883ac5ca
<!--
<!--
$PostgreSQL: pgsql/doc/src/sgml/plperl.sgml,v 2.3
4 2004/12/13 18:05:08 petere
Exp $
$PostgreSQL: pgsql/doc/src/sgml/plperl.sgml,v 2.3
5 2004/12/30 21:45:36 tgl
Exp $
-->
-->
<chapter id="plperl">
<chapter id="plperl">
...
@@ -132,9 +132,66 @@ CREATE FUNCTION empcomp(employee) RETURNS integer AS $$
...
@@ -132,9 +132,66 @@ CREATE FUNCTION empcomp(employee) RETURNS integer AS $$
return $emp->{basesalary} + $emp->{bonus};
return $emp->{basesalary} + $emp->{bonus};
$$ LANGUAGE plperl;
$$ LANGUAGE plperl;
SELECT name, empcomp(employee) FROM employee;
SELECT name, empcomp(employee
.*
) FROM employee;
</programlisting>
</programlisting>
</para>
</para>
<para>
A PL/Perl function can return a composite-type result using the same
approach: return a reference to a hash that has the required attributes.
For example,
<programlisting>
CREATE TYPE testrowperl AS (f1 integer, f2 text, f3 text);
CREATE OR REPLACE FUNCTION perl_row() RETURNS testrowperl AS $$
return {f2 => 'hello', f1 => 1, f3 => 'world'};
$$ LANGUAGE plperl;
SELECT * FROM perl_row();
</programlisting>
Any columns in the declared result data type that are not present in the
hash will be returned as NULLs.
</para>
<para>
PL/Perl functions can also return sets of either scalar or composite
types. To do this, return a reference to an array that contains
either scalars or references to hashes, respectively. Here are
some simple examples:
<programlisting>
CREATE OR REPLACE FUNCTION perl_set_int(int) RETURNS SETOF INTEGER AS $$
return [0..$_[0]];
$$ LANGUAGE plperl;
SELECT * FROM perl_set_int(5);
CREATE OR REPLACE FUNCTION perl_set() RETURNS SETOF testrowperl AS $$
return [
{ f1 => 1, f2 => 'Hello', f3 => 'World' },
{ f1 => 2, f2 => 'Hello', f3 => 'PostgreSQL' },
{ f1 => 3, f2 => 'Hello', f3 => 'PL/Perl' }
];
$$ LANGUAGE plperl;
SELECT * FROM perl_set();
</programlisting>
Note that when you do this, Perl will have to build the entire array in
memory; therefore the technique does not scale to very large result sets.
</para>
<para>
<application>PL/Perl</> does not currently have full support for
domain types: it treats a domain the same as the underlying scalar
type. This means that constraints associated with the domain will
not be enforced. This is not an issue for function arguments, but
it is a hazard if you declare a <application>PL/Perl</> function
as returning a domain type.
</para>
</sect1>
</sect1>
<sect1 id="plperl-database">
<sect1 id="plperl-database">
...
@@ -202,6 +259,37 @@ $res = $rv->{status};
...
@@ -202,6 +259,37 @@ $res = $rv->{status};
To get the number of rows affected, do:
To get the number of rows affected, do:
<programlisting>
<programlisting>
$nrows = $rv->{processed};
$nrows = $rv->{processed};
</programlisting>
</para>
<para>
Here is a complete example:
<programlisting>
CREATE TABLE test (
i int,
v varchar
);
INSERT INTO test (i, v) VALUES (1, 'first line');
INSERT INTO test (i, v) VALUES (2, 'second line');
INSERT INTO test (i, v) VALUES (3, 'third line');
INSERT INTO test (i, v) VALUES (4, 'immortal');
CREATE FUNCTION test_munge() RETURNS SETOF test AS $$
my $res = [];
my $rv = spi_exec_query('select i, v from test;');
my $status = $rv->{status};
my $nrows = $rv->{processed};
foreach my $rn (0 .. $nrows - 1) {
my $row = $rv->{rows}[$rn];
$row->{i} += 200 if defined($row->{i});
$row->{v} =~ tr/A-Za-z/a-zA-Z/ if (defined($row->{v}));
push @$res, $row;
}
return $res;
$$ LANGUAGE plperl;
SELECT * FROM test_munge();
</programlisting>
</programlisting>
</para>
</para>
</listitem>
</listitem>
...
@@ -224,8 +312,14 @@ $nrows = $rv->{processed};
...
@@ -224,8 +312,14 @@ $nrows = $rv->{processed};
Perl code, the error propagates out to the calling query, causing
Perl code, the error propagates out to the calling query, causing
the current transaction or subtransaction to be aborted. This
the current transaction or subtransaction to be aborted. This
is effectively the same as the Perl <literal>die</> command.
is effectively the same as the Perl <literal>die</> command.
The other levels simply report the message to the system log
The other levels only generate messages of different
and/or client.
priority levels.
Whether messages of a particular priority are reported to the client,
written to the server log, or both is controlled by the
<xref linkend="guc-log-min-messages"> and
<xref linkend="guc-client-min-messages"> configuration
variables. See <xref linkend="runtime-config"> for more
information.
</para>
</para>
</listitem>
</listitem>
</varlistentry>
</varlistentry>
...
@@ -242,72 +336,8 @@ $nrows = $rv->{processed};
...
@@ -242,72 +336,8 @@ $nrows = $rv->{processed};
had been displayed by a <command>SELECT</command> statement).
had been displayed by a <command>SELECT</command> statement).
Conversely, the <literal>return</> command will accept any string
Conversely, the <literal>return</> command will accept any string
that is acceptable input format for the function's declared return
that is acceptable input format for the function's declared return
type. So, the PL/Perl programmer can manipulate data values as if
type. So, within the PL/Perl function,
they were just text.
all values are just text strings.
</para>
<para>
PL/Perl can also return row sets and composite types, and row sets
of composite types. Here is an example of a PL/Perl function
returning a row set of a row type. Note that a composite type is
always represented as a hash reference.
<programlisting>
CREATE TABLE test (
i int,
v varchar
);
INSERT INTO test (i, v) VALUES (1, 'first line');
INSERT INTO test (i, v) VALUES (2, 'second line');
INSERT INTO test (i, v) VALUES (3, 'third line');
INSERT INTO test (i, v) VALUES (4, 'immortal');
CREATE FUNCTION test_munge() RETURNS SETOF test AS $$
my $res = [];
my $rv = spi_exec_query('select i, v from test;');
my $status = $rv->{status};
my $nrows = $rv->{processed};
foreach my $rn (0 .. $nrows - 1) {
my $row = $rv->{rows}[$rn];
$row->{i} += 200 if defined($row->{i});
$row->{v} =~ tr/A-Za-z/a-zA-Z/ if (defined($row->{v}));
push @$res, $row;
}
return $res;
$$ LANGUAGE plperl;
SELECT * FROM test_munge();
</programlisting>
</para>
<para>
Here is an example of a PL/Perl function returning a composite
type:
<programlisting>
CREATE TYPE testrowperl AS (f1 integer, f2 text, f3 text);
CREATE OR REPLACE FUNCTION perl_row() RETURNS testrowperl AS $$
return {f2 => 'hello', f1 => 1, f3 => 'world'};
$$ LANGUAGE plperl;
</programlisting>
</para>
<para>
Here is an example of a PL/Perl function returning a row set of a
composite type. Since a row set is always a reference to an array
and a composite type is always a reference to a hash, a row set of a
composite type is a reference to an array of hash references.
<programlisting>
CREATE TYPE testsetperl AS (f1 integer, f2 text, f3 text);
CREATE OR REPLACE FUNCTION perl_set() RETURNS SETOF testsetperl AS $$
return [
{ f1 => 1, f2 => 'Hello', f3 => 'World' },
{ f1 => 2, f2 => 'Hello', f3 => 'PostgreSQL' },
{ f1 => 3, f2 => 'Hello', f3 => 'PL/Perl' }
];
$$ LANGUAGE plperl;
</programlisting>
</para>
</para>
</sect1>
</sect1>
...
@@ -317,8 +347,7 @@ $$ LANGUAGE plperl;
...
@@ -317,8 +347,7 @@ $$ LANGUAGE plperl;
<para>
<para>
You can use the global hash <varname>%_SHARED</varname> to store
You can use the global hash <varname>%_SHARED</varname> to store
data, including code references, between function calls for the
data, including code references, between function calls for the
lifetime of the current session, which is bounded from below by
lifetime of the current session.
the lifetime of the current transaction.
</para>
</para>
<para>
<para>
...
@@ -360,12 +389,12 @@ SELECT myfuncs(); /* initializes the function */
...
@@ -360,12 +389,12 @@ SELECT myfuncs(); /* initializes the function */
CREATE OR REPLACE FUNCTION use_quote(TEXT) RETURNS text AS $$
CREATE OR REPLACE FUNCTION use_quote(TEXT) RETURNS text AS $$
my $text_to_quote = shift;
my $text_to_quote = shift;
my $qfunc = $_SHARED{myquote};
my $qfunc = $_SHARED{myquote};
return &$qfunc($text_to_quote);
return &
amp;
$qfunc($text_to_quote);
$$ LANGUAGE plperl;
$$ LANGUAGE plperl;
</programlisting>
</programlisting>
(You could have replaced the above with the one-liner
(You could have replaced the above with the one-liner
<literal>return $_SHARED{myquote}-
>
($_[0]);</literal>
<literal>return $_SHARED{myquote}-
>
($_[0]);</literal>
at the expense of readability.)
at the expense of readability.)
</para>
</para>
</sect1>
</sect1>
...
@@ -619,9 +648,7 @@ CREATE TRIGGER test_valid_id_trig
...
@@ -619,9 +648,7 @@ CREATE TRIGGER test_valid_id_trig
<para>
<para>
In the current implementation, if you are fetching or returning
In the current implementation, if you are fetching or returning
very large data sets, you should be aware that these will all go
very large data sets, you should be aware that these will all go
into memory. Future features will help with this. In the
into memory.
meantime, we suggest that you not use PL/Perl if you will fetch
or return very large result sets.
</para>
</para>
</listitem>
</listitem>
</itemizedlist>
</itemizedlist>
...
...
doc/src/sgml/plpgsql.sgml
View file @
883ac5ca
<!--
<!--
$PostgreSQL: pgsql/doc/src/sgml/plpgsql.sgml,v 1.5
3 2004/12/19 22:10:41
tgl Exp $
$PostgreSQL: pgsql/doc/src/sgml/plpgsql.sgml,v 1.5
4 2004/12/30 21:45:36
tgl Exp $
-->
-->
<chapter id="plpgsql">
<chapter id="plpgsql">
...
@@ -150,7 +150,7 @@ $$ LANGUAGE plpgsql;
...
@@ -150,7 +150,7 @@ $$ LANGUAGE plpgsql;
<para>
<para>
<acronym>SQL</acronym> is the language <productname>PostgreSQL</>
<acronym>SQL</acronym> is the language <productname>PostgreSQL</>
(and most other relational databases)
use as query language. It's
and most other relational databases
use as query language. It's
portable and easy to learn. But every <acronym>SQL</acronym>
portable and easy to learn. But every <acronym>SQL</acronym>
statement must be executed individually by the database server.
statement must be executed individually by the database server.
</para>
</para>
...
@@ -214,6 +214,15 @@ $$ LANGUAGE plpgsql;
...
@@ -214,6 +214,15 @@ $$ LANGUAGE plpgsql;
Finally, a <application>PL/pgSQL</> function may be declared to return
Finally, a <application>PL/pgSQL</> function may be declared to return
<type>void</> if it has no useful return value.
<type>void</> if it has no useful return value.
</para>
</para>
<para>
<application>PL/pgSQL</> does not currently have full support for
domain types: it treats a domain the same as the underlying scalar
type. This means that constraints associated with the domain will
not be enforced. This is not an issue for function arguments, but
it is a hazard if you declare a <application>PL/pgSQL</> function
as returning a domain type.
</para>
</sect2>
</sect2>
</sect1>
</sect1>
...
@@ -267,7 +276,8 @@ $$ LANGUAGE plpgsql;
...
@@ -267,7 +276,8 @@ $$ LANGUAGE plpgsql;
the code can become downright incomprehensible, because you can
the code can become downright incomprehensible, because you can
easily find yourself needing half a dozen or more adjacent quote marks.
easily find yourself needing half a dozen or more adjacent quote marks.
It's recommended that you instead write the function body as a
It's recommended that you instead write the function body as a
<quote>dollar-quoted</> string literal. In the dollar-quoting
<quote>dollar-quoted</> string literal (see <xref
linkend="sql-syntax-dollar-quoting">). In the dollar-quoting
approach, you never double any quote marks, but instead take care to
approach, you never double any quote marks, but instead take care to
choose a different dollar-quoting delimiter for each level of
choose a different dollar-quoting delimiter for each level of
nesting you need. For example, you might write the <command>CREATE
nesting you need. For example, you might write the <command>CREATE
...
@@ -437,8 +447,10 @@ END;
...
@@ -437,8 +447,10 @@ END;
<para>
<para>
Each declaration and each statement within a block is terminated
Each declaration and each statement within a block is terminated
by a semicolon, although the final <literal>END</literal> that
by a semicolon. A block that appears within another block must
concludes a function body does not require one.
have a semicolon after <literal>END</literal>, as shown above;
however the final <literal>END</literal> that
concludes a function body does not require a semicolon.
</para>
</para>
<para>
<para>
...
@@ -503,7 +515,7 @@ $$ LANGUAGE plpgsql;
...
@@ -503,7 +515,7 @@ $$ LANGUAGE plpgsql;
transaction, since there would be no context for them to execute in.
transaction, since there would be no context for them to execute in.
However, a block containing an <literal>EXCEPTION</> clause effectively
However, a block containing an <literal>EXCEPTION</> clause effectively
forms a subtransaction that can be rolled back without affecting the
forms a subtransaction that can be rolled back without affecting the
outer transaction. For more
details
see <xref
outer transaction. For more
about that
see <xref
linkend="plpgsql-error-trapping">.
linkend="plpgsql-error-trapping">.
</para>
</para>
</sect1>
</sect1>
...
@@ -556,7 +568,7 @@ arow RECORD;
...
@@ -556,7 +568,7 @@ arow RECORD;
<para>
<para>
The default value is evaluated every time the block is entered. So,
The default value is evaluated every time the block is entered. So,
for example, assigning <literal>
'now'
</literal> to a variable of type
for example, assigning <literal>
now()
</literal> to a variable of type
<type>timestamp</type> causes the variable to have the
<type>timestamp</type> causes the variable to have the
time of the current function call, not the time when the function was
time of the current function call, not the time when the function was
precompiled.
precompiled.
...
@@ -581,6 +593,9 @@ user_id CONSTANT integer := 10;
...
@@ -581,6 +593,9 @@ user_id CONSTANT integer := 10;
<literal>$<replaceable>n</replaceable></literal>
<literal>$<replaceable>n</replaceable></literal>
parameter names for increased readability. Either the alias or the
parameter names for increased readability. Either the alias or the
numeric identifier can then be used to refer to the parameter value.
numeric identifier can then be used to refer to the parameter value.
</para>
<para>
There are two ways to create an alias. The preferred way is to give a
There are two ways to create an alias. The preferred way is to give a
name to the parameter in the <command>CREATE FUNCTION</command> command,
name to the parameter in the <command>CREATE FUNCTION</command> command,
for example:
for example:
...
@@ -827,17 +842,11 @@ RENAME this_var TO that_var;
...
@@ -827,17 +842,11 @@ RENAME this_var TO that_var;
<para>
<para>
All expressions used in <application>PL/pgSQL</application>
All expressions used in <application>PL/pgSQL</application>
statements are processed using the server's regular
statements are processed using the server's regular
<acronym>SQL</acronym> executor. Expressions that appear to
<acronym>SQL</acronym> executor. In effect, a query like
contain constants may in fact require run-time evaluation
(e.g., <literal>'now'</literal> for the <type>timestamp</type>
type) so it is impossible for the
<application>PL/pgSQL</application> parser to identify real
constant values other than the key word <literal>NULL</>. All expressions are
evaluated internally by executing a query
<synopsis>
<synopsis>
SELECT <replaceable>expression</replaceable>
SELECT <replaceable>expression</replaceable>
</synopsis>
</synopsis>
using the <acronym>SPI</acronym> manager. For
evaluation,
is executed using the <acronym>SPI</acronym> manager. Before
evaluation,
occurrences of <application>PL/pgSQL</application> variable
occurrences of <application>PL/pgSQL</application> 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.
the variables are passed to the executor in the parameter array.
...
@@ -1013,6 +1022,14 @@ SELECT INTO <replaceable>target</replaceable> <replaceable>select_expressions</r
...
@@ -1013,6 +1022,14 @@ SELECT INTO <replaceable>target</replaceable> <replaceable>select_expressions</r
and can use its full power.
and can use its full power.
</para>
</para>
<para>
The <literal>INTO</> clause can appear almost anywhere in the
<command>SELECT</command> statement. Customarily it is written
either just after <literal>SELECT</> as shown above, or
just before <literal>FROM</> — that is, either just before
or just after the list of <replaceable>select_expressions</replaceable>.
</para>
<para>
<para>
If the query returns zero rows, null values are assigned to the
If the query returns zero rows, null values are assigned to the
target(s). If the query returns multiple rows, the first
target(s). If the query returns multiple rows, the first
...
@@ -1022,14 +1039,11 @@ SELECT INTO <replaceable>target</replaceable> <replaceable>select_expressions</r
...
@@ -1022,14 +1039,11 @@ SELECT INTO <replaceable>target</replaceable> <replaceable>select_expressions</r
</para>
</para>
<para>
<para>
The <literal>INTO</> clause can appear almost anywhere in the <command>SELECT</command>
You can check the special <literal>FOUND</literal> variable (see
statement.
<xref linkend="plpgsql-statements-diagnostics">) after a
</para>
<command>SELECT INTO</command> statement to determine whether the
assignment was successful, that is, at least one row was was returned by
<para>
the query. For example:
You can use <literal>FOUND</literal> immediately after a <command>SELECT
INTO</command> statement to determine whether the assignment was successful
(that is, at least one row was was returned by the query). For example:
<programlisting>
<programlisting>
SELECT INTO myrec * FROM emp WHERE empname = myname;
SELECT INTO myrec * FROM emp WHERE empname = myname;
...
@@ -1175,22 +1189,13 @@ EXECUTE <replaceable class="command">command-string</replaceable>;
...
@@ -1175,22 +1189,13 @@ EXECUTE <replaceable class="command">command-string</replaceable>;
be inserted in the command string as it is constructed.
be inserted in the command string as it is constructed.
</para>
</para>
<para>
When working with dynamic commands you will often have to handle escaping
of single quotes. The recommended method for quoting fixed text in your
function body is dollar quoting. If you have legacy code that does
not use dollar quoting, please refer to the
overview in <xref linkend="plpgsql-quote-tips">, which can save you
some effort when translating said code to a more reasonable scheme.
</para>
<para>
<para>
Unlike all other commands in <application>PL/pgSQL</>, a command
Unlike all other commands in <application>PL/pgSQL</>, a command
run by an <command>EXECUTE</command> statement is not prepared
run by an <command>EXECUTE</command> statement is not prepared
and saved just once during the life of the session. Instead, the
and saved just once during the life of the session. Instead, the
command is prepared each time the statement is run. The command
command is prepared each time the statement is run. The command
string can be dynamically created within the function to perform
string can be dynamically created within the function to perform
actions on
variable
tables and columns.
actions on
different
tables and columns.
</para>
</para>
<para>
<para>
...
@@ -1207,6 +1212,18 @@ EXECUTE <replaceable class="command">command-string</replaceable>;
...
@@ -1207,6 +1212,18 @@ EXECUTE <replaceable class="command">command-string</replaceable>;
</para>
</para>
<para>
<para>
When working with dynamic commands you will often have to handle escaping
of single quotes. The recommended method for quoting fixed text in your
function body is dollar quoting. (If you have legacy code that does
not use dollar quoting, please refer to the
overview in <xref linkend="plpgsql-quote-tips">, which can save you
some effort when translating said code to a more reasonable scheme.)
</para>
<para>
Dynamic values that are to be inserted into the constructed
query require special handling since they might themselves contain
quote characters.
An example (this assumes that you are using dollar quoting for the
An example (this assumes that you are using dollar quoting for the
function as a whole, so the quote marks need not be doubled):
function as a whole, so the quote marks need not be doubled):
<programlisting>
<programlisting>
...
@@ -1333,17 +1350,18 @@ GET DIAGNOSTICS integer_var = ROW_COUNT;
...
@@ -1333,17 +1350,18 @@ GET DIAGNOSTICS integer_var = ROW_COUNT;
all three variants of the <command>FOR</> statement (integer
all three variants of the <command>FOR</> statement (integer
<command>FOR</> loops, record-set <command>FOR</> loops, and
<command>FOR</> loops, record-set <command>FOR</> loops, and
dynamic record-set <command>FOR</>
dynamic record-set <command>FOR</>
loops). <literal>FOUND</literal> is
only set
when the
loops). <literal>FOUND</literal> is
set this way
when the
<command>FOR</> loop exits
:
inside the execution of the loop,
<command>FOR</> loop exits
;
inside the execution of the loop,
<literal>FOUND</literal> is not modified by the
<literal>FOUND</literal> is not modified by the
<command>FOR</> statement, although it may be changed by the
<command>FOR</> statement, although it may be changed by the
execution of other statements within the loop body.
execution of other statements within the loop body.
</para>
</para>
</listitem>
</listitem>
</itemizedlist>
</itemizedlist>
<literal>FOUND</literal> is a local variable; any changes
to it affect only the current <application>PL/pgSQL</application>
<literal>FOUND</literal> is a local variable within each
function.
<application>PL/pgSQL</application> function; so any changes
to it affect only the current function.
</para>
</para>
</sect2>
</sect2>
...
@@ -1434,15 +1452,14 @@ RETURN NEXT <replaceable>expression</replaceable>;
...
@@ -1434,15 +1452,14 @@ RETURN NEXT <replaceable>expression</replaceable>;
SELECT * FROM some_func();
SELECT * FROM some_func();
</programlisting>
</programlisting>
That is, the function
is used as a table source in a <literal>FROM</literal>
That is, the function
must be used as a table source in a
clause.
<literal>FROM</literal>
clause.
</para>
</para>
<para>
<para>
<command>RETURN NEXT</command> does not actually return from the
<command>RETURN NEXT</command> does not actually return from the
function; it simply saves away the value of the expression (or
function; it simply saves away the value of the expression.
record or row variable, as appropriate for the data type being
Execution then continues with the next statement in
returned). Execution then continues with the next statement in
the <application>PL/pgSQL</> function. As successive
the <application>PL/pgSQL</> function. As successive
<command>RETURN NEXT</command> commands are executed, the result
<command>RETURN NEXT</command> commands are executed, the result
set is built up. A final <command>RETURN</command>, which should
set is built up. A final <command>RETURN</command>, which should
...
@@ -1727,7 +1744,7 @@ END LOOP;
...
@@ -1727,7 +1744,7 @@ END LOOP;
BEGIN
BEGIN
-- some computations
-- some computations
IF stocks > 100000 THEN
IF stocks > 100000 THEN
EXIT; --
invalid; cannot use EXIT outside of LOOP
EXIT; --
causes exit from the BEGIN block
END IF;
END IF;
END;
END;
</programlisting>
</programlisting>
...
@@ -1821,8 +1838,9 @@ FOR <replaceable>record_or_row</replaceable> IN <replaceable>query</replaceable>
...
@@ -1821,8 +1838,9 @@ FOR <replaceable>record_or_row</replaceable> IN <replaceable>query</replaceable>
END LOOP;
END LOOP;
</synopsis>
</synopsis>
The record or row variable is successively assigned each row
The record or row variable is successively assigned each row
resulting from the query (which must be a <command>SELECT</command>
resulting from the <replaceable>query</replaceable> (which must be a
command) and the loop body is executed for each row. Here is an example:
<command>SELECT</command> command) and the loop body is executed for each
row. Here is an example:
<programlisting>
<programlisting>
CREATE FUNCTION cs_refresh_mviews() RETURNS integer AS $$
CREATE FUNCTION cs_refresh_mviews() RETURNS integer AS $$
DECLARE
DECLARE
...
@@ -1874,7 +1892,7 @@ END LOOP;
...
@@ -1874,7 +1892,7 @@ END LOOP;
<literal>IN</> and <literal>LOOP</>. If <literal>..</> is not seen then
<literal>IN</> and <literal>LOOP</>. If <literal>..</> is not seen then
the loop is presumed to be a loop over rows. Mistyping the <literal>..</>
the loop is presumed to be a loop over rows. Mistyping the <literal>..</>
is thus likely to lead to a complaint along the lines of
is thus likely to lead to a complaint along the lines of
<quote>loop variable of loop over rows must be a record or row</>,
<quote>loop variable of loop over rows must be a record or row
variable
</>,
rather than the simple syntax error one might expect to get.
rather than the simple syntax error one might expect to get.
</para>
</para>
</note>
</note>
...
@@ -1902,7 +1920,7 @@ EXCEPTION
...
@@ -1902,7 +1920,7 @@ EXCEPTION
<replaceable>handler_statements</replaceable>
<replaceable>handler_statements</replaceable>
<optional> WHEN <replaceable>condition</replaceable> <optional> OR <replaceable>condition</replaceable> ... </optional> THEN
<optional> WHEN <replaceable>condition</replaceable> <optional> OR <replaceable>condition</replaceable> ... </optional> THEN
<replaceable>handler_statements</replaceable>
<replaceable>handler_statements</replaceable>
... </optional>
... </optional>
END;
END;
</synopsis>
</synopsis>
</para>
</para>
...
@@ -2060,7 +2078,7 @@ DECLARE
...
@@ -2060,7 +2078,7 @@ DECLARE
<title><command>OPEN FOR SELECT</command></title>
<title><command>OPEN FOR SELECT</command></title>
<synopsis>
<synopsis>
OPEN <replaceable>unbound
-
cursor</replaceable> FOR SELECT ...;
OPEN <replaceable>unbound
_
cursor</replaceable> FOR SELECT ...;
</synopsis>
</synopsis>
<para>
<para>
...
@@ -2086,7 +2104,7 @@ OPEN curs1 FOR SELECT * FROM foo WHERE key = mykey;
...
@@ -2086,7 +2104,7 @@ OPEN curs1 FOR SELECT * FROM foo WHERE key = mykey;
<title><command>OPEN FOR EXECUTE</command></title>
<title><command>OPEN FOR EXECUTE</command></title>
<synopsis>
<synopsis>
OPEN <replaceable>unbound
-cursor</replaceable> FOR EXECUTE <replaceable class="command">query-
string</replaceable>;
OPEN <replaceable>unbound
_cursor</replaceable> FOR EXECUTE <replaceable class="command">query_
string</replaceable>;
</synopsis>
</synopsis>
<para>
<para>
...
@@ -2111,7 +2129,7 @@ OPEN curs1 FOR EXECUTE 'SELECT * FROM ' || quote_ident($1);
...
@@ -2111,7 +2129,7 @@ OPEN curs1 FOR EXECUTE 'SELECT * FROM ' || quote_ident($1);
<title>Opening a Bound Cursor</title>
<title>Opening a Bound Cursor</title>
<synopsis>
<synopsis>
OPEN <replaceable>bound
-
cursor</replaceable> <optional> ( <replaceable>argument_values</replaceable> ) </optional>;
OPEN <replaceable>bound
_
cursor</replaceable> <optional> ( <replaceable>argument_values</replaceable> ) </optional>;
</synopsis>
</synopsis>
<para>
<para>
...
@@ -2312,8 +2330,8 @@ RAISE <replaceable class="parameter">level</replaceable> '<replaceable class="pa
...
@@ -2312,8 +2330,8 @@ RAISE <replaceable class="parameter">level</replaceable> '<replaceable class="pa
priority levels.
priority levels.
Whether messages of a particular priority are reported to the client,
Whether messages of a particular priority are reported to the client,
written to the server log, or both is controlled by the
written to the server log, or both is controlled by the
<
varname>log_min_messages</varname
> and
<
xref linkend="guc-log-min-messages"
> and
<
varname>client_min_messages</varname
> configuration
<
xref linkend="guc-client-min-messages"
> configuration
variables. See <xref linkend="runtime-config"> for more
variables. See <xref linkend="runtime-config"> for more
information.
information.
</para>
</para>
...
@@ -2573,11 +2591,8 @@ CREATE TRIGGER emp_stamp BEFORE INSERT OR UPDATE ON emp
...
@@ -2573,11 +2591,8 @@ CREATE TRIGGER emp_stamp BEFORE INSERT OR UPDATE ON emp
<para>
<para>
Another way to log changes to a table involves creating a new table that
Another way to log changes to a table involves creating a new table that
holds a row for each insert, update, delete that occurs. This approach can
holds a row for each insert, update, or delete that occurs. This approach
be thought of as auditing changes to a table.
can be thought of as auditing changes to a table.
</para>
<para>
<xref linkend="plpgsql-trigger-audit-example"> shows an example of an
<xref linkend="plpgsql-trigger-audit-example"> shows an example of an
audit trigger procedure in <application>PL/pgSQL</application>.
audit trigger procedure in <application>PL/pgSQL</application>.
</para>
</para>
...
@@ -2606,7 +2621,7 @@ CREATE TABLE emp_audit(
...
@@ -2606,7 +2621,7 @@ CREATE TABLE emp_audit(
salary integer
salary integer
);
);
CREATE OR REPLACE
FUNCTION process_emp_audit() RETURNS TRIGGER AS $emp_audit$
CREATE OR REPLACE FUNCTION process_emp_audit() RETURNS TRIGGER AS $emp_audit$
BEGIN
BEGIN
--
--
-- Create a row in emp_audit to reflect the operation performed on emp,
-- Create a row in emp_audit to reflect the operation performed on emp,
...
@@ -2622,14 +2637,13 @@ CREATE OR REPLACE FUNCTION process_emp_audit() RETURNS TRIGGER AS $emp_audit$
...
@@ -2622,14 +2637,13 @@ CREATE OR REPLACE FUNCTION process_emp_audit() RETURNS TRIGGER AS $emp_audit$
INSERT INTO emp_audit SELECT 'I', now(), user, NEW.*;
INSERT INTO emp_audit SELECT 'I', now(), user, NEW.*;
RETURN NEW;
RETURN NEW;
END IF;
END IF;
RETURN NULL; -- result is ignored since this is an AFTER trigger
END;
END;
$emp_audit$ language plpgsql;
$emp_audit$ language plpgsql;
CREATE TRIGGER emp_audit
CREATE TRIGGER emp_audit
AFTER INSERT OR UPDATE OR DELETE ON emp
AFTER INSERT OR UPDATE OR DELETE ON emp
FOR EACH ROW EXECUTE PROCEDURE process_emp_audit()
FOR EACH ROW EXECUTE PROCEDURE process_emp_audit();
;
</programlisting>
</programlisting>
</example>
</example>
</sect1>
</sect1>
...
...
doc/src/sgml/plpython.sgml
View file @
883ac5ca
<!-- $PostgreSQL: pgsql/doc/src/sgml/plpython.sgml,v 1.2
5 2004/12/17 02:14:44
tgl Exp $ -->
<!-- $PostgreSQL: pgsql/doc/src/sgml/plpython.sgml,v 1.2
6 2004/12/30 21:45:36
tgl Exp $ -->
<chapter id="plpython">
<chapter id="plpython">
<title>PL/Python - Python Procedural Language</title>
<title>PL/Python - Python Procedural Language</title>
...
@@ -46,15 +46,16 @@
...
@@ -46,15 +46,16 @@
<title>PL/Python Functions</title>
<title>PL/Python Functions</title>
<para>
<para>
The Python code you write gets transformed into a Python function.
Functions in PL/Python are declared in the usual way, for example
For example,
<programlisting>
<programlisting>
CREATE FUNCTION myfunc(text) RETURNS text
CREATE FUNCTION myfunc(text) RETURNS text
AS 'return args[0]'
AS 'return args[0]'
LANGUAGE plpythonu;
LANGUAGE plpythonu;
</programlisting>
</programlisting>
gets transformed into
The Python code that is given as the body of the function definition
gets transformed into a Python function.
For example, the above results in
<programlisting>
<programlisting>
def __plpython_procedure_myfunc_23456():
def __plpython_procedure_myfunc_23456():
...
@@ -151,19 +152,23 @@ def __plpython_procedure_myfunc_23456():
...
@@ -151,19 +152,23 @@ def __plpython_procedure_myfunc_23456():
<literal>plpy.notice(<replaceable>msg</>)</literal>,
<literal>plpy.notice(<replaceable>msg</>)</literal>,
<literal>plpy.warning(<replaceable>msg</>)</literal>,
<literal>plpy.warning(<replaceable>msg</>)</literal>,
<literal>plpy.error(<replaceable>msg</>)</literal>, and
<literal>plpy.error(<replaceable>msg</>)</literal>, and
<literal>plpy.fatal(<replaceable>msg</>)</literal>.
<literal>plpy.fatal(<replaceable>msg</>)</literal>.<indexterm><primary>elog</><secondary>in PL/Python</></indexterm>
These are mostly equivalent to calling
<function>plpy.error</function> and
<literal>elog(<replaceable>level</>, <replaceable>msg</>)</literal>
from C code.<indexterm><primary>elog</><secondary>in
PL/Python</></indexterm> <function>plpy.error</function> and
<function>plpy.fatal</function> actually raise a Python exception
<function>plpy.fatal</function> actually raise a Python exception
which, if uncaught,
causes the PL/Python module to call
which, if uncaught,
propagates out to the calling query, causing
<literal>elog(ERROR, msg)</literal> when the function handler
the current transaction or subtransaction to be aborted.
returns from the Python interpreter. <literal>raise
<literal>raise plpy.ERROR(<replaceable>msg</>)</literal> and
plpy.ERROR(<replaceable>msg</>)</literal> and <literal>rais
e
<literal>raise plpy.FATAL(<replaceable>msg</>)</literal> ar
e
plpy.FATAL(<replaceable>msg</>)</literal> are
equivalent to calling
equivalent to calling
<function>plpy.error</function> and
<function>plpy.error</function> and
<function>plpy.fatal</function>, respectively.
<function>plpy.fatal</function>, respectively.
The other functions only generate messages of different
priority levels.
Whether messages of a particular priority are reported to the client,
written to the server log, or both is controlled by the
<xref linkend="guc-log-min-messages"> and
<xref linkend="guc-client-min-messages"> configuration
variables. See <xref linkend="runtime-config"> for more information.
</para>
</para>
<para>
<para>
...
...
doc/src/sgml/pltcl.sgml
View file @
883ac5ca
<!--
<!--
$PostgreSQL: pgsql/doc/src/sgml/pltcl.sgml,v 2.3
2 2004/11/21 21:17:02
tgl Exp $
$PostgreSQL: pgsql/doc/src/sgml/pltcl.sgml,v 2.3
3 2004/12/30 21:45:37
tgl Exp $
-->
-->
<chapter id="pltcl">
<chapter id="pltcl">
...
@@ -16,7 +16,8 @@ $PostgreSQL: pgsql/doc/src/sgml/pltcl.sgml,v 2.32 2004/11/21 21:17:02 tgl Exp $
...
@@ -16,7 +16,8 @@ $PostgreSQL: pgsql/doc/src/sgml/pltcl.sgml,v 2.32 2004/11/21 21:17:02 tgl Exp $
<para>
<para>
PL/Tcl is a loadable procedural language for the
PL/Tcl is a loadable procedural language for the
<productname>PostgreSQL</productname> database system
<productname>PostgreSQL</productname> database system
that enables the Tcl language to be used to write functions and
that enables the <ulink url="http://www.tcl.tk/">Tcl</ulink>
language to be used to write functions and
trigger procedures.
trigger procedures.
</para>
</para>
...
@@ -59,7 +60,7 @@ $PostgreSQL: pgsql/doc/src/sgml/pltcl.sgml,v 2.32 2004/11/21 21:17:02 tgl Exp $
...
@@ -59,7 +60,7 @@ $PostgreSQL: pgsql/doc/src/sgml/pltcl.sgml,v 2.32 2004/11/21 21:17:02 tgl Exp $
The shared object for the <application>PL/Tcl</> and <application>PL/TclU</> call handlers is
The shared object for the <application>PL/Tcl</> and <application>PL/TclU</> call handlers is
automatically built and installed in the
automatically built and installed in the
<productname>PostgreSQL</productname>
<productname>PostgreSQL</productname>
library directory if Tcl
/Tk
support is specified
library directory if Tcl support is specified
in the configuration step of the installation procedure. To install
in the configuration step of the installation procedure. To install
<application>PL/Tcl</> and/or <application>PL/TclU</> in a particular database, use the
<application>PL/Tcl</> and/or <application>PL/TclU</> in a particular database, use the
<command>createlang</command> program, for example
<command>createlang</command> program, for example
...
@@ -77,8 +78,7 @@ $PostgreSQL: pgsql/doc/src/sgml/pltcl.sgml,v 2.32 2004/11/21 21:17:02 tgl Exp $
...
@@ -77,8 +78,7 @@ $PostgreSQL: pgsql/doc/src/sgml/pltcl.sgml,v 2.32 2004/11/21 21:17:02 tgl Exp $
To create a function in the <application>PL/Tcl</> language, use the standard syntax:
To create a function in the <application>PL/Tcl</> language, use the standard syntax:
<programlisting>
<programlisting>
CREATE FUNCTION <replaceable>funcname</replaceable>
CREATE FUNCTION <replaceable>funcname</replaceable> (<replaceable>argument-types</replaceable>) RETURNS <replaceable>return-type</replaceable> AS $$
(<replaceable>argument-types</replaceable>) RETURNS <replaceable>return-type</replaceable> AS $$
# PL/Tcl function body
# PL/Tcl function body
$$ LANGUAGE pltcl;
$$ LANGUAGE pltcl;
</programlisting>
</programlisting>
...
@@ -169,7 +169,16 @@ $$ LANGUAGE pltcl;
...
@@ -169,7 +169,16 @@ $$ LANGUAGE pltcl;
<para>
<para>
There is currently no support for returning a composite-type
There is currently no support for returning a composite-type
result value.
result value, nor for returning sets.
</para>
<para>
<application>PL/Tcl</> does not currently have full support for
domain types: it treats a domain the same as the underlying scalar
type. This means that constraints associated with the domain will
not be enforced. This is not an issue for function arguments, but
it is a hazard if you declare a <application>PL/Tcl</> function
as returning a domain type.
</para>
</para>
</sect1>
</sect1>
...
@@ -180,10 +189,11 @@ $$ LANGUAGE pltcl;
...
@@ -180,10 +189,11 @@ $$ LANGUAGE pltcl;
<para>
<para>
The argument values supplied to a PL/Tcl function's code 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
the input arguments converted to text form (just as if they had been
displayed by a <command>SELECT</> statement). Conversely, the <literal>return</>
displayed by a <command>SELECT</> statement). Conversely, the
<literal>return</>
command will accept any string that is acceptable input format for
command will accept any string that is acceptable input format for
the function's declared return type. So,
the PL/Tcl programmer can
the function's declared return type. So,
within the PL/Tcl function,
manipulate data values as if they were just text
.
all values are just text strings
.
</para>
</para>
</sect1>
</sect1>
...
@@ -215,9 +225,9 @@ $$ LANGUAGE pltcl;
...
@@ -215,9 +225,9 @@ $$ LANGUAGE pltcl;
command. The global name of this variable is the function's internal
command. The global name of this variable is the function's internal
name, and the local name is <literal>GD</>. It is recommended that
name, and the local name is <literal>GD</>. It is recommended that
<literal>GD</> be used
<literal>GD</> be used
for p
rivate data of a function. Use regular Tcl global variables
for p
ersistent private data of a function. Use regular Tcl global
only for values that you specifically intend to be shared among multiple
variables only for values that you specifically intend to be shared among
functions.
multiple
functions.
</para>
</para>
<para>
<para>
...
@@ -239,48 +249,48 @@ $$ LANGUAGE pltcl;
...
@@ -239,48 +249,48 @@ $$ LANGUAGE pltcl;
<term><literal><function>spi_exec</function> <optional role="tcl">-count <replaceable>n</replaceable></optional> <optional role="tcl">-array <replaceable>name</replaceable></optional> <replaceable>command</replaceable> <optional role="tcl"><replaceable>loop-body</replaceable></optional></literal></term>
<term><literal><function>spi_exec</function> <optional role="tcl">-count <replaceable>n</replaceable></optional> <optional role="tcl">-array <replaceable>name</replaceable></optional> <replaceable>command</replaceable> <optional role="tcl"><replaceable>loop-body</replaceable></optional></literal></term>
<listitem>
<listitem>
<para>
<para>
Executes an SQL command given as a string. An error in the command
Executes an SQL command given as a string. An error in the command
causes an error to be raised. Otherwise, the return value of <function>spi_exec</function>
causes an error to be raised. Otherwise, the return value of <function>spi_exec</function>
is the number of rows processed (selected, inserted, updated, or
is the number of rows processed (selected, inserted, updated, or
deleted) by the command, or zero if the command is a utility
deleted) by the command, or zero if the command is a utility
statement. In addition, if the command is a <command>SELECT</> statement, the
statement. In addition, if the command is a <command>SELECT</> statement, the
values of the selected columns are placed in Tcl variables as
values of the selected columns are placed in Tcl variables as
described below.
described below.
</para>
</para>
<para>
<para>
The optional <literal>-count</> value tells
The optional <literal>-count</> value tells
<function>spi_exec</function> the maximum number of rows
<function>spi_exec</function> the maximum number of rows
to process in the command. The effect of this is comparable to
to process in the command. The effect of this is comparable to
setting up a query as a cursor and then saying <literal>FETCH <replaceable>n</></>.
setting up a query as a cursor and then saying <literal>FETCH <replaceable>n</></>.
</para>
</para>
<para>
<para>
If the command is a <command>SELECT</> statement, the values of the
If the command is a <command>SELECT</> statement, the values of the
result columns are placed into Tcl variables named after the columns.
result columns are placed into Tcl variables named after the columns.
If the <literal>-array</> option is given, the column values are
If the <literal>-array</> option is given, the column values are
instead stored into the named associative array, with the
instead stored into the named associative array, with the
column names used as array indexes.
column names used as array indexes.
</para>
</para>
<para>
<para>
If the command is a <command>SELECT</> statement and no <replaceable>loop-body</>
If the command is a <command>SELECT</> statement and no <replaceable>loop-body</>
script is given, then only the first row of results are stored into
script is given, then only the first row of results are stored into
Tcl variables; remaining rows, if any, are ignored. No storing occurs
Tcl variables; remaining rows, if any, are ignored. No storing occurs
if the
if the
query returns no rows. (This case can be detected by checking the
query returns no rows. (This case can be detected by checking the
result of <function>spi_exec</function>.) For example,
result of <function>spi_exec</function>.) For example,
<programlisting>
<programlisting>
spi_exec "SELECT count(*) AS cnt FROM pg_proc"
spi_exec "SELECT count(*) AS cnt FROM pg_proc"
</programlisting>
</programlisting>
will set the Tcl variable <literal>$cnt</> to the number of rows in
will set the Tcl variable <literal>$cnt</> to the number of rows in
the <structname>pg_proc</> system catalog.
the <structname>pg_proc</> system catalog.
</para>
</para>
<para>
<para>
If the optional <replaceable>loop-body</> argument is given, it is
If the optional <replaceable>loop-body</> argument is given, it is
a piece of Tcl script that is executed once for each row in the
a piece of Tcl script that is executed once for each row in the
query result. (<replaceable>loop-body</> is ignored if the given
query result. (<replaceable>loop-body</> is ignored if the given
command is not a <command>SELECT</>.) The values of the current row's columns
command is not a <command>SELECT</>.) The values of the current row's columns
are stored into Tcl variables before each iteration. For example,
are stored into Tcl variables before each iteration. For example,
<programlisting>
<programlisting>
spi_exec -array C "SELECT * FROM pg_class" {
spi_exec -array C "SELECT * FROM pg_class" {
...
@@ -288,14 +298,14 @@ spi_exec -array C "SELECT * FROM pg_class" {
...
@@ -288,14 +298,14 @@ spi_exec -array C "SELECT * FROM pg_class" {
}
}
</programlisting>
</programlisting>
will print a log message for every row of <literal>pg_class</>. This
will print a log message for every row of <literal>pg_class</>. This
feature works similarly to other Tcl looping constructs; in
feature works similarly to other Tcl looping constructs; in
particular <literal>continue</> and <literal>break</> work in the
particular <literal>continue</> and <literal>break</> work in the
usual way inside the loop body.
usual way inside the loop body.
</para>
</para>
<para>
<para>
If a column of a query result is null, the target
If a column of a query result is null, the target
variable for it is <quote>unset</> rather than being set.
variable for it is <quote>unset</> rather than being set.
</para>
</para>
</listitem>
</listitem>
</varlistentry>
</varlistentry>
...
@@ -304,27 +314,27 @@ spi_exec -array C "SELECT * FROM pg_class" {
...
@@ -304,27 +314,27 @@ spi_exec -array C "SELECT * FROM pg_class" {
<term><function>spi_prepare</function> <replaceable>query</replaceable> <replaceable>typelist</replaceable></term>
<term><function>spi_prepare</function> <replaceable>query</replaceable> <replaceable>typelist</replaceable></term>
<listitem>
<listitem>
<para>
<para>
Prepares and saves a query plan for later execution. The
Prepares and saves a query plan for later execution. The
saved plan will be retained for the life of the current
saved plan will be retained for the life of the current
session.<indexterm><primary>preparing a query</><secondary>in
session.<indexterm><primary>preparing a query</><secondary>in
PL/Tcl</></>
PL/Tcl</></>
</para>
</para>
<para>
<para>
The query may use parameters, that is, placeholders for
The query may use parameters, that is, placeholders for
values to be supplied whenever the plan is actually executed.
values to be supplied whenever the plan is actually executed.
In the query string, refer to parameters
In the query string, refer to parameters
by the symbols <literal>$1</literal> ... <literal>$<replaceable>n</replaceable></literal>.
by the symbols <literal>$1</literal> ... <literal>$<replaceable>n</replaceable></literal>.
If the query uses parameters, the names of the parameter types
If the query uses parameters, the names of the parameter types
must be given as a Tcl list. (Write an empty list for
must be given as a Tcl list. (Write an empty list for
<replaceable>typelist</replaceable> if no parameters are used.)
<replaceable>typelist</replaceable> if no parameters are used.)
Presently, the parameter types must be identified by the internal
Presently, the parameter types must be identified by the internal
type names shown in the system table <literal>pg_type</>; for example <literal>int4</> not
type names shown in the system table <literal>pg_type</>; for example <literal>int4</> not
<literal>integer</>.
<literal>integer</>.
</para>
</para>
<para>
<para>
The return value from <function>spi_prepare</function> is a query ID
The return value from <function>spi_prepare</function> is a query ID
to be used in subsequent calls to <function>spi_execp</function>. See
to be used in subsequent calls to <function>spi_execp</function>. See
<function>spi_execp</function> for an example.
<function>spi_execp</function> for an example.
</para>
</para>
</listitem>
</listitem>
</varlistentry>
</varlistentry>
...
@@ -333,31 +343,31 @@ spi_exec -array C "SELECT * FROM pg_class" {
...
@@ -333,31 +343,31 @@ spi_exec -array C "SELECT * FROM pg_class" {
<term><literal><function>spi_execp</> <optional role="tcl">-count <replaceable>n</replaceable></optional> <optional role="tcl">-array <replaceable>name</replaceable></optional> <optional role="tcl">-nulls <replaceable>string</replaceable></optional> <replaceable>queryid</replaceable> <optional role="tcl"><replaceable>value-list</replaceable></optional> <optional role="tcl"><replaceable>loop-body</replaceable></optional></literal></term>
<term><literal><function>spi_execp</> <optional role="tcl">-count <replaceable>n</replaceable></optional> <optional role="tcl">-array <replaceable>name</replaceable></optional> <optional role="tcl">-nulls <replaceable>string</replaceable></optional> <replaceable>queryid</replaceable> <optional role="tcl"><replaceable>value-list</replaceable></optional> <optional role="tcl"><replaceable>loop-body</replaceable></optional></literal></term>
<listitem>
<listitem>
<para>
<para>
Executes a query previously prepared with <function>spi_prepare</>.
Executes a query previously prepared with <function>spi_prepare</>.
<replaceable>queryid</replaceable> is the ID returned by
<replaceable>queryid</replaceable> is the ID returned by
<function>spi_prepare</>. If the query references parameters,
<function>spi_prepare</>. If the query references parameters,
a <replaceable>value-list</replaceable> must be supplied. This
a <replaceable>value-list</replaceable> must be supplied. This
is a Tcl list of actual values for the parameters. The list must be
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
the same length as the parameter type list previously given to
<function>spi_prepare</>. Omit <replaceable>value-list</replaceable>
<function>spi_prepare</>. Omit <replaceable>value-list</replaceable>
if the query has no parameters.
if the query has no parameters.
</para>
</para>
<para>
<para>
The optional value for <literal>-nulls</> is a string of spaces and
The optional value for <literal>-nulls</> is a string of spaces and
<literal>'n'</> characters telling <function>spi_execp</function>
<literal>'n'</> characters telling <function>spi_execp</function>
which of the parameters 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 <replaceable>value-list</replaceable>. If it
same length as the <replaceable>value-list</replaceable>. If it
is not given, all the parameter values are nonnull.
is not given, all the parameter values are nonnull.
</para>
</para>
<para>
<para>
Except for the way in which the query and its parameters are specified,
Except for the way in which the query and its parameters are specified,
<function>spi_execp</> works just like <function>spi_exec</>.
<function>spi_execp</> works just like <function>spi_exec</>.
The <literal>-count</>, <literal>-array</>, and
The <literal>-count</>, <literal>-array</>, and
<replaceable>loop-body</replaceable> options are the same,
<replaceable>loop-body</replaceable> options are the same,
and so is the result value.
and so is the result value.
</para>
</para>
<para>
<para>
Here's an example of a PL/Tcl function using a prepared plan:
Here's an example of a PL/Tcl function using a prepared plan:
<programlisting>
<programlisting>
CREATE FUNCTION t1_count(integer, integer) RETURNS integer AS $$
CREATE FUNCTION t1_count(integer, integer) RETURNS integer AS $$
...
@@ -389,9 +399,9 @@ $$ LANGUAGE pltcl;
...
@@ -389,9 +399,9 @@ $$ LANGUAGE pltcl;
<term><function>spi_lastoid</></term>
<term><function>spi_lastoid</></term>
<listitem>
<listitem>
<para>
<para>
Returns the OID of the row inserted by the last
Returns the OID of the row inserted by the last
<function>spi_exec</> or <function>spi_execp</>,
<function>spi_exec</> or <function>spi_execp</>,
if the command was a single-row <command>INSERT</>. (If not, you get zero.)
if the command was a single-row <command>INSERT</>. (If not, you get zero.)
</para>
</para>
</listitem>
</listitem>
</varlistentry>
</varlistentry>
...
@@ -400,43 +410,43 @@ $$ LANGUAGE pltcl;
...
@@ -400,43 +410,43 @@ $$ LANGUAGE pltcl;
<term><function>quote</> <replaceable>string</replaceable></term>
<term><function>quote</> <replaceable>string</replaceable></term>
<listitem>
<listitem>
<para>
<para>
Doubles all occurrences of single quote and backslash characters
Doubles all occurrences of single quote and backslash characters
in the given string. This may be used to safely quote strings
in the given string. This may be used to safely quote strings
that are to be inserted into SQL commands given
that are to be inserted into SQL commands given
to <function>spi_exec</function> or
to <function>spi_exec</function> or
<function>spi_prepare</function>.
<function>spi_prepare</function>.
For example, think about an SQL command string like
For example, think about an SQL command string like
<programlisting>
<programlisting>
"SELECT '$val' AS ret"
"SELECT '$val' AS ret"
</programlisting>
</programlisting>
where the Tcl variable <literal>val</> actually contains
where the Tcl variable <literal>val</> actually contains
<literal>doesn't</literal>. This would result
<literal>doesn't</literal>. This would result
in the final command string
in the final command string
<programlisting>
<programlisting>
SELECT 'doesn't' AS ret
SELECT 'doesn't' AS ret
</programlisting>
</programlisting>
which would cause a parse error during
which would cause a parse error during
<function>spi_exec</function> or
<function>spi_exec</function> or
<function>spi_prepare</function>.
<function>spi_prepare</function>.
To work properly, the submitted command should contain
To work properly, the submitted command should contain
<programlisting>
<programlisting>
SELECT 'doesn''t' AS ret
SELECT 'doesn''t' AS ret
</programlisting>
</programlisting>
which can be formed in PL/Tcl using
which can be formed in PL/Tcl using
<programlisting>
<programlisting>
"SELECT '[ quote $val ]' AS ret"
"SELECT '[ quote $val ]' AS ret"
</programlisting>
</programlisting>
One advantage of <function>spi_execp</function> is that you don't
One advantage of <function>spi_execp</function> is that you don't
have to quote parameter values like this, since the parameters are never
have to quote parameter values like this, since the parameters are never
parsed as part of an SQL command string.
parsed as part of an SQL command string.
</para>
</para>
</listitem>
</listitem>
</varlistentry>
</varlistentry>
...
@@ -452,8 +462,7 @@ SELECT 'doesn''t' AS ret
...
@@ -452,8 +462,7 @@ SELECT 'doesn''t' AS ret
Emits a log or error message. Possible levels are
Emits a log or error message. Possible levels are
<literal>DEBUG</>, <literal>LOG</>, <literal>INFO</>,
<literal>DEBUG</>, <literal>LOG</>, <literal>INFO</>,
<literal>NOTICE</>, <literal>WARNING</>, <literal>ERROR</>, and
<literal>NOTICE</>, <literal>WARNING</>, <literal>ERROR</>, and
<literal>FATAL</>. Most simply emit the given message just like
<literal>FATAL</>. <literal>ERROR</>
the <literal>elog</> C function. <literal>ERROR</>
raises an error condition; if this is not trapped by the surrounding
raises an error condition; if this is not trapped by the surrounding
Tcl code, the error propagates out to the calling query, causing
Tcl code, the error propagates out to the calling query, causing
the current transaction or subtransaction to be aborted. This
the current transaction or subtransaction to be aborted. This
...
@@ -461,7 +470,14 @@ SELECT 'doesn''t' AS ret
...
@@ -461,7 +470,14 @@ SELECT 'doesn''t' AS ret
<literal>FATAL</> aborts the transaction and causes the current
<literal>FATAL</> aborts the transaction and causes the current
session 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
this error level in PL/Tcl functions, but it's provided for
completeness.)
completeness.) The other levels only generate messages of different
priority levels.
Whether messages of a particular priority are reported to the client,
written to the server log, or both is controlled by the
<xref linkend="guc-log-min-messages"> and
<xref linkend="guc-client-min-messages"> configuration
variables. See <xref linkend="runtime-config"> for more
information.
</para>
</para>
</listitem>
</listitem>
</varlistentry>
</varlistentry>
...
@@ -494,100 +510,100 @@ SELECT 'doesn''t' AS ret
...
@@ -494,100 +510,100 @@ SELECT 'doesn''t' AS ret
<varlistentry>
<varlistentry>
<term><varname>$TG_name</varname></term>
<term><varname>$TG_name</varname></term>
<listitem>
<listitem>
<para>
<para>
The name of the trigger from the <command>CREATE TRIGGER</command> statement.
The name of the trigger from the <command>CREATE TRIGGER</command> statement.
</para>
</para>
</listitem>
</listitem>
</varlistentry>
</varlistentry>
<varlistentry>
<varlistentry>
<term><varname>$TG_relid</varname></term>
<term><varname>$TG_relid</varname></term>
<listitem>
<listitem>
<para>
<para>
The object ID of the table that caused the trigger procedure
The object ID of the table that caused the trigger procedure
to be invoked.
to be invoked.
</para>
</para>
</listitem>
</listitem>
</varlistentry>
</varlistentry>
<varlistentry>
<varlistentry>
<term><varname>$TG_relatts</varname></term>
<term><varname>$TG_relatts</varname></term>
<listitem>
<listitem>
<para>
<para>
A Tcl list of the table column names, prefixed with an empty list
A Tcl list of the table column names, prefixed with an empty list
element. So looking up a column name in the list with <application>Tcl</>'s
element. So looking up a column name in the list with <application>Tcl</>'s
<function>lsearch</> command returns the element's number starting
<function>lsearch</> command returns the element's number starting
with 1 for the first column, the same way the columns are customarily
with 1 for the first column, the same way the columns are customarily
numbered in <productname>PostgreSQL</productname>. (Empty list
numbered in <productname>PostgreSQL</productname>. (Empty list
elements also appear in the positions of columns that have been
elements also appear in the positions of columns that have been
dropped, so that the attribute numbering is correct for columns
dropped, so that the attribute numbering is correct for columns
to their right.)
to their right.)
</para>
</para>
</listitem>
</listitem>
</varlistentry>
</varlistentry>
<varlistentry>
<varlistentry>
<term><varname>$TG_when</varname></term>
<term><varname>$TG_when</varname></term>
<listitem>
<listitem>
<para>
<para>
The string <literal>BEFORE</> or <literal>AFTER</> depending on the
The string <literal>BEFORE</> or <literal>AFTER</> depending on the
type of trigger call.
type of trigger call.
</para>
</para>
</listitem>
</listitem>
</varlistentry>
</varlistentry>
<varlistentry>
<varlistentry>
<term><varname>$TG_level</varname></term>
<term><varname>$TG_level</varname></term>
<listitem>
<listitem>
<para>
<para>
The string <literal>ROW</> or <literal>STATEMENT</> depending on the
The string <literal>ROW</> or <literal>STATEMENT</> depending on the
type of trigger call.
type of trigger call.
</para>
</para>
</listitem>
</listitem>
</varlistentry>
</varlistentry>
<varlistentry>
<varlistentry>
<term><varname>$TG_op</varname></term>
<term><varname>$TG_op</varname></term>
<listitem>
<listitem>
<para>
<para>
The string <literal>INSERT</>, <literal>UPDATE</>, or
The string <literal>INSERT</>, <literal>UPDATE</>, or
<literal>DELETE</> depending on the type of trigger call.
<literal>DELETE</> depending on the type of trigger call.
</para>
</para>
</listitem>
</listitem>
</varlistentry>
</varlistentry>
<varlistentry>
<varlistentry>
<term><varname>$NEW</varname></term>
<term><varname>$NEW</varname></term>
<listitem>
<listitem>
<para>
<para>
An associative array containing the values of the new table
An associative array containing the values of the new table
row for <command>INSERT</> or <command>UPDATE</> actions, or
row for <command>INSERT</> or <command>UPDATE</> actions, or
empty for <command>DELETE</>. The array is indexed by column
empty for <command>DELETE</>. The array is indexed by column
name. Columns that are null will not appear in the array.
name. Columns that are null will not appear in the array.
</para>
</para>
</listitem>
</listitem>
</varlistentry>
</varlistentry>
<varlistentry>
<varlistentry>
<term><varname>$OLD</varname></term>
<term><varname>$OLD</varname></term>
<listitem>
<listitem>
<para>
<para>
An associative array containing the values of the old table
An associative array containing the values of the old table
row for <command>UPDATE</> or <command>DELETE</> actions, or
row for <command>UPDATE</> or <command>DELETE</> actions, or
empty for <command>INSERT</>. The array is indexed by column
empty for <command>INSERT</>. The array is indexed by column
name. Columns that are null will not appear in the array.
name. Columns that are null will not appear in the array.
</para>
</para>
</listitem>
</listitem>
</varlistentry>
</varlistentry>
<varlistentry>
<varlistentry>
<term><varname>$args</varname></term>
<term><varname>$args</varname></term>
<listitem>
<listitem>
<para>
<para>
A Tcl list of the arguments to the procedure as given in the
A Tcl list of the arguments to the procedure as given in the
<command>CREATE TRIGGER</command> statement. These arguments are also accessible as
<command>CREATE TRIGGER</command> statement. These arguments are also accessible as
<literal>$1</literal> ... <literal>$<replaceable>n</replaceable></literal> in the procedure body.
<literal>$1</literal> ... <literal>$<replaceable>n</replaceable></literal> in the procedure body.
</para>
</para>
</listitem>
</listitem>
</varlistentry>
</varlistentry>
...
@@ -644,39 +660,39 @@ CREATE TRIGGER trig_mytab_modcount BEFORE INSERT OR UPDATE ON mytab
...
@@ -644,39 +660,39 @@ CREATE TRIGGER trig_mytab_modcount BEFORE INSERT OR UPDATE ON mytab
<sect1 id="pltcl-unknown">
<sect1 id="pltcl-unknown">
<title>Modules and the <function>unknown</> command</title>
<title>Modules and the <function>unknown</> command</title>
<para>
<para>
PL/Tcl has support for autoloading Tcl code when used.
PL/Tcl has support for autoloading Tcl code when used.
It recognizes a special table, <literal>pltcl_modules</>, which
It recognizes a special table, <literal>pltcl_modules</>, which
is presumed to contain modules of Tcl code. If this table
is presumed to contain modules of Tcl code. If this table
exists, the module <literal>unknown</> is fetched from the table
exists, the module <literal>unknown</> is fetched from the table
and loaded into the Tcl interpreter immediately after creating
and loaded into the Tcl interpreter immediately after creating
the interpreter.
the interpreter.
</para>
</para>
<para>
<para>
While the <literal>unknown</> module could actually contain any
While the <literal>unknown</> module could actually contain any
initialization script you need, it normally defines a Tcl
initialization script you need, it normally defines a Tcl
<function>unknown</> procedure that is invoked whenever Tcl does
<function>unknown</> procedure that is invoked whenever Tcl does
not recognize an invoked procedure name. <application>PL/Tcl</>'s standard version
not recognize an invoked procedure name. <application>PL/Tcl</>'s standard version
of this procedure tries to find a module in <literal>pltcl_modules</>
of this procedure tries to find a module in <literal>pltcl_modules</>
that will define the required procedure. If one is found, it is
that will define the required procedure. If one is found, it is
loaded into the interpreter, and then execution is allowed to
loaded into the interpreter, and then execution is allowed to
proceed with the originally attempted procedure call. A
proceed with the originally attempted procedure call. A
secondary table <literal>pltcl_modfuncs</> provides an index of
secondary table <literal>pltcl_modfuncs</> provides an index of
which functions are defined by which modules, so that the lookup
which functions are defined by which modules, so that the lookup
is reasonably quick.
is reasonably quick.
</para>
</para>
<para>
<para>
The <productname>PostgreSQL</productname> distribution includes
The <productname>PostgreSQL</productname> distribution includes
support scripts to maintain these tables:
support scripts to maintain these tables:
<command>pltcl_loadmod</>, <command>pltcl_listmod</>,
<command>pltcl_loadmod</>, <command>pltcl_listmod</>,
<command>pltcl_delmod</>, as well as source for the standard
<command>pltcl_delmod</>, as well as source for the standard
<literal>unknown</> module in <filename>share/unknown.pltcl</>. This module
<literal>unknown</> module in <filename>share/unknown.pltcl</>. This module
must be loaded
must be loaded
into each database initially to support the autoloading mechanism.
into each database initially to support the autoloading mechanism.
</para>
</para>
<para>
<para>
The tables <literal>pltcl_modules</> and <literal>pltcl_modfuncs</>
The tables <literal>pltcl_modules</> and <literal>pltcl_modfuncs</>
must be readable by all, but it is wise to make them owned and
must be readable by all, but it is wise to make them owned and
writable only by the database administrator.
writable only by the database administrator.
</para>
</para>
</sect1>
</sect1>
...
...
doc/src/sgml/spi.sgml
View file @
883ac5ca
<!--
<!--
$PostgreSQL: pgsql/doc/src/sgml/spi.sgml,v 1.3
6 2004/12/13 18:05:09 petere
Exp $
$PostgreSQL: pgsql/doc/src/sgml/spi.sgml,v 1.3
7 2004/12/30 21:45:37 tgl
Exp $
-->
-->
<chapter id="spi">
<chapter id="spi">
...
@@ -23,8 +23,8 @@ $PostgreSQL: pgsql/doc/src/sgml/spi.sgml,v 1.36 2004/12/13 18:05:09 petere Exp $
...
@@ -23,8 +23,8 @@ $PostgreSQL: pgsql/doc/src/sgml/spi.sgml,v 1.36 2004/12/13 18:05:09 petere Exp $
<note>
<note>
<para>
<para>
The available procedural languages provide various means to
The available procedural languages provide various means to
execute SQL commands from procedures.
Some of these are based on or
execute SQL commands from procedures.
Most of these facilities are
modelled after
SPI, so this documentation might be of use for users
based on
SPI, so this documentation might be of use for users
of those languages as well.
of those languages as well.
</para>
</para>
</note>
</note>
...
@@ -37,15 +37,15 @@ $PostgreSQL: pgsql/doc/src/sgml/spi.sgml,v 1.36 2004/12/13 18:05:09 petere Exp $
...
@@ -37,15 +37,15 @@ $PostgreSQL: pgsql/doc/src/sgml/spi.sgml,v 1.36 2004/12/13 18:05:09 petere Exp $
</para>
</para>
<para>
<para>
Note that if
during the execution of a procedure the transaction is
Note that if
a command invoked via SPI fails, then control will not be
aborted because of an error in a command, then control will not b
e
returned to your procedure. Rather, th
e
returned to your procedure. Rather, all work will be rolled back
transaction or subtransaction in which your procedure executes will be
and the server will wait for the next command from the client. A
rolled back. (This may seem surprising given that the SPI functions mostly
related restriction is the inability to execute
have documented error-return conventions. Those conventions only apply
<command>BEGIN</command>, <command>COMMIT</command>, and
for errors detected within the SPI functions themselves, however.)
<command>ROLLBACK</command> (transaction control statements) inside
It is possible to recover control after an error by establishing your own
a procedure. Both of these restrictions will probably be changed in
subtransaction surrounding SPI calls that might fail. This is not currently
the future
.
documented because the mechanisms required are still in flux
.
</para>
</para>
<para>
<para>
...
@@ -104,6 +104,7 @@ int SPI_connect(void)
...
@@ -104,6 +104,7 @@ int SPI_connect(void)
<acronym>SPI</acronym>, directly nested calls to
<acronym>SPI</acronym>, directly nested calls to
<function>SPI_connect</function> and
<function>SPI_connect</function> and
<function>SPI_finish</function> are forbidden.
<function>SPI_finish</function> are forbidden.
(But see <function>SPI_push</function> and <function>SPI_pop</function>.)
</para>
</para>
</refsect1>
</refsect1>
...
@@ -206,7 +207,7 @@ int SPI_finish(void)
...
@@ -206,7 +207,7 @@ int SPI_finish(void)
<refnamediv>
<refnamediv>
<refname>SPI_push</refname>
<refname>SPI_push</refname>
<refpurpose>push
es
SPI stack to allow recursive SPI usage</refpurpose>
<refpurpose>push SPI stack to allow recursive SPI usage</refpurpose>
</refnamediv>
</refnamediv>
<indexterm><primary>SPI_push</primary></indexterm>
<indexterm><primary>SPI_push</primary></indexterm>
...
@@ -253,7 +254,7 @@ void SPI_push(void)
...
@@ -253,7 +254,7 @@ void SPI_push(void)
<refnamediv>
<refnamediv>
<refname>SPI_pop</refname>
<refname>SPI_pop</refname>
<refpurpose>pop
s
SPI stack to return from recursive SPI usage</refpurpose>
<refpurpose>pop SPI stack to return from recursive SPI usage</refpurpose>
</refnamediv>
</refnamediv>
<indexterm><primary>SPI_pop</primary></indexterm>
<indexterm><primary>SPI_pop</primary></indexterm>
...
@@ -322,8 +323,8 @@ SPI_execute("INSERT INTO foo SELECT * FROM bar", false, 5);
...
@@ -322,8 +323,8 @@ SPI_execute("INSERT INTO foo SELECT * FROM bar", false, 5);
</para>
</para>
<para>
<para>
You may pass multiple commands in one string
, and the commands may
You may pass multiple commands in one string
.
be rewritten by rules.
<function>SPI_execute</function> returns the
<function>SPI_execute</function> returns the
result for the command executed last. The <parameter>count</parameter>
result for the command executed last. The <parameter>count</parameter>
limit applies to each command separately, but it is not applied to
limit applies to each command separately, but it is not applied to
hidden commands generated by rules.
hidden commands generated by rules.
...
@@ -693,7 +694,7 @@ void * SPI_prepare(const char * <parameter>command</parameter>, int <parameter>n
...
@@ -693,7 +694,7 @@ void * SPI_prepare(const char * <parameter>command</parameter>, int <parameter>n
<para>
<para>
The plan returned by <function>SPI_prepare</function> can be used
The plan returned by <function>SPI_prepare</function> can be used
only in the current invocation of the procedure since
only in the current invocation of the procedure
,
since
<function>SPI_finish</function> frees memory allocated for a plan.
<function>SPI_finish</function> frees memory allocated for a plan.
But a plan can be saved for longer using the function
But a plan can be saved for longer using the function
<function>SPI_saveplan</function>.
<function>SPI_saveplan</function>.
...
@@ -770,7 +771,7 @@ void * SPI_prepare(const char * <parameter>command</parameter>, int <parameter>n
...
@@ -770,7 +771,7 @@ void * SPI_prepare(const char * <parameter>command</parameter>, int <parameter>n
<refnamediv>
<refnamediv>
<refname>SPI_getargcount</refname>
<refname>SPI_getargcount</refname>
<refpurpose>return
s
the number of arguments needed by a plan
<refpurpose>return the number of arguments needed by a plan
prepared by <function>SPI_prepare</function></refpurpose>
prepared by <function>SPI_prepare</function></refpurpose>
</refnamediv>
</refnamediv>
...
@@ -825,7 +826,7 @@ int SPI_getargcount(void * <parameter>plan</parameter>)
...
@@ -825,7 +826,7 @@ int SPI_getargcount(void * <parameter>plan</parameter>)
<refnamediv>
<refnamediv>
<refname>SPI_getargtypeid</refname>
<refname>SPI_getargtypeid</refname>
<refpurpose>return
s the expected <parameter>typeid</parameter> for the specified
argument of
<refpurpose>return
the data type OID for an
argument of
a plan prepared by <function>SPI_prepare</function></refpurpose>
a plan prepared by <function>SPI_prepare</function></refpurpose>
</refnamediv>
</refnamediv>
...
@@ -892,7 +893,7 @@ Oid SPI_getargtypeid(void * <parameter>plan</parameter>, int <parameter>argIndex
...
@@ -892,7 +893,7 @@ Oid SPI_getargtypeid(void * <parameter>plan</parameter>, int <parameter>argIndex
<refnamediv>
<refnamediv>
<refname>SPI_is_cursor_plan</refname>
<refname>SPI_is_cursor_plan</refname>
<refpurpose>return
s
<symbol>true</symbol> if a plan
<refpurpose>return <symbol>true</symbol> if a plan
prepared by <function>SPI_prepare</function> can be used with
prepared by <function>SPI_prepare</function> can be used with
<function>SPI_cursor_open</function></refpurpose>
<function>SPI_cursor_open</function></refpurpose>
</refnamediv>
</refnamediv>
...
@@ -954,7 +955,7 @@ bool SPI_is_cursor_plan(void * <parameter>plan</parameter>)
...
@@ -954,7 +955,7 @@ bool SPI_is_cursor_plan(void * <parameter>plan</parameter>)
<refnamediv>
<refnamediv>
<refname>SPI_execute_plan</refname>
<refname>SPI_execute_plan</refname>
<refpurpose>execute
s
a plan prepared by <function>SPI_prepare</function></refpurpose>
<refpurpose>execute a plan prepared by <function>SPI_prepare</function></refpurpose>
</refnamediv>
</refnamediv>
<indexterm><primary>SPI_execute_plan</primary></indexterm>
<indexterm><primary>SPI_execute_plan</primary></indexterm>
...
@@ -1096,7 +1097,7 @@ int SPI_execute_plan(void * <parameter>plan</parameter>, Datum * <parameter>valu
...
@@ -1096,7 +1097,7 @@ int SPI_execute_plan(void * <parameter>plan</parameter>, Datum * <parameter>valu
<refnamediv>
<refnamediv>
<refname>SPI_execp</refname>
<refname>SPI_execp</refname>
<refpurpose>execute
s
a plan in read/write mode</refpurpose>
<refpurpose>execute a plan in read/write mode</refpurpose>
</refnamediv>
</refnamediv>
<indexterm><primary>SPI_execp</primary></indexterm>
<indexterm><primary>SPI_execp</primary></indexterm>
...
@@ -1677,7 +1678,7 @@ char * SPI_fname(TupleDesc <parameter>rowdesc</parameter>, int <parameter>colnum
...
@@ -1677,7 +1678,7 @@ char * SPI_fname(TupleDesc <parameter>rowdesc</parameter>, int <parameter>colnum
<title>Description</title>
<title>Description</title>
<para>
<para>
<function>SPI_fname</function> returns the column name of the
<function>SPI_fname</function> returns
a copy of
the column name of the
specified column. (You can use <function>pfree</function> to
specified column. (You can use <function>pfree</function> to
release the copy of the name when you don't need it anymore.)
release the copy of the name when you don't need it anymore.)
</para>
</para>
...
@@ -1992,7 +1993,7 @@ char * SPI_gettype(TupleDesc <parameter>rowdesc</parameter>, int <parameter>coln
...
@@ -1992,7 +1993,7 @@ char * SPI_gettype(TupleDesc <parameter>rowdesc</parameter>, int <parameter>coln
<title>Description</title>
<title>Description</title>
<para>
<para>
<function>SPI_gettype</function> returns the data type name of the
<function>SPI_gettype</function> returns
a copy of
the data type name of the
specified column. (You can use <function>pfree</function> to
specified column. (You can use <function>pfree</function> to
release the copy of the name when you don't need it anymore.)
release the copy of the name when you don't need it anymore.)
</para>
</para>
...
@@ -2122,7 +2123,7 @@ char * SPI_getrelname(Relation <parameter>rel</parameter>)
...
@@ -2122,7 +2123,7 @@ char * SPI_getrelname(Relation <parameter>rel</parameter>)
<title>Description</title>
<title>Description</title>
<para>
<para>
<function>SPI_getrelname</function> returns the name of the
<function>SPI_getrelname</function> returns
a copy of
the name of the
specified relation. (You can use <function>pfree</function> to
specified relation. (You can use <function>pfree</function> to
release the copy of the name when you don't need it anymore.)
release the copy of the name when you don't need it anymore.)
</para>
</para>
...
@@ -2190,7 +2191,7 @@ char * SPI_getrelname(Relation <parameter>rel</parameter>)
...
@@ -2190,7 +2191,7 @@ char * SPI_getrelname(Relation <parameter>rel</parameter>)
object. <function>SPI_palloc</function> allocates memory in the
object. <function>SPI_palloc</function> allocates memory in the
<quote>upper executor context</quote>, that is, the memory context
<quote>upper executor context</quote>, that is, the memory context
that was current when <function>SPI_connect</function> was called,
that was current when <function>SPI_connect</function> was called,
which is precisely the right context for
return a value
from your
which is precisely the right context for
a value returned
from your
procedure.
procedure.
</para>
</para>
...
@@ -2600,7 +2601,7 @@ HeapTuple SPI_modifytuple(Relation <parameter>rel</parameter>, HeapTuple <parame
...
@@ -2600,7 +2601,7 @@ HeapTuple SPI_modifytuple(Relation <parameter>rel</parameter>, HeapTuple <parame
<listitem>
<listitem>
<para>
<para>
array of the numbers of the columns that are to be changed
array of the numbers of the columns that are to be changed
(co
unt starts
at 1)
(co
lumn numbers start
at 1)
</para>
</para>
</listitem>
</listitem>
</varlistentry>
</varlistentry>
...
@@ -2674,7 +2675,7 @@ HeapTuple SPI_modifytuple(Relation <parameter>rel</parameter>, HeapTuple <parame
...
@@ -2674,7 +2675,7 @@ HeapTuple SPI_modifytuple(Relation <parameter>rel</parameter>, HeapTuple <parame
<refnamediv>
<refnamediv>
<refname>SPI_freetuple</refname>
<refname>SPI_freetuple</refname>
<refpurpose>free
s
a row allocated in the upper executor context</refpurpose>
<refpurpose>free a row allocated in the upper executor context</refpurpose>
</refnamediv>
</refnamediv>
<indexterm><primary>SPI_freetuple</primary></indexterm>
<indexterm><primary>SPI_freetuple</primary></indexterm>
...
@@ -2833,16 +2834,15 @@ int SPI_freeplan(void *<parameter>plan</parameter>)
...
@@ -2833,16 +2834,15 @@ int SPI_freeplan(void *<parameter>plan</parameter>)
<title>Visibility of Data Changes</title>
<title>Visibility of Data Changes</title>
<para>
<para>
The following
two
rules govern the visibility of data changes in
The following rules govern the visibility of data changes in
functions that use SPI (or any other C function):
functions that use SPI (or any other C function):
<itemizedlist>
<itemizedlist>
<listitem>
<listitem>
<para>
<para>
During the execution of an SQL command, any data changes made by
During the execution of an SQL command, any data changes made by
the command (or by function called by the command, including
the command are invisible to the command itself. For
trigger functions) are invisible to the command. For
example, in
example, in command
<programlisting>
<programlisting>
INSERT INTO a SELECT * FROM a;
INSERT INTO a SELECT * FROM a;
</programlisting>
</programlisting>
...
@@ -2858,6 +2858,29 @@ INSERT INTO a SELECT * FROM a;
...
@@ -2858,6 +2858,29 @@ INSERT INTO a SELECT * FROM a;
(during the execution of C) or after C is done.
(during the execution of C) or after C is done.
</para>
</para>
</listitem>
</listitem>
<listitem>
<para>
Commands executed via SPI inside a function called by an SQL command
(either an ordinary function or a trigger) follow one or the
other of the above rules depending on the read/write flag passed
to SPI. Commands executed in read-only mode follow the first
rule: they can't see changes of the calling command. Commands executed
in read-write mode follow the second rule: they can see all changes made
so far.
</para>
</listitem>
<listitem>
<para>
All standard procedural languages set the SPI read-write mode
depending on the volatility attribute of the function. Commands of
<literal>STABLE</> and <literal>IMMUTABLE</> functions are done in
read-only mode, while commands of <literal>VOLATILE</> functions are
done in read-write mode. While authors of C functions are able to
violate this convention, it's unlikely to be a good idea to do so.
</para>
</listitem>
</itemizedlist>
</itemizedlist>
</para>
</para>
...
@@ -2934,7 +2957,7 @@ execq(text *sql, int cnt)
...
@@ -2934,7 +2957,7 @@ execq(text *sql, int cnt)
<para>
<para>
(This function uses call convention version 0, to make the example
(This function uses call convention version 0, to make the example
easier to understand. In real applications you should use
r
the new
easier to understand. In real applications you should use the new
version 1 interface.)
version 1 interface.)
</para>
</para>
...
...
doc/src/sgml/xfunc.sgml
View file @
883ac5ca
<!--
<!--
$PostgreSQL: pgsql/doc/src/sgml/xfunc.sgml,v 1.9
1 2004/12/30 03:13:56
tgl Exp $
$PostgreSQL: pgsql/doc/src/sgml/xfunc.sgml,v 1.9
2 2004/12/30 21:45:37
tgl Exp $
-->
-->
<sect1 id="xfunc">
<sect1 id="xfunc">
...
@@ -823,23 +823,15 @@ CREATE FUNCTION test(int, int) RETURNS int
...
@@ -823,23 +823,15 @@ CREATE FUNCTION test(int, int) RETURNS int
<title>Procedural Language Functions</title>
<title>Procedural Language Functions</title>
<para>
<para>
<productname>PostgreSQL</productname> allows user-defined functions
to be written in other languages besides SQL and C. These other
languages are generically called <firstterm>procedural
languages</firstterm> (<acronym>PL</>s).
Procedural languages aren't built into the
Procedural languages aren't built into the
<productname>PostgreSQL</productname> server; they are offered
<productname>PostgreSQL</productname> server; they are offered
by loadable modules. Please refer to the documentation of the
by loadable modules.
procedural language in question for details about the syntax and how the
See <xref linkend="xplang"> and following chapters for more
function body is interpreted for each language.
information.
</para>
<para>
There are currently four procedural languages available in the
standard <productname>PostgreSQL</productname> distribution:
<application>PL/pgSQL</application>, <application>PL/Tcl</application>,
<application>PL/Perl</application>, and
<application>PL/Python</application>.
Refer to <xref linkend="xplang"> for more information.
Other languages can be defined by users.
The basics of developing a new procedural language are covered in <xref
linkend="plhandler">.
</para>
</para>
</sect1>
</sect1>
...
...
doc/src/sgml/xplang.sgml
View file @
883ac5ca
<!--
<!--
$PostgreSQL: pgsql/doc/src/sgml/xplang.sgml,v 1.2
7 2004/12/30 03:13:56
tgl Exp $
$PostgreSQL: pgsql/doc/src/sgml/xplang.sgml,v 1.2
8 2004/12/30 21:45:37
tgl Exp $
-->
-->
<chapter id="xplang">
<chapter id="xplang">
...
@@ -10,27 +10,32 @@ $PostgreSQL: pgsql/doc/src/sgml/xplang.sgml,v 1.27 2004/12/30 03:13:56 tgl Exp $
...
@@ -10,27 +10,32 @@ $PostgreSQL: pgsql/doc/src/sgml/xplang.sgml,v 1.27 2004/12/30 03:13:56 tgl Exp $
</indexterm>
</indexterm>
<para>
<para>
<productname>PostgreSQL</productname> allows user
s to add new
<productname>PostgreSQL</productname> allows user
-defined functions
programming languages to be available for writing functions and
to be written in other languages besides SQL and C. These other
procedures. These are
called <firstterm>procedural
languages are generically
called <firstterm>procedural
languages</firstterm> (
PL). In the case of a function or trigger
languages</firstterm> (
<acronym>PL</>s). For a function
procedure
written in a procedural language, the database server has
written in a procedural language, the database server has
no built-in knowledge about how to interpret the function's source
no built-in knowledge about how to interpret the function's source
text. Instead, the task is passed to a special handler that knows
text. Instead, the task is passed to a special handler that knows
the details of the language. The handler could either do all the
the details of the language. The handler could either do all the
work of parsing, syntax analysis, execution, etc. itself, or it
work of parsing, syntax analysis, execution, etc. itself, or it
could serve as <quote>glue</quote> between
could serve as <quote>glue</quote> between
<productname>PostgreSQL</productname> and an existing implementation
<productname>PostgreSQL</productname> and an existing implementation
of a programming language. The handler itself is a
special
of a programming language. The handler itself is a
C language function compiled into a shared object and
C language function compiled into a shared object and
loaded on demand.
loaded on demand
, just like any other C function
.
</para>
</para>
<para>
<para>
Writing a handler for a new procedural language is described in
There are currently four procedural languages available in the
<xref linkend="plhandler">. Several procedural languages are
standard <productname>PostgreSQL</productname> distribution:
available in the core <productname>PostgreSQL</productname>
<application>PL/pgSQL</application> (<xref linkend="plpgsql">),
distribution, which can serve as examples.
<application>PL/Tcl</application> (<xref linkend="pltcl">),
<application>PL/Perl</application> (<xref linkend="plperl">), and
<application>PL/Python</application> (<xref linkend="plpython">).
Other languages can be defined by users.
The basics of developing a new procedural language are covered in <xref
linkend="plhandler">.
</para>
</para>
<para>
<para>
...
@@ -46,14 +51,16 @@ $PostgreSQL: pgsql/doc/src/sgml/xplang.sgml,v 1.27 2004/12/30 03:13:56 tgl Exp $
...
@@ -46,14 +51,16 @@ $PostgreSQL: pgsql/doc/src/sgml/xplang.sgml,v 1.27 2004/12/30 03:13:56 tgl Exp $
A procedural language must be <quote>installed</quote> into each
A procedural language must be <quote>installed</quote> into each
database where it is to be used. But procedural languages installed in
database where it is to be used. But procedural languages installed in
the database <literal>template1</> are automatically available in all
the database <literal>template1</> are automatically available in all
subsequently created databases. So the database administrator can
subsequently created databases, since their entries in
<literal>template1</> will be copied by <command>CREATE DATABASE</>.
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.
some languages available by default if he chooses.
</para>
</para>
<para>
<para>
For the languages supplied with the standard distribution, the
For the languages supplied with the standard distribution, the
program <
command>createlang</command
> may be used to install the
program <
xref linkend="app-createlang"
> may be used to install the
language instead of carrying out the details by hand. For
language instead of carrying out the details by hand. For
example, to install the language
example, to install the language
<application>PL/pgSQL</application> into the database
<application>PL/pgSQL</application> into the database
...
@@ -72,23 +79,24 @@ createlang plpgsql template1
...
@@ -72,23 +79,24 @@ createlang plpgsql template1
</title>
</title>
<para>
<para>
A procedural language is installed in a database in
three
steps,
A procedural language is installed in a database in
four
steps,
which must be carried out by a database superuser. The
which must be carried out by a database superuser. The
<command>createlang</command> program automates <xref
<command>createlang</command> program automates all but <xref
linkend="xplang-install-cr1"> and <xref
linkend="xplang-install-cr1">.
linkend="xplang-install-cr2">.
</para>
</para>
<step performance="required">
<step performance="required"
id="xplang-install-cr1"
>
<para>
<para>
The shared object for the language handler must be compiled and
The shared object for the language handler must be compiled and
installed into an appropriate library directory. This works in the same
installed into an appropriate library directory. This works in the same
way as building and installing modules with regular user-defined C
way as building and installing modules with regular user-defined C
functions does; see <xref linkend="dfunc">.
functions does; see <xref linkend="dfunc">. Often, the language
handler will depend on an external library that provides the actual
programming language engine; if so, that must be installed as well.
</para>
</para>
</step>
</step>
<step performance="required" id="xplang-install-cr
1
">
<step performance="required" id="xplang-install-cr
2
">
<para>
<para>
The handler must be declared with the command
The handler must be declared with the command
<synopsis>
<synopsis>
...
@@ -104,12 +112,29 @@ CREATE FUNCTION <replaceable>handler_function_name</replaceable>()
...
@@ -104,12 +112,29 @@ CREATE FUNCTION <replaceable>handler_function_name</replaceable>()
</para>
</para>
</step>
</step>
<step performance="required" id="xplang-install-cr2">
<step performance="optional" id="xplang-install-cr3">
<para>
Optionally, the language handler may provide a <quote>validator</>
function that checks a function definition for correctness without
actually executing it. The validator function is called by
<command>CREATE FUNCTION</> if it exists. If a validator function
is provided by the handler, declare it with a command like
<synopsis>
CREATE FUNCTION <replaceable>validator_function_name</replaceable>(oid)
RETURNS void
AS '<replaceable>path-to-shared-object</replaceable>'
LANGUAGE C;
</synopsis>
</para>
</step>
<step performance="required" id="xplang-install-cr4">
<para>
<para>
The PL must be declared with the command
The PL must be declared with the command
<synopsis>
<synopsis>
CREATE <optional>TRUSTED</optional> <optional>PROCEDURAL</optional> LANGUAGE <replaceable>language-name</replaceable>
CREATE <optional>TRUSTED</optional> <optional>PROCEDURAL</optional> LANGUAGE <replaceable>language-name</replaceable>
HANDLER <replaceable>handler_function_name</replaceable>;
HANDLER <replaceable>handler_function_name</replaceable>
<optional>VALIDATOR <replaceable>validator_function_name</replaceable></optional> ;
</synopsis>
</synopsis>
The optional key word <literal>TRUSTED</literal> specifies that
The optional key word <literal>TRUSTED</literal> specifies that
ordinary database users that have no superuser privileges should
ordinary database users that have no superuser privileges should
...
@@ -150,13 +175,24 @@ CREATE FUNCTION plpgsql_call_handler() RETURNS language_handler AS
...
@@ -150,13 +175,24 @@ CREATE FUNCTION plpgsql_call_handler() RETURNS language_handler AS
</programlisting>
</programlisting>
</para>
</para>
<para>
<application>PL/pgSQL</application> has a validator function,
so we declare that too:
<programlisting>
CREATE FUNCTION plpgsql_validator(oid) RETURNS void AS
'$libdir/plpgsql' LANGUAGE C;
</programlisting>
</para>
<para>
<para>
The command
The command
<programlisting>
<programlisting>
CREATE TRUSTED PROCEDURAL LANGUAGE plpgsql
CREATE TRUSTED PROCEDURAL LANGUAGE plpgsql
HANDLER plpgsql_call_handler;
HANDLER plpgsql_call_handler
VALIDATOR plpgsql_validator;
</programlisting>
</programlisting>
then defines that the previously declared
call handler function
then defines that the previously declared
functions
should be invoked for functions and trigger procedures where the
should be invoked for functions and trigger procedures where the
language attribute is <literal>plpgsql</literal>.
language attribute is <literal>plpgsql</literal>.
</para>
</para>
...
@@ -166,7 +202,7 @@ CREATE TRUSTED PROCEDURAL LANGUAGE plpgsql
...
@@ -166,7 +202,7 @@ CREATE TRUSTED PROCEDURAL LANGUAGE plpgsql
In a default <productname>PostgreSQL</productname> installation,
In a default <productname>PostgreSQL</productname> installation,
the handler for the <application>PL/pgSQL</application> language
the handler for the <application>PL/pgSQL</application> language
is built and installed into the <quote>library</quote>
is built and installed into the <quote>library</quote>
directory. If <application>Tcl
/Tk
</> support is configured in, the handlers for
directory. If <application>Tcl</> support is configured in, the handlers for
<application>PL/Tcl</> and <application>PL/TclU</> are also built and installed in the same
<application>PL/Tcl</> and <application>PL/TclU</> are also built and installed in the same
location. Likewise, the <application>PL/Perl</> and <application>PL/PerlU</> handlers are built
location. Likewise, the <application>PL/Perl</> and <application>PL/PerlU</> handlers are built
and installed if Perl support is configured, and <application>PL/PythonU</> is
and installed if Perl support is configured, and <application>PL/PythonU</> is
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment