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 (PreparedStatement *pstmt, List *params, const char *queryString, EState *estate)
 
static Datum build_regtype_array (Oid *param_types, int num_params)
 
void PrepareQuery (PrepareStmt *stmt, const char *queryString, int stmt_location, int stmt_len)
 
void ExecuteQuery (ExecuteStmt *stmt, IntoClause *intoClause, const char *queryString, ParamListInfo params, DestReceiver *dest, char *completionTag)
 
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 792 of file prepare.c.

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

Referenced by pg_prepared_statement().

793 {
794  Datum *tmp_ary;
795  ArrayType *result;
796  int i;
797 
798  tmp_ary = (Datum *) palloc(num_params * sizeof(Datum));
799 
800  for (i = 0; i < num_params; i++)
801  tmp_ary[i] = ObjectIdGetDatum(param_types[i]);
802 
803  /* XXX: this hardcodes assumptions about the regtype type */
804  result = construct_array(tmp_ary, num_params, REGTYPEOID, 4, true, 'i');
805  return PointerGetDatum(result);
806 }
#define PointerGetDatum(X)
Definition: postgres.h:556
ArrayType * construct_array(Datum *elems, int nelems, Oid elmtype, int elmlen, bool elmbyval, char elmalign)
Definition: arrayfuncs.c:3291
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
uintptr_t Datum
Definition: postgres.h:367
void * palloc(Size size)
Definition: mcxt.c:949
int i

◆ DeallocateQuery()

void DeallocateQuery ( DeallocateStmt stmt)

Definition at line 557 of file prepare.c.

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

Referenced by standard_ProcessUtility().

558 {
559  if (stmt->name)
560  DropPreparedStatement(stmt->name, true);
561  else
563 }
void DropAllPreparedStatements(void)
Definition: prepare.c:592
void DropPreparedStatement(const char *stmt_name, bool showError)
Definition: prepare.c:571

◆ DropAllPreparedStatements()

void DropAllPreparedStatements ( void  )

Definition at line 592 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().

593 {
594  HASH_SEQ_STATUS seq;
595  PreparedStatement *entry;
596 
597  /* nothing cached */
598  if (!prepared_queries)
599  return;
600 
601  /* walk over cache */
603  while ((entry = hash_seq_search(&seq)) != NULL)
604  {
605  /* Release the plancache entry */
606  DropCachedPlan(entry->plansource);
607 
608  /* Now we can remove the hash table entry */
610  }
611 }
CachedPlanSource * plansource
Definition: prepare.h:31
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:906
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:1389
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1379
void DropCachedPlan(CachedPlanSource *plansource)
Definition: plancache.c:496

◆ DropPreparedStatement()

void DropPreparedStatement ( const char *  stmt_name,
bool  showError 
)

Definition at line 571 of file prepare.c.

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

Referenced by DeallocateQuery(), and PostgresMain().

572 {
573  PreparedStatement *entry;
574 
575  /* Find the query's hash table entry; raise error if wanted */
576  entry = FetchPreparedStatement(stmt_name, showError);
577 
578  if (entry)
579  {
580  /* Release the plancache entry */
581  DropCachedPlan(entry->plansource);
582 
583  /* Now we can remove the hash table entry */
585  }
586 }
CachedPlanSource * plansource
Definition: prepare.h:31
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:906
static HTAB * prepared_queries
Definition: prepare.c:46
char stmt_name[NAMEDATALEN]
Definition: prepare.h:30
void DropCachedPlan(CachedPlanSource *plansource)
Definition: plancache.c:496
PreparedStatement * FetchPreparedStatement(const char *stmt_name, bool throwError)
Definition: prepare.c:486

◆ EvaluateParams()

static ParamListInfo EvaluateParams ( PreparedStatement pstmt,
List params,
const char *  queryString,
EState estate 
)
static

