Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit0339047

Browse files
committed
Code review for protransform patches.
Fix loss of previous expression-simplification work when a transformfunction fires: we must not simply revert to untransformed input tree.Instead build a dummy FuncExpr node to pass to the transform function.This has the additional advantage of providing a simpler, more uniformAPI for transform functions.Move documentation to a somewhat less buried spot, relocate somepoorly-placed code, be more wary of null constants and invalid typmodvalues, add an opr_sanity check on protransform function signatures,and some other minor cosmetic adjustments.Note: although this patch touches pg_proc.h, no need for catversionbump, because the changes are cosmetic and don't actually change theintended catalog contents.
1 parente08b410 commit0339047

File tree

15 files changed

+205
-172
lines changed

15 files changed

+205
-172
lines changed

‎doc/src/sgml/catalogs.sgml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4398,7 +4398,8 @@
43984398
<entry><structfield>protransform</structfield></entry>
43994399
<entry><type>regproc</type></entry>
44004400
<entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
4401-
<entry>Calls to function can be simplified by this other function</entry>
4401+
<entry>Calls to this function can be simplified by this other function
4402+
(see <xref linkend="xfunc-transform-functions">)</entry>
44024403
</row>
44034404

44044405
<row>

‎doc/src/sgml/xfunc.sgml

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3177,6 +3177,40 @@ CREATE FUNCTION make_array(anyelement) RETURNS anyarray
31773177
</para>
31783178
</sect2>
31793179

3180+
<sect2 id="xfunc-transform-functions">
3181+
<title>Transform Functions</title>
3182+
3183+
<para>
3184+
Some function calls can be simplified during planning based on
3185+
properties specific to the function. For example,
3186+
<literal>int4mul(n, 1)</> could be simplified to just <literal>n</>.
3187+
To define such function-specific optimizations, write a
3188+
<firstterm>transform function</> and place its OID in the
3189+
<structfield>protransform</> field of the primary function's
3190+
<structname>pg_proc</> entry. The transform function must have the SQL
3191+
signature <literal>protransform(internal) RETURNS internal</>. The
3192+
argument, actually <type>FuncExpr *</>, is a dummy node representing a
3193+
call to the primary function. If the transform function's study of the
3194+
expression tree proves that a simplified expression tree can substitute
3195+
for all possible concrete calls represented thereby, build and return
3196+
that simplified expression. Otherwise, return a <literal>NULL</>
3197+
pointer (<emphasis>not</> a SQL null).
3198+
</para>
3199+
3200+
<para>
3201+
We make no guarantee that <productname>PostgreSQL</> will never call the
3202+
primary function in cases that the transform function could simplify.
3203+
Ensure rigorous equivalence between the simplified expression and an
3204+
actual call to the primary function.
3205+
</para>
3206+
3207+
<para>
3208+
Currently, this facility is not exposed to users at the SQL level
3209+
because of security concerns, so it is only practical to use for
3210+
optimizing built-in functions.
3211+
</para>
3212+
</sect2>
3213+
31803214
<sect2>
31813215
<title>Shared Memory and LWLocks</title>
31823216

‎src/backend/nodes/nodeFuncs.c

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include"catalog/pg_collation.h"
1818
#include"catalog/pg_type.h"
1919
#include"miscadmin.h"
20+
#include"nodes/makefuncs.h"
2021
#include"nodes/nodeFuncs.h"
2122
#include"nodes/relation.h"
2223
#include"utils/builtins.h"
@@ -547,6 +548,30 @@ exprIsLengthCoercion(const Node *expr, int32 *coercedTypmod)
547548
return false;
548549
}
549550

