diff -Naur pgsql.virg/src/backend/executor/execQual.c pgsql.dev/src/backend/executor/execQual.c
--- pgsql.virg/src/backend/executor/execQual.c	Sat Jun 16 18:56:42 2001
+++ pgsql.dev/src/backend/executor/execQual.c	Tue Jun 19 05:26:22 2001
@@ -62,7 +62,10 @@
 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);
 
 /*----------
  *	  ExecEvalArrayRef
@@ -1092,6 +1095,110 @@
 }
 
 /* ----------------------------------------------------------------
+ *		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 (result == true)
+                return BoolGetDatum(true);
+			else
+                return BoolGetDatum(false);
+        case IS_NOT_FALSE:
+            if (*isNull)
+            {
+                *isNull = false;
+                return BoolGetDatum(true);
+            }
+            else if (result == true)
+                return BoolGetDatum(true);
+			else
+                return BoolGetDatum(false);
+        case IS_FALSE:
+            if (*isNull)
+            {
+                *isNull = false;
+                return BoolGetDatum(false);
+            }
+            else if (result == false)
+                return BoolGetDatum(true);
+			else
+                return BoolGetDatum(false);
+        case IS_NOT_TRUE:
+            if (*isNull)
+            {
+                *isNull = false;
+                return BoolGetDatum(true);
+            }
+            else if (result == false)
+                return BoolGetDatum(true);
+			else
+                return BoolGetDatum(false);
+        default:
+            elog(ERROR, "ExecEvalBooleanTest: unexpected booltesttype %d",
+                 (int) btest->booltesttype);
+            return (Datum) 0;  /* keep compiler quiet */
+    }
+}
+
+/* ----------------------------------------------------------------
  *		ExecEvalFieldSelect
  *
  *		Evaluate a FieldSelect node.
@@ -1262,6 +1369,18 @@
 			break;
 		case T_CaseExpr:
 			retDatum = ExecEvalCase((CaseExpr *) expression,
+									econtext,
+									isNull,
+									isDone);
+			break;
+		case T_NullTest:
+			retDatum = ExecEvalNullTest((NullTest *) expression,
+									econtext,
+									isNull,
+									isDone);
+			break;
+		case T_BooleanTest:
+			retDatum = ExecEvalBooleanTest((BooleanTest *) expression,
 									econtext,
 									isNull,
 									isDone);
diff -Naur pgsql.virg/src/backend/nodes/copyfuncs.c pgsql.dev/src/backend/nodes/copyfuncs.c
--- pgsql.virg/src/backend/nodes/copyfuncs.c	Sat Jun 16 18:56:45 2001
+++ pgsql.dev/src/backend/nodes/copyfuncs.c	Tue Jun 19 05:05:22 2001
@@ -1017,6 +1017,42 @@
 	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)
 {
@@ -2953,6 +2989,12 @@
 			break;
 		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);
diff -Naur pgsql.virg/src/backend/nodes/equalfuncs.c pgsql.dev/src/backend/nodes/equalfuncs.c
--- pgsql.virg/src/backend/nodes/equalfuncs.c	Sat Jun 16 18:56:45 2001
+++ pgsql.dev/src/backend/nodes/equalfuncs.c	Tue Jun 19 05:12:10 2001
@@ -1712,6 +1712,26 @@
 	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
  */
@@ -2119,6 +2139,12 @@
 			break;
 		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);
