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 "miscadmin.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)
 
static TupleTableSlotExecLimit (PlanState *pstate)
 
LimitStateExecInitLimit (Limit *node, EState *estate, int eflags)
 
void ExecEndLimit (LimitState *node)
 
void ExecReScanLimit (LimitState *node)
 

Function Documentation

void ExecEndLimit ( LimitState node)

Definition at line 431 of file nodeLimit.c.

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

Referenced by ExecEndNode().

432 {
433  ExecFreeExprContext(&node->ps);
435 }
void ExecEndNode(PlanState *node)
Definition: execProcnode.c:523
void ExecFreeExprContext(PlanState *planstate)
Definition: execUtils.c:521
#define outerPlanState(node)
Definition: execnodes.h:893
PlanState ps
Definition: execnodes.h:2034
LimitState* ExecInitLimit ( Limit node,
EState estate,
int  eflags 
)

Definition at line 368 of file nodeLimit.c.

References Assert, EXEC_FLAG_MARK, ExecAssignExprContext(), ExecAssignResultTypeFromTL(), ExecInitExpr(), ExecInitNode(), ExecInitResultTupleSlot(), ExecLimit(), PlanState::ExecProcNode, 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().

369 {
370  LimitState *limitstate;
371  Plan *outerPlan;
372 
373  /* check for unsupported flags */
374  Assert(!(eflags & EXEC_FLAG_MARK));
375 
376  /*
377  * create state structure
378  */
379  limitstate = makeNode(LimitState);
380  limitstate->ps.plan = (Plan *) node;
381  limitstate->ps.state = estate;
382  limitstate->ps.ExecProcNode = ExecLimit;
383 
384  limitstate->lstate = LIMIT_INITIAL;
385 
386  /*
387  * Miscellaneous initialization
388  *
389  * Limit nodes never call ExecQual or ExecProject, but they need an
390  * exprcontext anyway to evaluate the limit/offset parameters in.
391  */
392  ExecAssignExprContext(estate, &limitstate->ps);
393 
394  /*
395  * initialize child expressions
396  */
397  limitstate->limitOffset = ExecInitExpr((Expr *) node->limitOffset,
398  (PlanState *) limitstate);
399  limitstate->limitCount = ExecInitExpr((Expr *) node->limitCount,
400  (PlanState *) limitstate);
401 
402  /*
403  * Tuple table initialization (XXX not actually used...)
404  */
405  ExecInitResultTupleSlot(estate, &limitstate->ps);
406 
407  /*
408  * then initialize outer plan
409  */
410  outerPlan = outerPlan(node);
411  outerPlanState(limitstate) = ExecInitNode(outerPlan, estate, eflags);
412 
413  /*
414  * limit nodes do no projections, so initialize projection info for this
415  * node appropriately
416  */
417  ExecAssignResultTypeFromTL(&limitstate->ps);
418  limitstate->ps.ps_ProjInfo = NULL;
419 
420  return limitstate;
421 }
static TupleTableSlot * ExecLimit(PlanState *pstate)
Definition: nodeLimit.c:41
ProjectionInfo * ps_ProjInfo
Definition: execnodes.h:882
EState * state
Definition: execnodes.h:849
LimitStateCond lstate
Definition: execnodes.h:2040
ExprState * limitCount
Definition: execnodes.h:2036
Node * limitOffset
Definition: plannodes.h:915
void ExecAssignResultTypeFromTL(PlanState *planstate)
Definition: execUtils.c:445
void ExecInitResultTupleSlot(EState *estate, PlanState *planstate)
Definition: execTuples.c:832
Node * limitCount
Definition: plannodes.h:916
#define outerPlanState(node)
Definition: execnodes.h:893
ExprState * limitOffset
Definition: execnodes.h:2035
#define outerPlan(node)
Definition: plannodes.h:174
ExecProcNodeMtd ExecProcNode
Definition: execnodes.h:853
Plan * plan
Definition: execnodes.h:847
#define makeNode(_type_)
Definition: nodes.h:557
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:676
#define EXEC_FLAG_MARK
Definition: executor.h:61
void ExecAssignExprContext(EState *estate, PlanState *planstate)
Definition: execUtils.c:423
ExprState * ExecInitExpr(Expr *node, PlanState *parent)
Definition: execExpr.c:113
PlanState * ExecInitNode(Plan *node, EState *estate, int eflags)
Definition: execProcnode.c:139
PlanState ps
Definition: execnodes.h:2034
static TupleTableSlot* ExecLimit ( PlanState pstate)
static

Definition at line 41 of file nodeLimit.c.

References Assert, castNode, CHECK_FOR_INTERRUPTS, 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 ExecInitLimit().

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

Definition at line 439 of file nodeLimit.c.

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

Referenced by ExecReScan().

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

Definition at line 321 of file nodeLimit.c.

