Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 11da83a

Browse files
committed
Add uuid to the set of types supported by contrib/btree_gist.
Paul Jungwirth, reviewed and hacked on by Teodor Sigaev, Ildus Kurbangaliev, Adam Brusselback, Chris Bandy, and myself. Discussion: https://postgr.es/m/CA+renyUEE29=X01JXdz8_TQvo6n9=2XoEBBRnQ8rkLyr+kjPxQ@mail.gmail.com Discussion: https://postgr.es/m/55F6EE82.8080209@sigaev.ru
1 parent 721f7bd commit 11da83a

File tree

11 files changed

+1120
-21
lines changed

11 files changed

+1120
-21
lines changed

contrib/btree_gist/Makefile

+4-4
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,16 @@ OBJS = btree_gist.o btree_utils_num.o btree_utils_var.o btree_int2.o \
66
btree_int4.o btree_int8.o btree_float4.o btree_float8.o btree_cash.o \
77
btree_oid.o btree_ts.o btree_time.o btree_date.o btree_interval.o \
88
btree_macaddr.o btree_inet.o btree_text.o btree_bytea.o btree_bit.o \
9-
btree_numeric.o $(WIN32RES)
9+
btree_numeric.o btree_uuid.o $(WIN32RES)
1010

1111
EXTENSION = btree_gist
12-
DATA = btree_gist--1.2.sql btree_gist--1.1--1.2.sql btree_gist--1.0--1.1.sql \
13-
btree_gist--unpackaged--1.0.sql
12+
DATA = btree_gist--unpackaged--1.0.sql btree_gist--1.0--1.1.sql \
13+
btree_gist--1.1--1.2.sql btree_gist--1.2.sql btree_gist--1.2--1.3.sql
1414
PGFILEDESC = "btree_gist - B-tree equivalent GiST operator classes"
1515

1616
REGRESS = init int2 int4 int8 float4 float8 cash oid timestamp timestamptz \
1717
time timetz date interval macaddr inet cidr text varchar char bytea \
18-
bit varbit numeric not_equal
18+
bit varbit numeric uuid not_equal
1919

2020
SHLIB_LINK += $(filter -lm, $(LIBS))
2121

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/* contrib/btree_gist/btree_gist--1.2--1.3.sql */
2+
3+
-- complain if script is sourced in psql, rather than via ALTER EXTENSION
4+
\echo Use "ALTER EXTENSION btree_gist UPDATE TO '1.3'" to load this file. \quit
5+
6+
-- Add support for indexing UUID columns
7+
8+
-- define the GiST support methods
9+
CREATE FUNCTION gbt_uuid_consistent(internal,uuid,int2,oid,internal)
10+
RETURNS bool
11+
AS 'MODULE_PATHNAME'
12+
LANGUAGE C IMMUTABLE STRICT;
13+
14+
CREATE FUNCTION gbt_uuid_fetch(internal)
15+
RETURNS internal
16+
AS 'MODULE_PATHNAME'
17+
LANGUAGE C IMMUTABLE STRICT;
18+
19+
CREATE FUNCTION gbt_uuid_compress(internal)
20+
RETURNS internal
21+
AS 'MODULE_PATHNAME'
22+
LANGUAGE C IMMUTABLE STRICT;
23+
24+
CREATE FUNCTION gbt_uuid_penalty(internal,internal,internal)
25+
RETURNS internal
26+
AS 'MODULE_PATHNAME'
27+
LANGUAGE C IMMUTABLE STRICT;
28+
29+
CREATE FUNCTION gbt_uuid_picksplit(internal, internal)
30+
RETURNS internal
31+
AS 'MODULE_PATHNAME'
32+
LANGUAGE C IMMUTABLE STRICT;
33+
34+
CREATE FUNCTION gbt_uuid_union(internal, internal)
35+
RETURNS gbtreekey32
36+
AS 'MODULE_PATHNAME'
37+
LANGUAGE C IMMUTABLE STRICT;
38+
39+
CREATE FUNCTION gbt_uuid_same(gbtreekey32, gbtreekey32, internal)
40+
RETURNS internal
41+
AS 'MODULE_PATHNAME'
42+
LANGUAGE C IMMUTABLE STRICT;
43+
44+
-- Create the operator class
45+
CREATE OPERATOR CLASS gist_uuid_ops
46+
DEFAULT FOR TYPE uuid USING gist
47+
AS
48+
OPERATOR 1 < ,
49+
OPERATOR 2 <= ,
50+
OPERATOR 3 = ,
51+
OPERATOR 4 >= ,
52+
OPERATOR 5 > ,
53+
FUNCTION 1 gbt_uuid_consistent (internal, uuid, int2, oid, internal),
54+
FUNCTION 2 gbt_uuid_union (internal, internal),
55+
FUNCTION 3 gbt_uuid_compress (internal),
56+
FUNCTION 4 gbt_decompress (internal),
57+
FUNCTION 5 gbt_uuid_penalty (internal, internal, internal),
58+
FUNCTION 6 gbt_uuid_picksplit (internal, internal),
59+
FUNCTION 7 gbt_uuid_same (gbtreekey32, gbtreekey32, internal),
60+
STORAGE gbtreekey32;
61+
62+
-- These are "loose" in the opfamily for consistency with the rest of btree_gist
63+
ALTER OPERATOR FAMILY gist_uuid_ops USING gist ADD
64+
OPERATOR 6 <> (uuid, uuid) ,
65+
FUNCTION 9 (uuid, uuid) gbt_uuid_fetch (internal) ;

