Skip to content

Commit ab9907f

Browse files
committed
Add a new, improved version of citext as a contrib module.
David E. Wheeler
1 parent 6fe8796 commit ab9907f

File tree

11 files changed

+2517
-3
lines changed

11 files changed

+2517
-3
lines changed

contrib/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# $PostgreSQL: pgsql/contrib/Makefile,v 1.83 2008/05/08 16:49:36 tgl Exp $
1+
# $PostgreSQL: pgsql/contrib/Makefile,v 1.84 2008/07/29 18:31:20 tgl Exp $
22

33
subdir = contrib
44
top_builddir = ..
@@ -8,6 +8,7 @@ WANTED_DIRS = \
88
adminpack \
99
btree_gist \
1010
chkpass \
11+
citext \
1112
cube \
1213
dblink \
1314
dict_int \

contrib/README

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ chkpass -
3636
An auto-encrypted password datatype
3737
by D'Arcy J.M. Cain <darcy@druid.net>
3838

39+
citext -
40+
A case-insensitive character string datatype
41+
by David E. Wheeler <david@kineticode.com>
42+
3943
cube -
4044
Multidimensional-cube datatype (GiST indexing example)
4145
by Gene Selkov, Jr. <selkovjr@mcs.anl.gov>

contrib/citext/Makefile

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# $PostgreSQL: pgsql/contrib/citext/Makefile,v 1.1 2008/07/29 18:31:20 tgl Exp $
2+
3+
MODULES = citext
4+
DATA_built = citext.sql
5+
DATA = uninstall_citext.sql
6+
REGRESS = citext
7+
8+
ifdef USE_PGXS
9+
PG_CONFIG = pg_config
10+
PGXS := $(shell $(PG_CONFIG) --pgxs)
11+
include $(PGXS)
12+
else
13+
subdir = contrib/citext
14+
top_builddir = ../..
15+
include $(top_builddir)/src/Makefile.global
16+
include $(top_srcdir)/contrib/contrib-global.mk
17+
endif

contrib/citext/citext.c

Lines changed: 268 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,268 @@
1+
/*
2+
* $PostgreSQL: pgsql/contrib/citext/citext.c,v 1.1 2008/07/29 18:31:20 tgl Exp $
3+
*/
4+
#include "postgres.h"
5+
6+
#include "access/hash.h"
7+
#include "fmgr.h"
8+
#include "utils/builtins.h"
9+
#include "utils/formatting.h"
10+
11+
#ifdef PG_MODULE_MAGIC
12+
PG_MODULE_MAGIC;
13+
#endif
14+
15+
/*
16+
* ====================
17+
* FORWARD DECLARATIONS
18+
* ====================
19+
*/
20+
21+
static int32 citextcmp (text *left, text *right);
22+
extern Datum citext_cmp (PG_FUNCTION_ARGS);
23+
extern Datum citext_hash (PG_FUNCTION_ARGS);
24+
extern Datum citext_eq (PG_FUNCTION_ARGS);
25+
extern Datum citext_ne (PG_FUNCTION_ARGS);
26+
extern Datum citext_gt (PG_FUNCTION_ARGS);
27+
extern Datum citext_ge (PG_FUNCTION_ARGS);
28+
extern Datum citext_lt (PG_FUNCTION_ARGS);
29+
extern Datum citext_le (PG_FUNCTION_ARGS);
30+
extern Datum citext_smaller (PG_FUNCTION_ARGS);
31+
extern Datum citext_larger (PG_FUNCTION_ARGS);
32+
33+
/*
34+
* =================
35+
* UTILITY FUNCTIONS
36+
* =================
37+
*/
38+
39+
/*
40+
* citextcmp()
41+
* Internal comparison function for citext strings.
42+
* Returns int32 negative, zero, or positive.
43+
*/
44+
static int32
45+
citextcmp (text *left, text *right)
46+
{
47+
char *lcstr, *rcstr;
48+
int32 result;
49+
50+
lcstr = str_tolower(VARDATA_ANY(left), VARSIZE_ANY_EXHDR(left));
51+
rcstr = str_tolower(VARDATA_ANY(right), VARSIZE_ANY_EXHDR(right));
52+
53+
result = varstr_cmp(lcstr, strlen(lcstr),
54+
rcstr, strlen(rcstr));
55+
56+
pfree(lcstr);
57+
pfree(rcstr);
58+
59+
return result;
60+
}
61+
62+
/*
63+
* ==================
64+
* INDEXING FUNCTIONS
65+
* ==================
66+
*/
67+
68+
PG_FUNCTION_INFO_V1(citext_cmp);
69+
70+
Datum
71+
citext_cmp(PG_FUNCTION_ARGS)
72+
{
73+
text *left = PG_GETARG_TEXT_PP(0);
74+
text *right = PG_GETARG_TEXT_PP(1);
75+
int32 result;
76+
77+
result = citextcmp(left, right);
78+
79+
PG_FREE_IF_COPY(left, 0);
80+
PG_FREE_IF_COPY(right, 1);
81+
82+
PG_RETURN_INT32(result);
83+
}
84+
85+
PG_FUNCTION_INFO_V1(citext_hash);
86+
87+
Datum
88+
citext_hash(PG_FUNCTION_ARGS)
89+
{
90+
text *txt = PG_GETARG_TEXT_PP(0);
91+
char *str;
92+
Datum result;
93+
94+
str = str_tolower(VARDATA_ANY(txt), VARSIZE_ANY_EXHDR(txt));
95+
result = hash_any((unsigned char *) str, strlen(str));
96+
pfree(str);
97+
98+
/* Avoid leaking memory for toasted inputs */
99+
PG_FREE_IF_COPY(txt, 0);
100+
101+
PG_RETURN_DATUM(result);
102+
}
103+
104+
/*
105+
* ==================
106+
* OPERATOR FUNCTIONS
107+
* ==================
108+
*/
109+
110+
PG_FUNCTION_INFO_V1(citext_eq);
111+
112+
Datum
113+
citext_eq(PG_FUNCTION_ARGS)
114+
{
115+
text *left = PG_GETARG_TEXT_PP(0);
116+
text *right = PG_GETARG_TEXT_PP(1);
117+
char *lcstr, *rcstr;
118+
bool result;
119+
120+
/* We can't compare lengths in advance of downcasing ... */
121+
122+
lcstr = str_tolower(VARDATA_ANY(left), VARSIZE_ANY_EXHDR(left));
123+
rcstr = str_tolower(VARDATA_ANY(right), VARSIZE_ANY_EXHDR(right));
124+
125+
/*
126+
* Since we only care about equality or not-equality, we can
127+
* avoid all the expense of strcoll() here, and just do bitwise
128+
* comparison.
129+
*/
130+
result = (strcmp(lcstr, rcstr) == 0);
131+
132+
pfree(lcstr);
133+
pfree(rcstr);
134+
PG_FREE_IF_COPY(left, 0);
135+
PG_FREE_IF_COPY(right, 1);
136+
137+
PG_RETURN_BOOL(result);
138+
}
139+
140+
PG_FUNCTION_INFO_V1(citext_ne);
141+
142+
Datum
143+
citext_ne(PG_FUNCTION_ARGS)
144+
{
145+
text *left = PG_GETARG_TEXT_PP(0);
146+
text *right = PG_GETARG_TEXT_PP(1);
147+
char *lcstr, *rcstr;
148+
bool result;
149+
150+
/* We can't compare lengths in advance of downcasing ... */
151+
152+
lcstr = str_tolower(VARDATA_ANY(left), VARSIZE_ANY_EXHDR(left));
153+
rcstr = str_tolower(VARDATA_ANY(right), VARSIZE_ANY_EXHDR(right));
154+
155+
/*
156+
* Since we only care about equality or not-equality, we can
157+
* avoid all the expense of strcoll() here, and just do bitwise
158+
* comparison.
159+
*/
160+
result = (strcmp(lcstr, rcstr) != 0);
161+
162+
pfree(lcstr);
163+
pfree(rcstr);
164+
PG_FREE_IF_COPY(left, 0);
165+
PG_FREE_IF_COPY(right, 1);
166+
167+
PG_RETURN_BOOL(result);
168+
}
169+
170+
PG_FUNCTION_INFO_V1(citext_lt);
171+
172+
Datum
173+
citext_lt(PG_FUNCTION_ARGS)
174+
{
175+
text *left = PG_GETARG_TEXT_PP(0);
176+
text *right = PG_GETARG_TEXT_PP(1);
177+
bool result;
178+
179+
result = citextcmp(left, right) < 0;
180+
181+
PG_FREE_IF_COPY(left, 0);
182+
PG_FREE_IF_COPY(right, 1);
183+
184+
PG_RETURN_BOOL(result);
185+
}
186+
187+
PG_FUNCTION_INFO_V1(citext_le);
188+
189+
Datum
190+
citext_le(PG_FUNCTION_ARGS)
191+
{
192+
text *left = PG_GETARG_TEXT_PP(0);
193+
text *right = PG_GETARG_TEXT_PP(1);
194+
bool result;
195+
196+
result = citextcmp(left, right) <= 0;
197+
198+
PG_FREE_IF_COPY(left, 0);
199+
PG_FREE_IF_COPY(right, 1);
200+
201+
PG_RETURN_BOOL(result);
202+
}
203+
204+
PG_FUNCTION_INFO_V1(citext_gt);
205+
206+
Datum
207+
citext_gt(PG_FUNCTION_ARGS)
208+
{
209+
text *left = PG_GETARG_TEXT_PP(0);
210+
text *right = PG_GETARG_TEXT_PP(1);
211+
bool result;
212+
213+
result = citextcmp(left, right) > 0;
214+
215+
PG_FREE_IF_COPY(left, 0);
216+
PG_FREE_IF_COPY(right, 1);
217+
218+
PG_RETURN_BOOL(result);
219+
}
220+
221+
PG_FUNCTION_INFO_V1(citext_ge);
222+
223+
Datum
224+
citext_ge(PG_FUNCTION_ARGS)
225+
{
226+
text *left = PG_GETARG_TEXT_PP(0);
227+
text *right = PG_GETARG_TEXT_PP(1);
228+
bool result;
229+
230+
result = citextcmp(left, right) >= 0;
231+
232+
PG_FREE_IF_COPY(left, 0);
233+
PG_FREE_IF_COPY(right, 1);
234+
235+
PG_RETURN_BOOL(result);
236+
}
237+
238+
/*
239+
* ===================
240+
* AGGREGATE FUNCTIONS
241+
* ===================
242+
*/
243+
244+
PG_FUNCTION_INFO_V1(citext_smaller);
245+
246+
Datum
247+
citext_smaller(PG_FUNCTION_ARGS)
248+
{
249+
text *left = PG_GETARG_TEXT_PP(0);
250+
text *right = PG_GETARG_TEXT_PP(1);
251+
text *result;
252+
253+
result = citextcmp(left, right) < 0 ? left : right;
254+
PG_RETURN_TEXT_P(result);
255+
}
256+
257+
PG_FUNCTION_INFO_V1(citext_larger);
258+
259+
Datum
260+
citext_larger(PG_FUNCTION_ARGS)
261+
{
262+
text *left = PG_GETARG_TEXT_PP(0);
263+
text *right = PG_GETARG_TEXT_PP(1);
264+
text *result;
265+
266+
result = citextcmp(left, right) > 0 ? left : right;
267+
PG_RETURN_TEXT_P(result);
268+
}

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