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 "utils/builtins.h"
9 : #include "utils/formatting.h"
10 : #include "utils/varlena.h"
11 : #include "varatt.h"
12 :
13 GIC 2 : PG_MODULE_MAGIC;
14 ECB :
15 : /*
16 : * ====================
17 : * FORWARD DECLARATIONS
18 : * ====================
19 : */
20 :
21 : static int32 citextcmp(text *left, text *right, Oid collid);
22 : static int32 internal_citext_pattern_cmp(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 : */
35 : static int32
36 GIC 159 : citextcmp(text *left, text *right, Oid collid)
37 ECB : {
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 GIC 159 : lcstr = str_tolower(VARDATA_ANY(left), VARSIZE_ANY_EXHDR(left), DEFAULT_COLLATION_OID);
51 CBC 159 : rcstr = str_tolower(VARDATA_ANY(right), VARSIZE_ANY_EXHDR(right), DEFAULT_COLLATION_OID);
52 ECB :
53 GIC 159 : result = varstr_cmp(lcstr, strlen(lcstr),
54 CBC 159 : rcstr, strlen(rcstr),
55 ECB : collid);
56 :
57 GIC 159 : pfree(lcstr);
58 CBC 159 : pfree(rcstr);
59 ECB :
60 GIC 159 : return result;
61 ECB : }
62 :
63 : /*
64 : * citext_pattern_cmp()
65 : * Internal character-by-character comparison function for citext strings.
66 : * Returns int32 negative, zero, or positive.
67 : */
68 : static int32
69 GIC 51 : internal_citext_pattern_cmp(text *left, text *right, Oid collid)
70 ECB : {
71 : char *lcstr,
72 : *rcstr;
73 : int llen,
74 : rlen;
75 : int32 result;
76 :
77 GIC 51 : lcstr = str_tolower(VARDATA_ANY(left), VARSIZE_ANY_EXHDR(left), DEFAULT_COLLATION_OID);
78 CBC 51 : rcstr = str_tolower(VARDATA_ANY(right), VARSIZE_ANY_EXHDR(right), DEFAULT_COLLATION_OID);
79 ECB :
80 GIC 51 : llen = strlen(lcstr);
81 CBC 51 : rlen = strlen(rcstr);
82 ECB :
83 GNC 51 : result = memcmp(lcstr, rcstr, Min(llen, rlen));
84 CBC 51 : if (result == 0)
85 ECB : {
86 GIC 16 : if (llen < rlen)
87 CBC 1 : result = -1;
88 15 : else if (llen > rlen)
89 1 : result = 1;
90 ECB : }
91 :
92 GIC 51 : pfree(lcstr);
93 CBC 51 : pfree(rcstr);
94 ECB :
95 GIC 51 : return result;
96 ECB : }
97 :
98 : /*
99 : * ==================
100 : * INDEXING FUNCTIONS
101 : * ==================
102 : */
103 :
104 GIC 4 : PG_FUNCTION_INFO_V1(citext_cmp);
105 ECB :
106 : Datum
107 GIC 140 : citext_cmp(PG_FUNCTION_ARGS)
108 ECB : {
109 GIC 140 : text *left = PG_GETARG_TEXT_PP(0);
110 CBC 140 : text *right = PG_GETARG_TEXT_PP(1);
111 ECB : int32 result;
112 :
113 GIC 140 : result = citextcmp(left, right, PG_GET_COLLATION());
114 ECB :
115 GIC 140 : PG_FREE_IF_COPY(left, 0);
116 CBC 140 : PG_FREE_IF_COPY(right, 1);
117 ECB :
118 GIC 140 : PG_RETURN_INT32(result);
119 ECB : }
120 :
121 GIC 4 : PG_FUNCTION_INFO_V1(citext_pattern_cmp);
122 ECB :
123 : Datum
124 GIC 11 : citext_pattern_cmp(PG_FUNCTION_ARGS)
125 ECB : {
126 GIC 11 : text *left = PG_GETARG_TEXT_PP(0);
127 CBC 11 : text *right = PG_GETARG_TEXT_PP(1);
128 ECB : int32 result;
129 :
130 GIC 11 : result = internal_citext_pattern_cmp(left, right, PG_GET_COLLATION());
131 ECB :
132 GIC 11 : PG_FREE_IF_COPY(left, 0);
133 CBC 11 : PG_FREE_IF_COPY(right, 1);
134 ECB :
135 GIC 11 : PG_RETURN_INT32(result);
136 ECB : }
137 :
138 GIC 3 : PG_FUNCTION_INFO_V1(citext_hash);
139 ECB :
140 : Datum
141 GIC 10 : citext_hash(PG_FUNCTION_ARGS)
142 ECB : {
143 GIC 10 : text *txt = PG_GETARG_TEXT_PP(0);
144 ECB : char *str;
145 : Datum result;
146 :
147 GIC 10 : str = str_tolower(VARDATA_ANY(txt), VARSIZE_ANY_EXHDR(txt), DEFAULT_COLLATION_OID);
148 CBC 10 : result = hash_any((unsigned char *) str, strlen(str));
149 10 : pfree(str);
150 ECB :
151 : /* Avoid leaking memory for toasted inputs */
152 GIC 10 : PG_FREE_IF_COPY(txt, 0);
153 ECB :
154 GIC 10 : PG_RETURN_DATUM(result);
155 ECB : }
156 :
157 GIC 3 : PG_FUNCTION_INFO_V1(citext_hash_extended);
158 ECB :
159 : Datum
160 GIC 10 : citext_hash_extended(PG_FUNCTION_ARGS)
161 ECB : {
162 GIC 10 : text *txt = PG_GETARG_TEXT_PP(0);
163 CBC 10 : uint64 seed = PG_GETARG_INT64(1);
164 ECB : char *str;
165 : Datum result;
166 :
167 GIC 10 : str = str_tolower(VARDATA_ANY(txt), VARSIZE_ANY_EXHDR(txt), DEFAULT_COLLATION_OID);
168 CBC 10 : result = hash_any_extended((unsigned char *) str, strlen(str), seed);
169 10 : pfree(str);
170 ECB :
171 : /* Avoid leaking memory for toasted inputs */
172 GIC 10 : PG_FREE_IF_COPY(txt, 0);
173 ECB :
174 GIC 10 : PG_RETURN_DATUM(result);
175 ECB : }
176 :
177 : /*
178 : * ==================
179 : * OPERATOR FUNCTIONS
180 : * ==================
181 : */
182 :
183 GIC 4 : PG_FUNCTION_INFO_V1(citext_eq);
184 ECB :
185 : Datum
186 GIC 80 : citext_eq(PG_FUNCTION_ARGS)
187 ECB : {
188 GIC 80 : text *left = PG_GETARG_TEXT_PP(0);
189 CBC 80 : text *right = PG_GETARG_TEXT_PP(1);
190 ECB : char *lcstr,
191 : *rcstr;
192 : bool result;
193 :
194 : /* We can't compare lengths in advance of downcasing ... */
195 :
196 GIC 80 : lcstr = str_tolower(VARDATA_ANY(left), VARSIZE_ANY_EXHDR(left), DEFAULT_COLLATION_OID);
197 CBC 80 : rcstr = str_tolower(VARDATA_ANY(right), VARSIZE_ANY_EXHDR(right), DEFAULT_COLLATION_OID);
198 ECB :
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 GIC 80 : result = (strcmp(lcstr, rcstr) == 0);
204 ECB :
205 GIC 80 : pfree(lcstr);
206 CBC 80 : pfree(rcstr);
207 80 : PG_FREE_IF_COPY(left, 0);
208 80 : PG_FREE_IF_COPY(right, 1);
209 ECB :
210 GIC 80 : PG_RETURN_BOOL(result);
211 ECB : }
212 :
213 GIC 3 : PG_FUNCTION_INFO_V1(citext_ne);
214 ECB :
215 : Datum
216 GIC 17 : citext_ne(PG_FUNCTION_ARGS)
217 ECB : {
218 GIC 17 : text *left = PG_GETARG_TEXT_PP(0);
219 CBC 17 : text *right = PG_GETARG_TEXT_PP(1);
220 ECB : char *lcstr,
221 : *rcstr;
222 : bool result;
223 :
224 : /* We can't compare lengths in advance of downcasing ... */
225 :
226 GIC 17 : lcstr = str_tolower(VARDATA_ANY(left), VARSIZE_ANY_EXHDR(left), DEFAULT_COLLATION_OID);
227 CBC 17 : rcstr = str_tolower(VARDATA_ANY(right), VARSIZE_ANY_EXHDR(right), DEFAULT_COLLATION_OID);
228 ECB :
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 GIC 17 : result = (strcmp(lcstr, rcstr) != 0);
234 ECB :
235 GIC 17 : pfree(lcstr);
236 CBC 17 : pfree(rcstr);
237 17 : PG_FREE_IF_COPY(left, 0);
238 17 : PG_FREE_IF_COPY(right, 1);
239 ECB :
240 GIC 17 : PG_RETURN_BOOL(result);
241 ECB : }
242 :
243 GIC 3 : PG_FUNCTION_INFO_V1(citext_lt);
244 ECB :
245 : Datum
246 GIC 1 : citext_lt(PG_FUNCTION_ARGS)
247 ECB : {
248 GIC 1 : text *left = PG_GETARG_TEXT_PP(0);
249 CBC 1 : text *right = PG_GETARG_TEXT_PP(1);
250 ECB : bool result;
251 :
252 GIC 1 : result = citextcmp(left, right, PG_GET_COLLATION()) < 0;
253 ECB :
254 GIC 1 : PG_FREE_IF_COPY(left, 0);
255 CBC 1 : PG_FREE_IF_COPY(right, 1);
256 ECB :
257 GIC 1 : PG_RETURN_BOOL(result);
258 ECB : }
259 :
260 GIC 3 : PG_FUNCTION_INFO_V1(citext_le);
261 ECB :
262 : Datum
263 GIC 1 : citext_le(PG_FUNCTION_ARGS)
264 ECB : {
265 GIC 1 : text *left = PG_GETARG_TEXT_PP(0);
266 CBC 1 : text *right = PG_GETARG_TEXT_PP(1);
267 ECB : bool result;
268 :
269 GIC 1 : result = citextcmp(left, right, PG_GET_COLLATION()) <= 0;
270 ECB :
271 GIC 1 : PG_FREE_IF_COPY(left, 0);
272 CBC 1 : PG_FREE_IF_COPY(right, 1);
273 ECB :
274 GIC 1 : PG_RETURN_BOOL(result);
275 ECB : }
276 :
277 GIC 3 : PG_FUNCTION_INFO_V1(citext_gt);
278 ECB :
279 : Datum
280 GIC 3 : citext_gt(PG_FUNCTION_ARGS)
281 ECB : {
282 GIC 3 : text *left = PG_GETARG_TEXT_PP(0);
283 CBC 3 : text *right = PG_GETARG_TEXT_PP(1);
284 ECB : bool result;
285 :
286 GIC 3 : result = citextcmp(left, right, PG_GET_COLLATION()) > 0;
287 ECB :
288 GIC 3 : PG_FREE_IF_COPY(left, 0);
289 CBC 3 : PG_FREE_IF_COPY(right, 1);
290 ECB :
291 GIC 3 : PG_RETURN_BOOL(result);
292 ECB : }
293 :
294 GIC 3 : PG_FUNCTION_INFO_V1(citext_ge);
295 ECB :
296 : Datum
297 GIC 1 : citext_ge(PG_FUNCTION_ARGS)
298 ECB : {
299 GIC 1 : text *left = PG_GETARG_TEXT_PP(0);
300 CBC 1 : text *right = PG_GETARG_TEXT_PP(1);
301 ECB : bool result;
302 :
303 GIC 1 : result = citextcmp(left, right, PG_GET_COLLATION()) >= 0;
304 ECB :
305 GIC 1 : PG_FREE_IF_COPY(left, 0);
306 CBC 1 : PG_FREE_IF_COPY(right, 1);
307 ECB :
308 GIC 1 : PG_RETURN_BOOL(result);
309 ECB : }
310 :
311 GIC 3 : PG_FUNCTION_INFO_V1(citext_pattern_lt);
312 ECB :
313 : Datum
314 GIC 8 : citext_pattern_lt(PG_FUNCTION_ARGS)
315 ECB : {
316 GIC 8 : text *left = PG_GETARG_TEXT_PP(0);
317 CBC 8 : text *right = PG_GETARG_TEXT_PP(1);
318 ECB : bool result;
319 :
320 GIC 8 : result = internal_citext_pattern_cmp(left, right, PG_GET_COLLATION()) < 0;
321 ECB :
322 GIC 8 : PG_FREE_IF_COPY(left, 0);
323 CBC 8 : PG_FREE_IF_COPY(right, 1);
324 ECB :
325 GIC 8 : PG_RETURN_BOOL(result);
326 ECB : }
327 :
328 GIC 3 : PG_FUNCTION_INFO_V1(citext_pattern_le);
329 ECB :
330 : Datum
331 GIC 12 : citext_pattern_le(PG_FUNCTION_ARGS)
332 ECB : {
333 GIC 12 : text *left = PG_GETARG_TEXT_PP(0);
334 CBC 12 : text *right = PG_GETARG_TEXT_PP(1);
335 ECB : bool result;
336 :
337 GIC 12 : result = internal_citext_pattern_cmp(left, right, PG_GET_COLLATION()) <= 0;
338 ECB :
339 GIC 12 : PG_FREE_IF_COPY(left, 0);
340 CBC 12 : PG_FREE_IF_COPY(right, 1);
341 ECB :
342 GIC 12 : PG_RETURN_BOOL(result);
343 ECB : }
344 :
345 GIC 3 : PG_FUNCTION_INFO_V1(citext_pattern_gt);
346 ECB :
347 : Datum
348 GIC 9 : citext_pattern_gt(PG_FUNCTION_ARGS)
349 ECB : {
350 GIC 9 : text *left = PG_GETARG_TEXT_PP(0);
351 CBC 9 : text *right = PG_GETARG_TEXT_PP(1);
352 ECB : bool result;
353 :
354 GIC 9 : result = internal_citext_pattern_cmp(left, right, PG_GET_COLLATION()) > 0;
355 ECB :
356 GIC 9 : PG_FREE_IF_COPY(left, 0);
357 CBC 9 : PG_FREE_IF_COPY(right, 1);
358 ECB :
359 GIC 9 : PG_RETURN_BOOL(result);
360 ECB : }
361 :
362 GIC 3 : PG_FUNCTION_INFO_V1(citext_pattern_ge);
363 ECB :
364 : Datum
365 GIC 11 : citext_pattern_ge(PG_FUNCTION_ARGS)
366 ECB : {
367 GIC 11 : text *left = PG_GETARG_TEXT_PP(0);
368 CBC 11 : text *right = PG_GETARG_TEXT_PP(1);
369 ECB : bool result;
370 :
371 GIC 11 : result = internal_citext_pattern_cmp(left, right, PG_GET_COLLATION()) >= 0;
372 ECB :
373 GIC 11 : PG_FREE_IF_COPY(left, 0);
374 CBC 11 : PG_FREE_IF_COPY(right, 1);
375 ECB :
376 GIC 11 : PG_RETURN_BOOL(result);
377 ECB : }
378 :
379 : /*
380 : * ===================
381 : * AGGREGATE FUNCTIONS
382 : * ===================
383 : */
384 :
385 GIC 3 : PG_FUNCTION_INFO_V1(citext_smaller);
386 ECB :
387 : Datum
388 GIC 7 : citext_smaller(PG_FUNCTION_ARGS)
389 ECB : {
390 GIC 7 : text *left = PG_GETARG_TEXT_PP(0);
391 CBC 7 : text *right = PG_GETARG_TEXT_PP(1);
392 ECB : text *result;
393 :
394 GIC 7 : result = citextcmp(left, right, PG_GET_COLLATION()) < 0 ? left : right;
395 CBC 7 : PG_RETURN_TEXT_P(result);
396 ECB : }
397 :
398 GIC 3 : PG_FUNCTION_INFO_V1(citext_larger);
399 ECB :
400 : Datum
401 GIC 6 : citext_larger(PG_FUNCTION_ARGS)
402 ECB : {
403 GIC 6 : text *left = PG_GETARG_TEXT_PP(0);
404 CBC 6 : text *right = PG_GETARG_TEXT_PP(1);
405 ECB : text *result;
406 :
407 GIC 6 : result = citextcmp(left, right, PG_GET_COLLATION()) > 0 ? left : right;
408 CBC 6 : PG_RETURN_TEXT_P(result);
409 ECB : }
|