On Tue, 2006-01-03 at 18:00 -0500, Neil Conway wrote:
> Anyway, if there was a reasonably cheap way to present the query strings 
> of protocol-level and SQL prepared statements in the same manner, I 
> think we should definitely do so. Since there doesn't appear to be one, 
> I'm content to just use the query string as sent by the user. I'll post 
> a revised patch that does that soon.

Attached is the patch I applied to HEAD that uses the query string
supplied by the client, without any rewriting.

-Neil

============================================================
*** doc/src/sgml/catalogs.sgml	29fbade056e00ee4a48ba6a3f686627f62a103cf
--- doc/src/sgml/catalogs.sgml	f265188b9a381a6c2e67f94290b56f9dc993f5d1
***************
*** 4373,4378 ****
--- 4373,4383 ----
       </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>
***************
*** 4778,4783 ****
--- 4783,4883 ----
  
   </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>
  
============================================================
*** doc/src/sgml/ref/prepare.sgml	17fce269c43549b6ffa7bf3d5770da9fbdf18896
--- doc/src/sgml/ref/prepare.sgml	98824b3ad9ac4ffa50677f3b8ac821f8a1c84e16
***************
*** 145,150 ****
--- 145,155 ----
     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">
============================================================
*** src/backend/catalog/system_views.sql	307260ff7bc30a48c0c60a40d4130f70310ebff2
--- src/backend/catalog/system_views.sql	7b92550bbcaf9d0ee99c12527f7785385cfeefe7
***************
*** 156,161 ****
--- 156,167 ----
           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 
============================================================
*** src/backend/commands/prepare.c	3c1a8b677a84566407472a0b7b85b4cb86587956
--- src/backend/commands/prepare.c	dc237de8d42ca2cd72d75e3b9bf64b8786702e5a
***************
*** 16,30 ****
   */
  #include "postgres.h"
  
  #include "commands/explain.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"
  
--- 16,35 ----
   */
  #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 "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,45 ****
--- 45,51 ----
  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,120 ****
  						   commandTag,
  						   query_list,
  						   plan_list,
! 						   stmt->argtype_oids);
  }
  
  /*
--- 120,127 ----
  						   commandTag,
  						   query_list,
  						   plan_list,
! 						   stmt->argtype_oids,
! 						   true);
  }
  
  /*
***************
*** 298,304 ****
  					   const char *commandTag,
  					   List *query_list,
  					   List *plan_list,
! 					   List *argtype_list)
  {
  	PreparedStatement *entry;
  	MemoryContext oldcxt,
--- 305,312 ----
  					   const char *commandTag,
  					   List *query_list,
  					   List *plan_list,
! 					   List *argtype_list,
! 					   bool from_sql)
  {
  	PreparedStatement *entry;
  	MemoryContext oldcxt,
***************
*** 361,366 ****
--- 369,376 ----
  	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,389 ****
  	{
  		/*
  		 * 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.
  		 */
  		StrNCpy(key, stmt_name, sizeof(key));
--- 393,399 ----
  	{
  		/*
  		 * We can't just use the statement name as supplied by the user: the
! 		 * 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,663 ****
--- 671,795 ----
  	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);
+ }
============================================================
*** src/backend/tcop/postgres.c	f7e0f0dfaefca6014bb740974b51674d9856af52
--- src/backend/tcop/postgres.c	7e0c12bb20c7c728cb3c75a3b9fa3216cbb930c4
***************
*** 55,60 ****
--- 55,61 ----
  #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,1314 ****
  							   commandTag,
  							   querytree_list,
  							   plantree_list,
! 							   param_list);
  	}
  	else
  	{
--- 1309,1316 ----
  							   commandTag,
  							   querytree_list,
  							   plantree_list,
! 							   param_list,
! 							   false);
  	}
  	else
  	{
***************
*** 1322,1327 ****
--- 1324,1330 ----
  		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;
============================================================
*** src/include/catalog/catversion.h	a927f31e147ee53ba1556ece5c1274ad51d3ac90
--- src/include/catalog/catversion.h	ec1699040aae8697aac9fca28606a491e794bead
***************
*** 53,58 ****
   */
  
  /*							yyyymmddN */
! #define CATALOG_VERSION_NO	200512271
  
  #endif
--- 53,58 ----
   */
  
  /*							yyyymmddN */
! #define CATALOG_VERSION_NO	200601081
  
  #endif
============================================================
*** src/include/catalog/pg_proc.h	cf6670bbb53ec82df8cef94c7816568e84f76649
--- src/include/catalog/pg_proc.h	30a03ca195666dbb6c2ce4c9276c59c85bf733a3
***************
*** 3617,3622 ****
--- 3617,3624 ----
  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_ ));
