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

Commitefdc53e

Browse files
authored
Merge branch 'postgres:master' into master
2 parents75c0054 +b006bcd commitefdc53e

File tree

16 files changed

+461
-77
lines changed

16 files changed

+461
-77
lines changed

‎contrib/postgres_fdw/postgres_fdw.c

Lines changed: 35 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,7 @@ typedef struct PgFdwDirectModifyState
240240
PGresult*result;/* result for query */
241241
intnum_tuples;/* # of result tuples */
242242
intnext_tuple;/* index of next one to return */
243+
MemoryContextCallbackresult_cb;/* ensures result will get freed */
243244
RelationresultRel;/* relcache entry for the target relation */
244245
AttrNumber*attnoMap;/* array of attnums of input user columns */
245246
AttrNumberctidAttno;/* attnum of input ctid column */
@@ -2670,6 +2671,17 @@ postgresBeginDirectModify(ForeignScanState *node, int eflags)
26702671
dmstate= (PgFdwDirectModifyState*)palloc0(sizeof(PgFdwDirectModifyState));
26712672
node->fdw_state=dmstate;
26722673

2674+
/*
2675+
* We use a memory context callback to ensure that the dmstate's PGresult
2676+
* (if any) will be released, even if the query fails somewhere that's
2677+
* outside our control. The callback is always armed for the duration of
2678+
* the query; this relies on PQclear(NULL) being a no-op.
2679+
*/
2680+
dmstate->result_cb.func= (MemoryContextCallbackFunction)PQclear;
2681+
dmstate->result_cb.arg=NULL;
2682+
MemoryContextRegisterResetCallback(CurrentMemoryContext,
2683+
&dmstate->result_cb);
2684+
26732685
/*
26742686
* Identify which user to do the remote access as. This should match what
26752687
* ExecCheckPermissions() does.
@@ -2817,7 +2829,13 @@ postgresEndDirectModify(ForeignScanState *node)
28172829
return;
28182830

28192831
/* Release PGresult */
2820-
PQclear(dmstate->result);
2832+
if (dmstate->result)
2833+
{
2834+
PQclear(dmstate->result);
2835+
dmstate->result=NULL;
2836+
/* ... and don't forget to disable the callback */
2837+
dmstate->result_cb.arg=NULL;
2838+
}
28212839

28222840
/* Release remote connection */
28232841
ReleaseConnection(dmstate->conn);
@@ -4591,13 +4609,17 @@ execute_dml_stmt(ForeignScanState *node)
45914609
/*
45924610
* Get the result, and check for success.
45934611
*
4594-
* We don't use a PG_TRY block here, so be careful not to throw error
4595-
* without releasing the PGresult.
4612+
* We use a memory context callback to ensure that the PGresult will be
4613+
* released, even if the query fails somewhere that's outside our control.
4614+
* The callback is already registered, just need to fill in its arg.
45964615
*/
4616+
Assert(dmstate->result==NULL);
45974617
dmstate->result=pgfdw_get_result(dmstate->conn);
4618+
dmstate->result_cb.arg=dmstate->result;
4619+
45984620
if (PQresultStatus(dmstate->result)!=
45994621
(dmstate->has_returning ?PGRES_TUPLES_OK :PGRES_COMMAND_OK))
4600-
pgfdw_report_error(ERROR,dmstate->result,dmstate->conn,true,
4622+
pgfdw_report_error(ERROR,dmstate->result,dmstate->conn,false,
46014623
dmstate->query);
46024624

46034625
/* Get the number of rows affected. */
@@ -4641,30 +4663,16 @@ get_returning_data(ForeignScanState *node)
46414663
}
46424664
else
46434665
{
4644-
/*
4645-
* On error, be sure to release the PGresult on the way out. Callers
4646-
* do not have PG_TRY blocks to ensure this happens.
4647-
*/
4648-
PG_TRY();
4649-
{
4650-
HeapTuplenewtup;
4651-
4652-
newtup=make_tuple_from_result_row(dmstate->result,
4653-
dmstate->next_tuple,
4654-
dmstate->rel,
4655-
dmstate->attinmeta,
4656-
dmstate->retrieved_attrs,
4657-
node,
4658-
dmstate->temp_cxt);
4659-
ExecStoreHeapTuple(newtup,slot, false);
4660-
}
4661-
PG_CATCH();
4662-
{
4663-
PQclear(dmstate->result);
4664-
PG_RE_THROW();
4665-
}
4666-
PG_END_TRY();
4666+
HeapTuplenewtup;
46674667

4668+
newtup=make_tuple_from_result_row(dmstate->result,
4669+
dmstate->next_tuple,
4670+
dmstate->rel,
4671+
dmstate->attinmeta,
4672+
dmstate->retrieved_attrs,
4673+
node,
4674+
dmstate->temp_cxt);
4675+
ExecStoreHeapTuple(newtup,slot, false);
46684676
/* Get the updated/deleted tuple. */
46694677
if (dmstate->rel)
46704678
resultSlot=slot;

‎src/backend/access/heap/heapam.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,27 @@ static const int MultiXactStatusLock[MaxMultiXactStatus + 1] =
213213
#defineTUPLOCK_from_mxstatus(status) \
214214
(MultiXactStatusLock[(status)])
215215

216+
/*
217+
* Check that we have a valid snapshot if we might need TOAST access.
218+
*/
219+
staticinlinevoid
220+
AssertHasSnapshotForToast(Relationrel)
221+
{
222+
#ifdefUSE_ASSERT_CHECKING
223+
224+
/* bootstrap mode in particular breaks this rule */
225+
if (!IsNormalProcessingMode())
226+
return;
227+
228+
/* if the relation doesn't have a TOAST table, we are good */
229+
if (!OidIsValid(rel->rd_rel->reltoastrelid))
230+
return;
231+
232+
Assert(HaveRegisteredOrActiveSnapshot());
233+
234+
#endif/* USE_ASSERT_CHECKING */
235+
}
236+
216237
/* ----------------------------------------------------------------
217238
* heap support routines
218239
* ----------------------------------------------------------------
@@ -2066,6 +2087,8 @@ heap_insert(Relation relation, HeapTuple tup, CommandId cid,
20662087
Assert(HeapTupleHeaderGetNatts(tup->t_data) <=
20672088
RelationGetNumberOfAttributes(relation));
20682089

2090+
AssertHasSnapshotForToast(relation);
2091+
20692092
/*
20702093
* Fill in tuple header fields and toast the tuple if necessary.
20712094
*
@@ -2343,6 +2366,8 @@ heap_multi_insert(Relation relation, TupleTableSlot **slots, int ntuples,
23432366
/* currently not needed (thus unsupported) for heap_multi_insert() */
23442367
Assert(!(options&HEAP_INSERT_NO_LOGICAL));
23452368

2369+
AssertHasSnapshotForToast(relation);
2370+
23462371
needwal=RelationNeedsWAL(relation);
23472372
saveFreeSpace=RelationGetTargetPageFreeSpace(relation,
23482373
HEAP_DEFAULT_FILLFACTOR);
@@ -2765,6 +2790,8 @@ heap_delete(Relation relation, ItemPointer tid,
27652790

27662791
Assert(ItemPointerIsValid(tid));
27672792

2793+
AssertHasSnapshotForToast(relation);
2794+
27682795
/*
27692796
* Forbid this during a parallel operation, lest it allocate a combo CID.
27702797
* Other workers might need that combo CID for visibility checks, and we
@@ -3260,6 +3287,8 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup,
32603287
Assert(HeapTupleHeaderGetNatts(newtup->t_data) <=
32613288
RelationGetNumberOfAttributes(relation));
32623289

3290+
AssertHasSnapshotForToast(relation);
3291+
32633292
/*
32643293
* Forbid this during a parallel operation, lest it allocate a combo CID.
32653294
* Other workers might need that combo CID for visibility checks, and we

‎src/backend/commands/indexcmds.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4226,7 +4226,7 @@ ReindexRelationConcurrently(const ReindexStmt *stmt, Oid relationOid, const Rein
42264226
false);
42274227

42284228
/*
4229-
*Updating pg_index might involve TOAST table access, so ensure we
4229+
*Swapping the indexes might involve TOAST table access, so ensure we
42304230
* have a valid snapshot.
42314231
*/
42324232
PushActiveSnapshot(GetTransactionSnapshot());

‎src/backend/commands/tablecmds.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20964,9 +20964,17 @@ ATExecDetachPartition(List **wqueue, AlteredTableInfo *tab, Relation rel,
2096420964
tab->rel = rel;
2096520965
}
2096620966

20967+
/*
20968+
* Detaching the partition might involve TOAST table access, so ensure we
20969+
* have a valid snapshot.
20970+
*/
20971+
PushActiveSnapshot(GetTransactionSnapshot());
20972+
2096720973
/* Do the final part of detaching */
2096820974
DetachPartitionFinalize(rel, partRel, concurrent, defaultPartOid);
2096920975

20976+
PopActiveSnapshot();
20977+
2097020978
ObjectAddressSet(address, RelationRelationId, RelationGetRelid(partRel));
2097120979

2097220980
/* keep our lock until commit */

‎src/backend/executor/nodeModifyTable.c

Lines changed: 127 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
#include"nodes/nodeFuncs.h"
6565
#include"optimizer/optimizer.h"
6666
#include"rewrite/rewriteHandler.h"
67+
#include"rewrite/rewriteManip.h"
6768
#include"storage/lmgr.h"
6869
#include"utils/builtins.h"
6970
#include"utils/datum.h"
@@ -3735,6 +3736,7 @@ ExecInitMerge(ModifyTableState *mtstate, EState *estate)
37353736
switch (action->commandType)
37363737
{
37373738
caseCMD_INSERT:
3739+
/* INSERT actions always use rootRelInfo */
37383740
ExecCheckPlanOutput(rootRelInfo->ri_RelationDesc,
37393741
action->targetList);
37403742

@@ -3774,9 +3776,23 @@ ExecInitMerge(ModifyTableState *mtstate, EState *estate)
37743776
}
37753777
else
37763778
{
3777-
/* not partitioned? use the stock relation and slot */
3778-
tgtslot=resultRelInfo->ri_newTupleSlot;
3779-
tgtdesc=RelationGetDescr(resultRelInfo->ri_RelationDesc);
3779+
/*
3780+
* If the MERGE targets an inherited table, we insert
3781+
* into the root table, so we must initialize its
3782+
* "new" tuple slot, if not already done, and use its
3783+
* relation descriptor for the projection.
3784+
*
3785+
* For non-inherited tables, rootRelInfo and
3786+
* resultRelInfo are the same, and the "new" tuple
3787+
* slot will already have been initialized.
3788+
*/
3789+
if (rootRelInfo->ri_newTupleSlot==NULL)
3790+
rootRelInfo->ri_newTupleSlot=
3791+
table_slot_create(rootRelInfo->ri_RelationDesc,
3792+
&estate->es_tupleTable);
3793+
3794+
tgtslot=rootRelInfo->ri_newTupleSlot;
3795+
tgtdesc=RelationGetDescr(rootRelInfo->ri_RelationDesc);
37803796
}
37813797

37823798
action_state->mas_proj=
@@ -3809,6 +3825,114 @@ ExecInitMerge(ModifyTableState *mtstate, EState *estate)
38093825
}
38103826
}
38113827
}
3828+
3829+
/*
3830+
* If the MERGE targets an inherited table, any INSERT actions will use
3831+
* rootRelInfo, and rootRelInfo will not be in the resultRelInfo array.
3832+
* Therefore we must initialize its WITH CHECK OPTION constraints and
3833+
* RETURNING projection, as ExecInitModifyTable did for the resultRelInfo
3834+
* entries.
3835+
*
3836+
* Note that the planner does not build a withCheckOptionList or
3837+
* returningList for the root relation, but as in ExecInitPartitionInfo,
3838+
* we can use the first resultRelInfo entry as a reference to calculate
3839+
* the attno's for the root table.
3840+
*/
3841+
if (rootRelInfo!=mtstate->resultRelInfo&&
3842+
rootRelInfo->ri_RelationDesc->rd_rel->relkind!=RELKIND_PARTITIONED_TABLE&&
3843+
(mtstate->mt_merge_subcommands&MERGE_INSERT)!=0)
3844+
{
3845+
ModifyTable*node= (ModifyTable*)mtstate->ps.plan;
3846+
RelationrootRelation=rootRelInfo->ri_RelationDesc;
3847+
RelationfirstResultRel=mtstate->resultRelInfo[0].ri_RelationDesc;
3848+
intfirstVarno=mtstate->resultRelInfo[0].ri_RangeTableIndex;
3849+
AttrMap*part_attmap=NULL;
3850+
boolfound_whole_row;
3851+
3852+
if (node->withCheckOptionLists!=NIL)
3853+
{
3854+
List*wcoList;
3855+
List*wcoExprs=NIL;
3856+
3857+
/* There should be as many WCO lists as result rels */
3858+
Assert(list_length(node->withCheckOptionLists)==
3859+
list_length(node->resultRelations));
3860+
3861+
/*
3862+
* Use the first WCO list as a reference. In the most common case,
3863+
* this will be for the same relation as rootRelInfo, and so there
3864+
* will be no need to adjust its attno's.
3865+
*/
3866+
wcoList=linitial(node->withCheckOptionLists);
3867+
if (rootRelation!=firstResultRel)
3868+
{
3869+
/* Convert any Vars in it to contain the root's attno's */
3870+
part_attmap=
3871+
build_attrmap_by_name(RelationGetDescr(rootRelation),
3872+
RelationGetDescr(firstResultRel),
3873+
false);
3874+
3875+
wcoList= (List*)
3876+
map_variable_attnos((Node*)wcoList,
3877+
firstVarno,0,
3878+
part_attmap,
3879+
RelationGetForm(rootRelation)->reltype,
3880+
&found_whole_row);
3881+
}
3882+
3883+
foreach(lc,wcoList)
3884+
{
3885+
WithCheckOption*wco=lfirst_node(WithCheckOption,lc);
3886+
ExprState*wcoExpr=ExecInitQual(castNode(List,wco->qual),
3887+
&mtstate->ps);
3888+
3889+
wcoExprs=lappend(wcoExprs,wcoExpr);
3890+
}
3891+
3892+
rootRelInfo->ri_WithCheckOptions=wcoList;
3893+
rootRelInfo->ri_WithCheckOptionExprs=wcoExprs;
3894+
}
3895+
3896+
if (node->returningLists!=NIL)
3897+
{
3898+
List*returningList;
3899+
3900+
/* There should be as many returning lists as result rels */
3901+
Assert(list_length(node->returningLists)==
3902+
list_length(node->resultRelations));
3903+
3904+
/*
3905+
* Use the first returning list as a reference. In the most common
3906+
* case, this will be for the same relation as rootRelInfo, and so
3907+
* there will be no need to adjust its attno's.
3908+
*/
3909+
returningList=linitial(node->returningLists);
3910+
if (rootRelation!=firstResultRel)
3911+
{
3912+
/* Convert any Vars in it to contain the root's attno's */
3913+
if (part_attmap==NULL)
3914+
part_attmap=
3915+
build_attrmap_by_name(RelationGetDescr(rootRelation),
3916+
RelationGetDescr(firstResultRel),
3917+
false);
3918+
3919+
returningList= (List*)
3920+
map_variable_attnos((Node*)returningList,
3921+
firstVarno,0,
3922+
part_attmap,
3923+
RelationGetForm(rootRelation)->reltype,
3924+
&found_whole_row);
3925+
}
3926+
rootRelInfo->ri_returningList=returningList;
3927+
3928+
/* Initialize the RETURNING projection */
3929+
rootRelInfo->ri_projectReturning=
3930+
ExecBuildProjectionInfo(returningList,econtext,
3931+
mtstate->ps.ps_ResultTupleSlot,
3932+
&mtstate->ps,
3933+
RelationGetDescr(rootRelation));
3934+
}
3935+
}
38123936
}
38133937

38143938
/*

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp