From 067a720aeb273372aa536f0620ec53f022d40d85 Mon Sep 17 00:00:00 2001
From: Andy Fan <yizhi.fzh@alibaba-inc.com>
Date: Mon, 7 Mar 2022 10:07:44 +0800
Subject: [PATCH v3 1/5] expand the duties of check_mergejoinable to check
 non-equal btree

operator as well to support the EC Filter function.  A new filed
named btreeineqopfamilies is added in RestictInfo and it is set
with the same round syscache search for check_mergejoinable. because
of this, check_mergejoinable is renamed to check_btreeable.

The bad part of this is it only works for opclause so far.
---
 src/backend/optimizer/plan/initsplan.c    | 33 ++++++++++-----------
 src/backend/optimizer/util/restrictinfo.c |  1 +
 src/backend/utils/cache/lsyscache.c       | 35 +++++++++++++++++++++++
 src/include/nodes/pathnodes.h             |  1 +
 src/include/utils/lsyscache.h             |  1 +
 5 files changed, 55 insertions(+), 16 deletions(-)

diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index 023efbaf092..d61419f61a5 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -76,7 +76,7 @@ static bool check_outerjoin_delay(PlannerInfo *root, Relids *relids_p,
 static bool check_equivalence_delay(PlannerInfo *root,
 									RestrictInfo *restrictinfo);
 static bool check_redundant_nullability_qual(PlannerInfo *root, Node *clause);
-static void check_mergejoinable(RestrictInfo *restrictinfo);
+static void check_btreeable(RestrictInfo *restrictinfo);
 static void check_hashjoinable(RestrictInfo *restrictinfo);
 static void check_memoizable(RestrictInfo *restrictinfo);
 
@@ -1874,8 +1874,11 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
 	 * We check "mergejoinability" of every clause, not only join clauses,
 	 * because we want to know about equivalences between vars of the same
 	 * relation, or between vars and consts.
+	 *
+	 * We also checked the btree-able properity at the same round of checking
+	 * mergejoinability to support ec filter function.
 	 */
-	check_mergejoinable(restrictinfo);
+	check_btreeable(restrictinfo);
 
 	/*
 	 * If it is a true equivalence clause, send it to the EquivalenceClass
@@ -2389,7 +2392,7 @@ process_implied_equality(PlannerInfo *root,
 	 * from an EquivalenceClass; but we could have reduced the original clause
 	 * to a constant.
 	 */
-	check_mergejoinable(restrictinfo);
+	check_btreeable(restrictinfo);
 
 	/*
 	 * Note we don't do initialize_mergeclause_eclasses(); the caller can
@@ -2456,8 +2459,8 @@ build_implied_join_equality(PlannerInfo *root,
 									 NULL,	/* outer_relids */
 									 nullable_relids);	/* nullable_relids */
 
-	/* Set mergejoinability/hashjoinability flags */
-	check_mergejoinable(restrictinfo);
+	/* Set btreeability/hashjoinability flags */
+	check_btreeable(restrictinfo);
 	check_hashjoinable(restrictinfo);
 	check_memoizable(restrictinfo);
 
@@ -2641,16 +2644,13 @@ match_foreign_keys_to_quals(PlannerInfo *root)
  *****************************************************************************/
 
 /*
- * check_mergejoinable
- *	  If the restrictinfo's clause is mergejoinable, set the mergejoin
- *	  info fields in the restrictinfo.
- *
- *	  Currently, we support mergejoin for binary opclauses where
- *	  the operator is a mergejoinable operator.  The arguments can be
- *	  anything --- as long as there are no volatile functions in them.
+ * check_btreeable
+ *	  If the restrictinfo's clause is btreeable, set the mergejoin
+ *	  info field and btreeineq info field in the restrictinfo. btreeable
+ *	  now is a superset of mergeable.
  */
 static void
