@@ -109,7 +109,9 @@ static void set_baserel_partition_constraint(Relation relation,
109
109
* If inhparent is true, all we need to do is set up the attr arrays:
110
110
* the RelOptInfo actually represents the appendrel formed by an inheritance
111
111
* tree, and so the parent rel's physical size and index information isn't
112
- * important for it.
112
+ * important for it, however, for partitioned tables, we do populate the
113
+ * indexlist as the planner uses unique indexes as unique proofs for certain
114
+ * optimizations.
113
115
*/
114
116
void
115
117
get_relation_info (PlannerInfo * root , Oid relationObjectId , bool inhparent ,
@@ -175,10 +177,14 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
175
177
176
178
/*
177
179
* Make list of indexes. Ignore indexes on system catalogs if told to.
178
- * Don't bother with indexes for an inheritance parent, either.
180
+ * Don't bother with indexes from traditional inheritance parents. For
181
+ * partitioned tables, we need a list of at least unique indexes as these
182
+ * serve as unique proofs for certain planner optimizations. However,
183
+ * let's not discriminate here and just record all partitioned indexes
184
+ * whether they're unique indexes or not.
179
185
*/
180
- if (inhparent ||
181
- (IgnoreSystemIndexes && IsSystemRelation (relation )))
186
+ if (( inhparent && relation -> rd_rel -> relkind != RELKIND_PARTITIONED_TABLE )
187
+ || (IgnoreSystemIndexes && IsSystemRelation (relation )))
182
188
hasindex = false;
183
189
else
184
190
hasindex = relation -> rd_rel -> relhasindex ;
@@ -231,16 +237,6 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
231
237
continue ;
232
238
}
233
239
234
- /*
235
- * Ignore partitioned indexes, since they are not usable for
236
- * queries.
237
- */
238
- if (indexRelation -> rd_rel -> relkind == RELKIND_PARTITIONED_INDEX )
239
- {
240
- index_close (indexRelation , NoLock );
241
- continue ;
242
- }
243
-
244
240
/*
245
241
* If the index is valid, but cannot yet be used, ignore it; but
246
242
* mark the plan we are generating as transient. See
@@ -285,105 +281,129 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
285
281
286
282
info -> relam = indexRelation -> rd_rel -> relam ;
287
283
288
- /* We copy just the fields we need, not all of rd_indam */
289
- amroutine = indexRelation -> rd_indam ;
290
- info -> amcanorderbyop = amroutine -> amcanorderbyop ;
291
- info -> amoptionalkey = amroutine -> amoptionalkey ;
292
- info -> amsearcharray = amroutine -> amsearcharray ;
293
- info -> amsearchnulls = amroutine -> amsearchnulls ;
294
- info -> amcanparallel = amroutine -> amcanparallel ;
295
- info -> amhasgettuple = (amroutine -> amgettuple != NULL );
296
- info -> amhasgetbitmap = amroutine -> amgetbitmap != NULL &&
297
- relation -> rd_tableam -> scan_bitmap_next_block != NULL ;
298
- info -> amcanmarkpos = (amroutine -> ammarkpos != NULL &&
299
- amroutine -> amrestrpos != NULL );
300
- info -> amcostestimate = amroutine -> amcostestimate ;
301
- Assert (info -> amcostestimate != NULL );
302
-
303
- /* Fetch index opclass options */
304
- info -> opclassoptions = RelationGetIndexAttOptions (indexRelation , true);
305
-
306
284
/*
307
- * Fetch the ordering information for the index, if any.
285
+ * We don't have an AM for partitioned indexes, so we'll just
286
+ * NULLify the AM related fields for those.
308
287
*/
309
- if (info -> relam == BTREE_AM_OID )
288
+ if (indexRelation -> rd_rel -> relkind != RELKIND_PARTITIONED_INDEX )
310
289
{
290
+ /* We copy just the fields we need, not all of rd_indam */
291
+ amroutine = indexRelation -> rd_indam ;
292
+ info -> amcanorderbyop = amroutine -> amcanorderbyop ;
293
+ info -> amoptionalkey = amroutine -> amoptionalkey ;
294
+ info -> amsearcharray = amroutine -> amsearcharray ;
295
+ info -> amsearchnulls = amroutine -> amsearchnulls ;
296
+ info -> amcanparallel = amroutine -> amcanparallel ;
297
+ info -> amhasgettuple = (amroutine -> amgettuple != NULL );
298
+ info -> amhasgetbitmap = amroutine -> amgetbitmap != NULL &&
299
+ relation -> rd_tableam -> scan_bitmap_next_block != NULL ;
300
+ info -> amcanmarkpos = (amroutine -> ammarkpos != NULL &&
301
+ amroutine -> amrestrpos != NULL );
302
+ info -> amcostestimate = amroutine -> amcostestimate ;
303
+ Assert (info -> amcostestimate != NULL );
304
+
305
+ /* Fetch index opclass options */
306
+ info -> opclassoptions = RelationGetIndexAttOptions (indexRelation , true);
307
+
311
308
/*
312
- * If it's a btree index, we can use its opfamily OIDs
313
- * directly as the sort ordering opfamily OIDs.
309
+ * Fetch the ordering information for the index, if any.
314
310
*/
315
- Assert (amroutine -> amcanorder );
316
-
317
- info -> sortopfamily = info -> opfamily ;
318
- info -> reverse_sort = (bool * ) palloc (sizeof (bool ) * nkeycolumns );
319
- info -> nulls_first = (bool * ) palloc (sizeof (bool ) * nkeycolumns );
320
-
321
- for (i = 0 ; i < nkeycolumns ; i ++ )
311
+ if (info -> relam == BTREE_AM_OID )
322
312
{
323
- int16 opt = indexRelation -> rd_indoption [i ];
313
+ /*
314
+ * If it's a btree index, we can use its opfamily OIDs
315
+ * directly as the sort ordering opfamily OIDs.
316
+ */
317
+ Assert (amroutine -> amcanorder );
324
318
325
- info -> reverse_sort [i ] = (opt & INDOPTION_DESC ) != 0 ;
326
- info -> nulls_first [i ] = (opt & INDOPTION_NULLS_FIRST ) != 0 ;
327
- }
328
- }
329
- else if (amroutine -> amcanorder )
330
- {
331
- /*
332
- * Otherwise, identify the corresponding btree opfamilies by
333
- * trying to map this index's "<" operators into btree. Since
334
- * "<" uniquely defines the behavior of a sort order, this is
335
- * a sufficient test.
336
- *
337
- * XXX This method is rather slow and also requires the
338
- * undesirable assumption that the other index AM numbers its
339
- * strategies the same as btree. It'd be better to have a way
340
- * to explicitly declare the corresponding btree opfamily for
341
- * each opfamily of the other index type. But given the lack
342
- * of current or foreseeable amcanorder index types, it's not
343
- * worth expending more effort on now.
344
- */
345
- info -> sortopfamily = (Oid * ) palloc (sizeof (Oid ) * nkeycolumns );
346
- info -> reverse_sort = (bool * ) palloc (sizeof (bool ) * nkeycolumns );
347
- info -> nulls_first = (bool * ) palloc (sizeof (bool ) * nkeycolumns );
319
+ info -> sortopfamily = info -> opfamily ;
320
+ info -> reverse_sort = (bool * ) palloc (sizeof (bool ) * nkeycolumns );
321
+ info -> nulls_first = (bool * ) palloc (sizeof (bool ) * nkeycolumns );
348
322
349
- for (i = 0 ; i < nkeycolumns ; i ++ )
350
- {
351
- int16 opt = indexRelation -> rd_indoption [i ];
352
- Oid ltopr ;
353
- Oid btopfamily ;
354
- Oid btopcintype ;
355
- int16 btstrategy ;
356
-
357
- info -> reverse_sort [i ] = (opt & INDOPTION_DESC ) != 0 ;
358
- info -> nulls_first [i ] = (opt & INDOPTION_NULLS_FIRST ) != 0 ;
359
-
360
- ltopr = get_opfamily_member (info -> opfamily [i ],
361
- info -> opcintype [i ],
362
- info -> opcintype [i ],
363
- BTLessStrategyNumber );
364
- if (OidIsValid (ltopr ) &&
365
- get_ordering_op_properties (ltopr ,
366
- & btopfamily ,
367
- & btopcintype ,
368
- & btstrategy ) &&
369
- btopcintype == info -> opcintype [i ] &&
370
- btstrategy == BTLessStrategyNumber )
323
+ for (i = 0 ; i < nkeycolumns ; i ++ )
371
324
{
372
- /* Successful mapping */
373
- info -> sortopfamily [i ] = btopfamily ;
325
+ int16 opt = indexRelation -> rd_indoption [i ];
326
+
327
+ info -> reverse_sort [i ] = (opt & INDOPTION_DESC ) != 0 ;
328
+ info -> nulls_first [i ] = (opt & INDOPTION_NULLS_FIRST ) != 0 ;
374
329
}
375
- else
330
+ }
331
+ else if (amroutine -> amcanorder )
332
+ {
333
+ /*
334
+ * Otherwise, identify the corresponding btree opfamilies
335
+ * by trying to map this index's "<" operators into btree.
336
+ * Since "<" uniquely defines the behavior of a sort
337
+ * order, this is a sufficient test.
338
+ *
339
+ * XXX This method is rather slow and also requires the
340
+ * undesirable assumption that the other index AM numbers
341
+ * its strategies the same as btree. It'd be better to
342
+ * have a way to explicitly declare the corresponding
343
+ * btree opfamily for each opfamily of the other index
344
+ * type. But given the lack of current or foreseeable
345
+ * amcanorder index types, it's not worth expending more
346
+ * effort on now.
347
+ */
348
+ info -> sortopfamily = (Oid * ) palloc (sizeof (Oid ) * nkeycolumns );
349
+ info -> reverse_sort = (bool * ) palloc (sizeof (bool ) * nkeycolumns );
350
+ info -> nulls_first = (bool * ) palloc (sizeof (bool ) * nkeycolumns );
351
+
352
+ for (i = 0 ; i < nkeycolumns ; i ++ )
376
353
{
377
- /* Fail ... quietly treat index as unordered */
378
- info -> sortopfamily = NULL ;
379
- info -> reverse_sort = NULL ;
380
- info -> nulls_first = NULL ;
381
- break ;
354
+ int16 opt = indexRelation -> rd_indoption [i ];
355
+ Oid ltopr ;
356
+ Oid btopfamily ;
357
+ Oid btopcintype ;
358
+ int16 btstrategy ;
359
+
360
+ info -> reverse_sort [i ] = (opt & INDOPTION_DESC ) != 0 ;
361
+ info -> nulls_first [i ] = (opt & INDOPTION_NULLS_FIRST ) != 0 ;
362
+
363
+ ltopr = get_opfamily_member (info -> opfamily [i ],
364
+ info -> opcintype [i ],
365
+ info -> opcintype [i ],
366
+ BTLessStrategyNumber );
367
+ if (OidIsValid (ltopr ) &&
368
+ get_ordering_op_properties (ltopr ,
369
+ & btopfamily ,
370
+ & btopcintype ,
371
+ & btstrategy ) &&
372
+ btopcintype == info -> opcintype [i ] &&
373
+ btstrategy == BTLessStrategyNumber )
374
+ {
375
+ /* Successful mapping */
376
+ info -> sortopfamily [i ] = btopfamily ;
377
+ }
378
+ else
379
+ {
380
+ /* Fail ... quietly treat index as unordered */
381
+ info -> sortopfamily = NULL ;
382
+ info -> reverse_sort = NULL ;
383
+ info -> nulls_first = NULL ;
384
+ break ;
385
+ }
382
386
}
383
387
}
388
+ else
389
+ {
390
+ info -> sortopfamily = NULL ;
391
+ info -> reverse_sort = NULL ;
392
+ info -> nulls_first = NULL ;
393
+ }
384
394
}
385
395
else
386
396
{
397
+ info -> amcanorderbyop = false;
398
+ info -> amoptionalkey = false;
399
+ info -> amsearcharray = false;
400
+ info -> amsearchnulls = false;
401
+ info -> amcanparallel = false;
402
+ info -> amhasgettuple = false;
403
+ info -> amhasgetbitmap = false;
404
+ info -> amcanmarkpos = false;
405
+ info -> amcostestimate = NULL ;
406
+
387
407
info -> sortopfamily = NULL ;
388
408
info -> reverse_sort = NULL ;
389
409
info -> nulls_first = NULL ;
@@ -416,31 +436,45 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
416
436
* the number-of-tuples estimate to equal the parent table; if it
417
437
* is partial then we have to use the same methods as we would for
418
438
* a table, except we can be sure that the index is not larger
419
- * than the table.
439
+ * than the table. We must ignore partitioned indexes here as as
440
+ * there are not physical indexes.
420
441
*/
421
- if (info -> indpred == NIL )
442
+ if (indexRelation -> rd_rel -> relkind != RELKIND_PARTITIONED_INDEX )
422
443
{
423
- info -> pages = RelationGetNumberOfBlocks (indexRelation );
424
- info -> tuples = rel -> tuples ;
425
- }
426
- else
427
- {
428
- double allvisfrac ; /* dummy */
429
-
430
- estimate_rel_size (indexRelation , NULL ,
431
- & info -> pages , & info -> tuples , & allvisfrac );
432
- if (info -> tuples > rel -> tuples )
444
+ if (info -> indpred == NIL )
445
+ {
446
+ info -> pages = RelationGetNumberOfBlocks (indexRelation );
433
447
info -> tuples = rel -> tuples ;
434
- }
448
+ }
449
+ else
450
+ {
451
+ double allvisfrac ; /* dummy */
435
452
436
- if (info -> relam == BTREE_AM_OID )
437
- {
438
- /* For btrees, get tree height while we have the index open */
439
- info -> tree_height = _bt_getrootheight (indexRelation );
453
+ estimate_rel_size (indexRelation , NULL ,
454
+ & info -> pages , & info -> tuples , & allvisfrac );
455
+ if (info -> tuples > rel -> tuples )
456
+ info -> tuples = rel -> tuples ;
457
+ }
458
+
459
+ if (info -> relam == BTREE_AM_OID )
460
+ {
461
+ /*
462
+ * For btrees, get tree height while we have the index
463
+ * open
464
+ */
465
+ info -> tree_height = _bt_getrootheight (indexRelation );
466
+ }
467
+ else
468
+ {
469
+ /* For other index types, just set it to "unknown" for now */
470
+ info -> tree_height = -1 ;
471
+ }
440
472
}
441
473
else
442
474
{
443
- /* For other index types, just set it to "unknown" for now */
475
+ /* Zero these out for partitioned indexes */
476
+ info -> pages = 0 ;
477
+ info -> tuples = 0.0 ;
444
478
info -> tree_height = -1 ;
445
479
}
446
480
0 commit comments