mirror of
https://github.com/postgres/postgres.git
synced 2025-05-21 15:54:08 +03:00
BRIN: be more strict about required support procs
With improperly defined operator classes, it's possible to get a Postgres crash because we'd try to invoke a procedure that doesn't exist. This is because the code is being a bit too trusting that the opclass is correctly defined. Add some ereport(ERROR)s for cases where mandatory support procedures are not defined, transforming the crashes into errors. The particular case that was reported is an incomplete opclass in PostGIS. Backpatch all the way down to 13. Reported-by: Tobias Wendorff <tobias.wendorff@tu-dortmund.de> Diagnosed-by: David Rowley <dgrowleyml@gmail.com> Reviewed-by: Tomas Vondra <tomas@vondra.me> Discussion: https://postgr.es/m/fb6d9a35-6c8e-4869-af80-0a4944a793a4@tu-dortmund.de
This commit is contained in:
parent
f1ef111a09
commit
ade976f8b4
@ -439,7 +439,6 @@ typedef struct BloomOpaque
|
|||||||
* consistency. We may need additional procs in the future.
|
* consistency. We may need additional procs in the future.
|
||||||
*/
|
*/
|
||||||
FmgrInfo extra_procinfos[BLOOM_MAX_PROCNUMS];
|
FmgrInfo extra_procinfos[BLOOM_MAX_PROCNUMS];
|
||||||
bool extra_proc_missing[BLOOM_MAX_PROCNUMS];
|
|
||||||
} BloomOpaque;
|
} BloomOpaque;
|
||||||
|
|
||||||
static FmgrInfo *bloom_get_procinfo(BrinDesc *bdesc, uint16 attno,
|
static FmgrInfo *bloom_get_procinfo(BrinDesc *bdesc, uint16 attno,
|
||||||
@ -715,27 +714,19 @@ bloom_get_procinfo(BrinDesc *bdesc, uint16 attno, uint16 procnum)
|
|||||||
*/
|
*/
|
||||||
opaque = (BloomOpaque *) bdesc->bd_info[attno - 1]->oi_opaque;
|
opaque = (BloomOpaque *) bdesc->bd_info[attno - 1]->oi_opaque;
|
||||||
|
|
||||||
/*
|
|
||||||
* If we already searched for this proc and didn't find it, don't bother
|
|
||||||
* searching again.
|
|
||||||
*/
|
|
||||||
if (opaque->extra_proc_missing[basenum])
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (opaque->extra_procinfos[basenum].fn_oid == InvalidOid)
|
if (opaque->extra_procinfos[basenum].fn_oid == InvalidOid)
|
||||||
{
|
{
|
||||||
if (RegProcedureIsValid(index_getprocid(bdesc->bd_index, attno,
|
if (RegProcedureIsValid(index_getprocid(bdesc->bd_index, attno,
|
||||||
procnum)))
|
procnum)))
|
||||||
{
|
|
||||||
fmgr_info_copy(&opaque->extra_procinfos[basenum],
|
fmgr_info_copy(&opaque->extra_procinfos[basenum],
|
||||||
index_getprocinfo(bdesc->bd_index, attno, procnum),
|
index_getprocinfo(bdesc->bd_index, attno, procnum),
|
||||||
bdesc->bd_context);
|
bdesc->bd_context);
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
ereport(ERROR,
|
||||||
opaque->extra_proc_missing[basenum] = true;
|
errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
||||||
return NULL;
|
errmsg_internal("invalid opclass definition"),
|
||||||
}
|
errdetail_internal("The operator class is missing support function %d for column %d.",
|
||||||
|
procnum, attno));
|
||||||
}
|
}
|
||||||
|
|
||||||
return &opaque->extra_procinfos[basenum];
|
return &opaque->extra_procinfos[basenum];
|
||||||
|
@ -82,7 +82,7 @@ typedef struct InclusionOpaque
|
|||||||
} InclusionOpaque;
|
} InclusionOpaque;
|
||||||
|
|
||||||
static FmgrInfo *inclusion_get_procinfo(BrinDesc *bdesc, uint16 attno,
|
static FmgrInfo *inclusion_get_procinfo(BrinDesc *bdesc, uint16 attno,
|
||||||
uint16 procnum);
|
uint16 procnum, bool missing_ok);
|
||||||
static FmgrInfo *inclusion_get_strategy_procinfo(BrinDesc *bdesc, uint16 attno,
|
static FmgrInfo *inclusion_get_strategy_procinfo(BrinDesc *bdesc, uint16 attno,
|
||||||
Oid subtype, uint16 strategynum);
|
Oid subtype, uint16 strategynum);
|
||||||
|
|
||||||
@ -179,7 +179,7 @@ brin_inclusion_add_value(PG_FUNCTION_ARGS)
|
|||||||
* new value for emptiness; if it returns true, we need to set the
|
* new value for emptiness; if it returns true, we need to set the
|
||||||
* "contains empty" flag in the element (unless already set).
|
* "contains empty" flag in the element (unless already set).
|
||||||
*/
|
*/
|
||||||
finfo = inclusion_get_procinfo(bdesc, attno, PROCNUM_EMPTY);
|
finfo = inclusion_get_procinfo(bdesc, attno, PROCNUM_EMPTY, true);
|
||||||
if (finfo != NULL && DatumGetBool(FunctionCall1Coll(finfo, colloid, newval)))
|
if (finfo != NULL && DatumGetBool(FunctionCall1Coll(finfo, colloid, newval)))
|
||||||
{
|
{
|
||||||
if (!DatumGetBool(column->bv_values[INCLUSION_CONTAINS_EMPTY]))
|
if (!DatumGetBool(column->bv_values[INCLUSION_CONTAINS_EMPTY]))
|
||||||
@ -195,7 +195,7 @@ brin_inclusion_add_value(PG_FUNCTION_ARGS)
|
|||||||
PG_RETURN_BOOL(true);
|
PG_RETURN_BOOL(true);
|
||||||
|
|
||||||
/* Check if the new value is already contained. */
|
/* Check if the new value is already contained. */
|
||||||
finfo = inclusion_get_procinfo(bdesc, attno, PROCNUM_CONTAINS);
|
finfo = inclusion_get_procinfo(bdesc, attno, PROCNUM_CONTAINS, true);
|
||||||
if (finfo != NULL &&
|
if (finfo != NULL &&
|
||||||
DatumGetBool(FunctionCall2Coll(finfo, colloid,
|
DatumGetBool(FunctionCall2Coll(finfo, colloid,
|
||||||
column->bv_values[INCLUSION_UNION],
|
column->bv_values[INCLUSION_UNION],
|
||||||
@ -210,7 +210,7 @@ brin_inclusion_add_value(PG_FUNCTION_ARGS)
|
|||||||
* it's not going to be used any longer. However, the BRIN framework
|
* it's not going to be used any longer. However, the BRIN framework
|
||||||
* doesn't allow for the value not being present. Improve someday.
|
* doesn't allow for the value not being present. Improve someday.
|
||||||
*/
|
*/
|
||||||
finfo = inclusion_get_procinfo(bdesc, attno, PROCNUM_MERGEABLE);
|
finfo = inclusion_get_procinfo(bdesc, attno, PROCNUM_MERGEABLE, true);
|
||||||
if (finfo != NULL &&
|
if (finfo != NULL &&
|
||||||
!DatumGetBool(FunctionCall2Coll(finfo, colloid,
|
!DatumGetBool(FunctionCall2Coll(finfo, colloid,
|
||||||
column->bv_values[INCLUSION_UNION],
|
column->bv_values[INCLUSION_UNION],
|
||||||
@ -221,8 +221,7 @@ brin_inclusion_add_value(PG_FUNCTION_ARGS)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Finally, merge the new value to the existing union. */
|
/* Finally, merge the new value to the existing union. */
|
||||||
finfo = inclusion_get_procinfo(bdesc, attno, PROCNUM_MERGE);
|
finfo = inclusion_get_procinfo(bdesc, attno, PROCNUM_MERGE, false);
|
||||||
Assert(finfo != NULL);
|
|
||||||
result = FunctionCall2Coll(finfo, colloid,
|
result = FunctionCall2Coll(finfo, colloid,
|
||||||
column->bv_values[INCLUSION_UNION], newval);
|
column->bv_values[INCLUSION_UNION], newval);
|
||||||
if (!attr->attbyval &&
|
if (!attr->attbyval &&
|
||||||
@ -506,7 +505,7 @@ brin_inclusion_union(PG_FUNCTION_ARGS)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Check if A and B are mergeable; if not, mark A unmergeable. */
|
/* Check if A and B are mergeable; if not, mark A unmergeable. */
|
||||||
finfo = inclusion_get_procinfo(bdesc, attno, PROCNUM_MERGEABLE);
|
finfo = inclusion_get_procinfo(bdesc, attno, PROCNUM_MERGEABLE, true);
|
||||||
if (finfo != NULL &&
|
if (finfo != NULL &&
|
||||||
!DatumGetBool(FunctionCall2Coll(finfo, colloid,
|
!DatumGetBool(FunctionCall2Coll(finfo, colloid,
|
||||||
col_a->bv_values[INCLUSION_UNION],
|
col_a->bv_values[INCLUSION_UNION],
|
||||||
@ -517,8 +516,7 @@ brin_inclusion_union(PG_FUNCTION_ARGS)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Finally, merge B to A. */
|
/* Finally, merge B to A. */
|
||||||
finfo = inclusion_get_procinfo(bdesc, attno, PROCNUM_MERGE);
|
finfo = inclusion_get_procinfo(bdesc, attno, PROCNUM_MERGE, false);
|
||||||
Assert(finfo != NULL);
|
|
||||||
result = FunctionCall2Coll(finfo, colloid,
|
result = FunctionCall2Coll(finfo, colloid,
|
||||||
col_a->bv_values[INCLUSION_UNION],
|
col_a->bv_values[INCLUSION_UNION],
|
||||||
col_b->bv_values[INCLUSION_UNION]);
|
col_b->bv_values[INCLUSION_UNION]);
|
||||||
@ -539,10 +537,12 @@ brin_inclusion_union(PG_FUNCTION_ARGS)
|
|||||||
* Cache and return inclusion opclass support procedure
|
* Cache and return inclusion opclass support procedure
|
||||||
*
|
*
|
||||||
* Return the procedure corresponding to the given function support number
|
* Return the procedure corresponding to the given function support number
|
||||||
* or null if it is not exists.
|
* or null if it is not exists. If missing_ok is true and the procedure
|
||||||
|
* isn't set up for this opclass, return NULL instead of raising an error.
|
||||||
*/
|
*/
|
||||||
static FmgrInfo *
|
static FmgrInfo *
|
||||||
inclusion_get_procinfo(BrinDesc *bdesc, uint16 attno, uint16 procnum)
|
inclusion_get_procinfo(BrinDesc *bdesc, uint16 attno, uint16 procnum,
|
||||||
|
bool missing_ok)
|
||||||
{
|
{
|
||||||
InclusionOpaque *opaque;
|
InclusionOpaque *opaque;
|
||||||
uint16 basenum = procnum - PROCNUM_BASE;
|
uint16 basenum = procnum - PROCNUM_BASE;
|
||||||
@ -564,13 +564,18 @@ inclusion_get_procinfo(BrinDesc *bdesc, uint16 attno, uint16 procnum)
|
|||||||
{
|
{
|
||||||
if (RegProcedureIsValid(index_getprocid(bdesc->bd_index, attno,
|
if (RegProcedureIsValid(index_getprocid(bdesc->bd_index, attno,
|
||||||
procnum)))
|
procnum)))
|
||||||
{
|
|
||||||
fmgr_info_copy(&opaque->extra_procinfos[basenum],
|
fmgr_info_copy(&opaque->extra_procinfos[basenum],
|
||||||
index_getprocinfo(bdesc->bd_index, attno, procnum),
|
index_getprocinfo(bdesc->bd_index, attno, procnum),
|
||||||
bdesc->bd_context);
|
bdesc->bd_context);
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if (!missing_ok)
|
||||||
|
ereport(ERROR,
|
||||||
|
errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
||||||
|
errmsg_internal("invalid opclass definition"),
|
||||||
|
errdetail_internal("The operator class is missing support function %d for column %d.",
|
||||||
|
procnum, attno));
|
||||||
|
|
||||||
opaque->extra_proc_missing[basenum] = true;
|
opaque->extra_proc_missing[basenum] = true;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -111,7 +111,6 @@
|
|||||||
typedef struct MinmaxMultiOpaque
|
typedef struct MinmaxMultiOpaque
|
||||||
{
|
{
|
||||||
FmgrInfo extra_procinfos[MINMAX_MAX_PROCNUMS];
|
FmgrInfo extra_procinfos[MINMAX_MAX_PROCNUMS];
|
||||||
bool extra_proc_missing[MINMAX_MAX_PROCNUMS];
|
|
||||||
Oid cached_subtype;
|
Oid cached_subtype;
|
||||||
FmgrInfo strategy_procinfos[BTMaxStrategyNumber];
|
FmgrInfo strategy_procinfos[BTMaxStrategyNumber];
|
||||||
} MinmaxMultiOpaque;
|
} MinmaxMultiOpaque;
|
||||||
@ -2872,27 +2871,19 @@ minmax_multi_get_procinfo(BrinDesc *bdesc, uint16 attno, uint16 procnum)
|
|||||||
*/
|
*/
|
||||||
opaque = (MinmaxMultiOpaque *) bdesc->bd_info[attno - 1]->oi_opaque;
|
opaque = (MinmaxMultiOpaque *) bdesc->bd_info[attno - 1]->oi_opaque;
|
||||||
|
|
||||||
/*
|
|
||||||
* If we already searched for this proc and didn't find it, don't bother
|
|
||||||
* searching again.
|
|
||||||
*/
|
|
||||||
if (opaque->extra_proc_missing[basenum])
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (opaque->extra_procinfos[basenum].fn_oid == InvalidOid)
|
if (opaque->extra_procinfos[basenum].fn_oid == InvalidOid)
|
||||||
{
|
{
|
||||||
if (RegProcedureIsValid(index_getprocid(bdesc->bd_index, attno,
|
if (RegProcedureIsValid(index_getprocid(bdesc->bd_index, attno,
|
||||||
procnum)))
|
procnum)))
|
||||||
{
|
|
||||||
fmgr_info_copy(&opaque->extra_procinfos[basenum],
|
fmgr_info_copy(&opaque->extra_procinfos[basenum],
|
||||||
index_getprocinfo(bdesc->bd_index, attno, procnum),
|
index_getprocinfo(bdesc->bd_index, attno, procnum),
|
||||||
bdesc->bd_context);
|
bdesc->bd_context);
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
ereport(ERROR,
|
||||||
opaque->extra_proc_missing[basenum] = true;
|
errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
|
||||||
return NULL;
|
errmsg_internal("invalid opclass definition"),
|
||||||
}
|
errdetail_internal("The operator class is missing support function %d for column %d.",
|
||||||
|
procnum, attno));
|
||||||
}
|
}
|
||||||
|
|
||||||
return &opaque->extra_procinfos[basenum];
|
return &opaque->extra_procinfos[basenum];
|
||||||
|
Loading…
x
Reference in New Issue
Block a user