diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/commands/portalcmds.c | 19 | ||||
-rw-r--r-- | src/backend/commands/prepare.c | 11 | ||||
-rw-r--r-- | src/backend/commands/schemacmds.c | 4 | ||||
-rw-r--r-- | src/backend/executor/execQual.c | 62 | ||||
-rw-r--r-- | src/backend/executor/functions.c | 8 | ||||
-rw-r--r-- | src/backend/executor/spi.c | 8 | ||||
-rw-r--r-- | src/backend/nodes/Makefile | 4 | ||||
-rw-r--r-- | src/backend/nodes/params.c | 122 | ||||
-rw-r--r-- | src/backend/optimizer/util/clauses.c | 42 | ||||
-rw-r--r-- | src/backend/tcop/postgres.c | 3 | ||||
-rw-r--r-- | src/backend/tcop/pquery.c | 6 | ||||
-rw-r--r-- | src/backend/tcop/utility.c | 6 | ||||
-rw-r--r-- | src/include/commands/portalcmds.h | 4 | ||||
-rw-r--r-- | src/include/nodes/params.h | 13 | ||||
-rw-r--r-- | src/include/tcop/utility.h | 7 | ||||
-rw-r--r-- | src/pl/plpgsql/src/pl_exec.c | 7 | ||||
-rw-r--r-- | src/test/regress/expected/portals.out | 35 | ||||
-rw-r--r-- | src/test/regress/sql/portals.sql | 17 |
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], - ¶mtypeid, + ¶mLI[i].ptype, ¶mLI[i].value, ¶mLI[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; |