mirror of
https://github.com/postgres/postgres.git
synced 2025-05-08 07:21:33 +03:00
Make ExecGetInsertedCols() and friends more robust and improve comments.
If ExecGetInsertedCols(), ExecGetUpdatedCols() or ExecGetExtraUpdatedCols() were called with a ResultRelInfo that's not in the range table and isn't a partition routing target, the functions would dereference a NULL pointer, relinfo->ri_RootResultRelInfo. Such ResultRelInfos are created when firing RI triggers in tables that are not modified directly. None of the current callers of these functions pass such relations, so this isn't a live bug, but let's make them more robust. Also update comment in ResultRelInfo; after commit 6214e2b228, ri_RangeTableIndex is zero for ResultRelInfos created for partition tuple routing. Noted by Coverity. Backpatch down to v11, like commit 6214e2b228. Reviewed-by: Tom Lane, Amit Langote
This commit is contained in:
parent
a27f3a7f41
commit
2b81444a88
@ -1182,10 +1182,10 @@ Bitmapset *
|
||||
ExecGetInsertedCols(ResultRelInfo *relinfo, EState *estate)
|
||||
{
|
||||
/*
|
||||
* The columns are stored in the range table entry. If this ResultRelInfo
|
||||
* doesn't have an entry in the range table (i.e. if it represents a
|
||||
* partition routing target), fetch the parent's RTE and map the columns
|
||||
* to the order they are in the partition.
|
||||
* The columns are stored in the range table entry. If this ResultRelInfo
|
||||
* represents a partition routing target, and doesn't have an entry of its
|
||||
* own in the range table, fetch the parent's RTE and map the columns to
|
||||
* the order they are in the partition.
|
||||
*/
|
||||
if (relinfo->ri_RangeTableIndex != 0)
|
||||
{
|
||||
@ -1193,7 +1193,7 @@ ExecGetInsertedCols(ResultRelInfo *relinfo, EState *estate)
|
||||
|
||||
return rte->insertedCols;
|
||||
}
|
||||
else
|
||||
else if (relinfo->ri_RootResultRelInfo)
|
||||
{
|
||||
ResultRelInfo *rootRelInfo = relinfo->ri_RootResultRelInfo;
|
||||
RangeTblEntry *rte = exec_rt_fetch(rootRelInfo->ri_RangeTableIndex, estate);
|
||||
@ -1205,6 +1205,16 @@ ExecGetInsertedCols(ResultRelInfo *relinfo, EState *estate)
|
||||
else
|
||||
return rte->insertedCols;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* The relation isn't in the range table and it isn't a partition
|
||||
* routing target. This ResultRelInfo must've been created only for
|
||||
* firing triggers and the relation is not being inserted into. (See
|
||||
* ExecGetTriggerResultRel.)
|
||||
*/
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return a bitmap representing columns being updated */
|
||||
@ -1218,7 +1228,7 @@ ExecGetUpdatedCols(ResultRelInfo *relinfo, EState *estate)
|
||||
|
||||
return rte->updatedCols;
|
||||
}
|
||||
else
|
||||
else if (relinfo->ri_RootResultRelInfo)
|
||||
{
|
||||
ResultRelInfo *rootRelInfo = relinfo->ri_RootResultRelInfo;
|
||||
RangeTblEntry *rte = exec_rt_fetch(rootRelInfo->ri_RangeTableIndex, estate);
|
||||
@ -1230,6 +1240,8 @@ ExecGetUpdatedCols(ResultRelInfo *relinfo, EState *estate)
|
||||
else
|
||||
return rte->updatedCols;
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Return a bitmap representing generated columns being updated */
|
||||
@ -1243,7 +1255,7 @@ ExecGetExtraUpdatedCols(ResultRelInfo *relinfo, EState *estate)
|
||||
|
||||
return rte->extraUpdatedCols;
|
||||
}
|
||||
else
|
||||
else if (relinfo->ri_RootResultRelInfo)
|
||||
{
|
||||
ResultRelInfo *rootRelInfo = relinfo->ri_RootResultRelInfo;
|
||||
RangeTblEntry *rte = exec_rt_fetch(rootRelInfo->ri_RangeTableIndex, estate);
|
||||
@ -1255,6 +1267,8 @@ ExecGetExtraUpdatedCols(ResultRelInfo *relinfo, EState *estate)
|
||||
else
|
||||
return rte->extraUpdatedCols;
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Return columns being updated, including generated columns */
|
||||
|
@ -392,12 +392,15 @@ typedef struct OnConflictSetState
|
||||
* relation, and perhaps also fire triggers. ResultRelInfo holds all the
|
||||
* information needed about a result relation, including indexes.
|
||||
*
|
||||
* Normally, a ResultRelInfo refers to a table that is in the query's
|
||||
* range table; then ri_RangeTableIndex is the RT index and ri_RelationDesc
|
||||
* is just a copy of the relevant es_relations[] entry. But sometimes,
|
||||
* in ResultRelInfos used only for triggers, ri_RangeTableIndex is zero
|
||||
* and ri_RelationDesc is a separately-opened relcache pointer that needs
|
||||
* to be separately closed. See ExecGetTriggerResultRel.
|
||||
* Normally, a ResultRelInfo refers to a table that is in the query's range
|
||||
* table; then ri_RangeTableIndex is the RT index and ri_RelationDesc is
|
||||
* just a copy of the relevant es_relations[] entry. However, in some
|
||||
* situations we create ResultRelInfos for relations that are not in the
|
||||
* range table, namely for targets of tuple routing in a partitioned table,
|
||||
* and when firing triggers in tables other than the target tables (See
|
||||
* ExecGetTriggerResultRel). In these situations, ri_RangeTableIndex is 0
|
||||
* and ri_RelationDesc is a separately-opened relcache pointer that needs to
|
||||
* be separately closed.
|
||||
*/
|
||||
typedef struct ResultRelInfo
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user