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
269755ef
Commit
269755ef
authored
Nov 28, 2011
by
Bruce Momjian
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Pgindent clauses.c, per request from Tom.
parent
a04161f2
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
924 additions
and
889 deletions
+924
-889
src/backend/optimizer/util/clauses.c
src/backend/optimizer/util/clauses.c
+924
-889
No files found.
src/backend/optimizer/util/clauses.c
View file @
269755ef
...
...
@@ -2109,982 +2109,1017 @@ eval_const_expressions_mutator(Node *node,
switch
(
nodeTag
(
node
))
{
case
T_Param
:
{
Param
*
param
=
(
Param
*
)
node
;
/* Look to see if we've been given a value for this Param */
if
(
param
->
paramkind
==
PARAM_EXTERN
&&
context
->
boundParams
!=
NULL
&&
param
->
paramid
>
0
&&
param
->
paramid
<=
context
->
boundParams
->
numParams
)
{
ParamExternData
*
prm
=
&
context
->
boundParams
->
params
[
param
->
paramid
-
1
];
if
(
OidIsValid
(
prm
->
ptype
))
{
/* OK to substitute parameter value? */
if
(
context
->
estimate
||
(
prm
->
pflags
&
PARAM_FLAG_CONST
))
Param
*
param
=
(
Param
*
)
node
;
/* Look to see if we've been given a value for this Param */
if
(
param
->
paramkind
==
PARAM_EXTERN
&&
context
->
boundParams
!=
NULL
&&
param
->
paramid
>
0
&&
param
->
paramid
<=
context
->
boundParams
->
numParams
)
{
/*
* Return a Const representing the param value. Must copy
* pass-by-ref datatypes, since the Param might be in a
* memory context shorter-lived than our output plan
* should be.
*/
int16
typLen
;
bool
typByVal
;
Datum
pval
;
Assert
(
prm
->
ptype
==
param
->
paramtype
);
get_typlenbyval
(
param
->
paramtype
,
&
typLen
,
&
typByVal
);
if
(
prm
->
isnull
||
typByVal
)
pval
=
prm
->
value
;
else
pval
=
datumCopy
(
prm
->
value
,
typByVal
,
typLen
);
return
(
Node
*
)
makeConst
(
param
->
paramtype
,
param
->
paramtypmod
,
param
->
paramcollid
,
(
int
)
typLen
,
pval
,
prm
->
isnull
,
typByVal
);
ParamExternData
*
prm
=
&
context
->
boundParams
->
params
[
param
->
paramid
-
1
];
if
(
OidIsValid
(
prm
->
ptype
))
{
/* OK to substitute parameter value? */
if
(
context
->
estimate
||
(
prm
->
pflags
&
PARAM_FLAG_CONST
))
{
/*
* Return a Const representing the param value.
* Must copy pass-by-ref datatypes, since the
* Param might be in a memory context
* shorter-lived than our output plan should be.
*/
int16
typLen
;
bool
typByVal
;
Datum
pval
;
Assert
(
prm
->
ptype
==
param
->
paramtype
);
get_typlenbyval
(
param
->
paramtype
,
&
typLen
,
&
typByVal
);
if
(
prm
->
isnull
||
typByVal
)
pval
=
prm
->
value
;
else
pval
=
datumCopy
(
prm
->
value
,
typByVal
,
typLen
);
return
(
Node
*
)
makeConst
(
param
->
paramtype
,
param
->
paramtypmod
,
param
->
paramcollid
,
(
int
)
typLen
,
pval
,
prm
->
isnull
,
typByVal
);
}
}
}
/*
* Not replaceable, so just copy the Param (no need to
* recurse)
*/
return
(
Node
*
)
copyObject
(
param
);
}
}
/* Not replaceable, so just copy the Param (no need to recurse) */
return
(
Node
*
)
copyObject
(
param
);
}
case
T_FuncExpr
:
{
FuncExpr
*
expr
=
(
FuncExpr
*
)
node
;
List
*
args
;
bool
has_named_args
;
Expr
*
simple
;
FuncExpr
*
newexpr
;
ListCell
*
lc
;
{
FuncExpr
*
expr
=
(
FuncExpr
*
)
node
;
List
*
args
;
bool
has_named_args
;
Expr
*
simple
;
FuncExpr
*
newexpr
;
ListCell
*
lc
;
/*
* Reduce constants in the FuncExpr's arguments, and check to see if
*
there are any named args.
*/
args
=
NIL
;
has_named_args
=
false
;
foreach
(
lc
,
expr
->
args
)
{
Node
*
arg
=
(
Node
*
)
lfirst
(
lc
);
/*
* Reduce constants in the FuncExpr's arguments, and check to
* see if
there are any named args.
*/
args
=
NIL
;
has_named_args
=
false
;
foreach
(
lc
,
expr
->
args
)
{
Node
*
arg
=
(
Node
*
)
lfirst
(
lc
);
arg
=
eval_const_expressions_mutator
(
arg
,
context
);
if
(
IsA
(
arg
,
NamedArgExpr
))
has_named_args
=
true
;
args
=
lappend
(
args
,
arg
);
}
arg
=
eval_const_expressions_mutator
(
arg
,
context
);
if
(
IsA
(
arg
,
NamedArgExpr
))
has_named_args
=
true
;
args
=
lappend
(
args
,
arg
);
}
/*
* Code for op/func reduction is pretty bulky, so split it out as a
* separate function. Note: exprTypmod normally returns -1 for a
* FuncExpr, but not when the node is recognizably a length coercion;
* we want to preserve the typmod in the eventual Const if so.
*/
simple
=
simplify_function
((
Expr
*
)
expr
,
expr
->
funcid
,
expr
->
funcresulttype
,
exprTypmod
(
node
),
expr
->
funccollid
,
expr
->
inputcollid
,
&
args
,
has_named_args
,
true
,
context
);
if
(
simple
)
/* successfully simplified it */
return
(
Node
*
)
simple
;
/*
* Code for op/func reduction is pretty bulky, so split it out
* as a separate function. Note: exprTypmod normally returns
* -1 for a FuncExpr, but not when the node is recognizably a
* length coercion; we want to preserve the typmod in the
* eventual Const if so.
*/
simple
=
simplify_function
((
Expr
*
)
expr
,
expr
->
funcid
,
expr
->
funcresulttype
,
exprTypmod
(
node
),
expr
->
funccollid
,
expr
->
inputcollid
,
&
args
,
has_named_args
,
true
,
context
);
if
(
simple
)
/* successfully simplified it */
return
(
Node
*
)
simple
;
/*
* The expression cannot be simplified any further, so build an
d
* return a replacement FuncExpr node using the possibly-simplified
* arguments. Note that we have also converted the argument list t
o
*
positional notation.
*/
newexpr
=
makeNode
(
FuncExpr
);
newexpr
->
funcid
=
expr
->
funcid
;
newexpr
->
funcresulttype
=
expr
->
funcresulttype
;
newexpr
->
funcretset
=
expr
->
funcretset
;
newexpr
->
funcformat
=
expr
->
funcformat
;
newexpr
->
funccollid
=
expr
->
funccollid
;
newexpr
->
inputcollid
=
expr
->
inputcollid
;
newexpr
->
args
=
args
;
newexpr
->
location
=
expr
->
location
;
return
(
Node
*
)
newexpr
;
}
/*
* The expression cannot be simplified any further, so buil
d
* and return a replacement FuncExpr node using the
* possibly-simplified arguments. Note that we have als
o
* converted the argument list to
positional notation.
*/
newexpr
=
makeNode
(
FuncExpr
);
newexpr
->
funcid
=
expr
->
funcid
;
newexpr
->
funcresulttype
=
expr
->
funcresulttype
;
newexpr
->
funcretset
=
expr
->
funcretset
;
newexpr
->
funcformat
=
expr
->
funcformat
;
newexpr
->
funccollid
=
expr
->
funccollid
;
newexpr
->
inputcollid
=
expr
->
inputcollid
;
newexpr
->
args
=
args
;
newexpr
->
location
=
expr
->
location
;
return
(
Node
*
)
newexpr
;
}
case
T_OpExpr
:
{
OpExpr
*
expr
=
(
OpExpr
*
)
node
;
List
*
args
;
Expr
*
simple
;
OpExpr
*
newexpr
;
{
OpExpr
*
expr
=
(
OpExpr
*
)
node
;
List
*
args
;
Expr
*
simple
;
OpExpr
*
newexpr
;
/*
* Reduce constants in the OpExpr's arguments. We know args is either
* NIL or a List node, so we can call expression_tree_mutator directly
* rather than recursing to self.
*/
args
=
(
List
*
)
expression_tree_mutator
((
Node
*
)
expr
->
args
,
/*
* Reduce constants in the OpExpr's arguments. We know args
* is either NIL or a List node, so we can call
* expression_tree_mutator directly rather than recursing to
* self.
*/
args
=
(
List
*
)
expression_tree_mutator
((
Node
*
)
expr
->
args
,
eval_const_expressions_mutator
,
(
void
*
)
context
);
(
void
*
)
context
);
/*
* Need to get OID of underlying function. Okay to scribble on input
*
to this extent.
*/
set_opfuncid
(
expr
);
/*
* Need to get OID of underlying function. Okay to scribble
* on input
to this extent.
*/
set_opfuncid
(
expr
);
/*
* Code for op/func reduction is pretty bulky, so split it out as a
*
separate function.
*/
simple
=
simplify_function
((
Expr
*
)
expr
,
expr
->
opfuncid
,
expr
->
opresulttype
,
-
1
,
expr
->
opcollid
,
expr
->
inputcollid
,
&
args
,
false
,
true
,
context
);
if
(
simple
)
/* successfully simplified it */
return
(
Node
*
)
simple
;
/*
* Code for op/func reduction is pretty bulky, so split it out
* as a
separate function.
*/
simple
=
simplify_function
((
Expr
*
)
expr
,
expr
->
opfuncid
,
expr
->
opresulttype
,
-
1
,
expr
->
opcollid
,
expr
->
inputcollid
,
&
args
,
false
,
true
,
context
);
if
(
simple
)
/* successfully simplified it */
return
(
Node
*
)
simple
;
/*
* If the operator is boolean equality or inequality, we know how to
* simplify cases involving one constant and one non-constant
*
argument.
*/
if
(
expr
->
opno
==
BooleanEqualOperator
||
expr
->
opno
==
BooleanNotEqualOperator
)
{
simple
=
(
Expr
*
)
simplify_boolean_equality
(
expr
->
opno
,
args
);
if
(
simple
)
/* successfully simplified it */
return
(
Node
*
)
simple
;
}
/*
* If the operator is boolean equality or inequality, we know
* how to simplify cases involving one constant and one
* non-constant
argument.
*/
if
(
expr
->
opno
==
BooleanEqualOperator
||
expr
->
opno
==
BooleanNotEqualOperator
)
{
simple
=
(
Expr
*
)
simplify_boolean_equality
(
expr
->
opno
,
args
);
if
(
simple
)
/* successfully simplified it */
return
(
Node
*
)
simple
;
}
/*
* The expression cannot be simplified any further, so build an
d
* return a replacement OpExpr node using the possibly-simplified
*
arguments.
*/
newexpr
=
makeNode
(
OpExpr
);
newexpr
->
opno
=
expr
->
opno
;
newexpr
->
opfuncid
=
expr
->
opfuncid
;
newexpr
->
opresulttype
=
expr
->
opresulttype
;
newexpr
->
opretset
=
expr
->
opretset
;
newexpr
->
opcollid
=
expr
->
opcollid
;
newexpr
->
inputcollid
=
expr
->
inputcollid
;
newexpr
->
args
=
args
;
newexpr
->
location
=
expr
->
location
;
return
(
Node
*
)
newexpr
;
}
/*
* The expression cannot be simplified any further, so buil
d
* and return a replacement OpExpr node using the
* possibly-simplified
arguments.
*/
newexpr
=
makeNode
(
OpExpr
);
newexpr
->
opno
=
expr
->
opno
;
newexpr
->
opfuncid
=
expr
->
opfuncid
;
newexpr
->
opresulttype
=
expr
->
opresulttype
;
newexpr
->
opretset
=
expr
->
opretset
;
newexpr
->
opcollid
=
expr
->
opcollid
;
newexpr
->
inputcollid
=
expr
->
inputcollid
;
newexpr
->
args
=
args
;
newexpr
->
location
=
expr
->
location
;
return
(
Node
*
)
newexpr
;
}
case
T_DistinctExpr
:
{
DistinctExpr
*
expr
=
(
DistinctExpr
*
)
node
;
List
*
args
;
ListCell
*
arg
;
bool
has_null_input
=
false
;
bool
all_null_input
=
true
;
bool
has_nonconst_input
=
false
;
Expr
*
simple
;
DistinctExpr
*
newexpr
;
{
DistinctExpr
*
expr
=
(
DistinctExpr
*
)
node
;
List
*
args
;
ListCell
*
arg
;
bool
has_null_input
=
false
;
bool
all_null_input
=
true
;
bool
has_nonconst_input
=
false
;
Expr
*
simple
;
DistinctExpr
*
newexpr
;
/*
* Reduce constants in the DistinctExpr's arguments. We know args is
* either NIL or a List node, so we can call expression_tree_mutator
* directly rather than recursing to self.
*/
args
=
(
List
*
)
expression_tree_mutator
((
Node
*
)
expr
->
args
,
/*
* Reduce constants in the DistinctExpr's arguments. We know
* args is either NIL or a List node, so we can call
* expression_tree_mutator directly rather than recursing to
* self.
*/
args
=
(
List
*
)
expression_tree_mutator
((
Node
*
)
expr
->
args
,
eval_const_expressions_mutator
,
(
void
*
)
context
);
(
void
*
)
context
);
/*
* We must do our own check for NULLs because DistinctExpr has
* different results for NULL input than the underlying operator does.
*/
foreach
(
arg
,
args
)
{
if
(
IsA
(
lfirst
(
arg
),
Const
))
{
has_null_input
|=
((
Const
*
)
lfirst
(
arg
))
->
constisnull
;
all_null_input
&=
((
Const
*
)
lfirst
(
arg
))
->
constisnull
;
}
else
has_nonconst_input
=
true
;
}
/*
* We must do our own check for NULLs because DistinctExpr has
* different results for NULL input than the underlying
* operator does.
*/
foreach
(
arg
,
args
)
{
if
(
IsA
(
lfirst
(
arg
),
Const
))
{
has_null_input
|=
((
Const
*
)
lfirst
(
arg
))
->
constisnull
;
all_null_input
&=
((
Const
*
)
lfirst
(
arg
))
->
constisnull
;
}
else
has_nonconst_input
=
true
;
}
/* all constants? then can optimize this out */
if
(
!
has_nonconst_input
)
{
/* all nulls? then not distinct */
if
(
all_null_input
)
return
makeBoolConst
(
false
,
false
);
/* all constants? then can optimize this out */
if
(
!
has_nonconst_input
)
{
/* all nulls? then not distinct */
if
(
all_null_input
)
return
makeBoolConst
(
false
,
false
);
/* one null? then distinct */
if
(
has_null_input
)
return
makeBoolConst
(
true
,
false
);
/* one null? then distinct */
if
(
has_null_input
)
return
makeBoolConst
(
true
,
false
);
/* otherwise try to evaluate the '=' operator */
/* (NOT okay to try to inline it, though!) */
/* otherwise try to evaluate the '=' operator */
/* (NOT okay to try to inline it, though!) */
/*
* Need to get OID of underlying function. Okay to scribble on
* input to this extent.
*/
set_opfuncid
((
OpExpr
*
)
expr
);
/* rely on struct equivalence */
/*
* Need to get OID of underlying function. Okay to
* scribble on input to this extent.
*/
set_opfuncid
((
OpExpr
*
)
expr
);
/* rely on struct
* equivalence */
/*
* Code for op/func reduction is pretty bulky, so split it
* out as a separate function.
*/
simple
=
simplify_function
((
Expr
*
)
expr
,
expr
->
opfuncid
,
expr
->
opresulttype
,
-
1
,
expr
->
opcollid
,
expr
->
inputcollid
,
&
args
,
false
,
false
,
context
);
if
(
simple
)
/* successfully simplified it */
{
/*
* Since the underlying operator is "=", must negate
* its result
*/
Const
*
csimple
=
(
Const
*
)
simple
;
Assert
(
IsA
(
csimple
,
Const
));
csimple
->
constvalue
=
BoolGetDatum
(
!
DatumGetBool
(
csimple
->
constvalue
));
return
(
Node
*
)
csimple
;
}
}
/*
* Code for op/func reduction is pretty bulky, so split it out as
* a separate function.
*/
simple
=
simplify_function
((
Expr
*
)
expr
,
expr
->
opfuncid
,
expr
->
opresulttype
,
-
1
,
expr
->
opcollid
,
expr
->
inputcollid
,
&
args
,
false
,
false
,
context
);
if
(
simple
)
/* successfully simplified it */
{
/*
* Since the underlying operator is "=", must negate its
* result
* The expression cannot be simplified any further, so build
* and return a replacement DistinctExpr node using the
* possibly-simplified arguments.
*/
Const
*
csimple
=
(
Const
*
)
simple
;
Assert
(
IsA
(
csimple
,
Const
));
csimple
->
constvalue
=
BoolGetDatum
(
!
DatumGetBool
(
csimple
->
constvalue
));
return
(
Node
*
)
csimple
;
newexpr
=
makeNode
(
DistinctExpr
);
newexpr
->
opno
=
expr
->
opno
;
newexpr
->
opfuncid
=
expr
->
opfuncid
;
newexpr
->
opresulttype
=
expr
->
opresulttype
;
newexpr
->
opretset
=
expr
->
opretset
;
newexpr
->
opcollid
=
expr
->
opcollid
;
newexpr
->
inputcollid
=
expr
->
inputcollid
;
newexpr
->
args
=
args
;
newexpr
->
location
=
expr
->
location
;
return
(
Node
*
)
newexpr
;
}
}
/*
* The expression cannot be simplified any further, so build and
* return a replacement DistinctExpr node using the
* possibly-simplified arguments.
*/
newexpr
=
makeNode
(
DistinctExpr
);
newexpr
->
opno
=
expr
->
opno
;
newexpr
->
opfuncid
=
expr
->
opfuncid
;
newexpr
->
opresulttype
=
expr
->
opresulttype
;
newexpr
->
opretset
=
expr
->
opretset
;
newexpr
->
opcollid
=
expr
->
opcollid
;
newexpr
->
inputcollid
=
expr
->
inputcollid
;
newexpr
->
args
=
args
;
newexpr
->
location
=
expr
->
location
;
return
(
Node
*
)
newexpr
;
}
case
T_BoolExpr
:
{
BoolExpr
*
expr
=
(
BoolExpr
*
)
node
;
switch
(
expr
->
boolop
)
{
case
OR_EXPR
:
{
List
*
newargs
;
bool
haveNull
=
false
;
bool
forceTrue
=
false
;
{
BoolExpr
*
expr
=
(
BoolExpr
*
)
node
;
newargs
=
simplify_or_arguments
(
expr
->
args
,
context
,
&
haveNull
,
&
forceTrue
);
if
(
forceTrue
)
return
makeBoolConst
(
true
,
false
);
if
(
haveNull
)
newargs
=
lappend
(
newargs
,
makeBoolConst
(
false
,
true
));
/* If all the inputs are FALSE, result is FALSE */
if
(
newargs
==
NIL
)
return
makeBoolConst
(
false
,
false
);
/* If only one nonconst-or-NULL input, it's the result */
if
(
list_length
(
newargs
)
==
1
)
return
(
Node
*
)
linitial
(
newargs
);
/* Else we still need an OR node */
return
(
Node
*
)
make_orclause
(
newargs
);
}
case
AND_EXPR
:
switch
(
expr
->
boolop
)
{
List
*
newargs
;
bool
haveNull
=
false
;
bool
forceFalse
=
false
;
newargs
=
simplify_and_arguments
(
expr
->
args
,
context
,
case
OR_EXPR
:
{
List
*
newargs
;
bool
haveNull
=
false
;
bool
forceTrue
=
false
;
newargs
=
simplify_or_arguments
(
expr
->
args
,
context
,
&
haveNull
,
&
forceTrue
);
if
(
forceTrue
)
return
makeBoolConst
(
true
,
false
);
if
(
haveNull
)
newargs
=
lappend
(
newargs
,
makeBoolConst
(
false
,
true
));
/* If all the inputs are FALSE, result is FALSE */
if
(
newargs
==
NIL
)
return
makeBoolConst
(
false
,
false
);
/*
* If only one nonconst-or-NULL input, it's the
* result
*/
if
(
list_length
(
newargs
)
==
1
)
return
(
Node
*
)
linitial
(
newargs
);
/* Else we still need an OR node */
return
(
Node
*
)
make_orclause
(
newargs
);
}
case
AND_EXPR
:
{
List
*
newargs
;
bool
haveNull
=
false
;
bool
forceFalse
=
false
;
newargs
=
simplify_and_arguments
(
expr
->
args
,
context
,
&
haveNull
,
&
forceFalse
);
if
(
forceFalse
)
return
makeBoolConst
(
false
,
false
);
if
(
haveNull
)
newargs
=
lappend
(
newargs
,
makeBoolConst
(
false
,
true
));
/* If all the inputs are TRUE, result is TRUE */
if
(
newargs
==
NIL
)
return
makeBoolConst
(
true
,
false
);
/* If only one nonconst-or-NULL input, it's the result */
if
(
list_length
(
newargs
)
==
1
)
return
(
Node
*
)
linitial
(
newargs
);
/* Else we still need an AND node */
return
(
Node
*
)
make_andclause
(
newargs
);
}
case
NOT_EXPR
:
{
Node
*
arg
;
Assert
(
list_length
(
expr
->
args
)
==
1
);
arg
=
eval_const_expressions_mutator
(
linitial
(
expr
->
args
),
context
);
/*
* Use negate_clause() to see if we can simplify away the
* NOT.
*/
return
negate_clause
(
arg
);
if
(
forceFalse
)
return
makeBoolConst
(
false
,
false
);
if
(
haveNull
)
newargs
=
lappend
(
newargs
,
makeBoolConst
(
false
,
true
));
/* If all the inputs are TRUE, result is TRUE */
if
(
newargs
==
NIL
)
return
makeBoolConst
(
true
,
false
);
/*
* If only one nonconst-or-NULL input, it's the
* result
*/
if
(
list_length
(
newargs
)
==
1
)
return
(
Node
*
)
linitial
(
newargs
);
/* Else we still need an AND node */
return
(
Node
*
)
make_andclause
(
newargs
);
}
case
NOT_EXPR
:
{
Node
*
arg
;
Assert
(
list_length
(
expr
->
args
)
==
1
);
arg
=
eval_const_expressions_mutator
(
linitial
(
expr
->
args
),
context
);
/*
* Use negate_clause() to see if we can simplify
* away the NOT.
*/
return
negate_clause
(
arg
);
}
default:
elog
(
ERROR
,
"unrecognized boolop: %d"
,
(
int
)
expr
->
boolop
);
break
;
}
default:
elog
(
ERROR
,
"unrecognized boolop: %d"
,
(
int
)
expr
->
boolop
);
break
;
}
break
;
}
}
case
T_SubPlan
:
case
T_AlternativeSubPlan
:
/*
* Return a SubPlan unchanged --- too late to do anything with it.
*
* XXX should we ereport() here instead? Probably this routine should
* never be invoked after SubPlan creation.
*/
return
node
;
/*
* Return a SubPlan unchanged --- too late to do anything with it.
*
* XXX should we ereport() here instead? Probably this routine
* should never be invoked after SubPlan creation.
*/
return
node
;
case
T_RelabelType
:
{
/*
* If we can simplify the input to a constant, then we don't need the
* RelabelType node anymore: just change the type field of the Const
* node. Otherwise, must copy the RelabelType node.
*/
RelabelType
*
relabel
=
(
RelabelType
*
)
node
;
Node
*
arg
;
{
/*
* If we can simplify the input to a constant, then we don't
* need the RelabelType node anymore: just change the type
* field of the Const node. Otherwise, must copy the
* RelabelType node.
*/
RelabelType
*
relabel
=
(
RelabelType
*
)
node
;
Node
*
arg
;
arg
=
eval_const_expressions_mutator
((
Node
*
)
relabel
->
arg
,
context
);
arg
=
eval_const_expressions_mutator
((
Node
*
)
relabel
->
arg
,
context
);
/*
* If we find stacked RelabelTypes (eg, from foo :: int :: oid) we can
*
discard all but the top one.
*/
while
(
arg
&&
IsA
(
arg
,
RelabelType
))
arg
=
(
Node
*
)
((
RelabelType
*
)
arg
)
->
arg
;
/*
* If we find stacked RelabelTypes (eg, from foo :: int ::
* oid) we can
discard all but the top one.
*/
while
(
arg
&&
IsA
(
arg
,
RelabelType
))
arg
=
(
Node
*
)
((
RelabelType
*
)
arg
)
->
arg
;
if
(
arg
&&
IsA
(
arg
,
Const
))
{
Const
*
con
=
(
Const
*
)
arg
;
if
(
arg
&&
IsA
(
arg
,
Const
))
{
Const
*
con
=
(
Const
*
)
arg
;
con
->
consttype
=
relabel
->
resulttype
;
con
->
consttypmod
=
relabel
->
resulttypmod
;
con
->
constcollid
=
relabel
->
resultcollid
;
return
(
Node
*
)
con
;
}
else
{
RelabelType
*
newrelabel
=
makeNode
(
RelabelType
);
newrelabel
->
arg
=
(
Expr
*
)
arg
;
newrelabel
->
resulttype
=
relabel
->
resulttype
;
newrelabel
->
resulttypmod
=
relabel
->
resulttypmod
;
newrelabel
->
resultcollid
=
relabel
->
resultcollid
;
newrelabel
->
relabelformat
=
relabel
->
relabelformat
;
newrelabel
->
location
=
relabel
->
location
;
return
(
Node
*
)
newrelabel
;
}
}
con
->
consttype
=
relabel
->
resulttype
;
con
->
consttypmod
=
relabel
->
resulttypmod
;
con
->
constcollid
=
relabel
->
resultcollid
;
return
(
Node
*
)
con
;
}
else
{
RelabelType
*
newrelabel
=
makeNode
(
RelabelType
);
newrelabel
->
arg
=
(
Expr
*
)
arg
;
newrelabel
->
resulttype
=
relabel
->
resulttype
;
newrelabel
->
resulttypmod
=
relabel
->
resulttypmod
;
newrelabel
->
resultcollid
=
relabel
->
resultcollid
;
newrelabel
->
relabelformat
=
relabel
->
relabelformat
;
newrelabel
->
location
=
relabel
->
location
;
return
(
Node
*
)
newrelabel
;
}
}
case
T_CoerceViaIO
:
{
CoerceViaIO
*
expr
=
(
CoerceViaIO
*
)
node
;
Expr
*
arg
;
List
*
args
;
Oid
outfunc
;
bool
outtypisvarlena
;
Oid
infunc
;
Oid
intypioparam
;
Expr
*
simple
;
CoerceViaIO
*
newexpr
;
{
CoerceViaIO
*
expr
=
(
CoerceViaIO
*
)
node
;
Expr
*
arg
;
List
*
args
;
Oid
outfunc
;
bool
outtypisvarlena
;
Oid
infunc
;
Oid
intypioparam
;
Expr
*
simple
;
CoerceViaIO
*
newexpr
;
/*
* Reduce constants in the CoerceViaIO's argument.
*/
arg
=
(
Expr
*
)
eval_const_expressions_mutator
((
Node
*
)
expr
->
arg
,
context
);
args
=
list_make1
(
arg
);
/*
* Reduce constants in the CoerceViaIO's argument.
*/
arg
=
(
Expr
*
)
eval_const_expressions_mutator
((
Node
*
)
expr
->
arg
,
context
);
args
=
list_make1
(
arg
);
/*
* CoerceViaIO represents calling the source type's output function
* then the result type's input function. So, try to simplify it as
* though it were a stack of two such function calls. First we need
* to know what the functions are.
*
* Note that the coercion functions are assumed not to care about
* input collation, so we just pass InvalidOid for that.
*/
getTypeOutputInfo
(
exprType
((
Node
*
)
arg
),
&
outfunc
,
&
outtypisvarlena
);
getTypeInputInfo
(
expr
->
resulttype
,
&
infunc
,
&
intypioparam
);
simple
=
simplify_function
(
NULL
,
outfunc
,
CSTRINGOID
,
-
1
,
InvalidOid
,
InvalidOid
,
&
args
,
false
,
true
,
context
);
if
(
simple
)
/* successfully simplified output fn */
{
/*
* Input functions may want 1 to 3 arguments. We always supply
* all three, trusting that nothing downstream will complain.
*/
args
=
list_make3
(
simple
,
makeConst
(
OIDOID
,
-
1
,
InvalidOid
,
sizeof
(
Oid
),
ObjectIdGetDatum
(
intypioparam
),
false
,
true
),
/*
* CoerceViaIO represents calling the source type's output
* function then the result type's input function. So, try to
* simplify it as though it were a stack of two such function
* calls. First we need to know what the functions are.
*
* Note that the coercion functions are assumed not to care
* about input collation, so we just pass InvalidOid for that.
*/
getTypeOutputInfo
(
exprType
((
Node
*
)
arg
),
&
outfunc
,
&
outtypisvarlena
);
getTypeInputInfo
(
expr
->
resulttype
,
&
infunc
,
&
intypioparam
);
simple
=
simplify_function
(
NULL
,
outfunc
,
CSTRINGOID
,
-
1
,
InvalidOid
,
InvalidOid
,
&
args
,
false
,
true
,
context
);
if
(
simple
)
/* successfully simplified output fn */
{
/*
* Input functions may want 1 to 3 arguments. We always
* supply all three, trusting that nothing downstream will
* complain.
*/
args
=
list_make3
(
simple
,
makeConst
(
OIDOID
,
-
1
,
InvalidOid
,
sizeof
(
Oid
),
ObjectIdGetDatum
(
intypioparam
),
false
,
true
),
makeConst
(
INT4OID
,
-
1
,
InvalidOid
,
sizeof
(
int32
),
Int32GetDatum
(
-
1
),
false
,
true
));
simple
=
simplify_function
(
NULL
,
infunc
,
expr
->
resulttype
,
-
1
,
expr
->
resultcollid
,
InvalidOid
,
&
args
,
false
,
true
,
context
);
if
(
simple
)
/* successfully simplified input fn */
return
(
Node
*
)
simple
;
}
simple
=
simplify_function
(
NULL
,
infunc
,
expr
->
resulttype
,
-
1
,
expr
->
resultcollid
,
InvalidOid
,
&
args
,
false
,
true
,
context
);
if
(
simple
)
/* successfully simplified input fn */
return
(
Node
*
)
simple
;
}
/*
* The expression cannot be simplified any further, so build an
d
* return a replacement CoerceViaIO node using the possibly-simplified
*
argument.
*/
newexpr
=
makeNode
(
CoerceViaIO
);
newexpr
->
arg
=
arg
;
newexpr
->
resulttype
=
expr
->
resulttype
;
newexpr
->
resultcollid
=
expr
->
resultcollid
;
newexpr
->
coerceformat
=
expr
->
coerceformat
;
newexpr
->
location
=
expr
->
location
;
return
(
Node
*
)
newexpr
;
}
/*
* The expression cannot be simplified any further, so buil
d
* and return a replacement CoerceViaIO node using the
* possibly-simplified
argument.
*/
newexpr
=
makeNode
(
CoerceViaIO
);
newexpr
->
arg
=
arg
;
newexpr
->
resulttype
=
expr
->
resulttype
;
newexpr
->
resultcollid
=
expr
->
resultcollid
;
newexpr
->
coerceformat
=
expr
->
coerceformat
;
newexpr
->
location
=
expr
->
location
;
return
(
Node
*
)
newexpr
;
}
case
T_ArrayCoerceExpr
:
{
ArrayCoerceExpr
*
expr
=
(
ArrayCoerceExpr
*
)
node
;
Expr
*
arg
;
ArrayCoerceExpr
*
newexpr
;
/*
* Reduce constants in the ArrayCoerceExpr's argument, then build a
* new ArrayCoerceExpr.
*/
arg
=
(
Expr
*
)
eval_const_expressions_mutator
((
Node
*
)
expr
->
arg
,
context
);
{
ArrayCoerceExpr
*
expr
=
(
ArrayCoerceExpr
*
)
node
;
Expr
*
arg
;
ArrayCoerceExpr
*
newexpr
;
newexpr
=
makeNode
(
ArrayCoerceExpr
);
newexpr
->
arg
=
arg
;
newexpr
->
elemfuncid
=
expr
->
elemfuncid
;
newexpr
->
resulttype
=
expr
->
resulttype
;
newexpr
->
resulttypmod
=
expr
->
resulttypmod
;
newexpr
->
resultcollid
=
expr
->
resultcollid
;
newexpr
->
isExplicit
=
expr
->
isExplicit
;
newexpr
->
coerceformat
=
expr
->
coerceformat
;
newexpr
->
location
=
expr
->
location
;
/*
* Reduce constants in the ArrayCoerceExpr's argument, then
* build a new ArrayCoerceExpr.
*/
arg
=
(
Expr
*
)
eval_const_expressions_mutator
((
Node
*
)
expr
->
arg
,
context
);
newexpr
=
makeNode
(
ArrayCoerceExpr
);
newexpr
->
arg
=
arg
;
newexpr
->
elemfuncid
=
expr
->
elemfuncid
;
newexpr
->
resulttype
=
expr
->
resulttype
;
newexpr
->
resulttypmod
=
expr
->
resulttypmod
;
newexpr
->
resultcollid
=
expr
->
resultcollid
;
newexpr
->
isExplicit
=
expr
->
isExplicit
;
newexpr
->
coerceformat
=
expr
->
coerceformat
;
newexpr
->
location
=
expr
->
location
;
/*
* If constant argument and it's a binary-coercible or immutable
* conversion, we can simplify it to a constant.
*/
if
(
arg
&&
IsA
(
arg
,
Const
)
&&
(
!
OidIsValid
(
newexpr
->
elemfuncid
)
||
func_volatile
(
newexpr
->
elemfuncid
)
==
PROVOLATILE_IMMUTABLE
))
return
(
Node
*
)
evaluate_expr
((
Expr
*
)
newexpr
,
newexpr
->
resulttype
,
newexpr
->
resulttypmod
,
newexpr
->
resultcollid
);
/* Else we must return the partially-simplified node */
return
(
Node
*
)
newexpr
;
}
case
T_CollateExpr
:
{
/*
* If we can simplify the input to a constant, then we don't need the
* CollateExpr node at all: just change the constcollid field of the
* Const node. Otherwise, replace the CollateExpr with a RelabelType.
* (We do that so as to improve uniformity of expression
* representation and thus simplify comparison of expressions.)
*/
CollateExpr
*
collate
=
(
CollateExpr
*
)
node
;
Node
*
arg
;
/*
* If constant argument and it's a binary-coercible or
* immutable conversion, we can simplify it to a constant.
*/
if
(
arg
&&
IsA
(
arg
,
Const
)
&&
(
!
OidIsValid
(
newexpr
->
elemfuncid
)
||
func_volatile
(
newexpr
->
elemfuncid
)
==
PROVOLATILE_IMMUTABLE
))
return
(
Node
*
)
evaluate_expr
((
Expr
*
)
newexpr
,
newexpr
->
resulttype
,
newexpr
->
resulttypmod
,
newexpr
->
resultcollid
);
/* Else we must return the partially-simplified node */
return
(
Node
*
)
newexpr
;
}
case
T_CollateExpr
:
{
/*
* If we can simplify the input to a constant, then we don't
* need the CollateExpr node at all: just change the
* constcollid field of the Const node. Otherwise, replace
* the CollateExpr with a RelabelType. (We do that so as to
* improve uniformity of expression representation and thus
* simplify comparison of expressions.)
*/
CollateExpr
*
collate
=
(
CollateExpr
*
)
node
;
Node
*
arg
;
arg
=
eval_const_expressions_mutator
((
Node
*
)
collate
->
arg
,
context
);
arg
=
eval_const_expressions_mutator
((
Node
*
)
collate
->
arg
,
context
);
if
(
arg
&&
IsA
(
arg
,
Const
))
{
Const
*
con
=
(
Const
*
)
arg
;
if
(
arg
&&
IsA
(
arg
,
Const
))
{
Const
*
con
=
(
Const
*
)
arg
;
con
->
constcollid
=
collate
->
collOid
;
return
(
Node
*
)
con
;
}
else
if
(
collate
->
collOid
==
exprCollation
(
arg
))
{
/* Don't need a RelabelType either... */
return
arg
;
}
else
{
RelabelType
*
relabel
=
makeNode
(
RelabelType
);
con
->
constcollid
=
collate
->
collOid
;
return
(
Node
*
)
con
;
}
else
if
(
collate
->
collOid
==
exprCollation
(
arg
))
{
/* Don't need a RelabelType either... */
return
arg
;
}
else
{
RelabelType
*
relabel
=
makeNode
(
RelabelType
);
relabel
->
resulttype
=
exprType
(
arg
);
relabel
->
resulttypmod
=
exprTypmod
(
arg
);
relabel
->
resultcollid
=
collate
->
collOid
;
relabel
->
relabelformat
=
COERCE_DONTCARE
;
relabel
->
location
=
collate
->
location
;
relabel
->
resulttype
=
exprType
(
arg
);
relabel
->
resulttypmod
=
exprTypmod
(
arg
);
relabel
->
resultcollid
=
collate
->
collOid
;
relabel
->
relabelformat
=
COERCE_DONTCARE
;
relabel
->
location
=
collate
->
location
;
/* Don't create stacked RelabelTypes */
while
(
arg
&&
IsA
(
arg
,
RelabelType
))
arg
=
(
Node
*
)
((
RelabelType
*
)
arg
)
->
arg
;
relabel
->
arg
=
(
Expr
*
)
arg
;
/* Don't create stacked RelabelTypes */
while
(
arg
&&
IsA
(
arg
,
RelabelType
))
arg
=
(
Node
*
)
((
RelabelType
*
)
arg
)
->
arg
;
relabel
->
arg
=
(
Expr
*
)
arg
;
return
(
Node
*
)
relabel
;
}
}
case
T_CaseExpr
:
{
/*----------
* CASE expressions can be simplified if there are constant
* condition clauses:
* FALSE (or NULL): drop the alternative
* TRUE: drop all remaining alternatives
* If the first non-FALSE alternative is a constant TRUE, we can
* simplify the entire CASE to that alternative's expression.
* If there are no non-FALSE alternatives, we simplify the entire
* CASE to the default result (ELSE result).
*
* If we have a simple-form CASE with constant test expression,
* we substitute the constant value for contained CaseTestExpr
* placeholder nodes, so that we have the opportunity to reduce
* constant test conditions. For example this allows
* CASE 0 WHEN 0 THEN 1 ELSE 1/0 END
* to reduce to 1 rather than drawing a divide-by-0 error. Note
* that when the test expression is constant, we don't have to
* include it in the resulting CASE; for example
* CASE 0 WHEN x THEN y ELSE z END
* is transformed by the parser to
* CASE 0 WHEN CaseTestExpr = x THEN y ELSE z END
* which we can simplify to
* CASE WHEN 0 = x THEN y ELSE z END
* It is not necessary for the executor to evaluate the "arg"
* expression when executing the CASE, since any contained
* CaseTestExprs that might have referred to it will have been
* replaced by the constant.
*----------
*/
CaseExpr
*
caseexpr
=
(
CaseExpr
*
)
node
;
CaseExpr
*
newcase
;
Node
*
save_case_val
;
Node
*
newarg
;
List
*
newargs
;
bool
const_true_cond
;
Node
*
defresult
=
NULL
;
ListCell
*
arg
;
/* Simplify the test expression, if any */
newarg
=
eval_const_expressions_mutator
((
Node
*
)
caseexpr
->
arg
,
context
);
/* Set up for contained CaseTestExpr nodes */
save_case_val
=
context
->
case_val
;
if
(
newarg
&&
IsA
(
newarg
,
Const
))
{
context
->
case_val
=
newarg
;
newarg
=
NULL
;
/* not needed anymore, see comment above */
}
else
context
->
case_val
=
NULL
;
return
(
Node
*
)
relabel
;
}
}
case
T_CaseExpr
:
{
/*----------
* CASE expressions can be simplified if there are constant
* condition clauses:
* FALSE (or NULL): drop the alternative
* TRUE: drop all remaining alternatives
* If the first non-FALSE alternative is a constant TRUE, we can
* simplify the entire CASE to that alternative's expression.
* If there are no non-FALSE alternatives, we simplify the entire
* CASE to the default result (ELSE result).
*
* If we have a simple-form CASE with constant test expression,
* we substitute the constant value for contained CaseTestExpr
* placeholder nodes, so that we have the opportunity to reduce
* constant test conditions. For example this allows
* CASE 0 WHEN 0 THEN 1 ELSE 1/0 END
* to reduce to 1 rather than drawing a divide-by-0 error. Note
* that when the test expression is constant, we don't have to
* include it in the resulting CASE; for example
* CASE 0 WHEN x THEN y ELSE z END
* is transformed by the parser to
* CASE 0 WHEN CaseTestExpr = x THEN y ELSE z END
* which we can simplify to
* CASE WHEN 0 = x THEN y ELSE z END
* It is not necessary for the executor to evaluate the "arg"
* expression when executing the CASE, since any contained
* CaseTestExprs that might have referred to it will have been
* replaced by the constant.
*----------
*/
CaseExpr
*
caseexpr
=
(
CaseExpr
*
)
node
;
CaseExpr
*
newcase
;
Node
*
save_case_val
;
Node
*
newarg
;
List
*
newargs
;
bool
const_true_cond
;
Node
*
defresult
=
NULL
;
ListCell
*
arg
;
/* Simplify the test expression, if any */
newarg
=
eval_const_expressions_mutator
((
Node
*
)
caseexpr
->
arg
,
context
);
/* Set up for contained CaseTestExpr nodes */
save_case_val
=
context
->
case_val
;
if
(
newarg
&&
IsA
(
newarg
,
Const
))
{
context
->
case_val
=
newarg
;
newarg
=
NULL
;
/* not needed anymore, see comment
* above */
}
else
context
->
case_val
=
NULL
;
/* Simplify the WHEN clauses */
newargs
=
NIL
;
const_true_cond
=
false
;
foreach
(
arg
,
caseexpr
->
args
)
{
CaseWhen
*
oldcasewhen
=
(
CaseWhen
*
)
lfirst
(
arg
);
Node
*
casecond
;
Node
*
caseresult
;
/* Simplify the WHEN clauses */
newargs
=
NIL
;
const_true_cond
=
false
;
foreach
(
arg
,
caseexpr
->
args
)
{
CaseWhen
*
oldcasewhen
=
(
CaseWhen
*
)
lfirst
(
arg
);
Node
*
casecond
;
Node
*
caseresult
;
Assert
(
IsA
(
oldcasewhen
,
CaseWhen
));
Assert
(
IsA
(
oldcasewhen
,
CaseWhen
));
/* Simplify this alternative's test condition */
casecond
=
eval_const_expressions_mutator
((
Node
*
)
oldcasewhen
->
expr
,
context
);
/* Simplify this alternative's test condition */
casecond
=
eval_const_expressions_mutator
((
Node
*
)
oldcasewhen
->
expr
,
context
);
/*
* If the test condition is constant FALSE (or NULL), then drop
* this WHEN clause completely, without processing the result.
*/
if
(
casecond
&&
IsA
(
casecond
,
Const
))
{
Const
*
const_input
=
(
Const
*
)
casecond
;
/*
* If the test condition is constant FALSE (or NULL), then
* drop this WHEN clause completely, without processing
* the result.
*/
if
(
casecond
&&
IsA
(
casecond
,
Const
))
{
Const
*
const_input
=
(
Const
*
)
casecond
;
if
(
const_input
->
constisnull
||
!
DatumGetBool
(
const_input
->
constvalue
))
continue
;
/* drop alternative with FALSE
* condition */
/* Else it's constant TRUE */
const_true_cond
=
true
;
}
/* Simplify this alternative's result value */
caseresult
=
eval_const_expressions_mutator
((
Node
*
)
oldcasewhen
->
result
,
context
);
/* If non-constant test condition, emit a new WHEN node */
if
(
!
const_true_cond
)
{
CaseWhen
*
newcasewhen
=
makeNode
(
CaseWhen
);
newcasewhen
->
expr
=
(
Expr
*
)
casecond
;
newcasewhen
->
result
=
(
Expr
*
)
caseresult
;
newcasewhen
->
location
=
oldcasewhen
->
location
;
newargs
=
lappend
(
newargs
,
newcasewhen
);
continue
;
}
if
(
const_input
->
constisnull
||
!
DatumGetBool
(
const_input
->
constvalue
))
continue
;
/* drop alternative with FALSE condition */
/* Else it's constant TRUE */
const_true_cond
=
true
;
}
/*
* Found a TRUE condition, so none of the remaining
* alternatives can be reached. We treat the result as
* the default result.
*/
defresult
=
caseresult
;
break
;
}
/* Simplify this alternative's result value */
caseresult
=
eval_const_expressions_mutator
((
Node
*
)
oldcasewhen
->
result
,
context
);
/* Simplify the default result, unless we replaced it above */
if
(
!
const_true_cond
)
defresult
=
eval_const_expressions_mutator
((
Node
*
)
caseexpr
->
defresult
,
context
);
/* If non-constant test condition, emit a new WHEN node */
if
(
!
const_true_cond
)
{
CaseWhen
*
newcasewhen
=
makeNode
(
CaseWhen
);
context
->
case_val
=
save_case_val
;
newcasewhen
->
expr
=
(
Expr
*
)
casecond
;
newcasewhen
->
result
=
(
Expr
*
)
caseresult
;
newcasewhen
->
location
=
oldcasewhen
->
location
;
newargs
=
lappend
(
newargs
,
newcasewhen
);
continue
;
/*
* If no non-FALSE alternatives, CASE reduces to the default
* result
*/
if
(
newargs
==
NIL
)
return
defresult
;
/* Otherwise we need a new CASE node */
newcase
=
makeNode
(
CaseExpr
);
newcase
->
casetype
=
caseexpr
->
casetype
;
newcase
->
casecollid
=
caseexpr
->
casecollid
;
newcase
->
arg
=
(
Expr
*
)
newarg
;
newcase
->
args
=
newargs
;
newcase
->
defresult
=
(
Expr
*
)
defresult
;
newcase
->
location
=
caseexpr
->
location
;
return
(
Node
*
)
newcase
;
}
/*
* Found a TRUE condition, so none of the remaining alternatives
* can be reached. We treat the result as the default result.
*/
defresult
=
caseresult
;
break
;
}
/* Simplify the default result, unless we replaced it above */
if
(
!
const_true_cond
)
defresult
=
eval_const_expressions_mutator
((
Node
*
)
caseexpr
->
defresult
,
context
);
context
->
case_val
=
save_case_val
;
/* If no non-FALSE alternatives, CASE reduces to the default result */
if
(
newargs
==
NIL
)
return
defresult
;
/* Otherwise we need a new CASE node */
newcase
=
makeNode
(
CaseExpr
);
newcase
->
casetype
=
caseexpr
->
casetype
;
newcase
->
casecollid
=
caseexpr
->
casecollid
;
newcase
->
arg
=
(
Expr
*
)
newarg
;
newcase
->
args
=
newargs
;
newcase
->
defresult
=
(
Expr
*
)
defresult
;
newcase
->
location
=
caseexpr
->
location
;
return
(
Node
*
)
newcase
;
}
case
T_CaseTestExpr
:
{
/*
* If we know a constant test value for the current CASE construct,
* substitute it for the placeholder. Else just return the
*
placeholder as-is.
*/
if
(
context
->
case_val
)
return
copyObject
(
context
->
case_val
);
else
return
copyObject
(
node
);
}
{
/*
* If we know a constant test value for the current CASE
* construct, substitute it for the placeholder. Else just
* return the
placeholder as-is.
*/
if
(
context
->
case_val
)
return
copyObject
(
context
->
case_val
);
else
return
copyObject
(
node
);
}
case
T_ArrayExpr
:
{
ArrayExpr
*
arrayexpr
=
(
ArrayExpr
*
)
node
;
ArrayExpr
*
newarray
;
bool
all_const
=
true
;
List
*
newelems
;
ListCell
*
element
;
newelems
=
NIL
;
foreach
(
element
,
arrayexpr
->
elements
)
{
Node
*
e
;
{
ArrayExpr
*
arrayexpr
=
(
ArrayExpr
*
)
node
;
ArrayExpr
*
newarray
;
bool
all_const
=
true
;
List
*
newelems
;
ListCell
*
element
;
newelems
=
NIL
;
foreach
(
element
,
arrayexpr
->
elements
)
{
Node
*
e
;
e
=
eval_const_expressions_mutator
((
Node
*
)
lfirst
(
element
),
context
);
if
(
!
IsA
(
e
,
Const
))
all_const
=
false
;
newelems
=
lappend
(
newelems
,
e
);
}
e
=
eval_const_expressions_mutator
((
Node
*
)
lfirst
(
element
),
context
);
if
(
!
IsA
(
e
,
Const
))
all_const
=
false
;
newelems
=
lappend
(
newelems
,
e
);
}
newarray
=
makeNode
(
ArrayExpr
);
newarray
->
array_typeid
=
arrayexpr
->
array_typeid
;
newarray
->
array_collid
=
arrayexpr
->
array_collid
;
newarray
->
element_typeid
=
arrayexpr
->
element_typeid
;
newarray
->
elements
=
newelems
;
newarray
->
multidims
=
arrayexpr
->
multidims
;
newarray
->
location
=
arrayexpr
->
location
;
if
(
all_const
)
return
(
Node
*
)
evaluate_expr
((
Expr
*
)
newarray
,
newarray
->
array_typeid
,
exprTypmod
(
node
),
newarray
->
array_collid
);
return
(
Node
*
)
newarray
;
}
newarray
=
makeNode
(
ArrayExpr
);
newarray
->
array_typeid
=
arrayexpr
->
array_typeid
;
newarray
->
array_collid
=
arrayexpr
->
array_collid
;
newarray
->
element_typeid
=
arrayexpr
->
element_typeid
;
newarray
->
elements
=
newelems
;
newarray
->
multidims
=
arrayexpr
->
multidims
;
newarray
->
location
=
arrayexpr
->
location
;
if
(
all_const
)
return
(
Node
*
)
evaluate_expr
((
Expr
*
)
newarray
,
newarray
->
array_typeid
,
exprTypmod
(
node
),
newarray
->
array_collid
);
return
(
Node
*
)
newarray
;
}
case
T_CoalesceExpr
:
{
CoalesceExpr
*
coalesceexpr
=
(
CoalesceExpr
*
)
node
;
CoalesceExpr
*
newcoalesce
;
List
*
newargs
;
ListCell
*
arg
;
{
CoalesceExpr
*
coalesceexpr
=
(
CoalesceExpr
*
)
node
;
CoalesceExpr
*
newcoalesce
;
List
*
newargs
;
ListCell
*
arg
;
newargs
=
NIL
;
foreach
(
arg
,
coalesceexpr
->
args
)
{
Node
*
e
;
newargs
=
NIL
;
foreach
(
arg
,
coalesceexpr
->
args
)
{
Node
*
e
;
e
=
eval_const_expressions_mutator
((
Node
*
)
lfirst
(
arg
),
context
);
e
=
eval_const_expressions_mutator
((
Node
*
)
lfirst
(
arg
),
context
);
/*
* We can remove null constants from the list. For a non-null
* constant, if it has not been preceded by any other
* non-null-constant expressions then it is the result. Otherwise,
* it's the next argument, but we can drop following arguments
* since they will never be reached.
*/
if
(
IsA
(
e
,
Const
))
{
if
(((
Const
*
)
e
)
->
constisnull
)
continue
;
/* drop null constant */
/*
* We can remove null constants from the list. For a
* non-null constant, if it has not been preceded by any
* other non-null-constant expressions then it is the
* result. Otherwise, it's the next argument, but we can
* drop following arguments since they will never be
* reached.
*/
if
(
IsA
(
e
,
Const
))
{
if
(((
Const
*
)
e
)
->
constisnull
)
continue
;
/* drop null constant */
if
(
newargs
==
NIL
)
return
e
;
/* first expr */
newargs
=
lappend
(
newargs
,
e
);
break
;
}
newargs
=
lappend
(
newargs
,
e
);
}
/*
* If all the arguments were constant null, the result is just
* null
*/
if
(
newargs
==
NIL
)
return
e
;
/* first expr */
newargs
=
lappend
(
newargs
,
e
);
break
;
return
(
Node
*
)
makeNullConst
(
coalesceexpr
->
coalescetype
,
-
1
,
coalesceexpr
->
coalescecollid
);
newcoalesce
=
makeNode
(
CoalesceExpr
);
newcoalesce
->
coalescetype
=
coalesceexpr
->
coalescetype
;
newcoalesce
->
coalescecollid
=
coalesceexpr
->
coalescecollid
;
newcoalesce
->
args
=
newargs
;
newcoalesce
->
location
=
coalesceexpr
->
location
;
return
(
Node
*
)
newcoalesce
;
}
newargs
=
lappend
(
newargs
,
e
);
}
/* If all the arguments were constant null, the result is just null */
if
(
newargs
==
NIL
)
return
(
Node
*
)
makeNullConst
(
coalesceexpr
->
coalescetype
,
-
1
,
coalesceexpr
->
coalescecollid
);
newcoalesce
=
makeNode
(
CoalesceExpr
);
newcoalesce
->
coalescetype
=
coalesceexpr
->
coalescetype
;
newcoalesce
->
coalescecollid
=
coalesceexpr
->
coalescecollid
;
newcoalesce
->
args
=
newargs
;
newcoalesce
->
location
=
coalesceexpr
->
location
;
return
(
Node
*
)
newcoalesce
;
}
case
T_FieldSelect
:
{
/*
* We can optimize field selection from a whole-row Var into a simple
* Var. (This case won't be generated directly by the parser, because
* ParseComplexProjection short-circuits it. But it can arise while
* simplifying functions.) Also, we can optimize field selection from
* a RowExpr construct.
*
* We must however check that the declared type of the field is still
* the same as when the FieldSelect was created --- this can change if
* someone did ALTER COLUMN TYPE on the rowtype.
*/
FieldSelect
*
fselect
=
(
FieldSelect
*
)
node
;
FieldSelect
*
newfselect
;
Node
*
arg
;
arg
=
eval_const_expressions_mutator
((
Node
*
)
fselect
->
arg
,
context
);
if
(
arg
&&
IsA
(
arg
,
Var
)
&&
((
Var
*
)
arg
)
->
varattno
==
InvalidAttrNumber
)
{
if
(
rowtype_field_matches
(((
Var
*
)
arg
)
->
vartype
,
fselect
->
fieldnum
,
fselect
->
resulttype
,
fselect
->
resulttypmod
,
fselect
->
resultcollid
))
return
(
Node
*
)
makeVar
(((
Var
*
)
arg
)
->
varno
,
fselect
->
fieldnum
,
fselect
->
resulttype
,
fselect
->
resulttypmod
,
fselect
->
resultcollid
,
((
Var
*
)
arg
)
->
varlevelsup
);
}
if
(
arg
&&
IsA
(
arg
,
RowExpr
))
{
RowExpr
*
rowexpr
=
(
RowExpr
*
)
arg
;
if
(
fselect
->
fieldnum
>
0
&&
fselect
->
fieldnum
<=
list_length
(
rowexpr
->
args
))
{
Node
*
fld
=
(
Node
*
)
list_nth
(
rowexpr
->
args
,
fselect
->
fieldnum
-
1
);
if
(
rowtype_field_matches
(
rowexpr
->
row_typeid
,
fselect
->
fieldnum
,
fselect
->
resulttype
,
fselect
->
resulttypmod
,
fselect
->
resultcollid
)
&&
fselect
->
resulttype
==
exprType
(
fld
)
&&
fselect
->
resulttypmod
==
exprTypmod
(
fld
)
&&
fselect
->
resultcollid
==
exprCollation
(
fld
))
return
fld
;
/*
* We can optimize field selection from a whole-row Var into a
* simple Var. (This case won't be generated directly by the
* parser, because ParseComplexProjection short-circuits it.
* But it can arise while simplifying functions.) Also, we
* can optimize field selection from a RowExpr construct.
*
* We must however check that the declared type of the field
* is still the same as when the FieldSelect was created ---
* this can change if someone did ALTER COLUMN TYPE on the
* rowtype.
*/
FieldSelect
*
fselect
=
(
FieldSelect
*
)
node
;
FieldSelect
*
newfselect
;
Node
*
arg
;
arg
=
eval_const_expressions_mutator
((
Node
*
)
fselect
->
arg
,
context
);
if
(
arg
&&
IsA
(
arg
,
Var
)
&&
((
Var
*
)
arg
)
->
varattno
==
InvalidAttrNumber
)
{
if
(
rowtype_field_matches
(((
Var
*
)
arg
)
->
vartype
,
fselect
->
fieldnum
,
fselect
->
resulttype
,
fselect
->
resulttypmod
,
fselect
->
resultcollid
))
return
(
Node
*
)
makeVar
(((
Var
*
)
arg
)
->
varno
,
fselect
->
fieldnum
,
fselect
->
resulttype
,
fselect
->
resulttypmod
,
fselect
->
resultcollid
,
((
Var
*
)
arg
)
->
varlevelsup
);
}
if
(
arg
&&
IsA
(
arg
,
RowExpr
))
{
RowExpr
*
rowexpr
=
(
RowExpr
*
)
arg
;
if
(
fselect
->
fieldnum
>
0
&&
fselect
->
fieldnum
<=
list_length
(
rowexpr
->
args
))
{
Node
*
fld
=
(
Node
*
)
list_nth
(
rowexpr
->
args
,
fselect
->
fieldnum
-
1
);
if
(
rowtype_field_matches
(
rowexpr
->
row_typeid
,
fselect
->
fieldnum
,
fselect
->
resulttype
,
fselect
->
resulttypmod
,
fselect
->
resultcollid
)
&&
fselect
->
resulttype
==
exprType
(
fld
)
&&
fselect
->
resulttypmod
==
exprTypmod
(
fld
)
&&
fselect
->
resultcollid
==
exprCollation
(
fld
))
return
fld
;
}
}
newfselect
=
makeNode
(
FieldSelect
);
newfselect
->
arg
=
(
Expr
*
)
arg
;
newfselect
->
fieldnum
=
fselect
->
fieldnum
;
newfselect
->
resulttype
=
fselect
->
resulttype
;
newfselect
->
resulttypmod
=
fselect
->
resulttypmod
;
newfselect
->
resultcollid
=
fselect
->
resultcollid
;
return
(
Node
*
)
newfselect
;
}
}
newfselect
=
makeNode
(
FieldSelect
);
newfselect
->
arg
=
(
Expr
*
)
arg
;
newfselect
->
fieldnum
=
fselect
->
fieldnum
;
newfselect
->
resulttype
=
fselect
->
resulttype
;
newfselect
->
resulttypmod
=
fselect
->
resulttypmod
;
newfselect
->
resultcollid
=
fselect
->
resultcollid
;
return
(
Node
*
)
newfselect
;
}
case
T_NullTest
:
{
NullTest
*
ntest
=
(
NullTest
*
)
node
;
NullTest
*
newntest
;
Node
*
arg
;
arg
=
eval_const_expressions_mutator
((
Node
*
)
ntest
->
arg
,
context
);
if
(
arg
&&
IsA
(
arg
,
RowExpr
))
{
/*
* We break ROW(...) IS [NOT] NULL into separate tests on its
* component fields. This form is usually more efficient to
* evaluate, as well as being more amenable to optimization.
*/
RowExpr
*
rarg
=
(
RowExpr
*
)
arg
;
List
*
newargs
=
NIL
;
ListCell
*
l
;
Assert
(
ntest
->
argisrow
);
foreach
(
l
,
rarg
->
args
)
{
Node
*
relem
=
(
Node
*
)
lfirst
(
l
);
NullTest
*
ntest
=
(
NullTest
*
)
node
;
NullTest
*
newntest
;
Node
*
arg
;
/*
* A constant field refutes the whole NullTest if it's of the
* wrong nullness; else we can discard it.
*/
if
(
relem
&&
IsA
(
relem
,
Const
))
arg
=
eval_const_expressions_mutator
((
Node
*
)
ntest
->
arg
,
context
);
if
(
arg
&&
IsA
(
arg
,
RowExpr
))
{
Const
*
carg
=
(
Const
*
)
relem
;
if
(
carg
->
constisnull
?
(
ntest
->
nulltesttype
==
IS_NOT_NULL
)
:
(
ntest
->
nulltesttype
==
IS_NULL
))
return
makeBoolConst
(
false
,
false
);
continue
;
/*
* We break ROW(...) IS [NOT] NULL into separate tests on
* its component fields. This form is usually more
* efficient to evaluate, as well as being more amenable
* to optimization.
*/
RowExpr
*
rarg
=
(
RowExpr
*
)
arg
;
List
*
newargs
=
NIL
;
ListCell
*
l
;
Assert
(
ntest
->
argisrow
);
foreach
(
l
,
rarg
->
args
)
{
Node
*
relem
=
(
Node
*
)
lfirst
(
l
);
/*
* A constant field refutes the whole NullTest if it's
* of the wrong nullness; else we can discard it.
*/
if
(
relem
&&
IsA
(
relem
,
Const
))
{
Const
*
carg
=
(
Const
*
)
relem
;
if
(
carg
->
constisnull
?
(
ntest
->
nulltesttype
==
IS_NOT_NULL
)
:
(
ntest
->
nulltesttype
==
IS_NULL
))
return
makeBoolConst
(
false
,
false
);
continue
;
}
newntest
=
makeNode
(
NullTest
);
newntest
->
arg
=
(
Expr
*
)
relem
;
newntest
->
nulltesttype
=
ntest
->
nulltesttype
;
newntest
->
argisrow
=
type_is_rowtype
(
exprType
(
relem
));
newargs
=
lappend
(
newargs
,
newntest
);
}
/* If all the inputs were constants, result is TRUE */
if
(
newargs
==
NIL
)
return
makeBoolConst
(
true
,
false
);
/* If only one nonconst input, it's the result */
if
(
list_length
(
newargs
)
==
1
)
return
(
Node
*
)
linitial
(
newargs
);
/* Else we need an AND node */
return
(
Node
*
)
make_andclause
(
newargs
);
}
if
(
!
ntest
->
argisrow
&&
arg
&&
IsA
(
arg
,
Const
))
{
Const
*
carg
=
(
Const
*
)
arg
;
bool
result
;
switch
(
ntest
->
nulltesttype
)
{
case
IS_NULL
:
result
=
carg
->
constisnull
;
break
;
case
IS_NOT_NULL
:
result
=
!
carg
->
constisnull
;
break
;
default:
elog
(
ERROR
,
"unrecognized nulltesttype: %d"
,
(
int
)
ntest
->
nulltesttype
);
result
=
false
;
/* keep compiler quiet */
break
;
}
return
makeBoolConst
(
result
,
false
);
}
newntest
=
makeNode
(
NullTest
);
newntest
->
arg
=
(
Expr
*
)
relem
;
newntest
->
arg
=
(
Expr
*
)
arg
;
newntest
->
nulltesttype
=
ntest
->
nulltesttype
;
newntest
->
argisrow
=
type_is_rowtype
(
exprType
(
relem
))
;
newargs
=
lappend
(
newargs
,
newntest
)
;
newntest
->
argisrow
=
ntest
->
argisrow
;
return
(
Node
*
)
newntest
;
}
/* If all the inputs were constants, result is TRUE */
if
(
newargs
==
NIL
)
return
makeBoolConst
(
true
,
false
);
/* If only one nonconst input, it's the result */
if
(
list_length
(
newargs
)
==
1
)
return
(
Node
*
)
linitial
(
newargs
);
/* Else we need an AND node */
return
(
Node
*
)
make_andclause
(
newargs
);
}
if
(
!
ntest
->
argisrow
&&
arg
&&
IsA
(
arg
,
Const
))
{
Const
*
carg
=
(
Const
*
)
arg
;
bool
result
;
switch
(
ntest
->
nulltesttype
)
{
case
IS_NULL
:
result
=
carg
->
constisnull
;
break
;
case
IS_NOT_NULL
:
result
=
!
carg
->
constisnull
;
break
;
default:
elog
(
ERROR
,
"unrecognized nulltesttype: %d"
,
(
int
)
ntest
->
nulltesttype
);
result
=
false
;
/* keep compiler quiet */
break
;
}
return
makeBoolConst
(
result
,
false
);
}
newntest
=
makeNode
(
NullTest
);
newntest
->
arg
=
(
Expr
*
)
arg
;
newntest
->
nulltesttype
=
ntest
->
nulltesttype
;
newntest
->
argisrow
=
ntest
->
argisrow
;
return
(
Node
*
)
newntest
;
}
case
T_BooleanTest
:
{
BooleanTest
*
btest
=
(
BooleanTest
*
)
node
;
BooleanTest
*
newbtest
;
Node
*
arg
;
arg
=
eval_const_expressions_mutator
((
Node
*
)
btest
->
arg
,
context
);
if
(
arg
&&
IsA
(
arg
,
Const
))
{
Const
*
carg
=
(
Const
*
)
arg
;
bool
result
;
switch
(
btest
->
booltesttype
)
{
case
IS_TRUE
:
result
=
(
!
carg
->
constisnull
&&
DatumGetBool
(
carg
->
constvalue
));
break
;
case
IS_NOT_TRUE
:
result
=
(
carg
->
constisnull
||
!
DatumGetBool
(
carg
->
constvalue
));
break
;
case
IS_FALSE
:
result
=
(
!
carg
->
constisnull
&&
!
DatumGetBool
(
carg
->
constvalue
));
break
;
case
IS_NOT_FALSE
:
result
=
(
carg
->
constisnull
||
DatumGetBool
(
carg
->
constvalue
));
break
;
case
IS_UNKNOWN
:
result
=
carg
->
constisnull
;
break
;
case
IS_NOT_UNKNOWN
:
result
=
!
carg
->
constisnull
;
break
;
default:
elog
(
ERROR
,
"unrecognized booltesttype: %d"
,
(
int
)
btest
->
booltesttype
);
result
=
false
;
/* keep compiler quiet */
break
;
}
BooleanTest
*
btest
=
(
BooleanTest
*
)
node
;
BooleanTest
*
newbtest
;
Node
*
arg
;
return
makeBoolConst
(
result
,
false
);
}
arg
=
eval_const_expressions_mutator
((
Node
*
)
btest
->
arg
,
context
);
if
(
arg
&&
IsA
(
arg
,
Const
))
{
Const
*
carg
=
(
Const
*
)
arg
;
bool
result
;
switch
(
btest
->
booltesttype
)
{
case
IS_TRUE
:
result
=
(
!
carg
->
constisnull
&&
DatumGetBool
(
carg
->
constvalue
));
break
;
case
IS_NOT_TRUE
:
result
=
(
carg
->
constisnull
||
!
DatumGetBool
(
carg
->
constvalue
));
break
;
case
IS_FALSE
:
result
=
(
!
carg
->
constisnull
&&
!
DatumGetBool
(
carg
->
constvalue
));
break
;
case
IS_NOT_FALSE
:
result
=
(
carg
->
constisnull
||
DatumGetBool
(
carg
->
constvalue
));
break
;
case
IS_UNKNOWN
:
result
=
carg
->
constisnull
;
break
;
case
IS_NOT_UNKNOWN
:
result
=
!
carg
->
constisnull
;
break
;
default:
elog
(
ERROR
,
"unrecognized booltesttype: %d"
,
(
int
)
btest
->
booltesttype
);
result
=
false
;
/* keep compiler quiet */
break
;
}
return
makeBoolConst
(
result
,
false
);
}
newbtest
=
makeNode
(
BooleanTest
);
newbtest
->
arg
=
(
Expr
*
)
arg
;
newbtest
->
booltesttype
=
btest
->
booltesttype
;
return
(
Node
*
)
newbtest
;
}
newbtest
=
makeNode
(
BooleanTest
);
newbtest
->
arg
=
(
Expr
*
)
arg
;
newbtest
->
booltesttype
=
btest
->
booltesttype
;
return
(
Node
*
)
newbtest
;
}
case
T_PlaceHolderVar
:
/*
* In estimation mode, just strip the PlaceHolderVar node altogether;
* this amounts to estimating that the contained value won't be forced
* to null by an outer join. In regular mode we just use the default
* behavior (ie, simplify the expression but leave the PlaceHolderVar
* node intact).
*/
/*
* In estimation mode, just strip the PlaceHolderVar node
* altogether; this amounts to estimating that the contained value
* won't be forced to null by an outer join. In regular mode we
* just use the default behavior (ie, simplify the expression but
* leave the PlaceHolderVar node intact).
*/
if
(
context
->
estimate
)
{
PlaceHolderVar
*
phv
=
(
PlaceHolderVar
*
)
node
;
...
...
@@ -3392,7 +3427,7 @@ simplify_boolean_equality(Oid opno, List *args)
* result type OID (which is needed for polymorphic functions), result typmod,
* result collation, the input collation to use for the function, the
* pre-simplified argument list, and some flags; also the context data for
* eval_const_expressions.
In common cases, several of the arguments could be
* eval_const_expressions.
In common cases, several of the arguments could be
* derived from the original expression. Sending them separately avoids
* duplicating NodeTag-specific knowledge, and it's necessary for CoerceViaIO.
* A NULL original expression disables use of transform functions while
...
...
@@ -3424,7 +3459,7 @@ simplify_function(Expr *oldexpr, Oid funcid,
* deliver a constant result, use a transform function to generate a
* substitute node tree, or expand in-line the body of the function
* definition (which only works for simple SQL-language functions, but
* that is a common case).
Each needs access to the function's pg_proc
* that is a common case).
Each needs access to the function's pg_proc
* tuple, so fetch it just once.
*/
func_tuple
=
SearchSysCache1
(
PROCOID
,
ObjectIdGetDatum
(
funcid
));
...
...
@@ -3469,15 +3504,15 @@ simplify_function(Expr *oldexpr, Oid funcid,
*
* Currently, this facility is undocumented and not exposed to users at
* the SQL level. Core length coercion casts use it to avoid calls
* guaranteed to return their input unchanged.
This in turn allows ALTER
* TABLE ALTER TYPE to avoid rewriting tables for some typmod changes.
In
* guaranteed to return their input unchanged.
This in turn allows ALTER
* TABLE ALTER TYPE to avoid rewriting tables for some typmod changes.
In
* the future, this facility may find other applications, like simplifying
* x*0, x*1, and x+0.
*/
transform
=
((
Form_pg_proc
)
GETSTRUCT
(
func_tuple
))
->
protransform
;
if
(
!
newexpr
&&
OidIsValid
(
transform
)
&&
oldexpr
)
newexpr
=
(
Expr
*
)
DatumGetPointer
(
OidFunctionCall1
(
transform
,
PointerGetDatum
(
oldexpr
)));
PointerGetDatum
(
oldexpr
)));
if
(
!
newexpr
&&
allow_inline
)
newexpr
=
inline_function
(
funcid
,
result_type
,
result_collid
,
...
...
@@ -4523,7 +4558,7 @@ inline_set_returning_function(PlannerInfo *root, RangeTblEntry *rte)
* If it returns RECORD, we have to check against the column type list
* provided in the RTE; check_sql_fn_retval can't do that. (If no match,
* we just fail to inline, rather than complaining; see notes for
* tlist_matches_coltypelist.)
We don't have to do this for functions
* tlist_matches_coltypelist.)
We don't have to do this for functions
* with declared OUT parameters, even though their funcresulttype is
* RECORDOID, so check get_func_result_type too.
*/
...
...
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