1 /*-------------------------------------------------------------------------
2  *
3  * prepare.c
4  *	  Prepareable SQL statements via PREPARE, EXECUTE and DEALLOCATE
5  *
6  * This module also implements storage of prepared statements that are
7  * accessed via the extended FE/BE query protocol.
8  *
9  *
10  * Copyright (c) 2002-2017, PostgreSQL Global Development Group
11  *
12  * IDENTIFICATION
13  *	  src/backend/commands/prepare.c
14  *
15  *-------------------------------------------------------------------------
16  */
17 #include "postgres.h"
18 
19 #include <limits.h>
20 
21 #include "access/xact.h"
22 #include "catalog/pg_type.h"
23 #include "commands/createas.h"
24 #include "commands/prepare.h"
25 #include "miscadmin.h"
26 #include "nodes/nodeFuncs.h"
27 #include "parser/analyze.h"
28 #include "parser/parse_coerce.h"
29 #include "parser/parse_collate.h"
30 #include "parser/parse_expr.h"
31 #include "parser/parse_type.h"
32 #include "rewrite/rewriteHandler.h"
33 #include "tcop/pquery.h"
34 #include "tcop/utility.h"
35 #include "utils/builtins.h"
36 #include "utils/snapmgr.h"
37 #include "utils/timestamp.h"
38 
39 
40 /*
41  * The hash table in which prepared queries are stored. This is
42  * per-backend: query plans are not shared between backends.
43  * The keys for this hash table are the arguments to PREPARE and EXECUTE
44  * (statement names); the entries are PreparedStatement structs.
45  */
46 static HTAB *prepared_queries = NULL;
47 
48 static void InitQueryHashTable(void);
49 static ParamListInfo EvaluateParams(PreparedStatement *pstmt, List *params,
50 			   const char *queryString, EState *estate);
51 static Datum build_regtype_array(Oid *param_types, int num_params);
52 
53 /*
54  * Implements the 'PREPARE' utility statement.
55  */
56 void
PrepareQuery(PrepareStmt * stmt,const char * queryString,int stmt_location,int stmt_len)57 PrepareQuery(PrepareStmt *stmt, const char *queryString,
58 			 int stmt_location, int stmt_len)
59 {
60 	RawStmt    *rawstmt;
61 	CachedPlanSource *plansource;
62 	Oid		   *argtypes = NULL;
63 	int			nargs;
64 	Query	   *query;
65 	List	   *query_list;
66 	int			i;
67 
68 	/*
69 	 * Disallow empty-string statement name (conflicts with protocol-level
70 	 * unnamed statement).
71 	 */
72 	if (!stmt->name || stmt->name[0] == '\0')
73 		ereport(ERROR,
74 				(errcode(ERRCODE_INVALID_PSTATEMENT_DEFINITION),
75 				 errmsg("invalid statement name: must not be empty")));
76 
77 	/*
78 	 * Need to wrap the contained statement in a RawStmt node to pass it to
79 	 * parse analysis.
80 	 *
81 	 * Because parse analysis scribbles on the raw querytree, we must make a
82 	 * copy to ensure we don't modify the passed-in tree.  FIXME someday.
83 	 */
84 	rawstmt = makeNode(RawStmt);
85 	rawstmt->stmt = (Node *) copyObject(stmt->query);
86 	rawstmt->stmt_location = stmt_location;
87 	rawstmt->stmt_len = stmt_len;
88 
89 	/*
90 	 * Create the CachedPlanSource before we do parse analysis, since it needs
91 	 * to see the unmodified raw parse tree.
92 	 */
93 	plansource = CreateCachedPlan(rawstmt, queryString,
94 								  CreateCommandTag(stmt->query));
95 
96 	/* Transform list of TypeNames to array of type OIDs */
97 	nargs = list_length(stmt->argtypes);
98 
99 	if (nargs)
100 	{
101 		ParseState *pstate;
102 		ListCell   *l;
103 
104 		/*
105 		 * typenameTypeId wants a ParseState to carry the source query string.
106 		 * Is it worth refactoring its API to avoid this?
107 		 */
108 		pstate = make_parsestate(NULL);
109 		pstate->p_sourcetext = queryString;
110 
111 		argtypes = (Oid *) palloc(nargs * sizeof(Oid));
112 		i = 0;
113 
114 		foreach(l, stmt->argtypes)
115 		{
116 			TypeName   *tn = lfirst(l);
117 			Oid			toid = typenameTypeId(pstate, tn);
118 
119 			argtypes[i++] = toid;
120 		}
121 	}
122 
123 	/*
124 	 * Analyze the statement using these parameter types (any parameters
125 	 * passed in from above us will not be visible to it), allowing
126 	 * information about unknown parameters to be deduced from context.
127 	 */
128 	query = parse_analyze_varparams(rawstmt, queryString,
129 									&argtypes, &nargs);
130 
131 	/*
132 	 * Check that all parameter types were determined.
133 	 */
134 	for (i = 0; i < nargs; i++)
135 	{
136 		Oid			argtype = argtypes[i];
137 
138 		if (argtype == InvalidOid || argtype == UNKNOWNOID)
139 			ereport(ERROR,
140 					(errcode(ERRCODE_INDETERMINATE_DATATYPE),
141 					 errmsg("could not determine data type of parameter $%d",
142 							i + 1)));
143 	}
144 
145 	/*
146 	 * grammar only allows OptimizableStmt, so this check should be redundant
147 	 */
148 	switch (query->commandType)
149 	{
150 		case CMD_SELECT:
151 		case CMD_INSERT:
152 		case CMD_UPDATE:
153 		case CMD_DELETE:
154 			/* OK */
155 			break;
156 		default:
157 			ereport(ERROR,
158 					(errcode(ERRCODE_INVALID_PSTATEMENT_DEFINITION),
159 					 errmsg("utility statements cannot be prepared")));
160 			break;
161 	}
162 
163 	/* Rewrite the query. The result could be 0, 1, or many queries. */
164 	query_list = QueryRewrite(query);
165 
166 	/* Finish filling in the CachedPlanSource */
167 	CompleteCachedPlan(plansource,
168 					   query_list,
169 					   NULL,
170 					   argtypes,
171 					   nargs,
172 					   NULL,
173 					   NULL,
174 					   CURSOR_OPT_PARALLEL_OK,	/* allow parallel mode */
175 					   true);	/* fixed result */
176 
177 	/*
178 	 * Save the results.
179 	 */
180 	StorePreparedStatement(stmt->name,
181 						   plansource,
182 						   true);
183 }
184 
185 /*
186  * ExecuteQuery --- implement the 'EXECUTE' utility statement.
187  *
188  * This code also supports CREATE TABLE ... AS EXECUTE.  That case is
189  * indicated by passing a non-null intoClause.  The DestReceiver is already
190  * set up correctly for CREATE TABLE AS, but we still have to make a few
191  * other adjustments here.
192  *
193  * Note: this is one of very few places in the code that needs to deal with
194  * two query strings at once.  The passed-in queryString is that of the
195  * EXECUTE, which we might need for error reporting while processing the
196  * parameter expressions.  The query_string that we copy from the plan
197  * source is that of the original PREPARE.
198  */
199 void
ExecuteQuery(ExecuteStmt * stmt,IntoClause * intoClause,const char * queryString,ParamListInfo params,DestReceiver * dest,char * completionTag)200 ExecuteQuery(ExecuteStmt *stmt, IntoClause *intoClause,
201 			 const char *queryString, ParamListInfo params,
202 			 DestReceiver *dest, char *completionTag)
203 {
204 	PreparedStatement *entry;
205 	CachedPlan *cplan;
206 	List	   *plan_list;
207 	ParamListInfo paramLI = NULL;
208 	EState	   *estate = NULL;
209 	Portal		portal;
210 	char	   *query_string;
211 	int			eflags;
212 	long		count;
213 
214 	/* Look it up in the hash table */
215 	entry = FetchPreparedStatement(stmt->name, true);
216 
217 	/* Shouldn't find a non-fixed-result cached plan */
218 	if (!entry->plansource->fixed_result)
219 		elog(ERROR, "EXECUTE does not support variable-result cached plans");
220 
221 	/* Evaluate parameters, if any */
222 	if (entry->plansource->num_params > 0)
223 	{
224 		/*
225 		 * Need an EState to evaluate parameters; must not delete it till end
226 		 * of query, in case parameters are pass-by-reference.  Note that the
227 		 * passed-in "params" could possibly be referenced in the parameter
228 		 * expressions.
229 		 */
230 		estate = CreateExecutorState();
231 		estate->es_param_list_info = params;
232 		paramLI = EvaluateParams(entry, stmt->params,
233 								 queryString, estate);
234 	}
235 
236 	/* Create a new portal to run the query in */
237 	portal = CreateNewPortal();
238 	/* Don't display the portal in pg_cursors, it is for internal use only */
239 	portal->visible = false;
240 
241 	/* Copy the plan's saved query string into the portal's memory */
242 	query_string = MemoryContextStrdup(PortalGetHeapMemory(portal),
243 									   entry->plansource->query_string);
244 
245 	/* Replan if needed, and increment plan refcount for portal */
246 	cplan = GetCachedPlan(entry->plansource, paramLI, false, NULL);
247 	plan_list = cplan->stmt_list;
248 
249 	/*
250 	 * DO NOT add any logic that could possibly throw an error between
251 	 * GetCachedPlan and PortalDefineQuery, or you'll leak the plan refcount.
252 	 */
253 	PortalDefineQuery(portal,
254 					  NULL,
255 					  query_string,
256 					  entry->plansource->commandTag,
257 					  plan_list,
258 					  cplan);
259 
260 	/*
261 	 * For CREATE TABLE ... AS EXECUTE, we must verify that the prepared
262 	 * statement is one that produces tuples.  Currently we insist that it be
263 	 * a plain old SELECT.  In future we might consider supporting other
264 	 * things such as INSERT ... RETURNING, but there are a couple of issues
265 	 * to be settled first, notably how WITH NO DATA should be handled in such
266 	 * a case (do we really want to suppress execution?) and how to pass down
267 	 * the OID-determining eflags (PortalStart won't handle them in such a
268 	 * case, and for that matter it's not clear the executor will either).
269 	 *
270 	 * For CREATE TABLE ... AS EXECUTE, we also have to ensure that the proper
271 	 * eflags and fetch count are passed to PortalStart/PortalRun.
272 	 */
273 	if (intoClause)
274 	{
275 		PlannedStmt *pstmt;
276 
277 		if (list_length(plan_list) != 1)
278 			ereport(ERROR,
279 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
280 					 errmsg("prepared statement is not a SELECT")));
281 		pstmt = linitial_node(PlannedStmt, plan_list);
282 		if (pstmt->commandType != CMD_SELECT)
283 			ereport(ERROR,
284 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
285 					 errmsg("prepared statement is not a SELECT")));
286 
287 		/* Set appropriate eflags */
288 		eflags = GetIntoRelEFlags(intoClause);
289 
290 		/* And tell PortalRun whether to run to completion or not */
291 		if (intoClause->skipData)
292 			count = 0;
293 		else
294 			count = FETCH_ALL;
295 	}
296 	else
297 	{
298 		/* Plain old EXECUTE */
299 		eflags = 0;
300 		count = FETCH_ALL;
301 	}
302 
303 	/*
304 	 * Run the portal as appropriate.
305 	 */
306 	PortalStart(portal, paramLI, eflags, GetActiveSnapshot());
307 
308 	(void) PortalRun(portal, count, false, true, dest, dest, completionTag);
309 
310 	PortalDrop(portal, false);
311 
312 	if (estate)
313 		FreeExecutorState(estate);
314 
315 	/* No need to pfree other memory, MemoryContext will be reset */
316 }
317 
318 /*
319  * EvaluateParams: evaluate a list of parameters.
320  *
321  * pstmt: statement we are getting parameters for.
322  * params: list of given parameter expressions (raw parser output!)
323  * queryString: source text for error messages.
324  * estate: executor state to use.
325  *
326  * Returns a filled-in ParamListInfo -- this can later be passed to
327  * CreateQueryDesc(), which allows the executor to make use of the parameters
328  * during query execution.
329  */
330 static ParamListInfo
EvaluateParams(PreparedStatement * pstmt,List * params,const char * queryString,EState * estate)331 EvaluateParams(PreparedStatement *pstmt, List *params,
332 			   const char *queryString, EState *estate)
333 {
334 	Oid		   *param_types = pstmt->plansource->param_types;
335 	int			num_params = pstmt->plansource->num_params;
336 	int			nparams = list_length(params);
337 	ParseState *pstate;
338 	ParamListInfo paramLI;
339 	List	   *exprstates;
340 	ListCell   *l;
341 	int			i;
342 
343 	if (nparams != num_params)
344 		ereport(ERROR,
345 				(errcode(ERRCODE_SYNTAX_ERROR),
346 				 errmsg("wrong number of parameters for prepared statement \"%s\"",
347 						pstmt->stmt_name),
348 				 errdetail("Expected %d parameters but got %d.",
349 						   num_params, nparams)));
350 
351 	/* Quick exit if no parameters */
352 	if (num_params == 0)
353 		return NULL;
354 
355 	/*
356 	 * We have to run parse analysis for the expressions.  Since the parser is
357 	 * not cool about scribbling on its input, copy first.
358 	 */
359 	params = copyObject(params);
360 
361 	pstate = make_parsestate(NULL);
362 	pstate->p_sourcetext = queryString;
363 
364 	i = 0;
365 	foreach(l, params)
366 	{
367 		Node	   *expr = lfirst(l);
368 		Oid			expected_type_id = param_types[i];
369 		Oid			given_type_id;
370 
371 		expr = transformExpr(pstate, expr, EXPR_KIND_EXECUTE_PARAMETER);
372 
373 		given_type_id = exprType(expr);
374 
375 		expr = coerce_to_target_type(pstate, expr, given_type_id,
376 									 expected_type_id, -1,
377 									 COERCION_ASSIGNMENT,
378 									 COERCE_IMPLICIT_CAST,
379 									 -1);
380 
381 		if (expr == NULL)
382 			ereport(ERROR,
383 					(errcode(ERRCODE_DATATYPE_MISMATCH),
384 					 errmsg("parameter $%d of type %s cannot be coerced to the expected type %s",
385 							i + 1,
386 							format_type_be(given_type_id),
387 							format_type_be(expected_type_id)),
388 					 errhint("You will need to rewrite or cast the expression.")));
389 
390 		/* Take care of collations in the finished expression. */
391 		assign_expr_collations(pstate, expr);
392 
393 		lfirst(l) = expr;
394 		i++;
395 	}
396 
397 	/* Prepare the expressions for execution */
398 	exprstates = ExecPrepareExprList(params, estate);
399 
400 	paramLI = (ParamListInfo)
401 		palloc(offsetof(ParamListInfoData, params) +
402 			   num_params * sizeof(ParamExternData));
403 	/* we have static list of params, so no hooks needed */
404 	paramLI->paramFetch = NULL;
405 	paramLI->paramFetchArg = NULL;
406 	paramLI->parserSetup = NULL;
407 	paramLI->parserSetupArg = NULL;
408 	paramLI->numParams = num_params;
409 	paramLI->paramMask = NULL;
410 
411 	i = 0;
412 	foreach(l, exprstates)
413 	{
414 		ExprState  *n = (ExprState *) lfirst(l);
415 		ParamExternData *prm = &paramLI->params[i];
416 
417 		prm->ptype = param_types[i];
418 		prm->pflags = PARAM_FLAG_CONST;
419 		prm->value = ExecEvalExprSwitchContext(n,
420 											   GetPerTupleExprContext(estate),
421 											   &prm->isnull);
422 
423 		i++;
424 	}
425 
426 	return paramLI;
427 }
428 
429 
430 /*
431  * Initialize query hash table upon first use.
432  */
433 static void
InitQueryHashTable(void)434 InitQueryHashTable(void)
435 {
436 	HASHCTL		hash_ctl;
437 
438 	MemSet(&hash_ctl, 0, sizeof(hash_ctl));
439 
440 	hash_ctl.keysize = NAMEDATALEN;
441 	hash_ctl.entrysize = sizeof(PreparedStatement);
442 
443 	prepared_queries = hash_create("Prepared Queries",
444 								   32,
445 								   &hash_ctl,
446 								   HASH_ELEM);
447 }
448 
449 /*
450  * Store all the data pertaining to a query in the hash table using
451  * the specified key.  The passed CachedPlanSource should be "unsaved"
452  * in case we get an error here; we'll save it once we've created the hash
453  * table entry.
454  */
455 void
StorePreparedStatement(const char * stmt_name,CachedPlanSource * plansource,bool from_sql)456 StorePreparedStatement(const char *stmt_name,
457 					   CachedPlanSource *plansource,
458 					   bool from_sql)
459 {
460 	PreparedStatement *entry;
461 	TimestampTz cur_ts = GetCurrentStatementStartTimestamp();
462 	bool		found;
463 
464 	/* Initialize the hash table, if necessary */
465 	if (!prepared_queries)
466 		InitQueryHashTable();
467 
468 	/* Add entry to hash table */
469 	entry = (PreparedStatement *) hash_search(prepared_queries,
470 											  stmt_name,
471 											  HASH_ENTER,
472 											  &found);
473 
474 	/* Shouldn't get a duplicate entry */
475 	if (found)
476 		ereport(ERROR,
477 				(errcode(ERRCODE_DUPLICATE_PSTATEMENT),
478 				 errmsg("prepared statement \"%s\" already exists",
479 						stmt_name)));
480 
481 	/* Fill in the hash table entry */
482 	entry->plansource = plansource;
483 	entry->from_sql = from_sql;
484 	entry->prepare_time = cur_ts;
485 
486 	/* Now it's safe to move the CachedPlanSource to permanent memory */
487 	SaveCachedPlan(plansource);
488 }
489 
490 /*
491  * Lookup an existing query in the hash table. If the query does not
492  * actually exist, throw ereport(ERROR) or return NULL per second parameter.
493  *
494  * Note: this does not force the referenced plancache entry to be valid,
495  * since not all callers care.
496  */
497 PreparedStatement *
FetchPreparedStatement(const char * stmt_name,bool throwError)498 FetchPreparedStatement(const char *stmt_name, bool throwError)
499 {
500 	PreparedStatement *entry;
501 
502 	/*
503 	 * If the hash table hasn't been initialized, it can't be storing
504 	 * anything, therefore it couldn't possibly store our plan.
505 	 */
506 	if (prepared_queries)
507 		entry = (PreparedStatement *) hash_search(prepared_queries,
508 												  stmt_name,
509 												  HASH_FIND,
510 												  NULL);
511 	else
512 		entry = NULL;
513 
514 	if (!entry && throwError)
515 		ereport(ERROR,
516 				(errcode(ERRCODE_UNDEFINED_PSTATEMENT),
517 				 errmsg("prepared statement \"%s\" does not exist",
518 						stmt_name)));
519 
520 	return entry;
521 }
522 
523 /*
524  * Given a prepared statement, determine the result tupledesc it will
525  * produce.  Returns NULL if the execution will not return tuples.
526  *
527  * Note: the result is created or copied into current memory context.
528  */
529 TupleDesc
FetchPreparedStatementResultDesc(PreparedStatement * stmt)530 FetchPreparedStatementResultDesc(PreparedStatement *stmt)
531 {
532 	/*
533 	 * Since we don't allow prepared statements' result tupdescs to change,
534 	 * there's no need to worry about revalidating the cached plan here.
535 	 */
536 	Assert(stmt->plansource->fixed_result);
537 	if (stmt->plansource->resultDesc)
538 		return CreateTupleDescCopy(stmt->plansource->resultDesc);
539 	else
540 		return NULL;
541 }
542 
543 /*
544  * Given a prepared statement that returns tuples, extract the query
545  * targetlist.  Returns NIL if the statement doesn't have a determinable
546  * targetlist.
547  *
548  * Note: this is pretty ugly, but since it's only used in corner cases like
549  * Describe Statement on an EXECUTE command, we don't worry too much about
550  * efficiency.
551  */
552 List *
FetchPreparedStatementTargetList(PreparedStatement * stmt)553 FetchPreparedStatementTargetList(PreparedStatement *stmt)
554 {
555 	List	   *tlist;
556 
557 	/* Get the plan's primary targetlist */
558 	tlist = CachedPlanGetTargetList(stmt->plansource, NULL);
559 
560 	/* Copy into caller's context in case plan gets invalidated */
561 	return copyObject(tlist);
562 }
563 
564 /*
565  * Implements the 'DEALLOCATE' utility statement: deletes the
566  * specified plan from storage.
567  */
568 void
DeallocateQuery(DeallocateStmt * stmt)569 DeallocateQuery(DeallocateStmt *stmt)
570 {
571 	if (stmt->name)
572 		DropPreparedStatement(stmt->name, true);
573 	else
574 		DropAllPreparedStatements();
575 }
576 
577 /*
578  * Internal version of DEALLOCATE
579  *
580  * If showError is false, dropping a nonexistent statement is a no-op.
581  */
582 void
DropPreparedStatement(const char * stmt_name,bool showError)583 DropPreparedStatement(const char *stmt_name, bool showError)
584 {
585 	PreparedStatement *entry;
586 
587 	/* Find the query's hash table entry; raise error if wanted */
588 	entry = FetchPreparedStatement(stmt_name, showError);
589 
590 	if (entry)
591 	{
592 		/* Release the plancache entry */
593 		DropCachedPlan(entry->plansource);
594 
595 		/* Now we can remove the hash table entry */
596 		hash_search(prepared_queries, entry->stmt_name, HASH_REMOVE, NULL);
597 	}
598 }
599 
600 /*
601  * Drop all cached statements.
602  */
603 void
DropAllPreparedStatements(void)604 DropAllPreparedStatements(void)
605 {
606 	HASH_SEQ_STATUS seq;
607 	PreparedStatement *entry;
608 
609 	/* nothing cached */
610 	if (!prepared_queries)
611 		return;
612 
613 	/* walk over cache */
614 	hash_seq_init(&seq, prepared_queries);
615 	while ((entry = hash_seq_search(&seq)) != NULL)
616 	{
617 		/* Release the plancache entry */
618 		DropCachedPlan(entry->plansource);
619 
620 		/* Now we can remove the hash table entry */
621 		hash_search(prepared_queries, entry->stmt_name, HASH_REMOVE, NULL);
622 	}
623 }
624 
625 /*
626  * Implements the 'EXPLAIN EXECUTE' utility statement.
627  *
628  * "into" is NULL unless we are doing EXPLAIN CREATE TABLE AS EXECUTE,
629  * in which case executing the query should result in creating that table.
630  *
631  * Note: the passed-in queryString is that of the EXPLAIN EXECUTE,
632  * not the original PREPARE; we get the latter string from the plancache.
633  */
634 void
ExplainExecuteQuery(ExecuteStmt * execstmt,IntoClause * into,ExplainState * es,const char * queryString,ParamListInfo params,QueryEnvironment * queryEnv)635 ExplainExecuteQuery(ExecuteStmt *execstmt, IntoClause *into, ExplainState *es,
636 					const char *queryString, ParamListInfo params,
637 					QueryEnvironment *queryEnv)
638 {
639 	PreparedStatement *entry;
640 	const char *query_string;
641 	CachedPlan *cplan;
642 	List	   *plan_list;
643 	ListCell   *p;
644 	ParamListInfo paramLI = NULL;
645 	EState	   *estate = NULL;
646 	instr_time	planstart;
647 	instr_time	planduration;
648 
649 	INSTR_TIME_SET_CURRENT(planstart);
650 
651 	/* Look it up in the hash table */
652 	entry = FetchPreparedStatement(execstmt->name, true);
653 
654 	/* Shouldn't find a non-fixed-result cached plan */
655 	if (!entry->plansource->fixed_result)
656 		elog(ERROR, "EXPLAIN EXECUTE does not support variable-result cached plans");
657 
658 	query_string = entry->plansource->query_string;
659 
660 	/* Evaluate parameters, if any */
661 	if (entry->plansource->num_params)
662 	{
663 		/*
664 		 * Need an EState to evaluate parameters; must not delete it till end
665 		 * of query, in case parameters are pass-by-reference.  Note that the
666 		 * passed-in "params" could possibly be referenced in the parameter
667 		 * expressions.
668 		 */
669 		estate = CreateExecutorState();
670 		estate->es_param_list_info = params;
671 		paramLI = EvaluateParams(entry, execstmt->params,
672 								 queryString, estate);
673 	}
674 
675 	/* Replan if needed, and acquire a transient refcount */
676 	cplan = GetCachedPlan(entry->plansource, paramLI, true, queryEnv);
677 
678 	INSTR_TIME_SET_CURRENT(planduration);
679 	INSTR_TIME_SUBTRACT(planduration, planstart);
680 
681 	plan_list = cplan->stmt_list;
682 
683 	/* Explain each query */
684 	foreach(p, plan_list)
685 	{
686 		PlannedStmt *pstmt = lfirst_node(PlannedStmt, p);
687 
688 		if (pstmt->commandType != CMD_UTILITY)
689 			ExplainOnePlan(pstmt, into, es, query_string, paramLI, queryEnv,
690 						   &planduration);
691 		else
692 			ExplainOneUtility(pstmt->utilityStmt, into, es, query_string,
693 							  paramLI, queryEnv);
694 
695 		/* No need for CommandCounterIncrement, as ExplainOnePlan did it */
696 
697 		/* Separate plans with an appropriate separator */
698 		if (lnext(p) != NULL)
699 			ExplainSeparatePlans(es);
700 	}
701 
702 	if (estate)
703 		FreeExecutorState(estate);
704 
705 	ReleaseCachedPlan(cplan, true);
706 }
707 
708 /*
709  * This set returning function reads all the prepared statements and
710  * returns a set of (name, statement, prepare_time, param_types, from_sql).
711  */
712 Datum
pg_prepared_statement(PG_FUNCTION_ARGS)713 pg_prepared_statement(PG_FUNCTION_ARGS)
714 {
715 	ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
716 	TupleDesc	tupdesc;
717 	Tuplestorestate *tupstore;
718 	MemoryContext per_query_ctx;
719 	MemoryContext oldcontext;
720 
721 	/* check to see if caller supports us returning a tuplestore */
722 	if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
723 		ereport(ERROR,
724 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
725 				 errmsg("set-valued function called in context that cannot accept a set")));
726 	if (!(rsinfo->allowedModes & SFRM_Materialize))
727 		ereport(ERROR,
728 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
729 				 errmsg("materialize mode required, but it is not " \
730 						"allowed in this context")));
731 
732 	/* need to build tuplestore in query context */
733 	per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
734 	oldcontext = MemoryContextSwitchTo(per_query_ctx);
735 
736 	/*
737 	 * build tupdesc for result tuples. This must match the definition of the
738 	 * pg_prepared_statements view in system_views.sql
739 	 */
740 	tupdesc = CreateTemplateTupleDesc(5, false);
741 	TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name",
742 					   TEXTOID, -1, 0);
743 	TupleDescInitEntry(tupdesc, (AttrNumber) 2, "statement",
744 					   TEXTOID, -1, 0);
745 	TupleDescInitEntry(tupdesc, (AttrNumber) 3, "prepare_time",
746 					   TIMESTAMPTZOID, -1, 0);
747 	TupleDescInitEntry(tupdesc, (AttrNumber) 4, "parameter_types",
748 					   REGTYPEARRAYOID, -1, 0);
749 	TupleDescInitEntry(tupdesc, (AttrNumber) 5, "from_sql",
750 					   BOOLOID, -1, 0);
751 
752 	/*
753 	 * We put all the tuples into a tuplestore in one scan of the hashtable.
754 	 * This avoids any issue of the hashtable possibly changing between calls.
755 	 */
756 	tupstore =
757 		tuplestore_begin_heap(rsinfo->allowedModes & SFRM_Materialize_Random,
758 							  false, work_mem);
759 
760 	/* generate junk in short-term context */
761 	MemoryContextSwitchTo(oldcontext);
762 
763 	/* hash table might be uninitialized */
764 	if (prepared_queries)
765 	{
766 		HASH_SEQ_STATUS hash_seq;
767 		PreparedStatement *prep_stmt;
768 
769 		hash_seq_init(&hash_seq, prepared_queries);
770 		while ((prep_stmt = hash_seq_search(&hash_seq)) != NULL)
771 		{
772 			Datum		values[5];
773 			bool		nulls[5];
774 
775 			MemSet(nulls, 0, sizeof(nulls));
776 
777 			values[0] = CStringGetTextDatum(prep_stmt->stmt_name);
778 			values[1] = CStringGetTextDatum(prep_stmt->plansource->query_string);
779 			values[2] = TimestampTzGetDatum(prep_stmt->prepare_time);
780 			values[3] = build_regtype_array(prep_stmt->plansource->param_types,
781 											prep_stmt->plansource->num_params);
782 			values[4] = BoolGetDatum(prep_stmt->from_sql);
783 
784 			tuplestore_putvalues(tupstore, tupdesc, values, nulls);
785 		}
786 	}
787 
788 	/* clean up and return the tuplestore */
789 	tuplestore_donestoring(tupstore);
790 
791 	rsinfo->returnMode = SFRM_Materialize;
792 	rsinfo->setResult = tupstore;
793 	rsinfo->setDesc = tupdesc;
794 
795 	return (Datum) 0;
796 }
797 
798 /*
799  * This utility function takes a C array of Oids, and returns a Datum
800  * pointing to a one-dimensional Postgres array of regtypes. An empty
801  * array is returned as a zero-element array, not NULL.
802  */
803 static Datum
build_regtype_array(Oid * param_types,int num_params)804 build_regtype_array(Oid *param_types, int num_params)
805 {
806 	Datum	   *tmp_ary;
807 	ArrayType  *result;
808 	int			i;
809 
810 	tmp_ary = (Datum *) palloc(num_params * sizeof(Datum));
811 
812 	for (i = 0; i < num_params; i++)
813 		tmp_ary[i] = ObjectIdGetDatum(param_types[i]);
814 
815 	/* XXX: this hardcodes assumptions about the regtype type */
816 	result = construct_array(tmp_ary, num_params, REGTYPEOID, 4, true, 'i');
817 	return PointerGetDatum(result);
818 }
819