Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
Greenplum
Gpdb
提交
8aea617c
G
Gpdb
项目概览
Greenplum
/
Gpdb
通知
7
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
G
Gpdb
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
8aea617c
编写于
7月 15, 1999
作者:
T
Tom Lane
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Several routines failed to cope with CASE expressions, and
indeed some of 'em were missing support for more node types than that...
上级
d72168d6
变更
1
隐藏空白更改
内联
并排
Showing
1 changed file
with
200 addition
and
137 deletion
+200
-137
src/backend/optimizer/plan/subselect.c
src/backend/optimizer/plan/subselect.c
+200
-137
未找到文件。
src/backend/optimizer/plan/subselect.c
浏览文件 @
8aea617c
...
...
@@ -6,7 +6,7 @@
* Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.1
8 1999/06/21 01:20:57
tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.1
9 1999/07/15 01:52:09
tgl Exp $
*
*-------------------------------------------------------------------------
*/
...
...
@@ -292,108 +292,129 @@ set_unioni(List *l1, List *l2)
return
nconc
(
l1
,
set_differencei
(
l2
,
l1
));
}
static
List
*
_finalize_primnode
(
void
*
expr
,
List
**
subplan
)
{
List
*
result
=
NULL
;
typedef
struct
finalize_primnode_results
{
List
*
subplans
;
/* List of subplans found in expr */
List
*
paramids
;
/* List of PARAM_EXEC paramids found */
}
finalize_primnode_results
;
if
(
expr
==
NULL
)
return
NULL
;
static
bool
finalize_primnode_walker
(
Node
*
node
,
finalize_primnode_results
*
results
)
;
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
;
static
void
finalize_primnode
(
Node
*
expr
,
finalize_primnode_results
*
results
)
{
results
->
subplans
=
NIL
;
/* initialize */
results
->
paramids
=
NIL
;
(
void
)
finalize_primnode_walker
(
expr
,
results
);
}
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
,
Aggref
))
return
_finalize_primnode
(((
Aggref
*
)
expr
)
->
target
,
subplan
);
else
if
(
IsA
(
expr
,
ArrayRef
))
static
bool
finalize_primnode_walker
(
Node
*
node
,
finalize_primnode_results
*
results
)
{
if
(
node
==
NULL
)
return
false
;
if
(
IsA
(
node
,
Param
))
{
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
));
if
(((
Param
*
)
node
)
->
paramkind
==
PARAM_EXEC
)
{
int
paramid
=
(
int
)
((
Param
*
)
node
)
->
paramid
;
if
(
!
intMember
(
paramid
,
results
->
paramids
))
results
->
paramids
=
lconsi
(
paramid
,
results
->
paramids
);
}
return
false
;
/* no more to do here */
}
else
if
(
IsA
(
expr
,
TargetEntry
))
return
_finalize_primnode
(((
TargetEntry
*
)
expr
)
->
expr
,
subplan
);
else
if
(
is_subplan
(
expr
))
if
(
is_subplan
(
node
))
{
SubPlan
*
subplan
=
(
SubPlan
*
)
((
Expr
*
)
node
)
->
oper
;
List
*
lst
;
*
subplan
=
lappend
(
*
subplan
,
((
Expr
*
)
expr
)
->
oper
);
foreach
(
lst
,
((
SubPlan
*
)
((
Expr
*
)
expr
)
->
oper
)
->
plan
->
extParam
)
/* Add subplan to subplans list */
results
->
subplans
=
lappend
(
results
->
subplans
,
subplan
);
/* Check extParam list for params to add to paramids */
foreach
(
lst
,
subplan
->
plan
->
extParam
)
{
Var
*
var
=
nth
(
lfirsti
(
lst
),
PlannerParamVar
);
int
paramid
=
lfirsti
(
lst
);
Var
*
var
=
nth
(
paramid
,
PlannerParamVar
);
/* note varlevelsup is absolute level number */
if
(
var
->
varlevelsup
<
PlannerQueryLevel
&&
!
intMember
(
lfirsti
(
lst
),
result
))
result
=
lappendi
(
result
,
lfirsti
(
lst
)
);
!
intMember
(
paramid
,
results
->
paramids
))
result
s
->
paramids
=
lconsi
(
paramid
,
results
->
paramids
);
}
/* XXX We do NOT allow expression_tree_walker to examine the args
* passed to the subplan. Is that correct??? It's what the
* old code did, but it seems mighty bogus... tgl 7/14/99
*/
return
false
;
/* don't recurse into subplan args */
}
else
elog
(
ERROR
,
"_finalize_primnode: can't handle node %d"
,
nodeTag
(
expr
));
return
result
;
return
expression_tree_walker
(
node
,
finalize_primnode_walker
,
(
void
*
)
results
);
}
/* Replace correlation vars (uplevel vars) with Params. */
/* XXX should replace this with use of a generalized tree rebuilder,
* designed along the same lines as expression_tree_walker.
* Not done yet.
*/
Node
*
SS_replace_correlation_vars
(
Node
*
expr
)
{
if
(
expr
==
NULL
)
return
NULL
;
if
(
IsA
(
expr
,
List
))
if
(
IsA
(
expr
,
Var
))
{
if
(((
Var
*
)
expr
)
->
varlevelsup
>
0
)
expr
=
(
Node
*
)
_replace_var
((
Var
*
)
expr
);
}
else
if
(
single_node
(
expr
))
return
expr
;
else
if
(
IsA
(
expr
,
List
))
{
List
*
le
;
foreach
(
le
,
(
List
*
)
expr
)
lfirst
(
le
)
=
SS_replace_correlation_vars
((
Node
*
)
lfirst
(
le
));
}
else
if
(
IsA
(
expr
,
Va
r
))
else
if
(
IsA
(
expr
,
Exp
r
))
{
if
(((
Var
*
)
expr
)
->
varlevelsup
>
0
)
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
))
/* XXX do we need to do anything special with subplans? */
((
Expr
*
)
expr
)
->
args
=
(
List
*
)
SS_replace_correlation_vars
((
Node
*
)
((
Expr
*
)
expr
)
->
args
);
}
else
if
(
IsA
(
expr
,
Aggref
))
((
Aggref
*
)
expr
)
->
target
=
SS_replace_correlation_vars
((
Node
*
)
((
Aggref
*
)
expr
)
->
target
);
((
Aggref
*
)
expr
)
->
target
=
SS_replace_correlation_vars
(((
Aggref
*
)
expr
)
->
target
);
else
if
(
IsA
(
expr
,
Iter
))
((
Iter
*
)
expr
)
->
iterexpr
=
SS_replace_correlation_vars
(((
Iter
*
)
expr
)
->
iterexpr
);
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
)
->
refexpr
=
SS_replace_correlation_vars
(((
ArrayRef
*
)
expr
)
->
refexpr
);
((
ArrayRef
*
)
expr
)
->
refassgnexpr
=
SS_replace_correlation_vars
(((
ArrayRef
*
)
expr
)
->
refassgnexpr
);
}
else
if
(
IsA
(
expr
,
CaseExpr
))
{
CaseExpr
*
caseexpr
=
(
CaseExpr
*
)
expr
;
List
*
le
;
foreach
(
le
,
caseexpr
->
args
)
{
CaseWhen
*
when
=
(
CaseWhen
*
)
lfirst
(
le
);
Assert
(
IsA
(
when
,
CaseWhen
));
when
->
expr
=
SS_replace_correlation_vars
(
when
->
expr
);
when
->
result
=
SS_replace_correlation_vars
(
when
->
result
);
}
/* caseexpr->arg should be null, but we'll check it anyway */
caseexpr
->
arg
=
SS_replace_correlation_vars
(
caseexpr
->
arg
);
caseexpr
->
defresult
=
SS_replace_correlation_vars
(
caseexpr
->
defresult
);
}
else
if
(
IsA
(
expr
,
TargetEntry
))
((
TargetEntry
*
)
expr
)
->
expr
=
SS_replace_correlation_vars
((
Node
*
)
(
(
TargetEntry
*
)
expr
)
->
expr
);
((
TargetEntry
*
)
expr
)
->
expr
=
SS_replace_correlation_vars
(((
TargetEntry
*
)
expr
)
->
expr
);
else
if
(
IsA
(
expr
,
SubLink
))
{
List
*
le
;
...
...
@@ -409,30 +430,76 @@ SS_replace_correlation_vars(Node *expr)
SS_replace_correlation_vars
((
Node
*
)
((
SubLink
*
)
expr
)
->
lefthand
);
}
else
elog
(
NOTICE
,
"SS_replace_correlation_vars: can't handle node %d"
,
elog
(
ERROR
,
"SS_replace_correlation_vars: can't handle node %d"
,
nodeTag
(
expr
));
return
expr
;
}
/* Replace sublinks by subplans in the given expression */
/* XXX should replace this with use of a generalized tree rebuilder,
* designed along the same lines as expression_tree_walker.
* Not done yet.
*/
Node
*
SS_process_sublinks
(
Node
*
expr
)
{
if
(
expr
==
NULL
)
return
NULL
;
if
(
IsA
(
expr
,
List
))
if
(
IsA
(
expr
,
SubLink
))
{
expr
=
_make_subplan
((
SubLink
*
)
expr
);
}
else
if
(
single_node
(
expr
))
return
expr
;
else
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
))
else
if
(
IsA
(
expr
,
Expr
))
{
/* We should never see a subplan node here, since this is the
* routine that makes 'em in the first place. No need to check.
*/
((
Expr
*
)
expr
)
->
args
=
(
List
*
)
SS_process_sublinks
((
Node
*
)
((
Expr
*
)
expr
)
->
args
);
else
if
(
IsA
(
expr
,
SubLink
))
/* got it! */
expr
=
_make_subplan
((
SubLink
*
)
expr
);
}
else
if
(
IsA
(
expr
,
Aggref
))
((
Aggref
*
)
expr
)
->
target
=
SS_process_sublinks
(((
Aggref
*
)
expr
)
->
target
);
else
if
(
IsA
(
expr
,
Iter
))
((
Iter
*
)
expr
)
->
iterexpr
=
SS_process_sublinks
(((
Iter
*
)
expr
)
->
iterexpr
);
else
if
(
IsA
(
expr
,
ArrayRef
))
{
((
ArrayRef
*
)
expr
)
->
refupperindexpr
=
(
List
*
)
SS_process_sublinks
((
Node
*
)
((
ArrayRef
*
)
expr
)
->
refupperindexpr
);
((
ArrayRef
*
)
expr
)
->
reflowerindexpr
=
(
List
*
)
SS_process_sublinks
((
Node
*
)
((
ArrayRef
*
)
expr
)
->
reflowerindexpr
);
((
ArrayRef
*
)
expr
)
->
refexpr
=
SS_process_sublinks
(((
ArrayRef
*
)
expr
)
->
refexpr
);
((
ArrayRef
*
)
expr
)
->
refassgnexpr
=
SS_process_sublinks
(((
ArrayRef
*
)
expr
)
->
refassgnexpr
);
}
else
if
(
IsA
(
expr
,
CaseExpr
))
{
CaseExpr
*
caseexpr
=
(
CaseExpr
*
)
expr
;
List
*
le
;
foreach
(
le
,
caseexpr
->
args
)
{
CaseWhen
*
when
=
(
CaseWhen
*
)
lfirst
(
le
);
Assert
(
IsA
(
when
,
CaseWhen
));
when
->
expr
=
SS_process_sublinks
(
when
->
expr
);
when
->
result
=
SS_process_sublinks
(
when
->
result
);
}
/* caseexpr->arg should be null, but we'll check it anyway */
caseexpr
->
arg
=
SS_process_sublinks
(
caseexpr
->
arg
);
caseexpr
->
defresult
=
SS_process_sublinks
(
caseexpr
->
defresult
);
}
else
elog
(
ERROR
,
"SS_process_sublinks: can't handle node %d"
,
nodeTag
(
expr
));
return
expr
;
}
...
...
@@ -440,60 +507,65 @@ SS_process_sublinks(Node *expr)
List
*
SS_finalize_plan
(
Plan
*
plan
)
{
List
*
extParam
=
NULL
;
List
*
locParam
=
NULL
;
List
*
subPlan
=
NULL
;
List
*
param_list
;
List
*
extParam
=
NIL
;
List
*
locParam
=
NIL
;
finalize_primnode_results
results
;
List
*
lst
;
if
(
plan
==
NULL
)
return
NULL
;
param_list
=
_finalize_primnode
(
plan
->
targetlist
,
&
subPlan
);
Assert
(
subPlan
==
NULL
);
/* Find params in targetlist, make sure there are no subplans there */
finalize_primnode
((
Node
*
)
plan
->
targetlist
,
&
results
);
Assert
(
results
.
subplans
==
NIL
);
/* From here on, we invoke finalize_primnode_walker not finalize_primnode,
* so that results.paramids lists are automatically merged together and
* we don't have to do it the hard way. But when recursing to self,
* we do have to merge the lists. Oh well.
*/
switch
(
nodeTag
(
plan
))
{
case
T_Result
:
param_list
=
set_unioni
(
param_list
,
_finalize_primnode
(((
Result
*
)
plan
)
->
resconstantqual
,
&
subPlan
)
);
/*
subPlan is NOT necessarily NULL
here ... */
finalize_primnode_walker
(((
Result
*
)
plan
)
->
resconstantqual
,
&
results
);
/*
results.subplans is NOT necessarily empty
here ... */
break
;
case
T_Append
:
foreach
(
lst
,
((
Append
*
)
plan
)
->
appendplans
)
param_list
=
set_unioni
(
param_list
,
SS_finalize_plan
((
Plan
*
)
lfirst
(
lst
)));
results
.
paramids
=
set_unioni
(
results
.
paramids
,
SS_finalize_plan
((
Plan
*
)
lfirst
(
lst
)));
break
;
case
T_IndexScan
:
param_list
=
set_unioni
(
param_list
,
_finalize_primnode
(((
IndexScan
*
)
plan
)
->
indxqual
,
&
subPlan
)
);
Assert
(
subPlan
==
NUL
L
);
finalize_primnode_walker
((
Node
*
)
((
IndexScan
*
)
plan
)
->
indxqual
,
&
results
);
Assert
(
results
.
subplans
==
NI
L
);
break
;
case
T_MergeJoin
:
param_list
=
set_unioni
(
param_list
,
_finalize_primnode
(((
MergeJoin
*
)
plan
)
->
mergeclauses
,
&
subPlan
)
);
Assert
(
subPlan
==
NUL
L
);
finalize_primnode_walker
((
Node
*
)
((
MergeJoin
*
)
plan
)
->
mergeclauses
,
&
results
);
Assert
(
results
.
subplans
==
NI
L
);
break
;
case
T_HashJoin
:
param_list
=
set_unioni
(
param_list
,
_finalize_primnode
(((
HashJoin
*
)
plan
)
->
hashclauses
,
&
subPlan
)
);
Assert
(
subPlan
==
NUL
L
);
finalize_primnode_walker
((
Node
*
)
((
HashJoin
*
)
plan
)
->
hashclauses
,
&
results
);
Assert
(
results
.
subplans
==
NI
L
);
break
;
case
T_Hash
:
param_list
=
set_unioni
(
param_list
,
_finalize_primnode
(((
Hash
*
)
plan
)
->
hashkey
,
&
subPlan
)
);
Assert
(
subPlan
==
NUL
L
);
finalize_primnode_walker
((
Node
*
)
((
Hash
*
)
plan
)
->
hashkey
,
&
results
);
Assert
(
results
.
subplans
==
NI
L
);
break
;
case
T_Agg
:
param_list
=
set_unioni
(
param_list
,
_finalize_primnode
(((
Agg
*
)
plan
)
->
aggs
,
&
subPlan
)
);
Assert
(
subPlan
==
NUL
L
);
finalize_primnode_walker
((
Node
*
)
((
Agg
*
)
plan
)
->
aggs
,
&
results
);
Assert
(
results
.
subplans
==
NI
L
);
break
;
case
T_SeqScan
:
...
...
@@ -503,16 +575,24 @@ SS_finalize_plan(Plan *plan)
case
T_Unique
:
case
T_Group
:
break
;
default:
elog
(
ERROR
,
"SS_finalize_plan: node %d unsupported"
,
nodeTag
(
plan
));
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
));
finalize_primnode_walker
((
Node
*
)
plan
->
qual
,
&
results
);
/* subplans are OK in the qual... */
results
.
paramids
=
set_unioni
(
results
.
paramids
,
SS_finalize_plan
(
plan
->
lefttree
));
results
.
paramids
=
set_unioni
(
results
.
paramids
,
SS_finalize_plan
(
plan
->
righttree
));
/* Now we have all the paramids and subplans */
foreach
(
lst
,
param_list
)
foreach
(
lst
,
results
.
paramids
)
{
Var
*
var
=
nth
(
lfirsti
(
lst
),
PlannerParamVar
);
...
...
@@ -520,7 +600,7 @@ SS_finalize_plan(Plan *plan)
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"
);
elog
(
ERROR
,
"SS_finalize_plan: plan shouldn't reference subplan'
s
variable"
);
else
{
Assert
(
var
->
varno
==
0
&&
var
->
varattno
==
0
);
...
...
@@ -530,52 +610,35 @@ SS_finalize_plan(Plan *plan)
plan
->
extParam
=
extParam
;
plan
->
locParam
=
locParam
;
plan
->
subPlan
=
subPlan
;
return
param_list
;
plan
->
subPlan
=
results
.
subplans
;
return
results
.
paramids
;
}
/* Construct a list of all subplans found within the given node tree */
static
bool
SS_pull_subplan_walker
(
Node
*
node
,
List
**
listptr
);
List
*
SS_pull_subplan
(
Node
*
expr
)
{
List
*
result
=
NULL
;
if
(
expr
==
NULL
||
single_node
(
expr
))
return
NULL
;
List
*
result
=
NIL
;
if
(
IsA
(
expr
,
List
))
{
List
*
le
;
SS_pull_subplan_walker
(
expr
,
&
result
);
return
result
;
}
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
((
Node
*
)
((
Expr
*
)
expr
)
->
args
);
else
if
(
IsA
(
expr
,
Aggref
))
return
SS_pull_subplan
(((
Aggref
*
)
expr
)
->
target
);
else
if
(
IsA
(
expr
,
ArrayRef
))
static
bool
SS_pull_subplan_walker
(
Node
*
node
,
List
**
listptr
)
{
if
(
node
==
NULL
)
return
false
;
if
(
is_subplan
(
node
))
{
result
=
SS_pull_subplan
((
Node
*
)
((
ArrayRef
*
)
expr
)
->
refupperindexpr
);
result
=
nconc
(
result
,
SS_pull_subplan
((
Node
*
)
((
ArrayRef
*
)
expr
)
->
reflowerindexpr
));
result
=
nconc
(
result
,
SS_pull_subplan
(((
ArrayRef
*
)
expr
)
->
refexpr
));
result
=
nconc
(
result
,
SS_pull_subplan
(((
ArrayRef
*
)
expr
)
->
refassgnexpr
));
*
listptr
=
lappend
(
*
listptr
,
((
Expr
*
)
node
)
->
oper
);
/* XXX original code did not examine args to subplan, is this right? */
return
false
;
}
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
;
return
expression_tree_walker
(
node
,
SS_pull_subplan_walker
,
(
void
*
)
listptr
);
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录