Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
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

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)