mirror of
https://github.com/postgres/postgres.git
synced 2025-09-02 04:21:28 +03:00
Added LIMIT/OFFSET functionality including new regression test for it.
Removed CURRENT keyword for rule queries and changed rules regression accordingly. CURRENT has beed announced to disappear in v6.5. Jan
This commit is contained in:
@@ -26,7 +26,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.75 1999/02/07 16:17:11 wieck Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.76 1999/02/08 14:14:09 wieck Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -60,21 +60,27 @@ void ExecCheckPerms(CmdType operation, int resultRelation, List *rangeTable,
|
||||
|
||||
|
||||
/* decls for local routines only used within this module */
|
||||
static TupleDesc InitPlan(CmdType operation, Query *parseTree,
|
||||
Plan *plan, EState *estate);
|
||||
static void EndPlan(Plan *plan, EState *estate);
|
||||
static TupleDesc InitPlan(CmdType operation,
|
||||
Query *parseTree,
|
||||
Plan *plan,
|
||||
EState *estate);
|
||||
static void EndPlan(Plan *plan,
|
||||
EState *estate);
|
||||
static TupleTableSlot *ExecutePlan(EState *estate, Plan *plan,
|
||||
CmdType operation, int numberTuples, ScanDirection direction,
|
||||
DestReceiver *destfunc);
|
||||
CmdType operation,
|
||||
int offsetTuples,
|
||||
int numberTuples,
|
||||
ScanDirection direction,
|
||||
DestReceiver *destfunc);
|
||||
static void ExecRetrieve(TupleTableSlot *slot,
|
||||
DestReceiver *destfunc,
|
||||
EState *estate);
|
||||
DestReceiver *destfunc,
|
||||
EState *estate);
|
||||
static void ExecAppend(TupleTableSlot *slot, ItemPointer tupleid,
|
||||
EState *estate);
|
||||
EState *estate);
|
||||
static void ExecDelete(TupleTableSlot *slot, ItemPointer tupleid,
|
||||
EState *estate);
|
||||
EState *estate);
|
||||
static void ExecReplace(TupleTableSlot *slot, ItemPointer tupleid,
|
||||
EState *estate);
|
||||
EState *estate);
|
||||
|
||||
TupleTableSlot *EvalPlanQual(EState *estate, Index rti, ItemPointer tid);
|
||||
static TupleTableSlot *EvalPlanQualNext(EState *estate);
|
||||
@@ -187,13 +193,16 @@ ExecutorStart(QueryDesc *queryDesc, EState *estate)
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
TupleTableSlot *
|
||||
ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count)
|
||||
ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature,
|
||||
Node *limoffset, Node *limcount)
|
||||
{
|
||||
CmdType operation;
|
||||
Plan *plan;
|
||||
TupleTableSlot *result;
|
||||
CommandDest dest;
|
||||
DestReceiver *destfunc;
|
||||
int offset = 0;
|
||||
int count = 0;
|
||||
|
||||
/******************
|
||||
* sanity checks
|
||||
@@ -222,6 +231,96 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count)
|
||||
*/
|
||||
(*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)
|
||||
{
|
||||
|
||||
@@ -229,7 +328,8 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count)
|
||||
result = ExecutePlan(estate,
|
||||
plan,
|
||||
operation,
|
||||
ALL_TUPLES,
|
||||
offset,
|
||||
count,
|
||||
ForwardScanDirection,
|
||||
destfunc);
|
||||
break;
|
||||
@@ -237,6 +337,7 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count)
|
||||
result = ExecutePlan(estate,
|
||||
plan,
|
||||
operation,
|
||||
offset,
|
||||
count,
|
||||
ForwardScanDirection,
|
||||
destfunc);
|
||||
@@ -250,6 +351,7 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count)
|
||||
result = ExecutePlan(estate,
|
||||
plan,
|
||||
operation,
|
||||
offset,
|
||||
count,
|
||||
BackwardScanDirection,
|
||||
destfunc);
|
||||
@@ -264,6 +366,7 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, int count)
|
||||
result = ExecutePlan(estate,
|
||||
plan,
|
||||
operation,
|
||||
0,
|
||||
ONE_TUPLE,
|
||||
ForwardScanDirection,
|
||||
destfunc);
|
||||
@@ -784,6 +887,7 @@ static TupleTableSlot *
|
||||
ExecutePlan(EState *estate,
|
||||
Plan *plan,
|
||||
CmdType operation,
|
||||
int offsetTuples,
|
||||
int numberTuples,
|
||||
ScanDirection direction,
|
||||
DestReceiver* destfunc)
|
||||
@@ -845,6 +949,20 @@ lnext:;
|
||||
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 junk removed.
|
||||
|
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.22 1999/02/03 21:16:12 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.23 1999/02/08 14:14:09 wieck Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -130,6 +130,9 @@ init_execution_state(FunctionCachePtr fcache,
|
||||
None);
|
||||
estate = CreateExecutorState();
|
||||
|
||||
if (queryTree->limitOffset != NULL || queryTree->limitCount != NULL)
|
||||
elog(ERROR, "LIMIT clause from SQL functions not yet implemented");
|
||||
|
||||
if (nargs > 0)
|
||||
{
|
||||
int i;
|
||||
@@ -199,7 +202,7 @@ postquel_getnext(execution_state *es)
|
||||
|
||||
feature = (LAST_POSTQUEL_COMMAND(es)) ? EXEC_RETONE : EXEC_RUN;
|
||||
|
||||
return ExecutorRun(es->qd, es->estate, feature, 0);
|
||||
return ExecutorRun(es->qd, es->estate, feature, (Node *)NULL, (Node *)NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@@ -3,7 +3,7 @@
|
||||
* spi.c--
|
||||
* Server Programming Interface
|
||||
*
|
||||
* $Id: spi.c,v 1.32 1999/01/27 16:15:20 wieck Exp $
|
||||
* $Id: spi.c,v 1.33 1999/02/08 14:14:10 wieck Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -779,6 +779,8 @@ _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount)
|
||||
bool isRetrieveIntoRelation = false;
|
||||
char *intoName = NULL;
|
||||
int res;
|
||||
Const tcount_const;
|
||||
Node *count = NULL;
|
||||
|
||||
switch (operation)
|
||||
{
|
||||
@@ -813,6 +815,39 @@ _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount)
|
||||
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 */
|
||||
return res;
|
||||
#ifdef SPI_EXECUTOR_STATS
|
||||
@@ -833,7 +868,7 @@ _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount)
|
||||
return SPI_OK_CURSOR;
|
||||
}
|
||||
|
||||
ExecutorRun(queryDesc, state, EXEC_FOR, tcount);
|
||||
ExecutorRun(queryDesc, state, EXEC_FOR, parseTree->limitOffset, count);
|
||||
|
||||
_SPI_current->processed = state->es_processed;
|
||||
if (operation == CMD_SELECT && queryDesc->dest == SPI)
|
||||
|
Reference in New Issue
Block a user