diff options
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/commands/command.c | 22 | ||||
-rw-r--r-- | src/backend/executor/execMain.c | 144 | ||||
-rw-r--r-- | src/backend/executor/functions.c | 7 | ||||
-rw-r--r-- | src/backend/executor/spi.c | 39 | ||||
-rw-r--r-- | src/backend/parser/analyze.c | 6 | ||||
-rw-r--r-- | src/backend/parser/gram.y | 95 | ||||
-rw-r--r-- | src/backend/parser/keywords.c | 7 | ||||
-rw-r--r-- | src/backend/rewrite/rewriteDefine.c | 8 | ||||
-rw-r--r-- | src/backend/tcop/pquery.c | 12 |
9 files changed, 305 insertions, 35 deletions
diff --git a/src/backend/commands/command.c b/src/backend/commands/command.c index 1a65f4d4d0d..310325d2f81 100644 --- a/src/backend/commands/command.c +++ b/src/backend/commands/command.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.36 1999/02/03 21:16:02 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.37 1999/02/08 14:14:08 wieck Exp $ * * NOTES * The PortalExecutorHeapMemory crap needs to be eliminated @@ -40,6 +40,7 @@ #include "utils/portal.h" #include "utils/syscache.h" #include "miscadmin.h" +#include "string.h" /* ---------------- * PortalExecutorHeapMemory stuff @@ -102,6 +103,7 @@ PerformPortalFetch(char *name, int feature; QueryDesc *queryDesc; MemoryContext context; + Const limcount; /* ---------------- * sanity checks @@ -114,6 +116,21 @@ PerformPortalFetch(char *name, } /* ---------------- + * 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 = (Datum)count; + limcount.constisnull = FALSE; + limcount.constbyval = TRUE; + limcount.constisset = FALSE; + limcount.constiscast = FALSE; + + + /* ---------------- * get the portal from the portal name * ---------------- */ @@ -176,7 +193,8 @@ PerformPortalFetch(char *name, PortalExecutorHeapMemory = (MemoryContext) PortalGetHeapMemory(portal); - ExecutorRun(queryDesc, PortalGetState(portal), feature, count); + ExecutorRun(queryDesc, PortalGetState(portal), feature, + (Node *)NULL, (Node *)&limcount); if (dest == None) /* MOVE */ pfree(queryDesc); diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index 5ce90902b4c..e11869ce783 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -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) @@ -846,6 +950,20 @@ lnext:; } /****************** + * 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. * diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c index 51ea6655e9d..7108a1cab52 100644 --- a/src/backend/executor/functions.c +++ b/src/backend/executor/functions.c @@ -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 diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c index 7ca2a6c21e5..397f68a4055 100644 --- a/src/backend/executor/spi.c +++ b/src/backend/executor/spi.c @@ -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) diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index 6232a2d067d..ada18bb71d3 100644 --- a/src/backend/parser/analyze.c +++ b/src/backend/parser/analyze.c @@ -5,7 +5,7 @@ * * Copyright (c) 1994, Regents of the University of California * - * $Id: analyze.c,v 1.97 1999/02/02 03:44:32 momjian Exp $ + * $Id: analyze.c,v 1.98 1999/02/08 14:14:11 wieck Exp $ * *------------------------------------------------------------------------- */ @@ -205,7 +205,11 @@ transformStmt(ParseState *pstate, Node *parseTree) case T_SelectStmt: if (!((SelectStmt *) parseTree)->portalname) + { result = transformSelectStmt(pstate, (SelectStmt *) parseTree); + result->limitOffset = ((SelectStmt *)parseTree)->limitOffset; + result->limitCount = ((SelectStmt *)parseTree)->limitCount; + } else result = transformCursorStmt(pstate, (SelectStmt *) parseTree); break; diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index e88b9073084..b649ceba36c 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.53 1999/02/07 19:02:19 wieck Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.54 1999/02/08 14:14:12 wieck Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -48,6 +48,7 @@ #include "storage/lmgr.h" #include "utils/numeric.h" #include "parser/analyze.h" +#include "catalog/pg_type.h" #ifdef MULTIBYTE #include "mb/pg_wchar.h" @@ -168,7 +169,8 @@ Oid param_type(int t); /* used in parse_expr.c */ sort_clause, sortby_list, index_params, index_list, name_list, from_clause, from_list, opt_array_bounds, nest_array_bounds, expr_list, attrs, res_target_list, res_target_list2, - def_list, opt_indirection, group_clause, TriggerFuncArgs + def_list, opt_indirection, group_clause, TriggerFuncArgs, + opt_select_limit %type <node> func_return %type <boolean> set_opt @@ -197,6 +199,8 @@ Oid param_type(int t); /* used in parse_expr.c */ %type <ival> fetch_how_many +%type <node> select_limit_value, select_offset_value + %type <list> OptSeqList %type <defelt> OptSeqElem @@ -306,9 +310,10 @@ Oid param_type(int t); /* used in parse_expr.c */ DATABASE, DELIMITERS, DO, EACH, ENCODING, EXPLAIN, EXTEND, FORWARD, FUNCTION, HANDLER, INCREMENT, INDEX, INHERITS, INSTEAD, ISNULL, - LANCOMPILER, LISTEN, LOAD, LOCATION, LOCK_P, MAXVALUE, MINVALUE, MOVE, + LANCOMPILER, LIMIT, LISTEN, LOAD, LOCATION, LOCK_P, + MAXVALUE, MINVALUE, MOVE, NEW, NOCREATEDB, NOCREATEUSER, NONE, NOTHING, NOTIFY, NOTNULL, - OIDS, OPERATOR, PASSWORD, PROCEDURAL, + OFFSET, OIDS, OPERATOR, PASSWORD, PROCEDURAL, RECIPE, RENAME, RESET, RETURNS, ROW, RULE, SEQUENCE, SERIAL, SETOF, SHOW, START, STATEMENT, STDIN, STDOUT, TRUSTED, UNLISTEN, UNTIL, VACUUM, VALID, VERBOSE, VERSION @@ -2731,7 +2736,7 @@ opt_of: OF columnList * * The rule returns a SelectStmt Node having the set operations attached to * unionClause and intersectClause (NIL if no set operations were present) */ -SelectStmt: select_w_o_sort sort_clause for_update_clause +SelectStmt: select_w_o_sort sort_clause for_update_clause opt_select_limit { /* There were no set operations, so just attach the sortClause */ if IsA($1, SelectStmt) @@ -2739,6 +2744,8 @@ SelectStmt: select_w_o_sort sort_clause for_update_clause SelectStmt *n = (SelectStmt *)$1; n->sortClause = $2; n->forUpdate = $3; + n->limitOffset = nth(0, $4); + n->limitCount = nth(1, $4); $$ = (Node *)n; } /* There were set operations: The root of the operator tree @@ -2920,6 +2927,84 @@ OptUseOp: USING Op { $$ = $2; } | /*EMPTY*/ { $$ = "<"; /*default*/ } ; + +opt_select_limit: LIMIT select_limit_value ',' select_offset_value + { $$ = lappend(lappend(NIL, $4), $2); } + | LIMIT select_limit_value OFFSET select_offset_value + { $$ = lappend(lappend(NIL, $4), $2); } + | LIMIT select_limit_value + { $$ = lappend(lappend(NIL, NULL), $2); } + | OFFSET select_offset_value LIMIT select_limit_value + { $$ = lappend(lappend(NIL, $2), $4); } + | OFFSET select_offset_value + { $$ = lappend(lappend(NIL, $2), NULL); } + | /* EMPTY */ + { $$ = lappend(lappend(NIL, NULL), NULL); } + ; + +select_limit_value: Iconst + { + Const *n = makeNode(Const); + + if ($1 < 1) + elog(ERROR, "selection limit must be ALL or a positive integer value > 0"); + + n->consttype = INT4OID; + n->constlen = sizeof(int4); + n->constvalue = (Datum)$1; + n->constisnull = FALSE; + n->constbyval = TRUE; + n->constisset = FALSE; + n->constiscast = FALSE; + $$ = (Node *)n; + } + | ALL + { + Const *n = makeNode(Const); + + n->consttype = INT4OID; + n->constlen = sizeof(int4); + n->constvalue = (Datum)0; + n->constisnull = FALSE; + n->constbyval = TRUE; + n->constisset = FALSE; + n->constiscast = FALSE; + $$ = (Node *)n; + } + | PARAM + { + Param *n = makeNode(Param); + + n->paramkind = PARAM_NUM; + n->paramid = $1; + n->paramtype = INT4OID; + $$ = (Node *)n; + } + ; + +select_offset_value: Iconst + { + Const *n = makeNode(Const); + + n->consttype = INT4OID; + n->constlen = sizeof(int4); + n->constvalue = (Datum)$1; + n->constisnull = FALSE; + n->constbyval = TRUE; + n->constisset = FALSE; + n->constiscast = FALSE; + $$ = (Node *)n; + } + | PARAM + { + Param *n = makeNode(Param); + + n->paramkind = PARAM_NUM; + n->paramid = $1; + n->paramtype = INT4OID; + $$ = (Node *)n; + } + ; /* * jimmy bell-style recursive queries aren't supported in the * current system. diff --git a/src/backend/parser/keywords.c b/src/backend/parser/keywords.c index f1e59781ff3..b9af71dc46b 100644 --- a/src/backend/parser/keywords.c +++ b/src/backend/parser/keywords.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.52 1999/02/02 03:44:42 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.53 1999/02/08 14:14:13 wieck Exp $ * *------------------------------------------------------------------------- */ @@ -68,9 +68,6 @@ static ScanKeyword ScanKeywords[] = { {"createdb", CREATEDB}, {"createuser", CREATEUSER}, {"cross", CROSS}, - {"current", CURRENT}, /* 6.4 to 6.5 is migration time! CURRENT - * will be removed in 6.5! Use OLD keyword - * in rules. Jan */ {"current_date", CURRENT_DATE}, {"current_time", CURRENT_TIME}, {"current_timestamp", CURRENT_TIMESTAMP}, @@ -139,6 +136,7 @@ static ScanKeyword ScanKeywords[] = { {"left", LEFT}, {"level", LEVEL}, {"like", LIKE}, + {"limit", LIMIT}, {"listen", LISTEN}, {"load", LOAD}, {"local", LOCAL}, @@ -168,6 +166,7 @@ static ScanKeyword ScanKeywords[] = { {"nullif", NULLIF}, {"numeric", NUMERIC}, {"of", OF}, + {"offset", OFFSET}, {"oids", OIDS}, {"old", CURRENT}, {"on", ON}, diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c index b20b6f69d32..a1145402d86 100644 --- a/src/backend/rewrite/rewriteDefine.c +++ b/src/backend/rewrite/rewriteDefine.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteDefine.c,v 1.23 1998/10/06 22:14:14 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/rewrite/rewriteDefine.c,v 1.24 1999/02/08 14:14:13 wieck Exp $ * *------------------------------------------------------------------------- */ @@ -312,6 +312,12 @@ DefineQueryRewrite(RuleStmt *stmt) heap_close(event_relation); /* + * 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. */ sprintf(expected_name, "_RET%s", event_obj->relname); diff --git a/src/backend/tcop/pquery.c b/src/backend/tcop/pquery.c index 577a8590779..abe3c31a9cc 100644 --- a/src/backend/tcop/pquery.c +++ b/src/backend/tcop/pquery.c @@ -7,7 +7,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.19 1998/09/02 23:05:34 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.20 1999/02/08 14:14:14 wieck Exp $ * *------------------------------------------------------------------------- */ @@ -40,7 +40,8 @@ #include "commands/command.h" static char *CreateOperationTag(int operationType); -static void ProcessQueryDesc(QueryDesc *queryDesc); +static void ProcessQueryDesc(QueryDesc *queryDesc, Node *limoffset, + Node *limcount); /* ---------------------------------------------------------------- @@ -205,7 +206,7 @@ ProcessPortal(char *portalName, * ---------------------------------------------------------------- */ static void -ProcessQueryDesc(QueryDesc *queryDesc) +ProcessQueryDesc(QueryDesc *queryDesc, Node *limoffset, Node *limcount) { Query *parseTree; Plan *plan; @@ -330,7 +331,7 @@ ProcessQueryDesc(QueryDesc *queryDesc) * actually run the plan.. * ---------------- */ - ExecutorRun(queryDesc, state, EXEC_RUN, 0); + ExecutorRun(queryDesc, state, EXEC_RUN, limoffset, limcount); /* save infos for EndCommand */ UpdateCommandInfo(operation, state->es_lastoid, state->es_processed); @@ -373,5 +374,6 @@ ProcessQuery(Query *parsetree, print_plan(plan, parsetree); } else - ProcessQueryDesc(queryDesc); + ProcessQueryDesc(queryDesc, parsetree->limitOffset, + parsetree->limitCount); } |