Move routines to manipulate WAL into PostgreSQL::Test::Cluster
[pgsql.git] / src / backend / commands / prepare.c
blob8989c0c882d700aef8f1238877d3b851f1922672
1 /*-------------------------------------------------------------------------
3 * prepare.c
4 * Prepareable SQL statements via PREPARE, EXECUTE and DEALLOCATE
6 * This module also implements storage of prepared statements that are
7 * accessed via the extended FE/BE query protocol.
10 * Copyright (c) 2002-2025, PostgreSQL Global Development Group
12 * IDENTIFICATION
13 * src/backend/commands/prepare.c
15 *-------------------------------------------------------------------------
17 #include "postgres.h"
19 #include <limits.h>
21 #include "access/xact.h"
22 #include "catalog/pg_type.h"
23 #include "commands/createas.h"
24 #include "commands/prepare.h"
25 #include "funcapi.h"
26 #include "nodes/nodeFuncs.h"
27 #include "parser/parse_coerce.h"
28 #include "parser/parse_collate.h"
29 #include "parser/parse_expr.h"
30 #include "parser/parse_type.h"
31 #include "tcop/pquery.h"
32 #include "tcop/utility.h"
33 #include "utils/builtins.h"
34 #include "utils/snapmgr.h"
35 #include "utils/timestamp.h"
39 * The hash table in which prepared queries are stored. This is
40 * per-backend: query plans are not shared between backends.
41 * The keys for this hash table are the arguments to PREPARE and EXECUTE
42 * (statement names); the entries are PreparedStatement structs.
44 static HTAB *prepared_queries = NULL;
46 static void InitQueryHashTable(void);
47 static ParamListInfo EvaluateParams(ParseState *pstate,
48 PreparedStatement *pstmt, List *params,
49 EState *estate);
50 static Datum build_regtype_array(Oid *param_types, int num_params);
53 * Implements the 'PREPARE' utility statement.
55 void
56 PrepareQuery(ParseState *pstate, PrepareStmt *stmt,
57 int stmt_location, int stmt_len)
59 RawStmt *rawstmt;
60 CachedPlanSource *plansource;
61 Oid *argtypes = NULL;
62 int nargs;
63 List *query_list;
66 * Disallow empty-string statement name (conflicts with protocol-level
67 * unnamed statement).
69 if (!stmt->name || stmt->name[0] == '\0')
70 ereport(ERROR,
71 (errcode(ERRCODE_INVALID_PSTATEMENT_DEFINITION),
72 errmsg("invalid statement name: must not be empty")));
75 * Need to wrap the contained statement in a RawStmt node to pass it to
76 * parse analysis.
78 rawstmt = makeNode(RawStmt);
79 rawstmt->stmt = stmt->query;
80 rawstmt->stmt_location = stmt_location;
81 rawstmt->stmt_len = stmt_len;
84 * Create the CachedPlanSource before we do parse analysis, since it needs
85 * to see the unmodified raw parse tree.
87 plansource = CreateCachedPlan(rawstmt, pstate->p_sourcetext,
88 CreateCommandTag(stmt->query));
90 /* Transform list of TypeNames to array of type OIDs */
91 nargs = list_length(stmt->argtypes);
93 if (nargs)
95 int i;
96 ListCell *l;
98 argtypes = palloc_array(Oid, nargs);
99 i = 0;
101 foreach(l, stmt->argtypes)
103 TypeName *tn = lfirst(l);
104 Oid toid = typenameTypeId(pstate, tn);
106 argtypes[i++] = toid;
111 * Analyze the statement using these parameter types (any parameters
112 * passed in from above us will not be visible to it), allowing
113 * information about unknown parameters to be deduced from context.
114 * Rewrite the query. The result could be 0, 1, or many queries.
116 query_list = pg_analyze_and_rewrite_varparams(rawstmt, pstate->p_sourcetext,
117 &argtypes, &nargs, NULL);
119 /* Finish filling in the CachedPlanSource */
120 CompleteCachedPlan(plansource,
121 query_list,
122 NULL,
123 argtypes,
124 nargs,
125 NULL,
126 NULL,
127 CURSOR_OPT_PARALLEL_OK, /* allow parallel mode */
128 true); /* fixed result */
131 * Save the results.
133 StorePreparedStatement(stmt->name,
134 plansource,
135 true);
139 * ExecuteQuery --- implement the 'EXECUTE' utility statement.
141 * This code also supports CREATE TABLE ... AS EXECUTE. That case is
142 * indicated by passing a non-null intoClause. The DestReceiver is already
143 * set up correctly for CREATE TABLE AS, but we still have to make a few
144 * other adjustments here.
146 void
147 ExecuteQuery(ParseState *pstate,
148 ExecuteStmt *stmt, IntoClause *intoClause,
149 ParamListInfo params,
150 DestReceiver *dest, QueryCompletion *qc)
152 PreparedStatement *entry;
153 CachedPlan *cplan;
154 List *plan_list;
155 ParamListInfo paramLI = NULL;
156 EState *estate = NULL;
157 Portal portal;
158 char *query_string;
159 int eflags;
160 long count;
162 /* Look it up in the hash table */
163 entry = FetchPreparedStatement(stmt->name, true);
165 /* Shouldn't find a non-fixed-result cached plan */
166 if (!entry->plansource->fixed_result)
167 elog(ERROR, "EXECUTE does not support variable-result cached plans");
169 /* Evaluate parameters, if any */
170 if (entry->plansource->num_params > 0)
173 * Need an EState to evaluate parameters; must not delete it till end
174 * of query, in case parameters are pass-by-reference. Note that the
175 * passed-in "params" could possibly be referenced in the parameter
176 * expressions.
178 estate = CreateExecutorState();
179 estate->es_param_list_info = params;
180 paramLI = EvaluateParams(pstate, entry, stmt->params, estate);
183 /* Create a new portal to run the query in */
184 portal = CreateNewPortal();
185 /* Don't display the portal in pg_cursors, it is for internal use only */
186 portal->visible = false;
188 /* Copy the plan's saved query string into the portal's memory */
189 query_string = MemoryContextStrdup(portal->portalContext,
190 entry->plansource->query_string);
192 /* Replan if needed, and increment plan refcount for portal */
193 cplan = GetCachedPlan(entry->plansource, paramLI, NULL, NULL);
194 plan_list = cplan->stmt_list;
197 * DO NOT add any logic that could possibly throw an error between
198 * GetCachedPlan and PortalDefineQuery, or you'll leak the plan refcount.
200 PortalDefineQuery(portal,
201 NULL,
202 query_string,
203 entry->plansource->commandTag,
204 plan_list,
205 cplan);
208 * For CREATE TABLE ... AS EXECUTE, we must verify that the prepared
209 * statement is one that produces tuples. Currently we insist that it be
210 * a plain old SELECT. In future we might consider supporting other
211 * things such as INSERT ... RETURNING, but there are a couple of issues
212 * to be settled first, notably how WITH NO DATA should be handled in such
213 * a case (do we really want to suppress execution?) and how to pass down
214 * the OID-determining eflags (PortalStart won't handle them in such a
215 * case, and for that matter it's not clear the executor will either).
217 * For CREATE TABLE ... AS EXECUTE, we also have to ensure that the proper
218 * eflags and fetch count are passed to PortalStart/PortalRun.
220 if (intoClause)
222 PlannedStmt *pstmt;
224 if (list_length(plan_list) != 1)
225 ereport(ERROR,
226 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
227 errmsg("prepared statement is not a SELECT")));
228 pstmt = linitial_node(PlannedStmt, plan_list);
229 if (pstmt->commandType != CMD_SELECT)
230 ereport(ERROR,
231 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
232 errmsg("prepared statement is not a SELECT")));
234 /* Set appropriate eflags */
235 eflags = GetIntoRelEFlags(intoClause);
237 /* And tell PortalRun whether to run to completion or not */
238 if (intoClause->skipData)
239 count = 0;
240 else
241 count = FETCH_ALL;
243 else
245 /* Plain old EXECUTE */
246 eflags = 0;
247 count = FETCH_ALL;
251 * Run the portal as appropriate.
253 PortalStart(portal, paramLI, eflags, GetActiveSnapshot());
255 (void) PortalRun(portal, count, false, dest, dest, qc);
257 PortalDrop(portal, false);
259 if (estate)
260 FreeExecutorState(estate);
262 /* No need to pfree other memory, MemoryContext will be reset */
266 * EvaluateParams: evaluate a list of parameters.
268 * pstate: parse state
269 * pstmt: statement we are getting parameters for.
270 * params: list of given parameter expressions (raw parser output!)
271 * estate: executor state to use.
273 * Returns a filled-in ParamListInfo -- this can later be passed to
274 * CreateQueryDesc(), which allows the executor to make use of the parameters
275 * during query execution.
277 static ParamListInfo
278 EvaluateParams(ParseState *pstate, PreparedStatement *pstmt, List *params,
279 EState *estate)
281 Oid *param_types = pstmt->plansource->param_types;
282 int num_params = pstmt->plansource->num_params;
283 int nparams = list_length(params);
284 ParamListInfo paramLI;
285 List *exprstates;
286 ListCell *l;
287 int i;
289 if (nparams != num_params)
290 ereport(ERROR,
291 (errcode(ERRCODE_SYNTAX_ERROR),
292 errmsg("wrong number of parameters for prepared statement \"%s\"",
293 pstmt->stmt_name),
294 errdetail("Expected %d parameters but got %d.",
295 num_params, nparams)));
297 /* Quick exit if no parameters */
298 if (num_params == 0)
299 return NULL;
302 * We have to run parse analysis for the expressions. Since the parser is
303 * not cool about scribbling on its input, copy first.
305 params = copyObject(params);
307 i = 0;
308 foreach(l, params)
310 Node *expr = lfirst(l);
311 Oid expected_type_id = param_types[i];
312 Oid given_type_id;
314 expr = transformExpr(pstate, expr, EXPR_KIND_EXECUTE_PARAMETER);
316 given_type_id = exprType(expr);
318 expr = coerce_to_target_type(pstate, expr, given_type_id,
319 expected_type_id, -1,
320 COERCION_ASSIGNMENT,
321 COERCE_IMPLICIT_CAST,
322 -1);
324 if (expr == NULL)
325 ereport(ERROR,
326 (errcode(ERRCODE_DATATYPE_MISMATCH),
327 errmsg("parameter $%d of type %s cannot be coerced to the expected type %s",
328 i + 1,
329 format_type_be(given_type_id),
330 format_type_be(expected_type_id)),
331 errhint("You will need to rewrite or cast the expression."),
332 parser_errposition(pstate, exprLocation(lfirst(l)))));
334 /* Take care of collations in the finished expression. */
335 assign_expr_collations(pstate, expr);
337 lfirst(l) = expr;
338 i++;
341 /* Prepare the expressions for execution */
342 exprstates = ExecPrepareExprList(params, estate);
344 paramLI = makeParamList(num_params);
346 i = 0;
347 foreach(l, exprstates)
349 ExprState *n = (ExprState *) lfirst(l);
350 ParamExternData *prm = &paramLI->params[i];
352 prm->ptype = param_types[i];
353 prm->pflags = PARAM_FLAG_CONST;
354 prm->value = ExecEvalExprSwitchContext(n,
355 GetPerTupleExprContext(estate),
356 &prm->isnull);
358 i++;
361 return paramLI;
366 * Initialize query hash table upon first use.
368 static void
369 InitQueryHashTable(void)
371 HASHCTL hash_ctl;
373 hash_ctl.keysize = NAMEDATALEN;
374 hash_ctl.entrysize = sizeof(PreparedStatement);
376 prepared_queries = hash_create("Prepared Queries",
378 &hash_ctl,
379 HASH_ELEM | HASH_STRINGS);
383 * Store all the data pertaining to a query in the hash table using
384 * the specified key. The passed CachedPlanSource should be "unsaved"
385 * in case we get an error here; we'll save it once we've created the hash
386 * table entry.
388 void
389 StorePreparedStatement(const char *stmt_name,
390 CachedPlanSource *plansource,
391 bool from_sql)
393 PreparedStatement *entry;
394 TimestampTz cur_ts = GetCurrentStatementStartTimestamp();
395 bool found;
397 /* Initialize the hash table, if necessary */
398 if (!prepared_queries)
399 InitQueryHashTable();
401 /* Add entry to hash table */
402 entry = (PreparedStatement *) hash_search(prepared_queries,
403 stmt_name,
404 HASH_ENTER,
405 &found);
407 /* Shouldn't get a duplicate entry */
408 if (found)
409 ereport(ERROR,
410 (errcode(ERRCODE_DUPLICATE_PSTATEMENT),
411 errmsg("prepared statement \"%s\" already exists",
412 stmt_name)));
414 /* Fill in the hash table entry */
415 entry->plansource = plansource;
416 entry->from_sql = from_sql;
417 entry->prepare_time = cur_ts;
419 /* Now it's safe to move the CachedPlanSource to permanent memory */
420 SaveCachedPlan(plansource);
424 * Lookup an existing query in the hash table. If the query does not
425 * actually exist, throw ereport(ERROR) or return NULL per second parameter.
427 * Note: this does not force the referenced plancache entry to be valid,
428 * since not all callers care.
430 PreparedStatement *
431 FetchPreparedStatement(const char *stmt_name, bool throwError)
433 PreparedStatement *entry;
436 * If the hash table hasn't been initialized, it can't be storing
437 * anything, therefore it couldn't possibly store our plan.
439 if (prepared_queries)
440 entry = (PreparedStatement *) hash_search(prepared_queries,
441 stmt_name,
442 HASH_FIND,
443 NULL);
444 else
445 entry = NULL;
447 if (!entry && throwError)
448 ereport(ERROR,
449 (errcode(ERRCODE_UNDEFINED_PSTATEMENT),
450 errmsg("prepared statement \"%s\" does not exist",
451 stmt_name)));
453 return entry;
457 * Given a prepared statement, determine the result tupledesc it will
458 * produce. Returns NULL if the execution will not return tuples.
460 * Note: the result is created or copied into current memory context.
462 TupleDesc
463 FetchPreparedStatementResultDesc(PreparedStatement *stmt)
466 * Since we don't allow prepared statements' result tupdescs to change,
467 * there's no need to worry about revalidating the cached plan here.
469 Assert(stmt->plansource->fixed_result);
470 if (stmt->plansource->resultDesc)
471 return CreateTupleDescCopy(stmt->plansource->resultDesc);
472 else
473 return NULL;
477 * Given a prepared statement that returns tuples, extract the query
478 * targetlist. Returns NIL if the statement doesn't have a determinable
479 * targetlist.
481 * Note: this is pretty ugly, but since it's only used in corner cases like
482 * Describe Statement on an EXECUTE command, we don't worry too much about
483 * efficiency.
485 List *
486 FetchPreparedStatementTargetList(PreparedStatement *stmt)
488 List *tlist;
490 /* Get the plan's primary targetlist */
491 tlist = CachedPlanGetTargetList(stmt->plansource, NULL);
493 /* Copy into caller's context in case plan gets invalidated */
494 return copyObject(tlist);
498 * Implements the 'DEALLOCATE' utility statement: deletes the
499 * specified plan from storage.
501 void
502 DeallocateQuery(DeallocateStmt *stmt)
504 if (stmt->name)
505 DropPreparedStatement(stmt->name, true);
506 else
507 DropAllPreparedStatements();
511 * Internal version of DEALLOCATE
513 * If showError is false, dropping a nonexistent statement is a no-op.
515 void
516 DropPreparedStatement(const char *stmt_name, bool showError)
518 PreparedStatement *entry;
520 /* Find the query's hash table entry; raise error if wanted */
521 entry = FetchPreparedStatement(stmt_name, showError);
523 if (entry)
525 /* Release the plancache entry */
526 DropCachedPlan(entry->plansource);
528 /* Now we can remove the hash table entry */
529 hash_search(prepared_queries, entry->stmt_name, HASH_REMOVE, NULL);
534 * Drop all cached statements.
536 void
537 DropAllPreparedStatements(void)
539 HASH_SEQ_STATUS seq;
540 PreparedStatement *entry;
542 /* nothing cached */
543 if (!prepared_queries)
544 return;
546 /* walk over cache */
547 hash_seq_init(&seq, prepared_queries);
548 while ((entry = hash_seq_search(&seq)) != NULL)
550 /* Release the plancache entry */
551 DropCachedPlan(entry->plansource);
553 /* Now we can remove the hash table entry */
554 hash_search(prepared_queries, entry->stmt_name, HASH_REMOVE, NULL);
559 * Implements the 'EXPLAIN EXECUTE' utility statement.
561 * "into" is NULL unless we are doing EXPLAIN CREATE TABLE AS EXECUTE,
562 * in which case executing the query should result in creating that table.
564 * Note: the passed-in pstate's queryString is that of the EXPLAIN EXECUTE,
565 * not the original PREPARE; we get the latter string from the plancache.
567 void
568 ExplainExecuteQuery(ExecuteStmt *execstmt, IntoClause *into, ExplainState *es,
569 ParseState *pstate, ParamListInfo params)
571 PreparedStatement *entry;
572 const char *query_string;
573 CachedPlan *cplan;
574 List *plan_list;
575 ListCell *p;
576 ParamListInfo paramLI = NULL;
577 EState *estate = NULL;
578 instr_time planstart;
579 instr_time planduration;
580 BufferUsage bufusage_start,
581 bufusage;
582 MemoryContextCounters mem_counters;
583 MemoryContext planner_ctx = NULL;
584 MemoryContext saved_ctx = NULL;
586 if (es->memory)
588 /* See ExplainOneQuery about this */
589 Assert(IsA(CurrentMemoryContext, AllocSetContext));
590 planner_ctx = AllocSetContextCreate(CurrentMemoryContext,
591 "explain analyze planner context",
592 ALLOCSET_DEFAULT_SIZES);
593 saved_ctx = MemoryContextSwitchTo(planner_ctx);
596 if (es->buffers)
597 bufusage_start = pgBufferUsage;
598 INSTR_TIME_SET_CURRENT(planstart);
600 /* Look it up in the hash table */
601 entry = FetchPreparedStatement(execstmt->name, true);
603 /* Shouldn't find a non-fixed-result cached plan */
604 if (!entry->plansource->fixed_result)
605 elog(ERROR, "EXPLAIN EXECUTE does not support variable-result cached plans");
607 query_string = entry->plansource->query_string;
609 /* Evaluate parameters, if any */
610 if (entry->plansource->num_params)
612 ParseState *pstate_params;
614 pstate_params = make_parsestate(NULL);
615 pstate_params->p_sourcetext = pstate->p_sourcetext;
618 * Need an EState to evaluate parameters; must not delete it till end
619 * of query, in case parameters are pass-by-reference. Note that the
620 * passed-in "params" could possibly be referenced in the parameter
621 * expressions.
623 estate = CreateExecutorState();
624 estate->es_param_list_info = params;
626 paramLI = EvaluateParams(pstate_params, entry, execstmt->params, estate);
629 /* Replan if needed, and acquire a transient refcount */
630 cplan = GetCachedPlan(entry->plansource, paramLI,
631 CurrentResourceOwner, pstate->p_queryEnv);
633 INSTR_TIME_SET_CURRENT(planduration);
634 INSTR_TIME_SUBTRACT(planduration, planstart);
636 if (es->memory)
638 MemoryContextSwitchTo(saved_ctx);
639 MemoryContextMemConsumed(planner_ctx, &mem_counters);
642 /* calc differences of buffer counters. */
643 if (es->buffers)
645 memset(&bufusage, 0, sizeof(BufferUsage));
646 BufferUsageAccumDiff(&bufusage, &pgBufferUsage, &bufusage_start);
649 plan_list = cplan->stmt_list;
651 /* Explain each query */
652 foreach(p, plan_list)
654 PlannedStmt *pstmt = lfirst_node(PlannedStmt, p);
656 if (pstmt->commandType != CMD_UTILITY)
657 ExplainOnePlan(pstmt, into, es, query_string, paramLI, pstate->p_queryEnv,
658 &planduration, (es->buffers ? &bufusage : NULL),
659 es->memory ? &mem_counters : NULL);
660 else
661 ExplainOneUtility(pstmt->utilityStmt, into, es, pstate, paramLI);
663 /* No need for CommandCounterIncrement, as ExplainOnePlan did it */
665 /* Separate plans with an appropriate separator */
666 if (lnext(plan_list, p) != NULL)
667 ExplainSeparatePlans(es);
670 if (estate)
671 FreeExecutorState(estate);
673 ReleaseCachedPlan(cplan, CurrentResourceOwner);
677 * This set returning function reads all the prepared statements and
678 * returns a set of (name, statement, prepare_time, param_types, from_sql,
679 * generic_plans, custom_plans).
681 Datum
682 pg_prepared_statement(PG_FUNCTION_ARGS)
684 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
687 * We put all the tuples into a tuplestore in one scan of the hashtable.
688 * This avoids any issue of the hashtable possibly changing between calls.
690 InitMaterializedSRF(fcinfo, 0);
692 /* hash table might be uninitialized */
693 if (prepared_queries)
695 HASH_SEQ_STATUS hash_seq;
696 PreparedStatement *prep_stmt;
698 hash_seq_init(&hash_seq, prepared_queries);
699 while ((prep_stmt = hash_seq_search(&hash_seq)) != NULL)
701 TupleDesc result_desc;
702 Datum values[8];
703 bool nulls[8] = {0};
705 result_desc = prep_stmt->plansource->resultDesc;
707 values[0] = CStringGetTextDatum(prep_stmt->stmt_name);
708 values[1] = CStringGetTextDatum(prep_stmt->plansource->query_string);
709 values[2] = TimestampTzGetDatum(prep_stmt->prepare_time);
710 values[3] = build_regtype_array(prep_stmt->plansource->param_types,
711 prep_stmt->plansource->num_params);
712 if (result_desc)
714 Oid *result_types;
716 result_types = palloc_array(Oid, result_desc->natts);
717 for (int i = 0; i < result_desc->natts; i++)
718 result_types[i] = TupleDescAttr(result_desc, i)->atttypid;
719 values[4] = build_regtype_array(result_types, result_desc->natts);
721 else
723 /* no result descriptor (for example, DML statement) */
724 nulls[4] = true;
726 values[5] = BoolGetDatum(prep_stmt->from_sql);
727 values[6] = Int64GetDatumFast(prep_stmt->plansource->num_generic_plans);
728 values[7] = Int64GetDatumFast(prep_stmt->plansource->num_custom_plans);
730 tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc,
731 values, nulls);
735 return (Datum) 0;
739 * This utility function takes a C array of Oids, and returns a Datum
740 * pointing to a one-dimensional Postgres array of regtypes. An empty
741 * array is returned as a zero-element array, not NULL.
743 static Datum
744 build_regtype_array(Oid *param_types, int num_params)
746 Datum *tmp_ary;
747 ArrayType *result;
748 int i;
750 tmp_ary = palloc_array(Datum, num_params);
752 for (i = 0; i < num_params; i++)
753 tmp_ary[i] = ObjectIdGetDatum(param_types[i]);
755 result = construct_array_builtin(tmp_ary, num_params, REGTYPEOID);
756 return PointerGetDatum(result);