#include "commands/explain.h"#include "datatype/timestamp.h"#include "utils/plancache.h"

Go to the source code of this file.
Data Structures | |
| struct | PreparedStatement |
Functions | |
| void | PrepareQuery (PrepareStmt *stmt, const char *queryString) |
| void | ExecuteQuery (ExecuteStmt *stmt, IntoClause *intoClause, const char *queryString, ParamListInfo params, DestReceiver *dest, char *completionTag) |
| void | DeallocateQuery (DeallocateStmt *stmt) |
| void | ExplainExecuteQuery (ExecuteStmt *execstmt, IntoClause *into, ExplainState *es, const char *queryString, ParamListInfo params) |
| void | StorePreparedStatement (const char *stmt_name, CachedPlanSource *plansource, bool from_sql) |
| PreparedStatement * | FetchPreparedStatement (const char *stmt_name, bool throwError) |
| void | DropPreparedStatement (const char *stmt_name, bool showError) |
| TupleDesc | FetchPreparedStatementResultDesc (PreparedStatement *stmt) |
| List * | FetchPreparedStatementTargetList (PreparedStatement *stmt) |
| void | DropAllPreparedStatements (void) |
| 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);
}
}
| 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);
}
| 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);
}
1.7.1