-
Notifications
You must be signed in to change notification settings - Fork 4.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adds bool opclass to btree_gist extension, to allow creating GiST indexes on bool columns. GiST indexes on a single bool column don't seem particularly useful, but this allows defining exclusion constraings involving a bool column, for example. Author: Emre Hasegeli Reviewed-by: Andrey Borodin Discussion: https://postgr.es/m/CAE2gYzyDKJBZngssR84VGZEN=Ux=V9FV23QfPgo+7-yYnKKg4g@mail.gmail.com
- Loading branch information
Showing
8 changed files
with
382 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
-- 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) | ||
|
||
-- Test index-only scans | ||
SET enable_bitmapscan=off; | ||
EXPLAIN (COSTS OFF) | ||
SELECT * FROM booltmp WHERE a; | ||
QUERY PLAN | ||
------------------------------------------ | ||
Index Only Scan using boolidx on booltmp | ||
Filter: a | ||
(2 rows) | ||
|
||
SELECT * FROM booltmp WHERE a; | ||
a | ||
--- | ||
t | ||
(1 row) | ||
|
||
EXPLAIN (COSTS OFF) | ||
SELECT * FROM booltmp WHERE NOT a; | ||
QUERY PLAN | ||
------------------------------------------ | ||
Index Only Scan using boolidx on booltmp | ||
Filter: (NOT a) | ||
(2 rows) | ||
|
||
SELECT * FROM booltmp WHERE NOT a; | ||
a | ||
--- | ||
f | ||
(1 row) | ||
|
Oops, something went wrong.