aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser/parse_expr.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2002-05-12 23:43:04 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2002-05-12 23:43:04 +0000
commit3389a110d40a505951e7c7babdfb8681173bb2ca (patch)
tree438acebac5cfd161cf920bcda6ad168affcb96a7 /src/backend/parser/parse_expr.c
parentf9e4f611a18f64fd9106a72ec9af9e2220075780 (diff)
downloadpostgresql-3389a110d40a505951e7c7babdfb8681173bb2ca.tar.gz
postgresql-3389a110d40a505951e7c7babdfb8681173bb2ca.zip
Get rid of long-since-vestigial Iter node type, in favor of adding a
returns-set boolean field in Func and Oper nodes. This allows cleaner, more reliable tests for expressions returning sets in the planner and parser. For example, a WHERE clause returning a set is now detected and complained of in the parser, not only at runtime.
Diffstat (limited to 'src/backend/parser/parse_expr.c')
-rw-r--r--src/backend/parser/parse_expr.c107
1 files changed, 43 insertions, 64 deletions
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;