From 735e199d6736569eb648e33256b3c5268c2a36eb Mon Sep 17 00:00:00 2001
From: Nikita Glukhov <n.gluhov@postgrespro.ru>
Date: Tue, 10 Sep 2019 03:35:39 +0300
Subject: [PATCH 3/5] Use amattoptions in contrib/bloom

---
 contrib/bloom/bloom.h            | 10 +++++++++
 contrib/bloom/blutils.c          | 44 +++++++++++++++++++++-------------------
 contrib/bloom/expected/bloom.out | 23 +++++++++++++--------
 contrib/bloom/sql/bloom.sql      |  9 ++++----
 4 files changed, 53 insertions(+), 33 deletions(-)

diff --git a/contrib/bloom/bloom.h b/contrib/bloom/bloom.h
index 010148e..681aaaa 100644
--- a/contrib/bloom/bloom.h
+++ b/contrib/bloom/bloom.h
@@ -16,6 +16,7 @@
 #include "access/amapi.h"
 #include "access/generic_xlog.h"
 #include "access/itup.h"
+#include "access/reloptions.h"
 #include "access/xlog.h"
 #include "nodes/pathnodes.h"
 #include "fmgr.h"
@@ -105,6 +106,13 @@ typedef struct BloomOptions
 											 * index key */
 } BloomOptions;
 
+/* Bloom attribute options */
+typedef struct BloomAttOptions
+{
+	int32		vl_len_;		/* varlena header (do not touch directly!) */
+	int			bitSize;		/* # of bits generated for this index key */
+} BloomAttOptions;
+
 /*
  * FreeBlockNumberArray - array of block numbers sized so that metadata fill
  * all space in metapage.
@@ -206,6 +214,8 @@ extern IndexBulkDeleteResult *blbulkdelete(IndexVacuumInfo *info,
 extern IndexBulkDeleteResult *blvacuumcleanup(IndexVacuumInfo *info,
 											  IndexBulkDeleteResult *stats);
 extern bytea *bloptions(Datum reloptions, bool validate);
+extern void blattoptions(local_relopts *relopts, int attno);
+
 extern void blcostestimate(PlannerInfo *root, IndexPath *path,
 						   double loop_count, Cost *indexStartupCost,
 						   Cost *indexTotalCost, Selectivity *indexSelectivity,
diff --git a/contrib/bloom/blutils.c b/contrib/bloom/blutils.c
index b62ba7f..b286081 100644
--- a/contrib/bloom/blutils.c
+++ b/contrib/bloom/blutils.c
@@ -39,7 +39,7 @@ PG_FUNCTION_INFO_V1(blhandler);
 static relopt_kind bl_relopt_kind;
 
 /* parse table for fillRelOptions */
-static relopt_parse_elt bl_relopt_tab[INDEX_MAX_KEYS + 1];
+static relopt_parse_elt bl_relopt_tab[1];
 
 static int32 myRand(void);
 static void mySrand(uint32 seed);
@@ -52,9 +52,6 @@ static void mySrand(uint32 seed);
 void
 _PG_init(void)
 {
-	int			i;
-	char		buf[16];
-
 	bl_relopt_kind = add_reloption_kind();
 
 	/* Option for length of signature */
@@ -64,19 +61,6 @@ _PG_init(void)
 	bl_relopt_tab[0].optname = "length";
 	bl_relopt_tab[0].opttype = RELOPT_TYPE_INT;
 	bl_relopt_tab[0].offset = offsetof(BloomOptions, bloomLength);
-
-	/* Number of bits for each possible index column: col1, col2, ... */
-	for (i = 0; i < INDEX_MAX_KEYS; i++)
-	{
-		snprintf(buf, sizeof(buf), "col%d", i + 1);
-		add_int_reloption(bl_relopt_kind, buf,
-						  "Number of bits generated for each index column",
-						  DEFAULT_BLOOM_BITS, 1, MAX_BLOOM_BITS);
-		bl_relopt_tab[i + 1].optname = MemoryContextStrdup(TopMemoryContext,
-														   buf);
-		bl_relopt_tab[i + 1].opttype = RELOPT_TYPE_INT;
-		bl_relopt_tab[i + 1].offset = offsetof(BloomOptions, bitSize[0]) + sizeof(int) * i;
-	}
 }
 
 /*
@@ -86,13 +70,10 @@ static BloomOptions *
 makeDefaultBloomOptions(void)
 {
 	BloomOptions *opts;
-	int			i;
 
 	opts = (BloomOptions *) palloc0(sizeof(BloomOptions));
 	/* Convert DEFAULT_BLOOM_LENGTH from # of bits to # of words */
 	opts->bloomLength = (DEFAULT_BLOOM_LENGTH + SIGNWORDBITS - 1) / SIGNWORDBITS;
