PostgreSQL Source Code  git master
prepare.c File Reference
#include "postgres.h"
#include <limits.h>
#include "access/xact.h"
#include "catalog/pg_type.h"
#include "commands/createas.h"
#include "commands/prepare.h"
#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
#include "parser/analyze.h"
#include "parser/parse_coerce.h"
#include "parser/parse_collate.h"
#include "parser/parse_expr.h"
#include "parser/parse_type.h"
#include "rewrite/rewriteHandler.h"
#include "tcop/pquery.h"
#include "tcop/utility.h"
#include "utils/builtins.h"
#include "utils/snapmgr.h"
#include "utils/timestamp.h"
Include dependency graph for prepare.c:

Go to the source code of this file.

Functions

static void InitQueryHashTable (void)
 
static ParamListInfo EvaluateParams (ParseState *pstate, PreparedStatement *pstmt, List *params, EState *estate)
 
static Datum build_regtype_array (Oid *param_types, int num_params)
 
void PrepareQuery (ParseState *pstate, PrepareStmt *stmt, int stmt_location, int stmt_len)
 
void ExecuteQuery (ParseState *pstate, ExecuteStmt *stmt, IntoClause *intoClause, ParamListInfo params, DestReceiver *dest, QueryCompletion *qc)
 
void StorePreparedStatement (const char *stmt_name, CachedPlanSource *plansource, bool from_sql)
 
PreparedStatementFetchPreparedStatement (const char *stmt_name, bool throwError)
 
TupleDesc FetchPreparedStatementResultDesc (PreparedStatement *stmt)
 
ListFetchPreparedStatementTargetList (PreparedStatement *stmt)
 
void DeallocateQuery (DeallocateStmt *stmt)
 
void DropPreparedStatement (const char *stmt_name, bool showError)
 
void DropAllPreparedStatements (void)
 
void ExplainExecuteQuery (ExecuteStmt *execstmt, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params, QueryEnvironment *queryEnv)
 
Datum pg_prepared_statement (PG_FUNCTION_ARGS)
 

Variables

static HTABprepared_queries = NULL
 

Function Documentation

◆ build_regtype_array()

static Datum build_regtype_array ( Oid param_types,
int  num_params 
)
static

Definition at line 797 of file prepare.c.

References construct_array(), i, ObjectIdGetDatum, palloc(), and PointerGetDatum.

Referenced by pg_prepared_statement().

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,
810  4, true, TYPALIGN_INT);
811  return PointerGetDatum(result);
812 }
#define PointerGetDatum(X)
Definition: postgres.h:600
ArrayType * construct_array(Datum *elems, int nelems, Oid elmtype, int elmlen, bool elmbyval, char elmalign)
Definition: arrayfuncs.c:3319
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
uintptr_t Datum
Definition: postgres.h:411
void * palloc(Size size)
Definition: mcxt.c:1062
int i

◆ DeallocateQuery()

void DeallocateQuery ( DeallocateStmt stmt)

Definition at line 539 of file prepare.c.

References DropAllPreparedStatements(), DropPreparedStatement(), and DeallocateStmt::name.

Referenced by standard_ProcessUtility().

540 {
541  if (stmt->name)
542  DropPreparedStatement(stmt->name, true);
543  else
545 }
void DropAllPreparedStatements(void)
Definition: prepare.c:574
void DropPreparedStatement(const char *stmt_name, bool showError)
Definition: prepare.c:553

◆ DropAllPreparedStatements()

void DropAllPreparedStatements ( void  )

Definition at line 574 of file prepare.c.

References DropCachedPlan(), HASH_REMOVE, hash_search(), hash_seq_init(), hash_seq_search(), PreparedStatement::plansource, and PreparedStatement::stmt_name.

Referenced by DeallocateQuery(), and DiscardAll().

575 {
576  HASH_SEQ_STATUS seq;
577  PreparedStatement *entry;
578 
579  /* nothing cached */
580  if (!prepared_queries)
581  return;
582 
583  /* walk over cache */
585  while ((entry = hash_seq_search(&seq)) != NULL)
586  {
587  /* Release the plancache entry */
588  DropCachedPlan(entry->plansource);
589 
590  /* Now we can remove the hash table entry */
592  }
593 }
CachedPlanSource * plansource
Definition: prepare.h:31
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:954
static HTAB * prepared_queries
Definition: prepare.c:46
char stmt_name[NAMEDATALEN]
Definition: prepare.h:30
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1436
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1426
void DropCachedPlan(CachedPlanSource *plansource)
Definition: plancache.c:498

◆ DropPreparedStatement()

void DropPreparedStatement ( const char *  stmt_name,
bool  showError 
)

Definition at line 553 of file prepare.c.

References DropCachedPlan(), FetchPreparedStatement(), HASH_REMOVE, hash_search(), PreparedStatement::plansource, and PreparedStatement::stmt_name.

Referenced by DeallocateQuery(), and PostgresMain().

554 {
555  PreparedStatement *entry;
556 
557  /* Find the query's hash table entry; raise error if wanted */
558  entry = FetchPreparedStatement(stmt_name, showError);
559 
560  if (entry)
561  {
562  /* Release the plancache entry */
563  DropCachedPlan(entry->plansource);
564 
565  /* Now we can remove the hash table entry */
567  }
568 }
CachedPlanSource * plansource
Definition: prepare.h:31
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:954
static HTAB * prepared_queries
Definition: prepare.c:46
char stmt_name[NAMEDATALEN]
Definition: prepare.h:30
void DropCachedPlan(CachedPlanSource *plansource)
Definition: plancache.c:498
PreparedStatement * FetchPreparedStatement(const char *stmt_name, bool throwError)
Definition: prepare.c:468

