Revert commit 66c0185a3 and follow-on patches.
[pgsql.git] / contrib / citext / citext.c
blob26af935a70f6f6ccaa5dfbf2fb6fbef478ee91c3
1 /*
2 * contrib/citext/citext.c
3 */
4 #include "postgres.h"
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"
13 PG_MODULE_MAGIC;
16 * ====================
17 * FORWARD DECLARATIONS
18 * ====================
21 static int32 citextcmp(text *left, text *right, Oid collid);
22 static int32 internal_citext_pattern_cmp(text *left, text *right, Oid collid);
25 * =================
26 * UTILITY FUNCTIONS
27 * =================
31 * citextcmp()
32 * Internal comparison function for citext strings.
33 * Returns int32 negative, zero, or positive.
35 static int32
36 citextcmp(text *left, text *right, Oid collid)
38 char *lcstr,
39 *rcstr;
40 int32 result;
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.
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);
53 result = varstr_cmp(lcstr, strlen(lcstr),
54 rcstr, strlen(rcstr),
55 collid);
57 pfree(lcstr);
58 pfree(rcstr);
60 return result;
64 * citext_pattern_cmp()
65 * Internal character-by-character comparison function for citext strings.
66 * Returns int32 negative, zero, or positive.
68 static int32
69 internal_citext_pattern_cmp(text *left, text *right, Oid collid)
71 char *lcstr,
72 *rcstr;
73 int llen,
74 rlen;
75 int32 result;
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);
80 llen = strlen(lcstr);
81 rlen = strlen(rcstr);
83 result = memcmp(lcstr, rcstr, Min(llen, rlen));
84 if (result == 0)
86 if (llen < rlen)
87 result = -1;
88 else if (llen > rlen)
89 result = 1;
92 pfree(lcstr);
93 pfree(rcstr);
95 return result;
99 * ==================
100 * INDEXING FUNCTIONS
101 * ==================
104 PG_FUNCTION_INFO_V1(citext_cmp);
106 Datum
107 citext_cmp(PG_FUNCTION_ARGS)
109 text *left = PG_GETARG_TEXT_PP(0);
110 text *right = PG_GETARG_TEXT_PP(1);
111 int32 result;
113 result = citextcmp(left, right, PG_GET_COLLATION());
115 PG_FREE_IF_COPY(left, 0);
116 PG_FREE_IF_COPY(right, 1);
118 PG_RETURN_INT32(result);
121 PG_FUNCTION_INFO_V1(citext_pattern_cmp);
123 Datum
124 citext_pattern_cmp(PG_FUNCTION_ARGS)
126 text *left = PG_GETARG_TEXT_PP(0);
127 text *right = PG_GETARG_TEXT_PP(1);
128 int32 result;
130 result = internal_citext_pattern_cmp(left, right, PG_GET_COLLATION());
132 PG_FREE_IF_COPY(left, 0);
133 PG_FREE_IF_COPY(right, 1);
135 PG_RETURN_INT32(result);
138 PG_FUNCTION_INFO_V1(citext_hash);
140 Datum
141 citext_hash(PG_FUNCTION_ARGS)
143 text *txt = PG_GETARG_TEXT_PP(0);
144 char *str;
145 Datum result;
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);
151 /* Avoid leaking memory for toasted inputs */
152 PG_FREE_IF_COPY(txt, 0);
154 PG_RETURN_DATUM(result);
157 PG_FUNCTION_INFO_V1(citext_hash_extended);
159 Datum
160 citext_hash_extended(PG_FUNCTION_ARGS)
162 text *txt = PG_GETARG_TEXT_PP(0);
163 uint64 seed = PG_GETARG_INT64(1);
164 char *str;
165 Datum result;
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);
171 /* Avoid leaking memory for toasted inputs */
172 PG_FREE_IF_COPY(txt, 0);
174 PG_RETURN_DATUM(result);
178 * ==================
179 * OPERATOR FUNCTIONS
180 * ==================
183 PG_FUNCTION_INFO_V1(citext_eq);
185 Datum
186 citext_eq(PG_FUNCTION_ARGS)
188 text *left = PG_GETARG_TEXT_PP(0);
189 text *right = PG_GETARG_TEXT_PP(1);
190 char *lcstr,
191 *rcstr;
192 bool result;
194 /* We can't compare lengths in advance of downcasing ... */
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);
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.
203 result = (strcmp(lcstr, rcstr) == 0);
205 pfree(lcstr);
206 pfree(rcstr);
207 PG_FREE_IF_COPY(left, 0);
208 PG_FREE_IF_COPY(right, 1);
210 PG_RETURN_BOOL(result);
213 PG_FUNCTION_INFO_V1(citext_ne);
215 Datum
216 citext_ne(PG_FUNCTION_ARGS)
218 text *left = PG_GETARG_TEXT_PP(0);
219 text *right = PG_GETARG_TEXT_PP(1);
220 char *lcstr,
221 *rcstr;
222 bool result;
224 /* We can't compare lengths in advance of downcasing ... */
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);
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.
233 result = (strcmp(lcstr, rcstr) != 0);
235 pfree(lcstr);
236 pfree(rcstr);
237 PG_FREE_IF_COPY(left, 0);
238 PG_FREE_IF_COPY(right, 1);
240 PG_RETURN_BOOL(result);
243 PG_FUNCTION_INFO_V1(citext_lt);
245 Datum
246 citext_lt(PG_FUNCTION_ARGS)
248 text *left = PG_GETARG_TEXT_PP(0);
249 text *right = PG_GETARG_TEXT_PP(1);
250 bool result;
252 result = citextcmp(left, right, PG_GET_COLLATION()) < 0;
254 PG_FREE_IF_COPY(left, 0);
255 PG_FREE_IF_COPY(right, 1);
257 PG_RETURN_BOOL(result);
260 PG_FUNCTION_INFO_V1(citext_le);
262 Datum
263 citext_le(PG_FUNCTION_ARGS)
265 text *left = PG_GETARG_TEXT_PP(0);
266 text *right = PG_GETARG_TEXT_PP(1);
267 bool result;
269 result = citextcmp(left, right, PG_GET_COLLATION()) <= 0;
271 PG_FREE_IF_COPY(left, 0);
272 PG_FREE_IF_COPY(right, 1);
274 PG_RETURN_BOOL(result);
277 PG_FUNCTION_INFO_V1(citext_gt);
279 Datum
280 citext_gt(PG_FUNCTION_ARGS)
282 text *left = PG_GETARG_TEXT_PP(0);
283 text *right = PG_GETARG_TEXT_PP(1);
284 bool result;
286 result = citextcmp(left, right, PG_GET_COLLATION()) > 0;
288 PG_FREE_IF_COPY(left, 0);
289 PG_FREE_IF_COPY(right, 1);
291 PG_RETURN_BOOL(result);
294 PG_FUNCTION_INFO_V1(citext_ge);
296 Datum
297 citext_ge(PG_FUNCTION_ARGS)
299 text *left = PG_GETARG_TEXT_PP(0);
300 text *right = PG_GETARG_TEXT_PP(1);
301 bool result;
303 result = citextcmp(left, right, PG_GET_COLLATION()) >= 0;
305 PG_FREE_IF_COPY(left, 0);
306 PG_FREE_IF_COPY(right, 1);
308 PG_RETURN_BOOL(result);
311 PG_FUNCTION_INFO_V1(citext_pattern_lt);
313 Datum
314 citext_pattern_lt(PG_FUNCTION_ARGS)
316 text *left = PG_GETARG_TEXT_PP(0);
317 text *right = PG_GETARG_TEXT_PP(1);
318 bool result;
320 result = internal_citext_pattern_cmp(left, right, PG_GET_COLLATION()) < 0;
322 PG_FREE_IF_COPY(left, 0);
323 PG_FREE_IF_COPY(right, 1);
325 PG_RETURN_BOOL(result);
328 PG_FUNCTION_INFO_V1(citext_pattern_le);
330 Datum
331 citext_pattern_le(PG_FUNCTION_ARGS)
333 text *left = PG_GETARG_TEXT_PP(0);
334 text *right = PG_GETARG_TEXT_PP(1);
335 bool result;
337 result = internal_citext_pattern_cmp(left, right, PG_GET_COLLATION()) <= 0;
339 PG_FREE_IF_COPY(left, 0);
340 PG_FREE_IF_COPY(right, 1);
342 PG_RETURN_BOOL(result);
345 PG_FUNCTION_INFO_V1(citext_pattern_gt);
347 Datum
348 citext_pattern_gt(PG_FUNCTION_ARGS)
350 text *left = PG_GETARG_TEXT_PP(0);
351 text *right = PG_GETARG_TEXT_PP(1);
352 bool result;
354 result = internal_citext_pattern_cmp(left, right, PG_GET_COLLATION()) > 0;
356 PG_FREE_IF_COPY(left, 0);
357 PG_FREE_IF_COPY(right, 1);
359 PG_RETURN_BOOL(result);
362 PG_FUNCTION_INFO_V1(citext_pattern_ge);
364 Datum
365 citext_pattern_ge(PG_FUNCTION_ARGS)
367 text *left = PG_GETARG_TEXT_PP(0);
368 text *right = PG_GETARG_TEXT_PP(1);
369 bool result;
371 result = internal_citext_pattern_cmp(left, right, PG_GET_COLLATION()) >= 0;
373 PG_FREE_IF_COPY(left, 0);
374 PG_FREE_IF_COPY(right, 1);
376 PG_RETURN_BOOL(result);
380 * ===================
381 * AGGREGATE FUNCTIONS
382 * ===================
385 PG_FUNCTION_INFO_V1(citext_smaller);
387 Datum
388 citext_smaller(PG_FUNCTION_ARGS)
390 text *left = PG_GETARG_TEXT_PP(0);
391 text *right = PG_GETARG_TEXT_PP(1);
392 text *result;
394 result = citextcmp(left, right, PG_GET_COLLATION()) < 0 ? left : right;
395 PG_RETURN_TEXT_P(result);
398 PG_FUNCTION_INFO_V1(citext_larger);
400 Datum
401 citext_larger(PG_FUNCTION_ARGS)
403 text *left = PG_GETARG_TEXT_PP(0);
404 text *right = PG_GETARG_TEXT_PP(1);
405 text *result;
407 result = citextcmp(left, right, PG_GET_COLLATION()) > 0 ? left : right;
408 PG_RETURN_TEXT_P(result);