OSDN Git Service

Add a new system view, pg_prepared_statements, that can be used to
authorNeil Conway <neilc@samurai.com>
Sun, 8 Jan 2006 07:00:27 +0000 (07:00 +0000)
committerNeil Conway <neilc@samurai.com>
Sun, 8 Jan 2006 07:00:27 +0000 (07:00 +0000)
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.

13 files changed:
doc/src/sgml/catalogs.sgml
doc/src/sgml/ref/prepare.sgml
src/backend/catalog/system_views.sql
src/backend/commands/prepare.c
src/backend/tcop/postgres.c
src/include/catalog/catversion.h
src/include/catalog/pg_proc.h
src/include/catalog/pg_type.h
src/include/commands/prepare.h
src/include/utils/builtins.h
src/test/regress/expected/prepare.out
src/test/regress/expected/rules.out
src/test/regress/sql/prepare.sql

index cfd8b8d..624b5df 100644 (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">
      </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>
      </row>
 
  </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>
 
index d0abc49..51c3985 100644 (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">
index 4ffb8ac..a186c33 100644 (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 
index 1ee955e..ccf8c29 100644 (file)
  * 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);
+}
index e38e66a..0fe8ee0 100644 (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;
index a7bad3d..6eb5f72 100644 (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
index 824f7a3..7b78e78 100644 (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_ ));
index 4b7b7c2..c6ca59c 100644 (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_ ));
index 5076774..503f27e 100644 (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 $
  *
  *-------------------------------------------------------------------------
  */
 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);
index 4d13499..97fbfdc 100644 (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 */
index 43fd8ec..5461619 100644 (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 
 ---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+---------
index 2c8070d..67616b7 100644 (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;
index fc69243..95db2a0 100644 (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