diff -Naur pgsql.virg/src/backend/nodes/outfuncs.c pgsql.dev/src/backend/nodes/outfuncs.c
--- pgsql.virg/src/backend/nodes/outfuncs.c	Sat Jun 16 18:56:45 2001
+++ pgsql.dev/src/backend/nodes/outfuncs.c	Tue Jun 19 05:11:03 2001
@@ -1403,6 +1403,32 @@
 }
 
 /*
+ *	NullTest
+ */
+static void
+_outNullTest(StringInfo str, NullTest *node)
+{
+	appendStringInfo(str, " NULLTEST :arg ");
+	_outNode(str, node->arg);
+
+	appendStringInfo(str, " :nulltesttype %d ",
+				   node->nulltesttype);
+}
+
+/*
+ *	BooleanTest
+ */
+static void
+_outBooleanTest(StringInfo str, BooleanTest *node)
+{
+	appendStringInfo(str, " BOOLEANTEST :arg ");
+	_outNode(str, node->arg);
+
+	appendStringInfo(str, " :booltesttype %d ",
+				   node->booltesttype);
+}
+
+/*
  * _outNode -
  *	  converts a Node into ascii string and append it to 'str'
  */
@@ -1639,7 +1665,12 @@
 			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:
diff -Naur pgsql.virg/src/backend/nodes/readfuncs.c pgsql.dev/src/backend/nodes/readfuncs.c
--- pgsql.virg/src/backend/nodes/readfuncs.c	Sat Jun 16 18:56:45 2001
+++ pgsql.dev/src/backend/nodes/readfuncs.c	Tue Jun 19 05:27:26 2001
@@ -860,6 +860,56 @@
 }
 
 /* ----------------
+ *		_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 @@
 		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);
 
diff -Naur pgsql.virg/src/backend/optimizer/util/clauses.c pgsql.dev/src/backend/optimizer/util/clauses.c
--- pgsql.virg/src/backend/optimizer/util/clauses.c	Sat Jun 16 18:56:46 2001
+++ pgsql.dev/src/backend/optimizer/util/clauses.c	Tue Jun 19 05:02:53 2001
@@ -1580,6 +1580,10 @@
 					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;
@@ -1930,6 +1934,26 @@
 				FLATCOPY(newnode, casewhen, CaseWhen);
 				MUTATE(newnode->expr, casewhen->expr, Node *);
 				MUTATE(newnode->result, casewhen->result, 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;
diff -Naur pgsql.virg/src/backend/parser/gram.y pgsql.dev/src/backend/parser/gram.y
--- pgsql.virg/src/backend/parser/gram.y	Sat Jun 16 18:56:47 2001
+++ pgsql.dev/src/backend/parser/gram.y	Tue Jun 19 04:46:06 2001
@@ -4434,9 +4434,19 @@
 					 * (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,79 @@
 					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
+		 */
 		| 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_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_FALSE;
+					$$ = (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_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_TRUE;
+					$$ = (Node *)b;
 				}
 		| a_expr BETWEEN b_expr AND b_expr			%prec BETWEEN
 				{
diff -Naur pgsql.virg/src/backend/parser/parse_expr.c pgsql.dev/src/backend/parser/parse_expr.c
--- pgsql.virg/src/backend/parser/parse_expr.c	Sat Jun 16 18:56:47 2001
+++ pgsql.dev/src/backend/parser/parse_expr.c	Tue Jun 19 05:01:12 2001
@@ -510,6 +510,26 @@
 				break;
 			}
 
+		case T_NullTest:
+			{
+				NullTest   *n = (NullTest *) expr;
+
+				n->arg = transformExpr(pstate, n->arg, precedence);
+
+				result = (Node *) expr;
+				break;
+			}
+
+		case T_BooleanTest:
+			{
+				BooleanTest   *b = (BooleanTest *) expr;
+
+				b->arg = transformExpr(pstate, b->arg, precedence);
+
+				result = (Node *) expr;
+				break;
+			}
+
 			/*
 			 * Quietly accept node types that may be presented when we are
 			 * called on an already-transformed tree.
@@ -668,6 +688,12 @@
 			break;
 		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? */
diff -Naur pgsql.virg/src/backend/utils/adt/ruleutils.c pgsql.dev/src/backend/utils/adt/ruleutils.c
--- pgsql.virg/src/backend/utils/adt/ruleutils.c	Sat Jun 16 18:56:48 2001
+++ pgsql.dev/src/backend/utils/adt/ruleutils.c	Tue Jun 19 04:59:46 2001
@@ -1948,6 +1948,52 @@
 			}
 			break;
 
