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

Commit8f9fe6e

Browse files
committed
Add notion of a "transform function" that can simplify function calls.
Initially, we use this only to eliminate calls to the varchar()function in cases where the length is not being reduced and, therefore,the function call is equivalent to a RelabelType operation. The mostsignificant effect of this is that we can avoid a table rewrite whenchanging a varchar(X) column to a varchar(Y) column, where Y > X.Noah Misch, reviewed by me and Alexey Klyukin
1 parent771a9f6 commit8f9fe6e

File tree

11 files changed

+2428
-2307
lines changed

11 files changed

+2428
-2307
lines changed

‎doc/src/sgml/catalogs.sgml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4337,6 +4337,13 @@
43374337
or zero if the function does not have a variadic parameter</entry>
43384338
</row>
43394339

4340+
<row>
4341+
<entry><structfield>protransform</structfield></entry>
4342+
<entry><type>regproc</type></entry>
4343+
<entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
4344+
<entry>Calls to function can be simplified by this other function</entry>
4345+
</row>
4346+
43404347
<row>
43414348
<entry><structfield>proisagg</structfield></entry>
43424349
<entry><type>bool</type></entry>

‎src/backend/catalog/pg_proc.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,7 @@ ProcedureCreate(const char *procedureName,
304304
values[Anum_pg_proc_procost-1]=Float4GetDatum(procost);
305305
values[Anum_pg_proc_prorows-1]=Float4GetDatum(prorows);
306306
values[Anum_pg_proc_provariadic-1]=ObjectIdGetDatum(variadicType);
307+
values[Anum_pg_proc_protransform-1]=ObjectIdGetDatum(InvalidOid);
307308
values[Anum_pg_proc_proisagg-1]=BoolGetDatum(isAgg);
308309
values[Anum_pg_proc_proiswindow-1]=BoolGetDatum(isWindowFunc);
309310
values[Anum_pg_proc_prosecdef-1]=BoolGetDatum(security_definer);

‎src/backend/commands/tablecmds.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
#include"nodes/nodeFuncs.h"
5757
#include"nodes/parsenodes.h"
5858
#include"optimizer/clauses.h"
59+
#include"optimizer/planner.h"
5960
#include"parser/parse_clause.h"
6061
#include"parser/parse_coerce.h"
6162
#include"parser/parse_collate.h"
@@ -3495,7 +3496,8 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap, LOCKMODE lockmode)
34953496
{
34963497
NewColumnValue*ex=lfirst(l);
34973498

3498-
ex->exprstate=ExecPrepareExpr((Expr*)ex->expr,estate);
3499+
/* expr already planned */
3500+
ex->exprstate=ExecInitExpr((Expr*)ex->expr,NULL);
34993501
}
35003502

