GiST operator class for bool

Started by Emre Hasegeliover 4 years ago11 messages
#1Emre Hasegeli
emre@hasegeli.com
1 attachment(s)

It could be useful to use bool in exclusion constraints, but it's
currently not nicely supported. The attached patch adds support for
bool to the btree_gist extension, so we can do this.

I am adding this to the commitfest 2021-07.

Attachments:

0001-btree_gist-Support-bool.patchapplication/octet-stream; name=0001-btree_gist-Support-bool.patchDownload
From 95d864ac93fa272f936e78ca4c03b0277a093379 Mon Sep 17 00:00:00 2001
From: Emre Hasegeli <emre@hasegeli.com>
Date: Tue, 8 Jun 2021 12:53:25 +0300
Subject: [PATCH] btree_gist: Support bool

---
 contrib/btree_gist/Makefile                 |   5 +-
 contrib/btree_gist/btree_bool.c             | 169 ++++++++++++++++++++
 contrib/btree_gist/btree_gist--1.6--1.7.sql |  62 +++++++
 contrib/btree_gist/btree_gist.control       |   2 +-
 contrib/btree_gist/btree_gist.h             |   1 +
 contrib/btree_gist/btree_utils_num.c        |   8 +
 contrib/btree_gist/expected/bool.out        |  66 ++++++++
 contrib/btree_gist/sql/bool.sql             |  31 ++++
 8 files changed, 341 insertions(+), 3 deletions(-)
 create mode 100644 contrib/btree_gist/btree_bool.c
 create mode 100644 contrib/btree_gist/btree_gist--1.6--1.7.sql
 create mode 100644 contrib/btree_gist/expected/bool.out
 create mode 100644 contrib/btree_gist/sql/bool.sql

diff --git a/contrib/btree_gist/Makefile b/contrib/btree_gist/Makefile
index e92d974a1a..48997c75f6 100644
--- a/contrib/btree_gist/Makefile
+++ b/contrib/btree_gist/Makefile
@@ -1,17 +1,18 @@
 # contrib/btree_gist/Makefile
 
 MODULE_big = btree_gist
 
 OBJS =  \
 	$(WIN32RES) \
 	btree_bit.o \
+	btree_bool.o \
 	btree_bytea.o \
 	btree_cash.o \
 	btree_date.o \
 	btree_enum.o \
 	btree_float4.o \
 	btree_float8.o \
 	btree_gist.o \
 	btree_inet.o \
 	btree_int2.o \
 	btree_int4.o \
@@ -25,26 +26,26 @@ OBJS =  \
 	btree_time.o \
 	btree_ts.o \
 	btree_utils_num.o \
 	btree_utils_var.o \
 	btree_uuid.o
 
 EXTENSION = btree_gist
 DATA = btree_gist--1.0--1.1.sql \
        btree_gist--1.1--1.2.sql btree_gist--1.2.sql btree_gist--1.2--1.3.sql \
        btree_gist--1.3--1.4.sql btree_gist--1.4--1.5.sql \
-       btree_gist--1.5--1.6.sql
+       btree_gist--1.5--1.6.sql btree_gist--1.6--1.7.sql
 PGFILEDESC = "btree_gist - B-tree equivalent GiST operator classes"
 
 REGRESS = init int2 int4 int8 float4 float8 cash oid timestamp timestamptz \
         time timetz date interval macaddr macaddr8 inet cidr text varchar char \
-        bytea bit varbit numeric uuid not_equal enum
+        bytea bit varbit numeric uuid not_equal enum bool
 
 SHLIB_LINK += $(filter -lm, $(LIBS))
 
 ifdef USE_PGXS
 PG_CONFIG = pg_config
 PGXS := $(shell $(PG_CONFIG) --pgxs)
 include $(PGXS)
 else
 subdir = contrib/btree_gist
 top_builddir = ../..