◆ EvaluateParams()

static ParamListInfo EvaluateParams ( ParseState pstate,
PreparedStatement pstmt,
List params,
EState estate 
)
static

Definition at line 315 of file prepare.c.

References assign_expr_collations(), COERCE_IMPLICIT_CAST, coerce_to_target_type(), COERCION_ASSIGNMENT, copyObject, ereport, errcode(), errdetail(), errhint(), errmsg(), ERROR, ExecEvalExprSwitchContext(), ExecPrepareExprList(), EXPR_KIND_EXECUTE_PARAMETER, exprLocation(), exprType(), format_type_be(), GetPerTupleExprContext, i, ParamExternData::isnull, lfirst, list_length(), makeParamList(), CachedPlanSource::num_params, PARAM_FLAG_CONST, CachedPlanSource::param_types, ParamListInfoData::params, parser_errposition(), ParamExternData::pflags, PreparedStatement::plansource, ParamExternData::ptype, PreparedStatement::stmt_name, transformExpr(), and ParamExternData::value.

Referenced by ExecuteQuery(), and ExplainExecuteQuery().

317 {
318  Oid *param_types = pstmt->plansource->param_types;
319  int num_params = pstmt->plansource->num_params;
320  int nparams = list_length(params);
321  ParamListInfo paramLI;
322  List *exprstates;
323  ListCell *l;
324  int i;
325 
326  if (nparams != num_params)
327  ereport(ERROR,
328  (errcode(ERRCODE_SYNTAX_ERROR),
329  errmsg("wrong number of parameters for prepared statement \"%s\"",
330  pstmt->stmt_name),
331  errdetail("Expected %d parameters but got %d.",
332  num_params, nparams)));
333 
334  /* Quick exit if no parameters */
335  if (num_params == 0)
336  return NULL;
337 
338  /*
339  * We have to run parse analysis for the expressions. Since the parser is
340  * not cool about scribbling on its input, copy first.
341  */
342  params = copyObject(params);
343 
344  i = 0;
345  foreach(l, params)
346  {
347  Node *expr = lfirst(l);
348  Oid expected_type_id = param_types[i];
349  Oid given_type_id;
350 
351  expr = transformExpr(pstate, expr, EXPR_KIND_EXECUTE_PARAMETER);
352 
353  given_type_id = exprType(expr);
354 
355  expr = coerce_to_target_type(pstate, expr, given_type_id,
356  expected_type_id, -1,
359  -1);
360 
361  if (expr == NULL)
362  ereport(ERROR,
363  (errcode(ERRCODE_DATATYPE_MISMATCH),
364  errmsg("parameter $%d of type %s cannot be coerced to the expected type %s",
365  i + 1,
366  format_type_be(given_type_id),
367  format_type_be(expected_type_id)),
368  errhint("You will need to rewrite or cast the expression."),
369  parser_errposition(pstate, exprLocation(lfirst(l)))));
370 
371  /* Take care of collations in the finished expression. */
372  assign_expr_collations(pstate, expr);
373 
374  lfirst(l) = expr;
375  i++;
376  }
377 
378  /* Prepare the expressions for execution */
379  exprstates = ExecPrepareExprList(params, estate);
380 
381  paramLI = makeParamList(num_params);
382 
383  i = 0;
384  foreach(l, exprstates)
385  {
386  ExprState *n = (ExprState *) lfirst(l);
387  ParamExternData *prm = &paramLI->params[i];
388 
389  prm->ptype = param_types[i];
390  prm->pflags = PARAM_FLAG_CONST;
392  GetPerTupleExprContext(estate),
393  &prm->isnull);
394 
395  i++;
396  }
397 
398  return paramLI;
399 }
ParamExternData params[FLEXIBLE_ARRAY_MEMBER]
Definition: params.h:125
Datum value
Definition: params.h:92
static Datum ExecEvalExprSwitchContext(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:331
int errhint(const char *fmt,...)
Definition: elog.c:1156
int exprLocation(const Node *expr)
Definition: nodeFuncs.c:1250
CachedPlanSource * plansource
Definition: prepare.h:31
Node * transformExpr(ParseState *pstate, Node *expr, ParseExprKind exprKind)
Definition: parse_expr.c:94
Definition: nodes.h:538
int errcode(int sqlerrcode)
Definition: elog.c:698
char * format_type_be(Oid type_oid)
Definition: format_type.c:339
unsigned int Oid
Definition: postgres_ext.h:31
ParamListInfo makeParamList(int numParams)
Definition: params.c:44
void assign_expr_collations(ParseState *pstate, Node *expr)
#define GetPerTupleExprContext(estate)
Definition: executor.h:533
char stmt_name[NAMEDATALEN]
Definition: prepare.h:30
#define ERROR
Definition: elog.h:46
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:78
int errdetail(const char *fmt,...)
Definition: elog.c:1042
List * ExecPrepareExprList(List *nodes, EState *estate)
Definition: execExpr.c:820
#define ereport(elevel,...)
Definition: elog.h:157
#define lfirst(lc)
Definition: pg_list.h:169
uint16 pflags
Definition: params.h:94
Oid exprType(const Node *expr)
Definition: nodeFuncs.c:41
static int list_length(const List *l)
Definition: pg_list.h:149
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:111
int errmsg(const char *fmt,...)
Definition: elog.c:909
int i
#define copyObject(obj)
Definition: nodes.h:654
Definition: pg_list.h:50
bool isnull
Definition: params.h:93
#define PARAM_FLAG_CONST
Definition: params.h:88

◆ ExecuteQuery()

void ExecuteQuery ( ParseState pstate,
ExecuteStmt stmt,
IntoClause intoClause,
ParamListInfo  params,
DestReceiver dest,
QueryCompletion qc 
)

Definition at line 184 of file prepare.c.

References CMD_SELECT, CachedPlanSource::commandTag, PlannedStmt::commandType, CreateExecutorState(), CreateNewPortal(), elog, ereport, errcode(), errmsg(), ERROR, EState::es_param_list_info, EvaluateParams(), FETCH_ALL, FetchPreparedStatement(), CachedPlanSource::fixed_result, FreeExecutorState(), GetActiveSnapshot(), GetCachedPlan(), GetIntoRelEFlags(), linitial_node, list_length(), MemoryContextStrdup(), ExecuteStmt::name, CachedPlanSource::num_params, ExecuteStmt::params, PreparedStatement::plansource, PortalData::portalContext, PortalDefineQuery(), PortalDrop(), PortalRun(), PortalStart(), CachedPlanSource::query_string, IntoClause::skipData, CachedPlan::stmt_list, and PortalData::visible.

Referenced by ExecCreateTableAs(), and standard_ProcessUtility().

188 {
189  PreparedStatement *entry;
190  CachedPlan *cplan;
191  List *plan_list;
192  ParamListInfo paramLI = NULL;
193  EState *estate = NULL;
194  Portal portal;
195  char *query_string;
196  int eflags;
197  long count;
198 
199  /* Look it up in the hash table */
200  entry = FetchPreparedStatement(stmt->name, true);
201 
202  /* Shouldn't find a non-fixed-result cached plan */
203  if (!entry->plansource->fixed_result)
204  elog(ERROR, "EXECUTE does not support variable-result cached plans");
205 
206  /* Evaluate parameters, if any */
207  if (entry->plansource->num_params > 0)
208  {
209  /*
210  * Need an EState to evaluate parameters; must not delete it till end
211  * of query, in case parameters are pass-by-reference. Note that the
212  * passed-in "params" could possibly be referenced in the parameter
213  * expressions.
214  */
215  estate = CreateExecutorState();
216  estate->es_param_list_info = params;
217  paramLI = EvaluateParams(pstate, entry, stmt->params, estate);
218  }
219 
220  /* Create a new portal to run the query in */
221  portal = CreateNewPortal();
222  /* Don't display the portal in pg_cursors, it is for internal use only */
223  portal->visible = false;
224 
225  /* Copy the plan's saved query string into the portal's memory */
226  query_string = MemoryContextStrdup(portal->portalContext,
227  entry->plansource->query_string);
228 
229  /* Replan if needed, and increment plan refcount for portal */
230  cplan = GetCachedPlan(entry->plansource, paramLI, NULL, NULL);
231  plan_list = cplan->stmt_list;
232 
233  /*
234  * DO NOT add any logic that could possibly throw an error between
235  * GetCachedPlan and PortalDefineQuery, or you'll leak the plan refcount.
236  */
237  PortalDefineQuery(portal,
238  NULL,
239  query_string,
240  entry->plansource->commandTag,
241  plan_list,
242  cplan);
243 
244  /*
245  * For CREATE TABLE ... AS EXECUTE, we must verify that the prepared
246  * statement is one that produces tuples. Currently we insist that it be
247  * a plain old SELECT. In future we might consider supporting other
248  * things such as INSERT ... RETURNING, but there are a couple of issues
249  * to be settled first, notably how WITH NO DATA should be handled in such
250  * a case (do we really want to suppress execution?) and how to pass down
251  * the OID-determining eflags (PortalStart won't handle them in such a
252  * case, and for that matter it's not clear the executor will either).
253  *
254  * For CREATE TABLE ... AS EXECUTE, we also have to ensure that the proper
255  * eflags and fetch count are passed to PortalStart/PortalRun.
256  */
257  if (intoClause)
258  {
259  PlannedStmt *pstmt;
260 
261  if (list_length(plan_list) != 1)
262  ereport(ERROR,
263  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
264  errmsg("prepared statement is not a SELECT")));
265  pstmt = linitial_node(PlannedStmt, plan_list);
266  if (pstmt->commandType != CMD_SELECT)
267  ereport(ERROR,
268  (errcode(ERRCODE_WRONG_OBJECT_TYPE),
269  errmsg("prepared statement is not a SELECT")));
270 
271  /* Set appropriate eflags */
272  eflags = GetIntoRelEFlags(intoClause);
273 
274  /* And tell PortalRun whether to run to completion or not */
275  if (intoClause->skipData)
276  count = 0;
277  else
278  count = FETCH_ALL;
279  }
280  else
281  {
282  /* Plain old EXECUTE */
283  eflags = 0;
284  count = FETCH_ALL;
285  }
286 
287  /*
288  * Run the portal as appropriate.
289  */
290  PortalStart(portal, paramLI, eflags, GetActiveSnapshot());
291 
292  (void) PortalRun(portal, count, false, true, dest, dest, qc);
293 
294  PortalDrop(portal, false);
295 
296  if (estate)
297  FreeExecutorState(estate);
298 
299  /* No need to pfree other memory, MemoryContext will be reset */
300 }
Portal CreateNewPortal(void)
Definition: portalmem.c:235
void PortalStart(Portal portal, ParamListInfo params, int eflags, Snapshot snapshot)
Definition: pquery.c:430
bool visible
Definition: portal.h:205
CachedPlanSource * plansource
Definition: prepare.h:31
Snapshot GetActiveSnapshot(void)
Definition: snapmgr.c:801
static ParamListInfo EvaluateParams(ParseState *pstate, PreparedStatement *pstmt, List *params, EState *estate)
Definition: prepare.c:315
int errcode(int sqlerrcode)
Definition: elog.c:698
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:282
#define linitial_node(type, l)
Definition: pg_list.h:177
MemoryContext portalContext
Definition: portal.h:120
bool PortalRun(Portal portal, long count, bool isTopLevel, bool run_once, DestReceiver *dest, DestReceiver *altdest, QueryCompletion *qc)
Definition: pquery.c:681
void FreeExecutorState(EState *estate)
Definition: execUtils.c:186
int GetIntoRelEFlags(IntoClause *intoClause)
Definition: createas.c:375
#define ERROR
Definition: elog.h:46
CachedPlan * GetCachedPlan(CachedPlanSource *plansource, ParamListInfo boundParams, ResourceOwner owner, QueryEnvironment *queryEnv)
Definition: plancache.c:1141
EState * CreateExecutorState(void)
Definition: execUtils.c:90
CmdType commandType
Definition: plannodes.h:46
#define ereport(elevel,...)
Definition: elog.h:157
const char * query_string
Definition: plancache.h:100
CommandTag commandTag
Definition: plancache.h:101
static int list_length(const List *l)
Definition: pg_list.h:149
int errmsg(const char *fmt,...)
Definition: elog.c:909
void PortalDrop(Portal portal, bool isTopCommit)
Definition: portalmem.c:468
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1286
#define elog(elevel,...)
Definition: elog.h:232
char * name
Definition: parsenodes.h:3565
ParamListInfo es_param_list_info
Definition: execnodes.h:595
List * params
Definition: parsenodes.h:3566
List * stmt_list
Definition: plancache.h:150
PreparedStatement * FetchPreparedStatement(const char *stmt_name, bool throwError)
Definition: prepare.c:468
Definition: pg_list.h:50
#define FETCH_ALL
Definition: parsenodes.h:2864

