00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "postgres.h"
00016
00017 #include <math.h>
00018
00019 #include "miscadmin.h"
00020 #include "nodes/nodeFuncs.h"
00021 #include "optimizer/clauses.h"
00022 #include "optimizer/cost.h"
00023 #include "optimizer/pathnode.h"
00024 #include "optimizer/paths.h"
00025 #include "optimizer/restrictinfo.h"
00026 #include "optimizer/tlist.h"
00027 #include "parser/parsetree.h"
00028 #include "utils/lsyscache.h"
00029 #include "utils/selfuncs.h"
00030
00031
00032 typedef enum
00033 {
00034 COSTS_EQUAL,
00035 COSTS_BETTER1,
00036 COSTS_BETTER2,
00037 COSTS_DIFFERENT
00038 } PathCostComparison;
00039
00040 static List *translate_sub_tlist(List *tlist, int relid);
00041 static bool query_is_distinct_for(Query *query, List *colnos, List *opids);
00042 static Oid distinct_col_search(int colno, List *colnos, List *opids);
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054 int
00055 compare_path_costs(Path *path1, Path *path2, CostSelector criterion)
00056 {
00057 if (criterion == STARTUP_COST)
00058 {
00059 if (path1->startup_cost < path2->startup_cost)
00060 return -1;
00061 if (path1->startup_cost > path2->startup_cost)
00062 return +1;
00063
00064
00065
00066
00067
00068 if (path1->total_cost < path2->total_cost)
00069 return -1;
00070 if (path1->total_cost > path2->total_cost)
00071 return +1;
00072 }
00073 else
00074 {
00075 if (path1->total_cost < path2->total_cost)
00076 return -1;
00077 if (path1->total_cost > path2->total_cost)
00078 return +1;
00079
00080
00081
00082
00083 if (path1->startup_cost < path2->startup_cost)
00084 return -1;
00085 if (path1->startup_cost > path2->startup_cost)
00086 return +1;
00087 }
00088 return 0;
00089 }
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100 int
00101 compare_fractional_path_costs(Path *path1, Path *path2,
00102 double fraction)
00103 {
00104 Cost cost1,
00105 cost2;
00106
00107 if (fraction <= 0.0 || fraction >= 1.0)
00108 return compare_path_costs(path1, path2, TOTAL_COST);
00109 cost1 = path1->startup_cost +
00110 fraction * (path1->total_cost - path1->startup_cost);
00111 cost2 = path2->startup_cost +
00112 fraction * (path2->total_cost - path2->startup_cost);
00113 if (cost1 < cost2)
00114 return -1;
00115 if (cost1 > cost2)
00116 return +1;
00117 return 0;
00118 }
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151 static PathCostComparison
00152 compare_path_costs_fuzzily(Path *path1, Path *path2, double fuzz_factor,
00153 bool consider_startup)
00154 {
00155
00156
00157
00158
00159 if (path1->total_cost > path2->total_cost * fuzz_factor)
00160 {
00161
00162 if (consider_startup &&
00163 path2->startup_cost > path1->startup_cost * fuzz_factor &&
00164 path1->param_info == NULL)
00165 {
00166
00167 return COSTS_DIFFERENT;
00168 }
00169
00170 return COSTS_BETTER2;
00171 }
00172 if (path2->total_cost > path1->total_cost * fuzz_factor)
00173 {
00174
00175 if (consider_startup &&
00176 path1->startup_cost > path2->startup_cost * fuzz_factor &&
00177 path2->param_info == NULL)
00178 {
00179
00180 return COSTS_DIFFERENT;
00181 }
00182
00183 return COSTS_BETTER1;
00184 }
00185
00186
00187 if (path1->startup_cost > path2->startup_cost * fuzz_factor &&
00188 path2->param_info == NULL)
00189 {
00190
00191 return COSTS_BETTER2;
00192 }
00193 if (path2->startup_cost > path1->startup_cost * fuzz_factor &&
00194 path1->param_info == NULL)
00195 {
00196
00197 return COSTS_BETTER1;
00198 }
00199
00200 return COSTS_EQUAL;
00201 }
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225 void
00226 set_cheapest(RelOptInfo *parent_rel)
00227 {
00228 Path *cheapest_startup_path;
00229 Path *cheapest_total_path;
00230 Path *best_param_path;
00231 List *parameterized_paths;
00232 ListCell *p;
00233
00234 Assert(IsA(parent_rel, RelOptInfo));
00235
00236 if (parent_rel->pathlist == NIL)
00237 elog(ERROR, "could not devise a query plan for the given query");
00238
00239 cheapest_startup_path = cheapest_total_path = best_param_path = NULL;
00240 parameterized_paths = NIL;
00241
00242 foreach(p, parent_rel->pathlist)
00243 {
00244 Path *path = (Path *) lfirst(p);
00245 int cmp;
00246
00247 if (path->param_info)
00248 {
00249
00250 parameterized_paths = lappend(parameterized_paths, path);
00251
00252
00253
00254
00255
00256 if (cheapest_total_path)
00257 continue;
00258
00259
00260
00261
00262
00263
00264 if (best_param_path == NULL)
00265 best_param_path = path;
00266 else
00267 {
00268 switch (bms_subset_compare(PATH_REQ_OUTER(path),
00269 PATH_REQ_OUTER(best_param_path)))
00270 {
00271 case BMS_EQUAL:
00272
00273 if (compare_path_costs(path, best_param_path,
00274 TOTAL_COST) < 0)
00275 best_param_path = path;
00276 break;
00277 case BMS_SUBSET1:
00278
00279 best_param_path = path;
00280 break;
00281 case BMS_SUBSET2:
00282
00283 break;
00284 case BMS_DIFFERENT:
00285
00286
00287
00288
00289
00290 break;
00291 }
00292 }
00293 }
00294 else
00295 {
00296
00297 if (cheapest_total_path == NULL)
00298 {
00299 cheapest_startup_path = cheapest_total_path = path;
00300 continue;
00301 }
00302
00303
00304
00305
00306
00307
00308
00309
00310 cmp = compare_path_costs(cheapest_startup_path, path, STARTUP_COST);
00311 if (cmp > 0 ||
00312 (cmp == 0 &&
00313 compare_pathkeys(cheapest_startup_path->pathkeys,
00314 path->pathkeys) == PATHKEYS_BETTER2))
00315 cheapest_startup_path = path;
00316
00317 cmp = compare_path_costs(cheapest_total_path, path, TOTAL_COST);
00318 if (cmp > 0 ||
00319 (cmp == 0 &&
00320 compare_pathkeys(cheapest_total_path->pathkeys,
00321 path->pathkeys) == PATHKEYS_BETTER2))
00322 cheapest_total_path = path;
00323 }
00324 }
00325
00326
00327 if (cheapest_total_path)
00328 parameterized_paths = lcons(cheapest_total_path, parameterized_paths);
00329
00330
00331
00332
00333
00334 if (cheapest_total_path == NULL)
00335 cheapest_total_path = best_param_path;
00336 Assert(cheapest_total_path != NULL);
00337
00338 parent_rel->cheapest_startup_path = cheapest_startup_path;
00339 parent_rel->cheapest_total_path = cheapest_total_path;
00340 parent_rel->cheapest_unique_path = NULL;
00341 parent_rel->cheapest_parameterized_paths = parameterized_paths;
00342 }
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394 void
00395 add_path(RelOptInfo *parent_rel, Path *new_path)
00396 {
00397 bool accept_new = true;
00398 ListCell *insert_after = NULL;
00399 List *new_path_pathkeys;
00400 ListCell *p1;
00401 ListCell *p1_prev;
00402 ListCell *p1_next;
00403
00404
00405
00406
00407
00408 CHECK_FOR_INTERRUPTS();
00409
00410
00411 new_path_pathkeys = new_path->param_info ? NIL : new_path->pathkeys;
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421 p1_prev = NULL;
00422 for (p1 = list_head(parent_rel->pathlist); p1 != NULL; p1 = p1_next)
00423 {
00424 Path *old_path = (Path *) lfirst(p1);
00425 bool remove_old = false;
00426 PathCostComparison costcmp;
00427 PathKeysComparison keyscmp;
00428 BMS_Comparison outercmp;
00429
00430 p1_next = lnext(p1);
00431
00432
00433
00434
00435
00436 costcmp = compare_path_costs_fuzzily(new_path, old_path, 1.01,
00437 parent_rel->consider_startup);
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450 if (costcmp != COSTS_DIFFERENT)
00451 {
00452
00453 List *old_path_pathkeys;
00454
00455 old_path_pathkeys = old_path->param_info ? NIL : old_path->pathkeys;
00456 keyscmp = compare_pathkeys(new_path_pathkeys,
00457 old_path_pathkeys);
00458 if (keyscmp != PATHKEYS_DIFFERENT)
00459 {
00460 switch (costcmp)
00461 {
00462 case COSTS_EQUAL:
00463 outercmp = bms_subset_compare(PATH_REQ_OUTER(new_path),
00464 PATH_REQ_OUTER(old_path));
00465 if (keyscmp == PATHKEYS_BETTER1)
00466 {
00467 if ((outercmp == BMS_EQUAL ||
00468 outercmp == BMS_SUBSET1) &&
00469 new_path->rows <= old_path->rows)
00470 remove_old = true;
00471 }
00472 else if (keyscmp == PATHKEYS_BETTER2)
00473 {
00474 if ((outercmp == BMS_EQUAL ||
00475 outercmp == BMS_SUBSET2) &&
00476 new_path->rows >= old_path->rows)
00477 accept_new = false;
00478 }
00479 else
00480 {
00481 if (outercmp == BMS_EQUAL)
00482 {
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498 if (new_path->rows < old_path->rows)
00499 remove_old = true;
00500 else if (new_path->rows > old_path->rows)
00501 accept_new = false;
00502 else if (compare_path_costs_fuzzily(new_path,
00503 old_path,
00504 1.0000000001,
00505 parent_rel->consider_startup) == COSTS_BETTER1)
00506 remove_old = true;
00507 else
00508 accept_new = false;
00509
00510 }
00511 else if (outercmp == BMS_SUBSET1 &&
00512 new_path->rows <= old_path->rows)
00513 remove_old = true;
00514 else if (outercmp == BMS_SUBSET2 &&
00515 new_path->rows >= old_path->rows)
00516 accept_new = false;
00517
00518 }
00519 break;
00520 case COSTS_BETTER1:
00521 if (keyscmp != PATHKEYS_BETTER2)
00522 {
00523 outercmp = bms_subset_compare(PATH_REQ_OUTER(new_path),
00524 PATH_REQ_OUTER(old_path));
00525 if ((outercmp == BMS_EQUAL ||
00526 outercmp == BMS_SUBSET1) &&
00527 new_path->rows <= old_path->rows)
00528 remove_old = true;
00529 }
00530 break;
00531 case COSTS_BETTER2:
00532 if (keyscmp != PATHKEYS_BETTER1)
00533 {
00534 outercmp = bms_subset_compare(PATH_REQ_OUTER(new_path),
00535 PATH_REQ_OUTER(old_path));
00536 if ((outercmp == BMS_EQUAL ||
00537 outercmp == BMS_SUBSET2) &&
00538 new_path->rows >= old_path->rows)
00539 accept_new = false;
00540 }
00541 break;
00542 case COSTS_DIFFERENT:
00543
00544
00545
00546
00547
00548 break;
00549 }
00550 }
00551 }
00552
00553
00554
00555
00556 if (remove_old)
00557 {
00558 parent_rel->pathlist = list_delete_cell(parent_rel->pathlist,
00559 p1, p1_prev);
00560
00561
00562
00563
00564 if (!IsA(old_path, IndexPath))
00565 pfree(old_path);
00566
00567 }
00568 else
00569 {
00570
00571 if (new_path->total_cost >= old_path->total_cost)
00572 insert_after = p1;
00573
00574 p1_prev = p1;
00575 }
00576
00577
00578
00579
00580
00581
00582 if (!accept_new)
00583 break;
00584 }
00585
00586 if (accept_new)
00587 {
00588
00589 if (insert_after)
00590 lappend_cell(parent_rel->pathlist, insert_after, new_path);
00591 else
00592 parent_rel->pathlist = lcons(new_path, parent_rel->pathlist);
00593 }
00594 else
00595 {
00596
00597 if (!IsA(new_path, IndexPath))
00598 pfree(new_path);
00599 }
00600 }
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619 bool
00620 add_path_precheck(RelOptInfo *parent_rel,
00621 Cost startup_cost, Cost total_cost,
00622 List *pathkeys, Relids required_outer)
00623 {
00624 List *new_path_pathkeys;
00625 ListCell *p1;
00626
00627
00628 new_path_pathkeys = required_outer ? NIL : pathkeys;
00629
00630 foreach(p1, parent_rel->pathlist)
00631 {
00632 Path *old_path = (Path *) lfirst(p1);
00633 PathKeysComparison keyscmp;
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645 if (total_cost >= old_path->total_cost)
00646 {
00647
00648 if (startup_cost >= old_path->startup_cost || required_outer)
00649 {
00650
00651 List *old_path_pathkeys;
00652
00653 old_path_pathkeys = old_path->param_info ? NIL : old_path->pathkeys;
00654 keyscmp = compare_pathkeys(new_path_pathkeys,
00655 old_path_pathkeys);
00656 if (keyscmp == PATHKEYS_EQUAL ||
00657 keyscmp == PATHKEYS_BETTER2)
00658 {
00659
00660 if (bms_equal(required_outer, PATH_REQ_OUTER(old_path)))
00661 {
00662
00663 return false;
00664 }
00665 }
00666 }
00667 }
00668 else
00669 {
00670
00671
00672
00673
00674
00675 break;
00676 }
00677 }
00678
00679 return true;
00680 }
00681
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692 Path *
00693 create_seqscan_path(PlannerInfo *root, RelOptInfo *rel, Relids required_outer)
00694 {
00695 Path *pathnode = makeNode(Path);
00696
00697 pathnode->pathtype = T_SeqScan;
00698 pathnode->parent = rel;
00699 pathnode->param_info = get_baserel_parampathinfo(root, rel,
00700 required_outer);
00701 pathnode->pathkeys = NIL;
00702
00703 cost_seqscan(pathnode, root, rel, pathnode->param_info);
00704
00705 return pathnode;
00706 }
00707
00708
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730
00731
00732 IndexPath *
00733 create_index_path(PlannerInfo *root,
00734 IndexOptInfo *index,
00735 List *indexclauses,
00736 List *indexclausecols,
00737 List *indexorderbys,
00738 List *indexorderbycols,
00739 List *pathkeys,
00740 ScanDirection indexscandir,
00741 bool indexonly,
00742 Relids required_outer,
00743 double loop_count)
00744 {
00745 IndexPath *pathnode = makeNode(IndexPath);
00746 RelOptInfo *rel = index->rel;
00747 List *indexquals,
00748 *indexqualcols;
00749
00750 pathnode->path.pathtype = indexonly ? T_IndexOnlyScan : T_IndexScan;
00751 pathnode->path.parent = rel;
00752 pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
00753 required_outer);
00754 pathnode->path.pathkeys = pathkeys;
00755
00756
00757 expand_indexqual_conditions(index, indexclauses, indexclausecols,
00758 &indexquals, &indexqualcols);
00759
00760
00761 pathnode->indexinfo = index;
00762 pathnode->indexclauses = indexclauses;
00763 pathnode->indexquals = indexquals;
00764 pathnode->indexqualcols = indexqualcols;
00765 pathnode->indexorderbys = indexorderbys;
00766 pathnode->indexorderbycols = indexorderbycols;
00767 pathnode->indexscandir = indexscandir;
00768
00769 cost_index(pathnode, root, loop_count);
00770
00771 return pathnode;
00772 }
00773
00774
00775
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786 BitmapHeapPath *
00787 create_bitmap_heap_path(PlannerInfo *root,
00788 RelOptInfo *rel,
00789 Path *bitmapqual,
00790 Relids required_outer,
00791 double loop_count)
00792 {
00793 BitmapHeapPath *pathnode = makeNode(BitmapHeapPath);
00794
00795 pathnode->path.pathtype = T_BitmapHeapScan;
00796 pathnode->path.parent = rel;
00797 pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
00798 required_outer);
00799 pathnode->path.pathkeys = NIL;
00800
00801 pathnode->bitmapqual = bitmapqual;
00802
00803 cost_bitmap_heap_scan(&pathnode->path, root, rel,
00804 pathnode->path.param_info,
00805 bitmapqual, loop_count);
00806
00807 return pathnode;
00808 }
00809
00810
00811
00812
00813
00814 BitmapAndPath *
00815 create_bitmap_and_path(PlannerInfo *root,
00816 RelOptInfo *rel,
00817 List *bitmapquals)
00818 {
00819 BitmapAndPath *pathnode = makeNode(BitmapAndPath);
00820
00821 pathnode->path.pathtype = T_BitmapAnd;
00822 pathnode->path.parent = rel;
00823 pathnode->path.param_info = NULL;
00824 pathnode->path.pathkeys = NIL;
00825
00826 pathnode->bitmapquals = bitmapquals;
00827
00828
00829 cost_bitmap_and_node(pathnode, root);
00830
00831 return pathnode;
00832 }
00833
00834
00835
00836
00837
00838 BitmapOrPath *
00839 create_bitmap_or_path(PlannerInfo *root,
00840 RelOptInfo *rel,
00841 List *bitmapquals)
00842 {
00843 BitmapOrPath *pathnode = makeNode(BitmapOrPath);
00844
00845 pathnode->path.pathtype = T_BitmapOr;
00846 pathnode->path.parent = rel;
00847 pathnode->path.param_info = NULL;
00848 pathnode->path.pathkeys = NIL;
00849
00850 pathnode->bitmapquals = bitmapquals;
00851
00852
00853 cost_bitmap_or_node(pathnode, root);
00854
00855 return pathnode;
00856 }
00857
00858
00859
00860
00861
00862 TidPath *
00863 create_tidscan_path(PlannerInfo *root, RelOptInfo *rel, List *tidquals,
00864 Relids required_outer)
00865 {
00866 TidPath *pathnode = makeNode(TidPath);
00867
00868 pathnode->path.pathtype = T_TidScan;
00869 pathnode->path.parent = rel;
00870 pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
00871 required_outer);
00872 pathnode->path.pathkeys = NIL;
00873
00874 pathnode->tidquals = tidquals;
00875
00876 cost_tidscan(&pathnode->path, root, rel, tidquals,
00877 pathnode->path.param_info);
00878
00879 return pathnode;
00880 }
00881
00882
00883
00884
00885
00886
00887
00888
00889 AppendPath *
00890 create_append_path(RelOptInfo *rel, List *subpaths, Relids required_outer)
00891 {
00892 AppendPath *pathnode = makeNode(AppendPath);
00893 ListCell *l;
00894
00895 pathnode->path.pathtype = T_Append;
00896 pathnode->path.parent = rel;
00897 pathnode->path.param_info = get_appendrel_parampathinfo(rel,
00898 required_outer);
00899 pathnode->path.pathkeys = NIL;
00900
00901 pathnode->subpaths = subpaths;
00902
00903
00904
00905
00906
00907
00908
00909
00910
00911 pathnode->path.rows = 0;
00912 pathnode->path.startup_cost = 0;
00913 pathnode->path.total_cost = 0;
00914 foreach(l, subpaths)
00915 {
00916 Path *subpath = (Path *) lfirst(l);
00917
00918 pathnode->path.rows += subpath->rows;
00919
00920 if (l == list_head(subpaths))
00921 pathnode->path.startup_cost = subpath->startup_cost;
00922 pathnode->path.total_cost += subpath->total_cost;
00923
00924
00925 Assert(bms_equal(PATH_REQ_OUTER(subpath), required_outer));
00926 }
00927
00928 return pathnode;
00929 }
00930
00931
00932
00933
00934
00935
00936 MergeAppendPath *
00937 create_merge_append_path(PlannerInfo *root,
00938 RelOptInfo *rel,
00939 List *subpaths,
00940 List *pathkeys,
00941 Relids required_outer)
00942 {
00943 MergeAppendPath *pathnode = makeNode(MergeAppendPath);
00944 Cost input_startup_cost;
00945 Cost input_total_cost;
00946 ListCell *l;
00947
00948 pathnode->path.pathtype = T_MergeAppend;
00949 pathnode->path.parent = rel;
00950 pathnode->path.param_info = get_appendrel_parampathinfo(rel,
00951 required_outer);
00952 pathnode->path.pathkeys = pathkeys;
00953 pathnode->subpaths = subpaths;
00954
00955
00956
00957
00958
00959 if (bms_equal(rel->relids, root->all_baserels))
00960 pathnode->limit_tuples = root->limit_tuples;
00961 else
00962 pathnode->limit_tuples = -1.0;
00963
00964
00965
00966
00967 pathnode->path.rows = 0;
00968 input_startup_cost = 0;
00969 input_total_cost = 0;
00970 foreach(l, subpaths)
00971 {
00972 Path *subpath = (Path *) lfirst(l);
00973
00974 pathnode->path.rows += subpath->rows;
00975
00976 if (pathkeys_contained_in(pathkeys, subpath->pathkeys))
00977 {
00978
00979 input_startup_cost += subpath->startup_cost;
00980 input_total_cost += subpath->total_cost;
00981 }
00982 else
00983 {
00984
00985 Path sort_path;
00986
00987 cost_sort(&sort_path,
00988 root,
00989 pathkeys,
00990 subpath->total_cost,
00991 subpath->parent->tuples,
00992 subpath->parent->width,
00993 0.0,
00994 work_mem,
00995 pathnode->limit_tuples);
00996 input_startup_cost += sort_path.startup_cost;
00997 input_total_cost += sort_path.total_cost;
00998 }
00999
01000
01001 Assert(bms_equal(PATH_REQ_OUTER(subpath), required_outer));
01002 }
01003
01004
01005 cost_merge_append(&pathnode->path, root,
01006 pathkeys, list_length(subpaths),
01007 input_startup_cost, input_total_cost,
01008 rel->tuples);
01009
01010 return pathnode;
01011 }
01012
01013
01014
01015
01016
01017
01018 ResultPath *
01019 create_result_path(List *quals)
01020 {
01021 ResultPath *pathnode = makeNode(ResultPath);
01022
01023 pathnode->path.pathtype = T_Result;
01024 pathnode->path.parent = NULL;
01025 pathnode->path.param_info = NULL;
01026 pathnode->path.pathkeys = NIL;
01027 pathnode->quals = quals;
01028
01029
01030 pathnode->path.rows = 1;
01031 pathnode->path.startup_cost = 0;
01032 pathnode->path.total_cost = cpu_tuple_cost;
01033
01034
01035
01036
01037
01038
01039
01040
01041 return pathnode;
01042 }
01043
01044
01045
01046
01047
01048
01049 MaterialPath *
01050 create_material_path(RelOptInfo *rel, Path *subpath)
01051 {
01052 MaterialPath *pathnode = makeNode(MaterialPath);
01053
01054 Assert(subpath->parent == rel);
01055
01056 pathnode->path.pathtype = T_Material;
01057 pathnode->path.parent = rel;
01058 pathnode->path.param_info = subpath->param_info;
01059 pathnode->path.pathkeys = subpath->pathkeys;
01060
01061 pathnode->subpath = subpath;
01062
01063 cost_material(&pathnode->path,
01064 subpath->startup_cost,
01065 subpath->total_cost,
01066 subpath->rows,
01067 rel->width);
01068
01069 return pathnode;
01070 }
01071
01072
01073
01074
01075
01076
01077
01078
01079
01080
01081
01082
01083 UniquePath *
01084 create_unique_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath,
01085 SpecialJoinInfo *sjinfo)
01086 {
01087 UniquePath *pathnode;
01088 Path sort_path;
01089 Path agg_path;
01090 MemoryContext oldcontext;
01091 List *in_operators;
01092 List *uniq_exprs;
01093 bool all_btree;
01094 bool all_hash;
01095 int numCols;
01096 ListCell *lc;
01097
01098
01099 Assert(subpath == rel->cheapest_total_path);
01100 Assert(subpath->parent == rel);
01101
01102 Assert(sjinfo->jointype == JOIN_SEMI);
01103 Assert(bms_equal(rel->relids, sjinfo->syn_righthand));
01104
01105
01106 if (rel->cheapest_unique_path)
01107 return (UniquePath *) rel->cheapest_unique_path;
01108
01109
01110 if (sjinfo->join_quals == NIL)
01111 return NULL;
01112
01113
01114
01115
01116
01117 oldcontext = MemoryContextSwitchTo(root->planner_cxt);
01118
01119
01120
01121
01122
01123
01124
01125
01126
01127
01128
01129
01130
01131
01132
01133
01134
01135
01136
01137
01138
01139
01140
01141
01142
01143
01144
01145
01146
01147
01148 in_operators = NIL;
01149 uniq_exprs = NIL;
01150 all_btree = true;
01151 all_hash = enable_hashagg;
01152 foreach(lc, sjinfo->join_quals)
01153 {
01154 OpExpr *op = (OpExpr *) lfirst(lc);
01155 Oid opno;
01156 Node *left_expr;
01157 Node *right_expr;
01158 Relids left_varnos;
01159 Relids right_varnos;
01160 Relids all_varnos;
01161 Oid opinputtype;
01162
01163
01164 if (!IsA(op, OpExpr) ||
01165 list_length(op->args) != 2)
01166 {
01167
01168 all_varnos = pull_varnos((Node *) op);
01169 if (!bms_overlap(all_varnos, sjinfo->syn_righthand) ||
01170 bms_is_subset(all_varnos, sjinfo->syn_righthand))
01171 {
01172
01173
01174
01175
01176
01177 if (contain_volatile_functions((Node *) op))
01178 goto no_unique_path;
01179 continue;
01180 }
01181
01182 goto no_unique_path;
01183 }
01184
01185
01186 opno = op->opno;
01187 left_expr = linitial(op->args);
01188 right_expr = lsecond(op->args);
01189 left_varnos = pull_varnos(left_expr);
01190 right_varnos = pull_varnos(right_expr);
01191 all_varnos = bms_union(left_varnos, right_varnos);
01192 opinputtype = exprType(left_expr);
01193
01194
01195 if (!bms_overlap(all_varnos, sjinfo->syn_righthand) ||
01196 bms_is_subset(all_varnos, sjinfo->syn_righthand))
01197 {
01198
01199
01200
01201
01202 if (contain_volatile_functions((Node *) op))
01203 goto no_unique_path;
01204 continue;
01205 }
01206
01207
01208 if (!bms_is_empty(right_varnos) &&
01209 bms_is_subset(right_varnos, sjinfo->syn_righthand) &&
01210 !bms_overlap(left_varnos, sjinfo->syn_righthand))
01211 {
01212
01213 }
01214 else if (!bms_is_empty(left_varnos) &&
01215 bms_is_subset(left_varnos, sjinfo->syn_righthand) &&
01216 !bms_overlap(right_varnos, sjinfo->syn_righthand))
01217 {
01218
01219 opno = get_commutator(opno);
01220 if (!OidIsValid(opno))
01221 goto no_unique_path;
01222 right_expr = left_expr;
01223 }
01224 else
01225 goto no_unique_path;
01226
01227
01228 if (all_btree)
01229 {
01230
01231 if (!op_mergejoinable(opno, opinputtype) ||
01232 get_mergejoin_opfamilies(opno) == NIL)
01233 all_btree = false;
01234 }
01235 if (all_hash)
01236 {
01237
01238 if (!op_hashjoinable(opno, opinputtype))
01239 all_hash = false;
01240 }
01241 if (!(all_btree || all_hash))
01242 goto no_unique_path;
01243
01244
01245 in_operators = lappend_oid(in_operators, opno);
01246 uniq_exprs = lappend(uniq_exprs, copyObject(right_expr));
01247 }
01248
01249
01250 if (uniq_exprs == NIL)
01251 goto no_unique_path;
01252
01253
01254
01255
01256 if (contain_volatile_functions((Node *) uniq_exprs))
01257 goto no_unique_path;
01258
01259
01260
01261
01262
01263 pathnode = makeNode(UniquePath);
01264
01265 pathnode->path.pathtype = T_Unique;
01266 pathnode->path.parent = rel;
01267 pathnode->path.param_info = subpath->param_info;
01268
01269
01270
01271
01272
01273 pathnode->path.pathkeys = NIL;
01274
01275 pathnode->subpath = subpath;
01276 pathnode->in_operators = in_operators;
01277 pathnode->uniq_exprs = uniq_exprs;
01278
01279
01280
01281
01282
01283
01284
01285 if (rel->rtekind == RTE_RELATION && all_btree &&
01286 relation_has_unique_index_for(root, rel, NIL,
01287 uniq_exprs, in_operators))
01288 {
01289 pathnode->umethod = UNIQUE_PATH_NOOP;
01290 pathnode->path.rows = rel->rows;
01291 pathnode->path.startup_cost = subpath->startup_cost;
01292 pathnode->path.total_cost = subpath->total_cost;
01293 pathnode->path.pathkeys = subpath->pathkeys;
01294
01295 rel->cheapest_unique_path = (Path *) pathnode;
01296
01297 MemoryContextSwitchTo(oldcontext);
01298
01299 return pathnode;
01300 }
01301
01302
01303
01304
01305
01306
01307
01308
01309
01310
01311 if (rel->rtekind == RTE_SUBQUERY)
01312 {
01313 RangeTblEntry *rte = planner_rt_fetch(rel->relid, root);
01314 List *sub_tlist_colnos;
01315
01316 sub_tlist_colnos = translate_sub_tlist(uniq_exprs, rel->relid);
01317
01318 if (sub_tlist_colnos &&
01319 query_is_distinct_for(rte->subquery,
01320 sub_tlist_colnos, in_operators))
01321 {
01322 pathnode->umethod = UNIQUE_PATH_NOOP;
01323 pathnode->path.rows = rel->rows;
01324 pathnode->path.startup_cost = subpath->startup_cost;
01325 pathnode->path.total_cost = subpath->total_cost;
01326 pathnode->path.pathkeys = subpath->pathkeys;
01327
01328 rel->cheapest_unique_path = (Path *) pathnode;
01329
01330 MemoryContextSwitchTo(oldcontext);
01331
01332 return pathnode;
01333 }
01334 }
01335
01336
01337 pathnode->path.rows = estimate_num_groups(root, uniq_exprs, rel->rows);
01338 numCols = list_length(uniq_exprs);
01339
01340 if (all_btree)
01341 {
01342
01343
01344
01345 cost_sort(&sort_path, root, NIL,
01346 subpath->total_cost,
01347 rel->rows,
01348 rel->width,
01349 0.0,
01350 work_mem,
01351 -1.0);
01352
01353
01354
01355
01356
01357
01358
01359 sort_path.total_cost += cpu_operator_cost * rel->rows * numCols;
01360 }
01361
01362 if (all_hash)
01363 {
01364
01365
01366
01367
01368 int hashentrysize = rel->width + 64;
01369
01370 if (hashentrysize * pathnode->path.rows > work_mem * 1024L)
01371 all_hash = false;
01372 else
01373 cost_agg(&agg_path, root,
01374 AGG_HASHED, NULL,
01375 numCols, pathnode->path.rows,
01376 subpath->startup_cost,
01377 subpath->total_cost,
01378 rel->rows);
01379 }
01380
01381 if (all_btree && all_hash)
01382 {
01383 if (agg_path.total_cost < sort_path.total_cost)
01384 pathnode->umethod = UNIQUE_PATH_HASH;
01385 else
01386 pathnode->umethod = UNIQUE_PATH_SORT;
01387 }
01388 else if (all_btree)
01389 pathnode->umethod = UNIQUE_PATH_SORT;
01390 else if (all_hash)
01391 pathnode->umethod = UNIQUE_PATH_HASH;
01392 else
01393 goto no_unique_path;
01394
01395 if (pathnode->umethod == UNIQUE_PATH_HASH)
01396 {
01397 pathnode->path.startup_cost = agg_path.startup_cost;
01398 pathnode->path.total_cost = agg_path.total_cost;
01399 }
01400 else
01401 {
01402 pathnode->path.startup_cost = sort_path.startup_cost;
01403 pathnode->path.total_cost = sort_path.total_cost;
01404 }
01405
01406 rel->cheapest_unique_path = (Path *) pathnode;
01407
01408 MemoryContextSwitchTo(oldcontext);
01409
01410 return pathnode;
01411
01412 no_unique_path:
01413
01414
01415 sjinfo->join_quals = NIL;
01416
01417 MemoryContextSwitchTo(oldcontext);
01418
01419 return NULL;
01420 }
01421
01422
01423
01424
01425
01426
01427
01428
01429
01430
01431
01432
01433 static List *
01434 translate_sub_tlist(List *tlist, int relid)
01435 {
01436 List *result = NIL;
01437 ListCell *l;
01438
01439 foreach(l, tlist)
01440 {
01441 Var *var = (Var *) lfirst(l);
01442
01443 if (!var || !IsA(var, Var) ||
01444 var->varno != relid)
01445 return NIL;
01446
01447 result = lappend_int(result, var->varattno);
01448 }
01449 return result;
01450 }
01451
01452
01453
01454
01455
01456
01457
01458
01459
01460
01461
01462
01463
01464
01465
01466
01467 static bool
01468 query_is_distinct_for(Query *query, List *colnos, List *opids)
01469 {
01470 ListCell *l;
01471 Oid opid;
01472
01473 Assert(list_length(colnos) == list_length(opids));
01474
01475
01476
01477
01478
01479
01480 if (query->distinctClause)
01481 {
01482 foreach(l, query->distinctClause)
01483 {
01484 SortGroupClause *sgc = (SortGroupClause *) lfirst(l);
01485 TargetEntry *tle = get_sortgroupclause_tle(sgc,
01486 query->targetList);
01487
01488 opid = distinct_col_search(tle->resno, colnos, opids);
01489 if (!OidIsValid(opid) ||
01490 !equality_ops_are_compatible(opid, sgc->eqop))
01491 break;
01492 }
01493 if (l == NULL)
01494 return true;
01495 }
01496
01497
01498
01499
01500
01501 if (query->groupClause)
01502 {
01503 foreach(l, query->groupClause)
01504 {
01505 SortGroupClause *sgc = (SortGroupClause *) lfirst(l);
01506 TargetEntry *tle = get_sortgroupclause_tle(sgc,
01507 query->targetList);
01508
01509 opid = distinct_col_search(tle->resno, colnos, opids);
01510 if (!OidIsValid(opid) ||
01511 !equality_ops_are_compatible(opid, sgc->eqop))
01512 break;
01513 }
01514 if (l == NULL)
01515 return true;
01516 }
01517 else
01518 {
01519
01520
01521
01522
01523 if (query->hasAggs || query->havingQual)
01524 return true;
01525 }
01526
01527
01528
01529
01530
01531 if (query->setOperations)
01532 {
01533 SetOperationStmt *topop = (SetOperationStmt *) query->setOperations;
01534
01535 Assert(IsA(topop, SetOperationStmt));
01536 Assert(topop->op != SETOP_NONE);
01537
01538 if (!topop->all)
01539 {
01540 ListCell *lg;
01541
01542
01543 lg = list_head(topop->groupClauses);
01544 foreach(l, query->targetList)
01545 {
01546 TargetEntry *tle = (TargetEntry *) lfirst(l);
01547 SortGroupClause *sgc;
01548
01549 if (tle->resjunk)
01550 continue;
01551
01552
01553 Assert(lg != NULL);
01554 sgc = (SortGroupClause *) lfirst(lg);
01555 lg = lnext(lg);
01556
01557 opid = distinct_col_search(tle->resno, colnos, opids);
01558 if (!OidIsValid(opid) ||
01559 !equality_ops_are_compatible(opid, sgc->eqop))
01560 break;
01561 }
01562 if (l == NULL)
01563 return true;
01564 }
01565 }
01566
01567
01568
01569
01570
01571
01572 return false;
01573 }
01574
01575
01576
01577
01578
01579
01580
01581
01582 static Oid
01583 distinct_col_search(int colno, List *colnos, List *opids)
01584 {
01585 ListCell *lc1,
01586 *lc2;
01587
01588 forboth(lc1, colnos, lc2, opids)
01589 {
01590 if (colno == lfirst_int(lc1))
01591 return lfirst_oid(lc2);
01592 }
01593 return InvalidOid;
01594 }
01595
01596
01597
01598
01599
01600
01601 Path *
01602 create_subqueryscan_path(PlannerInfo *root, RelOptInfo *rel,
01603 List *pathkeys, Relids required_outer)
01604 {
01605 Path *pathnode = makeNode(Path);
01606
01607 pathnode->pathtype = T_SubqueryScan;
01608 pathnode->parent = rel;
01609 pathnode->param_info = get_baserel_parampathinfo(root, rel,
01610 required_outer);
01611 pathnode->pathkeys = pathkeys;
01612
01613 cost_subqueryscan(pathnode, root, rel, pathnode->param_info);
01614
01615 return pathnode;
01616 }
01617
01618
01619
01620
01621
01622
01623 Path *
01624 create_functionscan_path(PlannerInfo *root, RelOptInfo *rel,
01625 Relids required_outer)
01626 {
01627 Path *pathnode = makeNode(Path);
01628
01629 pathnode->pathtype = T_FunctionScan;
01630 pathnode->parent = rel;
01631 pathnode->param_info = get_baserel_parampathinfo(root, rel,
01632 required_outer);
01633 pathnode->pathkeys = NIL;
01634
01635 cost_functionscan(pathnode, root, rel, pathnode->param_info);
01636
01637 return pathnode;
01638 }
01639
01640
01641
01642
01643
01644
01645 Path *
01646 create_valuesscan_path(PlannerInfo *root, RelOptInfo *rel,
01647 Relids required_outer)
01648 {
01649 Path *pathnode = makeNode(Path);
01650
01651 pathnode->pathtype = T_ValuesScan;
01652 pathnode->parent = rel;
01653 pathnode->param_info = get_baserel_parampathinfo(root, rel,
01654 required_outer);
01655 pathnode->pathkeys = NIL;
01656
01657 cost_valuesscan(pathnode, root, rel, pathnode->param_info);
01658
01659 return pathnode;
01660 }
01661
01662
01663
01664
01665
01666
01667 Path *
01668 create_ctescan_path(PlannerInfo *root, RelOptInfo *rel, Relids required_outer)
01669 {
01670 Path *pathnode = makeNode(Path);
01671
01672 pathnode->pathtype = T_CteScan;
01673 pathnode->parent = rel;
01674 pathnode->param_info = get_baserel_parampathinfo(root, rel,
01675 required_outer);
01676 pathnode->pathkeys = NIL;
01677
01678 cost_ctescan(pathnode, root, rel, pathnode->param_info);
01679
01680 return pathnode;
01681 }
01682
01683
01684
01685
01686
01687
01688 Path *
01689 create_worktablescan_path(PlannerInfo *root, RelOptInfo *rel,
01690 Relids required_outer)
01691 {
01692 Path *pathnode = makeNode(Path);
01693
01694 pathnode->pathtype = T_WorkTableScan;
01695 pathnode->parent = rel;
01696 pathnode->param_info = get_baserel_parampathinfo(root, rel,
01697 required_outer);
01698 pathnode->pathkeys = NIL;
01699
01700
01701 cost_ctescan(pathnode, root, rel, pathnode->param_info);
01702
01703 return pathnode;
01704 }
01705
01706
01707
01708
01709
01710
01711
01712
01713
01714
01715
01716 ForeignPath *
01717 create_foreignscan_path(PlannerInfo *root, RelOptInfo *rel,
01718 double rows, Cost startup_cost, Cost total_cost,
01719 List *pathkeys,
01720 Relids required_outer,
01721 List *fdw_private)
01722 {
01723 ForeignPath *pathnode = makeNode(ForeignPath);
01724
01725 pathnode->path.pathtype = T_ForeignScan;
01726 pathnode->path.parent = rel;
01727 pathnode->path.param_info = get_baserel_parampathinfo(root, rel,
01728 required_outer);
01729 pathnode->path.rows = rows;
01730 pathnode->path.startup_cost = startup_cost;
01731 pathnode->path.total_cost = total_cost;
01732 pathnode->path.pathkeys = pathkeys;
01733
01734 pathnode->fdw_private = fdw_private;
01735
01736 return pathnode;
01737 }
01738
01739
01740
01741
01742
01743
01744
01745 Relids
01746 calc_nestloop_required_outer(Path *outer_path, Path *inner_path)
01747 {
01748 Relids outer_paramrels = PATH_REQ_OUTER(outer_path);
01749 Relids inner_paramrels = PATH_REQ_OUTER(inner_path);
01750 Relids required_outer;
01751
01752
01753 Assert(!bms_overlap(outer_paramrels, inner_path->parent->relids));
01754
01755 if (!inner_paramrels)
01756 return bms_copy(outer_paramrels);
01757
01758 required_outer = bms_union(outer_paramrels, inner_paramrels);
01759
01760 required_outer = bms_del_members(required_outer,
01761 outer_path->parent->relids);
01762
01763 if (bms_is_empty(required_outer))
01764 {
01765 bms_free(required_outer);
01766 required_outer = NULL;
01767 }
01768 return required_outer;
01769 }
01770
01771
01772
01773
01774
01775
01776
01777 Relids
01778 calc_non_nestloop_required_outer(Path *outer_path, Path *inner_path)
01779 {
01780 Relids outer_paramrels = PATH_REQ_OUTER(outer_path);
01781 Relids inner_paramrels = PATH_REQ_OUTER(inner_path);
01782 Relids required_outer;
01783
01784
01785 Assert(!bms_overlap(outer_paramrels, inner_path->parent->relids));
01786 Assert(!bms_overlap(inner_paramrels, outer_path->parent->relids));
01787
01788 required_outer = bms_union(outer_paramrels, inner_paramrels);
01789
01790 return required_outer;
01791 }
01792
01793
01794
01795
01796
01797
01798
01799
01800
01801
01802
01803
01804
01805
01806
01807
01808
01809
01810
01811 NestPath *
01812 create_nestloop_path(PlannerInfo *root,
01813 RelOptInfo *joinrel,
01814 JoinType jointype,
01815 JoinCostWorkspace *workspace,
01816 SpecialJoinInfo *sjinfo,
01817 SemiAntiJoinFactors *semifactors,
01818 Path *outer_path,
01819 Path *inner_path,
01820 List *restrict_clauses,
01821 List *pathkeys,
01822 Relids required_outer)
01823 {
01824 NestPath *pathnode = makeNode(NestPath);
01825 Relids inner_req_outer = PATH_REQ_OUTER(inner_path);
01826
01827
01828
01829
01830
01831
01832
01833
01834 if (bms_overlap(inner_req_outer, outer_path->parent->relids))
01835 {
01836 Relids inner_and_outer = bms_union(inner_path->parent->relids,
01837 inner_req_outer);
01838 List *jclauses = NIL;
01839 ListCell *lc;
01840
01841 foreach(lc, restrict_clauses)
01842 {
01843 RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
01844
01845 if (!join_clause_is_movable_into(rinfo,
01846 inner_path->parent->relids,
01847 inner_and_outer))
01848 jclauses = lappend(jclauses, rinfo);
01849 }
01850 restrict_clauses = jclauses;
01851 }
01852
01853 pathnode->path.pathtype = T_NestLoop;
01854 pathnode->path.parent = joinrel;
01855 pathnode->path.param_info =
01856 get_joinrel_parampathinfo(root,
01857 joinrel,
01858 outer_path,
01859 inner_path,
01860 sjinfo,
01861 required_outer,
01862 &restrict_clauses);
01863 pathnode->path.pathkeys = pathkeys;
01864 pathnode->jointype = jointype;
01865 pathnode->outerjoinpath = outer_path;
01866 pathnode->innerjoinpath = inner_path;
01867 pathnode->joinrestrictinfo = restrict_clauses;
01868
01869 final_cost_nestloop(root, pathnode, workspace, sjinfo, semifactors);
01870
01871 return pathnode;
01872 }
01873
01874
01875
01876
01877
01878
01879
01880
01881
01882
01883
01884
01885
01886
01887
01888
01889
01890
01891
01892
01893 MergePath *
01894 create_mergejoin_path(PlannerInfo *root,
01895 RelOptInfo *joinrel,
01896 JoinType jointype,
01897 JoinCostWorkspace *workspace,
01898 SpecialJoinInfo *sjinfo,
01899 Path *outer_path,
01900 Path *inner_path,
01901 List *restrict_clauses,
01902 List *pathkeys,
01903 Relids required_outer,
01904 List *mergeclauses,
01905 List *outersortkeys,
01906 List *innersortkeys)
01907 {
01908 MergePath *pathnode = makeNode(MergePath);
01909
01910 pathnode->jpath.path.pathtype = T_MergeJoin;
01911 pathnode->jpath.path.parent = joinrel;
01912 pathnode->jpath.path.param_info =
01913 get_joinrel_parampathinfo(root,
01914 joinrel,
01915 outer_path,
01916 inner_path,
01917 sjinfo,
01918 required_outer,
01919 &restrict_clauses);
01920 pathnode->jpath.path.pathkeys = pathkeys;
01921 pathnode->jpath.jointype = jointype;
01922 pathnode->jpath.outerjoinpath = outer_path;
01923 pathnode->jpath.innerjoinpath = inner_path;
01924 pathnode->jpath.joinrestrictinfo = restrict_clauses;
01925 pathnode->path_mergeclauses = mergeclauses;
01926 pathnode->outersortkeys = outersortkeys;
01927 pathnode->innersortkeys = innersortkeys;
01928
01929
01930 final_cost_mergejoin(root, pathnode, workspace, sjinfo);
01931
01932 return pathnode;
01933 }
01934
01935
01936
01937
01938
01939
01940
01941
01942
01943
01944
01945
01946
01947
01948
01949
01950
01951 HashPath *
01952 create_hashjoin_path(PlannerInfo *root,
01953 RelOptInfo *joinrel,
01954 JoinType jointype,
01955 JoinCostWorkspace *workspace,
01956 SpecialJoinInfo *sjinfo,
01957 SemiAntiJoinFactors *semifactors,
01958 Path *outer_path,
01959 Path *inner_path,
01960 List *restrict_clauses,
01961 Relids required_outer,
01962 List *hashclauses)
01963 {
01964 HashPath *pathnode = makeNode(HashPath);
01965
01966 pathnode->jpath.path.pathtype = T_HashJoin;
01967 pathnode->jpath.path.parent = joinrel;
01968 pathnode->jpath.path.param_info =
01969 get_joinrel_parampathinfo(root,
01970 joinrel,
01971 outer_path,
01972 inner_path,
01973 sjinfo,
01974 required_outer,
01975 &restrict_clauses);
01976
01977
01978
01979
01980
01981
01982
01983
01984
01985
01986
01987
01988 pathnode->jpath.path.pathkeys = NIL;
01989 pathnode->jpath.jointype = jointype;
01990 pathnode->jpath.outerjoinpath = outer_path;
01991 pathnode->jpath.innerjoinpath = inner_path;
01992 pathnode->jpath.joinrestrictinfo = restrict_clauses;
01993 pathnode->path_hashclauses = hashclauses;
01994
01995
01996 final_cost_hashjoin(root, pathnode, workspace, sjinfo, semifactors);
01997
01998 return pathnode;
01999 }
02000
02001
02002
02003
02004
02005
02006
02007
02008
02009
02010
02011
02012
02013
02014
02015
02016
02017
02018 Path *
02019 reparameterize_path(PlannerInfo *root, Path *path,
02020 Relids required_outer,
02021 double loop_count)
02022 {
02023 RelOptInfo *rel = path->parent;
02024
02025
02026 if (!bms_is_subset(PATH_REQ_OUTER(path), required_outer))
02027 return NULL;
02028 switch (path->pathtype)
02029 {
02030 case T_SeqScan:
02031 return create_seqscan_path(root, rel, required_outer);
02032 case T_IndexScan:
02033 case T_IndexOnlyScan:
02034 {
02035 IndexPath *ipath = (IndexPath *) path;
02036 IndexPath *newpath = makeNode(IndexPath);
02037
02038
02039
02040
02041
02042
02043
02044
02045 memcpy(newpath, ipath, sizeof(IndexPath));
02046 newpath->path.param_info =
02047 get_baserel_parampathinfo(root, rel, required_outer);
02048 cost_index(newpath, root, loop_count);
02049 return (Path *) newpath;
02050 }
02051 case T_BitmapHeapScan:
02052 {
02053 BitmapHeapPath *bpath = (BitmapHeapPath *) path;
02054
02055 return (Path *) create_bitmap_heap_path(root,
02056 rel,
02057 bpath->bitmapqual,
02058 required_outer,
02059 loop_count);
02060 }
02061 case T_SubqueryScan:
02062 return create_subqueryscan_path(root, rel, path->pathkeys,
02063 required_outer);
02064 default:
02065 break;
02066 }
02067 return NULL;
02068 }