diff options
Diffstat (limited to 'src/backend/parser')
-rw-r--r-- | src/backend/parser/parse_clause.c | 28 | ||||
-rw-r--r-- | src/backend/parser/parse_coerce.c | 46 | ||||
-rw-r--r-- | src/backend/parser/parse_expr.c | 107 | ||||
-rw-r--r-- | src/backend/parser/parse_func.c | 40 | ||||
-rw-r--r-- | src/backend/parser/parse_node.c | 5 |
5 files changed, 83 insertions, 143 deletions
diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c index 19aa688ff94..a41182e9398 100644 --- a/src/backend/parser/parse_clause.c +++ b/src/backend/parser/parse_clause.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.91 2002/05/12 20:10:04 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.92 2002/05/12 23:43:03 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -285,14 +285,7 @@ transformJoinUsingClause(ParseState *pstate, List *leftVars, List *rightVars) */ result = transformExpr(pstate, result); - /* - * We expect the result to yield bool directly, otherwise complain. We - * could try coerce_to_boolean() here, but it seems likely that an "=" - * operator that doesn't return bool is wrong anyway. - */ - if (exprType(result) != BOOLOID) - elog(ERROR, "JOIN/USING clause must return type boolean, not type %s", - format_type_be(exprType(result))); + result = coerce_to_boolean(result, "JOIN/USING"); return result; } /* transformJoinUsingClause() */ @@ -326,9 +319,7 @@ transformJoinOnClause(ParseState *pstate, JoinExpr *j, /* This part is just like transformWhereClause() */ result = transformExpr(pstate, j->quals); - if (!coerce_to_boolean(pstate, &result)) - elog(ERROR, "JOIN/ON clause must return type boolean, not type %s", - format_type_be(exprType(result))); + result = coerce_to_boolean(result, "JOIN/ON"); pstate->p_namespace = save_namespace; @@ -486,14 +477,7 @@ transformRangeFunction(ParseState *pstate, RangeFunction *r) elog(ERROR, "cannot use subselect in FROM function expression"); /* - * Remove any Iter nodes added by parse_func.c. We oughta get rid of - * Iter completely ... - */ - while (funcexpr && IsA(funcexpr, Iter)) - funcexpr = ((Iter *) funcexpr)->iterexpr; - - /* - * Insist we now have a bare function call (explain.c is the only place + * Insist we have a bare function call (explain.c is the only place * that depends on this, I think). If this fails, it's probably because * transformExpr interpreted the function notation as a type coercion. */ @@ -947,9 +931,7 @@ transformWhereClause(ParseState *pstate, Node *clause) qual = transformExpr(pstate, clause); - if (!coerce_to_boolean(pstate, &qual)) - elog(ERROR, "WHERE clause must return type boolean, not type %s", - format_type_be(exprType(qual))); + qual = coerce_to_boolean(qual, "WHERE"); return qual; } diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c index 57aad4dbf58..716cbcbb756 100644 --- a/src/backend/parser/parse_coerce.c +++ b/src/backend/parser/parse_coerce.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.71 2002/04/25 02:56:55 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.72 2002/05/12 23:43:03 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -313,26 +313,37 @@ coerce_type_typmod(ParseState *pstate, Node *node, /* coerce_to_boolean() * Coerce an argument of a construct that requires boolean input - * (AND, OR, NOT, etc). + * (AND, OR, NOT, etc). Also check that input is not a set. * - * If successful, update *pnode to be the transformed argument (if any - * transformation is needed), and return TRUE. If fail, return FALSE. - * (The caller must check for FALSE and emit a suitable error message.) + * Returns the possibly-transformed node tree. */ -bool -coerce_to_boolean(ParseState *pstate, Node **pnode) +Node * +coerce_to_boolean(Node *node, const char *constructName) { - Oid inputTypeId = exprType(*pnode); + Oid inputTypeId = exprType(node); Oid targetTypeId; - if (inputTypeId == BOOLOID) - return true; /* no work */ - targetTypeId = BOOLOID; - if (!can_coerce_type(1, &inputTypeId, &targetTypeId, false)) - return false; /* fail, but let caller choose error msg */ - *pnode = coerce_type(pstate, *pnode, inputTypeId, targetTypeId, -1, - false); - return true; + if (inputTypeId != BOOLOID) + { + targetTypeId = BOOLOID; + if (!can_coerce_type(1, &inputTypeId, &targetTypeId, false)) + { + /* translator: first %s is name of a SQL construct, eg WHERE */ + elog(ERROR, "Argument of %s must be type boolean, not type %s", + constructName, format_type_be(inputTypeId)); + } + node = coerce_type(NULL, node, inputTypeId, targetTypeId, -1, + false); + } + + if (expression_returns_set(node)) + { + /* translator: %s is name of a SQL construct, eg WHERE */ + elog(ERROR, "Argument of %s must not be a set function", + constructName); + } + + return node; } @@ -782,7 +793,8 @@ build_func_call(Oid funcid, Oid rettype, List *args) funcnode = makeNode(Func); funcnode->funcid = funcid; - funcnode->functype = rettype; + funcnode->funcresulttype = rettype; + funcnode->funcretset = false; /* only possible case here */ funcnode->func_fcache = NULL; expr = makeNode(Expr); diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index 100bf9a7b49..e29d5ca4b5c 100644 --- a/src/backend/parser/parse_expr.c +++ b/src/backend/parser/parse_expr.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.116 2002/04/28 00:49:12 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.117 2002/05/12 23:43:03 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -31,6 +31,7 @@ #include "parser/parse_target.h" #include "parser/parse_type.h" #include "utils/builtins.h" +#include "utils/lsyscache.h" #include "utils/syscache.h" @@ -230,15 +231,8 @@ transformExpr(ParseState *pstate, Node *expr) a->rexpr); Expr *expr = makeNode(Expr); - if (!coerce_to_boolean(pstate, &lexpr)) - elog(ERROR, "left-hand side of AND is type '%s', not '%s'", - format_type_be(exprType(lexpr)), - format_type_be(BOOLOID)); - - if (!coerce_to_boolean(pstate, &rexpr)) - elog(ERROR, "right-hand side of AND is type '%s', not '%s'", - format_type_be(exprType(rexpr)), - format_type_be(BOOLOID)); + lexpr = coerce_to_boolean(lexpr, "AND"); + rexpr = coerce_to_boolean(rexpr, "AND"); expr->typeOid = BOOLOID; expr->opType = AND_EXPR; @@ -254,15 +248,8 @@ transformExpr(ParseState *pstate, Node *expr) a->rexpr); Expr *expr = makeNode(Expr); - if (!coerce_to_boolean(pstate, &lexpr)) - elog(ERROR, "left-hand side of OR is type '%s', not '%s'", - format_type_be(exprType(lexpr)), - format_type_be(BOOLOID)); - - if (!coerce_to_boolean(pstate, &rexpr)) - elog(ERROR, "right-hand side of OR is type '%s', not '%s'", - format_type_be(exprType(rexpr)), - format_type_be(BOOLOID)); + lexpr = coerce_to_boolean(lexpr, "OR"); + rexpr = coerce_to_boolean(rexpr, "OR"); expr->typeOid = BOOLOID; expr->opType = OR_EXPR; @@ -276,10 +263,7 @@ transformExpr(ParseState *pstate, Node *expr) a->rexpr); Expr *expr = makeNode(Expr); - if (!coerce_to_boolean(pstate, &rexpr)) - elog(ERROR, "argument to NOT is type '%s', not '%s'", - format_type_be(exprType(rexpr)), - format_type_be(BOOLOID)); + rexpr = coerce_to_boolean(rexpr, "NOT"); expr->typeOid = BOOLOID; expr->opType = NOT_EXPR; @@ -426,9 +410,15 @@ transformExpr(ParseState *pstate, Node *expr) opname, typeidTypeName(opform->oprresult), typeidTypeName(BOOLOID)); + if (get_func_retset(opform->oprcode)) + elog(ERROR, "'%s' must not return a set" + " to be used with quantified predicate subquery", + opname); + newop = makeOper(oprid(optup), /* opno */ InvalidOid, /* opid */ - opform->oprresult); + opform->oprresult, + false); sublink->oper = lappend(sublink->oper, newop); ReleaseSysCache(optup); } @@ -467,8 +457,7 @@ transformExpr(ParseState *pstate, Node *expr) } neww->expr = transformExpr(pstate, warg); - if (!coerce_to_boolean(pstate, &neww->expr)) - elog(ERROR, "WHEN clause must have a boolean result"); + neww->expr = coerce_to_boolean(neww->expr, "CASE/WHEN"); /* * result is NULL for NULLIF() construct - thomas @@ -553,42 +542,38 @@ transformExpr(ParseState *pstate, Node *expr) case T_BooleanTest: { BooleanTest *b = (BooleanTest *) expr; + const char *clausename; - b->arg = transformExpr(pstate, b->arg); - - if (!coerce_to_boolean(pstate, &b->arg)) + switch (b->booltesttype) { - const char *clausename; + case IS_TRUE: + clausename = "IS TRUE"; + break; + case IS_NOT_TRUE: + clausename = "IS NOT TRUE"; + break; + case IS_FALSE: + clausename = "IS FALSE"; + break; + case IS_NOT_FALSE: + clausename = "IS NOT FALSE"; + break; + case IS_UNKNOWN: + clausename = "IS UNKNOWN"; + break; + case IS_NOT_UNKNOWN: + clausename = "IS NOT UNKNOWN"; + break; + default: + elog(ERROR, "transformExpr: unexpected booltesttype %d", + (int) b->booltesttype); + clausename = NULL; /* keep compiler quiet */ + } - switch (b->booltesttype) - { - case IS_TRUE: - clausename = "IS TRUE"; - break; - case IS_NOT_TRUE: - clausename = "IS NOT TRUE"; - break; - case IS_FALSE: - clausename = "IS FALSE"; - break; - case IS_NOT_FALSE: - clausename = "IS NOT FALSE"; - break; - case IS_UNKNOWN: - clausename = "IS UNKNOWN"; - break; - case IS_NOT_UNKNOWN: - clausename = "IS NOT UNKNOWN"; - break; - default: - elog(ERROR, "transformExpr: unexpected booltesttype %d", - (int) b->booltesttype); - clausename = NULL; /* keep compiler quiet */ - } + b->arg = transformExpr(pstate, b->arg); + + b->arg = coerce_to_boolean(b->arg, clausename); - elog(ERROR, "Argument of %s must be boolean", - clausename); - } result = expr; break; } @@ -833,12 +818,6 @@ exprType(Node *expr) switch (nodeTag(expr)) { - case T_Func: - type = ((Func *) expr)->functype; - break; - case T_Iter: - type = ((Iter *) expr)->itertype; - break; case T_Var: type = ((Var *) expr)->vartype; break; diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c index 339577f39ca..1912ab4e072 100644 --- a/src/backend/parser/parse_func.c +++ b/src/backend/parser/parse_func.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.128 2002/05/12 20:10:04 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.129 2002/05/12 23:43:03 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -280,7 +280,8 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, Func *funcnode = makeNode(Func); funcnode->funcid = funcid; - funcnode->functype = rettype; + funcnode->funcresulttype = rettype; + funcnode->funcretset = retset; funcnode->func_fcache = NULL; expr->typeOid = rettype; @@ -289,21 +290,6 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, expr->args = fargs; retval = (Node *) expr; - - /* - * if the function returns a set of values, then we need to iterate - * over all the returned values in the executor, so we stick an iter - * node here. if it returns a singleton, then we don't need the iter - * node. - */ - if (retset) - { - Iter *iter = makeNode(Iter); - - iter->itertype = rettype; - iter->iterexpr = retval; - retval = (Node *) iter; - } } else { @@ -1186,26 +1172,6 @@ ParseComplexProjection(ParseState *pstate, */ switch (nodeTag(first_arg)) { - case T_Iter: - { - Iter *iter = (Iter *) first_arg; - - /* - * If it's an Iter, we stick the FieldSelect - * *inside* the Iter --- this is klugy, but necessary - * because ExecTargetList() currently does the right thing - * only when the Iter node is at the top level of a - * targetlist item. - * - * XXX Iter should go away altogether... - */ - fselect = setup_field_select(iter->iterexpr, - funcname, argrelid); - iter->iterexpr = (Node *) fselect; - iter->itertype = fselect->resulttype; - return (Node *) iter; - break; - } case T_Var: { Var *var = (Var *) first_arg; diff --git a/src/backend/parser/parse_node.c b/src/backend/parser/parse_node.c index 2c4467035a5..e4b0766c63f 100644 --- a/src/backend/parser/parse_node.c +++ b/src/backend/parser/parse_node.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.64 2002/05/01 19:26:07 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.65 2002/05/12 23:43:03 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -135,7 +135,8 @@ make_op(List *opname, Node *ltree, Node *rtree) newop = makeOper(oprid(tup), /* opno */ InvalidOid, /* opid */ - opform->oprresult); /* operator result type */ + opform->oprresult, /* opresulttype */ + get_func_retset(opform->oprcode)); /* opretset */ result = makeNode(Expr); result->typeOid = opform->oprresult; |