From 2875a76136293589b6e409cb6be4defab87ade59 Mon Sep 17 00:00:00 2001
From: Andy Fan <yizhi.fzh@alibaba-inc.com>
Date: Wed, 2 Feb 2022 11:54:24 +0800
Subject: [PATCH v2 5/6] Support ScalarArrayOpExpr and perudoconstant on
 ef_filter.

---
 src/backend/optimizer/path/equivclass.c | 110 +++++++++++++++++-------
 src/backend/optimizer/plan/initsplan.c  |  48 +++++++----
 src/include/nodes/pathnodes.h           |   3 +-
 3 files changed, 114 insertions(+), 47 deletions(-)

diff --git a/src/backend/optimizer/path/equivclass.c b/src/backend/optimizer/path/equivclass.c
index 9ce0249b10d..4271bacb070 100644
--- a/src/backend/optimizer/path/equivclass.c
+++ b/src/backend/optimizer/path/equivclass.c
@@ -1386,23 +1386,55 @@ generate_base_implied_equalities_no_const(PlannerInfo *root,
 				rightexpr = (Expr *) ef->ef_const;
 			}
 
-			opno = get_opfamily_member(family,
-										exprType((Node *) leftexpr),
-										exprType((Node *) rightexpr),
-										strategy);
+			if (ef->ef_expr_type == T_OpExpr)
+			{
+				opno = get_opfamily_member(family,
+										   exprType((Node *) leftexpr),
+										   exprType((Node *) rightexpr),
+										   strategy);
 
-			if (opno == InvalidOid)
-				continue;
+				if (opno == InvalidOid)
+					continue;
 
-			rinfo = process_implied_equality(root, opno,
-											 ec->ec_collation,
-											 leftexpr,
-											 rightexpr,
-											 bms_copy(ec->ec_relids),
-											 bms_copy(cur_em->em_nullable_relids),
-											 ec->ec_min_security,
-											 ec->ec_below_outer_join,
-											 false);
+				rinfo = process_implied_equality(root, opno,
+												 ec->ec_collation,
+												 leftexpr,
+												 rightexpr,
+												 bms_copy(ec->ec_relids),
+												 bms_copy(cur_em->em_nullable_relids),
+												 ec->ec_min_security,
+												 ec->ec_below_outer_join,
+												 false);
+			}
+			else
+			{
+				ScalarArrayOpExpr *arr_opexpr;
+				Relids relids;
+
+				Assert(ef->ef_expr_type == T_ScalarArrayOpExpr);
+				arr_opexpr = makeNode(ScalarArrayOpExpr);
+				arr_opexpr->opno = ef->ef_opno;
+				arr_opexpr->opfuncid = get_opcode(ef->ef_opno);
+				arr_opexpr->useOr = true; /* See is_simple_filter_qual */
+				arr_opexpr->args = list_make2(leftexpr, ef->ef_const);
+				arr_opexpr->inputcollid = ec->ec_collation;
+
+				relids = pull_varnos(root, (Node *)arr_opexpr);
+
+				rinfo = make_restrictinfo(root,
+										  (Expr *) arr_opexpr,
+										  true,
+										  false,
+										  false, /* perudoconstant */
+										  ec->ec_min_security,
+										  relids,
+										  NULL,
+										  bms_copy(cur_em->em_nullable_relids));
+
+				// check_mergejoinable(rinfo);
+
+				distribute_restrictinfo_to_rels(root, rinfo);
+			}
 			rinfo->derived = ec;
 		}
 
