mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-12-15 08:20:16 +08:00
Turn the rangetable used by the executor into a flat list, and avoid storing
useless substructure for its RangeTblEntry nodes. (I chose to keep using the same struct node type and just zero out the link fields for unneeded info, rather than making a separate ExecRangeTblEntry type --- it seemed too fragile to have two different rangetable representations.) Along the way, put subplans into a list in the toplevel PlannedStmt node, and have SubPlan nodes refer to them by list index instead of direct pointers. Vadim wanted to do that years ago, but I never understood what he was on about until now. It makes things a *whole* lot more robust, because we can stop worrying about duplicate processing of subplans during expression tree traversals. That's been a constant source of bugs, and it's finally gone. There are some consequent simplifications yet to be made, like not using a separate EState for subplans in the executor, but I'll tackle that later.
This commit is contained in:
parent
849000c782
commit
eab6b8b27e
@ -1,4 +1,4 @@
|
||||
<!-- $PostgreSQL: pgsql/doc/src/sgml/indexam.sgml,v 2.21 2007/01/31 20:56:17 momjian Exp $ -->
|
||||
<!-- $PostgreSQL: pgsql/doc/src/sgml/indexam.sgml,v 2.22 2007/02/22 22:00:22 tgl Exp $ -->
|
||||
|
||||
<chapter id="indexam">
|
||||
<title>Index Access Method Interface Definition</title>
|
||||
@ -903,7 +903,7 @@ amcostestimate (PlannerInfo *root,
|
||||
* Also, we charge for evaluation of the indexquals at each index row.
|
||||
* All the costs are assumed to be paid incrementally during the scan.
|
||||
*/
|
||||
cost_qual_eval(&index_qual_cost, indexQuals);
|
||||
cost_qual_eval(&index_qual_cost, indexQuals, root);
|
||||
*indexStartupCost = index_qual_cost.startup;
|
||||
*indexTotalCost = seq_page_cost * numIndexPages +
|
||||
(cpu_index_tuple_cost + index_qual_cost.per_tuple) * numIndexTuples;
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1994-5, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.156 2007/02/20 17:32:14 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.157 2007/02/22 22:00:22 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -37,6 +37,7 @@ typedef struct ExplainState
|
||||
bool printNodes; /* do nodeToString() too */
|
||||
bool printAnalyze; /* print actual times */
|
||||
/* other states */
|
||||
PlannedStmt *pstmt; /* top of plan */
|
||||
List *rtable; /* range table */
|
||||
} ExplainState;
|
||||
|
||||
@ -260,6 +261,7 @@ ExplainOnePlan(QueryDesc *queryDesc, ExplainStmt *stmt,
|
||||
|
||||
es->printNodes = stmt->verbose;
|
||||
es->printAnalyze = stmt->analyze;
|
||||
es->pstmt = queryDesc->plannedstmt;
|
||||
es->rtable = queryDesc->plannedstmt->rtable;
|
||||
|
||||
if (es->printNodes)
|
||||
@ -858,7 +860,6 @@ explain_outNode(StringInfo str,
|
||||
/* initPlan-s */
|
||||
if (plan->initPlan)
|
||||
{
|
||||
List *saved_rtable = es->rtable;
|
||||
ListCell *lst;
|
||||
|
||||
for (i = 0; i < indent; i++)
|
||||
@ -869,16 +870,15 @@ explain_outNode(StringInfo str,
|
||||
SubPlanState *sps = (SubPlanState *) lfirst(lst);
|
||||
SubPlan *sp = (SubPlan *) sps->xprstate.expr;
|
||||
|
||||
es->rtable = sp->rtable;
|
||||
for (i = 0; i < indent; i++)
|
||||
appendStringInfo(str, " ");
|
||||
appendStringInfo(str, " -> ");
|
||||
explain_outNode(str, sp->plan,
|
||||
explain_outNode(str,
|
||||
exec_subplan_get_plan(es->pstmt, sp),
|
||||
sps->planstate,
|
||||
NULL,
|
||||
indent + 4, es);
|
||||
}
|
||||
es->rtable = saved_rtable;
|
||||
}
|
||||
|
||||
/* lefttree */
|
||||
@ -994,12 +994,6 @@ explain_outNode(StringInfo str,
|
||||
SubqueryScan *subqueryscan = (SubqueryScan *) plan;
|
||||
SubqueryScanState *subquerystate = (SubqueryScanState *) planstate;
|
||||
Plan *subnode = subqueryscan->subplan;
|
||||
RangeTblEntry *rte = rt_fetch(subqueryscan->scan.scanrelid,
|
||||
es->rtable);
|
||||
List *saved_rtable = es->rtable;
|
||||
|
||||
Assert(rte->rtekind == RTE_SUBQUERY);
|
||||
es->rtable = rte->subquery->rtable;
|
||||
|
||||
for (i = 0; i < indent; i++)
|
||||
appendStringInfo(str, " ");
|
||||
@ -1009,14 +1003,11 @@ explain_outNode(StringInfo str,
|
||||
subquerystate->subplan,
|
||||
NULL,
|
||||
indent + 3, es);
|
||||
|
||||
es->rtable = saved_rtable;
|
||||
}
|
||||
|
||||
/* subPlan-s */
|
||||
if (planstate->subPlan)
|
||||
{
|
||||
List *saved_rtable = es->rtable;
|
||||
ListCell *lst;
|
||||
|
||||
for (i = 0; i < indent; i++)
|
||||
@ -1027,16 +1018,15 @@ explain_outNode(StringInfo str,
|
||||
SubPlanState *sps = (SubPlanState *) lfirst(lst);
|
||||
SubPlan *sp = (SubPlan *) sps->xprstate.expr;
|
||||
|
||||
es->rtable = sp->rtable;
|
||||
for (i = 0; i < indent; i++)
|
||||
appendStringInfo(str, " ");
|
||||
appendStringInfo(str, " -> ");
|
||||
explain_outNode(str, sp->plan,
|
||||
explain_outNode(str,
|
||||
exec_subplan_get_plan(es->pstmt, sp),
|
||||
sps->planstate,
|
||||
NULL,
|
||||
indent + 4, es);
|
||||
}
|
||||
es->rtable = saved_rtable;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.287 2007/02/20 17:32:14 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.288 2007/02/22 22:00:22 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -92,9 +92,9 @@ static void ExecProcessReturning(ProjectionInfo *projectReturning,
|
||||
DestReceiver *dest);
|
||||
static TupleTableSlot *EvalPlanQualNext(EState *estate);
|
||||
static void EndEvalPlanQual(EState *estate);
|
||||
static void ExecCheckRTPerms(List *rangeTable);
|
||||
static void ExecCheckRTEPerms(RangeTblEntry *rte);
|
||||
static void ExecCheckXactReadOnly(PlannedStmt *plannedstmt);
|
||||
static void ExecCheckRangeTblReadOnly(List *rtable);
|
||||
static void EvalPlanQualStart(evalPlanQual *epq, EState *estate,
|
||||
evalPlanQual *priorepq);
|
||||
static void EvalPlanQualStop(evalPlanQual *epq);
|
||||
@ -348,16 +348,14 @@ ExecutorRewind(QueryDesc *queryDesc)
|
||||
* ExecCheckRTPerms
|
||||
* Check access permissions for all relations listed in a range table.
|
||||
*/
|
||||
void
|
||||
static void
|
||||
ExecCheckRTPerms(List *rangeTable)
|
||||
{
|
||||
ListCell *l;
|
||||
|
||||
foreach(l, rangeTable)
|
||||
{
|
||||
RangeTblEntry *rte = lfirst(l);
|
||||
|
||||
ExecCheckRTEPerms(rte);
|
||||
ExecCheckRTEPerms((RangeTblEntry *) lfirst(l));
|
||||
}
|
||||
}
|
||||
|
||||
@ -373,12 +371,9 @@ ExecCheckRTEPerms(RangeTblEntry *rte)
|
||||
Oid userid;
|
||||
|
||||
/*
|
||||
* Only plain-relation RTEs need to be checked here. Subquery RTEs are
|
||||
* checked by ExecInitSubqueryScan if the subquery is still a separate
|
||||
* subquery --- if it's been pulled up into our query level then the RTEs
|
||||
* are in our rangetable and will be checked here. Function RTEs are
|
||||
* Only plain-relation RTEs need to be checked here. Function RTEs are
|
||||
* checked by init_fcache when the function is prepared for execution.
|
||||
* Join and special RTEs need no checks.
|
||||
* Join, subquery, and special RTEs need no checks.
|
||||
*/
|
||||
if (rte->rtekind != RTE_RELATION)
|
||||
return;
|
||||
@ -417,6 +412,8 @@ ExecCheckRTEPerms(RangeTblEntry *rte)
|
||||
static void
|
||||
ExecCheckXactReadOnly(PlannedStmt *plannedstmt)
|
||||
{
|
||||
ListCell *l;
|
||||
|
||||
/*
|
||||
* CREATE TABLE AS or SELECT INTO?
|
||||
*
|
||||
@ -426,32 +423,9 @@ ExecCheckXactReadOnly(PlannedStmt *plannedstmt)
|
||||
goto fail;
|
||||
|
||||
/* Fail if write permissions are requested on any non-temp table */
|
||||
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)
|
||||
foreach(l, plannedstmt->rtable)
|
||||
{
|
||||
RangeTblEntry *rte = lfirst(l);
|
||||
|
||||
if (rte->rtekind == RTE_SUBQUERY)
|
||||
{
|
||||
Assert(!rte->subquery->into);
|
||||
ExecCheckRangeTblReadOnly(rte->subquery->rtable);
|
||||
continue;
|
||||
}
|
||||
RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);
|
||||
|
||||
if (rte->rtekind != RTE_RELATION)
|
||||
continue;
|
||||
@ -494,9 +468,7 @@ InitPlan(QueryDesc *queryDesc, int eflags)
|
||||
ListCell *l;
|
||||
|
||||
/*
|
||||
* Do permissions checks. It's sufficient to examine the query's top
|
||||
* rangetable here --- subplan RTEs will be checked during
|
||||
* ExecInitSubPlan().
|
||||
* Do permissions checks
|
||||
*/
|
||||
ExecCheckRTPerms(rangeTable);
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/executor/execUtils.c,v 1.145 2007/02/20 17:32:14 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/executor/execUtils.c,v 1.146 2007/02/22 22:00:22 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -847,7 +847,6 @@ ExecRelationIsTargetRelation(EState *estate, Index scanrelid)
|
||||
Relation
|
||||
ExecOpenScanRelation(EState *estate, Index scanrelid)
|
||||
{
|
||||
RangeTblEntry *rtentry;
|
||||
Oid reloid;
|
||||
LOCKMODE lockmode;
|
||||
ResultRelInfo *resultRelInfos;
|
||||
@ -885,8 +884,7 @@ ExecOpenScanRelation(EState *estate, Index scanrelid)
|
||||
}
|
||||
|
||||
/* OK, open the relation and acquire lock as needed */
|
||||
rtentry = rt_fetch(scanrelid, estate->es_range_table);
|
||||
reloid = rtentry->relid;
|
||||
reloid = getrelid(scanrelid, estate->es_range_table);
|
||||
|
||||
return heap_open(reloid, lockmode);
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/executor/nodeFunctionscan.c,v 1.43 2007/02/19 02:23:11 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/executor/nodeFunctionscan.c,v 1.44 2007/02/22 22:00:23 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -24,7 +24,6 @@
|
||||
|
||||
#include "executor/nodeFunctionscan.h"
|
||||
#include "funcapi.h"
|
||||
#include "parser/parsetree.h"
|
||||
#include "utils/builtins.h"
|
||||
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/executor/nodeSubplan.c,v 1.85 2007/02/06 02:59:11 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/executor/nodeSubplan.c,v 1.86 2007/02/22 22:00:23 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -637,13 +637,9 @@ void
|
||||
ExecInitSubPlan(SubPlanState *node, EState *estate, int eflags)
|
||||
{
|
||||
SubPlan *subplan = (SubPlan *) node->xprstate.expr;
|
||||
Plan *plan = exec_subplan_get_plan(estate->es_plannedstmt, subplan);
|
||||
EState *sp_estate;
|
||||
|
||||
/*
|
||||
* Do access checking on the rangetable entries in the subquery.
|
||||
*/
|
||||
ExecCheckRTPerms(subplan->rtable);
|
||||
|
||||
/*
|
||||
* initialize my state
|
||||
*/
|
||||
@ -668,18 +664,21 @@ ExecInitSubPlan(SubPlanState *node, EState *estate, int eflags)
|
||||
* shares our Param ID space and es_query_cxt, however. XXX if rangetable
|
||||
* access were done differently, the subquery could share our EState,
|
||||
* which would eliminate some thrashing about in this module...
|
||||
*
|
||||
* XXX make that happen!
|
||||
*/
|
||||
sp_estate = CreateSubExecutorState(estate);
|
||||
node->sub_estate = sp_estate;
|
||||
|
||||
sp_estate->es_range_table = subplan->rtable;
|
||||
sp_estate->es_range_table = estate->es_range_table;
|
||||
sp_estate->es_param_list_info = estate->es_param_list_info;
|
||||
sp_estate->es_param_exec_vals = estate->es_param_exec_vals;
|
||||
sp_estate->es_tupleTable =
|
||||
ExecCreateTupleTable(ExecCountSlotsNode(subplan->plan) + 10);
|
||||
ExecCreateTupleTable(ExecCountSlotsNode(plan) + 10);
|
||||
sp_estate->es_snapshot = estate->es_snapshot;
|
||||
sp_estate->es_crosscheck_snapshot = estate->es_crosscheck_snapshot;
|
||||
sp_estate->es_instrument = estate->es_instrument;
|
||||
sp_estate->es_plannedstmt = estate->es_plannedstmt;
|
||||
|
||||
/*
|
||||
* Start up the subplan (this is a very cut-down form of InitPlan())
|
||||
@ -692,7 +691,7 @@ ExecInitSubPlan(SubPlanState *node, EState *estate, int eflags)
|
||||
if (subplan->parParam == NIL && subplan->setParam == NIL)
|
||||
eflags |= EXEC_FLAG_REWIND;
|
||||
|
||||
node->planstate = ExecInitNode(subplan->plan, sp_estate, eflags);
|
||||
node->planstate = ExecInitNode(plan, sp_estate, eflags);
|
||||
|
||||
node->needShutdown = true; /* now we need to shutdown the subplan */
|
||||
|
||||
|
@ -12,7 +12,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/executor/nodeSubqueryscan.c,v 1.35 2007/01/05 22:19:28 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/executor/nodeSubqueryscan.c,v 1.36 2007/02/22 22:00:23 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -29,7 +29,6 @@
|
||||
|
||||
#include "executor/execdebug.h"
|
||||
#include "executor/nodeSubqueryscan.h"
|
||||
#include "parser/parsetree.h"
|
||||
|
||||
static TupleTableSlot *SubqueryNext(SubqueryScanState *node);
|
||||
|
||||
@ -104,17 +103,18 @@ SubqueryScanState *
|
||||
ExecInitSubqueryScan(SubqueryScan *node, EState *estate, int eflags)
|
||||
{
|
||||
SubqueryScanState *subquerystate;
|
||||
RangeTblEntry *rte;
|
||||
EState *sp_estate;
|
||||
|
||||
/* check for unsupported flags */
|
||||
Assert(!(eflags & EXEC_FLAG_MARK));
|
||||
|
||||
/*
|
||||
* SubqueryScan should not have any "normal" children.
|
||||
* SubqueryScan should not have any "normal" children. Also, if planner
|
||||
* left anything in subrtable, it's fishy.
|
||||
*/
|
||||
Assert(outerPlan(node) == NULL);
|
||||
Assert(innerPlan(node) == NULL);
|
||||
Assert(node->subrtable == NIL);
|
||||
|
||||
/*
|
||||
* create state structure
|
||||
@ -152,25 +152,18 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate, int eflags)
|
||||
* initialize subquery
|
||||
*
|
||||
* This should agree with ExecInitSubPlan
|
||||
*/
|
||||
rte = rt_fetch(node->scan.scanrelid, estate->es_range_table);
|
||||
Assert(rte->rtekind == RTE_SUBQUERY);
|
||||
|
||||
/*
|
||||
* Do access checking on the rangetable entries in the subquery.
|
||||
*/
|
||||
ExecCheckRTPerms(rte->subquery->rtable);
|
||||
|
||||
/*
|
||||
*
|
||||
* The subquery needs its own EState because it has its own rangetable. It
|
||||
* shares our Param ID space and es_query_cxt, however. XXX if rangetable
|
||||
* access were done differently, the subquery could share our EState,
|
||||
* which would eliminate some thrashing about in this module...
|
||||
*
|
||||
* XXX make that happen!
|
||||
*/
|
||||
sp_estate = CreateSubExecutorState(estate);
|
||||
subquerystate->sss_SubEState = sp_estate;
|
||||
|
||||
sp_estate->es_range_table = rte->subquery->rtable;
|
||||
sp_estate->es_range_table = estate->es_range_table;
|
||||
sp_estate->es_param_list_info = estate->es_param_list_info;
|
||||
sp_estate->es_param_exec_vals = estate->es_param_exec_vals;
|
||||
sp_estate->es_tupleTable =
|
||||
@ -178,6 +171,7 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate, int eflags)
|
||||
sp_estate->es_snapshot = estate->es_snapshot;
|
||||
sp_estate->es_crosscheck_snapshot = estate->es_crosscheck_snapshot;
|
||||
sp_estate->es_instrument = estate->es_instrument;
|
||||
sp_estate->es_plannedstmt = estate->es_plannedstmt;
|
||||
|
||||
/*
|
||||
* Start up the subplan (this is a very cut-down form of InitPlan())
|
||||
|
@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/executor/nodeValuesscan.c,v 1.6 2007/02/19 02:23:11 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/executor/nodeValuesscan.c,v 1.7 2007/02/22 22:00:23 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -25,7 +25,6 @@
|
||||
|
||||
#include "executor/executor.h"
|
||||
#include "executor/nodeValuesscan.h"
|
||||
#include "parser/parsetree.h"
|
||||
#include "utils/memutils.h"
|
||||
|
||||
|
||||
|
@ -15,7 +15,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.367 2007/02/20 17:32:15 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.368 2007/02/22 22:00:23 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -78,6 +78,7 @@ _copyPlannedStmt(PlannedStmt *from)
|
||||
COPY_NODE_FIELD(rtable);
|
||||
COPY_NODE_FIELD(resultRelations);
|
||||
COPY_NODE_FIELD(into);
|
||||
COPY_NODE_FIELD(subplans);
|
||||
COPY_NODE_FIELD(returningLists);
|
||||
COPY_NODE_FIELD(rowMarks);
|
||||
COPY_SCALAR_FIELD(nParamExec);
|
||||
@ -366,6 +367,7 @@ _copySubqueryScan(SubqueryScan *from)
|
||||
* copy remainder of node
|
||||
*/
|
||||
COPY_NODE_FIELD(subplan);
|
||||
COPY_NODE_FIELD(subrtable);
|
||||
|
||||
return newnode;
|
||||
}
|
||||
@ -957,9 +959,8 @@ _copySubPlan(SubPlan *from)
|
||||
COPY_SCALAR_FIELD(subLinkType);
|
||||
COPY_NODE_FIELD(testexpr);
|
||||
COPY_NODE_FIELD(paramIds);
|
||||
COPY_NODE_FIELD(plan);
|
||||
COPY_SCALAR_FIELD(plan_id);
|
||||
COPY_NODE_FIELD(rtable);
|
||||
COPY_SCALAR_FIELD(firstColType);
|
||||
COPY_SCALAR_FIELD(useHashTable);
|
||||
COPY_SCALAR_FIELD(unknownEqFalse);
|
||||
COPY_NODE_FIELD(setParam);
|
||||
|
@ -18,7 +18,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.299 2007/02/20 17:32:15 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.300 2007/02/22 22:00:23 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -306,9 +306,8 @@ _equalSubPlan(SubPlan *a, SubPlan *b)
|
||||
COMPARE_SCALAR_FIELD(subLinkType);
|
||||
COMPARE_NODE_FIELD(testexpr);
|
||||
COMPARE_NODE_FIELD(paramIds);
|
||||
/* should compare plans, but have to settle for comparing plan IDs */
|
||||
COMPARE_SCALAR_FIELD(plan_id);
|
||||
COMPARE_NODE_FIELD(rtable);
|
||||
COMPARE_SCALAR_FIELD(firstColType);
|
||||
COMPARE_SCALAR_FIELD(useHashTable);
|
||||
COMPARE_SCALAR_FIELD(unknownEqFalse);
|
||||
COMPARE_NODE_FIELD(setParam);
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.300 2007/02/20 17:32:15 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.301 2007/02/22 22:00:23 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* Every node type that can appear in stored rules' parsetrees *must*
|
||||
@ -245,6 +245,7 @@ _outPlannedStmt(StringInfo str, PlannedStmt *node)
|
||||
WRITE_NODE_FIELD(rtable);
|
||||
WRITE_NODE_FIELD(resultRelations);
|
||||
WRITE_NODE_FIELD(into);
|
||||
WRITE_NODE_FIELD(subplans);
|
||||
WRITE_NODE_FIELD(returningLists);
|
||||
WRITE_NODE_FIELD(rowMarks);
|
||||
WRITE_INT_FIELD(nParamExec);
|
||||
@ -415,6 +416,7 @@ _outSubqueryScan(StringInfo str, SubqueryScan *node)
|
||||
_outScanInfo(str, (Scan *) node);
|
||||
|
||||
WRITE_NODE_FIELD(subplan);
|
||||
WRITE_NODE_FIELD(subrtable);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -823,9 +825,8 @@ _outSubPlan(StringInfo str, SubPlan *node)
|
||||
WRITE_ENUM_FIELD(subLinkType, SubLinkType);
|
||||
WRITE_NODE_FIELD(testexpr);
|
||||
WRITE_NODE_FIELD(paramIds);
|
||||
WRITE_NODE_FIELD(plan);
|
||||
WRITE_INT_FIELD(plan_id);
|
||||
WRITE_NODE_FIELD(rtable);
|
||||
WRITE_OID_FIELD(firstColType);
|
||||
WRITE_BOOL_FIELD(useHashTable);
|
||||
WRITE_BOOL_FIELD(unknownEqFalse);
|
||||
WRITE_NODE_FIELD(setParam);
|
||||
@ -1259,7 +1260,9 @@ _outPlannerGlobal(StringInfo str, PlannerGlobal *node)
|
||||
|
||||
/* NB: this isn't a complete set of fields */
|
||||
WRITE_NODE_FIELD(paramlist);
|
||||
WRITE_INT_FIELD(next_plan_id);
|
||||
WRITE_NODE_FIELD(subplans);
|
||||
WRITE_NODE_FIELD(subrtables);
|
||||
WRITE_NODE_FIELD(finalrtable);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -1317,6 +1320,7 @@ _outRelOptInfo(StringInfo str, RelOptInfo *node)
|
||||
WRITE_UINT_FIELD(pages);
|
||||
WRITE_FLOAT_FIELD(tuples, "%.0f");
|
||||
WRITE_NODE_FIELD(subplan);
|
||||
WRITE_NODE_FIELD(subrtable);
|
||||
WRITE_NODE_FIELD(baserestrictinfo);
|
||||
WRITE_NODE_FIELD(joininfo);
|
||||
WRITE_BOOL_FIELD(has_eclass_joins);
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/nodes/print.c,v 1.84 2007/02/10 14:58:54 petere Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/nodes/print.c,v 1.85 2007/02/22 22:00:23 tgl Exp $
|
||||
*
|
||||
* HISTORY
|
||||
* AUTHOR DATE MAJOR EVENT
|
||||
@ -25,7 +25,6 @@
|
||||
#include "parser/parsetree.h"
|
||||
#include "utils/lsyscache.h"
|
||||
|
||||
static char *plannode_type(Plan *p);
|
||||
|
||||
/*
|
||||
* print
|
||||
@ -488,171 +487,3 @@ print_slot(TupleTableSlot *slot)
|
||||
|
||||
debugtup(slot, NULL);
|
||||
}
|
||||
|
||||
static char *
|
||||
plannode_type(Plan *p)
|
||||
{
|
||||
switch (nodeTag(p))
|
||||
{
|
||||
case T_Plan:
|
||||
return "PLAN";
|
||||
case T_Result:
|
||||
return "RESULT";
|
||||
case T_Append:
|
||||
return "APPEND";
|
||||
case T_BitmapAnd:
|
||||
return "BITMAPAND";
|
||||
case T_BitmapOr:
|
||||
return "BITMAPOR";
|
||||
case T_Scan:
|
||||
return "SCAN";
|
||||
case T_SeqScan:
|
||||
return "SEQSCAN";
|
||||
case T_IndexScan:
|
||||
return "INDEXSCAN";
|
||||
case T_BitmapIndexScan:
|
||||
return "BITMAPINDEXSCAN";
|
||||
case T_BitmapHeapScan:
|
||||
return "BITMAPHEAPSCAN";
|
||||
case T_TidScan:
|
||||
return "TIDSCAN";
|
||||
case T_SubqueryScan:
|
||||
return "SUBQUERYSCAN";
|
||||
case T_FunctionScan:
|
||||
return "FUNCTIONSCAN";
|
||||
case T_ValuesScan:
|
||||
return "VALUESSCAN";
|
||||
case T_Join:
|
||||
return "JOIN";
|
||||
case T_NestLoop:
|
||||
return "NESTLOOP";
|
||||
case T_MergeJoin:
|
||||
return "MERGEJOIN";
|
||||
case T_HashJoin:
|
||||
return "HASHJOIN";
|
||||
case T_Material:
|
||||
return "MATERIAL";
|
||||
case T_Sort:
|
||||
return "SORT";
|
||||
case T_Agg:
|
||||
return "AGG";
|
||||
case T_Unique:
|
||||
return "UNIQUE";
|
||||
case T_SetOp:
|
||||
return "SETOP";
|
||||
case T_Limit:
|
||||
return "LIMIT";
|
||||
case T_Hash:
|
||||
return "HASH";
|
||||
case T_Group:
|
||||
return "GROUP";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Recursively prints a simple text description of the plan tree
|
||||
*/
|
||||
void
|
||||
print_plan_recursive(Plan *p, Query *parsetree, int indentLevel, char *label)
|
||||
{
|
||||
int i;
|
||||
char extraInfo[NAMEDATALEN + 100];
|
||||
|
||||
if (!p)
|
||||
return;
|
||||
for (i = 0; i < indentLevel; i++)
|
||||
printf(" ");
|
||||
printf("%s%s :c=%.2f..%.2f :r=%.0f :w=%d ", label, plannode_type(p),
|
||||
p->startup_cost, p->total_cost,
|
||||
p->plan_rows, p->plan_width);
|
||||
if (IsA(p, Scan) ||
|
||||
IsA(p, SeqScan) ||
|
||||
IsA(p, BitmapHeapScan))
|
||||
{
|
||||
RangeTblEntry *rte;
|
||||
|
||||
rte = rt_fetch(((Scan *) p)->scanrelid, parsetree->rtable);
|
||||
strlcpy(extraInfo, rte->eref->aliasname, NAMEDATALEN);
|
||||
}
|
||||
else if (IsA(p, IndexScan))
|
||||
{
|
||||
RangeTblEntry *rte;
|
||||
|
||||
rte = rt_fetch(((IndexScan *) p)->scan.scanrelid, parsetree->rtable);
|
||||
strlcpy(extraInfo, rte->eref->aliasname, NAMEDATALEN);
|
||||
}
|
||||
else if (IsA(p, FunctionScan))
|
||||
{
|
||||
RangeTblEntry *rte;
|
||||
|
||||
rte = rt_fetch(((FunctionScan *) p)->scan.scanrelid, parsetree->rtable);
|
||||
strlcpy(extraInfo, rte->eref->aliasname, NAMEDATALEN);
|
||||
}
|
||||
else if (IsA(p, ValuesScan))
|
||||
{
|
||||
RangeTblEntry *rte;
|
||||
|
||||
rte = rt_fetch(((ValuesScan *) p)->scan.scanrelid, parsetree->rtable);
|
||||
strlcpy(extraInfo, rte->eref->aliasname, NAMEDATALEN);
|
||||
}
|
||||
else
|
||||
extraInfo[0] = '\0';
|
||||
if (extraInfo[0] != '\0')
|
||||
printf(" ( %s )\n", extraInfo);
|
||||
else
|
||||
printf("\n");
|
||||
print_plan_recursive(p->lefttree, parsetree, indentLevel + 3, "l: ");
|
||||
print_plan_recursive(p->righttree, parsetree, indentLevel + 3, "r: ");
|
||||
|
||||
if (IsA(p, Append))
|
||||
{
|
||||
ListCell *l;
|
||||
Append *appendplan = (Append *) p;
|
||||
|
||||
foreach(l, appendplan->appendplans)
|
||||
{
|
||||
Plan *subnode = (Plan *) lfirst(l);
|
||||
|
||||
print_plan_recursive(subnode, parsetree, indentLevel + 3, "a: ");
|
||||
}
|
||||
}
|
||||
|
||||
if (IsA(p, BitmapAnd))
|
||||
{
|
||||
ListCell *l;
|
||||
BitmapAnd *bitmapandplan = (BitmapAnd *) p;
|
||||
|
||||
foreach(l, bitmapandplan->bitmapplans)
|
||||
{
|
||||
Plan *subnode = (Plan *) lfirst(l);
|
||||
|
||||
print_plan_recursive(subnode, parsetree, indentLevel + 3, "a: ");
|
||||
}
|
||||
}
|
||||
|
||||
if (IsA(p, BitmapOr))
|
||||
{
|
||||
ListCell *l;
|
||||
BitmapOr *bitmaporplan = (BitmapOr *) p;
|
||||
|
||||
foreach(l, bitmaporplan->bitmapplans)
|
||||
{
|
||||
Plan *subnode = (Plan *) lfirst(l);
|
||||
|
||||
print_plan_recursive(subnode, parsetree, indentLevel + 3, "a: ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* print_plan
|
||||
*
|
||||
* prints just the plan node types
|
||||
*/
|
||||
void
|
||||
print_plan(Plan *p, Query *parsetree)
|
||||
{
|
||||
print_plan_recursive(p, parsetree, 0, "");
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.160 2007/02/20 17:32:15 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.161 2007/02/22 22:00:23 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -521,6 +521,7 @@ set_subquery_pathlist(PlannerInfo *root, RelOptInfo *rel,
|
||||
root->query_level + 1,
|
||||
tuple_fraction,
|
||||
&subroot);
|
||||
rel->subrtable = subroot->parse->rtable;
|
||||
|
||||
/* Copy number of output rows from subplan */
|
||||
rel->tuples = rel->subplan->plan_rows;
|
||||
|
@ -54,7 +54,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.177 2007/01/22 20:00:39 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.178 2007/02/22 22:00:24 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -107,11 +107,16 @@ bool enable_nestloop = true;
|
||||
bool enable_mergejoin = true;
|
||||
bool enable_hashjoin = true;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
PlannerInfo *root;
|
||||
QualCost total;
|
||||
} cost_qual_eval_context;
|
||||
|
||||
static MergeScanSelCache *cached_scansel(PlannerInfo *root,
|
||||
RestrictInfo *rinfo,
|
||||
PathKey *pathkey);
|
||||
static bool cost_qual_eval_walker(Node *node, QualCost *total);
|
||||
static bool cost_qual_eval_walker(Node *node, cost_qual_eval_context *context);
|
||||
static Selectivity approx_selectivity(PlannerInfo *root, List *quals,
|
||||
JoinType jointype);
|
||||
static Selectivity join_in_selectivity(JoinPath *path, PlannerInfo *root);
|
||||
@ -362,7 +367,7 @@ cost_index(IndexPath *path, PlannerInfo *root,
|
||||
{
|
||||
QualCost index_qual_cost;
|
||||
|
||||
cost_qual_eval(&index_qual_cost, indexQuals);
|
||||
cost_qual_eval(&index_qual_cost, indexQuals, root);
|
||||
/* any startup cost still has to be paid ... */
|
||||
cpu_per_tuple -= index_qual_cost.per_tuple;
|
||||
}
|
||||
@ -855,7 +860,7 @@ cost_functionscan(Path *path, PlannerInfo *root, RelOptInfo *baserel)
|
||||
Assert(rte->rtekind == RTE_FUNCTION);
|
||||
|
||||
/* Estimate costs of executing the function expression */
|
||||
cost_qual_eval_node(&exprcost, rte->funcexpr);
|
||||
cost_qual_eval_node(&exprcost, rte->funcexpr, root);
|
||||
|
||||
startup_cost += exprcost.startup;
|
||||
cpu_per_tuple = exprcost.per_tuple;
|
||||
@ -1241,7 +1246,7 @@ cost_nestloop(NestPath *path, PlannerInfo *root)
|
||||
ntuples = outer_path_rows * inner_path_rows * joininfactor;
|
||||
|
||||
/* CPU costs */
|
||||
cost_qual_eval(&restrict_qual_cost, path->joinrestrictinfo);
|
||||
cost_qual_eval(&restrict_qual_cost, path->joinrestrictinfo, root);
|
||||
startup_cost += restrict_qual_cost.startup;
|
||||
cpu_per_tuple = cpu_tuple_cost + restrict_qual_cost.per_tuple;
|
||||
run_cost += cpu_per_tuple * ntuples;
|
||||
@ -1301,8 +1306,8 @@ cost_mergejoin(MergePath *path, PlannerInfo *root)
|
||||
*/
|
||||
merge_selec = approx_selectivity(root, mergeclauses,
|
||||
path->jpath.jointype);
|
||||
cost_qual_eval(&merge_qual_cost, mergeclauses);
|
||||
cost_qual_eval(&qp_qual_cost, path->jpath.joinrestrictinfo);
|
||||
cost_qual_eval(&merge_qual_cost, mergeclauses, root);
|
||||
cost_qual_eval(&qp_qual_cost, path->jpath.joinrestrictinfo, root);
|
||||
qp_qual_cost.startup -= merge_qual_cost.startup;
|
||||
qp_qual_cost.per_tuple -= merge_qual_cost.per_tuple;
|
||||
|
||||
@ -1587,8 +1592,8 @@ cost_hashjoin(HashPath *path, PlannerInfo *root)
|
||||
*/
|
||||
hash_selec = approx_selectivity(root, hashclauses,
|
||||
path->jpath.jointype);
|
||||
cost_qual_eval(&hash_qual_cost, hashclauses);
|
||||
cost_qual_eval(&qp_qual_cost, path->jpath.joinrestrictinfo);
|
||||
cost_qual_eval(&hash_qual_cost, hashclauses, root);
|
||||
cost_qual_eval(&qp_qual_cost, path->jpath.joinrestrictinfo, root);
|
||||
qp_qual_cost.startup -= hash_qual_cost.startup;
|
||||
qp_qual_cost.per_tuple -= hash_qual_cost.per_tuple;
|
||||
|
||||
@ -1756,12 +1761,14 @@ cost_hashjoin(HashPath *path, PlannerInfo *root)
|
||||
* and a per-evaluation component.
|
||||
*/
|
||||
void
|
||||
cost_qual_eval(QualCost *cost, List *quals)
|
||||
cost_qual_eval(QualCost *cost, List *quals, PlannerInfo *root)
|
||||
{
|
||||
cost_qual_eval_context context;
|
||||
ListCell *l;
|
||||
|
||||
cost->startup = 0;
|
||||
cost->per_tuple = 0;
|
||||
context.root = root;
|
||||
context.total.startup = 0;
|
||||
context.total.per_tuple = 0;
|
||||
|
||||
/* We don't charge any cost for the implicit ANDing at top level ... */
|
||||
|
||||
@ -1769,8 +1776,10 @@ cost_qual_eval(QualCost *cost, List *quals)
|
||||
{
|
||||
Node *qual = (Node *) lfirst(l);
|
||||
|
||||
cost_qual_eval_walker(qual, cost);
|
||||
cost_qual_eval_walker(qual, &context);
|
||||
}
|
||||
|
||||
*cost = context.total;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1778,15 +1787,21 @@ cost_qual_eval(QualCost *cost, List *quals)
|
||||
* As above, for a single RestrictInfo or expression.
|
||||
*/
|
||||
void
|
||||
cost_qual_eval_node(QualCost *cost, Node *qual)
|
||||
cost_qual_eval_node(QualCost *cost, Node *qual, PlannerInfo *root)
|
||||
{
|
||||
cost->startup = 0;
|
||||
cost->per_tuple = 0;
|
||||
cost_qual_eval_walker(qual, cost);
|
||||
cost_qual_eval_context context;
|
||||
|
||||
context.root = root;
|
||||
context.total.startup = 0;
|
||||
context.total.per_tuple = 0;
|
||||
|
||||
cost_qual_eval_walker(qual, &context);
|
||||
|
||||
*cost = context.total;
|
||||
}
|
||||
|
||||
static bool
|
||||
cost_qual_eval_walker(Node *node, QualCost *total)
|
||||
cost_qual_eval_walker(Node *node, cost_qual_eval_context *context)
|
||||
{
|
||||
if (node == NULL)
|
||||
return false;
|
||||
@ -1803,18 +1818,19 @@ cost_qual_eval_walker(Node *node, QualCost *total)
|
||||
|
||||
if (rinfo->eval_cost.startup < 0)
|
||||
{
|
||||
rinfo->eval_cost.startup = 0;
|
||||
rinfo->eval_cost.per_tuple = 0;
|
||||
cost_qual_eval_context locContext;
|
||||
|
||||
locContext.root = context->root;
|
||||
locContext.total.startup = 0;
|
||||
locContext.total.per_tuple = 0;
|
||||
/*
|
||||
* For an OR clause, recurse into the marked-up tree so that
|
||||
* we set the eval_cost for contained RestrictInfos too.
|
||||
*/
|
||||
if (rinfo->orclause)
|
||||
cost_qual_eval_walker((Node *) rinfo->orclause,
|
||||
&rinfo->eval_cost);
|
||||
cost_qual_eval_walker((Node *) rinfo->orclause, &locContext);
|
||||
else
|
||||
cost_qual_eval_walker((Node *) rinfo->clause,
|
||||
&rinfo->eval_cost);
|
||||
cost_qual_eval_walker((Node *) rinfo->clause, &locContext);
|
||||
/*
|
||||
* If the RestrictInfo is marked pseudoconstant, it will be tested
|
||||
* only once, so treat its cost as all startup cost.
|
||||
@ -1822,12 +1838,13 @@ cost_qual_eval_walker(Node *node, QualCost *total)
|
||||
if (rinfo->pseudoconstant)
|
||||
{
|
||||
/* count one execution during startup */
|
||||
rinfo->eval_cost.startup += rinfo->eval_cost.per_tuple;
|
||||
rinfo->eval_cost.per_tuple = 0;
|
||||
locContext.total.startup += locContext.total.per_tuple;
|
||||
locContext.total.per_tuple = 0;
|
||||
}
|
||||
rinfo->eval_cost = locContext.total;
|
||||
}
|
||||
total->startup += rinfo->eval_cost.startup;
|
||||
total->per_tuple += rinfo->eval_cost.per_tuple;
|
||||
context->total.startup += rinfo->eval_cost.startup;
|
||||
context->total.per_tuple += rinfo->eval_cost.per_tuple;
|
||||
/* do NOT recurse into children */
|
||||
return false;
|
||||
}
|
||||
@ -1849,8 +1866,8 @@ cost_qual_eval_walker(Node *node, QualCost *total)
|
||||
*/
|
||||
if (IsA(node, FuncExpr))
|
||||
{
|
||||
total->per_tuple += get_func_cost(((FuncExpr *) node)->funcid) *
|
||||
cpu_operator_cost;
|
||||
context->total.per_tuple +=
|
||||
get_func_cost(((FuncExpr *) node)->funcid) * cpu_operator_cost;
|
||||
}
|
||||
else if (IsA(node, OpExpr) ||
|
||||
IsA(node, DistinctExpr) ||
|
||||
@ -1858,8 +1875,8 @@ cost_qual_eval_walker(Node *node, QualCost *total)
|
||||
{
|
||||
/* rely on struct equivalence to treat these all alike */
|
||||
set_opfuncid((OpExpr *) node);
|
||||
total->per_tuple += get_func_cost(((OpExpr *) node)->opfuncid) *
|
||||
cpu_operator_cost;
|
||||
context->total.per_tuple +=
|
||||
get_func_cost(((OpExpr *) node)->opfuncid) * cpu_operator_cost;
|
||||
}
|
||||
else if (IsA(node, ScalarArrayOpExpr))
|
||||
{
|
||||
@ -1871,7 +1888,7 @@ cost_qual_eval_walker(Node *node, QualCost *total)
|
||||
Node *arraynode = (Node *) lsecond(saop->args);
|
||||
|
||||
set_sa_opfuncid(saop);
|
||||
total->per_tuple += get_func_cost(saop->opfuncid) *
|
||||
context->total.per_tuple += get_func_cost(saop->opfuncid) *
|
||||
cpu_operator_cost * estimate_array_length(arraynode) * 0.5;
|
||||
}
|
||||
else if (IsA(node, RowCompareExpr))
|
||||
@ -1884,7 +1901,7 @@ cost_qual_eval_walker(Node *node, QualCost *total)
|
||||
{
|
||||
Oid opid = lfirst_oid(lc);
|
||||
|
||||
total->per_tuple += get_func_cost(get_opcode(opid)) *
|
||||
context->total.per_tuple += get_func_cost(get_opcode(opid)) *
|
||||
cpu_operator_cost;
|
||||
}
|
||||
}
|
||||
@ -1905,7 +1922,7 @@ cost_qual_eval_walker(Node *node, QualCost *total)
|
||||
* subplan by hashing.
|
||||
*/
|
||||
SubPlan *subplan = (SubPlan *) node;
|
||||
Plan *plan = subplan->plan;
|
||||
Plan *plan = planner_subplan_get_plan(context->root, subplan);
|
||||
|
||||
if (subplan->useHashTable)
|
||||
{
|
||||
@ -1915,7 +1932,7 @@ cost_qual_eval_walker(Node *node, QualCost *total)
|
||||
* cpu_operator_cost per tuple for the work of loading the
|
||||
* hashtable, too.
|
||||
*/
|
||||
total->startup += plan->total_cost +
|
||||
context->total.startup += plan->total_cost +
|
||||
cpu_operator_cost * plan->plan_rows;
|
||||
|
||||
/*
|
||||
@ -1941,20 +1958,21 @@ cost_qual_eval_walker(Node *node, QualCost *total)
|
||||
if (subplan->subLinkType == EXISTS_SUBLINK)
|
||||
{
|
||||
/* we only need to fetch 1 tuple */
|
||||
total->per_tuple += plan_run_cost / plan->plan_rows;
|
||||
context->total.per_tuple += plan_run_cost / plan->plan_rows;
|
||||
}
|
||||
else if (subplan->subLinkType == ALL_SUBLINK ||
|
||||
subplan->subLinkType == ANY_SUBLINK)
|
||||
{
|
||||
/* assume we need 50% of the tuples */
|
||||
total->per_tuple += 0.50 * plan_run_cost;
|
||||
context->total.per_tuple += 0.50 * plan_run_cost;
|
||||
/* also charge a cpu_operator_cost per row examined */
|
||||
total->per_tuple += 0.50 * plan->plan_rows * cpu_operator_cost;
|
||||
context->total.per_tuple +=
|
||||
0.50 * plan->plan_rows * cpu_operator_cost;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* assume we need all tuples */
|
||||
total->per_tuple += plan_run_cost;
|
||||
context->total.per_tuple += plan_run_cost;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1967,15 +1985,15 @@ cost_qual_eval_walker(Node *node, QualCost *total)
|
||||
if (subplan->parParam == NIL &&
|
||||
(IsA(plan, Sort) ||
|
||||
IsA(plan, Material)))
|
||||
total->startup += plan->startup_cost;
|
||||
context->total.startup += plan->startup_cost;
|
||||
else
|
||||
total->per_tuple += plan->startup_cost;
|
||||
context->total.per_tuple += plan->startup_cost;
|
||||
}
|
||||
}
|
||||
|
||||
/* recurse into children */
|
||||
return expression_tree_walker(node, cost_qual_eval_walker,
|
||||
(void *) total);
|
||||
(void *) context);
|
||||
}
|
||||
|
||||
|
||||
@ -2042,7 +2060,7 @@ set_baserel_size_estimates(PlannerInfo *root, RelOptInfo *rel)
|
||||
|
||||
rel->rows = clamp_row_est(nrows);
|
||||
|
||||
cost_qual_eval(&rel->baserestrictcost, rel->baserestrictinfo);
|
||||
cost_qual_eval(&rel->baserestrictcost, rel->baserestrictinfo, root);
|
||||
|
||||
set_rel_width(root, rel);
|
||||
}
|
||||
|
@ -10,7 +10,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.225 2007/02/19 02:23:12 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.226 2007/02/22 22:00:24 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -128,12 +128,12 @@ static Sort *make_sort(PlannerInfo *root, Plan *lefttree, int numCols,
|
||||
* create_plan
|
||||
* Creates the access plan for a query by tracing backwards through the
|
||||
* desired chain of pathnodes, starting at the node 'best_path'. For
|
||||
* every pathnode found:
|
||||
* (1) Create a corresponding plan node containing appropriate id,
|
||||
* target list, and qualification information.
|
||||
* (2) Modify qual clauses of join nodes so that subplan attributes are
|
||||
* referenced using relative values.
|
||||
* (3) Target lists are not modified, but will be in setrefs.c.
|
||||
* every pathnode found, we create a corresponding plan node containing
|
||||
* appropriate id, target list, and qualification information.
|
||||
*
|
||||
* The tlists and quals in the plan tree are still in planner format,
|
||||
* ie, Vars still correspond to the parser's numbering. This will be
|
||||
* fixed later by setrefs.c.
|
||||
*
|
||||
* best_path is the best access path
|
||||
*
|
||||
@ -421,7 +421,8 @@ create_gating_plan(PlannerInfo *root, Plan *plan, List *quals)
|
||||
if (!pseudoconstants)
|
||||
return plan;
|
||||
|
||||
return (Plan *) make_result((List *) copyObject(plan->targetlist),
|
||||
return (Plan *) make_result(root,
|
||||
plan->targetlist,
|
||||
(Node *) pseudoconstants,
|
||||
plan);
|
||||
}
|
||||
@ -519,7 +520,8 @@ create_append_plan(PlannerInfo *root, AppendPath *best_path)
|
||||
if (best_path->subpaths == NIL)
|
||||
{
|
||||
/* Generate a Result plan with constant-FALSE gating qual */
|
||||
return (Plan *) make_result(tlist,
|
||||
return (Plan *) make_result(root,
|
||||
tlist,
|
||||
(Node *) list_make1(makeBoolConst(false,
|
||||
false)),
|
||||
NULL);
|
||||
@ -559,7 +561,7 @@ create_result_plan(PlannerInfo *root, ResultPath *best_path)
|
||||
|
||||
quals = order_qual_clauses(root, best_path->quals);
|
||||
|
||||
return make_result(tlist, (Node *) quals, NULL);
|
||||
return make_result(root, tlist, (Node *) quals, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -682,7 +684,7 @@ create_unique_plan(PlannerInfo *root, UniquePath *best_path)
|
||||
* node to help it along.
|
||||
*/
|
||||
if (!is_projection_capable_plan(subplan))
|
||||
subplan = (Plan *) make_result(newtlist, NULL, subplan);
|
||||
subplan = (Plan *) make_result(root, newtlist, NULL, subplan);
|
||||
else
|
||||
subplan->targetlist = newtlist;
|
||||
}
|
||||
@ -1065,12 +1067,6 @@ create_bitmap_scan_plan(PlannerInfo *root,
|
||||
*/
|
||||
bitmapqualorig = list_difference_ptr(bitmapqualorig, qpqual);
|
||||
|
||||
/*
|
||||
* Copy the finished bitmapqualorig to make sure we have an independent
|
||||
* copy --- needed in case there are subplans in the index quals
|
||||
*/
|
||||
bitmapqualorig = copyObject(bitmapqualorig);
|
||||
|
||||
/* Finally ready to build the plan node */
|
||||
scan_plan = make_bitmap_heapscan(tlist,
|
||||
qpqual,
|
||||
@ -1333,7 +1329,8 @@ create_subqueryscan_plan(PlannerInfo *root, Path *best_path,
|
||||
scan_plan = make_subqueryscan(tlist,
|
||||
scan_clauses,
|
||||
scan_relid,
|
||||
best_path->parent->subplan);
|
||||
best_path->parent->subplan,
|
||||
best_path->parent->subrtable);
|
||||
|
||||
copy_path_costsize(&scan_plan->scan.plan, best_path);
|
||||
|
||||
@ -2115,7 +2112,7 @@ order_qual_clauses(PlannerInfo *root, List *clauses)
|
||||
Node *clause = (Node *) lfirst(lc);
|
||||
QualCost qcost;
|
||||
|
||||
cost_qual_eval_node(&qcost, clause);
|
||||
cost_qual_eval_node(&qcost, clause, root);
|
||||
items[i].clause = clause;
|
||||
items[i].cost = qcost.per_tuple;
|
||||
i++;
|
||||
@ -2326,7 +2323,8 @@ SubqueryScan *
|
||||
make_subqueryscan(List *qptlist,
|
||||
List *qpqual,
|
||||
Index scanrelid,
|
||||
Plan *subplan)
|
||||
Plan *subplan,
|
||||
List *subrtable)
|
||||
{
|
||||
SubqueryScan *node = makeNode(SubqueryScan);
|
||||
Plan *plan = &node->scan.plan;
|
||||
@ -2345,6 +2343,7 @@ make_subqueryscan(List *qptlist,
|
||||
plan->righttree = NULL;
|
||||
node->scan.scanrelid = scanrelid;
|
||||
node->subplan = subplan;
|
||||
node->subrtable = subrtable;
|
||||
|
||||
return node;
|
||||
}
|
||||
@ -2524,7 +2523,7 @@ make_hash(Plan *lefttree)
|
||||
* plan; this only affects EXPLAIN display not decisions.
|
||||
*/
|
||||
plan->startup_cost = plan->total_cost;
|
||||
plan->targetlist = copyObject(lefttree->targetlist);
|
||||
plan->targetlist = lefttree->targetlist;
|
||||
plan->qual = NIL;
|
||||
plan->lefttree = lefttree;
|
||||
plan->righttree = NULL;
|
||||
@ -2583,7 +2582,7 @@ make_sort(PlannerInfo *root, Plan *lefttree, int numCols,
|
||||
lefttree->plan_width);
|
||||
plan->startup_cost = sort_path.startup_cost;
|
||||
plan->total_cost = sort_path.total_cost;
|
||||
plan->targetlist = copyObject(lefttree->targetlist);
|
||||
plan->targetlist = lefttree->targetlist;
|
||||
plan->qual = NIL;
|
||||
plan->lefttree = lefttree;
|
||||
plan->righttree = NULL;
|
||||
@ -2741,10 +2740,7 @@ make_sort_from_pathkeys(PlannerInfo *root, Plan *lefttree, List *pathkeys)
|
||||
* Do we need to insert a Result node?
|
||||
*/
|
||||
if (!is_projection_capable_plan(lefttree))
|
||||
{
|
||||
tlist = copyObject(tlist);
|
||||
lefttree = (Plan *) make_result(tlist, NULL, lefttree);
|
||||
}
|
||||
lefttree = (Plan *) make_result(root, tlist, NULL, lefttree);
|
||||
|
||||
/*
|
||||
* Add resjunk entry to input's tlist
|
||||
@ -2905,7 +2901,7 @@ make_material(Plan *lefttree)
|
||||
Plan *plan = &node->plan;
|
||||
|
||||
/* cost should be inserted by caller */
|
||||
plan->targetlist = copyObject(lefttree->targetlist);
|
||||
plan->targetlist = lefttree->targetlist;
|
||||
plan->qual = NIL;
|
||||
plan->lefttree = lefttree;
|
||||
plan->righttree = NULL;
|
||||
@ -2996,12 +2992,12 @@ make_agg(PlannerInfo *root, List *tlist, List *qual,
|
||||
*/
|
||||
if (qual)
|
||||
{
|
||||
cost_qual_eval(&qual_cost, qual);
|
||||
cost_qual_eval(&qual_cost, qual, root);
|
||||
plan->startup_cost += qual_cost.startup;
|
||||
plan->total_cost += qual_cost.startup;
|
||||
plan->total_cost += qual_cost.per_tuple * plan->plan_rows;
|
||||
}
|
||||
cost_qual_eval(&qual_cost, tlist);
|
||||
cost_qual_eval(&qual_cost, tlist, root);
|
||||
plan->startup_cost += qual_cost.startup;
|
||||
plan->total_cost += qual_cost.startup;
|
||||
plan->total_cost += qual_cost.per_tuple * plan->plan_rows;
|
||||
@ -3059,12 +3055,12 @@ make_group(PlannerInfo *root,
|
||||
*/
|
||||
if (qual)
|
||||
{
|
||||
cost_qual_eval(&qual_cost, qual);
|
||||
cost_qual_eval(&qual_cost, qual, root);
|
||||
plan->startup_cost += qual_cost.startup;
|
||||
plan->total_cost += qual_cost.startup;
|
||||
plan->total_cost += qual_cost.per_tuple * plan->plan_rows;
|
||||
}
|
||||
cost_qual_eval(&qual_cost, tlist);
|
||||
cost_qual_eval(&qual_cost, tlist, root);
|
||||
plan->startup_cost += qual_cost.startup;
|
||||
plan->total_cost += qual_cost.startup;
|
||||
plan->total_cost += qual_cost.per_tuple * plan->plan_rows;
|
||||
@ -3108,7 +3104,7 @@ make_unique(Plan *lefttree, List *distinctList)
|
||||
* has a better idea.
|
||||
*/
|
||||
|
||||
plan->targetlist = copyObject(lefttree->targetlist);
|
||||
plan->targetlist = lefttree->targetlist;
|
||||
plan->qual = NIL;
|
||||
plan->lefttree = lefttree;
|
||||
plan->righttree = NULL;
|
||||
@ -3174,7 +3170,7 @@ make_setop(SetOpCmd cmd, Plan *lefttree,
|
||||
if (plan->plan_rows < 1)
|
||||
plan->plan_rows = 1;
|
||||
|
||||
plan->targetlist = copyObject(lefttree->targetlist);
|
||||
plan->targetlist = lefttree->targetlist;
|
||||
plan->qual = NIL;
|
||||
plan->lefttree = lefttree;
|
||||
plan->righttree = NULL;
|
||||
@ -3272,7 +3268,7 @@ make_limit(Plan *lefttree, Node *limitOffset, Node *limitCount,
|
||||
plan->plan_rows = 1;
|
||||
}
|
||||
|
||||
plan->targetlist = copyObject(lefttree->targetlist);
|
||||
plan->targetlist = lefttree->targetlist;
|
||||
plan->qual = NIL;
|
||||
plan->lefttree = lefttree;
|
||||
plan->righttree = NULL;
|
||||
@ -3293,7 +3289,8 @@ make_limit(Plan *lefttree, Node *limitOffset, Node *limitCount,
|
||||
* cost. In either case, tlist eval cost is not to be included here.
|
||||
*/
|
||||
Result *
|
||||
make_result(List *tlist,
|
||||
make_result(PlannerInfo *root,
|
||||
List *tlist,
|
||||
Node *resconstantqual,
|
||||
Plan *subplan)
|
||||
{
|
||||
@ -3312,7 +3309,7 @@ make_result(List *tlist,
|
||||
{
|
||||
QualCost qual_cost;
|
||||
|
||||
cost_qual_eval(&qual_cost, (List *) resconstantqual);
|
||||
cost_qual_eval(&qual_cost, (List *) resconstantqual, root);
|
||||
/* resconstantqual is evaluated once at startup */
|
||||
plan->startup_cost += qual_cost.startup + qual_cost.per_tuple;
|
||||
plan->total_cost += qual_cost.startup + qual_cost.per_tuple;
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/plan/planagg.c,v 1.28 2007/02/20 17:32:15 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/plan/planagg.c,v 1.29 2007/02/22 22:00:24 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -188,10 +188,10 @@ optimize_minmax_aggregates(PlannerInfo *root, List *tlist, Path *best_path)
|
||||
/*
|
||||
* Generate the output plan --- basically just a Result
|
||||
*/
|
||||
plan = (Plan *) make_result(tlist, hqual, NULL);
|
||||
plan = (Plan *) make_result(root, tlist, hqual, NULL);
|
||||
|
||||
/* Account for evaluation cost of the tlist (make_result did the rest) */
|
||||
cost_qual_eval(&tlist_cost, tlist);
|
||||
cost_qual_eval(&tlist_cost, tlist, root);
|
||||
plan->startup_cost += tlist_cost.startup;
|
||||
plan->total_cost += tlist_cost.startup + tlist_cost.per_tuple;
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.214 2007/02/20 17:32:15 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.215 2007/02/22 22:00:24 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -88,6 +88,8 @@ planner(Query *parse, bool isCursor, int cursorOptions,
|
||||
double tuple_fraction;
|
||||
PlannerInfo *root;
|
||||
Plan *top_plan;
|
||||
ListCell *lp,
|
||||
*lr;
|
||||
|
||||
/*
|
||||
* Set up global state for this planner invocation. This data is needed
|
||||
@ -99,7 +101,9 @@ planner(Query *parse, bool isCursor, int cursorOptions,
|
||||
|
||||
glob->boundParams = boundParams;
|
||||
glob->paramlist = NIL;
|
||||
glob->next_plan_id = 0;
|
||||
glob->subplans = NIL;
|
||||
glob->subrtables = NIL;
|
||||
glob->finalrtable = NIL;
|
||||
|
||||
/* Determine what fraction of the plan is likely to be scanned */
|
||||
if (isCursor)
|
||||
@ -132,7 +136,17 @@ planner(Query *parse, bool isCursor, int cursorOptions,
|
||||
}
|
||||
|
||||
/* final cleanup of the plan */
|
||||
top_plan = set_plan_references(top_plan, parse->rtable);
|
||||
Assert(glob->finalrtable == NIL);
|
||||
top_plan = set_plan_references(glob, top_plan, root->parse->rtable);
|
||||
/* ... and the subplans (both regular subplans and initplans) */
|
||||
Assert(list_length(glob->subplans) == list_length(glob->subrtables));
|
||||
forboth(lp, glob->subplans, lr, glob->subrtables)
|
||||
{
|
||||
Plan *subplan = (Plan *) lfirst(lp);
|
||||
List *subrtable = (List *) lfirst(lr);
|
||||
|
||||
lfirst(lp) = set_plan_references(glob, subplan, subrtable);
|
||||
}
|
||||
|
||||
/* build the PlannedStmt result */
|
||||
result = makeNode(PlannedStmt);
|
||||
@ -140,9 +154,10 @@ planner(Query *parse, bool isCursor, int cursorOptions,
|
||||
result->commandType = parse->commandType;
|
||||
result->canSetTag = parse->canSetTag;
|
||||
result->planTree = top_plan;
|
||||
result->rtable = parse->rtable;
|
||||
result->rtable = glob->finalrtable;
|
||||
result->resultRelations = root->resultRelations;
|
||||
result->into = parse->into;
|
||||
result->subplans = glob->subplans;
|
||||
result->returningLists = root->returningLists;
|
||||
result->rowMarks = parse->rowMarks;
|
||||
result->nParamExec = list_length(glob->paramlist);
|
||||
@ -182,7 +197,7 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
|
||||
Index level, double tuple_fraction,
|
||||
PlannerInfo **subroot)
|
||||
{
|
||||
int saved_plan_id = glob->next_plan_id;
|
||||
int num_old_subplans = list_length(glob->subplans);
|
||||
PlannerInfo *root;
|
||||
Plan *plan;
|
||||
List *newHaving;
|
||||
@ -384,7 +399,8 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
|
||||
* initPlan list and extParam/allParam sets for plan nodes, and attach the
|
||||
* initPlans to the top plan node.
|
||||
*/
|
||||
if (root->glob->next_plan_id != saved_plan_id || root->query_level > 1)
|
||||
if (list_length(glob->subplans) != num_old_subplans ||
|
||||
root->query_level > 1)
|
||||
SS_finalize_plan(root, plan);
|
||||
|
||||
/* Return internal info if caller wants it */
|
||||
@ -621,7 +637,8 @@ inheritance_planner(PlannerInfo *root)
|
||||
* If we managed to exclude every child rel, return a dummy plan
|
||||
*/
|
||||
if (subplans == NIL)
|
||||
return (Plan *) make_result(tlist,
|
||||
return (Plan *) make_result(root,
|
||||
tlist,
|
||||
(Node *) list_make1(makeBoolConst(false,
|
||||
false)),
|
||||
NULL);
|
||||
@ -639,6 +656,10 @@ inheritance_planner(PlannerInfo *root)
|
||||
*/
|
||||
parse->rtable = rtable;
|
||||
|
||||
/* Suppress Append if there's only one surviving child rel */
|
||||
if (list_length(subplans) == 1)
|
||||
return (Plan *) linitial(subplans);
|
||||
|
||||
return (Plan *) make_append(subplans, true, tlist);
|
||||
}
|
||||
|
||||
@ -897,7 +918,9 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
|
||||
*/
|
||||
if (!is_projection_capable_plan(result_plan))
|
||||
{
|
||||
result_plan = (Plan *) make_result(sub_tlist, NULL,
|
||||
result_plan = (Plan *) make_result(root,
|
||||
sub_tlist,
|
||||
NULL,
|
||||
result_plan);
|
||||
}
|
||||
else
|
||||
@ -928,7 +951,7 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
|
||||
* tuples) --- so make_agg() and make_group() are responsible
|
||||
* for computing the added cost.
|
||||
*/
|
||||
cost_qual_eval(&tlist_cost, sub_tlist);
|
||||
cost_qual_eval(&tlist_cost, sub_tlist, root);
|
||||
result_plan->startup_cost += tlist_cost.startup;
|
||||
result_plan->total_cost += tlist_cost.startup +
|
||||
tlist_cost.per_tuple * result_plan->plan_rows;
|
||||
@ -1051,7 +1074,8 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
|
||||
* this routine to avoid having to generate the plan in the
|
||||
* first place.
|
||||
*/
|
||||
result_plan = (Plan *) make_result(tlist,
|
||||
result_plan = (Plan *) make_result(root,
|
||||
tlist,
|
||||
parse->havingQual,
|
||||
NULL);
|
||||
}
|
||||
@ -1110,6 +1134,7 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
|
||||
{
|
||||
List *rlist;
|
||||
|
||||
Assert(parse->resultRelation);
|
||||
rlist = set_returning_clause_references(parse->returningList,
|
||||
result_plan,
|
||||
parse->resultRelation);
|
||||
@ -1544,7 +1569,7 @@ choose_hashed_grouping(PlannerInfo *root, double tuple_fraction,
|
||||
* pass down only c,d,a+b, but it's not really worth the trouble to
|
||||
* eliminate simple var references from the subplan. We will avoid doing
|
||||
* the extra computation to recompute a+b at the outer level; see
|
||||
* replace_vars_with_subplan_refs() in setrefs.c.)
|
||||
* fix_upper_expr() in setrefs.c.)
|
||||
*
|
||||
* If we are grouping or aggregating, *and* there are no non-Var grouping
|
||||
* expressions, then the returned tlist is effectively dummy; we do not
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.120 2007/02/19 07:03:30 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/plan/subselect.c,v 1.121 2007/02/22 22:00:24 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -46,6 +46,7 @@ typedef struct process_sublinks_context
|
||||
|
||||
typedef struct finalize_primnode_context
|
||||
{
|
||||
PlannerInfo *root;
|
||||
Bitmapset *paramids; /* Set of PARAM_EXEC paramids found */
|
||||
Bitmapset *outer_params; /* Set of accessible outer paramids */
|
||||
} finalize_primnode_context;
|
||||
@ -57,12 +58,13 @@ static Node *convert_testexpr(PlannerInfo *root,
|
||||
List **righthandIds);
|
||||
static Node *convert_testexpr_mutator(Node *node,
|
||||
convert_testexpr_context *context);
|
||||
static bool subplan_is_hashable(SubLink *slink, SubPlan *node);
|
||||
static bool subplan_is_hashable(SubLink *slink, SubPlan *node, Plan *plan);
|
||||
static bool hash_ok_operator(OpExpr *expr);
|
||||
static Node *replace_correlation_vars_mutator(Node *node, PlannerInfo *root);
|
||||
static Node *process_sublinks_mutator(Node *node,
|
||||
process_sublinks_context *context);
|
||||
static Bitmapset *finalize_plan(Plan *plan, List *rtable,
|
||||
static Bitmapset *finalize_plan(PlannerInfo *root,
|
||||
Plan *plan,
|
||||
Bitmapset *outer_params,
|
||||
Bitmapset *valid_params);
|
||||
static bool finalize_primnode(Node *node, finalize_primnode_context *context);
|
||||
@ -203,6 +205,24 @@ generate_new_param(PlannerInfo *root, Oid paramtype, int32 paramtypmod)
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the datatype of the first column of the plan's output.
|
||||
*
|
||||
* This is a hack to support exprType(), which doesn't have any way to get
|
||||
* at the plan associated with a SubPlan node. We really only need the value
|
||||
* for EXPR_SUBLINK and ARRAY_SUBLINK subplans, but for consistency we set
|
||||
* it always.
|
||||
*/
|
||||
static Oid
|
||||
get_first_col_type(Plan *plan)
|
||||
{
|
||||
TargetEntry *tent = (TargetEntry *) linitial(plan->targetlist);
|
||||
|
||||
Assert(IsA(tent, TargetEntry));
|
||||
Assert(!tent->resjunk);
|
||||
return exprType((Node *) tent->expr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert a SubLink (as created by the parser) into a SubPlan.
|
||||
*
|
||||
@ -219,10 +239,11 @@ generate_new_param(PlannerInfo *root, Oid paramtype, int32 paramtypmod)
|
||||
static Node *
|
||||
make_subplan(PlannerInfo *root, SubLink *slink, Node *testexpr, bool isTopQual)
|
||||
{
|
||||
SubPlan *node = makeNode(SubPlan);
|
||||
Query *subquery = (Query *) (slink->subselect);
|
||||
double tuple_fraction;
|
||||
SubPlan *node;
|
||||
Plan *plan;
|
||||
PlannerInfo *subroot;
|
||||
Bitmapset *tmpset;
|
||||
int paramid;
|
||||
Node *result;
|
||||
@ -266,22 +287,19 @@ make_subplan(PlannerInfo *root, SubLink *slink, Node *testexpr, bool isTopQual)
|
||||
/*
|
||||
* Generate the plan for the subquery.
|
||||
*/
|
||||
node->plan = plan = subquery_planner(root->glob, subquery,
|
||||
root->query_level + 1,
|
||||
tuple_fraction,
|
||||
NULL);
|
||||
|
||||
/* Assign quasi-unique ID to this SubPlan */
|
||||
node->plan_id = root->glob->next_plan_id++;
|
||||
|
||||
node->rtable = subquery->rtable;
|
||||
plan = subquery_planner(root->glob, subquery,
|
||||
root->query_level + 1,
|
||||
tuple_fraction,
|
||||
&subroot);
|
||||
|
||||
/*
|
||||
* Initialize other fields of the SubPlan node.
|
||||
* Initialize the SubPlan node. Note plan_id isn't set yet.
|
||||
*/
|
||||
node = makeNode(SubPlan);
|
||||
node->subLinkType = slink->subLinkType;
|
||||
node->testexpr = NULL;
|
||||
node->paramIds = NIL;
|
||||
node->firstColType = get_first_col_type(plan);
|
||||
node->useHashTable = false;
|
||||
/* At top level of a qual, can treat UNKNOWN the same as FALSE */
|
||||
node->unknownEqFalse = isTopQual;
|
||||
@ -384,7 +402,7 @@ make_subplan(PlannerInfo *root, SubLink *slink, Node *testexpr, bool isTopQual)
|
||||
* tuple. But if it's an IN (= ANY) test, we might be able to use a
|
||||
* hashtable to avoid comparing all the tuples.
|
||||
*/
|
||||
if (subplan_is_hashable(slink, node))
|
||||
if (subplan_is_hashable(slink, node, plan))
|
||||
node->useHashTable = true;
|
||||
|
||||
/*
|
||||
@ -411,7 +429,7 @@ make_subplan(PlannerInfo *root, SubLink *slink, Node *testexpr, bool isTopQual)
|
||||
break;
|
||||
}
|
||||
if (use_material)
|
||||
node->plan = plan = materialize_finished_plan(plan);
|
||||
plan = materialize_finished_plan(plan);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -435,6 +453,15 @@ make_subplan(PlannerInfo *root, SubLink *slink, Node *testexpr, bool isTopQual)
|
||||
result = (Node *) node;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add the subplan and its rtable to the global lists.
|
||||
*/
|
||||
root->glob->subplans = lappend(root->glob->subplans,
|
||||
plan);
|
||||
root->glob->subrtables = lappend(root->glob->subrtables,
|
||||
subroot->parse->rtable);
|
||||
node->plan_id = list_length(root->glob->subplans);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -539,7 +566,7 @@ convert_testexpr_mutator(Node *node,
|
||||
* on its plan and parParam fields, however.
|
||||
*/
|
||||
static bool
|
||||
subplan_is_hashable(SubLink *slink, SubPlan *node)
|
||||
subplan_is_hashable(SubLink *slink, SubPlan *node, Plan *plan)
|
||||
{
|
||||
double subquery_size;
|
||||
ListCell *l;
|
||||
@ -574,8 +601,8 @@ subplan_is_hashable(SubLink *slink, SubPlan *node)
|
||||
* actually be stored as MinimalTuples; this provides some fudge factor
|
||||
* for hashtable overhead.)
|
||||
*/
|
||||
subquery_size = node->plan->plan_rows *
|
||||
(MAXALIGN(node->plan->plan_width) + MAXALIGN(sizeof(HeapTupleHeaderData)));
|
||||
subquery_size = plan->plan_rows *
|
||||
(MAXALIGN(plan->plan_width) + MAXALIGN(sizeof(HeapTupleHeaderData)));
|
||||
if (subquery_size > work_mem * 1024L)
|
||||
return false;
|
||||
|
||||
@ -964,7 +991,7 @@ SS_finalize_plan(PlannerInfo *root, Plan *plan)
|
||||
/*
|
||||
* Now recurse through plan tree.
|
||||
*/
|
||||
(void) finalize_plan(plan, root->parse->rtable, outer_params, valid_params);
|
||||
(void) finalize_plan(root, plan, outer_params, valid_params);
|
||||
|
||||
bms_free(outer_params);
|
||||
bms_free(valid_params);
|
||||
@ -988,16 +1015,16 @@ SS_finalize_plan(PlannerInfo *root, Plan *plan)
|
||||
initplan_cost = 0;
|
||||
foreach(l, plan->initPlan)
|
||||
{
|
||||
SubPlan *initplan = (SubPlan *) lfirst(l);
|
||||
SubPlan *initsubplan = (SubPlan *) lfirst(l);
|
||||
Plan *initplan = planner_subplan_get_plan(root, initsubplan);
|
||||
ListCell *l2;
|
||||
|
||||
initExtParam = bms_add_members(initExtParam,
|
||||
initplan->plan->extParam);
|
||||
foreach(l2, initplan->setParam)
|
||||
initExtParam = bms_add_members(initExtParam, initplan->extParam);
|
||||
foreach(l2, initsubplan->setParam)
|
||||
{
|
||||
initSetParam = bms_add_member(initSetParam, lfirst_int(l2));
|
||||
}
|
||||
initplan_cost += initplan->plan->total_cost;
|
||||
initplan_cost += initplan->total_cost;
|
||||
}
|
||||
/* allParam must include all these params */
|
||||
plan->allParam = bms_add_members(plan->allParam, initExtParam);
|
||||
@ -1019,7 +1046,7 @@ SS_finalize_plan(PlannerInfo *root, Plan *plan)
|
||||
* This is just an internal notational convenience.
|
||||
*/
|
||||
static Bitmapset *
|
||||
finalize_plan(Plan *plan, List *rtable,
|
||||
finalize_plan(PlannerInfo *root, Plan *plan,
|
||||
Bitmapset *outer_params, Bitmapset *valid_params)
|
||||
{
|
||||
finalize_primnode_context context;
|
||||
@ -1027,6 +1054,7 @@ finalize_plan(Plan *plan, List *rtable,
|
||||
if (plan == NULL)
|
||||
return NULL;
|
||||
|
||||
context.root = root;
|
||||
context.paramids = NULL; /* initialize set to empty */
|
||||
context.outer_params = outer_params;
|
||||
|
||||
@ -1110,8 +1138,8 @@ finalize_plan(Plan *plan, List *rtable,
|
||||
{
|
||||
context.paramids =
|
||||
bms_add_members(context.paramids,
|
||||
finalize_plan((Plan *) lfirst(l),
|
||||
rtable,
|
||||
finalize_plan(root,
|
||||
(Plan *) lfirst(l),
|
||||
outer_params,
|
||||
valid_params));
|
||||
}
|
||||
@ -1126,8 +1154,8 @@ finalize_plan(Plan *plan, List *rtable,
|
||||
{
|
||||
context.paramids =
|
||||
bms_add_members(context.paramids,
|
||||
finalize_plan((Plan *) lfirst(l),
|
||||
rtable,
|
||||
finalize_plan(root,
|
||||
(Plan *) lfirst(l),
|
||||
outer_params,
|
||||
valid_params));
|
||||
}
|
||||
@ -1142,8 +1170,8 @@ finalize_plan(Plan *plan, List *rtable,
|
||||
{
|
||||
context.paramids =
|
||||
bms_add_members(context.paramids,
|
||||
finalize_plan((Plan *) lfirst(l),
|
||||
rtable,
|
||||
finalize_plan(root,
|
||||
(Plan *) lfirst(l),
|
||||
outer_params,
|
||||
valid_params));
|
||||
}
|
||||
@ -1193,14 +1221,14 @@ finalize_plan(Plan *plan, List *rtable,
|
||||
|
||||
/* Process left and right child plans, if any */
|
||||
context.paramids = bms_add_members(context.paramids,
|
||||
finalize_plan(plan->lefttree,
|
||||
rtable,
|
||||
finalize_plan(root,
|
||||
plan->lefttree,
|
||||
outer_params,
|
||||
valid_params));
|
||||
|
||||
context.paramids = bms_add_members(context.paramids,
|
||||
finalize_plan(plan->righttree,
|
||||
rtable,
|
||||
finalize_plan(root,
|
||||
plan->righttree,
|
||||
outer_params,
|
||||
valid_params));
|
||||
|
||||
@ -1252,10 +1280,11 @@ finalize_primnode(Node *node, finalize_primnode_context *context)
|
||||
if (is_subplan(node))
|
||||
{
|
||||
SubPlan *subplan = (SubPlan *) node;
|
||||
Plan *plan = planner_subplan_get_plan(context->root, subplan);
|
||||
|
||||
/* Add outer-level params needed by the subplan to paramids */
|
||||
context->paramids = bms_join(context->paramids,
|
||||
bms_intersect(subplan->plan->extParam,
|
||||
bms_intersect(plan->extParam,
|
||||
context->outer_params));
|
||||
/* fall through to recurse into subplan args */
|
||||
}
|
||||
@ -1299,16 +1328,21 @@ SS_make_initplan_from_plan(PlannerInfo *root, Plan *plan,
|
||||
root->query_level--;
|
||||
root->init_plans = saved_init_plans;
|
||||
|
||||
/*
|
||||
* Add the subplan and its rtable to the global lists.
|
||||
*/
|
||||
root->glob->subplans = lappend(root->glob->subplans,
|
||||
plan);
|
||||
root->glob->subrtables = lappend(root->glob->subrtables,
|
||||
root->parse->rtable);
|
||||
|
||||
/*
|
||||
* Create a SubPlan node and add it to the outer list of InitPlans.
|
||||
*/
|
||||
node = makeNode(SubPlan);
|
||||
node->subLinkType = EXPR_SUBLINK;
|
||||
node->plan = plan;
|
||||
/* Assign quasi-unique ID to this SubPlan */
|
||||
node->plan_id = root->glob->next_plan_id++;
|
||||
|
||||
node->rtable = root->parse->rtable;
|
||||
node->firstColType = get_first_col_type(plan);
|
||||
node->plan_id = list_length(root->glob->subplans);
|
||||
|
||||
root->init_plans = lappend(root->init_plans, node);
|
||||
|
||||
|
@ -22,7 +22,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.138 2007/02/19 07:03:30 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.139 2007/02/22 22:00:24 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -169,6 +169,7 @@ recurse_set_operations(Node *setOp, PlannerInfo *root,
|
||||
RangeTblRef *rtr = (RangeTblRef *) setOp;
|
||||
RangeTblEntry *rte = rt_fetch(rtr->rtindex, root->parse->rtable);
|
||||
Query *subquery = rte->subquery;
|
||||
PlannerInfo *subroot;
|
||||
Plan *subplan,
|
||||
*plan;
|
||||
|
||||
@ -180,7 +181,7 @@ recurse_set_operations(Node *setOp, PlannerInfo *root,
|
||||
subplan = subquery_planner(root->glob, subquery,
|
||||
root->query_level + 1,
|
||||
tuple_fraction,
|
||||
NULL);
|
||||
&subroot);
|
||||
|
||||
/*
|
||||
* Add a SubqueryScan with the caller-requested targetlist
|
||||
@ -193,7 +194,8 @@ recurse_set_operations(Node *setOp, PlannerInfo *root,
|
||||
refnames_tlist),
|
||||
NIL,
|
||||
rtr->rtindex,
|
||||
subplan);
|
||||
subplan,
|
||||
subroot->parse->rtable);
|
||||
|
||||
/*
|
||||
* We don't bother to determine the subquery's output ordering since
|
||||
@ -223,7 +225,7 @@ recurse_set_operations(Node *setOp, PlannerInfo *root,
|
||||
* output columns.
|
||||
*
|
||||
* XXX you don't really want to know about this: setrefs.c will apply
|
||||
* replace_vars_with_subplan_refs() to the Result node's tlist. This
|
||||
* fix_upper_expr() to the Result node's tlist. This
|
||||
* would fail if the Vars generated by generate_setop_tlist() were not
|
||||
* exactly equal() to the corresponding tlist entries of the subplan.
|
||||
* However, since the subplan was generated by generate_union_plan()
|
||||
@ -235,7 +237,8 @@ recurse_set_operations(Node *setOp, PlannerInfo *root,
|
||||
!tlist_same_datatypes(plan->targetlist, colTypes, junkOK))
|
||||
{
|
||||
plan = (Plan *)
|
||||
make_result(generate_setop_tlist(colTypes, flag,
|
||||
make_result(root,
|
||||
generate_setop_tlist(colTypes, flag,
|
||||
0,
|
||||
false,
|
||||
plan->targetlist,
|
||||
@ -1216,28 +1219,6 @@ adjust_appendrel_attrs_mutator(Node *node, AppendRelInfo *context)
|
||||
Assert(!IsA(node, SubLink));
|
||||
Assert(!IsA(node, Query));
|
||||
|
||||
/*
|
||||
* BUT: although we don't need to recurse into subplans, we do need to
|
||||
* make sure that they are copied, not just referenced as
|
||||
* expression_tree_mutator will do by default. Otherwise we'll have the
|
||||
* same subplan node referenced from each arm of the finished APPEND plan,
|
||||
* which will cause trouble in the executor. This is a kluge that should
|
||||
* go away when we redesign querytrees.
|
||||
*/
|
||||
if (is_subplan(node))
|
||||
{
|
||||
SubPlan *subplan;
|
||||
|
||||
/* Copy the node and process subplan args */
|
||||
node = expression_tree_mutator(node, adjust_appendrel_attrs_mutator,
|
||||
(void *) context);
|
||||
/* Make sure we have separate copies of subplan and its rtable */
|
||||
subplan = (SubPlan *) node;
|
||||
subplan->plan = copyObject(subplan->plan);
|
||||
subplan->rtable = copyObject(subplan->rtable);
|
||||
return node;
|
||||
}
|
||||
|
||||
return expression_tree_mutator(node, adjust_appendrel_attrs_mutator,
|
||||
(void *) context);
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.235 2007/02/19 07:03:30 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.236 2007/02/22 22:00:24 tgl Exp $
|
||||
*
|
||||
* HISTORY
|
||||
* AUTHOR DATE MAJOR EVENT
|
||||
@ -2989,7 +2989,7 @@ inline_function(Oid funcid, Oid result_type, List *args,
|
||||
*/
|
||||
if (contain_subplans(param))
|
||||
goto fail;
|
||||
cost_qual_eval(&eval_cost, list_make1(param));
|
||||
cost_qual_eval(&eval_cost, list_make1(param), NULL);
|
||||
if (eval_cost.startup + eval_cost.per_tuple >
|
||||
10 * cpu_operator_cost)
|
||||
goto fail;
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/util/relnode.c,v 1.85 2007/01/20 20:45:40 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/util/relnode.c,v 1.86 2007/02/22 22:00:25 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -82,6 +82,7 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptKind reloptkind)
|
||||
rel->pages = 0;
|
||||
rel->tuples = 0;
|
||||
rel->subplan = NULL;
|
||||
rel->subrtable = NIL;
|
||||
rel->baserestrictinfo = NIL;
|
||||
rel->baserestrictcost.startup = 0;
|
||||
rel->baserestrictcost.per_tuple = 0;
|
||||
@ -333,6 +334,7 @@ build_join_rel(PlannerInfo *root,
|
||||
joinrel->pages = 0;
|
||||
joinrel->tuples = 0;
|
||||
joinrel->subplan = NULL;
|
||||
joinrel->subrtable = NIL;
|
||||
joinrel->baserestrictinfo = NIL;
|
||||
joinrel->baserestrictcost.startup = 0;
|
||||
joinrel->baserestrictcost.per_tuple = 0;
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.211 2007/02/11 22:18:15 petere Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.212 2007/02/22 22:00:25 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -1769,12 +1769,7 @@ exprType(Node *expr)
|
||||
subplan->subLinkType == ARRAY_SUBLINK)
|
||||
{
|
||||
/* get the type of the subselect's first target column */
|
||||
TargetEntry *tent;
|
||||
|
||||
tent = (TargetEntry *) linitial(subplan->plan->targetlist);
|
||||
Assert(IsA(tent, TargetEntry));
|
||||
Assert(!tent->resjunk);
|
||||
type = exprType((Node *) tent->expr);
|
||||
type = subplan->firstColType;
|
||||
if (subplan->subLinkType == ARRAY_SUBLINK)
|
||||
{
|
||||
type = get_array_type(type);
|
||||
@ -1782,7 +1777,7 @@ exprType(Node *expr)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
||||
errmsg("could not find array type for data type %s",
|
||||
format_type_be(exprType((Node *) tent->expr)))));
|
||||
format_type_be(subplan->firstColType))));
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -15,7 +15,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.226 2007/02/19 07:03:31 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.227 2007/02/22 22:00:25 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -4964,7 +4964,7 @@ genericcostestimate(PlannerInfo *root,
|
||||
* more expensive than it's worth, though, considering all the other
|
||||
* inaccuracies here ...
|
||||
*/
|
||||
cost_qual_eval(&index_qual_cost, indexQuals);
|
||||
cost_qual_eval(&index_qual_cost, indexQuals, root);
|
||||
qual_op_cost = cpu_operator_cost * list_length(indexQuals);
|
||||
qual_arg_cost = index_qual_cost.startup +
|
||||
index_qual_cost.per_tuple - qual_op_cost;
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/include/executor/executor.h,v 1.137 2007/02/20 17:32:17 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/include/executor/executor.h,v 1.138 2007/02/22 22:00:25 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -130,7 +130,6 @@ extern TupleTableSlot *ExecutorRun(QueryDesc *queryDesc,
|
||||
ScanDirection direction, long count);
|
||||
extern void ExecutorEnd(QueryDesc *queryDesc);
|
||||
extern void ExecutorRewind(QueryDesc *queryDesc);
|
||||
extern void ExecCheckRTPerms(List *rangeTable);
|
||||
extern void ExecEndPlan(PlanState *planstate, EState *estate);
|
||||
extern bool ExecContextForcesOids(PlanState *planstate, bool *hasoids);
|
||||
extern void ExecConstraints(ResultRelInfo *resultRelInfo,
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.168 2007/02/20 17:32:17 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.169 2007/02/22 22:00:25 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -302,7 +302,7 @@ typedef struct EState
|
||||
ScanDirection es_direction; /* current scan direction */
|
||||
Snapshot es_snapshot; /* time qual to use */
|
||||
Snapshot es_crosscheck_snapshot; /* crosscheck time qual for RI */
|
||||
List *es_range_table; /* List of RangeTableEntrys */
|
||||
List *es_range_table; /* List of RangeTblEntry */
|
||||
|
||||
/* Info about target table for insert/update/delete queries: */
|
||||
ResultRelInfo *es_result_relations; /* array of ResultRelInfos */
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/include/nodes/plannodes.h,v 1.91 2007/02/20 17:32:17 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/include/nodes/plannodes.h,v 1.92 2007/02/22 22:00:25 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -48,6 +48,8 @@ typedef struct PlannedStmt
|
||||
|
||||
IntoClause *into; /* target for SELECT INTO / CREATE TABLE AS */
|
||||
|
||||
List *subplans; /* Plan trees for SubPlan expressions */
|
||||
|
||||
/*
|
||||
* If the query has a returningList then the planner will store a list of
|
||||
* processed targetlists (one per result relation) here. We must have a
|
||||
@ -65,6 +67,10 @@ typedef struct PlannedStmt
|
||||
int nParamExec; /* number of PARAM_EXEC Params used */
|
||||
} PlannedStmt;
|
||||
|
||||
/* macro for fetching the Plan associated with a SubPlan node */
|
||||
#define exec_subplan_get_plan(plannedstmt, subplan) \
|
||||
((Plan *) list_nth((plannedstmt)->subplans, (subplan)->plan_id - 1))
|
||||
|
||||
|
||||
/* ----------------
|
||||
* Plan node
|
||||
@ -313,12 +319,17 @@ typedef struct TidScan
|
||||
* the generic lefttree field as you might expect. This is because we do
|
||||
* not want plan-tree-traversal routines to recurse into the subplan without
|
||||
* knowing that they are changing Query contexts.
|
||||
*
|
||||
* Note: subrtable is used just to carry the subquery rangetable from
|
||||
* createplan.c to setrefs.c; it should always be NIL by the time the
|
||||
* executor sees the plan.
|
||||
* ----------------
|
||||
*/
|
||||
typedef struct SubqueryScan
|
||||
{
|
||||
Scan scan;
|
||||
Plan *subplan;
|
||||
List *subrtable; /* temporary workspace for planner */
|
||||
} SubqueryScan;
|
||||
|
||||
/* ----------------
|
||||
|
@ -10,7 +10,7 @@
|
||||
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.126 2007/02/20 17:32:17 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.127 2007/02/22 22:00:25 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -428,8 +428,10 @@ typedef struct SubLink
|
||||
* SubPlan - executable expression node for a subplan (sub-SELECT)
|
||||
*
|
||||
* The planner replaces SubLink nodes in expression trees with SubPlan
|
||||
* nodes after it has finished planning the subquery. SubPlan contains
|
||||
* a sub-plantree and rtable instead of a sub-Query.
|
||||
* nodes after it has finished planning the subquery. SubPlan references
|
||||
* a sub-plantree stored in the subplans list of the toplevel PlannedStmt.
|
||||
* (We avoid a direct link to make it easier to copy expression trees
|
||||
* without causing multiple processing of the subplan.)
|
||||
*
|
||||
* In an ordinary subplan, testexpr points to an executable expression
|
||||
* (OpExpr, an AND/OR tree of OpExprs, or RowCompareExpr) for the combining
|
||||
@ -463,12 +465,10 @@ typedef struct SubPlan
|
||||
/* The combining operators, transformed to an executable expression: */
|
||||
Node *testexpr; /* OpExpr or RowCompareExpr expression tree */
|
||||
List *paramIds; /* IDs of Params embedded in the above */
|
||||
/* The subselect, transformed to a Plan: */
|
||||
struct Plan *plan; /* subselect plan itself */
|
||||
int plan_id; /* kluge because we haven't equal-funcs for
|
||||
* plan nodes... we compare this instead of
|
||||
* subselect plan */
|
||||
List *rtable; /* range table for subselect */
|
||||
/* Identification of the Plan tree to use: */
|
||||
int plan_id; /* Index (from 1) in PlannedStmt.subplans */
|
||||
/* Extra data saved for the convenience of exprType(): */
|
||||
Oid firstColType; /* Type of first column of subplan result */
|
||||
/* Information about execution strategy: */
|
||||
bool useHashTable; /* TRUE to store subselect output in a hash
|
||||
* table (implies we are doing "IN") */
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/include/nodes/print.h,v 1.26 2007/01/05 22:19:56 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/include/nodes/print.h,v 1.27 2007/02/22 22:00:25 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -31,8 +31,5 @@ extern void print_expr(Node *expr, List *rtable);
|
||||
extern void print_pathkeys(List *pathkeys, List *rtable);
|
||||
extern void print_tl(List *tlist, List *rtable);
|
||||
extern void print_slot(TupleTableSlot *slot);
|
||||
extern void print_plan_recursive(Plan *p, Query *parsetree,
|
||||
int indentLevel, char *label);
|
||||
extern void print_plan(Plan *p, Query *parsetree);
|
||||
|
||||
#endif /* PRINT_H */
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.137 2007/02/20 17:32:17 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.138 2007/02/22 22:00:26 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -64,9 +64,17 @@ typedef struct PlannerGlobal
|
||||
|
||||
List *paramlist; /* to keep track of cross-level Params */
|
||||
|
||||
int next_plan_id; /* hack for distinguishing SubPlans */
|
||||
List *subplans; /* Plans for SubPlan nodes */
|
||||
|
||||
List *subrtables; /* Rangetables for SubPlan nodes */
|
||||
|
||||
List *finalrtable; /* "flat" rangetable for executor */
|
||||
} PlannerGlobal;
|
||||
|
||||
/* macro for fetching the Plan associated with a SubPlan node */
|
||||
#define planner_subplan_get_plan(root, subplan) \
|
||||
((Plan *) list_nth((root)->glob->subplans, (subplan)->plan_id - 1))
|
||||
|
||||
|
||||
/*----------
|
||||
* PlannerInfo
|
||||
@ -228,6 +236,7 @@ typedef struct PlannerInfo
|
||||
* pages - number of disk pages in relation (zero if not a table)
|
||||
* tuples - number of tuples in relation (not considering restrictions)
|
||||
* subplan - plan for subquery (NULL if it's not a subquery)
|
||||
* subrtable - rangetable for subquery (NIL if it's not a subquery)
|
||||
*
|
||||
* Note: for a subquery, tuples and subplan are not set immediately
|
||||
* upon creation of the RelOptInfo object; they are filled in when
|
||||
@ -310,6 +319,7 @@ typedef struct RelOptInfo
|
||||
BlockNumber pages;
|
||||
double tuples;
|
||||
struct Plan *subplan; /* if subquery */
|
||||
List *subrtable; /* if subquery */
|
||||
|
||||
/* used by various scans and joins: */
|
||||
List *baserestrictinfo; /* RestrictInfo structures (if base
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/include/optimizer/cost.h,v 1.84 2007/01/22 01:35:22 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/include/optimizer/cost.h,v 1.85 2007/02/22 22:00:26 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -88,8 +88,8 @@ extern void cost_group(Path *path, PlannerInfo *root,
|
||||
extern void cost_nestloop(NestPath *path, PlannerInfo *root);
|
||||
extern void cost_mergejoin(MergePath *path, PlannerInfo *root);
|
||||
extern void cost_hashjoin(HashPath *path, PlannerInfo *root);
|
||||
extern void cost_qual_eval(QualCost *cost, List *quals);
|
||||
extern void cost_qual_eval_node(QualCost *cost, Node *qual);
|
||||
extern void cost_qual_eval(QualCost *cost, List *quals, PlannerInfo *root);
|
||||
extern void cost_qual_eval_node(QualCost *cost, Node *qual, PlannerInfo *root);
|
||||
extern void set_baserel_size_estimates(PlannerInfo *root, RelOptInfo *rel);
|
||||
extern void set_joinrel_size_estimates(PlannerInfo *root, RelOptInfo *rel,
|
||||
RelOptInfo *outer_rel,
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/include/optimizer/planmain.h,v 1.99 2007/01/22 01:35:22 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/include/optimizer/planmain.h,v 1.100 2007/02/22 22:00:26 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -36,7 +36,7 @@ extern Plan *optimize_minmax_aggregates(PlannerInfo *root, List *tlist,
|
||||
*/
|
||||
extern Plan *create_plan(PlannerInfo *root, Path *best_path);
|
||||
extern SubqueryScan *make_subqueryscan(List *qptlist, List *qpqual,
|
||||
Index scanrelid, Plan *subplan);
|
||||
Index scanrelid, Plan *subplan, List *subrtable);
|
||||
extern Append *make_append(List *appendplans, bool isTarget, List *tlist);
|
||||
extern Sort *make_sort_from_pathkeys(PlannerInfo *root, Plan *lefttree,
|
||||
List *pathkeys);
|
||||
@ -60,7 +60,8 @@ extern Limit *make_limit(Plan *lefttree, Node *limitOffset, Node *limitCount,
|
||||
int64 offset_est, int64 count_est);
|
||||
extern SetOp *make_setop(SetOpCmd cmd, Plan *lefttree,
|
||||
List *distinctList, AttrNumber flagColIdx);
|
||||
extern Result *make_result(List *tlist, Node *resconstantqual, Plan *subplan);
|
||||
extern Result *make_result(PlannerInfo *root, List *tlist,
|
||||
Node *resconstantqual, Plan *subplan);
|
||||
extern bool is_projection_capable_plan(Plan *plan);
|
||||
|
||||
/*
|
||||
@ -91,7 +92,9 @@ extern RestrictInfo *build_implied_join_equality(Oid opno,
|
||||
/*
|
||||
* prototypes for plan/setrefs.c
|
||||
*/
|
||||
extern Plan *set_plan_references(Plan *plan, List *rtable);
|
||||
extern Plan *set_plan_references(PlannerGlobal *glob,
|
||||
Plan *plan,
|
||||
List *rtable);
|
||||
extern List *set_returning_clause_references(List *rlist,
|
||||
Plan *topplan,
|
||||
Index resultRelation);
|
||||
|
Loading…
Reference in New Issue
Block a user