◆ ExplainExecuteQuery()

void ExplainExecuteQuery ( ExecuteStmt execstmt,
IntoClause into,
ExplainState es,
const char *  queryString,
ParamListInfo  params,
QueryEnvironment queryEnv 
)

Definition at line 605 of file prepare.c.

References ExplainState::buffers, BufferUsageAccumDiff(), CMD_UTILITY, PlannedStmt::commandType, CreateExecutorState(), CurrentResourceOwner, elog, ERROR, EState::es_param_list_info, EvaluateParams(), ExplainOnePlan(), ExplainOneUtility(), ExplainSeparatePlans(), FetchPreparedStatement(), CachedPlanSource::fixed_result, FreeExecutorState(), GetCachedPlan(), INSTR_TIME_SET_CURRENT, INSTR_TIME_SUBTRACT, lfirst_node, lnext(), make_parsestate(), ExecuteStmt::name, CachedPlanSource::num_params, ParseState::p_sourcetext, ExecuteStmt::params, pgBufferUsage, PreparedStatement::plansource, CachedPlanSource::query_string, ReleaseCachedPlan(), CachedPlan::stmt_list, and PlannedStmt::utilityStmt.

Referenced by ExplainOneUtility().

608 {
609  PreparedStatement *entry;
610  const char *query_string;
611  CachedPlan *cplan;
612  List *plan_list;
613  ListCell *p;
614  ParamListInfo paramLI = NULL;
615  EState *estate = NULL;
616  instr_time planstart;
617  instr_time planduration;
618  BufferUsage bufusage_start,
619  bufusage;
620 
621  if (es->buffers)
622  bufusage_start = pgBufferUsage;
623  INSTR_TIME_SET_CURRENT(planstart);
624 
625  /* Look it up in the hash table */
626  entry = FetchPreparedStatement(execstmt->name, true);
627 
628  /* Shouldn't find a non-fixed-result cached plan */
629  if (!entry->plansource->fixed_result)
630  elog(ERROR, "EXPLAIN EXECUTE does not support variable-result cached plans");
631 
632  query_string = entry->plansource->query_string;
633 
634  /* Evaluate parameters, if any */
635  if (entry->plansource->num_params)
636  {
637  ParseState *pstate;
638 
639  pstate = make_parsestate(NULL);
640  pstate->p_sourcetext = queryString;
641 
642  /*
643  * Need an EState to evaluate parameters; must not delete it till end
644  * of query, in case parameters are pass-by-reference. Note that the
645  * passed-in "params" could possibly be referenced in the parameter
646  * expressions.
647  */
648  estate = CreateExecutorState();
649  estate->es_param_list_info = params;
650 
651  paramLI = EvaluateParams(pstate, entry, execstmt->params, estate);
652  }
653 
654  /* Replan if needed, and acquire a transient refcount */
655  cplan = GetCachedPlan(entry->plansource, paramLI,
656  CurrentResourceOwner, queryEnv);
657 
658  INSTR_TIME_SET_CURRENT(planduration);
659  INSTR_TIME_SUBTRACT(planduration, planstart);
660 
661  /* calc differences of buffer counters. */
662  if (es->buffers)
663  {
664  memset(&bufusage, 0, sizeof(BufferUsage));
665  BufferUsageAccumDiff(&bufusage, &pgBufferUsage, &bufusage_start);
666  }
667 
668  plan_list = cplan->stmt_list;
669 
670  /* Explain each query */
671  foreach(p, plan_list)
672  {
673  PlannedStmt *pstmt = lfirst_node(PlannedStmt, p);
674 
675  if (pstmt->commandType != CMD_UTILITY)
676  ExplainOnePlan(pstmt, into, es, query_string, paramLI, queryEnv,
677  &planduration, (es->buffers ? &bufusage : NULL));
678  else
679  ExplainOneUtility(pstmt->utilityStmt, into, es, query_string,
680  paramLI, queryEnv);
681 
682  /* No need for CommandCounterIncrement, as ExplainOnePlan did it */
683 
684  /* Separate plans with an appropriate separator */
685  if (lnext(plan_list, p) != NULL)
687  }
688 
689  if (estate)
690  FreeExecutorState(estate);
691 
693 }
void ExplainSeparatePlans(ExplainState *es)
Definition: explain.c:4805
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:322
CachedPlanSource * plansource
Definition: prepare.h:31
ResourceOwner CurrentResourceOwner
Definition: resowner.c:146
struct timeval instr_time
Definition: instr_time.h:150
static ParamListInfo EvaluateParams(ParseState *pstate, PreparedStatement *pstmt, List *params, EState *estate)
Definition: prepare.c:315
void ReleaseCachedPlan(CachedPlan *plan, ResourceOwner owner)
Definition: plancache.c:1264
void BufferUsageAccumDiff(BufferUsage *dst, const BufferUsage *add, const BufferUsage *sub)
Definition: instrument.c:244
ParseState * make_parsestate(ParseState *parentParseState)
Definition: parse_node.c:44
void FreeExecutorState(EState *estate)
Definition: execUtils.c:186
#define ERROR
Definition: elog.h:46
#define INSTR_TIME_SUBTRACT(x, y)
Definition: instr_time.h:170
#define lfirst_node(type, lc)
Definition: pg_list.h:172
Node * utilityStmt
Definition: plannodes.h:86
const char * p_sourcetext
Definition: parse_node.h:181
CachedPlan * GetCachedPlan(CachedPlanSource *plansource, ParamListInfo boundParams, ResourceOwner owner, QueryEnvironment *queryEnv)
Definition: plancache.c:1141
EState * CreateExecutorState(void)
Definition: execUtils.c:90
CmdType commandType
Definition: plannodes.h:46
void ExplainOnePlan(PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params, QueryEnvironment *queryEnv, const instr_time *planduration, const BufferUsage *bufusage)
Definition: explain.c:518
const char * query_string
Definition: plancache.h:100
#define INSTR_TIME_SET_CURRENT(t)
Definition: instr_time.h:156
#define elog(elevel,...)
Definition: elog.h:232
char * name
Definition: parsenodes.h:3565
bool buffers
Definition: explain.h:44
ParamListInfo es_param_list_info
Definition: execnodes.h:595
List * params
Definition: parsenodes.h:3566
List * stmt_list
Definition: plancache.h:150
PreparedStatement * FetchPreparedStatement(const char *stmt_name, bool throwError)
Definition: prepare.c:468
Definition: pg_list.h:50
void ExplainOneUtility(Node *utilityStmt, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params, QueryEnvironment *queryEnv)
Definition: explain.c:428
BufferUsage pgBufferUsage
Definition: instrument.c:20

