Skip to content

Commit 2f35b4e

Browse files
committed
Re-implement LIMIT/OFFSET as a plan node type, instead of a hack in
ExecutorRun. This allows LIMIT to work in a view. Also, LIMIT in a cursor declaration will behave in a reasonable fashion, whereas before it was overridden by the FETCH count.
1 parent c9476ba commit 2f35b4e

File tree

26 files changed

+572
-232
lines changed

26 files changed

+572
-232
lines changed

src/backend/commands/command.c

Lines changed: 4 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.107 2000/10/16 17:08:05 momjian Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.108 2000/10/26 21:34:44 tgl Exp $
1212
*
1313
* NOTES
1414
* The PerformAddAttribute() code, like most of the relation
@@ -111,7 +111,6 @@ PerformPortalFetch(char *name,
111111
int feature;
112112
QueryDesc *queryDesc;
113113
MemoryContext oldcontext;
114-
Const limcount;
115114

116115
/* ----------------
117116
* sanity checks
@@ -123,20 +122,6 @@ PerformPortalFetch(char *name,
123122
return;
124123
}
125124

126-
/* ----------------
127-
* Create a const node from the given count value
128-
* ----------------
129-
*/
130-
memset(&limcount, 0, sizeof(limcount));
131-
limcount.type = T_Const;
132-
limcount.consttype = INT4OID;
133-
limcount.constlen = sizeof(int4);
134-
limcount.constvalue = Int32GetDatum(count);
135-
limcount.constisnull = false;
136-
limcount.constbyval = true;
137-
limcount.constisset = false;
138-
limcount.constiscast = false;
139-
140125
/* ----------------
141126
* get the portal from the portal name
142127
* ----------------
@@ -156,8 +141,7 @@ PerformPortalFetch(char *name,
156141
oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
157142

158143
/* ----------------
159-
* setup "feature" to tell the executor what direction and
160-
* how many tuples to fetch.
144+
* setup "feature" to tell the executor which direction to go in.
161145
* ----------------
162146
*/
163147
if (forward)
@@ -166,7 +150,7 @@ PerformPortalFetch(char *name,
166150
feature = EXEC_BACK;
167151

168152
/* ----------------
169-
* tell the destination to prepare to recieve some tuples
153+
* tell the destination to prepare to receive some tuples
170154
* ----------------
171155
*/
172156
queryDesc = PortalGetQueryDesc(portal);
@@ -194,8 +178,7 @@ PerformPortalFetch(char *name,
194178
* execute the portal fetch operation
195179
* ----------------
196180
*/
197-
ExecutorRun(queryDesc, PortalGetState(portal), feature,
198-
(Node *) NULL, (Node *) &limcount);
181+
ExecutorRun(queryDesc, PortalGetState(portal), feature, (long) count);
199182

200183
if (dest == None) /* MOVE */
201184
pfree(queryDesc);

src/backend/commands/explain.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
66
* Portions Copyright (c) 1994-5, Regents of the University of California
77
*
8-
* $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.60 2000/10/05 19:11:26 tgl Exp $
8+
* $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.61 2000/10/26 21:34:44 tgl Exp $
99
*
1010
*/
1111

@@ -217,6 +217,9 @@ explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
217217
break;
218218
}
219219
break;
220+
case T_Limit:
221+
pname = "Limit";
222+
break;
220223
case T_Hash:
221224
pname = "Hash";
222225
break;

src/backend/executor/Makefile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
# Makefile for executor
55
#
66
# IDENTIFICATION
7-
# $Header: /cvsroot/pgsql/src/backend/executor/Makefile,v 1.15 2000/10/05 19:11:26 tgl Exp $
7+
# $Header: /cvsroot/pgsql/src/backend/executor/Makefile,v 1.16 2000/10/26 21:35:15 tgl Exp $
88
#
99
#-------------------------------------------------------------------------
1010

@@ -17,8 +17,8 @@ OBJS = execAmi.o execFlatten.o execJunk.o execMain.o \
1717
execUtils.o functions.o nodeAppend.o nodeAgg.o nodeHash.o \
1818
nodeHashjoin.o nodeIndexscan.o nodeMaterial.o nodeMergejoin.o \
1919
nodeNestloop.o nodeResult.o nodeSeqscan.o nodeSetOp.o nodeSort.o \
20-
nodeUnique.o nodeGroup.o spi.o nodeSubplan.o \
21-
nodeSubqueryscan.o nodeTidscan.o
20+
nodeUnique.o nodeLimit.o nodeGroup.o nodeSubplan.o \
21+
nodeSubqueryscan.o nodeTidscan.o spi.o
2222

2323
all: SUBSYS.o
2424

src/backend/executor/execAmi.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
77
* Portions Copyright (c) 1994, Regents of the University of California
88
*
9-
* $Id: execAmi.c,v 1.53 2000/10/05 19:11:26 tgl Exp $
9+
* $Id: execAmi.c,v 1.54 2000/10/26 21:35:15 tgl Exp $
1010
*
1111
*-------------------------------------------------------------------------
1212
*/
@@ -37,6 +37,7 @@
3737
#include "executor/nodeHashjoin.h"
3838
#include "executor/nodeIndexscan.h"
3939
#include "executor/nodeTidscan.h"
40+
#include "executor/nodeLimit.h"
4041
#include "executor/nodeMaterial.h"
4142
#include "executor/nodeMergejoin.h"
4243
#include "executor/nodeNestloop.h"
@@ -350,6 +351,10 @@ ExecReScan(Plan *node, ExprContext *exprCtxt, Plan *parent)
350351
ExecReScanSetOp((SetOp *) node, exprCtxt, parent);
351352
break;
352353

354+
case T_Limit:
355+
ExecReScanLimit((Limit *) node, exprCtxt, parent);
356+
break;
357+
353358
case T_Sort:
354359
ExecReScanSort((Sort *) node, exprCtxt, parent);
355360
break;

src/backend/executor/execMain.c

Lines changed: 20 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
*
2828
*
2929
* IDENTIFICATION
30-
* $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.130 2000/10/16 17:08:06 momjian Exp $
30+
* $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.131 2000/10/26 21:35:15 tgl Exp $
3131
*
3232
*-------------------------------------------------------------------------
3333
*/
@@ -52,11 +52,10 @@ static TupleDesc InitPlan(CmdType operation,
5252
EState *estate);
5353
static void EndPlan(Plan *plan, EState *estate);
5454
static TupleTableSlot *ExecutePlan(EState *estate, Plan *plan,
55-
CmdType operation,
56-
int offsetTuples,
57-
int numberTuples,
58-
ScanDirection direction,
59-
DestReceiver *destfunc);
55+
CmdType operation,
56+
long numberTuples,
57+
ScanDirection direction,
58+
DestReceiver *destfunc);
6059
static void ExecRetrieve(TupleTableSlot *slot,
6160
DestReceiver *destfunc,
6261
EState *estate);
@@ -153,19 +152,18 @@ ExecutorStart(QueryDesc *queryDesc, EState *estate)
153152
* EXEC_RETONE: return one tuple but don't 'retrieve' it
154153
* used in postquel function processing
155154
*
155+
* Note: count = 0 is interpreted as "no limit".
156+
*
156157
* ----------------------------------------------------------------
157158
*/
158159
TupleTableSlot *
159-
ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature,
160-
Node *limoffset, Node *limcount)
160+
ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, long count)
161161
{
162162
CmdType operation;
163163
Plan *plan;
164164
TupleTableSlot *result;
165165
CommandDest dest;
166166
DestReceiver *destfunc;
167-
int offset = 0;
168-
int count = 0;
169167

170168
/*
171169
* sanity checks
@@ -191,111 +189,21 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature,
191189
*/
192190
(*destfunc->setup) (destfunc, (TupleDesc) NULL);
193191

194-
/*
195-
* if given get the offset of the LIMIT clause
196-
*/
197-
if (limoffset != NULL)
198-
{
199-
Const *coffset;
200-
Param *poffset;
201-
ParamListInfo paramLI;
202-
int i;
203-
204-
switch (nodeTag(limoffset))
205-
{
206-
case T_Const:
207-
coffset = (Const *) limoffset;
208-
offset = (int) (coffset->constvalue);
209-
break;
210-
211-
case T_Param:
212-
poffset = (Param *) limoffset;
213-
paramLI = estate->es_param_list_info;
214-
215-
if (paramLI == NULL)
216-
elog(ERROR, "parameter for limit offset not in executor state");
217-
for (i = 0; paramLI[i].kind != PARAM_INVALID; i++)
218-
{
219-
if (paramLI[i].kind == PARAM_NUM && paramLI[i].id == poffset->paramid)
220-
break;
221-
}
222-
if (paramLI[i].kind == PARAM_INVALID)
223-
elog(ERROR, "parameter for limit offset not in executor state");
224-
if (paramLI[i].isnull)
225-
elog(ERROR, "limit offset cannot be NULL value");
226-
offset = (int) (paramLI[i].value);
227-
228-
break;
229-
230-
default:
231-
elog(ERROR, "unexpected node type %d as limit offset", nodeTag(limoffset));
232-
}
233-
234-
if (offset < 0)
235-
elog(ERROR, "limit offset cannot be negative");
236-
}
237-
238-
/*
239-
* if given get the count of the LIMIT clause
240-
*/
241-
if (limcount != NULL)
242-
{
243-
Const *ccount;
244-
Param *pcount;
245-
ParamListInfo paramLI;
246-
int i;
247-
248-
switch (nodeTag(limcount))
249-
{
250-
case T_Const:
251-
ccount = (Const *) limcount;
252-
count = (int) (ccount->constvalue);
253-
break;
254-
255-
case T_Param:
256-
pcount = (Param *) limcount;
257-
paramLI = estate->es_param_list_info;
258-
259-
if (paramLI == NULL)
260-
elog(ERROR, "parameter for limit count not in executor state");
261-
for (i = 0; paramLI[i].kind != PARAM_INVALID; i++)
262-
{
263-
if (paramLI[i].kind == PARAM_NUM && paramLI[i].id == pcount->paramid)
264-
break;
265-
}
266-
if (paramLI[i].kind == PARAM_INVALID)
267-
elog(ERROR, "parameter for limit count not in executor state");
268-
if (paramLI[i].isnull)
269-
elog(ERROR, "limit count cannot be NULL value");
270-
count = (int) (paramLI[i].value);
271-
272-
break;
273-
274-
default:
275-
elog(ERROR, "unexpected node type %d as limit count", nodeTag(limcount));
276-
}
277-
278-
if (count < 0)
279-
elog(ERROR, "limit count cannot be negative");
280-
}
281-
282192
switch (feature)
283193
{
284-
285194
case EXEC_RUN:
286195
result = ExecutePlan(estate,
287196
plan,
288197
operation,
289-
offset,
290198
count,
291199
ForwardScanDirection,
292200
destfunc);
293201
break;
202+
294203
case EXEC_FOR:
295204
result = ExecutePlan(estate,
296205
plan,
297206
operation,
298-
offset,
299207
count,
300208
ForwardScanDirection,
301209
destfunc);
@@ -308,7 +216,6 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature,
308216
result = ExecutePlan(estate,
309217
plan,
310218
operation,
311-
offset,
312219
count,
313220
BackwardScanDirection,
314221
destfunc);
@@ -322,14 +229,14 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature,
322229
result = ExecutePlan(estate,
323230
plan,
324231
operation,
325-
0,
326232
ONE_TUPLE,
327233
ForwardScanDirection,
328234
destfunc);
329235
break;
236+
330237
default:
331-
result = NULL;
332238
elog(DEBUG, "ExecutorRun: Unknown feature %d", feature);
239+
result = NULL;
333240
break;
334241
}
335242

@@ -917,33 +824,30 @@ EndPlan(Plan *plan, EState *estate)
917824
/* ----------------------------------------------------------------
918825
* ExecutePlan
919826
*
920-
* processes the query plan to retrieve 'tupleCount' tuples in the
827+
* processes the query plan to retrieve 'numberTuples' tuples in the
921828
* direction specified.
922829
* Retrieves all tuples if tupleCount is 0
923830
*
924-
* result is either a slot containing a tuple in the case
831+
* result is either a slot containing the last tuple in the case
925832
* of a RETRIEVE or NULL otherwise.
926833
*
834+
* Note: the ctid attribute is a 'junk' attribute that is removed before the
835+
* user can see it
927836
* ----------------------------------------------------------------
928837
*/
929-
930-
/* the ctid attribute is a 'junk' attribute that is removed before the
931-
user can see it*/
932-
933838
static TupleTableSlot *
934839
ExecutePlan(EState *estate,
935840
Plan *plan,
936841
CmdType operation,
937-
int offsetTuples,
938-
int numberTuples,
842+
long numberTuples,
939843
ScanDirection direction,
940844
DestReceiver *destfunc)
941845
{
942846
JunkFilter *junkfilter;
943847
TupleTableSlot *slot;
944848
ItemPointer tupleid = NULL;
945849
ItemPointerData tuple_ctid;
946-
int current_tuple_count;
850+
long current_tuple_count;
947851
TupleTableSlot *result;
948852

949853
/*
@@ -990,17 +894,6 @@ lnext: ;
990894
break;
991895
}
992896

993-
/*
994-
* For now we completely execute the plan and skip result tuples
995-
* if requested by LIMIT offset. Finally we should try to do it in
996-
* deeper levels if possible (during index scan) - Jan
997-
*/
998-
if (offsetTuples > 0)
999-
{
1000-
--offsetTuples;
1001-
continue;
1002-
}
1003-
1004897
/*
1005898
* if we have a junk filter, then project a new tuple with the
1006899
* junk removed.
@@ -1152,10 +1045,10 @@ lnext: ;
11521045
}
11531046

11541047
/*
1155-
* check our tuple count.. if we've returned the proper number
1156-
* then return, else loop again and process more tuples..
1048+
* check our tuple count.. if we've processed the proper number
1049+
* then quit, else loop again and process more tuples..
11571050
*/
1158-
current_tuple_count += 1;
1051+
current_tuple_count++;
11591052
if (numberTuples == current_tuple_count)
11601053
break;
11611054
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy