PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
nodeLimit.c File Reference
#include "postgres.h"
#include "executor/executor.h"
#include "executor/nodeLimit.h"
#include "nodes/nodeFuncs.h"
Include dependency graph for nodeLimit.c:

Go to the source code of this file.

Functions

static void recompute_limits (LimitState *node)
 
static void pass_down_bound (LimitState *node, PlanState *child_node)
 
TupleTableSlotExecLimit (LimitState *node)
 
LimitStateExecInitLimit (Limit *node, EState *estate, int eflags)
 
void ExecEndLimit (LimitState *node)
 
void ExecReScanLimit (LimitState *node)
 

Function Documentation

void ExecEndLimit ( LimitState node)

Definition at line 435 of file nodeLimit.c.

References ExecEndNode(), ExecFreeExprContext(), outerPlanState, and LimitState::ps.

Referenced by ExecEndNode().

436 {
437  ExecFreeExprContext(&node->ps);
439 }
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:624
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:690
#define outerPlanState(node)
Definition: execnodes.h:1096
PlanState ps
Definition: execnodes.h:2099
LimitState* ExecInitLimit ( Limit node,
EState estate,
int  eflags 
)

Definition at line 373 of file nodeLimit.c.

References Assert, EXEC_FLAG_MARK, ExecAssignExprContext(), ExecAssignResultTypeFromTL(), ExecInitExpr(), ExecInitNode(), ExecInitResultTupleSlot(), LIMIT_INITIAL, Limit::limitCount, LimitState::limitCount, Limit::limitOffset, LimitState::limitOffset, LimitState::lstate, makeNode, NULL, outerPlan, outerPlanState, PlanState::plan, LimitState::ps, PlanState::ps_ProjInfo, and PlanState::state.

Referenced by ExecInitNode().

374 {
375  LimitState *limitstate;
376  Plan *outerPlan;
377 
378  /* check for unsupported flags */
379  Assert(!(eflags & EXEC_FLAG_MARK));
380 
381  /*
382  * create state structure
383  */
384  limitstate = makeNode(LimitState);
385  limitstate->ps.plan = (Plan *) node;
386  limitstate->ps.state = estate;
387 
388  limitstate->lstate = LIMIT_INITIAL;
389 
390  /*
391  * Miscellaneous initialization
392  *
393  * Limit nodes never call ExecQual or ExecProject, but they need an
394  * exprcontext anyway to evaluate the limit/offset parameters in.
395  */
396  ExecAssignExprContext(estate, &limitstate->ps);
397 
398  /*
399  * initialize child expressions
400  */
401  limitstate->limitOffset = ExecInitExpr((Expr *) node->limitOffset,
402  (PlanState *) limitstate);
403  limitstate->limitCount = ExecInitExpr((Expr *) node->limitCount,
404  (PlanState *) limitstate);
405 
406  /*
407  * Tuple table initialization (XXX not actually used...)
408  */
409  ExecInitResultTupleSlot(estate, &limitstate->ps);
410 
411  /*
412  * then initialize outer plan
413  */
414  outerPlan = outerPlan(node);
415  outerPlanState(limitstate) = ExecInitNode(outerPlan, estate, eflags);
416 
417  /*
418  * limit nodes do no projections, so initialize projection info for this
419  * node appropriately
420  */
421  ExecAssignResultTypeFromTL(&limitstate->ps);
422  limitstate->ps.ps_ProjInfo = NULL;
423 
424  return limitstate;
425 }
ProjectionInfo * ps_ProjInfo
Definition: execnodes.h:1083
EState * state
Definition: execnodes.h:1053
LimitStateCond lstate
Definition: execnodes.h:2105
ExprState * limitCount
Definition: execnodes.h:2101
Node * limitOffset
Definition: plannodes.h:852
void ExecAssignResultTypeFromTL(PlanState *planstate)
Definition: execUtils.c:429
ExprState * ExecInitExpr(Expr *node, PlanState *parent)
Definition: execQual.c:4562
void ExecInitResultTupleSlot(EState *estate, PlanState *planstate)
Definition: execTuples.c:835
Node * limitCount
Definition: plannodes.h:853
#define outerPlanState(node)
Definition: execnodes.h:1096
ExprState * limitOffset
Definition: execnodes.h:2100
#define outerPlan(node)
Definition: plannodes.h:159
Plan * plan
Definition: execnodes.h:1051
#define makeNode(_type_)
Definition: nodes.h:551
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:667
#define EXEC_FLAG_MARK
Definition: executor.h:61
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition: execUtils.c:407
PlanState * ExecInitNode(Plan *node, EState *estate, int eflags)
Definition: execProcnode.c:137
PlanState ps
Definition: execnodes.h:2099
TupleTableSlot* ExecLimit ( LimitState node)

Definition at line 40 of file nodeLimit.c.

