|
19 | 19 | #include "catalog/pg_type.h"
|
20 | 20 | #include "foreign/fdwapi.h"
|
21 | 21 | #include "foreign/foreign.h"
|
| 22 | +#include "miscadmin.h" |
22 | 23 | #include "nodes/nodeFuncs.h"
|
23 | 24 | #include "rewrite/rewriteManip.h"
|
24 | 25 | #include "utils/guc.h"
|
@@ -239,6 +240,9 @@ scan_result_parts_storage(Oid partid, ResultPartsStorage *parts_storage)
|
239 | 240 | (const void *) &partid,
|
240 | 241 | HASH_ENTER, &found);
|
241 | 242 |
|
| 243 | + /* Don't execute recheck_partition_for_value() every time */ |
| 244 | + rri_holder->first_time = !found; |
| 245 | + |
242 | 246 | /* If not found, create & cache new ResultRelInfo */
|
243 | 247 | if (!found)
|
244 | 248 | {
|
@@ -432,43 +436,52 @@ select_partition_for_insert(Datum value, Oid value_type,
|
432 | 436 |
|
433 | 437 | do
|
434 | 438 | {
|
| 439 | + bool refresh_prel; |
| 440 | + |
435 | 441 | /* Search for matching partitions */
|
436 | 442 | parts = find_partitions_for_value(value, value_type, prel, &nparts);
|
437 | 443 |
|
438 | 444 | if (nparts > 1)
|
439 | 445 | elog(ERROR, ERR_PART_ATTR_MULTIPLE);
|
440 | 446 | else if (nparts == 0)
|
441 | 447 | {
|
442 |
| - selected_partid = create_partitions_for_value(parent_relid, |
443 |
| - value, value_type); |
| 448 | + selected_partid = create_partitions_for_value(parent_relid, |
| 449 | + value, value_type); |
444 | 450 |
|
445 |
| - /* get_pathman_relation_info() will refresh this entry */ |
446 |
| - invalidate_pathman_relation_info(parent_relid, NULL); |
| 451 | + /* get_pathman_relation_info() will refresh this entry */ |
| 452 | + invalidate_pathman_relation_info(parent_relid, NULL); |
447 | 453 | }
|
448 | 454 | else selected_partid = parts[0];
|
449 | 455 |
|
450 |
| - /* Replace parent table with a suitable partition */ |
| 456 | + pfree(parts); |
| 457 | + |
| 458 | + /* Get ResultRelationInfo of a suitable partition (may invalidate 'prel') */ |
451 | 459 | old_mcxt = MemoryContextSwitchTo(estate->es_query_cxt);
|
452 | 460 | rri_holder = scan_result_parts_storage(selected_partid, parts_storage);
|
453 | 461 | MemoryContextSwitchTo(old_mcxt);
|
454 | 462 |
|
455 |
| - /* This partition has been dropped, repeat with a new 'prel' */ |
456 |
| - if (rri_holder == NULL) |
| 463 | + /* |
| 464 | + * We'd like to refresh PartRelationInfo if: |
| 465 | + * 1) Partition we've just chosen had been removed; |
| 466 | + * 2) It changed and we've chosen a visible partition for the 1st time. |
| 467 | + */ |
| 468 | + refresh_prel = !PointerIsValid(rri_holder) || |
| 469 | + (!PrelIsValid(prel) && rri_holder->first_time && nparts > 0); |
| 470 | + |
| 471 | + if (refresh_prel) |
457 | 472 | {
|
458 |
| - /* get_pathman_relation_info() will refresh this entry */ |
459 | 473 | invalidate_pathman_relation_info(parent_relid, NULL);
|
460 | 474 |
|
461 | 475 | /* Get a fresh PartRelationInfo */
|
462 | 476 | prel = get_pathman_relation_info(parent_relid);
|
| 477 | + shout_if_prel_is_invalid(parent_relid, prel, PT_ANY); |
463 | 478 |
|
464 |
| - /* Paranoid check (all partitions have vanished) */ |
465 |
| - if (!prel) |
466 |
| - elog(ERROR, "table \"%s\" is not partitioned", |
467 |
| - get_rel_name_or_relid(parent_relid)); |
| 479 | + /* Reset selected partition */ |
| 480 | + rri_holder = NULL; |
468 | 481 | }
|
469 | 482 | }
|
470 | 483 | /* Loop until we get some result */
|
471 |
| - while (rri_holder == NULL); |
| 484 | + while (!PointerIsValid(rri_holder)); |
472 | 485 |
|
473 | 486 | return rri_holder;
|
474 | 487 | }
|
|
0 commit comments