OSDN Git Service

Add IS UNKNOWN, IS NOT UNKNOWN boolean tests, fix the existing boolean
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 19 Jun 2001 22:39:12 +0000 (22:39 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 19 Jun 2001 22:39:12 +0000 (22:39 +0000)
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.

18 files changed:
doc/src/sgml/func.sgml
doc/src/sgml/syntax.sgml
src/backend/executor/execQual.c
src/backend/nodes/copyfuncs.c
src/backend/nodes/equalfuncs.c
src/backend/nodes/outfuncs.c
src/backend/nodes/readfuncs.c
src/backend/optimizer/util/clauses.c
src/backend/parser/gram.y
src/backend/parser/keywords.c
src/backend/parser/parse_clause.c
src/backend/parser/parse_coerce.c
src/backend/parser/parse_expr.c
src/backend/utils/adt/ruleutils.c
src/include/catalog/catversion.h
src/include/nodes/nodes.h
src/include/nodes/parsenodes.h
src/include/parser/parse_coerce.h

index dc64632..00d476e 100644 (file)
@@ -1,4 +1,4 @@
-<!-- $Header: /cvsroot/pgsql/doc/src/sgml/func.sgml,v 1.61 2001/06/15 21:03:07 tgl Exp $ -->
+<!-- $Header: /cvsroot/pgsql/doc/src/sgml/func.sgml,v 1.62 2001/06/19 22:39:08 tgl Exp $ -->
 
 <chapter id="functions">
  <title>Functions and Operators</title>
    <productname>Microsoft Access</productname>) to work, but this may
    be discontinued in a future release.
   </para>
+
+  <para>
+   Boolean values can be tested using the constructs
+<synopsis>
+<replaceable>expression</replaceable> IS TRUE
+<replaceable>expression</replaceable> IS NOT TRUE
+<replaceable>expression</replaceable> IS FALSE
+<replaceable>expression</replaceable> IS NOT FALSE
+<replaceable>expression</replaceable> IS UNKNOWN
+<replaceable>expression</replaceable> IS NOT UNKNOWN
+</synopsis>
+   These are similar to <literal>IS NULL</literal> in that they will
+   always return TRUE or FALSE, never NULL, even when the operand is NULL.
+   A NULL input is treated as the logical value UNKNOWN.
+  </para>
  </sect1>
 
 
index 9234e3c..3008512 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$Header: /cvsroot/pgsql/doc/src/sgml/syntax.sgml,v 1.42 2001/05/12 22:51:35 petere Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/syntax.sgml,v 1.43 2001/06/19 22:39:08 tgl Exp $
 -->
 
 <chapter id="sql-syntax">
@@ -1060,7 +1060,7 @@ SELECT (5 !) - 6;
       <row>
        <entry><token>IS</token></entry>
        <entry></entry>
-       <entry>test for TRUE, FALSE, NULL</entry>
+       <entry>test for TRUE, FALSE, UNKNOWN, NULL</entry>
       </row>
 
       <row>
index 84aa271..fb950fd 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.86 2001/04/19 04:29:02 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/executor/execQual.c,v 1.87 2001/06/19 22:39:11 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -62,6 +62,10 @@ static Datum ExecEvalAnd(Expr *andExpr, ExprContext *econtext, bool *isNull);
 static Datum ExecEvalOr(Expr *orExpr, ExprContext *econtext, bool *isNull);
 static Datum ExecEvalCase(CaseExpr *caseExpr, ExprContext *econtext,
                         bool *isNull, ExprDoneCond *isDone);