contrib/btree_gist/btree_gist.control

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# btree_gist extension
22
comment = 'support for indexing common datatypes in GiST'
3-
default_version = '1.2'
3+
default_version = '1.3'
44
module_pathname = '$libdir/btree_gist'
55
relocatable = true

contrib/btree_gist/btree_gist.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ enum gbtree_type
3131
gbt_t_bpchar,
3232
gbt_t_bytea,
3333
gbt_t_bit,
34-
gbt_t_inet
34+
gbt_t_inet,
35+
gbt_t_uuid
3536
};
3637

3738
#endif

contrib/btree_gist/btree_uuid.c

+238
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
/*
2+
* contrib/btree_gist/btree_uuid.c
3+
*/
4+
#include "postgres.h"
5+
6+
#include "btree_gist.h"
7+
#include "btree_utils_num.h"
8+
#include "port/pg_bswap.h"
9+
#include "utils/uuid.h"
10+
11+
typedef struct
12+
{
13+
pg_uuid_t lower,
14+
upper;
15+
} uuidKEY;
16+
17+
18+
/*
19+
* UUID ops
20+
*/
21+
PG_FUNCTION_INFO_V1(gbt_uuid_compress);
22+
PG_FUNCTION_INFO_V1(gbt_uuid_fetch);
23+
PG_FUNCTION_INFO_V1(gbt_uuid_union);
24+
PG_FUNCTION_INFO_V1(gbt_uuid_picksplit);
25+
PG_FUNCTION_INFO_V1(gbt_uuid_consistent);
26+
PG_FUNCTION_INFO_V1(gbt_uuid_penalty);
27+
PG_FUNCTION_INFO_V1(gbt_uuid_same);
28+
29+
30+
static int
31+
uuid_internal_cmp(const pg_uuid_t *arg1, const pg_uuid_t *arg2)
32+
{
33+
return memcmp(arg1->data, arg2->data, UUID_LEN);
34+
}
35+
36+
static bool
37+
gbt_uuidgt(const void *a, const void *b)
38+
{
39+
return uuid_internal_cmp((const pg_uuid_t *) a, (const pg_uuid_t *) b) > 0;
40+
}
41+
42+
static bool
43+
gbt_uuidge(const void *a, const void *b)
44+
{
45+
return uuid_internal_cmp((const pg_uuid_t *) a, (const pg_uuid_t *) b) >= 0;
46+
}
47+
48+
static bool
49+
gbt_uuideq(const void *a, const void *b)
50+
{
51+
return uuid_internal_cmp((const pg_uuid_t *) a, (const pg_uuid_t *) b) == 0;
52+
}
53+
54+
static bool
55+
gbt_uuidle(const void *a, const void *b)
56+
{
57+
return uuid_internal_cmp((const pg_uuid_t *) a, (const pg_uuid_t *) b) <= 0;
58+
}
59+
60+
static bool
61+
gbt_uuidlt(const void *a, const void *b)
62+
{
63+
return uuid_internal_cmp((const pg_uuid_t *) a, (const pg_uuid_t *) b) < 0;
64+
}
65+
66+
static int
67+
gbt_uuidkey_cmp(const void *a, const void *b)
68+
{
69+
uuidKEY *ia = (uuidKEY *) (((const Nsrt *) a)->t);
70+
uuidKEY *ib = (uuidKEY *) (((const Nsrt *) b)->t);
71+
int res;
72+
73+
res = uuid_internal_cmp(&ia->lower, &ib->lower);
74+
if (res == 0)
75+
res = uuid_internal_cmp(&ia->upper, &ib->upper);
76+
return res;
77+
}
78+
79+
80+
static const gbtree_ninfo tinfo =
81+
{
82+
gbt_t_uuid,
83+
UUID_LEN,
84+
32, /* sizeof(gbtreekey32) */
85+
gbt_uuidgt,
86+
gbt_uuidge,
87+
gbt_uuideq,
88+
gbt_uuidle,
89+
gbt_uuidlt,
90+
gbt_uuidkey_cmp,
91+
NULL
92+
};
93+
94+
95+
/**************************************************
96+
* uuid ops
97+
**************************************************/
98+
99+
100+
Datum
101+
gbt_uuid_compress(PG_FUNCTION_ARGS)
102+
{
103+
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
104+
GISTENTRY *retval;
105+
106+
if (entry->leafkey)
107+
{
108+
char *r = (char *) palloc(2 * UUID_LEN);
109+
pg_uuid_t *key = DatumGetUUIDP(entry->key);
110+
111+
retval = palloc(sizeof(GISTENTRY));
112+
113+
memcpy((void *) r, (void *) key, UUID_LEN);
114+
memcpy((void *) (r + UUID_LEN), (void *) key, UUID_LEN);
115+
gistentryinit(*retval, PointerGetDatum(r),
116+
entry->rel, entry->page,
117+
entry->offset, FALSE);
118+
}
119+
else
120+
retval = entry;
121+
122+
PG_RETURN_POINTER(retval);
123+
}
124+
125+
Datum
126+
gbt_uuid_fetch(PG_FUNCTION_ARGS)
127+
{
128+
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
129+
130+
PG_RETURN_POINTER(gbt_num_fetch(entry, &tinfo));
131+
}
132+
133+
Datum
134+
gbt_uuid_consistent(PG_FUNCTION_ARGS)
135+
{
136+
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
137+
pg_uuid_t *query = PG_GETARG_UUID_P(1);
138+
StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
139+
140+
/* Oid subtype = PG_GETARG_OID(3); */
141+
bool *recheck = (bool *) PG_GETARG_POINTER(4);
142+
uuidKEY *kkk = (uuidKEY *) DatumGetPointer(entry->key);
143+
GBT_NUMKEY_R key;
144+
145+
/* All cases served by this function are exact */
146+
*recheck = false;
147+
148+
key.lower = (GBT_NUMKEY *) &kkk->lower;
149+
key.upper = (GBT_NUMKEY *) &kkk->upper;
150+
151+
PG_RETURN_BOOL(
152+
gbt_num_consistent(&key, (void *) query, &strategy,
153+
GIST_LEAF(entry), &tinfo)
154+
);
155+
}
156+
157+
Datum
158+
gbt_uuid_union(PG_FUNCTION_ARGS)
159+
{
160+
GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
161+
void *out = palloc(sizeof(uuidKEY));
162+
163+
*(int *) PG_GETARG_POINTER(1) = sizeof(uuidKEY);
164+
PG_RETURN_POINTER(gbt_num_union((void *) out, entryvec, &tinfo));
165+
}
166+
167+
/*
168+
* Convert a uuid to a "double" value for estimating sizes of ranges.
169+
*/
170+
static double
171+
uuid_2_double(const pg_uuid_t *u)
172+
{
173+
uint64 uu[2];
174+
const double two64 = 18446744073709551616.0; /* 2^64 */
175+
176+
/* Source data may not be suitably aligned, so copy */
177+
memcpy(uu, u->data, UUID_LEN);
178+
179+
/*
180+
* uuid values should be considered as big-endian numbers, since that
181+
* corresponds to how memcmp will compare them. On a little-endian
182+
* machine, byte-swap each half so we can use native uint64 arithmetic.
183+
*/
184+
#ifndef WORDS_BIGENDIAN
185+
uu[0] = BSWAP64(uu[0]);
186+
uu[1] = BSWAP64(uu[1]);
187+
#endif
188+
189+
/*
190+
* 2^128 is about 3.4e38, which in theory could exceed the range of
191+
* "double" (POSIX only requires 1e37). To avoid any risk of overflow,
192+
* put the decimal point between the two halves rather than treating the
193+
* uuid value as a 128-bit integer.
194+
*/
195+
return (double) uu[0] + (double) uu[1] / two64;
196+
}
197+
198+
Datum
199+
gbt_uuid_penalty(PG_FUNCTION_ARGS)
200+
{
201+
uuidKEY *origentry = (uuidKEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(0))->key);
202+
uuidKEY *newentry = (uuidKEY *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(1))->key);
203+
float *result = (float *) PG_GETARG_POINTER(2);
204+
double olower,
205+
oupper,
206+
nlower,
207+
nupper;
208+
209+
olower = uuid_2_double(&origentry->lower);
210+
oupper = uuid_2_double(&origentry->upper);
211+
nlower = uuid_2_double(&newentry->lower);
212+
nupper = uuid_2_double(&newentry->upper);
213+
214+
penalty_num(result, olower, oupper, nlower, nupper);
215+
216+
PG_RETURN_POINTER(result);
217+
}
218+
219+
Datum
220+
gbt_uuid_picksplit(PG_FUNCTION_ARGS)
221+
{
222+
PG_RETURN_POINTER(gbt_num_picksplit(
223+
(GistEntryVector *) PG_GETARG_POINTER(0),
224+
(GIST_SPLITVEC *) PG_GETARG_POINTER(1),
225+
&tinfo
226+
));
227+
}
228+
229+
Datum
230+
gbt_uuid_same(PG_FUNCTION_ARGS)
231+
{
232+
uuidKEY *b1 = (uuidKEY *) PG_GETARG_POINTER(0);
233+
uuidKEY *b2 = (uuidKEY *) PG_GETARG_POINTER(1);
234+
bool *result = (bool *) PG_GETARG_POINTER(2);
235+
236+
*result = gbt_num_same((void *) b1, (void *) b2, &tinfo);
237+
PG_RETURN_POINTER(result);
238+
}

0 commit comments

Comments
 (0)