35013503
notnull_attrs=NIL;
@@ -4398,7 +4400,7 @@ ATExecAddColumn(List **wqueue, AlteredTableInfo *tab, Relation rel,
43984400

43994401
newval= (NewColumnValue*)palloc0(sizeof(NewColumnValue));
44004402
newval->attnum=attribute.attnum;
4401-
newval->expr=defval;
4403+
newval->expr=expression_planner(defval);
44024404

44034405
tab->newvals=lappend(tab->newvals,newval);
44044406
tab->rewrite= true;
@@ -6707,6 +6709,9 @@ ATPrepAlterColumnType(List **wqueue,
67076709
/* Fix collations after all else */
67086710
assign_expr_collations(pstate,transform);
67096711

6712+
/* Plan the expr now so we can accurately assess the need to rewrite. */
6713+
transform= (Node*)expression_planner((Expr*)transform);
6714+
67106715
/*
67116716
* Add a work queue item to make ATRewriteTable update the column
67126717
* contents.

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

Lines changed: 66 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -106,9 +106,9 @@ static List *simplify_and_arguments(List *args,
106106
eval_const_expressions_context*context,
107107
bool*haveNull,bool*forceFalse);
108108
staticNode*simplify_boolean_equality(Oidopno,List*args);
109-
staticExpr*simplify_function(Oidfuncid,
110-
Oidresult_type,int32result_typmod,
111-
Oidresult_collid,Oidinput_collid,List**args,
109+
staticExpr*simplify_function(Expr*oldexpr,Oidfuncid,
110+
Oidresult_type,int32result_typmod,Oidresult_collid,
111+
Oidinput_collid,List**args,
112112
boolhas_named_args,
113113
boolallow_inline,
114114
eval_const_expressions_context*context);
@@ -2223,7 +2223,8 @@ eval_const_expressions_mutator(Node *node,
22232223
* FuncExpr, but not when the node is recognizably a length coercion;
22242224
* we want to preserve the typmod in the eventual Const if so.
22252225
*/
2226-
simple=simplify_function(expr->funcid,
2226+
simple=simplify_function((Expr*)expr,
2227+
expr->funcid,
22272228
expr->funcresulttype,exprTypmod(node),
22282229
expr->funccollid,
22292230
expr->inputcollid,
@@ -2275,7 +2276,8 @@ eval_const_expressions_mutator(Node *node,
22752276
* Code for op/func reduction is pretty bulky, so split it out as a
22762277
* separate function.
22772278
*/
2278-
simple=simplify_function(expr->opfuncid,
2279+
simple=simplify_function((Expr*)expr,
2280+
expr->opfuncid,
22792281
expr->opresulttype,-1,
22802282
expr->opcollid,
22812283
expr->inputcollid,
@@ -2372,7 +2374,8 @@ eval_const_expressions_mutator(Node *node,
23722374
* Code for op/func reduction is pretty bulky, so split it out as
23732375
* a separate function.
23742376
*/
2375-
simple=simplify_function(expr->opfuncid,
2377+
simple=simplify_function((Expr*)expr,
2378+
expr->opfuncid,
23762379
expr->opresulttype,-1,
23772380
expr->opcollid,
23782381
expr->inputcollid,
@@ -2561,7 +2564,8 @@ eval_const_expressions_mutator(Node *node,
25612564
getTypeOutputInfo(exprType((Node*)arg),&outfunc,&outtypisvarlena);
25622565
getTypeInputInfo(expr->resulttype,&infunc,&intypioparam);
25632566

2564-
simple=simplify_function(outfunc,
2567+
simple=simplify_function(NULL,
2568+
outfunc,
25652569
CSTRINGOID,-1,
25662570
InvalidOid,
25672571
InvalidOid,
@@ -2581,7 +2585,8 @@ eval_const_expressions_mutator(Node *node,
25812585
Int32GetDatum(-1),
25822586
false, true));
25832587

2584-
simple=simplify_function(infunc,
2588+
simple=simplify_function(NULL,
2589+
infunc,
25852590
expr->resulttype,-1,
25862591
expr->resultcollid,
25872592
InvalidOid,
@@ -3417,11 +3422,15 @@ simplify_boolean_equality(Oid opno, List *args)
34173422
* Subroutine for eval_const_expressions: try to simplify a function call
34183423
* (which might originally have been an operator; we don't care)
34193424
*
3420-
* Inputs are the function OID, actual result type OID (which is needed for
3421-
* polymorphic functions), result typmod, result collation,
3422-
* the input collation to use for the function,
3423-
* the pre-simplified argument list, and some flags;
3424-
* also the context data for eval_const_expressions.
3425+
* Inputs are the original expression (can be NULL), function OID, actual
3426+
* result type OID (which is needed for polymorphic functions), result typmod,
3427+
* result collation, the input collation to use for the function, the
3428+
* pre-simplified argument list, and some flags; also the context data for
3429+
* eval_const_expressions. In common cases, several of the arguments could be
3430+
* derived from the original expression. Sending them separately avoids
3431+
* duplicating NodeTag-specific knowledge, and it's necessary for CoerceViaIO.
3432+
* A NULL original expression disables use of transform functions while
3433+
* retaining all other behaviors.
34253434
*
34263435
* Returns a simplified expression if successful, or NULL if cannot
34273436
* simplify the function call.
@@ -3433,22 +3442,24 @@ simplify_boolean_equality(Oid opno, List *args)
34333442
* pass-by-reference, and it may get modified even if simplification fails.
34343443
*/
34353444
staticExpr*
3436-
simplify_function(Oidfuncid,Oidresult_type,int32result_typmod,
3437-
Oidresult_collid,Oidinput_collid,List**args,
3445+
simplify_function(Expr*oldexpr,Oidfuncid,
3446+
Oidresult_type,int32result_typmod,Oidresult_collid,
3447+
Oidinput_collid,List**args,
34383448
boolhas_named_args,
34393449
boolallow_inline,
34403450
eval_const_expressions_context*context)
34413451
{
34423452
HeapTuplefunc_tuple;
34433453
Expr*newexpr;
3454+
Oidtransform;
34443455

34453456
/*
3446-
* We havetwo strategies for simplification:eitherexecute the function
3447-
*todeliver a constant result,or expand in-line the body of the
3448-
*function definition (which only works for simple SQL-language
3449-
*functions, but that is a common case). In either case we need access
3450-
*to the function's pg_proc tuple, so fetch it just oncetouse in both
3451-
*attempts.
3457+
* We havethree strategies for simplification: execute the function to
3458+
* deliver a constant result,use a transform function to generate a
3459+
*substitute node tree, or expand in-line the body of the function
3460+
*definition (which only works for simple SQL-language functions, but
3461+
*that is a common case). Each needs accesstothe function's pg_proc
3462+
*tuple, so fetch it just once.
34523463
*/
34533464
func_tuple=SearchSysCache1(PROCOID,ObjectIdGetDatum(funcid));
34543465
if (!HeapTupleIsValid(func_tuple))
@@ -3468,6 +3479,40 @@ simplify_function(Oid funcid, Oid result_type, int32 result_typmod,
34683479
result_collid,input_collid,*args,
34693480
func_tuple,context);
34703481

3482+
/*
3483+
* Some functions calls can be simplified at plan time based on properties
3484+
* specific to the function. For example, "varchar(s::varchar(4), 8,
3485+
* true)" simplifies to "s::varchar(4)", and "int4mul(n, 1)" could
3486+
* simplify to "n". To define such function-specific optimizations, write
3487+
* a "transform function" and store its OID in the pg_proc.protransform of
3488+
* the primary function. Give each transform function the signature
3489+
* "protransform(internal) RETURNS internal". The argument, internally an
3490+
* Expr *, is the node representing a call to the primary function. If
3491+
* the transform function's study of that node proves that a simplified
3492+
* Expr substitutes for all possible concrete calls represented thereby,
3493+
* return that simplified Expr. Otherwise, return the NULL pointer.
3494+
*
3495+
* Currently, the specific Expr nodetag can be FuncExpr, OpExpr or
3496+
* DistinctExpr. This list may change in the future. The function should
3497+
* check the nodetag and return the NULL pointer for unexpected inputs.
3498+
*
3499+
* We make no guarantee that PostgreSQL will never call the primary
3500+
* function in cases that the transform function would simplify. Ensure
3501+
* rigorous equivalence between the simplified expression and an actual
3502+
* call to the primary function.
3503+
*
3504+
* Currently, this facility is undocumented and not exposed to users at
3505+
* the SQL level. Core length coercion casts use it to avoid calls
3506+
* guaranteed to return their input unchanged. This in turn allows ALTER
3507+
* TABLE ALTER TYPE to avoid rewriting tables for some typmod changes. In
3508+
* the future, this facility may find other applications, like simplifying
3509+
* x*0, x*1, and x+0.
3510+
*/
3511+
transform= ((Form_pg_proc)GETSTRUCT(func_tuple))->protransform;
3512+
if (!newexpr&&OidIsValid(transform)&&oldexpr)
3513+
newexpr= (Expr*)DatumGetPointer(OidFunctionCall1(transform,
3514+
PointerGetDatum(oldexpr)));
3515+
34713516
if (!newexpr&&allow_inline)
34723517
newexpr=inline_function(funcid,result_type,result_collid,
34733518
input_collid,*args,

‎src/backend/parser/parse_clause.c

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

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

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

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
#include"access/hash.h"
1919
#include"access/tuptoaster.h"
2020
#include"libpq/pqformat.h"
21+
#include"nodes/nodeFuncs.h"
22+
#include"parser/parse_clause.h"
2123
#include"utils/array.h"
2224
#include"utils/builtins.h"
2325
#include"mb/pg_wchar.h"
@@ -548,6 +550,38 @@ varcharsend(PG_FUNCTION_ARGS)
548550
}
549551

550552

553+
/*
554+
* Flatten calls to our length coercion function that leave the new maximum
555+
* length >= the previous maximum length. We ignore the isExplicit argument,
556+
* which only affects truncation.
557+
*/
558+
Datum
559+
varchar_transform(PG_FUNCTION_ARGS)
560+
{
561+
FuncExpr*expr= (FuncExpr*)PG_GETARG_POINTER(0);
562+
Node*typmod;
563+
Node*ret=NULL;
564+
565+
if (!IsA(expr,FuncExpr))
566+
PG_RETURN_POINTER(ret);
567+
568+
Assert(list_length(expr->args)==3);
569+
typmod=lsecond(expr->args);
570+
571+
if (IsA(typmod,Const))
572+
{
573+
Node*source=linitial(expr->args);
574+
int32new_typmod=DatumGetInt32(((Const*)typmod)->constvalue);
575+
int32old_max=exprTypmod(source)-VARHDRSZ;
576+
int32new_max=new_typmod-VARHDRSZ;
577+
578+
if (new_max<0|| (old_max >=0&&old_max <=new_max))
579+
ret=relabel_to_typmod(source,new_typmod);
580+
}
581+
582+
PG_RETURN_POINTER(ret);
583+
}
584+
551585
/*
552586
* Converts a VARCHAR type to the specified size.
553587
*

‎src/include/catalog/catversion.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,6 @@
5353
*/
5454

5555
/*yyyymmddN */
56-
#defineCATALOG_VERSION_NO201105231
56+
#defineCATALOG_VERSION_NO201106211
5757

5858
#endif

‎src/include/catalog/pg_class.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ DATA(insert OID = 1247 ( pg_typePGNSP 71 0 PGUID 0 0 0 0 0 0 0 f f p r 29 0 t
134134
DESCR("");
135135
DATA(insertOID=1249 (pg_attributePGNSP750PGUID0000000ffpr200fffff3_null__null_ ));
136136
DESCR("");
137-
DATA(insertOID=1255 (pg_procPGNSP810PGUID0000000ffpr250tffff3_null__null_ ));
137+
DATA(insertOID=1255 (pg_procPGNSP810PGUID0000000ffpr260tffff3_null__null_ ));
138138
DESCR("");
139139
DATA(insertOID=1259 (pg_classPGNSP830PGUID0000000ffpr260tffff3_null__null_ ));
140140
DESCR("");

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp