From 66888f7424f7d6c7cea2c26e181054d1455d4e7a Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 16 Apr 2007 01:14:58 +0000 Subject: [PATCH] Expose more cursor-related functionality in SPI: specifically, allow access to the planner's cursor-related planning options, and provide new FETCH/MOVE routines that allow access to the full power of those commands. Small refactoring of planner(), pg_plan_query(), and pg_plan_queries() APIs to make it convenient to pass the planning options down from SPI. This is the core-code portion of Pavel Stehule's patch for scrollable cursor support in plpgsql; I'll review and apply the plpgsql changes separately. --- doc/src/sgml/spi.sgml | 322 ++++++++++++++++++++++++++- src/backend/commands/copy.c | 4 +- src/backend/commands/explain.c | 12 +- src/backend/commands/portalcmds.c | 4 +- src/backend/commands/prepare.c | 4 +- src/backend/executor/functions.c | 4 +- src/backend/executor/spi.c | 63 +++++- src/backend/optimizer/plan/planner.c | 9 +- src/backend/parser/gram.y | 17 +- src/backend/tcop/postgres.c | 21 +- src/backend/utils/cache/plancache.c | 9 +- src/include/executor/spi.h | 11 +- src/include/nodes/parsenodes.h | 13 +- src/include/optimizer/planner.h | 4 +- src/include/tcop/tcopprot.h | 9 +- 15 files changed, 435 insertions(+), 71 deletions(-) diff --git a/doc/src/sgml/spi.sgml b/doc/src/sgml/spi.sgml index 14e975b5fc..7ee47162cd 100644 --- a/doc/src/sgml/spi.sgml +++ b/doc/src/sgml/spi.sgml @@ -1,4 +1,4 @@ - + Server Programming Interface @@ -799,6 +799,104 @@ SPIPlanPtr SPI_prepare(const char * command, int + + + SPI_prepare_cursor + + + + SPI_prepare_cursor + prepare a plan for a command, without executing it yet + + + SPI_prepare_cursor + + + +SPIPlanPtr SPI_prepare_cursor(const char * command, int nargs, Oid * argtypes, int cursorOptions) + + + + + Description + + + SPI_prepare_cursor is identical to + SPI_prepare, except that it also allows specification + of the planner's cursor options parameter. This is a bitmask + having the values shown in nodes/parsenodes.h + for the options field of DeclareCursorStmt. + SPI_prepare always takes these options as zero. + + + + + Arguments + + + + const char * command + + + command string + + + + + + int nargs + + + number of input parameters ($1, $2, etc.) + + + + + + Oid * argtypes + + + pointer to an array containing the OIDs of + the data types of the parameters + + + + + + int cursorOptions + + + integer bitmask of cursor options; zero produces default behavior + + + + + + + + Return Value + + + SPI_prepare_cursor has the same return conventions as + SPI_prepare. + + + + + Notes + + + Useful bits to set in cursorOptions include + CURSOR_OPT_SCROLL, + CURSOR_OPT_NO_SCROLL, and + CURSOR_OPT_FAST_PLAN. Note in particular that + CURSOR_OPT_HOLD is ignored. + + + + + + SPI_getargcount @@ -1430,7 +1528,9 @@ void SPI_cursor_fetch(Portal portal, bool forw SPI_cursor_fetch fetches some rows from a - cursor. This is equivalent to the SQL command FETCH. + cursor. This is equivalent to a subset of the SQL command + FETCH (see SPI_scroll_cursor_fetch + for more functionality). @@ -1476,6 +1576,15 @@ void SPI_cursor_fetch(Portal portal, bool forw SPI_execute if successful. + + + Notes + + + Fetching backward may fail if the cursor's plan was not created + with the CURSOR_OPT_SCROLL option. + + @@ -1503,8 +1612,9 @@ void SPI_cursor_move(Portal portal, bool forwa SPI_cursor_move skips over some number of rows - in a cursor. This is equivalent to the SQL command - MOVE. + in a cursor. This is equivalent to a subset of the SQL command + MOVE (see SPI_scroll_cursor_move + for more functionality). @@ -1540,6 +1650,210 @@ void SPI_cursor_move(Portal portal, bool forwa + + + Notes + + + Moving backward may fail if the cursor's plan was not created + with the CURSOR_OPT_SCROLL option. + + + + + + + + + SPI_scroll_cursor_fetch + + + + SPI_scroll_cursor_fetch + fetch some rows from a cursor + + + SPI_scroll_cursor_fetch + + + +void SPI_scroll_cursor_fetch(Portal portal, FetchDirection direction, long count) + + + + + Description + + + SPI_scroll_cursor_fetch fetches some rows from a + cursor. This is equivalent to the SQL command FETCH. + + + + + Arguments + + + + Portal portal + + + portal containing the cursor + + + + + + FetchDirection direction + + + one of FETCH_FORWARD, + FETCH_BACKWARD, + FETCH_ABSOLUTE or + FETCH_RELATIVE + + + + + + long count + + + number of rows to fetch for + FETCH_FORWARD or + FETCH_BACKWARD; absolute row number to fetch for + FETCH_ABSOLUTE; or relative row number to fetch for + FETCH_RELATIVE + + + + + + + + Return Value + + + SPI_processed and + SPI_tuptable are set as in + SPI_execute if successful. + + + + + Notes + + + See the SQL command + for details of the interpretation of the + direction and + count parameters. + + + + Direction values other than FETCH_FORWARD + may fail if the cursor's plan was not created + with the CURSOR_OPT_SCROLL option. + + + + + + + + + SPI_scroll_cursor_move + + + + SPI_scroll_cursor_move + move a cursor + + + SPI_scroll_cursor_move + + + +void SPI_scroll_cursor_move(Portal portal, FetchDirection direction, long count) + + + + + Description + + + SPI_scroll_cursor_move skips over some number of rows + in a cursor. This is equivalent to the SQL command + MOVE. + + + + + Arguments + + + + Portal portal + + + portal containing the cursor + + + + + + FetchDirection direction + + + one of FETCH_FORWARD, + FETCH_BACKWARD, + FETCH_ABSOLUTE or + FETCH_RELATIVE + + + + + + long count + + + number of rows to move for + FETCH_FORWARD or + FETCH_BACKWARD; absolute row number to move to for + FETCH_ABSOLUTE; or relative row number to move to for + FETCH_RELATIVE + + + + + + + + Return Value + + + SPI_processed and + SPI_tuptable are set as in + SPI_execute if successful. + + + + + Notes + + + See the SQL command + for details of the interpretation of the + direction and + count parameters. + + + + Direction values other than FETCH_FORWARD + may fail if the cursor's plan was not created + with the CURSOR_OPT_SCROLL option. + + diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index 99d347f590..42121f3fe4 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/copy.c,v 1.279 2007/03/29 00:15:38 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/copy.c,v 1.280 2007/04/16 01:14:55 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1023,7 +1023,7 @@ DoCopy(const CopyStmt *stmt, const char *queryString) errmsg("COPY (SELECT INTO) is not supported"))); /* plan the query */ - plan = planner(query, false, 0, NULL); + plan = planner(query, 0, NULL); /* * Update snapshot command ID to ensure this query sees results of any diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c index 1b2cfccce9..bb7d430359 100644 --- a/src/backend/commands/explain.c +++ b/src/backend/commands/explain.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994-5, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.160 2007/03/13 00:33:39 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.161 2007/04/16 01:14:55 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -42,7 +42,7 @@ typedef struct ExplainState List *rtable; /* range table */ } ExplainState; -static void ExplainOneQuery(Query *query, bool isCursor, int cursorOptions, +static void ExplainOneQuery(Query *query, int cursorOptions, ExplainStmt *stmt, const char *queryString, ParamListInfo params, TupOutputState *tstate); static double elapsed_time(instr_time *starttime); @@ -102,7 +102,7 @@ ExplainQuery(ExplainStmt *stmt, const char *queryString, /* Explain every plan */ foreach(l, rewritten) { - ExplainOneQuery((Query *) lfirst(l), false, 0, + ExplainOneQuery((Query *) lfirst(l), 0, stmt, queryString, params, tstate); /* put a blank line between plans */ if (lnext(l) != NULL) @@ -134,7 +134,7 @@ ExplainResultDesc(ExplainStmt *stmt) * print out the execution plan for one Query */ static void -ExplainOneQuery(Query *query, bool isCursor, int cursorOptions, +ExplainOneQuery(Query *query, int cursorOptions, ExplainStmt *stmt, const char *queryString, ParamListInfo params, TupOutputState *tstate) { @@ -150,7 +150,7 @@ ExplainOneQuery(Query *query, bool isCursor, int cursorOptions, } /* plan the query */ - plan = planner(query, isCursor, cursorOptions, params); + plan = planner(query, cursorOptions, params); /* * Update snapshot command ID to ensure this query sees results of any @@ -229,7 +229,7 @@ ExplainOneUtility(Node *utilityStmt, ExplainStmt *stmt, /* do not actually execute the underlying query! */ memcpy(&newstmt, stmt, sizeof(ExplainStmt)); newstmt.analyze = false; - ExplainOneQuery(query, true, dcstmt->options, &newstmt, + ExplainOneQuery(query, dcstmt->options, &newstmt, queryString, params, tstate); } else if (IsA(utilityStmt, ExecuteStmt)) diff --git a/src/backend/commands/portalcmds.c b/src/backend/commands/portalcmds.c index d759ed4ac2..eb381ebb70 100644 --- a/src/backend/commands/portalcmds.c +++ b/src/backend/commands/portalcmds.c @@ -14,7 +14,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/portalcmds.c,v 1.63 2007/04/12 06:53:46 neilc Exp $ + * $PostgreSQL: pgsql/src/backend/commands/portalcmds.c,v 1.64 2007/04/16 01:14:55 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -111,7 +111,7 @@ PerformCursorOpen(DeclareCursorStmt *stmt, ParamListInfo params, errdetail("Cursors must be READ ONLY."))); /* plan the query */ - plan = planner(query, true, stmt->options, params); + plan = planner(query, stmt->options, params); /* * Create a portal and copy the plan into its memory context. diff --git a/src/backend/commands/prepare.c b/src/backend/commands/prepare.c index fe1a8532f0..9a4f88d1a0 100644 --- a/src/backend/commands/prepare.c +++ b/src/backend/commands/prepare.c @@ -10,7 +10,7 @@ * Copyright (c) 2002-2007, PostgreSQL Global Development Group * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.71 2007/04/12 06:53:46 neilc Exp $ + * $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.72 2007/04/16 01:14:55 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -160,7 +160,7 @@ PrepareQuery(PrepareStmt *stmt, const char *queryString) query_list = QueryRewrite(query); /* Generate plans for queries. Snapshot is already set. */ - plan_list = pg_plan_queries(query_list, NULL, false); + plan_list = pg_plan_queries(query_list, 0, NULL, false); /* * Save the results. diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c index 1e1d450be5..b59228b0c9 100644 --- a/src/backend/executor/functions.c +++ b/src/backend/executor/functions.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/functions.c,v 1.114 2007/04/02 18:49:29 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/executor/functions.c,v 1.115 2007/04/16 01:14:56 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -115,7 +115,7 @@ init_execution_state(List *queryTree_list, bool readonly_func) if (queryTree->commandType == CMD_UTILITY) stmt = queryTree->utilityStmt; else - stmt = (Node *) pg_plan_query(queryTree, NULL); + stmt = (Node *) pg_plan_query(queryTree, 0, NULL); /* Precheck all commands for validity in a function */ if (IsA(stmt, TransactionStmt)) diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c index 655503cd70..bf3bbdbceb 100644 --- a/src/backend/executor/spi.c +++ b/src/backend/executor/spi.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.175 2007/03/25 23:42:43 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.176 2007/04/16 01:14:56 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -34,7 +34,8 @@ static int _SPI_stack_depth = 0; /* allocated size of _SPI_stack */ static int _SPI_connected = -1; static int _SPI_curid = -1; -static void _SPI_prepare_plan(const char *src, SPIPlanPtr plan); +static void _SPI_prepare_plan(const char *src, SPIPlanPtr plan, + int cursorOptions); static int _SPI_execute_plan(SPIPlanPtr plan, Datum *Values, const char *Nulls, @@ -45,8 +46,9 @@ static int _SPI_pquery(QueryDesc *queryDesc, long tcount); static void _SPI_error_callback(void *arg); -static void _SPI_cursor_operation(Portal portal, bool forward, long count, - DestReceiver *dest); +static void _SPI_cursor_operation(Portal portal, + FetchDirection direction, long count, + DestReceiver *dest); static SPIPlanPtr _SPI_copy_plan(SPIPlanPtr plan, MemoryContext parentcxt); static SPIPlanPtr _SPI_save_plan(SPIPlanPtr plan); @@ -310,7 +312,7 @@ SPI_execute(const char *src, bool read_only, long tcount) memset(&plan, 0, sizeof(_SPI_plan)); plan.magic = _SPI_PLAN_MAGIC; - _SPI_prepare_plan(src, &plan); + _SPI_prepare_plan(src, &plan, 0); res = _SPI_execute_plan(&plan, NULL, NULL, InvalidSnapshot, InvalidSnapshot, @@ -398,6 +400,13 @@ SPI_execute_snapshot(SPIPlanPtr plan, SPIPlanPtr SPI_prepare(const char *src, int nargs, Oid *argtypes) +{ + return SPI_prepare_cursor(src, nargs, argtypes, 0); +} + +SPIPlanPtr +SPI_prepare_cursor(const char *src, int nargs, Oid *argtypes, + int cursorOptions) { _SPI_plan plan; SPIPlanPtr result; @@ -417,7 +426,7 @@ SPI_prepare(const char *src, int nargs, Oid *argtypes) plan.nargs = nargs; plan.argtypes = argtypes; - _SPI_prepare_plan(src, &plan); + _SPI_prepare_plan(src, &plan, cursorOptions); /* copy plan to procedure context */ result = _SPI_copy_plan(&plan, _SPI_current->procCxt); @@ -1032,7 +1041,8 @@ SPI_cursor_find(const char *name) void SPI_cursor_fetch(Portal portal, bool forward, long count) { - _SPI_cursor_operation(portal, forward, count, + _SPI_cursor_operation(portal, + forward ? FETCH_FORWARD : FETCH_BACKWARD, count, CreateDestReceiver(DestSPI, NULL)); /* we know that the DestSPI receiver doesn't need a destroy call */ } @@ -1046,7 +1056,36 @@ SPI_cursor_fetch(Portal portal, bool forward, long count) void SPI_cursor_move(Portal portal, bool forward, long count) { - _SPI_cursor_operation(portal, forward, count, None_Receiver); + _SPI_cursor_operation(portal, + forward ? FETCH_FORWARD : FETCH_BACKWARD, count, + None_Receiver); +} + + +/* + * SPI_scroll_cursor_fetch() + * + * Fetch rows in a scrollable cursor + */ +void +SPI_scroll_cursor_fetch(Portal portal, FetchDirection direction, long count) +{ + _SPI_cursor_operation(portal, + direction, count, + CreateDestReceiver(DestSPI, NULL)); + /* we know that the DestSPI receiver doesn't need a destroy call */ +} + + +/* + * SPI_scroll_cursor_move() + * + * Move in a scrollable cursor + */ +void +SPI_scroll_cursor_move(Portal portal, FetchDirection direction, long count) +{ + _SPI_cursor_operation(portal, direction, count, None_Receiver); } @@ -1299,7 +1338,7 @@ spi_printtup(TupleTableSlot *slot, DestReceiver *self) * and need to be copied somewhere to survive. */ static void -_SPI_prepare_plan(const char *src, SPIPlanPtr plan) +_SPI_prepare_plan(const char *src, SPIPlanPtr plan, int cursorOptions) { List *raw_parsetree_list; List *plancache_list; @@ -1345,7 +1384,7 @@ _SPI_prepare_plan(const char *src, SPIPlanPtr plan) /* Need a copyObject here to keep parser from modifying raw tree */ stmt_list = pg_analyze_and_rewrite(copyObject(parsetree), src, argtypes, nargs); - stmt_list = pg_plan_queries(stmt_list, NULL, false); + stmt_list = pg_plan_queries(stmt_list, cursorOptions, NULL, false); plansource = (CachedPlanSource *) palloc0(sizeof(CachedPlanSource)); cplan = (CachedPlan *) palloc0(sizeof(CachedPlan)); @@ -1739,7 +1778,7 @@ _SPI_error_callback(void *arg) * Do a FETCH or MOVE in a cursor */ static void -_SPI_cursor_operation(Portal portal, bool forward, long count, +_SPI_cursor_operation(Portal portal, FetchDirection direction, long count, DestReceiver *dest) { long nfetched; @@ -1760,7 +1799,7 @@ _SPI_cursor_operation(Portal portal, bool forward, long count, /* Run the cursor */ nfetched = PortalRunFetch(portal, - forward ? FETCH_FORWARD : FETCH_BACKWARD, + direction, count, dest); diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 9bf5516ca4..5c65a78d6f 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.216 2007/02/27 01:11:25 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.217 2007/04/16 01:14:56 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -80,8 +80,7 @@ static List *postprocess_setop_tlist(List *new_tlist, List *orig_tlist); * *****************************************************************************/ PlannedStmt * -planner(Query *parse, bool isCursor, int cursorOptions, - ParamListInfo boundParams) +planner(Query *parse, int cursorOptions, ParamListInfo boundParams) { PlannedStmt *result; PlannerGlobal *glob; @@ -107,7 +106,7 @@ planner(Query *parse, bool isCursor, int cursorOptions, glob->finalrtable = NIL; /* Determine what fraction of the plan is likely to be scanned */ - if (isCursor) + if (cursorOptions & CURSOR_OPT_FAST_PLAN) { /* * We have no real idea how many tuples the user will ultimately FETCH @@ -130,7 +129,7 @@ planner(Query *parse, bool isCursor, int cursorOptions, * If creating a plan for a scrollable cursor, make sure it can run * backwards on demand. Add a Material node at the top at need. */ - if (isCursor && (cursorOptions & CURSOR_OPT_SCROLL)) + if (cursorOptions & CURSOR_OPT_SCROLL) { if (!ExecSupportsBackwardScan(top_plan)) top_plan = materialize_finished_plan(top_plan); diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 6aa81eec3e..b9728deaad 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -11,7 +11,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.588 2007/04/12 06:53:46 neilc Exp $ + * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.589 2007/04/16 01:14:56 tgl Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -279,9 +279,9 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args) %type opt_freeze opt_default opt_recheck %type opt_binary opt_oids copy_delimiter -%type copy_from opt_hold +%type copy_from -%type opt_column event cursor_options +%type opt_column event cursor_options opt_hold %type reindex_type drop_type comment_type %type fetch_direction select_limit_value select_offset_value @@ -5821,10 +5821,9 @@ DeclareCursorStmt: DECLARE name cursor_options CURSOR opt_hold FOR SelectStmt { DeclareCursorStmt *n = makeNode(DeclareCursorStmt); n->portalname = $2; - n->options = $3; + /* currently we always set FAST_PLAN option */ + n->options = $3 | $5 | CURSOR_OPT_FAST_PLAN; n->query = $7; - if ($5) - n->options |= CURSOR_OPT_HOLD; $$ = (Node *)n; } ; @@ -5836,9 +5835,9 @@ cursor_options: /*EMPTY*/ { $$ = 0; } | cursor_options INSENSITIVE { $$ = $1 | CURSOR_OPT_INSENSITIVE; } ; -opt_hold: /* EMPTY */ { $$ = FALSE; } - | WITH HOLD { $$ = TRUE; } - | WITHOUT HOLD { $$ = FALSE; } +opt_hold: /* EMPTY */ { $$ = 0; } + | WITH HOLD { $$ = CURSOR_OPT_HOLD; } + | WITHOUT HOLD { $$ = 0; } ; /***************************************************************************** diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index bfcc271996..7722eddf34 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.530 2007/03/29 19:10:10 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.531 2007/04/16 01:14:57 tgl Exp $ * * NOTES * this is the "main" module of the postgres backend and @@ -656,9 +656,12 @@ pg_rewrite_queries(List *querytree_list) } -/* Generate a plan for a single already-rewritten query. */ +/* + * Generate a plan for a single already-rewritten query. + * This is a thin wrapper around planner() and takes the same parameters. + */ PlannedStmt * -pg_plan_query(Query *querytree, ParamListInfo boundParams) +pg_plan_query(Query *querytree, int cursorOptions, ParamListInfo boundParams) { PlannedStmt *plan; @@ -670,7 +673,7 @@ pg_plan_query(Query *querytree, ParamListInfo boundParams) ResetUsage(); /* call the optimizer */ - plan = planner(querytree, false, 0, boundParams); + plan = planner(querytree, cursorOptions, boundParams); if (log_planner_stats) ShowUsage("PLANNER STATISTICS"); @@ -718,7 +721,7 @@ pg_plan_query(Query *querytree, ParamListInfo boundParams) * list. Utility statements are simply represented by their statement nodes. */ List * -pg_plan_queries(List *querytrees, ParamListInfo boundParams, +pg_plan_queries(List *querytrees, int cursorOptions, ParamListInfo boundParams, bool needSnapshot) { List *stmt_list = NIL; @@ -741,7 +744,7 @@ pg_plan_queries(List *querytrees, ParamListInfo boundParams, ActiveSnapshot = CopySnapshot(GetTransactionSnapshot()); needSnapshot = false; } - stmt = (Node *) pg_plan_query(query, boundParams); + stmt = (Node *) pg_plan_query(query, cursorOptions, boundParams); } stmt_list = lappend(stmt_list, stmt); @@ -892,7 +895,7 @@ exec_simple_query(const char *query_string) querytree_list = pg_analyze_and_rewrite(parsetree, query_string, NULL, 0); - plantree_list = pg_plan_queries(querytree_list, NULL, true); + plantree_list = pg_plan_queries(querytree_list, 0, NULL, true); /* If we got a cancel signal in analysis or planning, quit */ CHECK_FOR_INTERRUPTS(); @@ -1207,7 +1210,7 @@ exec_parse_message(const char *query_string, /* string to execute */ } else { - stmt_list = pg_plan_queries(querytree_list, NULL, true); + stmt_list = pg_plan_queries(querytree_list, 0, NULL, true); fully_planned = true; } } @@ -1621,7 +1624,7 @@ exec_bind_message(StringInfo input_message) */ oldContext = MemoryContextSwitchTo(PortalGetHeapMemory(portal)); query_list = copyObject(cplan->stmt_list); - plan_list = pg_plan_queries(query_list, params, true); + plan_list = pg_plan_queries(query_list, 0, params, true); MemoryContextSwitchTo(oldContext); /* We no longer need the cached plan refcount ... */ diff --git a/src/backend/utils/cache/plancache.c b/src/backend/utils/cache/plancache.c index 6165e59c6e..28838eba09 100644 --- a/src/backend/utils/cache/plancache.c +++ b/src/backend/utils/cache/plancache.c @@ -33,7 +33,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/cache/plancache.c,v 1.6 2007/04/12 06:53:47 neilc Exp $ + * $PostgreSQL: pgsql/src/backend/utils/cache/plancache.c,v 1.7 2007/04/16 01:14:57 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -458,10 +458,13 @@ RevalidateCachedPlan(CachedPlanSource *plansource, bool useResOwner) if (plansource->fully_planned) { /* - * Generate plans for queries. Assume snapshot is not set yet + * Generate plans for queries. We don't need any boundParams, and + * currently we don't need to worry about cursor options because + * cursor plans are never saved in the plancache (that might have + * to change someday). Also, assume snapshot is not set yet * (XXX this may be wasteful, won't all callers have done that?) */ - slist = pg_plan_queries(slist, NULL, true); + slist = pg_plan_queries(slist, 0, NULL, true); } /* diff --git a/src/include/executor/spi.h b/src/include/executor/spi.h index 80c8993c7c..c996f644c0 100644 --- a/src/include/executor/spi.h +++ b/src/include/executor/spi.h @@ -6,7 +6,7 @@ * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/executor/spi.h,v 1.60 2007/03/25 23:27:59 tgl Exp $ + * $PostgreSQL: pgsql/src/include/executor/spi.h,v 1.61 2007/04/16 01:14:57 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -20,8 +20,8 @@ #include "postgres.h" /* - * These are not needed by this file, but used by other programs - * using SPI + * Most of these are not needed by this file, but may be used by + * user-written code that uses SPI */ #include "access/heapam.h" #include "access/xact.h" @@ -32,6 +32,7 @@ #include "executor/executor.h" #include "nodes/execnodes.h" #include "nodes/params.h" +#include "nodes/parsenodes.h" #include "nodes/plannodes.h" #include "nodes/primnodes.h" #include "nodes/relation.h" @@ -105,6 +106,8 @@ extern int SPI_execute_snapshot(SPIPlanPtr plan, Snapshot crosscheck_snapshot, bool read_only, long tcount); extern SPIPlanPtr SPI_prepare(const char *src, int nargs, Oid *argtypes); +extern SPIPlanPtr SPI_prepare_cursor(const char *src, int nargs, Oid *argtypes, + int cursorOptions); extern SPIPlanPtr SPI_saveplan(SPIPlanPtr plan); extern int SPI_freeplan(SPIPlanPtr plan); @@ -136,6 +139,8 @@ extern Portal SPI_cursor_open(const char *name, SPIPlanPtr plan, extern Portal SPI_cursor_find(const char *name); extern void SPI_cursor_fetch(Portal portal, bool forward, long count); extern void SPI_cursor_move(Portal portal, bool forward, long count); +extern void SPI_scroll_cursor_fetch(Portal, FetchDirection direction, long count); +extern void SPI_scroll_cursor_move(Portal, FetchDirection direction, long count); extern void SPI_cursor_close(Portal portal); extern void AtEOXact_SPI(bool isCommit); diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index bc421e265f..dbc29642f0 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.345 2007/04/12 06:53:48 neilc Exp $ + * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.346 2007/04/16 01:14:57 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1429,11 +1429,12 @@ typedef struct CommentStmt * Declare Cursor Statement * ---------------------- */ -#define CURSOR_OPT_BINARY 0x0001 -#define CURSOR_OPT_SCROLL 0x0002 -#define CURSOR_OPT_NO_SCROLL 0x0004 -#define CURSOR_OPT_INSENSITIVE 0x0008 -#define CURSOR_OPT_HOLD 0x0010 +#define CURSOR_OPT_BINARY 0x0001 /* BINARY */ +#define CURSOR_OPT_SCROLL 0x0002 /* SCROLL explicitly given */ +#define CURSOR_OPT_NO_SCROLL 0x0004 /* NO SCROLL explicitly given */ +#define CURSOR_OPT_INSENSITIVE 0x0008 /* INSENSITIVE (unimplemented) */ +#define CURSOR_OPT_HOLD 0x0010 /* WITH HOLD */ +#define CURSOR_OPT_FAST_PLAN 0x0020 /* prefer fast-start plan */ typedef struct DeclareCursorStmt { diff --git a/src/include/optimizer/planner.h b/src/include/optimizer/planner.h index c243cdbc35..b568a7dbe8 100644 --- a/src/include/optimizer/planner.h +++ b/src/include/optimizer/planner.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/optimizer/planner.h,v 1.38 2007/02/20 17:32:17 tgl Exp $ + * $PostgreSQL: pgsql/src/include/optimizer/planner.h,v 1.39 2007/04/16 01:14:58 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -18,7 +18,7 @@ #include "nodes/relation.h" -extern PlannedStmt *planner(Query *parse, bool isCursor, int cursorOptions, +extern PlannedStmt *planner(Query *parse, int cursorOptions, ParamListInfo boundParams); extern Plan *subquery_planner(PlannerGlobal *glob, Query *parse, Index level, double tuple_fraction, diff --git a/src/include/tcop/tcopprot.h b/src/include/tcop/tcopprot.h index 098cb1da1e..613d9a9983 100644 --- a/src/include/tcop/tcopprot.h +++ b/src/include/tcop/tcopprot.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/tcop/tcopprot.h,v 1.88 2007/03/07 13:35:03 alvherre Exp $ + * $PostgreSQL: pgsql/src/include/tcop/tcopprot.h,v 1.89 2007/04/16 01:14:58 tgl Exp $ * * OLD COMMENTS * This file was created so that other c files could get the two @@ -49,9 +49,10 @@ extern List *pg_parse_and_rewrite(const char *query_string, extern List *pg_parse_query(const char *query_string); extern List *pg_analyze_and_rewrite(Node *parsetree, const char *query_string, Oid *paramTypes, int numParams); -extern PlannedStmt *pg_plan_query(Query *querytree, ParamListInfo boundParams); -extern List *pg_plan_queries(List *querytrees, ParamListInfo boundParams, - bool needSnapshot); +extern PlannedStmt *pg_plan_query(Query *querytree, int cursorOptions, + ParamListInfo boundParams); +extern List *pg_plan_queries(List *querytrees, int cursorOptions, + ParamListInfo boundParams, bool needSnapshot); extern bool assign_max_stack_depth(int newval, bool doit, GucSource source);