@@ -6281,14 +6281,14 @@ gincostestimate(PG_FUNCTION_ARGS)
6281
6281
Selectivity * indexSelectivity = (Selectivity * ) PG_GETARG_POINTER (7 );
6282
6282
double * indexCorrelation = (double * ) PG_GETARG_POINTER (8 );
6283
6283
ListCell * l ;
6284
- int32 nfullscan = 0 ;
6285
6284
List * selectivityQuals ;
6286
6285
double numPages = index -> pages ,
6287
6286
numTuples = index -> tuples ;
6288
6287
double numEntryPages ,
6289
6288
numDataPages ,
6290
6289
numPendingPages ,
6291
6290
numEntries ;
6291
+ bool haveFullScan = false;
6292
6292
double partialEntriesInQuals = 0.0 ;
6293
6293
double searchEntriesInQuals = 0.0 ;
6294
6294
double exactEntriesInQuals = 0.0 ;
@@ -6394,6 +6394,8 @@ gincostestimate(PG_FUNCTION_ARGS)
6394
6394
int32 nentries = 0 ;
6395
6395
bool * partial_matches = NULL ;
6396
6396
Pointer * extra_data = NULL ;
6397
+ bool * nullFlags = NULL ;
6398
+ int32 searchMode = GIN_SEARCH_MODE_DEFAULT ;
6397
6399
int indexcol ;
6398
6400
6399
6401
Assert (IsA (rinfo , RestrictInfo ));
@@ -6414,7 +6416,7 @@ gincostestimate(PG_FUNCTION_ARGS)
6414
6416
}
6415
6417
else
6416
6418
{
6417
- elog (ERROR , "Could not match index to operand" );
6419
+ elog (ERROR , "could not match index to operand" );
6418
6420
operand = NULL ; /* keep compiler quiet */
6419
6421
}
6420
6422
@@ -6443,50 +6445,51 @@ gincostestimate(PG_FUNCTION_ARGS)
6443
6445
6444
6446
/*
6445
6447
* Get the operator's strategy number and declared input data types
6446
- * within the index opfamily.
6448
+ * within the index opfamily. (We don't need the latter, but we
6449
+ * use get_op_opfamily_properties because it will throw error if
6450
+ * it fails to find a matching pg_amop entry.)
6447
6451
*/
6448
6452
get_op_opfamily_properties (clause_op , index -> opfamily [indexcol ], false,
6449
6453
& strategy_op , & lefttype , & righttype );
6450
6454
6451
6455
/*
6452
- * GIN (like GiST) always has lefttype == righttype in pg_amproc
6453
- * and they are equal to type Oid on which index was created/designed
6456
+ * GIN always uses the "default" support functions, which are those
6457
+ * with lefttype == righttype == the opclass' opcintype (see
6458
+ * IndexSupportInitialize in relcache.c).
6454
6459
*/
6455
6460
extractProcOid = get_opfamily_proc (index -> opfamily [indexcol ],
6456
- lefttype , lefttype ,
6461
+ index -> opcintype [indexcol ],
6462
+ index -> opcintype [indexcol ],
6457
6463
GIN_EXTRACTQUERY_PROC );
6458
6464
6459
6465
if (!OidIsValid (extractProcOid ))
6460
6466
{
6461
- /* probably shouldn't happen, but cope sanely if so */
6462
- searchEntriesInQuals ++ ;
6463
- continue ;
6467
+ /* should not happen; throw same error as index_getprocinfo */
6468
+ elog (ERROR , "missing support function %d for attribute %d of index \"%s\"" ,
6469
+ GIN_EXTRACTQUERY_PROC , indexcol + 1 ,
6470
+ get_rel_name (index -> indexoid ));
6464
6471
}
6465
6472
6466
- OidFunctionCall5 (extractProcOid ,
6467
- ((Const * )operand )-> constvalue ,
6473
+ OidFunctionCall7 (extractProcOid ,
6474
+ ((Const * ) operand )-> constvalue ,
6468
6475
PointerGetDatum (& nentries ),
6469
6476
UInt16GetDatum (strategy_op ),
6470
6477
PointerGetDatum (& partial_matches ),
6471
- PointerGetDatum (& extra_data ));
6478
+ PointerGetDatum (& extra_data ),
6479
+ PointerGetDatum (& nullFlags ),
6480
+ PointerGetDatum (& searchMode ));
6472
6481
6473
- if (nentries == 0 )
6474
- {
6475
- nfullscan ++ ;
6476
- }
6477
- else if (nentries < 0 )
6482
+ if (nentries <= 0 && searchMode == GIN_SEARCH_MODE_DEFAULT )
6478
6483
{
6479
- /*
6480
- * GIN_EXTRACTQUERY_PROC guarantees that nothing will be found
6481
- */
6484
+ /* No match is possible */
6482
6485
* indexStartupCost = 0 ;
6483
6486
* indexTotalCost = 0 ;
6484
6487
* indexSelectivity = 0 ;
6485
6488
PG_RETURN_VOID ();
6486
6489
}
6487
6490
else
6488
6491
{
6489
- int i ;
6492
+ int32 i ;
6490
6493
6491
6494
for (i = 0 ; i < nentries ; i ++ )
6492
6495
{
@@ -6503,10 +6506,28 @@ gincostestimate(PG_FUNCTION_ARGS)
6503
6506
searchEntriesInQuals ++ ;
6504
6507
}
6505
6508
}
6509
+
6510
+ if (searchMode == GIN_SEARCH_MODE_INCLUDE_EMPTY )
6511
+ {
6512
+ /* Treat "include empty" like an exact-match item */
6513
+ exactEntriesInQuals ++ ;
6514
+ searchEntriesInQuals ++ ;
6515
+ }
6516
+ else if (searchMode != GIN_SEARCH_MODE_DEFAULT )
6517
+ {
6518
+ /* It's GIN_SEARCH_MODE_ALL */
6519
+ haveFullScan = true;
6520
+ }
6506
6521
}
6507
6522
6508
- if (nfullscan == list_length (indexQuals ))
6523
+ if (haveFullScan || indexQuals == NIL )
6524
+ {
6525
+ /*
6526
+ * Full index scan will be required. We treat this as if every key in
6527
+ * the index had been listed in the query; is that reasonable?
6528
+ */
6509
6529
searchEntriesInQuals = numEntries ;
6530
+ }
6510
6531
6511
6532
/* Will we have more than one iteration of a nestloop scan? */
6512
6533
if (outer_rel != NULL && outer_rel -> rows > 1 )
0 commit comments