|
| 1 | +#include"postgres.h" |
| 2 | +#include"optimizer/cost.h" |
| 3 | +#include"optimizer/restrictinfo.h" |
| 4 | +#include"hooks.h" |
| 5 | +#include"pathman.h" |
| 6 | +#include"pickyappend.h" |
| 7 | + |
| 8 | + |
| 9 | +set_join_pathlist_hook_typeset_join_pathlist_next=NULL; |
| 10 | +set_rel_pathlist_hook_typeset_rel_pathlist_hook_next=NULL; |
| 11 | + |
| 12 | + |
| 13 | +void |
| 14 | +pathman_join_pathlist_hook(PlannerInfo*root, |
| 15 | +RelOptInfo*joinrel, |
| 16 | +RelOptInfo*outerrel, |
| 17 | +RelOptInfo*innerrel, |
| 18 | +JoinTypejointype, |
| 19 | +JoinPathExtraData*extra) |
| 20 | +{ |
| 21 | +JoinCostWorkspaceworkspace; |
| 22 | +Path*outer, |
| 23 | +*inner; |
| 24 | +Relidsinner_required; |
| 25 | +RangeTblEntry*inner_entry=root->simple_rte_array[innerrel->relid]; |
| 26 | +PartRelationInfo*inner_prel; |
| 27 | +NestPath*nest_path; |
| 28 | +List*pathkeys=NIL; |
| 29 | +List*joinrestrictclauses=extra->restrictlist; |
| 30 | +List*joinclauses, |
| 31 | +*otherclauses; |
| 32 | +ListCell*lc; |
| 33 | + |
| 34 | +if (set_join_pathlist_next) |
| 35 | +set_join_pathlist_next(root,joinrel,outerrel, |
| 36 | +innerrel,jointype,extra); |
| 37 | + |
| 38 | +if (jointype==JOIN_UNIQUE_OUTER|| |
| 39 | +jointype==JOIN_UNIQUE_INNER) |
| 40 | +{ |
| 41 | +jointype=JOIN_INNER; |
| 42 | +} |
| 43 | + |
| 44 | +if (jointype==JOIN_FULL|| !pg_pathman_enable_pickyappend) |
| 45 | +return; |
| 46 | + |
| 47 | +if (innerrel->reloptkind!=RELOPT_BASEREL|| |
| 48 | +!inner_entry->inh|| |
| 49 | +!(inner_prel=get_pathman_relation_info(inner_entry->relid,NULL))) |
| 50 | +{ |
| 51 | +return;/* Obviously not our case */ |
| 52 | +} |
| 53 | + |
| 54 | +/* Extract join clauses which will separate partitions */ |
| 55 | +if (IS_OUTER_JOIN(extra->sjinfo->jointype)) |
| 56 | +{ |
| 57 | +extract_actual_join_clauses(joinrestrictclauses, |
| 58 | +&joinclauses,&otherclauses); |
| 59 | +} |
| 60 | +else |
| 61 | +{ |
| 62 | +/* We can treat all clauses alike for an inner join */ |
| 63 | +joinclauses=extract_actual_clauses(joinrestrictclauses, false); |
| 64 | +otherclauses=NIL; |
| 65 | +} |
| 66 | + |
| 67 | +foreach (lc,innerrel->pathlist) |
| 68 | +{ |
| 69 | +AppendPath*cur_inner_path= (AppendPath*)lfirst(lc); |
| 70 | + |
| 71 | +if (!IsA(cur_inner_path,AppendPath)) |
| 72 | +continue; |
| 73 | + |
| 74 | +outer=outerrel->cheapest_total_path; |
| 75 | + |
| 76 | +inner_required=bms_union(PATH_REQ_OUTER((Path*)cur_inner_path), |
| 77 | +bms_make_singleton(outerrel->relid)); |
| 78 | + |
| 79 | +inner=create_pickyappend_path(root,cur_inner_path, |
| 80 | +get_appendrel_parampathinfo(innerrel, |
| 81 | +inner_required), |
| 82 | +joinclauses); |
| 83 | + |
| 84 | +initial_cost_nestloop(root,&workspace,jointype, |
| 85 | +outer,inner, |
| 86 | +extra->sjinfo,&extra->semifactors); |
| 87 | + |
| 88 | +pathkeys=build_join_pathkeys(root,joinrel,jointype,outer->pathkeys); |
| 89 | + |
| 90 | +nest_path=create_nestloop_path(root,joinrel,jointype,&workspace, |
| 91 | +extra->sjinfo,&extra->semifactors, |
| 92 | +outer,inner,extra->restrictlist, |
| 93 | +pathkeys, |
| 94 | +calc_nestloop_required_outer(outer,inner)); |
| 95 | + |
| 96 | +add_path(joinrel, (Path*)nest_path); |
| 97 | +} |
| 98 | +} |
| 99 | + |
| 100 | +/* |
| 101 | + * Main hook. All the magic goes here |
| 102 | + */ |
| 103 | +void |
| 104 | +pathman_rel_pathlist_hook(PlannerInfo*root,RelOptInfo*rel,Indexrti,RangeTblEntry*rte) |
| 105 | +{ |
| 106 | +PartRelationInfo*prel=NULL; |
| 107 | +RelOptInfo**new_rel_array; |
| 108 | +RangeTblEntry**new_rte_array; |
| 109 | +intlen; |
| 110 | +boolfound; |
| 111 | +intfirst_child_relid=0; |
| 112 | + |
| 113 | +if (!pg_pathman_enable) |
| 114 | +return; |
| 115 | + |
| 116 | +/* This works only for SELECT queries */ |
| 117 | +if (root->parse->commandType!=CMD_SELECT|| !inheritance_disabled) |
| 118 | +return; |
| 119 | + |
| 120 | +/* Lookup partitioning information for parent relation */ |
| 121 | +prel=get_pathman_relation_info(rte->relid,&found); |
| 122 | + |
| 123 | +if (prel!=NULL&&found) |
| 124 | +{ |
| 125 | +ListCell*lc; |
| 126 | +inti; |
| 127 | +Oid*dsm_arr; |
| 128 | +List*ranges, |
| 129 | +*wrappers; |
| 130 | +PathKey*pathkeyAsc=NULL, |
| 131 | +*pathkeyDesc=NULL; |
| 132 | + |
| 133 | +if (prel->parttype==PT_RANGE) |
| 134 | +{ |
| 135 | +/* |
| 136 | + * Get pathkeys for ascending and descending sort by partition |
| 137 | + * column |
| 138 | + */ |
| 139 | +List*pathkeys; |
| 140 | +Var*var; |
| 141 | +Oidvartypeid, |
| 142 | +varcollid; |
| 143 | +int32type_mod; |
| 144 | +TypeCacheEntry*tce; |
| 145 | + |
| 146 | +/* Make Var from patition column */ |
| 147 | +get_rte_attribute_type(rte,prel->attnum, |
| 148 | +&vartypeid,&type_mod,&varcollid); |
| 149 | +var=makeVar(rti,prel->attnum,vartypeid,type_mod,varcollid,0); |
| 150 | +var->location=-1; |
| 151 | + |
| 152 | +/* Determine operator type */ |
| 153 | +tce=lookup_type_cache(var->vartype,TYPECACHE_LT_OPR |TYPECACHE_GT_OPR); |
| 154 | + |
| 155 | +/* Make pathkeys */ |
| 156 | +pathkeys=build_expression_pathkey(root, (Expr*)var,NULL, |
| 157 | +tce->lt_opr,NULL, false); |
| 158 | +if (pathkeys) |
| 159 | +pathkeyAsc= (PathKey*)linitial(pathkeys); |
| 160 | +pathkeys=build_expression_pathkey(root, (Expr*)var,NULL, |
| 161 | +tce->gt_opr,NULL, false); |
| 162 | +if (pathkeys) |
| 163 | +pathkeyDesc= (PathKey*)linitial(pathkeys); |
| 164 | +} |
| 165 | + |
| 166 | +rte->inh= true; |
| 167 | +dsm_arr= (Oid*)dsm_array_get_pointer(&prel->children); |
| 168 | +ranges=list_make1_int(make_irange(0,prel->children_count-1, false)); |
| 169 | + |
| 170 | +/* Make wrappers over restrictions and collect final rangeset */ |
| 171 | +wrappers=NIL; |
| 172 | +foreach(lc,rel->baserestrictinfo) |
| 173 | +{ |
| 174 | +WrapperNode*wrap; |
| 175 | + |
| 176 | +RestrictInfo*rinfo= (RestrictInfo*)lfirst(lc); |
| 177 | + |
| 178 | +wrap=walk_expr_tree(NULL,rinfo->clause,prel); |
| 179 | +wrappers=lappend(wrappers,wrap); |
| 180 | +ranges=irange_list_intersect(ranges,wrap->rangeset); |
| 181 | +} |
| 182 | + |
| 183 | +/* |
| 184 | + * Expand simple_rte_array and simple_rel_array |
| 185 | + */ |
| 186 | + |
| 187 | +if (ranges) |
| 188 | +{ |
| 189 | +len=irange_list_length(ranges); |
| 190 | + |
| 191 | +/* Expand simple_rel_array and simple_rte_array */ |
| 192 | +new_rel_array= (RelOptInfo**) |
| 193 | +palloc0((root->simple_rel_array_size+len)*sizeof(RelOptInfo*)); |
| 194 | + |
| 195 | +/* simple_rte_array is an array equivalent of the rtable list */ |
| 196 | +new_rte_array= (RangeTblEntry**) |
| 197 | +palloc0((root->simple_rel_array_size+len)*sizeof(RangeTblEntry*)); |
| 198 | + |
| 199 | +/* Copy relations to the new arrays */ |
| 200 | +for (i=0;i<root->simple_rel_array_size;i++) |
| 201 | + { |
| 202 | +new_rel_array[i]=root->simple_rel_array[i]; |
| 203 | +new_rte_array[i]=root->simple_rte_array[i]; |
| 204 | + } |
| 205 | + |
| 206 | +/* Free old arrays */ |
| 207 | +pfree(root->simple_rel_array); |
| 208 | +pfree(root->simple_rte_array); |
| 209 | + |
| 210 | +root->simple_rel_array_size+=len; |
| 211 | +root->simple_rel_array=new_rel_array; |
| 212 | +root->simple_rte_array=new_rte_array; |
| 213 | +} |
| 214 | + |
| 215 | +/* |
| 216 | + * Iterate all indexes in rangeset and append corresponding child |
| 217 | + * relations. |
| 218 | + */ |
| 219 | +foreach(lc,ranges) |
| 220 | +{ |
| 221 | +IndexRangeirange=lfirst_irange(lc); |
| 222 | +OidchildOid; |
| 223 | + |
| 224 | +for (i=irange_lower(irange);i <=irange_upper(irange);i++) |
| 225 | +{ |
| 226 | +intidx; |
| 227 | + |
| 228 | +childOid=dsm_arr[i]; |
| 229 | +idx=append_child_relation(root,rel,rti,rte,i,childOid,wrappers); |
| 230 | + |
| 231 | +if (!first_child_relid) |
| 232 | +first_child_relid=idx; |
| 233 | +} |
| 234 | +} |
| 235 | + |
| 236 | +/* Clear old path list */ |
| 237 | +list_free(rel->pathlist); |
| 238 | + |
| 239 | +rel->pathlist=NIL; |
| 240 | +set_append_rel_pathlist(root,rel,rti,rte,pathkeyAsc,pathkeyDesc); |
| 241 | +set_append_rel_size(root,rel,rti,rte); |
| 242 | +} |
| 243 | + |
| 244 | +/* Invoke original hook if needed */ |
| 245 | +if (set_rel_pathlist_hook_next!=NULL) |
| 246 | +set_rel_pathlist_hook_next(root,rel,rti,rte); |
| 247 | +} |
| 248 | + |