10
10
* Copyright (c) 2002-2005, PostgreSQL Global Development Group
11
11
*
12
12
* IDENTIFICATION
13
- * $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.44 2005/12/14 17:06:27 tgl Exp $
13
+ * $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.45 2006/01/08 07:00:25 neilc Exp $
14
14
*
15
15
*-------------------------------------------------------------------------
16
16
*/
17
17
#include "postgres.h"
18
18
19
+ #include "access/heapam.h"
20
+ #include "catalog/pg_type.h"
19
21
#include "commands/explain.h"
20
22
#include "commands/prepare.h"
21
23
#include "executor/executor.h"
22
- #include "utils/guc.h"
24
+ #include "funcapi.h"
25
+ #include "parser/parsetree.h"
23
26
#include "optimizer/planner.h"
24
27
#include "rewrite/rewriteHandler.h"
25
28
#include "tcop/pquery.h"
26
29
#include "tcop/tcopprot.h"
27
30
#include "tcop/utility.h"
31
+ #include "utils/builtins.h"
32
+ #include "utils/guc.h"
28
33
#include "utils/hsearch.h"
29
34
#include "utils/memutils.h"
30
35
@@ -40,6 +45,7 @@ static HTAB *prepared_queries = NULL;
40
45
static void InitQueryHashTable (void );
41
46
static ParamListInfo EvaluateParams (EState * estate ,
42
47
List * params , List * argtypes );
48
+ static Datum build_oid_array (List * oid_list );
43
49
44
50
/*
45
51
* Implements the 'PREPARE' utility statement.
@@ -114,7 +120,8 @@ PrepareQuery(PrepareStmt *stmt)
114
120
commandTag ,
115
121
query_list ,
116
122
plan_list ,
117
- stmt -> argtype_oids );
123
+ stmt -> argtype_oids ,
124
+ true);
118
125
}
119
126
120
127
/*
@@ -298,7 +305,8 @@ StorePreparedStatement(const char *stmt_name,
298
305
const char * commandTag ,
299
306
List * query_list ,
300
307
List * plan_list ,
301
- List * argtype_list )
308
+ List * argtype_list ,
309
+ bool from_sql )
302
310
{
303
311
PreparedStatement * entry ;
304
312
MemoryContext oldcxt ,
@@ -361,6 +369,8 @@ StorePreparedStatement(const char *stmt_name,
361
369
entry -> plan_list = plan_list ;
362
370
entry -> argtype_list = argtype_list ;
363
371
entry -> context = entrycxt ;
372
+ entry -> prepare_time = GetCurrentTimestamp ();
373
+ entry -> from_sql = from_sql ;
364
374
365
375
MemoryContextSwitchTo (oldcxt );
366
376
}
@@ -383,7 +393,7 @@ FetchPreparedStatement(const char *stmt_name, bool throwError)
383
393
{
384
394
/*
385
395
* We can't just use the statement name as supplied by the user: the
386
- * hash package is picky enough that it needs to be NULL -padded out to
396
+ * hash package is picky enough that it needs to be NUL -padded out to
387
397
* the appropriate length to work correctly.
388
398
*/
389
399
StrNCpy (key , stmt_name , sizeof (key ));
@@ -661,3 +671,125 @@ ExplainExecuteQuery(ExplainStmt *stmt, ParamListInfo params,
661
671
if (estate )
662
672
FreeExecutorState (estate );
663
673
}
674
+
675
+ /*
676
+ * This set returning function reads all the prepared statements and
677
+ * returns a set of (name, statement, prepare_time, param_types).
678
+ */
679
+ Datum
680
+ pg_prepared_statement (PG_FUNCTION_ARGS )
681
+ {
682
+ FuncCallContext * funcctx ;
683
+ HASH_SEQ_STATUS * hash_seq ;
684
+ PreparedStatement * prep_stmt ;
685
+
686
+ /* stuff done only on the first call of the function */
687
+ if (SRF_IS_FIRSTCALL ())
688
+ {
689
+ TupleDesc tupdesc ;
690
+ MemoryContext oldcontext ;
691
+
692
+ /* create a function context for cross-call persistence */
693
+ funcctx = SRF_FIRSTCALL_INIT ();
694
+
695
+ /*
696
+ * switch to memory context appropriate for multiple function
697
+ * calls
698
+ */
699
+ oldcontext = MemoryContextSwitchTo (funcctx -> multi_call_memory_ctx );
700
+
701
+ /* allocate memory for user context */
702
+ if (prepared_queries )
703
+ {
704
+ hash_seq = (HASH_SEQ_STATUS * ) palloc (sizeof (HASH_SEQ_STATUS ));
705
+ hash_seq_init (hash_seq , prepared_queries );
706
+ funcctx -> user_fctx = (void * ) hash_seq ;
707
+ }
708
+ else
709
+ funcctx -> user_fctx = NULL ;
710
+
711
+ /*
712
+ * build tupdesc for result tuples. This must match the
713
+ * definition of the pg_prepared_statements view in
714
+ * system_views.sql
715
+ */
716
+ tupdesc = CreateTemplateTupleDesc (5 , false);
717
+ TupleDescInitEntry (tupdesc , (AttrNumber ) 1 , "name" ,
718
+ TEXTOID , -1 , 0 );
719
+ TupleDescInitEntry (tupdesc , (AttrNumber ) 2 , "statement" ,
720
+ TEXTOID , -1 , 0 );
721
+ TupleDescInitEntry (tupdesc , (AttrNumber ) 3 , "prepare_time" ,
722
+ TIMESTAMPTZOID , -1 , 0 );
723
+ TupleDescInitEntry (tupdesc , (AttrNumber ) 4 , "parameter_types" ,
724
+ OIDARRAYOID , -1 , 0 );
725
+ TupleDescInitEntry (tupdesc , (AttrNumber ) 5 , "from_sql" ,
726
+ BOOLOID , -1 , 0 );
727
+
728
+ funcctx -> tuple_desc = BlessTupleDesc (tupdesc );
729
+ MemoryContextSwitchTo (oldcontext );
730
+ }
731
+
732
+ /* stuff done on every call of the function */
733
+ funcctx = SRF_PERCALL_SETUP ();
734
+ hash_seq = (HASH_SEQ_STATUS * ) funcctx -> user_fctx ;
735
+
736
+ /* if the hash table is uninitialized, we're done */
737
+ if (hash_seq == NULL )
738
+ SRF_RETURN_DONE (funcctx );
739
+
740
+ prep_stmt = hash_seq_search (hash_seq );
741
+ if (prep_stmt )
742
+ {
743
+ Datum result ;
744
+ HeapTuple tuple ;
745
+ Datum values [5 ];
746
+ bool nulls [5 ];
747
+
748
+ MemSet (nulls , 0 , sizeof (nulls ));
749
+
750
+ values [0 ] = DirectFunctionCall1 (textin ,
751
+ CStringGetDatum (prep_stmt -> stmt_name ));
752
+
753
+ if (prep_stmt -> query_string == NULL )
754
+ nulls [1 ] = true;
755
+ else
756
+ values [1 ] = DirectFunctionCall1 (textin ,
757
+ CStringGetDatum (prep_stmt -> query_string ));
758
+
759
+ values [2 ] = TimestampTzGetDatum (prep_stmt -> prepare_time );
760
+ values [3 ] = build_oid_array (prep_stmt -> argtype_list );
761
+ values [4 ] = BoolGetDatum (prep_stmt -> from_sql );
762
+
763
+ tuple = heap_form_tuple (funcctx -> tuple_desc , values , nulls );
764
+ result = HeapTupleGetDatum (tuple );
765
+ SRF_RETURN_NEXT (funcctx , result );
766
+ }
767
+
768
+ SRF_RETURN_DONE (funcctx );
769
+ }
770
+
771
+ /*
772
+ * This utility function takes a List of Oids, and returns a Datum
773
+ * pointing to a Postgres array containing those OIDs. The empty list
774
+ * is returned as a zero-element array, not NULL.
775
+ */
776
+ static Datum
777
+ build_oid_array (List * oid_list )
778
+ {
779
+ ListCell * lc ;
780
+ int len ;
781
+ int i ;
782
+ Datum * tmp_ary ;
783
+ ArrayType * ary ;
784
+
785
+ len = list_length (oid_list );
786
+ tmp_ary = (Datum * ) palloc (len * sizeof (Datum ));
787
+
788
+ i = 0 ;
789
+ foreach (lc , oid_list )
790
+ tmp_ary [i ++ ] = ObjectIdGetDatum (lfirst_oid (lc ));
791
+
792
+ /* XXX: this hardcodes assumptions about the OID type... */
793
+ ary = construct_array (tmp_ary , len , OIDOID , sizeof (Oid ), true, 'i' );
794
+ return PointerGetDatum (ary );
795
+ }
0 commit comments