delta-2.diff

text/plain

Filename: delta-2.diff
Type: text/plain
Part: 0
Message: Re: POC, WIP: OR-clause support for indexes

Patch

Same data as JSON: GET /api/v1/attachments/:id/patch the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes. API reference →
Format: unified
File+
src/backend/parser/parse_expr.c 46 39
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index 26648b0876..67d6f85010 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -111,38 +111,27 @@ transformBoolExprOr(ParseState *pstate, BoolExpr *expr_orig)
 {
 	List		   *or_list = NIL;
 	List		   *groups_list = NIL;
-	ListCell	   *lc_eargs;
+	ListCell	   *lc;
 	Node 		   *result;
 	BoolExpr 	   *expr;
 	bool			change_apply = false;
 
-	/* If this is not expression "Or", then will do it the old way. */
+	/* If this is not an 'OR' expression, skip the transformation */
 	if (expr_orig->boolop != OR_EXPR ||
 		list_length(expr_orig->args) < const_transform_or_limit)
-		return transformBoolExpr(pstate, (BoolExpr *)expr_orig);
+		return transformBoolExpr(pstate, (BoolExpr *) expr_orig);
 
 	expr = (BoolExpr *)copyObject(expr_orig);
 
-	/*
-		* NOTE:
-		* It is an OR-clause. So, rinfo->orclause is a BoolExpr node, contains
-		* a list of sub-restrictinfo args, and rinfo->clause - which is the
-		* same expression, made from bare clauses. To not break selectivity
-		* caches and other optimizations, use both:
-		* - use rinfos from orclause if no transformation needed
-		* - use  bare quals from rinfo->clause in the case of transformation,
-		* to create new RestrictInfo: in this case we have no options to avoid
-		* selectivity estimation procedure.
-		*/
-	foreach(lc_eargs, expr->args)
+	foreach(lc, expr->args)
 	{
-		A_Expr			   *arg = (A_Expr *) lfirst(lc_eargs);
-		Node			   *bare_orarg;
+		Node			   *arg = lfirst(lc);
+		Node			   *orqual;
 		Node			   *const_expr;
-		Node			   *non_const_expr;
+		Node			   *nconst_expr;
 		ListCell		   *lc_groups;
 		OrClauseGroupEntry *gentry;
-		bool 				allow_transformation;
+		bool				const_is_left = true;
 
 		/*
 		 * The first step: checking that the expression consists only of equality.
@@ -154,33 +143,51 @@ transformBoolExprOr(ParseState *pstate, BoolExpr *expr_orig)
 		 * same level of a single BoolExpr expression, otherwise all of them cannot be converted.
 		 */
 
-		if (!arg)
-			break;
+		orqual = transformExprRecurse(pstate, (Node *) arg);
+		orqual = coerce_to_boolean(pstate, orqual, "OR");
+		orqual = eval_const_expressions(NULL, orqual);
 
-		allow_transformation = (arg->type == T_A_Expr && (arg)->kind == AEXPR_OP &&
-							    list_length((arg)->name) >=1 && strcmp(strVal(linitial((arg)->name)), "=") == 0
-							   );
+		if (!IsA(orqual, OpExpr))
+		{
+			or_list = lappend(or_list, orqual);
+			continue;
+		}
 
+		/* Detect constant side of the clause */
+		if (IsA(get_leftop(orqual), Const))
+			const_is_left = true;
+		else if (IsA(get_rightop(orqual), Const))
+			const_is_left = false;
+		else
+		{
+			or_list = lappend(or_list, orqual);
+			continue;
+		}
 
-		bare_orarg = transformExprRecurse(pstate, (Node *)arg);
-		bare_orarg = coerce_to_boolean(pstate, bare_orarg, "OR");
+		/* Get pointers to constant and expression sides of the qual */
+		nconst_expr = (const_is_left) ? get_rightop(orqual) :
+										get_leftop(orqual);
+		const_expr = (const_is_left) ?  get_leftop(orqual) :
+										get_rightop(orqual);
+
+		if (!op_mergejoinable(((OpExpr *) orqual)->opno, exprType(nconst_expr)))
+		{
+			or_list = lappend(or_list, orqual);
+			continue;
+		}
 
 		/*
 		 * The next step: transform all the inputs, and detect whether any contain
 	 	 * Vars.
 		 */
-		if (!allow_transformation || !bare_orarg || !IsA(bare_orarg, OpExpr) || !contain_vars_of_level(bare_orarg, 0))
+		if (!contain_vars_of_level(orqual, 0))
 		{
 			/* Again, it's not the expr we can transform */
-			or_list = lappend(or_list, bare_orarg);
+			or_list = lappend(or_list, orqual);
 			continue;
 		}
 
-		/*
-		 * Get pointers to constant and expression sides of the clause
-		 */
-		non_const_expr = get_leftop(bare_orarg);
-		const_expr = get_rightop(bare_orarg);
+		;
 
 		/*
 			* At this point we definitely have a transformable clause.
@@ -196,15 +203,15 @@ transformBoolExprOr(ParseState *pstate, BoolExpr *expr_orig)
 
 			Assert(v->node != NULL);
 
-			if (equal(v->node, non_const_expr))
+			if (equal(v->node, nconst_expr))
 			{
 				v->consts = lappend(v->consts, const_expr);
-				non_const_expr = NULL;
+				nconst_expr = NULL;
 				break;
 			}
 		}
 
-		if (non_const_expr == NULL)
+		if (nconst_expr == NULL)
 			/*
 				* The clause classified successfully and added into existed
 				* clause group.
@@ -213,10 +220,10 @@ transformBoolExprOr(ParseState *pstate, BoolExpr *expr_orig)
 
 		/* New clause group needed */
 		gentry = palloc(sizeof(OrClauseGroupEntry));
-		gentry->node = non_const_expr;
+		gentry->node = nconst_expr;
 		gentry->consts = list_make1(const_expr);
-		gentry->opno = ((OpExpr *)bare_orarg)->opno;
-		gentry->expr = (Expr *)bare_orarg;
+		gentry->opno = ((OpExpr *)orqual)->opno;
+		gentry->expr = (Expr *)orqual;
 		groups_list = lappend(groups_list,  (void *) gentry);
 	}