◆ FetchPreparedStatement()

PreparedStatement* FetchPreparedStatement ( const char *  stmt_name,
bool  throwError 
)

Definition at line 468 of file prepare.c.

References ereport, errcode(), errmsg(), ERROR, HASH_FIND, and hash_search().

Referenced by DropPreparedStatement(), errdetail_execute(), exec_bind_message(), exec_describe_statement_message(), ExecuteQuery(), ExplainExecuteQuery(), FetchStatementTargetList(), GetCommandLogLevel(), UtilityReturnsTuples(), and UtilityTupleDescriptor().

469 {
470  PreparedStatement *entry;
471 
472  /*
473  * If the hash table hasn't been initialized, it can't be storing
474  * anything, therefore it couldn't possibly store our plan.
475  */
476  if (prepared_queries)
478  stmt_name,
479  HASH_FIND,
480  NULL);
481  else
482  entry = NULL;
483 
484  if (!entry && throwError)
485  ereport(ERROR,
486  (errcode(ERRCODE_UNDEFINED_PSTATEMENT),
487  errmsg("prepared statement \"%s\" does not exist",
488  stmt_name)));
489 
490  return entry;
491 }
int errcode(int sqlerrcode)
Definition: elog.c:698
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:954
static HTAB * prepared_queries
Definition: prepare.c:46
#define ERROR
Definition: elog.h:46
#define ereport(elevel,...)
Definition: elog.h:157
int errmsg(const char *fmt,...)
Definition: elog.c:909

