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