diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2001-06-19 22:39:12 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2001-06-19 22:39:12 +0000 |
commit | 116d2bba7eeaf25c544bc187e3ad2a8677a9a22c (patch) | |
tree | c77a6b20a3acdbb6e25a1fc4a561c0e839ddbb1e /src/backend/parser/parse_expr.c | |
parent | 8c30aca2ba1a48d38b1206f8559d1dc6b65c5ca7 (diff) | |
download | postgresql-116d2bba7eeaf25c544bc187e3ad2a8677a9a22c.tar.gz postgresql-116d2bba7eeaf25c544bc187e3ad2a8677a9a22c.zip |
Add IS UNKNOWN, IS NOT UNKNOWN boolean tests, fix the existing boolean
tests to return the correct results per SQL9x when given NULL inputs.
Reimplement these tests as well as IS [NOT] NULL to have their own
expression node types, instead of depending on special functions.
From Joe Conway, with a little help from Tom Lane.
Diffstat (limited to 'src/backend/parser/parse_expr.c')
-rw-r--r-- | src/backend/parser/parse_expr.c | 120 |
1 files changed, 81 insertions, 39 deletions
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c index a196779f44c..5fda57f5f92 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.97 2001/06/04 23:27:23 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.98 2001/06/19 22:39:11 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -167,32 +167,6 @@ transformExpr(ParseState *pstate, Node *expr, int precedence) result = (Node *) make_op(a->opname, lexpr, rexpr); } break; - case ISNULL: - { - Node *lexpr = transformExpr(pstate, - a->lexpr, - precedence); - - result = ParseFuncOrColumn(pstate, - "nullvalue", - makeList1(lexpr), - false, false, - precedence); - } - break; - case NOTNULL: - { - Node *lexpr = transformExpr(pstate, - a->lexpr, - precedence); - - result = ParseFuncOrColumn(pstate, - "nonnullvalue", - makeList1(lexpr), - false, false, - precedence); - } - break; case AND: { Node *lexpr = transformExpr(pstate, @@ -203,13 +177,15 @@ transformExpr(ParseState *pstate, Node *expr, int precedence) precedence); Expr *expr = makeNode(Expr); - if (exprType(lexpr) != BOOLOID) + if (! coerce_to_boolean(pstate, &lexpr)) elog(ERROR, "left-hand side of AND is type '%s', not '%s'", - typeidTypeName(exprType(lexpr)), typeidTypeName(BOOLOID)); + typeidTypeName(exprType(lexpr)), + typeidTypeName(BOOLOID)); - if (exprType(rexpr) != BOOLOID) + if (! coerce_to_boolean(pstate, &rexpr)) elog(ERROR, "right-hand side of AND is type '%s', not '%s'", - typeidTypeName(exprType(rexpr)), typeidTypeName(BOOLOID)); + typeidTypeName(exprType(rexpr)), + typeidTypeName(BOOLOID)); expr->typeOid = BOOLOID; expr->opType = AND_EXPR; @@ -227,12 +203,16 @@ transformExpr(ParseState *pstate, Node *expr, int precedence) precedence); Expr *expr = makeNode(Expr); - if (exprType(lexpr) != BOOLOID) + if (! coerce_to_boolean(pstate, &lexpr)) elog(ERROR, "left-hand side of OR is type '%s', not '%s'", - typeidTypeName(exprType(lexpr)), typeidTypeName(BOOLOID)); - if (exprType(rexpr) != BOOLOID) + typeidTypeName(exprType(lexpr)), + typeidTypeName(BOOLOID)); + + if (! coerce_to_boolean(pstate, &rexpr)) elog(ERROR, "right-hand side of OR is type '%s', not '%s'", - typeidTypeName(exprType(rexpr)), typeidTypeName(BOOLOID)); + typeidTypeName(exprType(rexpr)), + typeidTypeName(BOOLOID)); + expr->typeOid = BOOLOID; expr->opType = OR_EXPR; expr->args = makeList2(lexpr, rexpr); @@ -246,9 +226,11 @@ transformExpr(ParseState *pstate, Node *expr, int precedence) precedence); Expr *expr = makeNode(Expr); - if (exprType(rexpr) != BOOLOID) + if (! coerce_to_boolean(pstate, &rexpr)) elog(ERROR, "argument to NOT is type '%s', not '%s'", - typeidTypeName(exprType(rexpr)), typeidTypeName(BOOLOID)); + typeidTypeName(exprType(rexpr)), + typeidTypeName(BOOLOID)); + expr->typeOid = BOOLOID; expr->opType = NOT_EXPR; expr->args = makeList1(rexpr); @@ -491,7 +473,8 @@ transformExpr(ParseState *pstate, Node *expr, int precedence) CaseWhen *w = (CaseWhen *) expr; w->expr = transformExpr(pstate, w->expr, precedence); - if (exprType(w->expr) != BOOLOID) + + if (! coerce_to_boolean(pstate, &w->expr)) elog(ERROR, "WHEN clause must have a boolean result"); /* @@ -510,6 +493,59 @@ transformExpr(ParseState *pstate, Node *expr, int precedence) break; } + case T_NullTest: + { + NullTest *n = (NullTest *) expr; + + n->arg = transformExpr(pstate, n->arg, precedence); + /* the argument can be any type, so don't coerce it */ + result = expr; + break; + } + + case T_BooleanTest: + { + BooleanTest *b = (BooleanTest *) expr; + + b->arg = transformExpr(pstate, b->arg, precedence); + + if (! coerce_to_boolean(pstate, &b->arg)) + { + const char *clausename; + + 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 */ + } + + elog(ERROR, "Argument of %s must be boolean", + clausename); + } + result = expr; + break; + } + /* * Quietly accept node types that may be presented when we are * called on an already-transformed tree. @@ -669,8 +705,14 @@ exprType(Node *expr) case T_CaseWhen: type = exprType(((CaseWhen *) expr)->result); break; + case T_NullTest: + type = BOOLOID; + break; + case T_BooleanTest: + type = BOOLOID; + break; case T_Ident: - /* is this right? */ + /* XXX is this right? */ type = UNKNOWNOID; break; default: |