◆ FetchPreparedStatementResultDesc()

TupleDesc FetchPreparedStatementResultDesc ( PreparedStatement stmt)

Definition at line 500 of file prepare.c.

References Assert, CreateTupleDescCopy(), CachedPlanSource::fixed_result, PreparedStatement::plansource, and CachedPlanSource::resultDesc.

Referenced by UtilityTupleDescriptor().

501 {
502  /*
503  * Since we don't allow prepared statements' result tupdescs to change,
504  * there's no need to worry about revalidating the cached plan here.
505  */
507  if (stmt->plansource->resultDesc)
509  else
510  return NULL;
511 }
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition: tupdesc.c:111
CachedPlanSource * plansource
Definition: prepare.h:31
TupleDesc resultDesc
Definition: plancache.h:108
#define Assert(condition)
Definition: c.h:804

◆ FetchPreparedStatementTargetList()

List* FetchPreparedStatementTargetList ( PreparedStatement stmt)

Definition at line 523 of file prepare.c.

References CachedPlanGetTargetList(), copyObject, and PreparedStatement::plansource.

Referenced by FetchStatementTargetList().

524 {
525  List *tlist;
526 
527  /* Get the plan's primary targetlist */
528  tlist = CachedPlanGetTargetList(stmt->plansource, NULL);
529 
530  /* Copy into caller's context in case plan gets invalidated */
531  return copyObject(tlist);
532 }
CachedPlanSource * plansource
Definition: prepare.h:31
List * CachedPlanGetTargetList(CachedPlanSource *plansource, QueryEnvironment *queryEnv)
Definition: plancache.c:1611
#define copyObject(obj)
Definition: nodes.h:654
Definition: pg_list.h:50

