aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/commands/portalcmds.c19
-rw-r--r--src/backend/commands/prepare.c11
-rw-r--r--src/backend/commands/schemacmds.c4
-rw-r--r--src/backend/executor/execQual.c62
-rw-r--r--src/backend/executor/functions.c8
-rw-r--r--src/backend/executor/spi.c8
-rw-r--r--src/backend/nodes/Makefile4
-rw-r--r--src/backend/nodes/params.c122
-rw-r--r--src/backend/optimizer/util/clauses.c42
-rw-r--r--src/backend/tcop/postgres.c3
-rw-r--r--src/backend/tcop/pquery.c6
-rw-r--r--src/backend/tcop/utility.c6
-rw-r--r--src/include/commands/portalcmds.h4
-rw-r--r--src/include/nodes/params.h13
-rw-r--r--src/include/tcop/utility.h7
-rw-r--r--src/pl/plpgsql/src/pl_exec.c7
-rw-r--r--src/test/regress/expected/portals.out35
-rw-r--r--src/test/regress/sql/portals.sql17
18 files changed, 263 insertions, 115 deletions
diff --git a/src/backend/commands/portalcmds.c b/src/backend/commands/portalcmds.c
index 509d9e0dfa1..64d0c77489b 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.30 2004/07/31 00:45:31 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/portalcmds.c,v 1.31 2004/08/02 01:30:40 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -36,7 +36,7 @@
* Execute SQL DECLARE CURSOR command.
*/
void
-PerformCursorOpen(DeclareCursorStmt *stmt)
+PerformCursorOpen(DeclareCursorStmt *stmt, ParamListInfo params)
{
List *rewritten;
Query *query;
@@ -104,6 +104,17 @@ PerformCursorOpen(DeclareCursorStmt *stmt)
list_make1(plan),
PortalGetHeapMemory(portal));
+ /*
+ * Also copy the outer portal's parameter list into the inner portal's
+ * memory context. We want to pass down the parameter values in case
+ * we had a command like
+ * DECLARE c CURSOR FOR SELECT ... WHERE foo = $1
+ * This will have been parsed using the outer parameter set and the
+ * parameter value needs to be preserved for use when the cursor is
+ * executed.
+ */
+ params = copyParamList(params);
+
MemoryContextSwitchTo(oldContext);
/*
@@ -123,9 +134,9 @@ PerformCursorOpen(DeclareCursorStmt *stmt)
}
/*
- * Start execution --- never any params for a cursor.
+ * Start execution, inserting parameters if any.
*/
- PortalStart(portal, NULL);
+ PortalStart(portal, params);
Assert(portal->strategy == PORTAL_ONE_SELECT);
diff --git a/src/backend/commands/prepare.c b/src/backend/commands/prepare.c
index 9c183cb7827..d4c8357ff0b 100644
--- a/src/backend/commands/prepare.c
+++ b/src/backend/commands/prepare.c
@@ -10,7 +10,7 @@
* Copyright (c) 2002-2003, PostgreSQL Global Development Group
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.28 2004/06/11 01:08:38 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.29 2004/08/02 01:30:40 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -200,7 +200,7 @@ ExecuteQuery(ExecuteStmt *stmt, DestReceiver *dest, char *completionTag)
/*
* Evaluates a list of parameters, using the given executor state. It
- * requires a list of the parameter values themselves, and a list of
+ * requires a list of the parameter expressions themselves, and a list of
* their types. It returns a filled-in ParamListInfo -- this can later
* be passed to CreateQueryDesc(), which allows the executor to make use
* of the parameters during query execution.
@@ -211,7 +211,7 @@ EvaluateParams(EState *estate, List *params, List *argtypes)
int nargs = list_length(argtypes);
ParamListInfo paramLI;
List *exprstates;
- ListCell *l;
+ ListCell *le, *la;
int i = 0;
/* Parser should have caught this error, but check for safety */
@@ -223,9 +223,9 @@ EvaluateParams(EState *estate, List *params, List *argtypes)
paramLI = (ParamListInfo)
palloc0((nargs + 1) * sizeof(ParamListInfoData));
- foreach(l, exprstates)
+ forboth(le, exprstates, la, argtypes)
{
- ExprState *n = lfirst(l);
+ ExprState *n = lfirst(le);
bool isNull;
paramLI[i].value = ExecEvalExprSwitchContext(n,
@@ -234,6 +234,7 @@ EvaluateParams(EState *estate, List *params, List *argtypes)
NULL);
paramLI[i].kind = PARAM_NUM;
paramLI[i].id = i + 1;
+ paramLI[i].ptype = lfirst_oid(la);
paramLI[i].isnull = isNull;
i++;
diff --git a/src/backend/commands/schemacmds.c b/src/backend/commands/schemacmds.c
index 2dead1e15a1..d73c65aa6b2 100644
--- a/src/backend/commands/schemacmds.c
+++ b/src/backend/commands/schemacmds.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/schemacmds.c,v 1.21 2004/08/01 20:30:48 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/schemacmds.c,v 1.22 2004/08/02 01:30:40 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -168,7 +168,7 @@ CreateSchemaCommand(CreateSchemaStmt *stmt)
/* schemas should contain only utility stmts */
Assert(querytree->commandType == CMD_UTILITY);
/* do this step */
- ProcessUtility(querytree->utilityStmt, None_Receiver, NULL);
+ ProcessUtility(querytree->utilityStmt, NULL, None_Receiver, NULL);
/* make sure later steps can see the object created here */
CommandCounterIncrement();
}
diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c
index e4362c38f58..6ac61d3c5be 100644
--- a/src/backend/executor/execQual.c
+++ b/src/backend/executor/execQual.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.164 2004/06/09 19:08:14 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.165 2004/08/02 01:30:41 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -589,56 +589,18 @@ ExecEvalParam(ExprState *exprstate, ExprContext *econtext,
else
{
/*
- * All other parameter types must be sought in
- * ecxt_param_list_info. NOTE: The last entry in the param array
- * is always an entry with kind == PARAM_INVALID.
+ * All other parameter types must be sought in ecxt_param_list_info.
*/
- ParamListInfo paramList = econtext->ecxt_param_list_info;
- char *thisParamName = expression->paramname;
- bool matchFound = false;
-
- if (paramList != NULL)
- {
- while (paramList->kind != PARAM_INVALID && !matchFound)
- {
- if (thisParamKind == paramList->kind)
- {
- switch (thisParamKind)
- {
- case PARAM_NAMED:
- if (strcmp(paramList->name, thisParamName) == 0)
- matchFound = true;
- break;
- case PARAM_NUM:
- if (paramList->id == thisParamId)
- matchFound = true;
- break;
- default:
- elog(ERROR, "unrecognized paramkind: %d",
- thisParamKind);
- }
- }
- if (!matchFound)
- paramList++;
- } /* while */
- } /* if */
-
- if (!matchFound)
- {
- if (thisParamKind == PARAM_NAMED)
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("no value found for parameter \"%s\"",
- thisParamName)));
- else
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("no value found for parameter %d",
- thisParamId)));
- }
-
- *isNull = paramList->isnull;
- return paramList->value;
+ ParamListInfo paramInfo;
+
+ paramInfo = lookupParam(econtext->ecxt_param_list_info,
+ thisParamKind,
+ expression->paramname,
+ thisParamId,
+ false);
+ Assert(paramInfo->ptype == expression->paramtype);
+ *isNull = paramInfo->isnull;
+ return paramInfo->value;
}
}
diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c
index 0073f8f55c1..cfcccb6169e 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.83 2004/07/15 13:51:38 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/functions.c,v 1.84 2004/08/02 01:30:41 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -58,6 +58,7 @@ typedef struct local_es
*/
typedef struct
{
+ Oid *argtypes; /* resolved types of arguments */
Oid rettype; /* actual return type */
int typlen; /* length of the return type */
bool typbyval; /* true if return type is pass by value */
@@ -223,6 +224,7 @@ init_sql_fcache(FmgrInfo *finfo)
}
else
argOidVect = NULL;
+ fcache->argtypes = argOidVect;
tmp = SysCacheGetAttr(PROCOID,
procedureTuple,
@@ -283,7 +285,8 @@ postquel_getnext(execution_state *es)
if (es->qd->operation == CMD_UTILITY)
{
- ProcessUtility(es->qd->parsetree->utilityStmt, es->qd->dest, NULL);
+ ProcessUtility(es->qd->parsetree->utilityStmt, es->qd->params,
+ es->qd->dest, NULL);
return NULL;
}
@@ -332,6 +335,7 @@ postquel_sub_params(SQLFunctionCachePtr fcache,
{
paramLI[i].kind = PARAM_NUM;
paramLI[i].id = i + 1;
+ paramLI[i].ptype = fcache->argtypes[i];
paramLI[i].value = fcinfo->arg[i];
paramLI[i].isnull = fcinfo->argnull[i];
}
diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
index 7840f5f787a..33379d52222 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.122 2004/07/31 20:55:41 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.123 2004/08/02 01:30:41 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -820,6 +820,7 @@ SPI_cursor_open(const char *name, void *plan, Datum *Values, const char *Nulls)
{
paramLI[k].kind = PARAM_NUM;
paramLI[k].id = k + 1;
+ paramLI[k].ptype = spiplan->argtypes[k];
paramLI[k].isnull = (Nulls && Nulls[k] == 'n');
if (paramLI[k].isnull)
{
@@ -1251,7 +1252,7 @@ _SPI_execute(const char *src, int tcount, _SPI_plan *plan)
res = SPI_OK_UTILITY;
if (plan == NULL)
{
- ProcessUtility(queryTree->utilityStmt, dest, NULL);
+ ProcessUtility(queryTree->utilityStmt, NULL, dest, NULL);
CommandCounterIncrement();
}
}
@@ -1319,6 +1320,7 @@ _SPI_execute_plan(_SPI_plan *plan, Datum *Values, const char *Nulls,
{
paramLI[k].kind = PARAM_NUM;
paramLI[k].id = k + 1;
+ paramLI[k].ptype = plan->argtypes[k];
paramLI[k].isnull = (Nulls && Nulls[k] == 'n');
paramLI[k].value = Values[k];
}
@@ -1366,7 +1368,7 @@ _SPI_execute_plan(_SPI_plan *plan, Datum *Values, const char *Nulls,
dest = CreateDestReceiver(queryTree->canSetTag ? SPI : None, NULL);
if (queryTree->commandType == CMD_UTILITY)
{
- ProcessUtility(queryTree->utilityStmt, dest, NULL);
+ ProcessUtility(queryTree->utilityStmt, paramLI, dest, NULL);
res = SPI_OK_UTILITY;
CommandCounterIncrement();
}
diff --git a/src/backend/nodes/Makefile b/src/backend/nodes/Makefile
index a4c19201bb2..86f533e7a0e 100644
--- a/src/backend/nodes/Makefile
+++ b/src/backend/nodes/Makefile
@@ -4,7 +4,7 @@
# Makefile for backend/nodes
#
# IDENTIFICATION
-# $PostgreSQL: pgsql/src/backend/nodes/Makefile,v 1.16 2004/01/07 18:43:36 neilc Exp $
+# $PostgreSQL: pgsql/src/backend/nodes/Makefile,v 1.17 2004/08/02 01:30:42 tgl Exp $
#
#-------------------------------------------------------------------------
@@ -14,7 +14,7 @@ include $(top_builddir)/src/Makefile.global
OBJS = nodeFuncs.o nodes.o list.o bitmapset.o \
copyfuncs.o equalfuncs.o makefuncs.o \
- outfuncs.o readfuncs.o print.o read.o value.o
+ outfuncs.o readfuncs.o print.o read.o params.o value.o
all: SUBSYS.o
diff --git a/src/backend/nodes/params.c b/src/backend/nodes/params.c
new file mode 100644
index 00000000000..43bc40b9e1c
--- /dev/null
+++ b/src/backend/nodes/params.c
@@ -0,0 +1,122 @@
+/*-------------------------------------------------------------------------
+ *
+ * params.c
+ * Support functions for plan parameter lists.
+ *
+ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * IDENTIFICATION
+ * $PostgreSQL: pgsql/src/backend/nodes/params.c,v 1.1 2004/08/02 01:30:42 tgl Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+
+#include "nodes/params.h"
+#include "utils/datum.h"
+#include "utils/lsyscache.h"
+
+
+/*
+ * Copy a ParamList.
+ *
+ * The result is allocated in CurrentMemoryContext.
+ */
+ParamListInfo
+copyParamList(ParamListInfo from)
+{
+ ParamListInfo retval;
+ int i, size;
+
+ if (from == NULL)
+ return NULL;
+
+ size = 0;
+ while (from[size].kind != PARAM_INVALID)
+ size++;
+
+ retval = (ParamListInfo) palloc0((size + 1) * sizeof(ParamListInfoData));
+
+ for (i = 0; i < size; i++) {
+ /* copy metadata */
+ retval[i].kind = from[i].kind;
+ if (from[i].kind == PARAM_NAMED)
+ retval[i].name = pstrdup(from[i].name);
+ retval[i].id = from[i].id;
+ retval[i].ptype = from[i].ptype;
+
+ /* copy value */
+ retval[i].isnull = from[i].isnull;
+ if (from[i].isnull)
+ {
+ retval[i].value = from[i].value; /* nulls just copy */
+ }
+ else
+ {
+ int16 typLen;
+ bool typByVal;
+
+ get_typlenbyval(from[i].ptype, &typLen, &typByVal);
+ retval[i].value = datumCopy(from[i].value, typByVal, typLen);
+ }
+ }
+
+ retval[size].kind = PARAM_INVALID;
+
+ return retval;
+}
+
+/*
+ * Search a ParamList for a given parameter.
+ *
+ * On success, returns a pointer to the parameter's entry.
+ * On failure, returns NULL if noError is true, else ereports the error.
+ */
+ParamListInfo
+lookupParam(ParamListInfo paramList, int thisParamKind,
+ const char *thisParamName, AttrNumber thisParamId,
+ bool noError)
+{
+ if (paramList != NULL)
+ {
+ while (paramList->kind != PARAM_INVALID)
+ {
+ if (thisParamKind == paramList->kind)
+ {
+ switch (thisParamKind)
+ {
+ case PARAM_NAMED:
+ if (strcmp(paramList->name, thisParamName) == 0)
+ return paramList;
+ break;
+ case PARAM_NUM:
+ if (paramList->id == thisParamId)
+ return paramList;
+ break;
+ default:
+ elog(ERROR, "unrecognized paramkind: %d",
+ thisParamKind);
+ }
+ }
+ paramList++;
+ }
+ }
+
+ if (!noError)
+ {
+ if (thisParamKind == PARAM_NAMED)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("no value found for parameter \"%s\"",
+ thisParamName)));
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("no value found for parameter %d",
+ thisParamId)));
+ }
+
+ return NULL;
+}
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index e7088d2b761..68d2529889e 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.176 2004/06/11 01:08:54 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.177 2004/08/02 01:30:43 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -1120,39 +1120,20 @@ eval_const_expressions_mutator(Node *node,
if (IsA(node, Param))
{
Param *param = (Param *) node;
- int thisParamKind = param->paramkind;
/* OK to try to substitute value? */
- if (context->estimate && thisParamKind != PARAM_EXEC &&
+ if (context->estimate && param->paramkind != PARAM_EXEC &&
PlannerBoundParamList != NULL)
{
- ParamListInfo paramList = PlannerBoundParamList;
- bool matchFound = false;
+ ParamListInfo paramInfo;
/* Search to see if we've been given a value for this Param */
- while (paramList->kind != PARAM_INVALID && !matchFound)
- {
- if (thisParamKind == paramList->kind)
- {
- switch (thisParamKind)
- {
- case PARAM_NAMED:
- if (strcmp(paramList->name, param->paramname) == 0)
- matchFound = true;
- break;
- case PARAM_NUM:
- if (paramList->id == param->paramid)
- matchFound = true;
- break;
- default:
- elog(ERROR, "unrecognized paramkind: %d",
- thisParamKind);
- }
- }
- if (!matchFound)
- paramList++;
- }
- if (matchFound)
+ paramInfo = lookupParam(PlannerBoundParamList,
+ param->paramkind,
+ param->paramname,
+ param->paramid,
+ true);
+ if (paramInfo)
{
/*
* Found it, so return a Const representing the param value.
@@ -1164,11 +1145,12 @@ eval_const_expressions_mutator(Node *node,
int16 typLen;
bool typByVal;
+ Assert(paramInfo->ptype == param->paramtype);
get_typlenbyval(param->paramtype, &typLen, &typByVal);
return (Node *) makeConst(param->paramtype,
(int) typLen,
- paramList->value,
- paramList->isnull,
+ paramInfo->value,
+ paramInfo->isnull,
typByVal);
}
}
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 89ee40a5321..bfbe0a53c5c 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.427 2004/07/31 00:45:36 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.428 2004/08/02 01:30:44 tgl Exp $
*
* NOTES
* this is the "main" module of the postgres backend and
@@ -1488,6 +1488,7 @@ exec_bind_message(StringInfo input_message)
params[i].kind = PARAM_NUM;
params[i].id = i + 1;
+ params[i].ptype = ptype;
params[i].isnull = isNull;
i++;
diff --git a/src/backend/tcop/pquery.c b/src/backend/tcop/pquery.c
index 8973cca6d26..588523f8493 100644
--- a/src/backend/tcop/pquery.c
+++ b/src/backend/tcop/pquery.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/tcop/pquery.c,v 1.82 2004/07/31 00:45:36 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/tcop/pquery.c,v 1.83 2004/08/02 01:30:45 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -833,14 +833,14 @@ PortalRunUtility(Portal portal, Query *query,
if (query->canSetTag)
{
/* utility statement can override default tag string */
- ProcessUtility(utilityStmt, dest, completionTag);
+ ProcessUtility(utilityStmt, portal->portalParams, dest, completionTag);
if (completionTag && completionTag[0] == '\0' && portal->commandTag)
strcpy(completionTag, portal->commandTag); /* use the default */
}
else
{
/* utility added by rewrite cannot set tag */
- ProcessUtility(utilityStmt, dest, NULL);
+ ProcessUtility(utilityStmt, portal->portalParams, dest, NULL);
}
/* Some utility statements may change context on us */
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index d8d718a1823..b9c50d7d81c 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.222 2004/08/01 17:32:18 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.223 2004/08/02 01:30:45 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -294,6 +294,7 @@ check_xact_readonly(Node *parsetree)
* general utility function invoker
*
* parsetree: the parse tree for the utility statement
+ * params: parameters to use during execution (currently only used by DECLARE)
* dest: where to send results
* completionTag: points to a buffer of size COMPLETION_TAG_BUFSIZE
* in which to store a command completion status string.
@@ -305,6 +306,7 @@ check_xact_readonly(Node *parsetree)
*/
void
ProcessUtility(Node *parsetree,
+ ParamListInfo params,
DestReceiver *dest,
char *completionTag)
{
@@ -406,7 +408,7 @@ ProcessUtility(Node *parsetree,
* Portal (cursor) manipulation
*/
case T_DeclareCursorStmt:
- PerformCursorOpen((DeclareCursorStmt *) parsetree);
+ PerformCursorOpen((DeclareCursorStmt *) parsetree, params);
break;
case T_ClosePortalStmt:
diff --git a/src/include/commands/portalcmds.h b/src/include/commands/portalcmds.h
index 60e7d524d29..b16ef233846 100644
--- a/src/include/commands/portalcmds.h
+++ b/src/include/commands/portalcmds.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/commands/portalcmds.h,v 1.15 2004/07/17 03:30:56 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/commands/portalcmds.h,v 1.16 2004/08/02 01:30:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -17,7 +17,7 @@
#include "utils/portal.h"
-extern void PerformCursorOpen(DeclareCursorStmt *stmt);
+extern void PerformCursorOpen(DeclareCursorStmt *stmt, ParamListInfo params);
extern void PerformPortalFetch(FetchStmt *stmt, DestReceiver *dest,
char *completionTag);
diff --git a/src/include/nodes/params.h b/src/include/nodes/params.h
index e22ff27a3b7..d4acbe2699e 100644
--- a/src/include/nodes/params.h
+++ b/src/include/nodes/params.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/nodes/params.h,v 1.24 2003/11/29 22:41:06 pgsql Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/params.h,v 1.25 2004/08/02 01:30:47 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -56,7 +56,8 @@
*
* kind : the kind of parameter (PARAM_NAMED or PARAM_NUM)
* name : the parameter name (valid if kind == PARAM_NAMED)
- * id : the parameter id (valid if kind == PARAM_NUM)
+ * id : the parameter id (valid if kind == PARAM_NUM)
+ * ptype : the type of the parameter value
* isnull : true if the value is null (if so 'value' is undefined)
* value : the value that has to be substituted in the place
* of the parameter.
@@ -72,6 +73,7 @@ typedef struct ParamListInfoData
int kind;
char *name;
AttrNumber id;
+ Oid ptype;
bool isnull;
Datum value;
} ParamListInfoData;
@@ -103,4 +105,11 @@ typedef struct ParamExecData
bool isnull;
} ParamExecData;
+
+/* Functions found in src/backend/nodes/params.c */
+extern ParamListInfo copyParamList(ParamListInfo from);
+extern ParamListInfo lookupParam(ParamListInfo paramList, int thisParamKind,
+ const char *thisParamName, AttrNumber thisParamId,
+ bool noError);
+
#endif /* PARAMS_H */
diff --git a/src/include/tcop/utility.h b/src/include/tcop/utility.h
index 59a9a8133d1..a5398e0deda 100644
--- a/src/include/tcop/utility.h
+++ b/src/include/tcop/utility.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/tcop/utility.h,v 1.21 2003/11/29 22:41:14 pgsql Exp $
+ * $PostgreSQL: pgsql/src/include/tcop/utility.h,v 1.22 2004/08/02 01:30:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -16,8 +16,9 @@
#include "executor/execdesc.h"
-extern void ProcessUtility(Node *parsetree, DestReceiver *dest,
- char *completionTag);
+
+extern void ProcessUtility(Node *parsetree, ParamListInfo params,
+ DestReceiver *dest, char *completionTag);
extern bool UtilityReturnsTuples(Node *parsetree);
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index f075b96c0fc..124d3c4bad2 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -3,7 +3,7 @@
* procedural language
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.112 2004/08/01 17:32:21 tgl Exp $
+ * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.113 2004/08/02 01:30:49 tgl Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
@@ -3582,7 +3582,7 @@ exec_eval_simple_expr(PLpgSQL_execstate * estate,
* need to have more than one active param list.
*/
paramLI = (ParamListInfo)
- MemoryContextAlloc(econtext->ecxt_per_tuple_memory,
+ MemoryContextAllocZero(econtext->ecxt_per_tuple_memory,
(expr->nparams + 1) * sizeof(ParamListInfoData));
/*
@@ -3591,12 +3591,11 @@ exec_eval_simple_expr(PLpgSQL_execstate * estate,
for (i = 0; i < expr->nparams; i++)
{
PLpgSQL_datum *datum = estate->datums[expr->params[i]];
- Oid paramtypeid;
paramLI[i].kind = PARAM_NUM;
paramLI[i].id = i + 1;
exec_eval_datum(estate, datum, expr->plan_argtypes[i],
- &paramtypeid,
+ &paramLI[i].ptype,
&paramLI[i].value, &paramLI[i].isnull);
}
paramLI[i].kind = PARAM_INVALID;
diff --git a/src/test/regress/expected/portals.out b/src/test/regress/expected/portals.out
index b8f83418982..a46a14ce80c 100644
--- a/src/test/regress/expected/portals.out
+++ b/src/test/regress/expected/portals.out
@@ -738,3 +738,38 @@ ROLLBACK;
-- should fail
FETCH FROM foo26;
ERROR: cursor "foo26" does not exist
+--
+-- Parameterized DECLARE needs to insert param values into the cursor portal
+--
+BEGIN;
+CREATE FUNCTION declares_cursor(text)
+ RETURNS void
+ AS 'DECLARE c CURSOR FOR SELECT stringu1 FROM tenk1 WHERE stringu1 LIKE $1;'
+ LANGUAGE 'sql';
+SELECT declares_cursor('AB%');
+ declares_cursor
+-----------------
+
+(1 row)
+
+FETCH ALL FROM c;
+ stringu1
+----------
+ ABAAAA
+ ABAAAA
+ ABAAAA
+ ABAAAA
+ ABAAAA
+ ABAAAA
+ ABAAAA
+ ABAAAA
+ ABAAAA
+ ABAAAA
+ ABAAAA
+ ABAAAA
+ ABAAAA
+ ABAAAA
+ ABAAAA
+(15 rows)
+
+ROLLBACK;
diff --git a/src/test/regress/sql/portals.sql b/src/test/regress/sql/portals.sql
index 807c847bc3c..c7e29c37868 100644
--- a/src/test/regress/sql/portals.sql
+++ b/src/test/regress/sql/portals.sql
@@ -218,3 +218,20 @@ ROLLBACK;
-- should fail
FETCH FROM foo26;
+
+--
+-- Parameterized DECLARE needs to insert param values into the cursor portal
+--
+
+BEGIN;
+
+CREATE FUNCTION declares_cursor(text)
+ RETURNS void
+ AS 'DECLARE c CURSOR FOR SELECT stringu1 FROM tenk1 WHERE stringu1 LIKE $1;'
+ LANGUAGE 'sql';
+
+SELECT declares_cursor('AB%');
+
+FETCH ALL FROM c;
+
+ROLLBACK;