@ -125,6 +125,27 @@ ginFillScanEntry(GinScanOpaque so, OffsetNumber attnum,
return scanEntry ;
return scanEntry ;
}
}
/*
* Append hidden scan entry of given category to the scan key .
*
* NB : this had better be called at most once per scan key , since
* ginFillScanKey leaves room for only one hidden entry . Currently ,
* it seems sufficiently clear that this is true that we don ' t bother
* with any cross - check logic .
*/
static void
ginScanKeyAddHiddenEntry ( GinScanOpaque so , GinScanKey key ,
GinNullCategory queryCategory )
{
int i = key - > nentries + + ;
/* strategy is of no interest because this is not a partial-match item */
key - > scanEntry [ i ] = ginFillScanEntry ( so , key - > attnum ,
InvalidStrategy , key - > searchMode ,
( Datum ) 0 , queryCategory ,
false , NULL ) ;
}
/*
/*
* Initialize the next GinScanKey using the output from the extractQueryFn
* Initialize the next GinScanKey using the output from the extractQueryFn
*/
*/
@ -137,17 +158,16 @@ ginFillScanKey(GinScanOpaque so, OffsetNumber attnum,
{
{
GinScanKey key = & ( so - > keys [ so - > nkeys + + ] ) ;
GinScanKey key = & ( so - > keys [ so - > nkeys + + ] ) ;
GinState * ginstate = & so - > ginstate ;
GinState * ginstate = & so - > ginstate ;
uint32 nUserQueryValues = nQueryValues ;
uint32 i ;
uint32 i ;
/* Non-default search modes add one "hidden" entry to each key */
if ( searchMode ! = GIN_SEARCH_MODE_DEFAULT )
nQueryValues + + ;
key - > nentries = nQueryValues ;
key - > nentries = nQueryValues ;
key - > nuserentries = nUser QueryValues ;
key - > nuserentries = nQueryValues ;
key - > scanEntry = ( GinScanEntry * ) palloc ( sizeof ( GinScanEntry ) * nQueryValues ) ;
/* Allocate one extra array slot for possible "hidden" entry */
key - > entryRes = ( GinTernaryValue * ) palloc0 ( sizeof ( GinTernaryValue ) * nQueryValues ) ;
key - > scanEntry = ( GinScanEntry * ) palloc ( sizeof ( GinScanEntry ) *
( nQueryValues + 1 ) ) ;
key - > entryRes = ( GinTernaryValue * ) palloc0 ( sizeof ( GinTernaryValue ) *
( nQueryValues + 1 ) ) ;
key - > query = query ;
key - > query = query ;
key - > queryValues = queryValues ;
key - > queryValues = queryValues ;
@ -157,6 +177,12 @@ ginFillScanKey(GinScanOpaque so, OffsetNumber attnum,
key - > searchMode = searchMode ;
key - > searchMode = searchMode ;
key - > attnum = attnum ;
key - > attnum = attnum ;
/*
* Initially , scan keys of GIN_SEARCH_MODE_ALL mode are marked
* excludeOnly . This might get changed later .
*/
key - > excludeOnly = ( searchMode = = GIN_SEARCH_MODE_ALL ) ;
ItemPointerSetMin ( & key - > curItem ) ;
ItemPointerSetMin ( & key - > curItem ) ;
key - > curItemMatches = false ;
key - > curItemMatches = false ;
key - > recheckCurItem = false ;
key - > recheckCurItem = false ;
@ -168,6 +194,7 @@ ginFillScanKey(GinScanOpaque so, OffsetNumber attnum,
ginInitConsistentFunction ( ginstate , key ) ;
ginInitConsistentFunction ( ginstate , key ) ;
/* Set up normal scan entries using extractQueryFn's outputs */
for ( i = 0 ; i < nQueryValues ; i + + )
for ( i = 0 ; i < nQueryValues ; i + + )
{
{
Datum queryKey ;
Datum queryKey ;
@ -175,54 +202,28 @@ ginFillScanKey(GinScanOpaque so, OffsetNumber attnum,
bool isPartialMatch ;
bool isPartialMatch ;
Pointer this_extra ;
Pointer this_extra ;
if ( i < nUserQueryValues )
{
/* set up normal entry using extractQueryFn's outputs */
queryKey = queryValues [ i ] ;
queryKey = queryValues [ i ] ;
queryCategory = queryCategories [ i ] ;
queryCategory = queryCategories [ i ] ;
isPartialMatch =
isPartialMatch =
( ginstate - > canPartialMatch [ attnum - 1 ] & & partial_matches )
( ginstate - > canPartialMatch [ attnum - 1 ] & & partial_matches )
? partial_matches [ i ] : false ;
? partial_matches [ i ] : false ;
this_extra = ( extra_data ) ? extra_data [ i ] : NULL ;
this_extra = ( extra_data ) ? extra_data [ i ] : NULL ;
}
else
{
/* set up hidden entry */
queryKey = ( Datum ) 0 ;
switch ( searchMode )
{
case GIN_SEARCH_MODE_INCLUDE_EMPTY :
queryCategory = GIN_CAT_EMPTY_ITEM ;
break ;
case GIN_SEARCH_MODE_ALL :
queryCategory = GIN_CAT_EMPTY_QUERY ;
break ;
case GIN_SEARCH_MODE_EVERYTHING :
queryCategory = GIN_CAT_EMPTY_QUERY ;
break ;
default :
elog ( ERROR , " unexpected searchMode: %d " , searchMode ) ;
queryCategory = 0 ; /* keep compiler quiet */
break ;
}
isPartialMatch = false ;
this_extra = NULL ;
/*
* We set the strategy to a fixed value so that ginFillScanEntry
* can combine these entries for different scan keys . This is
* safe because the strategy value in the entry struct is only
* used for partial - match cases . It ' s OK to overwrite our local
* variable here because this is the last loop iteration .
*/
strategy = InvalidStrategy ;
}
key - > scanEntry [ i ] = ginFillScanEntry ( so , attnum ,
key - > scanEntry [ i ] = ginFillScanEntry ( so , attnum ,
strategy , searchMode ,
strategy , searchMode ,
queryKey , queryCategory ,
queryKey , queryCategory ,
isPartialMatch , this_extra ) ;
isPartialMatch , this_extra ) ;
}
}
/*
* For GIN_SEARCH_MODE_INCLUDE_EMPTY and GIN_SEARCH_MODE_EVERYTHING search
* modes , we add the " hidden " entry immediately . GIN_SEARCH_MODE_ALL is
* handled later , since we might be able to omit the hidden entry for it .
*/
if ( searchMode = = GIN_SEARCH_MODE_INCLUDE_EMPTY )
ginScanKeyAddHiddenEntry ( so , key , GIN_CAT_EMPTY_ITEM ) ;
else if ( searchMode = = GIN_SEARCH_MODE_EVERYTHING )
ginScanKeyAddHiddenEntry ( so , key , GIN_CAT_EMPTY_QUERY ) ;
}
}
/*
/*
@ -265,6 +266,7 @@ ginNewScanKey(IndexScanDesc scan)
GinScanOpaque so = ( GinScanOpaque ) scan - > opaque ;
GinScanOpaque so = ( GinScanOpaque ) scan - > opaque ;
int i ;
int i ;
bool hasNullQuery = false ;
bool hasNullQuery = false ;
bool attrHasNormalScan [ INDEX_MAX_KEYS ] = { false } ;
MemoryContext oldCtx ;
MemoryContext oldCtx ;
/*
/*
@ -371,6 +373,33 @@ ginNewScanKey(IndexScanDesc scan)
skey - > sk_argument , nQueryValues ,
skey - > sk_argument , nQueryValues ,
queryValues , categories ,
queryValues , categories ,
partial_matches , extra_data ) ;
partial_matches , extra_data ) ;
/* Remember if we had any non-excludeOnly keys */
if ( searchMode ! = GIN_SEARCH_MODE_ALL )
attrHasNormalScan [ skey - > sk_attno - 1 ] = true ;
}
/*
* Processing GIN_SEARCH_MODE_ALL scan keys requires us to make a second
* pass over the scan keys . Above we marked each such scan key as
* excludeOnly . If the involved column has any normal ( not excludeOnly )
* scan key as well , then we can leave it like that . Otherwise , one
* excludeOnly scan key must receive a GIN_CAT_EMPTY_QUERY hidden entry
* and be set to normal ( excludeOnly = false ) .
*/
for ( i = 0 ; i < so - > nkeys ; i + + )
{
GinScanKey key = & so - > keys [ i ] ;
if ( key - > searchMode ! = GIN_SEARCH_MODE_ALL )
continue ;
if ( ! attrHasNormalScan [ key - > attnum - 1 ] )
{
key - > excludeOnly = false ;
ginScanKeyAddHiddenEntry ( so , key , GIN_CAT_EMPTY_QUERY ) ;
attrHasNormalScan [ key - > attnum - 1 ] = true ;
}
}
}
/*
/*