From 888dcb811bcdd6ed6a576ebd65f851b750da3937 Mon Sep 17 00:00:00 2001
From: root <root@localhost.localdomain>
Date: Tue, 10 Nov 2020 14:13:22 -0500
Subject: [PATCH] OSS patch eval NULLIF

---
 src/backend/optimizer/util/clauses.c | 70 ++++++++++++++++++++++++++++++++++++
 src/test/regress/expected/case.out   | 24 +++++++++++++
 src/test/regress/sql/case.sql        |  9 +++++
 3 files changed, 103 insertions(+)

diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 65534ed..d83ce24 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -2596,6 +2596,76 @@ eval_const_expressions_mutator(Node *node,
 				newexpr->location = expr->location;
 				return (Node *) newexpr;
 			}
+		case T_NullIfExpr:
+			{
+				NullIfExpr	 *expr = (NullIfExpr *) node;
+				List		 *args = expr->args;
+				ListCell	 *arg;
+				Expr		 *simple;
+				NullIfExpr	 *newexpr;
+
+				/* Recursively simplify the args */
+				args = (List *) expression_tree_mutator((Node *) expr->args,
+														eval_const_expressions_mutator,
+														(void *) context);
+
+				/* If either argument is NULL they can't be equal */
+				foreach(arg, args)
+				{
+					if (IsA(lfirst(arg), Const) && ((Const *) lfirst(arg))->constisnull)
+					{
+						return (Node *) linitial(args);
+					}
+				}
+
+				/*
+				 * Need to get OID of underlying function.  Okay to scribble
+				 * on input to this extent.
+				 */
+				set_opfuncid(expr);
+
+				/*
+				 * Code for op/func reduction is pretty bulky, so split it out
+				 * as a separate function.
+				 */
+				simple = simplify_function(expr->opfuncid,
+										   BOOLOID, -1,
+										   expr->opcollid,
+										   expr->inputcollid,
+										   &args,
+										   false,
+										   false,
+										   true,
+										   context);
+
+				/* successfully simplified it */
+				if (simple && IsA(simple, Const))
+				{
+					/* if the arguments are equal return null */
+					if(DatumGetBool(((Const *) simple)->constvalue))
+						return (Node *) makeNullConst(exprType(node),
+													  exprTypmod(node),
+													  exprCollation(node));
+					else
+						return (Node *) linitial(args);
+				}
+
+				/*
+				 * The expression cannot be simplified any further, so build
+				 * and return a replacement NullIfExpr node using the
+				 * possibly-simplified arguments.
+				 */
+				newexpr = makeNode(NullIfExpr);
+				newexpr->opno = expr->opno;
+				newexpr->opfuncid = expr->opfuncid;
+				newexpr->opresulttype = expr->opresulttype;
+				newexpr->opretset = expr->opretset;
+				newexpr->opcollid = expr->opcollid;
+				newexpr->inputcollid = expr->inputcollid;
+				newexpr->args = args;
+				newexpr->location = expr->location;
+				return (Node *) newexpr;
+			}
 		case T_DistinctExpr:
 			{
 				DistinctExpr *expr = (DistinctExpr *) node;
diff --git a/src/test/regress/expected/case.out b/src/test/regress/expected/case.out
index c0c8acf..130b9f0 100644
--- a/src/test/regress/expected/case.out
+++ b/src/test/regress/expected/case.out
@@ -263,6 +263,30 @@ SELECT '' AS "Two", *
      | 4 |   | 2 | -4
 (2 rows)
 
+explain (costs off)
+SELECT * FROM CASE_TBL WHERE NULLIF(1, 2) = 2;
+        QUERY PLAN        
+--------------------------
+ Result
+   One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM CASE_TBL WHERE NULLIF(1, 1) IS NOT NULL;
+        QUERY PLAN        
+--------------------------
+ Result
+   One-Time Filter: false
+(2 rows)
+
+explain (costs off)
+SELECT * FROM CASE_TBL WHERE NULLIF(1, null) = 2;
+        QUERY PLAN        
+--------------------------
+ Result
+   One-Time Filter: false
+(2 rows)
+
 --
 -- Examples of updates involving tables
 --
diff --git a/src/test/regress/sql/case.sql b/src/test/regress/sql/case.sql
index 17436c5..c328f34 100644
--- a/src/test/regress/sql/case.sql
+++ b/src/test/regress/sql/case.sql
@@ -137,6 +137,15 @@ SELECT '' AS "Two", *
   FROM CASE_TBL a, CASE2_TBL b
   WHERE COALESCE(f,b.i) = 2;
 
+explain (costs off)
+SELECT * FROM CASE_TBL WHERE NULLIF(1, 2) = 2;
+
+explain (costs off)
+SELECT * FROM CASE_TBL WHERE NULLIF(1, 1) IS NOT NULL;
+
+explain (costs off)
+SELECT * FROM CASE_TBL WHERE NULLIF(1, null) = 2;
+
 --
 -- Examples of updates involving tables
 --
-- 
2.7.2.windows.1

