@ -85,6 +85,8 @@ 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 ) ;
/*
@ -251,6 +253,10 @@ 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 .
*
* All of the strategies are optional .
*/
Datum
@ -258,24 +264,31 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS)
{
BrinDesc * bdesc = ( BrinDesc * ) PG_GETARG_POINTER ( 0 ) ;
BrinValues * column = ( BrinValues * ) PG_GETARG_POINTER ( 1 ) ;
ScanKey key = ( ScanKey ) PG_GETARG_POINTER ( 2 ) ;
Oid colloid = PG_GET_COLLATION ( ) ,
subtype ;
Datum unionval ;
AttrNumber attno ;
Datum query ;
FmgrInfo * finfo ;
Datum result ;
Assert ( key - > sk_attno = = column - > bv_attno ) ;
ScanKey * keys = ( ScanKey * ) PG_GETARG_POINTER ( 2 ) ;
int nkeys = PG_GETARG_INT32 ( 3 ) ;
Oid colloid = PG_GET_COLLATION ( ) ;
int keyno ;
bool has_regular_keys = false ;
/* Handle IS NULL/IS NOT NULL tests. */
i f ( key - > sk_flags & SK_ISNULL )
/* Handle IS NULL/IS NOT NULL tests */
for ( keyno = 0 ; keyno < nkeys ; keyno + + )
{
ScanKey key = keys [ keyno ] ;
Assert ( key - > sk_attno = = column - > bv_attno ) ;
/* Skip regular scan keys (and remember that we have some). */
if ( ( ! key - > sk_flags & SK_ISNULL ) )
{
has_regular_keys = true ;
continue ;
}
if ( key - > sk_flags & SK_SEARCHNULL )
{
if ( column - > bv_allnulls | | column - > bv_hasnulls )
PG_RETURN_BOOL ( true ) ;
continue ; /* this key is fine, continue */
PG_RETURN_BOOL ( false ) ;
}
@ -284,7 +297,12 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS)
* only nulls .
*/
if ( key - > sk_flags & SK_SEARCHNOTNULL )
PG_RETURN_BOOL ( ! column - > bv_allnulls ) ;
{
if ( column - > bv_allnulls )
PG_RETURN_BOOL ( false ) ;
continue ;
}
/*
* Neither IS NULL nor IS NOT NULL was used ; assume all indexable
@ -293,7 +311,14 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS)
PG_RETURN_BOOL ( false ) ;
}
/* If it is all nulls, it cannot possibly be consistent. */
/* If there are no regular keys, the page range is considered consistent. */
if ( ! has_regular_keys )
PG_RETURN_BOOL ( true ) ;
/*
* 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 ) ;
@ -301,10 +326,45 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS)
if ( DatumGetBool ( column - > bv_values [ INCLUSION_UNMERGEABLE ] ) )
PG_RETURN_BOOL ( true ) ;
attno = key - > sk_attno ;
subtype = key - > sk_subtype ;
query = key - > sk_argument ;
unionval = column - > bv_values [ INCLUSION_UNION ] ;
/* Check that the range is consistent with all regular scan keys. */
for ( keyno = 0 ; keyno < nkeys ; keyno + + )
{
ScanKey key = keys [ keyno ] ;
/* Skip IS NULL/IS NOT NULL keys (already handled above). */
if ( key - > sk_flags & SK_ISNULL )
continue ;
/*
* 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 ) ) ;
switch ( key - > sk_strategy )
{
/*
@ -324,49 +384,49 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS)
finfo = inclusion_get_strategy_procinfo ( bdesc , attno , subtype ,
RTOverRightStrategyNumber ) ;
result = FunctionCall2Coll ( finfo , colloid , unionval , query ) ;
PG_RETURN_BOOL ( ! DatumGetBool ( result ) ) ;
return ! DatumGetBool ( result ) ;
case RTOverLeftStrategyNumber :
finfo = inclusion_get_strategy_procinfo ( bdesc , attno , subtype ,
RTRightStrategyNumber ) ;
result = FunctionCall2Coll ( finfo , colloid , unionval , query ) ;
PG_RETURN_BOOL ( ! DatumGetBool ( result ) ) ;
return ! DatumGetBool ( result ) ;
case RTOverRightStrategyNumber :
finfo = inclusion_get_strategy_procinfo ( bdesc , attno , subtype ,
RTLeftStrategyNumber ) ;
result = FunctionCall2Coll ( finfo , colloid , unionval , query ) ;
PG_RETURN_BOOL ( ! DatumGetBool ( result ) ) ;
return ! DatumGetBool ( result ) ;
case RTRightStrategyNumber :
finfo = inclusion_get_strategy_procinfo ( bdesc , attno , subtype ,
RTOverLeftStrategyNumber ) ;
result = FunctionCall2Coll ( finfo , colloid , unionval , query ) ;
PG_RETURN_BOOL ( ! DatumGetBool ( result ) ) ;
return ! DatumGetBool ( result ) ;
case RTBelowStrategyNumber :
finfo = inclusion_get_strategy_procinfo ( bdesc , attno , subtype ,
RTOverAboveStrategyNumber ) ;
result = FunctionCall2Coll ( finfo , colloid , unionval , query ) ;
PG_RETURN_BOOL ( ! DatumGetBool ( result ) ) ;
return ! DatumGetBool ( result ) ;
case RTOverBelowStrategyNumber :
finfo = inclusion_get_strategy_procinfo ( bdesc , attno , subtype ,
RTAboveStrategyNumber ) ;
result = FunctionCall2Coll ( finfo , colloid , unionval , query ) ;
PG_RETURN_BOOL ( ! DatumGetBool ( result ) ) ;
return ! DatumGetBool ( result ) ;
case RTOverAboveStrategyNumber :
finfo = inclusion_get_strategy_procinfo ( bdesc , attno , subtype ,
RTBelowStrategyNumber ) ;
result = FunctionCall2Coll ( finfo , colloid , unionval , query ) ;
PG_RETURN_BOOL ( ! DatumGetBool ( result ) ) ;
return ! DatumGetBool ( result ) ;
case RTAboveStrategyNumber :
finfo = inclusion_get_strategy_procinfo ( bdesc , attno , subtype ,
RTOverBelowStrategyNumber ) ;
result = FunctionCall2Coll ( finfo , colloid , unionval , query ) ;
PG_RETURN_BOOL ( ! DatumGetBool ( result ) ) ;
return ! DatumGetBool ( result ) ;
/*
* Overlap and contains strategies
@ -384,7 +444,7 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS)
finfo = inclusion_get_strategy_procinfo ( bdesc , attno , subtype ,
key - > sk_strategy ) ;
result = FunctionCall2Coll ( finfo , colloid , unionval , query ) ;
PG_RETURN_DATUM ( result ) ;
return DatumGetBool ( result ) ;
/*
* Contained by strategies
@ -404,9 +464,9 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS)
RTOverlapStrategyNumber ) ;
result = FunctionCall2Coll ( finfo , colloid , unionval , query ) ;
if ( DatumGetBool ( result ) )
PG_RETURN_BOOL ( true ) ;
return true ;
PG_RETURN_DATUM ( column - > bv_values [ INCLUSION_CONTAINS_EMPTY ] ) ;
return DatumGetBool ( column - > bv_values [ INCLUSION_CONTAINS_EMPTY ] ) ;
/*
* Adjacent strategy
@ -423,12 +483,12 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS)
RTOverlapStrategyNumber ) ;
result = FunctionCall2Coll ( finfo , colloid , unionval , query ) ;
if ( DatumGetBool ( result ) )
PG_RETURN_BOOL ( true ) ;
return true ;
finfo = inclusion_get_strategy_procinfo ( bdesc , attno , subtype ,
RTAdjacentStrategyNumber ) ;
result = FunctionCall2Coll ( finfo , colloid , unionval , query ) ;
PG_RETURN_DATUM ( result ) ;
return DatumGetBool ( result ) ;
/*
* Basic comparison strategies
@ -458,9 +518,9 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS)
RTRightStrategyNumber ) ;
result = FunctionCall2Coll ( finfo , colloid , unionval , query ) ;
if ( ! DatumGetBool ( result ) )
PG_RETURN_BOOL ( true ) ;
return true ;
PG_RETURN_DATUM ( column - > bv_values [ INCLUSION_CONTAINS_EMPTY ] ) ;
return DatumGetBool ( column - > bv_values [ INCLUSION_CONTAINS_EMPTY ] ) ;
case RTSameStrategyNumber :
case RTEqualStrategyNumber :
@ -468,30 +528,30 @@ brin_inclusion_consistent(PG_FUNCTION_ARGS)
RTContainsStrategyNumber ) ;
result = FunctionCall2Coll ( finfo , colloid , unionval , query ) ;
if ( DatumGetBool ( result ) )
PG_RETURN_BOOL ( true ) ;
return true ;
PG_RETURN_DATUM ( column - > bv_values [ INCLUSION_CONTAINS_EMPTY ] ) ;
return DatumGetBool ( 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 ) )
PG_RETURN_BOOL ( true ) ;
return true ;
PG_RETURN_DATUM ( column - > bv_values [ INCLUSION_CONTAINS_EMPTY ] ) ;
return DatumGetBool ( 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 ) ;
PG_RETURN_BOOL ( ! DatumGetBool ( result ) ) ;
return ! DatumGetBool ( result ) ;
default :
/* shouldn't happen */
elog ( ERROR , " invalid strategy number %d " , key - > sk_strategy ) ;
PG_RETURN_BOOL ( false ) ;
return false ;
}
}