◆ InitQueryHashTable()

static void InitQueryHashTable ( void  )
static

Definition at line 406 of file prepare.c.

References HASHCTL::entrysize, hash_create(), HASH_ELEM, HASH_STRINGS, HASHCTL::keysize, and NAMEDATALEN.

Referenced by StorePreparedStatement().

407 {
408  HASHCTL hash_ctl;
409 
410  hash_ctl.keysize = NAMEDATALEN;
411  hash_ctl.entrysize = sizeof(PreparedStatement);
412 
413  prepared_queries = hash_create("Prepared Queries",
414  32,
415  &hash_ctl,
417 }
#define HASH_ELEM
Definition: hsearch.h:95
Size entrysize
Definition: hsearch.h:76
#define NAMEDATALEN
static HTAB * prepared_queries
Definition: prepare.c:46
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:349
Size keysize
Definition: hsearch.h:75
#define HASH_STRINGS
Definition: hsearch.h:96

◆ pg_prepared_statement()

Datum pg_prepared_statement ( PG_FUNCTION_ARGS  )

Definition at line 701 of file prepare.c.

References ReturnSetInfo::allowedModes, BoolGetDatum, build_regtype_array(), CreateTemplateTupleDesc(), CStringGetTextDatum, ReturnSetInfo::econtext, ExprContext::ecxt_per_query_memory, ereport, errcode(), errmsg(), ERROR, PreparedStatement::from_sql, hash_seq_init(), hash_seq_search(), Int64GetDatumFast, IsA, MemoryContextSwitchTo(), MemSet, CachedPlanSource::num_custom_plans, CachedPlanSource::num_generic_plans, CachedPlanSource::num_params, CachedPlanSource::param_types, PreparedStatement::plansource, PreparedStatement::prepare_time, CachedPlanSource::query_string, ReturnSetInfo::returnMode, ReturnSetInfo::setDesc, ReturnSetInfo::setResult, SFRM_Materialize, SFRM_Materialize_Random, PreparedStatement::stmt_name, TimestampTzGetDatum, TupleDescInitEntry(), tuplestore_begin_heap(), tuplestore_donestoring, tuplestore_putvalues(), values, and work_mem.

702 {
703  ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
704  TupleDesc tupdesc;
705  Tuplestorestate *tupstore;
706  MemoryContext per_query_ctx;
707  MemoryContext oldcontext;
708 
709  /* check to see if caller supports us returning a tuplestore */
710  if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
711  ereport(ERROR,
712  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
713  errmsg("set-valued function called in context that cannot accept a set")));
714  if (!(rsinfo->allowedModes & SFRM_Materialize))
715  ereport(ERROR,
716  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
717  errmsg("materialize mode required, but it is not allowed in this context")));
718 
719  /* need to build tuplestore in query context */
720  per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
721  oldcontext = MemoryContextSwitchTo(per_query_ctx);
722 
723  /*
724  * build tupdesc for result tuples. This must match the definition of the
725  * pg_prepared_statements view in system_views.sql
726  */
727  tupdesc = CreateTemplateTupleDesc(7);
728  TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name",
729  TEXTOID, -1, 0);
730  TupleDescInitEntry(tupdesc, (AttrNumber) 2, "statement",
731  TEXTOID, -1, 0);
732  TupleDescInitEntry(tupdesc, (AttrNumber) 3, "prepare_time",
733  TIMESTAMPTZOID, -1, 0);
734  TupleDescInitEntry(tupdesc, (AttrNumber) 4, "parameter_types",
735  REGTYPEARRAYOID, -1, 0);
736  TupleDescInitEntry(tupdesc, (AttrNumber) 5, "from_sql",
737  BOOLOID, -1, 0);
738  TupleDescInitEntry(tupdesc, (AttrNumber) 6, "generic_plans",
739  INT8OID, -1, 0);
740  TupleDescInitEntry(tupdesc, (AttrNumber) 7, "custom_plans",
741  INT8OID, -1, 0);
742 
743  /*
744  * We put all the tuples into a tuplestore in one scan of the hashtable.
745  * This avoids any issue of the hashtable possibly changing between calls.
746  */
747  tupstore =
749  false, work_mem);
750 
751  /* generate junk in short-term context */
752  MemoryContextSwitchTo(oldcontext);
753 
754  /* hash table might be uninitialized */
755  if (prepared_queries)
756  {
757  HASH_SEQ_STATUS hash_seq;
758  PreparedStatement *prep_stmt;
759 
760  hash_seq_init(&hash_seq, prepared_queries);
761  while ((prep_stmt = hash_seq_search(&hash_seq)) != NULL)
762  {
763  Datum values[7];
764  bool nulls[7];
765 
766  MemSet(nulls, 0, sizeof(nulls));
767 
768  values[0] = CStringGetTextDatum(prep_stmt->stmt_name);
769  values[1] = CStringGetTextDatum(prep_stmt->plansource->query_string);
770  values[2] = TimestampTzGetDatum(prep_stmt->prepare_time);
771  values[3] = build_regtype_array(prep_stmt->plansource->param_types,
772  prep_stmt->plansource->num_params);
773  values[4] = BoolGetDatum(prep_stmt->from_sql);
774  values[5] = Int64GetDatumFast(prep_stmt->plansource->num_generic_plans);
775  values[6] = Int64GetDatumFast(prep_stmt->plansource->num_custom_plans);
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 }
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, Datum *values, bool *isnull)
Definition: tuplestore.c:750
#define IsA(nodeptr, _type_)
Definition: nodes.h:589
TupleDesc CreateTemplateTupleDesc(int natts)
Definition: tupdesc.c:45
CachedPlanSource * plansource
Definition: prepare.h:31
#define tuplestore_donestoring(state)
Definition: tuplestore.h:60
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
int errcode(int sqlerrcode)
Definition: elog.c:698
#define MemSet(start, val, len)
Definition: c.h:1008
int64 num_custom_plans
Definition: plancache.h:133
static HTAB * prepared_queries
Definition: prepare.c:46
char stmt_name[NAMEDATALEN]
Definition: prepare.h:30
#define ERROR
Definition: elog.h:46
#define TimestampTzGetDatum(X)
Definition: timestamp.h:32
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition: tupdesc.c:583
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:318
uintptr_t Datum
Definition: postgres.h:411
#define Int64GetDatumFast(X)
Definition: postgres.h:804
int work_mem
Definition: globals.c:124
int64 num_generic_plans
Definition: plancache.h:134
#define BoolGetDatum(X)
Definition: postgres.h:446
#define ereport(elevel,...)
Definition: elog.h:157
int allowedModes
Definition: execnodes.h:306
TimestampTz prepare_time
Definition: prepare.h:33
SetFunctionReturnMode returnMode
Definition: execnodes.h:308
const char * query_string
Definition: plancache.h:100
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1436
MemoryContext ecxt_per_query_memory
Definition: execnodes.h:234
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1426
Tuplestorestate * setResult
Definition: execnodes.h:311
static Datum values[MAXATTR]
Definition: bootstrap.c:156
ExprContext * econtext
Definition: execnodes.h:304
TupleDesc setDesc
Definition: execnodes.h:312
int errmsg(const char *fmt,...)
Definition: elog.c:909
#define CStringGetTextDatum(s)
Definition: builtins.h:86
int16 AttrNumber
Definition: attnum.h:21

