Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
P
Postgres FD Implementation
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Abuhujair Javed
Postgres FD Implementation
Commits
ecef2caa
Commit
ecef2caa
authored
Aug 09, 1999
by
Tom Lane
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Clean up routines in setrefs.c by replacing individual tree
walking logic with expression_tree_walker/mutator calls.
parent
6bc601b6
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
157 additions
and
551 deletions
+157
-551
src/backend/optimizer/plan/setrefs.c
src/backend/optimizer/plan/setrefs.c
+155
-547
src/include/optimizer/planmain.h
src/include/optimizer/planmain.h
+2
-4
No files found.
src/backend/optimizer/plan/setrefs.c
View file @
ecef2caa
...
...
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.5
3 1999/07/16 04:59:20 momjian
Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.5
4 1999/08/09 00:56:05 tgl
Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -15,8 +15,6 @@
#include "postgres.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "optimizer/clauses.h"
...
...
@@ -24,22 +22,40 @@
#include "optimizer/tlist.h"
#include "optimizer/var.h"
typedef
struct
{
List
*
outer_tlist
;
List
*
inner_tlist
;
}
replace_joinvar_refs_context
;
typedef
struct
{
Index
subvarno
;
List
*
subplanTargetList
;
}
replace_vars_with_subplan_refs_context
;
typedef
struct
{
List
*
groupClause
;
List
*
targetList
;
}
check_having_for_ungrouped_vars_context
;
static
void
set_join_tlist_references
(
Join
*
join
);
static
void
set_nonamescan_tlist_references
(
SeqScan
*
nonamescan
);
static
void
set_noname_tlist_references
(
Noname
*
noname
);
static
Node
*
replace_clause_joinvar_refs
(
Node
*
clause
,
List
*
outer_tlist
,
List
*
inner_tlist
);
static
Var
*
replace_joinvar_refs
(
Var
*
var
,
List
*
outer_tlist
,
List
*
inner_tlist
);
static
Node
*
replace_joinvar_refs
(
Node
*
clause
,
List
*
outer_tlist
,
List
*
inner_tlist
);
static
Node
*
replace_joinvar_refs_mutator
(
Node
*
node
,
replace_joinvar_refs_context
*
context
);
static
List
*
tlist_noname_references
(
Oid
nonameid
,
List
*
tlist
);
static
bool
OperandIsInner
(
Node
*
opnd
,
int
inner_relid
);
static
List
*
pull_agg_clause
(
Node
*
clause
);
static
void
set_result_tlist_references
(
Result
*
resultNode
);
static
void
replace_vars_with_subplan_refs
(
Node
*
clause
,
Index
subvarno
,
List
*
subplanTargetList
);
Index
subvarno
,
List
*
subplanTargetList
);
static
bool
replace_vars_with_subplan_refs_walker
(
Node
*
node
,
replace_vars_with_subplan_refs_context
*
context
);
static
List
*
pull_agg_clause
(
Node
*
clause
);
static
bool
pull_agg_clause_walker
(
Node
*
node
,
List
**
listptr
);
static
bool
check_having_for_ungrouped_vars_walker
(
Node
*
node
,
check_having_for_ungrouped_vars_context
*
context
);
/*****************************************************************************
*
...
...
@@ -107,12 +123,12 @@ set_join_tlist_references(Join *join)
foreach
(
entry
,
qptlist
)
{
TargetEntry
*
xtl
=
(
TargetEntry
*
)
lfirst
(
entry
);
Node
*
join
var
=
replace_claus
e_joinvar_refs
(
xtl
->
expr
,
outer_tlist
,
inner_tlist
);
Node
*
join
expr
=
replac
e_joinvar_refs
(
xtl
->
expr
,
outer_tlist
,
inner_tlist
);
new_join_targetlist
=
lappend
(
new_join_targetlist
,
makeTargetEntry
(
xtl
->
resdom
,
joinva
r
));
makeTargetEntry
(
xtl
->
resdom
,
joinexp
r
));
}
((
Plan
*
)
join
)
->
targetlist
=
new_join_targetlist
;
...
...
@@ -173,7 +189,7 @@ set_noname_tlist_references(Noname *noname)
* Creates a new set of join clauses by changing the varno/varattno
* values of variables in the clauses to reference target list values
* from the outer and inner join relation target lists.
* This is just an external interface for replace_
clause_
joinvar_refs.
* This is just an external interface for replace_joinvar_refs.
*
* 'clauses' is the list of join clauses
* 'outer_tlist' is the target list of the outer join relation
...
...
@@ -188,291 +204,75 @@ join_references(List *clauses,
List
*
outer_tlist
,
List
*
inner_tlist
)
{
return
(
List
*
)
replace_
clause_
joinvar_refs
((
Node
*
)
clauses
,
outer_tlist
,
inner_tlist
);
return
(
List
*
)
replace_joinvar_refs
((
Node
*
)
clauses
,
outer_tlist
,
inner_tlist
);
}
/*
* index_outerjoin_references
* Given a list of join clauses, replace the operand corresponding to the
* outer relation in the join with references to the corresponding target
* list element in 'outer_tlist' (the outer is rather obscurely
* identified as the side that doesn't contain a var whose varno equals
* 'inner_relid').
*
* As a side effect, the operator is replaced by the regproc id.
*
* 'inner_indxqual' is the list of join clauses (so-called because they
* are used as qualifications for the inner (inbex) scan of a nestloop)
*
* Returns the new list of clauses.
*
*/
List
*
index_outerjoin_references
(
List
*
inner_indxqual
,
List
*
outer_tlist
,
Index
inner_relid
)
{
List
*
t_list
=
NIL
;
Expr
*
temp
=
NULL
;
List
*
t_clause
=
NIL
;
Expr
*
clause
=
NULL
;
foreach
(
t_clause
,
inner_indxqual
)
{
clause
=
lfirst
(
t_clause
);
/*
* if inner scan on the right.
*/
if
(
OperandIsInner
((
Node
*
)
get_rightop
(
clause
),
inner_relid
))
{
Var
*
joinvar
=
(
Var
*
)
replace_clause_joinvar_refs
((
Node
*
)
get_leftop
(
clause
),
outer_tlist
,
NIL
);
temp
=
make_opclause
(
replace_opid
((
Oper
*
)
((
Expr
*
)
clause
)
->
oper
),
joinvar
,
get_rightop
(
clause
));
t_list
=
lappend
(
t_list
,
temp
);
}
else
{
/* inner scan on left */
Var
*
joinvar
=
(
Var
*
)
replace_clause_joinvar_refs
((
Node
*
)
get_rightop
(
clause
),
outer_tlist
,
NIL
);
temp
=
make_opclause
(
replace_opid
((
Oper
*
)
((
Expr
*
)
clause
)
->
oper
),
get_leftop
(
clause
),
joinvar
);
t_list
=
lappend
(
t_list
,
temp
);
}
}
return
t_list
;
}
/*
* replace_clause_joinvar_refs
* replace_joinvar_refs
*
* Replaces all variables within a join clause with a new var node
* whose varno/varattno fields contain a reference to a target list
* element from either the outer or inner join relation.
*
* Returns a suitably modified copy of the join clause;
* the original is not modified (and must not be!)
*
* Side effect: also runs fix_opids on the modified join clause.
* Really ought to make that happen in a uniform, consistent place...
*
* 'clause' is the join clause
* 'outer_tlist' is the target list of the outer join relation
* 'inner_tlist' is the target list of the inner join relation
*
* Returns the new join clause.
* NB: it is critical that the original clause structure not be modified!
* The changes must be applied to a copy.
*
* XXX the current implementation does not copy unchanged primitive
* nodes; they remain shared with the original. Is this safe?
*/
static
Node
*
replace_
clause_
joinvar_refs
(
Node
*
clause
,
List
*
outer_tlist
,
List
*
inner_tlist
)
replace_joinvar_refs
(
Node
*
clause
,
List
*
outer_tlist
,
List
*
inner_tlist
)
{
if
(
clause
==
NULL
)
return
NULL
;
if
(
IsA
(
clause
,
Var
))
{
Var
*
temp
=
replace_joinvar_refs
((
Var
*
)
clause
,
outer_tlist
,
inner_tlist
);
replace_joinvar_refs_context
context
;
if
(
temp
!=
NULL
)
return
(
Node
*
)
temp
;
else
return
clause
;
}
else
if
(
single_node
(
clause
))
return
clause
;
else
if
(
and_clause
(
clause
))
{
return
(
Node
*
)
make_andclause
((
List
*
)
replace_clause_joinvar_refs
((
Node
*
)
((
Expr
*
)
clause
)
->
args
,
outer_tlist
,
inner_tlist
));
}
else
if
(
or_clause
(
clause
))
{
return
(
Node
*
)
make_orclause
((
List
*
)
replace_clause_joinvar_refs
((
Node
*
)
((
Expr
*
)
clause
)
->
args
,
outer_tlist
,
inner_tlist
));
}
else
if
(
IsA
(
clause
,
ArrayRef
))
{
ArrayRef
*
oldnode
=
(
ArrayRef
*
)
clause
;
ArrayRef
*
newnode
=
makeNode
(
ArrayRef
);
newnode
->
refattrlength
=
oldnode
->
refattrlength
;
newnode
->
refelemlength
=
oldnode
->
refelemlength
;
newnode
->
refelemtype
=
oldnode
->
refelemtype
;
newnode
->
refelembyval
=
oldnode
->
refelembyval
;
newnode
->
refupperindexpr
=
(
List
*
)
replace_clause_joinvar_refs
((
Node
*
)
oldnode
->
refupperindexpr
,
outer_tlist
,
inner_tlist
);
newnode
->
reflowerindexpr
=
(
List
*
)
replace_clause_joinvar_refs
((
Node
*
)
oldnode
->
reflowerindexpr
,
outer_tlist
,
inner_tlist
);
newnode
->
refexpr
=
replace_clause_joinvar_refs
(
oldnode
->
refexpr
,
outer_tlist
,
inner_tlist
);
newnode
->
refassgnexpr
=
replace_clause_joinvar_refs
(
oldnode
->
refassgnexpr
,
outer_tlist
,
inner_tlist
);
return
(
Node
*
)
newnode
;
}
else
if
(
is_funcclause
(
clause
))
{
return
(
Node
*
)
make_funcclause
(
(
Func
*
)
((
Expr
*
)
clause
)
->
oper
,
(
List
*
)
replace_clause_joinvar_refs
(
(
Node
*
)
((
Expr
*
)
clause
)
->
args
,
outer_tlist
,
inner_tlist
));
}
else
if
(
not_clause
(
clause
))
{
return
(
Node
*
)
make_notclause
((
Expr
*
)
replace_clause_joinvar_refs
(
(
Node
*
)
get_notclausearg
((
Expr
*
)
clause
),
outer_tlist
,
inner_tlist
));
}
else
if
(
is_opclause
(
clause
))
{
return
(
Node
*
)
make_opclause
(
replace_opid
((
Oper
*
)
((
Expr
*
)
clause
)
->
oper
),
(
Var
*
)
replace_clause_joinvar_refs
(
(
Node
*
)
get_leftop
((
Expr
*
)
clause
),
outer_tlist
,
inner_tlist
),
(
Var
*
)
replace_clause_joinvar_refs
(
(
Node
*
)
get_rightop
((
Expr
*
)
clause
),
outer_tlist
,
inner_tlist
));
}
else
if
(
IsA
(
clause
,
List
))
{
List
*
t_list
=
NIL
;
List
*
subclause
;
foreach
(
subclause
,
(
List
*
)
clause
)
{
t_list
=
lappend
(
t_list
,
replace_clause_joinvar_refs
(
lfirst
(
subclause
),
outer_tlist
,
inner_tlist
));
}
return
(
Node
*
)
t_list
;
}
else
if
(
is_subplan
(
clause
))
{
/* This is a tad wasteful of space, but it works... */
Expr
*
newclause
=
(
Expr
*
)
copyObject
(
clause
);
newclause
->
args
=
(
List
*
)
replace_clause_joinvar_refs
((
Node
*
)
newclause
->
args
,
outer_tlist
,
inner_tlist
);
((
SubPlan
*
)
newclause
->
oper
)
->
sublink
->
oper
=
(
List
*
)
replace_clause_joinvar_refs
(
(
Node
*
)
((
SubPlan
*
)
newclause
->
oper
)
->
sublink
->
oper
,
outer_tlist
,
inner_tlist
);
return
(
Node
*
)
newclause
;
}
else
if
(
IsA
(
clause
,
CaseExpr
))
{
CaseExpr
*
oldnode
=
(
CaseExpr
*
)
clause
;
CaseExpr
*
newnode
=
makeNode
(
CaseExpr
);
newnode
->
casetype
=
oldnode
->
casetype
;
newnode
->
arg
=
oldnode
->
arg
;
/* XXX should always be null
* anyway ... */
newnode
->
args
=
(
List
*
)
replace_clause_joinvar_refs
((
Node
*
)
oldnode
->
args
,
outer_tlist
,
inner_tlist
);
newnode
->
defresult
=
replace_clause_joinvar_refs
(
oldnode
->
defresult
,
outer_tlist
,
inner_tlist
);
return
(
Node
*
)
newnode
;
}
else
if
(
IsA
(
clause
,
CaseWhen
))
{
CaseWhen
*
oldnode
=
(
CaseWhen
*
)
clause
;
CaseWhen
*
newnode
=
makeNode
(
CaseWhen
);
newnode
->
expr
=
replace_clause_joinvar_refs
(
oldnode
->
expr
,
outer_tlist
,
inner_tlist
);
newnode
->
result
=
replace_clause_joinvar_refs
(
oldnode
->
result
,
outer_tlist
,
inner_tlist
);
return
(
Node
*
)
newnode
;
}
else
{
elog
(
ERROR
,
"replace_clause_joinvar_refs: unsupported clause %d"
,
nodeTag
(
clause
));
return
NULL
;
}
context
.
outer_tlist
=
outer_tlist
;
context
.
inner_tlist
=
inner_tlist
;
return
(
Node
*
)
fix_opids
((
List
*
)
replace_joinvar_refs_mutator
(
clause
,
&
context
));
}
static
Var
*
replace_joinvar_refs
(
Var
*
var
,
List
*
outer_tlist
,
List
*
inner_tlist
)
static
Node
*
replace_joinvar_refs_mutator
(
Node
*
node
,
replace_joinvar_refs_context
*
context
)
{
Resdom
*
outer_resdom
;
outer_resdom
=
tlist_member
(
var
,
outer_tlist
);
if
(
outer_resdom
!=
NULL
&&
IsA
(
outer_resdom
,
Resdom
))
{
return
(
makeVar
(
OUTER
,
outer_resdom
->
resno
,
var
->
vartype
,
var
->
vartypmod
,
0
,
var
->
varnoold
,
var
->
varoattno
));
}
else
{
Resdom
*
inner_resdom
;
inner_resdom
=
tlist_member
(
var
,
inner_tlist
);
if
(
inner_resdom
!=
NULL
&&
IsA
(
inner_resdom
,
Resdom
))
{
return
(
makeVar
(
INNER
,
inner_resdom
->
resno
,
var
->
vartype
,
var
->
vartypmod
,
0
,
var
->
varnoold
,
var
->
varoattno
));
}
}
return
(
Var
*
)
NULL
;
if
(
node
==
NULL
)
return
NULL
;
if
(
IsA
(
node
,
Var
))
{
Var
*
var
=
(
Var
*
)
node
;
Resdom
*
resdom
=
tlist_member
(
var
,
context
->
outer_tlist
);
if
(
resdom
!=
NULL
&&
IsA
(
resdom
,
Resdom
))
return
(
Node
*
)
makeVar
(
OUTER
,
resdom
->
resno
,
var
->
vartype
,
var
->
vartypmod
,
0
,
var
->
varnoold
,
var
->
varoattno
);
resdom
=
tlist_member
(
var
,
context
->
inner_tlist
);
if
(
resdom
!=
NULL
&&
IsA
(
resdom
,
Resdom
))
return
(
Node
*
)
makeVar
(
INNER
,
resdom
->
resno
,
var
->
vartype
,
var
->
vartypmod
,
0
,
var
->
varnoold
,
var
->
varoattno
);
/* Var not in either tlist, return an unmodified copy. */
return
copyObject
(
node
);
}
return
expression_tree_mutator
(
node
,
replace_joinvar_refs_mutator
,
(
void
*
)
context
);
}
/*
...
...
@@ -494,15 +294,14 @@ tlist_noname_references(Oid nonameid,
List
*
tlist
)
{
List
*
t_list
=
NIL
;
TargetEntry
*
noname
=
(
TargetEntry
*
)
NULL
;
TargetEntry
*
xtl
=
NULL
;
List
*
entry
;
foreach
(
entry
,
tlist
)
{
TargetEntry
*
xtl
=
lfirst
(
entry
);
AttrNumber
oattno
;
TargetEntry
*
noname
;
xtl
=
lfirst
(
entry
);
if
(
IsA
(
get_expr
(
xtl
),
Var
))
oattno
=
((
Var
*
)
xtl
->
expr
)
->
varoattno
;
else
...
...
@@ -531,7 +330,7 @@ tlist_noname_references(Oid nonameid,
*
* NOTE:
* 1) we ignore the right tree! (in the current implementation
* it is always nil
* it is always nil
)
* 2) this routine will probably *NOT* work with nested dot
* fields....
*/
...
...
@@ -601,131 +400,52 @@ replace_vars_with_subplan_refs(Node *clause,
Index
subvarno
,
List
*
subplanTargetList
)
{
List
*
t
;
replace_vars_with_subplan_refs_context
contex
t
;
if
(
clause
==
NULL
)
return
;
if
(
IsA
(
clause
,
Var
))
{
context
.
subvarno
=
subvarno
;
context
.
subplanTargetList
=
subplanTargetList
;
replace_vars_with_subplan_refs_walker
(
clause
,
&
context
);
}
static
bool
replace_vars_with_subplan_refs_walker
(
Node
*
node
,
replace_vars_with_subplan_refs_context
*
context
)
{
if
(
node
==
NULL
)
return
false
;
if
(
IsA
(
node
,
Var
))
{
/*
* Ha! A Var node!
*
* It could be that this varnode has been created by make_groupplan
* and is already set up to reference the subplan target list. We
* recognize that case by varno = 1, varnoold = -1, varattno =
* varoattno, and varlevelsup = 0. (Probably ought to have an
* explicit flag, but this should do for now.)
*/
Var
*
var
=
(
Var
*
)
claus
e
;
Var
*
var
=
(
Var
*
)
nod
e
;
TargetEntry
*
subplanVar
;
if
(
var
->
varno
==
(
Index
)
1
&&
var
->
varnoold
==
((
Index
)
-
1
)
&&
var
->
varattno
==
var
->
varoattno
&&
var
->
varlevelsup
==
0
)
return
;
/* OK to leave it alone */
return
false
;
/* OK to leave it alone */
/* Otherwise it had better be in the subplan list. */
subplanVar
=
match_varid
(
var
,
subplanTargetList
);
subplanVar
=
match_varid
(
var
,
context
->
subplanTargetList
);
if
(
!
subplanVar
)
elog
(
ERROR
,
"replace_vars_with_subplan_refs: variable not in target list"
);
/*
* Change the varno & varattno fields of the var node.
*/
var
->
varno
=
subvarno
;
var
->
varno
=
context
->
subvarno
;
var
->
varattno
=
subplanVar
->
resdom
->
resno
;
return
false
;
}
else
if
(
single_node
(
clause
))
{
/* do nothing! */
}
else
if
(
IsA
(
clause
,
Iter
))
replace_vars_with_subplan_refs
(((
Iter
*
)
clause
)
->
iterexpr
,
subvarno
,
subplanTargetList
);
else
if
(
is_subplan
(
clause
))
{
foreach
(
t
,
((
Expr
*
)
clause
)
->
args
)
replace_vars_with_subplan_refs
(
lfirst
(
t
),
subvarno
,
subplanTargetList
);
foreach
(
t
,
((
SubPlan
*
)
((
Expr
*
)
clause
)
->
oper
)
->
sublink
->
oper
)
replace_vars_with_subplan_refs
(
lfirst
(((
Expr
*
)
lfirst
(
t
))
->
args
),
subvarno
,
subplanTargetList
);
}
else
if
(
IsA
(
clause
,
Expr
))
{
/*
* Recursively scan the arguments of an expression. NOTE: this
* must come after is_subplan() case since subplan is a kind of
* Expr node.
*/
foreach
(
t
,
((
Expr
*
)
clause
)
->
args
)
replace_vars_with_subplan_refs
(
lfirst
(
t
),
subvarno
,
subplanTargetList
);
}
else
if
(
IsA
(
clause
,
Aggref
))
replace_vars_with_subplan_refs
(((
Aggref
*
)
clause
)
->
target
,
subvarno
,
subplanTargetList
);
else
if
(
IsA
(
clause
,
ArrayRef
))
{
ArrayRef
*
aref
=
(
ArrayRef
*
)
clause
;
foreach
(
t
,
aref
->
refupperindexpr
)
replace_vars_with_subplan_refs
(
lfirst
(
t
),
subvarno
,
subplanTargetList
);
foreach
(
t
,
aref
->
reflowerindexpr
)
replace_vars_with_subplan_refs
(
lfirst
(
t
),
subvarno
,
subplanTargetList
);
replace_vars_with_subplan_refs
(
aref
->
refexpr
,
subvarno
,
subplanTargetList
);
replace_vars_with_subplan_refs
(
aref
->
refassgnexpr
,
subvarno
,
subplanTargetList
);
}
else
if
(
case_clause
(
clause
))
{
foreach
(
t
,
((
CaseExpr
*
)
clause
)
->
args
)
{
CaseWhen
*
when
=
(
CaseWhen
*
)
lfirst
(
t
);
replace_vars_with_subplan_refs
(
when
->
expr
,
subvarno
,
subplanTargetList
);
replace_vars_with_subplan_refs
(
when
->
result
,
subvarno
,
subplanTargetList
);
}
replace_vars_with_subplan_refs
(((
CaseExpr
*
)
clause
)
->
defresult
,
subvarno
,
subplanTargetList
);
}
else
{
elog
(
ERROR
,
"replace_vars_with_subplan_refs: Cannot handle node type %d"
,
nodeTag
(
clause
));
}
}
static
bool
OperandIsInner
(
Node
*
opnd
,
int
inner_relid
)
{
/*
* Can be the inner scan if its a varnode or a function and the
* inner_relid is equal to the varnode's var number or in the case of
* a function the first argument's var number (all args in a
* functional index are from the same relation).
*/
if
(
IsA
(
opnd
,
Var
)
&&
(
inner_relid
==
((
Var
*
)
opnd
)
->
varno
))
return
true
;
if
(
is_funcclause
(
opnd
))
{
List
*
firstArg
=
lfirst
(((
Expr
*
)
opnd
)
->
args
);
if
(
IsA
(
firstArg
,
Var
)
&&
(
inner_relid
==
((
Var
*
)
firstArg
)
->
varno
))
return
true
;
}
return
false
;
return
expression_tree_walker
(
node
,
replace_vars_with_subplan_refs_walker
,
(
void
*
)
context
);
}
/*****************************************************************************
...
...
@@ -787,83 +507,35 @@ set_agg_tlist_references(Agg *aggNode)
}
/*
* Make a list of all Aggref nodes contained in the given expression.
* pull_agg_clause
* Recursively pulls all Aggref nodes from an expression clause.
*
* Returns list of Aggref nodes found. Note the nodes themselves are not
* copied, only referenced.
*/
static
List
*
pull_agg_clause
(
Node
*
clause
)
{
List
*
agg_list
=
NIL
;
List
*
t
;
if
(
clause
==
NULL
)
return
NIL
;
else
if
(
single_node
(
clause
))
return
NIL
;
else
if
(
IsA
(
clause
,
Iter
))
return
pull_agg_clause
(((
Iter
*
)
clause
)
->
iterexpr
);
else
if
(
is_subplan
(
clause
))
{
SubLink
*
sublink
=
((
SubPlan
*
)
((
Expr
*
)
clause
)
->
oper
)
->
sublink
;
List
*
result
=
NIL
;
/*
* Only the lefthand side of the sublink should be checked for
* aggregates to be attached to the aggs list
*/
foreach
(
t
,
sublink
->
lefthand
)
agg_list
=
nconc
(
pull_agg_clause
(
lfirst
(
t
)),
agg_list
);
/* The first argument of ...->oper has also to be checked */
foreach
(
t
,
sublink
->
oper
)
agg_list
=
nconc
(
pull_agg_clause
(
lfirst
(
t
)),
agg_list
);
}
else
if
(
IsA
(
clause
,
Expr
))
{
/*
* Recursively scan the arguments of an expression. NOTE: this
* must come after is_subplan() case since subplan is a kind of
* Expr node.
*/
foreach
(
t
,
((
Expr
*
)
clause
)
->
args
)
agg_list
=
nconc
(
pull_agg_clause
(
lfirst
(
t
)),
agg_list
);
}
else
if
(
IsA
(
clause
,
Aggref
))
{
return
lcons
(
clause
,
pull_agg_clause
(((
Aggref
*
)
clause
)
->
target
));
}
else
if
(
IsA
(
clause
,
ArrayRef
))
{
ArrayRef
*
aref
=
(
ArrayRef
*
)
clause
;
foreach
(
t
,
aref
->
refupperindexpr
)
agg_list
=
nconc
(
pull_agg_clause
(
lfirst
(
t
)),
agg_list
);
foreach
(
t
,
aref
->
reflowerindexpr
)
agg_list
=
nconc
(
pull_agg_clause
(
lfirst
(
t
)),
agg_list
);
agg_list
=
nconc
(
pull_agg_clause
(
aref
->
refexpr
),
agg_list
);
agg_list
=
nconc
(
pull_agg_clause
(
aref
->
refassgnexpr
),
agg_list
);
}
else
if
(
case_clause
(
clause
))
{
foreach
(
t
,
((
CaseExpr
*
)
clause
)
->
args
)
{
CaseWhen
*
when
=
(
CaseWhen
*
)
lfirst
(
t
);
pull_agg_clause_walker
(
clause
,
&
result
);
return
result
;
}
agg_list
=
nconc
(
agg_list
,
pull_agg_clause
(
when
->
expr
));
agg_list
=
nconc
(
agg_list
,
pull_agg_clause
(
when
->
result
));
}
agg_list
=
nconc
(
pull_agg_clause
(((
CaseExpr
*
)
clause
)
->
defresult
),
agg_list
);
}
else
static
bool
pull_agg_clause_walker
(
Node
*
node
,
List
**
listptr
)
{
if
(
node
==
NULL
)
return
false
;
if
(
IsA
(
node
,
Aggref
))
{
elog
(
ERROR
,
"pull_agg_clause: Cannot handle node type %d"
,
nodeTag
(
clause
))
;
*
listptr
=
lappend
(
*
listptr
,
node
);
return
false
;
}
return
agg_list
;
return
expression_tree_walker
(
node
,
pull_agg_clause_walker
,
(
void
*
)
listptr
)
;
}
/*
* check_having_for_ungrouped_vars takes the havingQual and the list of
* GROUP BY clauses and checks for subplans in the havingQual that are being
...
...
@@ -882,45 +554,43 @@ void
check_having_for_ungrouped_vars
(
Node
*
clause
,
List
*
groupClause
,
List
*
targetList
)
{
List
*
t
;
if
(
clause
==
NULL
)
return
;
check_having_for_ungrouped_vars_context
context
;
if
(
IsA
(
clause
,
Var
))
{
context
.
groupClause
=
groupClause
;
context
.
targetList
=
targetList
;
check_having_for_ungrouped_vars_walker
(
clause
,
&
context
);
}
/*
* Ignore vars elsewhere in the having clause, since the parser
* already checked 'em.
*/
}
else
if
(
single_node
(
clause
))
{
/* ignore */
}
else
if
(
IsA
(
clause
,
Iter
))
{
check_having_for_ungrouped_vars
(((
Iter
*
)
clause
)
->
iterexpr
,
groupClause
,
targetList
);
}
else
if
(
is_subplan
(
clause
))
static
bool
check_having_for_ungrouped_vars_walker
(
Node
*
node
,
check_having_for_ungrouped_vars_context
*
context
)
{
if
(
node
==
NULL
)
return
false
;
/*
* We can ignore Vars other than in subplan args lists,
* since the parser already checked 'em.
*/
if
(
is_subplan
(
node
))
{
/*
* The args list of the subplan node represents attributes from
* outside passed into the sublink.
*/
foreach
(
t
,
((
Expr
*
)
clause
)
->
args
)
List
*
t
;
foreach
(
t
,
((
Expr
*
)
node
)
->
args
)
{
Node
*
thisarg
=
lfirst
(
t
);
bool
contained_in_group_clause
=
false
;
List
*
gl
;
foreach
(
gl
,
groupClause
)
foreach
(
gl
,
context
->
groupClause
)
{
if
(
var_equal
(
lfirst
(
t
),
get_groupclause_expr
((
GroupClause
*
)
lfirst
(
gl
),
targetList
)))
Var
*
groupexpr
=
get_groupclause_expr
(
lfirst
(
gl
),
context
->
targetList
);
if
(
var_equal
((
Var
*
)
thisarg
,
groupexpr
))
{
contained_in_group_clause
=
true
;
break
;
...
...
@@ -931,69 +601,7 @@ check_having_for_ungrouped_vars(Node *clause, List *groupClause,
elog
(
ERROR
,
"Sub-SELECT in HAVING clause must use only GROUPed attributes from outer SELECT"
);
}
}
else
if
(
IsA
(
clause
,
Expr
))
{
/*
* Recursively scan the arguments of an expression. NOTE: this
* must come after is_subplan() case since subplan is a kind of
* Expr node.
*/
foreach
(
t
,
((
Expr
*
)
clause
)
->
args
)
check_having_for_ungrouped_vars
(
lfirst
(
t
),
groupClause
,
targetList
);
}
else
if
(
IsA
(
clause
,
List
))
{
/*
* Recursively scan AND subclauses (see NOTE above).
*/
foreach
(
t
,
((
List
*
)
clause
))
check_having_for_ungrouped_vars
(
lfirst
(
t
),
groupClause
,
targetList
);
}
else
if
(
IsA
(
clause
,
Aggref
))
{
check_having_for_ungrouped_vars
(((
Aggref
*
)
clause
)
->
target
,
groupClause
,
targetList
);
}
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
)
check_having_for_ungrouped_vars
(
lfirst
(
t
),
groupClause
,
targetList
);
foreach
(
t
,
aref
->
reflowerindexpr
)
check_having_for_ungrouped_vars
(
lfirst
(
t
),
groupClause
,
targetList
);
check_having_for_ungrouped_vars
(
aref
->
refexpr
,
groupClause
,
targetList
);
check_having_for_ungrouped_vars
(
aref
->
refassgnexpr
,
groupClause
,
targetList
);
}
else
if
(
case_clause
(
clause
))
{
foreach
(
t
,
((
CaseExpr
*
)
clause
)
->
args
)
{
CaseWhen
*
when
=
(
CaseWhen
*
)
lfirst
(
t
);
check_having_for_ungrouped_vars
(
when
->
expr
,
groupClause
,
targetList
);
check_having_for_ungrouped_vars
(
when
->
result
,
groupClause
,
targetList
);
}
check_having_for_ungrouped_vars
(((
CaseExpr
*
)
clause
)
->
defresult
,
groupClause
,
targetList
);
}
else
{
elog
(
ERROR
,
"check_having_for_ungrouped_vars: Cannot handle node type %d"
,
nodeTag
(
clause
));
}
return
expression_tree_walker
(
node
,
check_having_for_ungrouped_vars_walker
,
(
void
*
)
context
);
}
src/include/optimizer/planmain.h
View file @
ecef2caa
...
...
@@ -6,7 +6,7 @@
*
* Copyright (c) 1994, Regents of the University of California
*
* $Id: planmain.h,v 1.
29 1999/07/15 15:21:22 momjian
Exp $
* $Id: planmain.h,v 1.
30 1999/08/09 00:56:04 tgl
Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -49,9 +49,7 @@ extern void add_missing_vars_to_tlist(Query *root, List *tlist);
*/
extern
void
set_tlist_references
(
Plan
*
plan
);
extern
List
*
join_references
(
List
*
clauses
,
List
*
outer_tlist
,
List
*
inner_tlist
);
extern
List
*
index_outerjoin_references
(
List
*
inner_indxqual
,
List
*
outer_tlist
,
Index
inner_relid
);
List
*
inner_tlist
);
extern
void
replace_tlist_with_subplan_refs
(
List
*
tlist
,
Index
subvarno
,
List
*
subplanTargetList
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment