mirror of https://github.com/postgres/postgres
parent
bc8f725a4a
commit
28e82066a1
@ -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: |
||||||
|
--> |
@ -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: |
||||||
|
--> |
@ -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: |
||||||
|
--> |
@ -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); |
||||||
|
} |
@ -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 */ |
@ -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) |
||||||
|
|
@ -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; |
Loading…
Reference in new issue