-	for (i = 0; i < INDEX_MAX_KEYS; i++)
-		opts->bitSize[i] = DEFAULT_BLOOM_BITS;
 	SET_VARSIZE(opts, sizeof(BloomOptions));
 	return opts;
 }
@@ -131,7 +112,7 @@ blhandler(PG_FUNCTION_ARGS)
 	amroutine->amcanreturn = NULL;
 	amroutine->amcostestimate = blcostestimate;
 	amroutine->amoptions = bloptions;
-	amroutine->amattoptions = NULL;
+	amroutine->amattoptions = blattoptions;
 	amroutine->amproperty = NULL;
 	amroutine->ambuildphasename = NULL;
 	amroutine->amvalidate = blvalidate;
@@ -418,6 +399,7 @@ void
 BloomFillMetapage(Relation index, Page metaPage)
 {
 	BloomOptions *opts;
+	BloomAttOptions **attopts;
 	BloomMetaPageData *metadata;
 
 	/*
@@ -428,6 +410,11 @@ BloomFillMetapage(Relation index, Page metaPage)
 	if (!opts)
 		opts = makeDefaultBloomOptions();
 
+	attopts = (BloomAttOptions **) RelationGetIndexAttOptions(index, false);
+
+	for (int i = 0; i < RelationGetNumberOfAttributes(index); i++)
+		opts->bitSize[i] = attopts[i]->bitSize;
+
 	/*
 	 * Initialize contents of meta page, including a copy of the options,
 	 * which are now frozen for the life of the index.
@@ -491,3 +478,18 @@ bloptions(Datum reloptions, bool validate)
 
 	return (bytea *) rdopts;
 }
+
+/*
+ * Parse per-attribute reloptions for bloom index, producing a BloomOptions struct.
+ */
+void
+blattoptions(local_relopts *relopts, int attno)
+{
+	BloomAttOptions *attopts = NULL;
+
+	init_local_reloptions(relopts, attopts, sizeof(*attopts));
+	add_local_int_reloption(relopts, "bits",
+							"Number of bits generated for index column",
+							DEFAULT_BLOOM_BITS, 1, MAX_BLOOM_BITS,
+							&attopts->bitSize);
+}
diff --git a/contrib/bloom/expected/bloom.out b/contrib/bloom/expected/bloom.out
index 5ab9e34..3ade0b3 100644
--- a/contrib/bloom/expected/bloom.out
+++ b/contrib/bloom/expected/bloom.out
@@ -4,7 +4,7 @@ CREATE TABLE tst (
 	t	text
 );
 INSERT INTO tst SELECT i%10, substr(md5(i::text), 1, 1) FROM generate_series(1,2000) i;
-CREATE INDEX bloomidx ON tst USING bloom (i, t) WITH (col1 = 3);
+CREATE INDEX bloomidx ON tst USING bloom (i DEFAULT (bits = 3), t);
 SET enable_seqscan=on;
 SET enable_bitmapscan=off;
 SET enable_indexscan=off;
@@ -144,7 +144,7 @@ CREATE UNLOGGED TABLE tstu (
 	t	text
 );
 INSERT INTO tstu SELECT i%10, substr(md5(i::text), 1, 1) FROM generate_series(1,2000) i;
-CREATE INDEX bloomidxu ON tstu USING bloom (i, t) WITH (col2 = 4);
+CREATE INDEX bloomidxu ON tstu USING bloom (i, t DEFAULT (bits = 4));
 SET enable_seqscan=off;
 SET enable_bitmapscan=on;
 SET enable_indexscan=on;
@@ -214,16 +214,23 @@ ORDER BY 1;
 -- relation options
 --
 DROP INDEX bloomidx;
-CREATE INDEX bloomidx ON tst USING bloom (i, t) WITH (length=7, col1=4);
+CREATE INDEX bloomidx ON tst USING bloom (i  DEFAULT (bits=4), t) WITH (length=7);
 SELECT reloptions FROM pg_class WHERE oid = 'bloomidx'::regclass;
-    reloptions     
--------------------
- {length=7,col1=4}
+ reloptions 
+------------
+ {length=7}
 (1 row)
 
+SELECT attnum, attoptions FROM pg_attribute WHERE attrelid = 'bloomidx'::regclass ORDER BY 1;
+ attnum | attoptions 
+--------+------------
+      1 | {bits=4}
+      2 | 
+(2 rows)
+
 -- check for min and max values
 \set VERBOSITY terse
 CREATE INDEX bloomidx2 ON tst USING bloom (i, t) WITH (length=0);
 ERROR:  value 0 out of bounds for option "length"
-CREATE INDEX bloomidx2 ON tst USING bloom (i, t) WITH (col1=0);
-ERROR:  value 0 out of bounds for option "col1"
+CREATE INDEX bloomidx2 ON tst USING bloom (i DEFAULT (bits=0), t);
+ERROR:  value 0 out of bounds for option "bits"
diff --git a/contrib/bloom/sql/bloom.sql b/contrib/bloom/sql/bloom.sql
index 32755f2..362647a 100644
--- a/contrib/bloom/sql/bloom.sql
+++ b/contrib/bloom/sql/bloom.sql
@@ -6,7 +6,7 @@ CREATE TABLE tst (
 );
 
 INSERT INTO tst SELECT i%10, substr(md5(i::text), 1, 1) FROM generate_series(1,2000) i;
-CREATE INDEX bloomidx ON tst USING bloom (i, t) WITH (col1 = 3);
+CREATE INDEX bloomidx ON tst USING bloom (i DEFAULT (bits = 3), t);
 
 SET enable_seqscan=on;
 SET enable_bitmapscan=off;
@@ -58,7 +58,7 @@ CREATE UNLOGGED TABLE tstu (
 );
 
 INSERT INTO tstu SELECT i%10, substr(md5(i::text), 1, 1) FROM generate_series(1,2000) i;
-CREATE INDEX bloomidxu ON tstu USING bloom (i, t) WITH (col2 = 4);
+CREATE INDEX bloomidxu ON tstu USING bloom (i, t DEFAULT (bits = 4));
 
 SET enable_seqscan=off;
 SET enable_bitmapscan=on;
@@ -86,9 +86,10 @@ ORDER BY 1;
 -- relation options
 --
 DROP INDEX bloomidx;
-CREATE INDEX bloomidx ON tst USING bloom (i, t) WITH (length=7, col1=4);
+CREATE INDEX bloomidx ON tst USING bloom (i  DEFAULT (bits=4), t) WITH (length=7);
 SELECT reloptions FROM pg_class WHERE oid = 'bloomidx'::regclass;
+SELECT attnum, attoptions FROM pg_attribute WHERE attrelid = 'bloomidx'::regclass ORDER BY 1;
 -- check for min and max values
 \set VERBOSITY terse
 CREATE INDEX bloomidx2 ON tst USING bloom (i, t) WITH (length=0);
-CREATE INDEX bloomidx2 ON tst USING bloom (i, t) WITH (col1=0);
+CREATE INDEX bloomidx2 ON tst USING bloom (i DEFAULT (bits=0), t);
-- 
2.7.4

