mirror of
https://github.com/postgres/postgres.git
synced 2025-06-13 07:41:39 +03:00
PREPARE/EXECUTE statements. Patch by Neil Conway, some kibitzing
from Tom Lane.
This commit is contained in:
@ -1,5 +1,5 @@
|
|||||||
<!--
|
<!--
|
||||||
$Header: /cvsroot/pgsql/doc/src/sgml/ref/allfiles.sgml,v 1.47 2002/08/27 03:38:27 momjian Exp $
|
$Header: /cvsroot/pgsql/doc/src/sgml/ref/allfiles.sgml,v 1.48 2002/08/27 04:55:07 tgl Exp $
|
||||||
PostgreSQL documentation
|
PostgreSQL documentation
|
||||||
Complete list of usable sgml source files in this directory.
|
Complete list of usable sgml source files in this directory.
|
||||||
-->
|
-->
|
||||||
@ -71,6 +71,7 @@ Complete list of usable sgml source files in this directory.
|
|||||||
<!entity createType system "create_type.sgml">
|
<!entity createType system "create_type.sgml">
|
||||||
<!entity createUser system "create_user.sgml">
|
<!entity createUser system "create_user.sgml">
|
||||||
<!entity createView system "create_view.sgml">
|
<!entity createView system "create_view.sgml">
|
||||||
|
<!entity deallocate system "deallocate.sgml">
|
||||||
<!entity declare system "declare.sgml">
|
<!entity declare system "declare.sgml">
|
||||||
<!entity delete system "delete.sgml">
|
<!entity delete system "delete.sgml">
|
||||||
<!entity dropAggregate system "drop_aggregate.sgml">
|
<!entity dropAggregate system "drop_aggregate.sgml">
|
||||||
@ -93,6 +94,7 @@ Complete list of usable sgml source files in this directory.
|
|||||||
<!entity dropUser system "drop_user.sgml">
|
<!entity dropUser system "drop_user.sgml">
|
||||||
<!entity dropView system "drop_view.sgml">
|
<!entity dropView system "drop_view.sgml">
|
||||||
<!entity end system "end.sgml">
|
<!entity end system "end.sgml">
|
||||||
|
<!entity execute system "execute.sgml">
|
||||||
<!entity explain system "explain.sgml">
|
<!entity explain system "explain.sgml">
|
||||||
<!entity fetch system "fetch.sgml">
|
<!entity fetch system "fetch.sgml">
|
||||||
<!entity grant system "grant.sgml">
|
<!entity grant system "grant.sgml">
|
||||||
@ -102,6 +104,7 @@ Complete list of usable sgml source files in this directory.
|
|||||||
<!entity lock system "lock.sgml">
|
<!entity lock system "lock.sgml">
|
||||||
<!entity move system "move.sgml">
|
<!entity move system "move.sgml">
|
||||||
<!entity notify system "notify.sgml">
|
<!entity notify system "notify.sgml">
|
||||||
|
<!entity prepare system "prepare.sgml">
|
||||||
<!entity reindex system "reindex.sgml">
|
<!entity reindex system "reindex.sgml">
|
||||||
<!entity reset system "reset.sgml">
|
<!entity reset system "reset.sgml">
|
||||||
<!entity revoke system "revoke.sgml">
|
<!entity revoke system "revoke.sgml">
|
||||||
|
137
doc/src/sgml/ref/deallocate.sgml
Normal file
137
doc/src/sgml/ref/deallocate.sgml
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
<!--
|
||||||
|
$Header: /cvsroot/pgsql/doc/src/sgml/ref/deallocate.sgml,v 1.1 2002/08/27 04:55:07 tgl Exp $
|
||||||
|
PostgreSQL documentation
|
||||||
|
-->
|
||||||
|
|
||||||
|
<refentry id="SQL-DEALLOCATE">
|
||||||
|
<refmeta>
|
||||||
|
<refentrytitle id="sql-deallocate-title">DEALLOCATE</refentrytitle>
|
||||||
|
<refmiscinfo>SQL - Language Statements</refmiscinfo>
|
||||||
|
</refmeta>
|
||||||
|
<refnamediv>
|
||||||
|
<refname>
|
||||||
|
DEALLOCATE
|
||||||
|
</refname>
|
||||||
|
<refpurpose>
|
||||||
|
remove a prepared query
|
||||||
|
</refpurpose>
|
||||||
|
</refnamediv>
|
||||||
|
<refsynopsisdiv>
|
||||||
|
<refsynopsisdivinfo>
|
||||||
|
<date>2002-08-12</date>
|
||||||
|
</refsynopsisdivinfo>
|
||||||
|
<synopsis>
|
||||||
|
DEALLOCATE [ PREPARE ] <replaceable class="PARAMETER">plan_name</replaceable>
|
||||||
|
</synopsis>
|
||||||
|
|
||||||
|
<refsect2 id="R2-SQL-DEALLOCATE-1">
|
||||||
|
<refsect2info>
|
||||||
|
<date>2002-08-12</date>
|
||||||
|
</refsect2info>
|
||||||
|
<title>
|
||||||
|
Inputs
|
||||||
|
</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
<variablelist>
|
||||||
|
<varlistentry>
|
||||||
|
<term>PREPARE</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
This keyword is ignored.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
<varlistentry>
|
||||||
|
<term><replaceable class="PARAMETER">plan_name</replaceable></term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
The name of the prepared query to remove.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
</variablelist>
|
||||||
|
</para>
|
||||||
|
</refsect2>
|
||||||
|
<refsect2 id="R2-SQL-DEALLOCATE-2">
|
||||||
|
<refsect2info>
|
||||||
|
<date>2002-08-12</date>
|
||||||
|
</refsect2info>
|
||||||
|
<title>
|
||||||
|
Outputs
|
||||||
|
</title>
|
||||||
|
<para>
|
||||||
|
|
||||||
|
<variablelist>
|
||||||
|
<varlistentry>
|
||||||
|
<term><computeroutput>
|
||||||
|
<returnvalue>DEALLOCATE</returnvalue>
|
||||||
|
</computeroutput></term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
The prepared query was removed successfully.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
</variablelist>
|
||||||
|
</para>
|
||||||
|
</refsect2>
|
||||||
|
</refsynopsisdiv>
|
||||||
|
|
||||||
|
<refsect1 id="R1-SQL-DEALLOCATE-1">
|
||||||
|
<refsect1info>
|
||||||
|
<date>2002-08-12</date>
|
||||||
|
</refsect1info>
|
||||||
|
<title>
|
||||||
|
Description
|
||||||
|
</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
<command>DEALLOCATE</command> is used to remove a previously
|
||||||
|
prepared query. If you do not explicitly
|
||||||
|
<command>DEALLOCATE</command> a prepared query, it is removed when
|
||||||
|
the session ends.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
For more information on prepared queries, see <xref
|
||||||
|
linkend="sql-prepare" endterm="sql-prepare-title">.
|
||||||
|
</para>
|
||||||
|
</refsect1>
|
||||||
|
|
||||||
|
<refsect1 id="R1-SQL-DEALLOCATE-2">
|
||||||
|
<title>
|
||||||
|
Compatibility
|
||||||
|
</title>
|
||||||
|
|
||||||
|
<refsect2 id="R2-SQL-DEALLOCATE-3">
|
||||||
|
<refsect2info>
|
||||||
|
<date>2002-08-12</date>
|
||||||
|
</refsect2info>
|
||||||
|
<title>
|
||||||
|
SQL92
|
||||||
|
</title>
|
||||||
|
<para>
|
||||||
|
SQL92 includes a <command>DEALLOCATE</command> statement, but it is
|
||||||
|
only for use in embedded SQL clients.
|
||||||
|
</para>
|
||||||
|
</refsect2>
|
||||||
|
</refsect1>
|
||||||
|
</refentry>
|
||||||
|
|
||||||
|
<!-- Keep this comment at the end of the file
|
||||||
|
Local variables:
|
||||||
|
mode: sgml
|
||||||
|
sgml-omittag:nil
|
||||||
|
sgml-shorttag:t
|
||||||
|
sgml-minimize-attributes:nil
|
||||||
|
sgml-always-quote-attributes:t
|
||||||
|
sgml-indent-step:1
|
||||||
|
sgml-indent-data:t
|
||||||
|
sgml-parent-document:nil
|
||||||
|
sgml-default-dtd-file:"../reference.ced"
|
||||||
|
sgml-exposed-tags:nil
|
||||||
|
sgml-local-catalogs:"/usr/lib/sgml/catalog"
|
||||||
|
sgml-local-ecat-files:nil
|
||||||
|
End:
|
||||||
|
-->
|
132
doc/src/sgml/ref/execute.sgml
Normal file
132
doc/src/sgml/ref/execute.sgml
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
<!--
|
||||||
|
$Header: /cvsroot/pgsql/doc/src/sgml/ref/execute.sgml,v 1.1 2002/08/27 04:55:07 tgl Exp $
|
||||||
|
PostgreSQL documentation
|
||||||
|
-->
|
||||||
|
|
||||||
|
<refentry id="SQL-EXECUTE">
|
||||||
|
<refmeta>
|
||||||
|
<refentrytitle id="sql-execute-title">EXECUTE</refentrytitle>
|
||||||
|
<refmiscinfo>SQL - Language Statements</refmiscinfo>
|
||||||
|
</refmeta>
|
||||||
|
<refnamediv>
|
||||||
|
<refname>
|
||||||
|
EXECUTE
|
||||||
|
</refname>
|
||||||
|
<refpurpose>
|
||||||
|
execute a prepared query
|
||||||
|
</refpurpose>
|
||||||
|
</refnamediv>
|
||||||
|
<refsynopsisdiv>
|
||||||
|
<refsynopsisdivinfo>
|
||||||
|
<date>2002-08-12</date>
|
||||||
|
</refsynopsisdivinfo>
|
||||||
|
<synopsis>
|
||||||
|
EXECUTE <replaceable class="PARAMETER">plan_name</replaceable> [ (<replaceable class="PARAMETER">parameter</replaceable> [, ...] ) ]
|
||||||
|
</synopsis>
|
||||||
|
|
||||||
|
<refsect2 id="R2-SQL-EXECUTE-1">
|
||||||
|
<refsect2info>
|
||||||
|
<date>2002-08-12</date>
|
||||||
|
</refsect2info>
|
||||||
|
<title>
|
||||||
|
Inputs
|
||||||
|
</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
<variablelist>
|
||||||
|
<varlistentry>
|
||||||
|
<term><replaceable class="PARAMETER">plan_name</replaceable></term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
The name of the prepared query to execute.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
<varlistentry>
|
||||||
|
<term><replaceable class="PARAMETER">parameter</replaceable></term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
The actual value of a parameter to the prepared query.
|
||||||
|
This must be an expression yielding a value of a type
|
||||||
|
compatible with
|
||||||
|
the data-type specified for this parameter position in the
|
||||||
|
<command>PREPARE</command> statement that created the prepared
|
||||||
|
query.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
</variablelist>
|
||||||
|
</para>
|
||||||
|
</refsect2>
|
||||||
|
</refsynopsisdiv>
|
||||||
|
|
||||||
|
<refsect1 id="R1-SQL-EXECUTE-1">
|
||||||
|
<refsect1info>
|
||||||
|
<date>2002-08-12</date>
|
||||||
|
</refsect1info>
|
||||||
|
<title>
|
||||||
|
Description
|
||||||
|
</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
<command>EXECUTE</command> is used to execute a previously prepared
|
||||||
|
query. Since prepared queries only exist for the duration of a
|
||||||
|
session, the prepared query must have been created by a
|
||||||
|
<command>PREPARE</command> statement executed earlier in the
|
||||||
|
current session.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
If the <command>PREPARE</command> statement that created the query
|
||||||
|
specified some parameters, a compatible set of parameters must be
|
||||||
|
passed to the <command>EXECUTE</command> statement, or else an
|
||||||
|
error is raised. Note that (unlike functions) prepared queries are
|
||||||
|
not overloaded based on the type or number of their parameters: the
|
||||||
|
name of a prepared query must be unique within a database session.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
For more information on the creation and usage of prepared queries,
|
||||||
|
see <xref linkend="sql-prepare" endterm="sql-prepare-title">.
|
||||||
|
</para>
|
||||||
|
</refsect1>
|
||||||
|
|
||||||
|
<refsect1 id="R1-SQL-EXECUTE-2">
|
||||||
|
<title>
|
||||||
|
Compatibility
|
||||||
|
</title>
|
||||||
|
|
||||||
|
<refsect2 id="R2-SQL-EXECUTE-2">
|
||||||
|
<refsect2info>
|
||||||
|
<date>2002-08-12</date>
|
||||||
|
</refsect2info>
|
||||||
|
<title>
|
||||||
|
SQL92
|
||||||
|
</title>
|
||||||
|
<para>
|
||||||
|
SQL92 includes an <command>EXECUTE</command> statement, but it is
|
||||||
|
only for use in embedded SQL clients. The
|
||||||
|
<command>EXECUTE</command> statement implemented by
|
||||||
|
<productname>PostgreSQL</productname> also uses a somewhat
|
||||||
|
different syntax.
|
||||||
|
</para>
|
||||||
|
</refsect2>
|
||||||
|
</refsect1>
|
||||||
|
</refentry>
|
||||||
|
|
||||||
|
<!-- Keep this comment at the end of the file
|
||||||
|
Local variables:
|
||||||
|
mode: sgml
|
||||||
|
sgml-omittag:nil
|
||||||
|
sgml-shorttag:t
|
||||||
|
sgml-minimize-attributes:nil
|
||||||
|
sgml-always-quote-attributes:t
|
||||||
|
sgml-indent-step:1
|
||||||
|
sgml-indent-data:t
|
||||||
|
sgml-parent-document:nil
|
||||||
|
sgml-default-dtd-file:"../reference.ced"
|
||||||
|
sgml-exposed-tags:nil
|
||||||
|
sgml-local-catalogs:"/usr/lib/sgml/catalog"
|
||||||
|
sgml-local-ecat-files:nil
|
||||||
|
End:
|
||||||
|
-->
|
209
doc/src/sgml/ref/prepare.sgml
Normal file
209
doc/src/sgml/ref/prepare.sgml
Normal file
@ -0,0 +1,209 @@
|
|||||||
|
<!--
|
||||||
|
$Header: /cvsroot/pgsql/doc/src/sgml/ref/prepare.sgml,v 1.1 2002/08/27 04:55:07 tgl Exp $
|
||||||
|
PostgreSQL documentation
|
||||||
|
-->
|
||||||
|
|
||||||
|
<refentry id="SQL-PREPARE">
|
||||||
|
<refmeta>
|
||||||
|
<refentrytitle id="sql-prepare-title">PREPARE</refentrytitle>
|
||||||
|
<refmiscinfo>SQL - Language Statements</refmiscinfo>
|
||||||
|
</refmeta>
|
||||||
|
<refnamediv>
|
||||||
|
<refname>
|
||||||
|
PREPARE
|
||||||
|
</refname>
|
||||||
|
<refpurpose>
|
||||||
|
create a prepared query
|
||||||
|
</refpurpose>
|
||||||
|
</refnamediv>
|
||||||
|
<refsynopsisdiv>
|
||||||
|
<refsynopsisdivinfo>
|
||||||
|
<date>2002-08-12</date>
|
||||||
|
</refsynopsisdivinfo>
|
||||||
|
<synopsis>
|
||||||
|
PREPARE <replaceable class="PARAMETER">plan_name</replaceable> [ (<replaceable class="PARAMETER">datatype</replaceable> [, ...] ) ] AS <replaceable class="PARAMETER">query</replaceable>
|
||||||
|
</synopsis>
|
||||||
|
|
||||||
|
<refsect2 id="R2-SQL-PREPARE-1">
|
||||||
|
<refsect2info>
|
||||||
|
<date>2002-08-12</date>
|
||||||
|
</refsect2info>
|
||||||
|
<title>
|
||||||
|
Inputs
|
||||||
|
</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
<variablelist>
|
||||||
|
<varlistentry>
|
||||||
|
<term><replaceable class="PARAMETER">plan_name</replaceable></term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
An arbitrary name given to this particular prepared query. It
|
||||||
|
must be unique within a single session, and is used to execute
|
||||||
|
or remove a previously prepared query.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
<varlistentry>
|
||||||
|
<term><replaceable class="PARAMETER">datatype</replaceable></term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
The data-type of a parameter to the prepared query.
|
||||||
|
To refer to the parameters in the prepared query itself,
|
||||||
|
use <literal>$1</literal>, <literal>$2</literal>, etc.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
</variablelist>
|
||||||
|
</para>
|
||||||
|
</refsect2>
|
||||||
|
|
||||||
|
<refsect2 id="R2-SQL-PREPARE-2">
|
||||||
|
<refsect2info>
|
||||||
|
<date>2002-08-12</date>
|
||||||
|
</refsect2info>
|
||||||
|
<title>
|
||||||
|
Outputs
|
||||||
|
</title>
|
||||||
|
<para>
|
||||||
|
|
||||||
|
<variablelist>
|
||||||
|
<varlistentry>
|
||||||
|
<term><computeroutput>
|
||||||
|
<returnvalue>PREPARE</returnvalue>
|
||||||
|
</computeroutput></term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
The query has been prepared successfully.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
|
</variablelist>
|
||||||
|
</para>
|
||||||
|
</refsect2>
|
||||||
|
</refsynopsisdiv>
|
||||||
|
|
||||||
|
<refsect1 id="R1-SQL-PREPARE-1">
|
||||||
|
<refsect1info>
|
||||||
|
<date>2002-08-12</date>
|
||||||
|
</refsect1info>
|
||||||
|
<title>
|
||||||
|
Description
|
||||||
|
</title>
|
||||||
|
<para>
|
||||||
|
<command>PREPARE</command> creates a prepared query. A prepared
|
||||||
|
query is a server-side object that can be used to optimize
|
||||||
|
performance. When the <command>PREPARE</command> statement is
|
||||||
|
executed, the specified query is parsed, rewritten, and
|
||||||
|
planned. When a subsequent <command>EXECUTE</command> statement is
|
||||||
|
issued, the prepared query need only be executed. Thus, the
|
||||||
|
parsing, rewriting, and planning stages are only performed once,
|
||||||
|
instead of every time the query is executed.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Prepared queries can take parameters: values that are
|
||||||
|
substituted into the query when it is executed. To specify the
|
||||||
|
parameters to a prepared query, include a list of data-types with
|
||||||
|
the <command>PREPARE</command> statement. In the query itself, you
|
||||||
|
can refer to the parameters by position using
|
||||||
|
<literal>$1</literal>, <literal>$2</literal>, etc. When executing
|
||||||
|
the query, specify the actual values for these parameters in the
|
||||||
|
<command>EXECUTE</command> statement -- refer to <xref
|
||||||
|
linkend="sql-execute" endterm="sql-execute-title">
|
||||||
|
for more information.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Prepared queries are stored locally (in the current backend), and
|
||||||
|
only exist for the duration of the current database session. When
|
||||||
|
the client exits, the prepared query is forgotten, and so it must be
|
||||||
|
re-created before being used again. This also means that a single
|
||||||
|
prepared query cannot be used by multiple simultaneous database
|
||||||
|
clients; however, each client can create their own prepared query
|
||||||
|
to use.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Prepared queries have the largest performance advantage when a
|
||||||
|
single backend is being used to execute a large number of similar
|
||||||
|
queries. The performance difference will be particularly
|
||||||
|
significant if the queries are complex to plan or rewrite. For
|
||||||
|
example, if the query involves a join of many tables or requires
|
||||||
|
the application of several rules. If the query is relatively simple
|
||||||
|
to plan and rewrite but relatively expensive to execute, the
|
||||||
|
performance advantage of prepared queries will be less noticeable.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<refsect2 id="R2-SQL-PREPARE-3">
|
||||||
|
<refsect2info>
|
||||||
|
<date>2002-08-12</date>
|
||||||
|
</refsect2info>
|
||||||
|
<title>
|
||||||
|
Notes
|
||||||
|
</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
In some situations, the query plan produced by
|
||||||
|
<productname>PostgreSQL</productname> for a prepared query may be
|
||||||
|
inferior to the plan produced if the query were submitted and
|
||||||
|
executed normally. This is because when the query is planned (and
|
||||||
|
the optimizer attempts to determine the optimal query plan), the
|
||||||
|
actual values of any parameters specified in the query are
|
||||||
|
unavailable. <productname>PostgreSQL</productname> collects
|
||||||
|
statistics on the distribution of data in the table, and can use
|
||||||
|
constant values in a query to make guesses about the likely
|
||||||
|
result of executing the query. Since this data is unavailable when
|
||||||
|
planning prepared queries with parameters, the chosen plan may be
|
||||||
|
sub-optimal.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
For more information on query planning and the statistics
|
||||||
|
collected by <productname>PostgreSQL</productname> for query
|
||||||
|
optimization purposes, see the <xref linkend="sql-analyze"
|
||||||
|
endterm="sql-analyze-title"> documentation.
|
||||||
|
</para>
|
||||||
|
</refsect2>
|
||||||
|
</refsect1>
|
||||||
|
|
||||||
|
<refsect1 id="R1-SQL-PREPARE-3">
|
||||||
|
<title>
|
||||||
|
Compatibility
|
||||||
|
</title>
|
||||||
|
|
||||||
|
<refsect2 id="R2-SQL-PREPARE-4">
|
||||||
|
<refsect2info>
|
||||||
|
<date>2002-08-12</date>
|
||||||
|
</refsect2info>
|
||||||
|
<title>
|
||||||
|
SQL92
|
||||||
|
</title>
|
||||||
|
<para>
|
||||||
|
SQL92 includes a <command>PREPARE</command> statement, but it is
|
||||||
|
only for use in embedded SQL clients. The
|
||||||
|
<command>PREPARE</command> statement implemented by
|
||||||
|
<productname>PostgreSQL</productname> also uses a somewhat
|
||||||
|
different syntax.
|
||||||
|
</para>
|
||||||
|
</refsect2>
|
||||||
|
</refsect1>
|
||||||
|
</refentry>
|
||||||
|
|
||||||
|
<!-- Keep this comment at the end of the file
|
||||||
|
Local variables:
|
||||||
|
mode: sgml
|
||||||
|
sgml-omittag:nil
|
||||||
|
sgml-shorttag:t
|
||||||
|
sgml-minimize-attributes:nil
|
||||||
|
sgml-always-quote-attributes:t
|
||||||
|
sgml-indent-step:1
|
||||||
|
sgml-indent-data:t
|
||||||
|
sgml-parent-document:nil
|
||||||
|
sgml-default-dtd-file:"../reference.ced"
|
||||||
|
sgml-exposed-tags:nil
|
||||||
|
sgml-local-catalogs:"/usr/lib/sgml/catalog"
|
||||||
|
sgml-local-ecat-files:nil
|
||||||
|
End:
|
||||||
|
-->
|
@ -1,5 +1,5 @@
|
|||||||
<!-- reference.sgml
|
<!-- reference.sgml
|
||||||
$Header: /cvsroot/pgsql/doc/src/sgml/reference.sgml,v 1.36 2002/08/27 03:38:27 momjian Exp $
|
$Header: /cvsroot/pgsql/doc/src/sgml/reference.sgml,v 1.37 2002/08/27 04:55:07 tgl Exp $
|
||||||
|
|
||||||
PostgreSQL Reference Manual
|
PostgreSQL Reference Manual
|
||||||
-->
|
-->
|
||||||
@ -80,6 +80,7 @@ PostgreSQL Reference Manual
|
|||||||
&createType;
|
&createType;
|
||||||
&createUser;
|
&createUser;
|
||||||
&createView;
|
&createView;
|
||||||
|
&deallocate;
|
||||||
&declare;
|
&declare;
|
||||||
&delete;
|
&delete;
|
||||||
&dropAggregate;
|
&dropAggregate;
|
||||||
@ -98,10 +99,11 @@ PostgreSQL Reference Manual
|
|||||||
&dropSequence;
|
&dropSequence;
|
||||||
&dropTable;
|
&dropTable;
|
||||||
&dropTrigger;
|
&dropTrigger;
|
||||||
&dropType
|
&dropType;
|
||||||
&dropUser;
|
&dropUser;
|
||||||
&dropView;
|
&dropView;
|
||||||
&end;
|
&end;
|
||||||
|
&execute;
|
||||||
&explain;
|
&explain;
|
||||||
&fetch;
|
&fetch;
|
||||||
&grant;
|
&grant;
|
||||||
@ -111,6 +113,7 @@ PostgreSQL Reference Manual
|
|||||||
&lock;
|
&lock;
|
||||||
&move;
|
&move;
|
||||||
¬ify;
|
¬ify;
|
||||||
|
&prepare;
|
||||||
&reindex;
|
&reindex;
|
||||||
&reset;
|
&reset;
|
||||||
&revoke;
|
&revoke;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<!--
|
<!--
|
||||||
$Header: /cvsroot/pgsql/doc/src/sgml/release.sgml,v 1.151 2002/08/25 14:34:24 momjian Exp $
|
$Header: /cvsroot/pgsql/doc/src/sgml/release.sgml,v 1.152 2002/08/27 04:55:07 tgl Exp $
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<appendix id="release">
|
<appendix id="release">
|
||||||
@ -24,6 +24,7 @@ CDATA means the content is "SGML-free", so you can write without
|
|||||||
worries about funny characters.
|
worries about funny characters.
|
||||||
-->
|
-->
|
||||||
<literallayout><![CDATA[
|
<literallayout><![CDATA[
|
||||||
|
PREPARE statement allows caching query plans for interactive statements
|
||||||
Type OPAQUE is now deprecated in favor of pseudo-types cstring, trigger, etc
|
Type OPAQUE is now deprecated in favor of pseudo-types cstring, trigger, etc
|
||||||
Files larger than 2 GB are now supported (if supported by the operating system)
|
Files larger than 2 GB are now supported (if supported by the operating system)
|
||||||
SERIAL no longer implies UNIQUE; specify explicitly if index is wanted
|
SERIAL no longer implies UNIQUE; specify explicitly if index is wanted
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
# Makefile for backend/commands
|
# Makefile for backend/commands
|
||||||
#
|
#
|
||||||
# IDENTIFICATION
|
# IDENTIFICATION
|
||||||
# $Header: /cvsroot/pgsql/src/backend/commands/Makefile,v 1.30 2002/07/29 22:14:10 tgl Exp $
|
# $Header: /cvsroot/pgsql/src/backend/commands/Makefile,v 1.31 2002/08/27 04:55:07 tgl Exp $
|
||||||
#
|
#
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
|
|
||||||
@ -16,7 +16,7 @@ OBJS = aggregatecmds.o analyze.o async.o cluster.o comment.o \
|
|||||||
conversioncmds.o copy.o \
|
conversioncmds.o copy.o \
|
||||||
dbcommands.o define.o explain.o functioncmds.o \
|
dbcommands.o define.o explain.o functioncmds.o \
|
||||||
indexcmds.o lockcmds.o operatorcmds.o opclasscmds.o \
|
indexcmds.o lockcmds.o operatorcmds.o opclasscmds.o \
|
||||||
portalcmds.o proclang.o \
|
portalcmds.o prepare.o proclang.o \
|
||||||
schemacmds.o sequence.o tablecmds.o trigger.o typecmds.o user.o \
|
schemacmds.o sequence.o tablecmds.o trigger.o typecmds.o user.o \
|
||||||
vacuum.o vacuumlazy.o variable.o view.o
|
vacuum.o vacuumlazy.o variable.o view.o
|
||||||
|
|
||||||
|
407
src/backend/commands/prepare.c
Normal file
407
src/backend/commands/prepare.c
Normal file
@ -0,0 +1,407 @@
|
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* prepare.c
|
||||||
|
* Prepareable SQL statements via PREPARE, EXECUTE and DEALLOCATE
|
||||||
|
*
|
||||||
|
* Copyright (c) 2002, PostgreSQL Global Development Group
|
||||||
|
*
|
||||||
|
* IDENTIFICATION
|
||||||
|
* $Header: /cvsroot/pgsql/src/backend/commands/prepare.c,v 1.1 2002/08/27 04:55:07 tgl Exp $
|
||||||
|
*
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
#include "postgres.h"
|
||||||
|
|
||||||
|
#include "commands/prepare.h"
|
||||||
|
#include "executor/executor.h"
|
||||||
|
#include "utils/guc.h"
|
||||||
|
#include "optimizer/planner.h"
|
||||||
|
#include "rewrite/rewriteHandler.h"
|
||||||
|
#include "tcop/pquery.h"
|
||||||
|
#include "tcop/tcopprot.h"
|
||||||
|
#include "tcop/utility.h"
|
||||||
|
#include "utils/hsearch.h"
|
||||||
|
#include "utils/memutils.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define HASH_KEY_LEN NAMEDATALEN
|
||||||
|
|
||||||
|
/* All the data we need to remember about a stored query */
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
/* dynahash.c requires key to be first field */
|
||||||
|
char key[HASH_KEY_LEN];
|
||||||
|
List *query_list; /* list of queries */
|
||||||
|
List *plan_list; /* list of plans */
|
||||||
|
List *argtype_list; /* list of parameter type OIDs */
|
||||||
|
MemoryContext context; /* context containing this query */
|
||||||
|
} QueryHashEntry;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The hash table in which prepared queries are stored. This is
|
||||||
|
* per-backend: query plans are not shared between backends.
|
||||||
|
* The keys for this hash table are the arguments to PREPARE
|
||||||
|
* and EXECUTE ("plan names"); the entries are QueryHashEntry structs.
|
||||||
|
*/
|
||||||
|
static HTAB *prepared_queries = NULL;
|
||||||
|
|
||||||
|
static void InitQueryHashTable(void);
|
||||||
|
static void StoreQuery(const char *stmt_name, List *query_list,
|
||||||
|
List *plan_list, List *argtype_list);
|
||||||
|
static QueryHashEntry *FetchQuery(const char *plan_name);
|
||||||
|
static void RunQuery(QueryDesc *qdesc, EState *state);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Implements the 'PREPARE' utility statement.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
PrepareQuery(PrepareStmt *stmt)
|
||||||
|
{
|
||||||
|
List *plan_list = NIL;
|
||||||
|
List *query_list,
|
||||||
|
*query_list_item;
|
||||||
|
|
||||||
|
if (!stmt->name)
|
||||||
|
elog(ERROR, "No statement name given");
|
||||||
|
|
||||||
|
if (stmt->query->commandType == CMD_UTILITY)
|
||||||
|
elog(ERROR, "Utility statements cannot be prepared");
|
||||||
|
|
||||||
|
/* Rewrite the query. The result could be 0, 1, or many queries. */
|
||||||
|
query_list = QueryRewrite(stmt->query);
|
||||||
|
|
||||||
|
foreach(query_list_item, query_list)
|
||||||
|
{
|
||||||
|
Query *query = (Query *) lfirst(query_list_item);
|
||||||
|
Plan *plan;
|
||||||
|
|
||||||
|
/* We can't generate plans for utility statements. */
|
||||||
|
if (query->commandType == CMD_UTILITY)
|
||||||
|
plan = NULL;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Call the query planner to generate a plan. */
|
||||||
|
plan = planner(query);
|
||||||
|
}
|
||||||
|
|
||||||
|
plan_list = lappend(plan_list, plan);
|
||||||
|
}
|
||||||
|
|
||||||
|
StoreQuery(stmt->name, query_list, plan_list, stmt->argtype_oids);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Implements the 'EXECUTE' utility statement.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
ExecuteQuery(ExecuteStmt *stmt, CommandDest outputDest)
|
||||||
|
{
|
||||||
|
QueryHashEntry *entry;
|
||||||
|
List *l,
|
||||||
|
*query_list,
|
||||||
|
*plan_list;
|
||||||
|
ParamListInfo paramLI = NULL;
|
||||||
|
|
||||||
|
/* Look it up in the hash table */
|
||||||
|
entry = FetchQuery(stmt->name);
|
||||||
|
|
||||||
|
/* Make working copies the executor can safely scribble on */
|
||||||
|
query_list = (List *) copyObject(entry->query_list);
|
||||||
|
plan_list = (List *) copyObject(entry->plan_list);
|
||||||
|
|
||||||
|
Assert(length(query_list) == length(plan_list));
|
||||||
|
|
||||||
|
/* Evaluate parameters, if any */
|
||||||
|
if (entry->argtype_list != NIL)
|
||||||
|
{
|
||||||
|
int nargs = length(entry->argtype_list);
|
||||||
|
int i = 0;
|
||||||
|
ExprContext *econtext = MakeExprContext(NULL, CurrentMemoryContext);
|
||||||
|
|
||||||
|
/* Parser should have caught this error, but check */
|
||||||
|
if (nargs != length(stmt->params))
|
||||||
|
elog(ERROR, "ExecuteQuery: wrong number of arguments");
|
||||||
|
|
||||||
|
paramLI = (ParamListInfo) palloc((nargs + 1) * sizeof(ParamListInfoData));
|
||||||
|
MemSet(paramLI, 0, (nargs + 1) * sizeof(ParamListInfoData));
|
||||||
|
|
||||||
|
foreach (l, stmt->params)
|
||||||
|
{
|
||||||
|
Node *n = lfirst(l);
|
||||||
|
bool isNull;
|
||||||
|
|
||||||
|
paramLI[i].value = ExecEvalExprSwitchContext(n,
|
||||||
|
econtext,
|
||||||
|
&isNull,
|
||||||
|
NULL);
|
||||||
|
paramLI[i].kind = PARAM_NUM;
|
||||||
|
paramLI[i].id = i + 1;
|
||||||
|
paramLI[i].isnull = isNull;
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
paramLI[i].kind = PARAM_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Execute each query */
|
||||||
|
foreach(l, query_list)
|
||||||
|
{
|
||||||
|
Query *query = lfirst(l);
|
||||||
|
Plan *plan = lfirst(plan_list);
|
||||||
|
bool is_last_query;
|
||||||
|
|
||||||
|
plan_list = lnext(plan_list);
|
||||||
|
is_last_query = (plan_list == NIL);
|
||||||
|
|
||||||
|
if (query->commandType == CMD_UTILITY)
|
||||||
|
ProcessUtility(query->utilityStmt, outputDest, NULL);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QueryDesc *qdesc;
|
||||||
|
EState *state;
|
||||||
|
|
||||||
|
if (Show_executor_stats)
|
||||||
|
ResetUsage();
|
||||||
|
|
||||||
|
qdesc = CreateQueryDesc(query, plan, outputDest, NULL);
|
||||||
|
state = CreateExecutorState();
|
||||||
|
|
||||||
|
state->es_param_list_info = paramLI;
|
||||||
|
|
||||||
|
if (stmt->into)
|
||||||
|
{
|
||||||
|
if (qdesc->operation != CMD_SELECT)
|
||||||
|
elog(ERROR, "INTO clause specified for non-SELECT query");
|
||||||
|
|
||||||
|
query->into = stmt->into;
|
||||||
|
qdesc->dest = None;
|
||||||
|
}
|
||||||
|
|
||||||
|
RunQuery(qdesc, state);
|
||||||
|
|
||||||
|
if (Show_executor_stats)
|
||||||
|
ShowUsage("EXECUTOR STATISTICS");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we're processing multiple queries, we need to increment
|
||||||
|
* the command counter between them. For the last query,
|
||||||
|
* there's no need to do this, it's done automatically.
|
||||||
|
*/
|
||||||
|
if (! is_last_query)
|
||||||
|
CommandCounterIncrement();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* No need to pfree memory, MemoryContext will be reset */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize query hash table upon first use.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
InitQueryHashTable(void)
|
||||||
|
{
|
||||||
|
HASHCTL hash_ctl;
|
||||||
|
|
||||||
|
MemSet(&hash_ctl, 0, sizeof(hash_ctl));
|
||||||
|
|
||||||
|
hash_ctl.keysize = HASH_KEY_LEN;
|
||||||
|
hash_ctl.entrysize = sizeof(QueryHashEntry);
|
||||||
|
|
||||||
|
prepared_queries = hash_create("Prepared Queries",
|
||||||
|
32,
|
||||||
|
&hash_ctl,
|
||||||
|
HASH_ELEM);
|
||||||
|
|
||||||
|
if (!prepared_queries)
|
||||||
|
elog(ERROR, "InitQueryHashTable: unable to create hash table");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Store all the data pertaining to a query in the hash table using
|
||||||
|
* the specified key. A copy of the data is made in a memory context belonging
|
||||||
|
* to the hash entry, so the caller can dispose of their copy.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
StoreQuery(const char *stmt_name, List *query_list, List *plan_list,
|
||||||
|
List *argtype_list)
|
||||||
|
{
|
||||||
|
QueryHashEntry *entry;
|
||||||
|
MemoryContext oldcxt,
|
||||||
|
entrycxt;
|
||||||
|
char key[HASH_KEY_LEN];
|
||||||
|
bool found;
|
||||||
|
|
||||||
|
/* Initialize the hash table, if necessary */
|
||||||
|
if (!prepared_queries)
|
||||||
|
InitQueryHashTable();
|
||||||
|
|
||||||
|
/* Check for pre-existing entry of same name */
|
||||||
|
/* See notes in FetchQuery */
|
||||||
|
MemSet(key, 0, sizeof(key));
|
||||||
|
strncpy(key, stmt_name, sizeof(key));
|
||||||
|
|
||||||
|
hash_search(prepared_queries, key, HASH_FIND, &found);
|
||||||
|
|
||||||
|
if (found)
|
||||||
|
elog(ERROR, "Prepared statement with name \"%s\" already exists",
|
||||||
|
stmt_name);
|
||||||
|
|
||||||
|
/* Okay. Make a permanent memory context for the hashtable entry */
|
||||||
|
entrycxt = AllocSetContextCreate(TopMemoryContext,
|
||||||
|
stmt_name,
|
||||||
|
1024,
|
||||||
|
1024,
|
||||||
|
ALLOCSET_DEFAULT_MAXSIZE);
|
||||||
|
|
||||||
|
oldcxt = MemoryContextSwitchTo(entrycxt);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We need to copy the data so that it is stored in the correct
|
||||||
|
* memory context. Do this before making hashtable entry, so that
|
||||||
|
* an out-of-memory failure only wastes memory and doesn't leave us
|
||||||
|
* with an incomplete (ie corrupt) hashtable entry.
|
||||||
|
*/
|
||||||
|
query_list = (List *) copyObject(query_list);
|
||||||
|
plan_list = (List *) copyObject(plan_list);
|
||||||
|
argtype_list = listCopy(argtype_list);
|
||||||
|
|
||||||
|
/* Now we can add entry to hash table */
|
||||||
|
entry = (QueryHashEntry *) hash_search(prepared_queries,
|
||||||
|
key,
|
||||||
|
HASH_ENTER,
|
||||||
|
&found);
|
||||||
|
|
||||||
|
/* Shouldn't get a failure, nor duplicate entry */
|
||||||
|
if (!entry || found)
|
||||||
|
elog(ERROR, "Unable to store prepared statement \"%s\"!",
|
||||||
|
stmt_name);
|
||||||
|
|
||||||
|
/* Fill in the hash table entry with copied data */
|
||||||
|
entry->query_list = query_list;
|
||||||
|
entry->plan_list = plan_list;
|
||||||
|
entry->argtype_list = argtype_list;
|
||||||
|
entry->context = entrycxt;
|
||||||
|
|
||||||
|
MemoryContextSwitchTo(oldcxt);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Lookup an existing query in the hash table.
|
||||||
|
*/
|
||||||
|
static QueryHashEntry *
|
||||||
|
FetchQuery(const char *plan_name)
|
||||||
|
{
|
||||||
|
char key[HASH_KEY_LEN];
|
||||||
|
QueryHashEntry *entry;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the hash table hasn't been initialized, it can't be storing
|
||||||
|
* anything, therefore it couldn't possibly store our plan.
|
||||||
|
*/
|
||||||
|
if (!prepared_queries)
|
||||||
|
elog(ERROR, "Prepared statement with name \"%s\" does not exist",
|
||||||
|
plan_name);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We can't just use the statement name as supplied by the user: the
|
||||||
|
* hash package is picky enough that it needs to be NULL-padded out
|
||||||
|
* to the appropriate length to work correctly.
|
||||||
|
*/
|
||||||
|
MemSet(key, 0, sizeof(key));
|
||||||
|
strncpy(key, plan_name, sizeof(key));
|
||||||
|
|
||||||
|
entry = (QueryHashEntry *) hash_search(prepared_queries,
|
||||||
|
key,
|
||||||
|
HASH_FIND,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
if (!entry)
|
||||||
|
elog(ERROR, "Prepared statement with name \"%s\" does not exist",
|
||||||
|
plan_name);
|
||||||
|
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Given a plan name, look up the stored plan (giving error if not found).
|
||||||
|
* If found, return the list of argument type OIDs.
|
||||||
|
*/
|
||||||
|
List *
|
||||||
|
FetchQueryParams(const char *plan_name)
|
||||||
|
{
|
||||||
|
QueryHashEntry *entry;
|
||||||
|
|
||||||
|
entry = FetchQuery(plan_name);
|
||||||
|
|
||||||
|
return entry->argtype_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Actually execute a prepared query.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
RunQuery(QueryDesc *qdesc, EState *state)
|
||||||
|
{
|
||||||
|
TupleDesc tupdesc;
|
||||||
|
|
||||||
|
tupdesc = ExecutorStart(qdesc, state);
|
||||||
|
|
||||||
|
ExecutorRun(qdesc, state, state->es_direction, 0L);
|
||||||
|
|
||||||
|
ExecutorEnd(qdesc, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Implements the 'DEALLOCATE' utility statement: deletes the
|
||||||
|
* specified plan from storage.
|
||||||
|
*
|
||||||
|
* The initial part of this routine is identical to FetchQuery(),
|
||||||
|
* but we repeat the coding because we need to use the key twice.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
DeallocateQuery(DeallocateStmt *stmt)
|
||||||
|
{
|
||||||
|
char key[HASH_KEY_LEN];
|
||||||
|
QueryHashEntry *entry;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the hash table hasn't been initialized, it can't be storing
|
||||||
|
* anything, therefore it couldn't possibly store our plan.
|
||||||
|
*/
|
||||||
|
if (!prepared_queries)
|
||||||
|
elog(ERROR, "Prepared statement with name \"%s\" does not exist",
|
||||||
|
stmt->name);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We can't just use the statement name as supplied by the user: the
|
||||||
|
* hash package is picky enough that it needs to be NULL-padded out
|
||||||
|
* to the appropriate length to work correctly.
|
||||||
|
*/
|
||||||
|
MemSet(key, 0, sizeof(key));
|
||||||
|
strncpy(key, stmt->name, sizeof(key));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* First lookup the entry, so we can release all the subsidiary memory
|
||||||
|
* it has allocated (when it's removed, hash_search() will return
|
||||||
|
* a dangling pointer, so it needs to be done prior to HASH_REMOVE).
|
||||||
|
* This requires an extra hash-table lookup, but DEALLOCATE
|
||||||
|
* isn't exactly a performance bottleneck.
|
||||||
|
*/
|
||||||
|
entry = (QueryHashEntry *) hash_search(prepared_queries,
|
||||||
|
key,
|
||||||
|
HASH_FIND,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
if (!entry)
|
||||||
|
elog(ERROR, "Prepared statement with name \"%s\" does not exist",
|
||||||
|
stmt->name);
|
||||||
|
|
||||||
|
/* Flush the context holding the subsidiary data */
|
||||||
|
if (MemoryContextIsValid(entry->context))
|
||||||
|
MemoryContextDelete(entry->context);
|
||||||
|
|
||||||
|
/* Now we can remove the hash table entry */
|
||||||
|
hash_search(prepared_queries, key, HASH_REMOVE, NULL);
|
||||||
|
}
|
@ -15,7 +15,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.206 2002/08/26 17:53:57 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.207 2002/08/27 04:55:07 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -2647,6 +2647,41 @@ _copyDropCastStmt(DropCastStmt *from)
|
|||||||
return newnode;
|
return newnode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static PrepareStmt *
|
||||||
|
_copyPrepareStmt(PrepareStmt *from)
|
||||||
|
{
|
||||||
|
PrepareStmt *newnode = makeNode(PrepareStmt);
|
||||||
|
|
||||||
|
newnode->name = pstrdup(from->name);
|
||||||
|
Node_Copy(from, newnode, argtypes);
|
||||||
|
newnode->argtype_oids = listCopy(from->argtype_oids);
|
||||||
|
Node_Copy(from, newnode, query);
|
||||||
|
|
||||||
|
return newnode;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ExecuteStmt *
|
||||||
|
_copyExecuteStmt(ExecuteStmt *from)
|
||||||
|
{
|
||||||
|
ExecuteStmt *newnode = makeNode(ExecuteStmt);
|
||||||
|
|
||||||
|
newnode->name = pstrdup(from->name);
|
||||||
|
Node_Copy(from, newnode, into);
|
||||||
|
Node_Copy(from, newnode, params);
|
||||||
|
|
||||||
|
return newnode;
|
||||||
|
}
|
||||||
|
|
||||||
|
static DeallocateStmt *
|
||||||
|
_copyDeallocateStmt(DeallocateStmt *from)
|
||||||
|
{
|
||||||
|
DeallocateStmt *newnode = makeNode(DeallocateStmt);
|
||||||
|
|
||||||
|
newnode->name = pstrdup(from->name);
|
||||||
|
|
||||||
|
return newnode;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ****************************************************************
|
/* ****************************************************************
|
||||||
* pg_list.h copy functions
|
* pg_list.h copy functions
|
||||||
@ -3079,6 +3114,15 @@ copyObject(void *from)
|
|||||||
case T_DropCastStmt:
|
case T_DropCastStmt:
|
||||||
retval = _copyDropCastStmt(from);
|
retval = _copyDropCastStmt(from);
|
||||||
break;
|
break;
|
||||||
|
case T_PrepareStmt:
|
||||||
|
retval = _copyPrepareStmt(from);
|
||||||
|
break;
|
||||||
|
case T_ExecuteStmt:
|
||||||
|
retval = _copyExecuteStmt(from);
|
||||||
|
break;
|
||||||
|
case T_DeallocateStmt:
|
||||||
|
retval = _copyDeallocateStmt(from);
|
||||||
|
break;
|
||||||
|
|
||||||
case T_A_Expr:
|
case T_A_Expr:
|
||||||
retval = _copyAExpr(from);
|
retval = _copyAExpr(from);
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.154 2002/08/26 17:53:57 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.155 2002/08/27 04:55:07 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -1490,6 +1490,43 @@ _equalDropCastStmt(DropCastStmt *a, DropCastStmt *b)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
_equalPrepareStmt(PrepareStmt *a, PrepareStmt *b)
|
||||||
|
{
|
||||||
|
if (!equalstr(a->name, b->name))
|
||||||
|
return false;
|
||||||
|
if (!equal(a->argtypes, b->argtypes))
|
||||||
|
return false;
|
||||||
|
if (!equali(a->argtype_oids, b->argtype_oids))
|
||||||
|
return false;
|
||||||
|
if (!equal(a->query, b->query))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
_equalExecuteStmt(ExecuteStmt *a, ExecuteStmt *b)
|
||||||
|
{
|
||||||
|
if (!equalstr(a->name, b->name))
|
||||||
|
return false;
|
||||||
|
if (!equal(a->into, b->into))
|
||||||
|
return false;
|
||||||
|
if (!equal(a->params, b->params))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
_equalDeallocateStmt(DeallocateStmt *a, DeallocateStmt *b)
|
||||||
|
{
|
||||||
|
if (!equalstr(a->name, b->name))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
_equalAExpr(A_Expr *a, A_Expr *b)
|
_equalAExpr(A_Expr *a, A_Expr *b)
|
||||||
{
|
{
|
||||||
@ -2249,6 +2286,15 @@ equal(void *a, void *b)
|
|||||||
case T_DropCastStmt:
|
case T_DropCastStmt:
|
||||||
retval = _equalDropCastStmt(a, b);
|
retval = _equalDropCastStmt(a, b);
|
||||||
break;
|
break;
|
||||||
|
case T_PrepareStmt:
|
||||||
|
retval = _equalPrepareStmt(a, b);
|
||||||
|
break;
|
||||||
|
case T_ExecuteStmt:
|
||||||
|
retval = _equalExecuteStmt(a, b);
|
||||||
|
break;
|
||||||
|
case T_DeallocateStmt:
|
||||||
|
retval = _equalDeallocateStmt(a, b);
|
||||||
|
break;
|
||||||
|
|
||||||
case T_A_Expr:
|
case T_A_Expr:
|
||||||
retval = _equalAExpr(a, b);
|
retval = _equalAExpr(a, b);
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.243 2002/08/27 03:56:34 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.244 2002/08/27 04:55:07 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -20,7 +20,10 @@
|
|||||||
#include "catalog/namespace.h"
|
#include "catalog/namespace.h"
|
||||||
#include "catalog/pg_index.h"
|
#include "catalog/pg_index.h"
|
||||||
#include "catalog/pg_type.h"
|
#include "catalog/pg_type.h"
|
||||||
|
#include "commands/prepare.h"
|
||||||
#include "nodes/makefuncs.h"
|
#include "nodes/makefuncs.h"
|
||||||
|
#include "optimizer/clauses.h"
|
||||||
|
#include "optimizer/planmain.h"
|
||||||
#include "parser/analyze.h"
|
#include "parser/analyze.h"
|
||||||
#include "parser/gramparse.h"
|
#include "parser/gramparse.h"
|
||||||
#include "parser/parsetree.h"
|
#include "parser/parsetree.h"
|
||||||
@ -94,6 +97,8 @@ static Query *transformSelectStmt(ParseState *pstate, SelectStmt *stmt);
|
|||||||
static Query *transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt);
|
static Query *transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt);
|
||||||
static Node *transformSetOperationTree(ParseState *pstate, SelectStmt *stmt);
|
static Node *transformSetOperationTree(ParseState *pstate, SelectStmt *stmt);
|
||||||
static Query *transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt);
|
static Query *transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt);
|
||||||
|
static Query *transformPrepareStmt(ParseState *pstate, PrepareStmt *stmt);
|
||||||
|
static Query *transformExecuteStmt(ParseState *pstate, ExecuteStmt *stmt);
|
||||||
static Query *transformCreateStmt(ParseState *pstate, CreateStmt *stmt,
|
static Query *transformCreateStmt(ParseState *pstate, CreateStmt *stmt,
|
||||||
List **extras_before, List **extras_after);
|
List **extras_before, List **extras_after);
|
||||||
static Query *transformAlterTableStmt(ParseState *pstate, AlterTableStmt *stmt,
|
static Query *transformAlterTableStmt(ParseState *pstate, AlterTableStmt *stmt,
|
||||||
@ -277,6 +282,14 @@ transformStmt(ParseState *pstate, Node *parseTree,
|
|||||||
extras_before, extras_after);
|
extras_before, extras_after);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case T_PrepareStmt:
|
||||||
|
result = transformPrepareStmt(pstate, (PrepareStmt *) parseTree);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case T_ExecuteStmt:
|
||||||
|
result = transformExecuteStmt(pstate, (ExecuteStmt *) parseTree);
|
||||||
|
break;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Optimizable statements
|
* Optimizable statements
|
||||||
*/
|
*/
|
||||||
@ -2454,6 +2467,131 @@ transformAlterTableStmt(ParseState *pstate, AlterTableStmt *stmt,
|
|||||||
return qry;
|
return qry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Query *
|
||||||
|
transformPrepareStmt(ParseState *pstate, PrepareStmt *stmt)
|
||||||
|
{
|
||||||
|
Query *result = makeNode(Query);
|
||||||
|
List *extras_before = NIL,
|
||||||
|
*extras_after = NIL;
|
||||||
|
List *argtype_oids = NIL; /* argtype OIDs in a list */
|
||||||
|
Oid *argtoids = NULL; /* as an array for parser_param_set */
|
||||||
|
int nargs;
|
||||||
|
|
||||||
|
result->commandType = CMD_UTILITY;
|
||||||
|
result->utilityStmt = (Node *) stmt;
|
||||||
|
|
||||||
|
/* Transform list of TypeNames to list (and array) of type OIDs */
|
||||||
|
nargs = length(stmt->argtypes);
|
||||||
|
|
||||||
|
if (nargs)
|
||||||
|
{
|
||||||
|
List *l;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
argtoids = (Oid *) palloc(nargs * sizeof(Oid));
|
||||||
|
|
||||||
|
foreach (l, stmt->argtypes)
|
||||||
|
{
|
||||||
|
TypeName *tn = lfirst(l);
|
||||||
|
Oid toid = typenameTypeId(tn);
|
||||||
|
|
||||||
|
argtype_oids = lappendi(argtype_oids, toid);
|
||||||
|
argtoids[i++] = toid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stmt->argtype_oids = argtype_oids;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We need to adjust the parameters expected by the
|
||||||
|
* rest of the system, so that $1, ... $n are parsed properly.
|
||||||
|
*
|
||||||
|
* This is somewhat of a hack; however, the main parser interface
|
||||||
|
* only allows parameters to be specified when working with a
|
||||||
|
* raw query string, which is not helpful here.
|
||||||
|
*/
|
||||||
|
parser_param_set(argtoids, nargs);
|
||||||
|
|
||||||
|
stmt->query = transformStmt(pstate, (Node *) stmt->query,
|
||||||
|
&extras_before, &extras_after);
|
||||||
|
|
||||||
|
/* Shouldn't get any extras, since grammar only allows OptimizableStmt */
|
||||||
|
if (extras_before || extras_after)
|
||||||
|
elog(ERROR, "transformPrepareStmt: internal error");
|
||||||
|
|
||||||
|
/* Remove links to our local parameters */
|
||||||
|
parser_param_set(NULL, 0);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Query *
|
||||||
|
transformExecuteStmt(ParseState *pstate, ExecuteStmt *stmt)
|
||||||
|
{
|
||||||
|
Query *result = makeNode(Query);
|
||||||
|
List *paramtypes;
|
||||||
|
|
||||||
|
result->commandType = CMD_UTILITY;
|
||||||
|
result->utilityStmt = (Node *) stmt;
|
||||||
|
|
||||||
|
paramtypes = FetchQueryParams(stmt->name);
|
||||||
|
|
||||||
|
if (stmt->params || paramtypes)
|
||||||
|
{
|
||||||
|
int nparams = length(stmt->params);
|
||||||
|
int nexpected = length(paramtypes);
|
||||||
|
List *l;
|
||||||
|
int i = 1;
|
||||||
|
|
||||||
|
if (nparams != nexpected)
|
||||||
|
elog(ERROR, "Wrong number of parameters, expected %d but got %d",
|
||||||
|
nexpected, nparams);
|
||||||
|
|
||||||
|
foreach (l, stmt->params)
|
||||||
|
{
|
||||||
|
Node *expr = lfirst(l);
|
||||||
|
Oid expected_type_id,
|
||||||
|
given_type_id;
|
||||||
|
|
||||||
|
expr = transformExpr(pstate, expr);
|
||||||
|
|
||||||
|
/* Cannot contain subselects or aggregates */
|
||||||
|
if (contain_subplans(expr))
|
||||||
|
elog(ERROR, "Cannot use subselects in EXECUTE parameters");
|
||||||
|
if (contain_agg_clause(expr))
|
||||||
|
elog(ERROR, "Cannot use aggregates in EXECUTE parameters");
|
||||||
|
|
||||||
|
given_type_id = exprType(expr);
|
||||||
|
expected_type_id = (Oid) lfirsti(paramtypes);
|
||||||
|
|
||||||
|
if (given_type_id != expected_type_id)
|
||||||
|
{
|
||||||
|
expr = CoerceTargetExpr(pstate,
|
||||||
|
expr,
|
||||||
|
given_type_id,
|
||||||
|
expected_type_id,
|
||||||
|
-1,
|
||||||
|
false);
|
||||||
|
|
||||||
|
if (!expr)
|
||||||
|
elog(ERROR, "Parameter $%d of type %s cannot be coerced into the expected type %s"
|
||||||
|
"\n\tYou will need to rewrite or cast the expression",
|
||||||
|
i,
|
||||||
|
format_type_be(given_type_id),
|
||||||
|
format_type_be(expected_type_id));
|
||||||
|
}
|
||||||
|
|
||||||
|
fix_opids(expr);
|
||||||
|
lfirst(l) = expr;
|
||||||
|
|
||||||
|
paramtypes = lnext(paramtypes);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/* exported so planner can check again after rewriting, query pullup, etc */
|
/* exported so planner can check again after rewriting, query pullup, etc */
|
||||||
void
|
void
|
||||||
CheckSelectForUpdate(Query *qry)
|
CheckSelectForUpdate(Query *qry)
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.360 2002/08/19 15:08:47 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.361 2002/08/27 04:55:08 tgl Exp $
|
||||||
*
|
*
|
||||||
* HISTORY
|
* HISTORY
|
||||||
* AUTHOR DATE MAJOR EVENT
|
* AUTHOR DATE MAJOR EVENT
|
||||||
@ -68,8 +68,6 @@
|
|||||||
extern List *parsetree; /* final parse result is delivered here */
|
extern List *parsetree; /* final parse result is delivered here */
|
||||||
|
|
||||||
static bool QueryIsRule = FALSE;
|
static bool QueryIsRule = FALSE;
|
||||||
static Oid *param_type_info;
|
|
||||||
static int pfunc_num_args;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If you need access to certain yacc-generated variables and find that
|
* If you need access to certain yacc-generated variables and find that
|
||||||
@ -149,7 +147,8 @@ static void doNegateFloat(Value *v);
|
|||||||
SelectStmt, TransactionStmt, TruncateStmt,
|
SelectStmt, TransactionStmt, TruncateStmt,
|
||||||
UnlistenStmt, UpdateStmt, VacuumStmt,
|
UnlistenStmt, UpdateStmt, VacuumStmt,
|
||||||
VariableResetStmt, VariableSetStmt, VariableShowStmt,
|
VariableResetStmt, VariableSetStmt, VariableShowStmt,
|
||||||
ViewStmt, CheckPointStmt, CreateConversionStmt
|
ViewStmt, CheckPointStmt, CreateConversionStmt,
|
||||||
|
DeallocateStmt, PrepareStmt, ExecuteStmt
|
||||||
|
|
||||||
%type <node> select_no_parens, select_with_parens, select_clause,
|
%type <node> select_no_parens, select_with_parens, select_clause,
|
||||||
simple_select
|
simple_select
|
||||||
@ -218,7 +217,8 @@ static void doNegateFloat(Value *v);
|
|||||||
group_clause, TriggerFuncArgs, select_limit,
|
group_clause, TriggerFuncArgs, select_limit,
|
||||||
opt_select_limit, opclass_item_list, trans_options,
|
opt_select_limit, opclass_item_list, trans_options,
|
||||||
TableFuncElementList, OptTableFuncElementList,
|
TableFuncElementList, OptTableFuncElementList,
|
||||||
convert_args
|
convert_args, prep_type_clause, prep_type_list,
|
||||||
|
execute_param_clause, execute_param_list
|
||||||
|
|
||||||
%type <range> into_clause, OptTempTableName
|
%type <range> into_clause, OptTempTableName
|
||||||
|
|
||||||
@ -335,7 +335,7 @@ static void doNegateFloat(Value *v);
|
|||||||
CREATEUSER, CROSS, CURRENT_DATE, CURRENT_TIME,
|
CREATEUSER, CROSS, CURRENT_DATE, CURRENT_TIME,
|
||||||
CURRENT_TIMESTAMP, CURRENT_USER, CURSOR, CYCLE,
|
CURRENT_TIMESTAMP, CURRENT_USER, CURSOR, CYCLE,
|
||||||
|
|
||||||
DATABASE, DAY_P, DEC, DECIMAL, DECLARE, DEFAULT,
|
DATABASE, DAY_P, DEALLOCATE, DEC, DECIMAL, DECLARE, DEFAULT,
|
||||||
DEFERRABLE, DEFERRED, DEFINER, DELETE_P, DELIMITER, DELIMITERS,
|
DEFERRABLE, DEFERRED, DEFINER, DELETE_P, DELIMITER, DELIMITERS,
|
||||||
DESC, DISTINCT, DO, DOMAIN_P, DOUBLE, DROP,
|
DESC, DISTINCT, DO, DOMAIN_P, DOUBLE, DROP,
|
||||||
|
|
||||||
@ -371,7 +371,7 @@ static void doNegateFloat(Value *v);
|
|||||||
ORDER, OUT_P, OUTER_P, OVERLAPS, OVERLAY, OWNER,
|
ORDER, OUT_P, OUTER_P, OVERLAPS, OVERLAY, OWNER,
|
||||||
|
|
||||||
PARTIAL, PASSWORD, PATH_P, PENDANT, PLACING, POSITION,
|
PARTIAL, PASSWORD, PATH_P, PENDANT, PLACING, POSITION,
|
||||||
PRECISION, PRIMARY, PRIOR, PRIVILEGES, PROCEDURE,
|
PRECISION, PREPARE, PRIMARY, PRIOR, PRIVILEGES, PROCEDURE,
|
||||||
PROCEDURAL,
|
PROCEDURAL,
|
||||||
|
|
||||||
READ, REAL, RECHECK, REFERENCES, REINDEX, RELATIVE, RENAME, REPLACE,
|
READ, REAL, RECHECK, REFERENCES, REINDEX, RELATIVE, RENAME, REPLACE,
|
||||||
@ -490,6 +490,7 @@ stmt :
|
|||||||
| CreateTrigStmt
|
| CreateTrigStmt
|
||||||
| CreateUserStmt
|
| CreateUserStmt
|
||||||
| ClusterStmt
|
| ClusterStmt
|
||||||
|
| DeallocateStmt
|
||||||
| DefineStmt
|
| DefineStmt
|
||||||
| DropStmt
|
| DropStmt
|
||||||
| TruncateStmt
|
| TruncateStmt
|
||||||
@ -502,6 +503,7 @@ stmt :
|
|||||||
| DropTrigStmt
|
| DropTrigStmt
|
||||||
| DropRuleStmt
|
| DropRuleStmt
|
||||||
| DropUserStmt
|
| DropUserStmt
|
||||||
|
| ExecuteStmt
|
||||||
| ExplainStmt
|
| ExplainStmt
|
||||||
| FetchStmt
|
| FetchStmt
|
||||||
| GrantStmt
|
| GrantStmt
|
||||||
@ -510,6 +512,7 @@ stmt :
|
|||||||
| UnlistenStmt
|
| UnlistenStmt
|
||||||
| LockStmt
|
| LockStmt
|
||||||
| NotifyStmt
|
| NotifyStmt
|
||||||
|
| PrepareStmt
|
||||||
| ReindexStmt
|
| ReindexStmt
|
||||||
| RemoveAggrStmt
|
| RemoveAggrStmt
|
||||||
| RemoveOperStmt
|
| RemoveOperStmt
|
||||||
@ -3875,6 +3878,77 @@ ExplainStmt:
|
|||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
*
|
||||||
|
* QUERY:
|
||||||
|
* PREPARE <plan_name> [(args, ...)] AS <query>
|
||||||
|
*
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
PrepareStmt: PREPARE name prep_type_clause AS OptimizableStmt
|
||||||
|
{
|
||||||
|
PrepareStmt *n = makeNode(PrepareStmt);
|
||||||
|
n->name = $2;
|
||||||
|
n->argtypes = $3;
|
||||||
|
n->query = (Query *) $5;
|
||||||
|
$$ = (Node *) n;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
prep_type_clause: '(' prep_type_list ')' { $$ = $2; }
|
||||||
|
| /* EMPTY */ { $$ = NIL; }
|
||||||
|
;
|
||||||
|
|
||||||
|
prep_type_list: Typename { $$ = makeList1($1); }
|
||||||
|
| prep_type_list ',' Typename
|
||||||
|
{ $$ = lappend($1, $3); }
|
||||||
|
;
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
*
|
||||||
|
* QUERY:
|
||||||
|
* EXECUTE <plan_name> [(params, ...)] [INTO ...]
|
||||||
|
*
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
ExecuteStmt: EXECUTE name execute_param_clause into_clause
|
||||||
|
{
|
||||||
|
ExecuteStmt *n = makeNode(ExecuteStmt);
|
||||||
|
n->name = $2;
|
||||||
|
n->params = $3;
|
||||||
|
n->into = $4;
|
||||||
|
$$ = (Node *) n;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
execute_param_clause: '(' execute_param_list ')' { $$ = $2; }
|
||||||
|
| /* EMPTY */ { $$ = NIL; }
|
||||||
|
;
|
||||||
|
|
||||||
|
execute_param_list: a_expr { $$ = makeList1($1); }
|
||||||
|
| execute_param_list ',' a_expr { $$ = lappend($1, $3); }
|
||||||
|
;
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
*
|
||||||
|
* QUERY:
|
||||||
|
* DEALLOCATE [PREPARE] <plan_name>
|
||||||
|
*
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
DeallocateStmt: DEALLOCATE name
|
||||||
|
{
|
||||||
|
DeallocateStmt *n = makeNode(DeallocateStmt);
|
||||||
|
n->name = $2;
|
||||||
|
$$ = (Node *) n;
|
||||||
|
}
|
||||||
|
| DEALLOCATE PREPARE name
|
||||||
|
{
|
||||||
|
DeallocateStmt *n = makeNode(DeallocateStmt);
|
||||||
|
n->name = $3;
|
||||||
|
$$ = (Node *) n;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
* *
|
* *
|
||||||
@ -6947,6 +7021,7 @@ unreserved_keyword:
|
|||||||
| CYCLE
|
| CYCLE
|
||||||
| DATABASE
|
| DATABASE
|
||||||
| DAY_P
|
| DAY_P
|
||||||
|
| DEALLOCATE
|
||||||
| DECLARE
|
| DECLARE
|
||||||
| DEFERRED
|
| DEFERRED
|
||||||
| DEFINER
|
| DEFINER
|
||||||
@ -7019,6 +7094,7 @@ unreserved_keyword:
|
|||||||
| PATH_P
|
| PATH_P
|
||||||
| PENDANT
|
| PENDANT
|
||||||
| PRECISION
|
| PRECISION
|
||||||
|
| PREPARE
|
||||||
| PRIOR
|
| PRIOR
|
||||||
| PRIVILEGES
|
| PRIVILEGES
|
||||||
| PROCEDURAL
|
| PROCEDURAL
|
||||||
@ -7589,26 +7665,9 @@ SystemTypeName(char *name)
|
|||||||
* Initialize to parse one query string
|
* Initialize to parse one query string
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
parser_init(Oid *typev, int nargs)
|
parser_init(void)
|
||||||
{
|
{
|
||||||
QueryIsRule = FALSE;
|
QueryIsRule = FALSE;
|
||||||
/*
|
|
||||||
* Keep enough information around to fill out the type of param nodes
|
|
||||||
* used in postquel functions
|
|
||||||
*/
|
|
||||||
param_type_info = typev;
|
|
||||||
pfunc_num_args = nargs;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* param_type()
|
|
||||||
* Fetch a parameter type previously passed to parser_init
|
|
||||||
*/
|
|
||||||
Oid
|
|
||||||
param_type(int t)
|
|
||||||
{
|
|
||||||
if ((t > pfunc_num_args) || (t <= 0))
|
|
||||||
return InvalidOid;
|
|
||||||
return param_type_info[t - 1];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* exprIsNullConstant()
|
/* exprIsNullConstant()
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.125 2002/08/18 09:36:25 petere Exp $
|
* $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.126 2002/08/27 04:55:09 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -96,6 +96,7 @@ static const ScanKeyword ScanKeywords[] = {
|
|||||||
{"cycle", CYCLE},
|
{"cycle", CYCLE},
|
||||||
{"database", DATABASE},
|
{"database", DATABASE},
|
||||||
{"day", DAY_P},
|
{"day", DAY_P},
|
||||||
|
{"deallocate", DEALLOCATE},
|
||||||
{"dec", DEC},
|
{"dec", DEC},
|
||||||
{"decimal", DECIMAL},
|
{"decimal", DECIMAL},
|
||||||
{"declare", DECLARE},
|
{"declare", DECLARE},
|
||||||
@ -229,6 +230,7 @@ static const ScanKeyword ScanKeywords[] = {
|
|||||||
{"placing", PLACING},
|
{"placing", PLACING},
|
||||||
{"position", POSITION},
|
{"position", POSITION},
|
||||||
{"precision", PRECISION},
|
{"precision", PRECISION},
|
||||||
|
{"prepare", PREPARE},
|
||||||
{"primary", PRIMARY},
|
{"primary", PRIMARY},
|
||||||
{"prior", PRIOR},
|
{"prior", PRIOR},
|
||||||
{"privileges", PRIVILEGES},
|
{"privileges", PRIVILEGES},
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/parser/parser.c,v 1.53 2002/06/20 20:29:33 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/parser/parser.c,v 1.54 2002/08/27 04:55:11 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -30,6 +30,9 @@
|
|||||||
|
|
||||||
List *parsetree; /* result of parsing is left here */
|
List *parsetree; /* result of parsing is left here */
|
||||||
|
|
||||||
|
static Oid *param_type_info; /* state for param_type() */
|
||||||
|
static int param_count;
|
||||||
|
|
||||||
static int lookahead_token; /* one-token lookahead */
|
static int lookahead_token; /* one-token lookahead */
|
||||||
static bool have_lookahead; /* lookahead_token set? */
|
static bool have_lookahead; /* lookahead_token set? */
|
||||||
|
|
||||||
@ -50,8 +53,9 @@ parser(StringInfo str, Oid *typev, int nargs)
|
|||||||
have_lookahead = false;
|
have_lookahead = false;
|
||||||
|
|
||||||
scanner_init(str);
|
scanner_init(str);
|
||||||
parser_init(typev, nargs);
|
parser_init();
|
||||||
parse_expr_init();
|
parse_expr_init();
|
||||||
|
parser_param_set(typev, nargs);
|
||||||
|
|
||||||
yyresult = yyparse();
|
yyresult = yyparse();
|
||||||
|
|
||||||
@ -65,6 +69,35 @@ parser(StringInfo str, Oid *typev, int nargs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Save information needed to fill out the type of Param references ($n)
|
||||||
|
*
|
||||||
|
* This is used for SQL functions, PREPARE statements, etc. It's split
|
||||||
|
* out from parser() setup because PREPARE needs to change the info after
|
||||||
|
* the grammar runs and before parse analysis is done on the preparable
|
||||||
|
* query.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
parser_param_set(Oid *typev, int nargs)
|
||||||
|
{
|
||||||
|
param_type_info = typev;
|
||||||
|
param_count = nargs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* param_type()
|
||||||
|
*
|
||||||
|
* Fetch a parameter type previously passed to parser_param_set
|
||||||
|
*/
|
||||||
|
Oid
|
||||||
|
param_type(int t)
|
||||||
|
{
|
||||||
|
if (t > param_count || t <= 0)
|
||||||
|
return InvalidOid;
|
||||||
|
return param_type_info[t - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Intermediate filter between parser and base lexer (base_yylex in scan.l).
|
* Intermediate filter between parser and base lexer (base_yylex in scan.l).
|
||||||
*
|
*
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.283 2002/08/17 15:12:07 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.284 2002/08/27 04:55:11 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* this is the "main" module of the postgres backend and
|
* this is the "main" module of the postgres backend and
|
||||||
@ -1666,7 +1666,7 @@ PostgresMain(int argc, char *argv[], const char *username)
|
|||||||
if (!IsUnderPostmaster)
|
if (!IsUnderPostmaster)
|
||||||
{
|
{
|
||||||
puts("\nPOSTGRES backend interactive interface ");
|
puts("\nPOSTGRES backend interactive interface ");
|
||||||
puts("$Revision: 1.283 $ $Date: 2002/08/17 15:12:07 $\n");
|
puts("$Revision: 1.284 $ $Date: 2002/08/27 04:55:11 $\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2406,6 +2406,18 @@ CreateCommandTag(Node *parsetree)
|
|||||||
tag = "DROP OPERATOR CLASS";
|
tag = "DROP OPERATOR CLASS";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case T_PrepareStmt:
|
||||||
|
tag = "PREPARE";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case T_ExecuteStmt:
|
||||||
|
tag = "EXECUTE";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case T_DeallocateStmt:
|
||||||
|
tag = "DEALLOCATE";
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
elog(LOG, "CreateCommandTag: unknown parse node type %d",
|
elog(LOG, "CreateCommandTag: unknown parse node type %d",
|
||||||
nodeTag(parsetree));
|
nodeTag(parsetree));
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.172 2002/08/17 13:04:15 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.173 2002/08/27 04:55:11 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -30,6 +30,7 @@
|
|||||||
#include "commands/explain.h"
|
#include "commands/explain.h"
|
||||||
#include "commands/lockcmds.h"
|
#include "commands/lockcmds.h"
|
||||||
#include "commands/portalcmds.h"
|
#include "commands/portalcmds.h"
|
||||||
|
#include "commands/prepare.h"
|
||||||
#include "commands/proclang.h"
|
#include "commands/proclang.h"
|
||||||
#include "commands/schemacmds.h"
|
#include "commands/schemacmds.h"
|
||||||
#include "commands/sequence.h"
|
#include "commands/sequence.h"
|
||||||
@ -379,6 +380,18 @@ ProcessUtility(Node *parsetree,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case T_PrepareStmt:
|
||||||
|
PrepareQuery((PrepareStmt *) parsetree);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case T_ExecuteStmt:
|
||||||
|
ExecuteQuery((ExecuteStmt *) parsetree, dest);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case T_DeallocateStmt:
|
||||||
|
DeallocateQuery((DeallocateStmt *) parsetree);
|
||||||
|
break;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* schema
|
* schema
|
||||||
*/
|
*/
|
||||||
@ -541,11 +554,7 @@ ProcessUtility(Node *parsetree,
|
|||||||
|
|
||||||
|
|
||||||
case T_GrantStmt:
|
case T_GrantStmt:
|
||||||
{
|
ExecuteGrantStmt((GrantStmt *) parsetree);
|
||||||
GrantStmt *stmt = (GrantStmt *) parsetree;
|
|
||||||
|
|
||||||
ExecuteGrantStmt(stmt);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -841,9 +850,7 @@ ProcessUtility(Node *parsetree,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case T_CreateConversionStmt:
|
case T_CreateConversionStmt:
|
||||||
{
|
|
||||||
CreateConversionCommand((CreateConversionStmt *) parsetree);
|
CreateConversionCommand((CreateConversionStmt *) parsetree);
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_CreateCastStmt:
|
case T_CreateCastStmt:
|
||||||
|
29
src/include/commands/prepare.h
Normal file
29
src/include/commands/prepare.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* prepare.h
|
||||||
|
* PREPARE, EXECUTE and DEALLOCATE command prototypes
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Copyright (c) 2002, PostgreSQL Global Development Group
|
||||||
|
*
|
||||||
|
* $Id: prepare.h,v 1.1 2002/08/27 04:55:11 tgl Exp $
|
||||||
|
*
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PREPARE_H
|
||||||
|
#define PREPARE_H
|
||||||
|
|
||||||
|
#include "nodes/parsenodes.h"
|
||||||
|
#include "tcop/dest.h"
|
||||||
|
|
||||||
|
|
||||||
|
extern void PrepareQuery(PrepareStmt *stmt);
|
||||||
|
|
||||||
|
extern void ExecuteQuery(ExecuteStmt *stmt, CommandDest outputDest);
|
||||||
|
|
||||||
|
extern void DeallocateQuery(DeallocateStmt *stmt);
|
||||||
|
|
||||||
|
extern List *FetchQueryParams(const char *plan_name);
|
||||||
|
|
||||||
|
#endif /* PREPARE_H */
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: nodes.h,v 1.116 2002/08/19 15:08:47 tgl Exp $
|
* $Id: nodes.h,v 1.117 2002/08/27 04:55:11 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -200,6 +200,9 @@ typedef enum NodeTag
|
|||||||
T_DropCastStmt,
|
T_DropCastStmt,
|
||||||
T_CreateOpClassStmt,
|
T_CreateOpClassStmt,
|
||||||
T_RemoveOpClassStmt,
|
T_RemoveOpClassStmt,
|
||||||
|
T_PrepareStmt,
|
||||||
|
T_ExecuteStmt,
|
||||||
|
T_DeallocateStmt,
|
||||||
|
|
||||||
T_A_Expr = 700,
|
T_A_Expr = 700,
|
||||||
T_ColumnRef,
|
T_ColumnRef,
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: parsenodes.h,v 1.201 2002/08/19 15:08:47 tgl Exp $
|
* $Id: parsenodes.h,v 1.202 2002/08/27 04:55:12 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -1620,4 +1620,42 @@ typedef struct DropCastStmt
|
|||||||
} DropCastStmt;
|
} DropCastStmt;
|
||||||
|
|
||||||
|
|
||||||
|
/* ----------------------
|
||||||
|
* PREPARE Statement
|
||||||
|
* ----------------------
|
||||||
|
*/
|
||||||
|
typedef struct PrepareStmt
|
||||||
|
{
|
||||||
|
NodeTag type;
|
||||||
|
char *name; /* Name of plan, arbitrary */
|
||||||
|
List *argtypes; /* Types of parameters (TypeNames) */
|
||||||
|
List *argtype_oids; /* Types of parameters (OIDs) */
|
||||||
|
Query *query; /* The query itself */
|
||||||
|
} PrepareStmt;
|
||||||
|
|
||||||
|
|
||||||
|
/* ----------------------
|
||||||
|
* EXECUTE Statement
|
||||||
|
* ----------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef struct ExecuteStmt
|
||||||
|
{
|
||||||
|
NodeTag type;
|
||||||
|
char *name; /* The name of the plan to execute */
|
||||||
|
RangeVar *into; /* Optional table to store results in */
|
||||||
|
List *params; /* Values to assign to parameters */
|
||||||
|
} ExecuteStmt;
|
||||||
|
|
||||||
|
|
||||||
|
/* ----------------------
|
||||||
|
* DEALLOCATE Statement
|
||||||
|
* ----------------------
|
||||||
|
*/
|
||||||
|
typedef struct DeallocateStmt
|
||||||
|
{
|
||||||
|
NodeTag type;
|
||||||
|
char *name; /* The name of the plan to remove */
|
||||||
|
} DeallocateStmt;
|
||||||
|
|
||||||
#endif /* PARSENODES_H */
|
#endif /* PARSENODES_H */
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: gramparse.h,v 1.23 2002/06/20 20:29:51 momjian Exp $
|
* $Id: gramparse.h,v 1.24 2002/08/27 04:55:12 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -19,6 +19,8 @@
|
|||||||
#include "nodes/parsenodes.h"
|
#include "nodes/parsenodes.h"
|
||||||
|
|
||||||
/* from parser.c */
|
/* from parser.c */
|
||||||
|
extern void parser_param_set(Oid *typev, int nargs);
|
||||||
|
extern Oid param_type(int t);
|
||||||
extern int yylex(void);
|
extern int yylex(void);
|
||||||
|
|
||||||
/* from scan.l */
|
/* from scan.l */
|
||||||
@ -28,8 +30,7 @@ extern int base_yylex(void);
|
|||||||
extern void yyerror(const char *message);
|
extern void yyerror(const char *message);
|
||||||
|
|
||||||
/* from gram.y */
|
/* from gram.y */
|
||||||
extern void parser_init(Oid *typev, int nargs);
|
extern void parser_init(void);
|
||||||
extern Oid param_type(int t);
|
|
||||||
extern int yyparse(void);
|
extern int yyparse(void);
|
||||||
extern List *SystemFuncName(char *name);
|
extern List *SystemFuncName(char *name);
|
||||||
extern TypeName *SystemTypeName(char *name);
|
extern TypeName *SystemTypeName(char *name);
|
||||||
|
107
src/test/regress/expected/prepare.out
Normal file
107
src/test/regress/expected/prepare.out
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
-- Regression tests for prepareable statements
|
||||||
|
PREPARE q1 AS SELECT 1;
|
||||||
|
EXECUTE q1;
|
||||||
|
?column?
|
||||||
|
----------
|
||||||
|
1
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- should fail
|
||||||
|
PREPARE q1 AS SELECT 2;
|
||||||
|
ERROR: Prepared statement with name "q1" already exists
|
||||||
|
-- should succeed
|
||||||
|
DEALLOCATE q1;
|
||||||
|
PREPARE q1 AS SELECT 2;
|
||||||
|
EXECUTE q1;
|
||||||
|
?column?
|
||||||
|
----------
|
||||||
|
2
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- sql92 syntax
|
||||||
|
DEALLOCATE PREPARE q1;
|
||||||
|
-- parameterized queries
|
||||||
|
PREPARE q2(text) AS
|
||||||
|
SELECT datname, datistemplate, datallowconn
|
||||||
|
FROM pg_database WHERE datname = $1;
|
||||||
|
EXECUTE q2('regression');
|
||||||
|
datname | datistemplate | datallowconn
|
||||||
|
------------+---------------+--------------
|
||||||
|
regression | f | t
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
PREPARE q3(text, int, float, boolean, oid, smallint) AS
|
||||||
|
SELECT * FROM tenk1 WHERE string4 = $1 AND (four = $2 OR
|
||||||
|
ten = $3::bigint OR true = $4 OR oid = $5 OR odd = $6::int);
|
||||||
|
EXECUTE q3('AAAAxx', 5::smallint, 10.5::float, false, 500::oid, 4::bigint);
|
||||||
|
unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4
|
||||||
|
---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+---------
|
||||||
|
4502 | 412 | 0 | 2 | 2 | 2 | 2 | 502 | 502 | 4502 | 4502 | 4 | 5 | ERAAAA | WPAAAA | AAAAxx
|
||||||
|
102 | 612 | 0 | 2 | 2 | 2 | 2 | 102 | 102 | 102 | 102 | 4 | 5 | YDAAAA | OXAAAA | AAAAxx
|
||||||
|
7602 | 1040 | 0 | 2 | 2 | 2 | 2 | 602 | 1602 | 2602 | 7602 | 4 | 5 | KGAAAA | AOBAAA | AAAAxx
|
||||||
|
902 | 1104 | 0 | 2 | 2 | 2 | 2 | 902 | 902 | 902 | 902 | 4 | 5 | SIAAAA | MQBAAA | AAAAxx
|
||||||
|
4902 | 1600 | 0 | 2 | 2 | 2 | 2 | 902 | 902 | 4902 | 4902 | 4 | 5 | OGAAAA | OJCAAA | AAAAxx
|
||||||
|
9502 | 1812 | 0 | 2 | 2 | 2 | 2 | 502 | 1502 | 4502 | 9502 | 4 | 5 | MBAAAA | SRCAAA | AAAAxx
|
||||||
|
4702 | 2520 | 0 | 2 | 2 | 2 | 2 | 702 | 702 | 4702 | 4702 | 4 | 5 | WYAAAA | YSDAAA | AAAAxx
|
||||||
|
1002 | 2580 | 0 | 2 | 2 | 2 | 2 | 2 | 1002 | 1002 | 1002 | 4 | 5 | OMAAAA | GVDAAA | AAAAxx
|
||||||
|
2 | 2716 | 0 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 4 | 5 | CAAAAA | MAEAAA | AAAAxx
|
||||||
|
802 | 2908 | 0 | 2 | 2 | 2 | 2 | 802 | 802 | 802 | 802 | 4 | 5 | WEAAAA | WHEAAA | AAAAxx
|
||||||
|
6402 | 3808 | 0 | 2 | 2 | 2 | 2 | 402 | 402 | 1402 | 6402 | 4 | 5 | GMAAAA | MQFAAA | AAAAxx
|
||||||
|
8602 | 5440 | 0 | 2 | 2 | 2 | 2 | 602 | 602 | 3602 | 8602 | 4 | 5 | WSAAAA | GBIAAA | AAAAxx
|
||||||
|
8402 | 5708 | 0 | 2 | 2 | 2 | 2 | 402 | 402 | 3402 | 8402 | 4 | 5 | ELAAAA | OLIAAA | AAAAxx
|
||||||
|
2102 | 6184 | 0 | 2 | 2 | 2 | 2 | 102 | 102 | 2102 | 2102 | 4 | 5 | WCAAAA | WDJAAA | AAAAxx
|
||||||
|
4202 | 6628 | 0 | 2 | 2 | 2 | 2 | 202 | 202 | 4202 | 4202 | 4 | 5 | QFAAAA | YUJAAA | AAAAxx
|
||||||
|
2902 | 6816 | 0 | 2 | 2 | 2 | 2 | 902 | 902 | 2902 | 2902 | 4 | 5 | QHAAAA | ECKAAA | AAAAxx
|
||||||
|
2302 | 7112 | 0 | 2 | 2 | 2 | 2 | 302 | 302 | 2302 | 2302 | 4 | 5 | OKAAAA | ONKAAA | AAAAxx
|
||||||
|
3202 | 7128 | 0 | 2 | 2 | 2 | 2 | 202 | 1202 | 3202 | 3202 | 4 | 5 | ETAAAA | EOKAAA | AAAAxx
|
||||||
|
7802 | 7508 | 0 | 2 | 2 | 2 | 2 | 802 | 1802 | 2802 | 7802 | 4 | 5 | COAAAA | UCLAAA | AAAAxx
|
||||||
|
4102 | 7676 | 0 | 2 | 2 | 2 | 2 | 102 | 102 | 4102 | 4102 | 4 | 5 | UBAAAA | GJLAAA | AAAAxx
|
||||||
|
8302 | 7800 | 0 | 2 | 2 | 2 | 2 | 302 | 302 | 3302 | 8302 | 4 | 5 | IHAAAA | AOLAAA | AAAAxx
|
||||||
|
1702 | 7940 | 0 | 2 | 2 | 2 | 2 | 702 | 1702 | 1702 | 1702 | 4 | 5 | MNAAAA | KTLAAA | AAAAxx
|
||||||
|
2202 | 8028 | 0 | 2 | 2 | 2 | 2 | 202 | 202 | 2202 | 2202 | 4 | 5 | SGAAAA | UWLAAA | AAAAxx
|
||||||
|
1602 | 8148 | 0 | 2 | 2 | 2 | 2 | 602 | 1602 | 1602 | 1602 | 4 | 5 | QJAAAA | KBMAAA | AAAAxx
|
||||||
|
5602 | 8796 | 0 | 2 | 2 | 2 | 2 | 602 | 1602 | 602 | 5602 | 4 | 5 | MHAAAA | IANAAA | AAAAxx
|
||||||
|
6002 | 8932 | 0 | 2 | 2 | 2 | 2 | 2 | 2 | 1002 | 6002 | 4 | 5 | WWAAAA | OFNAAA | AAAAxx
|
||||||
|
3902 | 9224 | 0 | 2 | 2 | 2 | 2 | 902 | 1902 | 3902 | 3902 | 4 | 5 | CUAAAA | UQNAAA | AAAAxx
|
||||||
|
9602 | 9972 | 0 | 2 | 2 | 2 | 2 | 602 | 1602 | 4602 | 9602 | 4 | 5 | IFAAAA | OTOAAA | AAAAxx
|
||||||
|
8002 | 9980 | 0 | 2 | 2 | 2 | 2 | 2 | 2 | 3002 | 8002 | 4 | 5 | UVAAAA | WTOAAA | AAAAxx
|
||||||
|
(29 rows)
|
||||||
|
|
||||||
|
-- too few params
|
||||||
|
EXECUTE q3('bool');
|
||||||
|
ERROR: Wrong number of parameters, expected 6 but got 1
|
||||||
|
-- too many params
|
||||||
|
EXECUTE q3('bytea', 5::smallint, 10.5::float, false, 500::oid, 4::bigint, true);
|
||||||
|
ERROR: Wrong number of parameters, expected 6 but got 7
|
||||||
|
-- wrong param types
|
||||||
|
EXECUTE q3(5::smallint, 10.5::float, false, 500::oid, 4::bigint, 'bytea');
|
||||||
|
ERROR: Parameter $2 of type double precision cannot be coerced into the expected type integer
|
||||||
|
You will need to rewrite or cast the expression
|
||||||
|
-- invalid type
|
||||||
|
PREPARE q4(nonexistenttype) AS SELECT $1;
|
||||||
|
ERROR: Type "nonexistenttype" does not exist
|
||||||
|
-- execute into
|
||||||
|
PREPARE q5(int, text) AS
|
||||||
|
SELECT * FROM tenk1 WHERE unique1 = $1 OR stringu1 = $2;
|
||||||
|
EXECUTE q5(200, 'DTAAAA') INTO TEMPORARY q5_prep_results;
|
||||||
|
SELECT * FROM q5_prep_results;
|
||||||
|
unique1 | unique2 | two | four | ten | twenty | hundred | thousand | twothousand | fivethous | tenthous | odd | even | stringu1 | stringu2 | string4
|
||||||
|
---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+---------
|
||||||
|
2525 | 64 | 1 | 1 | 5 | 5 | 25 | 525 | 525 | 2525 | 2525 | 50 | 51 | DTAAAA | MCAAAA | AAAAxx
|
||||||
|
7257 | 1895 | 1 | 1 | 7 | 17 | 57 | 257 | 1257 | 2257 | 7257 | 114 | 115 | DTAAAA | XUCAAA | VVVVxx
|
||||||
|
9961 | 2058 | 1 | 1 | 1 | 1 | 61 | 961 | 1961 | 4961 | 9961 | 122 | 123 | DTAAAA | EBDAAA | OOOOxx
|
||||||
|
3877 | 4060 | 1 | 1 | 7 | 17 | 77 | 877 | 1877 | 3877 | 3877 | 154 | 155 | DTAAAA | EAGAAA | AAAAxx
|
||||||
|
4553 | 4113 | 1 | 1 | 3 | 13 | 53 | 553 | 553 | 4553 | 4553 | 106 | 107 | DTAAAA | FCGAAA | HHHHxx
|
||||||
|
7933 | 4514 | 1 | 1 | 3 | 13 | 33 | 933 | 1933 | 2933 | 7933 | 66 | 67 | DTAAAA | QRGAAA | OOOOxx
|
||||||
|
6581 | 4686 | 1 | 1 | 1 | 1 | 81 | 581 | 581 | 1581 | 6581 | 162 | 163 | DTAAAA | GYGAAA | OOOOxx
|
||||||
|
8609 | 5918 | 1 | 1 | 9 | 9 | 9 | 609 | 609 | 3609 | 8609 | 18 | 19 | DTAAAA | QTIAAA | OOOOxx
|
||||||
|
5229 | 6407 | 1 | 1 | 9 | 9 | 29 | 229 | 1229 | 229 | 5229 | 58 | 59 | DTAAAA | LMJAAA | VVVVxx
|
||||||
|
1173 | 6699 | 1 | 1 | 3 | 13 | 73 | 173 | 1173 | 1173 | 1173 | 146 | 147 | DTAAAA | RXJAAA | VVVVxx
|
||||||
|
3201 | 7309 | 1 | 1 | 1 | 1 | 1 | 201 | 1201 | 3201 | 3201 | 2 | 3 | DTAAAA | DVKAAA | HHHHxx
|
||||||
|
1849 | 8143 | 1 | 1 | 9 | 9 | 49 | 849 | 1849 | 1849 | 1849 | 98 | 99 | DTAAAA | FBMAAA | VVVVxx
|
||||||
|
9285 | 8469 | 1 | 1 | 5 | 5 | 85 | 285 | 1285 | 4285 | 9285 | 170 | 171 | DTAAAA | TNMAAA | HHHHxx
|
||||||
|
497 | 9092 | 1 | 1 | 7 | 17 | 97 | 497 | 497 | 497 | 497 | 194 | 195 | DTAAAA | SLNAAA | AAAAxx
|
||||||
|
200 | 9441 | 0 | 0 | 0 | 0 | 0 | 200 | 200 | 200 | 200 | 0 | 1 | SHAAAA | DZNAAA | HHHHxx
|
||||||
|
5905 | 9537 | 1 | 1 | 5 | 5 | 5 | 905 | 1905 | 905 | 5905 | 10 | 11 | DTAAAA | VCOAAA | HHHHxx
|
||||||
|
(16 rows)
|
||||||
|
|
@ -74,4 +74,4 @@ test: select_views alter_table portals_p2 rules foreign_key cluster
|
|||||||
# The sixth group of parallel test
|
# The sixth group of parallel test
|
||||||
# ----------
|
# ----------
|
||||||
# "plpgsql" cannot run concurrently with "rules"
|
# "plpgsql" cannot run concurrently with "rules"
|
||||||
test: limit plpgsql temp domain rangefuncs copy2 conversion without_oid truncate
|
test: limit plpgsql copy2 temp domain rangefuncs prepare without_oid conversion truncate
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
# $Header: /cvsroot/pgsql/src/test/regress/serial_schedule,v 1.16 2002/08/22 04:51:06 momjian Exp $
|
# $Header: /cvsroot/pgsql/src/test/regress/serial_schedule,v 1.17 2002/08/27 04:55:12 tgl Exp $
|
||||||
# This should probably be in an order similar to parallel_schedule.
|
# This should probably be in an order similar to parallel_schedule.
|
||||||
test: boolean
|
test: boolean
|
||||||
test: char
|
test: char
|
||||||
@ -86,6 +86,7 @@ test: copy2
|
|||||||
test: temp
|
test: temp
|
||||||
test: domain
|
test: domain
|
||||||
test: rangefuncs
|
test: rangefuncs
|
||||||
|
test: prepare
|
||||||
test: without_oid
|
test: without_oid
|
||||||
test: conversion
|
test: conversion
|
||||||
test: truncate
|
test: truncate
|
||||||
|
45
src/test/regress/sql/prepare.sql
Normal file
45
src/test/regress/sql/prepare.sql
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
-- Regression tests for prepareable statements
|
||||||
|
|
||||||
|
PREPARE q1 AS SELECT 1;
|
||||||
|
EXECUTE q1;
|
||||||
|
|
||||||
|
-- should fail
|
||||||
|
PREPARE q1 AS SELECT 2;
|
||||||
|
|
||||||
|
-- should succeed
|
||||||
|
DEALLOCATE q1;
|
||||||
|
PREPARE q1 AS SELECT 2;
|
||||||
|
EXECUTE q1;
|
||||||
|
|
||||||
|
-- sql92 syntax
|
||||||
|
DEALLOCATE PREPARE q1;
|
||||||
|
|
||||||
|
-- parameterized queries
|
||||||
|
PREPARE q2(text) AS
|
||||||
|
SELECT datname, datistemplate, datallowconn
|
||||||
|
FROM pg_database WHERE datname = $1;
|
||||||
|
EXECUTE q2('regression');
|
||||||
|
|
||||||
|
PREPARE q3(text, int, float, boolean, oid, smallint) AS
|
||||||
|
SELECT * FROM tenk1 WHERE string4 = $1 AND (four = $2 OR
|
||||||
|
ten = $3::bigint OR true = $4 OR oid = $5 OR odd = $6::int);
|
||||||
|
|
||||||
|
EXECUTE q3('AAAAxx', 5::smallint, 10.5::float, false, 500::oid, 4::bigint);
|
||||||
|
|
||||||
|
-- too few params
|
||||||
|
EXECUTE q3('bool');
|
||||||
|
|
||||||
|
-- too many params
|
||||||
|
EXECUTE q3('bytea', 5::smallint, 10.5::float, false, 500::oid, 4::bigint, true);
|
||||||
|
|
||||||
|
-- wrong param types
|
||||||
|
EXECUTE q3(5::smallint, 10.5::float, false, 500::oid, 4::bigint, 'bytea');
|
||||||
|
|
||||||
|
-- invalid type
|
||||||
|
PREPARE q4(nonexistenttype) AS SELECT $1;
|
||||||
|
|
||||||
|
-- execute into
|
||||||
|
PREPARE q5(int, text) AS
|
||||||
|
SELECT * FROM tenk1 WHERE unique1 = $1 OR stringu1 = $2;
|
||||||
|
EXECUTE q5(200, 'DTAAAA') INTO TEMPORARY q5_prep_results;
|
||||||
|
SELECT * FROM q5_prep_results;
|
Reference in New Issue
Block a user