◆ PrepareQuery()

void PrepareQuery ( ParseState pstate,
PrepareStmt stmt,
int  stmt_location,
int  stmt_len 
)

Definition at line 58 of file prepare.c.

References PrepareStmt::argtypes, CMD_DELETE, CMD_INSERT, CMD_SELECT, CMD_UPDATE, Query::commandType, CompleteCachedPlan(), CreateCachedPlan(), CreateCommandTag(), CURSOR_OPT_PARALLEL_OK, ereport, errcode(), errmsg(), ERROR, i, InvalidOid, lfirst, list_length(), makeNode, PrepareStmt::name, ParseState::p_sourcetext, palloc(), parse_analyze_varparams(), PrepareStmt::query, QueryRewrite(), RawStmt::stmt, RawStmt::stmt_len, RawStmt::stmt_location, StorePreparedStatement(), and typenameTypeId().

Referenced by standard_ProcessUtility().

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  rawstmt = makeNode(RawStmt);
83  rawstmt->stmt = stmt->query;
84  rawstmt->stmt_location = stmt_location;
85  rawstmt->stmt_len = stmt_len;
86 
87  /*
88  * Create the CachedPlanSource before we do parse analysis, since it needs
89  * to see the unmodified raw parse tree.
90  */
91  plansource = CreateCachedPlan(rawstmt, pstate->p_sourcetext,
92  CreateCommandTag(stmt->query));
93 
94  /* Transform list of TypeNames to array of type OIDs */
95  nargs = list_length(stmt->argtypes);
96 
97  if (nargs)
98  {
99  ListCell *l;
100 
101  argtypes = (Oid *) palloc(nargs * sizeof(Oid));
102  i = 0;
103 
104  foreach(l, stmt->argtypes)
105  {
106  TypeName *tn = lfirst(l);
107  Oid toid = typenameTypeId(pstate, tn);
108 
109  argtypes[i++] = toid;
110  }
111  }
112 
113  /*
114  * Analyze the statement using these parameter types (any parameters
115  * passed in from above us will not be visible to it), allowing
116  * information about unknown parameters to be deduced from context.
117  */
118  query = parse_analyze_varparams(rawstmt, pstate->p_sourcetext,
119  &argtypes, &nargs);
120 
121  /*
122  * Check that all parameter types were determined.
123  */
124  for (i = 0; i < nargs; i++)
125  {
126  Oid argtype = argtypes[i];
127 
128  if (argtype == InvalidOid || argtype == UNKNOWNOID)
129  ereport(ERROR,
130  (errcode(ERRCODE_INDETERMINATE_DATATYPE),
131  errmsg("could not determine data type of parameter $%d",
132  i + 1)));
133  }
134 
135  /*
136  * grammar only allows PreparableStmt, so this check should be redundant
137  */
138  switch (query->commandType)
139  {
140  case CMD_SELECT:
141  case CMD_INSERT:
142  case CMD_UPDATE:
143  case CMD_DELETE:
144  /* OK */
145  break;
146  default:
147  ereport(ERROR,
148  (errcode(ERRCODE_INVALID_PSTATEMENT_DEFINITION),
149  errmsg("utility statements cannot be prepared")));
150  break;
151  }
152 
153  /* Rewrite the query. The result could be 0, 1, or many queries. */
154  query_list = QueryRewrite(query);
155 
156  /* Finish filling in the CachedPlanSource */
157  CompleteCachedPlan(plansource,
158  query_list,
159  NULL,
160  argtypes,
161  nargs,
162  NULL,
163  NULL,
164  CURSOR_OPT_PARALLEL_OK, /* allow parallel mode */
165  true); /* fixed result */
166 
167  /*
168  * Save the results.
169  */
171  plansource,
172  true);
173 }
List * QueryRewrite(Query *parsetree)
CachedPlanSource * CreateCachedPlan(RawStmt *raw_parse_tree, const char *query_string, CommandTag commandTag)
Definition: plancache.c:164
int errcode(int sqlerrcode)
Definition: elog.c:698
Query * parse_analyze_varparams(RawStmt *parseTree, const char *sourceText, Oid **paramTypes, int *numParams)
Definition: analyze.c:150
unsigned int Oid
Definition: postgres_ext.h:31
#define ERROR
Definition: elog.h:46
Node * stmt
Definition: parsenodes.h:1572
const char * p_sourcetext
Definition: parse_node.h:181
int stmt_len
Definition: parsenodes.h:1574
int stmt_location
Definition: parsenodes.h:1573
void StorePreparedStatement(const char *stmt_name, CachedPlanSource *plansource, bool from_sql)
Definition: prepare.c:426
#define InvalidOid
Definition: postgres_ext.h:36
#define ereport(elevel,...)
Definition: elog.h:157
CmdType commandType
Definition: parsenodes.h:120
#define makeNode(_type_)
Definition: nodes.h:586
char * name
Definition: parsenodes.h:3551
#define lfirst(lc)
Definition: pg_list.h:169
CommandTag CreateCommandTag(Node *parsetree)
Definition: utility.c:2337
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:338
Node * query
Definition: parsenodes.h:3553
static int list_length(const List *l)
Definition: pg_list.h:149
List * argtypes
Definition: parsenodes.h:3552
#define CURSOR_OPT_PARALLEL_OK
Definition: parsenodes.h:2829
void * palloc(Size size)
Definition: mcxt.c:1062
int errmsg(const char *fmt,...)
Definition: elog.c:909
int i
Definition: pg_list.h:50
Oid typenameTypeId(ParseState *pstate, const TypeName *typeName)
Definition: parse_type.c:291

