Add a new system view, pg_prepared_statements, that can be used to

access information about the prepared statements that are available
in the current session. Original patch from Joachim Wieland, various
improvements by Neil Conway.

The "statement" column of the view contains the literal query string
sent by the client, without any rewriting or pretty printing. This
means that prepared statements created via SQL will be prefixed with
"PREPARE ... AS ", whereas those prepared via the FE/BE protocol will
not. That is unfortunate, but discussion on -patches did not yield an
efficient way to improve this, and there is some merit in returning
exactly what the client sent to the backend.

Catalog version bumped, regression tests updated.
This commit is contained in:
Neil Conway 2006-01-08 07:00:27 +00:00
parent afa8f1971a
commit 44b928e876
13 changed files with 362 additions and 32 deletions

View File

@ -1,6 +1,6 @@
<!--
Documentation of the system catalogs, directed toward PostgreSQL developers
$PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.115 2005/11/04 23:13:59 petere Exp $
$PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.116 2006/01/08 07:00:24 neilc Exp $
-->
<chapter id="catalogs">
@ -4372,6 +4372,11 @@
<entry>currently held locks</entry>
</row>
<row>
<entry><link linkend="view-pg-prepared-statements"><structname>pg_prepared_statements</structname></link></entry>
<entry>current prepared statements</entry>
</row>
<row>
<entry><link linkend="view-pg-prepared-xacts"><structname>pg_prepared_xacts</structname></link></entry>
<entry>currently prepared transactions</entry>
@ -4778,6 +4783,101 @@
</sect1>
<sect1 id="view-pg-prepared-statements">
<title><structname>pg_prepared_statements</structname></title>
<indexterm zone="view-pg-prepared-statements">
<primary>pg_prepared_statements</primary>
</indexterm>
<para>
The <structname>pg_prepared_statements</structname> view displays
all the prepared statements that are available in the current
session. See <xref linkend="sql-prepare"
endterm="sql-prepare-title"> for more information about prepared
statements.
</para>
<para>
<structname>pg_prepared_statements</structname> contains one row
for each prepared statement. Rows are added to the view when a new
prepared statement is created, and removed when a prepared
statement is released (for example, via the <xref
linkend="sql-deallocate" endterm="sql-deallocate-title">
command).
</para>
<table>
<title><structname>pg_prepared_statements</> Columns</title>
<tgroup cols=4>
<thead>
<row>
<entry>Name</entry>
<entry>Type</entry>
<entry>References</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry><structfield>name</structfield></entry>
<entry><type>text</type></entry>
<entry></entry>
<entry>
The identifier of the prepared statement.
</entry>
</row>
<row>
<entry><structfield>statement</structfield></entry>
<entry><type>text</type></entry>
<entry></entry>
<entry>
The query string submitted by the client to create this
prepared statement. For prepared statements created via SQL,
this is the <command>PREPARE</command> statement submitted by
the client. For prepared statements created via the
frontend/backend protocol, this is the text of the prepared
statement itself.
</entry>
</row>
<row>
<entry><structfield>prepare_time</structfield></entry>
<entry><type>timestamptz</type></entry>
<entry></entry>
<entry>
The time at which the prepared statement was created.
</entry>
</row>
<row>
<entry><structfield>parameter_types</structfield></entry>
<entry><type>oid[]</type></entry>
<entry></entry>
<entry>
The expected parameter types for the prepared statement in the form of
an array of type OIDs.
</entry>
</row>
<row>
<entry><structfield>from_sql</structfield></entry>
<entry><type>boolean</type></entry>
<entry></entry>
<entry>
<literal>true</literal> if the prepared statement was created
via the <command>PREPARE</command> SQL statement;
<literal>false</literal> if the statement was prepared via the
frontend/backend protocol.
</entry>
</row>
</tbody>
</tgroup>
</table>
<para>
The <structname>pg_prepared_statements</structname> view is read only.
</para>
</sect1>
<sect1 id="view-pg-prepared-xacts">
<title><structname>pg_prepared_xacts</structname></title>

View File