Definition at line 327 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(), make_parsestate(), makeParamList(), CachedPlanSource::num_params, ParseState::p_sourcetext, 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().

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 = 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  parser_errposition(pstate, exprLocation(lfirst(l)))));
386 
387  /* Take care of collations in the finished expression. */
388  assign_expr_collations(pstate, expr);
389 
390  lfirst(l) = expr;
391  i++;
392  }
393 
394  /* Prepare the expressions for execution */
395  exprstates = ExecPrepareExprList(params, estate);
396 
397  paramLI = makeParamList(num_params);
398 
399  i = 0;
400  foreach(l, exprstates)
401  {
402  ExprState *n = (ExprState *) lfirst(l);
403  ParamExternData *prm = &paramLI->params[i];
404 
405  prm->ptype = param_types[i];
406  prm->pflags = PARAM_FLAG_CONST;
408  GetPerTupleExprContext(estate),
409  &prm->isnull);
410 
411  i++;
412  }
413 
414  return paramLI;
415 }
ParamExternData params[FLEXIBLE_ARRAY_MEMBER]
Definition: params.h:124
Datum value
Definition: params.h:92
static Datum ExecEvalExprSwitchContext(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:300
int errhint(const char *fmt,...)
Definition: elog.c:1069
int exprLocation(const Node *expr)
Definition: nodeFuncs.c:1191
CachedPlanSource * plansource
Definition: prepare.h:31
Node * transformExpr(ParseState *pstate, Node *expr, ParseExprKind exprKind)
Definition: parse_expr.c:144
Definition: nodes.h:525
int errcode(int sqlerrcode)
Definition: elog.c:608
char * format_type_be(Oid type_oid)
Definition: format_type.c:326
unsigned int Oid
Definition: postgres_ext.h:31
ParamListInfo makeParamList(int numParams)
Definition: params.c:32
ParseState * make_parsestate(ParseState *parentParseState)
Definition: parse_node.c:43
void assign_expr_collations(ParseState *pstate, Node *expr)
#define GetPerTupleExprContext(estate)
Definition: executor.h:501
char stmt_name[NAMEDATALEN]
Definition: prepare.h:30
#define ERROR
Definition: elog.h:43
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
Oid * param_types
Definition: plancache.h:99
int errdetail(const char *fmt,...)
Definition: elog.c:955
const char * p_sourcetext
Definition: parse_node.h:176
#define ereport(elevel, rest)
Definition: elog.h:141
List * ExecPrepareExprList(List *nodes, EState *estate)
Definition: execExpr.c:564
#define lfirst(lc)
Definition: pg_list.h:190
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:169
int parser_errposition(ParseState *pstate, int location)
Definition: parse_node.c:110
int errmsg(const char *fmt,...)
Definition: elog.c:822
int i
#define copyObject(obj)
Definition: nodes.h:641
Definition: pg_list.h:50
bool isnull
Definition: params.h:93
#define PARAM_FLAG_CONST
Definition: params.h:88

◆ ExecuteQuery()

void ExecuteQuery ( ExecuteStmt stmt,
IntoClause intoClause,
const char *  queryString,
ParamListInfo  params,
DestReceiver dest,
char *  completionTag 
)

Definition at line 200 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().

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(portal->portalContext,
243  entry->plansource->query_string);
244 
245  /* Replan if needed, and increment plan refcount for portal */
246  cplan = GetCachedPlan(entry->plansource, paramLI, false, NULL);
247  plan_list = cplan->stmt_list;
248 
249  /*
250  * 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 = linitial_node(PlannedStmt, 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 }
CachedPlan * GetCachedPlan(CachedPlanSource *plansource, ParamListInfo boundParams, bool useResOwner, QueryEnvironment *queryEnv)
Definition: plancache.c:1138
Portal CreateNewPortal(void)
Definition: portalmem.c:234
void PortalStart(Portal portal, ParamListInfo params, int eflags, Snapshot snapshot)
Definition: pquery.c:443
bool visible
Definition: portal.h:194
void PortalDefineQuery(Portal portal, const char *prepStmtName, const char *sourceText, const char *commandTag, List *stmts, CachedPlan *cplan)
Definition: portalmem.c:281
const char * commandTag
Definition: plancache.h:98
CachedPlanSource * plansource
Definition: prepare.h:31
Snapshot GetActiveSnapshot(void)
Definition: snapmgr.c:841
bool PortalRun(Portal portal, long count, bool isTopLevel, bool run_once, DestReceiver *dest, DestReceiver *altdest, char *completionTag)
Definition: pquery.c:686
int errcode(int sqlerrcode)
Definition: elog.c:608
bool skipData
Definition: primnodes.h:119
#define linitial_node(type, l)
Definition: pg_list.h:198
MemoryContext portalContext
Definition: portal.h:119
void FreeExecutorState(EState *estate)
Definition: execUtils.c:190
int GetIntoRelEFlags(IntoClause *intoClause)
Definition: createas.c:394
#define ERROR
Definition: elog.h:43
#define ereport(elevel, rest)
Definition: elog.h:141
EState * CreateExecutorState(void)
Definition: execUtils.c:88
CmdType commandType
Definition: plannodes.h:46
const char * query_string
Definition: plancache.h:97
static int list_length(const List *l)
Definition: pg_list.h:169
static ParamListInfo EvaluateParams(PreparedStatement *pstmt, List *params, const char *queryString, EState *estate)
Definition: prepare.c:327
int errmsg(const char *fmt,...)
Definition: elog.c:822
void PortalDrop(Portal portal, bool isTopCommit)
Definition: portalmem.c:465
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1173
#define elog(elevel,...)
Definition: elog.h:228
char * name
Definition: parsenodes.h:3402
ParamListInfo es_param_list_info
Definition: execnodes.h:543
List * params
Definition: parsenodes.h:3403
List * stmt_list
Definition: plancache.h:146
PreparedStatement * FetchPreparedStatement(const char *stmt_name, bool throwError)
Definition: prepare.c:486
Definition: pg_list.h:50
#define FETCH_ALL
Definition: parsenodes.h:2727

◆ ExplainExecuteQuery()

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

Definition at line 623 of file prepare.c.

References CMD_UTILITY, PlannedStmt::commandType, CreateExecutorState(), 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(), ExecuteStmt::name, CachedPlanSource::num_params, ExecuteStmt::params, PreparedStatement::plansource, CachedPlanSource::query_string, ReleaseCachedPlan(), CachedPlan::stmt_list, and PlannedStmt::utilityStmt.

Referenced by ExplainOneUtility().

626 {
627  PreparedStatement *entry;
628  const char *query_string;
629  CachedPlan *cplan;
630  List *plan_list;
631  ListCell *p;
632  ParamListInfo paramLI = NULL;
633  EState *estate = NULL;
634  instr_time planstart;
635  instr_time planduration;
636 
637  INSTR_TIME_SET_CURRENT(planstart);
638 
639  /* Look it up in the hash table */
640  entry = FetchPreparedStatement(execstmt->name, true);
641 
642  /* Shouldn't find a non-fixed-result cached plan */
643  if (!entry->plansource->fixed_result)
644  elog(ERROR, "EXPLAIN EXECUTE does not support variable-result cached plans");
645 
646  query_string = entry->plansource->query_string;
647 
648  /* Evaluate parameters, if any */
649  if (entry->plansource->num_params)
650  {
651  /*
652  * Need an EState to evaluate parameters; must not delete it till end
653  * of query, in case parameters are pass-by-reference. Note that the
654  * passed-in "params" could possibly be referenced in the parameter
655  * expressions.
656  */
657  estate = CreateExecutorState();
658  estate->es_param_list_info = params;
659  paramLI = EvaluateParams(entry, execstmt->params,
660  queryString, estate);
661  }
662 
663  /* Replan if needed, and acquire a transient refcount */
664  cplan = GetCachedPlan(entry->plansource, paramLI, true, queryEnv);
665 
666  INSTR_TIME_SET_CURRENT(planduration);
667  INSTR_TIME_SUBTRACT(planduration, planstart);
668 
669  plan_list = cplan->stmt_list;
670 
671  /* Explain each query */
672  foreach(p, plan_list)
673  {
674  PlannedStmt *pstmt = lfirst_node(PlannedStmt, p);
675 
676  if (pstmt->commandType != CMD_UTILITY)
677  ExplainOnePlan(pstmt, into, es, query_string, paramLI, queryEnv,
678  &planduration);
679  else
680  ExplainOneUtility(pstmt->utilityStmt, into, es, query_string,
681  paramLI, queryEnv);
682 
683  /* No need for CommandCounterIncrement, as ExplainOnePlan did it */
684 
685  /* Separate plans with an appropriate separator */
686  if (lnext(plan_list, p) != NULL)
688  }
689 
690  if (estate)
691  FreeExecutorState(estate);
692 
693  ReleaseCachedPlan(cplan, true);
694 }
void ExplainOnePlan(PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params, QueryEnvironment *queryEnv, const instr_time *planduration)
Definition: explain.c:465
CachedPlan * GetCachedPlan(CachedPlanSource *plansource, ParamListInfo boundParams, bool useResOwner, QueryEnvironment *queryEnv)
Definition: plancache.c:1138
void ExplainSeparatePlans(ExplainState *es)
Definition: explain.c:3832
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:321
CachedPlanSource * plansource
Definition: prepare.h:31
struct timeval instr_time
Definition: instr_time.h:150
void FreeExecutorState(EState *estate)
Definition: execUtils.c:190
#define ERROR
Definition: elog.h:43
#define INSTR_TIME_SUBTRACT(x, y)
Definition: instr_time.h:170
#define lfirst_node(type, lc)
Definition: pg_list.h:193
Node * utilityStmt
Definition: plannodes.h:90
void ReleaseCachedPlan(CachedPlan *plan, bool useResOwner)
Definition: plancache.c:1259
EState * CreateExecutorState(void)
Definition: execUtils.c:88
CmdType commandType
Definition: plannodes.h:46
const char * query_string
Definition: plancache.h:97
static ParamListInfo EvaluateParams(PreparedStatement *pstmt, List *params, const char *queryString, EState *estate)
Definition: prepare.c:327
#define INSTR_TIME_SET_CURRENT(t)
Definition: instr_time.h:156
#define elog(elevel,...)
Definition: elog.h:228
char * name
Definition: parsenodes.h:3402
ParamListInfo es_param_list_info
Definition: execnodes.h:543
List * params
Definition: parsenodes.h:3403
List * stmt_list
Definition: plancache.h:146
PreparedStatement * FetchPreparedStatement(const char *stmt_name, bool throwError)
Definition: prepare.c:486
Definition: pg_list.h:50
void ExplainOneUtility(Node *utilityStmt, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params, QueryEnvironment *queryEnv)
Definition: explain.c:390

