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