-check_mergejoinable(RestrictInfo *restrictinfo)
+check_btreeable(RestrictInfo *restrictinfo)
 {
 	Expr	   *clause = restrictinfo->clause;
 	Oid			opno;
@@ -2666,9 +2666,10 @@ check_mergejoinable(RestrictInfo *restrictinfo)
 	opno = ((OpExpr *) clause)->opno;
 	leftarg = linitial(((OpExpr *) clause)->args);
 
-	if (op_mergejoinable(opno, exprType(leftarg)) &&
-		!contain_volatile_functions((Node *) restrictinfo))
-		restrictinfo->mergeopfamilies = get_mergejoin_opfamilies(opno);
+	if (!contain_volatile_functions((Node *) restrictinfo))
+		get_btree_opfamilies(opno,
+							 &restrictinfo->mergeopfamilies,
+							 &restrictinfo->btreeineqopfamilies);
 
 	/*
 	 * Note: op_mergejoinable is just a hint; if we fail to find the operator
diff --git a/src/backend/optimizer/util/restrictinfo.c b/src/backend/optimizer/util/restrictinfo.c
index ef8df3d098e..e09196d26f6 100644
--- a/src/backend/optimizer/util/restrictinfo.c
+++ b/src/backend/optimizer/util/restrictinfo.c
@@ -201,6 +201,7 @@ make_restrictinfo_internal(PlannerInfo *root,
 	restrictinfo->outer_selec = -1;
 
 	restrictinfo->mergeopfamilies = NIL;
+	restrictinfo->btreeineqopfamilies = NIL;
 
 	restrictinfo->left_ec = NULL;
 	restrictinfo->right_ec = NULL;
diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c
index feef9998634..92c34ed8a49 100644
--- a/src/backend/utils/cache/lsyscache.c
+++ b/src/backend/utils/cache/lsyscache.c
@@ -389,6 +389,41 @@ get_mergejoin_opfamilies(Oid opno)
 	return result;
 }
 
+/*
+ * TODO:  get_mergejoin_opfamilies shoud be replaced with this function.
+ */
+void
+get_btree_opfamilies(Oid opno,
+					 List **mergeable_opfamilies,
+					 List **unmergeable_btree_opfamilies)
+{
+	CatCList   *catlist;
+	int			i;
+
+	/*
+	 * Search pg_amop to see find out all the btree opfamilies.
+	 */
+	catlist = SearchSysCacheList1(AMOPOPID, ObjectIdGetDatum(opno));
+
+	for (i = 0; i < catlist->n_members; i++)
+	{
+		HeapTuple	tuple = &catlist->members[i]->tuple;
+		Form_pg_amop aform = (Form_pg_amop) GETSTRUCT(tuple);
+
+		if (aform->amopmethod == BTREE_AM_OID)
+		{
+			if (aform->amopstrategy == BTEqualStrategyNumber)
+				*mergeable_opfamilies = lappend_oid(*mergeable_opfamilies,
+													aform->amopfamily);
+			else
+				*unmergeable_btree_opfamilies = lappend_oid(*unmergeable_btree_opfamilies,
+															aform->amopfamily);
+		}
+	}
+
+	ReleaseSysCacheList(catlist);
+}
+
 /*
  * get_compatible_hash_operators
  *		Get the OID(s) of hash equality operator(s) compatible with the given
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 1f3845b3fec..3b95e4a8eae 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -2105,6 +2105,7 @@ typedef struct RestrictInfo
 
 	/* valid if clause is mergejoinable, else NIL */
 	List	   *mergeopfamilies;	/* opfamilies containing clause operator */
+	List		*btreeineqopfamilies; /* btree families except the mergeable ones */
 
 	/* cache space for mergeclause processing; NULL if not yet set */
 	EquivalenceClass *left_ec;	/* EquivalenceClass containing lefthand */
diff --git a/src/include/utils/lsyscache.h b/src/include/utils/lsyscache.h
index b8dd27d4a96..5b5fac0397c 100644
--- a/src/include/utils/lsyscache.h
+++ b/src/include/utils/lsyscache.h
@@ -79,6 +79,7 @@ extern bool get_ordering_op_properties(Oid opno,
 extern Oid	get_equality_op_for_ordering_op(Oid opno, bool *reverse);
 extern Oid	get_ordering_op_for_equality_op(Oid opno, bool use_lhs_type);
 extern List *get_mergejoin_opfamilies(Oid opno);
+extern void get_btree_opfamilies(Oid opno, List **mergeable_opfamilies, List **unmergeable_btree_opfamilies);
 extern bool get_compatible_hash_operators(Oid opno,
 										  Oid *lhs_opno, Oid *rhs_opno);
 extern bool get_op_hash_functions(Oid opno,
-- 
2.21.0

