mirror of
https://github.com/postgres/postgres.git
synced 2025-11-12 05:01:15 +03:00
OK, folks, here is the pgindent output.
This commit is contained in:
@@ -7,7 +7,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.31 1998/09/01 03:23:35 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.32 1998/09/01 04:29:47 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -46,44 +46,33 @@
|
||||
static List *switch_outer(List *clauses);
|
||||
static Scan *create_scan_node(Path *best_path, List *tlist);
|
||||
static Join *create_join_node(JoinPath *best_path, List *tlist);
|
||||
static SeqScan *
|
||||
create_seqscan_node(Path *best_path, List *tlist,
|
||||
static SeqScan *create_seqscan_node(Path *best_path, List *tlist,
|
||||
List *scan_clauses);
|
||||
static IndexScan *
|
||||
create_indexscan_node(IndexPath *best_path, List *tlist,
|
||||
static IndexScan *create_indexscan_node(IndexPath *best_path, List *tlist,
|
||||
List *scan_clauses);
|
||||
static NestLoop *
|
||||
create_nestloop_node(JoinPath *best_path, List *tlist,
|
||||
static NestLoop *create_nestloop_node(JoinPath *best_path, List *tlist,
|
||||
List *clauses, Plan *outer_node, List *outer_tlist,
|
||||
Plan *inner_node, List *inner_tlist);
|
||||
static MergeJoin *
|
||||
create_mergejoin_node(MergePath *best_path, List *tlist,
|
||||
static MergeJoin *create_mergejoin_node(MergePath *best_path, List *tlist,
|
||||
List *clauses, Plan *outer_node, List *outer_tlist,
|
||||
Plan *inner_node, List *inner_tlist);
|
||||
static HashJoin *
|
||||
create_hashjoin_node(HashPath *best_path, List *tlist,
|
||||
static HashJoin *create_hashjoin_node(HashPath *best_path, List *tlist,
|
||||
List *clauses, Plan *outer_node, List *outer_tlist,
|
||||
Plan *inner_node, List *inner_tlist);
|
||||
static Node *fix_indxqual_references(Node *clause, Path *index_path);
|
||||
static Temp *
|
||||
make_temp(List *tlist, List *keys, Oid *operators,
|
||||
static Temp *make_temp(List *tlist, List *keys, Oid *operators,
|
||||
Plan *plan_node, int temptype);
|
||||
static IndexScan *
|
||||
make_indexscan(List *qptlist, List *qpqual, Index scanrelid,
|
||||
static IndexScan *make_indexscan(List *qptlist, List *qpqual, Index scanrelid,
|
||||
List *indxid, List *indxqual, Cost cost);
|
||||
static NestLoop *
|
||||
make_nestloop(List *qptlist, List *qpqual, Plan *lefttree,
|
||||
static NestLoop *make_nestloop(List *qptlist, List *qpqual, Plan *lefttree,
|
||||
Plan *righttree);
|
||||
static HashJoin *
|
||||
make_hashjoin(List *tlist, List *qpqual,
|
||||
static HashJoin *make_hashjoin(List *tlist, List *qpqual,
|
||||
List *hashclauses, Plan *lefttree, Plan *righttree);
|
||||
static Hash *make_hash(List *tlist, Var *hashkey, Plan *lefttree);
|
||||
static MergeJoin *
|
||||
make_mergejoin(List *tlist, List *qpqual,
|
||||
static MergeJoin *make_mergejoin(List *tlist, List *qpqual,
|
||||
List *mergeclauses, Oid opcode, Oid *rightorder,
|
||||
Oid *leftorder, Plan *righttree, Plan *lefttree);
|
||||
static Material *
|
||||
make_material(List *tlist, Oid tempid, Plan *lefttree,
|
||||
static Material *make_material(List *tlist, Oid tempid, Plan *lefttree,
|
||||
int keycount);
|
||||
|
||||
/*
|
||||
@@ -106,7 +95,7 @@ create_plan(Path *best_path)
|
||||
{
|
||||
List *tlist;
|
||||
Plan *plan_node = (Plan *) NULL;
|
||||
RelOptInfo *parent_rel;
|
||||
RelOptInfo *parent_rel;
|
||||
int size;
|
||||
int width;
|
||||
int pages;
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.19 1998/09/01 03:23:36 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.20 1998/09/01 04:29:50 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -40,8 +40,8 @@
|
||||
extern int Quiet;
|
||||
|
||||
static void add_clause_to_rels(Query *root, List *clause);
|
||||
static void add_join_info_to_rels(Query *root, ClauseInfo *clauseinfo,
|
||||
List *join_relids);
|
||||
static void add_join_info_to_rels(Query *root, ClauseInfo * clauseinfo,
|
||||
List *join_relids);
|
||||
static void add_vars_to_targetlist(Query *root, List *vars, List *join_relids);
|
||||
|
||||
static MergeOrder *mergejoinop(Expr *clause);
|
||||
@@ -170,7 +170,7 @@ add_clause_to_rels(Query *root, List *clause)
|
||||
{
|
||||
List *relids;
|
||||
List *vars;
|
||||
ClauseInfo *clauseinfo = makeNode(ClauseInfo);
|
||||
ClauseInfo *clauseinfo = makeNode(ClauseInfo);
|
||||
|
||||
/*
|
||||
* Retrieve all relids and vars contained within the clause.
|
||||
@@ -199,6 +199,7 @@ add_clause_to_rels(Query *root, List *clause)
|
||||
*/
|
||||
if (is_funcclause((Node *) clause))
|
||||
{
|
||||
|
||||
/*
|
||||
* XXX If we have a func clause set selectivity to 1/3, really
|
||||
* need a true selectivity function.
|
||||
@@ -222,6 +223,7 @@ add_clause_to_rels(Query *root, List *clause)
|
||||
|
||||
if (is_funcclause((Node *) clause))
|
||||
{
|
||||
|
||||
/*
|
||||
* XXX If we have a func clause set selectivity to 1/3, really
|
||||
* need a true selectivity function.
|
||||
@@ -252,13 +254,13 @@ add_clause_to_rels(Query *root, List *clause)
|
||||
*
|
||||
*/
|
||||
static void
|
||||
add_join_info_to_rels(Query *root, ClauseInfo *clauseinfo, List *join_relids)
|
||||
add_join_info_to_rels(Query *root, ClauseInfo * clauseinfo, List *join_relids)
|
||||
{
|
||||
List *join_relid;
|
||||
|
||||
foreach(join_relid, join_relids)
|
||||
{
|
||||
JoinInfo *joininfo;
|
||||
JoinInfo *joininfo;
|
||||
List *other_rels = NIL;
|
||||
List *rel;
|
||||
|
||||
@@ -269,7 +271,7 @@ add_join_info_to_rels(Query *root, ClauseInfo *clauseinfo, List *join_relids)
|
||||
}
|
||||
|
||||
joininfo = find_joininfo_node(get_base_rel(root, lfirsti(join_relid)),
|
||||
other_rels);
|
||||
other_rels);
|
||||
joininfo->jinfoclauseinfo =
|
||||
lcons(copyObject((void *) clauseinfo), joininfo->jinfoclauseinfo);
|
||||
|
||||
@@ -332,8 +334,8 @@ init_join_info(List *rel_list)
|
||||
*y,
|
||||
*z;
|
||||
RelOptInfo *rel;
|
||||
JoinInfo *joininfo;
|
||||
ClauseInfo *clauseinfo;
|
||||
JoinInfo *joininfo;
|
||||
ClauseInfo *clauseinfo;
|
||||
Expr *clause;
|
||||
|
||||
foreach(x, rel_list)
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planmain.c,v 1.27 1998/09/01 03:23:38 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planmain.c,v 1.28 1998/09/01 04:29:51 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -44,8 +44,7 @@
|
||||
static Plan *subplanner(Query *root, List *flat_tlist, List *qual);
|
||||
static Result *make_result(List *tlist, Node *resconstantqual, Plan *subplan);
|
||||
|
||||
extern Plan *
|
||||
make_groupPlan(List **tlist, bool tuplePerGroup,
|
||||
extern Plan *make_groupPlan(List **tlist, bool tuplePerGroup,
|
||||
List *groupClause, Plan *subplan);
|
||||
|
||||
/*
|
||||
@@ -90,7 +89,7 @@ query_planner(Query *root,
|
||||
printf("After cnfify()\n");
|
||||
pprint(qual);
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* A command without a target list or qualification is an error,
|
||||
* except for "delete foo".
|
||||
@@ -191,8 +190,8 @@ query_planner(Query *root,
|
||||
if (constant_qual)
|
||||
{
|
||||
subplan = (Plan *) make_result((!root->hasAggs &&
|
||||
!root->groupClause &&
|
||||
!root->havingQual)
|
||||
!root->groupClause &&
|
||||
!root->havingQual)
|
||||
? tlist : subplan->targetlist,
|
||||
(Node *) constant_qual,
|
||||
subplan);
|
||||
@@ -255,13 +254,13 @@ subplanner(Query *root,
|
||||
List *flat_tlist,
|
||||
List *qual)
|
||||
{
|
||||
RelOptInfo *final_rel;
|
||||
List *final_rel_list;
|
||||
RelOptInfo *final_rel;
|
||||
List *final_rel_list;
|
||||
|
||||
/*
|
||||
* Initialize the targetlist and qualification, adding entries to
|
||||
* base_rel_list as relation references are found (e.g., in
|
||||
* the qualification, the targetlist, etc.)
|
||||
* base_rel_list as relation references are found (e.g., in the
|
||||
* qualification, the targetlist, etc.)
|
||||
*/
|
||||
root->base_rel_list = NIL;
|
||||
root->join_rel_list = NIL;
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.31 1998/09/01 03:23:39 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.32 1998/09/01 04:29:53 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -49,8 +49,7 @@
|
||||
#include "executor/executor.h"
|
||||
|
||||
static Plan *make_sortplan(List *tlist, List *sortcls, Plan *plannode);
|
||||
extern Plan *
|
||||
make_groupPlan(List **tlist, bool tuplePerGroup,
|
||||
extern Plan *make_groupPlan(List **tlist, bool tuplePerGroup,
|
||||
List *groupClause, Plan *subplan);
|
||||
|
||||
/*****************************************************************************
|
||||
@@ -96,10 +95,12 @@ union_planner(Query *parse)
|
||||
{
|
||||
List *tlist = parse->targetList;
|
||||
|
||||
/* copy the original tlist, we will need the original one
|
||||
* for the AGG node later on */
|
||||
List *new_tlist = new_unsorted_tlist(tlist);
|
||||
|
||||
/*
|
||||
* copy the original tlist, we will need the original one for the AGG
|
||||
* node later on
|
||||
*/
|
||||
List *new_tlist = new_unsorted_tlist(tlist);
|
||||
|
||||
List *rangetable = parse->rtable;
|
||||
|
||||
Plan *result_plan = (Plan *) NULL;
|
||||
@@ -109,12 +110,12 @@ union_planner(Query *parse)
|
||||
|
||||
if (parse->unionClause)
|
||||
{
|
||||
result_plan = (Plan *) plan_union_queries(parse);
|
||||
/* XXX do we need to do this? bjm 12/19/97 */
|
||||
tlist = preprocess_targetlist(tlist,
|
||||
parse->commandType,
|
||||
parse->resultRelation,
|
||||
parse->rtable);
|
||||
result_plan = (Plan *) plan_union_queries(parse);
|
||||
/* XXX do we need to do this? bjm 12/19/97 */
|
||||
tlist = preprocess_targetlist(tlist,
|
||||
parse->commandType,
|
||||
parse->resultRelation,
|
||||
parse->rtable);
|
||||
}
|
||||
else if ((rt_index =
|
||||
first_inherit_rt_entry(rangetable)) != -1)
|
||||
@@ -122,64 +123,65 @@ union_planner(Query *parse)
|
||||
result_plan = (Plan *) plan_inherit_queries(parse, rt_index);
|
||||
/* XXX do we need to do this? bjm 12/19/97 */
|
||||
tlist = preprocess_targetlist(tlist,
|
||||
parse->commandType,
|
||||
parse->resultRelation,
|
||||
parse->rtable);
|
||||
parse->commandType,
|
||||
parse->resultRelation,
|
||||
parse->rtable);
|
||||
}
|
||||
else
|
||||
{
|
||||
List **vpm = NULL;
|
||||
|
||||
/* This is only necessary if aggregates are in use in queries like:
|
||||
* SELECT sid
|
||||
* FROM part
|
||||
* GROUP BY sid
|
||||
* HAVING MIN(pid) > 1; (pid is used but never selected for!!!)
|
||||
* because the function 'query_planner' creates the plan for the lefttree
|
||||
* of the 'GROUP' node and returns only those attributes contained in 'tlist'.
|
||||
* The original 'tlist' contains only 'sid' here and that's why we have to
|
||||
* to extend it to attributes which are not selected but are used in the
|
||||
* havingQual. */
|
||||
|
||||
/* 'check_having_qual_for_vars' takes the havingQual and the actual 'tlist'
|
||||
* as arguments and recursively scans the havingQual for attributes
|
||||
* (VAR nodes) that are not contained in 'tlist' yet. If so, it creates
|
||||
* a new entry and attaches it to the list 'new_tlist' (consisting of the
|
||||
* VAR node and the RESDOM node as usual with tlists :-) ) */
|
||||
if (parse->hasAggs)
|
||||
{
|
||||
if (parse->havingQual != NULL)
|
||||
List **vpm = NULL;
|
||||
|
||||
/*
|
||||
* This is only necessary if aggregates are in use in queries
|
||||
* like: SELECT sid FROM part GROUP BY sid HAVING MIN(pid) > 1;
|
||||
* (pid is used but never selected for!!!) because the function
|
||||
* 'query_planner' creates the plan for the lefttree of the
|
||||
* 'GROUP' node and returns only those attributes contained in
|
||||
* 'tlist'. The original 'tlist' contains only 'sid' here and
|
||||
* that's why we have to to extend it to attributes which are not
|
||||
* selected but are used in the havingQual.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 'check_having_qual_for_vars' takes the havingQual and the
|
||||
* actual 'tlist' as arguments and recursively scans the
|
||||
* havingQual for attributes (VAR nodes) that are not contained in
|
||||
* 'tlist' yet. If so, it creates a new entry and attaches it to
|
||||
* the list 'new_tlist' (consisting of the VAR node and the RESDOM
|
||||
* node as usual with tlists :-) )
|
||||
*/
|
||||
if (parse->hasAggs)
|
||||
{
|
||||
new_tlist = check_having_qual_for_vars(parse->havingQual,new_tlist);
|
||||
if (parse->havingQual != NULL)
|
||||
new_tlist = check_having_qual_for_vars(parse->havingQual, new_tlist);
|
||||
}
|
||||
}
|
||||
|
||||
new_tlist = preprocess_targetlist(new_tlist,
|
||||
parse->commandType,
|
||||
parse->resultRelation,
|
||||
parse->rtable);
|
||||
|
||||
/* Here starts the original (pre having) code */
|
||||
tlist = preprocess_targetlist(tlist,
|
||||
parse->commandType,
|
||||
parse->resultRelation,
|
||||
parse->rtable);
|
||||
|
||||
if (parse->rtable != NULL)
|
||||
{
|
||||
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,
|
||||
parse->commandType,
|
||||
new_tlist,
|
||||
(List *) parse->qual);
|
||||
PlannerVarParam = lnext(PlannerVarParam);
|
||||
if (vpm != NULL)
|
||||
pfree(vpm);
|
||||
|
||||
new_tlist = preprocess_targetlist(new_tlist,
|
||||
parse->commandType,
|
||||
parse->resultRelation,
|
||||
parse->rtable);
|
||||
|
||||
/* Here starts the original (pre having) code */
|
||||
tlist = preprocess_targetlist(tlist,
|
||||
parse->commandType,
|
||||
parse->resultRelation,
|
||||
parse->rtable);
|
||||
|
||||
if (parse->rtable != NULL)
|
||||
{
|
||||
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,
|
||||
parse->commandType,
|
||||
new_tlist,
|
||||
(List *) parse->qual);
|
||||
PlannerVarParam = lnext(PlannerVarParam);
|
||||
if (vpm != NULL)
|
||||
pfree(vpm);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* If we have a GROUP BY clause, insert a group node (with the
|
||||
* appropriate sort node.)
|
||||
@@ -209,11 +211,14 @@ union_planner(Query *parse)
|
||||
*/
|
||||
if (parse->hasAggs)
|
||||
{
|
||||
int old_length=0, new_length=0;
|
||||
|
||||
/* Create the AGG node but use 'tlist' not 'new_tlist' as target list because we
|
||||
* don't want the additional attributes (only used for the havingQual, see above)
|
||||
* to show up in the result */
|
||||
int old_length = 0,
|
||||
new_length = 0;
|
||||
|
||||
/*
|
||||
* Create the AGG node but use 'tlist' not 'new_tlist' as target
|
||||
* list because we don't want the additional attributes (only used
|
||||
* for the havingQual, see above) to show up in the result
|
||||
*/
|
||||
result_plan = (Plan *) make_agg(tlist, result_plan);
|
||||
|
||||
/*
|
||||
@@ -221,70 +226,84 @@ union_planner(Query *parse)
|
||||
* the result tuple of the subplans.
|
||||
*/
|
||||
((Agg *) result_plan)->aggs =
|
||||
set_agg_tlist_references((Agg *) result_plan);
|
||||
set_agg_tlist_references((Agg *) result_plan);
|
||||
|
||||
|
||||
if(parse->havingQual!=NULL)
|
||||
{
|
||||
List *clause;
|
||||
List **vpm = NULL;
|
||||
|
||||
|
||||
/* stuff copied from above to handle the use of attributes from outside
|
||||
* in subselects */
|
||||
if (parse->havingQual != NULL)
|
||||
{
|
||||
List *clause;
|
||||
List **vpm = NULL;
|
||||
|
||||
if (parse->rtable != NULL)
|
||||
{
|
||||
vpm = (List **) palloc(length(parse->rtable) * sizeof(List *));
|
||||
memset(vpm, 0, length(parse->rtable) * sizeof(List *));
|
||||
}
|
||||
PlannerVarParam = lcons(vpm, PlannerVarParam);
|
||||
|
||||
/* There is a subselect in the havingQual, so we have to process it
|
||||
* using the same function as for a subselect in 'where' */
|
||||
if (parse->hasSubLinks)
|
||||
{
|
||||
parse->havingQual = SS_process_sublinks((Node *) parse->havingQual);
|
||||
}
|
||||
|
||||
/* convert the havingQual to conjunctive normal form (cnf) */
|
||||
parse->havingQual = (Node * ) cnfify((Expr *)(Node *) parse->havingQual,true);
|
||||
|
||||
/* Calculate the opfids from the opnos (=select the correct functions for
|
||||
* the used VAR datatypes) */
|
||||
parse->havingQual = (Node * ) fix_opids((List *) parse->havingQual);
|
||||
|
||||
((Agg *) result_plan)->plan.qual=(List *) parse->havingQual;
|
||||
|
||||
/* Check every clause of the havingQual for aggregates used and append
|
||||
* them to result_plan->aggs */
|
||||
foreach(clause, ((Agg *) result_plan)->plan.qual)
|
||||
{
|
||||
/* Make sure there are aggregates in the havingQual
|
||||
* if so, the list must be longer after check_having_qual_for_aggs */
|
||||
old_length=length(((Agg *) result_plan)->aggs);
|
||||
|
||||
((Agg *) result_plan)->aggs = nconc(((Agg *) result_plan)->aggs,
|
||||
check_having_qual_for_aggs((Node *) lfirst(clause),
|
||||
((Agg *) result_plan)->plan.lefttree->targetlist,
|
||||
((List *) parse->groupClause)));
|
||||
/*
|
||||
* stuff copied from above to handle the use of attributes
|
||||
* from outside in subselects
|
||||
*/
|
||||
|
||||
if (parse->rtable != NULL)
|
||||
{
|
||||
vpm = (List **) palloc(length(parse->rtable) * sizeof(List *));
|
||||
memset(vpm, 0, length(parse->rtable) * sizeof(List *));
|
||||
}
|
||||
PlannerVarParam = lcons(vpm, PlannerVarParam);
|
||||
|
||||
/*
|
||||
* There is a subselect in the havingQual, so we have to
|
||||
* process it using the same function as for a subselect in
|
||||
* 'where'
|
||||
*/
|
||||
if (parse->hasSubLinks)
|
||||
parse->havingQual = SS_process_sublinks((Node *) parse->havingQual);
|
||||
|
||||
/* convert the havingQual to conjunctive normal form (cnf) */
|
||||
parse->havingQual = (Node *) cnfify((Expr *) (Node *) parse->havingQual, true);
|
||||
|
||||
/*
|
||||
* Calculate the opfids from the opnos (=select the correct
|
||||
* functions for the used VAR datatypes)
|
||||
*/
|
||||
parse->havingQual = (Node *) fix_opids((List *) parse->havingQual);
|
||||
|
||||
((Agg *) result_plan)->plan.qual = (List *) parse->havingQual;
|
||||
|
||||
/*
|
||||
* Check every clause of the havingQual for aggregates used
|
||||
* and append them to result_plan->aggs
|
||||
*/
|
||||
foreach(clause, ((Agg *) result_plan)->plan.qual)
|
||||
{
|
||||
|
||||
/*
|
||||
* Make sure there are aggregates in the havingQual if so,
|
||||
* the list must be longer after
|
||||
* check_having_qual_for_aggs
|
||||
*/
|
||||
old_length = length(((Agg *) result_plan)->aggs);
|
||||
|
||||
((Agg *) result_plan)->aggs = nconc(((Agg *) result_plan)->aggs,
|
||||
check_having_qual_for_aggs((Node *) lfirst(clause),
|
||||
((Agg *) result_plan)->plan.lefttree->targetlist,
|
||||
((List *) parse->groupClause)));
|
||||
|
||||
/*
|
||||
* Have a look at the length of the returned list. If
|
||||
* there is no difference, no aggregates have been found
|
||||
* and that means, that the Qual belongs to the where
|
||||
* clause
|
||||
*/
|
||||
if (((new_length = length(((Agg *) result_plan)->aggs)) == old_length) ||
|
||||
(new_length == 0))
|
||||
{
|
||||
elog(ERROR, "This could have been done in a where clause!!");
|
||||
return (Plan *) NIL;
|
||||
}
|
||||
}
|
||||
PlannerVarParam = lnext(PlannerVarParam);
|
||||
if (vpm != NULL)
|
||||
pfree(vpm);
|
||||
}
|
||||
}
|
||||
|
||||
/* Have a look at the length of the returned list. If there is no
|
||||
* difference, no aggregates have been found and that means, that
|
||||
* the Qual belongs to the where clause */
|
||||
if (((new_length=length(((Agg *) result_plan)->aggs)) == old_length) ||
|
||||
(new_length == 0))
|
||||
{
|
||||
elog(ERROR,"This could have been done in a where clause!!");
|
||||
return (Plan *)NIL;
|
||||
}
|
||||
}
|
||||
PlannerVarParam = lnext(PlannerVarParam);
|
||||
if (vpm != NULL)
|
||||
pfree(vpm);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* For now, before we hand back the plan, check to see if there is a
|
||||
* user-specified sort that needs to be done. Eventually, this will
|
||||
@@ -530,6 +549,3 @@ pg_checkretval(Oid rettype, QueryTreeList *queryTreeList)
|
||||
/* success */
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.25 1998/09/01 03:23:40 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.26 1998/09/01 04:29:54 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -36,11 +36,9 @@
|
||||
static void set_join_tlist_references(Join *join);
|
||||
static void set_tempscan_tlist_references(SeqScan *tempscan);
|
||||
static void set_temp_tlist_references(Temp *temp);
|
||||
static List *
|
||||
replace_clause_joinvar_refs(Expr *clause,
|
||||
static List *replace_clause_joinvar_refs(Expr *clause,
|
||||
List *outer_tlist, List *inner_tlist);
|
||||
static List *
|
||||
replace_subclause_joinvar_refs(List *clauses,
|
||||
static List *replace_subclause_joinvar_refs(List *clauses,
|
||||
List *outer_tlist, List *inner_tlist);
|
||||
static Var *replace_joinvar_refs(Var *var, List *outer_tlist, List *inner_tlist);
|
||||
static List *tlist_temp_references(Oid tempid, List *tlist);
|
||||
@@ -498,13 +496,13 @@ tlist_temp_references(Oid tempid,
|
||||
oattno = 0;
|
||||
|
||||
temp = makeTargetEntry(xtl->resdom,
|
||||
(Node *) makeVar(tempid,
|
||||
xtl->resdom->resno,
|
||||
xtl->resdom->restype,
|
||||
xtl->resdom->restypmod,
|
||||
0,
|
||||
tempid,
|
||||
oattno));
|
||||
(Node *) makeVar(tempid,
|
||||
xtl->resdom->resno,
|
||||
xtl->resdom->restype,
|
||||
xtl->resdom->restypmod,
|
||||
0,
|
||||
tempid,
|
||||
oattno));
|
||||
|
||||
t_list = lappend(t_list, temp);
|
||||
}
|
||||
@@ -901,190 +899,190 @@ del_agg_clause(Node *clause)
|
||||
/* check_having_qual_for_vars takes the the havingQual and the actual targetlist as arguments
|
||||
* and recursively scans the havingQual for attributes that are not included in the targetlist
|
||||
* yet. Attributes contained in the havingQual but not in the targetlist show up with queries
|
||||
* like:
|
||||
* SELECT sid
|
||||
* like:
|
||||
* SELECT sid
|
||||
* FROM part
|
||||
* GROUP BY sid
|
||||
* HAVING MIN(pid) > 1; (pid is used but never selected for!!!).
|
||||
* HAVING MIN(pid) > 1; (pid is used but never selected for!!!).
|
||||
* To be able to handle queries like that correctly we have to extend the actual targetlist
|
||||
* (which will be the one used for the GROUP node later on) by these attributes. */
|
||||
* (which will be the one used for the GROUP node later on) by these attributes. */
|
||||
List *
|
||||
check_having_qual_for_vars(Node *clause, List *targetlist_so_far)
|
||||
{
|
||||
List *t;
|
||||
List *t;
|
||||
|
||||
|
||||
if (IsA(clause, Var))
|
||||
{
|
||||
RelOptInfo tmp_rel;
|
||||
|
||||
if (IsA(clause, Var))
|
||||
{
|
||||
RelOptInfo tmp_rel;
|
||||
|
||||
tmp_rel.targetlist = targetlist_so_far;
|
||||
|
||||
/*
|
||||
* Ha! A Var node!
|
||||
*/
|
||||
|
||||
/* Check if the VAR is already contained in the targetlist */
|
||||
if (tlist_member((Var *)clause, (List *)targetlist_so_far) == NULL)
|
||||
{
|
||||
add_tl_element(&tmp_rel, (Var *)clause);
|
||||
}
|
||||
|
||||
return tmp_rel.targetlist;
|
||||
}
|
||||
|
||||
else if (is_funcclause(clause) || not_clause(clause) ||
|
||||
or_clause(clause) || and_clause(clause))
|
||||
{
|
||||
|
||||
/*
|
||||
* This is a function. Recursively call this routine for its
|
||||
* arguments...
|
||||
*/
|
||||
foreach(t, ((Expr *) clause)->args)
|
||||
{
|
||||
targetlist_so_far = check_having_qual_for_vars(lfirst(t), targetlist_so_far);
|
||||
tmp_rel.targetlist = targetlist_so_far;
|
||||
|
||||
/*
|
||||
* Ha! A Var node!
|
||||
*/
|
||||
|
||||
/* Check if the VAR is already contained in the targetlist */
|
||||
if (tlist_member((Var *) clause, (List *) targetlist_so_far) == NULL)
|
||||
add_tl_element(&tmp_rel, (Var *) clause);
|
||||
|
||||
return tmp_rel.targetlist;
|
||||
}
|
||||
return targetlist_so_far;
|
||||
}
|
||||
else if (IsA(clause, Aggreg))
|
||||
{
|
||||
targetlist_so_far =
|
||||
check_having_qual_for_vars(((Aggreg *) clause)->target, targetlist_so_far);
|
||||
return targetlist_so_far;
|
||||
}
|
||||
else if (IsA(clause, ArrayRef))
|
||||
{
|
||||
ArrayRef *aref = (ArrayRef *) clause;
|
||||
|
||||
/*
|
||||
* This is an arrayref. Recursively call this routine for its
|
||||
* expression and its index expression...
|
||||
*/
|
||||
foreach(t, aref->refupperindexpr)
|
||||
|
||||
else if (is_funcclause(clause) || not_clause(clause) ||
|
||||
or_clause(clause) || and_clause(clause))
|
||||
{
|
||||
targetlist_so_far = check_having_qual_for_vars(lfirst(t), targetlist_so_far);
|
||||
|
||||
/*
|
||||
* This is a function. Recursively call this routine for its
|
||||
* arguments...
|
||||
*/
|
||||
foreach(t, ((Expr *) clause)->args)
|
||||
targetlist_so_far = check_having_qual_for_vars(lfirst(t), targetlist_so_far);
|
||||
return targetlist_so_far;
|
||||
}
|
||||
foreach(t, aref->reflowerindexpr)
|
||||
else if (IsA(clause, Aggreg))
|
||||
{
|
||||
targetlist_so_far = check_having_qual_for_vars(lfirst(t), targetlist_so_far);
|
||||
targetlist_so_far =
|
||||
check_having_qual_for_vars(((Aggreg *) clause)->target, targetlist_so_far);
|
||||
return targetlist_so_far;
|
||||
}
|
||||
targetlist_so_far = check_having_qual_for_vars(aref->refexpr, targetlist_so_far);
|
||||
targetlist_so_far = check_having_qual_for_vars(aref->refassgnexpr, targetlist_so_far);
|
||||
|
||||
return targetlist_so_far;
|
||||
}
|
||||
else if (is_opclause(clause))
|
||||
{
|
||||
|
||||
/*
|
||||
* This is an operator. Recursively call this routine for both its
|
||||
* left and right operands
|
||||
*/
|
||||
Node *left = (Node *) get_leftop((Expr *) clause);
|
||||
Node *right = (Node *) get_rightop((Expr *) clause);
|
||||
|
||||
if (left != (Node *) NULL)
|
||||
targetlist_so_far = check_having_qual_for_vars(left, targetlist_so_far);
|
||||
if (right != (Node *) NULL)
|
||||
targetlist_so_far = check_having_qual_for_vars(right, targetlist_so_far);
|
||||
|
||||
return targetlist_so_far;
|
||||
}
|
||||
else if (IsA(clause, Param) || IsA(clause, Const))
|
||||
{
|
||||
/* do nothing! */
|
||||
return targetlist_so_far;
|
||||
}
|
||||
/* If we get to a sublink, then we only have to check the lefthand side of the expression
|
||||
* to see if there are any additional VARs */
|
||||
else if (IsA(clause, SubLink))
|
||||
{
|
||||
foreach(t,((List *)((SubLink *)clause)->lefthand))
|
||||
else if (IsA(clause, ArrayRef))
|
||||
{
|
||||
targetlist_so_far = check_having_qual_for_vars(lfirst(t), targetlist_so_far);
|
||||
ArrayRef *aref = (ArrayRef *) clause;
|
||||
|
||||
/*
|
||||
* This is an arrayref. Recursively call this routine for its
|
||||
* expression and its index expression...
|
||||
*/
|
||||
foreach(t, aref->refupperindexpr)
|
||||
targetlist_so_far = check_having_qual_for_vars(lfirst(t), targetlist_so_far);
|
||||
foreach(t, aref->reflowerindexpr)
|
||||
targetlist_so_far = check_having_qual_for_vars(lfirst(t), targetlist_so_far);
|
||||
targetlist_so_far = check_having_qual_for_vars(aref->refexpr, targetlist_so_far);
|
||||
targetlist_so_far = check_having_qual_for_vars(aref->refassgnexpr, targetlist_so_far);
|
||||
|
||||
return targetlist_so_far;
|
||||
}
|
||||
else if (is_opclause(clause))
|
||||
{
|
||||
|
||||
/*
|
||||
* This is an operator. Recursively call this routine for both its
|
||||
* left and right operands
|
||||
*/
|
||||
Node *left = (Node *) get_leftop((Expr *) clause);
|
||||
Node *right = (Node *) get_rightop((Expr *) clause);
|
||||
|
||||
if (left != (Node *) NULL)
|
||||
targetlist_so_far = check_having_qual_for_vars(left, targetlist_so_far);
|
||||
if (right != (Node *) NULL)
|
||||
targetlist_so_far = check_having_qual_for_vars(right, targetlist_so_far);
|
||||
|
||||
return targetlist_so_far;
|
||||
}
|
||||
else if (IsA(clause, Param) ||IsA(clause, Const))
|
||||
{
|
||||
/* do nothing! */
|
||||
return targetlist_so_far;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we get to a sublink, then we only have to check the lefthand
|
||||
* side of the expression to see if there are any additional VARs
|
||||
*/
|
||||
else if (IsA(clause, SubLink))
|
||||
{
|
||||
foreach(t, ((List *) ((SubLink *) clause)->lefthand))
|
||||
targetlist_so_far = check_having_qual_for_vars(lfirst(t), targetlist_so_far);
|
||||
return targetlist_so_far;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* Ooops! we can not handle that!
|
||||
*/
|
||||
elog(ERROR, "check_having_qual_for_vars: Can not handle this having_qual! %d\n",
|
||||
nodeTag(clause));
|
||||
return NIL;
|
||||
}
|
||||
return targetlist_so_far;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* Ooops! we can not handle that!
|
||||
*/
|
||||
elog(ERROR, "check_having_qual_for_vars: Can not handle this having_qual! %d\n",
|
||||
nodeTag(clause));
|
||||
return NIL;
|
||||
}
|
||||
}
|
||||
|
||||
/* check_having_qual_for_aggs takes the havingQual, the targetlist and the groupClause
|
||||
/* check_having_qual_for_aggs takes the havingQual, the targetlist and the groupClause
|
||||
* as arguments and scans the havingQual recursively for aggregates. If an aggregate is
|
||||
* found it is attached to a list and returned by the function. (All the returned lists
|
||||
* found it is attached to a list and returned by the function. (All the returned lists
|
||||
* are concenated to result_plan->aggs in planner.c:union_planner() */
|
||||
List *
|
||||
check_having_qual_for_aggs(Node *clause, List *subplanTargetList, List *groupClause)
|
||||
{
|
||||
List *t, *l1;
|
||||
List *t,
|
||||
*l1;
|
||||
List *agg_list = NIL;
|
||||
|
||||
int contained_in_group_clause = 0;
|
||||
|
||||
int contained_in_group_clause = 0;
|
||||
|
||||
|
||||
if (IsA(clause, Var))
|
||||
{
|
||||
TargetEntry *subplanVar;
|
||||
|
||||
/*
|
||||
* Ha! A Var node!
|
||||
*/
|
||||
subplanVar = match_varid((Var *) clause, subplanTargetList);
|
||||
|
||||
/*
|
||||
* Change the varno & varattno fields of the var node to point to the resdom->resno
|
||||
* fields of the subplan (lefttree)
|
||||
*/
|
||||
((Var *) clause)->varattno = subplanVar->resdom->resno;
|
||||
TargetEntry *subplanVar;
|
||||
|
||||
return NIL;
|
||||
/*
|
||||
* Ha! A Var node!
|
||||
*/
|
||||
subplanVar = match_varid((Var *) clause, subplanTargetList);
|
||||
|
||||
/*
|
||||
* Change the varno & varattno fields of the var node to point to
|
||||
* the resdom->resno fields of the subplan (lefttree)
|
||||
*/
|
||||
((Var *) clause)->varattno = subplanVar->resdom->resno;
|
||||
|
||||
return NIL;
|
||||
|
||||
}
|
||||
else if (is_funcclause(clause) || not_clause(clause) ||
|
||||
or_clause(clause) || and_clause(clause))
|
||||
else if (is_funcclause(clause) || not_clause(clause) ||
|
||||
or_clause(clause) || and_clause(clause))
|
||||
{
|
||||
int new_length=0, old_length=0;
|
||||
|
||||
int new_length = 0,
|
||||
old_length = 0;
|
||||
|
||||
/*
|
||||
* This is a function. Recursively call this routine for its
|
||||
* arguments... (i.e. for AND, OR, ... clauses!)
|
||||
*/
|
||||
foreach(t, ((Expr *) clause)->args)
|
||||
{
|
||||
old_length=length((List *)agg_list);
|
||||
old_length = length((List *) agg_list);
|
||||
|
||||
agg_list = nconc(agg_list,
|
||||
check_having_qual_for_aggs(lfirst(t), subplanTargetList,
|
||||
groupClause));
|
||||
agg_list = nconc(agg_list,
|
||||
check_having_qual_for_aggs(lfirst(t), subplanTargetList,
|
||||
groupClause));
|
||||
|
||||
/* The arguments of OR or AND clauses are comparisons or relations
|
||||
* and because we are in the havingQual there must be at least one operand
|
||||
* using an aggregate function. If so, we will find it and the lenght of the
|
||||
* agg_list will be increased after the above call to
|
||||
* check_having_qual_for_aggs. If there are no aggregates used, the query
|
||||
* could have been formulated using the 'where' clause */
|
||||
if(((new_length=length((List *)agg_list)) == old_length) || (new_length == 0))
|
||||
{
|
||||
elog(ERROR,"This could have been done in a where clause!!");
|
||||
return NIL;
|
||||
}
|
||||
/*
|
||||
* The arguments of OR or AND clauses are comparisons or
|
||||
* relations and because we are in the havingQual there must
|
||||
* be at least one operand using an aggregate function. If so,
|
||||
* we will find it and the lenght of the agg_list will be
|
||||
* increased after the above call to
|
||||
* check_having_qual_for_aggs. If there are no aggregates
|
||||
* used, the query could have been formulated using the
|
||||
* 'where' clause
|
||||
*/
|
||||
if (((new_length = length((List *) agg_list)) == old_length) || (new_length == 0))
|
||||
{
|
||||
elog(ERROR, "This could have been done in a where clause!!");
|
||||
return NIL;
|
||||
}
|
||||
}
|
||||
return agg_list;
|
||||
}
|
||||
else if (IsA(clause, Aggreg))
|
||||
{
|
||||
return lcons(clause,
|
||||
check_having_qual_for_aggs(((Aggreg *) clause)->target, subplanTargetList,
|
||||
groupClause));
|
||||
check_having_qual_for_aggs(((Aggreg *) clause)->target, subplanTargetList,
|
||||
groupClause));
|
||||
}
|
||||
else if (IsA(clause, ArrayRef))
|
||||
{
|
||||
@@ -1097,21 +1095,21 @@ check_having_qual_for_aggs(Node *clause, List *subplanTargetList, List *groupCla
|
||||
foreach(t, aref->refupperindexpr)
|
||||
{
|
||||
agg_list = nconc(agg_list,
|
||||
check_having_qual_for_aggs(lfirst(t), subplanTargetList,
|
||||
groupClause));
|
||||
check_having_qual_for_aggs(lfirst(t), subplanTargetList,
|
||||
groupClause));
|
||||
}
|
||||
foreach(t, aref->reflowerindexpr)
|
||||
{
|
||||
agg_list = nconc(agg_list,
|
||||
check_having_qual_for_aggs(lfirst(t), subplanTargetList,
|
||||
groupClause));
|
||||
check_having_qual_for_aggs(lfirst(t), subplanTargetList,
|
||||
groupClause));
|
||||
}
|
||||
agg_list = nconc(agg_list,
|
||||
check_having_qual_for_aggs(aref->refexpr, subplanTargetList,
|
||||
groupClause));
|
||||
check_having_qual_for_aggs(aref->refexpr, subplanTargetList,
|
||||
groupClause));
|
||||
agg_list = nconc(agg_list,
|
||||
check_having_qual_for_aggs(aref->refassgnexpr, subplanTargetList,
|
||||
groupClause));
|
||||
check_having_qual_for_aggs(aref->refassgnexpr, subplanTargetList,
|
||||
groupClause));
|
||||
|
||||
return agg_list;
|
||||
}
|
||||
@@ -1127,80 +1125,86 @@ check_having_qual_for_aggs(Node *clause, List *subplanTargetList, List *groupCla
|
||||
|
||||
if (left != (Node *) NULL)
|
||||
agg_list = nconc(agg_list,
|
||||
check_having_qual_for_aggs(left, subplanTargetList,
|
||||
groupClause));
|
||||
check_having_qual_for_aggs(left, subplanTargetList,
|
||||
groupClause));
|
||||
if (right != (Node *) NULL)
|
||||
agg_list = nconc(agg_list,
|
||||
check_having_qual_for_aggs(right, subplanTargetList,
|
||||
groupClause));
|
||||
groupClause));
|
||||
|
||||
return agg_list;
|
||||
}
|
||||
else if (IsA(clause, Param) || IsA(clause, Const))
|
||||
else if (IsA(clause, Param) ||IsA(clause, Const))
|
||||
{
|
||||
/* do nothing! */
|
||||
return NIL;
|
||||
}
|
||||
/* This is for Sublinks which show up as EXPR nodes. All the other EXPR nodes
|
||||
* (funcclauses, and_clauses, or_clauses) were caught above */
|
||||
|
||||
/*
|
||||
* This is for Sublinks which show up as EXPR nodes. All the other
|
||||
* EXPR nodes (funcclauses, and_clauses, or_clauses) were caught above
|
||||
*/
|
||||
else if (IsA(clause, Expr))
|
||||
{
|
||||
/* Only the lefthand side of the sublink has to be checked for aggregates
|
||||
* to be attached to result_plan->aggs (see planner.c:union_planner() )
|
||||
*/
|
||||
foreach(t,((List *)((SubLink *)((SubPlan *)
|
||||
((Expr *)clause)->oper)->sublink)->lefthand))
|
||||
{
|
||||
agg_list =
|
||||
nconc(agg_list,
|
||||
check_having_qual_for_aggs(lfirst(t),
|
||||
subplanTargetList, groupClause));
|
||||
}
|
||||
|
||||
|
||||
/* All arguments to the Sublink node are attributes from outside used within
|
||||
* the sublink. Here we have to check that only attributes that is grouped for
|
||||
* are used! */
|
||||
foreach(t,((Expr *)clause)->args)
|
||||
{
|
||||
contained_in_group_clause = 0;
|
||||
{
|
||||
|
||||
foreach(l1,groupClause)
|
||||
{
|
||||
if (tlist_member(lfirst(t),lcons(((GroupClause *)lfirst(l1))->entry,NIL)) !=
|
||||
NULL)
|
||||
{
|
||||
contained_in_group_clause=1;
|
||||
}
|
||||
}
|
||||
|
||||
/* If the use of the attribute is allowed (i.e. it is in the groupClause)
|
||||
* we have to adjust the varnos and varattnos */
|
||||
if (contained_in_group_clause)
|
||||
{
|
||||
agg_list =
|
||||
nconc(agg_list,
|
||||
check_having_qual_for_aggs(lfirst(t),
|
||||
subplanTargetList, groupClause));
|
||||
}
|
||||
else
|
||||
{
|
||||
elog(ERROR,"You must group by the attribute used from outside!");
|
||||
return NIL;
|
||||
}
|
||||
}
|
||||
return agg_list;
|
||||
}
|
||||
/*
|
||||
* Only the lefthand side of the sublink has to be checked for
|
||||
* aggregates to be attached to result_plan->aggs (see
|
||||
* planner.c:union_planner() )
|
||||
*/
|
||||
foreach(t, ((List *) ((SubLink *) ((SubPlan *)
|
||||
((Expr *) clause)->oper)->sublink)->lefthand))
|
||||
{
|
||||
agg_list =
|
||||
nconc(agg_list,
|
||||
check_having_qual_for_aggs(lfirst(t),
|
||||
subplanTargetList, groupClause));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* All arguments to the Sublink node are attributes from outside
|
||||
* used within the sublink. Here we have to check that only
|
||||
* attributes that is grouped for are used!
|
||||
*/
|
||||
foreach(t, ((Expr *) clause)->args)
|
||||
{
|
||||
contained_in_group_clause = 0;
|
||||
|
||||
foreach(l1, groupClause)
|
||||
{
|
||||
if (tlist_member(lfirst(t), lcons(((GroupClause *) lfirst(l1))->entry, NIL)) !=
|
||||
NULL)
|
||||
contained_in_group_clause = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the use of the attribute is allowed (i.e. it is in the
|
||||
* groupClause) we have to adjust the varnos and varattnos
|
||||
*/
|
||||
if (contained_in_group_clause)
|
||||
{
|
||||
agg_list =
|
||||
nconc(agg_list,
|
||||
check_having_qual_for_aggs(lfirst(t),
|
||||
subplanTargetList, groupClause));
|
||||
}
|
||||
else
|
||||
{
|
||||
elog(ERROR, "You must group by the attribute used from outside!");
|
||||
return NIL;
|
||||
}
|
||||
}
|
||||
return agg_list;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* Ooops! we can not handle that!
|
||||
*/
|
||||
elog(ERROR, "check_having_qual_for_aggs: Can not handle this having_qual! %d\n",
|
||||
nodeTag(clause));
|
||||
return NIL;
|
||||
}
|
||||
{
|
||||
|
||||
/*
|
||||
* Ooops! we can not handle that!
|
||||
*/
|
||||
elog(ERROR, "check_having_qual_for_aggs: Can not handle this having_qual! %d\n",
|
||||
nodeTag(clause));
|
||||
return NIL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -405,20 +405,23 @@ SS_process_sublinks(Node *expr)
|
||||
SS_process_sublinks((Node *) ((Expr *) expr)->args);
|
||||
else if (IsA(expr, SubLink))/* got it! */
|
||||
{
|
||||
/* Hack to make sure expr->oper->args points to the same VAR node
|
||||
* as expr->lefthand does. Needed for subselects in the havingQual
|
||||
* when used on views.
|
||||
* Otherwise aggregate functions will fail later on (at execution
|
||||
* time!) Reason: The rewite System makes several copies of the
|
||||
* VAR nodes and in this case it should not do so :-( */
|
||||
if(((SubLink *) expr)->lefthand != NULL)
|
||||
|
||||
/*
|
||||
* Hack to make sure expr->oper->args points to the same VAR node
|
||||
* as expr->lefthand does. Needed for subselects in the havingQual
|
||||
* when used on views. Otherwise aggregate functions will fail
|
||||
* later on (at execution time!) Reason: The rewite System makes
|
||||
* several copies of the VAR nodes and in this case it should not
|
||||
* do so :-(
|
||||
*/
|
||||
if (((SubLink *) expr)->lefthand != NULL)
|
||||
{
|
||||
lfirst(((Expr *) lfirst(((SubLink *)expr)->oper))->args) =
|
||||
lfirst(((SubLink *)expr)->lefthand);
|
||||
lfirst(((Expr *) lfirst(((SubLink *) expr)->oper))->args) =
|
||||
lfirst(((SubLink *) expr)->lefthand);
|
||||
}
|
||||
expr = _make_subplan((SubLink *) expr);
|
||||
expr = _make_subplan((SubLink *) expr);
|
||||
}
|
||||
|
||||
|
||||
return expr;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user