@@ -2009,29 +2041,48 @@ distribute_filter_quals_to_eclass(PlannerInfo *root, List *quallist)
 	 */
 	foreach(l, quallist)
 	{
-		OpExpr	   *opexpr = (OpExpr *) lfirst(l);
-		Expr	   *leftexpr = (Expr *) linitial(opexpr->args);
-		Expr	   *rightexpr = (Expr *) lsecond(opexpr->args);
-		Const	   *constexpr;
-		Expr	   *varexpr;
+		Expr	*expr = lfirst(l);
+
+		List	*args;
+		Node	   *leftexpr;
+		Node	   *rightexpr;
+		Node	   *constexpr;
+		Node	   *varexpr;
+		Oid			opno;
+
 		Relids		exprrels;
 		int			relid;
 		bool		const_isleft;
 		ListCell *l2;
 
-		/*
-		 * Determine if the the OpExpr is in the form "expr op const" or
-		 * "const op expr".
-		 */
-		if (IsA(leftexpr, Const))
+		if (nodeTag(expr) == T_OpExpr)
+		{
+			OpExpr	   *opexpr = (OpExpr *) lfirst(l);
+			args = opexpr->args;
+			opno = opexpr->opno;
+		}
+		else if (nodeTag(expr) == T_ScalarArrayOpExpr)
+		{
+			ScalarArrayOpExpr *arr_expr = (ScalarArrayOpExpr *) lfirst(l);
+			args = arr_expr->args;
+			opno = arr_expr->opno;
+		}
+		else
+		{
+			Assert(false);
+		}
+
+		leftexpr = linitial(args);
+		rightexpr = lsecond(args);
+		if (is_pseudo_constant_clause(leftexpr))
 		{
-			constexpr = (Const *) leftexpr;
+			constexpr = leftexpr;
 			varexpr = rightexpr;
 			const_isleft = true;
 		}
 		else
 		{
-			constexpr = (Const *) rightexpr;
+			constexpr = rightexpr;
 			varexpr = leftexpr;
 			const_isleft = false;
 		}
@@ -2073,10 +2124,11 @@ distribute_filter_quals_to_eclass(PlannerInfo *root, List *quallist)
 				{
 					EquivalenceFilter *efilter;
 					efilter = makeNode(EquivalenceFilter);
-					efilter->ef_const = (Const *) copyObject(constexpr);
+					efilter->ef_const = (Node *)copyObject(constexpr);
 					efilter->ef_const_is_left = const_isleft;
-					efilter->ef_opno = opexpr->opno;
+					efilter->ef_opno = opno;
 					efilter->ef_source_rel = relid;
+					efilter->ef_expr_type = nodeTag(expr);
 
 					ec->ec_filters = lappend(ec->ec_filters, efilter);
 					break;		/* Onto the next eclass */
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index b5204b3c4f4..120380ea3ae 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -658,31 +658,39 @@ create_lateral_join_info(PlannerInfo *root)
  *             false if it should not be used.
  */
 static bool
-is_simple_filter_qual(PlannerInfo *root, OpExpr *expr)
+is_simple_filter_qual(PlannerInfo *root, Expr *expr)
 {
-	Expr *leftexpr;
-	Expr *rightexpr;
+	Node *leftexpr;
+	Node *rightexpr;
+	List *args = NIL;
 
-	if (!IsA(expr, OpExpr))
+	if (IsA(expr, OpExpr))
+		args = castNode(OpExpr, expr)->args;
+	else if (IsA(expr, ScalarArrayOpExpr))
+	{
+		ScalarArrayOpExpr *arr_opexpr = castNode(ScalarArrayOpExpr, expr);
+		if (!arr_opexpr->useOr)
+			/* Just support IN for now */
 			return false;
+		args = arr_opexpr->args;
+	}
 
-	if (list_length(expr->args) != 2)
-			return false;
+	if (list_length(args) != 2)
+		return false;
 
-	leftexpr = (Expr *) linitial(expr->args);
-	rightexpr = (Expr *) lsecond(expr->args);
+	leftexpr = linitial(args);
+	rightexpr = lsecond(args);
 
-	/* XXX should we restrict these to simple Var op Const expressions? */
-	if (IsA(leftexpr, Const))
+	if (is_pseudo_constant_clause(leftexpr))
 	{
-		if (bms_membership(pull_varnos(root, (Node *) rightexpr)) == BMS_SINGLETON &&
-			!contain_volatile_functions((Node *) rightexpr))
+		if (bms_membership(pull_varnos(root, rightexpr)) == BMS_SINGLETON &&
+			!contain_volatile_functions(rightexpr))
 			return true;
 	}
-	else if (IsA(rightexpr, Const))
+	else if (is_pseudo_constant_clause(rightexpr))
 	{
-		if (bms_membership(pull_varnos(root, (Node *) leftexpr)) == BMS_SINGLETON &&
-			!contain_volatile_functions((Node *) leftexpr))
+		if (bms_membership(pull_varnos(root, leftexpr)) == BMS_SINGLETON &&
+			!contain_volatile_functions(leftexpr))
 			return true;
 	}
 
@@ -739,7 +747,13 @@ deconstruct_jointree(PlannerInfo *root)
 
 	result = deconstruct_recurse(root, (Node *) root->parse->jointree, false,
 								 &qualscope, &inner_join_rels,
-								 &postponed_qual_list, &filter_qual_list);
+								 &postponed_qual_list,
+								 /*
+								  * geqo option here is just used for testing
+								  * during review stage, set enable_geqo to
+								  * false to disable this feature.
+								  */
+								 enable_geqo ? &filter_qual_list : NULL);
 
 	/* Shouldn't be any leftover quals */
 	Assert(postponed_qual_list == NIL);
@@ -2024,7 +2038,7 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
 	distribute_restrictinfo_to_rels(root, restrictinfo);
 
 	/* Check if the qual looks useful to harvest as an EquivalenceFilter */
-	if (filter_qual_list != NULL && is_simple_filter_qual(root, (OpExpr *) clause))
+	if (filter_qual_list != NULL && is_simple_filter_qual(root, (Expr *) clause))
 		*filter_qual_list = lappend(*filter_qual_list, clause);
 }
 
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index dbe1775f96d..c1ef0066188 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -1035,10 +1035,11 @@ typedef struct EquivalenceFilter
 {
 	NodeTag		type;
 
-	Const	   *ef_const;		/* the constant expression to filter on */
+	Node		*ef_const;		/* pseudo const */
 	Oid			ef_opno;		/* Operator Oid of filter operator */
 	bool		ef_const_is_left; /* Is the Const on the left of the OpExrp? */
 	Index		ef_source_rel;	/* relid of originating relation. */
+	NodeTag		ef_expr_type;
 } EquivalenceFilter;
 
 /*
-- 
2.21.0

