-<!-- $PostgreSQL: pgsql/doc/src/sgml/spi.sgml,v 1.55 2007/03/25 23:27:59 tgl Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/spi.sgml,v 1.56 2007/04/16 01:14:55 tgl Exp $ -->
<chapter id="spi">
<title>Server Programming Interface</title>
<!-- *********************************************** -->
+<refentry id="spi-spi-prepare-cursor">
+ <refmeta>
+ <refentrytitle>SPI_prepare_cursor</refentrytitle>
+ </refmeta>
+
+ <refnamediv>
+ <refname>SPI_prepare_cursor</refname>
+ <refpurpose>prepare a plan for a command, without executing it yet</refpurpose>
+ </refnamediv>
+
+ <indexterm><primary>SPI_prepare_cursor</primary></indexterm>
+
+ <refsynopsisdiv>
+<synopsis>
+SPIPlanPtr SPI_prepare_cursor(const char * <parameter>command</parameter>, int <parameter>nargs</parameter>, Oid * <parameter>argtypes</parameter>, int <parameter>cursorOptions</parameter>)
+</synopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para>
+ <function>SPI_prepare_cursor</function> is identical to
+ <function>SPI_prepare</function>, except that it also allows specification
+ of the planner's <quote>cursor options</> parameter. This is a bitmask
+ having the values shown in <filename>nodes/parsenodes.h</filename>
+ for the <structfield>options</> field of <structname>DeclareCursorStmt</>.
+ <function>SPI_prepare</function> always takes these options as zero.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>Arguments</title>
+
+ <variablelist>
+ <varlistentry>
+ <term><literal>const char * <parameter>command</parameter></literal></term>
+ <listitem>
+ <para>
+ command string
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>int <parameter>nargs</parameter></literal></term>
+ <listitem>
+ <para>
+ number of input parameters (<literal>$1</>, <literal>$2</>, etc.)
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>Oid * <parameter>argtypes</parameter></literal></term>
+ <listitem>
+ <para>
+ pointer to an array containing the <acronym>OID</acronym>s of
+ the data types of the parameters
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>int <parameter>cursorOptions</parameter></literal></term>
+ <listitem>
+ <para>
+ integer bitmask of cursor options; zero produces default behavior
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Return Value</title>
+
+ <para>
+ <function>SPI_prepare_cursor</function> has the same return conventions as
+ <function>SPI_prepare</function>.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>Notes</title>
+
+ <para>
+ Useful bits to set in <parameter>cursorOptions</> include
+ <symbol>CURSOR_OPT_SCROLL</symbol>,
+ <symbol>CURSOR_OPT_NO_SCROLL</symbol>, and
+ <symbol>CURSOR_OPT_FAST_PLAN</symbol>. Note in particular that
+ <symbol>CURSOR_OPT_HOLD</symbol> is ignored.
+ </para>
+ </refsect1>
+</refentry>
+
+<!-- *********************************************** -->
+
<refentry id="spi-spi-getargcount">
<refmeta>
<refentrytitle>SPI_getargcount</refentrytitle>
<para>
<function>SPI_cursor_fetch</function> fetches some rows from a
- cursor. This is equivalent to the SQL command <command>FETCH</>.
+ cursor. This is equivalent to a subset of the SQL command
+ <command>FETCH</> (see <function>SPI_scroll_cursor_fetch</function>
+ for more functionality).
</para>
</refsect1>
<function>SPI_execute</function> if successful.
</para>
</refsect1>
+
+ <refsect1>
+ <title>Notes</title>
+
+ <para>
+ Fetching backward may fail if the cursor's plan was not created
+ with the <symbol>CURSOR_OPT_SCROLL</symbol> option.
+ </para>
+ </refsect1>
</refentry>
<!-- *********************************************** -->
<para>
<function>SPI_cursor_move</function> skips over some number of rows
- in a cursor. This is equivalent to the SQL command
- <command>MOVE</>.
+ in a cursor. This is equivalent to a subset of the SQL command
+ <command>MOVE</> (see <function>SPI_scroll_cursor_move</function>
+ for more functionality).
</para>
</refsect1>
</varlistentry>
</variablelist>
</refsect1>
+
+ <refsect1>
+ <title>Notes</title>
+
+ <para>
+ Moving backward may fail if the cursor's plan was not created
+ with the <symbol>CURSOR_OPT_SCROLL</symbol> option.
+ </para>
+ </refsect1>
+</refentry>
+
+<!-- *********************************************** -->
+
+<refentry id="spi-spi-scroll-cursor-fetch">
+ <refmeta>
+ <refentrytitle>SPI_scroll_cursor_fetch</refentrytitle>
+ </refmeta>
+
+ <refnamediv>
+ <refname>SPI_scroll_cursor_fetch</refname>
+ <refpurpose>fetch some rows from a cursor</refpurpose>
+ </refnamediv>
+
+ <indexterm><primary>SPI_scroll_cursor_fetch</primary></indexterm>
+
+ <refsynopsisdiv>
+<synopsis>
+void SPI_scroll_cursor_fetch(Portal <parameter>portal</parameter>, FetchDirection <parameter>direction</parameter>, long <parameter>count</parameter>)
+</synopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para>
+ <function>SPI_scroll_cursor_fetch</function> fetches some rows from a
+ cursor. This is equivalent to the SQL command <command>FETCH</>.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>Arguments</title>
+
+ <variablelist>
+ <varlistentry>
+ <term><literal>Portal <parameter>portal</parameter></literal></term>
+ <listitem>
+ <para>
+ portal containing the cursor
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>FetchDirection <parameter>direction</parameter></literal></term>
+ <listitem>
+ <para>
+ one of <symbol>FETCH_FORWARD</symbol>,
+ <symbol>FETCH_BACKWARD</symbol>,
+ <symbol>FETCH_ABSOLUTE</symbol> or
+ <symbol>FETCH_RELATIVE</symbol>
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>long <parameter>count</parameter></literal></term>
+ <listitem>
+ <para>
+ number of rows to fetch for
+ <symbol>FETCH_FORWARD</symbol> or
+ <symbol>FETCH_BACKWARD</symbol>; absolute row number to fetch for
+ <symbol>FETCH_ABSOLUTE</symbol>; or relative row number to fetch for
+ <symbol>FETCH_RELATIVE</symbol>
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Return Value</title>
+
+ <para>
+ <varname>SPI_processed</varname> and
+ <varname>SPI_tuptable</varname> are set as in
+ <function>SPI_execute</function> if successful.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>Notes</title>
+
+ <para>
+ See the SQL <xref linkend="sql-fetch" endterm="sql-fetch-title"> command
+ for details of the interpretation of the
+ <parameter>direction</parameter> and
+ <parameter>count</parameter> parameters.
+ </para>
+
+ <para>
+ Direction values other than <symbol>FETCH_FORWARD</symbol>
+ may fail if the cursor's plan was not created
+ with the <symbol>CURSOR_OPT_SCROLL</symbol> option.
+ </para>
+ </refsect1>
+</refentry>
+
+<!-- *********************************************** -->
+
+<refentry id="spi-spi-scroll-cursor-move">
+ <refmeta>
+ <refentrytitle>SPI_scroll_cursor_move</refentrytitle>
+ </refmeta>
+
+ <refnamediv>
+ <refname>SPI_scroll_cursor_move</refname>
+ <refpurpose>move a cursor</refpurpose>
+ </refnamediv>
+
+ <indexterm><primary>SPI_scroll_cursor_move</primary></indexterm>
+
+ <refsynopsisdiv>
+<synopsis>
+void SPI_scroll_cursor_move(Portal <parameter>portal</parameter>, FetchDirection <parameter>direction</parameter>, long <parameter>count</parameter>)
+</synopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para>
+ <function>SPI_scroll_cursor_move</function> skips over some number of rows
+ in a cursor. This is equivalent to the SQL command
+ <command>MOVE</>.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>Arguments</title>
+
+ <variablelist>
+ <varlistentry>
+ <term><literal>Portal <parameter>portal</parameter></literal></term>
+ <listitem>
+ <para>
+ portal containing the cursor
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>FetchDirection <parameter>direction</parameter></literal></term>
+ <listitem>
+ <para>
+ one of <symbol>FETCH_FORWARD</symbol>,
+ <symbol>FETCH_BACKWARD</symbol>,
+ <symbol>FETCH_ABSOLUTE</symbol> or
+ <symbol>FETCH_RELATIVE</symbol>
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>long <parameter>count</parameter></literal></term>
+ <listitem>
+ <para>
+ number of rows to move for
+ <symbol>FETCH_FORWARD</symbol> or
+ <symbol>FETCH_BACKWARD</symbol>; absolute row number to move to for
+ <symbol>FETCH_ABSOLUTE</symbol>; or relative row number to move to for
+ <symbol>FETCH_RELATIVE</symbol>
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Return Value</title>
+
+ <para>
+ <varname>SPI_processed</varname> and
+ <varname>SPI_tuptable</varname> are set as in
+ <function>SPI_execute</function> if successful.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>Notes</title>
+
+ <para>
+ See the SQL <xref linkend="sql-fetch" endterm="sql-fetch-title"> command
+ for details of the interpretation of the
+ <parameter>direction</parameter> and
+ <parameter>count</parameter> parameters.
+ </para>
+
+ <para>
+ Direction values other than <symbol>FETCH_FORWARD</symbol>
+ may fail if the cursor's plan was not created
+ with the <symbol>CURSOR_OPT_SCROLL</symbol> option.
+ </para>
+ </refsect1>
</refentry>
<!-- *********************************************** -->
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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
* 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 $
*
*-------------------------------------------------------------------------
*/
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);
/* 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)
* 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)
{
}
/* 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
/* 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))
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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.
* 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 $
*
*-------------------------------------------------------------------------
*/
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.
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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))
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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,
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);
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,
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;
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);
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 */
}
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);
}
* 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;
/* 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));
* 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;
/* Run the cursor */
nfetched = PortalRunFetch(portal,
- forward ? FETCH_FORWARD : FETCH_BACKWARD,
+ direction,
count,
dest);
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
*
*****************************************************************************/
PlannedStmt *
-planner(Query *parse, bool isCursor, int cursorOptions,
- ParamListInfo boundParams)
+planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
{
PlannedStmt *result;
PlannerGlobal *glob;
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
* 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);
*
*
* 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
%type <boolean> opt_freeze opt_default opt_recheck
%type <defelt> opt_binary opt_oids copy_delimiter
-%type <boolean> copy_from opt_hold
+%type <boolean> copy_from
-%type <ival> opt_column event cursor_options
+%type <ival> opt_column event cursor_options opt_hold
%type <objtype> reindex_type drop_type comment_type
%type <node> fetch_direction select_limit_value select_offset_value
{
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;
}
;
| 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; }
;
/*****************************************************************************
*
*
* 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
}
-/* 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;
ResetUsage();
/* call the optimizer */
- plan = planner(querytree, false, 0, boundParams);
+ plan = planner(querytree, cursorOptions, boundParams);
if (log_planner_stats)
ShowUsage("PLANNER STATISTICS");
* 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;
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);
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();
}
else
{
- stmt_list = pg_plan_queries(querytree_list, NULL, true);
+ stmt_list = pg_plan_queries(querytree_list, 0, NULL, true);
fully_planned = true;
}
}
*/
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 ... */
* 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 $
*
*-------------------------------------------------------------------------
*/
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);
}
/*
* 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 $
*
*-------------------------------------------------------------------------
*/
#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"
#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"
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);
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);
* 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 $
*
*-------------------------------------------------------------------------
*/
* 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
{
* 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 $
*
*-------------------------------------------------------------------------
*/
#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,
* 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
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);