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

Commitad38e2f

Browse files
committed
Fix calculation of which GENERATED columns need to be updated.
We were identifying the updatable generated columns of inheritancechildren by transposing the calculation made for their parent.However, there's nothing that says a traditional-inheritance childcan't have generated columns that aren't there in its parent, or thathave different dependencies than are in the parent's expression.(At present it seems that we don't enforce that for partitioningeither, which is likely wrong to some degree or other; but the caseclearly needs to be handled with traditional inheritance.)Hence, drop the very-klugy-anyway "extraUpdatedCols" RTE fieldin favor of identifying which generated columns depend on updatedcolumns during executor startup. In HEAD we can removeextraUpdatedCols altogether; in back branches, it's still there butalways empty. Another difference between the HEAD and back-branchversions of this patch is that in HEAD we can add the new bitmap fieldto ResultRelInfo, but that would cause an ABI break in back branches.Like4b3e379, add a List field at the end of struct EState instead.Back-patch to v13. The bogus calculation is also being made in v12,but it doesn't have the same visible effect because we don't use itto decide which generated columns to recalculate; as a consequence ofwhich the patch doesn't apply easily. I think that there might stillbe a demonstrable bug associated with trigger firing conditions, butthat's such a weird corner-case usage that I'm content to leave itunfixed in v12.Amit Langote and Tom LaneDiscussion:https://postgr.es/m/CA+HiwqFshLKNvQUd1DgwJ-7tsTp=dwv7KZqXC4j2wYBV1aCDUA@mail.gmail.comDiscussion:https://postgr.es/m/2793383.1672944799@sss.pgh.pa.us
1 parent5dac191 commitad38e2f

File tree

14 files changed

+329
-126
lines changed

14 files changed

+329
-126
lines changed

‎contrib/postgres_fdw/postgres_fdw.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include"nodes/nodeFuncs.h"
3030
#include"optimizer/clauses.h"
3131
#include"optimizer/cost.h"
32+
#include"optimizer/inherit.h"
3233
#include"optimizer/optimizer.h"
3334
#include"optimizer/pathnode.h"
3435
#include"optimizer/paths.h"
@@ -1697,7 +1698,8 @@ postgresPlanForeignModify(PlannerInfo *root,
16971698
elseif (operation==CMD_UPDATE)
16981699
{
16991700
intcol;
1700-
Bitmapset*allUpdatedCols=bms_union(rte->updatedCols,rte->extraUpdatedCols);
1701+
RelOptInfo*rel=find_base_rel(root,resultRelation);
1702+
Bitmapset*allUpdatedCols=get_rel_all_updated_cols(root,rel);
17011703

17021704
col=-1;
17031705
while ((col=bms_next_member(allUpdatedCols,col)) >=0)

‎src/backend/executor/execUtils.c

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,8 @@ CreateExecutorState(void)
135135

136136
estate->es_trig_target_relations=NIL;
137137

138+
estate->es_resultrelinfo_extra=NIL;
139+
138140
estate->es_param_list_info=NULL;
139141
estate->es_param_exec_vals=NULL;
140142

@@ -1276,27 +1278,25 @@ ExecGetUpdatedCols(ResultRelInfo *relinfo, EState *estate)
12761278
Bitmapset*
12771279
ExecGetExtraUpdatedCols(ResultRelInfo*relinfo,EState*estate)
12781280
{
1279-
/* see ExecGetInsertedCols() */
1280-
if (relinfo->ri_RangeTableIndex!=0)
1281-
{
1282-
RangeTblEntry*rte=exec_rt_fetch(relinfo->ri_RangeTableIndex,estate);
1281+
Relationrel=relinfo->ri_RelationDesc;
1282+
TupleDesctupdesc=RelationGetDescr(rel);
12831283

1284-
returnrte->extraUpdatedCols;
1285-
}
1286-
elseif (relinfo->ri_RootResultRelInfo)
1284+
if (tupdesc->constr&&tupdesc->constr->has_generated_stored)
12871285
{
1288-
ResultRelInfo*rootRelInfo=relinfo->ri_RootResultRelInfo;
1289-
RangeTblEntry*rte=exec_rt_fetch(rootRelInfo->ri_RangeTableIndex,estate);
1290-
PartitionRoutingInfo*partrouteinfo=relinfo->ri_PartitionInfo;
1286+
ListCell*lc;
12911287

1292-
if (partrouteinfo->pi_RootToPartitionMap!=NULL)
1293-
returnexecute_attr_map_cols(partrouteinfo->pi_RootToPartitionMap->attrMap,
1294-
rte->extraUpdatedCols);
1295-
else
1296-
returnrte->extraUpdatedCols;
1288+
/* Assert that ExecInitStoredGenerated has been called. */
1289+
Assert(relinfo->ri_GeneratedExprs!=NULL);
1290+
foreach(lc,estate->es_resultrelinfo_extra)
1291+
{
1292+
ResultRelInfoExtra*rextra= (ResultRelInfoExtra*)lfirst(lc);
1293+
1294+
if (rextra->rinfo==relinfo)
1295+
returnrextra->ri_extraUpdatedCols;
1296+
}
1297+
Assert(false);/* shouldn't get here */
12971298
}
1298-
else
1299-
returnNULL;
1299+
returnNULL;
13001300
}
13011301

13021302
/* Return columns being updated, including generated columns */

‎src/backend/executor/nodeModifyTable.c

Lines changed: 114 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
#include"foreign/fdwapi.h"
5050
#include"miscadmin.h"
5151
#include"nodes/nodeFuncs.h"
52+
#include"optimizer/optimizer.h"
5253
#include"rewrite/rewriteHandler.h"
5354
#include"storage/bufmgr.h"
5455
#include"storage/lmgr.h"
@@ -249,68 +250,127 @@ ExecCheckTIDVisible(EState *estate,
249250
}
250251

251252
/*
252-
* Compute stored generated columns for a tuple
253+
* Initialize to compute stored generated columns for a tuple
254+
*
255+
* This fills the resultRelInfo's ri_GeneratedExprs field and makes an
256+
* associated ResultRelInfoExtra struct to hold ri_extraUpdatedCols.
257+
* (Currently, ri_extraUpdatedCols is consulted only in UPDATE, but we might
258+
* as well fill it for INSERT too.)
253259
*/
254-
void
255-
ExecComputeStoredGenerated(EState*estate,TupleTableSlot*slot,CmdTypecmdtype)
260+
staticvoid
261+
ExecInitStoredGenerated(ResultRelInfo*resultRelInfo,
262+
EState*estate,
263+
CmdTypecmdtype)
256264
{
257-
ResultRelInfo*resultRelInfo=estate->es_result_relation_info;
258265
Relationrel=resultRelInfo->ri_RelationDesc;
259266
TupleDesctupdesc=RelationGetDescr(rel);
260267
intnatts=tupdesc->natts;
268+
Bitmapset*updatedCols;
269+
ResultRelInfoExtra*rextra;
261270
MemoryContextoldContext;
262-
Datum*values;
263-
bool*nulls;
264271

265-
Assert(tupdesc->constr&&tupdesc->constr->has_generated_stored);
272+
/* Don't call twice */
273+
Assert(resultRelInfo->ri_GeneratedExprs==NULL);
274+
275+
/* Nothing to do if no generated columns */
276+
if (!(tupdesc->constr&&tupdesc->constr->has_generated_stored))
277+
return;
266278

267279
/*
268-
* If first time through for this result relation, build expression
269-
* nodetrees for rel's stored generation expressions. Keep them in the
270-
* per-query memory context so they'll survive throughout the query.
280+
* In an UPDATE, we can skip computing any generated columns that do not
281+
* depend on any UPDATE target column. But if there is a BEFORE ROW
282+
* UPDATE trigger, we cannot skip because the trigger might change more
283+
* columns.
271284
*/
272-
if (resultRelInfo->ri_GeneratedExprs==NULL)
273-
{
274-
oldContext=MemoryContextSwitchTo(estate->es_query_cxt);
285+
if (cmdtype==CMD_UPDATE&&
286+
!(rel->trigdesc&&rel->trigdesc->trig_update_before_row))
287+
updatedCols=ExecGetUpdatedCols(resultRelInfo,estate);
288+
else
289+
updatedCols=NULL;
275290

276-
resultRelInfo->ri_GeneratedExprs=
277-
(ExprState**)palloc(natts*sizeof(ExprState*));
278-
resultRelInfo->ri_NumGeneratedNeeded=0;
291+
/*
292+
* Make sure these data structures are built in the per-query memory
293+
* context so they'll survive throughout the query.
294+
*/
295+
oldContext=MemoryContextSwitchTo(estate->es_query_cxt);
296+
297+
resultRelInfo->ri_GeneratedExprs=
298+
(ExprState**)palloc0(natts*sizeof(ExprState*));
299+
resultRelInfo->ri_NumGeneratedNeeded=0;
300+
301+
rextra=palloc_object(ResultRelInfoExtra);
302+
rextra->rinfo=resultRelInfo;
303+
rextra->ri_extraUpdatedCols=NULL;
304+
estate->es_resultrelinfo_extra=lappend(estate->es_resultrelinfo_extra,
305+
rextra);
279306

280-
for (inti=0;i<natts;i++)
307+
for (inti=0;i<natts;i++)
308+
{
309+
if (TupleDescAttr(tupdesc,i)->attgenerated==ATTRIBUTE_GENERATED_STORED)
281310
{
282-
if (TupleDescAttr(tupdesc,i)->attgenerated==ATTRIBUTE_GENERATED_STORED)
283-
{
284-
Expr*expr;
311+
Expr*expr;
285312

286-
/*
287-
* If it's an update and the current column was not marked as
288-
* being updated, then we can skip the computation. But if
289-
* there is a BEFORE ROW UPDATE trigger, we cannot skip
290-
* because the trigger might affect additional columns.
291-
*/
292-
if (cmdtype==CMD_UPDATE&&
293-
!(rel->trigdesc&&rel->trigdesc->trig_update_before_row)&&
294-
!bms_is_member(i+1-FirstLowInvalidHeapAttributeNumber,
295-
ExecGetExtraUpdatedCols(resultRelInfo,estate)))
296-
{
297-
resultRelInfo->ri_GeneratedExprs[i]=NULL;
298-
continue;
299-
}
313+
/* Fetch the GENERATED AS expression tree */
314+
expr= (Expr*)build_column_default(rel,i+1);
315+
if (expr==NULL)
316+
elog(ERROR,"no generation expression found for column number %d of table \"%s\"",
317+
i+1,RelationGetRelationName(rel));
318+
319+
/*
320+
* If it's an update with a known set of update target columns,
321+
* see if we can skip the computation.
322+
*/
323+
if (updatedCols)
324+
{
325+
Bitmapset*attrs_used=NULL;
300326

301-
expr= (Expr*)build_column_default(rel,i+1);
302-
if (expr==NULL)
303-
elog(ERROR,"no generation expression found for column number %d of table \"%s\"",
304-
i+1,RelationGetRelationName(rel));
327+
pull_varattnos((Node*)expr,1,&attrs_used);
305328

306-
resultRelInfo->ri_GeneratedExprs[i]=ExecPrepareExpr(expr,estate);
307-
resultRelInfo->ri_NumGeneratedNeeded++;
329+
if (!bms_overlap(updatedCols,attrs_used))
330+
continue;/* need not update this column */
308331
}
309-
}
310332

311-
MemoryContextSwitchTo(oldContext);
333+
/* No luck, so prepare the expression for execution */
334+
resultRelInfo->ri_GeneratedExprs[i]=ExecPrepareExpr(expr,estate);
335+
resultRelInfo->ri_NumGeneratedNeeded++;
336+
337+
/* And mark this column in rextra->ri_extraUpdatedCols */
338+
rextra->ri_extraUpdatedCols=
339+
bms_add_member(rextra->ri_extraUpdatedCols,
340+
i+1-FirstLowInvalidHeapAttributeNumber);
341+
}
312342
}
313343

344+
MemoryContextSwitchTo(oldContext);
345+
}
346+
347+
/*
348+
* Compute stored generated columns for a tuple
349+
*/
350+
void
351+
ExecComputeStoredGenerated(EState*estate,TupleTableSlot*slot,CmdTypecmdtype)
352+
{
353+
ResultRelInfo*resultRelInfo=estate->es_result_relation_info;
354+
Relationrel=resultRelInfo->ri_RelationDesc;
355+
TupleDesctupdesc=RelationGetDescr(rel);
356+
intnatts=tupdesc->natts;
357+
ExprContext*econtext=GetPerTupleExprContext(estate);
358+
MemoryContextoldContext;
359+
Datum*values;
360+
bool*nulls;
361+
362+
/* We should not be called unless this is true */
363+
Assert(tupdesc->constr&&tupdesc->constr->has_generated_stored);
364+
365+
/*
366+
* For relations named directly in the query, ExecInitStoredGenerated
367+
* should have been called already; but this might not have happened yet
368+
* for a partition child rel. Also, it's convenient for outside callers
369+
* to not have to call ExecInitStoredGenerated explicitly.
370+
*/
371+
if (resultRelInfo->ri_GeneratedExprs==NULL)
372+
ExecInitStoredGenerated(resultRelInfo,estate,cmdtype);
373+
314374
/*
315375
* If no generated columns have been affected by this change, then skip
316376
* the rest.
@@ -330,14 +390,13 @@ ExecComputeStoredGenerated(EState *estate, TupleTableSlot *slot, CmdType cmdtype
330390
{
331391
Form_pg_attributeattr=TupleDescAttr(tupdesc,i);
332392

333-
if (attr->attgenerated==ATTRIBUTE_GENERATED_STORED&&
334-
resultRelInfo->ri_GeneratedExprs[i])
393+
if (resultRelInfo->ri_GeneratedExprs[i])
335394
{
336-
ExprContext*econtext;
337395
Datumval;
338396
boolisnull;
339397

340-
econtext=GetPerTupleExprContext(estate);
398+
Assert(attr->attgenerated==ATTRIBUTE_GENERATED_STORED);
399+
341400
econtext->ecxt_scantuple=slot;
342401

343402
val=ExecEvalExpr(resultRelInfo->ri_GeneratedExprs[i],econtext,&isnull);
@@ -2488,6 +2547,15 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
24882547
eflags);
24892548
}
24902549

2550+
/*
2551+
* For INSERT and UPDATE, prepare to evaluate any generated columns.
2552+
* We must do this now, even if we never insert or update any rows,
2553+
* because we have to fill resultRelInfo->ri_extraUpdatedCols for
2554+
* possible use by the trigger machinery.
2555+
*/
2556+
if (operation==CMD_INSERT||operation==CMD_UPDATE)
2557+
ExecInitStoredGenerated(resultRelInfo,estate,operation);
2558+
24912559
resultRelInfo++;
24922560
i++;
24932561
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp