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

Lines changed: 4 additions & 4 deletions
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

Lines changed: 65 additions & 0 deletions
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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 2 additions & 1 deletion
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

Lines changed: 238 additions & 0 deletions
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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy