00001 /*------------------------------------------------------------------------- 00002 * 00003 * nodeAppend.c 00004 * routines to handle append nodes. 00005 * 00006 * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group 00007 * Portions Copyright (c) 1994, Regents of the University of California 00008 * 00009 * 00010 * IDENTIFICATION 00011 * src/backend/executor/nodeAppend.c 00012 * 00013 *------------------------------------------------------------------------- 00014 */ 00015 /* INTERFACE ROUTINES 00016 * ExecInitAppend - initialize the append node 00017 * ExecAppend - retrieve the next tuple from the node 00018 * ExecEndAppend - shut down the append node 00019 * ExecReScanAppend - rescan the append node 00020 * 00021 * NOTES 00022 * Each append node contains a list of one or more subplans which 00023 * must be iteratively processed (forwards or backwards). 00024 * Tuples are retrieved by executing the 'whichplan'th subplan 00025 * until the subplan stops returning tuples, at which point that 00026 * plan is shut down and the next started up. 00027 * 00028 * Append nodes don't make use of their left and right 00029 * subtrees, rather they maintain a list of subplans so 00030 * a typical append node looks like this in the plan tree: 00031 * 00032 * ... 00033 * / 00034 * Append -------+------+------+--- nil 00035 * / \ | | | 00036 * nil nil ... ... ... 00037 * subplans 00038 * 00039 * Append nodes are currently used for unions, and to support 00040 * inheritance queries, where several relations need to be scanned. 00041 * For example, in our standard person/student/employee/student-emp 00042 * example, where student and employee inherit from person 00043 * and student-emp inherits from student and employee, the 00044 * query: 00045 * 00046 * select name from person 00047 * 00048 * generates the plan: 00049 * 00050 * | 00051 * Append -------+-------+--------+--------+ 00052 * / \ | | | | 00053 * nil nil Scan Scan Scan Scan 00054 * | | | | 00055 * person employee student student-emp 00056 */ 00057 00058 #include "postgres.h" 00059 00060 #include "executor/execdebug.h" 00061 #include "executor/nodeAppend.h" 00062 00063 static bool exec_append_initialize_next(AppendState *appendstate); 00064 00065 00066 /* ---------------------------------------------------------------- 00067 * exec_append_initialize_next 00068 * 00069 * Sets up the append state node for the "next" scan. 00070 * 00071 * Returns t iff there is a "next" scan to process. 00072 * ---------------------------------------------------------------- 00073 */ 00074 static bool 00075 exec_append_initialize_next(AppendState *appendstate) 00076 { 00077 int whichplan; 00078 00079 /* 00080 * get information from the append node 00081 */ 00082 whichplan = appendstate->as_whichplan; 00083 00084 if (whichplan < 0) 00085 { 00086 /* 00087 * if scanning in reverse, we start at the last scan in the list and 00088 * then proceed back to the first.. in any case we inform ExecAppend 00089 * that we are at the end of the line by returning FALSE 00090 */ 00091 appendstate->as_whichplan = 0; 00092 return FALSE; 00093 } 00094 else if (whichplan >= appendstate->as_nplans) 00095 { 00096 /* 00097 * as above, end the scan if we go beyond the last scan in our list.. 00098 */ 00099 appendstate->as_whichplan = appendstate->as_nplans - 1; 00100 return FALSE; 00101 } 00102 else 00103 { 00104 return TRUE; 00105 } 00106 } 00107 00108 /* ---------------------------------------------------------------- 00109 * ExecInitAppend 00110 * 00111 * Begin all of the subscans of the append node. 00112 * 00113 * (This is potentially wasteful, since the entire result of the 00114 * append node may not be scanned, but this way all of the 00115 * structures get allocated in the executor's top level memory 00116 * block instead of that of the call to ExecAppend.) 00117 * ---------------------------------------------------------------- 00118 */ 00119 AppendState * 00120 ExecInitAppend(Append *node, EState *estate, int eflags) 00121 { 00122 AppendState *appendstate = makeNode(AppendState); 00123 PlanState **appendplanstates; 00124 int nplans; 00125 int i; 00126 ListCell *lc; 00127 00128 /* check for unsupported flags */ 00129 Assert(!(eflags & EXEC_FLAG_MARK)); 00130 00131 /* 00132 * Set up empty vector of subplan states 00133 */ 00134 nplans = list_length(node->appendplans); 00135 00136 appendplanstates = (PlanState **) palloc0(nplans * sizeof(PlanState *)); 00137 00138 /* 00139 * create new AppendState for our append node 00140 */ 00141 appendstate->ps.plan = (Plan *) node; 00142 appendstate->ps.state = estate; 00143 appendstate->appendplans = appendplanstates; 00144 appendstate->as_nplans = nplans; 00145 00146 /* 00147 * Miscellaneous initialization 00148 * 00149 * Append plans don't have expression contexts because they never call 00150 * ExecQual or ExecProject. 00151 */ 00152 00153 /* 00154 * append nodes still have Result slots, which hold pointers to tuples, so 00155 * we have to initialize them. 00156 */ 00157 ExecInitResultTupleSlot(estate, &appendstate->ps); 00158 00159 /* 00160 * call ExecInitNode on each of the plans to be executed and save the 00161 * results into the array "appendplans". 00162 */ 00163 i = 0; 00164 foreach(lc, node->appendplans) 00165 { 00166 Plan *initNode = (Plan *) lfirst(lc); 00167 00168 appendplanstates[i] = ExecInitNode(initNode, estate, eflags); 00169 i++; 00170 } 00171 00172 /* 00173 * initialize output tuple type 00174 */ 00175 ExecAssignResultTypeFromTL(&appendstate->ps); 00176 appendstate->ps.ps_ProjInfo = NULL; 00177 00178 /* 00179 * initialize to scan first subplan 00180 */ 00181 appendstate->as_whichplan = 0; 00182 exec_append_initialize_next(appendstate); 00183 00184 return appendstate; 00185 } 00186 00187 /* ---------------------------------------------------------------- 00188 * ExecAppend 00189 * 00190 * Handles iteration over multiple subplans. 00191 * ---------------------------------------------------------------- 00192 */ 00193 TupleTableSlot * 00194 ExecAppend(AppendState *node) 00195 { 00196 for (;;) 00197 { 00198 PlanState *subnode; 00199 TupleTableSlot *result; 00200 00201 /* 00202 * figure out which subplan we are currently processing 00203 */ 00204 subnode = node->appendplans[node->as_whichplan]; 00205 00206 /* 00207 * get a tuple from the subplan 00208 */ 00209 result = ExecProcNode(subnode); 00210 00211 if (!TupIsNull(result)) 00212 { 00213 /* 00214 * If the subplan gave us something then return it as-is. We do 00215 * NOT make use of the result slot that was set up in 00216 * ExecInitAppend; there's no need for it. 00217 */ 00218 return result; 00219 } 00220 00221 /* 00222 * Go on to the "next" subplan in the appropriate direction. If no 00223 * more subplans, return the empty slot set up for us by 00224 * ExecInitAppend. 00225 */ 00226 if (ScanDirectionIsForward(node->ps.state->es_direction)) 00227 node->as_whichplan++; 00228 else 00229 node->as_whichplan--; 00230 if (!exec_append_initialize_next(node)) 00231 return ExecClearTuple(node->ps.ps_ResultTupleSlot); 00232 00233 /* Else loop back and try to get a tuple from the new subplan */ 00234 } 00235 } 00236 00237 /* ---------------------------------------------------------------- 00238 * ExecEndAppend 00239 * 00240 * Shuts down the subscans of the append node. 00241 * 00242 * Returns nothing of interest. 00243 * ---------------------------------------------------------------- 00244 */ 00245 void 00246 ExecEndAppend(AppendState *node) 00247 { 00248 PlanState **appendplans; 00249 int nplans; 00250 int i; 00251 00252 /* 00253 * get information from the node 00254 */ 00255 appendplans = node->appendplans; 00256 nplans = node->as_nplans; 00257 00258 /* 00259 * shut down each of the subscans 00260 */ 00261 for (i = 0; i < nplans; i++) 00262 ExecEndNode(appendplans[i]); 00263 } 00264 00265 void 00266 ExecReScanAppend(AppendState *node) 00267 { 00268 int i; 00269 00270 for (i = 0; i < node->as_nplans; i++) 00271 { 00272 PlanState *subnode = node->appendplans[i]; 00273 00274 /* 00275 * ExecReScan doesn't know about my subplans, so I have to do 00276 * changed-parameter signaling myself. 00277 */ 00278 if (node->ps.chgParam != NULL) 00279 UpdateChangedParamSet(subnode, node->ps.chgParam); 00280 00281 /* 00282 * If chgParam of subnode is not null then plan will be re-scanned by 00283 * first ExecProcNode. 00284 */ 00285 if (subnode->chgParam == NULL) 00286 ExecReScan(subnode); 00287 } 00288 node->as_whichplan = 0; 00289 exec_append_initialize_next(node); 00290 }