References Assert, LimitState::count, elog, ERROR, EState::es_direction, ExecProcNode(), LIMIT_EMPTY, LIMIT_INITIAL, LIMIT_INWINDOW, LIMIT_RESCAN, LIMIT_SUBPLANEOF, LIMIT_WINDOWEND, LIMIT_WINDOWSTART, LimitState::lstate, LimitState::noCount, NULL, LimitState::offset, outerPlan, outerPlanState, LimitState::position, LimitState::ps, recompute_limits(), ScanDirectionIsForward, PlanState::state, LimitState::subSlot, and TupIsNull.

Referenced by ExecProcNode().

41 {
42  ScanDirection direction;
43  TupleTableSlot *slot;
45 
46  /*
47  * get information from the node
48  */
49  direction = node->ps.state->es_direction;
50  outerPlan = outerPlanState(node);
51 
52  /*
53  * The main logic is a simple state machine.
54  */
55  switch (node->lstate)
56  {
57  case LIMIT_INITIAL:
58 
59  /*
60  * First call for this node, so compute limit/offset. (We can't do
61  * this any earlier, because parameters from upper nodes will not
62  * be set during ExecInitLimit.) This also sets position = 0 and
63  * changes the state to LIMIT_RESCAN.
64  */
65  recompute_limits(node);
66 
67  /* FALL THRU */
68 
69  case LIMIT_RESCAN:
70 
71  /*
72  * If backwards scan, just return NULL without changing state.
73  */
74  if (!ScanDirectionIsForward(direction))
75  return NULL;
76 
77  /*
78  * Check for empty window; if so, treat like empty subplan.
79  */
80  if (node->count <= 0 && !node->noCount)
81  {
82  node->lstate = LIMIT_EMPTY;
83  return NULL;
84  }
85 
86  /*
87  * Fetch rows from subplan until we reach position > offset.
88  */
89  for (;;)
90  {
91  slot = ExecProcNode(outerPlan);
92  if (TupIsNull(slot))
93  {
94  /*
95  * The subplan returns too few tuples for us to produce
96  * any output at all.
97  */
98  node->lstate = LIMIT_EMPTY;
99  return NULL;
100  }
101  node->subSlot = slot;
102  if (++node->position > node->offset)
103  break;
104  }
105 
106  /*
107  * Okay, we have the first tuple of the window.
108  */
109  node->lstate = LIMIT_INWINDOW;
110  break;
111 
112  case LIMIT_EMPTY:
113 
114  /*
115  * The subplan is known to return no tuples (or not more than
116  * OFFSET tuples, in general). So we return no tuples.
117  */
118  return NULL;
119 
120  case LIMIT_INWINDOW:
121  if (ScanDirectionIsForward(direction))
122  {
123  /*
124  * Forwards scan, so check for stepping off end of window. If
125  * we are at the end of the window, return NULL without
126  * advancing the subplan or the position variable; but change
127  * the state machine state to record having done so.
128  */
129  if (!node->noCount &&
130  node->position - node->offset >= node->count)
131  {
132  node->lstate = LIMIT_WINDOWEND;
133  return NULL;
134  }
135 
136  /*
137  * Get next tuple from subplan, if any.
138  */
139  slot = ExecProcNode(outerPlan);
140  if (TupIsNull(slot))
141  {
142  node->lstate = LIMIT_SUBPLANEOF;
143  return NULL;
144  }
145  node->subSlot = slot;
146  node->position++;
147  }
148  else
149  {
150  /*
151  * Backwards scan, so check for stepping off start of window.
152  * As above, change only state-machine status if so.
153  */
154  if (node->position <= node->offset + 1)
155  {
156  node->lstate = LIMIT_WINDOWSTART;
157  return NULL;
158  }
159 
160  /*
161  * Get previous tuple from subplan; there should be one!
162  */
163  slot = ExecProcNode(outerPlan);
164  if (TupIsNull(slot))
165  elog(ERROR, "LIMIT subplan failed to run backwards");
166  node->subSlot = slot;
167  node->position--;
168  }
169  break;
170 
171  case LIMIT_SUBPLANEOF:
172  if (ScanDirectionIsForward(direction))
173  return NULL;
174 
175  /*
176  * Backing up from subplan EOF, so re-fetch previous tuple; there
177  * should be one! Note previous tuple must be in window.
178  */
179  slot = ExecProcNode(outerPlan);
180  if (TupIsNull(slot))
181  elog(ERROR, "LIMIT subplan failed to run backwards");
182  node->subSlot = slot;
183  node->lstate = LIMIT_INWINDOW;
184  /* position does not change 'cause we didn't advance it before */
185  break;
186 
187  case LIMIT_WINDOWEND:
188  if (ScanDirectionIsForward(direction))
189  return NULL;
190 
191  /*
192  * Backing up from window end: simply re-return the last tuple
193  * fetched from the subplan.
194  */
195  slot = node->subSlot;
196  node->lstate = LIMIT_INWINDOW;
197  /* position does not change 'cause we didn't advance it before */
198  break;
199 
200  case LIMIT_WINDOWSTART:
201  if (!ScanDirectionIsForward(direction))
202  return NULL;
203 
204  /*
205  * Advancing after having backed off window start: simply
206  * re-return the last tuple fetched from the subplan.
207  */
208  slot = node->subSlot;
209  node->lstate = LIMIT_INWINDOW;
210  /* position does not change 'cause we didn't change it before */
211  break;
212 
213  default:
214  elog(ERROR, "impossible LIMIT state: %d",
215  (int) node->lstate);
216  slot = NULL; /* keep compiler quiet */
217  break;
218  }
219 
220  /* Return the current tuple */
221  Assert(!TupIsNull(slot));
222 
223  return slot;
224 }
TupleTableSlot * ExecProcNode(PlanState *node)
Definition: execProcnode.c:380
#define ScanDirectionIsForward(direction)
Definition: sdir.h:55
bool noCount
Definition: execnodes.h:2104
EState * state
Definition: execnodes.h:1053
LimitStateCond lstate
Definition: execnodes.h:2105
int64 position
Definition: execnodes.h:2106
ScanDirection es_direction
Definition: execnodes.h:366
int64 count
Definition: execnodes.h:2103
#define ERROR
Definition: elog.h:43
int64 offset
Definition: execnodes.h:2102
#define outerPlanState(node)
Definition: execnodes.h:1096
ScanDirection
Definition: sdir.h:22
#define TupIsNull(slot)
Definition: tuptable.h:138
#define outerPlan(node)
Definition: plannodes.h:159
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:667
TupleTableSlot * subSlot
Definition: execnodes.h:2107
static void recompute_limits(LimitState *node)
Definition: nodeLimit.c:232
#define elog
Definition: elog.h:219
PlanState ps
Definition: execnodes.h:2099
void ExecReScanLimit ( LimitState node)

