diff options
Diffstat (limited to 'src/backend/parser/parse_expr.c')
-rw-r--r-- | src/backend/parser/parse_expr.c | 114 |
1 files changed, 76 insertions, 38 deletions
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index 6601bfe40ee..da4bcf208f9 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.219 2007/06/11 01:16:25 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.220 2007/06/11 22:22:42 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -59,10 +59,10 @@ static Node *transformMinMaxExpr(ParseState *pstate, MinMaxExpr *m); static Node *transformXmlExpr(ParseState *pstate, XmlExpr *x); static Node *transformXmlSerialize(ParseState *pstate, XmlSerialize *xs); static Node *transformBooleanTest(ParseState *pstate, BooleanTest *b); +static Node *transformCurrentOfExpr(ParseState *pstate, CurrentOfExpr *cexpr); static Node *transformColumnRef(ParseState *pstate, ColumnRef *cref); static Node *transformWholeRowRef(ParseState *pstate, char *schemaname, char *relname, int location); -static Node *transformBooleanTest(ParseState *pstate, BooleanTest *b); static Node *transformIndirection(ParseState *pstate, Node *basenode, List *indirection); static Node *typecast_expression(ParseState *pstate, Node *expr, @@ -244,19 +244,8 @@ transformExpr(ParseState *pstate, Node *expr) break; case T_CurrentOfExpr: - { - CurrentOfExpr *c = (CurrentOfExpr *) expr; - int sublevels_up; - - /* CURRENT OF can only appear at top level of UPDATE/DELETE */ - Assert(pstate->p_target_rangetblentry != NULL); - c->cvarno = RTERangeTablePosn(pstate, - pstate->p_target_rangetblentry, - &sublevels_up); - Assert(sublevels_up == 0); - result = expr; - break; - } + result = transformCurrentOfExpr(pstate, (CurrentOfExpr *) expr); + break; /********************************************* * Quietly accept node types that may be presented when we are @@ -549,57 +538,69 @@ transformColumnRef(ParseState *pstate, ColumnRef *cref) return node; } -static Node * -transformParamRef(ParseState *pstate, ParamRef *pref) +/* + * Locate the parameter type info for the given parameter number, and + * return a pointer to it. + */ +static Oid * +find_param_type(ParseState *pstate, int paramno) { - int paramno = pref->number; - ParseState *toppstate; - Param *param; + Oid *result; /* * Find topmost ParseState, which is where paramtype info lives. */ - toppstate = pstate; - while (toppstate->parentParseState != NULL) - toppstate = toppstate->parentParseState; + while (pstate->parentParseState != NULL) + pstate = pstate->parentParseState; /* Check parameter number is in range */ if (paramno <= 0) /* probably can't happen? */ ereport(ERROR, (errcode(ERRCODE_UNDEFINED_PARAMETER), errmsg("there is no parameter $%d", paramno))); - if (paramno > toppstate->p_numparams) + if (paramno > pstate->p_numparams) { - if (!toppstate->p_variableparams) + if (!pstate->p_variableparams) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_PARAMETER), errmsg("there is no parameter $%d", paramno))); /* Okay to enlarge param array */ - if (toppstate->p_paramtypes) - toppstate->p_paramtypes = - (Oid *) repalloc(toppstate->p_paramtypes, - paramno * sizeof(Oid)); + if (pstate->p_paramtypes) + pstate->p_paramtypes = (Oid *) repalloc(pstate->p_paramtypes, + paramno * sizeof(Oid)); else - toppstate->p_paramtypes = - (Oid *) palloc(paramno * sizeof(Oid)); + pstate->p_paramtypes = (Oid *) palloc(paramno * sizeof(Oid)); /* Zero out the previously-unreferenced slots */ - MemSet(toppstate->p_paramtypes + toppstate->p_numparams, + MemSet(pstate->p_paramtypes + pstate->p_numparams, 0, - (paramno - toppstate->p_numparams) * sizeof(Oid)); - toppstate->p_numparams = paramno; + (paramno - pstate->p_numparams) * sizeof(Oid)); + pstate->p_numparams = paramno; } - if (toppstate->p_variableparams) + + result = &pstate->p_paramtypes[paramno - 1]; + + if (pstate->p_variableparams) { /* If not seen before, initialize to UNKNOWN type */ - if (toppstate->p_paramtypes[paramno - 1] == InvalidOid) - toppstate->p_paramtypes[paramno - 1] = UNKNOWNOID; + if (*result == InvalidOid) + *result = UNKNOWNOID; } + return result; +} + +static Node * +transformParamRef(ParseState *pstate, ParamRef *pref) +{ + int paramno = pref->number; + Oid *pptype = find_param_type(pstate, paramno); + Param *param; + param = makeNode(Param); param->paramkind = PARAM_EXTERN; param->paramid = paramno; - param->paramtype = toppstate->p_paramtypes[paramno - 1]; + param->paramtype = *pptype; param->paramtypmod = -1; return (Node *) param; @@ -1596,6 +1597,43 @@ transformBooleanTest(ParseState *pstate, BooleanTest *b) return (Node *) b; } +static Node * +transformCurrentOfExpr(ParseState *pstate, CurrentOfExpr *cexpr) +{ + int sublevels_up; + + /* CURRENT OF can only appear at top level of UPDATE/DELETE */ + Assert(pstate->p_target_rangetblentry != NULL); + cexpr->cvarno = RTERangeTablePosn(pstate, + pstate->p_target_rangetblentry, + &sublevels_up); + Assert(sublevels_up == 0); + + /* If a parameter is used, it must be of type REFCURSOR */ + if (cexpr->cursor_name == NULL) + { + Oid *pptype = find_param_type(pstate, cexpr->cursor_param); + + if (pstate->p_variableparams && *pptype == UNKNOWNOID) + { + /* resolve unknown param type as REFCURSOR */ + *pptype = REFCURSOROID; + } + else if (*pptype != REFCURSOROID) + { + ereport(ERROR, + (errcode(ERRCODE_AMBIGUOUS_PARAMETER), + errmsg("inconsistent types deduced for parameter $%d", + cexpr->cursor_param), + errdetail("%s versus %s", + format_type_be(*pptype), + format_type_be(REFCURSOROID)))); + } + } + + return (Node *) cexpr; +} + /* * Construct a whole-row reference to represent the notation "relation.*". * |