aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser/parse_expr.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2009-11-09 02:36:59 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2009-11-09 02:36:59 +0000
commit2ace38d226246b83e5cc4d8f4063a82a485ddc95 (patch)
tree5ba7f075efde9d793b927253f28b5802c6806322 /src/backend/parser/parse_expr.c
parent39bd3fd1db6f3aa3764d4a1bebcd71c4e9c00281 (diff)
downloadpostgresql-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.c60
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;