+static Datum ExecEvalNullTest(NullTest *ntest, ExprContext *econtext,
+                        bool *isNull, ExprDoneCond *isDone);
+static Datum ExecEvalBooleanTest(BooleanTest *btest, ExprContext *econtext,
+                        bool *isNull, ExprDoneCond *isDone);
 
 
 /*----------
@@ -1092,6 +1096,126 @@ ExecEvalCase(CaseExpr *caseExpr, ExprContext *econtext,
 }
 
 /* ----------------------------------------------------------------
+ *             ExecEvalNullTest
+ *
+ *             Evaluate a NullTest node.
+ * ----------------------------------------------------------------
+ */
+static Datum
+ExecEvalNullTest(NullTest *ntest,
+                                ExprContext *econtext,
+                                bool *isNull,
+                                ExprDoneCond *isDone)
+{
+       Datum           result;
+
+       result = ExecEvalExpr(ntest->arg, econtext, isNull, isDone);
+       switch (ntest->nulltesttype)
+    {
+        case IS_NULL:
+            if (*isNull)
+            {
+                *isNull = false;
+                return BoolGetDatum(true);
+            }
+            else
+                return BoolGetDatum(false);
+        case IS_NOT_NULL:
+            if (*isNull)
+            {
+                *isNull = false;
+                return BoolGetDatum(false);
+            }
+            else
+                return BoolGetDatum(true);
+        default:
+            elog(ERROR, "ExecEvalNullTest: unexpected nulltesttype %d",
+                 (int) ntest->nulltesttype);
+            return (Datum) 0;  /* keep compiler quiet */
+    }
+}
+
+/* ----------------------------------------------------------------
+ *             ExecEvalBooleanTest
+ *
+ *             Evaluate a BooleanTest node.
+ * ----------------------------------------------------------------
+ */
+static Datum
+ExecEvalBooleanTest(BooleanTest *btest,
+                                       ExprContext *econtext,
+                                       bool *isNull,
+                                       ExprDoneCond *isDone)
+{
+       Datum           result;
+
+       result = ExecEvalExpr(btest->arg, econtext, isNull, isDone);
+       switch (btest->booltesttype)
+    {
+        case IS_TRUE:
+            if (*isNull)
+            {
+                *isNull = false;
+                return BoolGetDatum(false);
+            }
+            else if (DatumGetBool(result))
+                return BoolGetDatum(true);
+                       else
+                return BoolGetDatum(false);
+        case IS_NOT_TRUE:
+            if (*isNull)
+            {
+                *isNull = false;
+                return BoolGetDatum(true);
+            }
+            else if (DatumGetBool(result))
+                return BoolGetDatum(false);
+                       else
+                return BoolGetDatum(true);
+        case IS_FALSE:
+            if (*isNull)
+            {
+                *isNull = false;
+                return BoolGetDatum(false);
+            }
+            else if (DatumGetBool(result))
+                return BoolGetDatum(false);
+                       else
+                return BoolGetDatum(true);
+        case IS_NOT_FALSE:
+            if (*isNull)
+            {
+                *isNull = false;
+                return BoolGetDatum(true);
+            }
+            else if (DatumGetBool(result))
+                return BoolGetDatum(true);
+                       else
+                return BoolGetDatum(false);
+        case IS_UNKNOWN:
+            if (*isNull)
+            {
+                *isNull = false;
+                return BoolGetDatum(true);
+            }
+                       else
+                return BoolGetDatum(false);
+        case IS_NOT_UNKNOWN:
+            if (*isNull)
+            {
+                *isNull = false;
+                return BoolGetDatum(false);
+            }
+                       else
+                return BoolGetDatum(true);
+        default:
+            elog(ERROR, "ExecEvalBooleanTest: unexpected booltesttype %d",
+                 (int) btest->booltesttype);
+            return (Datum) 0;  /* keep compiler quiet */
+    }
+}
+
+/* ----------------------------------------------------------------
  *             ExecEvalFieldSelect
  *
  *             Evaluate a FieldSelect node.
@@ -1266,6 +1390,18 @@ ExecEvalExpr(Node *expression,
                                                                        isNull,
                                                                        isDone);
                        break;
+               case T_NullTest:
+                       retDatum = ExecEvalNullTest((NullTest *) expression,
+                                                                       econtext,
+                                                                       isNull,
+                                                                       isDone);
+                       break;
+               case T_BooleanTest:
+                       retDatum = ExecEvalBooleanTest((BooleanTest *) expression,
+                                                                       econtext,
+                                                                       isNull,
+                                                                       isDone);
+                       break;
 
                default:
                        elog(ERROR, "ExecEvalExpr: unknown expression type %d",
index 77ae4fb..6cf5b35 100644 (file)
@@ -15,7 +15,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.144 2001/06/09 23:21:54 petere Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.145 2001/06/19 22:39:11 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1017,6 +1017,42 @@ _copyCaseWhen(CaseWhen *from)
        return newnode;
 }
 
+/* ----------------
+ *             _copyNullTest
+ * ----------------
+ */
+static NullTest *
+_copyNullTest(NullTest *from)
+{
+       NullTest *newnode = makeNode(NullTest);
+
+       /*
+        * copy remainder of node
+        */
+       Node_Copy(from, newnode, arg);
+       newnode->nulltesttype = from->nulltesttype;
+
+       return newnode;
+}
+
+/* ----------------
+ *             _copyBooleanTest
+ * ----------------
+ */
+static BooleanTest *
+_copyBooleanTest(BooleanTest *from)
+{
+       BooleanTest *newnode = makeNode(BooleanTest);
+
+       /*
+        * copy remainder of node
+        */
+       Node_Copy(from, newnode, arg);
+       newnode->booltesttype = from->booltesttype;
+
+       return newnode;
+}
+
 static ArrayRef *
 _copyArrayRef(ArrayRef *from)
 {
@@ -2954,6 +2990,12 @@ copyObject(void *from)
                case T_CaseWhen:
                        retval = _copyCaseWhen(from);
                        break;
+               case T_NullTest:
+                       retval = _copyNullTest(from);
+                       break;
+               case T_BooleanTest:
+                       retval = _copyBooleanTest(from);
+                       break;
                case T_FkConstraint:
                        retval = _copyFkConstraint(from);
                        break;
index f7bfcc1..b12b4c2 100644 (file)
@@ -20,7 +20,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.92 2001/06/09 23:21:54 petere Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.93 2001/06/19 22:39:11 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1712,6 +1712,26 @@ _equalCaseWhen(CaseWhen *a, CaseWhen *b)
        return true;
 }
 
+static bool
+_equalNullTest(NullTest *a, NullTest *b)
+{
+       if (!equal(a->arg, b->arg))
+               return false;
+       if (a->nulltesttype != b->nulltesttype)
+               return false;
+       return true;
+}
+
+static bool
+_equalBooleanTest(BooleanTest *a, BooleanTest *b)
+{
+       if (!equal(a->arg, b->arg))
+               return false;
+       if (a->booltesttype != b->booltesttype)
+               return false;
+       return true;
+}
+
 /*
  * Stuff from pg_list.h
  */
@@ -2120,6 +2140,12 @@ equal(void *a, void *b)
                case T_CaseWhen:
                        retval = _equalCaseWhen(a, b);
                        break;
+               case T_NullTest:
+                       retval = _equalNullTest(a, b);
+                       break;
+               case T_BooleanTest:
+                       retval = _equalBooleanTest(a, b);
+                       break;
                case T_FkConstraint:
                        retval = _equalFkConstraint(a, b);
                        break;
index ebcacd4..e555e95 100644 (file)
@@ -5,7 +5,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- *     $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.141 2001/05/20 20:28:18 tgl Exp $
+ *     $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.142 2001/06/19 22:39:11 tgl Exp $
  *
  * NOTES
  *       Every (plan) node in POSTGRES has an associated "out" routine which
@@ -1259,12 +1259,6 @@ _outAExpr(StringInfo str, A_Expr *node)
                case NOT:
                        appendStringInfo(str, "NOT ");
                        break;
-               case ISNULL:
-                       appendStringInfo(str, "ISNULL ");
-                       break;
-               case NOTNULL:
-                       appendStringInfo(str, "NOTNULL ");
-                       break;
                case OP:
                        _outToken(str, node->opname);
                        appendStringInfo(str, " ");
@@ -1403,6 +1397,32 @@ _outCaseWhen(StringInfo str, CaseWhen *node)
 }
 
 /*
+ *     NullTest
+ */
+static void
+_outNullTest(StringInfo str, NullTest *node)
+{
+       appendStringInfo(str, " NULLTEST :arg ");
+       _outNode(str, node->arg);
+
+       appendStringInfo(str, " :nulltesttype %d ",
+                                        (int) node->nulltesttype);
+}
+
+/*
+ *     BooleanTest
+ */
+static void
+_outBooleanTest(StringInfo str, BooleanTest *node)
+{
+       appendStringInfo(str, " BOOLEANTEST :arg ");
+       _outNode(str, node->arg);
+
+       appendStringInfo(str, " :booltesttype %d ",
+                                        (int) node->booltesttype);
+}
+
+/*
  * _outNode -
  *       converts a Node into ascii string and append it to 'str'
  */
@@ -1639,7 +1659,12 @@ _outNode(StringInfo str, void *obj)
                        case T_CaseWhen:
                                _outCaseWhen(str, obj);
                                break;
-
+                       case T_NullTest:
+                               _outNullTest(str, obj);
+                               break;
+                       case T_BooleanTest:
+                               _outBooleanTest(str, obj);
+                               break;
                        case T_VariableSetStmt:
                                break;
                        case T_SelectStmt:
index a83f0b6..2f0dec0 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.110 2001/06/05 05:26:04 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.111 2001/06/19 22:39:11 tgl Exp $
  *
  * NOTES
  *       Most of the read functions for plan nodes are tested. (In fact, they
@@ -860,6 +860,56 @@ _readCaseWhen(void)
 }
 
 /* ----------------
+ *             _readNullTest
+ *
+ *     NullTest is a subclass of Node
+ * ----------------
+ */
+static NullTest *
+_readNullTest(void)
+{
+       NullTest        *local_node;
+       char            *token;
+       int                     length;
+
+       local_node = makeNode(NullTest);
+
+       token = pg_strtok(&length); /* eat :arg */
+       local_node->arg = nodeRead(true);       /* now read it */
+
+       token = pg_strtok(&length); /* eat :nulltesttype */
+       token = pg_strtok(&length); /* get nulltesttype */
+       local_node->nulltesttype = (NullTestType) atoi(token);
+
+       return local_node;
+}
+
+/* ----------------
+ *             _readBooleanTest
+ *
+ *     BooleanTest is a subclass of Node
+ * ----------------
+ */
+static BooleanTest *
+_readBooleanTest(void)
+{
+       BooleanTest     *local_node;
+       char            *token;
+       int                     length;
+
+       local_node = makeNode(BooleanTest);
+
+       token = pg_strtok(&length); /* eat :arg */
+       local_node->arg = nodeRead(true);       /* now read it */
+
+       token = pg_strtok(&length); /* eat :booltesttype */
+       token = pg_strtok(&length); /* get booltesttype */
+       local_node->booltesttype = (BoolTestType) atoi(token);
+
+       return local_node;
+}
+
+/* ----------------
  *             _readVar
  *
  *     Var is a subclass of Expr
@@ -1966,6 +2016,10 @@ parsePlanString(void)
                return_value = _readCaseExpr();
        else if (length == 4 && strncmp(token, "WHEN", length) == 0)
                return_value = _readCaseWhen();
+       else if (length == 8 && strncmp(token, "NULLTEST", length) == 0)
+               return_value = _readNullTest();
+       else if (length == 11 && strncmp(token, "BOOLEANTEST", length) == 0)
+               return_value = _readBooleanTest();
        else
                elog(ERROR, "badly formatted planstring \"%.10s\"...", token);
 
index e0cc97e..6ee962f 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.85 2001/05/20 20:28:19 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.86 2001/06/19 22:39:11 tgl Exp $
  *
  * HISTORY
  *       AUTHOR                        DATE                    MAJOR EVENT
@@ -1580,6 +1580,10 @@ expression_tree_walker(Node *node,
                                        return true;
                        }
                        break;
+               case T_NullTest:
+                       return walker(((NullTest *) node)->arg, context);
+               case T_BooleanTest:
+                       return walker(((BooleanTest *) node)->arg, context);
                case T_SubLink:
                        {
                                SubLink    *sublink = (SubLink *) node;
@@ -1933,6 +1937,26 @@ expression_tree_mutator(Node *node,
                                return (Node *) newnode;
                        }
                        break;
+               case T_NullTest:
+                       {
+                               NullTest *ntest = (NullTest *) node;
+                               NullTest *newnode;
+
+                               FLATCOPY(newnode, ntest, NullTest);
+                               MUTATE(newnode->arg, ntest->arg, Node *);
+                               return (Node *) newnode;
+                       }
+                       break;
+               case T_BooleanTest:
+                       {
+                               BooleanTest *btest = (BooleanTest *) node;
+                               BooleanTest *newnode;
+
+                               FLATCOPY(newnode, btest, BooleanTest);
+                               MUTATE(newnode->arg, btest->arg, Node *);
+                               return (Node *) newnode;
+                       }
+                       break;
                case T_SubLink:
                        {
 
index 2638302..e47c3f0 100644 (file)
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.230 2001/06/09 23:21:54 petere Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.231 2001/06/19 22:39:11 tgl Exp $
  *
  * HISTORY
  *       AUTHOR                        DATE                    MAJOR EVENT
@@ -315,7 +315,7 @@ static void doNegateFloat(Value *v);
                SCHEMA, SCROLL, SECOND_P, SELECT, SESSION, SESSION_USER, SET, SOME, SUBSTRING,
                TABLE, TEMPORARY, THEN, TIME, TIMESTAMP, TIMEZONE_HOUR,
                TIMEZONE_MINUTE, TO, TRAILING, TRANSACTION, TRIM, TRUE_P,
-               UNION, UNIQUE, UPDATE, USER, USING,
+               UNION, UNIQUE, UNKNOWN, UPDATE, USER, USING,
                VALUES, VARCHAR, VARYING, VIEW,
                WHEN, WHERE, WITH, WORK, YEAR_P, ZONE
 
@@ -386,7 +386,7 @@ static void doNegateFloat(Value *v);
 %left          Op                              /* multi-character ops and user-defined operators */
 %nonassoc      NOTNULL
 %nonassoc      ISNULL
-%nonassoc      IS NULL_P TRUE_P FALSE_P        /* sets precedence for IS NULL, etc */
+%nonassoc      IS NULL_P TRUE_P FALSE_P UNKNOWN        /* sets precedence for IS NULL, etc */
 %left          '+' '-'
 %left          '*' '/' '%'
 %left          '^'
@@ -4434,9 +4434,19 @@ a_expr:  c_expr
                                         * (like Microsoft's).  Turn these into IS NULL exprs.
                                         */
                                        if (exprIsNullConstant($3))
-                                               $$ = makeA_Expr(ISNULL, NULL, $1, NULL);
+                                       {
+                                               NullTest *n = makeNode(NullTest);
+                                               n->arg = $1;
+                                               n->nulltesttype = IS_NULL;
+                                               $$ = (Node *)n;
+                                       }
                                        else if (exprIsNullConstant($1))
-                                               $$ = makeA_Expr(ISNULL, NULL, $3, NULL);
+                                       {
+                                               NullTest *n = makeNode(NullTest);
+                                               n->arg = $3;
+                                               n->nulltesttype = IS_NULL;
+                                               $$ = (Node *)n;
+                                       }
                                        else
                                                $$ = makeA_Expr(OP, "=", $1, $3);
                                }
