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