PostgreSQL Source Code git master
citext.c
Go to the documentation of this file.
1/*
2 * contrib/citext/citext.c
3 */
4#include "postgres.h"
5
7#include "common/hashfn.h"
8#include "fmgr.h"
9#include "utils/formatting.h"
10#include "utils/varlena.h"
11#include "varatt.h"
12
14
15/*
16 * ====================
17 * FORWARD DECLARATIONS
18 * ====================
19 */
20
21static int32 citextcmp(text *left, text *right, Oid collid);
23
24/*
25 * =================
26 * UTILITY FUNCTIONS
27 * =================
28 */
29
30/*
31 * citextcmp()
32 * Internal comparison function for citext strings.
33 * Returns int32 negative, zero, or positive.
34 */
35static int32
36citextcmp(text *left, text *right, Oid collid)
37{
38 char *lcstr,
39 *rcstr;
40 int32 result;
41
42 /*
43 * We must do our str_tolower calls with DEFAULT_COLLATION_OID, not the
44 * input collation as you might expect. This is so that the behavior of
45 * citext's equality and hashing functions is not collation-dependent. We
46 * should change this once the core infrastructure is able to cope with
47 * collation-dependent equality and hashing functions.
48 */
49
50 lcstr = str_tolower(VARDATA_ANY(left), VARSIZE_ANY_EXHDR(left), DEFAULT_COLLATION_OID);
51 rcstr = str_tolower(VARDATA_ANY(right), VARSIZE_ANY_EXHDR(right), DEFAULT_COLLATION_OID);
52
53 result = varstr_cmp(lcstr, strlen(lcstr),
54 rcstr, strlen(rcstr),
55 collid);
56
57 pfree(lcstr);
58 pfree(rcstr);
59
60 return result;
61}
62
63/*
64 * citext_pattern_cmp()
65 * Internal character-by-character comparison function for citext strings.
66 * Returns int32 negative, zero, or positive.
67 */
68static int32
70{
71 char *lcstr,
72 *rcstr;
73 int llen,
74 rlen;
75 int32 result;
76
77 lcstr = str_tolower(VARDATA_ANY(left), VARSIZE_ANY_EXHDR(left), DEFAULT_COLLATION_OID);
78 rcstr = str_tolower(VARDATA_ANY(right), VARSIZE_ANY_EXHDR(right), DEFAULT_COLLATION_OID);
79
80 llen = strlen(lcstr);
81 rlen = strlen(rcstr);
82
83 result = memcmp(lcstr, rcstr, Min(llen, rlen));
84 if (result == 0)
85 {
86 if (llen < rlen)
87 result = -1;
88 else if (llen > rlen)
89 result = 1;
90 }
91
92 pfree(lcstr);
93 pfree(rcstr);
94
95 return result;
96}
97
98/*
99 * ==================
100 * INDEXING FUNCTIONS
101 * ==================
102 */
103
105
106Datum
108{
109 text *left = PG_GETARG_TEXT_PP(0);
110 text *right = PG_GETARG_TEXT_PP(1);
111 int32 result;
112
113 result = citextcmp(left, right, PG_GET_COLLATION());
114
115 PG_FREE_IF_COPY(left, 0);
116 PG_FREE_IF_COPY(right, 1);
117
118 PG_RETURN_INT32(result);
119}
120
122
123Datum
125{
126 text *left = PG_GETARG_TEXT_PP(0);
127 text *right = PG_GETARG_TEXT_PP(1);
128 int32 result;
129
130 result = internal_citext_pattern_cmp(left, right, PG_GET_COLLATION());
131
132 PG_FREE_IF_COPY(left, 0);
133 PG_FREE_IF_COPY(right, 1);
134
135 PG_RETURN_INT32(result);
136}
137
139
140Datum
142{
143 text *txt = PG_GETARG_TEXT_PP(0);
144 char *str;
145 Datum result;
146
147 str = str_tolower(VARDATA_ANY(txt), VARSIZE_ANY_EXHDR(txt), DEFAULT_COLLATION_OID);
148 result = hash_any((unsigned char *) str, strlen(str));
149 pfree(str);
150
151 /* Avoid leaking memory for toasted inputs */
152 PG_FREE_IF_COPY(txt, 0);
153
154 PG_RETURN_DATUM(result);
155}
156
158
159Datum
161{
162 text *txt = PG_GETARG_TEXT_PP(0);
163 uint64 seed = PG_GETARG_INT64(1);
164 char *str;
165 Datum result;
166
167 str = str_tolower(VARDATA_ANY(txt), VARSIZE_ANY_EXHDR(txt), DEFAULT_COLLATION_OID);
168 result = hash_any_extended((unsigned char *) str, strlen(str), seed);
169 pfree(str);
170
171 /* Avoid leaking memory for toasted inputs */
172 PG_FREE_IF_COPY(txt, 0);
173
174 PG_RETURN_DATUM(result);
175}
176
177/*
178 * ==================
179 * OPERATOR FUNCTIONS
180 * ==================
181 */
182
184
185Datum
187{
188 text *left = PG_GETARG_TEXT_PP(0);
189 text *right = PG_GETARG_TEXT_PP(1);
190 char *lcstr,
191 *rcstr;
192 bool result;
193
194 /* We can't compare lengths in advance of downcasing ... */
195
196 lcstr = str_tolower(VARDATA_ANY(left), VARSIZE_ANY_EXHDR(left), DEFAULT_COLLATION_OID);
197 rcstr = str_tolower(VARDATA_ANY(right), VARSIZE_ANY_EXHDR(right), DEFAULT_COLLATION_OID);
198
199 /*
200 * Since we only care about equality or not-equality, we can avoid all the
201 * expense of strcoll() here, and just do bitwise comparison.
202 */
203 result = (strcmp(lcstr, rcstr) == 0);
204
205 pfree(lcstr);
206 pfree(rcstr);
207 PG_FREE_IF_COPY(left, 0);
208 PG_FREE_IF_COPY(right, 1);
209
210 PG_RETURN_BOOL(result);
211}
212
214
215Datum
217{
218 text *left = PG_GETARG_TEXT_PP(0);
219 text *right = PG_GETARG_TEXT_PP(1);
220 char *lcstr,
221 *rcstr;
222 bool result;
223
224 /* We can't compare lengths in advance of downcasing ... */
225
226 lcstr = str_tolower(VARDATA_ANY(left), VARSIZE_ANY_EXHDR(left), DEFAULT_COLLATION_OID);
227 rcstr = str_tolower(VARDATA_ANY(right), VARSIZE_ANY_EXHDR(right), DEFAULT_COLLATION_OID);
228
229 /*
230 * Since we only care about equality or not-equality, we can avoid all the
231 * expense of strcoll() here, and just do bitwise comparison.
232 */
233 result = (strcmp(lcstr, rcstr) != 0);
234
235 pfree(lcstr);
236 pfree(rcstr);
237 PG_FREE_IF_COPY(left, 0);
238 PG_FREE_IF_COPY(right, 1);
239
240 PG_RETURN_BOOL(result);
241}
242
244
245Datum
247{
248 text *left = PG_GETARG_TEXT_PP(0);
249 text *right = PG_GETARG_TEXT_PP(1);
250 bool result;
251
252 result = citextcmp(left, right, PG_GET_COLLATION()) < 0;
253
254 PG_FREE_IF_COPY(left, 0);
255 PG_FREE_IF_COPY(right, 1);
256
257 PG_RETURN_BOOL(result);
258}
259
261
262Datum
264{
265 text *left = PG_GETARG_TEXT_PP(0);
266 text *right = PG_GETARG_TEXT_PP(1);
267 bool result;
268
269 result = citextcmp(left, right, PG_GET_COLLATION()) <= 0;
270
271 PG_FREE_IF_COPY(left, 0);
272 PG_FREE_IF_COPY(right, 1);
273
274 PG_RETURN_BOOL(result);
275}
276
278
279Datum
281{
282 text *left = PG_GETARG_TEXT_PP(0);
283 text *right = PG_GETARG_TEXT_PP(1);
284 bool result;
285
286 result = citextcmp(left, right, PG_GET_COLLATION()) > 0;
287
288 PG_FREE_IF_COPY(left, 0);
289 PG_FREE_IF_COPY(right, 1);
290
291 PG_RETURN_BOOL(result);
292}
293
295
296Datum
298{
299 text *left = PG_GETARG_TEXT_PP(0);
300 text *right = PG_GETARG_TEXT_PP(1);
301 bool result;
302
303 result = citextcmp(left, right, PG_GET_COLLATION()) >= 0;
304
305 PG_FREE_IF_COPY(left, 0);
306 PG_FREE_IF_COPY(right, 1);
307
308 PG_RETURN_BOOL(result);
309}
310
312
313Datum
315{
316 text *left = PG_GETARG_TEXT_PP(0);
317 text *right = PG_GETARG_TEXT_PP(1);
318 bool result;
319
320 result = internal_citext_pattern_cmp(left, right, PG_GET_COLLATION()) < 0;
321
322 PG_FREE_IF_COPY(left, 0);
323 PG_FREE_IF_COPY(right, 1);
324
325 PG_RETURN_BOOL(result);
326}
327
329
330Datum
332{
333 text *left = PG_GETARG_TEXT_PP(0);
334 text *right = PG_GETARG_TEXT_PP(1);
335 bool result;
336
337 result = internal_citext_pattern_cmp(left, right, PG_GET_COLLATION()) <= 0;
338
339 PG_FREE_IF_COPY(left, 0);
340 PG_FREE_IF_COPY(right, 1);
341
342 PG_RETURN_BOOL(result);
343}
344
346
347Datum
349{
350 text *left = PG_GETARG_TEXT_PP(0);
351 text *right = PG_GETARG_TEXT_PP(1);
352 bool result;
353
354 result = internal_citext_pattern_cmp(left, right, PG_GET_COLLATION()) > 0;
355
356 PG_FREE_IF_COPY(left, 0);
357 PG_FREE_IF_COPY(right, 1);
358
359 PG_RETURN_BOOL(result);
360}
361
363
364Datum
366{
367 text *left = PG_GETARG_TEXT_PP(0);
368 text *right = PG_GETARG_TEXT_PP(1);
369 bool result;
370
371 result = internal_citext_pattern_cmp(left, right, PG_GET_COLLATION()) >= 0;
372
373 PG_FREE_IF_COPY(left, 0);
374 PG_FREE_IF_COPY(right, 1);
375
376 PG_RETURN_BOOL(result);
377}
378
379/*
380 * ===================
381 * AGGREGATE FUNCTIONS
382 * ===================
383 */
384
386
387Datum
389{
390 text *left = PG_GETARG_TEXT_PP(0);
391 text *right = PG_GETARG_TEXT_PP(1);
392 text *result;
393
394 result = citextcmp(left, right, PG_GET_COLLATION()) < 0 ? left : right;
395 PG_RETURN_TEXT_P(result);
396}
397
399
400Datum
402{
403 text *left = PG_GETARG_TEXT_PP(0);
404 text *right = PG_GETARG_TEXT_PP(1);
405 text *result;
406
407 result = citextcmp(left, right, PG_GET_COLLATION()) > 0 ? left : right;
408 PG_RETURN_TEXT_P(result);
409}
#define Min(x, y)
Definition: c.h:975
int32_t int32
Definition: c.h:498
uint64_t uint64
Definition: c.h:503
Datum citext_le(PG_FUNCTION_ARGS)
Definition: citext.c:263
Datum citext_pattern_cmp(PG_FUNCTION_ARGS)
Definition: citext.c:124
Datum citext_ne(PG_FUNCTION_ARGS)
Definition: citext.c:216
Datum citext_hash(PG_FUNCTION_ARGS)
Definition: citext.c:141
Datum citext_larger(PG_FUNCTION_ARGS)
Definition: citext.c:401
PG_MODULE_MAGIC
Definition: citext.c:13
Datum citext_lt(PG_FUNCTION_ARGS)
Definition: citext.c:246
Datum citext_pattern_gt(PG_FUNCTION_ARGS)
Definition: citext.c:348
Datum citext_gt(PG_FUNCTION_ARGS)
Definition: citext.c:280
Datum citext_smaller(PG_FUNCTION_ARGS)
Definition: citext.c:388
Datum citext_ge(PG_FUNCTION_ARGS)
Definition: citext.c:297
Datum citext_pattern_lt(PG_FUNCTION_ARGS)
Definition: citext.c:314
static int32 internal_citext_pattern_cmp(text *left, text *right, Oid collid)
Definition: citext.c:69
PG_FUNCTION_INFO_V1(citext_cmp)
Datum citext_pattern_ge(PG_FUNCTION_ARGS)
Definition: citext.c:365
Datum citext_pattern_le(PG_FUNCTION_ARGS)
Definition: citext.c:331
Datum citext_cmp(PG_FUNCTION_ARGS)
Definition: citext.c:107
Datum citext_eq(PG_FUNCTION_ARGS)
Definition: citext.c:186
Datum citext_hash_extended(PG_FUNCTION_ARGS)
Definition: citext.c:160
static int32 citextcmp(text *left, text *right, Oid collid)
Definition: citext.c:36
Oid collid
#define PG_FREE_IF_COPY(ptr, n)
Definition: fmgr.h:260
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:309
#define PG_GETARG_INT64(n)
Definition: fmgr.h:283
#define PG_RETURN_TEXT_P(x)
Definition: fmgr.h:372
#define PG_RETURN_INT32(x)
Definition: fmgr.h:354
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:353
#define PG_GET_COLLATION()
Definition: fmgr.h:198
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:359
char * str_tolower(const char *buff, size_t nbytes, Oid collid)
Definition: formatting.c:1637
static Datum hash_any_extended(const unsigned char *k, int keylen, uint64 seed)
Definition: hashfn.h:37
static Datum hash_any(const unsigned char *k, int keylen)
Definition: hashfn.h:31
const char * str
void pfree(void *pointer)
Definition: mcxt.c:1524
uintptr_t Datum
Definition: postgres.h:69
unsigned int Oid
Definition: postgres_ext.h:32
Definition: c.h:658
#define VARDATA_ANY(PTR)
Definition: varatt.h:324
#define VARSIZE_ANY_EXHDR(PTR)
Definition: varatt.h:317
int varstr_cmp(const char *arg1, int len1, const char *arg2, int len2, Oid collid)
Definition: varlena.c:1610