diff --git a/doc/src/sgml/spi.sgml b/doc/src/sgml/spi.sgml
index a28d8170a4..04cd0ca179 100644
--- a/doc/src/sgml/spi.sgml
+++ b/doc/src/sgml/spi.sgml
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/spi.sgml,v 1.61 2008/03/25 22:42:42 tgl Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/spi.sgml,v 1.62 2008/04/01 03:09:30 tgl Exp $ -->
 
 <chapter id="spi">
  <title>Server Programming Interface</title>
@@ -267,7 +267,7 @@ void SPI_pop(void)
   <title>Description</title>
 
   <para>
-   <function>SPI_pop</function> pops the previous environment from the 
+   <function>SPI_pop</function> pops the previous environment from the
    SPI call stack.  See <function>SPI_push</function>.
   </para>
  </refsect1>
@@ -371,7 +371,7 @@ SPI_execute("INSERT INTO foo SELECT * FROM bar", false, 5);
    then you can use the
    global pointer <literal>SPITupleTable *SPI_tuptable</literal> to
    access the result rows.  Some utility commands (such as
-   <command>EXPLAIN</>) also return row sets, and <literal>SPI_tuptable</> 
+   <command>EXPLAIN</>) also return row sets, and <literal>SPI_tuptable</>
    will contain the result in these cases too.
   </para>
 
