From 27973d144f592249e2b8d9a548be3d563f58b737 Mon Sep 17 00:00:00 2001
From: Dmitrii Dolgov <9erthalion6@gmail.com>
Date: Mon, 10 Aug 2020 18:27:28 +0200
Subject: [PATCH] Reduce ArrayExpr into const array

In case if ArrayExpr generated for ScalarArrayOpExpr contains only
consts, reduce it to a const array. One of the advantages of that is
pg_stat_statements will consider this kind of array as a single entity
no matter how many elements are there, which will partially solve the
duplication problem (when the same query mentioned in pg_stat_statements
multiple times due to different number of elements in e.g. IN condition)
---
 src/backend/parser/parse_expr.c | 65 ++++++++++++++++++++++++++++++---
 1 file changed, 59 insertions(+), 6 deletions(-)

diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index f69976cc8c..6aea674810 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -32,6 +32,7 @@
 #include "parser/parse_relation.h"
 #include "parser/parse_target.h"
 #include "parser/parse_type.h"
+#include "utils/array.h"
 #include "utils/builtins.h"
 #include "utils/date.h"
 #include "utils/lsyscache.h"
@@ -1301,6 +1302,7 @@ transformAExprIn(ParseState *pstate, A_Expr *a)
 			 */
 			List	   *aexprs;
 			ArrayExpr  *newa;
+			bool		all_const = true;
 
 			aexprs = NIL;
 			foreach(l, rnonvars)
@@ -1310,6 +1312,10 @@ transformAExprIn(ParseState *pstate, A_Expr *a)
 				rexpr = coerce_to_common_type(pstate, rexpr,
 											  scalar_type,
 											  "IN");
+
+				if (!IsA(rexpr, Const))
+					all_const = false;
+
 				aexprs = lappend(aexprs, rexpr);
 			}
 			newa = makeNode(ArrayExpr);
@@ -1320,12 +1326,59 @@ transformAExprIn(ParseState *pstate, A_Expr *a)
 			newa->multidims = false;
 			newa->location = -1;
 
-			result = (Node *) make_scalar_array_op(pstate,
-												   a->name,
-												   useOr,
-												   lexpr,
-												   (Node *) newa,
-												   a->location);
+			/* if all elements are const reduce ArrayExpr to a const as well */
+			if (all_const)
+			{
+				ArrayType  	*const_array;
+				Datum 		*elems = (Datum *) palloc(sizeof(Datum) * aexprs->length);
+				bool 		*nulls = (bool *) palloc(sizeof(bool) * aexprs->length);
+
+				int			dims[1];
+				int			lbs[1];
+
+				bool 		elembyval;
+				int16 		elemlen;
+				char 		elemalign;
+				int 		i = 0;
+
+				foreach(l, aexprs)
+				{
+					Const	   *expr = (Const *) lfirst(l);
+
+					elems[i] = expr->constvalue;
+					nulls[i] = expr->constisnull;
+					i++;
+				}
+
+				/* ArrayExpr would have only one dimention */
+				dims[0] = aexprs->length;
+				lbs[0] = 1;
+
+				get_typlenbyvalalign(scalar_type, &elemlen,
+									 &elembyval, &elemalign);
+				const_array = construct_md_array(elems, nulls, 1, dims, lbs,
+												 scalar_type, elemlen,
+												 elembyval, elemalign);
+
+				result = (Node *) makeConst(array_type, -1,
+											newa->array_collid, -1,
+											PointerGetDatum(const_array),
+											false, false);
+
+				result = (Node *) make_scalar_array_op(pstate,
+													   a->name,
+													   useOr,
+													   lexpr,
+													   (Node *) result,
+													   a->location);
+			}
+			else
+				result = (Node *) make_scalar_array_op(pstate,
+													   a->name,
+													   useOr,
+													   lexpr,
+													   (Node *) newa,
+													   a->location);
 
 			/* Consider only the Vars (if any) in the loop below */
 			rexprs = rvars;
-- 
2.21.0

