diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2009-11-09 02:36:59 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2009-11-09 02:36:59 +0000 |
commit | 2ace38d226246b83e5cc4d8f4063a82a485ddc95 (patch) | |
tree | 5ba7f075efde9d793b927253f28b5802c6806322 /src/backend/parser/parse_expr.c | |
parent | 39bd3fd1db6f3aa3764d4a1bebcd71c4e9c00281 (diff) | |
download | postgresql-2ace38d226246b83e5cc4d8f4063a82a485ddc95.tar.gz postgresql-2ace38d226246b83e5cc4d8f4063a82a485ddc95.zip |
Fix WHERE CURRENT OF to work as designed within plpgsql. The argument
can be the name of a plpgsql cursor variable, which formerly was converted
to $N before the core parser saw it, but that's no longer the case.
Deal with plain name references to plpgsql variables, and add a regression
test case that exposes the failure.
Diffstat (limited to 'src/backend/parser/parse_expr.c')
-rw-r--r-- | src/backend/parser/parse_expr.c | 60 |
1 files changed, 35 insertions, 25 deletions
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index 1e76d3b546f..bae5c7fafad 100644 --- a/src/backend/parser/parse_expr.c +++ b/src/backend/parser/parse_expr.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.247 2009/10/31 01:41:31 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.248 2009/11/09 02:36:56 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1963,32 +1963,42 @@ transformCurrentOfExpr(ParseState *pstate, CurrentOfExpr *cexpr) Assert(sublevels_up == 0); /* - * If a parameter is used, it must be of type REFCURSOR. To verify - * that the parameter hooks think so, build a dummy ParamRef and - * transform it. + * Check to see if the cursor name matches a parameter of type REFCURSOR. + * If so, replace the raw name reference with a parameter reference. + * (This is a hack for the convenience of plpgsql.) */ - if (cexpr->cursor_name == NULL) + if (cexpr->cursor_name != NULL) /* in case already transformed */ { - ParamRef *p = makeNode(ParamRef); - Node *n; - - p->number = cexpr->cursor_param; - p->location = -1; - n = transformParamRef(pstate, p); - /* Allow the parameter type to be inferred if it's unknown */ - if (exprType(n) == UNKNOWNOID) - n = coerce_type(pstate, n, UNKNOWNOID, - REFCURSOROID, -1, - COERCION_IMPLICIT, COERCE_IMPLICIT_CAST, - -1); - if (exprType(n) != REFCURSOROID) - ereport(ERROR, - (errcode(ERRCODE_AMBIGUOUS_PARAMETER), - errmsg("inconsistent types deduced for parameter $%d", - cexpr->cursor_param), - errdetail("%s versus %s", - format_type_be(exprType(n)), - format_type_be(REFCURSOROID)))); + ColumnRef *cref = makeNode(ColumnRef); + Node *node = NULL; + + /* Build an unqualified ColumnRef with the given name */ + cref->fields = list_make1(makeString(cexpr->cursor_name)); + cref->location = -1; + + /* See if there is a translation available from a parser hook */ + if (pstate->p_pre_columnref_hook != NULL) + node = (*pstate->p_pre_columnref_hook) (pstate, cref); + if (node == NULL && pstate->p_post_columnref_hook != NULL) + node = (*pstate->p_post_columnref_hook) (pstate, cref, NULL); + + /* + * XXX Should we throw an error if we get a translation that isn't + * a refcursor Param? For now it seems best to silently ignore + * false matches. + */ + if (node != NULL && IsA(node, Param)) + { + Param *p = (Param *) node; + + if (p->paramkind == PARAM_EXTERN && + p->paramtype == REFCURSOROID) + { + /* Matches, so convert CURRENT OF to a param reference */ + cexpr->cursor_name = NULL; + cexpr->cursor_param = p->paramid; + } + } } return (Node *) cexpr; |