From 888dcb811bcdd6ed6a576ebd65f851b750da3937 Mon Sep 17 00:00:00 2001 From: root 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