Definition at line 443 of file nodeLimit.c.

References PlanState::chgParam, ExecReScan(), PlanState::lefttree, NULL, LimitState::ps, and recompute_limits().

Referenced by ExecReScan().

444 {
445  /*
446  * Recompute limit/offset in case parameters changed, and reset the state
447  * machine. We must do this before rescanning our child node, in case
448  * it's a Sort that we are passing the parameters down to.
449  */
450  recompute_limits(node);
451 
452  /*
453  * if chgParam of subnode is not null then plan will be re-scanned by
454  * first ExecProcNode.
455  */
456  if (node->ps.lefttree->chgParam == NULL)
457  ExecReScan(node->ps.lefttree);
458 }
void ExecReScan(PlanState *node)
Definition: execAmi.c:74
struct PlanState * lefttree
Definition: execnodes.h:1067
Bitmapset * chgParam
Definition: execnodes.h:1076
#define NULL
Definition: c.h:226
static void recompute_limits(LimitState *node)
Definition: nodeLimit.c:232
PlanState ps
Definition: execnodes.h:2099
static void pass_down_bound ( LimitState node,
PlanState child_node 
)
static

Definition at line 319 of file nodeLimit.c.

References SortState::bound, SortState::bounded, LimitState::count, expression_returns_set(), i, IsA, MergeAppendState::mergeplans, MergeAppendState::ms_nplans, LimitState::noCount, LimitState::offset, outerPlanState, PlanState::plan, and Plan::targetlist.

Referenced by recompute_limits().