References SortState::bound, SortState::bounded, LimitState::count, i, IsA, MergeAppendState::mergeplans, MergeAppendState::ms_nplans, LimitState::noCount, LimitState::offset, and outerPlanState.

Referenced by recompute_limits().

322 {
323  if (IsA(child_node, SortState))
324  {
325  SortState *sortState = (SortState *) child_node;
326  int64 tuples_needed = node->count + node->offset;
327 
328  /* negative test checks for overflow in sum */
329  if (node->noCount || tuples_needed < 0)
330  {
331  /* make sure flag gets reset if needed upon rescan */
332  sortState->bounded = false;
333  }
334  else
335  {
336  sortState->bounded = true;
337  sortState->bound = tuples_needed;
338  }
339  }
340  else if (IsA(child_node, MergeAppendState))
341  {
342  MergeAppendState *maState = (MergeAppendState *) child_node;
343  int i;
344 
345  for (i = 0; i < maState->ms_nplans; i++)
346  pass_down_bound(node, maState->mergeplans[i]);
347  }
348  else if (IsA(child_node, ResultState))
349  {
350  /*
351  * If Result supported qual checking, we'd have to punt on seeing a
352  * qual. Note that having a resconstantqual is not a showstopper: if
353  * that fails we're not getting any rows at all.
354  */
355  if (outerPlanState(child_node))
356  pass_down_bound(node, outerPlanState(child_node));
357  }
358 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:560
bool noCount
Definition: execnodes.h:2039
bool bounded
Definition: execnodes.h:1741
int64 bound
Definition: execnodes.h:1742
int64 count
Definition: execnodes.h:2038
int64 offset
Definition: execnodes.h:2037
#define outerPlanState(node)
Definition: execnodes.h:893
PlanState ** mergeplans
Definition: execnodes.h:1020
static void pass_down_bound(LimitState *node, PlanState *child_node)
Definition: nodeLimit.c:321
int i
static void recompute_limits ( LimitState node)
static

Definition at line 236 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().

237 {
238  ExprContext *econtext = node->ps.ps_ExprContext;
239  Datum val;
240  bool isNull;
241 
242  if (node->limitOffset)
243  {
245  econtext,
246  &isNull);
247  /* Interpret NULL offset as no offset */
248  if (isNull)
249  node->offset = 0;
250  else
251  {
252  node->offset = DatumGetInt64(val);
253  if (node->offset < 0)
254  ereport(ERROR,
255  (errcode(ERRCODE_INVALID_ROW_COUNT_IN_RESULT_OFFSET_CLAUSE),
256  errmsg("OFFSET must not be negative")));
257  }
258  }
259  else
260  {
261  /* No OFFSET supplied */
262  node->offset = 0;
263  }
264 
265  if (node->limitCount)
266  {
268  econtext,
269  &isNull);
270  /* Interpret NULL count as no count (LIMIT ALL) */
271  if (isNull)
272  {
273  node->count = 0;
274  node->noCount = true;
275  }
276  else
277  {
278  node->count = DatumGetInt64(val);
279  if (node->count < 0)
280  ereport(ERROR,
281  (errcode(ERRCODE_INVALID_ROW_COUNT_IN_LIMIT_CLAUSE),
282  errmsg("LIMIT must not be negative")));
283  node->noCount = false;
284  }
285  }
286  else
287  {
288  /* No COUNT supplied */
289  node->count = 0;
290  node->noCount = true;
291  }
292 
293  /* Reset position to start-of-scan */
294  node->position = 0;
295  node->subSlot = NULL;
296 
297  /* Set state-machine state */
298  node->lstate = LIMIT_RESCAN;
299 
300  /* Notify child node about limit, if useful */
301  pass_down_bound(node, outerPlanState(node));
302 }
static Datum ExecEvalExprSwitchContext(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:300
bool noCount
Definition: execnodes.h:2039
ExprContext * ps_ExprContext
Definition: execnodes.h:881
int errcode(int sqlerrcode)
Definition: elog.c:575
LimitStateCond lstate
Definition: execnodes.h:2040
ExprState * limitCount
Definition: execnodes.h:2036
int64 position
Definition: execnodes.h:2041
int64 count
Definition: execnodes.h:2038
#define ERROR
Definition: elog.h:43
int64 offset
Definition: execnodes.h:2037
#define DatumGetInt64(X)
Definition: postgres.h:613
#define outerPlanState(node)
Definition: execnodes.h:893
static void pass_down_bound(LimitState *node, PlanState *child_node)
Definition: nodeLimit.c:321
ExprState * limitOffset
Definition: execnodes.h:2035
#define ereport(elevel, rest)
Definition: elog.h:122
uintptr_t Datum
Definition: postgres.h:372
#define NULL
Definition: c.h:229
TupleTableSlot * subSlot
Definition: execnodes.h:2042
int errmsg(const char *fmt,...)
Definition: elog.c:797
long val
Definition: informix.c:689
PlanState ps
Definition: execnodes.h:2034