@ -1,5 +1,5 @@
<!--
$PostgreSQL: pgsql/doc/src/sgml/ref/prepare.sgml,v 1.16 2005/10/15 01:47:12 neilc Exp $
$PostgreSQL: pgsql/doc/src/sgml/ref/prepare.sgml,v 1.17 2006/01/08 07:00:25 neilc Exp $
PostgreSQL documentation
-->
@ -145,6 +145,11 @@ PREPARE <replaceable class="PARAMETER">plan_name</replaceable> [ (<replaceable c
the <xref linkend="sql-analyze" endterm="sql-analyze-title">
documentation.
</para>
<para>
You can see all available prepared statements of a session by querying the
<structname>pg_prepared_statements</> system view.
</para>
</refsect1>
<refsect1 id="sql-prepare-examples">

View File

@ -3,7 +3,7 @@
*
* Copyright (c) 1996-2005, PostgreSQL Global Development Group
*
* $PostgreSQL: pgsql/src/backend/catalog/system_views.sql,v 1.22 2005/10/06 02:29:15 tgl Exp $
* $PostgreSQL: pgsql/src/backend/catalog/system_views.sql,v 1.23 2006/01/08 07:00:25 neilc Exp $
*/
CREATE VIEW pg_roles AS
@ -156,6 +156,12 @@ CREATE VIEW pg_prepared_xacts AS
LEFT JOIN pg_authid U ON P.ownerid = U.oid
LEFT JOIN pg_database D ON P.dbid = D.oid;
CREATE VIEW pg_prepared_statements AS
SELECT P.name, P.statement, P.prepare_time, P.parameter_types, P.from_sql
FROM pg_prepared_statement() AS P
(name text, statement text, prepare_time timestamptz,
parameter_types oid[], from_sql boolean);
CREATE VIEW pg_settings AS
SELECT *
FROM pg_show_all_settings() AS A

View File

@ -10,21 +10,26 @@
* Copyright (c) 2002-2005, PostgreSQL Global Development Group
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.44 2005/12/14 17:06:27 tgl Exp $
* $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.45 2006/01/08 07:00:25 neilc Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/heapam.h"
#include "catalog/pg_type.h"
#include "commands/explain.h"
#include "commands/prepare.h"
#include "executor/executor.h"
#include "utils/guc.h"
#include "funcapi.h"
#include "parser/parsetree.h"
#include "optimizer/planner.h"
#include "rewrite/rewriteHandler.h"
#include "tcop/pquery.h"
#include "tcop/tcopprot.h"
#include "tcop/utility.h"
#include "utils/builtins.h"
#include "utils/guc.h"
#include "utils/hsearch.h"
#include "utils/memutils.h"
@ -40,6 +45,7 @@ static HTAB *prepared_queries = NULL;
static void InitQueryHashTable(void);
static ParamListInfo EvaluateParams(EState *estate,
List *params, List *argtypes);
static Datum build_oid_array(List *oid_list);
/*
* Implements the 'PREPARE' utility statement.
@ -114,7 +120,8 @@ PrepareQuery(PrepareStmt *stmt)
commandTag,
query_list,
plan_list,
stmt->argtype_oids);
stmt->argtype_oids,
true);
}
/*
@ -298,7 +305,8 @@ StorePreparedStatement(const char *stmt_name,
const char *commandTag,
List *query_list,
List *plan_list,
List *argtype_list)
List *argtype_list,
bool from_sql)
{
PreparedStatement *entry;
MemoryContext oldcxt,
@ -361,6 +369,8 @@ StorePreparedStatement(const char *stmt_name,
entry->plan_list = plan_list;
entry->argtype_list = argtype_list;
entry->context = entrycxt;
entry->prepare_time = GetCurrentTimestamp();
entry->from_sql = from_sql;
MemoryContextSwitchTo(oldcxt);
}
@ -383,7 +393,7 @@ FetchPreparedStatement(const char *stmt_name, bool throwError)
{
/*
* 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
* hash package is picky enough that it needs to be NUL-padded out to
* the appropriate length to work correctly.
*/
StrNCpy(key, stmt_name, sizeof(key));
@ -661,3 +671,125 @@ ExplainExecuteQuery(ExplainStmt *stmt, ParamListInfo params,
if (estate)
FreeExecutorState(estate);
}
/*
* This set returning function reads all the prepared statements and
* returns a set of (name, statement, prepare_time, param_types).
*/
Datum
pg_prepared_statement(PG_FUNCTION_ARGS)
{
FuncCallContext *funcctx;
HASH_SEQ_STATUS *hash_seq;
PreparedStatement *prep_stmt;
/* stuff done only on the first call of the function */
if (SRF_IS_FIRSTCALL())
{
TupleDesc tupdesc;
MemoryContext oldcontext;
/* create a function context for cross-call persistence */
funcctx = SRF_FIRSTCALL_INIT();
/*
* switch to memory context appropriate for multiple function
* calls
*/
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
/* allocate memory for user context */
if (prepared_queries)
{
hash_seq = (HASH_SEQ_STATUS *) palloc(sizeof(HASH_SEQ_STATUS));
hash_seq_init(hash_seq, prepared_queries);
funcctx->user_fctx = (void *) hash_seq;
}
else
funcctx->user_fctx = NULL;
/*
* build tupdesc for result tuples. This must match the
* definition of the pg_prepared_statements view in
* system_views.sql
*/
tupdesc = CreateTemplateTupleDesc(5, false);
TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name",
TEXTOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber) 2, "statement",
TEXTOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber) 3, "prepare_time",
TIMESTAMPTZOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber) 4, "parameter_types",
OIDARRAYOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber) 5, "from_sql",
BOOLOID, -1, 0);
funcctx->tuple_desc = BlessTupleDesc(tupdesc);
MemoryContextSwitchTo(oldcontext);
}
/* stuff done on every call of the function */
funcctx = SRF_PERCALL_SETUP();
hash_seq = (HASH_SEQ_STATUS *) funcctx->user_fctx;
/* if the hash table is uninitialized, we're done */
if (hash_seq == NULL)
SRF_RETURN_DONE(funcctx);
prep_stmt = hash_seq_search(hash_seq);
if (prep_stmt)
{
Datum result;
HeapTuple tuple;
Datum values[5];
bool nulls[5];
MemSet(nulls, 0, sizeof(nulls));
values[0] = DirectFunctionCall1(textin,
CStringGetDatum(prep_stmt->stmt_name));
if (prep_stmt->query_string == NULL)
nulls[1] = true;
else
values[1] = DirectFunctionCall1(textin,
CStringGetDatum(prep_stmt->query_string));
values[2] = TimestampTzGetDatum(prep_stmt->prepare_time);
values[3] = build_oid_array(prep_stmt->argtype_list);
values[4] = BoolGetDatum(prep_stmt->from_sql);
tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
result = HeapTupleGetDatum(tuple);
SRF_RETURN_NEXT(funcctx, result);
}
SRF_RETURN_DONE(funcctx);
}
/*
* This utility function takes a List of Oids, and returns a Datum
* pointing to a Postgres array containing those OIDs. The empty list
* is returned as a zero-element array, not NULL.
*/
static Datum
build_oid_array(List *oid_list)
{
ListCell *lc;
int len;
int i;
Datum *tmp_ary;
ArrayType *ary;
len = list_length(oid_list);
tmp_ary = (Datum *) palloc(len * sizeof(Datum));
i = 0;
foreach(lc, oid_list)
tmp_ary[i++] = ObjectIdGetDatum(lfirst_oid(lc));
/* XXX: this hardcodes assumptions about the OID type... */
ary = construct_array(tmp_ary, len, OIDOID, sizeof(Oid), true, 'i');
return PointerGetDatum(ary);
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.477 2006/01/05 10:07:45 petere Exp $
* $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.478 2006/01/08 07:00:25 neilc Exp $
*
* NOTES
* this is the "main" module of the postgres backend and
@ -55,6 +55,7 @@
#include "tcop/pquery.h"
#include "tcop/tcopprot.h"
#include "tcop/utility.h"
#include "utils/builtins.h"
#include "utils/flatfiles.h"
#include "utils/guc.h"
#include "utils/lsyscache.h"
@ -1308,7 +1309,8 @@ exec_parse_message(const char *query_string, /* string to execute */
commandTag,
querytree_list,
plantree_list,
param_list);
param_list,
false);
}
else
{
@ -1322,6 +1324,7 @@ exec_parse_message(const char *query_string, /* string to execute */
pstmt->query_list = querytree_list;
pstmt->plan_list = plantree_list;
pstmt->argtype_list = param_list;
pstmt->from_sql = false;
pstmt->context = unnamed_stmt_context;
/* Now the unnamed statement is complete and valid */
unnamed_stmt_pstmt = pstmt;

View File

@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.308 2005/12/28 01:30:01 tgl Exp $
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.309 2006/01/08 07:00:25 neilc Exp $
*
*-------------------------------------------------------------------------
*/
@ -53,6 +53,6 @@
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 200512271
#define CATALOG_VERSION_NO 200601081
#endif

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.389 2005/11/17 22:14:54 tgl Exp $
* $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.390 2006/01/08 07:00:25 neilc Exp $
*
* NOTES
* The script catalog/genbki.sh reads this file and generates .bki
@ -3617,6 +3617,8 @@ DATA(insert OID = 2508 ( pg_get_constraintdef PGNSP PGUID 12 f f t f s 2 25 "26
DESCR("constraint description with pretty-print option");
DATA(insert OID = 2509 ( pg_get_expr PGNSP PGUID 12 f f t f s 3 25 "25 26 16" _null_ _null_ _null_ pg_get_expr_ext - _null_ ));
DESCR("deparse an encoded expression with pretty-print option");
DATA(insert OID = 2510 ( pg_prepared_statement PGNSP PGUID 12 f f t t s 0 2249 "" _null_ _null_ _null_ pg_prepared_statement - _null_ ));
DESCR("get the prepared statements for this session");
/* non-persistent series generator */
DATA(insert OID = 1066 ( generate_series PGNSP PGUID 12 f f t t v 3 23 "23 23 23" _null_ _null_ _null_ generate_series_step_int4 - _null_ ));

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/pg_type.h,v 1.167 2005/11/22 18:17:30 momjian Exp $
* $PostgreSQL: pgsql/src/include/catalog/pg_type.h,v 1.168 2006/01/08 07:00:26 neilc Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
@ -406,6 +406,7 @@ DATA(insert OID = 1007 ( _int4 PGNSP PGUID -1 f b t \054 0 23 array_in array_
DATA(insert OID = 1008 ( _regproc PGNSP PGUID -1 f b t \054 0 24 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ ));
DATA(insert OID = 1009 ( _text PGNSP PGUID -1 f b t \054 0 25 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ ));
DATA(insert OID = 1028 ( _oid PGNSP PGUID -1 f b t \054 0 26 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ ));
#define OIDARRAYOID 1028
DATA(insert OID = 1010 ( _tid PGNSP PGUID -1 f b t \054 0 27 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ ));
DATA(insert OID = 1011 ( _xid PGNSP PGUID -1 f b t \054 0 28 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ ));
DATA(insert OID = 1012 ( _cid PGNSP PGUID -1 f b t \054 0 29 array_in array_out array_recv array_send - i x f 0 -1 0 _null_ _null_ ));

View File

@ -6,7 +6,7 @@
*
* Copyright (c) 2002-2005, PostgreSQL Global Development Group
*
* $PostgreSQL: pgsql/src/include/commands/prepare.h,v 1.16 2005/12/14 17:06:28 tgl Exp $
* $PostgreSQL: pgsql/src/include/commands/prepare.h,v 1.17 2006/01/08 07:00:26 neilc Exp $
*
*-------------------------------------------------------------------------
*/
@ -30,13 +30,16 @@
typedef struct
{
/* dynahash.c requires key to be first field */
char stmt_name[NAMEDATALEN];
char *query_string; /* text of query, or NULL */
const char *commandTag; /* command tag (a constant!), or NULL */
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 */
char stmt_name[NAMEDATALEN];
char *query_string; /* text of query, or NULL */
const char *commandTag; /* command tag (a constant!), or NULL */
List *query_list; /* list of queries, rewritten */
List *plan_list; /* list of plans */
List *argtype_list; /* list of parameter type OIDs */
TimestampTz prepare_time; /* the time when the stmt was prepared */
bool from_sql; /* stmt prepared via SQL, not
* FE/BE protocol? */
MemoryContext context; /* context containing this query */
} PreparedStatement;
@ -54,7 +57,8 @@ extern void StorePreparedStatement(const char *stmt_name,
const char *commandTag,
List *query_list,
List *plan_list,
List *argtype_list);
List *argtype_list,
bool from_sql);
extern PreparedStatement *FetchPreparedStatement(const char *stmt_name,
bool throwError);
extern void DropPreparedStatement(const char *stmt_name, bool showError);

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.268 2005/11/22 18:17:32 momjian Exp $
* $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.269 2006/01/08 07:00:26 neilc Exp $
*
*-------------------------------------------------------------------------
*/
@ -861,4 +861,7 @@ extern Datum pg_prepared_xact(PG_FUNCTION_ARGS);
/* catalog/pg_conversion.c */
extern Datum pg_convert_using(PG_FUNCTION_ARGS);
/* commands/prepare.c */
extern Datum pg_prepared_statement(PG_FUNCTION_ARGS);
#endif /* BUILTINS_H */

View File

@ -1,9 +1,22 @@
-- Regression tests for prepareable statements
PREPARE q1 AS SELECT 1;
-- Regression tests for prepareable statements. We query the content
-- of the pg_prepared_statements view as prepared statements are
-- created and removed.
SELECT name, statement, parameter_types FROM pg_prepared_statements;
name | statement | parameter_types
------+-----------+-----------------
(0 rows)
PREPARE q1 AS SELECT 1 AS a;
EXECUTE q1;
?column?
----------
1
a
---
1
(1 row)
SELECT name, statement, parameter_types FROM pg_prepared_statements;
name | statement | parameter_types
------+------------------------------+-----------------
q1 | PREPARE q1 AS SELECT 1 AS a; | {}
(1 row)
-- should fail
@ -18,12 +31,41 @@ EXECUTE q1;
2
(1 row)
PREPARE q2 AS SELECT 2 AS b;
SELECT name, statement, parameter_types FROM pg_prepared_statements;
name | statement | parameter_types
------+------------------------------+-----------------
q1 | PREPARE q1 AS SELECT 2; | {}
q2 | PREPARE q2 AS SELECT 2 AS b; | {}
(2 rows)
-- sql92 syntax
DEALLOCATE PREPARE q1;
SELECT name, statement, parameter_types FROM pg_prepared_statements;
name | statement | parameter_types
------+------------------------------+-----------------
q2 | PREPARE q2 AS SELECT 2 AS b; | {}
(1 row)
DEALLOCATE PREPARE q2;
-- the view should return the empty set again
SELECT name, statement, parameter_types FROM pg_prepared_statements;
name | statement | parameter_types
------+-----------+-----------------
(0 rows)
-- parameterized queries
PREPARE q2(text) AS
SELECT datname, datistemplate, datallowconn
FROM pg_database WHERE datname = $1;
SELECT name, statement, parameter_types FROM pg_prepared_statements;
name | statement | parameter_types
------+--------------------------------------------------------------------------------------------------------+-----------------
q2 | PREPARE q2(text) AS
SELECT datname, datistemplate, datallowconn
FROM pg_database WHERE datname = $1; | {25}
(1 row)
EXECUTE q2('regression');
datname | datistemplate | datallowconn
------------+---------------+--------------
@ -33,6 +75,17 @@ 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);
SELECT name, statement, parameter_types FROM pg_prepared_statements;
name | statement | parameter_types
------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+----------------------
q2 | PREPARE q2(text) AS
SELECT datname, datistemplate, datallowconn
FROM pg_database WHERE datname = $1; | {25}
q3 | 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); | {25,23,701,16,26,21}
(2 rows)
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
---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+---------

View File

@ -1280,6 +1280,7 @@ SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schem
pg_group | SELECT pg_authid.rolname AS groname, pg_authid.oid AS grosysid, ARRAY(SELECT pg_auth_members.member FROM pg_auth_members WHERE (pg_auth_members.roleid = pg_authid.oid)) AS grolist FROM pg_authid WHERE (NOT pg_authid.rolcanlogin);
pg_indexes | SELECT n.nspname AS schemaname, c.relname AS tablename, i.relname AS indexname, t.spcname AS "tablespace", pg_get_indexdef(i.oid) AS indexdef FROM ((((pg_index x JOIN pg_class c ON ((c.oid = x.indrelid))) JOIN pg_class i ON ((i.oid = x.indexrelid))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) LEFT JOIN pg_tablespace t ON ((t.oid = i.reltablespace))) WHERE ((c.relkind = 'r'::"char") AND (i.relkind = 'i'::"char"));
pg_locks | SELECT l.locktype, l."database", l.relation, l.page, l.tuple, l.transactionid, l.classid, l.objid, l.objsubid, l."transaction", l.pid, l."mode", l."granted" FROM pg_lock_status() l(locktype text, "database" oid, relation oid, page integer, tuple smallint, transactionid xid, classid oid, objid oid, objsubid smallint, "transaction" xid, pid integer, "mode" text, "granted" boolean);
pg_prepared_statements | SELECT p.name, p."statement", p.prepare_time, p.parameter_types, p.from_sql FROM pg_prepared_statement() p(name text, "statement" text, prepare_time timestamp with time zone, parameter_types oid[], from_sql boolean);
pg_prepared_xacts | SELECT p."transaction", p.gid, p."prepared", u.rolname AS "owner", d.datname AS "database" FROM ((pg_prepared_xact() p("transaction" xid, gid text, "prepared" timestamp with time zone, ownerid oid, dbid oid) LEFT JOIN pg_authid u ON ((p.ownerid = u.oid))) LEFT JOIN pg_database d ON ((p.dbid = d.oid)));
pg_roles | SELECT pg_authid.rolname, pg_authid.rolsuper, pg_authid.rolinherit, pg_authid.rolcreaterole, pg_authid.rolcreatedb, pg_authid.rolcatupdate, pg_authid.rolcanlogin, pg_authid.rolconnlimit, '********'::text AS rolpassword, pg_authid.rolvaliduntil, pg_authid.rolconfig, pg_authid.oid FROM pg_authid;
pg_rules | SELECT n.nspname AS schemaname, c.relname AS tablename, r.rulename, pg_get_ruledef(r.oid) AS definition FROM ((pg_rewrite r JOIN pg_class c ON ((c.oid = r.ev_class))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (r.rulename <> '_RETURN'::name);
@ -1320,7 +1321,7 @@ SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schem
shoelace_obsolete | SELECT shoelace.sl_name, shoelace.sl_avail, shoelace.sl_color, shoelace.sl_len, shoelace.sl_unit, shoelace.sl_len_cm FROM shoelace WHERE (NOT (EXISTS (SELECT shoe.shoename FROM shoe WHERE (shoe.slcolor = shoelace.sl_color))));
street | SELECT r.name, r.thepath, c.cname FROM ONLY road r, real_city c WHERE (c.outline ## r.thepath);
toyemp | SELECT emp.name, emp.age, emp."location", (12 * emp.salary) AS annualsal FROM emp;
(44 rows)
(45 rows)
SELECT tablename, rulename, definition FROM pg_rules
ORDER BY tablename, rulename;

View File

@ -1,8 +1,14 @@
-- Regression tests for prepareable statements
-- Regression tests for prepareable statements. We query the content
-- of the pg_prepared_statements view as prepared statements are
-- created and removed.
PREPARE q1 AS SELECT 1;
SELECT name, statement, parameter_types FROM pg_prepared_statements;
PREPARE q1 AS SELECT 1 AS a;
EXECUTE q1;
SELECT name, statement, parameter_types FROM pg_prepared_statements;
-- should fail
PREPARE q1 AS SELECT 2;
@ -11,19 +17,33 @@ DEALLOCATE q1;
PREPARE q1 AS SELECT 2;
EXECUTE q1;
PREPARE q2 AS SELECT 2 AS b;
SELECT name, statement, parameter_types FROM pg_prepared_statements;
-- sql92 syntax
DEALLOCATE PREPARE q1;
SELECT name, statement, parameter_types FROM pg_prepared_statements;
DEALLOCATE PREPARE q2;
-- the view should return the empty set again
SELECT name, statement, parameter_types FROM pg_prepared_statements;
-- parameterized queries
PREPARE q2(text) AS
SELECT datname, datistemplate, datallowconn
FROM pg_database WHERE datname = $1;
SELECT name, statement, parameter_types FROM pg_prepared_statements;
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);
SELECT name, statement, parameter_types FROM pg_prepared_statements;
EXECUTE q3('AAAAxx', 5::smallint, 10.5::float, false, 500::oid, 4::bigint);
-- too few params