320 {
321  if (IsA(child_node, SortState))
322  {
323  SortState *sortState = (SortState *) child_node;
324  int64 tuples_needed = node->count + node->offset;
325 
326  /* negative test checks for overflow in sum */
327  if (node->noCount || tuples_needed < 0)
328  {
329  /* make sure flag gets reset if needed upon rescan */
330  sortState->bounded = false;
331  }
332  else
333  {
334  sortState->bounded = true;
335  sortState->bound = tuples_needed;
336  }
337  }
338  else if (IsA(child_node, MergeAppendState))
339  {
340  MergeAppendState *maState = (MergeAppendState *) child_node;
341  int i;
342 
343  for (i = 0; i < maState->ms_nplans; i++)
344  pass_down_bound(node, maState->mergeplans[i]);
345  }
346  else if (IsA(child_node, ResultState))
347  {
348  /*
349  * An extra consideration here is that if the Result is projecting a
350  * targetlist that contains any SRFs, we can't assume that every input
351  * tuple generates an output tuple, so a Sort underneath might need to
352  * return more than N tuples to satisfy LIMIT N. So we cannot use
353  * bounded sort.
354  *
355  * If Result supported qual checking, we'd have to punt on seeing a
356  * qual, too. Note that having a resconstantqual is not a
357  * showstopper: if that fails we're not getting any rows at all.
358  */
359  if (outerPlanState(child_node) &&
360  !expression_returns_set((Node *) child_node->plan->targetlist))
361  pass_down_bound(node, outerPlanState(child_node));
362  }
363 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:554
bool noCount
Definition: execnodes.h:2104
bool bounded
Definition: execnodes.h:1830
int64 bound
Definition: execnodes.h:1831
bool expression_returns_set(Node *clause)
Definition: nodeFuncs.c:670
Definition: nodes.h:503
int64 count
Definition: execnodes.h:2103
int64 offset
Definition: execnodes.h:2102
#define outerPlanState(node)
Definition: execnodes.h:1096
PlanState ** mergeplans
Definition: execnodes.h:1216
static void pass_down_bound(LimitState *node, PlanState *child_node)
Definition: nodeLimit.c:319
Plan * plan
Definition: execnodes.h:1051
List * targetlist
Definition: plannodes.h:129
int i
static void recompute_limits ( LimitState node)
static

Definition at line 232 of file nodeLimit.c.

References LimitState::count, DatumGetInt64, ereport, errcode(), errmsg(), ERROR, ExecEvalExprSwitchContext(), LIMIT_RESCAN, LimitState::limitCount, LimitState::limitOffset, LimitState::lstate, LimitState::noCount, NULL, LimitState::offset, outerPlanState, pass_down_bound(), LimitState::position, LimitState::ps, PlanState::ps_ExprContext, LimitState::subSlot, and val.

Referenced by ExecLimit(), and ExecReScanLimit().

233 {
234  ExprContext *econtext = node->ps.ps_ExprContext;
235  Datum val;
236  bool isNull;
237 
238  if (node->limitOffset)
239  {
241  econtext,
242  &isNull,
243  NULL);
244  /* Interpret NULL offset as no offset */
245  if (isNull)
246  node->offset = 0;
247  else
248  {
249  node->offset = DatumGetInt64(val);
250  if (node->offset < 0)
251  ereport(ERROR,
252  (errcode(ERRCODE_INVALID_ROW_COUNT_IN_RESULT_OFFSET_CLAUSE),
253  errmsg("OFFSET must not be negative")));
254  }
255  }
256  else
257  {
258  /* No OFFSET supplied */
259  node->offset = 0;
260  }
261 
262  if (node->limitCount)
263  {
265  econtext,
266  &isNull,
267  NULL);
268  /* Interpret NULL count as no count (LIMIT ALL) */
269  if (isNull)
270  {
271  node->count = 0;
272  node->noCount = true;
273  }
274  else
275  {
276  node->count = DatumGetInt64(val);
277  if (node->count < 0)
278  ereport(ERROR,
279  (errcode(ERRCODE_INVALID_ROW_COUNT_IN_LIMIT_CLAUSE),
280  errmsg("LIMIT must not be negative")));
281  node->noCount = false;
282  }
283  }
284  else
285  {
286  /* No COUNT supplied */
287  node->count = 0;
288  node->noCount = true;
289  }
290 
291  /* Reset position to start-of-scan */
292  node->position = 0;
293  node->subSlot = NULL;
294 
295  /* Set state-machine state */
296  node->lstate = LIMIT_RESCAN;
297 
298  /* Notify child node about limit, if useful */
299  pass_down_bound(node, outerPlanState(node));
300 }
bool noCount
Definition: execnodes.h:2104
ExprContext * ps_ExprContext
Definition: execnodes.h:1082
int errcode(int sqlerrcode)
Definition: elog.c:575
LimitStateCond lstate
Definition: execnodes.h:2105
ExprState * limitCount
Definition: execnodes.h:2101
int64 position
Definition: execnodes.h:2106
int64 count
Definition: execnodes.h:2103
#define ERROR
Definition: elog.h:43
int64 offset
Definition: execnodes.h:2102
#define DatumGetInt64(X)
Definition: postgres.h:615
#define outerPlanState(node)
Definition: execnodes.h:1096
static void pass_down_bound(LimitState *node, PlanState *child_node)
Definition: nodeLimit.c:319
ExprState * limitOffset
Definition: execnodes.h:2100
#define ereport(elevel, rest)
Definition: elog.h:122
Datum ExecEvalExprSwitchContext(ExprState *expression, ExprContext *econtext, bool *isNull, ExprDoneCond *isDone)
Definition: execQual.c:4514
uintptr_t Datum
Definition: postgres.h:374
#define NULL
Definition: c.h:226
TupleTableSlot * subSlot
Definition: execnodes.h:2107
int errmsg(const char *fmt,...)
Definition: elog.c:797
long val
Definition: informix.c:689
PlanState ps
Definition: execnodes.h:2099