|
| 1 | +#include"postgres.h" |
| 2 | +#include"arrangeappend.h" |
| 3 | +#include"pickyappend.h" |
| 4 | + |
| 5 | +#include"pathman.h" |
| 6 | + |
| 7 | +#include"optimizer/clauses.h" |
| 8 | +#include"optimizer/cost.h" |
| 9 | +#include"optimizer/restrictinfo.h" |
| 10 | +#include"optimizer/planmain.h" |
| 11 | +#include"optimizer/tlist.h" |
| 12 | +#include"optimizer/var.h" |
| 13 | + |
| 14 | +#include"lib/binaryheap.h" |
| 15 | + |
| 16 | + |
| 17 | +boolpg_pathman_enable_arrangeappend= true; |
| 18 | + |
| 19 | +CustomPathMethodsarrangeappend_path_methods; |
| 20 | +CustomScanMethodsarrangeappend_plan_methods; |
| 21 | +CustomExecMethodsarrangeappend_exec_methods; |
| 22 | + |
| 23 | + |
| 24 | +/* |
| 25 | + * We have one slot for each item in the heap array. We use SlotNumber |
| 26 | + * to store slot indexes. This doesn't actually provide any formal |
| 27 | + * type-safety, but it makes the code more self-documenting. |
| 28 | + */ |
| 29 | +typedefint32SlotNumber; |
| 30 | + |
| 31 | +/* |
| 32 | + * Compare the tuples in the two given slots. |
| 33 | + */ |
| 34 | +staticint32 |
| 35 | +heap_compare_slots(Datuma,Datumb,void*arg) |
| 36 | +{ |
| 37 | +ArrangeAppendState*node= (ArrangeAppendState*)arg; |
| 38 | +SlotNumberslot1=DatumGetInt32(a); |
| 39 | +SlotNumberslot2=DatumGetInt32(b); |
| 40 | + |
| 41 | +TupleTableSlot*s1=node->ms_slots[slot1]; |
| 42 | +TupleTableSlot*s2=node->ms_slots[slot2]; |
| 43 | +intnkey; |
| 44 | + |
| 45 | +Assert(!TupIsNull(s1)); |
| 46 | +Assert(!TupIsNull(s2)); |
| 47 | + |
| 48 | +for (nkey=0;nkey<node->ms_nkeys;nkey++) |
| 49 | +{ |
| 50 | +SortSupportsortKey=node->ms_sortkeys+nkey; |
| 51 | +AttrNumberattno=sortKey->ssup_attno; |
| 52 | +Datumdatum1, |
| 53 | +datum2; |
| 54 | +boolisNull1, |
| 55 | +isNull2; |
| 56 | +intcompare; |
| 57 | + |
| 58 | +datum1=slot_getattr(s1,attno,&isNull1); |
| 59 | +datum2=slot_getattr(s2,attno,&isNull2); |
| 60 | + |
| 61 | +compare=ApplySortComparator(datum1,isNull1, |
| 62 | +datum2,isNull2, |
| 63 | +sortKey); |
| 64 | +if (compare!=0) |
| 65 | +return-compare; |
| 66 | +} |
| 67 | +return0; |
| 68 | +} |
| 69 | + |
| 70 | +Path* |
| 71 | +create_arrangeappend_path(PlannerInfo*root, |
| 72 | +AppendPath*inner_append, |
| 73 | +ParamPathInfo*param_info, |
| 74 | +List*picky_clauses) |
| 75 | +{ |
| 76 | +returncreate_append_path_common(root,inner_append, |
| 77 | +param_info,picky_clauses, |
| 78 | +&arrangeappend_path_methods); |
| 79 | +} |
| 80 | + |
| 81 | +Plan* |
| 82 | +create_arrangeappend_plan(PlannerInfo*root,RelOptInfo*rel, |
| 83 | +CustomPath*best_path,List*tlist, |
| 84 | +List*clauses,List*custom_plans) |
| 85 | +{ |
| 86 | +returncreate_append_plan_common(root,rel, |
| 87 | +best_path,tlist, |
| 88 | +clauses,custom_plans, |
| 89 | +&arrangeappend_plan_methods); |
| 90 | +} |
| 91 | + |
| 92 | +Node* |
| 93 | +arrangeappend_create_scan_state(CustomScan*node) |
| 94 | +{ |
| 95 | +returncreate_append_scan_state_common(node, |
| 96 | +&arrangeappend_exec_methods, |
| 97 | +sizeof(ArrangeAppendState)); |
| 98 | +} |
| 99 | + |
| 100 | +void |
| 101 | +arrangeappend_begin(CustomScanState*node,EState*estate,inteflags) |
| 102 | +{ |
| 103 | +ArrangeAppendState*scan_state= (ArrangeAppendState*)node; |
| 104 | + |
| 105 | +begin_append_common(node,estate,eflags); |
| 106 | +} |
| 107 | + |
| 108 | +TupleTableSlot* |
| 109 | +arrangeappend_exec(CustomScanState*node) |
| 110 | +{ |
| 111 | +ArrangeAppendState*scan_state= (ArrangeAppendState*)node; |
| 112 | + |
| 113 | +while (scan_state->running_idx<scan_state->ncur_plans) |
| 114 | +{ |
| 115 | +ChildScanCommonchild=scan_state->cur_plans[scan_state->running_idx]; |
| 116 | +PlanState*state=child->content.plan_state; |
| 117 | +TupleTableSlot*slot=NULL; |
| 118 | +boolquals; |
| 119 | + |
| 120 | +for (;;) |
| 121 | +{ |
| 122 | +slot=ExecProcNode(state); |
| 123 | + |
| 124 | +if (TupIsNull(slot)) |
| 125 | +break; |
| 126 | + |
| 127 | +node->ss.ps.ps_ExprContext->ecxt_scantuple=slot; |
| 128 | +quals=ExecQual(scan_state->custom_expr_states, |
| 129 | +node->ss.ps.ps_ExprContext, false); |
| 130 | + |
| 131 | +if (quals) |
| 132 | +returnslot; |
| 133 | +} |
| 134 | + |
| 135 | +scan_state->running_idx++; |
| 136 | +} |
| 137 | + |
| 138 | +returnNULL; |
| 139 | +} |
| 140 | + |
| 141 | +void |
| 142 | +arrangeappend_end(CustomScanState*node) |
| 143 | +{ |
| 144 | +ArrangeAppendState*scan_state= (ArrangeAppendState*)node; |
| 145 | + |
| 146 | +end_append_common(node); |
| 147 | +} |
| 148 | + |
| 149 | +void |
| 150 | +arrangeappend_rescan(CustomScanState*node) |
| 151 | +{ |
| 152 | +ArrangeAppendState*scan_state= (ArrangeAppendState*)node; |
| 153 | +intnplans=scan_state->picky_base.ncur_plans; |
| 154 | +inti; |
| 155 | + |
| 156 | +rescan_append_common(node); |
| 157 | + |
| 158 | +scan_state->ms_slots= (TupleTableSlot**)palloc0(sizeof(TupleTableSlot*)*nplans); |
| 159 | +scan_state->ms_heap=binaryheap_allocate(nplans,heap_compare_slots,scan_state); |
| 160 | + |
| 161 | +/* |
| 162 | + * initialize sort-key information |
| 163 | + */ |
| 164 | +scan_state->ms_nkeys=scan_state->numCols; |
| 165 | +scan_state->ms_sortkeys=palloc0(sizeof(SortSupportData)*scan_state->numCols); |
| 166 | + |
| 167 | +for (i=0;i<scan_state->numCols;i++) |
| 168 | +{ |
| 169 | +SortSupportsortKey=scan_state->ms_sortkeys+i; |
| 170 | + |
| 171 | +sortKey->ssup_cxt=CurrentMemoryContext; |
| 172 | +sortKey->ssup_collation=scan_state->collations[i]; |
| 173 | +sortKey->ssup_nulls_first=scan_state->nullsFirst[i]; |
| 174 | +sortKey->ssup_attno=scan_state->sortColIdx[i]; |
| 175 | + |
| 176 | +/* |
| 177 | + * It isn't feasible to perform abbreviated key conversion, since |
| 178 | + * tuples are pulled into mergestate's binary heap as needed. It |
| 179 | + * would likely be counter-productive to convert tuples into an |
| 180 | + * abbreviated representation as they're pulled up, so opt out of that |
| 181 | + * additional optimization entirely. |
| 182 | + */ |
| 183 | +sortKey->abbreviate= false; |
| 184 | + |
| 185 | +PrepareSortSupportFromOrderingOp(scan_state->sortOperators[i],sortKey); |
| 186 | +} |
| 187 | +} |
| 188 | + |
| 189 | +void |
| 190 | +pickyppend_explain(CustomScanState*node,List*ancestors,ExplainState*es) |
| 191 | +{ |
| 192 | +ArrangeAppendState*scan_state= (ArrangeAppendState*)node; |
| 193 | + |
| 194 | +explain_append_common(node,scan_state->picky_base.children_table,es); |
| 195 | +} |