@@ -4499,59 +4509,95 @@ a_expr:  c_expr
                                        n->agg_distinct = FALSE;
                                        $$ = makeA_Expr(OP, "!~~*", $1, (Node *) n);
                                }
-
+               /* NullTest clause
+                * Define SQL92-style Null test clause.
+                * Allow two forms described in the standard:
+                *  a IS NULL
+                *  a IS NOT NULL
+                * Allow two SQL extensions
+                *  a ISNULL
+                *  a NOTNULL
+                * NOTE: this is not yet fully SQL-compatible, since SQL92
+                * allows a row constructor as argument, not just a scalar.
+                */
                | a_expr ISNULL
-                               {       $$ = makeA_Expr(ISNULL, NULL, $1, NULL); }
+                               {
+                                       NullTest *n = makeNode(NullTest);
+                                       n->arg = $1;
+                                       n->nulltesttype = IS_NULL;
+                                       $$ = (Node *)n;
+                               }
                | a_expr IS NULL_P
-                               {       $$ = makeA_Expr(ISNULL, NULL, $1, NULL); }
+                               {
+                                       NullTest *n = makeNode(NullTest);
+                                       n->arg = $1;
+                                       n->nulltesttype = IS_NULL;
+                                       $$ = (Node *)n;
+                               }
                | a_expr NOTNULL
-                               {       $$ = makeA_Expr(NOTNULL, NULL, $1, NULL); }
+                               {
+                                       NullTest *n = makeNode(NullTest);
+                                       n->arg = $1;
+                                       n->nulltesttype = IS_NOT_NULL;
+                                       $$ = (Node *)n;
+                               }
                | a_expr IS NOT NULL_P
-                               {       $$ = makeA_Expr(NOTNULL, NULL, $1, NULL); }
+                               {
+                                       NullTest *n = makeNode(NullTest);
+                                       n->arg = $1;
+                                       n->nulltesttype = IS_NOT_NULL;
+                                       $$ = (Node *)n;
+                               }
                /* IS TRUE, IS FALSE, etc used to be function calls
                 *  but let's make them expressions to allow the optimizer
                 *  a chance to eliminate them if a_expr is a constant string.
                 * - thomas 1997-12-22
+                *
+                *  Created BooleanTest Node type, and changed handling
+                *  for NULL inputs
+                * - jec 2001-06-18
                 */
                | a_expr IS TRUE_P
                                {
-                                       A_Const *n = makeNode(A_Const);
-                                       n->val.type = T_String;
-                                       n->val.val.str = "t";
-                                       n->typename = makeNode(TypeName);
-                                       n->typename->name = xlateSqlType("bool");
-                                       n->typename->typmod = -1;
-                                       $$ = makeA_Expr(OP, "=", $1,(Node *)n);
+                                       BooleanTest *b = makeNode(BooleanTest);
+                                       b->arg = $1;
+                                       b->booltesttype = IS_TRUE;
+                                       $$ = (Node *)b;
                                }
-               | a_expr IS NOT FALSE_P
+               | a_expr IS NOT TRUE_P
                                {
-                                       A_Const *n = makeNode(A_Const);
-                                       n->val.type = T_String;
-                                       n->val.val.str = "t";
-                                       n->typename = makeNode(TypeName);
-                                       n->typename->name = xlateSqlType("bool");
-                                       n->typename->typmod = -1;
-                                       $$ = makeA_Expr(OP, "=", $1,(Node *)n);
+                                       BooleanTest *b = makeNode(BooleanTest);
+                                       b->arg = $1;
+                                       b->booltesttype = IS_NOT_TRUE;
+                                       $$ = (Node *)b;
                                }
                | a_expr IS FALSE_P
                                {
-                                       A_Const *n = makeNode(A_Const);
-                                       n->val.type = T_String;
-                                       n->val.val.str = "f";
-                                       n->typename = makeNode(TypeName);
-                                       n->typename->name = xlateSqlType("bool");
-                                       n->typename->typmod = -1;
-                                       $$ = makeA_Expr(OP, "=", $1,(Node *)n);
+                                       BooleanTest *b = makeNode(BooleanTest);
+                                       b->arg = $1;
+                                       b->booltesttype = IS_FALSE;
+                                       $$ = (Node *)b;
                                }