◆ FetchPreparedStatement()

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

Definition at line 486 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().

487 {
488  PreparedStatement *entry;
489 
490  /*
491  * If the hash table hasn't been initialized, it can't be storing
492  * anything, therefore it couldn't possibly store our plan.
493  */
494  if (prepared_queries)
496  stmt_name,
497  HASH_FIND,
498  NULL);
499  else
500  entry = NULL;
501 
502  if (!entry && throwError)
503  ereport(ERROR,
504  (errcode(ERRCODE_UNDEFINED_PSTATEMENT),
505  errmsg("prepared statement \"%s\" does not exist",
506  stmt_name)));
507 
508  return entry;
509 }
int errcode(int sqlerrcode)
Definition: elog.c:608
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:906
static HTAB * prepared_queries
Definition: prepare.c:46
#define ERROR
Definition: elog.h:43
#define ereport(elevel, rest)
Definition: elog.h:141
int errmsg(const char *fmt,...)
Definition: elog.c:822

◆ FetchPreparedStatementResultDesc()

TupleDesc FetchPreparedStatementResultDesc ( PreparedStatement stmt)

Definition at line 518 of file prepare.c.

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

Referenced by UtilityTupleDescriptor().

519 {
520  /*
521  * Since we don't allow prepared statements' result tupdescs to change,
522  * there's no need to worry about revalidating the cached plan here.
523  */
525  if (stmt->plansource->resultDesc)
527  else
528  return NULL;
529 }
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition: tupdesc.c:110
CachedPlanSource * plansource
Definition: prepare.h:31
TupleDesc resultDesc
Definition: plancache.h:105
#define Assert(condition)
Definition: c.h:739