551+
/*
552+
* relabel_to_typmod
553+
*Add a RelabelType node that changes just the typmod of the expression.
554+
*
555+
* This is primarily intended to be used during planning. Therefore, it
556+
* strips any existing RelabelType nodes to maintain the planner's invariant
557+
* that there are not adjacent RelabelTypes, and it uses COERCE_DONTCARE
558+
* which would typically be inappropriate earlier.
559+
*/
560+
Node*
561+
relabel_to_typmod(Node*expr,int32typmod)
562+
{
563+
Oidtype=exprType(expr);
564+
Oidcoll=exprCollation(expr);
565+
566+
/* Strip any existing RelabelType node(s) */
567+
while (expr&&IsA(expr,RelabelType))
568+
expr= (Node*) ((RelabelType*)expr)->arg;
569+
570+
/* Apply new typmod, preserving the previous exposed type and collation */
571+
return (Node*)makeRelabelType((Expr*)expr,type,typmod,coll,
572+
COERCE_DONTCARE);
573+
}
574+
550575
/*
551576
* expression_returns_set
552577
* Test whether an expression returns a set result.
@@ -2694,7 +2719,9 @@ query_or_expression_tree_mutator(Node *node,
26942719
* that could appear under it, but not other statement types.
26952720
*/
26962721
bool
2697-
raw_expression_tree_walker(Node*node,bool (*walker) (),void*context)
2722+
raw_expression_tree_walker(Node*node,
2723+
bool (*walker) (),
2724+
void*context)
26982725
{
26992726
ListCell*temp;
27002727

‎src/backend/optimizer/util/clauses.c

Lines changed: 50 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -107,11 +107,11 @@ static List *simplify_and_arguments(List *args,
107107
eval_const_expressions_context*context,
108108
bool*haveNull,bool*forceFalse);
109109
staticNode*simplify_boolean_equality(Oidopno,List*args);
110-
staticExpr*simplify_function(Expr*oldexpr,Oidfuncid,
111-
Oidresult_type,int32result_typmod,Oidresult_collid,
112-
Oidinput_collid,List**args,
110+
staticExpr*simplify_function(Oidfuncid,
111+
Oidresult_type,int32result_typmod,
112+
Oidresult_collid,Oidinput_collid,List**args,
113113
boolhas_named_args,
114-
boolallow_inline,
114+
boolallow_non_const,
115115
eval_const_expressions_context*context);
116116
staticList*reorder_function_arguments(List*args,Oidresult_type,
117117
HeapTuplefunc_tuple,
@@ -2332,8 +2332,7 @@ eval_const_expressions_mutator(Node *node,
23322332
* length coercion; we want to preserve the typmod in the
23332333
* eventual Const if so.
23342334
*/
2335-
simple=simplify_function((Expr*)expr,
2336-
expr->funcid,
2335+
simple=simplify_function(expr->funcid,
23372336
expr->funcresulttype,
23382337
exprTypmod(node),
23392338
expr->funccollid,
@@ -2389,8 +2388,7 @@ eval_const_expressions_mutator(Node *node,
23892388
* Code for op/func reduction is pretty bulky, so split it out
23902389
* as a separate function.
23912390
*/
2392-
simple=simplify_function((Expr*)expr,
2393-
expr->opfuncid,
2391+
simple=simplify_function(expr->opfuncid,
23942392
expr->opresulttype,-1,
23952393
expr->opcollid,
23962394
expr->inputcollid,
@@ -2491,8 +2489,7 @@ eval_const_expressions_mutator(Node *node,
24912489
* Code for op/func reduction is pretty bulky, so split it
24922490
* out as a separate function.
24932491
*/
2494-
simple=simplify_function((Expr*)expr,
2495-
expr->opfuncid,
2492+
simple=simplify_function(expr->opfuncid,
24962493
expr->opresulttype,-1,
24972494
expr->opcollid,
24982495
expr->inputcollid,
@@ -2698,8 +2695,7 @@ eval_const_expressions_mutator(Node *node,
26982695
getTypeInputInfo(expr->resulttype,
26992696
&infunc,&intypioparam);
27002697

2701-
simple=simplify_function(NULL,
2702-
outfunc,
2698+
simple=simplify_function(outfunc,
27032699
CSTRINGOID,-1,
27042700
InvalidOid,
27052701
InvalidOid,
@@ -2728,8 +2724,7 @@ eval_const_expressions_mutator(Node *node,
27282724
false,
27292725
true));
27302726

2731-
simple=simplify_function(NULL,
2732-
infunc,
2727+
simple=simplify_function(infunc,
27332728
expr->resulttype,-1,
27342729
expr->resultcollid,
27352730
InvalidOid,
@@ -3581,15 +3576,11 @@ simplify_boolean_equality(Oid opno, List *args)
35813576
* Subroutine for eval_const_expressions: try to simplify a function call
35823577
* (which might originally have been an operator; we don't care)
35833578
*
3584-
* Inputs are the original expression (can be NULL), function OID, actual
3585-
* result type OID (which is needed for polymorphic functions), result typmod,
3586-
* result collation, the input collation to use for the function, the
3587-
* pre-simplified argument list, and some flags; also the context data for
3588-
* eval_const_expressions.In common cases, several of the arguments could be
3589-
* derived from the original expression. Sending them separately avoids
3590-
* duplicating NodeTag-specific knowledge, and it's necessary for CoerceViaIO.
3591-
* A NULL original expression disables use of transform functions while
3592-
* retaining all other behaviors.
3579+
* Inputs are the function OID, actual result type OID (which is needed for
3580+
* polymorphic functions), result typmod, result collation,
3581+
* the input collation to use for the function,
3582+
* the pre-simplified argument list, and some flags;
3583+
* also the context data for eval_const_expressions.
35933584
*
35943585
* Returns a simplified expression if successful, or NULL if cannot
35953586
* simplify the function call.
@@ -3601,28 +3592,32 @@ simplify_boolean_equality(Oid opno, List *args)
36013592
* pass-by-reference, and it may get modified even if simplification fails.
36023593
*/
36033594
staticExpr*
3604-
simplify_function(Expr*oldexpr,Oidfuncid,
3605-
Oidresult_type,int32result_typmod,Oidresult_collid,
3606-
Oidinput_collid,List**args,
3595+
simplify_function(Oidfuncid,Oidresult_type,int32result_typmod,
3596+
Oidresult_collid,Oidinput_collid,List**args,
36073597
boolhas_named_args,
3608-
boolallow_inline,
3598+
boolallow_non_const,
36093599
eval_const_expressions_context*context)
36103600
{
36113601
HeapTuplefunc_tuple;
3602+
Form_pg_procfunc_form;
36123603
Expr*newexpr;
3613-
Oidtransform;
36143604

36153605
/*
36163606
* We have three strategies for simplification: execute the function to
36173607
* deliver a constant result, use a transform function to generate a
36183608
* substitute node tree, or expand in-line the body of the function
36193609
* definition (which only works for simple SQL-language functions, but
3620-
* that is a common case).Each needs access to the function's pg_proc
3621-
* tuple, so fetch it just once.
3610+
* that is a common case). Each case needs access to the function's
3611+
* pg_proc tuple, so fetch it just once.
3612+
*
3613+
* Note: the allow_non_const flag suppresses both the second and third
3614+
* strategies; so if !allow_non_const, simplify_function can only return
3615+
* a Const or NULL. Argument-list rewriting happens anyway, though.
36223616
*/
36233617
func_tuple=SearchSysCache1(PROCOID,ObjectIdGetDatum(funcid));
36243618
if (!HeapTupleIsValid(func_tuple))
36253619
elog(ERROR,"cache lookup failed for function %u",funcid);
3620+
func_form= (Form_pg_proc)GETSTRUCT(func_tuple);
36263621

36273622
/*
36283623
* While we have the tuple, reorder named arguments and add default
@@ -3631,48 +3626,38 @@ simplify_function(Expr *oldexpr, Oid funcid,
36313626
if (has_named_args)
36323627
*args=reorder_function_arguments(*args,result_type,func_tuple,
36333628
context);
3634-
elseif (((Form_pg_proc)GETSTRUCT(func_tuple))->pronargs>list_length(*args))
3629+
elseif (func_form->pronargs>list_length(*args))
36353630
*args=add_function_defaults(*args,result_type,func_tuple,context);
36363631

36373632
newexpr=evaluate_function(funcid,result_type,result_typmod,
36383633
result_collid,input_collid,*args,
36393634
func_tuple,context);
36403635

3641-
/*
3642-
* Some functions calls can be simplified at plan time based on properties
3643-
* specific to the function. For example, "varchar(s::varchar(4), 8,
3644-
* true)" simplifies to "s::varchar(4)", and "int4mul(n, 1)" could
3645-
* simplify to "n". To define such function-specific optimizations, write
3646-
* a "transform function" and store its OID in the pg_proc.protransform of
3647-
* the primary function. Give each transform function the signature
3648-
* "protransform(internal) RETURNS internal". The argument, internally an
3649-
* Expr *, is the node representing a call to the primary function. If
3650-
* the transform function's study of that node proves that a simplified
3651-
* Expr substitutes for all possible concrete calls represented thereby,
3652-
* return that simplified Expr. Otherwise, return the NULL pointer.
3653-
*
3654-
* Currently, the specific Expr nodetag can be FuncExpr, OpExpr or
3655-
* DistinctExpr. This list may change in the future. The function should
3656-
* check the nodetag and return the NULL pointer for unexpected inputs.
3657-
*
3658-
* We make no guarantee that PostgreSQL will never call the primary
3659-
* function in cases that the transform function would simplify. Ensure
3660-
* rigorous equivalence between the simplified expression and an actual
3661-
* call to the primary function.
3662-
*
3663-
* Currently, this facility is undocumented and not exposed to users at
3664-
* the SQL level. Core length coercion casts use it to avoid calls
3665-
* guaranteed to return their input unchanged.This in turn allows ALTER
3666-
* TABLE ALTER TYPE to avoid rewriting tables for some typmod changes.In
3667-
* the future, this facility may find other applications, like simplifying
3668-
* x*0, x*1, and x+0.
3669-
*/
3670-
transform= ((Form_pg_proc)GETSTRUCT(func_tuple))->protransform;
3671-
if (!newexpr&&OidIsValid(transform)&&oldexpr)
3672-
newexpr= (Expr*)DatumGetPointer(OidFunctionCall1(transform,
3673-
PointerGetDatum(oldexpr)));
3636+
if (!newexpr&&allow_non_const&&OidIsValid(func_form->protransform))
3637+
{
3638+
/*
3639+
* Build a dummy FuncExpr node containing the simplified arg list. We
3640+
* use this approach to present a uniform interface to the transform
3641+
* function regardless of how the function is actually being invoked.
3642+
*/
3643+
FuncExprfexpr;
3644+
3645+
fexpr.xpr.type=T_FuncExpr;
3646+
fexpr.funcid=funcid;
3647+
fexpr.funcresulttype=result_type;
3648+
fexpr.funcretset=func_form->proretset;
3649+
fexpr.funcformat=COERCE_DONTCARE;
3650+
fexpr.funccollid=result_collid;
3651+
fexpr.inputcollid=input_collid;
3652+
fexpr.args=*args;
3653+
fexpr.location=-1;
3654+
3655+
newexpr= (Expr*)
3656+
DatumGetPointer(OidFunctionCall1(func_form->protransform,
3657+
PointerGetDatum(&fexpr)));
3658+
}
36743659

3675-
if (!newexpr&&allow_inline)
3660+
if (!newexpr&&allow_non_const)
36763661
newexpr=inline_function(funcid,result_type,result_collid,
36773662
input_collid,*args,
36783663
func_tuple,context);

‎src/backend/parser/parse_clause.c

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2271,25 +2271,3 @@ transformFrameOffset(ParseState *pstate, int frameOptions, Node *clause)
22712271

22722272
returnnode;
22732273
}
2274-
2275-
/*
2276-
* relabel_to_typmod
2277-
*Add a RelabelType node that changes just the typmod, and remove all
2278-
*now-superfluous RelabelType nodes beneath it.
2279-
*/
2280-
Node*
2281-
relabel_to_typmod(Node*expr,int32typmod)
2282-
{
2283-
Oidtype=exprType(expr);
2284-
Oidcoll=exprCollation(expr);
2285-
2286-
/*
2287-
* Strip any existing RelabelType, then add one. This is to preserve the
2288-
* invariant of no redundant RelabelTypes.
2289-
*/
2290-
while (IsA(expr,RelabelType))
2291-
expr= (Node*) ((RelabelType*)expr)->arg;
2292-
2293-
return (Node*)makeRelabelType((Expr*)expr,type,typmod,coll,
2294-
COERCE_DONTCARE);
2295-
}

‎src/backend/utils/adt/datetime.c

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
#include"funcapi.h"
2525
#include"miscadmin.h"
2626
#include"nodes/nodeFuncs.h"
27-
#include"parser/parse_clause.h"
2827
#include"utils/builtins.h"
2928
#include"utils/date.h"
3029
#include"utils/datetime.h"
@@ -4153,32 +4152,34 @@ CheckDateTokenTables(void)
41534152
}
41544153

41554154
/*
4156-
* Helper for temporal protransform functions. Types time, timetz, timestamp
4157-
* and timestamptz each have a range of allowed precisions. An unspecified
4158-
* precision is rigorously equivalent to the highest specifiable precision.
4155+
* Common code for temporal protransform functions. Types time, timetz,
4156+
* timestamp and timestamptz each have a range of allowed precisions. An
4157+
* unspecified precision is rigorously equivalent to the highest specifiable
4158+
* precision.
4159+
*
4160+
* Note: timestamp_scale throws an error when the typmod is out of range, but
4161+
* we can't get there from a cast: our typmodin will have caught it already.
41594162
*/
41604163
Node*
41614164
TemporalTransform(int32max_precis,Node*node)
41624165
{
41634166
FuncExpr*expr= (FuncExpr*)node;
4164-
Node*typmod;
41654167
Node*ret=NULL;
4168+
Node*typmod;
41664169

4167-
if (!IsA(expr,FuncExpr))
4168-
returnret;
4170+
Assert(IsA(expr,FuncExpr));
4171+
Assert(list_length(expr->args) >=2);
41694172

4170-
Assert(list_length(expr->args)==2);
4171-
typmod=lsecond(expr->args);
4173+
typmod= (Node*)lsecond(expr->args);
41724174

4173-
if (IsA(typmod,Const))
4175+
if (IsA(typmod,Const)&& !((Const*)typmod)->constisnull)
41744176
{
4175-
Node*source=linitial(expr->args);
4177+
Node*source=(Node*)linitial(expr->args);
41764178
int32old_precis=exprTypmod(source);
41774179
int32new_precis=DatumGetInt32(((Const*)typmod)->constvalue);
41784180

4179-
if (new_precis==-1||
4180-
new_precis==max_precis||
4181-
(old_precis!=-1&&new_precis >=old_precis))
4181+
if (new_precis<0||new_precis==max_precis||
4182+
(old_precis >=0&&new_precis >=old_precis))
41824183
ret=relabel_to_typmod(source,new_precis);
41834184
}
41844185

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp