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