mirror of
https://github.com/postgres/postgres.git
synced 2025-05-02 11:44:50 +03:00
This patch makes a minor cleanup to the implementation of PERFORM in
PL/PgSQL. Previously, it had been bundled together with the assign statement implementation, for some reason that wasn't clear to me (they certainly don't share any code with one another). So I separated them and made PERFORM a statement like any other. No changes in functionality. Along the way, I added some regression tests for PERFORM, added a bunch more SGML tags to the PL/PgSQL docs, and removed an obsolete comment relating to the implementation of RETURN NEXT. Neil Conway
This commit is contained in:
parent
ceb4f5ea9c
commit
cfd2728100
@ -1,5 +1,5 @@
|
|||||||
<!--
|
<!--
|
||||||
$Header: /cvsroot/pgsql/doc/src/sgml/plpgsql.sgml,v 1.8 2002/09/21 18:32:53 petere Exp $
|
$Header: /cvsroot/pgsql/doc/src/sgml/plpgsql.sgml,v 1.9 2002/11/10 00:35:58 momjian Exp $
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<chapter id="plpgsql">
|
<chapter id="plpgsql">
|
||||||
@ -102,7 +102,7 @@ END;
|
|||||||
</programlisting>
|
</programlisting>
|
||||||
If you execute the above function, it will reference the OID for
|
If you execute the above function, it will reference the OID for
|
||||||
<function>my_function()</function> in the query plan produced for
|
<function>my_function()</function> in the query plan produced for
|
||||||
the PERFORM statement. Later, if you
|
the <command>PERFORM</command> statement. Later, if you
|
||||||
drop and re-create <function>my_function()</function>, then
|
drop and re-create <function>my_function()</function>, then
|
||||||
<function>populate()</function> will not be able to find
|
<function>populate()</function> will not be able to find
|
||||||
<function>my_function()</function> anymore. You would then have to
|
<function>my_function()</function> anymore. You would then have to
|
||||||
@ -117,17 +117,19 @@ END;
|
|||||||
same tables and fields on every execution; that is, you cannot use
|
same tables and fields on every execution; that is, you cannot use
|
||||||
a parameter as the name of a table or field in a query. To get
|
a parameter as the name of a table or field in a query. To get
|
||||||
around this restriction, you can construct dynamic queries using
|
around this restriction, you can construct dynamic queries using
|
||||||
the <application>PL/pgSQL</application> EXECUTE statement --- at
|
the <application>PL/pgSQL</application> <command>EXECUTE</command>
|
||||||
the price of constructing a new query plan on every execution.
|
statement --- at the price of constructing a new query plan on
|
||||||
|
every execution.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<note>
|
<note>
|
||||||
<para>
|
<para>
|
||||||
The <application>PL/pgSQL</application> EXECUTE statement is not
|
The <application>PL/pgSQL</application>
|
||||||
related to the EXECUTE statement supported by the
|
<command>EXECUTE</command> statement is not related to the
|
||||||
|
<command>EXECUTE</command> statement supported by the
|
||||||
<productname>PostgreSQL</productname> backend. The backend
|
<productname>PostgreSQL</productname> backend. The backend
|
||||||
EXECUTE statement cannot be used within <application>PL/pgSQL</> functions (and
|
<command>EXECUTE</command> statement cannot be used within
|
||||||
is not needed).
|
<application>PL/pgSQL</> functions (and is not needed).
|
||||||
</para>
|
</para>
|
||||||
</note>
|
</note>
|
||||||
|
|
||||||
@ -173,13 +175,12 @@ END;
|
|||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
That means that your client application must send each
|
That means that your client application must send each query to
|
||||||
query to the database server, wait for it to process it,
|
the database server, wait for it to process it, receive the
|
||||||
receive the results, do some computation, then send
|
results, do some computation, then send other queries to the
|
||||||
other queries to the server. All this incurs inter-process communication
|
server. All this incurs inter-process communication and may also
|
||||||
and may also incur network
|
incur network overhead if your client is on a different machine
|
||||||
overhead if your client is on a different machine than
|
than the database server.
|
||||||
the database server.
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
@ -753,14 +754,14 @@ CREATE FUNCTION logfunc2 (TEXT) RETURNS TIMESTAMP AS '
|
|||||||
|
|
||||||
<para>
|
<para>
|
||||||
The mutable nature of record variables presents a problem in this
|
The mutable nature of record variables presents a problem in this
|
||||||
connection. When fields of a record variable are used in expressions or
|
connection. When fields of a record variable are used in
|
||||||
statements, the data types of the
|
expressions or statements, the data types of the fields must not
|
||||||
fields must not change between calls of one and the same expression,
|
change between calls of one and the same expression, since the
|
||||||
since the expression will be planned using the data type that is present
|
expression will be planned using the data type that is present
|
||||||
when the expression is first reached.
|
when the expression is first reached. Keep this in mind when
|
||||||
Keep this in mind when writing trigger procedures that handle events
|
writing trigger procedures that handle events for more than one
|
||||||
for more than one table. (EXECUTE can be used to get around this
|
table. (<command>EXECUTE</command> can be used to get around
|
||||||
problem when necessary.)
|
this problem when necessary.)
|
||||||
</para>
|
</para>
|
||||||
</sect1>
|
</sect1>
|
||||||
|
|
||||||
@ -904,10 +905,11 @@ END;
|
|||||||
<title>Executing an expression or query with no result</title>
|
<title>Executing an expression or query with no result</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Sometimes one wishes to evaluate an expression or query but discard
|
Sometimes one wishes to evaluate an expression or query but
|
||||||
the result (typically because one is calling a function that has
|
discard the result (typically because one is calling a function
|
||||||
useful side-effects but no useful result value). To do this in
|
that has useful side-effects but no useful result value). To do
|
||||||
<application>PL/pgSQL</application>, use the PERFORM statement:
|
this in <application>PL/pgSQL</application>, use the
|
||||||
|
<command>PERFORM</command> statement:
|
||||||
|
|
||||||
<synopsis>
|
<synopsis>
|
||||||
PERFORM <replaceable>query</replaceable>;
|
PERFORM <replaceable>query</replaceable>;
|
||||||
@ -923,8 +925,9 @@ PERFORM <replaceable>query</replaceable>;
|
|||||||
|
|
||||||
<note>
|
<note>
|
||||||
<para>
|
<para>
|
||||||
One might expect that SELECT with no INTO clause would accomplish
|
One might expect that <command>SELECT</command> with no INTO
|
||||||
this result, but at present the only accepted way to do it is PERFORM.
|
clause would accomplish this result, but at present the only
|
||||||
|
accepted way to do it is <command>PERFORM</command>.
|
||||||
</para>
|
</para>
|
||||||
</note>
|
</note>
|
||||||
|
|
||||||
@ -940,13 +943,13 @@ PERFORM create_mv(''cs_session_page_requests_mv'', my_query);
|
|||||||
<title>Executing dynamic queries</title>
|
<title>Executing dynamic queries</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Oftentimes you will want to generate dynamic queries inside
|
Oftentimes you will want to generate dynamic queries inside your
|
||||||
your <application>PL/pgSQL</application> functions, that is,
|
<application>PL/pgSQL</application> functions, that is, queries
|
||||||
queries that will involve different tables or different data types
|
that will involve different tables or different data types each
|
||||||
each time they are executed. <application>PL/pgSQL</application>'s
|
time they are executed. <application>PL/pgSQL</application>'s
|
||||||
normal attempts to cache plans for queries will not work in such
|
normal attempts to cache plans for queries will not work in such
|
||||||
scenarios. To handle this sort of problem, the EXECUTE statement
|
scenarios. To handle this sort of problem, the
|
||||||
is provided:
|
<command>EXECUTE</command> statement is provided:
|
||||||
|
|
||||||
<synopsis>
|
<synopsis>
|
||||||
EXECUTE <replaceable class="command">query-string</replaceable>;
|
EXECUTE <replaceable class="command">query-string</replaceable>;
|
||||||
@ -973,20 +976,22 @@ EXECUTE <replaceable class="command">query-string</replaceable>;
|
|||||||
|
|
||||||
<para>
|
<para>
|
||||||
Unlike all other queries in <application>PL/pgSQL</>, a
|
Unlike all other queries in <application>PL/pgSQL</>, a
|
||||||
<replaceable>query</replaceable> run by an EXECUTE statement is
|
<replaceable>query</replaceable> run by an
|
||||||
not prepared and saved just once during the life of the server.
|
<command>EXECUTE</command> statement is not prepared and saved
|
||||||
Instead, the <replaceable>query</replaceable> is prepared each
|
just once during the life of the server. Instead, the
|
||||||
time the statement is run. The
|
<replaceable>query</replaceable> is prepared each time the
|
||||||
<replaceable>query-string</replaceable> can be dynamically
|
statement is run. The <replaceable>query-string</replaceable> can
|
||||||
created within the procedure to perform actions on variable
|
be dynamically created within the procedure to perform actions on
|
||||||
tables and fields.
|
variable tables and fields.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The results from SELECT queries are discarded by EXECUTE, and
|
The results from <command>SELECT</command> queries are discarded
|
||||||
SELECT INTO is not currently supported within EXECUTE. So, the
|
by <command>EXECUTE</command>, and <command>SELECT INTO</command>
|
||||||
only way to extract a result from a dynamically-created SELECT is
|
is not currently supported within <command>EXECUTE</command>.
|
||||||
to use the FOR-IN-EXECUTE form described later.
|
So, the only way to extract a result from a dynamically-created
|
||||||
|
<command>SELECT</command> is to use the FOR-IN-EXECUTE form
|
||||||
|
described later.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
@ -1017,7 +1022,8 @@ EXECUTE ''UPDATE tbl SET ''
|
|||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Here is a much larger example of a dynamic query and EXECUTE:
|
Here is a much larger example of a dynamic query and
|
||||||
|
<command>EXECUTE</command>:
|
||||||
<programlisting>
|
<programlisting>
|
||||||
CREATE FUNCTION cs_update_referrer_type_proc() RETURNS INTEGER AS '
|
CREATE FUNCTION cs_update_referrer_type_proc() RETURNS INTEGER AS '
|
||||||
DECLARE
|
DECLARE
|
||||||
@ -1159,9 +1165,9 @@ GET DIAGNOSTICS <replaceable>variable</replaceable> = <replaceable>item</replace
|
|||||||
RETURN <replaceable>expression</replaceable>;
|
RETURN <replaceable>expression</replaceable>;
|
||||||
</synopsis>
|
</synopsis>
|
||||||
|
|
||||||
RETURN with an expression is used to return from a
|
<command>RETURN</command> with an expression is used to return
|
||||||
<application>PL/pgSQL</> function that does not return a set.
|
from a <application>PL/pgSQL</> function that does not return a
|
||||||
The function terminates and the value of
|
set. The function terminates and the value of
|
||||||
<replaceable>expression</replaceable> is returned to the caller.
|
<replaceable>expression</replaceable> is returned to the caller.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
@ -1176,22 +1182,24 @@ RETURN <replaceable>expression</replaceable>;
|
|||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
The return value of a function cannot be left undefined. If control
|
The return value of a function cannot be left undefined. If
|
||||||
reaches the end of the top-level block of
|
control reaches the end of the top-level block of the function
|
||||||
the function without hitting a RETURN statement, a run-time error
|
without hitting a <command>RETURN</command> statement, a run-time
|
||||||
will occur.
|
error will occur.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
When a <application>PL/pgSQL</> function is declared to return
|
When a <application>PL/pgSQL</> function is declared to return
|
||||||
<literal>SETOF</literal> <replaceable>sometype</>, the procedure
|
<literal>SETOF</literal> <replaceable>sometype</>, the procedure
|
||||||
to follow is slightly different. In that case, the individual
|
to follow is slightly different. In that case, the individual
|
||||||
items to return are specified in RETURN NEXT commands, and then a
|
items to return are specified in <command>RETURN NEXT</command>
|
||||||
final RETURN command with no arguments is used to indicate that
|
commands, and then a final <command>RETURN</command> command with
|
||||||
the function has finished executing. RETURN NEXT can be used with
|
no arguments is used to indicate that the function has finished
|
||||||
both scalar and composite data types; in the later case, an
|
executing. <command>RETURN NEXT</command> can be used with both
|
||||||
entire "table" of results will be returned. Functions that use
|
scalar and composite data types; in the later case, an entire
|
||||||
RETURN NEXT should be called in the following fashion:
|
"table" of results will be returned. Functions that use
|
||||||
|
<command>RETURN NEXT</command> should be called in the following
|
||||||
|
fashion:
|
||||||
|
|
||||||
<programlisting>
|
<programlisting>
|
||||||
SELECT * FROM some_func();
|
SELECT * FROM some_func();
|
||||||
@ -1203,19 +1211,19 @@ SELECT * FROM some_func();
|
|||||||
RETURN NEXT <replaceable>expression</replaceable>;
|
RETURN NEXT <replaceable>expression</replaceable>;
|
||||||
</synopsis>
|
</synopsis>
|
||||||
|
|
||||||
RETURN NEXT does not actually return from the function; it simply
|
<command>RETURN NEXT</command> does not actually return from the
|
||||||
saves away the value of the expression (or record or row variable,
|
function; it simply saves away the value of the expression (or
|
||||||
as appropriate for the data type being returned).
|
record or row variable, as appropriate for the data type being
|
||||||
Execution then continues with the next statement in the
|
returned). Execution then continues with the next statement in
|
||||||
<application>PL/pgSQL</> function. As successive RETURN NEXT
|
the <application>PL/pgSQL</> function. As successive
|
||||||
commands are executed, the result set is built up. A final
|
<command>RETURN NEXT</command> commands are executed, the result
|
||||||
RETURN, which need have no argument, causes control to exit
|
set is built up. A final <command>RETURN</commmand>, which need
|
||||||
the function.
|
have no argument, causes control to exit the function.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<note>
|
<note>
|
||||||
<para>
|
<para>
|
||||||
The current implementation of RETURN NEXT for
|
The current implementation of <command>RETURN NEXT</command> for
|
||||||
<application>PL/pgSQL</> stores the entire result set before
|
<application>PL/pgSQL</> stores the entire result set before
|
||||||
returning from the function, as discussed above. That means that
|
returning from the function, as discussed above. That means that
|
||||||
if a <application>PL/pgSQL</> function produces a very large result set,
|
if a <application>PL/pgSQL</> function produces a very large result set,
|
||||||
@ -1586,12 +1594,12 @@ FOR <replaceable>record | row</replaceable> IN EXECUTE <replaceable>text_express
|
|||||||
<replaceable>statements</replaceable>
|
<replaceable>statements</replaceable>
|
||||||
END LOOP;
|
END LOOP;
|
||||||
</synopsis>
|
</synopsis>
|
||||||
This is like the previous form, except that the source SELECT
|
This is like the previous form, except that the source
|
||||||
statement is specified as a string expression, which is evaluated
|
<command>SELECT</command> statement is specified as a string
|
||||||
and re-planned on each entry to the FOR loop. This allows the
|
expression, which is evaluated and re-planned on each entry to
|
||||||
programmer to choose the speed of a pre-planned query or the
|
the FOR loop. This allows the programmer to choose the speed of
|
||||||
flexibility of a dynamic query, just as with a plain EXECUTE
|
a pre-planned query or the flexibility of a dynamic query, just
|
||||||
statement.
|
as with a plain <command>EXECUTE</command> statement.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<note>
|
<note>
|
||||||
@ -1705,12 +1713,12 @@ OPEN curs1 FOR SELECT * FROM foo WHERE key = mykey;
|
|||||||
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>
|
||||||
|
|
||||||
The cursor variable is opened and given the specified query
|
The cursor variable is opened and given the specified query to
|
||||||
to execute. The cursor cannot be open already, and it must
|
execute. The cursor cannot be open already, and it must have been
|
||||||
have been declared as an unbound cursor (that is, as a simple
|
declared as an unbound cursor (that is, as a simple
|
||||||
<type>refcursor</> variable). The query is specified as a
|
<type>refcursor</> variable). The query is specified as a string
|
||||||
string expression in the same way as in the EXECUTE command.
|
expression in the same way as in the <command>EXECUTE</command>
|
||||||
As usual, this gives flexibility so the query can vary
|
command. As usual, this gives flexibility so the query can vary
|
||||||
from one run to the next.
|
from one run to the next.
|
||||||
|
|
||||||
<programlisting>
|
<programlisting>
|
||||||
@ -1727,14 +1735,13 @@ OPEN curs1 FOR EXECUTE ''SELECT * FROM '' || quote_ident($1);
|
|||||||
OPEN <replaceable>bound-cursor</replaceable> <optional> ( <replaceable>argument_values</replaceable> ) </optional>;
|
OPEN <replaceable>bound-cursor</replaceable> <optional> ( <replaceable>argument_values</replaceable> ) </optional>;
|
||||||
</synopsis>
|
</synopsis>
|
||||||
|
|
||||||
This form of OPEN is used to open a cursor variable whose query
|
This form of <command>OPEN</command> is used to open a cursor
|
||||||
was bound to it when it was declared.
|
variable whose query was bound to it when it was declared. The
|
||||||
The cursor cannot be open already. A list of actual argument
|
cursor cannot be open already. A list of actual argument value
|
||||||
value expressions must appear if and only if the cursor was
|
expressions must appear if and only if the cursor was declared to
|
||||||
declared to take arguments. These values will be substituted
|
take arguments. These values will be substituted in the query.
|
||||||
in the query.
|
The query plan for a bound cursor is always considered cacheable
|
||||||
The query plan for a bound cursor is always considered
|
--- there is no equivalent of <command>EXECUTE</command> in this case.
|
||||||
cacheable --- there is no equivalent of EXECUTE in this case.
|
|
||||||
|
|
||||||
<programlisting>
|
<programlisting>
|
||||||
OPEN curs2;
|
OPEN curs2;
|
||||||
@ -1776,11 +1783,12 @@ OPEN curs3(42);
|
|||||||
FETCH <replaceable>cursor</replaceable> INTO <replaceable>target</replaceable>;
|
FETCH <replaceable>cursor</replaceable> INTO <replaceable>target</replaceable>;
|
||||||
</synopsis>
|
</synopsis>
|
||||||
|
|
||||||
FETCH retrieves the next row from the cursor into a target,
|
<command>FETCH</command> retrieves the next row from the
|
||||||
which may be a row variable, a record variable, or a comma-separated
|
cursor into a target, which may be a row variable, a record
|
||||||
list of simple variables, just like SELECT INTO. As with
|
variable, or a comma-separated list of simple variables, just like
|
||||||
SELECT INTO, the special variable <literal>FOUND</literal> may be
|
<command>SELECT INTO</command>. As with <command>SELECT
|
||||||
checked to see whether a row was obtained or not.
|
INTO</command>, the special variable <literal>FOUND</literal> may
|
||||||
|
be checked to see whether a row was obtained or not.
|
||||||
|
|
||||||
<programlisting>
|
<programlisting>
|
||||||
FETCH curs1 INTO rowvar;
|
FETCH curs1 INTO rowvar;
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
* procedural language
|
* procedural language
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/gram.y,v 1.39 2002/11/01 22:52:34 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/gram.y,v 1.40 2002/11/10 00:35:58 momjian Exp $
|
||||||
*
|
*
|
||||||
* This software is copyrighted by Jan Wieck - Hamburg.
|
* This software is copyrighted by Jan Wieck - Hamburg.
|
||||||
*
|
*
|
||||||
@ -728,14 +728,13 @@ proc_stmt : pl_block ';'
|
|||||||
|
|
||||||
stmt_perform : K_PERFORM lno expr_until_semi
|
stmt_perform : K_PERFORM lno expr_until_semi
|
||||||
{
|
{
|
||||||
PLpgSQL_stmt_assign *new;
|
PLpgSQL_stmt_perform *new;
|
||||||
|
|
||||||
new = malloc(sizeof(PLpgSQL_stmt_assign));
|
new = malloc(sizeof(PLpgSQL_stmt_perform));
|
||||||
memset(new, 0, sizeof(PLpgSQL_stmt_assign));
|
memset(new, 0, sizeof(PLpgSQL_stmt_perform));
|
||||||
|
|
||||||
new->cmd_type = PLPGSQL_STMT_ASSIGN;
|
new->cmd_type = PLPGSQL_STMT_PERFORM;
|
||||||
new->lineno = $2;
|
new->lineno = $2;
|
||||||
new->varno = -1;
|
|
||||||
new->expr = $3;
|
new->expr = $3;
|
||||||
|
|
||||||
$$ = (PLpgSQL_stmt *)new;
|
$$ = (PLpgSQL_stmt *)new;
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
* procedural language
|
* procedural language
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.65 2002/10/19 22:10:58 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.66 2002/11/10 00:35:58 momjian Exp $
|
||||||
*
|
*
|
||||||
* This software is copyrighted by Jan Wieck - Hamburg.
|
* This software is copyrighted by Jan Wieck - Hamburg.
|
||||||
*
|
*
|
||||||
@ -73,6 +73,8 @@ static int exec_stmt(PLpgSQL_execstate * estate,
|
|||||||
PLpgSQL_stmt * stmt);
|
PLpgSQL_stmt * stmt);
|
||||||
static int exec_stmt_assign(PLpgSQL_execstate * estate,
|
static int exec_stmt_assign(PLpgSQL_execstate * estate,
|
||||||
PLpgSQL_stmt_assign * stmt);
|
PLpgSQL_stmt_assign * stmt);
|
||||||
|
static int exec_stmt_perform(PLpgSQL_execstate * estate,
|
||||||
|
PLpgSQL_stmt_perform * stmt);
|
||||||
static int exec_stmt_getdiag(PLpgSQL_execstate * estate,
|
static int exec_stmt_getdiag(PLpgSQL_execstate * estate,
|
||||||
PLpgSQL_stmt_getdiag * stmt);
|
PLpgSQL_stmt_getdiag * stmt);
|
||||||
static int exec_stmt_if(PLpgSQL_execstate * estate,
|
static int exec_stmt_if(PLpgSQL_execstate * estate,
|
||||||
@ -890,6 +892,10 @@ exec_stmt(PLpgSQL_execstate * estate, PLpgSQL_stmt * stmt)
|
|||||||
rc = exec_stmt_assign(estate, (PLpgSQL_stmt_assign *) stmt);
|
rc = exec_stmt_assign(estate, (PLpgSQL_stmt_assign *) stmt);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case PLPGSQL_STMT_PERFORM:
|
||||||
|
rc = exec_stmt_perform(estate, (PLpgSQL_stmt_perform *) stmt);
|
||||||
|
break;
|
||||||
|
|
||||||
case PLPGSQL_STMT_GETDIAG:
|
case PLPGSQL_STMT_GETDIAG:
|
||||||
rc = exec_stmt_getdiag(estate, (PLpgSQL_stmt_getdiag *) stmt);
|
rc = exec_stmt_getdiag(estate, (PLpgSQL_stmt_getdiag *) stmt);
|
||||||
break;
|
break;
|
||||||
@ -973,27 +979,28 @@ exec_stmt(PLpgSQL_execstate * estate, PLpgSQL_stmt * stmt)
|
|||||||
/* ----------
|
/* ----------
|
||||||
* exec_stmt_assign Evaluate an expression and
|
* exec_stmt_assign Evaluate an expression and
|
||||||
* put the result into a variable.
|
* put the result into a variable.
|
||||||
*
|
|
||||||
* For no very good reason, this is also used for PERFORM statements.
|
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
exec_stmt_assign(PLpgSQL_execstate * estate, PLpgSQL_stmt_assign * stmt)
|
exec_stmt_assign(PLpgSQL_execstate * estate, PLpgSQL_stmt_assign * stmt)
|
||||||
{
|
{
|
||||||
PLpgSQL_expr *expr = stmt->expr;
|
Assert(stmt->varno >= 0);
|
||||||
|
|
||||||
if (stmt->varno >= 0)
|
exec_assign_expr(estate, estate->datums[stmt->varno], stmt->expr);
|
||||||
exec_assign_expr(estate, estate->datums[stmt->varno], expr);
|
|
||||||
else
|
return PLPGSQL_RC_OK;
|
||||||
{
|
}
|
||||||
/*
|
|
||||||
* PERFORM: evaluate query and discard result (but set FOUND
|
/* ----------
|
||||||
* depending on whether at least one row was returned).
|
* exec_stmt_perform Evaluate query and discard result (but set
|
||||||
*
|
* FOUND depending on whether at least one row
|
||||||
* This cannot share code with the assignment case since we do not
|
* was returned).
|
||||||
* wish to constrain the discarded result to be only one
|
* ----------
|
||||||
* row/column.
|
|
||||||
*/
|
*/
|
||||||
|
static int
|
||||||
|
exec_stmt_perform(PLpgSQL_execstate * estate, PLpgSQL_stmt_perform * stmt)
|
||||||
|
{
|
||||||
|
PLpgSQL_expr *expr = stmt->expr;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1009,7 +1016,6 @@ exec_stmt_assign(PLpgSQL_execstate * estate, PLpgSQL_stmt_assign * stmt)
|
|||||||
exec_set_found(estate, (estate->eval_processed != 0));
|
exec_set_found(estate, (estate->eval_processed != 0));
|
||||||
|
|
||||||
exec_eval_cleanup(estate);
|
exec_eval_cleanup(estate);
|
||||||
}
|
|
||||||
|
|
||||||
return PLPGSQL_RC_OK;
|
return PLPGSQL_RC_OK;
|
||||||
}
|
}
|
||||||
@ -1579,12 +1585,11 @@ exec_stmt_return(PLpgSQL_execstate * estate, PLpgSQL_stmt_return * stmt)
|
|||||||
return PLPGSQL_RC_RETURN;
|
return PLPGSQL_RC_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* ----------
|
||||||
* Notes:
|
* exec_stmt_return_next Evaluate an expression and add it to the
|
||||||
* - the tuple store must be created in a sufficiently long-lived
|
* list of tuples returned by the current
|
||||||
* memory context, as the same store must be used within the executor
|
* SRF.
|
||||||
* after the PL/PgSQL call returns. At present, the code uses
|
* ----------
|
||||||
* TopTransactionContext.
|
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
exec_stmt_return_next(PLpgSQL_execstate * estate,
|
exec_stmt_return_next(PLpgSQL_execstate * estate,
|
||||||
@ -1732,7 +1737,6 @@ exec_init_tuple_store(PLpgSQL_execstate * estate)
|
|||||||
estate->rettupdesc = rsi->expectedDesc;
|
estate->rettupdesc = rsi->expectedDesc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
* exec_stmt_raise Build a message and throw it with
|
* exec_stmt_raise Build a message and throw it with
|
||||||
* elog()
|
* elog()
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
* procedural language
|
* procedural language
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.28 2002/09/12 00:24:09 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.29 2002/11/10 00:35:58 momjian Exp $
|
||||||
*
|
*
|
||||||
* This software is copyrighted by Jan Wieck - Hamburg.
|
* This software is copyrighted by Jan Wieck - Hamburg.
|
||||||
*
|
*
|
||||||
@ -100,7 +100,8 @@ enum
|
|||||||
PLPGSQL_STMT_GETDIAG,
|
PLPGSQL_STMT_GETDIAG,
|
||||||
PLPGSQL_STMT_OPEN,
|
PLPGSQL_STMT_OPEN,
|
||||||
PLPGSQL_STMT_FETCH,
|
PLPGSQL_STMT_FETCH,
|
||||||
PLPGSQL_STMT_CLOSE
|
PLPGSQL_STMT_CLOSE,
|
||||||
|
PLPGSQL_STMT_PERFORM
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -288,6 +289,12 @@ typedef struct
|
|||||||
PLpgSQL_expr *expr;
|
PLpgSQL_expr *expr;
|
||||||
} PLpgSQL_stmt_assign;
|
} PLpgSQL_stmt_assign;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{ /* PERFORM statement */
|
||||||
|
int cmd_type;
|
||||||
|
int lineno;
|
||||||
|
PLpgSQL_expr *expr;
|
||||||
|
} PLpgSQL_stmt_perform;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{ /* Get Diagnostics item */
|
{ /* Get Diagnostics item */
|
||||||
|
@ -1733,3 +1733,54 @@ SELECT * FROM test_ret_rec_dyn(5) AS (a int, b numeric, c text);
|
|||||||
50 | 5 | xxx
|
50 | 5 | xxx
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
|
--
|
||||||
|
-- test PERFORM
|
||||||
|
--
|
||||||
|
create table perform_test (
|
||||||
|
a INT,
|
||||||
|
b INT
|
||||||
|
);
|
||||||
|
create function simple_func(int) returns boolean as '
|
||||||
|
BEGIN
|
||||||
|
IF $1 < 20 THEN
|
||||||
|
INSERT INTO perform_test VALUES ($1, $1 + 10);
|
||||||
|
RETURN TRUE;
|
||||||
|
ELSE
|
||||||
|
RETURN FALSE;
|
||||||
|
END IF;
|
||||||
|
END;' language 'plpgsql';
|
||||||
|
create function perform_test_func() returns void as '
|
||||||
|
BEGIN
|
||||||
|
IF FOUND then
|
||||||
|
INSERT INTO perform_test VALUES (100, 100);
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
PERFORM simple_func(5);
|
||||||
|
|
||||||
|
IF FOUND then
|
||||||
|
INSERT INTO perform_test VALUES (100, 100);
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
PERFORM simple_func(50);
|
||||||
|
|
||||||
|
IF FOUND then
|
||||||
|
INSERT INTO perform_test VALUES (100, 100);
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
RETURN;
|
||||||
|
END;' language 'plpgsql';
|
||||||
|
SELECT perform_test_func();
|
||||||
|
perform_test_func
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT * FROM perform_test;
|
||||||
|
a | b
|
||||||
|
-----+-----
|
||||||
|
5 | 15
|
||||||
|
100 | 100
|
||||||
|
100 | 100
|
||||||
|
(3 rows)
|
||||||
|
|
||||||
|
drop table perform_test;
|
||||||
|
@ -1559,3 +1559,48 @@ END;' language 'plpgsql';
|
|||||||
|
|
||||||
SELECT * FROM test_ret_rec_dyn(1500) AS (a int, b int, c int);
|
SELECT * FROM test_ret_rec_dyn(1500) AS (a int, b int, c int);
|
||||||
SELECT * FROM test_ret_rec_dyn(5) AS (a int, b numeric, c text);
|
SELECT * FROM test_ret_rec_dyn(5) AS (a int, b numeric, c text);
|
||||||
|
|
||||||
|
--
|
||||||
|
-- test PERFORM
|
||||||
|
--
|
||||||
|
|
||||||
|
create table perform_test (
|
||||||
|
a INT,
|
||||||
|
b INT
|
||||||
|
);
|
||||||
|
|
||||||
|
create function simple_func(int) returns boolean as '
|
||||||
|
BEGIN
|
||||||
|
IF $1 < 20 THEN
|
||||||
|
INSERT INTO perform_test VALUES ($1, $1 + 10);
|
||||||
|
RETURN TRUE;
|
||||||
|
ELSE
|
||||||
|
RETURN FALSE;
|
||||||
|
END IF;
|
||||||
|
END;' language 'plpgsql';
|
||||||
|
|
||||||
|
create function perform_test_func() returns void as '
|
||||||
|
BEGIN
|
||||||
|
IF FOUND then
|
||||||
|
INSERT INTO perform_test VALUES (100, 100);
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
PERFORM simple_func(5);
|
||||||
|
|
||||||
|
IF FOUND then
|
||||||
|
INSERT INTO perform_test VALUES (100, 100);
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
PERFORM simple_func(50);
|
||||||
|
|
||||||
|
IF FOUND then
|
||||||
|
INSERT INTO perform_test VALUES (100, 100);
|
||||||
|
END IF;
|
||||||
|
|
||||||
|
RETURN;
|
||||||
|
END;' language 'plpgsql';
|
||||||
|
|
||||||
|
SELECT perform_test_func();
|
||||||
|
SELECT * FROM perform_test;
|
||||||
|
|
||||||
|
drop table perform_test;
|
Loading…
x
Reference in New Issue
Block a user