Allow DECLARE CURSOR to take parameters from the portal in which it is
authorTom Lane
Mon, 2 Aug 2004 01:30:51 +0000 (01:30 +0000)
committerTom Lane
Mon, 2 Aug 2004 01:30:51 +0000 (01:30 +0000)
executed.  Previously, the DECLARE would succeed but subsequent FETCHes
would fail since the parameter values supplied to DECLARE were not
propagated to the portal created for the cursor.
In support of this, add type Oids to ParamListInfo entries, which seems
like a good idea anyway since code that extracts a value can double-check
that it got the type of value it was expecting.
Oliver Jowett, with minor editorialization by Tom Lane.

18 files changed:
src/backend/commands/portalcmds.c
src/backend/commands/prepare.c
src/backend/commands/schemacmds.c
src/backend/executor/execQual.c
src/backend/executor/functions.c
src/backend/executor/spi.c
src/backend/nodes/Makefile
src/backend/nodes/params.c [new file with mode: 0644]
src/backend/optimizer/util/clauses.c
src/backend/tcop/postgres.c
src/backend/tcop/pquery.c
src/backend/tcop/utility.c
src/include/commands/portalcmds.h
src/include/nodes/params.h
src/include/tcop/utility.h
src/pl/plpgsql/src/pl_exec.c
src/test/regress/expected/portals.out
src/test/regress/sql/portals.sql

index 509d9e0dfa12fb039b6417828e3a11b814fd4dd5..64d0c77489bbc1ac2b7c9dcbf6ce5b4a4ab6005b 100644 (file)
@@ -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);
 
index 9c183cb7827b193881a6cbfa1e44f4d296278e5d..d4c8357ff0b4d0b54efbe4853b3e0cfd4a4c8810 100644 (file)
@@ -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++;
index 2dead1e15a123b4a7390266789049b49cfa54ed3..d73c65aa6b29aead75f63d503c046201d32c43de 100644 (file)
@@ -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();
        }
index e4362c38f58437e90aa13057d528b119fccfc967..6ac61d3c5beb12389149bdea69e9a33ef7607fdf 100644 (file)
@@ -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;
    }
 }
 
index 0073f8f55c16082a2cec328ef114de8e0f86a67e..cfcccb6169e309682240d986413a8128845f1a41 100644 (file)
@@ -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];
        }
index 7840f5f787afc86854c829bf87f414da83455f73..33379d5222246c7f2ad64ccf5a8f77692dcfa7e7 100644 (file)
@@ -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();
            }
index a4c19201bb2f9b92ec99299875136c6f75b70012..86f533e7a0e4c3c1a7d0b819f9f3b04867154023 100644 (file)
@@ -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 (file)
index 0000000..43bc40b
--- /dev/null
@@ -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;
+}
index e7088d2b7610bea2b450f3e5079497b1b339fba1..68d2529889e86d7c884acb63c4ed8fdcb1a3a0e7 100644 (file)
@@ -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);
            }
        }
index 89ee40a53215141c806934442709303a9242570a..bfbe0a53c5c5caee1cfae7e6e99dd365842f2405 100644 (file)
@@ -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++;
index 8973cca6d2673ab9d9db61680d36ddd7a61d5917..588523f84936843e61b23884a19b14df384e1c1c 100644 (file)
@@ -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 */
index d8d718a18239ff17f7d268d1720e43f993d04744..b9c50d7d81c72d03544ac79e7d6a29fc4f465ee7 100644 (file)
@@ -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:
index 60e7d524d29c5c88e890c8b60b2c1d7688f7b9de..b16ef2338463b0d4aad8ccc983c0d1966d629327 100644 (file)
@@ -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);
index e22ff27a3b7967ac798abd6bd4a0b4fcbbf85a08..d4acbe2699e527fb2eca78cfceac90b58810a764 100644 (file)
@@ -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 */
index 59a9a8133d1545d423e7ab134bca96adcdb4cd8e..a5398e0dedae80c63699cfcf75228b69d5389d07 100644 (file)
@@ -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);
 
index f075b96c0fc6af539c92578da358a2f4121c49eb..124d3c4bad29207ebf71e8c1c8f607122e1a4c47 100644 (file)
@@ -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],
-                       ¶mtypeid,
+                       ¶mLI[i].ptype,
                        ¶mLI[i].value, ¶mLI[i].isnull);
    }
    paramLI[i].kind = PARAM_INVALID;
index b8f834189823e1462dee43f512058b0744c8854b..a46a14ce80ce8ce7fc2ea28a9c045f97ebaaf273 100644 (file)
@@ -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;
index 807c847bc3c1da72e71f7836d079a44092ef4634..c7e29c378680f6dbf53e99841949b49537e04f6e 100644 (file)
@@ -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;