#include "postgres.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"
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) |
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) |
PreparedStatement * | FetchPreparedStatement (const char *stmt_name, bool throwError) |
TupleDesc | FetchPreparedStatementResultDesc (PreparedStatement *stmt) |
List * | FetchPreparedStatementTargetList (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) |
Datum | pg_prepared_statement (PG_FUNCTION_ARGS) |
Variables | |
static HTAB * | prepared_queries = NULL |
Definition at line 781 of file prepare.c.
References construct_array(), i, ObjectIdGetDatum, palloc(), PointerGetDatum, and REGTYPEOID.
Referenced by pg_prepared_statement().
{ Datum *tmp_ary; ArrayType *result; int i; tmp_ary = (Datum *) palloc(num_params * sizeof(Datum)); for (i = 0; i < num_params; i++) tmp_ary[i] = ObjectIdGetDatum(param_types[i]); /* XXX: this hardcodes assumptions about the regtype type */ result = construct_array(tmp_ary, num_params, REGTYPEOID, 4, true, 'i'); return PointerGetDatum(result); }
void DeallocateQuery | ( | DeallocateStmt * | stmt | ) |
Definition at line 556 of file prepare.c.
References DropAllPreparedStatements(), DropPreparedStatement(), and DeallocateStmt::name.
Referenced by standard_ProcessUtility().
{ if (stmt->name) DropPreparedStatement(stmt->name, true); else DropAllPreparedStatements(); }
void DropAllPreparedStatements | ( | void | ) |
Definition at line 591 of file prepare.c.
References DropCachedPlan(), HASH_REMOVE, hash_search(), hash_seq_init(), hash_seq_search(), NULL, PreparedStatement::plansource, and PreparedStatement::stmt_name.
Referenced by DeallocateQuery(), and DiscardAll().
{ HASH_SEQ_STATUS seq; PreparedStatement *entry; /* nothing cached */ if (!prepared_queries) return; /* walk over cache */ hash_seq_init(&seq, prepared_queries); while ((entry = hash_seq_search(&seq)) != NULL) { /* Release the plancache entry */ DropCachedPlan(entry->plansource); /* Now we can remove the hash table entry */ hash_search(prepared_queries, entry->stmt_name, HASH_REMOVE, NULL); } }
void DropPreparedStatement | ( | const char * | stmt_name, | |
bool | showError | |||
) |
Definition at line 570 of file prepare.c.
References DropCachedPlan(), FetchPreparedStatement(), HASH_REMOVE, hash_search(), NULL, PreparedStatement::plansource, and PreparedStatement::stmt_name.
Referenced by DeallocateQuery(), and PostgresMain().
{ PreparedStatement *entry; /* Find the query's hash table entry; raise error if wanted */ entry = FetchPreparedStatement(stmt_name, showError); if (entry) { /* Release the plancache entry */ DropCachedPlan(entry->plansource); /* Now we can remove the hash table entry */ hash_search(prepared_queries, entry->stmt_name, HASH_REMOVE, NULL); } }
static ParamListInfo EvaluateParams | ( | PreparedStatement * | pstmt, | |
List * | params, | |||
const char * | queryString, | |||
EState * | estate | |||
) | [static] |
Definition at line 317 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(), ExecPrepareExpr(), EXPR_KIND_EXECUTE_PARAMETER, exprType(), format_type_be(), GetPerTupleExprContext, i, ParamExternData::isnull, lfirst, list_length(), make_parsestate(), NULL, CachedPlanSource::num_params, ParamListInfoData::numParams, ParseState::p_sourcetext, palloc(), CachedPlanSource::param_types, ParamListInfoData::paramFetch, ParamListInfoData::paramFetchArg, ParamListInfoData::params, ParamListInfoData::parserSetup, ParamListInfoData::parserSetupArg, ParamExternData::pflags, PreparedStatement::plansource, ParamExternData::ptype, PreparedStatement::stmt_name, transformExpr(), and ParamExternData::value.
Referenced by ExecuteQuery(), and ExplainExecuteQuery().
{ Oid *param_types = pstmt->plansource->param_types; int num_params = pstmt->plansource->num_params; int nparams = list_length(params); ParseState *pstate; ParamListInfo paramLI; List *exprstates; ListCell *l; int i; if (nparams != num_params) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("wrong number of parameters for prepared statement \"%s\"", pstmt->stmt_name), errdetail("Expected %d parameters but got %d.", num_params, nparams))); /* Quick exit if no parameters */ if (num_params == 0) return NULL; /* * We have to run parse analysis for the expressions. Since the parser is * not cool about scribbling on its input, copy first. */ params = (List *) copyObject(params); pstate = make_parsestate(NULL); pstate->p_sourcetext = queryString; i = 0; foreach(l, params) { Node *expr = lfirst(l); Oid expected_type_id = param_types[i]; Oid given_type_id; expr = transformExpr(pstate, expr, EXPR_KIND_EXECUTE_PARAMETER); given_type_id = exprType(expr); expr = coerce_to_target_type(pstate, expr, given_type_id, expected_type_id, -1, COERCION_ASSIGNMENT, COERCE_IMPLICIT_CAST, -1); if (expr == NULL) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("parameter $%d of type %s cannot be coerced to the expected type %s", i + 1, format_type_be(given_type_id), format_type_be(expected_type_id)), errhint("You will need to rewrite or cast the expression."))); /* Take care of collations in the finished expression. */ assign_expr_collations(pstate, expr); lfirst(l) = expr; i++; } /* Prepare the expressions for execution */ exprstates = (List *) ExecPrepareExpr((Expr *) params, estate); /* sizeof(ParamListInfoData) includes the first array element */ paramLI = (ParamListInfo) palloc(sizeof(ParamListInfoData) + (num_params - 1) * sizeof(ParamExternData)); /* we have static list of params, so no hooks needed */ paramLI->paramFetch = NULL; paramLI->paramFetchArg = NULL; paramLI->parserSetup = NULL; paramLI->parserSetupArg = NULL; paramLI->numParams = num_params; i = 0; foreach(l, exprstates) { ExprState *n = lfirst(l); ParamExternData *prm = ¶mLI->params[i]; prm->ptype = param_types[i]; prm->pflags = PARAM_FLAG_CONST; prm->value = ExecEvalExprSwitchContext(n, GetPerTupleExprContext(estate), &prm->isnull, NULL); i++; } return paramLI; }
void ExecuteQuery | ( | ExecuteStmt * | stmt, | |
IntoClause * | intoClause, | |||
const char * | queryString, | |||
ParamListInfo | params, | |||
DestReceiver * | dest, | |||
char * | completionTag | |||
) |
Definition at line 188 of file prepare.c.
References CMD_SELECT, CachedPlanSource::commandTag, PlannedStmt::commandType, CreateExecutorState(), CreateNewPortal(), elog, ereport, errcode(), errmsg(), ERROR, EState::es_param_list_info, EvaluateParams(), FetchPreparedStatement(), CachedPlanSource::fixed_result, FreeExecutorState(), GetActiveSnapshot(), GetCachedPlan(), GetIntoRelEFlags(), IsA, linitial, list_length(), MemoryContextStrdup(), ExecuteStmt::name, NULL, CachedPlanSource::num_params, ExecuteStmt::params, PreparedStatement::plansource, PortalDefineQuery(), PortalDrop(), PortalGetHeapMemory, PortalRun(), PortalStart(), CachedPlanSource::query_string, IntoClause::skipData, CachedPlan::stmt_list, PlannedStmt::utilityStmt, and PortalData::visible.
Referenced by ExecCreateTableAs(), and standard_ProcessUtility().
{ PreparedStatement *entry; CachedPlan *cplan; List *plan_list; ParamListInfo paramLI = NULL; EState *estate = NULL; Portal portal; char *query_string; int eflags; long count; /* Look it up in the hash table */ entry = FetchPreparedStatement(stmt->name, true); /* Shouldn't find a non-fixed-result cached plan */ if (!entry->plansource->fixed_result) elog(ERROR, "EXECUTE does not support variable-result cached plans"); /* Evaluate parameters, if any */ if (entry->plansource->num_params > 0) { /* * Need an EState to evaluate parameters; must not delete it till end * of query, in case parameters are pass-by-reference. Note that the * passed-in "params" could possibly be referenced in the parameter * expressions. */ estate = CreateExecutorState(); estate->es_param_list_info = params; paramLI = EvaluateParams(entry, stmt->params, queryString, estate); } /* Create a new portal to run the query in */ portal = CreateNewPortal(); /* Don't display the portal in pg_cursors, it is for internal use only */ portal->visible = false; /* Copy the plan's saved query string into the portal's memory */ query_string = MemoryContextStrdup(PortalGetHeapMemory(portal), entry->plansource->query_string); /* Replan if needed, and increment plan refcount for portal */ cplan = GetCachedPlan(entry->plansource, paramLI, false); plan_list = cplan->stmt_list; /* * For CREATE TABLE ... AS EXECUTE, we must verify that the prepared * statement is one that produces tuples. Currently we insist that it be * a plain old SELECT. In future we might consider supporting other * things such as INSERT ... RETURNING, but there are a couple of issues * to be settled first, notably how WITH NO DATA should be handled in such * a case (do we really want to suppress execution?) and how to pass down * the OID-determining eflags (PortalStart won't handle them in such a * case, and for that matter it's not clear the executor will either). * * For CREATE TABLE ... AS EXECUTE, we also have to ensure that the proper * eflags and fetch count are passed to PortalStart/PortalRun. */ if (intoClause) { PlannedStmt *pstmt; if (list_length(plan_list) != 1) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("prepared statement is not a SELECT"))); pstmt = (PlannedStmt *) linitial(plan_list); if (!IsA(pstmt, PlannedStmt) || pstmt->commandType != CMD_SELECT || pstmt->utilityStmt != NULL) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("prepared statement is not a SELECT"))); /* Set appropriate eflags */ eflags = GetIntoRelEFlags(intoClause); /* And tell PortalRun whether to run to completion or not */ if (intoClause->skipData) count = 0; else count = FETCH_ALL; } else { /* Plain old EXECUTE */ eflags = 0; count = FETCH_ALL; } PortalDefineQuery(portal, NULL, query_string, entry->plansource->commandTag, plan_list, cplan); /* * Run the portal as appropriate. */ PortalStart(portal, paramLI, eflags, GetActiveSnapshot()); (void) PortalRun(portal, count, false, dest, dest, completionTag); PortalDrop(portal, false); if (estate) FreeExecutorState(estate); /* No need to pfree other memory, MemoryContext will be reset */ }
void ExplainExecuteQuery | ( | ExecuteStmt * | execstmt, | |
IntoClause * | into, | |||
ExplainState * | es, | |||
const char * | queryString, | |||
ParamListInfo | params | |||
) |
Definition at line 622 of file prepare.c.
References CreateExecutorState(), elog, ERROR, EState::es_param_list_info, EvaluateParams(), ExplainOnePlan(), ExplainOneUtility(), ExplainSeparatePlans(), FetchPreparedStatement(), CachedPlanSource::fixed_result, FreeExecutorState(), GetCachedPlan(), IsA, lfirst, lnext, ExecuteStmt::name, NULL, CachedPlanSource::num_params, ExecuteStmt::params, PreparedStatement::plansource, CachedPlanSource::query_string, ReleaseCachedPlan(), and CachedPlan::stmt_list.
Referenced by ExplainOneUtility().
{ PreparedStatement *entry; const char *query_string; CachedPlan *cplan; List *plan_list; ListCell *p; ParamListInfo paramLI = NULL; EState *estate = NULL; /* Look it up in the hash table */ entry = FetchPreparedStatement(execstmt->name, true); /* Shouldn't find a non-fixed-result cached plan */ if (!entry->plansource->fixed_result) elog(ERROR, "EXPLAIN EXECUTE does not support variable-result cached plans"); query_string = entry->plansource->query_string; /* Evaluate parameters, if any */ if (entry->plansource->num_params) { /* * Need an EState to evaluate parameters; must not delete it till end * of query, in case parameters are pass-by-reference. Note that the * passed-in "params" could possibly be referenced in the parameter * expressions. */ estate = CreateExecutorState(); estate->es_param_list_info = params; paramLI = EvaluateParams(entry, execstmt->params, queryString, estate); } /* Replan if needed, and acquire a transient refcount */ cplan = GetCachedPlan(entry->plansource, paramLI, true); plan_list = cplan->stmt_list; /* Explain each query */ foreach(p, plan_list) { PlannedStmt *pstmt = (PlannedStmt *) lfirst(p); if (IsA(pstmt, PlannedStmt)) ExplainOnePlan(pstmt, into, es, query_string, paramLI); else ExplainOneUtility((Node *) pstmt, into, es, query_string, paramLI); /* No need for CommandCounterIncrement, as ExplainOnePlan did it */ /* Separate plans with an appropriate separator */ if (lnext(p) != NULL) ExplainSeparatePlans(es); } if (estate) FreeExecutorState(estate); ReleaseCachedPlan(cplan, true); }
PreparedStatement* FetchPreparedStatement | ( | const char * | stmt_name, | |
bool | throwError | |||
) |
Definition at line 485 of file prepare.c.
References ereport, errcode(), errmsg(), ERROR, HASH_FIND, hash_search(), and NULL.
Referenced by DropPreparedStatement(), errdetail_execute(), exec_bind_message(), exec_describe_statement_message(), ExecuteQuery(), ExplainExecuteQuery(), FetchStatementTargetList(), GetCommandLogLevel(), UtilityReturnsTuples(), and UtilityTupleDescriptor().
{ PreparedStatement *entry; /* * If the hash table hasn't been initialized, it can't be storing * anything, therefore it couldn't possibly store our plan. */ if (prepared_queries) entry = (PreparedStatement *) hash_search(prepared_queries, stmt_name, HASH_FIND, NULL); else entry = NULL; if (!entry && throwError) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_PSTATEMENT), errmsg("prepared statement \"%s\" does not exist", stmt_name))); return entry; }
TupleDesc FetchPreparedStatementResultDesc | ( | PreparedStatement * | stmt | ) |
Definition at line 517 of file prepare.c.
References Assert, CreateTupleDescCopy(), CachedPlanSource::fixed_result, PreparedStatement::plansource, and CachedPlanSource::resultDesc.
Referenced by UtilityTupleDescriptor().
{ /* * Since we don't allow prepared statements' result tupdescs to change, * there's no need to worry about revalidating the cached plan here. */ Assert(stmt->plansource->fixed_result); if (stmt->plansource->resultDesc) return CreateTupleDescCopy(stmt->plansource->resultDesc); else return NULL; }
List* FetchPreparedStatementTargetList | ( | PreparedStatement * | stmt | ) |
Definition at line 540 of file prepare.c.
References CachedPlanGetTargetList(), copyObject(), and PreparedStatement::plansource.
Referenced by FetchStatementTargetList().
{ List *tlist; /* Get the plan's primary targetlist */ tlist = CachedPlanGetTargetList(stmt->plansource); /* Copy into caller's context in case plan gets invalidated */ return (List *) copyObject(tlist); }
static void InitQueryHashTable | ( | void | ) | [static] |
Definition at line 421 of file prepare.c.
References HASHCTL::entrysize, hash_create(), HASH_ELEM, HASHCTL::keysize, and MemSet.
Referenced by StorePreparedStatement().
{ HASHCTL hash_ctl; MemSet(&hash_ctl, 0, sizeof(hash_ctl)); hash_ctl.keysize = NAMEDATALEN; hash_ctl.entrysize = sizeof(PreparedStatement); prepared_queries = hash_create("Prepared Queries", 32, &hash_ctl, HASH_ELEM); }
Datum pg_prepared_statement | ( | PG_FUNCTION_ARGS | ) |
Definition at line 690 of file prepare.c.
References ReturnSetInfo::allowedModes, BoolGetDatum, BOOLOID, 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, NULL, CachedPlanSource::num_params, CachedPlanSource::param_types, PreparedStatement::plansource, PreparedStatement::prepare_time, CachedPlanSource::query_string, REGTYPEARRAYOID, ReturnSetInfo::returnMode, ReturnSetInfo::setDesc, ReturnSetInfo::setResult, SFRM_Materialize, SFRM_Materialize_Random, PreparedStatement::stmt_name, TEXTOID, TimestampTzGetDatum, TIMESTAMPTZOID, TupleDescInitEntry(), tuplestore_begin_heap(), tuplestore_donestoring, tuplestore_putvalues(), values, and work_mem.
{ ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; TupleDesc tupdesc; Tuplestorestate *tupstore; MemoryContext per_query_ctx; MemoryContext oldcontext; /* check to see if caller supports us returning a tuplestore */ if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("set-valued function called in context that cannot accept a set"))); if (!(rsinfo->allowedModes & SFRM_Materialize)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("materialize mode required, but it is not " \ "allowed in this context"))); /* need to build tuplestore in query context */ per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; oldcontext = MemoryContextSwitchTo(per_query_ctx); /* * build tupdesc for result tuples. This must match the definition of the * pg_prepared_statements view in system_views.sql */ tupdesc = CreateTemplateTupleDesc(5, false); TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name", TEXTOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 2, "statement", TEXTOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 3, "prepare_time", TIMESTAMPTZOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 4, "parameter_types", REGTYPEARRAYOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 5, "from_sql", BOOLOID, -1, 0); /* * We put all the tuples into a tuplestore in one scan of the hashtable. * This avoids any issue of the hashtable possibly changing between calls. */ tupstore = tuplestore_begin_heap(rsinfo->allowedModes & SFRM_Materialize_Random, false, work_mem); /* generate junk in short-term context */ MemoryContextSwitchTo(oldcontext); /* hash table might be uninitialized */ if (prepared_queries) { HASH_SEQ_STATUS hash_seq; PreparedStatement *prep_stmt; hash_seq_init(&hash_seq, prepared_queries); while ((prep_stmt = hash_seq_search(&hash_seq)) != NULL) { Datum values[5]; bool nulls[5]; MemSet(nulls, 0, sizeof(nulls)); values[0] = CStringGetTextDatum(prep_stmt->stmt_name); values[1] = CStringGetTextDatum(prep_stmt->plansource->query_string); values[2] = TimestampTzGetDatum(prep_stmt->prepare_time); values[3] = build_regtype_array(prep_stmt->plansource->param_types, prep_stmt->plansource->num_params); values[4] = BoolGetDatum(prep_stmt->from_sql); tuplestore_putvalues(tupstore, tupdesc, values, nulls); } } /* clean up and return the tuplestore */ tuplestore_donestoring(tupstore); rsinfo->returnMode = SFRM_Materialize; rsinfo->setResult = tupstore; rsinfo->setDesc = tupdesc; return (Datum) 0; }
void PrepareQuery | ( | PrepareStmt * | stmt, | |
const char * | queryString | |||
) |
Definition at line 55 of file prepare.c.
References PrepareStmt::argtypes, CMD_DELETE, CMD_INSERT, CMD_SELECT, CMD_UPDATE, Query::commandType, CompleteCachedPlan(), copyObject(), CreateCachedPlan(), CreateCommandTag(), ereport, errcode(), errmsg(), ERROR, i, InvalidOid, lfirst, list_length(), make_parsestate(), PrepareStmt::name, NULL, ParseState::p_sourcetext, palloc(), parse_analyze_varparams(), PrepareStmt::query, QueryRewrite(), StorePreparedStatement(), typenameTypeId(), and UNKNOWNOID.
Referenced by standard_ProcessUtility().
{ CachedPlanSource *plansource; Oid *argtypes = NULL; int nargs; Query *query; List *query_list; int i; /* * Disallow empty-string statement name (conflicts with protocol-level * unnamed statement). */ if (!stmt->name || stmt->name[0] == '\0') ereport(ERROR, (errcode(ERRCODE_INVALID_PSTATEMENT_DEFINITION), errmsg("invalid statement name: must not be empty"))); /* * Create the CachedPlanSource before we do parse analysis, since it needs * to see the unmodified raw parse tree. */ plansource = CreateCachedPlan(stmt->query, queryString, CreateCommandTag(stmt->query)); /* Transform list of TypeNames to array of type OIDs */ nargs = list_length(stmt->argtypes); if (nargs) { ParseState *pstate; ListCell *l; /* * typenameTypeId wants a ParseState to carry the source query string. * Is it worth refactoring its API to avoid this? */ pstate = make_parsestate(NULL); pstate->p_sourcetext = queryString; argtypes = (Oid *) palloc(nargs * sizeof(Oid)); i = 0; foreach(l, stmt->argtypes) { TypeName *tn = lfirst(l); Oid toid = typenameTypeId(pstate, tn); argtypes[i++] = toid; } } /* * Analyze the statement using these parameter types (any parameters * passed in from above us will not be visible to it), allowing * information about unknown parameters to be deduced from context. * * Because parse analysis scribbles on the raw querytree, we must make a * copy to ensure we don't modify the passed-in tree. FIXME someday. */ query = parse_analyze_varparams((Node *) copyObject(stmt->query), queryString, &argtypes, &nargs); /* * Check that all parameter types were determined. */ for (i = 0; i < nargs; i++) { Oid argtype = argtypes[i]; if (argtype == InvalidOid || argtype == UNKNOWNOID) ereport(ERROR, (errcode(ERRCODE_INDETERMINATE_DATATYPE), errmsg("could not determine data type of parameter $%d", i + 1))); } /* * grammar only allows OptimizableStmt, so this check should be redundant */ switch (query->commandType) { case CMD_SELECT: case CMD_INSERT: case CMD_UPDATE: case CMD_DELETE: /* OK */ break; default: ereport(ERROR, (errcode(ERRCODE_INVALID_PSTATEMENT_DEFINITION), errmsg("utility statements cannot be prepared"))); break; } /* Rewrite the query. The result could be 0, 1, or many queries. */ query_list = QueryRewrite(query); /* Finish filling in the CachedPlanSource */ CompleteCachedPlan(plansource, query_list, NULL, argtypes, nargs, NULL, NULL, 0, /* default cursor options */ true); /* fixed result */ /* * Save the results. */ StorePreparedStatement(stmt->name, plansource, true); }
void StorePreparedStatement | ( | const char * | stmt_name, | |
CachedPlanSource * | plansource, | |||
bool | from_sql | |||
) |
Definition at line 443 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().
{ PreparedStatement *entry; TimestampTz cur_ts = GetCurrentStatementStartTimestamp(); bool found; /* Initialize the hash table, if necessary */ if (!prepared_queries) InitQueryHashTable(); /* Add entry to hash table */ entry = (PreparedStatement *) hash_search(prepared_queries, stmt_name, HASH_ENTER, &found); /* Shouldn't get a duplicate entry */ if (found) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_PSTATEMENT), errmsg("prepared statement \"%s\" already exists", stmt_name))); /* Fill in the hash table entry */ entry->plansource = plansource; entry->from_sql = from_sql; entry->prepare_time = cur_ts; /* Now it's safe to move the CachedPlanSource to permanent memory */ SaveCachedPlan(plansource); }
HTAB* prepared_queries = NULL [static] |