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