aboutsummaryrefslogtreecommitdiff
path: root/src/backend/commands/prepare.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/commands/prepare.c')
-rw-r--r--src/backend/commands/prepare.c151
1 files changed, 79 insertions, 72 deletions
diff --git a/src/backend/commands/prepare.c b/src/backend/commands/prepare.c
index 6b7c11a1894..d5ec457732a 100644
--- a/src/backend/commands/prepare.c
+++ b/src/backend/commands/prepare.c
@@ -10,7 +10,7 @@
* Copyright (c) 2002-2006, PostgreSQL Global Development Group
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.66 2006/10/04 00:29:51 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.66.2.1 2007/04/26 23:24:56 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -21,7 +21,7 @@
#include "catalog/pg_type.h"
#include "commands/explain.h"
#include "commands/prepare.h"
-#include "funcapi.h"
+#include "miscadmin.h"
#include "rewrite/rewriteHandler.h"
#include "tcop/pquery.h"
#include "tcop/tcopprot.h"
@@ -674,91 +674,98 @@ ExplainExecuteQuery(ExplainStmt *stmt, ParamListInfo params,
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();
+ ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
+ TupleDesc tupdesc;
+ Tuplestorestate *tupstore;
+ MemoryContext per_query_ctx;
+ MemoryContext oldcontext;
+
+ /* check to see if caller supports us returning a tuplestore */
+ if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("set-valued function called in context that cannot accept a set")));
+ if (!(rsinfo->allowedModes & SFRM_Materialize))
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("materialize mode required, but it is not " \
+ "allowed in this context")));
- /*
- * switch to memory context appropriate for multiple function calls
- */
- oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
+ /* need to build tuplestore in query context */
+ per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
+ oldcontext = MemoryContextSwitchTo(per_query_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",
+ REGTYPEARRAYOID, -1, 0);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 5, "from_sql",
+ BOOLOID, -1, 0);
- /*
- * 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",
- REGTYPEARRAYOID, -1, 0);
- TupleDescInitEntry(tupdesc, (AttrNumber) 5, "from_sql",
- BOOLOID, -1, 0);
-
- funcctx->tuple_desc = BlessTupleDesc(tupdesc);
- MemoryContextSwitchTo(oldcontext);
- }
+ /*
+ * We put all the tuples into a tuplestore in one scan of the hashtable.
+ * This avoids any issue of the hashtable possibly changing between calls.
+ */
+ tupstore = tuplestore_begin_heap(true, false, work_mem);
- /* stuff done on every call of the function */
- funcctx = SRF_PERCALL_SETUP();
- hash_seq = (HASH_SEQ_STATUS *) funcctx->user_fctx;
+ /* hash table might be uninitialized */
+ if (prepared_queries)
+ {
+ HASH_SEQ_STATUS hash_seq;
+ PreparedStatement *prep_stmt;
- /* if the hash table is uninitialized, we're done */
- if (hash_seq == NULL)
- SRF_RETURN_DONE(funcctx);
+ hash_seq_init(&hash_seq, prepared_queries);
+ while ((prep_stmt = hash_seq_search(&hash_seq)) != NULL)
+ {
+ HeapTuple tuple;
+ Datum values[5];
+ bool nulls[5];
- prep_stmt = hash_seq_search(hash_seq);
- if (prep_stmt)
- {
- Datum result;
- HeapTuple tuple;
- Datum values[5];
- bool nulls[5];
+ /* generate junk in short-term context */
+ MemoryContextSwitchTo(oldcontext);
- MemSet(nulls, 0, sizeof(nulls));
+ MemSet(nulls, 0, sizeof(nulls));
- values[0] = DirectFunctionCall1(textin,
+ values[0] = DirectFunctionCall1(textin,
CStringGetDatum(prep_stmt->stmt_name));
- if (prep_stmt->query_string == NULL)
- nulls[1] = true;
- else
- values[1] = DirectFunctionCall1(textin,
+ 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_regtype_array(prep_stmt->argtype_list);
- values[4] = BoolGetDatum(prep_stmt->from_sql);
+ values[2] = TimestampTzGetDatum(prep_stmt->prepare_time);
+ values[3] = build_regtype_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);
+ tuple = heap_form_tuple(tupdesc, values, nulls);
+
+ /* switch to appropriate context while storing the tuple */
+ MemoryContextSwitchTo(per_query_ctx);
+ tuplestore_puttuple(tupstore, tuple);
+ }
}
- SRF_RETURN_DONE(funcctx);
+ /* clean up and return the tuplestore */
+ tuplestore_donestoring(tupstore);
+
+ MemoryContextSwitchTo(oldcontext);
+
+ rsinfo->returnMode = SFRM_Materialize;
+ rsinfo->setResult = tupstore;
+ rsinfo->setDesc = tupdesc;
+
+ return (Datum) 0;
}
/*