-               | a_expr IS NOT TRUE_P
+               | a_expr IS NOT FALSE_P
                                {
-                                       A_Const *n = makeNode(A_Const);
-                                       n->val.type = T_String;
-                                       n->val.val.str = "f";
-                                       n->typename = makeNode(TypeName);
-                                       n->typename->name = xlateSqlType("bool");
-                                       n->typename->typmod = -1;
-                                       $$ = makeA_Expr(OP, "=", $1,(Node *)n);
+                                       BooleanTest *b = makeNode(BooleanTest);
+                                       b->arg = $1;
+                                       b->booltesttype = IS_NOT_FALSE;
+                                       $$ = (Node *)b;
+                               }
+               | a_expr IS UNKNOWN
+                               {
+                                       BooleanTest *b = makeNode(BooleanTest);
+                                       b->arg = $1;
+                                       b->booltesttype = IS_UNKNOWN;
+                                       $$ = (Node *)b;
+                               }
+               | a_expr IS NOT UNKNOWN
+                               {
+                                       BooleanTest *b = makeNode(BooleanTest);
+                                       b->arg = $1;
+                                       b->booltesttype = IS_NOT_UNKNOWN;
+                                       $$ = (Node *)b;
                                }
                | a_expr BETWEEN b_expr AND b_expr                      %prec BETWEEN
                                {
@@ -5206,12 +5252,14 @@ case_expr:  CASE case_arg when_clause_list case_default END_TRANS
                | COALESCE '(' expr_list ')'
                                {
                                        CaseExpr *c = makeNode(CaseExpr);
-                                       CaseWhen *w;
                                        List *l;
                                        foreach (l,$3)
                                        {
-                                               w = makeNode(CaseWhen);
-                                               w->expr = makeA_Expr(NOTNULL, NULL, lfirst(l), NULL);
+                                               CaseWhen *w = makeNode(CaseWhen);
+                                               NullTest *n = makeNode(NullTest);
+                                               n->arg = lfirst(l);
+                                               n->nulltesttype = IS_NOT_NULL;
+                                               w->expr = (Node *) n;
                                                w->result = lfirst(l);
                                                c->args = lappend(c->args, w);
                                        }
@@ -5765,6 +5813,7 @@ ColLabel:  ColId                                          { $$ = $1; }
                | TRUE_P                                                { $$ = "true"; }
                | UNION                                                 { $$ = "union"; }
                | UNIQUE                                                { $$ = "unique"; }
+               | UNKNOWN                                               { $$ = "unknown"; }
                | USER                                                  { $$ = "user"; }
                | USING                                                 { $$ = "using"; }
                | VACUUM                                                { $$ = "vacuum"; }
index 6064ca8..ccdfb88 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.92 2001/05/08 21:06:43 petere Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.93 2001/06/19 22:39:11 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -265,6 +265,7 @@ static ScanKeyword ScanKeywords[] = {
        {"type", TYPE_P},
        {"union", UNION},
        {"unique", UNIQUE},
+       {"unknown", UNKNOWN},
        {"unlisten", UNLISTEN},
        {"until", UNTIL},
        {"update", UPDATE},
index 02c6a4a..585b21b 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.80 2001/05/18 21:24:19 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.81 2001/06/19 22:39:11 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -286,16 +286,14 @@ transformJoinUsingClause(ParseState *pstate, List *leftVars, List *rightVars)
         */
        result = transformExpr(pstate, result, EXPR_COLUMN_FIRST);
 
+       /*
+        * 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)
-       {
-
-               /*
-                * This could only happen if someone defines a funny version of
-                * '='
-                */
                elog(ERROR, "JOIN/USING clause must return type bool, not type %s",
                         typeidTypeName(exprType(result)));
-       }
 
        return result;
 }      /* transformJoinUsingClause() */
@@ -328,11 +326,10 @@ transformJoinOnClause(ParseState *pstate, JoinExpr *j,
 
        /* This part is just like transformWhereClause() */
        result = transformExpr(pstate, j->quals, EXPR_COLUMN_FIRST);
-       if (exprType(result) != BOOLOID)
-       {
+
+       if (! coerce_to_boolean(pstate, &result))
                elog(ERROR, "JOIN/ON clause must return type bool, not type %s",
                         typeidTypeName(exprType(result)));
-       }
 
        pstate->p_namespace = save_namespace;
 
@@ -689,11 +686,11 @@ transformFromClauseItem(ParseState *pstate, Node *n, List **containedRels)
                                                        /* Need COALESCE(l_colvar, r_colvar) */
                                                        CaseExpr   *c = makeNode(CaseExpr);
                                                        CaseWhen   *w = makeNode(CaseWhen);
-                                                       A_Expr     *a = makeNode(A_Expr);
+                                                       NullTest   *n = makeNode(NullTest);
 
-                                                       a->oper = NOTNULL;
-                                                       a->lexpr = l_colvar;
-                                                       w->expr = (Node *) a;
+                                                       n->arg = l_colvar;
+                                                       n->nulltesttype = IS_NOT_NULL;
+                                                       w->expr = (Node *) n;
                                                        w->result = l_colvar;
                                                        c->args = makeList1(w);
                                                        c->defresult = r_colvar;
@@ -777,11 +774,10 @@ transformWhereClause(ParseState *pstate, Node *clause)
 
        qual = transformExpr(pstate, clause, EXPR_COLUMN_FIRST);
 
-       if (exprType(qual) != BOOLOID)
-       {
+       if (! coerce_to_boolean(pstate, &qual))
                elog(ERROR, "WHERE clause must return type bool, not type %s",
                         typeidTypeName(exprType(qual)));
-       }
+
        return qual;
 }
 
index 38f0442..283fd30 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.57 2001/05/22 16:37:16 petere Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.58 2001/06/19 22:39:11 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -321,6 +321,30 @@ coerce_type_typmod(ParseState *pstate, Node *node,
 }
 
 
+/* coerce_to_boolean()
+ *             Coerce an argument of a construct that requires boolean input
+ *             (AND, OR, NOT, etc).
+ *
+ * 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.)
+ */
+bool
+coerce_to_boolean(ParseState *pstate, Node **pnode)
+{
+       Oid                     inputTypeId = exprType(*pnode);
+       Oid                     targetTypeId;
+
+       if (inputTypeId == BOOLOID)
+               return true;                    /* no work */
+       targetTypeId = BOOLOID;
+       if (! can_coerce_type(1, &inputTypeId, &targetTypeId))
+               return false;                   /* fail, but let caller choose error msg */
+       *pnode = coerce_type(pstate, *pnode, inputTypeId, targetTypeId, -1);
+       return true;
+}
+
+
 /* select_common_type()
  *             Determine the common supertype of a list of input expression types.
  *             This is used for determining the output type of CASE and UNION
index a196779..5fda57f 100644 (file)
@@ -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:
index 5635b90..ae1a8c1 100644 (file)
@@ -3,7 +3,7 @@
  *                             back to source text
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.77 2001/04/18 17:04:24 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.78 2001/06/19 22:39:12 tgl Exp $
  *
  *       This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -52,7 +52,6 @@
 #include "parser/parse_expr.h"
 #include "parser/parsetree.h"
 #include "rewrite/rewriteManip.h"
-#include "utils/fmgroids.h"
 #include "utils/lsyscache.h"
 
 
@@ -1948,6 +1947,60 @@ get_rule_expr(Node *node, deparse_context *context)
                        }
                        break;
 
+               case T_NullTest:
+                       {
+                               NullTest                *ntest = (NullTest *) node;
+
+                               appendStringInfo(buf, "((");
+                               get_rule_expr(ntest->arg, context);
+                           switch (ntest->nulltesttype)
+                           {
+                               case IS_NULL:
+                                               appendStringInfo(buf, ") IS NULL)");
+                                               break;
+                               case IS_NOT_NULL:
+                                               appendStringInfo(buf, ") IS NOT NULL)");
+                                               break;
+                               default:
+                                   elog(ERROR, "get_rule_expr: unexpected nulltesttype %d",
+                                        (int) ntest->nulltesttype);
+                               }
+                       }
+                       break;
+
+               case T_BooleanTest:
+                       {
+                               BooleanTest             *btest = (BooleanTest *) node;
+
+                               appendStringInfo(buf, "((");
+                               get_rule_expr(btest->arg, context);
+                           switch (btest->booltesttype)
+                           {
+                               case IS_TRUE:
+                                               appendStringInfo(buf, ") IS TRUE)");
+                                               break;
+                               case IS_NOT_TRUE:
+                                               appendStringInfo(buf, ") IS NOT TRUE)");
+                                               break;
+                               case IS_FALSE:
+                                               appendStringInfo(buf, ") IS FALSE)");
+                                               break;
+                               case IS_NOT_FALSE:
+                                               appendStringInfo(buf, ") IS NOT FALSE)");
+                                               break;
+                               case IS_UNKNOWN:
+                                               appendStringInfo(buf, ") IS UNKNOWN)");
+                                               break;
+                               case IS_NOT_UNKNOWN:
+                                               appendStringInfo(buf, ") IS NOT UNKNOWN)");
+                                               break;
+                               default:
+                                   elog(ERROR, "get_rule_expr: unexpected booltesttype %d",
+                                        (int) btest->booltesttype);
+                               }
+                       }
+                       break;
+
                case T_SubLink:
                        get_sublink_expr(node, context);
                        break;
@@ -1979,25 +2032,6 @@ get_func_expr(Expr *expr, deparse_context *context)
        char       *sep;
 
        /*
-        * nullvalue() and nonnullvalue() should get turned into special
-        * syntax
-        */
-       if (funcoid == F_NULLVALUE)
-       {
-               appendStringInfoChar(buf, '(');
-               get_rule_expr((Node *) lfirst(expr->args), context);
-               appendStringInfo(buf, " ISNULL)");
-               return;
-       }
-       if (funcoid == F_NONNULLVALUE)
-       {
-               appendStringInfoChar(buf, '(');
-               get_rule_expr((Node *) lfirst(expr->args), context);
-               appendStringInfo(buf, " NOTNULL)");
-               return;
-       }
-
-       /*
         * Get the functions pg_proc tuple
         */
        proctup = SearchSysCache(PROCOID,
index 91feaec..c346553 100644 (file)
@@ -37,7 +37,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: catversion.h,v 1.83 2001/06/16 18:59:31 tgl Exp $
+ * $Id: catversion.h,v 1.84 2001/06/19 22:39:12 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,6 +53,6 @@
  */
 
 /*                                                     yyyymmddN */
-#define CATALOG_VERSION_NO     200106161
+#define CATALOG_VERSION_NO     200106191
 
 #endif
index d62583c..fe2d035 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: nodes.h,v 1.90 2001/06/09 23:21:55 petere Exp $
+ * $Id: nodes.h,v 1.91 2001/06/19 22:39:12 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -218,8 +218,8 @@ typedef enum NodeTag
        T_RangeTblEntry,
        T_SortClause,
        T_GroupClause,
-       T_SubSelectXXX,                         /* not used anymore; tag# available */
-       T_oldJoinExprXXX,                       /* not used anymore; tag# available */
+       T_NullTest,
+       T_BooleanTest,
        T_CaseExpr,
        T_CaseWhen,
        T_RowMarkXXX,                           /* not used anymore; tag# available */
index fe2d1bb..43e64b6 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parsenodes.h,v 1.131 2001/06/09 23:21:55 petere Exp $
+ * $Id: parsenodes.h,v 1.132 2001/06/19 22:39:12 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -983,9 +983,8 @@ typedef struct ParamNo
 typedef struct A_Expr
 {
        NodeTag         type;
-       int                     oper;                   /* type of operation
-                                                                * {OP,OR,AND,NOT,ISNULL,NOTNULL} */
-       char       *opname;                     /* name of operator/function */
+       int                     oper;                   /* type of operation (OP,OR,AND,NOT) */
+       char       *opname;                     /* name of operator */
        Node       *lexpr;                      /* left argument */
        Node       *rexpr;                      /* right argument */
 } A_Expr;
@@ -1054,6 +1053,50 @@ typedef struct CaseWhen
        Node       *result;                     /* substitution result */
 } CaseWhen;
 
+/* ----------------
+ * NullTest
+ *
+ * NullTest represents the operation of testing a value for NULLness.
+ * Currently, we only support scalar input values, but eventually a
+ * row-constructor input should be supported.
+ * The appropriate test is performed and returned as a boolean Datum.
+ * ----------------
+ */
+
+typedef enum NullTestType
+{
+       IS_NULL, IS_NOT_NULL
+} NullTestType;
+
+typedef struct NullTest
+{
+       NodeTag                 type;
+       Node                    *arg;                   /* input expression */
+       NullTestType    nulltesttype;   /* IS NULL, IS NOT NULL */
+} NullTest;
+
+/* ----------------
+ * BooleanTest
+ *
+ * BooleanTest represents the operation of determining whether a boolean
+ * is TRUE, FALSE, or UNKNOWN (ie, NULL).  All six meaningful combinations
+ * are supported.  Note that a NULL input does *not* cause a NULL result.
+ * The appropriate test is performed and returned as a boolean Datum.
+ * ----------------
+ */
+
+typedef enum BoolTestType
+{
+       IS_TRUE, IS_NOT_TRUE, IS_FALSE, IS_NOT_FALSE, IS_UNKNOWN, IS_NOT_UNKNOWN
+} BoolTestType;
+
+typedef struct BooleanTest
+{
+       NodeTag                 type;
+       Node                    *arg;                   /* input expression */
+       BoolTestType    booltesttype;   /* test type */
+} BooleanTest;
+
 /*
  * ColumnDef - column definition (used in various creates)
  *
index f81a3be..1f508b1 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parse_coerce.h,v 1.28 2001/05/22 16:37:17 petere Exp $
+ * $Id: parse_coerce.h,v 1.29 2001/06/19 22:39:12 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -136,6 +136,8 @@ extern Node *coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
 extern Node *coerce_type_typmod(ParseState *pstate, Node *node,
                                   Oid targetTypeId, int32 atttypmod);
 
+extern bool coerce_to_boolean(ParseState *pstate, Node **pnode);
+
 extern Oid     select_common_type(List *typeids, const char *context);
 extern Node *coerce_to_common_type(ParseState *pstate, Node *node,
                                          Oid targetTypeId,