Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "postgres.h"
00023
00024 #include "executor/executor.h"
00025 #include "executor/nodeLimit.h"
00026 #include "nodes/nodeFuncs.h"
00027
00028 static void recompute_limits(LimitState *node);
00029 static void pass_down_bound(LimitState *node, PlanState *child_node);
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039 TupleTableSlot *
00040 ExecLimit(LimitState *node)
00041 {
00042 ScanDirection direction;
00043 TupleTableSlot *slot;
00044 PlanState *outerPlan;
00045
00046
00047
00048
00049 direction = node->ps.state->es_direction;
00050 outerPlan = outerPlanState(node);
00051
00052
00053
00054
00055 switch (node->lstate)
00056 {
00057 case LIMIT_INITIAL:
00058
00059
00060
00061
00062
00063
00064
00065 recompute_limits(node);
00066
00067
00068
00069 case LIMIT_RESCAN:
00070
00071
00072
00073
00074 if (!ScanDirectionIsForward(direction))
00075 return NULL;
00076
00077
00078
00079
00080 if (node->count <= 0 && !node->noCount)
00081 {
00082 node->lstate = LIMIT_EMPTY;
00083 return NULL;
00084 }
00085
00086
00087
00088
00089 for (;;)
00090 {
00091 slot = ExecProcNode(outerPlan);
00092 if (TupIsNull(slot))
00093 {
00094
00095
00096
00097
00098 node->lstate = LIMIT_EMPTY;
00099 return NULL;
00100 }
00101 node->subSlot = slot;
00102 if (++node->position > node->offset)
00103 break;
00104 }
00105
00106
00107
00108
00109 node->lstate = LIMIT_INWINDOW;
00110 break;
00111
00112 case LIMIT_EMPTY:
00113
00114
00115
00116
00117
00118 return NULL;
00119
00120 case LIMIT_INWINDOW:
00121 if (ScanDirectionIsForward(direction))
00122 {
00123
00124
00125
00126
00127
00128
00129 if (!node->noCount &&
00130 node->position - node->offset >= node->count)
00131 {
00132 node->lstate = LIMIT_WINDOWEND;
00133 return NULL;
00134 }
00135
00136
00137
00138
00139 slot = ExecProcNode(outerPlan);
00140 if (TupIsNull(slot))
00141 {
00142 node->lstate = LIMIT_SUBPLANEOF;
00143 return NULL;
00144 }
00145 node->subSlot = slot;
00146 node->position++;
00147 }
00148 else
00149 {
00150
00151
00152
00153
00154 if (node->position <= node->offset + 1)
00155 {
00156 node->lstate = LIMIT_WINDOWSTART;
00157 return NULL;
00158 }
00159
00160
00161
00162
00163 slot = ExecProcNode(outerPlan);
00164 if (TupIsNull(slot))
00165 elog(ERROR, "LIMIT subplan failed to run backwards");
00166 node->subSlot = slot;
00167 node->position--;
00168 }
00169 break;
00170
00171 case LIMIT_SUBPLANEOF:
00172 if (ScanDirectionIsForward(direction))
00173 return NULL;
00174
00175
00176
00177
00178
00179 slot = ExecProcNode(outerPlan);
00180 if (TupIsNull(slot))
00181 elog(ERROR, "LIMIT subplan failed to run backwards");
00182 node->subSlot = slot;
00183 node->lstate = LIMIT_INWINDOW;
00184
00185 break;
00186
00187 case LIMIT_WINDOWEND:
00188 if (ScanDirectionIsForward(direction))
00189 return NULL;
00190
00191
00192
00193
00194
00195 slot = node->subSlot;
00196 node->lstate = LIMIT_INWINDOW;
00197
00198 break;
00199
00200 case LIMIT_WINDOWSTART:
00201 if (!ScanDirectionIsForward(direction))
00202 return NULL;
00203
00204
00205
00206
00207
00208 slot = node->subSlot;
00209 node->lstate = LIMIT_INWINDOW;
00210
00211 break;
00212
00213 default:
00214 elog(ERROR, "impossible LIMIT state: %d",
00215 (int) node->lstate);
00216 slot = NULL;
00217 break;
00218 }
00219
00220
00221 Assert(!TupIsNull(slot));
00222
00223 return slot;
00224 }
00225
00226
00227
00228
00229
00230
00231 static void
00232 recompute_limits(LimitState *node)
00233 {
00234 ExprContext *econtext = node->ps.ps_ExprContext;
00235 Datum val;
00236 bool isNull;
00237
00238 if (node->limitOffset)
00239 {
00240 val = ExecEvalExprSwitchContext(node->limitOffset,
00241 econtext,
00242 &isNull,
00243 NULL);
00244
00245 if (isNull)
00246 node->offset = 0;
00247 else
00248 {
00249 node->offset = DatumGetInt64(val);
00250 if (node->offset < 0)
00251 ereport(ERROR,
00252 (errcode(ERRCODE_INVALID_ROW_COUNT_IN_RESULT_OFFSET_CLAUSE),
00253 errmsg("OFFSET must not be negative")));
00254 }
00255 }
00256 else
00257 {
00258
00259 node->offset = 0;
00260 }
00261
00262 if (node->limitCount)
00263 {
00264 val = ExecEvalExprSwitchContext(node->limitCount,
00265 econtext,
00266 &isNull,
00267 NULL);
00268
00269 if (isNull)
00270 {
00271 node->count = 0;
00272 node->noCount = true;
00273 }
00274 else
00275 {
00276 node->count = DatumGetInt64(val);
00277 if (node->count < 0)
00278 ereport(ERROR,
00279 (errcode(ERRCODE_INVALID_ROW_COUNT_IN_LIMIT_CLAUSE),
00280 errmsg("LIMIT must not be negative")));
00281 node->noCount = false;
00282 }
00283 }
00284 else
00285 {
00286
00287 node->count = 0;
00288 node->noCount = true;
00289 }
00290
00291
00292 node->position = 0;
00293 node->subSlot = NULL;
00294
00295
00296 node->lstate = LIMIT_RESCAN;
00297
00298
00299 pass_down_bound(node, outerPlanState(node));
00300 }
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318 static void
00319 pass_down_bound(LimitState *node, PlanState *child_node)
00320 {
00321 if (IsA(child_node, SortState))
00322 {
00323 SortState *sortState = (SortState *) child_node;
00324 int64 tuples_needed = node->count + node->offset;
00325
00326
00327 if (node->noCount || tuples_needed < 0)
00328 {
00329
00330 sortState->bounded = false;
00331 }
00332 else
00333 {
00334 sortState->bounded = true;
00335 sortState->bound = tuples_needed;
00336 }
00337 }
00338 else if (IsA(child_node, MergeAppendState))
00339 {
00340 MergeAppendState *maState = (MergeAppendState *) child_node;
00341 int i;
00342
00343 for (i = 0; i < maState->ms_nplans; i++)
00344 pass_down_bound(node, maState->mergeplans[i]);
00345 }
00346 else if (IsA(child_node, ResultState))
00347 {
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359 if (outerPlanState(child_node) &&
00360 !expression_returns_set((Node *) child_node->plan->targetlist))
00361 pass_down_bound(node, outerPlanState(child_node));
00362 }
00363 }
00364
00365
00366
00367
00368
00369
00370
00371
00372 LimitState *
00373 ExecInitLimit(Limit *node, EState *estate, int eflags)
00374 {
00375 LimitState *limitstate;
00376 Plan *outerPlan;
00377
00378
00379 Assert(!(eflags & EXEC_FLAG_MARK));
00380
00381
00382
00383
00384 limitstate = makeNode(LimitState);
00385 limitstate->ps.plan = (Plan *) node;
00386 limitstate->ps.state = estate;
00387
00388 limitstate->lstate = LIMIT_INITIAL;
00389
00390
00391
00392
00393
00394
00395
00396 ExecAssignExprContext(estate, &limitstate->ps);
00397
00398
00399
00400
00401 limitstate->limitOffset = ExecInitExpr((Expr *) node->limitOffset,
00402 (PlanState *) limitstate);
00403 limitstate->limitCount = ExecInitExpr((Expr *) node->limitCount,
00404 (PlanState *) limitstate);
00405
00406
00407
00408
00409 ExecInitResultTupleSlot(estate, &limitstate->ps);
00410
00411
00412
00413
00414 outerPlan = outerPlan(node);
00415 outerPlanState(limitstate) = ExecInitNode(outerPlan, estate, eflags);
00416
00417
00418
00419
00420
00421 ExecAssignResultTypeFromTL(&limitstate->ps);
00422 limitstate->ps.ps_ProjInfo = NULL;
00423
00424 return limitstate;
00425 }
00426
00427
00428
00429
00430
00431
00432
00433
00434 void
00435 ExecEndLimit(LimitState *node)
00436 {
00437 ExecFreeExprContext(&node->ps);
00438 ExecEndNode(outerPlanState(node));
00439 }
00440
00441
00442 void
00443 ExecReScanLimit(LimitState *node)
00444 {
00445
00446
00447
00448
00449
00450 recompute_limits(node);
00451
00452
00453
00454
00455
00456 if (node->ps.lefttree->chgParam == NULL)
00457 ExecReScan(node->ps.lefttree);
00458 }