diff --git a/doc/src/sgml/brin.sgml b/doc/src/sgml/brin.sgml index 078f51bb55..4f15081674 100644 --- a/doc/src/sgml/brin.sgml +++ b/doc/src/sgml/brin.sgml @@ -476,6 +476,19 @@ typedef struct BrinOpcInfo + + bool consistent(BrinDesc *bdesc, BrinValues *column, + ScanKey key) + + + Returns whether the ScanKey is consistent with the given indexed + values for a range. + The attribute number to use is passed as part of the scan key. + This is an older backward-compatible variant of the consistent function. + + + + bool addValue(BrinDesc *bdesc, BrinValues *column, Datum newval, bool isnull) diff --git a/src/backend/access/brin/brin.c b/src/backend/access/brin/brin.c index 0bf25fd05b..2d8759c6c1 100644 --- a/src/backend/access/brin/brin.c +++ b/src/backend/access/brin/brin.c @@ -634,26 +634,58 @@ bringetbitmap(IndexScanDesc scan, TIDBitmap *tbm) break; } + /* + * Collation from the first key (has to be the same for + * all keys for the same attribue). + */ + collation = keys[attno - 1][0]->sk_collation; + /* * Check whether the scan key is consistent with the page * range values; if so, have the pages in the range added * to the output bitmap. * - * XXX We simply use the collation from the first key (it - * has to be the same for all keys for the same attribue). + * The opclass may or may not support processing of multiple + * scan keys. We can determine that based on the number of + * arguments - functions with extra parameter (number of scan + * keys) do support this, otherwise we have to simply pass the + * scan keys one by one. */ - collation = keys[attno - 1][0]->sk_collation; + if (consistentFn[attno - 1].fn_nargs >= 4) + { + /* Check all keys at once */ + add = FunctionCall4Coll(&consistentFn[attno - 1], + collation, + PointerGetDatum(bdesc), + PointerGetDatum(bval), + PointerGetDatum(keys[attno - 1]), + Int32GetDatum(nkeys[attno - 1])); + addrange = DatumGetBool(add); + } + else + { + /* + * Check keys one by one + * + * When there are multiple scan keys, failure to meet the + * criteria for a single one of them is enough to discard + * the range as a whole, so break out of the loop as soon + * as a false return value is obtained. + */ + int keyno; - /* Check all keys at once */ - add = FunctionCall4Coll(&consistentFn[attno - 1], - collation, - PointerGetDatum(bdesc), - PointerGetDatum(bval), - PointerGetDatum(keys[attno - 1]), - Int32GetDatum(nkeys[attno - 1])); - addrange = DatumGetBool(add); - if (!addrange) - break; + for (keyno = 0; keyno < nkeys[attno - 1]; keyno++) + { + add = FunctionCall3Coll(&consistentFn[attno - 1], + keys[attno - 1][keyno]->sk_collation, + PointerGetDatum(bdesc), + PointerGetDatum(bval), + PointerGetDatum(keys[attno - 1][keyno])); + addrange = DatumGetBool(add); + if (!addrange) + break; + } + } } } } diff --git a/src/backend/access/brin/brin_inclusion.c b/src/backend/access/brin/brin_inclusion.c index d8cfc9d909..0b384c0bd1 100644 --- a/src/backend/access/brin/brin_inclusion.c +++ b/src/backend/access/brin/brin_inclusion.c @@ -85,8 +85,6 @@ static FmgrInfo *inclusion_get_procinfo(BrinDesc *bdesc, uint16 attno, uint16 procnum); static FmgrInfo *inclusion_get_strategy_procinfo(BrinDesc *bdesc, uint16 attno, Oid subtype, uint16 strategynum); -static bool inclusion_consistent_key(BrinDesc *bdesc, BrinValues *column, - ScanKey key, Oid colloid); /* @@ -243,9 +241,9 @@ brin_inclusion_add_value(PG_FUNCTION_ARGS) /* * BRIN inclusion consistent function * - * We inspect the IS NULL scan keys first, which allows us to make a decision - * without looking at the contents of the page range. Only when the page range - * matches the IS NULL keys, we check the regular scan keys. + * We're no longer dealing with NULL keys in the consistent function, that is + * now handled by the AM code. That means we should not get any all-NULL ranges + * either, because those can't be consistent with regular (not [IS] NULL) keys. * * All of the strategies are optional. */ @@ -254,63 +252,29 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS) { BrinDesc *bdesc = (BrinDesc *) PG_GETARG_POINTER(0); BrinValues *column = (BrinValues *) PG_GETARG_POINTER(1); - ScanKey *keys = (ScanKey *) PG_GETARG_POINTER(2); - int nkeys = PG_GETARG_INT32(3); - Oid colloid = PG_GET_COLLATION(); - int keyno; + ScanKey key = (ScanKey) PG_GETARG_POINTER(2); + Oid colloid = PG_GET_COLLATION(), + subtype; + Datum unionval; + AttrNumber attno; + Datum query; + FmgrInfo *finfo; + Datum result; - /* make sure we got some scan keys */ - Assert((nkeys > 0) && (keys != NULL)); + /* This opclass uses the old signature with only three arguments. */ + Assert(PG_NARGS() == 3); - /* - * If is all nulls, it cannot possibly be consistent (at this point we - * know there are at least some regular scan keys). - */ - if (column->bv_allnulls) - PG_RETURN_BOOL(false); + /* Should not be dealing with all-NULL ranges. */ + Assert(!column->bv_allnulls); /* It has to be checked, if it contains elements that are not mergeable. */ if (DatumGetBool(column->bv_values[INCLUSION_UNMERGEABLE])) PG_RETURN_BOOL(true); - /* Check that the range is consistent with all regular scan keys. */ - for (keyno = 0; keyno < nkeys; keyno++) - { - ScanKey key = keys[keyno]; - - /* NULL keys are handled and filtered-out in bringetbitmap */ - Assert(!(key->sk_flags & SK_ISNULL)); - - /* - * When there are multiple scan keys, failure to meet the criteria for - * a single one of them is enough to discard the range as a whole, so - * break out of the loop as soon as a false return value is obtained. - */ - if (!inclusion_consistent_key(bdesc, column, key, colloid)) - PG_RETURN_BOOL(false); - } - - PG_RETURN_BOOL(true); -} - -/* - * inclusion_consistent_key - * Determine if the range is consistent with a single scan key. - */ -static bool -inclusion_consistent_key(BrinDesc *bdesc, BrinValues *column, ScanKey key, - Oid colloid) -{ - FmgrInfo *finfo; - AttrNumber attno = key->sk_attno; - Oid subtype = key->sk_subtype; - Datum query = key->sk_argument; - Datum unionval = column->bv_values[INCLUSION_UNION]; - Datum result; - - /* This should be called only for regular keys, not for IS [NOT] NULL. */ - Assert(!(key->sk_flags & SK_ISNULL)); - + attno = key->sk_attno; + subtype = key->sk_subtype; + query = key->sk_argument; + unionval = column->bv_values[INCLUSION_UNION]; switch (key->sk_strategy) { /* @@ -330,49 +294,49 @@ inclusion_consistent_key(BrinDesc *bdesc, BrinValues *column, ScanKey key, finfo = inclusion_get_strategy_procinfo(bdesc, attno, subtype, RTOverRightStrategyNumber); result = FunctionCall2Coll(finfo, colloid, unionval, query); - return !DatumGetBool(result); + PG_RETURN_BOOL(!DatumGetBool(result)); case RTOverLeftStrategyNumber: finfo = inclusion_get_strategy_procinfo(bdesc, attno, subtype, RTRightStrategyNumber); result = FunctionCall2Coll(finfo, colloid, unionval, query); - return !DatumGetBool(result); + PG_RETURN_BOOL(!DatumGetBool(result)); case RTOverRightStrategyNumber: finfo = inclusion_get_strategy_procinfo(bdesc, attno, subtype, RTLeftStrategyNumber); result = FunctionCall2Coll(finfo, colloid, unionval, query); - return !DatumGetBool(result); + PG_RETURN_BOOL(!DatumGetBool(result)); case RTRightStrategyNumber: finfo = inclusion_get_strategy_procinfo(bdesc, attno, subtype, RTOverLeftStrategyNumber); result = FunctionCall2Coll(finfo, colloid, unionval, query); - return !DatumGetBool(result); + PG_RETURN_BOOL(!DatumGetBool(result)); case RTBelowStrategyNumber: finfo = inclusion_get_strategy_procinfo(bdesc, attno, subtype, RTOverAboveStrategyNumber); result = FunctionCall2Coll(finfo, colloid, unionval, query); - return !DatumGetBool(result); + PG_RETURN_BOOL(!DatumGetBool(result)); case RTOverBelowStrategyNumber: finfo = inclusion_get_strategy_procinfo(bdesc, attno, subtype, RTAboveStrategyNumber); result = FunctionCall2Coll(finfo, colloid, unionval, query); - return !DatumGetBool(result); + PG_RETURN_BOOL(!DatumGetBool(result)); case RTOverAboveStrategyNumber: finfo = inclusion_get_strategy_procinfo(bdesc, attno, subtype, RTBelowStrategyNumber); result = FunctionCall2Coll(finfo, colloid, unionval, query); - return !DatumGetBool(result); + PG_RETURN_BOOL(!DatumGetBool(result)); case RTAboveStrategyNumber: finfo = inclusion_get_strategy_procinfo(bdesc, attno, subtype, RTOverBelowStrategyNumber); result = FunctionCall2Coll(finfo, colloid, unionval, query); - return !DatumGetBool(result); + PG_RETURN_BOOL(!DatumGetBool(result)); /* * Overlap and contains strategies @@ -390,7 +354,7 @@ inclusion_consistent_key(BrinDesc *bdesc, BrinValues *column, ScanKey key, finfo = inclusion_get_strategy_procinfo(bdesc, attno, subtype, key->sk_strategy); result = FunctionCall2Coll(finfo, colloid, unionval, query); - return DatumGetBool(result); + PG_RETURN_DATUM(result); /* * Contained by strategies @@ -410,9 +374,9 @@ inclusion_consistent_key(BrinDesc *bdesc, BrinValues *column, ScanKey key, RTOverlapStrategyNumber); result = FunctionCall2Coll(finfo, colloid, unionval, query); if (DatumGetBool(result)) - return true; + PG_RETURN_BOOL(true); - return DatumGetBool(column->bv_values[INCLUSION_CONTAINS_EMPTY]); + PG_RETURN_DATUM(column->bv_values[INCLUSION_CONTAINS_EMPTY]); /* * Adjacent strategy @@ -429,12 +393,12 @@ inclusion_consistent_key(BrinDesc *bdesc, BrinValues *column, ScanKey key, RTOverlapStrategyNumber); result = FunctionCall2Coll(finfo, colloid, unionval, query); if (DatumGetBool(result)) - return true; + PG_RETURN_BOOL(true); finfo = inclusion_get_strategy_procinfo(bdesc, attno, subtype, RTAdjacentStrategyNumber); result = FunctionCall2Coll(finfo, colloid, unionval, query); - return DatumGetBool(result); + PG_RETURN_DATUM(result); /* * Basic comparison strategies @@ -464,9 +428,9 @@ inclusion_consistent_key(BrinDesc *bdesc, BrinValues *column, ScanKey key, RTRightStrategyNumber); result = FunctionCall2Coll(finfo, colloid, unionval, query); if (!DatumGetBool(result)) - return true; + PG_RETURN_BOOL(true); - return DatumGetBool(column->bv_values[INCLUSION_CONTAINS_EMPTY]); + PG_RETURN_DATUM(column->bv_values[INCLUSION_CONTAINS_EMPTY]); case RTSameStrategyNumber: case RTEqualStrategyNumber: @@ -474,30 +438,30 @@ inclusion_consistent_key(BrinDesc *bdesc, BrinValues *column, ScanKey key, RTContainsStrategyNumber); result = FunctionCall2Coll(finfo, colloid, unionval, query); if (DatumGetBool(result)) - return true; + PG_RETURN_BOOL(true); - return DatumGetBool(column->bv_values[INCLUSION_CONTAINS_EMPTY]); + PG_RETURN_DATUM(column->bv_values[INCLUSION_CONTAINS_EMPTY]); case RTGreaterEqualStrategyNumber: finfo = inclusion_get_strategy_procinfo(bdesc, attno, subtype, RTLeftStrategyNumber); result = FunctionCall2Coll(finfo, colloid, unionval, query); if (!DatumGetBool(result)) - return true; + PG_RETURN_BOOL(true); - return DatumGetBool(column->bv_values[INCLUSION_CONTAINS_EMPTY]); + PG_RETURN_DATUM(column->bv_values[INCLUSION_CONTAINS_EMPTY]); case RTGreaterStrategyNumber: /* no need to check for empty elements */ finfo = inclusion_get_strategy_procinfo(bdesc, attno, subtype, RTLeftStrategyNumber); result = FunctionCall2Coll(finfo, colloid, unionval, query); - return !DatumGetBool(result); + PG_RETURN_BOOL(!DatumGetBool(result)); default: /* shouldn't happen */ elog(ERROR, "invalid strategy number %d", key->sk_strategy); - return false; + PG_RETURN_BOOL(false); } } diff --git a/src/backend/access/brin/brin_minmax.c b/src/backend/access/brin/brin_minmax.c index 032629950f..798f06c722 100644 --- a/src/backend/access/brin/brin_minmax.c +++ b/src/backend/access/brin/brin_minmax.c @@ -30,8 +30,6 @@ typedef struct MinmaxOpaque static FmgrInfo *minmax_get_strategy_procinfo(BrinDesc *bdesc, uint16 attno, Oid subtype, uint16 strategynum); -static bool minmax_consistent_key(BrinDesc *bdesc, BrinValues *column, - ScanKey key, Oid colloid); Datum @@ -133,64 +131,32 @@ brin_minmax_add_value(PG_FUNCTION_ARGS) * return whether the scan key is consistent with the index tuple's min/max * values. Return true if so, false otherwise. * - * We inspect the IS NULL scan keys first, which allows us to make a decision - * without looking at the contents of the page range. Only when the page range - * matches all those keys, we check the regular scan keys. + * We're no longer dealing with NULL keys in the consistent function, that is + * now handled by the AM code. That means we should not get any all-NULL ranges + * either, because those can't be consistent with regular (not [IS] NULL) keys. */ Datum brin_minmax_consistent(PG_FUNCTION_ARGS) { BrinDesc *bdesc = (BrinDesc *) PG_GETARG_POINTER(0); BrinValues *column = (BrinValues *) PG_GETARG_POINTER(1); - ScanKey *keys = (ScanKey *) PG_GETARG_POINTER(2); - int nkeys = PG_GETARG_INT32(3); - Oid colloid = PG_GET_COLLATION(); - int keyno; - - /* make sure we got some scan keys */ - Assert((nkeys > 0) && (keys != NULL)); - - /* - * If is all nulls, it cannot possibly be consistent (at this point we - * know there are at least some regular scan keys). - */ - if (column->bv_allnulls) - PG_RETURN_BOOL(false); - - /* Check that the range is consistent with all scan keys. */ - for (keyno = 0; keyno < nkeys; keyno++) - { - ScanKey key = keys[keyno]; - - /* NULL keys are handled and filtered-out in bringetbitmap */ - Assert(!(key->sk_flags & SK_ISNULL)); - - /* - * When there are multiple scan keys, failure to meet the criteria for - * a single one of them is enough to discard the range as a whole, so - * break out of the loop as soon as a false return value is obtained. - */ - if (!minmax_consistent_key(bdesc, column, key, colloid)) - PG_RETURN_DATUM(false); - } - - PG_RETURN_DATUM(true); -} - -/* - * minmax_consistent_key - * Determine if the range is consistent with a single scan key. - */ -static bool -minmax_consistent_key(BrinDesc *bdesc, BrinValues *column, ScanKey key, - Oid colloid) -{ - FmgrInfo *finfo; - AttrNumber attno = key->sk_attno; - Oid subtype = key->sk_subtype; - Datum value = key->sk_argument; + ScanKey key = (ScanKey) PG_GETARG_POINTER(2); + Oid colloid = PG_GET_COLLATION(), + subtype; + AttrNumber attno; + Datum value; Datum matches; + FmgrInfo *finfo; + /* This opclass uses the old signature with only three arguments. */ + Assert(PG_NARGS() == 3); + + /* Should not be dealing with all-NULL ranges. */ + Assert(!column->bv_allnulls); + + attno = key->sk_attno; + subtype = key->sk_subtype; + value = key->sk_argument; switch (key->sk_strategy) { case BTLessStrategyNumber: @@ -233,7 +199,7 @@ minmax_consistent_key(BrinDesc *bdesc, BrinValues *column, ScanKey key, break; } - return DatumGetBool(matches); + PG_RETURN_DATUM(matches); } /* diff --git a/src/backend/access/brin/brin_validate.c b/src/backend/access/brin/brin_validate.c index 2c4f9a3eff..11835d85cd 100644 --- a/src/backend/access/brin/brin_validate.c +++ b/src/backend/access/brin/brin_validate.c @@ -97,7 +97,7 @@ brinvalidate(Oid opclassoid) break; case BRIN_PROCNUM_CONSISTENT: ok = check_amproc_signature(procform->amproc, BOOLOID, true, - 4, 4, INTERNALOID, INTERNALOID, + 3, 4, INTERNALOID, INTERNALOID, INTERNALOID, INT4OID); break; case BRIN_PROCNUM_UNION: diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index 872f0445fa..7f8533c936 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 202103261 +#define CATALOG_VERSION_NO 202103262 #endif diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index 987ac9140b..1662ee93ee 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -8232,7 +8232,7 @@ prosrc => 'brin_minmax_add_value' }, { oid => '3385', descr => 'BRIN minmax support', proname => 'brin_minmax_consistent', prorettype => 'bool', - proargtypes => 'internal internal internal int4', + proargtypes => 'internal internal internal', prosrc => 'brin_minmax_consistent' }, { oid => '3386', descr => 'BRIN minmax support', proname => 'brin_minmax_union', prorettype => 'bool', @@ -8248,7 +8248,7 @@ prosrc => 'brin_inclusion_add_value' }, { oid => '4107', descr => 'BRIN inclusion support', proname => 'brin_inclusion_consistent', prorettype => 'bool', - proargtypes => 'internal internal internal int4', + proargtypes => 'internal internal internal', prosrc => 'brin_inclusion_consistent' }, { oid => '4108', descr => 'BRIN inclusion support', proname => 'brin_inclusion_union', prorettype => 'bool',