@@ -676,6 +676,150 @@ int SPI_exec(const char * <parameter>command</parameter>, long <parameter>count<
 
 <!-- *********************************************** -->
 
+<refentry id="spi-spi-execute-with-args">
+ <refmeta>
+  <refentrytitle>SPI_execute_with_args</refentrytitle>
+ </refmeta>
+
+ <refnamediv>
+  <refname>SPI_execute_with_args</refname>
+  <refpurpose>execute a command with out-of-line parameters</refpurpose>
+ </refnamediv>
+
+ <indexterm><primary>SPI_execute_with_args</primary></indexterm>
+
+ <refsynopsisdiv>
+<synopsis>
+int SPI_execute_with_args(const char *<parameter>command</parameter>,
+                          int <parameter>nargs</parameter>, Oid *<parameter>argtypes</parameter>,
+                          Datum *<parameter>values</parameter>, const char *<parameter>nulls</parameter>,
+                          bool <parameter>read_only</parameter>, long <parameter>count</parameter>)
+</synopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+  <title>Description</title>
+
+  <para>
+   <function>SPI_execute_with_args</function> executes a command that might
+   include references to externally supplied parameters.  The command text
+   refers to a parameter as <literal>$<replaceable>n</></literal>, and
+   the call specifies data types and values for each such symbol.
+   <parameter>read_only</parameter> and <parameter>count</parameter> have
+   the same interpretation as in <function>SPI_execute</function>.
+  </para>
+
+  <para>
+   The main advantage of this routine compared to
+   <function>SPI_execute</function> is that data values can be inserted
+   into the command without tedious quoting/escaping, and thus with much
+   less risk of SQL-injection attacks.
+  </para>
+
+  <para>
+   Similar results can be achieved with <function>SPI_prepare</> followed by
+   <function>SPI_execute_plan</function>; however, when using this function
+   the query plan is customized to the specific parameter values provided.
+   For one-time query execution, this function should be preferred.
+   If the same command is to be executed with many different parameters,
+   either method might be faster, depending on the cost of re-planning
+   versus the benefit of custom plans.
+  </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>
+      an array containing the <acronym>OID</acronym>s of
+      the data types of the parameters
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
+    <term><literal>Datum * <parameter>values</parameter></literal></term>
+    <listitem>
+     <para>
+      an array of actual parameter values
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
+    <term><literal>const char * <parameter>nulls</parameter></literal></term>
+    <listitem>
+     <para>
+      an array describing which parameters are null
+     </para>
+
+     <para>
+      If <parameter>nulls</parameter> is <symbol>NULL</symbol> then
+      <function>SPI_execute_with_args</function> assumes that no parameters are
+      null.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
+    <term><literal>bool <parameter>read_only</parameter></literal></term>
+    <listitem>
+     <para>
+      <literal>true</> for read-only execution
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
+    <term><literal>long <parameter>count</parameter></literal></term>
+    <listitem>
+     <para>
+      maximum number of rows to process or return
+     </para>
+    </listitem>
+   </varlistentry>
+  </variablelist>
+ </refsect1>
+
+ <refsect1>
+  <title>Return Value</title>
+
+  <para>
+   The return value is the same as for <function>SPI_execute</function>.
+  </para>
+
+  <para>
+   <varname>SPI_processed</varname> and
+   <varname>SPI_tuptable</varname> are set as in
+   <function>SPI_execute</function> if successful.
+  </para>
+ </refsect1>
+</refentry>
+
+<!-- *********************************************** -->
+
 <refentry id="spi-spi-prepare">
  <refmeta>
   <refentrytitle>SPI_prepare</refentrytitle>
@@ -861,7 +1005,7 @@ SPIPlanPtr SPI_prepare_cursor(const char * <parameter>command</parameter>, int <
      </para>
     </listitem>
    </varlistentry>
- 
+
    <varlistentry>
     <term><literal>int <parameter>cursorOptions</parameter></literal></term>
     <listitem>
@@ -1453,6 +1597,152 @@ Portal SPI_cursor_open(const char * <parameter>name</parameter>, SPIPlanPtr <par
 
 <!-- *********************************************** -->
 
+<refentry id="spi-spi-cursor-open-with-args">
+ <refmeta>
+  <refentrytitle>SPI_cursor_open_with_args</refentrytitle>
+ </refmeta>
+
+ <refnamediv>
+  <refname>SPI_cursor_open_with_args</refname>
+  <refpurpose>set up a cursor using a query and parameters</refpurpose>
+ </refnamediv>
+
+ <indexterm><primary>SPI_cursor_open_with_args</primary></indexterm>
+
+ <refsynopsisdiv>
+<synopsis>
+Portal SPI_cursor_open_with_args(const char *<parameter>name</parameter>,
+                                 const char *<parameter>command</parameter>,
+                                 int <parameter>nargs</parameter>, Oid *<parameter>argtypes</parameter>,
+                                 Datum *<parameter>values</parameter>, const char *<parameter>nulls</parameter>,
+                                 bool <parameter>read_only</parameter>, int <parameter>cursorOptions</parameter>)
+</synopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+  <title>Description</title>
+
+  <para>
+   <function>SPI_cursor_open_with_args</function> sets up a cursor
+   (internally, a portal) that will execute the specified query.
+   Most of the parameters have the same meanings as the corresponding
+   parameters to <function>SPI_prepare_cursor</function>
+   and <function>SPI_cursor_open</function>.
+  </para>
+
+  <para>
+   For one-time query execution, this function should be preferred
+   over <function>SPI_prepare_cursor</function> followed by
+   <function>SPI_cursor_open</function>.
+   If the same command is to be executed with many different parameters,
+   either method might be faster, depending on the cost of re-planning
+   versus the benefit of custom plans.
+  </para>
+
+  <para>
+   The passed-in data will be copied into the cursor's portal, so it
+   can be freed while the cursor still exists.
+  </para>
+ </refsect1>
+
+ <refsect1>
+  <title>Arguments</title>
+
+  <variablelist>
+   <varlistentry>
+    <term><literal>const char * <parameter>name</parameter></literal></term>
+    <listitem>
+     <para>
+      name for portal, or <symbol>NULL</symbol> to let the system
+      select a name
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <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>
+      an array containing the <acronym>OID</acronym>s of
+      the data types of the parameters
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
+    <term><literal>Datum * <parameter>values</parameter></literal></term>
+    <listitem>
+     <para>
+      an array of actual parameter values
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
+    <term><literal>const char * <parameter>nulls</parameter></literal></term>
+    <listitem>
+     <para>
+      an array describing which parameters are null
+     </para>
+
+     <para>
+      If <parameter>nulls</parameter> is <symbol>NULL</symbol> then
+      <function>SPI_cursor_open_with_args</function> assumes that no
+      parameters are null.
+     </para>
+    </listitem>
+   </varlistentry>
+
+   <varlistentry>
+    <term><literal>bool <parameter>read_only</parameter></literal></term>
+    <listitem>
+     <para>
+      <literal>true</> for read-only execution
+     </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>
+   Pointer to portal containing the cursor.  Note there is no error
+   return convention; any error will be reported via <function>elog</>.
+  </para>
+ </refsect1>
+</refentry>
+
+<!-- *********************************************** -->
+
 <refentry id="spi-spi-cursor-find">
  <refmeta>
   <refentrytitle>SPI_cursor_find</refentrytitle>
@@ -1748,7 +2038,7 @@ void SPI_scroll_cursor_fetch(Portal <parameter>portal</parameter>, FetchDirectio
 
   <para>
    See the SQL <xref linkend="sql-fetch" endterm="sql-fetch-title"> command
-   for details of the interpretation of the 
+   for details of the interpretation of the
    <parameter>direction</parameter> and
    <parameter>count</parameter> parameters.
   </para>
@@ -1847,7 +2137,7 @@ void SPI_scroll_cursor_move(Portal <parameter>portal</parameter>, FetchDirection
 
   <para>
    See the SQL <xref linkend="sql-fetch" endterm="sql-fetch-title"> command
-   for details of the interpretation of the 
+   for details of the interpretation of the
    <parameter>direction</parameter> and
    <parameter>count</parameter> parameters.
   </para>
@@ -3346,9 +3636,9 @@ execq(text *sql, int cnt)
     command = text_to_cstring(sql);
 
     SPI_connect();
-    
+
     ret = SPI_exec(command, cnt);
-    
+
     proc = SPI_processed;
     /*
      * If some rows were fetched, print them via elog(INFO).
@@ -3359,11 +3649,11 @@ execq(text *sql, int cnt)
         SPITupleTable *tuptable = SPI_tuptable;
         char buf[8192];
         int i, j;
-        
+
         for (j = 0; j &lt; proc; j++)
         {
             HeapTuple tuple = tuptable-&gt;vals[j];
-            
+
             for (i = 1, buf[0] = 0; i &lt;= tupdesc-&gt;natts; i++)
                 snprintf(buf + strlen (buf), sizeof(buf) - strlen(buf), " %s%s",
                         SPI_getvalue(tuple, tupdesc, i),
@@ -3469,7 +3759,7 @@ INSERT 0 2
  2
  2                  -- 2 rows * 1 (x in first row)
  6                  -- 3 rows (2 + 1 just inserted) * 2 (x in second row)
-(4 rows)               ^^^^^^ 
+(4 rows)               ^^^^^^
                        rows visible to execq() in different invocations
 </programlisting>
   </para>
diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
index 3cd2e57410..42187fe43a 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.191 2008/03/26 18:48:59 alvherre Exp $
+ *	  $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.192 2008/04/01 03:09:30 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -35,13 +35,17 @@ 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,
+							  ParamListInfo boundParams);
 
-static int _SPI_execute_plan(SPIPlanPtr plan,
-				  Datum *Values, const char *Nulls,
+static int _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI,
 				  Snapshot snapshot, Snapshot crosscheck_snapshot,
 				  bool read_only, bool fire_triggers, long tcount);
 
+static ParamListInfo _SPI_convert_params(int nargs, Oid *argtypes,
+					Datum *Values, const char *Nulls,
+					int pflags);
+
 static int	_SPI_pquery(QueryDesc *queryDesc, bool fire_triggers, long tcount);
 
 static void _SPI_error_callback(void *arg);
@@ -313,9 +317,9 @@ SPI_execute(const char *src, bool read_only, long tcount)
 	plan.magic = _SPI_PLAN_MAGIC;
 	plan.cursor_options = 0;
 
-	_SPI_prepare_plan(src, &plan);
+	_SPI_prepare_plan(src, &plan, NULL);
 
-	res = _SPI_execute_plan(&plan, NULL, NULL,
+	res = _SPI_execute_plan(&plan, NULL,
 							InvalidSnapshot, InvalidSnapshot,
 							read_only, true, tcount);
 
@@ -348,7 +352,9 @@ SPI_execute_plan(SPIPlanPtr plan, Datum *Values, const char *Nulls,
 		return res;
 
 	res = _SPI_execute_plan(plan,
-							Values, Nulls,
+							_SPI_convert_params(plan->nargs, plan->argtypes,
+												Values, Nulls,
+												0),
 							InvalidSnapshot, InvalidSnapshot,
 							read_only, true, tcount);
 
@@ -394,7 +400,9 @@ SPI_execute_snapshot(SPIPlanPtr plan,
 		return res;
 
 	res = _SPI_execute_plan(plan,
-							Values, Nulls,
+							_SPI_convert_params(plan->nargs, plan->argtypes,
+												Values, Nulls,
+												0),
 							snapshot, crosscheck_snapshot,
 							read_only, fire_triggers, tcount);
 
@@ -402,6 +410,57 @@ SPI_execute_snapshot(SPIPlanPtr plan,
 	return res;
 }
 
+/*
+ * SPI_execute_with_args -- plan and execute a query with supplied arguments
+ *
+ * This is functionally comparable to SPI_prepare followed by
+ * SPI_execute_plan, except that since we know the plan will be used only
+ * once, we can tell the planner to rely on the parameter values as constants.
+ * This eliminates potential performance disadvantages compared to
+ * inserting the parameter values directly into the query text.
+ */
+int
+SPI_execute_with_args(const char *src,
+					  int nargs, Oid *argtypes,
+					  Datum *Values, const char *Nulls,
+					  bool read_only, long tcount)
+{
+	int			res;
+	_SPI_plan	plan;
+	ParamListInfo paramLI;
+
+	if (src == NULL || nargs < 0 || tcount < 0)
+		return SPI_ERROR_ARGUMENT;
+
+	if (nargs > 0 && (argtypes == NULL || Values == NULL))
+		return SPI_ERROR_PARAM;
+
+	res = _SPI_begin_call(true);
+	if (res < 0)
+		return res;
+
+	memset(&plan, 0, sizeof(_SPI_plan));
+	plan.magic = _SPI_PLAN_MAGIC;
+	plan.cursor_options = 0;
+	plan.nargs = nargs;
+	plan.argtypes = argtypes;
+
+	paramLI = _SPI_convert_params(nargs, argtypes,
+								  Values, Nulls,
+								  PARAM_FLAG_CONST);
+
+	_SPI_prepare_plan(src, &plan, paramLI);
+
+	/* We don't need to copy the plan since it will be thrown away anyway */
+
+	res = _SPI_execute_plan(&plan, paramLI,
+							InvalidSnapshot, InvalidSnapshot,
+							read_only, true, tcount);
+
+	_SPI_end_call(true);
+	return res;
+}
+
 SPIPlanPtr
 SPI_prepare(const char *src, int nargs, Oid *argtypes)
 {
@@ -431,7 +490,7 @@ SPI_prepare_cursor(const char *src, int nargs, Oid *argtypes,
 	plan.nargs = nargs;
 	plan.argtypes = argtypes;
 
-	_SPI_prepare_plan(src, &plan);
+	_SPI_prepare_plan(src, &plan, NULL);
 
 	/* copy plan to procedure context */
 	result = _SPI_copy_plan(&plan, _SPI_current->procCxt);
@@ -1054,6 +1113,64 @@ SPI_cursor_open(const char *name, SPIPlanPtr plan,
 }
 
 
+/*
+ * SPI_cursor_open_with_args()
+ *
+ * Parse and plan a query and open it as a portal.  Like SPI_execute_with_args,
+ * we can tell the planner to rely on the parameter values as constants,
+ * because the plan will only be used once.
+ */
+Portal
+SPI_cursor_open_with_args(const char *name,
+						  const char *src,
+						  int nargs, Oid *argtypes,
+						  Datum *Values, const char *Nulls,
+						  bool read_only, int cursorOptions)
+{
+	Portal		result;
+	_SPI_plan	plan;
+	ParamListInfo paramLI;
+
+	if (src == NULL || nargs < 0)
+		elog(ERROR, "SPI_cursor_open_with_args called with invalid arguments");
+
+	if (nargs > 0 && (argtypes == NULL || Values == NULL))
+		elog(ERROR, "SPI_cursor_open_with_args called with missing parameters");
+
+	SPI_result = _SPI_begin_call(true);
+	if (SPI_result < 0)
+		elog(ERROR, "SPI_cursor_open_with_args called while not connected");
+
+	memset(&plan, 0, sizeof(_SPI_plan));
+	plan.magic = _SPI_PLAN_MAGIC;
+	plan.cursor_options = cursorOptions;
+	plan.nargs = nargs;
+	plan.argtypes = argtypes;
+
+	paramLI = _SPI_convert_params(nargs, argtypes,
+								  Values, Nulls,
+								  PARAM_FLAG_CONST);
+
+	_SPI_prepare_plan(src, &plan, paramLI);
+
+	/* We needn't copy the plan; SPI_cursor_open will do so */
+
+	/* Adjust stack so that SPI_cursor_open doesn't complain */
+	_SPI_curid--;
+
+	/* SPI_cursor_open expects to be called in procedure memory context */
+	_SPI_procmem();
+
+	result = SPI_cursor_open(name, &plan, Values, Nulls, read_only);
+
+	/* And clean up */
+	_SPI_curid++;
+	_SPI_end_call(true);
+
+	return result;
+}
+
+
 /*
  * SPI_cursor_find()
  *
@@ -1376,14 +1493,17 @@ spi_printtup(TupleTableSlot *slot, DestReceiver *self)
  * Parse and plan a querystring.
  *
  * At entry, plan->argtypes, plan->nargs, and plan->cursor_options must be
- * valid.
+ * valid.  If boundParams isn't NULL then it represents parameter values
+ * that are made available to the planner (as either estimates or hard values
+ * depending on their PARAM_FLAG_CONST marking).  The boundParams had better
+ * match the param types embedded in the plan!
  *
  * Results are stored into *plan (specifically, plan->plancache_list).
  * Note however that the result trees are all in CurrentMemoryContext
  * 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, ParamListInfo boundParams)
 {
 	List	   *raw_parsetree_list;
 	List	   *plancache_list;
@@ -1422,7 +1542,8 @@ _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, cursor_options, NULL, false);
+		stmt_list = pg_plan_queries(stmt_list, cursor_options,
+									boundParams, false);
 
 		plansource = (CachedPlanSource *) palloc0(sizeof(CachedPlanSource));
 		cplan = (CachedPlan *) palloc0(sizeof(CachedPlan));
@@ -1465,7 +1586,7 @@ _SPI_prepare_plan(const char *src, SPIPlanPtr plan)
  * tcount: execution tuple-count limit, or 0 for none
  */
 static int
-_SPI_execute_plan(SPIPlanPtr plan, Datum *Values, const char *Nulls,
+_SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI,
 				  Snapshot snapshot, Snapshot crosscheck_snapshot,
 				  bool read_only, bool fire_triggers, long tcount)
 {
@@ -1480,34 +1601,9 @@ _SPI_execute_plan(SPIPlanPtr plan, Datum *Values, const char *Nulls,
 	saveActiveSnapshot = ActiveSnapshot;
 	PG_TRY();
 	{
-		ListCell   *lc1;
 		ErrorContextCallback spierrcontext;
-		int			nargs = plan->nargs;
-		ParamListInfo paramLI;
 		CachedPlan *cplan = NULL;
-
-		/* Convert parameters to form wanted by executor */
-		if (nargs > 0)
-		{
-			int			k;
-
-			/* sizeof(ParamListInfoData) includes the first array element */
-			paramLI = (ParamListInfo) palloc(sizeof(ParamListInfoData) +
-									   (nargs - 1) *sizeof(ParamExternData));
-			paramLI->numParams = nargs;
-
-			for (k = 0; k < nargs; k++)
-			{
-				ParamExternData *prm = &paramLI->params[k];
-
-				prm->value = Values[k];
-				prm->isnull = (Nulls && Nulls[k] == 'n');
-				prm->pflags = 0;
-				prm->ptype = plan->argtypes[k];
-			}
-		}
-		else
-			paramLI = NULL;
+		ListCell   *lc1;
 
 		/*
 		 * Setup error traceback support for ereport()
@@ -1723,6 +1819,40 @@ fail:
 	return my_res;
 }
 
+/*
+ * Convert query parameters to form wanted by planner and executor
+ */
+static ParamListInfo
+_SPI_convert_params(int nargs, Oid *argtypes,
+					Datum *Values, const char *Nulls,
+					int pflags)
+{
+	ParamListInfo paramLI;
+
+	if (nargs > 0)
+	{
+		int			i;
+
+		/* sizeof(ParamListInfoData) includes the first array element */
+		paramLI = (ParamListInfo) palloc(sizeof(ParamListInfoData) +
+										 (nargs - 1) *sizeof(ParamExternData));
+		paramLI->numParams = nargs;
+
+		for (i = 0; i < nargs; i++)
+		{
+			ParamExternData *prm = &paramLI->params[i];
+
+			prm->value = Values[i];
+			prm->isnull = (Nulls && Nulls[i] == 'n');
+			prm->pflags = pflags;
+			prm->ptype = argtypes[i];
+		}
+	}
+	else
+		paramLI = NULL;
+	return paramLI;
+}
+
 static int
 _SPI_pquery(QueryDesc *queryDesc, bool fire_triggers, long tcount)
 {
diff --git a/src/include/executor/spi.h b/src/include/executor/spi.h
index e64fc39cba..9d3f65b8cf 100644
--- a/src/include/executor/spi.h
+++ b/src/include/executor/spi.h
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/executor/spi.h,v 1.65 2008/01/01 19:45:57 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/executor/spi.h,v 1.66 2008/04/01 03:09:30 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -105,6 +105,10 @@ extern int SPI_execute_snapshot(SPIPlanPtr plan,
 					 Snapshot snapshot,
 					 Snapshot crosscheck_snapshot,
 					 bool read_only, bool fire_triggers, long tcount);
+extern int	SPI_execute_with_args(const char *src,
+								  int nargs, Oid *argtypes,
+								  Datum *Values, const char *Nulls,
+								  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);
@@ -136,6 +140,11 @@ extern void SPI_freetuptable(SPITupleTable *tuptable);
 
 extern Portal SPI_cursor_open(const char *name, SPIPlanPtr plan,
 				Datum *Values, const char *Nulls, bool read_only);
+extern Portal SPI_cursor_open_with_args(const char *name,
+										const char *src,
+										int nargs, Oid *argtypes,
+										Datum *Values, const char *Nulls,
+										bool read_only, int cursorOptions);
 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);