◆ FetchPreparedStatementTargetList()

List* FetchPreparedStatementTargetList ( PreparedStatement stmt)

Definition at line 541 of file prepare.c.

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

Referenced by FetchStatementTargetList().

542 {
543  List *tlist;
544 
545  /* Get the plan's primary targetlist */
546  tlist = CachedPlanGetTargetList(stmt->plansource, NULL);
547 
548  /* Copy into caller's context in case plan gets invalidated */
549  return copyObject(tlist);
550 }
CachedPlanSource * plansource
Definition: prepare.h:31
List * CachedPlanGetTargetList(CachedPlanSource *plansource, QueryEnvironment *queryEnv)
Definition: plancache.c:1428
#define copyObject(obj)
Definition: nodes.h:641
Definition: pg_list.h:50

◆ InitQueryHashTable()

static void InitQueryHashTable ( void  )
static

Definition at line 422 of file prepare.c.

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

Referenced by StorePreparedStatement().

423 {
424  HASHCTL hash_ctl;
425 
426  MemSet(&hash_ctl, 0, sizeof(hash_ctl));
427 
428  hash_ctl.keysize = NAMEDATALEN;
429  hash_ctl.entrysize = sizeof(PreparedStatement);
430 
431  prepared_queries = hash_create("Prepared Queries",
432  32,
433  &hash_ctl,
434  HASH_ELEM);
435 }
#define HASH_ELEM
Definition: hsearch.h:87
Size entrysize
Definition: hsearch.h:73
#define MemSet(start, val, len)
Definition: c.h:962
#define NAMEDATALEN
static HTAB * prepared_queries
Definition: prepare.c:46
HTAB * hash_create(const char *tabname, long nelem, HASHCTL *info, int flags)
Definition: dynahash.c:316
Size keysize
Definition: hsearch.h:72