+		case T_NullTest:
+			{
+				NullTest		*ntest = (NullTest *) node;
+
+				get_rule_expr(ntest->arg, context);
+			    switch (ntest->nulltesttype)
+			    {
+			        case IS_NULL:
+						appendStringInfo(buf, "%s", " IS NULL ");
+						break;
+			        case IS_NOT_NULL:
+						appendStringInfo(buf, "%s", " IS NOT NULL ");
+						break;
+			        default:
+			            elog(ERROR, "get_rule_expr: unexpected nulltesttype %d",
+			                 (int) ntest->nulltesttype);
+				}
+			}
+			break;
+
+		case T_BooleanTest:
+			{
+				BooleanTest		*btest = (BooleanTest *) node;
+
+				get_rule_expr(btest->arg, context);
+			    switch (btest->booltesttype)
+			    {
+			        case IS_TRUE:
+						appendStringInfo(buf, "%s", " IS TRUE ");
+						break;
+			        case IS_NOT_FALSE:
+						appendStringInfo(buf, "%s", " IS NOT FALSE ");
+						break;
+			        case IS_FALSE:
+						appendStringInfo(buf, "%s", " IS FALSE ");
+						break;
+			        case IS_NOT_TRUE:
+						appendStringInfo(buf, "%s", " IS NOT TRUE ");
+						break;
+			        default:
+			            elog(ERROR, "get_rule_expr: unexpected booltesttype %d",
+			                 (int) btest->booltesttype);
+				}
+			}
+			break;
+
 		case T_SubLink:
 			get_sublink_expr(node, context);
 			break;
diff -Naur pgsql.virg/src/include/nodes/nodes.h pgsql.dev/src/include/nodes/nodes.h
--- pgsql.virg/src/include/nodes/nodes.h	Sat Jun 16 18:56:52 2001
+++ pgsql.dev/src/include/nodes/nodes.h	Tue Jun 19 04:46:52 2001
@@ -225,6 +225,8 @@
 	T_RowMarkXXX,				/* not used anymore; tag# available */
 	T_FkConstraint,
 	T_PrivGrantee,
+	T_NullTest,
+	T_BooleanTest,
 
 	/*
 	 * TAGS FOR FUNCTION-CALL CONTEXT AND RESULTINFO NODES (see fmgr.h)
diff -Naur pgsql.virg/src/include/nodes/parsenodes.h pgsql.dev/src/include/nodes/parsenodes.h
--- pgsql.virg/src/include/nodes/parsenodes.h	Sat Jun 16 18:56:52 2001
+++ pgsql.dev/src/include/nodes/parsenodes.h	Tue Jun 19 05:25:18 2001
@@ -1054,6 +1054,50 @@
 	Node	   *result;			/* substitution result */
 } CaseWhen;
 
+/* ----------------
+ * NullTest
+ *
+ * NullTest represents the operation of comparing a value to a NULL
+ * value.  At runtime, the input expression is expected to be IS NULL,
+ * IS NOT NULL, ISNULL, or NOTNULL.
+ * The appropriate test is performed and returned as a 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 comparing a value to a TRUE
+ * or FALSE value.  At runtime, the input expression is expected to be
+ * IS TRUE, IS NOT FALSE, IS FALSE, or IS NOT TRUE.
+ * The appropriate test is performed and returned as a Datum.
+ * ----------------
+ */
+
+typedef enum BoolTestType
+{
+	IS_TRUE, IS_NOT_FALSE, IS_FALSE, IS_NOT_TRUE
+} BoolTestType;
+
+typedef struct BooleanTest
+{
+	NodeTag			type;
+	Node			*arg;			/* input expression */
+	BoolTestType	booltesttype;	/* IS_TRUE, IS_NOT_FALSE, IS_FALSE, IS_NOT_TRUE */
+} BooleanTest;
+
 /*
  * ColumnDef - column definition (used in various creates)
  *
