mirror of
https://github.com/postgres/postgres.git
synced 2025-04-27 22:56:53 +03:00
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.
This commit is contained in:
parent
c9476bafdb
commit
2f35b4efdb
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.107 2000/10/16 17:08:05 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.108 2000/10/26 21:34:44 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* The PerformAddAttribute() code, like most of the relation
|
* The PerformAddAttribute() code, like most of the relation
|
||||||
@ -111,7 +111,6 @@ PerformPortalFetch(char *name,
|
|||||||
int feature;
|
int feature;
|
||||||
QueryDesc *queryDesc;
|
QueryDesc *queryDesc;
|
||||||
MemoryContext oldcontext;
|
MemoryContext oldcontext;
|
||||||
Const limcount;
|
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* sanity checks
|
* sanity checks
|
||||||
@ -123,20 +122,6 @@ PerformPortalFetch(char *name,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
|
||||||
* Create a const node from the given count value
|
|
||||||
* ----------------
|
|
||||||
*/
|
|
||||||
memset(&limcount, 0, sizeof(limcount));
|
|
||||||
limcount.type = T_Const;
|
|
||||||
limcount.consttype = INT4OID;
|
|
||||||
limcount.constlen = sizeof(int4);
|
|
||||||
limcount.constvalue = Int32GetDatum(count);
|
|
||||||
limcount.constisnull = false;
|
|
||||||
limcount.constbyval = true;
|
|
||||||
limcount.constisset = false;
|
|
||||||
limcount.constiscast = false;
|
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* get the portal from the portal name
|
* get the portal from the portal name
|
||||||
* ----------------
|
* ----------------
|
||||||
@ -156,8 +141,7 @@ PerformPortalFetch(char *name,
|
|||||||
oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
|
oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* setup "feature" to tell the executor what direction and
|
* setup "feature" to tell the executor which direction to go in.
|
||||||
* how many tuples to fetch.
|
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
if (forward)
|
if (forward)
|
||||||
@ -166,7 +150,7 @@ PerformPortalFetch(char *name,
|
|||||||
feature = EXEC_BACK;
|
feature = EXEC_BACK;
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* tell the destination to prepare to recieve some tuples
|
* tell the destination to prepare to receive some tuples
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
queryDesc = PortalGetQueryDesc(portal);
|
queryDesc = PortalGetQueryDesc(portal);
|
||||||
@ -194,8 +178,7 @@ PerformPortalFetch(char *name,
|
|||||||
* execute the portal fetch operation
|
* execute the portal fetch operation
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
ExecutorRun(queryDesc, PortalGetState(portal), feature,
|
ExecutorRun(queryDesc, PortalGetState(portal), feature, (long) count);
|
||||||
(Node *) NULL, (Node *) &limcount);
|
|
||||||
|
|
||||||
if (dest == None) /* MOVE */
|
if (dest == None) /* MOVE */
|
||||||
pfree(queryDesc);
|
pfree(queryDesc);
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||||
* Portions Copyright (c) 1994-5, Regents of the University of California
|
* Portions Copyright (c) 1994-5, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.60 2000/10/05 19:11:26 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.61 2000/10/26 21:34:44 tgl Exp $
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -217,6 +217,9 @@ explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case T_Limit:
|
||||||
|
pname = "Limit";
|
||||||
|
break;
|
||||||
case T_Hash:
|
case T_Hash:
|
||||||
pname = "Hash";
|
pname = "Hash";
|
||||||
break;
|
break;
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
# Makefile for executor
|
# Makefile for executor
|
||||||
#
|
#
|
||||||
# IDENTIFICATION
|
# IDENTIFICATION
|
||||||
# $Header: /cvsroot/pgsql/src/backend/executor/Makefile,v 1.15 2000/10/05 19:11:26 tgl Exp $
|
# $Header: /cvsroot/pgsql/src/backend/executor/Makefile,v 1.16 2000/10/26 21:35:15 tgl Exp $
|
||||||
#
|
#
|
||||||
#-------------------------------------------------------------------------
|
#-------------------------------------------------------------------------
|
||||||
|
|
||||||
@ -17,8 +17,8 @@ OBJS = execAmi.o execFlatten.o execJunk.o execMain.o \
|
|||||||
execUtils.o functions.o nodeAppend.o nodeAgg.o nodeHash.o \
|
execUtils.o functions.o nodeAppend.o nodeAgg.o nodeHash.o \
|
||||||
nodeHashjoin.o nodeIndexscan.o nodeMaterial.o nodeMergejoin.o \
|
nodeHashjoin.o nodeIndexscan.o nodeMaterial.o nodeMergejoin.o \
|
||||||
nodeNestloop.o nodeResult.o nodeSeqscan.o nodeSetOp.o nodeSort.o \
|
nodeNestloop.o nodeResult.o nodeSeqscan.o nodeSetOp.o nodeSort.o \
|
||||||
nodeUnique.o nodeGroup.o spi.o nodeSubplan.o \
|
nodeUnique.o nodeLimit.o nodeGroup.o nodeSubplan.o \
|
||||||
nodeSubqueryscan.o nodeTidscan.o
|
nodeSubqueryscan.o nodeTidscan.o spi.o
|
||||||
|
|
||||||
all: SUBSYS.o
|
all: SUBSYS.o
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: execAmi.c,v 1.53 2000/10/05 19:11:26 tgl Exp $
|
* $Id: execAmi.c,v 1.54 2000/10/26 21:35:15 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -37,6 +37,7 @@
|
|||||||
#include "executor/nodeHashjoin.h"
|
#include "executor/nodeHashjoin.h"
|
||||||
#include "executor/nodeIndexscan.h"
|
#include "executor/nodeIndexscan.h"
|
||||||
#include "executor/nodeTidscan.h"
|
#include "executor/nodeTidscan.h"
|
||||||
|
#include "executor/nodeLimit.h"
|
||||||
#include "executor/nodeMaterial.h"
|
#include "executor/nodeMaterial.h"
|
||||||
#include "executor/nodeMergejoin.h"
|
#include "executor/nodeMergejoin.h"
|
||||||
#include "executor/nodeNestloop.h"
|
#include "executor/nodeNestloop.h"
|
||||||
@ -350,6 +351,10 @@ ExecReScan(Plan *node, ExprContext *exprCtxt, Plan *parent)
|
|||||||
ExecReScanSetOp((SetOp *) node, exprCtxt, parent);
|
ExecReScanSetOp((SetOp *) node, exprCtxt, parent);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case T_Limit:
|
||||||
|
ExecReScanLimit((Limit *) node, exprCtxt, parent);
|
||||||
|
break;
|
||||||
|
|
||||||
case T_Sort:
|
case T_Sort:
|
||||||
ExecReScanSort((Sort *) node, exprCtxt, parent);
|
ExecReScanSort((Sort *) node, exprCtxt, parent);
|
||||||
break;
|
break;
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.130 2000/10/16 17:08:06 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.131 2000/10/26 21:35:15 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -52,11 +52,10 @@ static TupleDesc InitPlan(CmdType operation,
|
|||||||
EState *estate);
|
EState *estate);
|
||||||
static void EndPlan(Plan *plan, EState *estate);
|
static void EndPlan(Plan *plan, EState *estate);
|
||||||
static TupleTableSlot *ExecutePlan(EState *estate, Plan *plan,
|
static TupleTableSlot *ExecutePlan(EState *estate, Plan *plan,
|
||||||
CmdType operation,
|
CmdType operation,
|
||||||
int offsetTuples,
|
long numberTuples,
|
||||||
int numberTuples,
|
ScanDirection direction,
|
||||||
ScanDirection direction,
|
DestReceiver *destfunc);
|
||||||
DestReceiver *destfunc);
|
|
||||||
static void ExecRetrieve(TupleTableSlot *slot,
|
static void ExecRetrieve(TupleTableSlot *slot,
|
||||||
DestReceiver *destfunc,
|
DestReceiver *destfunc,
|
||||||
EState *estate);
|
EState *estate);
|
||||||
@ -153,19 +152,18 @@ ExecutorStart(QueryDesc *queryDesc, EState *estate)
|
|||||||
* EXEC_RETONE: return one tuple but don't 'retrieve' it
|
* EXEC_RETONE: return one tuple but don't 'retrieve' it
|
||||||
* used in postquel function processing
|
* used in postquel function processing
|
||||||
*
|
*
|
||||||
|
* Note: count = 0 is interpreted as "no limit".
|
||||||
|
*
|
||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
TupleTableSlot *
|
TupleTableSlot *
|
||||||
ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature,
|
ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, long count)
|
||||||
Node *limoffset, Node *limcount)
|
|
||||||
{
|
{
|
||||||
CmdType operation;
|
CmdType operation;
|
||||||
Plan *plan;
|
Plan *plan;
|
||||||
TupleTableSlot *result;
|
TupleTableSlot *result;
|
||||||
CommandDest dest;
|
CommandDest dest;
|
||||||
DestReceiver *destfunc;
|
DestReceiver *destfunc;
|
||||||
int offset = 0;
|
|
||||||
int count = 0;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* sanity checks
|
* sanity checks
|
||||||
@ -191,111 +189,21 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature,
|
|||||||
*/
|
*/
|
||||||
(*destfunc->setup) (destfunc, (TupleDesc) NULL);
|
(*destfunc->setup) (destfunc, (TupleDesc) NULL);
|
||||||
|
|
||||||
/*
|
|
||||||
* if given get the offset of the LIMIT clause
|
|
||||||
*/
|
|
||||||
if (limoffset != NULL)
|
|
||||||
{
|
|
||||||
Const *coffset;
|
|
||||||
Param *poffset;
|
|
||||||
ParamListInfo paramLI;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
switch (nodeTag(limoffset))
|
|
||||||
{
|
|
||||||
case T_Const:
|
|
||||||
coffset = (Const *) limoffset;
|
|
||||||
offset = (int) (coffset->constvalue);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case T_Param:
|
|
||||||
poffset = (Param *) limoffset;
|
|
||||||
paramLI = estate->es_param_list_info;
|
|
||||||
|
|
||||||
if (paramLI == NULL)
|
|
||||||
elog(ERROR, "parameter for limit offset not in executor state");
|
|
||||||
for (i = 0; paramLI[i].kind != PARAM_INVALID; i++)
|
|
||||||
{
|
|
||||||
if (paramLI[i].kind == PARAM_NUM && paramLI[i].id == poffset->paramid)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (paramLI[i].kind == PARAM_INVALID)
|
|
||||||
elog(ERROR, "parameter for limit offset not in executor state");
|
|
||||||
if (paramLI[i].isnull)
|
|
||||||
elog(ERROR, "limit offset cannot be NULL value");
|
|
||||||
offset = (int) (paramLI[i].value);
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
elog(ERROR, "unexpected node type %d as limit offset", nodeTag(limoffset));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (offset < 0)
|
|
||||||
elog(ERROR, "limit offset cannot be negative");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* if given get the count of the LIMIT clause
|
|
||||||
*/
|
|
||||||
if (limcount != NULL)
|
|
||||||
{
|
|
||||||
Const *ccount;
|
|
||||||
Param *pcount;
|
|
||||||
ParamListInfo paramLI;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
switch (nodeTag(limcount))
|
|
||||||
{
|
|
||||||
case T_Const:
|
|
||||||
ccount = (Const *) limcount;
|
|
||||||
count = (int) (ccount->constvalue);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case T_Param:
|
|
||||||
pcount = (Param *) limcount;
|
|
||||||
paramLI = estate->es_param_list_info;
|
|
||||||
|
|
||||||
if (paramLI == NULL)
|
|
||||||
elog(ERROR, "parameter for limit count not in executor state");
|
|
||||||
for (i = 0; paramLI[i].kind != PARAM_INVALID; i++)
|
|
||||||
{
|
|
||||||
if (paramLI[i].kind == PARAM_NUM && paramLI[i].id == pcount->paramid)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (paramLI[i].kind == PARAM_INVALID)
|
|
||||||
elog(ERROR, "parameter for limit count not in executor state");
|
|
||||||
if (paramLI[i].isnull)
|
|
||||||
elog(ERROR, "limit count cannot be NULL value");
|
|
||||||
count = (int) (paramLI[i].value);
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
elog(ERROR, "unexpected node type %d as limit count", nodeTag(limcount));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (count < 0)
|
|
||||||
elog(ERROR, "limit count cannot be negative");
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (feature)
|
switch (feature)
|
||||||
{
|
{
|
||||||
|
|
||||||
case EXEC_RUN:
|
case EXEC_RUN:
|
||||||
result = ExecutePlan(estate,
|
result = ExecutePlan(estate,
|
||||||
plan,
|
plan,
|
||||||
operation,
|
operation,
|
||||||
offset,
|
|
||||||
count,
|
count,
|
||||||
ForwardScanDirection,
|
ForwardScanDirection,
|
||||||
destfunc);
|
destfunc);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case EXEC_FOR:
|
case EXEC_FOR:
|
||||||
result = ExecutePlan(estate,
|
result = ExecutePlan(estate,
|
||||||
plan,
|
plan,
|
||||||
operation,
|
operation,
|
||||||
offset,
|
|
||||||
count,
|
count,
|
||||||
ForwardScanDirection,
|
ForwardScanDirection,
|
||||||
destfunc);
|
destfunc);
|
||||||
@ -308,7 +216,6 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature,
|
|||||||
result = ExecutePlan(estate,
|
result = ExecutePlan(estate,
|
||||||
plan,
|
plan,
|
||||||
operation,
|
operation,
|
||||||
offset,
|
|
||||||
count,
|
count,
|
||||||
BackwardScanDirection,
|
BackwardScanDirection,
|
||||||
destfunc);
|
destfunc);
|
||||||
@ -322,14 +229,14 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature,
|
|||||||
result = ExecutePlan(estate,
|
result = ExecutePlan(estate,
|
||||||
plan,
|
plan,
|
||||||
operation,
|
operation,
|
||||||
0,
|
|
||||||
ONE_TUPLE,
|
ONE_TUPLE,
|
||||||
ForwardScanDirection,
|
ForwardScanDirection,
|
||||||
destfunc);
|
destfunc);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
result = NULL;
|
|
||||||
elog(DEBUG, "ExecutorRun: Unknown feature %d", feature);
|
elog(DEBUG, "ExecutorRun: Unknown feature %d", feature);
|
||||||
|
result = NULL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -917,25 +824,22 @@ EndPlan(Plan *plan, EState *estate)
|
|||||||
/* ----------------------------------------------------------------
|
/* ----------------------------------------------------------------
|
||||||
* ExecutePlan
|
* ExecutePlan
|
||||||
*
|
*
|
||||||
* processes the query plan to retrieve 'tupleCount' tuples in the
|
* processes the query plan to retrieve 'numberTuples' tuples in the
|
||||||
* direction specified.
|
* direction specified.
|
||||||
* Retrieves all tuples if tupleCount is 0
|
* Retrieves all tuples if tupleCount is 0
|
||||||
*
|
*
|
||||||
* result is either a slot containing a tuple in the case
|
* result is either a slot containing the last tuple in the case
|
||||||
* of a RETRIEVE or NULL otherwise.
|
* of a RETRIEVE or NULL otherwise.
|
||||||
*
|
*
|
||||||
|
* Note: the ctid attribute is a 'junk' attribute that is removed before the
|
||||||
|
* user can see it
|
||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* the ctid attribute is a 'junk' attribute that is removed before the
|
|
||||||
user can see it*/
|
|
||||||
|
|
||||||
static TupleTableSlot *
|
static TupleTableSlot *
|
||||||
ExecutePlan(EState *estate,
|
ExecutePlan(EState *estate,
|
||||||
Plan *plan,
|
Plan *plan,
|
||||||
CmdType operation,
|
CmdType operation,
|
||||||
int offsetTuples,
|
long numberTuples,
|
||||||
int numberTuples,
|
|
||||||
ScanDirection direction,
|
ScanDirection direction,
|
||||||
DestReceiver *destfunc)
|
DestReceiver *destfunc)
|
||||||
{
|
{
|
||||||
@ -943,7 +847,7 @@ ExecutePlan(EState *estate,
|
|||||||
TupleTableSlot *slot;
|
TupleTableSlot *slot;
|
||||||
ItemPointer tupleid = NULL;
|
ItemPointer tupleid = NULL;
|
||||||
ItemPointerData tuple_ctid;
|
ItemPointerData tuple_ctid;
|
||||||
int current_tuple_count;
|
long current_tuple_count;
|
||||||
TupleTableSlot *result;
|
TupleTableSlot *result;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -990,17 +894,6 @@ lnext: ;
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* For now we completely execute the plan and skip result tuples
|
|
||||||
* if requested by LIMIT offset. Finally we should try to do it in
|
|
||||||
* deeper levels if possible (during index scan) - Jan
|
|
||||||
*/
|
|
||||||
if (offsetTuples > 0)
|
|
||||||
{
|
|
||||||
--offsetTuples;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if we have a junk filter, then project a new tuple with the
|
* if we have a junk filter, then project a new tuple with the
|
||||||
* junk removed.
|
* junk removed.
|
||||||
@ -1152,10 +1045,10 @@ lnext: ;
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* check our tuple count.. if we've returned the proper number
|
* check our tuple count.. if we've processed the proper number
|
||||||
* then return, else loop again and process more tuples..
|
* then quit, else loop again and process more tuples..
|
||||||
*/
|
*/
|
||||||
current_tuple_count += 1;
|
current_tuple_count++;
|
||||||
if (numberTuples == current_tuple_count)
|
if (numberTuples == current_tuple_count)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/execProcnode.c,v 1.21 2000/10/05 19:11:26 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/execProcnode.c,v 1.22 2000/10/26 21:35:15 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -83,6 +83,7 @@
|
|||||||
#include "executor/nodeHashjoin.h"
|
#include "executor/nodeHashjoin.h"
|
||||||
#include "executor/nodeIndexscan.h"
|
#include "executor/nodeIndexscan.h"
|
||||||
#include "executor/nodeTidscan.h"
|
#include "executor/nodeTidscan.h"
|
||||||
|
#include "executor/nodeLimit.h"
|
||||||
#include "executor/nodeMaterial.h"
|
#include "executor/nodeMaterial.h"
|
||||||
#include "executor/nodeMergejoin.h"
|
#include "executor/nodeMergejoin.h"
|
||||||
#include "executor/nodeNestloop.h"
|
#include "executor/nodeNestloop.h"
|
||||||
@ -204,6 +205,10 @@ ExecInitNode(Plan *node, EState *estate, Plan *parent)
|
|||||||
result = ExecInitSetOp((SetOp *) node, estate, parent);
|
result = ExecInitSetOp((SetOp *) node, estate, parent);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case T_Limit:
|
||||||
|
result = ExecInitLimit((Limit *) node, estate, parent);
|
||||||
|
break;
|
||||||
|
|
||||||
case T_Group:
|
case T_Group:
|
||||||
result = ExecInitGroup((Group *) node, estate, parent);
|
result = ExecInitGroup((Group *) node, estate, parent);
|
||||||
break;
|
break;
|
||||||
@ -331,6 +336,10 @@ ExecProcNode(Plan *node, Plan *parent)
|
|||||||
result = ExecSetOp((SetOp *) node);
|
result = ExecSetOp((SetOp *) node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case T_Limit:
|
||||||
|
result = ExecLimit((Limit *) node);
|
||||||
|
break;
|
||||||
|
|
||||||
case T_Group:
|
case T_Group:
|
||||||
result = ExecGroup((Group *) node);
|
result = ExecGroup((Group *) node);
|
||||||
break;
|
break;
|
||||||
@ -413,6 +422,9 @@ ExecCountSlotsNode(Plan *node)
|
|||||||
case T_SetOp:
|
case T_SetOp:
|
||||||
return ExecCountSlotsSetOp((SetOp *) node);
|
return ExecCountSlotsSetOp((SetOp *) node);
|
||||||
|
|
||||||
|
case T_Limit:
|
||||||
|
return ExecCountSlotsLimit((Limit *) node);
|
||||||
|
|
||||||
case T_Group:
|
case T_Group:
|
||||||
return ExecCountSlotsGroup((Group *) node);
|
return ExecCountSlotsGroup((Group *) node);
|
||||||
|
|
||||||
@ -535,6 +547,10 @@ ExecEndNode(Plan *node, Plan *parent)
|
|||||||
ExecEndSetOp((SetOp *) node);
|
ExecEndSetOp((SetOp *) node);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case T_Limit:
|
||||||
|
ExecEndLimit((Limit *) node);
|
||||||
|
break;
|
||||||
|
|
||||||
case T_Group:
|
case T_Group:
|
||||||
ExecEndGroup((Group *) node);
|
ExecEndGroup((Group *) node);
|
||||||
break;
|
break;
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.41 2000/10/05 19:11:26 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.42 2000/10/26 21:35:15 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -770,6 +770,14 @@ NodeGetResultTupleSlot(Plan *node)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case T_Limit:
|
||||||
|
{
|
||||||
|
LimitState *limitstate = ((Limit *) node)->limitstate;
|
||||||
|
|
||||||
|
slot = limitstate->cstate.cs_ResultTupleSlot;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case T_MergeJoin:
|
case T_MergeJoin:
|
||||||
{
|
{
|
||||||
MergeJoinState *mergestate = ((MergeJoin *) node)->mergestate;
|
MergeJoinState *mergestate = ((MergeJoin *) node)->mergestate;
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.38 2000/08/24 03:29:03 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.39 2000/10/26 21:35:15 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -135,9 +135,6 @@ init_execution_state(char *src, Oid *argOidVect, int nargs)
|
|||||||
None);
|
None);
|
||||||
estate = CreateExecutorState();
|
estate = CreateExecutorState();
|
||||||
|
|
||||||
if (queryTree->limitOffset != NULL || queryTree->limitCount != NULL)
|
|
||||||
elog(ERROR, "LIMIT clause from SQL functions not yet implemented");
|
|
||||||
|
|
||||||
if (nargs > 0)
|
if (nargs > 0)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@ -328,7 +325,7 @@ postquel_getnext(execution_state *es)
|
|||||||
|
|
||||||
feature = (LAST_POSTQUEL_COMMAND(es)) ? EXEC_RETONE : EXEC_RUN;
|
feature = (LAST_POSTQUEL_COMMAND(es)) ? EXEC_RETONE : EXEC_RUN;
|
||||||
|
|
||||||
return ExecutorRun(es->qd, es->estate, feature, (Node *) NULL, (Node *) NULL);
|
return ExecutorRun(es->qd, es->estate, feature, 0L);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
324
src/backend/executor/nodeLimit.c
Normal file
324
src/backend/executor/nodeLimit.c
Normal file
@ -0,0 +1,324 @@
|
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* nodeLimit.c
|
||||||
|
* Routines to handle limiting of query results where appropriate
|
||||||
|
*
|
||||||
|
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||||
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* IDENTIFICATION
|
||||||
|
* $Header: /cvsroot/pgsql/src/backend/executor/nodeLimit.c,v 1.1 2000/10/26 21:35:15 tgl Exp $
|
||||||
|
*
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* INTERFACE ROUTINES
|
||||||
|
* ExecLimit - extract a limited range of tuples
|
||||||
|
* ExecInitLimit - initialize node and subnodes..
|
||||||
|
* ExecEndLimit - shutdown node and subnodes
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "postgres.h"
|
||||||
|
|
||||||
|
#include "executor/executor.h"
|
||||||
|
#include "executor/nodeLimit.h"
|
||||||
|
|
||||||
|
static void recompute_limits(Limit *node);
|
||||||
|
|
||||||
|
|
||||||
|
/* ----------------------------------------------------------------
|
||||||
|
* ExecLimit
|
||||||
|
*
|
||||||
|
* This is a very simple node which just performs LIMIT/OFFSET
|
||||||
|
* filtering on the stream of tuples returned by a subplan.
|
||||||
|
* ----------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
TupleTableSlot * /* return: a tuple or NULL */
|
||||||
|
ExecLimit(Limit *node)
|
||||||
|
{
|
||||||
|
LimitState *limitstate;
|
||||||
|
ScanDirection direction;
|
||||||
|
TupleTableSlot *resultTupleSlot;
|
||||||
|
TupleTableSlot *slot;
|
||||||
|
Plan *outerPlan;
|
||||||
|
long netlimit;
|
||||||
|
|
||||||
|
/* ----------------
|
||||||
|
* get information from the node
|
||||||
|
* ----------------
|
||||||
|
*/
|
||||||
|
limitstate = node->limitstate;
|
||||||
|
direction = node->plan.state->es_direction;
|
||||||
|
outerPlan = outerPlan((Plan *) node);
|
||||||
|
resultTupleSlot = limitstate->cstate.cs_ResultTupleSlot;
|
||||||
|
|
||||||
|
/* ----------------
|
||||||
|
* If first call for this scan, compute limit/offset.
|
||||||
|
* (We can't do this any earlier, because parameters from upper nodes
|
||||||
|
* may not be set until now.)
|
||||||
|
* ----------------
|
||||||
|
*/
|
||||||
|
if (! limitstate->parmsSet)
|
||||||
|
recompute_limits(node);
|
||||||
|
netlimit = limitstate->offset + limitstate->count;
|
||||||
|
|
||||||
|
/* ----------------
|
||||||
|
* now loop, returning only desired tuples.
|
||||||
|
* ----------------
|
||||||
|
*/
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
/*----------------
|
||||||
|
* If we have reached the subplan EOF or the limit, just quit.
|
||||||
|
*
|
||||||
|
* NOTE: when scanning forwards, we must fetch one tuple beyond the
|
||||||
|
* COUNT limit before we can return NULL, else the subplan won't be
|
||||||
|
* properly positioned to start going backwards. Hence test here
|
||||||
|
* is for position > netlimit not position >= netlimit.
|
||||||
|
*
|
||||||
|
* Similarly, when scanning backwards, we must re-fetch the last
|
||||||
|
* tuple in the offset region before we can return NULL. Otherwise
|
||||||
|
* we won't be correctly aligned to start going forward again. So,
|
||||||
|
* although you might think we can quit when position = offset + 1,
|
||||||
|
* we have to fetch a subplan tuple first, and then exit when
|
||||||
|
* position = offset.
|
||||||
|
*----------------
|
||||||
|
*/
|
||||||
|
if (ScanDirectionIsForward(direction))
|
||||||
|
{
|
||||||
|
if (limitstate->atEnd)
|
||||||
|
return NULL;
|
||||||
|
if (! limitstate->noCount && limitstate->position > netlimit)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (limitstate->position <= limitstate->offset)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
/* ----------------
|
||||||
|
* fetch a tuple from the outer subplan
|
||||||
|
* ----------------
|
||||||
|
*/
|
||||||
|
slot = ExecProcNode(outerPlan, (Plan *) node);
|
||||||
|
if (TupIsNull(slot))
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* We are at start or end of the subplan. Update local state
|
||||||
|
* appropriately, but always return NULL.
|
||||||
|
*/
|
||||||
|
if (ScanDirectionIsForward(direction))
|
||||||
|
{
|
||||||
|
Assert(! limitstate->atEnd);
|
||||||
|
/* must bump position to stay in sync for backwards fetch */
|
||||||
|
limitstate->position++;
|
||||||
|
limitstate->atEnd = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
limitstate->position = 0;
|
||||||
|
limitstate->atEnd = false;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* We got the next subplan tuple successfully, so adjust state.
|
||||||
|
*/
|
||||||
|
if (ScanDirectionIsForward(direction))
|
||||||
|
limitstate->position++;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
limitstate->position--;
|
||||||
|
Assert(limitstate->position > 0);
|
||||||
|
}
|
||||||
|
limitstate->atEnd = false;
|
||||||
|
|
||||||
|
/* ----------------
|
||||||
|
* Now, is this a tuple we want? If not, loop around to fetch
|
||||||
|
* another tuple from the subplan.
|
||||||
|
* ----------------
|
||||||
|
*/
|
||||||
|
if (limitstate->position > limitstate->offset &&
|
||||||
|
(limitstate->noCount || limitstate->position <= netlimit))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ExecStoreTuple(slot->val,
|
||||||
|
resultTupleSlot,
|
||||||
|
InvalidBuffer,
|
||||||
|
false); /* tuple does not belong to slot */
|
||||||
|
|
||||||
|
return resultTupleSlot;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Evaluate the limit/offset expressions --- done at start of each scan.
|
||||||
|
*
|
||||||
|
* This is also a handy place to reset the current-position state info.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
recompute_limits(Limit *node)
|
||||||
|
{
|
||||||
|
LimitState *limitstate = node->limitstate;
|
||||||
|
ExprContext *econtext = limitstate->cstate.cs_ExprContext;
|
||||||
|
bool isNull;
|
||||||
|
|
||||||
|
if (node->limitOffset)
|
||||||
|
{
|
||||||
|
limitstate->offset = DatumGetInt32(ExecEvalExpr(node->limitOffset,
|
||||||
|
econtext,
|
||||||
|
&isNull,
|
||||||
|
NULL));
|
||||||
|
/* Interpret NULL offset as no offset */
|
||||||
|
if (isNull)
|
||||||
|
limitstate->offset = 0;
|
||||||
|
else if (limitstate->offset < 0)
|
||||||
|
limitstate->offset = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* No OFFSET supplied */
|
||||||
|
limitstate->offset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node->limitCount)
|
||||||
|
{
|
||||||
|
limitstate->count = DatumGetInt32(ExecEvalExpr(node->limitCount,
|
||||||
|
econtext,
|
||||||
|
&isNull,
|
||||||
|
NULL));
|
||||||
|
/* Interpret NULL count as no count */
|
||||||
|
if (isNull)
|
||||||
|
limitstate->noCount = true;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Currently, LIMIT 0 is specified as meaning no limit.
|
||||||
|
* I think this is pretty bogus, but ...
|
||||||
|
*/
|
||||||
|
if (limitstate->count <= 0)
|
||||||
|
limitstate->noCount = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* No COUNT supplied */
|
||||||
|
limitstate->count = 0;
|
||||||
|
limitstate->noCount = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reset position data to start-of-scan */
|
||||||
|
limitstate->position = 0;
|
||||||
|
limitstate->atEnd = false;
|
||||||
|
|
||||||
|
/* Set flag that params are computed */
|
||||||
|
limitstate->parmsSet = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ----------------------------------------------------------------
|
||||||
|
* ExecInitLimit
|
||||||
|
*
|
||||||
|
* This initializes the limit node state structures and
|
||||||
|
* the node's subplan.
|
||||||
|
* ----------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
bool /* return: initialization status */
|
||||||
|
ExecInitLimit(Limit *node, EState *estate, Plan *parent)
|
||||||
|
{
|
||||||
|
LimitState *limitstate;
|
||||||
|
Plan *outerPlan;
|
||||||
|
|
||||||
|
/* ----------------
|
||||||
|
* assign execution state to node
|
||||||
|
* ----------------
|
||||||
|
*/
|
||||||
|
node->plan.state = estate;
|
||||||
|
|
||||||
|
/* ----------------
|
||||||
|
* create new LimitState for node
|
||||||
|
* ----------------
|
||||||
|
*/
|
||||||
|
limitstate = makeNode(LimitState);
|
||||||
|
node->limitstate = limitstate;
|
||||||
|
limitstate->parmsSet = false;
|
||||||
|
|
||||||
|
/* ----------------
|
||||||
|
* Miscellaneous initialization
|
||||||
|
*
|
||||||
|
* Limit nodes never call ExecQual or ExecProject, but they need
|
||||||
|
* an exprcontext anyway to evaluate the limit/offset parameters in.
|
||||||
|
* ----------------
|
||||||
|
*/
|
||||||
|
ExecAssignExprContext(estate, &limitstate->cstate);
|
||||||
|
|
||||||
|
#define LIMIT_NSLOTS 1
|
||||||
|
/* ------------
|
||||||
|
* Tuple table initialization
|
||||||
|
* ------------
|
||||||
|
*/
|
||||||
|
ExecInitResultTupleSlot(estate, &limitstate->cstate);
|
||||||
|
|
||||||
|
/* ----------------
|
||||||
|
* then initialize outer plan
|
||||||
|
* ----------------
|
||||||
|
*/
|
||||||
|
outerPlan = outerPlan((Plan *) node);
|
||||||
|
ExecInitNode(outerPlan, estate, (Plan *) node);
|
||||||
|
|
||||||
|
/* ----------------
|
||||||
|
* limit nodes do no projections, so initialize
|
||||||
|
* projection info for this node appropriately
|
||||||
|
* ----------------
|
||||||
|
*/
|
||||||
|
ExecAssignResultTypeFromOuterPlan((Plan *) node, &limitstate->cstate);
|
||||||
|
limitstate->cstate.cs_ProjInfo = NULL;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
ExecCountSlotsLimit(Limit *node)
|
||||||
|
{
|
||||||
|
return ExecCountSlotsNode(outerPlan(node)) +
|
||||||
|
ExecCountSlotsNode(innerPlan(node)) +
|
||||||
|
LIMIT_NSLOTS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ----------------------------------------------------------------
|
||||||
|
* ExecEndLimit
|
||||||
|
*
|
||||||
|
* This shuts down the subplan and frees resources allocated
|
||||||
|
* to this node.
|
||||||
|
* ----------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
ExecEndLimit(Limit *node)
|
||||||
|
{
|
||||||
|
LimitState *limitstate = node->limitstate;
|
||||||
|
|
||||||
|
ExecFreeExprContext(&limitstate->cstate);
|
||||||
|
|
||||||
|
ExecEndNode(outerPlan((Plan *) node), (Plan *) node);
|
||||||
|
|
||||||
|
/* clean up tuple table */
|
||||||
|
ExecClearTuple(limitstate->cstate.cs_ResultTupleSlot);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ExecReScanLimit(Limit *node, ExprContext *exprCtxt, Plan *parent)
|
||||||
|
{
|
||||||
|
LimitState *limitstate = node->limitstate;
|
||||||
|
|
||||||
|
ExecClearTuple(limitstate->cstate.cs_ResultTupleSlot);
|
||||||
|
|
||||||
|
/* force recalculation of limit expressions on first call */
|
||||||
|
limitstate->parmsSet = false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* if chgParam of subnode is not null then plan will be re-scanned by
|
||||||
|
* first ExecProcNode.
|
||||||
|
*/
|
||||||
|
if (((Plan *) node)->lefttree->chgParam == NULL)
|
||||||
|
ExecReScan(((Plan *) node)->lefttree, exprCtxt, (Plan *) node);
|
||||||
|
}
|
@ -3,7 +3,7 @@
|
|||||||
* spi.c
|
* spi.c
|
||||||
* Server Programming Interface
|
* Server Programming Interface
|
||||||
*
|
*
|
||||||
* $Id: spi.c,v 1.47 2000/06/28 03:31:34 tgl Exp $
|
* $Id: spi.c,v 1.48 2000/10/26 21:35:15 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -762,8 +762,6 @@ _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount)
|
|||||||
bool isRetrieveIntoRelation = false;
|
bool isRetrieveIntoRelation = false;
|
||||||
char *intoName = NULL;
|
char *intoName = NULL;
|
||||||
int res;
|
int res;
|
||||||
Const tcount_const;
|
|
||||||
Node *count = NULL;
|
|
||||||
|
|
||||||
switch (operation)
|
switch (operation)
|
||||||
{
|
{
|
||||||
@ -798,39 +796,6 @@ _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount)
|
|||||||
return SPI_ERROR_OPUNKNOWN;
|
return SPI_ERROR_OPUNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------
|
|
||||||
* Get the query LIMIT tuple count
|
|
||||||
* ----------------
|
|
||||||
*/
|
|
||||||
if (parseTree->limitCount != NULL)
|
|
||||||
{
|
|
||||||
/* ----------------
|
|
||||||
* A limit clause in the parsetree overrides the
|
|
||||||
* tcount parameter
|
|
||||||
* ----------------
|
|
||||||
*/
|
|
||||||
count = parseTree->limitCount;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* ----------------
|
|
||||||
* No LIMIT clause in parsetree. Use a local Const node
|
|
||||||
* to put tcount into it
|
|
||||||
* ----------------
|
|
||||||
*/
|
|
||||||
memset(&tcount_const, 0, sizeof(tcount_const));
|
|
||||||
tcount_const.type = T_Const;
|
|
||||||
tcount_const.consttype = INT4OID;
|
|
||||||
tcount_const.constlen = sizeof(int4);
|
|
||||||
tcount_const.constvalue = (Datum) tcount;
|
|
||||||
tcount_const.constisnull = FALSE;
|
|
||||||
tcount_const.constbyval = TRUE;
|
|
||||||
tcount_const.constisset = FALSE;
|
|
||||||
tcount_const.constiscast = FALSE;
|
|
||||||
|
|
||||||
count = (Node *) &tcount_const;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state == NULL) /* plan preparation */
|
if (state == NULL) /* plan preparation */
|
||||||
return res;
|
return res;
|
||||||
#ifdef SPI_EXECUTOR_STATS
|
#ifdef SPI_EXECUTOR_STATS
|
||||||
@ -848,7 +813,7 @@ _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount)
|
|||||||
elog(FATAL, "SPI_select: retrieve into portal not implemented");
|
elog(FATAL, "SPI_select: retrieve into portal not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
ExecutorRun(queryDesc, state, EXEC_FOR, parseTree->limitOffset, count);
|
ExecutorRun(queryDesc, state, EXEC_FOR, (long) tcount);
|
||||||
|
|
||||||
_SPI_current->processed = state->es_processed;
|
_SPI_current->processed = state->es_processed;
|
||||||
if (operation == CMD_SELECT && queryDesc->dest == SPI)
|
if (operation == CMD_SELECT && queryDesc->dest == SPI)
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.126 2000/10/18 16:16:04 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.127 2000/10/26 21:35:47 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -592,6 +592,31 @@ _copySetOp(SetOp *from)
|
|||||||
return newnode;
|
return newnode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ----------------
|
||||||
|
* _copyLimit
|
||||||
|
* ----------------
|
||||||
|
*/
|
||||||
|
static Limit *
|
||||||
|
_copyLimit(Limit *from)
|
||||||
|
{
|
||||||
|
Limit *newnode = makeNode(Limit);
|
||||||
|
|
||||||
|
/* ----------------
|
||||||
|
* copy node superclass fields
|
||||||
|
* ----------------
|
||||||
|
*/
|
||||||
|
CopyPlanFields((Plan *) from, (Plan *) newnode);
|
||||||
|
|
||||||
|
/* ----------------
|
||||||
|
* copy remainder of node
|
||||||
|
* ----------------
|
||||||
|
*/
|
||||||
|
Node_Copy(from, newnode, limitOffset);
|
||||||
|
Node_Copy(from, newnode, limitCount);
|
||||||
|
|
||||||
|
return newnode;
|
||||||
|
}
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* _copyHash
|
* _copyHash
|
||||||
* ----------------
|
* ----------------
|
||||||
@ -2567,6 +2592,9 @@ copyObject(void *from)
|
|||||||
case T_SetOp:
|
case T_SetOp:
|
||||||
retval = _copySetOp(from);
|
retval = _copySetOp(from);
|
||||||
break;
|
break;
|
||||||
|
case T_Limit:
|
||||||
|
retval = _copyLimit(from);
|
||||||
|
break;
|
||||||
case T_Hash:
|
case T_Hash:
|
||||||
retval = _copyHash(from);
|
retval = _copyHash(from);
|
||||||
break;
|
break;
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.128 2000/10/05 19:11:27 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.129 2000/10/26 21:35:48 tgl Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* Every (plan) node in POSTGRES has an associated "out" routine which
|
* Every (plan) node in POSTGRES has an associated "out" routine which
|
||||||
@ -623,6 +623,18 @@ _outSetOp(StringInfo str, SetOp *node)
|
|||||||
(int) node->flagColIdx);
|
(int) node->flagColIdx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_outLimit(StringInfo str, Limit *node)
|
||||||
|
{
|
||||||
|
appendStringInfo(str, " LIMIT ");
|
||||||
|
_outPlanInfo(str, (Plan *) node);
|
||||||
|
|
||||||
|
appendStringInfo(str, " :limitOffset ");
|
||||||
|
_outNode(str, node->limitOffset);
|
||||||
|
appendStringInfo(str, " :limitCount ");
|
||||||
|
_outNode(str, node->limitCount);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Hash is a subclass of Plan
|
* Hash is a subclass of Plan
|
||||||
*/
|
*/
|
||||||
@ -1559,6 +1571,9 @@ _outNode(StringInfo str, void *obj)
|
|||||||
case T_SetOp:
|
case T_SetOp:
|
||||||
_outSetOp(str, obj);
|
_outSetOp(str, obj);
|
||||||
break;
|
break;
|
||||||
|
case T_Limit:
|
||||||
|
_outLimit(str, obj);
|
||||||
|
break;
|
||||||
case T_Hash:
|
case T_Hash:
|
||||||
_outHash(str, obj);
|
_outHash(str, obj);
|
||||||
break;
|
break;
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/nodes/print.c,v 1.44 2000/10/22 22:14:54 petere Exp $
|
* $Header: /cvsroot/pgsql/src/backend/nodes/print.c,v 1.45 2000/10/26 21:35:48 tgl Exp $
|
||||||
*
|
*
|
||||||
* HISTORY
|
* HISTORY
|
||||||
* AUTHOR DATE MAJOR EVENT
|
* AUTHOR DATE MAJOR EVENT
|
||||||
@ -324,6 +324,8 @@ plannode_type(Plan *p)
|
|||||||
return "UNIQUE";
|
return "UNIQUE";
|
||||||
case T_SetOp:
|
case T_SetOp:
|
||||||
return "SETOP";
|
return "SETOP";
|
||||||
|
case T_Limit:
|
||||||
|
return "LIMIT";
|
||||||
case T_Hash:
|
case T_Hash:
|
||||||
return "HASH";
|
return "HASH";
|
||||||
case T_Group:
|
case T_Group:
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.98 2000/10/05 19:11:29 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.99 2000/10/26 21:36:09 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -1651,6 +1651,27 @@ make_setop(SetOpCmd cmd, List *tlist, Plan *lefttree,
|
|||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Limit *
|
||||||
|
make_limit(List *tlist, Plan *lefttree,
|
||||||
|
Node *limitOffset, Node *limitCount)
|
||||||
|
{
|
||||||
|
Limit *node = makeNode(Limit);
|
||||||
|
Plan *plan = &node->plan;
|
||||||
|
|
||||||
|
copy_plan_costsize(plan, lefttree);
|
||||||
|
|
||||||
|
plan->state = (EState *) NULL;
|
||||||
|
plan->targetlist = tlist;
|
||||||
|
plan->qual = NIL;
|
||||||
|
plan->lefttree = lefttree;
|
||||||
|
plan->righttree = NULL;
|
||||||
|
|
||||||
|
node->limitOffset = limitOffset;
|
||||||
|
node->limitCount = limitCount;
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
Result *
|
Result *
|
||||||
make_result(List *tlist,
|
make_result(List *tlist,
|
||||||
Node *resconstantqual,
|
Node *resconstantqual,
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.92 2000/10/05 19:11:29 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.93 2000/10/26 21:36:09 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -341,8 +341,6 @@ is_simple_subquery(Query *subquery)
|
|||||||
*/
|
*/
|
||||||
if (subquery->rowMarks)
|
if (subquery->rowMarks)
|
||||||
elog(ERROR, "FOR UPDATE is not supported in subselects");
|
elog(ERROR, "FOR UPDATE is not supported in subselects");
|
||||||
if (subquery->limitOffset || subquery->limitCount)
|
|
||||||
elog(ERROR, "LIMIT is not supported in subselects");
|
|
||||||
/*
|
/*
|
||||||
* Can't currently pull up a query with setops.
|
* Can't currently pull up a query with setops.
|
||||||
* Maybe after querytree redesign...
|
* Maybe after querytree redesign...
|
||||||
@ -350,13 +348,16 @@ is_simple_subquery(Query *subquery)
|
|||||||
if (subquery->setOperations)
|
if (subquery->setOperations)
|
||||||
return false;
|
return false;
|
||||||
/*
|
/*
|
||||||
* Can't pull up a subquery involving grouping, aggregation, or sorting.
|
* Can't pull up a subquery involving grouping, aggregation, sorting,
|
||||||
|
* or limiting.
|
||||||
*/
|
*/
|
||||||
if (subquery->hasAggs ||
|
if (subquery->hasAggs ||
|
||||||
subquery->groupClause ||
|
subquery->groupClause ||
|
||||||
subquery->havingQual ||
|
subquery->havingQual ||
|
||||||
subquery->sortClause ||
|
subquery->sortClause ||
|
||||||
subquery->distinctClause)
|
subquery->distinctClause ||
|
||||||
|
subquery->limitOffset ||
|
||||||
|
subquery->limitCount)
|
||||||
return false;
|
return false;
|
||||||
/*
|
/*
|
||||||
* Hack: don't try to pull up a subquery with an empty jointree.
|
* Hack: don't try to pull up a subquery with an empty jointree.
|
||||||
@ -831,7 +832,7 @@ union_planner(Query *parse,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* It's a PARAM ... punt ... */
|
/* It's an expression ... punt ... */
|
||||||
tuple_fraction = 0.10;
|
tuple_fraction = 0.10;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -839,9 +840,8 @@ union_planner(Query *parse,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* COUNT is a PARAM ... don't know exactly what the
|
* COUNT is an expression ... don't know exactly what the
|
||||||
* limit will be, but for lack of a better idea assume
|
* limit will be, but for lack of a better idea assume
|
||||||
* 10% of the plan's result is wanted.
|
* 10% of the plan's result is wanted.
|
||||||
*/
|
*/
|
||||||
@ -1024,7 +1024,7 @@ union_planner(Query *parse,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Finally, if there is a DISTINCT clause, add the UNIQUE node.
|
* If there is a DISTINCT clause, add the UNIQUE node.
|
||||||
*/
|
*/
|
||||||
if (parse->distinctClause)
|
if (parse->distinctClause)
|
||||||
{
|
{
|
||||||
@ -1032,6 +1032,16 @@ union_planner(Query *parse,
|
|||||||
parse->distinctClause);
|
parse->distinctClause);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Finally, if there is a LIMIT/OFFSET clause, add the LIMIT node.
|
||||||
|
*/
|
||||||
|
if (parse->limitOffset || parse->limitCount)
|
||||||
|
{
|
||||||
|
result_plan = (Plan *) make_limit(tlist, result_plan,
|
||||||
|
parse->limitOffset,
|
||||||
|
parse->limitCount);
|
||||||
|
}
|
||||||
|
|
||||||
return result_plan;
|
return result_plan;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.67 2000/10/05 19:11:29 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.68 2000/10/26 21:36:09 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -139,6 +139,7 @@ set_plan_references(Plan *plan)
|
|||||||
case T_Sort:
|
case T_Sort:
|
||||||
case T_Unique:
|
case T_Unique:
|
||||||
case T_SetOp:
|
case T_SetOp:
|
||||||
|
case T_Limit:
|
||||||
case T_Hash:
|
case T_Hash:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.43 2000/10/05 19:11:29 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.44 2000/10/26 21:36:09 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -657,6 +657,7 @@ SS_finalize_plan(Plan *plan)
|
|||||||
case T_Sort:
|
case T_Sort:
|
||||||
case T_Unique:
|
case T_Unique:
|
||||||
case T_SetOp:
|
case T_SetOp:
|
||||||
|
case T_Limit:
|
||||||
case T_Group:
|
case T_Group:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteDefine.c,v 1.54 2000/10/05 19:11:34 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteDefine.c,v 1.55 2000/10/26 21:36:50 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -304,12 +304,6 @@ DefineQueryRewrite(RuleStmt *stmt)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* LIMIT in view is not supported
|
|
||||||
*/
|
|
||||||
if (query->limitOffset != NULL || query->limitCount != NULL)
|
|
||||||
elog(ERROR, "LIMIT clause not supported in views");
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ... and finally the rule must be named _RETviewname.
|
* ... and finally the rule must be named _RETviewname.
|
||||||
*/
|
*/
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.38 2000/08/22 04:06:20 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.39 2000/10/26 21:37:24 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -299,8 +299,7 @@ ProcessQuery(Query *parsetree,
|
|||||||
* actually run the plan..
|
* actually run the plan..
|
||||||
* ----------------
|
* ----------------
|
||||||
*/
|
*/
|
||||||
ExecutorRun(queryDesc, state, EXEC_RUN,
|
ExecutorRun(queryDesc, state, EXEC_RUN, 0L);
|
||||||
parsetree->limitOffset, parsetree->limitCount);
|
|
||||||
|
|
||||||
/* save infos for EndCommand */
|
/* save infos for EndCommand */
|
||||||
UpdateCommandInfo(operation, state->es_lastoid, state->es_processed);
|
UpdateCommandInfo(operation, state->es_lastoid, state->es_processed);
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
* back to source text
|
* back to source text
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.66 2000/10/05 21:52:08 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.67 2000/10/26 21:37:45 tgl Exp $
|
||||||
*
|
*
|
||||||
* This software is copyrighted by Jan Wieck - Hamburg.
|
* This software is copyrighted by Jan Wieck - Hamburg.
|
||||||
*
|
*
|
||||||
@ -886,8 +886,8 @@ get_select_query_def(Query *query, deparse_context *context)
|
|||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
* If the Query node has a setOperations tree, then it's the top
|
* If the Query node has a setOperations tree, then it's the top
|
||||||
* level of a UNION/INTERSECT/EXCEPT query; only the ORDER BY field
|
* level of a UNION/INTERSECT/EXCEPT query; only the ORDER BY and
|
||||||
* is interesting in the top query itself.
|
* LIMIT fields are interesting in the top query itself.
|
||||||
* ----------
|
* ----------
|
||||||
*/
|
*/
|
||||||
if (query->setOperations)
|
if (query->setOperations)
|
||||||
@ -931,6 +931,18 @@ get_select_query_def(Query *query, deparse_context *context)
|
|||||||
sep = ", ";
|
sep = ", ";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Add the LIMIT clause if given */
|
||||||
|
if (query->limitOffset != NULL)
|
||||||
|
{
|
||||||
|
appendStringInfo(buf, " OFFSET ");
|
||||||
|
get_rule_expr(query->limitOffset, context);
|
||||||
|
}
|
||||||
|
if (query->limitCount != NULL)
|
||||||
|
{
|
||||||
|
appendStringInfo(buf, " LIMIT ");
|
||||||
|
get_rule_expr(query->limitCount, context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: executor.h,v 1.51 2000/09/12 21:07:09 tgl Exp $
|
* $Id: executor.h,v 1.52 2000/10/26 21:38:03 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -54,7 +54,7 @@ extern HeapTuple ExecRemoveJunk(JunkFilter *junkfilter, TupleTableSlot *slot);
|
|||||||
*/
|
*/
|
||||||
extern TupleDesc ExecutorStart(QueryDesc *queryDesc, EState *estate);
|
extern TupleDesc ExecutorStart(QueryDesc *queryDesc, EState *estate);
|
||||||
extern TupleTableSlot *ExecutorRun(QueryDesc *queryDesc, EState *estate,
|
extern TupleTableSlot *ExecutorRun(QueryDesc *queryDesc, EState *estate,
|
||||||
int feature, Node *limoffset, Node *limcount);
|
int feature, long count);
|
||||||
extern void ExecutorEnd(QueryDesc *queryDesc, EState *estate);
|
extern void ExecutorEnd(QueryDesc *queryDesc, EState *estate);
|
||||||
extern void ExecConstraints(char *caller, Relation rel,
|
extern void ExecConstraints(char *caller, Relation rel,
|
||||||
TupleTableSlot *slot, EState *estate);
|
TupleTableSlot *slot, EState *estate);
|
||||||
|
25
src/include/executor/nodeLimit.h
Normal file
25
src/include/executor/nodeLimit.h
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
/*-------------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* nodeLimit.h
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||||
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
|
*
|
||||||
|
* $Id: nodeLimit.h,v 1.1 2000/10/26 21:38:03 tgl Exp $
|
||||||
|
*
|
||||||
|
*-------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
#ifndef NODELIMIT_H
|
||||||
|
#define NODELIMIT_H
|
||||||
|
|
||||||
|
#include "nodes/plannodes.h"
|
||||||
|
|
||||||
|
extern TupleTableSlot *ExecLimit(Limit *node);
|
||||||
|
extern bool ExecInitLimit(Limit *node, EState *estate, Plan *parent);
|
||||||
|
extern int ExecCountSlotsLimit(Limit *node);
|
||||||
|
extern void ExecEndLimit(Limit *node);
|
||||||
|
extern void ExecReScanLimit(Limit *node, ExprContext *exprCtxt, Plan *parent);
|
||||||
|
|
||||||
|
#endif /* NODELIMIT_H */
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: execnodes.h,v 1.51 2000/10/05 19:11:36 tgl Exp $
|
* $Id: execnodes.h,v 1.52 2000/10/26 21:38:12 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -675,6 +675,28 @@ typedef struct SetOpState
|
|||||||
MemoryContext tempContext; /* short-term context for comparisons */
|
MemoryContext tempContext; /* short-term context for comparisons */
|
||||||
} SetOpState;
|
} SetOpState;
|
||||||
|
|
||||||
|
/* ----------------
|
||||||
|
* LimitState information
|
||||||
|
*
|
||||||
|
* Limit nodes are used to enforce LIMIT/OFFSET clauses.
|
||||||
|
* They just select the desired subrange of their subplan's output.
|
||||||
|
*
|
||||||
|
* offset is the number of initial tuples to skip (0 does nothing).
|
||||||
|
* count is the number of tuples to return after skipping the offset tuples.
|
||||||
|
* If no limit count was specified, count is undefined and noCount is true.
|
||||||
|
* ----------------
|
||||||
|
*/
|
||||||
|
typedef struct LimitState
|
||||||
|
{
|
||||||
|
CommonState cstate; /* its first field is NodeTag */
|
||||||
|
long offset; /* current OFFSET value */
|
||||||
|
long count; /* current COUNT, if any */
|
||||||
|
long position; /* 1-based index of last tuple fetched */
|
||||||
|
bool parmsSet; /* have we calculated offset/limit yet? */
|
||||||
|
bool noCount; /* if true, ignore count */
|
||||||
|
bool atEnd; /* if true, we've reached EOF of subplan */
|
||||||
|
} LimitState;
|
||||||
|
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* HashState information
|
* HashState information
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: nodes.h,v 1.79 2000/10/22 23:32:44 tgl Exp $
|
* $Id: nodes.h,v 1.80 2000/10/26 21:38:12 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -39,7 +39,7 @@ typedef enum NodeTag
|
|||||||
T_NestLoop,
|
T_NestLoop,
|
||||||
T_MergeJoin,
|
T_MergeJoin,
|
||||||
T_HashJoin,
|
T_HashJoin,
|
||||||
T_Noname_XXX, /* not used anymore; this tag# is available */
|
T_Limit,
|
||||||
T_Material,
|
T_Material,
|
||||||
T_Sort,
|
T_Sort,
|
||||||
T_Agg,
|
T_Agg,
|
||||||
@ -122,6 +122,7 @@ typedef enum NodeTag
|
|||||||
T_TidScanState,
|
T_TidScanState,
|
||||||
T_SubqueryScanState,
|
T_SubqueryScanState,
|
||||||
T_SetOpState,
|
T_SetOpState,
|
||||||
|
T_LimitState,
|
||||||
|
|
||||||
/*---------------------
|
/*---------------------
|
||||||
* TAGS FOR MEMORY NODES (memnodes.h)
|
* TAGS FOR MEMORY NODES (memnodes.h)
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: plannodes.h,v 1.44 2000/10/05 19:11:36 tgl Exp $
|
* $Id: plannodes.h,v 1.45 2000/10/26 21:38:12 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -47,6 +47,7 @@
|
|||||||
* Sort SortState sortstate;
|
* Sort SortState sortstate;
|
||||||
* Unique UniqueState uniquestate;
|
* Unique UniqueState uniquestate;
|
||||||
* SetOp SetOpState setopstate;
|
* SetOp SetOpState setopstate;
|
||||||
|
* Limit LimitState limitstate;
|
||||||
* Hash HashState hashstate;
|
* Hash HashState hashstate;
|
||||||
*
|
*
|
||||||
* ----------------------------------------------------------------
|
* ----------------------------------------------------------------
|
||||||
@ -375,6 +376,18 @@ typedef struct SetOp
|
|||||||
SetOpState *setopstate;
|
SetOpState *setopstate;
|
||||||
} SetOp;
|
} SetOp;
|
||||||
|
|
||||||
|
/* ----------------
|
||||||
|
* limit node
|
||||||
|
* ----------------
|
||||||
|
*/
|
||||||
|
typedef struct Limit
|
||||||
|
{
|
||||||
|
Plan plan;
|
||||||
|
Node *limitOffset; /* OFFSET parameter, or NULL if none */
|
||||||
|
Node *limitCount; /* COUNT parameter, or NULL if none */
|
||||||
|
LimitState *limitstate;
|
||||||
|
} Limit;
|
||||||
|
|
||||||
/* ----------------
|
/* ----------------
|
||||||
* hash build node
|
* hash build node
|
||||||
* ----------------
|
* ----------------
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Id: planmain.h,v 1.46 2000/10/05 19:11:37 tgl Exp $
|
* $Id: planmain.h,v 1.47 2000/10/26 21:38:24 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -36,6 +36,8 @@ extern Group *make_group(List *tlist, bool tuplePerGroup, int ngrp,
|
|||||||
AttrNumber *grpColIdx, Plan *lefttree);
|
AttrNumber *grpColIdx, Plan *lefttree);
|
||||||
extern Material *make_material(List *tlist, Plan *lefttree);
|
extern Material *make_material(List *tlist, Plan *lefttree);
|
||||||
extern Unique *make_unique(List *tlist, Plan *lefttree, List *distinctList);
|
extern Unique *make_unique(List *tlist, Plan *lefttree, List *distinctList);
|
||||||
|
extern Limit *make_limit(List *tlist, Plan *lefttree,
|
||||||
|
Node *limitOffset, Node *limitCount);
|
||||||
extern SetOp *make_setop(SetOpCmd cmd, List *tlist, Plan *lefttree,
|
extern SetOp *make_setop(SetOpCmd cmd, List *tlist, Plan *lefttree,
|
||||||
List *distinctList, AttrNumber flagColIdx);
|
List *distinctList, AttrNumber flagColIdx);
|
||||||
extern Result *make_result(List *tlist, Node *resconstantqual, Plan *subplan);
|
extern Result *make_result(List *tlist, Node *resconstantqual, Plan *subplan);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user