◆ 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(), IsA, MemoryContextSwitchTo(), MemSet, 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 " \
718  "allowed in this context")));
719 
720  /* need to build tuplestore in query context */
721  per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
722  oldcontext = MemoryContextSwitchTo(per_query_ctx);
723 
724  /*
725  * build tupdesc for result tuples. This must match the definition of the
726  * pg_prepared_statements view in system_views.sql
727  */
728  tupdesc = CreateTemplateTupleDesc(5);
729  TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name",
730  TEXTOID, -1, 0);
731  TupleDescInitEntry(tupdesc, (AttrNumber) 2, "statement",
732  TEXTOID, -1, 0);
733  TupleDescInitEntry(tupdesc, (AttrNumber) 3, "prepare_time",
734  TIMESTAMPTZOID, -1, 0);
735  TupleDescInitEntry(tupdesc, (AttrNumber) 4, "parameter_types",
736  REGTYPEARRAYOID, -1, 0);
737  TupleDescInitEntry(tupdesc, (AttrNumber) 5, "from_sql",
738  BOOLOID, -1, 0);
739 
740  /*
741  * We put all the tuples into a tuplestore in one scan of the hashtable.
742  * This avoids any issue of the hashtable possibly changing between calls.
743  */
744  tupstore =
746  false, work_mem);
747 
748  /* generate junk in short-term context */
749  MemoryContextSwitchTo(oldcontext);
750 
751  /* hash table might be uninitialized */
752  if (prepared_queries)
753  {
754  HASH_SEQ_STATUS hash_seq;
755  PreparedStatement *prep_stmt;
756 
757  hash_seq_init(&hash_seq, prepared_queries);
758  while ((prep_stmt = hash_seq_search(&hash_seq)) != NULL)
759  {
760  Datum values[5];
761  bool nulls[5];
762 
763  MemSet(nulls, 0, sizeof(nulls));
764 
765  values[0] = CStringGetTextDatum(prep_stmt->stmt_name);
766  values[1] = CStringGetTextDatum(prep_stmt->plansource->query_string);
767  values[2] = TimestampTzGetDatum(prep_stmt->prepare_time);
768  values[3] = build_regtype_array(prep_stmt->plansource->param_types,
769  prep_stmt->plansource->num_params);
770  values[4] = BoolGetDatum(prep_stmt->from_sql);
771 
772  tuplestore_putvalues(tupstore, tupdesc, values, nulls);
773  }
774  }
775 
776  /* clean up and return the tuplestore */
777  tuplestore_donestoring(tupstore);
778 
779  rsinfo->returnMode = SFRM_Materialize;
780  rsinfo->setResult = tupstore;
781  rsinfo->setDesc = tupdesc;
782 
783  return (Datum) 0;
784 }
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, Datum *values, bool *isnull)
Definition: tuplestore.c:750
#define IsA(nodeptr, _type_)
Definition: nodes.h:576
TupleDesc CreateTemplateTupleDesc(int natts)
Definition: tupdesc.c:44
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:608
#define MemSet(start, val, len)
Definition: c.h:962
static HTAB * prepared_queries
Definition: prepare.c:46
char stmt_name[NAMEDATALEN]
Definition: prepare.h:30
#define ERROR
Definition: elog.h:43
#define TimestampTzGetDatum(X)
Definition: timestamp.h:32
Oid * param_types
Definition: plancache.h:99
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition: tupdesc.c:603
#define ereport(elevel, rest)
Definition: elog.h:141
static Datum build_regtype_array(Oid *param_types, int num_params)
Definition: prepare.c:792
Tuplestorestate * tuplestore_begin_heap(bool randomAccess, bool interXact, int maxKBytes)
Definition: tuplestore.c:318
uintptr_t Datum
Definition: postgres.h:367
int work_mem
Definition: globals.c:121
#define BoolGetDatum(X)
Definition: postgres.h:402
int allowedModes
Definition: execnodes.h:302
TimestampTz prepare_time
Definition: prepare.h:33
SetFunctionReturnMode returnMode
Definition: execnodes.h:304
const char * query_string
Definition: plancache.h:97
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1389
MemoryContext ecxt_per_query_memory
Definition: execnodes.h:230
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1379
Tuplestorestate * setResult
Definition: execnodes.h:307
static Datum values[MAXATTR]
Definition: bootstrap.c:167
ExprContext * econtext
Definition: execnodes.h:300
TupleDesc setDesc
Definition: execnodes.h:308
int errmsg(const char *fmt,...)
Definition: elog.c:822
#define CStringGetTextDatum(s)
Definition: builtins.h:83
int16 AttrNumber
Definition: attnum.h:21

◆ PrepareQuery()

void PrepareQuery ( PrepareStmt stmt,
const char *  queryString,
int  stmt_location,
int  stmt_len 
)

Definition at line 57 of file prepare.c.

References PrepareStmt::argtypes, CMD_DELETE, CMD_INSERT, CMD_SELECT, CMD_UPDATE, Query::commandType, CompleteCachedPlan(), copyObject, CreateCachedPlan(), CreateCommandTag(), CURSOR_OPT_PARALLEL_OK, ereport, errcode(), errmsg(), ERROR, i, InvalidOid, lfirst, list_length(), make_parsestate(), 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().

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 PreparableStmt, 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 }
List * QueryRewrite(Query *parsetree)
Definition: nodes.h:525
int errcode(int sqlerrcode)
Definition: elog.c:608
Query * parse_analyze_varparams(RawStmt *parseTree, const char *sourceText, Oid **paramTypes, int *numParams)
Definition: analyze.c:134
unsigned int Oid
Definition: postgres_ext.h:31
ParseState * make_parsestate(ParseState *parentParseState)
Definition: parse_node.c:43
#define ERROR
Definition: elog.h:43
Node * stmt
Definition: parsenodes.h:1485
CachedPlanSource * CreateCachedPlan(RawStmt *raw_parse_tree, const char *query_string, const char *commandTag)
Definition: plancache.c:164
const char * p_sourcetext
Definition: parse_node.h:176
#define ereport(elevel, rest)
Definition: elog.h:141
const char * CreateCommandTag(Node *parsetree)
Definition: utility.c:2093
int stmt_len
Definition: parsenodes.h:1487
int stmt_location
Definition: parsenodes.h:1486
void StorePreparedStatement(const char *stmt_name, CachedPlanSource *plansource, bool from_sql)
Definition: prepare.c:444
#define InvalidOid
Definition: postgres_ext.h:36
CmdType commandType
Definition: parsenodes.h:112
#define makeNode(_type_)
Definition: nodes.h:573
char * name
Definition: parsenodes.h:3388
#define lfirst(lc)
Definition: pg_list.h:190
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:3390
static int list_length(const List *l)
Definition: pg_list.h:169
List * argtypes
Definition: parsenodes.h:3389
#define CURSOR_OPT_PARALLEL_OK
Definition: parsenodes.h:2692
void * palloc(Size size)
Definition: mcxt.c:949
int errmsg(const char *fmt,...)
Definition: elog.c:822
int i
#define copyObject(obj)
Definition: nodes.h:641
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 444 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().

