From 99459d749505d98b1ba2b93398df46f50fd3a963 Mon Sep 17 00:00:00 2001
From: Andrey <amborodin@acm.org>
Date: Mon, 10 Jun 2019 11:54:59 +0500
Subject: [PATCH 3/3] Function relopt for gist build

---
 src/backend/access/common/reloptions.c | 12 ++++++
 src/backend/access/gist/gistbuild.c    | 56 ++++++++++++++++++++++++++
 src/backend/access/gist/gistutil.c     |  3 +-
 src/include/access/gist_private.h      |  2 +
 4 files changed, 72 insertions(+), 1 deletion(-)

diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c
index 5325dd3f61..698bc1a1aa 100644
--- a/src/backend/access/common/reloptions.c
+++ b/src/backend/access/common/reloptions.c
@@ -491,6 +491,18 @@ static relopt_enum enumRelOpts[] =
 
 static relopt_string stringRelOpts[] =
 {
+	{
+		{
+			"fast_build_sort_function",
+			"Function for presorting data instead of usual penalty\\split inserts",
+			RELOPT_KIND_GIST,
+			AccessExclusiveLock
+		},
+		0,
+		true,
+		gistValidateBuildFuncOption,
+		NULL
+	},
 	/* list terminator */
 	{{NULL}}
 };
diff --git a/src/backend/access/gist/gistbuild.c b/src/backend/access/gist/gistbuild.c
index 0df03c8c36..02fe1ac1d0 100644
--- a/src/backend/access/gist/gistbuild.c
+++ b/src/backend/access/gist/gistbuild.c
@@ -22,8 +22,10 @@
 #include "access/tableam.h"
 #include "access/xloginsert.h"
 #include "catalog/index.h"
+#include "catalog/pg_type.h"
 #include "miscadmin.h"
 #include "optimizer/optimizer.h"
+#include "parser/parse_func.h"
 #include "storage/bufmgr.h"
 #include "storage/smgr.h"
 #include "utils/memutils.h"
@@ -306,6 +308,8 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo)
 	Oid			SortSupportFnOids[INDEX_MAX_KEYS];
 	bool		hasallsortsupports = true;
 	int			keyscount = IndexRelationGetNumberOfKeyAttributes(index);
+	Oid			firstsortduncoid;
+	bool		havefirstsortfn = false;
 
 	buildstate.indexrel = index;
 	buildstate.heaprel = heap;
@@ -323,6 +327,16 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo)
 		else
 			buildstate.bufferingMode = GIST_BUFFERING_AUTO;
 
+		if (options->vl_len_ > offsetof(GiSTOptions, buildSortFunctionOffset) &&
+			options->buildSortFunctionOffset > 0)
+		{
+			char	*sortFuncName = (char *) options + options->buildSortFunctionOffset;
+			Oid		 argList[1] = {INTERNALOID};
+			List	*namelist = stringToQualifiedNameList(sortFuncName);
+			firstsortduncoid = LookupFuncName(namelist, 1, argList, false);
+			havefirstsortfn = true;
+		}
+
 		fillfactor = options->fillfactor;
 	}
 	else
@@ -339,6 +353,11 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo)
 
 	for (i = 0; i < keyscount; i++)
 	{
+		if (i == 0 && havefirstsortfn)
+		{
+			SortSupportFnOids[i] = firstsortduncoid;
+			continue;
+		}
 		SortSupportFnOids[i] = index_getprocid(index, i + 1, GIST_SORTSUPPORT_PROC);
 		if (!OidIsValid(SortSupportFnOids[i]))
 		{
@@ -446,6 +465,43 @@ gistbuild(Relation heap, Relation index, IndexInfo *indexInfo)
 }
 
 /*
+<<<<<<< HEAD
+=======
+ * Validator for "buffering" reloption on GiST indexes. Allows "on", "off"
+ * and "auto" values.
+ */
+void
+gistValidateBufferingOption(const char *value)
+{
+	if (value == NULL ||
+		(strcmp(value, "on") != 0 &&
+		 strcmp(value, "off") != 0 &&
+		 strcmp(value, "auto") != 0))
+	{
+		ereport(ERROR,
+				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+				 errmsg("invalid value for \"buffering\" option"),
+				 errdetail("Valid values are \"on\", \"off\", and \"auto\".")));
+	}
+}
+
+/*
+ * Validator for "fast_build_sort_function" reloption on GiST indexes. Allows function name
+ */
+void
+gistValidateBuildFuncOption(const char *value)
+{
+	Oid		 argList[1] = {INTERNALOID};
+	List	*namelist;
+	if (value == NULL)
+		return;
+	namelist = stringToQualifiedNameList(value);
+	/* LookupFuncName will fail if function is not existent */
+	LookupFuncName(namelist, 1, argList, false);
+}
+
+/*
+>>>>>>> function relopt for gist build
  * Attempt to switch to buffering mode.
  *
  * If there is not enough memory for buffering build, sets bufferingMode
diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c
index dfc2a7d36c..17d9fe4806 100644
--- a/src/backend/access/gist/gistutil.c
+++ b/src/backend/access/gist/gistutil.c
@@ -925,7 +925,8 @@ gistoptions(Datum reloptions, bool validate)
 {
 	static const relopt_parse_elt tab[] = {
 		{"fillfactor", RELOPT_TYPE_INT, offsetof(GiSTOptions, fillfactor)},
-		{"buffering", RELOPT_TYPE_ENUM, offsetof(GiSTOptions, buffering_mode)}
+		{"buffering", RELOPT_TYPE_ENUM, offsetof(GiSTOptions, buffering_mode)},
+		{"fast_build_sort_function", RELOPT_TYPE_STRING, offsetof(GiSTOptions, buildSortFunctionOffset)}
 	};
 
 	return (bytea *) build_reloptions(reloptions, validate,
diff --git a/src/include/access/gist_private.h b/src/include/access/gist_private.h
index 89f77ddcae..324dbeb815 100644
--- a/src/include/access/gist_private.h
+++ b/src/include/access/gist_private.h
@@ -396,6 +396,7 @@ typedef struct GiSTOptions
 	int32		vl_len_;		/* varlena header (do not touch directly!) */
 	int			fillfactor;		/* page fill factor in percent (0..100) */
 	GistOptBufferingMode buffering_mode;	/* buffering build mode */
+	int			buildSortFunctionOffset;	/* used buffering sort function */
 } GiSTOptions;
 
 /* gist.c */
@@ -543,6 +544,7 @@ extern void gistSplitByKey(Relation r, Page page, IndexTuple *itup,
 extern IndexBuildResult *gistbuild(Relation heap, Relation index,
 								   struct IndexInfo *indexInfo);
 extern void gistValidateBufferingOption(const char *value);
+extern void gistValidateBuildFuncOption(const char *value);
 
 /* gistbuildbuffers.c */
 extern GISTBuildBuffers *gistInitBuildBuffers(int pagesPerBuffer, int levelStep,
-- 
2.21.1 (Apple Git-122.3)

