aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/execMain.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2007-02-20 17:32:18 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2007-02-20 17:32:18 +0000
commit9cbd0c155d1602aad879f510256b626c58942080 (patch)
tree6d5504a4e841313d3a29cead80067006dc408e39 /src/backend/executor/execMain.c
parent71b0cf2f6bec3129f2c3f574d4e47408c2dc2516 (diff)
downloadpostgresql-9cbd0c155d1602aad879f510256b626c58942080.tar.gz
postgresql-9cbd0c155d1602aad879f510256b626c58942080.zip
Remove the Query structure from the executor's API. This allows us to stop
storing mostly-redundant Query trees in prepared statements, portals, etc. To replace Query, a new node type called PlannedStmt is inserted by the planner at the top of a completed plan tree; this carries just the fields of Query that are still needed at runtime. The statement lists kept in portals etc. now consist of intermixed PlannedStmt and bare utility-statement nodes --- no Query. This incidentally allows us to remove some fields from Query and Plan nodes that shouldn't have been there in the first place. Still to do: simplify the execution-time range table; at the moment the range table passed to the executor still contains Query trees for subqueries. initdb forced due to change of stored rules.
Diffstat (limited to 'src/backend/executor/execMain.c')
-rw-r--r--src/backend/executor/execMain.c154
1 files changed, 72 insertions, 82 deletions
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 91a76bb0779..405b58f9fd6 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -26,7 +26,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.286 2007/02/02 00:07:02 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.287 2007/02/20 17:32:14 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -93,7 +93,8 @@ static void ExecProcessReturning(ProjectionInfo *projectReturning,
static TupleTableSlot *EvalPlanQualNext(EState *estate);
static void EndEvalPlanQual(EState *estate);
static void ExecCheckRTEPerms(RangeTblEntry *rte);
-static void ExecCheckXactReadOnly(Query *parsetree);
+static void ExecCheckXactReadOnly(PlannedStmt *plannedstmt);
+static void ExecCheckRangeTblReadOnly(List *rtable);
static void EvalPlanQualStart(evalPlanQual *epq, EState *estate,
evalPlanQual *priorepq);
static void EvalPlanQualStop(evalPlanQual *epq);
@@ -139,7 +140,7 @@ ExecutorStart(QueryDesc *queryDesc, int eflags)
* planned to non-temporary tables. EXPLAIN is considered read-only.
*/
if (XactReadOnly && !(eflags & EXEC_FLAG_EXPLAIN_ONLY))
- ExecCheckXactReadOnly(queryDesc->parsetree);
+ ExecCheckXactReadOnly(queryDesc->plannedstmt);
/*
* Build EState, switch into per-query memory context for startup.
@@ -154,9 +155,9 @@ ExecutorStart(QueryDesc *queryDesc, int eflags)
*/
estate->es_param_list_info = queryDesc->params;
- if (queryDesc->plantree->nParamExec > 0)
+ if (queryDesc->plannedstmt->nParamExec > 0)
estate->es_param_exec_vals = (ParamExecData *)
- palloc0(queryDesc->plantree->nParamExec * sizeof(ParamExecData));
+ palloc0(queryDesc->plannedstmt->nParamExec * sizeof(ParamExecData));
/*
* Copy other important information into the EState
@@ -227,7 +228,7 @@ ExecutorRun(QueryDesc *queryDesc,
estate->es_lastoid = InvalidOid;
sendTuples = (operation == CMD_SELECT ||
- queryDesc->parsetree->returningList);
+ queryDesc->plannedstmt->returningLists);
if (sendTuples)
(*dest->rStartup) (dest, operation, queryDesc->tupDesc);
@@ -414,26 +415,41 @@ ExecCheckRTEPerms(RangeTblEntry *rte)
* Check that the query does not imply any writes to non-temp tables.
*/
static void
-ExecCheckXactReadOnly(Query *parsetree)
+ExecCheckXactReadOnly(PlannedStmt *plannedstmt)
{
- ListCell *l;
-
/*
* CREATE TABLE AS or SELECT INTO?
*
* XXX should we allow this if the destination is temp?
*/
- if (parsetree->into != NULL)
+ if (plannedstmt->into != NULL)
goto fail;
/* Fail if write permissions are requested on any non-temp table */
- foreach(l, parsetree->rtable)
+ ExecCheckRangeTblReadOnly(plannedstmt->rtable);
+
+ return;
+
+fail:
+ ereport(ERROR,
+ (errcode(ERRCODE_READ_ONLY_SQL_TRANSACTION),
+ errmsg("transaction is read-only")));
+}
+
+static void
+ExecCheckRangeTblReadOnly(List *rtable)
+{
+ ListCell *l;
+
+ /* Fail if write permissions are requested on any non-temp table */
+ foreach(l, rtable)
{
RangeTblEntry *rte = lfirst(l);
if (rte->rtekind == RTE_SUBQUERY)
{
- ExecCheckXactReadOnly(rte->subquery);
+ Assert(!rte->subquery->into);
+ ExecCheckRangeTblReadOnly(rte->subquery->rtable);
continue;
}
@@ -469,11 +485,11 @@ static void
InitPlan(QueryDesc *queryDesc, int eflags)
{
CmdType operation = queryDesc->operation;
- Query *parseTree = queryDesc->parsetree;
- Plan *plan = queryDesc->plantree;
+ PlannedStmt *plannedstmt = queryDesc->plannedstmt;
+ Plan *plan = plannedstmt->planTree;
+ List *rangeTable = plannedstmt->rtable;
EState *estate = queryDesc->estate;
PlanState *planstate;
- List *rangeTable;
TupleDesc tupType;
ListCell *l;
@@ -482,12 +498,7 @@ InitPlan(QueryDesc *queryDesc, int eflags)
* rangetable here --- subplan RTEs will be checked during
* ExecInitSubPlan().
*/
- ExecCheckRTPerms(parseTree->rtable);
-
- /*
- * get information from query descriptor
- */
- rangeTable = parseTree->rtable;
+ ExecCheckRTPerms(rangeTable);
/*
* initialize the node's execution state
@@ -495,50 +506,27 @@ InitPlan(QueryDesc *queryDesc, int eflags)
estate->es_range_table = rangeTable;
/*
- * if there is a result relation, initialize result relation stuff
+ * initialize result relation stuff
*/
- if (parseTree->resultRelation)
+ if (plannedstmt->resultRelations)
{
- List *resultRelations = parseTree->resultRelations;
- int numResultRelations;
+ List *resultRelations = plannedstmt->resultRelations;
+ int numResultRelations = list_length(resultRelations);
ResultRelInfo *resultRelInfos;
+ ResultRelInfo *resultRelInfo;
- if (resultRelations != NIL)
- {
- /*
- * Multiple result relations (due to inheritance)
- * parseTree->resultRelations identifies them all
- */
- ResultRelInfo *resultRelInfo;
-
- numResultRelations = list_length(resultRelations);
- resultRelInfos = (ResultRelInfo *)
- palloc(numResultRelations * sizeof(ResultRelInfo));
- resultRelInfo = resultRelInfos;
- foreach(l, resultRelations)
- {
- initResultRelInfo(resultRelInfo,
- lfirst_int(l),
- rangeTable,
- operation,
- estate->es_instrument);
- resultRelInfo++;
- }
- }
- else
+ resultRelInfos = (ResultRelInfo *)
+ palloc(numResultRelations * sizeof(ResultRelInfo));
+ resultRelInfo = resultRelInfos;
+ foreach(l, resultRelations)
{
- /*
- * Single result relation identified by parseTree->resultRelation
- */
- numResultRelations = 1;
- resultRelInfos = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
- initResultRelInfo(resultRelInfos,
- parseTree->resultRelation,
+ initResultRelInfo(resultRelInfo,
+ lfirst_int(l),
rangeTable,
operation,
estate->es_instrument);
+ resultRelInfo++;
}
-
estate->es_result_relations = resultRelInfos;
estate->es_num_result_relations = numResultRelations;
/* Initialize to first or only result rel */
@@ -560,10 +548,10 @@ InitPlan(QueryDesc *queryDesc, int eflags)
* correct tuple descriptors. (Other SELECT INTO stuff comes later.)
*/
estate->es_select_into = false;
- if (operation == CMD_SELECT && parseTree->into != NULL)
+ if (operation == CMD_SELECT && plannedstmt->into != NULL)
{
estate->es_select_into = true;
- estate->es_into_oids = interpretOidsOption(parseTree->intoOptions);
+ estate->es_into_oids = interpretOidsOption(plannedstmt->into->options);
}
/*
@@ -572,7 +560,7 @@ InitPlan(QueryDesc *queryDesc, int eflags)
* While we are at it, build the ExecRowMark list.
*/
estate->es_rowMarks = NIL;
- foreach(l, parseTree->rowMarks)
+ foreach(l, plannedstmt->rowMarks)
{
RowMarkClause *rc = (RowMarkClause *) lfirst(l);
Oid relid = getrelid(rc->rti, rangeTable);
@@ -600,13 +588,13 @@ InitPlan(QueryDesc *queryDesc, int eflags)
{
int nSlots = ExecCountSlotsNode(plan);
- if (parseTree->resultRelations != NIL)
- nSlots += list_length(parseTree->resultRelations);
+ if (plannedstmt->resultRelations != NIL)
+ nSlots += list_length(plannedstmt->resultRelations);
else
nSlots += 1;
if (operation != CMD_SELECT)
nSlots++; /* for es_trig_tuple_slot */
- if (parseTree->returningLists)
+ if (plannedstmt->returningLists)
nSlots++; /* for RETURNING projection */
estate->es_tupleTable = ExecCreateTupleTable(nSlots);
@@ -617,7 +605,7 @@ InitPlan(QueryDesc *queryDesc, int eflags)
}
/* mark EvalPlanQual not active */
- estate->es_topPlan = plan;
+ estate->es_plannedstmt = plannedstmt;
estate->es_evalPlanQual = NULL;
estate->es_evTupleNull = NULL;
estate->es_evTuple = NULL;
@@ -683,7 +671,7 @@ InitPlan(QueryDesc *queryDesc, int eflags)
* junk filter. Note this is only possible for UPDATE/DELETE, so
* we can't be fooled by some needing a filter and some not.
*/
- if (parseTree->resultRelations != NIL)
+ if (list_length(plannedstmt->resultRelations) > 1)
{
PlanState **appendplans;
int as_nplans;
@@ -772,7 +760,7 @@ InitPlan(QueryDesc *queryDesc, int eflags)
/*
* Initialize RETURNING projections if needed.
*/
- if (parseTree->returningLists)
+ if (plannedstmt->returningLists)
{
TupleTableSlot *slot;
ExprContext *econtext;
@@ -782,7 +770,7 @@ InitPlan(QueryDesc *queryDesc, int eflags)
* We set QueryDesc.tupDesc to be the RETURNING rowtype in this case.
* We assume all the sublists will generate the same output tupdesc.
*/
- tupType = ExecTypeFromTL((List *) linitial(parseTree->returningLists),
+ tupType = ExecTypeFromTL((List *) linitial(plannedstmt->returningLists),
false);
/* Set up a slot for the output of the RETURNING projection(s) */
@@ -795,9 +783,9 @@ InitPlan(QueryDesc *queryDesc, int eflags)
* Build a projection for each result rel. Note that any SubPlans in
* the RETURNING lists get attached to the topmost plan node.
*/
- Assert(list_length(parseTree->returningLists) == estate->es_num_result_relations);
+ Assert(list_length(plannedstmt->returningLists) == estate->es_num_result_relations);
resultRelInfo = estate->es_result_relations;
- foreach(l, parseTree->returningLists)
+ foreach(l, plannedstmt->returningLists)
{
List *rlist = (List *) lfirst(l);
List *rliststate;
@@ -2273,14 +2261,14 @@ EvalPlanQualStart(evalPlanQual *epq, EState *estate, evalPlanQual *priorepq)
epqstate->es_into_relation_descriptor = estate->es_into_relation_descriptor;
epqstate->es_into_relation_use_wal = estate->es_into_relation_use_wal;
epqstate->es_param_list_info = estate->es_param_list_info;
- if (estate->es_topPlan->nParamExec > 0)
+ if (estate->es_plannedstmt->nParamExec > 0)
epqstate->es_param_exec_vals = (ParamExecData *)
- palloc0(estate->es_topPlan->nParamExec * sizeof(ParamExecData));
+ palloc0(estate->es_plannedstmt->nParamExec * sizeof(ParamExecData));
epqstate->es_rowMarks = estate->es_rowMarks;
epqstate->es_instrument = estate->es_instrument;
epqstate->es_select_into = estate->es_select_into;
epqstate->es_into_oids = estate->es_into_oids;
- epqstate->es_topPlan = estate->es_topPlan;
+ epqstate->es_plannedstmt = estate->es_plannedstmt;
/*
* Each epqstate must have its own es_evTupleNull state, but all the stack
@@ -2299,7 +2287,7 @@ EvalPlanQualStart(evalPlanQual *epq, EState *estate, evalPlanQual *priorepq)
epqstate->es_tupleTable =
ExecCreateTupleTable(estate->es_tupleTable->size);
- epq->planstate = ExecInitNode(estate->es_topPlan, epqstate, 0);
+ epq->planstate = ExecInitNode(estate->es_plannedstmt->planTree, epqstate, 0);
MemoryContextSwitchTo(oldcontext);
}
@@ -2365,7 +2353,7 @@ typedef struct
static void
OpenIntoRel(QueryDesc *queryDesc)
{
- Query *parseTree = queryDesc->parsetree;
+ IntoClause *into = queryDesc->plannedstmt->into;
EState *estate = queryDesc->estate;
Relation intoRelationDesc;
char *intoName;
@@ -2377,10 +2365,12 @@ OpenIntoRel(QueryDesc *queryDesc)
TupleDesc tupdesc;
DR_intorel *myState;
+ Assert(into);
+
/*
* Check consistency of arguments
*/
- if (parseTree->intoOnCommit != ONCOMMIT_NOOP && !parseTree->into->istemp)
+ if (into->onCommit != ONCOMMIT_NOOP && !into->rel->istemp)
ereport(ERROR,
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
errmsg("ON COMMIT can only be used on temporary tables")));
@@ -2388,8 +2378,8 @@ OpenIntoRel(QueryDesc *queryDesc)
/*
* Find namespace to create in, check its permissions
*/
- intoName = parseTree->into->relname;
- namespaceId = RangeVarGetCreationNamespace(parseTree->into);
+ intoName = into->rel->relname;
+ namespaceId = RangeVarGetCreationNamespace(into->rel);
aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(),
ACL_CREATE);
@@ -2401,16 +2391,16 @@ OpenIntoRel(QueryDesc *queryDesc)
* Select tablespace to use. If not specified, use default_tablespace
* (which may in turn default to database's default).
*/
- if (parseTree->intoTableSpaceName)
+ if (into->tableSpaceName)
{
- tablespaceId = get_tablespace_oid(parseTree->intoTableSpaceName);
+ tablespaceId = get_tablespace_oid(into->tableSpaceName);
if (!OidIsValid(tablespaceId))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("tablespace \"%s\" does not exist",
- parseTree->intoTableSpaceName)));
+ into->tableSpaceName)));
}
- else if (parseTree->into->istemp)
+ else if (into->rel->istemp)
{
tablespaceId = GetTempTablespace();
}
@@ -2435,7 +2425,7 @@ OpenIntoRel(QueryDesc *queryDesc)
/* Parse and validate any reloptions */
reloptions = transformRelOptions((Datum) 0,
- parseTree->intoOptions,
+ into->options,
true,
false);
(void) heap_reloptions(RELKIND_RELATION, reloptions, true);
@@ -2454,7 +2444,7 @@ OpenIntoRel(QueryDesc *queryDesc)
false,
true,
0,
- parseTree->intoOnCommit,
+ into->onCommit,
reloptions,
allowSystemTableMods);