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

Commit3f7836f

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 parent529da08 commit3f7836f

File tree

15 files changed

+257
-186
lines changed

15 files changed

+257
-186
lines changed

‎src/backend/executor/execMain.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1225,6 +1225,7 @@ InitResultRelInfo(ResultRelInfo *resultRelInfo,
12251225

12261226
/* The following fields are set later if needed */
12271227
resultRelInfo->ri_RowIdAttNo=0;
1228+
resultRelInfo->ri_extraUpdatedCols=NULL;
12281229
resultRelInfo->ri_projectNew=NULL;
12291230
resultRelInfo->ri_newTupleSlot=NULL;
12301231
resultRelInfo->ri_oldTupleSlot=NULL;

‎src/backend/executor/execUtils.c

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1342,25 +1342,16 @@ ExecGetUpdatedCols(ResultRelInfo *relinfo, EState *estate)
13421342
Bitmapset*
13431343
ExecGetExtraUpdatedCols(ResultRelInfo*relinfo,EState*estate)
13441344
{
1345-
if (relinfo->ri_RangeTableIndex!=0)
1346-
{
1347-
RangeTblEntry*rte=exec_rt_fetch(relinfo->ri_RangeTableIndex,estate);
1345+
#ifdefUSE_ASSERT_CHECKING
1346+
/* Verify that ExecInitStoredGenerated has been called if needed. */
1347+
Relationrel=relinfo->ri_RelationDesc;
1348+
TupleDesctupdesc=RelationGetDescr(rel);
13481349

1349-
returnrte->extraUpdatedCols;
1350-
}
1351-
elseif (relinfo->ri_RootResultRelInfo)
1352-
{
1353-
ResultRelInfo*rootRelInfo=relinfo->ri_RootResultRelInfo;
1354-
RangeTblEntry*rte=exec_rt_fetch(rootRelInfo->ri_RangeTableIndex,estate);
1355-
TupleConversionMap*map=ExecGetRootToChildMap(relinfo,estate);
1350+
if (tupdesc->constr&&tupdesc->constr->has_generated_stored)
1351+
Assert(relinfo->ri_GeneratedExprs!=NULL);
1352+
#endif
13561353

1357-
if (map!=NULL)
1358-
returnexecute_attr_map_cols(map->attrMap,rte->extraUpdatedCols);
1359-
else
1360-
returnrte->extraUpdatedCols;
1361-
}
1362-
else
1363-
returnNULL;
1354+
returnrelinfo->ri_extraUpdatedCols;
13641355
}
13651356

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

‎src/backend/executor/nodeModifyTable.c

Lines changed: 107 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
#include"foreign/fdwapi.h"
5555
#include"miscadmin.h"
5656
#include"nodes/nodeFuncs.h"
57+
#include"optimizer/optimizer.h"
5758
#include"rewrite/rewriteHandler.h"
5859
#include"storage/bufmgr.h"
5960
#include"storage/lmgr.h"
@@ -353,69 +354,120 @@ ExecCheckTIDVisible(EState *estate,
353354
}
354355

355356
/*
356-
* Compute stored generated columns for a tuple
357+
* Initialize to compute stored generated columns for a tuple
358+
*
359+
* This fills the resultRelInfo's ri_GeneratedExprs and ri_extraUpdatedCols
360+
* fields. (Currently, ri_extraUpdatedCols is consulted only in UPDATE,
361+
* but we might as well fill it for INSERT too.)
357362
*/
358-
void
359-
ExecComputeStoredGenerated(ResultRelInfo*resultRelInfo,
360-
EState*estate,TupleTableSlot*slot,
361-
CmdTypecmdtype)
363+
staticvoid
364+
ExecInitStoredGenerated(ResultRelInfo*resultRelInfo,
365+
EState*estate,
366+
CmdTypecmdtype)
362367
{
363368
Relationrel=resultRelInfo->ri_RelationDesc;
364369
TupleDesctupdesc=RelationGetDescr(rel);
365370
intnatts=tupdesc->natts;
371+
Bitmapset*updatedCols;
366372
MemoryContextoldContext;
367-
Datum*values;
368-
bool*nulls;
369373

370-
Assert(tupdesc->constr&&tupdesc->constr->has_generated_stored);
374+
/* Don't call twice */
375+
Assert(resultRelInfo->ri_GeneratedExprs==NULL);
376+
377+
/* Nothing to do if no generated columns */
378+
if (!(tupdesc->constr&&tupdesc->constr->has_generated_stored))
379+
return;
371380

372381
/*
373-
* If first time through for this result relation, build expression
374-
* nodetrees for rel's stored generation expressions. Keep them in the
375-
* per-query memory context so they'll survive throughout the query.
382+
* In an UPDATE, we can skip computing any generated columns that do not
383+
* depend on any UPDATE target column. But if there is a BEFORE ROW
384+
* UPDATE trigger, we cannot skip because the trigger might change more
385+
* columns.
376386
*/
377-
if (resultRelInfo->ri_GeneratedExprs==NULL)
378-
{
379-
oldContext=MemoryContextSwitchTo(estate->es_query_cxt);
387+
if (cmdtype==CMD_UPDATE&&
388+
!(rel->trigdesc&&rel->trigdesc->trig_update_before_row))
389+
updatedCols=ExecGetUpdatedCols(resultRelInfo,estate);
390+
else
391+
updatedCols=NULL;
380392

381-
resultRelInfo->ri_GeneratedExprs=
382-
(ExprState**)palloc(natts*sizeof(ExprState*));
383-
resultRelInfo->ri_NumGeneratedNeeded=0;
393+
/*
394+
* Make sure these data structures are built in the per-query memory
395+
* context so they'll survive throughout the query.
396+
*/
397+
oldContext=MemoryContextSwitchTo(estate->es_query_cxt);
384398

385-
for (inti=0;i<natts;i++)
399+
resultRelInfo->ri_GeneratedExprs=
400+
(ExprState**)palloc0(natts*sizeof(ExprState*));
401+
resultRelInfo->ri_NumGeneratedNeeded=0;
402+
403+
for (inti=0;i<natts;i++)
404+
{
405+
if (TupleDescAttr(tupdesc,i)->attgenerated==ATTRIBUTE_GENERATED_STORED)
386406
{
387-
if (TupleDescAttr(tupdesc,i)->attgenerated==ATTRIBUTE_GENERATED_STORED)
388-
{
389-
Expr*expr;
407+
Expr*expr;
390408

391-
/*
392-
* If it's an update and the current column was not marked as
393-
* being updated, then we can skip the computation. But if
394-
* there is a BEFORE ROW UPDATE trigger, we cannot skip
395-
* because the trigger might affect additional columns.
396-
*/
397-
if (cmdtype==CMD_UPDATE&&
398-
!(rel->trigdesc&&rel->trigdesc->trig_update_before_row)&&
399-
!bms_is_member(i+1-FirstLowInvalidHeapAttributeNumber,
400-
ExecGetExtraUpdatedCols(resultRelInfo,estate)))
401-
{
402-
resultRelInfo->ri_GeneratedExprs[i]=NULL;
403-
continue;
404-
}
409+
/* Fetch the GENERATED AS expression tree */
410+
expr= (Expr*)build_column_default(rel,i+1);
411+
if (expr==NULL)
412+
elog(ERROR,"no generation expression found for column number %d of table \"%s\"",
413+
i+1,RelationGetRelationName(rel));
405414

406-
expr= (Expr*)build_column_default(rel,i+1);
407-
if (expr==NULL)
408-
elog(ERROR,"no generation expression found for column number %d of table \"%s\"",
409-
i+1,RelationGetRelationName(rel));
415+
/*
416+
* If it's an update with a known set of update target columns,
417+
* see if we can skip the computation.
418+
*/
419+
if (updatedCols)
420+
{
421+
Bitmapset*attrs_used=NULL;
422+
423+
pull_varattnos((Node*)expr,1,&attrs_used);
410424

411-
resultRelInfo->ri_GeneratedExprs[i]=ExecPrepareExpr(expr,estate);
412-
resultRelInfo->ri_NumGeneratedNeeded++;
425+
if (!bms_overlap(updatedCols,attrs_used))
426+
continue;/* need not update this column */
413427
}
414-
}
415428

416-
MemoryContextSwitchTo(oldContext);
429+
/* No luck, so prepare the expression for execution */
430+
resultRelInfo->ri_GeneratedExprs[i]=ExecPrepareExpr(expr,estate);
431+
resultRelInfo->ri_NumGeneratedNeeded++;
432+
433+
/* And mark this column in resultRelInfo->ri_extraUpdatedCols */
434+
resultRelInfo->ri_extraUpdatedCols=
435+
bms_add_member(resultRelInfo->ri_extraUpdatedCols,
436+
i+1-FirstLowInvalidHeapAttributeNumber);
437+
}
417438
}
418439

440+
MemoryContextSwitchTo(oldContext);
441+
}
442+
443+
/*
444+
* Compute stored generated columns for a tuple
445+
*/
446+
void
447+
ExecComputeStoredGenerated(ResultRelInfo*resultRelInfo,
448+
EState*estate,TupleTableSlot*slot,
449+
CmdTypecmdtype)
450+
{
451+
Relationrel=resultRelInfo->ri_RelationDesc;
452+
TupleDesctupdesc=RelationGetDescr(rel);
453+
intnatts=tupdesc->natts;
454+
ExprContext*econtext=GetPerTupleExprContext(estate);
455+
MemoryContextoldContext;
456+
Datum*values;
457+
bool*nulls;
458+
459+
/* We should not be called unless this is true */
460+
Assert(tupdesc->constr&&tupdesc->constr->has_generated_stored);
461+
462+
/*
463+
* For relations named directly in the query, ExecInitStoredGenerated
464+
* should have been called already; but this might not have happened yet
465+
* for a partition child rel. Also, it's convenient for outside callers
466+
* to not have to call ExecInitStoredGenerated explicitly.
467+
*/
468+
if (resultRelInfo->ri_GeneratedExprs==NULL)
469+
ExecInitStoredGenerated(resultRelInfo,estate,cmdtype);
470+
419471
/*
420472
* If no generated columns have been affected by this change, then skip
421473
* the rest.
@@ -435,14 +487,13 @@ ExecComputeStoredGenerated(ResultRelInfo *resultRelInfo,
435487
{
436488
Form_pg_attributeattr=TupleDescAttr(tupdesc,i);
437489

438-
if (attr->attgenerated==ATTRIBUTE_GENERATED_STORED&&
439-
resultRelInfo->ri_GeneratedExprs[i])
490+
if (resultRelInfo->ri_GeneratedExprs[i])
440491
{
441-
ExprContext*econtext;
442492
Datumval;
443493
boolisnull;
444494

445-
econtext=GetPerTupleExprContext(estate);
495+
Assert(attr->attgenerated==ATTRIBUTE_GENERATED_STORED);
496+
446497
econtext->ecxt_scantuple=slot;
447498

448499
val=ExecEvalExpr(resultRelInfo->ri_GeneratedExprs[i],econtext,&isnull);
@@ -4088,6 +4139,15 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
40884139
elog(ERROR,"could not find junk wholerow column");
40894140
}
40904141
}
4142+
4143+
/*
4144+
* For INSERT and UPDATE, prepare to evaluate any generated columns.
4145+
* We must do this now, even if we never insert or update any rows,
4146+
* because we have to fill resultRelInfo->ri_extraUpdatedCols for
4147+
* possible use by the trigger machinery.
4148+
*/
4149+
if (operation==CMD_INSERT||operation==CMD_UPDATE)
4150+
ExecInitStoredGenerated(resultRelInfo,estate,operation);
40914151
}
40924152

40934153
/*

‎src/backend/nodes/outfuncs.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -561,7 +561,6 @@ _outRangeTblEntry(StringInfo str, const RangeTblEntry *node)
561561
WRITE_BOOL_FIELD(lateral);
562562
WRITE_BOOL_FIELD(inh);
563563
WRITE_BOOL_FIELD(inFromCl);
564-
WRITE_BITMAPSET_FIELD(extraUpdatedCols);
565564
WRITE_NODE_FIELD(securityQuals);
566565
}
567566

‎src/backend/nodes/readfuncs.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -537,7 +537,6 @@ _readRangeTblEntry(void)
537537
READ_BOOL_FIELD(lateral);
538538
READ_BOOL_FIELD(inh);
539539
READ_BOOL_FIELD(inFromCl);
540-
READ_BITMAPSET_FIELD(extraUpdatedCols);
541540
READ_NODE_FIELD(securityQuals);
542541

543542
READ_DONE();

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp