2 * contrib/citext/citext.c
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"
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
);
32 * Internal comparison function for citext strings.
33 * Returns int32 negative, zero, or positive.
36 citextcmp(text
*left
, text
*right
, Oid collid
)
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
),
64 * citext_pattern_cmp()
65 * Internal character-by-character comparison function for citext strings.
66 * Returns int32 negative, zero, or positive.
69 internal_citext_pattern_cmp(text
*left
, text
*right
, Oid collid
)
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
);
83 result
= memcmp(lcstr
, rcstr
, Min(llen
, rlen
));
104 PG_FUNCTION_INFO_V1(citext_cmp
);
107 citext_cmp(PG_FUNCTION_ARGS
)
109 text
*left
= PG_GETARG_TEXT_PP(0);
110 text
*right
= PG_GETARG_TEXT_PP(1);
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
);
124 citext_pattern_cmp(PG_FUNCTION_ARGS
)
126 text
*left
= PG_GETARG_TEXT_PP(0);
127 text
*right
= PG_GETARG_TEXT_PP(1);
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
);
141 citext_hash(PG_FUNCTION_ARGS
)
143 text
*txt
= PG_GETARG_TEXT_PP(0);
147 str
= str_tolower(VARDATA_ANY(txt
), VARSIZE_ANY_EXHDR(txt
), DEFAULT_COLLATION_OID
);
148 result
= hash_any((unsigned char *) str
, strlen(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
);
160 citext_hash_extended(PG_FUNCTION_ARGS
)
162 text
*txt
= PG_GETARG_TEXT_PP(0);
163 uint64 seed
= PG_GETARG_INT64(1);
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
);
171 /* Avoid leaking memory for toasted inputs */
172 PG_FREE_IF_COPY(txt
, 0);
174 PG_RETURN_DATUM(result
);
183 PG_FUNCTION_INFO_V1(citext_eq
);
186 citext_eq(PG_FUNCTION_ARGS
)
188 text
*left
= PG_GETARG_TEXT_PP(0);
189 text
*right
= PG_GETARG_TEXT_PP(1);
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);
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
);
216 citext_ne(PG_FUNCTION_ARGS
)
218 text
*left
= PG_GETARG_TEXT_PP(0);
219 text
*right
= PG_GETARG_TEXT_PP(1);
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);
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
);
246 citext_lt(PG_FUNCTION_ARGS
)
248 text
*left
= PG_GETARG_TEXT_PP(0);
249 text
*right
= PG_GETARG_TEXT_PP(1);
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
);
263 citext_le(PG_FUNCTION_ARGS
)
265 text
*left
= PG_GETARG_TEXT_PP(0);
266 text
*right
= PG_GETARG_TEXT_PP(1);
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
);
280 citext_gt(PG_FUNCTION_ARGS
)
282 text
*left
= PG_GETARG_TEXT_PP(0);
283 text
*right
= PG_GETARG_TEXT_PP(1);
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
);
297 citext_ge(PG_FUNCTION_ARGS
)
299 text
*left
= PG_GETARG_TEXT_PP(0);
300 text
*right
= PG_GETARG_TEXT_PP(1);
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
);
314 citext_pattern_lt(PG_FUNCTION_ARGS
)
316 text
*left
= PG_GETARG_TEXT_PP(0);
317 text
*right
= PG_GETARG_TEXT_PP(1);
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
);
331 citext_pattern_le(PG_FUNCTION_ARGS
)
333 text
*left
= PG_GETARG_TEXT_PP(0);
334 text
*right
= PG_GETARG_TEXT_PP(1);
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
);
348 citext_pattern_gt(PG_FUNCTION_ARGS
)
350 text
*left
= PG_GETARG_TEXT_PP(0);
351 text
*right
= PG_GETARG_TEXT_PP(1);
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
);
365 citext_pattern_ge(PG_FUNCTION_ARGS
)
367 text
*left
= PG_GETARG_TEXT_PP(0);
368 text
*right
= PG_GETARG_TEXT_PP(1);
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
);
388 citext_smaller(PG_FUNCTION_ARGS
)
390 text
*left
= PG_GETARG_TEXT_PP(0);
391 text
*right
= PG_GETARG_TEXT_PP(1);
394 result
= citextcmp(left
, right
, PG_GET_COLLATION()) < 0 ? left
: right
;
395 PG_RETURN_TEXT_P(result
);
398 PG_FUNCTION_INFO_V1(citext_larger
);
401 citext_larger(PG_FUNCTION_ARGS
)
403 text
*left
= PG_GETARG_TEXT_PP(0);
404 text
*right
= PG_GETARG_TEXT_PP(1);
407 result
= citextcmp(left
, right
, PG_GET_COLLATION()) > 0 ? left
: right
;
408 PG_RETURN_TEXT_P(result
);