============================================================
*** src/include/catalog/pg_type.h	8ec7dd1d4090cf8d0e42e8e942be80a242663181
--- src/include/catalog/pg_type.h	b2c605634dd3fff9823efc37bffdc3df638c5e4d
***************
*** 406,411 ****
--- 406,412 ----
  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_ ));
============================================================
*** src/include/commands/prepare.h	6efc9215b98662a9c339ca3c4e00565039d6d1af
--- src/include/commands/prepare.h	0edc3f720309bfdedcd06ea718a04e76a46479d0
***************
*** 30,42 ****
  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 */
  } PreparedStatement;
  
  
--- 30,45 ----
  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, 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,60 ****
  					   const char *commandTag,
  					   List *query_list,
  					   List *plan_list,
! 					   List *argtype_list);
  extern PreparedStatement *FetchPreparedStatement(const char *stmt_name,
  					   bool throwError);
  extern void DropPreparedStatement(const char *stmt_name, bool showError);
--- 57,64 ----
  					   const char *commandTag,
  					   List *query_list,
  					   List *plan_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);
============================================================
*** src/include/utils/builtins.h	59e351f3d080f64a8f9c60208697d98be3a74cc0
--- src/include/utils/builtins.h	435078a846fa3528c3f72253440c25979e4f90cc
***************
*** 861,864 ****
--- 861,867 ----
  /* 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 */
============================================================
*** src/test/regress/expected/prepare.out	65183ee54b3fae638559a548c5326f0ad3f7ad17
--- src/test/regress/expected/prepare.out	ac00879338b4a595a7115ff49820258b9fea4556
***************
*** 1,11 ****
! -- 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 "q1" already exists
--- 1,24 ----
! -- 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;
!  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
  PREPARE q1 AS SELECT 2;
  ERROR:  prepared statement "q1" already exists
***************
*** 18,29 ****
--- 31,71 ----
          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,38 ****
--- 75,91 ----
  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 
  ---------+---------+-----+------+-----+--------+---------+----------+-------------+-----------+----------+-----+------+----------+----------+---------
============================================================
*** src/test/regress/expected/rules.out	50f1bbe53e81493d4e3ecd6f38ffedfdf78ba115
--- src/test/regress/expected/rules.out	d2b7b350c3d01bd98ee6ceaa0e92acb34c2380f6
***************
*** 1280,1285 ****
--- 1280,1286 ----
   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,1326 ****
   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)
  
  SELECT tablename, rulename, definition FROM pg_rules 
  	ORDER BY tablename, rulename;
--- 1321,1327 ----
   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;
! (45 rows)
  
  SELECT tablename, rulename, definition FROM pg_rules 
  	ORDER BY tablename, rulename;
============================================================
*** src/test/regress/sql/prepare.sql	77e19c33d5c686ea3013cefc80d4df7b997cc7b2
--- src/test/regress/sql/prepare.sql	90bc73b518b0d7ef0c1ede82d5ae088392ea3910
***************
*** 1,8 ****
! -- Regression tests for prepareable statements
  
! PREPARE q1 AS SELECT 1;
  EXECUTE q1;
  
  -- should fail
  PREPARE q1 AS SELECT 2;
  
--- 1,14 ----
! -- 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;
! 
! 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,29 ****
--- 17,49 ----
  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
---------------------------(end of broadcast)---------------------------
TIP 9: In versions below 8.0, the planner will ignore your desire to
       choose an index scan if your joining column's datatypes do not
       match

Reply via email to