mirror of
https://github.com/postgres/postgres.git
synced 2025-06-22 02:52:08 +03:00
Old planner() becomes union_planner(); new planner() makes initialization
of some global variables to support subselects and calls union_planner(). Calls to SS_replace_correlation_vars() and SS_process_sublinks() in query_planner() before planning. Get rid of #ifdef INDEXSCAN_PATCH in createplan.c.
This commit is contained in:
@ -4,7 +4,7 @@
|
|||||||
# Makefile for optimizer/plan
|
# Makefile for optimizer/plan
|
||||||
#
|
#
|
||||||
# IDENTIFICATION
|
# IDENTIFICATION
|
||||||
# $Header: /cvsroot/pgsql/src/backend/optimizer/plan/Makefile,v 1.5 1997/12/20 00:24:31 scrappy Exp $
|
# $Header: /cvsroot/pgsql/src/backend/optimizer/plan/Makefile,v 1.6 1998/02/13 03:36:51 vadim Exp $
|
||||||
#
|
#
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
|
|
||||||
@ -15,7 +15,7 @@ INCLUDE_OPT = -I../..
|
|||||||
|
|
||||||
CFLAGS+=$(INCLUDE_OPT)
|
CFLAGS+=$(INCLUDE_OPT)
|
||||||
|
|
||||||
OBJS = createplan.o initsplan.o planmain.o planner.o setrefs.o
|
OBJS = createplan.o initsplan.o planmain.o planner.o setrefs.o subselect.o
|
||||||
|
|
||||||
# not ready yet: predmig.o xfunc.o
|
# not ready yet: predmig.o xfunc.o
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.25 1998/02/10 04:01:09 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.26 1998/02/13 03:36:54 vadim Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -685,13 +685,11 @@ fix_indxqual_references(Node *clause, Path *index_path)
|
|||||||
else if (IsA(clause, Const))
|
else if (IsA(clause, Const))
|
||||||
{
|
{
|
||||||
return (clause);
|
return (clause);
|
||||||
#ifdef INDEXSCAN_PATCH
|
|
||||||
}
|
}
|
||||||
else if (IsA(clause, Param))
|
else if (IsA(clause, Param))
|
||||||
{
|
{
|
||||||
/* Function parameter used as index scan arg. DZ - 27-8-1996 */
|
/* Function parameter used as index scan arg. DZ - 27-8-1996 */
|
||||||
return (clause);
|
return (clause);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
else if (is_opclause(clause) &&
|
else if (is_opclause(clause) &&
|
||||||
is_funcclause((Node *) get_leftop((Expr *) clause)) &&
|
is_funcclause((Node *) get_leftop((Expr *) clause)) &&
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planmain.c,v 1.18 1998/02/10 04:01:12 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planmain.c,v 1.19 1998/02/13 03:36:57 vadim Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -22,7 +22,9 @@
|
|||||||
#include "nodes/makefuncs.h"
|
#include "nodes/makefuncs.h"
|
||||||
|
|
||||||
#include "optimizer/planmain.h"
|
#include "optimizer/planmain.h"
|
||||||
|
#include "optimizer/subselect.h"
|
||||||
#include "optimizer/internal.h"
|
#include "optimizer/internal.h"
|
||||||
|
#include "optimizer/prep.h"
|
||||||
#include "optimizer/paths.h"
|
#include "optimizer/paths.h"
|
||||||
#include "optimizer/clauses.h"
|
#include "optimizer/clauses.h"
|
||||||
#include "optimizer/keys.h"
|
#include "optimizer/keys.h"
|
||||||
@ -73,6 +75,17 @@ query_planner(Query *root,
|
|||||||
List *level_tlist = NIL;
|
List *level_tlist = NIL;
|
||||||
Plan *subplan = NULL;
|
Plan *subplan = NULL;
|
||||||
|
|
||||||
|
if ( PlannerQueryLevel > 1 )
|
||||||
|
{
|
||||||
|
/* should copy be made ? */
|
||||||
|
tlist = (List *) SS_replace_correlation_vars ((Node*)tlist);
|
||||||
|
qual = (List *) SS_replace_correlation_vars ((Node*)qual);
|
||||||
|
}
|
||||||
|
if (root->hasSubLinks)
|
||||||
|
qual = (List *) SS_process_sublinks ((Node*) qual);
|
||||||
|
|
||||||
|
qual = cnfify((Expr *) qual, true);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A command without a target list or qualification is an error,
|
* A command without a target list or qualification is an error,
|
||||||
* except for "delete foo".
|
* except for "delete foo".
|
||||||
|
@ -7,11 +7,12 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.21 1998/01/15 18:59:48 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.22 1998/02/13 03:36:59 vadim Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
@ -30,6 +31,7 @@
|
|||||||
#include "optimizer/plancat.h"
|
#include "optimizer/plancat.h"
|
||||||
#include "optimizer/prep.h"
|
#include "optimizer/prep.h"
|
||||||
#include "optimizer/planmain.h"
|
#include "optimizer/planmain.h"
|
||||||
|
#include "optimizer/subselect.h"
|
||||||
#include "optimizer/paths.h"
|
#include "optimizer/paths.h"
|
||||||
#include "optimizer/cost.h"
|
#include "optimizer/cost.h"
|
||||||
|
|
||||||
@ -56,10 +58,32 @@ extern Plan *make_groupPlan(List **tlist, bool tuplePerGroup,
|
|||||||
*
|
*
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
|
Plan*
|
||||||
|
planner(Query *parse)
|
||||||
|
{
|
||||||
|
Plan *result_plan;
|
||||||
|
|
||||||
|
PlannerQueryLevel = 1;
|
||||||
|
PlannerVarParam = NULL;
|
||||||
|
PlannerParamVar = NULL;
|
||||||
|
PlannerInitPlan = NULL;
|
||||||
|
PlannerPlanId = 0;
|
||||||
|
|
||||||
|
result_plan = union_planner (parse);
|
||||||
|
|
||||||
|
Assert (PlannerQueryLevel == 1);
|
||||||
|
if ( PlannerPlanId > 0 )
|
||||||
|
{
|
||||||
|
result_plan->initPlan = PlannerInitPlan;
|
||||||
|
(void) SS_finalize_plan (result_plan);
|
||||||
|
}
|
||||||
|
result_plan->nParamExec = length (PlannerParamVar);
|
||||||
|
|
||||||
|
return (result_plan);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* planner--
|
* union_planner--
|
||||||
* Main query optimizer routine.
|
|
||||||
*
|
*
|
||||||
* Invokes the planner on union queries if there are any left,
|
* Invokes the planner on union queries if there are any left,
|
||||||
* recursing if necessary to get them all, then processes normal plans.
|
* recursing if necessary to get them all, then processes normal plans.
|
||||||
@ -68,14 +92,13 @@ extern Plan *make_groupPlan(List **tlist, bool tuplePerGroup,
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
Plan *
|
Plan *
|
||||||
planner(Query *parse)
|
union_planner(Query *parse)
|
||||||
{
|
{
|
||||||
List *tlist = parse->targetList;
|
List *tlist = parse->targetList;
|
||||||
List *rangetable = parse->rtable;
|
List *rangetable = parse->rtable;
|
||||||
|
|
||||||
Plan *result_plan = (Plan *) NULL;
|
Plan *result_plan = (Plan *) NULL;
|
||||||
|
|
||||||
List *primary_qual;
|
|
||||||
Index rt_index;
|
Index rt_index;
|
||||||
|
|
||||||
|
|
||||||
@ -100,17 +123,25 @@ planner(Query *parse)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
List **vpm = NULL;
|
||||||
|
|
||||||
tlist = preprocess_targetlist(tlist,
|
tlist = preprocess_targetlist(tlist,
|
||||||
parse->commandType,
|
parse->commandType,
|
||||||
parse->resultRelation,
|
parse->resultRelation,
|
||||||
parse->rtable);
|
parse->rtable);
|
||||||
|
if ( parse->rtable != NULL )
|
||||||
primary_qual = cnfify((Expr *) parse->qual, true);
|
{
|
||||||
|
vpm = (List **) palloc (length (parse->rtable) * sizeof (List*));
|
||||||
|
memset (vpm, 0, length (parse->rtable) * sizeof (List*));
|
||||||
|
}
|
||||||
|
PlannerVarParam = lcons (vpm, PlannerVarParam);
|
||||||
result_plan = query_planner(parse,
|
result_plan = query_planner(parse,
|
||||||
parse->commandType,
|
parse->commandType,
|
||||||
tlist,
|
tlist,
|
||||||
primary_qual);
|
(List*) parse->qual);
|
||||||
|
PlannerVarParam = lnext (PlannerVarParam);
|
||||||
|
if ( vpm != NULL )
|
||||||
|
pfree (vpm);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.17 1998/02/10 04:01:13 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.18 1998/02/13 03:37:02 vadim Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -405,7 +405,21 @@ replace_clause_joinvar_refs(Expr *clause,
|
|||||||
leftvar,
|
leftvar,
|
||||||
rightvar));
|
rightvar));
|
||||||
}
|
}
|
||||||
|
else if (is_subplan(clause))
|
||||||
|
{
|
||||||
|
((Expr*) clause)->args =
|
||||||
|
replace_subclause_joinvar_refs(((Expr*) clause)->args,
|
||||||
|
outer_tlist,
|
||||||
|
inner_tlist);
|
||||||
|
((SubPlan*) ((Expr*) clause)->oper)->sublink->oper =
|
||||||
|
replace_subclause_joinvar_refs(((SubPlan*) ((Expr*) clause)->oper)->sublink->oper,
|
||||||
|
outer_tlist,
|
||||||
|
inner_tlist);
|
||||||
|
return ((List*) clause);
|
||||||
|
}
|
||||||
/* shouldn't reach here */
|
/* shouldn't reach here */
|
||||||
|
elog (ERROR, "replace_clause_joinvar_refs: unsupported clause %d",
|
||||||
|
nodeTag (clause));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
549
src/backend/optimizer/plan/subselect.c
Normal file
549
src/backend/optimizer/plan/subselect.c
Normal file
@ -0,0 +1,549 @@
|
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* subselect.c--
|
||||||
|
*
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
#include "postgres.h"
|
||||||
|
|
||||||
|
#include "catalog/pg_type.h"
|
||||||
|
|
||||||
|
#include "nodes/pg_list.h"
|
||||||
|
#include "nodes/plannodes.h"
|
||||||
|
#include "nodes/parsenodes.h"
|
||||||
|
#include "nodes/relation.h"
|
||||||
|
#include "nodes/makefuncs.h"
|
||||||
|
#include "nodes/nodeFuncs.h"
|
||||||
|
|
||||||
|
#include "optimizer/subselect.h"
|
||||||
|
#include "optimizer/planner.h"
|
||||||
|
#include "optimizer/planmain.h"
|
||||||
|
#include "optimizer/internal.h"
|
||||||
|
#include "optimizer/paths.h"
|
||||||
|
#include "optimizer/clauses.h"
|
||||||
|
#include "optimizer/keys.h"
|
||||||
|
#include "optimizer/tlist.h"
|
||||||
|
#include "optimizer/var.h"
|
||||||
|
#include "optimizer/cost.h"
|
||||||
|
|
||||||
|
int PlannerQueryLevel; /* level of current query */
|
||||||
|
List *PlannerVarParam; /* correlation Vars to Param mapper */
|
||||||
|
List *PlannerParamVar; /* to get Var from Param->paramid */
|
||||||
|
List *PlannerInitPlan; /* init subplans for current query */
|
||||||
|
int PlannerPlanId;
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
_new_param (Var *var, int varlevel)
|
||||||
|
{
|
||||||
|
List *last;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
if ( PlannerParamVar == NULL )
|
||||||
|
last = PlannerParamVar = makeNode(List);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (last = PlannerParamVar; ; )
|
||||||
|
{
|
||||||
|
i++;
|
||||||
|
if ( lnext(last) == NULL )
|
||||||
|
break;
|
||||||
|
last = lnext(last);
|
||||||
|
}
|
||||||
|
lnext(last) = makeNode(List);
|
||||||
|
last = lnext(last);
|
||||||
|
}
|
||||||
|
|
||||||
|
lnext(last) = NULL;
|
||||||
|
lfirst(last) = makeVar (var->varno, var->varattno, var->vartype,
|
||||||
|
var->vartypmod, varlevel, var->varnoold, var->varoattno);
|
||||||
|
|
||||||
|
return (i);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Param*
|
||||||
|
_replace_var (Var *var)
|
||||||
|
{
|
||||||
|
List **rt = (List**) nth (var->varlevelsup, PlannerVarParam);
|
||||||
|
List *vpe = rt[var->varno - 1];
|
||||||
|
Param *retval;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if ( vpe == NULL )
|
||||||
|
{
|
||||||
|
vpe = rt[var->varno - 1] = makeNode(List);
|
||||||
|
lfirsti(vpe) = -1;
|
||||||
|
lnext(vpe) = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 1; ; i++)
|
||||||
|
{
|
||||||
|
if ( i == var->varattno )
|
||||||
|
break;
|
||||||
|
if ( lnext(vpe) == NULL )
|
||||||
|
{
|
||||||
|
lnext(vpe) = makeNode(List);
|
||||||
|
vpe = lnext(vpe);
|
||||||
|
lfirsti(vpe) = -1;
|
||||||
|
lnext(vpe) = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
vpe = lnext(vpe);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( (i = lfirsti(vpe)) < 0 ) /* parameter is not assigned */
|
||||||
|
{
|
||||||
|
i = _new_param (var, PlannerQueryLevel - var->varlevelsup);
|
||||||
|
}
|
||||||
|
|
||||||
|
retval = makeNode(Param);
|
||||||
|
retval->paramkind = PARAM_EXEC;
|
||||||
|
retval->paramid = (AttrNumber) i;
|
||||||
|
retval->paramtype = var->vartype;
|
||||||
|
|
||||||
|
return (retval);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Node*
|
||||||
|
_make_subplan (SubLink *slink)
|
||||||
|
{
|
||||||
|
SubPlan *node = makeNode (SubPlan);
|
||||||
|
Plan *plan;
|
||||||
|
List *lst;
|
||||||
|
Node *result;
|
||||||
|
List *saved_ip = PlannerInitPlan;
|
||||||
|
|
||||||
|
PlannerInitPlan = NULL;
|
||||||
|
|
||||||
|
PlannerQueryLevel++; /* we becomes child */
|
||||||
|
|
||||||
|
node->plan = plan = union_planner ((Query*) slink->subselect);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Assign subPlan, extParam and locParam to plan nodes.
|
||||||
|
* At the moment, SS_finalize_plan doesn't handle initPlan-s
|
||||||
|
* and so we assigne them to the topmost plan node and take
|
||||||
|
* care about its extParam too.
|
||||||
|
*/
|
||||||
|
(void) SS_finalize_plan (plan);
|
||||||
|
plan->initPlan = PlannerInitPlan;
|
||||||
|
|
||||||
|
/* Get extParam from InitPlan-s */
|
||||||
|
foreach (lst, PlannerInitPlan)
|
||||||
|
{
|
||||||
|
List *lp;
|
||||||
|
|
||||||
|
foreach (lp, ((SubPlan*) lfirst (lst))->plan->extParam)
|
||||||
|
{
|
||||||
|
if ( !intMember (lfirsti(lp), plan->extParam) )
|
||||||
|
plan->extParam = lappendi (plan->extParam, lfirsti(lp));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* and now we are parent again */
|
||||||
|
PlannerInitPlan = saved_ip;
|
||||||
|
PlannerQueryLevel--;
|
||||||
|
|
||||||
|
node->plan_id = PlannerPlanId++;
|
||||||
|
node->rtable = ((Query*) slink->subselect)->rtable;
|
||||||
|
node->sublink = slink;
|
||||||
|
slink->subselect = NULL; /* cool ?! */
|
||||||
|
|
||||||
|
/* make parParam list */
|
||||||
|
foreach (lst, plan->extParam)
|
||||||
|
{
|
||||||
|
Var *var = nth (lfirsti(lst), PlannerParamVar);
|
||||||
|
|
||||||
|
if ( var->varlevelsup == PlannerQueryLevel )
|
||||||
|
node->parParam = lappendi (node->parParam, lfirsti(lst));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Un-correlated or undirect correlated plans of EXISTS or EXPR
|
||||||
|
* types can be used as initPlans...
|
||||||
|
*/
|
||||||
|
if ( node->parParam == NULL && slink->subLinkType == EXPR_SUBLINK )
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
/* transform right side of all sublink Oper-s into Param */
|
||||||
|
foreach (lst, slink->oper)
|
||||||
|
{
|
||||||
|
List *rside = lnext(((Expr*) lfirst(lst))->args);
|
||||||
|
TargetEntry *te = nth (i, plan->targetlist);
|
||||||
|
Var *var = makeVar (0, 0, te->resdom->restype,
|
||||||
|
te->resdom->restypmod,
|
||||||
|
PlannerQueryLevel, 0, 0);
|
||||||
|
Param *prm = makeNode(Param);
|
||||||
|
|
||||||
|
prm->paramkind = PARAM_EXEC;
|
||||||
|
prm->paramid = (AttrNumber) _new_param (var, PlannerQueryLevel);
|
||||||
|
prm->paramtype = var->vartype;
|
||||||
|
lfirst(rside) = prm;
|
||||||
|
node->setParam = lappendi (node->setParam, prm->paramid);
|
||||||
|
pfree (var);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
PlannerInitPlan = lappend (PlannerInitPlan, node);
|
||||||
|
if ( i > 1 )
|
||||||
|
result = (Node*) ((slink->useor) ? make_orclause (slink->oper) :
|
||||||
|
make_andclause (slink->oper));
|
||||||
|
else
|
||||||
|
result = (Node*) lfirst (slink->oper);
|
||||||
|
}
|
||||||
|
else if ( node->parParam == NULL && slink->subLinkType == EXISTS_SUBLINK )
|
||||||
|
{
|
||||||
|
Var *var = makeVar (0, 0, BOOLOID, -1, PlannerQueryLevel, 0, 0);
|
||||||
|
Param *prm = makeNode(Param);
|
||||||
|
|
||||||
|
prm->paramkind = PARAM_EXEC;
|
||||||
|
prm->paramid = (AttrNumber) _new_param (var, PlannerQueryLevel);
|
||||||
|
prm->paramtype = var->vartype;
|
||||||
|
node->setParam = lappendi (node->setParam, prm->paramid);
|
||||||
|
pfree (var);
|
||||||
|
PlannerInitPlan = lappend (PlannerInitPlan, node);
|
||||||
|
result = (Node*) prm;
|
||||||
|
}
|
||||||
|
else /* make expression of SUBPLAN type */
|
||||||
|
{
|
||||||
|
Expr *expr = makeNode (Expr);
|
||||||
|
List *args = NULL;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
expr->typeOid = BOOLOID;
|
||||||
|
expr->opType = SUBPLAN_EXPR;
|
||||||
|
expr->oper = (Node*) node;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Make expr->args from parParam. Left sides of sublink Oper-s
|
||||||
|
* are handled by optimizer directly...
|
||||||
|
* Also, transform right side of sublink Oper-s into Const.
|
||||||
|
*/
|
||||||
|
foreach (lst, node->parParam)
|
||||||
|
{
|
||||||
|
Var *var = nth (lfirsti (lst), PlannerParamVar);
|
||||||
|
|
||||||
|
var = (Var*) copyObject (var);
|
||||||
|
var->varlevelsup = 0;
|
||||||
|
args = lappend (args, var);
|
||||||
|
}
|
||||||
|
foreach (lst, slink->oper)
|
||||||
|
{
|
||||||
|
List *rside = lnext(((Expr*) lfirst(lst))->args);
|
||||||
|
TargetEntry *te = nth (i, plan->targetlist);
|
||||||
|
Const *con = makeConst (te->resdom->restype,
|
||||||
|
0, 0, true, 0, 0, 0);
|
||||||
|
lfirst(rside) = con;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
expr->args = args;
|
||||||
|
result = (Node*) expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (result);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static List *
|
||||||
|
set_unioni (List *l1, List *l2)
|
||||||
|
{
|
||||||
|
if (l1 == NULL)
|
||||||
|
return (l2);
|
||||||
|
if (l2 == NULL)
|
||||||
|
return (l1);
|
||||||
|
|
||||||
|
return (nconc (l1, set_differencei (l2, l1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
static List *
|
||||||
|
_finalize_primnode (void *expr, List **subplan)
|
||||||
|
{
|
||||||
|
List *result = NULL;
|
||||||
|
|
||||||
|
if ( expr == NULL )
|
||||||
|
return (NULL);
|
||||||
|
|
||||||
|
if (IsA (expr, Param))
|
||||||
|
{
|
||||||
|
if ( ((Param*) expr)->paramkind == PARAM_EXEC )
|
||||||
|
return (lconsi (((Param*) expr)->paramid, (List*) NULL));
|
||||||
|
}
|
||||||
|
else if (single_node(expr))
|
||||||
|
return (NULL);
|
||||||
|
else if (IsA (expr, List))
|
||||||
|
{
|
||||||
|
List *le;
|
||||||
|
foreach (le, (List*) expr)
|
||||||
|
result = set_unioni (result,
|
||||||
|
_finalize_primnode (lfirst(le), subplan));
|
||||||
|
}
|
||||||
|
else if (IsA (expr, Iter))
|
||||||
|
return (_finalize_primnode (((Iter*) expr)->iterexpr, subplan));
|
||||||
|
else if (or_clause(expr) || and_clause(expr) || is_opclause(expr) ||
|
||||||
|
not_clause (expr) || is_funcclause(expr))
|
||||||
|
return (_finalize_primnode (((Expr*) expr)->args, subplan));
|
||||||
|
else if (IsA (expr, Aggreg))
|
||||||
|
return (_finalize_primnode (((Aggreg *) expr)->target, subplan));
|
||||||
|
else if (IsA (expr, ArrayRef))
|
||||||
|
{
|
||||||
|
result = _finalize_primnode (((ArrayRef*) expr)->refupperindexpr, subplan);
|
||||||
|
result = set_unioni (result,
|
||||||
|
_finalize_primnode (((ArrayRef *) expr)->reflowerindexpr, subplan));
|
||||||
|
result = set_unioni (result,
|
||||||
|
_finalize_primnode (((ArrayRef *) expr)->refexpr, subplan));
|
||||||
|
result = set_unioni (result,
|
||||||
|
_finalize_primnode (((ArrayRef *) expr)->refassgnexpr, subplan));
|
||||||
|
}
|
||||||
|
else if (IsA (expr, TargetEntry))
|
||||||
|
return (_finalize_primnode (((TargetEntry*) expr)->expr, subplan));
|
||||||
|
else if (is_subplan (expr))
|
||||||
|
{
|
||||||
|
List *lst;
|
||||||
|
|
||||||
|
*subplan = lappend (*subplan, ((Expr*) expr)->oper);
|
||||||
|
foreach (lst, ((SubPlan*) ((Expr*) expr)->oper)->plan->extParam)
|
||||||
|
{
|
||||||
|
Var *var = nth (lfirsti(lst), PlannerParamVar);
|
||||||
|
|
||||||
|
if ( var->varlevelsup < PlannerQueryLevel &&
|
||||||
|
!intMember (lfirsti(lst), result) )
|
||||||
|
result = lappendi (result, lfirsti(lst));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
elog (ERROR, "_finalize_primnode: can't handle node %d",
|
||||||
|
nodeTag (expr));
|
||||||
|
|
||||||
|
return (result);
|
||||||
|
}
|
||||||
|
|
||||||
|
Node *
|
||||||
|
SS_replace_correlation_vars (Node *expr)
|
||||||
|
{
|
||||||
|
|
||||||
|
if ( expr == NULL )
|
||||||
|
return (NULL);
|
||||||
|
if (IsA (expr, List))
|
||||||
|
{
|
||||||
|
List *le;
|
||||||
|
foreach (le, (List*) expr)
|
||||||
|
lfirst(le) = SS_replace_correlation_vars ((Node*) lfirst(le));
|
||||||
|
}
|
||||||
|
else if (IsA (expr, Var))
|
||||||
|
{
|
||||||
|
if ( ((Var*) expr)->varlevelsup > 0 )
|
||||||
|
{
|
||||||
|
Assert (((Var*) expr)->varlevelsup < PlannerQueryLevel);
|
||||||
|
expr = (Node*) _replace_var ((Var*) expr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (IsA (expr, Iter))
|
||||||
|
{
|
||||||
|
((Iter*) expr)->iterexpr =
|
||||||
|
SS_replace_correlation_vars(((Iter*) expr)->iterexpr);
|
||||||
|
}
|
||||||
|
else if (single_node(expr))
|
||||||
|
return (expr);
|
||||||
|
else if (or_clause(expr) || and_clause(expr) || is_opclause(expr) ||
|
||||||
|
not_clause (expr) || is_funcclause(expr))
|
||||||
|
((Expr *) expr)->args = (List*)
|
||||||
|
SS_replace_correlation_vars ((Node*) ((Expr *) expr)->args);
|
||||||
|
else if (IsA (expr, Aggreg))
|
||||||
|
((Aggreg *) expr)->target =
|
||||||
|
SS_replace_correlation_vars ((Node*) ((Aggreg *) expr)->target);
|
||||||
|
else if (IsA (expr, ArrayRef))
|
||||||
|
{
|
||||||
|
((ArrayRef *) expr)->refupperindexpr = (List*)
|
||||||
|
SS_replace_correlation_vars ((Node*) ((ArrayRef *) expr)->refupperindexpr);
|
||||||
|
((ArrayRef *) expr)->reflowerindexpr = (List*)
|
||||||
|
SS_replace_correlation_vars ((Node*) ((ArrayRef *) expr)->reflowerindexpr);
|
||||||
|
((ArrayRef *) expr)->refexpr =
|
||||||
|
SS_replace_correlation_vars ((Node*) ((ArrayRef *) expr)->refexpr);
|
||||||
|
((ArrayRef *) expr)->refassgnexpr =
|
||||||
|
SS_replace_correlation_vars (((ArrayRef *) expr)->refassgnexpr);
|
||||||
|
}
|
||||||
|
else if (IsA (expr, TargetEntry))
|
||||||
|
((TargetEntry*) expr)->expr =
|
||||||
|
SS_replace_correlation_vars ((Node*) ((TargetEntry*) expr)->expr);
|
||||||
|
else if (IsA (expr, SubLink))
|
||||||
|
{
|
||||||
|
List *le;
|
||||||
|
|
||||||
|
foreach (le, ((SubLink*) expr)->oper) /* left sides only */
|
||||||
|
{
|
||||||
|
List *oparg = ((Expr*) lfirst (le))->args;
|
||||||
|
|
||||||
|
lfirst (oparg) = (List*)
|
||||||
|
SS_replace_correlation_vars ((Node*) lfirst (oparg));
|
||||||
|
}
|
||||||
|
((SubLink*) expr)->lefthand = (List*)
|
||||||
|
SS_replace_correlation_vars ((Node*) ((SubLink*) expr)->lefthand);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
elog (NOTICE, "SS_replace_correlation_vars: can't handle node %d",
|
||||||
|
nodeTag (expr));
|
||||||
|
|
||||||
|
return (expr);
|
||||||
|
}
|
||||||
|
|
||||||
|
Node*
|
||||||
|
SS_process_sublinks (Node *expr)
|
||||||
|
{
|
||||||
|
if ( expr == NULL )
|
||||||
|
return (NULL);
|
||||||
|
if (IsA (expr, List))
|
||||||
|
{
|
||||||
|
List *le;
|
||||||
|
foreach (le, (List*) expr)
|
||||||
|
lfirst(le) = SS_process_sublinks ((Node*) lfirst(le));
|
||||||
|
}
|
||||||
|
else if (or_clause(expr) || and_clause(expr) || is_opclause(expr) ||
|
||||||
|
not_clause (expr) || is_funcclause(expr))
|
||||||
|
((Expr *) expr)->args = (List*)
|
||||||
|
SS_process_sublinks ((Node*) ((Expr *) expr)->args);
|
||||||
|
else if (IsA (expr, SubLink)) /* got it! */
|
||||||
|
expr = _make_subplan ((SubLink*) expr);
|
||||||
|
|
||||||
|
return (expr);
|
||||||
|
}
|
||||||
|
|
||||||
|
List*
|
||||||
|
SS_finalize_plan (Plan *plan)
|
||||||
|
{
|
||||||
|
List *extParam = NULL;
|
||||||
|
List *locParam = NULL;
|
||||||
|
List *subPlan = NULL;
|
||||||
|
List *param_list;
|
||||||
|
List *lst;
|
||||||
|
|
||||||
|
if ( plan == NULL )
|
||||||
|
return (NULL);
|
||||||
|
|
||||||
|
param_list = _finalize_primnode (plan->targetlist, &subPlan);
|
||||||
|
Assert (subPlan == NULL);
|
||||||
|
|
||||||
|
switch (nodeTag(plan))
|
||||||
|
{
|
||||||
|
case T_Result:
|
||||||
|
param_list = set_unioni (param_list,
|
||||||
|
_finalize_primnode (((Result*) plan)->resconstantqual, &subPlan));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case T_Append:
|
||||||
|
foreach (lst, ((Append*) plan)->unionplans)
|
||||||
|
param_list = set_unioni (param_list,
|
||||||
|
SS_finalize_plan ((Plan*) lfirst (lst)));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case T_IndexScan:
|
||||||
|
param_list = set_unioni (param_list,
|
||||||
|
_finalize_primnode (((IndexScan*) plan)->indxqual, &subPlan));
|
||||||
|
Assert (subPlan == NULL);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case T_MergeJoin:
|
||||||
|
param_list = set_unioni (param_list,
|
||||||
|
_finalize_primnode (((MergeJoin*) plan)->mergeclauses, &subPlan));
|
||||||
|
Assert (subPlan == NULL);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case T_HashJoin:
|
||||||
|
param_list = set_unioni (param_list,
|
||||||
|
_finalize_primnode (((HashJoin*) plan)->hashclauses, &subPlan));
|
||||||
|
Assert (subPlan == NULL);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case T_Hash:
|
||||||
|
param_list = set_unioni (param_list,
|
||||||
|
_finalize_primnode (((Hash*) plan)->hashkey, &subPlan));
|
||||||
|
Assert (subPlan == NULL);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case T_Agg:
|
||||||
|
param_list = set_unioni (param_list,
|
||||||
|
_finalize_primnode (((Agg*) plan)->aggs, &subPlan));
|
||||||
|
Assert (subPlan == NULL);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case T_SeqScan:
|
||||||
|
case T_NestLoop:
|
||||||
|
case T_Material:
|
||||||
|
case T_Sort:
|
||||||
|
case T_Unique:
|
||||||
|
case T_Group:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
elog(ERROR, "SS_finalize_plan: node %d unsupported", nodeTag(plan));
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
param_list = set_unioni (param_list, _finalize_primnode (plan->qual, &subPlan));
|
||||||
|
param_list = set_unioni (param_list, SS_finalize_plan (plan->lefttree));
|
||||||
|
param_list = set_unioni (param_list, SS_finalize_plan (plan->righttree));
|
||||||
|
|
||||||
|
foreach (lst, param_list)
|
||||||
|
{
|
||||||
|
Var *var = nth (lfirsti(lst), PlannerParamVar);
|
||||||
|
|
||||||
|
if ( var->varlevelsup < PlannerQueryLevel )
|
||||||
|
extParam = lappendi (extParam, lfirsti(lst));
|
||||||
|
else if ( var->varlevelsup > PlannerQueryLevel )
|
||||||
|
elog (ERROR, "SS_finalize_plan: plan shouldn't reference subplan' variable");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Assert (var->varno == 0 && var->varattno == 0);
|
||||||
|
locParam = lappendi (locParam, lfirsti(lst));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
plan->extParam = extParam;
|
||||||
|
plan->locParam = locParam;
|
||||||
|
plan->subPlan = subPlan;
|
||||||
|
|
||||||
|
return (param_list);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
List *SS_pull_subplan (void *expr);
|
||||||
|
|
||||||
|
List *
|
||||||
|
SS_pull_subplan (void *expr)
|
||||||
|
{
|
||||||
|
List *result = NULL;
|
||||||
|
|
||||||
|
if ( expr == NULL || single_node(expr) )
|
||||||
|
return (NULL);
|
||||||
|
|
||||||
|
if (IsA (expr, List))
|
||||||
|
{
|
||||||
|
List *le;
|
||||||
|
foreach (le, (List*) expr)
|
||||||
|
result = nconc (result, SS_pull_subplan (lfirst(le)));
|
||||||
|
}
|
||||||
|
else if (IsA (expr, Iter))
|
||||||
|
return (SS_pull_subplan (((Iter*) expr)->iterexpr));
|
||||||
|
else if (or_clause(expr) || and_clause(expr) || is_opclause(expr) ||
|
||||||
|
not_clause (expr) || is_funcclause(expr))
|
||||||
|
return (SS_pull_subplan (((Expr*) expr)->args));
|
||||||
|
else if (IsA (expr, Aggreg))
|
||||||
|
return (SS_pull_subplan (((Aggreg *) expr)->target));
|
||||||
|
else if (IsA (expr, ArrayRef))
|
||||||
|
{
|
||||||
|
result = SS_pull_subplan (((ArrayRef*) expr)->refupperindexpr);
|
||||||
|
result = nconc (result,
|
||||||
|
SS_pull_subplan (((ArrayRef *) expr)->reflowerindexpr));
|
||||||
|
result = nconc (result,
|
||||||
|
SS_pull_subplan (((ArrayRef *) expr)->refexpr));
|
||||||
|
result = nconc (result,
|
||||||
|
SS_pull_subplan (((ArrayRef *) expr)->refassgnexpr));
|
||||||
|
}
|
||||||
|
else if (IsA (expr, TargetEntry))
|
||||||
|
return (SS_pull_subplan (((TargetEntry*) expr)->expr));
|
||||||
|
else if (is_subplan (expr))
|
||||||
|
return (lcons (((Expr*) expr)->oper, NULL));
|
||||||
|
else
|
||||||
|
elog (ERROR, "SS_pull_subplan: can't handle node %d",
|
||||||
|
nodeTag (expr));
|
||||||
|
|
||||||
|
return (result);
|
||||||
|
}
|
Reference in New Issue
Block a user