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

Function Documentation

static int64 compute_tuples_needed ( LimitState node)
static

Definition at line 314 of file nodeLimit.c.

References LimitState::count, LimitState::noCount, and LimitState::offset.

Referenced by recompute_limits().

315 {
316  if (node->noCount)
317  return -1;
318  /* Note: if this overflows, we'll return a negative value, which is OK */
319  return node->count + node->offset;
320 }
bool noCount
Definition: execnodes.h:2060
int64 count
Definition: execnodes.h:2059
int64 offset
Definition: execnodes.h:2058
void ExecEndLimit ( LimitState node)

Definition at line 393 of file nodeLimit.c.

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

Referenced by ExecEndNode().

394 {
395  ExecFreeExprContext(&node->ps);
397 }
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:2055
LimitState* ExecInitLimit ( Limit node,
EState estate,
int  eflags 
)

Definition at line 330 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, outerPlan, outerPlanState, PlanState::plan, LimitState::ps, PlanState::ps_ProjInfo, and PlanState::state.

Referenced by ExecInitNode().

331 {
332  LimitState *limitstate;
333  Plan *outerPlan;
334 
335  /* check for unsupported flags */
336  Assert(!(eflags & EXEC_FLAG_MARK));
337 
338  /*
339  * create state structure
340  */
341  limitstate = makeNode(LimitState);
342  limitstate->ps.plan = (Plan *) node;
343  limitstate->ps.state = estate;
344  limitstate->ps.ExecProcNode = ExecLimit;
345 
346  limitstate->lstate = LIMIT_INITIAL;
347 
348  /*
349  * Miscellaneous initialization
350  *
351  * Limit nodes never call ExecQual or ExecProject, but they need an
352  * exprcontext anyway to evaluate the limit/offset parameters in.
353  */
354  ExecAssignExprContext(estate, &limitstate->ps);
355 
356  /*
357  * initialize child expressions
358  */
359  limitstate->limitOffset = ExecInitExpr((Expr *) node->limitOffset,
360  (PlanState *) limitstate);
361  limitstate->limitCount = ExecInitExpr((Expr *) node->limitCount,
362  (PlanState *) limitstate);
363 
364  /*
365  * Tuple table initialization (XXX not actually used...)
366  */
367  ExecInitResultTupleSlot(estate, &limitstate->ps);
368 
369  /*
370  * then initialize outer plan
371  */
372  outerPlan = outerPlan(node);
373  outerPlanState(limitstate) = ExecInitNode(outerPlan, estate, eflags);
374 
375  /*
376  * limit nodes do no projections, so initialize projection info for this
377  * node appropriately
378  */
379  ExecAssignResultTypeFromTL(&limitstate->ps);
380  limitstate->ps.ps_ProjInfo = NULL;
381 
382  return limitstate;
383 }
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:2061
ExprState * limitCount
Definition: execnodes.h:2057
Node * limitOffset
Definition: plannodes.h:924
void ExecAssignResultTypeFromTL(PlanState *planstate)
Definition: execUtils.c:445
void ExecInitResultTupleSlot(EState *estate, PlanState *planstate)
Definition: execTuples.c:832
Node * limitCount
Definition: plannodes.h:925
#define outerPlanState(node)
Definition: execnodes.h:893
ExprState * limitOffset
Definition: execnodes.h:2056
#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:558
#define Assert(condition)
Definition: c.h:681
#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:2055
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, 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:2060
#define castNode(_type_, nodeptr)
Definition: nodes.h:579
EState * state
Definition: execnodes.h:849
LimitStateCond lstate
Definition: execnodes.h:2061
int64 position
Definition: execnodes.h:2062
ScanDirection es_direction
Definition: execnodes.h:428
int64 count
Definition: execnodes.h:2059
#define ERROR
Definition: elog.h:43
int64 offset
Definition: execnodes.h:2058
#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:246
#define Assert(condition)
Definition: c.h:681
TupleTableSlot * subSlot
Definition: execnodes.h:2063
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:2055
void ExecReScanLimit ( LimitState node)

Definition at line 401 of file nodeLimit.c.

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

Referenced by ExecReScan().

402 {
403  /*
404  * Recompute limit/offset in case parameters changed, and reset the state
405  * machine. We must do this before rescanning our child node, in case
406  * it's a Sort that we are passing the parameters down to.
407  */
408  recompute_limits(node);
409 
410  /*
411  * if chgParam of subnode is not null then plan will be re-scanned by
412  * first ExecProcNode.
413  */
414  if (node->ps.lefttree->chgParam == NULL)
415  ExecReScan(node->ps.lefttree);
416 }
void ExecReScan(PlanState *node)
Definition: execAmi.c:76
struct PlanState * lefttree
Definition: execnodes.h:866
Bitmapset * chgParam
Definition: execnodes.h:875
static void recompute_limits(LimitState *node)
Definition: nodeLimit.c:236
PlanState ps
Definition: execnodes.h:2055
static void recompute_limits ( LimitState node)
static

Definition at line 236 of file nodeLimit.c.

References compute_tuples_needed(), LimitState::count, DatumGetInt64, ereport, errcode(), errmsg(), ERROR, ExecEvalExprSwitchContext(), ExecSetTupleBound(), LIMIT_RESCAN, LimitState::limitCount, LimitState::limitOffset, LimitState::lstate, LimitState::noCount, LimitState::offset, outerPlanState, 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  /*
301  * Notify child node about limit. Note: think not to "optimize" by
302  * skipping ExecSetTupleBound if compute_tuples_needed returns < 0. We
303  * must update the child node anyway, in case this is a rescan and the
304  * previous time we got a different result.
305  */
307 }
static Datum ExecEvalExprSwitchContext(ExprState *state, ExprContext *econtext, bool *isNull)
Definition: executor.h:301
bool noCount
Definition: execnodes.h:2060
ExprContext * ps_ExprContext
Definition: execnodes.h:881
int errcode(int sqlerrcode)
Definition: elog.c:575
LimitStateCond lstate
Definition: execnodes.h:2061
ExprState * limitCount
Definition: execnodes.h:2057
int64 position
Definition: execnodes.h:2062
void ExecSetTupleBound(int64 tuples_needed, PlanState *child_node)
Definition: execProcnode.c:778
int64 count
Definition: execnodes.h:2059
#define ERROR
Definition: elog.h:43
int64 offset
Definition: execnodes.h:2058
#define DatumGetInt64(X)
Definition: postgres.h:613
#define outerPlanState(node)
Definition: execnodes.h:893
ExprState * limitOffset
Definition: execnodes.h:2056
#define ereport(elevel, rest)
Definition: elog.h:122
uintptr_t Datum
Definition: postgres.h:372
TupleTableSlot * subSlot
Definition: execnodes.h:2063
int errmsg(const char *fmt,...)
Definition: elog.c:797
long val
Definition: informix.c:689
PlanState ps
Definition: execnodes.h:2055
static int64 compute_tuples_needed(LimitState *node)
Definition: nodeLimit.c:314