PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
prepare.c
Go to the documentation of this file.
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  */
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
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  */
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
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);
247  plan_list = cplan->stmt_list;
248 
249  /*
250  * For CREATE TABLE ... AS EXECUTE, we must verify that the prepared
251  * statement is one that produces tuples. Currently we insist that it be
252  * a plain old SELECT. In future we might consider supporting other
253  * things such as INSERT ... RETURNING, but there are a couple of issues
254  * to be settled first, notably how WITH NO DATA should be handled in such
255  * a case (do we really want to suppress execution?) and how to pass down
256  * the OID-determining eflags (PortalStart won't handle them in such a
257  * case, and for that matter it's not clear the executor will either).
258  *
259  * For CREATE TABLE ... AS EXECUTE, we also have to ensure that the proper
260  * eflags and fetch count are passed to PortalStart/PortalRun.
261  */
262  if (intoClause)
263  {
264  PlannedStmt *pstmt;
265 
266  if (list_length(plan_list) != 1)
267  ereport(ERROR,
268  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
269  errmsg("prepared statement is not a SELECT")));
270  pstmt = castNode(PlannedStmt, linitial(plan_list));
271  if (pstmt->commandType != CMD_SELECT)
272  ereport(ERROR,
273  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
274  errmsg("prepared statement is not a SELECT")));
275 
276  /* Set appropriate eflags */
277  eflags = GetIntoRelEFlags(intoClause);
278 
279  /* And tell PortalRun whether to run to completion or not */
280  if (intoClause->skipData)
281  count = 0;
282  else
283  count = FETCH_ALL;
284  }
285  else
286  {
287  /* Plain old EXECUTE */
288  eflags = 0;
289  count = FETCH_ALL;
290  }
291 
292  PortalDefineQuery(portal,
293  NULL,
294  query_string,
295  entry->plansource->commandTag,
296  plan_list,
297  cplan);
298 
299  /*
300  * Run the portal as appropriate.
301  */
302  PortalStart(portal, paramLI, eflags, GetActiveSnapshot());
303 
304  (void) PortalRun(portal, count, false, true, dest, dest, completionTag);
305 
306  PortalDrop(portal, false);
307 
308  if (estate)
309  FreeExecutorState(estate);
310 
311  /* No need to pfree other memory, MemoryContext will be reset */
312 }
313 
314 /*
315  * EvaluateParams: evaluate a list of parameters.
316  *
317  * pstmt: statement we are getting parameters for.
318  * params: list of given parameter expressions (raw parser output!)
319  * queryString: source text for error messages.
320  * estate: executor state to use.
321  *
322  * Returns a filled-in ParamListInfo -- this can later be passed to
323  * CreateQueryDesc(), which allows the executor to make use of the parameters
324  * during query execution.
325  */
326 static ParamListInfo
328  const char *queryString, EState *estate)
329 {
330  Oid *param_types = pstmt->plansource->param_types;
331  int num_params = pstmt->plansource->num_params;
332  int nparams = list_length(params);
333  ParseState *pstate;
334  ParamListInfo paramLI;
335  List *exprstates;
336  ListCell *l;
337  int i;
338 
339  if (nparams != num_params)
340  ereport(ERROR,
341  (errcode(ERRCODE_SYNTAX_ERROR),
342  errmsg("wrong number of parameters for prepared statement \"%s\"",
343  pstmt->stmt_name),
344  errdetail("Expected %d parameters but got %d.",
345  num_params, nparams)));
346 
347  /* Quick exit if no parameters */
348  if (num_params == 0)
349  return NULL;
350 
351  /*
352  * We have to run parse analysis for the expressions. Since the parser is
353  * not cool about scribbling on its input, copy first.
354  */
355  params = (List *) copyObject(params);
356 
357  pstate = make_parsestate(NULL);
358  pstate->p_sourcetext = queryString;
359 
360  i = 0;
361  foreach(l, params)
362  {
363  Node *expr = lfirst(l);
364  Oid expected_type_id = param_types[i];
365  Oid given_type_id;
366 
367  expr = transformExpr(pstate, expr, EXPR_KIND_EXECUTE_PARAMETER);
368 
369  given_type_id = exprType(expr);
370 
371  expr = coerce_to_target_type(pstate, expr, given_type_id,
372  expected_type_id, -1,
375  -1);
376 
377  if (expr == NULL)
378  ereport(ERROR,
379  (errcode(ERRCODE_DATATYPE_MISMATCH),
380  errmsg("parameter $%d of type %s cannot be coerced to the expected type %s",
381  i + 1,
382  format_type_be(given_type_id),
383  format_type_be(expected_type_id)),
384  errhint("You will need to rewrite or cast the expression.")));
385 
386  /* Take care of collations in the finished expression. */
387  assign_expr_collations(pstate, expr);
388 
389  lfirst(l) = expr;
390  i++;
391  }
392 
393  /* Prepare the expressions for execution */
394  exprstates = ExecPrepareExprList(params, estate);
395 
396  paramLI = (ParamListInfo)
398  num_params * sizeof(ParamExternData));
399  /* we have static list of params, so no hooks needed */
400  paramLI->paramFetch = NULL;
401  paramLI->paramFetchArg = NULL;
402  paramLI->parserSetup = NULL;
403  paramLI->parserSetupArg = NULL;
404  paramLI->numParams = num_params;
405  paramLI->paramMask = NULL;
406 
407  i = 0;
408  foreach(l, exprstates)
409  {
410  ExprState *n = (ExprState *) lfirst(l);
411  ParamExternData *prm = &paramLI->params[i];
412 
413  prm->ptype = param_types[i];
414  prm->pflags = PARAM_FLAG_CONST;
416  GetPerTupleExprContext(estate),
417  &prm->isnull);
418 
419  i++;
420  }
421 
422  return paramLI;
423 }
424 
425 
426 /*
427  * Initialize query hash table upon first use.
428  */
429 static void
431 {
432  HASHCTL hash_ctl;
433 
434  MemSet(&hash_ctl, 0, sizeof(hash_ctl));
435 
436  hash_ctl.keysize = NAMEDATALEN;
437  hash_ctl.entrysize = sizeof(PreparedStatement);
438 
439  prepared_queries = hash_create("Prepared Queries",
440  32,
441  &hash_ctl,
442  HASH_ELEM);
443 }
444 
445 /*
446  * Store all the data pertaining to a query in the hash table using
447  * the specified key. The passed CachedPlanSource should be "unsaved"
448  * in case we get an error here; we'll save it once we've created the hash
449  * table entry.
450  */
451 void
452 StorePreparedStatement(const char *stmt_name,
453  CachedPlanSource *plansource,
454  bool from_sql)
455 {
456  PreparedStatement *entry;
458  bool found;
459 
460  /* Initialize the hash table, if necessary */
461  if (!prepared_queries)
463 
464  /* Add entry to hash table */
465  entry = (PreparedStatement *) hash_search(prepared_queries,
466  stmt_name,
467  HASH_ENTER,
468  &found);
469 
470  /* Shouldn't get a duplicate entry */
471  if (found)
472  ereport(ERROR,
473  (errcode(ERRCODE_DUPLICATE_PSTATEMENT),
474  errmsg("prepared statement \"%s\" already exists",
475  stmt_name)));
476 
477  /* Fill in the hash table entry */
478  entry->plansource = plansource;
479  entry->from_sql = from_sql;
480  entry->prepare_time = cur_ts;
481 
482  /* Now it's safe to move the CachedPlanSource to permanent memory */
483  SaveCachedPlan(plansource);
484 }
485 
486 /*
487  * Lookup an existing query in the hash table. If the query does not
488  * actually exist, throw ereport(ERROR) or return NULL per second parameter.
489  *
490  * Note: this does not force the referenced plancache entry to be valid,
491  * since not all callers care.
492  */
494 FetchPreparedStatement(const char *stmt_name, bool throwError)
495 {
496  PreparedStatement *entry;
497 
498  /*
499  * If the hash table hasn't been initialized, it can't be storing
500  * anything, therefore it couldn't possibly store our plan.
501  */
502  if (prepared_queries)
503  entry = (PreparedStatement *) hash_search(prepared_queries,
504  stmt_name,
505  HASH_FIND,
506  NULL);
507  else
508  entry = NULL;
509 
510  if (!entry && throwError)
511  ereport(ERROR,
512  (errcode(ERRCODE_UNDEFINED_PSTATEMENT),
513  errmsg("prepared statement \"%s\" does not exist",
514  stmt_name)));
515 
516  return entry;
517 }
518 
519 /*
520  * Given a prepared statement, determine the result tupledesc it will
521  * produce. Returns NULL if the execution will not return tuples.
522  *
523  * Note: the result is created or copied into current memory context.
524  */
525 TupleDesc
527 {
528  /*
529  * Since we don't allow prepared statements' result tupdescs to change,
530  * there's no need to worry about revalidating the cached plan here.
531  */
533  if (stmt->plansource->resultDesc)
535  else
536  return NULL;
537 }
538 
539 /*
540  * Given a prepared statement that returns tuples, extract the query
541  * targetlist. Returns NIL if the statement doesn't have a determinable
542  * targetlist.
543  *
544  * Note: this is pretty ugly, but since it's only used in corner cases like
545  * Describe Statement on an EXECUTE command, we don't worry too much about
546  * efficiency.
547  */
548 List *
550 {
551  List *tlist;
552 
553  /* Get the plan's primary targetlist */
554  tlist = CachedPlanGetTargetList(stmt->plansource);
555 
556  /* Copy into caller's context in case plan gets invalidated */
557  return (List *) copyObject(tlist);
558 }
559 
560 /*
561  * Implements the 'DEALLOCATE' utility statement: deletes the
562  * specified plan from storage.
563  */
564 void
566 {
567  if (stmt->name)
568  DropPreparedStatement(stmt->name, true);
569  else
571 }
572 
573 /*
574  * Internal version of DEALLOCATE
575  *
576  * If showError is false, dropping a nonexistent statement is a no-op.
577  */
578 void
579 DropPreparedStatement(const char *stmt_name, bool showError)
580 {
581  PreparedStatement *entry;
582 
583  /* Find the query's hash table entry; raise error if wanted */
584  entry = FetchPreparedStatement(stmt_name, showError);
585 
586  if (entry)
587  {
588  /* Release the plancache entry */
589  DropCachedPlan(entry->plansource);
590 
591  /* Now we can remove the hash table entry */
592  hash_search(prepared_queries, entry->stmt_name, HASH_REMOVE, NULL);
593  }
594 }
595 
596 /*
597  * Drop all cached statements.
598  */
599 void
601 {
602  HASH_SEQ_STATUS seq;
603  PreparedStatement *entry;
604 
605  /* nothing cached */
606  if (!prepared_queries)
607  return;
608 
609  /* walk over cache */
610  hash_seq_init(&seq, prepared_queries);
611  while ((entry = hash_seq_search(&seq)) != NULL)
612  {
613  /* Release the plancache entry */
614  DropCachedPlan(entry->plansource);
615 
616  /* Now we can remove the hash table entry */
617  hash_search(prepared_queries, entry->stmt_name, HASH_REMOVE, NULL);
618  }
619 }
620 
621 /*
622  * Implements the 'EXPLAIN EXECUTE' utility statement.
623  *
624  * "into" is NULL unless we are doing EXPLAIN CREATE TABLE AS EXECUTE,
625  * in which case executing the query should result in creating that table.
626  *
627  * Note: the passed-in queryString is that of the EXPLAIN EXECUTE,
628  * not the original PREPARE; we get the latter string from the plancache.
629  */
630 void
632  const char *queryString, ParamListInfo params)
633 {
634  PreparedStatement *entry;
635  const char *query_string;
636  CachedPlan *cplan;
637  List *plan_list;
638  ListCell *p;
639  ParamListInfo paramLI = NULL;
640  EState *estate = NULL;
641  instr_time planstart;
642  instr_time planduration;
643 
644  INSTR_TIME_SET_CURRENT(planstart);
645 
646  /* Look it up in the hash table */
647  entry = FetchPreparedStatement(execstmt->name, true);
648 
649  /* Shouldn't find a non-fixed-result cached plan */
650  if (!entry->plansource->fixed_result)
651  elog(ERROR, "EXPLAIN EXECUTE does not support variable-result cached plans");
652 
653  query_string = entry->plansource->query_string;
654 
655  /* Evaluate parameters, if any */
656  if (entry->plansource->num_params)
657  {
658  /*
659  * Need an EState to evaluate parameters; must not delete it till end
660  * of query, in case parameters are pass-by-reference. Note that the
661  * passed-in "params" could possibly be referenced in the parameter
662  * expressions.
663  */
664  estate = CreateExecutorState();
665  estate->es_param_list_info = params;
666  paramLI = EvaluateParams(entry, execstmt->params,
667  queryString, estate);
668  }
669 
670  /* Replan if needed, and acquire a transient refcount */
671  cplan = GetCachedPlan(entry->plansource, paramLI, true);
672 
673  INSTR_TIME_SET_CURRENT(planduration);
674  INSTR_TIME_SUBTRACT(planduration, planstart);
675 
676  plan_list = cplan->stmt_list;
677 
678  /* Explain each query */
679  foreach(p, plan_list)
680  {
681  PlannedStmt *pstmt = castNode(PlannedStmt, lfirst(p));
682 
683  if (pstmt->commandType != CMD_UTILITY)
684  ExplainOnePlan(pstmt, into, es, query_string, paramLI, &planduration);
685  else
686  ExplainOneUtility(pstmt->utilityStmt, into, es, query_string, paramLI);
687 
688  /* No need for CommandCounterIncrement, as ExplainOnePlan did it */
689 
690  /* Separate plans with an appropriate separator */
691  if (lnext(p) != NULL)
693  }
694 
695  if (estate)
696  FreeExecutorState(estate);
697 
698  ReleaseCachedPlan(cplan, true);
699 }
700 
701 /*
702  * This set returning function reads all the prepared statements and
703  * returns a set of (name, statement, prepare_time, param_types, from_sql).
704  */
705 Datum
707 {
708  ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
709  TupleDesc tupdesc;
710  Tuplestorestate *tupstore;
711  MemoryContext per_query_ctx;
712  MemoryContext oldcontext;
713 
714  /* check to see if caller supports us returning a tuplestore */
715  if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
716  ereport(ERROR,
717  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
718  errmsg("set-valued function called in context that cannot accept a set")));
719  if (!(rsinfo->allowedModes & SFRM_Materialize))
720  ereport(ERROR,
721  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
722  errmsg("materialize mode required, but it is not " \
723  "allowed in this context")));
724 
725  /* need to build tuplestore in query context */
726  per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
727  oldcontext = MemoryContextSwitchTo(per_query_ctx);
728 
729  /*
730  * build tupdesc for result tuples. This must match the definition of the
731  * pg_prepared_statements view in system_views.sql
732  */
733  tupdesc = CreateTemplateTupleDesc(5, false);
734  TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name",
735  TEXTOID, -1, 0);
736  TupleDescInitEntry(tupdesc, (AttrNumber) 2, "statement",
737  TEXTOID, -1, 0);
738  TupleDescInitEntry(tupdesc, (AttrNumber) 3, "prepare_time",
739  TIMESTAMPTZOID, -1, 0);
740  TupleDescInitEntry(tupdesc, (AttrNumber) 4, "parameter_types",
741  REGTYPEARRAYOID, -1, 0);
742  TupleDescInitEntry(tupdesc, (AttrNumber) 5, "from_sql",
743  BOOLOID, -1, 0);
744 
745  /*
746  * We put all the tuples into a tuplestore in one scan of the hashtable.
747  * This avoids any issue of the hashtable possibly changing between calls.
748  */
749  tupstore =
751  false, work_mem);
752 
753  /* generate junk in short-term context */
754  MemoryContextSwitchTo(oldcontext);
755 
756  /* hash table might be uninitialized */
757  if (prepared_queries)
758  {
759  HASH_SEQ_STATUS hash_seq;
760  PreparedStatement *prep_stmt;
761 
762  hash_seq_init(&hash_seq, prepared_queries);
763  while ((prep_stmt = hash_seq_search(&hash_seq)) != NULL)
764  {
765  Datum values[5];
766  bool nulls[5];
767 
768  MemSet(nulls, 0, sizeof(nulls));
769 
770  values[0] = CStringGetTextDatum(prep_stmt->stmt_name);
771  values[1] = CStringGetTextDatum(prep_stmt->plansource->query_string);
772  values[2] = TimestampTzGetDatum(prep_stmt->prepare_time);
773  values[3] = build_regtype_array(prep_stmt->plansource->param_types,
774  prep_stmt->plansource->num_params);
775  values[4] = BoolGetDatum(prep_stmt->from_sql);
776 
777  tuplestore_putvalues(tupstore, tupdesc, values, nulls);
778  }
779  }
780 
781  /* clean up and return the tuplestore */
782  tuplestore_donestoring(tupstore);
783 
784  rsinfo->returnMode = SFRM_Materialize;
785  rsinfo->setResult = tupstore;
786  rsinfo->setDesc = tupdesc;
787 
788  return (Datum) 0;
789 }
790 
791 /*
792  * This utility function takes a C array of Oids, and returns a Datum
793  * pointing to a one-dimensional Postgres array of regtypes. An empty
794  * array is returned as a zero-element array, not NULL.
795  */
796 static Datum
797 build_regtype_array(Oid *param_types, int num_params)
798 {
799  Datum *tmp_ary;
800  ArrayType *result;
801  int i;
802 
803  tmp_ary = (Datum *) palloc(num_params * sizeof(Datum));
804 
805  for (i = 0; i < num_params; i++)
806  tmp_ary[i] = ObjectIdGetDatum(param_types[i]);
807 
808  /* XXX: this hardcodes assumptions about the regtype type */
809  result = construct_array(tmp_ary, num_params, REGTYPEOID, 4, true, 'i');
810  return PointerGetDatum(result);
811 }
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, Datum *values, bool *isnull)
Definition: tuplestore.c:735
#define TIMESTAMPTZOID
Definition: pg_type.h:521
void ExplainOneUtility(Node *utilityStmt, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params)
Definition: explain.c:385
ParamExternData params[FLEXIBLE_ARRAY_MEMBER]
Definition: params.h:76
Datum value
Definition: params.h:56
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition: tupdesc.c:141
#define IsA(nodeptr, _type_)
Definition: nodes.h:557
List * QueryRewrite(Query *parsetree)
static Datum ExecEvalExprSwitchContext(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:281
int errhint(const char *fmt,...)
Definition: elog.c:987
void * parserSetupArg
Definition: params.h:73
Portal CreateNewPortal(void)
Definition: portalmem.c:230
void PortalStart(Portal portal, ParamListInfo params, int eflags, Snapshot snapshot)
Definition: pquery.c:442
void ExplainSeparatePlans(ExplainState *es)
Definition: explain.c:3389
#define HASH_ELEM
Definition: hsearch.h:87
bool visible
Definition: portal.h:191
static void InitQueryHashTable(void)
Definition: prepare.c:430
void PortalDefineQuery(Portal portal, const char *prepStmtName, const char *sourceText, const char *commandTag, List *stmts, CachedPlan *cplan)
Definition: portalmem.c:277
#define castNode(_type_, nodeptr)
Definition: nodes.h:575
const char * commandTag
Definition: plancache.h:84
#define TEXTOID
Definition: pg_type.h:324
CachedPlanSource * plansource
Definition: prepare.h:31
int64 TimestampTz
Definition: timestamp.h:39
#define PointerGetDatum(X)
Definition: postgres.h:562
struct timeval instr_time
Definition: instr_time.h:147
Node * transformExpr(ParseState *pstate, Node *expr, ParseExprKind exprKind)
Definition: parse_expr.c:147
#define tuplestore_donestoring(state)
Definition: tuplestore.h:60
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
ArrayType * construct_array(Datum *elems, int nelems, Oid elmtype, int elmlen, bool elmbyval, char elmalign)
Definition: arrayfuncs.c:3306
Snapshot GetActiveSnapshot(void)
Definition: snapmgr.c:834
Size entrysize
Definition: hsearch.h:73
Definition: nodes.h:506
bool PortalRun(Portal portal, long count, bool isTopLevel, bool run_once, DestReceiver *dest, DestReceiver *altdest, char *completionTag)
Definition: pquery.c:685
int errcode(int sqlerrcode)
Definition: elog.c:575
Query * parse_analyze_varparams(RawStmt *parseTree, const char *sourceText, Oid **paramTypes, int *numParams)
Definition: analyze.c:127
#define MemSet(start, val, len)
Definition: c.h:857
char * format_type_be(Oid type_oid)
Definition: format_type.c:94
return result
Definition: formatting.c:1618
ParserSetupHook parserSetup
Definition: params.h:72
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:885
bool skipData
Definition: primnodes.h:115
struct ParamListInfoData * ParamListInfo
Definition: params.h:62
unsigned int Oid
Definition: postgres_ext.h:31
#define REGTYPEOID
Definition: pg_type.h:577
void ExecuteQuery(ExecuteStmt *stmt, IntoClause *intoClause, const char *queryString, ParamListInfo params, DestReceiver *dest, char *completionTag)
Definition: prepare.c:200
ParseState * make_parsestate(ParseState *parentParseState)
Definition: parse_node.c:44
TupleDesc resultDesc
Definition: plancache.h:91
void * copyObject(const void *from)
Definition: copyfuncs.c:4619
#define NAMEDATALEN
void assign_expr_collations(ParseState *pstate, Node *expr)
static HTAB * prepared_queries
Definition: prepare.c:46
void FreeExecutorState(EState *estate)
Definition: execUtils.c:173
#define GetPerTupleExprContext(estate)
Definition: executor.h:456
void * paramFetchArg
Definition: params.h:71
void DeallocateQuery(DeallocateStmt *stmt)
Definition: prepare.c:565
Definition: dynahash.c:193
int GetIntoRelEFlags(IntoClause *intoClause)
Definition: createas.c:391
ParamFetchHook paramFetch
Definition: params.h:70
char stmt_name[NAMEDATALEN]
Definition: prepare.h:30
#define linitial(l)
Definition: pg_list.h:110
#define ObjectIdGetDatum(X)
Definition: postgres.h:513
#define ERROR
Definition: elog.h:43
CachedPlan * GetCachedPlan(CachedPlanSource *plansource, ParamListInfo boundParams, bool useResOwner)
Definition: plancache.c:1131
#define INSTR_TIME_SUBTRACT(x, y)
Definition: instr_time.h:167
Node * coerce_to_target_type(ParseState *pstate, Node *expr, Oid exprtype, Oid targettype, int32 targettypmod, CoercionContext ccontext, CoercionForm cformat, int location)
Definition: parse_coerce.c:77
#define TimestampTzGetDatum(X)
Definition: timestamp.h:32
Oid * param_types
Definition: plancache.h:85
Node * stmt
Definition: parsenodes.h:1376
int errdetail(const char *fmt,...)
Definition: elog.c:873
CachedPlanSource * CreateCachedPlan(RawStmt *raw_parse_tree, const char *query_string, const char *commandTag)
Definition: plancache.c:151
Node * utilityStmt
Definition: plannodes.h:83
void ReleaseCachedPlan(CachedPlan *plan, bool useResOwner)
Definition: plancache.c:1252
struct Bitmapset * paramMask
Definition: params.h:75
const char * p_sourcetext
Definition: parse_node.h:167
void PrepareQuery(PrepareStmt *stmt, const char *queryString, int stmt_location, int stmt_len)
Definition: prepare.c:57
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition: tupdesc.c:493
#define lnext(lc)
Definition: pg_list.h:105
#define ereport(elevel, rest)
Definition: elog.h:122
const char * CreateCommandTag(Node *parsetree)
Definition: utility.c:2024
EState * CreateExecutorState(void)
Definition: execUtils.c:77
List * ExecPrepareExprList(List *nodes, EState *estate)
Definition: execExpr.c:511
struct ParamExternData ParamExternData
static Datum build_regtype_array(Oid *param_types, int num_params)
Definition: prepare.c:797
Tuplestorestate * tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes)
Definition: tuplestore.c:316
HTAB * hash_create(const char *tabname, long nelem, HASHCTL *info, int flags)
Definition: dynahash.c:301
uintptr_t Datum
Definition: postgres.h:372
CmdType commandType
Definition: plannodes.h:45
TupleDesc FetchPreparedStatementResultDesc(PreparedStatement *stmt)
Definition: prepare.c:526
int stmt_len
Definition: parsenodes.h:1378
Size keysize
Definition: hsearch.h:72
int work_mem
Definition: globals.c:112
int stmt_location
Definition: parsenodes.h:1377
void StorePreparedStatement(const char *stmt_name, CachedPlanSource *plansource, bool from_sql)
Definition: prepare.c:452
#define BoolGetDatum(X)
Definition: postgres.h:408
#define InvalidOid
Definition: postgres_ext.h:36
List * FetchPreparedStatementTargetList(PreparedStatement *stmt)
Definition: prepare.c:549
void SaveCachedPlan(CachedPlanSource *plansource)
Definition: plancache.c:440
int allowedModes
Definition: execnodes.h:267
TimestampTz prepare_time
Definition: prepare.h:33
CmdType commandType
Definition: parsenodes.h:103
SetFunctionReturnMode returnMode
Definition: execnodes.h:269
#define makeNode(_type_)
Definition: nodes.h:554
void ExplainOnePlan(PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params, const instr_time *planduration)
Definition: explain.c:461
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
char * name
Definition: parsenodes.h:3226
#define lfirst(lc)
Definition: pg_list.h:106
void CompleteCachedPlan(CachedPlanSource *plansource, List *querytree_list, MemoryContext querytree_context, Oid *param_types, int num_params, ParserSetupHook parserSetup, void *parserSetupArg, int cursor_options, bool fixed_result)
Definition: plancache.c:324
Node * query
Definition: parsenodes.h:3228
uint16 pflags
Definition: params.h:58
const char * query_string
Definition: plancache.h:83
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:42
static int list_length(const List *l)
Definition: pg_list.h:89
void ExplainExecuteQuery(ExecuteStmt *execstmt, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params)
Definition: prepare.c:631
#define PortalGetHeapMemory(portal)
Definition: portal.h:204
List * argtypes
Definition: parsenodes.h:3227
List * CachedPlanGetTargetList(CachedPlanSource *plansource)
Definition: plancache.c:1421
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1353
#define BOOLOID
Definition: pg_type.h:288
MemoryContext ecxt_per_query_memory
Definition: execnodes.h:201
TupleDesc CreateTemplateTupleDesc(int natts, bool hasoid)
Definition: tupdesc.c:41
static ParamListInfo EvaluateParams(PreparedStatement *pstmt, List *params, const char *queryString, EState *estate)
Definition: prepare.c:327
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1343
#define UNKNOWNOID
Definition: pg_type.h:427
#define INSTR_TIME_SET_CURRENT(t)
Definition: instr_time.h:153
Tuplestorestate * setResult
Definition: execnodes.h:272
static Datum values[MAXATTR]
Definition: bootstrap.c:162
#define REGTYPEARRAYOID
Definition: pg_type.h:592
ExprContext * econtext
Definition: execnodes.h:265
#define CURSOR_OPT_PARALLEL_OK
Definition: parsenodes.h:2579
TupleDesc setDesc
Definition: execnodes.h:273
void * palloc(Size size)
Definition: mcxt.c:849
int errmsg(const char *fmt,...)
Definition: elog.c:797
void PortalDrop(Portal portal, bool isTopCommit)
Definition: portalmem.c:461
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1064
int i
char * name
Definition: parsenodes.h:3240
#define CStringGetTextDatum(s)
Definition: builtins.h:91
ParamListInfo es_param_list_info
Definition: execnodes.h:431
void DropCachedPlan(CachedPlanSource *plansource)
Definition: plancache.c:485
#define PG_FUNCTION_ARGS
Definition: fmgr.h:158
List * params
Definition: parsenodes.h:3241
List * stmt_list
Definition: plancache.h:132
#define elog
Definition: elog.h:219
PreparedStatement * FetchPreparedStatement(const char *stmt_name, bool throwError)
Definition: prepare.c:494
Datum pg_prepared_statement(PG_FUNCTION_ARGS)
Definition: prepare.c:706
Definition: pg_list.h:45
bool isnull
Definition: params.h:57
int16 AttrNumber
Definition: attnum.h:21
#define offsetof(type, field)
Definition: c.h:555
#define PARAM_FLAG_CONST
Definition: params.h:52
void DropAllPreparedStatements(void)
Definition: prepare.c:600
TimestampTz GetCurrentStatementStartTimestamp(void)
Definition: xact.c:717
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition: parse_type.c:274
#define FETCH_ALL
Definition: parsenodes.h:2614
void DropPreparedStatement(const char *stmt_name, bool showError)
Definition: prepare.c:579