Skip to content

Commit 5144e1f

Browse files
committed
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
1 parent 136e68b commit 5144e1f

File tree

3 files changed

+28
-41
lines changed

3 files changed

+28
-41
lines changed

src/backend/access/brin/brin_bloom.c

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,6 @@ typedef struct BloomOpaque
412412
* consistency. We may need additional procs in the future.
413413
*/
414414
FmgrInfo extra_procinfos[BLOOM_MAX_PROCNUMS];
415-
bool extra_proc_missing[BLOOM_MAX_PROCNUMS];
416415
} BloomOpaque;
417416

418417
static FmgrInfo *bloom_get_procinfo(BrinDesc *bdesc, uint16 attno,
@@ -685,27 +684,19 @@ bloom_get_procinfo(BrinDesc *bdesc, uint16 attno, uint16 procnum)
685684
*/
686685
opaque = (BloomOpaque *) bdesc->bd_info[attno - 1]->oi_opaque;
687686

688-
/*
689-
* If we already searched for this proc and didn't find it, don't bother
690-
* searching again.
691-
*/
692-
if (opaque->extra_proc_missing[basenum])
693-
return NULL;
694-
695687
if (opaque->extra_procinfos[basenum].fn_oid == InvalidOid)
696688
{
697689
if (RegProcedureIsValid(index_getprocid(bdesc->bd_index, attno,
698690
procnum)))
699-
{
700691
fmgr_info_copy(&opaque->extra_procinfos[basenum],
701692
index_getprocinfo(bdesc->bd_index, attno, procnum),
702693
bdesc->bd_context);
703-
}
704694
else
705-
{
706-
opaque->extra_proc_missing[basenum] = true;
707-
return NULL;
708-
}
695+
ereport(ERROR,
696+
errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
697+
errmsg_internal("invalid opclass definition"),
698+
errdetail_internal("The operator class is missing support function %d for column %d.",
699+
procnum, attno));
709700
}
710701

711702
return &opaque->extra_procinfos[basenum];

src/backend/access/brin/brin_inclusion.c

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ typedef struct InclusionOpaque
8282
} InclusionOpaque;
8383

8484
static FmgrInfo *inclusion_get_procinfo(BrinDesc *bdesc, uint16 attno,
85-
uint16 procnum);
85+
uint16 procnum, bool missing_ok);
8686
static FmgrInfo *inclusion_get_strategy_procinfo(BrinDesc *bdesc, uint16 attno,
8787
Oid subtype, uint16 strategynum);
8888

