commit bbf3d7570b638a630b3d79a279fa4a2d572ebdf3
Author: jcoleman <jtc331@gmail.com>
Date:   Fri Nov 9 19:39:49 2018 +0000

    Convert MAX_SAOP_ARRAY_SIZE into guc

diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index b8e32d765b..24a3353501 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -4379,6 +4379,23 @@ ANY <replaceable class="parameter">num_sync</replaceable> ( <replaceable class="
 
      <variablelist>
 
+     <varlistentry id="guc-array-optimization-size-limit" xreflabel="array_optimization_size_limit">
+      <term><varname>array_optimization_size_limit</varname> (<type>integer</type>)
+      <indexterm>
+       <primary><varname>array_optimization_size_limit</varname> configuration parameter</primary>
+      </indexterm>
+      </term>
+      <listitem>
+       <para>
+        Sets the array size limit beyond which predicate optimization is not used.
+        The optimizer evaluates scalar array expressions to determine if they can
+        be treated as AND or OR clauses. This optimization proving is only performed
+        if the array contains at most this many items.
+        The default is <literal>100</literal>.
+       </para>
+      </listitem>
+     </varlistentry>
+
      <varlistentry id="guc-default-statistics-target" xreflabel="default_statistics_target">
       <term><varname>default_statistics_target</varname> (<type>integer</type>)
       <indexterm>
diff --git a/src/backend/optimizer/util/predtest.c b/src/backend/optimizer/util/predtest.c
index 446207de30..cba6608ce2 100644
--- a/src/backend/optimizer/util/predtest.c
+++ b/src/backend/optimizer/util/predtest.c
@@ -33,9 +33,8 @@
  * likely to require O(N^2) time, and more often than not fail anyway.
  * So we set an arbitrary limit on the number of array elements that
  * we will allow to be treated as an AND or OR clause.
- * XXX is it worth exposing this as a GUC knob?
  */
-#define MAX_SAOP_ARRAY_SIZE		100
+int array_optimization_size_limit = ARRAY_OPTIMIZATION_SIZE_LIMIT;
 
 /*
  * To avoid redundant coding in predicate_implied_by_recurse and
@@ -812,11 +811,11 @@ predicate_refuted_by_recurse(Node *clause, Node *predicate,
  * If the expression is classified as AND- or OR-type, then *info is filled
  * in with the functions needed to iterate over its components.
  *
- * This function also implements enforcement of MAX_SAOP_ARRAY_SIZE: if a
+ * This function also implements enforcement of array_optimization_size_limit: if a
  * ScalarArrayOpExpr's array has too many elements, we just classify it as an
  * atom.  (This will result in its being passed as-is to the simple_clause
  * functions, which will fail to prove anything about it.)	Note that we
- * cannot just stop after considering MAX_SAOP_ARRAY_SIZE elements; in general
+ * cannot just stop after considering array_optimization_size_limit elements; in general
  * that would result in wrong proofs, rather than failing to prove anything.
  */
 static PredClass
@@ -874,7 +873,7 @@ predicate_classify(Node *clause, PredIterInfo info)
 
 			arrayval = DatumGetArrayTypeP(((Const *) arraynode)->constvalue);
 			nelems = ArrayGetNItems(ARR_NDIM(arrayval), ARR_DIMS(arrayval));
-			if (nelems <= MAX_SAOP_ARRAY_SIZE)
+			if (nelems <= array_optimization_size_limit)
 			{
 				info->startup_fn = arrayconst_startup_fn;
 				info->next_fn = arrayconst_next_fn;
@@ -884,7 +883,7 @@ predicate_classify(Node *clause, PredIterInfo info)
 		}
 		else if (arraynode && IsA(arraynode, ArrayExpr) &&
 				 !((ArrayExpr *) arraynode)->multidims &&
-				 list_length(((ArrayExpr *) arraynode)->elements) <= MAX_SAOP_ARRAY_SIZE)
+				 list_length(((ArrayExpr *) arraynode)->elements) <= array_optimization_size_limit)
 		{
 			info->startup_fn = arrayexpr_startup_fn;
 			info->next_fn = arrayexpr_next_fn;
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index ce54828fbb..f1bc483b2e 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -52,6 +52,7 @@
 #include "optimizer/geqo.h"
 #include "optimizer/paths.h"
 #include "optimizer/planmain.h"
+#include "optimizer/predtest.h"
 #include "parser/parse_expr.h"
 #include "parser/parse_type.h"
 #include "parser/parser.h"
@@ -3064,6 +3065,20 @@ static struct config_int ConfigureNamesInt[] =
 		NULL, NULL, NULL
 	},
 
+	{
+		{"array_optimization_size_limit", PGC_USERSET, QUERY_TUNING_OTHER,
+			gettext_noop("Sets the array size limit beyond which predicate "
+						 "optimization is not used."),
+			gettext_noop("The optimizer evaluates scalar array expressions "
+						 "to determine if they can be treated as AND or OR clauses. "
+						 "This optimization proving is only performed if the array "
+						 "contains at most this many items.")
+		},
+		&array_optimization_size_limit,
+		ARRAY_OPTIMIZATION_SIZE_LIMIT, 0, INT_MAX,
+		NULL, NULL, NULL
+	},
+
 	/* End-of-list marker */
 	{
 		{NULL, 0, 0, NULL, NULL}, NULL, 0, 0, 0, NULL, NULL, NULL
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index 4e61bc6521..58d911950e 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -344,6 +344,7 @@
 
 # - Other Planner Options -
 
+#array_optimization_size_limit = 100
 #default_statistics_target = 100	# range 1-10000
 #constraint_exclusion = partition	# on, off, or partition
 #cursor_tuple_fraction = 0.1		# range 0.0-1.0
diff --git a/src/include/optimizer/predtest.h b/src/include/optimizer/predtest.h
index 69d87ea5c5..e8f6b91ef2 100644
--- a/src/include/optimizer/predtest.h
+++ b/src/include/optimizer/predtest.h
@@ -16,6 +16,8 @@
 
 #include "nodes/primnodes.h"
 
+#define ARRAY_OPTIMIZATION_SIZE_LIMIT		100
+extern PGDLLIMPORT int array_optimization_size_limit;
 
 extern bool predicate_implied_by(List *predicate_list, List *clause_list,
 					 bool weak);
diff --git a/src/test/modules/test_predtest/expected/test_predtest.out b/src/test/modules/test_predtest/expected/test_predtest.out
index 5574e03204..bca47107a9 100644
--- a/src/test/modules/test_predtest/expected/test_predtest.out
+++ b/src/test/modules/test_predtest/expected/test_predtest.out
@@ -767,6 +767,22 @@ w_i_holds         | t
 s_r_holds         | f
 w_r_holds         | f
 
+set array_optimization_size_limit to 1;
+select * from test_predtest($$
+select x <= 3, x in (1,3)
+from integers
+$$);
+-[ RECORD 1 ]-----+--
+strong_implied_by | f
+weak_implied_by   | f
+strong_refuted_by | f
+weak_refuted_by   | f
+s_i_holds         | t
+w_i_holds         | t
+s_r_holds         | f
+w_r_holds         | f
+
+set array_optimization_size_limit to default;
 select * from test_predtest($$
 select x <= 5, x in (1,3,5,7)
 from integers
diff --git a/src/test/modules/test_predtest/sql/test_predtest.sql b/src/test/modules/test_predtest/sql/test_predtest.sql
index 2734735843..39c6d383ad 100644
--- a/src/test/modules/test_predtest/sql/test_predtest.sql
+++ b/src/test/modules/test_predtest/sql/test_predtest.sql
@@ -301,6 +301,13 @@ select x <= 5, x in (1,3,5)
 from integers
 $$);
 
+set array_optimization_size_limit to 1;
+select * from test_predtest($$
+select x <= 3, x in (1,3)
+from integers
+$$);
+set array_optimization_size_limit to default;
+
 select * from test_predtest($$
 select x <= 5, x in (1,3,5,7)
 from integers
