PostgreSQL Source Code  git master
citext.c
Go to the documentation of this file.
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 
14 
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 citextcmp(text *left, text *right, Oid collid)
37 {
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  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);
52 
53  result = varstr_cmp(lcstr, strlen(lcstr),
54  rcstr, strlen(rcstr),
55  collid);
56 
57  pfree(lcstr);
58  pfree(rcstr);
59 
60  return result;
61 }
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
70 {
71  char *lcstr,
72  *rcstr;
73  int llen,
74  rlen;
75  int32 result;
76 
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);
79 
80  llen = strlen(lcstr);
81  rlen = strlen(rcstr);
82 
83  result = memcmp(lcstr, rcstr, Min(llen, rlen));
84  if (result == 0)
85  {
86  if (llen < rlen)
87  result = -1;
88  else if (llen > rlen)
89  result = 1;
90  }
91 
92  pfree(lcstr);
93  pfree(rcstr);
94 
95  return result;
96 }
97 
98 /*
99  * ==================
100  * INDEXING FUNCTIONS
101  * ==================
102  */
103 
105 
106 Datum
108 {
109  text *left = PG_GETARG_TEXT_PP(0);
110  text *right = PG_GETARG_TEXT_PP(1);
111  int32 result;
112 
113  result = citextcmp(left, right, PG_GET_COLLATION());
114 
115  PG_FREE_IF_COPY(left, 0);
116  PG_FREE_IF_COPY(right, 1);
117 
118  PG_RETURN_INT32(result);
119 }
120 
122 
123 Datum
125 {
126  text *left = PG_GETARG_TEXT_PP(0);
127  text *right = PG_GETARG_TEXT_PP(1);
128  int32 result;
129 
130  result = internal_citext_pattern_cmp(left, right, PG_GET_COLLATION());
131 
132  PG_FREE_IF_COPY(left, 0);
133  PG_FREE_IF_COPY(right, 1);
134 
135  PG_RETURN_INT32(result);
136 }
137 
139 
140 Datum
142 {
143  text *txt = PG_GETARG_TEXT_PP(0);
144  char *str;
145  Datum result;
146 
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);
150 
151  /* Avoid leaking memory for toasted inputs */
152  PG_FREE_IF_COPY(txt, 0);
153 
154  PG_RETURN_DATUM(result);
155 }
156 
158 
159 Datum
161 {
162  text *txt = PG_GETARG_TEXT_PP(0);
163  uint64 seed = PG_GETARG_INT64(1);
164  char *str;
165  Datum result;
166 
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);
170 
171  /* Avoid leaking memory for toasted inputs */
172  PG_FREE_IF_COPY(txt, 0);
173 
174  PG_RETURN_DATUM(result);
175 }
176 
177 /*
178  * ==================
179  * OPERATOR FUNCTIONS
180  * ==================
181  */
182 
184 
185 Datum
187 {
188  text *left = PG_GETARG_TEXT_PP(0);
189  text *right = PG_GETARG_TEXT_PP(1);
190  char *lcstr,
191  *rcstr;
192  bool result;
193 
194  /* We can't compare lengths in advance of downcasing ... */
195 
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);
198 
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  result = (strcmp(lcstr, rcstr) == 0);
204 
205  pfree(lcstr);
206  pfree(rcstr);
207  PG_FREE_IF_COPY(left, 0);
208  PG_FREE_IF_COPY(right, 1);
209 
210  PG_RETURN_BOOL(result);
211 }
212 
214 
215 Datum
217 {
218  text *left = PG_GETARG_TEXT_PP(0);
219  text *right = PG_GETARG_TEXT_PP(1);
220  char *lcstr,
221  *rcstr;
222  bool result;
223 
224  /* We can't compare lengths in advance of downcasing ... */
225 
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);
228 
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  result = (strcmp(lcstr, rcstr) != 0);
234 
235  pfree(lcstr);
236  pfree(rcstr);
237  PG_FREE_IF_COPY(left, 0);
238  PG_FREE_IF_COPY(right, 1);
239 
240  PG_RETURN_BOOL(result);
241 }
242 
244 
245 Datum
247 {
248  text *left = PG_GETARG_TEXT_PP(0);
249  text *right = PG_GETARG_TEXT_PP(1);
250  bool result;
251 
252  result = citextcmp(left, right, PG_GET_COLLATION()) < 0;
253 
254  PG_FREE_IF_COPY(left, 0);
255  PG_FREE_IF_COPY(right, 1);
256 
257  PG_RETURN_BOOL(result);
258 }
259 
261 
262 Datum
264 {
265  text *left = PG_GETARG_TEXT_PP(0);
266  text *right = PG_GETARG_TEXT_PP(1);
267  bool result;
268 
269  result = citextcmp(left, right, PG_GET_COLLATION()) <= 0;
270 
271  PG_FREE_IF_COPY(left, 0);
272  PG_FREE_IF_COPY(right, 1);
273 
274  PG_RETURN_BOOL(result);
275 }
276 
278 
279 Datum
281 {
282  text *left = PG_GETARG_TEXT_PP(0);
283  text *right = PG_GETARG_TEXT_PP(1);
284  bool result;
285 
286  result = citextcmp(left, right, PG_GET_COLLATION()) > 0;
287 
288  PG_FREE_IF_COPY(left, 0);
289  PG_FREE_IF_COPY(right, 1);
290 
291  PG_RETURN_BOOL(result);
292 }
293 
295 
296 Datum
298 {
299  text *left = PG_GETARG_TEXT_PP(0);
300  text *right = PG_GETARG_TEXT_PP(1);
301  bool result;
302 
303  result = citextcmp(left, right, PG_GET_COLLATION()) >= 0;
304 
305  PG_FREE_IF_COPY(left, 0);
306  PG_FREE_IF_COPY(right, 1);
307 
308  PG_RETURN_BOOL(result);
309 }
310 
312 
313 Datum
315 {
316  text *left = PG_GETARG_TEXT_PP(0);
317  text *right = PG_GETARG_TEXT_PP(1);
318  bool result;
319 
320  result = internal_citext_pattern_cmp(left, right, PG_GET_COLLATION()) < 0;
321 
322  PG_FREE_IF_COPY(left, 0);
323  PG_FREE_IF_COPY(right, 1);
324 
325  PG_RETURN_BOOL(result);
326 }
327 
329 
330 Datum
332 {
333  text *left = PG_GETARG_TEXT_PP(0);
334  text *right = PG_GETARG_TEXT_PP(1);
335  bool result;
336 
337  result = internal_citext_pattern_cmp(left, right, PG_GET_COLLATION()) <= 0;
338 
339  PG_FREE_IF_COPY(left, 0);
340  PG_FREE_IF_COPY(right, 1);
341 
342  PG_RETURN_BOOL(result);
343 }
344 
346 
347 Datum
349 {
350  text *left = PG_GETARG_TEXT_PP(0);
351  text *right = PG_GETARG_TEXT_PP(1);
352  bool result;
353 
354  result = internal_citext_pattern_cmp(left, right, PG_GET_COLLATION()) > 0;
355 
356  PG_FREE_IF_COPY(left, 0);
357  PG_FREE_IF_COPY(right, 1);
358 
359  PG_RETURN_BOOL(result);
360 }
361 
363 
364 Datum
366 {
367  text *left = PG_GETARG_TEXT_PP(0);
368  text *right = PG_GETARG_TEXT_PP(1);
369  bool result;
370 
371  result = internal_citext_pattern_cmp(left, right, PG_GET_COLLATION()) >= 0;
372 
373  PG_FREE_IF_COPY(left, 0);
374  PG_FREE_IF_COPY(right, 1);
375 
376  PG_RETURN_BOOL(result);
377 }
378 
379 /*
380  * ===================
381  * AGGREGATE FUNCTIONS
382  * ===================
383  */
384 
386 
387 Datum
389 {
390  text *left = PG_GETARG_TEXT_PP(0);
391  text *right = PG_GETARG_TEXT_PP(1);
392  text *result;
393 
394  result = citextcmp(left, right, PG_GET_COLLATION()) < 0 ? left : right;
395  PG_RETURN_TEXT_P(result);
396 }
397 
399 
400 Datum
402 {
403  text *left = PG_GETARG_TEXT_PP(0);
404  text *right = PG_GETARG_TEXT_PP(1);
405  text *result;
406 
407  result = citextcmp(left, right, PG_GET_COLLATION()) > 0 ? left : right;
408  PG_RETURN_TEXT_P(result);
409 }
#define Min(x, y)
Definition: c.h:1004
signed int int32
Definition: c.h:494
Datum citext_le(PG_FUNCTION_ARGS)
Definition: citext.c:263
Datum citext_pattern_cmp(PG_FUNCTION_ARGS)
Definition: citext.c:124
Datum citext_ne(PG_FUNCTION_ARGS)
Definition: citext.c:216
Datum citext_hash(PG_FUNCTION_ARGS)
Definition: citext.c:141
Datum citext_larger(PG_FUNCTION_ARGS)
Definition: citext.c:401
PG_MODULE_MAGIC
Definition: citext.c:13
Datum citext_lt(PG_FUNCTION_ARGS)
Definition: citext.c:246
Datum citext_pattern_gt(PG_FUNCTION_ARGS)
Definition: citext.c:348
Datum citext_gt(PG_FUNCTION_ARGS)
Definition: citext.c:280
Datum citext_smaller(PG_FUNCTION_ARGS)
Definition: citext.c:388
Datum citext_ge(PG_FUNCTION_ARGS)
Definition: citext.c:297
Datum citext_pattern_lt(PG_FUNCTION_ARGS)
Definition: citext.c:314
static int32 internal_citext_pattern_cmp(text *left, text *right, Oid collid)
Definition: citext.c:69
PG_FUNCTION_INFO_V1(citext_cmp)
Datum citext_pattern_ge(PG_FUNCTION_ARGS)
Definition: citext.c:365
Datum citext_pattern_le(PG_FUNCTION_ARGS)
Definition: citext.c:331
Datum citext_cmp(PG_FUNCTION_ARGS)
Definition: citext.c:107
Datum citext_eq(PG_FUNCTION_ARGS)
Definition: citext.c:186
Datum citext_hash_extended(PG_FUNCTION_ARGS)
Definition: citext.c:160
static int32 citextcmp(text *left, text *right, Oid collid)
Definition: citext.c:36
Oid collid
#define PG_FREE_IF_COPY(ptr, n)
Definition: fmgr.h:260
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:309
#define PG_GETARG_INT64(n)
Definition: fmgr.h:283
#define PG_RETURN_TEXT_P(x)
Definition: fmgr.h:372
#define PG_RETURN_INT32(x)
Definition: fmgr.h:354
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:353
#define PG_GET_COLLATION()
Definition: fmgr.h:198
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:359
char * str_tolower(const char *buff, size_t nbytes, Oid collid)
Definition: formatting.c:1636
static Datum hash_any_extended(const unsigned char *k, int keylen, uint64 seed)
Definition: hashfn.h:37
static Datum hash_any(const unsigned char *k, int keylen)
Definition: hashfn.h:31
const char * str
void pfree(void *pointer)
Definition: mcxt.c:1520
uintptr_t Datum
Definition: postgres.h:64
unsigned int Oid
Definition: postgres_ext.h:31
Definition: c.h:687
#define VARDATA_ANY(PTR)
Definition: varatt.h:324
#define VARSIZE_ANY_EXHDR(PTR)
Definition: varatt.h:317
int varstr_cmp(const char *arg1, int len1, const char *arg2, int len2, Oid collid)
Definition: varlena.c:1539