2 * contrib/citext/citext.c
6 #include "access/hash.h"
7 #include "catalog/pg_collation.h"
9 #include "utils/builtins.h"
10 #include "utils/formatting.h"
12 #ifdef PG_MODULE_MAGIC
17 * ====================
18 * FORWARD DECLARATIONS
19 * ====================
22 static int32 citextcmp(text *left, text *right, Oid collid);
23 extern Datum citext_cmp(PG_FUNCTION_ARGS);
24 extern Datum citext_hash(PG_FUNCTION_ARGS);
25 extern Datum citext_eq(PG_FUNCTION_ARGS);
26 extern Datum citext_ne(PG_FUNCTION_ARGS);
27 extern Datum citext_gt(PG_FUNCTION_ARGS);
28 extern Datum citext_ge(PG_FUNCTION_ARGS);
29 extern Datum citext_lt(PG_FUNCTION_ARGS);
30 extern Datum citext_le(PG_FUNCTION_ARGS);
31 extern Datum citext_smaller(PG_FUNCTION_ARGS);
32 extern Datum citext_larger(PG_FUNCTION_ARGS);
42 * Internal comparison function for citext strings.
43 * Returns int32 negative, zero, or positive.
46 citextcmp(text *left, text *right, Oid collid)
53 * We must do our str_tolower calls with DEFAULT_COLLATION_OID, not the
54 * input collation as you might expect. This is so that the behavior of
55 * citext's equality and hashing functions is not collation-dependent. We
56 * should change this once the core infrastructure is able to cope with
57 * collation-dependent equality and hashing functions.
60 lcstr = str_tolower(VARDATA_ANY(left), VARSIZE_ANY_EXHDR(left), DEFAULT_COLLATION_OID);
61 rcstr = str_tolower(VARDATA_ANY(right), VARSIZE_ANY_EXHDR(right), DEFAULT_COLLATION_OID);
63 result = varstr_cmp(lcstr, strlen(lcstr),
79 PG_FUNCTION_INFO_V1(citext_cmp);
82 citext_cmp(PG_FUNCTION_ARGS)
84 text *left = PG_GETARG_TEXT_PP(0);
85 text *right = PG_GETARG_TEXT_PP(1);
88 result = citextcmp(left, right, PG_GET_COLLATION());
90 PG_FREE_IF_COPY(left, 0);
91 PG_FREE_IF_COPY(right, 1);
93 PG_RETURN_INT32(result);
96 PG_FUNCTION_INFO_V1(citext_hash);
99 citext_hash(PG_FUNCTION_ARGS)
101 text *txt = PG_GETARG_TEXT_PP(0);
105 str = str_tolower(VARDATA_ANY(txt), VARSIZE_ANY_EXHDR(txt), DEFAULT_COLLATION_OID);
106 result = hash_any((unsigned char *) str, strlen(str));
109 /* Avoid leaking memory for toasted inputs */
110 PG_FREE_IF_COPY(txt, 0);
112 PG_RETURN_DATUM(result);
121 PG_FUNCTION_INFO_V1(citext_eq);
124 citext_eq(PG_FUNCTION_ARGS)
126 text *left = PG_GETARG_TEXT_PP(0);
127 text *right = PG_GETARG_TEXT_PP(1);
132 /* We can't compare lengths in advance of downcasing ... */
134 lcstr = str_tolower(VARDATA_ANY(left), VARSIZE_ANY_EXHDR(left), DEFAULT_COLLATION_OID);
135 rcstr = str_tolower(VARDATA_ANY(right), VARSIZE_ANY_EXHDR(right), DEFAULT_COLLATION_OID);
138 * Since we only care about equality or not-equality, we can avoid all the
139 * expense of strcoll() here, and just do bitwise comparison.
141 result = (strcmp(lcstr, rcstr) == 0);
145 PG_FREE_IF_COPY(left, 0);
146 PG_FREE_IF_COPY(right, 1);
148 PG_RETURN_BOOL(result);
151 PG_FUNCTION_INFO_V1(citext_ne);
154 citext_ne(PG_FUNCTION_ARGS)
156 text *left = PG_GETARG_TEXT_PP(0);
157 text *right = PG_GETARG_TEXT_PP(1);
162 /* We can't compare lengths in advance of downcasing ... */
164 lcstr = str_tolower(VARDATA_ANY(left), VARSIZE_ANY_EXHDR(left), DEFAULT_COLLATION_OID);
165 rcstr = str_tolower(VARDATA_ANY(right), VARSIZE_ANY_EXHDR(right), DEFAULT_COLLATION_OID);
168 * Since we only care about equality or not-equality, we can avoid all the
169 * expense of strcoll() here, and just do bitwise comparison.
171 result = (strcmp(lcstr, rcstr) != 0);
175 PG_FREE_IF_COPY(left, 0);
176 PG_FREE_IF_COPY(right, 1);
178 PG_RETURN_BOOL(result);
181 PG_FUNCTION_INFO_V1(citext_lt);
184 citext_lt(PG_FUNCTION_ARGS)
186 text *left = PG_GETARG_TEXT_PP(0);
187 text *right = PG_GETARG_TEXT_PP(1);
190 result = citextcmp(left, right, PG_GET_COLLATION()) < 0;
192 PG_FREE_IF_COPY(left, 0);
193 PG_FREE_IF_COPY(right, 1);
195 PG_RETURN_BOOL(result);
198 PG_FUNCTION_INFO_V1(citext_le);
201 citext_le(PG_FUNCTION_ARGS)
203 text *left = PG_GETARG_TEXT_PP(0);
204 text *right = PG_GETARG_TEXT_PP(1);
207 result = citextcmp(left, right, PG_GET_COLLATION()) <= 0;
209 PG_FREE_IF_COPY(left, 0);
210 PG_FREE_IF_COPY(right, 1);
212 PG_RETURN_BOOL(result);
215 PG_FUNCTION_INFO_V1(citext_gt);
218 citext_gt(PG_FUNCTION_ARGS)
220 text *left = PG_GETARG_TEXT_PP(0);
221 text *right = PG_GETARG_TEXT_PP(1);
224 result = citextcmp(left, right, PG_GET_COLLATION()) > 0;
226 PG_FREE_IF_COPY(left, 0);
227 PG_FREE_IF_COPY(right, 1);
229 PG_RETURN_BOOL(result);
232 PG_FUNCTION_INFO_V1(citext_ge);
235 citext_ge(PG_FUNCTION_ARGS)
237 text *left = PG_GETARG_TEXT_PP(0);
238 text *right = PG_GETARG_TEXT_PP(1);
241 result = citextcmp(left, right, PG_GET_COLLATION()) >= 0;
243 PG_FREE_IF_COPY(left, 0);
244 PG_FREE_IF_COPY(right, 1);
246 PG_RETURN_BOOL(result);
250 * ===================
251 * AGGREGATE FUNCTIONS
252 * ===================
255 PG_FUNCTION_INFO_V1(citext_smaller);
258 citext_smaller(PG_FUNCTION_ARGS)
260 text *left = PG_GETARG_TEXT_PP(0);
261 text *right = PG_GETARG_TEXT_PP(1);
264 result = citextcmp(left, right, PG_GET_COLLATION()) < 0 ? left : right;
265 PG_RETURN_TEXT_P(result);
268 PG_FUNCTION_INFO_V1(citext_larger);
271 citext_larger(PG_FUNCTION_ARGS)
273 text *left = PG_GETARG_TEXT_PP(0);
274 text *right = PG_GETARG_TEXT_PP(1);
277 result = citextcmp(left, right, PG_GET_COLLATION()) > 0 ? left : right;
278 PG_RETURN_TEXT_P(result);