@@ -179,7 +179,7 @@ brin_inclusion_add_value(PG_FUNCTION_ARGS)
179179
* new value for emptiness; if it returns true, we need to set the
180180
* "contains empty" flag in the element (unless already set).
181181
*/
182-
finfo = inclusion_get_procinfo(bdesc, attno, PROCNUM_EMPTY);
182+
finfo = inclusion_get_procinfo(bdesc, attno, PROCNUM_EMPTY, true);
183183
if (finfo != NULL && DatumGetBool(FunctionCall1Coll(finfo, colloid, newval)))
184184
{
185185
if (!DatumGetBool(column->bv_values[INCLUSION_CONTAINS_EMPTY]))
@@ -195,7 +195,7 @@ brin_inclusion_add_value(PG_FUNCTION_ARGS)
195195
PG_RETURN_BOOL(true);
196196

197197
/* Check if the new value is already contained. */
198-
finfo = inclusion_get_procinfo(bdesc, attno, PROCNUM_CONTAINS);
198+
finfo = inclusion_get_procinfo(bdesc, attno, PROCNUM_CONTAINS, true);
199199
if (finfo != NULL &&
200200
DatumGetBool(FunctionCall2Coll(finfo, colloid,
201201
column->bv_values[INCLUSION_UNION],
@@ -210,7 +210,7 @@ brin_inclusion_add_value(PG_FUNCTION_ARGS)
210210
* it's not going to be used any longer. However, the BRIN framework
211211
* doesn't allow for the value not being present. Improve someday.
212212
*/
213-
finfo = inclusion_get_procinfo(bdesc, attno, PROCNUM_MERGEABLE);
213+
finfo = inclusion_get_procinfo(bdesc, attno, PROCNUM_MERGEABLE, true);
214214
if (finfo != NULL &&
215215
!DatumGetBool(FunctionCall2Coll(finfo, colloid,
216216
column->bv_values[INCLUSION_UNION],
@@ -221,8 +221,7 @@ brin_inclusion_add_value(PG_FUNCTION_ARGS)
221221
}
222222

223223
/* Finally, merge the new value to the existing union. */
224-
finfo = inclusion_get_procinfo(bdesc, attno, PROCNUM_MERGE);
225-
Assert(finfo != NULL);
224+
finfo = inclusion_get_procinfo(bdesc, attno, PROCNUM_MERGE, false);
226225
result = FunctionCall2Coll(finfo, colloid,
227226
column->bv_values[INCLUSION_UNION], newval);
228227
if (!attr->attbyval &&
@@ -506,7 +505,7 @@ brin_inclusion_union(PG_FUNCTION_ARGS)
506505
}
507506

508507
/* Check if A and B are mergeable; if not, mark A unmergeable. */
509-
finfo = inclusion_get_procinfo(bdesc, attno, PROCNUM_MERGEABLE);
508+
finfo = inclusion_get_procinfo(bdesc, attno, PROCNUM_MERGEABLE, true);
510509
if (finfo != NULL &&
511510
!DatumGetBool(FunctionCall2Coll(finfo, colloid,
512511
col_a->bv_values[INCLUSION_UNION],
@@ -517,8 +516,7 @@ brin_inclusion_union(PG_FUNCTION_ARGS)
517516
}
518517

519518
/* Finally, merge B to A. */
520-
finfo = inclusion_get_procinfo(bdesc, attno, PROCNUM_MERGE);
521-
Assert(finfo != NULL);
519+
finfo = inclusion_get_procinfo(bdesc, attno, PROCNUM_MERGE, false);
522520
result = FunctionCall2Coll(finfo, colloid,
523521
col_a->bv_values[INCLUSION_UNION],
524522
col_b->bv_values[INCLUSION_UNION]);
@@ -539,10 +537,12 @@ brin_inclusion_union(PG_FUNCTION_ARGS)
539537
* Cache and return inclusion opclass support procedure
540538
*
541539
* Return the procedure corresponding to the given function support number
542-
* or null if it is not exists.
540+
* or null if it is not exists. If missing_ok is true and the procedure
541+
* isn't set up for this opclass, return NULL instead of raising an error.
543542
*/
544543
static FmgrInfo *
545-
inclusion_get_procinfo(BrinDesc *bdesc, uint16 attno, uint16 procnum)
544+
inclusion_get_procinfo(BrinDesc *bdesc, uint16 attno, uint16 procnum,
545+
bool missing_ok)
546546
{
547547
InclusionOpaque *opaque;
548548
uint16 basenum = procnum - PROCNUM_BASE;
@@ -564,13 +564,18 @@ inclusion_get_procinfo(BrinDesc *bdesc, uint16 attno, uint16 procnum)
564564
{
565565
if (RegProcedureIsValid(index_getprocid(bdesc->bd_index, attno,
566566
procnum)))
567-
{
568567
fmgr_info_copy(&opaque->extra_procinfos[basenum],
569568
index_getprocinfo(bdesc->bd_index, attno, procnum),
570569
bdesc->bd_context);
571-
}
572570
else
573571
{
572+
if (!missing_ok)
573+
ereport(ERROR,
574+
errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
575+
errmsg_internal("invalid opclass definition"),
576+
errdetail_internal("The operator class is missing support function %d for column %d.",
577+
procnum, attno));
578+
574579
opaque->extra_proc_missing[basenum] = true;
575580
return NULL;
576581
}

src/backend/access/brin/brin_minmax_multi.c

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,6 @@
112112
typedef struct MinmaxMultiOpaque
113113
{
114114
FmgrInfo extra_procinfos[MINMAX_MAX_PROCNUMS];
115-
bool extra_proc_missing[MINMAX_MAX_PROCNUMS];
116115
Oid cached_subtype;
117116
FmgrInfo strategy_procinfos[BTMaxStrategyNumber];
118117
} MinmaxMultiOpaque;
@@ -2864,27 +2863,19 @@ minmax_multi_get_procinfo(BrinDesc *bdesc, uint16 attno, uint16 procnum)
28642863
*/
28652864
opaque = (MinmaxMultiOpaque *) bdesc->bd_info[attno - 1]->oi_opaque;
28662865

2867-
/*
2868-
* If we already searched for this proc and didn't find it, don't bother
2869-
* searching again.
2870-
*/
2871-
if (opaque->extra_proc_missing[basenum])
2872-
return NULL;
2873-
28742866
if (opaque->extra_procinfos[basenum].fn_oid == InvalidOid)
28752867
{
28762868
if (RegProcedureIsValid(index_getprocid(bdesc->bd_index, attno,
28772869
procnum)))
2878-
{
28792870
fmgr_info_copy(&opaque->extra_procinfos[basenum],
28802871
index_getprocinfo(bdesc->bd_index, attno, procnum),
28812872
bdesc->bd_context);
2882-
}
28832873
else
2884-
{
2885-
opaque->extra_proc_missing[basenum] = true;
2886-
return NULL;
2887-
}
2874+
ereport(ERROR,
2875+
errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
2876+
errmsg_internal("invalid opclass definition"),
2877+
errdetail_internal("The operator class is missing support function %d for column %d.",
2878+
procnum, attno));
28882879
}
28892880

28902881
return &opaque->extra_procinfos[basenum];

0 commit comments

Comments
 (0)