◆ StorePreparedStatement()

void StorePreparedStatement ( const char *  stmt_name,
CachedPlanSource plansource,
bool  from_sql 
)

Definition at line 426 of file prepare.c.

References ereport, errcode(), errmsg(), ERROR, PreparedStatement::from_sql, GetCurrentStatementStartTimestamp(), HASH_ENTER, hash_search(), InitQueryHashTable(), PreparedStatement::plansource, PreparedStatement::prepare_time, and SaveCachedPlan().

Referenced by exec_parse_message(), and PrepareQuery().

429 {
430  PreparedStatement *entry;
432  bool found;
433 
434  /* Initialize the hash table, if necessary */
435  if (!prepared_queries)
437 
438  /* Add entry to hash table */
440  stmt_name,
441  HASH_ENTER,
442  &found);
443 
444  /* Shouldn't get a duplicate entry */
445  if (found)
446  ereport(ERROR,
447  (errcode(ERRCODE_DUPLICATE_PSTATEMENT),
448  errmsg("prepared statement \"%s\" already exists",
449  stmt_name)));
450 
451  /* Fill in the hash table entry */
452  entry->plansource = plansource;
453  entry->from_sql = from_sql;
454  entry->prepare_time = cur_ts;
455 
456  /* Now it's safe to move the CachedPlanSource to permanent memory */
457  SaveCachedPlan(plansource);
458 }
static void InitQueryHashTable(void)
Definition: prepare.c:406
CachedPlanSource * plansource
Definition: prepare.h:31
int64 TimestampTz
Definition: timestamp.h:39
int errcode(int sqlerrcode)
Definition: elog.c:698
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:954
static HTAB * prepared_queries
Definition: prepare.c:46
#define ERROR
Definition: elog.h:46
#define ereport(elevel,...)
Definition: elog.h:157
void SaveCachedPlan(CachedPlanSource *plansource)
Definition: plancache.c:454
TimestampTz prepare_time
Definition: prepare.h:33
int errmsg(const char *fmt,...)
Definition: elog.c:909
TimestampTz GetCurrentStatementStartTimestamp(void)
Definition: xact.c:808

Variable Documentation

◆ prepared_queries

HTAB* prepared_queries = NULL
static

Definition at line 46 of file prepare.c.