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

Commit363a6e8

Browse files
author
Richard Guo
committed
Eliminate code duplication in replace_rte_variables callbacks
The callback functions ReplaceVarsFromTargetList_callback andpullup_replace_vars_callback are both used to replace Vars in anexpression tree that reference a particular RTE with items from atargetlist, and they both need to expand whole-tuple references anddeal with OLD/NEW RETURNING list Vars. As a result, currently thereis significant code duplication between these two functions.This patch introduces a new function, ReplaceVarFromTargetList, toperform the replacement and calls it from both callback functions,thereby eliminating code duplication.Author: Dean Rasheed <dean.a.rasheed@gmail.com>Author: Richard Guo <guofenglinux@gmail.com>Reviewed-by: Jian He <jian.universality@gmail.com>Discussion:https://postgr.es/m/CAEZATCWhr=FM4X5kCPvVs-g2XEk+ceLsNtBK_zZMkqFn9vUjsw@mail.gmail.com
1 parent1e4351a commit363a6e8

File tree

3 files changed

+96
-142
lines changed

3 files changed

+96
-142
lines changed

‎src/backend/optimizer/prep/prepjointree.c

Lines changed: 24 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -2666,131 +2666,38 @@ pullup_replace_vars_callback(Var *var,
26662666
/* Just copy the entry and fall through to adjust phlevelsup etc */
26672667
newnode=copyObject(rcon->rv_cache[varattno]);
26682668
}
2669-
elseif (varattno==InvalidAttrNumber)
2669+
else
26702670
{
2671-
/* Must expand whole-tuple reference into RowExpr */
2672-
RowExpr*rowexpr;
2673-
List*colnames;
2674-
List*fields;
2675-
boolsave_wrap_non_vars=rcon->wrap_non_vars;
2676-
intsave_sublevelsup=context->sublevels_up;
2677-
26782671
/*
2679-
* If generating an expansion for a var of a named rowtype (ie, this
2680-
* is a plain relation RTE), then we must include dummy items for
2681-
* dropped columns. If the var is RECORD (ie, this is a JOIN), then
2682-
* omit dropped columns. In the latter case, attach column names to
2683-
* the RowExpr for use of the executor and ruleutils.c.
2684-
*
2685-
* In order to be able to cache the results, we always generate the
2686-
* expansion with varlevelsup = 0, and then adjust below if needed.
2672+
* Generate the replacement expression. This takes care of expanding
2673+
* wholerow references and dealing with non-default varreturningtype.
26872674
*/
2688-
expandRTE(rcon->target_rte,
2689-
var->varno,0/* not varlevelsup */ ,
2690-
var->varreturningtype,var->location,
2691-
(var->vartype!=RECORDOID),
2692-
&colnames,&fields);
2693-
/* Expand the generated per-field Vars, but don't insert PHVs there */
2694-
rcon->wrap_non_vars= false;
2695-
context->sublevels_up=0;/* to match the expandRTE output */
2696-
fields= (List*)replace_rte_variables_mutator((Node*)fields,
2697-
context);
2698-
rcon->wrap_non_vars=save_wrap_non_vars;
2699-
context->sublevels_up=save_sublevelsup;
2700-
2701-
rowexpr=makeNode(RowExpr);
2702-
rowexpr->args=fields;
2703-
rowexpr->row_typeid=var->vartype;
2704-
rowexpr->row_format=COERCE_IMPLICIT_CAST;
2705-
rowexpr->colnames= (var->vartype==RECORDOID) ?colnames :NIL;
2706-
rowexpr->location=var->location;
2707-
newnode= (Node*)rowexpr;
2708-
2709-
/* Handle any OLD/NEW RETURNING list Vars */
2710-
if (var->varreturningtype!=VAR_RETURNING_DEFAULT)
2711-
{
2712-
/*
2713-
* Wrap the RowExpr in a ReturningExpr node, so that the executor
2714-
* returns NULL if the OLD/NEW row does not exist.
2715-
*/
2716-
ReturningExpr*rexpr=makeNode(ReturningExpr);
2717-
2718-
rexpr->retlevelsup=0;
2719-
rexpr->retold= (var->varreturningtype==VAR_RETURNING_OLD);
2720-
rexpr->retexpr= (Expr*)newnode;
2721-
2722-
newnode= (Node*)rexpr;
2723-
}
2724-
2725-
/*
2726-
* Insert PlaceHolderVar if needed. Notice that we are wrapping one
2727-
* PlaceHolderVar around the whole RowExpr, rather than putting one
2728-
* around each element of the row. This is because we need the
2729-
* expression to yield NULL, not ROW(NULL,NULL,...) when it is forced
2730-
* to null by an outer join.
2731-
*/
2732-
if (need_phv)
2733-
{
2734-
newnode= (Node*)
2735-
make_placeholder_expr(rcon->root,
2736-
(Expr*)newnode,
2737-
bms_make_singleton(rcon->varno));
2738-
/* cache it with the PHV, and with phlevelsup etc not set yet */
2739-
rcon->rv_cache[InvalidAttrNumber]=copyObject(newnode);
2740-
}
2741-
}
2742-
else
2743-
{
2744-
/* Normal case referencing one targetlist element */
2745-
TargetEntry*tle=get_tle_by_resno(rcon->targetlist,varattno);
2746-
2747-
if (tle==NULL)/* shouldn't happen */
2748-
elog(ERROR,"could not find attribute %d in subquery targetlist",
2749-
varattno);
2750-
2751-
/* Make a copy of the tlist item to return */
2752-
newnode= (Node*)copyObject(tle->expr);
2753-
2754-
/* Handle any OLD/NEW RETURNING list Vars */
2755-
if (var->varreturningtype!=VAR_RETURNING_DEFAULT)
2756-
{
2757-
/*
2758-
* Copy varreturningtype onto any Vars in the tlist item that
2759-
* refer to result_relation (which had better be non-zero).
2760-
*/
2761-
if (rcon->result_relation==0)
2762-
elog(ERROR,"variable returning old/new found outside RETURNING list");
2763-
2764-
SetVarReturningType((Node*)newnode,rcon->result_relation,
2765-
0,var->varreturningtype);
2766-
2767-
/*
2768-
* If the replacement expression in the targetlist is not simply a
2769-
* Var referencing result_relation, wrap it in a ReturningExpr
2770-
* node, so that the executor returns NULL if the OLD/NEW row does
2771-
* not exist.
2772-
*/
2773-
if (!IsA(newnode,Var)||
2774-
((Var*)newnode)->varno!=rcon->result_relation||
2775-
((Var*)newnode)->varlevelsup!=0)
2776-
{
2777-
ReturningExpr*rexpr=makeNode(ReturningExpr);
2778-
2779-
rexpr->retlevelsup=0;
2780-
rexpr->retold= (var->varreturningtype==VAR_RETURNING_OLD);
2781-
rexpr->retexpr= (Expr*)newnode;
2782-
2783-
newnode= (Node*)rexpr;
2784-
}
2785-
}
2675+
newnode=ReplaceVarFromTargetList(var,
2676+
rcon->target_rte,
2677+
rcon->targetlist,
2678+
rcon->result_relation,
2679+
REPLACEVARS_REPORT_ERROR,
2680+
0);
27862681

27872682
/* Insert PlaceHolderVar if needed */
27882683
if (need_phv)
27892684
{
27902685
boolwrap;
27912686

2792-
if (newnode&&IsA(newnode,Var)&&
2793-
((Var*)newnode)->varlevelsup==0)
2687+
if (varattno==InvalidAttrNumber)
2688+
{
2689+
/*
2690+
* Insert PlaceHolderVar for whole-tuple reference. Notice
2691+
* that we are wrapping one PlaceHolderVar around the whole
2692+
* RowExpr, rather than putting one around each element of the
2693+
* row. This is because we need the expression to yield NULL,
2694+
* not ROW(NULL,NULL,...) when it is forced to null by an
2695+
* outer join.
2696+
*/
2697+
wrap= true;
2698+
}
2699+
elseif (newnode&&IsA(newnode,Var)&&
2700+
((Var*)newnode)->varlevelsup==0)
27942701
{
27952702
/*
27962703
* Simple Vars always escape being wrapped, unless they are
@@ -2936,7 +2843,7 @@ pullup_replace_vars_callback(Var *var,
29362843
* Cache it if possible (ie, if the attno is in range, which
29372844
* it probably always should be).
29382845
*/
2939-
if (varattno>InvalidAttrNumber&&
2846+
if (varattno >=InvalidAttrNumber&&
29402847
varattno <=list_length(rcon->targetlist))
29412848
rcon->rv_cache[varattno]=copyObject(newnode);
29422849
}

‎src/backend/rewrite/rewriteManip.c

Lines changed: 66 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1010,7 +1010,7 @@ SetVarReturningType_walker(Node *node, SetVarReturningType_context *context)
10101010
returnexpression_tree_walker(node,SetVarReturningType_walker,context);
10111011
}
10121012

1013-
void
1013+
staticvoid
10141014
SetVarReturningType(Node*node,intresult_relation,intsublevels_up,
10151015
VarReturningTypereturning_type)
10161016
{
@@ -1797,6 +1797,11 @@ map_variable_attnos(Node *node,
17971797
* referencing result_relation, it is wrapped in a ReturningExpr node (causing
17981798
* the executor to return NULL if the OLD/NEW row doesn't exist).
17991799
*
1800+
* Note that ReplaceVarFromTargetList always generates the replacement
1801+
* expression with varlevelsup = 0. The caller is responsible for adjusting
1802+
* the varlevelsup if needed. This simplifies the caller's life if it wants to
1803+
* cache the replacement expressions.
1804+
*
18001805
* outer_hasSubLinks works the same as for replace_rte_variables().
18011806
*/
18021807

@@ -1814,6 +1819,30 @@ ReplaceVarsFromTargetList_callback(Var *var,
18141819
replace_rte_variables_context*context)
18151820
{
18161821
ReplaceVarsFromTargetList_context*rcon= (ReplaceVarsFromTargetList_context*)context->callback_arg;
1822+
Node*newnode;
1823+
1824+
newnode=ReplaceVarFromTargetList(var,
1825+
rcon->target_rte,
1826+
rcon->targetlist,
1827+
rcon->result_relation,
1828+
rcon->nomatch_option,
1829+
rcon->nomatch_varno);
1830+
1831+
/* Must adjust varlevelsup if replaced Var is within a subquery */
1832+
if (var->varlevelsup>0)
1833+
IncrementVarSublevelsUp(newnode,var->varlevelsup,0);
1834+
1835+
returnnewnode;
1836+
}
1837+
1838+
Node*
1839+
ReplaceVarFromTargetList(Var*var,
1840+
RangeTblEntry*target_rte,
1841+
List*targetlist,
1842+
intresult_relation,
1843+
ReplaceVarsNoMatchOptionnomatch_option,
1844+
intnomatch_varno)
1845+
{
18171846
TargetEntry*tle;
18181847

18191848
if (var->varattno==InvalidAttrNumber)
@@ -1822,6 +1851,7 @@ ReplaceVarsFromTargetList_callback(Var *var,
18221851
RowExpr*rowexpr;
18231852
List*colnames;
18241853
List*fields;
1854+
ListCell*lc;
18251855

18261856
/*
18271857
* If generating an expansion for a var of a named rowtype (ie, this
@@ -1830,29 +1860,46 @@ ReplaceVarsFromTargetList_callback(Var *var,
18301860
* omit dropped columns. In the latter case, attach column names to
18311861
* the RowExpr for use of the executor and ruleutils.c.
18321862
*
1863+
* In order to be able to cache the results, we always generate the
1864+
* expansion with varlevelsup = 0. The caller is responsible for
1865+
* adjusting it if needed.
1866+
*
18331867
* The varreturningtype is copied onto each individual field Var, so
18341868
* that it is handled correctly when we recurse.
18351869
*/
1836-
expandRTE(rcon->target_rte,
1837-
var->varno,var->varlevelsup,var->varreturningtype,
1838-
var->location, (var->vartype!=RECORDOID),
1870+
expandRTE(target_rte,
1871+
var->varno,0/* not varlevelsup */ ,
1872+
var->varreturningtype,var->location,
1873+
(var->vartype!=RECORDOID),
18391874
&colnames,&fields);
1840-
/* Adjust the generated per-field Vars... */
1841-
fields= (List*)replace_rte_variables_mutator((Node*)fields,
1842-
context);
18431875
rowexpr=makeNode(RowExpr);
1844-
rowexpr->args=fields;
1876+
/* the fields will be set below */
1877+
rowexpr->args=NIL;
18451878
rowexpr->row_typeid=var->vartype;
18461879
rowexpr->row_format=COERCE_IMPLICIT_CAST;
18471880
rowexpr->colnames= (var->vartype==RECORDOID) ?colnames :NIL;
18481881
rowexpr->location=var->location;
1882+
/* Adjust the generated per-field Vars... */
1883+
foreach(lc,fields)
1884+
{
1885+
Node*field=lfirst(lc);
1886+
1887+
if (field&&IsA(field,Var))
1888+
field=ReplaceVarFromTargetList((Var*)field,
1889+
target_rte,
1890+
targetlist,
1891+
result_relation,
1892+
nomatch_option,
1893+
nomatch_varno);
1894+
rowexpr->args=lappend(rowexpr->args,field);
1895+
}
18491896

18501897
/* Wrap it in a ReturningExpr, if needed, per comments above */
18511898
if (var->varreturningtype!=VAR_RETURNING_DEFAULT)
18521899
{
18531900
ReturningExpr*rexpr=makeNode(ReturningExpr);
18541901

1855-
rexpr->retlevelsup=var->varlevelsup;
1902+
rexpr->retlevelsup=0;
18561903
rexpr->retold= (var->varreturningtype==VAR_RETURNING_OLD);
18571904
rexpr->retexpr= (Expr*)rowexpr;
18581905

@@ -1863,20 +1910,21 @@ ReplaceVarsFromTargetList_callback(Var *var,
18631910
}
18641911

18651912
/* Normal case referencing one targetlist element */
1866-
tle=get_tle_by_resno(rcon->targetlist,var->varattno);
1913+
tle=get_tle_by_resno(targetlist,var->varattno);
18671914

18681915
if (tle==NULL||tle->resjunk)
18691916
{
18701917
/* Failed to find column in targetlist */
1871-
switch (rcon->nomatch_option)
1918+
switch (nomatch_option)
18721919
{
18731920
caseREPLACEVARS_REPORT_ERROR:
18741921
/* fall through, throw error below */
18751922
break;
18761923

18771924
caseREPLACEVARS_CHANGE_VARNO:
18781925
var=copyObject(var);
1879-
var->varno=rcon->nomatch_varno;
1926+
var->varno=nomatch_varno;
1927+
var->varlevelsup=0;
18801928
/* we leave the syntactic referent alone */
18811929
return (Node*)var;
18821930

@@ -1906,10 +1954,6 @@ ReplaceVarsFromTargetList_callback(Var *var,
19061954
/* Make a copy of the tlist item to return */
19071955
Expr*newnode=copyObject(tle->expr);
19081956

1909-
/* Must adjust varlevelsup if tlist item is from higher query */
1910-
if (var->varlevelsup>0)
1911-
IncrementVarSublevelsUp((Node*)newnode,var->varlevelsup,0);
1912-
19131957
/*
19141958
* Check to see if the tlist item contains a PARAM_MULTIEXPR Param,
19151959
* and throw error if so. This case could only happen when expanding
@@ -1932,20 +1976,20 @@ ReplaceVarsFromTargetList_callback(Var *var,
19321976
* Copy varreturningtype onto any Vars in the tlist item that
19331977
* refer to result_relation (which had better be non-zero).
19341978
*/
1935-
if (rcon->result_relation==0)
1979+
if (result_relation==0)
19361980
elog(ERROR,"variable returning old/new found outside RETURNING list");
19371981

1938-
SetVarReturningType((Node*)newnode,rcon->result_relation,
1939-
var->varlevelsup,var->varreturningtype);
1982+
SetVarReturningType((Node*)newnode,result_relation,
1983+
0,var->varreturningtype);
19401984

19411985
/* Wrap it in a ReturningExpr, if needed, per comments above */
19421986
if (!IsA(newnode,Var)||
1943-
((Var*)newnode)->varno!=rcon->result_relation||
1944-
((Var*)newnode)->varlevelsup!=var->varlevelsup)
1987+
((Var*)newnode)->varno!=result_relation||
1988+
((Var*)newnode)->varlevelsup!=0)
19451989
{
19461990
ReturningExpr*rexpr=makeNode(ReturningExpr);
19471991

1948-
rexpr->retlevelsup=var->varlevelsup;
1992+
rexpr->retlevelsup=0;
19491993
rexpr->retold= (var->varreturningtype==VAR_RETURNING_OLD);
19501994
rexpr->retexpr=newnode;
19511995

‎src/include/rewrite/rewriteManip.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,6 @@ extern void IncrementVarSublevelsUp(Node *node, int delta_sublevels_up,
5555
externvoidIncrementVarSublevelsUp_rtable(List*rtable,
5656
intdelta_sublevels_up,intmin_sublevels_up);
5757

58-
externvoidSetVarReturningType(Node*node,intresult_relation,intsublevels_up,
59-
VarReturningTypereturning_type);
60-
6158
externboolrangeTableEntry_used(Node*node,intrt_index,
6259
intsublevels_up);
6360

@@ -92,6 +89,12 @@ extern Node *map_variable_attnos(Node *node,
9289
conststructAttrMap*attno_map,
9390
Oidto_rowtype,bool*found_whole_row);
9491

92+
externNode*ReplaceVarFromTargetList(Var*var,
93+
RangeTblEntry*target_rte,
94+
List*targetlist,
95+
intresult_relation,
96+
ReplaceVarsNoMatchOptionnomatch_option,
97+
intnomatch_varno);
9598
externNode*ReplaceVarsFromTargetList(Node*node,
9699
inttarget_varno,intsublevels_up,
97100
RangeTblEntry*target_rte,

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp