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:
Heikki Linnakangas 2021-02-15 09:28:08 +02:00
parent 46d6e5f567
commit 54e51dcde0
2 changed files with 30 additions and 13 deletions

View File

@ -1230,10 +1230,10 @@ Bitmapset *
ExecGetInsertedCols(ResultRelInfo *relinfo, EState *estate) ExecGetInsertedCols(ResultRelInfo *relinfo, EState *estate)
{ {
/* /*
* The columns are stored in the range table entry. If this ResultRelInfo * 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 * represents a partition routing target, and doesn't have an entry of its
* partition routing target), fetch the parent's RTE and map the columns * own in the range table, fetch the parent's RTE and map the columns to
* to the order they are in the partition. * the order they are in the partition.
*/ */
if (relinfo->ri_RangeTableIndex != 0) if (relinfo->ri_RangeTableIndex != 0)
{ {
@ -1241,7 +1241,7 @@ ExecGetInsertedCols(ResultRelInfo *relinfo, EState *estate)
return rte->insertedCols; return rte->insertedCols;
} }
else else if (relinfo->ri_RootResultRelInfo)
{ {
ResultRelInfo *rootRelInfo = relinfo->ri_RootResultRelInfo; ResultRelInfo *rootRelInfo = relinfo->ri_RootResultRelInfo;
RangeTblEntry *rte = exec_rt_fetch(rootRelInfo->ri_RangeTableIndex, estate); RangeTblEntry *rte = exec_rt_fetch(rootRelInfo->ri_RangeTableIndex, estate);
@ -1252,6 +1252,16 @@ ExecGetInsertedCols(ResultRelInfo *relinfo, EState *estate)
else else
return rte->insertedCols; 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 */ /* Return a bitmap representing columns being updated */
@ -1265,7 +1275,7 @@ ExecGetUpdatedCols(ResultRelInfo *relinfo, EState *estate)
return rte->updatedCols; return rte->updatedCols;
} }
else else if (relinfo->ri_RootResultRelInfo)
{ {
ResultRelInfo *rootRelInfo = relinfo->ri_RootResultRelInfo; ResultRelInfo *rootRelInfo = relinfo->ri_RootResultRelInfo;
RangeTblEntry *rte = exec_rt_fetch(rootRelInfo->ri_RangeTableIndex, estate); RangeTblEntry *rte = exec_rt_fetch(rootRelInfo->ri_RangeTableIndex, estate);
@ -1276,6 +1286,8 @@ ExecGetUpdatedCols(ResultRelInfo *relinfo, EState *estate)
else else
return rte->updatedCols; return rte->updatedCols;
} }
else
return NULL;
} }
/* Return a bitmap representing generated columns being updated */ /* Return a bitmap representing generated columns being updated */
@ -1289,7 +1301,7 @@ ExecGetExtraUpdatedCols(ResultRelInfo *relinfo, EState *estate)
return rte->extraUpdatedCols; return rte->extraUpdatedCols;
} }
else else if (relinfo->ri_RootResultRelInfo)
{ {
ResultRelInfo *rootRelInfo = relinfo->ri_RootResultRelInfo; ResultRelInfo *rootRelInfo = relinfo->ri_RootResultRelInfo;
RangeTblEntry *rte = exec_rt_fetch(rootRelInfo->ri_RangeTableIndex, estate); RangeTblEntry *rte = exec_rt_fetch(rootRelInfo->ri_RangeTableIndex, estate);
@ -1300,6 +1312,8 @@ ExecGetExtraUpdatedCols(ResultRelInfo *relinfo, EState *estate)
else else
return rte->extraUpdatedCols; return rte->extraUpdatedCols;
} }
else
return NULL;
} }
/* Return columns being updated, including generated columns */ /* Return columns being updated, including generated columns */

View File

@ -394,12 +394,15 @@ typedef struct OnConflictSetState
* relation, and perhaps also fire triggers. ResultRelInfo holds all the * relation, and perhaps also fire triggers. ResultRelInfo holds all the
* information needed about a result relation, including indexes. * information needed about a result relation, including indexes.
* *
* Normally, a ResultRelInfo refers to a table that is in the query's * Normally, a ResultRelInfo refers to a table that is in the query's range
* range table; then ri_RangeTableIndex is the RT index and ri_RelationDesc * table; then ri_RangeTableIndex is the RT index and ri_RelationDesc is
* is just a copy of the relevant es_relations[] entry. But sometimes, * just a copy of the relevant es_relations[] entry. However, in some
* in ResultRelInfos used only for triggers, ri_RangeTableIndex is zero * situations we create ResultRelInfos for relations that are not in the
* and ri_RelationDesc is a separately-opened relcache pointer that needs * range table, namely for targets of tuple routing in a partitioned table,
* to be separately closed. See ExecGetTriggerResultRel. * 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 typedef struct ResultRelInfo
{ {