diff --git a/contrib/btree_gist/btree_bool.c b/contrib/btree_gist/btree_bool.c
new file mode 100644
index 0000000000..25ce1e2b77
--- /dev/null
+++ b/contrib/btree_gist/btree_bool.c
@@ -0,0 +1,169 @@
+/*
+ * contrib/btree_gist/btree_bool.c
+ */
+#include "postgres.h"
+
+#include "btree_gist.h"
+#include "btree_utils_num.h"
+#include "common/int.h"
+
+typedef struct boolkey
+{
+	bool		lower;
+	bool		upper;
+} boolKEY;
+
+/*
+** bool ops
+*/
+PG_FUNCTION_INFO_V1(gbt_bool_compress);
+PG_FUNCTION_INFO_V1(gbt_bool_fetch);
+PG_FUNCTION_INFO_V1(gbt_bool_union);
+PG_FUNCTION_INFO_V1(gbt_bool_picksplit);
+PG_FUNCTION_INFO_V1(gbt_bool_consistent);
+PG_FUNCTION_INFO_V1(gbt_bool_penalty);
+PG_FUNCTION_INFO_V1(gbt_bool_same);
+
+static bool
+gbt_boolgt(const void *a, const void *b, FmgrInfo *flinfo)
+{
+	return (*((const bool *) a) > *((const bool *) b));
+}
+static bool
+gbt_boolge(const void *a, const void *b, FmgrInfo *flinfo)
+{
+	return (*((const bool *) a) >= *((const bool *) b));
+}
+static bool
+gbt_booleq(const void *a, const void *b, FmgrInfo *flinfo)
+{
+	return (*((const bool *) a) == *((const bool *) b));
+}
+static bool
+gbt_boolle(const void *a, const void *b, FmgrInfo *flinfo)
+{
+	return (*((const bool *) a) <= *((const bool *) b));
+}
+static bool
+gbt_boollt(const void *a, const void *b, FmgrInfo *flinfo)
+{
+	return (*((const bool *) a) < *((const bool *) b));
+}
+
+static int
+gbt_boolkey_cmp(const void *a, const void *b, FmgrInfo *flinfo)
+{
+	boolKEY   *ia = (boolKEY *) (((const Nsrt *) a)->t);
+	boolKEY   *ib = (boolKEY *) (((const Nsrt *) b)->t);
+
+	if (ia->lower == ib->lower)
+	{
+		if (ia->upper == ib->upper)
+			return 0;
+
+		return (ia->upper > ib->upper) ? 1 : -1;
+	}
+
+	return (ia->lower > ib->lower) ? 1 : -1;
+}
+
+
+static const gbtree_ninfo tinfo =
+{
+	gbt_t_bool,
+	sizeof(bool),
+	4,							/* sizeof(gbtreekey4) */
+	gbt_boolgt,
+	gbt_boolge,
+	gbt_booleq,
+	gbt_boolle,
+	gbt_boollt,
+	gbt_boolkey_cmp,
+};
+
+
+/**************************************************
+ * bool ops
+ **************************************************/
+
+
+Datum
+gbt_bool_compress(PG_FUNCTION_ARGS)
+{
+	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
+
+	PG_RETURN_POINTER(gbt_num_compress(entry, &tinfo));
+}
+
+Datum
+gbt_bool_fetch(PG_FUNCTION_ARGS)
+{
+	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
+
+	PG_RETURN_POINTER(gbt_num_fetch(entry, &tinfo));
+}
+
+Datum
+gbt_bool_consistent(PG_FUNCTION_ARGS)
+{
+	GISTENTRY  *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
+	bool		query = PG_GETARG_INT16(1);
+	StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
+
+	/* Oid		subtype = PG_GETARG_OID(3); */
+	bool	   *recheck = (bool *) PG_GETARG_POINTER(4);
+	boolKEY    *kkk = (boolKEY *) DatumGetPointer(entry->key);
+	GBT_NUMKEY_R key;
+
+	/* All cases served by this function are exact */
+	*recheck = false;
+
+	key.lower = (GBT_NUMKEY *) &kkk->lower;
+	key.upper = (GBT_NUMKEY *) &kkk->upper;
+
+	PG_RETURN_BOOL(gbt_num_consistent(&key, (void *) &query, &strategy,
+									  GIST_LEAF(entry), &tinfo, fcinfo->flinfo));
+}
+
+
+Datum
+gbt_bool_union(PG_FUNCTION_ARGS)
+{
+	GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
+	void	   *out = palloc(sizeof(boolKEY));
+
+	*(int *) PG_GETARG_POINTER(1) = sizeof(boolKEY);
+	PG_RETURN_POINTER(gbt_num_union((void *) out, entryvec, &tinfo, fcinfo->flinfo));
+}
+
+
+Datum
+gbt_bool_penalty(PG_FUNCTION_ARGS)
+{
+	boolKEY    *origentry = (boolKEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(0))->key);
+	boolKEY    *newentry = (boolKEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(1))->key);
+	float	   *result = (float *) PG_GETARG_POINTER(2);
+
+	penalty_num(result, origentry->lower, origentry->upper, newentry->lower, newentry->upper);
+
+	PG_RETURN_POINTER(result);
+}
+
+Datum
+gbt_bool_picksplit(PG_FUNCTION_ARGS)
+{
+	PG_RETURN_POINTER(gbt_num_picksplit((GistEntryVector *) PG_GETARG_POINTER(0),
+										(GIST_SPLITVEC *) PG_GETARG_POINTER(1),
+										&tinfo, fcinfo->flinfo));
+}
+
+Datum
+gbt_bool_same(PG_FUNCTION_ARGS)
+{
+	boolKEY    *b1 = (boolKEY *) PG_GETARG_POINTER(0);
+	boolKEY    *b2 = (boolKEY *) PG_GETARG_POINTER(1);
+	bool	   *result = (bool *) PG_GETARG_POINTER(2);
+
+	*result = gbt_num_same((void *) b1, (void *) b2, &tinfo, fcinfo->flinfo);
+	PG_RETURN_POINTER(result);
+}
diff --git a/contrib/btree_gist/btree_gist--1.6--1.7.sql b/contrib/btree_gist/btree_gist--1.6--1.7.sql
new file mode 100644
index 0000000000..0e68356982
--- /dev/null
+++ b/contrib/btree_gist/btree_gist--1.6--1.7.sql
@@ -0,0 +1,62 @@
+/* contrib/btree_gist/btree_gist--1.6--1.7.sql */
+
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "ALTER EXTENSION btree_gist UPDATE TO '1.7'" to load this file. \quit
+
+-- This upgrade scripts add support for bool.
+
+-- Define the GiST support methods
+CREATE FUNCTION gbt_bool_consistent(internal,bool,int2,oid,internal)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_bool_compress(internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_bool_fetch(internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_bool_penalty(internal,internal,internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_bool_picksplit(internal, internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_bool_union(internal, internal)
+RETURNS gbtreekey8
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+CREATE FUNCTION gbt_bool_same(gbtreekey8, gbtreekey8, internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+-- Create the operator class
+CREATE OPERATOR CLASS gist_bool_ops
+DEFAULT FOR TYPE bool USING gist
+AS
+	OPERATOR	1	<  ,
+	OPERATOR	2	<= ,
+	OPERATOR	3	=  ,
+	OPERATOR	4	>= ,
+	OPERATOR	5	>  ,
+	OPERATOR	6	<> ,
+	FUNCTION	1	gbt_bool_consistent (internal, bool, int2, oid, internal),
+	FUNCTION	2	gbt_bool_union (internal, internal),
+	FUNCTION	3	gbt_bool_compress (internal),
+	FUNCTION	4	gbt_decompress (internal),
+	FUNCTION	5	gbt_bool_penalty (internal, internal, internal),
+	FUNCTION	6	gbt_bool_picksplit (internal, internal),
+	FUNCTION	7	gbt_bool_same (gbtreekey8, gbtreekey8, internal),
+	FUNCTION	9   gbt_bool_fetch (internal),
+	STORAGE		gbtreekey8;
diff --git a/contrib/btree_gist/btree_gist.control b/contrib/btree_gist/btree_gist.control
index e5c41fe8f3..fa9171a80a 100644
--- a/contrib/btree_gist/btree_gist.control
+++ b/contrib/btree_gist/btree_gist.control
@@ -1,6 +1,6 @@
 # btree_gist extension
 comment = 'support for indexing common datatypes in GiST'
-default_version = '1.6'
+default_version = '1.7'
 module_pathname = '$libdir/btree_gist'
 relocatable = true
 trusted = true
diff --git a/contrib/btree_gist/btree_gist.h b/contrib/btree_gist/btree_gist.h
index 14c7c8ee19..f22f14ac4c 100644
--- a/contrib/btree_gist/btree_gist.h
+++ b/contrib/btree_gist/btree_gist.h
@@ -25,16 +25,17 @@ enum gbtree_type
 	gbt_t_oid,
 	gbt_t_time,
 	gbt_t_date,
 	gbt_t_intv,
 	gbt_t_macad,
 	gbt_t_macad8,
 	gbt_t_text,
 	gbt_t_bpchar,
 	gbt_t_bytea,
 	gbt_t_bit,
+	gbt_t_bool,
 	gbt_t_inet,
 	gbt_t_uuid,
 	gbt_t_enum
 };
 
 #endif
diff --git a/contrib/btree_gist/btree_utils_num.c b/contrib/btree_gist/btree_utils_num.c
index 7564a403c7..5632ee0586 100644
--- a/contrib/btree_gist/btree_utils_num.c
+++ b/contrib/btree_gist/btree_utils_num.c
@@ -12,36 +12,41 @@
 
 GISTENTRY *
 gbt_num_compress(GISTENTRY *entry, const gbtree_ninfo *tinfo)
 {
 	GISTENTRY  *retval;
 
 	if (entry->leafkey)
 	{
 		union
 		{
+			bool		bo;
 			int16		i2;
 			int32		i4;
 			int64		i8;
 			float4		f4;
 			float8		f8;
 			DateADT		dt;
 			TimeADT		tm;
 			Timestamp	ts;
 			Cash		ch;
 		}			v;
 
 		GBT_NUMKEY *r = (GBT_NUMKEY *) palloc0(tinfo->indexsize);
 		void	   *leaf = NULL;
 
 		switch (tinfo->t)
 		{
+			case gbt_t_bool:
+				v.bo = DatumGetBool(entry->key);
+				leaf = &v.bo;
+				break;
 			case gbt_t_int2:
 				v.i2 = DatumGetInt16(entry->key);
 				leaf = &v.i2;
 				break;
 			case gbt_t_int4:
 				v.i4 = DatumGetInt32(entry->key);
 				leaf = &v.i4;
 				break;
 			case gbt_t_int8:
 				v.i8 = DatumGetInt64(entry->key);
@@ -106,20 +111,23 @@ gbt_num_fetch(GISTENTRY *entry, const gbtree_ninfo *tinfo)
 
 	Assert(tinfo->indexsize >= 2 * tinfo->size);
 
 	/*
 	 * Get the original Datum from the stored datum. On leaf entries, the
 	 * lower and upper bound are the same. We just grab the lower bound and
 	 * return it.
 	 */
 	switch (tinfo->t)
 	{
+		case gbt_t_bool:
+			datum = BoolGetDatum(*(bool *) entry->key);
+			break;
 		case gbt_t_int2:
 			datum = Int16GetDatum(*(int16 *) entry->key);
 			break;
 		case gbt_t_int4:
 			datum = Int32GetDatum(*(int32 *) entry->key);
 			break;
 		case gbt_t_int8:
 			datum = Int64GetDatum(*(int64 *) entry->key);
 			break;
 		case gbt_t_oid:
diff --git a/contrib/btree_gist/expected/bool.out b/contrib/btree_gist/expected/bool.out
new file mode 100644
index 0000000000..eda7f1f6be
--- /dev/null
+++ b/contrib/btree_gist/expected/bool.out
@@ -0,0 +1,66 @@
+-- bool check
+CREATE TABLE booltmp (a bool);
+INSERT INTO booltmp VALUES (false), (true);
+SET enable_seqscan=on;
+SELECT count(*) FROM booltmp WHERE a <  true;
+ count 
+-------
+     1
+(1 row)
+
+SELECT count(*) FROM booltmp WHERE a <= true;
+ count 
+-------
+     2
+(1 row)
+
+SELECT count(*) FROM booltmp WHERE a  = true;
+ count 
+-------
+     1
+(1 row)
+
+SELECT count(*) FROM booltmp WHERE a >= true;
+ count 
+-------
+     1
+(1 row)
+
+SELECT count(*) FROM booltmp WHERE a >  true;
+ count 
+-------
+     0
+(1 row)
+
+CREATE INDEX boolidx ON booltmp USING gist ( a );
+SET enable_seqscan=off;
+SELECT count(*) FROM booltmp WHERE a <  true;
+ count 
+-------
+     1
+(1 row)
+
+SELECT count(*) FROM booltmp WHERE a <= true;
+ count 
+-------
+     2
+(1 row)
+
+SELECT count(*) FROM booltmp WHERE a  = true;
+ count 
+-------
+     1
+(1 row)
+
+SELECT count(*) FROM booltmp WHERE a >= true;
+ count 
+-------
+     1
+(1 row)
+
+SELECT count(*) FROM booltmp WHERE a >  true;
+ count 
+-------
+     0
+(1 row)
+
diff --git a/contrib/btree_gist/sql/bool.sql b/contrib/btree_gist/sql/bool.sql
new file mode 100644
index 0000000000..e0c2a40e2b
--- /dev/null
+++ b/contrib/btree_gist/sql/bool.sql
@@ -0,0 +1,31 @@
+-- bool check
+
+CREATE TABLE booltmp (a bool);
+
+INSERT INTO booltmp VALUES (false), (true);
+
+SET enable_seqscan=on;
+
+SELECT count(*) FROM booltmp WHERE a <  true;
+
+SELECT count(*) FROM booltmp WHERE a <= true;
+
+SELECT count(*) FROM booltmp WHERE a  = true;
+
+SELECT count(*) FROM booltmp WHERE a >= true;
+
+SELECT count(*) FROM booltmp WHERE a >  true;
+
+CREATE INDEX boolidx ON booltmp USING gist ( a );
+
+SET enable_seqscan=off;
+
+SELECT count(*) FROM booltmp WHERE a <  true;
+
+SELECT count(*) FROM booltmp WHERE a <= true;
+
+SELECT count(*) FROM booltmp WHERE a  = true;
+
+SELECT count(*) FROM booltmp WHERE a >= true;
+
+SELECT count(*) FROM booltmp WHERE a >  true;
-- 
2.30.1 (Apple Git-130)

#2Andrey Borodin
x4mmm@yandex-team.ru
In reply to: Emre Hasegeli (#1)
Re: GiST operator class for bool

Hi!

8 июня 2021 г., в 13:48, Emre Hasegeli <emre@hasegeli.com> написал(а):

It could be useful to use bool in exclusion constraints, but it's
currently not nicely supported. The attached patch adds support for
bool to the btree_gist extension, so we can do this.

I am adding this to the commitfest 2021-07.
<0001-btree_gist-Support-bool.patch>

It definitely makes sense to include bool into list of supported types.
But patch that you propose does not support sorting build added in PG14.
Or we can add this functionality later in https://commitfest.postgresql.org/31/2824/ ...

Thanks!

Best regards, Andrey Borodin.

#3Emre Hasegeli
emre@hasegeli.com
In reply to: Andrey Borodin (#2)
Re: GiST operator class for bool

But patch that you propose does not support sorting build added in PG14.

It looks like the change to btree_gist is not committed yet. I'll
rebase my patch once it's committed.

It was a long thread. I couldn't read all of it. Though, the last
patches felt to me like a part of what's already been committed.
Shouldn't they also be committed to version 14?

#4Andrey Borodin
x4mmm@yandex-team.ru
In reply to: Emre Hasegeli (#3)
Re: GiST operator class for bool

8 июня 2021 г., в 19:53, Emre Hasegeli <emre@hasegeli.com> написал(а):

But patch that you propose does not support sorting build added in PG14.

It looks like the change to btree_gist is not committed yet. I'll
rebase my patch once it's committed.

Changes to GiST are committed. There will be no need to rebase anyway :)

It was a long thread. I couldn't read all of it. Though, the last
patches felt to me like a part of what's already been committed.
Shouldn't they also be committed to version 14?

Well, yeah, it could would be cool to have gist build and gist_btree support it together, but there was many parts and we could did not finish it before feature freeze.

Best regards, Andrey Borodin.

#5Tomas Vondra
tomas.vondra@enterprisedb.com
In reply to: Andrey Borodin (#4)
Re: GiST operator class for bool

Hi,

I looked at this patch today - it's pretty simple and in pretty good
shape, I can't think of anything that'd need fixing. Perhaps the test
might also do EXPLAIN like for other types, to verify the new index is
actually used. But that's minor enough to handle during commit.

I've marked this as RFC and will get it committed in a day or two.

--
Tomas Vondra
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#6Tomas Vondra
tomas.vondra@enterprisedb.com
In reply to: Tomas Vondra (#5)
Re: GiST operator class for bool

On 11/3/21 16:18, Tomas Vondra wrote:

Hi,

I looked at this patch today - it's pretty simple and in pretty good
shape, I can't think of anything that'd need fixing. Perhaps the test
might also do EXPLAIN like for other types, to verify the new index is
actually used. But that's minor enough to handle during commit.

I've marked this as RFC and will get it committed in a day or two.

Pushed, after adding some simple EXPLAIN to the regression test.

Thanks for the patch!

regards

--
Tomas Vondra
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

#7Tom Lane
tgl@sss.pgh.pa.us
In reply to: Tomas Vondra (#6)
Re: GiST operator class for bool

Tomas Vondra <tomas.vondra@enterprisedb.com> writes:

Pushed, after adding some simple EXPLAIN to the regression test.

skink is reporting that this has some valgrind issues [1]https://buildfarm.postgresql.org/cgi-bin/show_log.pl?nm=skink&amp;dt=2021-11-06%2023%3A56%3A57.
I suspect sloppy conversion between bool and Datum, but
didn't go looking.

==1805451== VALGRINDERROR-BEGIN
==1805451== Uninitialised byte(s) found during client check request
==1805451== at 0x59EFEA: PageAddItemExtended (bufpage.c:346)
==1805451== by 0x2100B9: gistfillbuffer (gistutil.c:46)
==1805451== by 0x2050F9: gistplacetopage (gist.c:562)
==1805451== by 0x20546B: gistinserttuples (gist.c:1277)
==1805451== by 0x205BB5: gistinserttuple (gist.c:1230)
==1805451== by 0x206067: gistdoinsert (gist.c:885)
==1805451== by 0x2084FB: gistBuildCallback (gistbuild.c:829)
==1805451== by 0x23B572: heapam_index_build_range_scan (heapam_handler.c:1694)
==1805451== by 0x208E7D: table_index_build_scan (tableam.h:1756)
==1805451== by 0x208E7D: gistbuild (gistbuild.c:309)
==1805451== by 0x2D10C8: index_build (index.c:2983)
==1805451== by 0x2D2A7D: index_create (index.c:1232)
==1805451== by 0x383E67: DefineIndex (indexcmds.c:1128)
==1805451== Address 0x10cab1e4 is 12 bytes inside a block of size 16 client-defined
==1805451== at 0x712AC5: palloc0 (mcxt.c:1118)
==1805451== by 0x1E0A07: index_form_tuple (indextuple.c:146)
==1805451== by 0x210BA8: gistFormTuple (gistutil.c:582)
==1805451== by 0x2084C2: gistBuildCallback (gistbuild.c:813)
==1805451== by 0x23B572: heapam_index_build_range_scan (heapam_handler.c:1694)
==1805451== by 0x208E7D: table_index_build_scan (tableam.h:1756)
==1805451== by 0x208E7D: gistbuild (gistbuild.c:309)
==1805451== by 0x2D10C8: index_build (index.c:2983)
==1805451== by 0x2D2A7D: index_create (index.c:1232)
==1805451== by 0x383E67: DefineIndex (indexcmds.c:1128)
==1805451== by 0x5AED2E: ProcessUtilitySlow (utility.c:1535)
==1805451== by 0x5AE262: standard_ProcessUtility (utility.c:1066)
==1805451== by 0x5AE33A: ProcessUtility (utility.c:527)
==1805451==
==1805451== VALGRINDERROR-END

regards, tom lane

[1]: https://buildfarm.postgresql.org/cgi-bin/show_log.pl?nm=skink&amp;dt=2021-11-06%2023%3A56%3A57

#8Tomas Vondra
tomas.vondra@enterprisedb.com
In reply to: Tom Lane (#7)
1 attachment(s)
Re: GiST operator class for bool

Hi,

On 11/7/21 17:44, Tom Lane wrote:

Tomas Vondra <tomas.vondra@enterprisedb.com> writes:

Pushed, after adding some simple EXPLAIN to the regression test.

skink is reporting that this has some valgrind issues [1].
I suspect sloppy conversion between bool and Datum, but
didn't go looking.

It's actually a bit worse than that :-( The opclass is somewhat confused
about the type it should use for storage. The gbtree_ninfo struct says
it's using gbtreekey4, the SQL script claims the params are gbtreekey8,
and it should actually use gbtreekey2. Sorry for not noticing that.

The attached patch fixes the valgrind error for me.

regards

--
Tomas Vondra
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

Attachments:

btree_gist-bool-fix.patchtext/x-patch; charset=UTF-8; name=btree_gist-bool-fix.patchDownload
diff --git a/contrib/btree_gist/btree_bool.c b/contrib/btree_gist/btree_bool.c
index 25ce1e2b77..1be246ea5e 100644
--- a/contrib/btree_gist/btree_bool.c
+++ b/contrib/btree_gist/btree_bool.c
@@ -72,7 +72,7 @@ static const gbtree_ninfo tinfo =
 {
 	gbt_t_bool,
 	sizeof(bool),
-	4,							/* sizeof(gbtreekey4) */
+	2,							/* sizeof(gbtreekey2) */
 	gbt_boolgt,
 	gbt_boolge,
 	gbt_booleq,
diff --git a/contrib/btree_gist/btree_gist--1.6--1.7.sql b/contrib/btree_gist/btree_gist--1.6--1.7.sql
index 0e68356982..1085216501 100644
--- a/contrib/btree_gist/btree_gist--1.6--1.7.sql
+++ b/contrib/btree_gist/btree_gist--1.6--1.7.sql
@@ -4,6 +4,21 @@
 \echo Use "ALTER EXTENSION btree_gist UPDATE TO '1.7'" to load this file. \quit
 
 -- This upgrade scripts add support for bool.
+CREATE FUNCTION gbtreekey2_in(cstring)
+RETURNS gbtreekey2
+AS 'MODULE_PATHNAME', 'gbtreekey_in'
+LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
+
+CREATE FUNCTION gbtreekey2_out(gbtreekey2)
+RETURNS cstring
+AS 'MODULE_PATHNAME', 'gbtreekey_out'
+LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
+
+CREATE TYPE gbtreekey2 (
+	INTERNALLENGTH = 2,
+	INPUT  = gbtreekey2_in,
+	OUTPUT = gbtreekey2_out
+);
 
 -- Define the GiST support methods
 CREATE FUNCTION gbt_bool_consistent(internal,bool,int2,oid,internal)
@@ -32,11 +47,11 @@ AS 'MODULE_PATHNAME'
 LANGUAGE C IMMUTABLE STRICT;
 
 CREATE FUNCTION gbt_bool_union(internal, internal)
-RETURNS gbtreekey8
+RETURNS gbtreekey2
 AS 'MODULE_PATHNAME'
 LANGUAGE C IMMUTABLE STRICT;
 
-CREATE FUNCTION gbt_bool_same(gbtreekey8, gbtreekey8, internal)
+CREATE FUNCTION gbt_bool_same(gbtreekey2, gbtreekey2, internal)
 RETURNS internal
 AS 'MODULE_PATHNAME'
 LANGUAGE C IMMUTABLE STRICT;
@@ -57,6 +72,6 @@ AS
 	FUNCTION	4	gbt_decompress (internal),
 	FUNCTION	5	gbt_bool_penalty (internal, internal, internal),
 	FUNCTION	6	gbt_bool_picksplit (internal, internal),
-	FUNCTION	7	gbt_bool_same (gbtreekey8, gbtreekey8, internal),
+	FUNCTION	7	gbt_bool_same (gbtreekey2, gbtreekey2, internal),
 	FUNCTION	9   gbt_bool_fetch (internal),
-	STORAGE		gbtreekey8;
+	STORAGE		gbtreekey2;
#9Tomas Vondra
tomas.vondra@enterprisedb.com
In reply to: Tomas Vondra (#8)
1 attachment(s)
Re: GiST operator class for bool

On 11/7/21 20:53, Tomas Vondra wrote:

Hi,

On 11/7/21 17:44, Tom Lane wrote:

Tomas Vondra <tomas.vondra@enterprisedb.com> writes:

Pushed, after adding some simple EXPLAIN to the regression test.

skink is reporting that this has some valgrind issues [1].
I suspect sloppy conversion between bool and Datum, but
didn't go looking.

It's actually a bit worse than that :-( The opclass is somewhat confused
about the type it should use for storage. The gbtree_ninfo struct says
it's using gbtreekey4, the SQL script claims the params are gbtreekey8,
and it should actually use gbtreekey2. Sorry for not noticing that.

The attached patch fixes the valgrind error for me.

I've pushed the fix, hopefully that'll make skink happy.

What surprised me a bit is that the opclass used gbtreekey4 storage, the
equality support proc was defined as using gbtreekey8

FUNCTION 7 gbt_bool_same (gbtreekey8, gbtreekey8, internal),

yet the gistvalidate() did not report this. Turns out this is because

ok = check_amproc_signature(procform->amproc, INTERNALOID, false,
3, 3, opckeytype, opckeytype,
INTERNALOID);

i.e. with exact=false, so these type differences are ignored. Changing
it to true reports the issue (and no other issues in check-world).

But maybe there are reasons to keep using false?

regards

--
Tomas Vondra
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

Attachments:

gistvalidate.patchtext/x-patch; charset=UTF-8; name=gistvalidate.patchDownload
diff --git a/src/backend/access/gist/gistvalidate.c b/src/backend/access/gist/gistvalidate.c
index b885fa2b25..31cc4f0a21 100644
--- a/src/backend/access/gist/gistvalidate.c
+++ b/src/backend/access/gist/gistvalidate.c
@@ -131,7 +131,7 @@ gistvalidate(Oid opclassoid)
 											2, 2, INTERNALOID, INTERNALOID);
 				break;
 			case GIST_EQUAL_PROC:
-				ok = check_amproc_signature(procform->amproc, INTERNALOID, false,
+				ok = check_amproc_signature(procform->amproc, INTERNALOID, true,
 											3, 3, opckeytype, opckeytype,
 											INTERNALOID);
 				break;
#10Pavel Luzanov
p.luzanov@postgrespro.ru
In reply to: Tomas Vondra (#9)
Re: GiST operator class for bool

Hello,

I don't see any changes in the documentation.[1]https://www.postgresql.org/docs/devel/btree-gist.html

Should bool appear in the looong list of supported operator classes?

[1]: https://www.postgresql.org/docs/devel/btree-gist.html

--
Pavel Luzanov
Postgres Professional: https://postgrespro.com
The Russian Postgres Company

#11Tomas Vondra
tomas.vondra@enterprisedb.com
In reply to: Pavel Luzanov (#10)
Re: GiST operator class for bool

On 12/6/21 22:35, Pavel Luzanov wrote:

Hello,

I don't see any changes in the documentation.[1]

Should bool appear in the looong list of supported operator classes?

You're right, I forgot to update the list of data types in the docs.
Fixed, thanks for the report.

regards

--
Tomas Vondra
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company