447 {
448  PreparedStatement *entry;
450  bool found;
451 
452  /* Initialize the hash table, if necessary */
453  if (!prepared_queries)
455 
456  /* Add entry to hash table */
458  stmt_name,
459  HASH_ENTER,
460  &found);
461 
462  /* Shouldn't get a duplicate entry */
463  if (found)
464  ereport(ERROR,
465  (errcode(ERRCODE_DUPLICATE_PSTATEMENT),
466  errmsg("prepared statement \"%s\" already exists",
467  stmt_name)));
468 
469  /* Fill in the hash table entry */
470  entry->plansource = plansource;
471  entry->from_sql = from_sql;
472  entry->prepare_time = cur_ts;
473 
474  /* Now it's safe to move the CachedPlanSource to permanent memory */
475  SaveCachedPlan(plansource);
476 }
static void InitQueryHashTable(void)
Definition: prepare.c:422
CachedPlanSource * plansource
Definition: prepare.h:31
int64 TimestampTz
Definition: timestamp.h:39
int errcode(int sqlerrcode)
Definition: elog.c:608
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:906
static HTAB * prepared_queries
Definition: prepare.c:46
#define ERROR
Definition: elog.h:43
#define ereport(elevel, rest)
Definition: elog.h:141
void SaveCachedPlan(CachedPlanSource *plansource)
Definition: plancache.c:452
TimestampTz prepare_time
Definition: prepare.h:33
int errmsg(const char *fmt,...)
Definition: elog.c:822
TimestampTz GetCurrentStatementStartTimestamp(void)
Definition: xact.c:791

Variable Documentation

◆ prepared_queries

HTAB* prepared_queries = NULL
static

Definition at line 46 of file prepare.c.