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 "access/hash.h"
7 #include "catalog/pg_collation.h"
8 #include "utils/builtins.h"
9 #include "utils/formatting.h"
10 #include "utils/varlena.h"
11 
13 
14 /*
15  * ====================
16  * FORWARD DECLARATIONS
17  * ====================
18  */
19 
20 static int32 citextcmp(text *left, text *right, Oid collid);
21 static int32 internal_citext_pattern_cmp(text *left, text *right, Oid collid);
22 
23 /*
24  * =================
25  * UTILITY FUNCTIONS
26  * =================
27  */
28 
29 /*
30  * citextcmp()
31  * Internal comparison function for citext strings.
32  * Returns int32 negative, zero, or positive.
33  */
34 static int32
35 citextcmp(text *left, text *right, Oid collid)
36 {
37  char *lcstr,
38  *rcstr;
39  int32 result;
40 
41  /*
42  * We must do our str_tolower calls with DEFAULT_COLLATION_OID, not the
43  * input collation as you might expect. This is so that the behavior of
44  * citext's equality and hashing functions is not collation-dependent. We
45  * should change this once the core infrastructure is able to cope with
46  * collation-dependent equality and hashing functions.
47  */
48 
51 
52  result = varstr_cmp(lcstr, strlen(lcstr),
53  rcstr, strlen(rcstr),
54  collid);
55 
56  pfree(lcstr);
57  pfree(rcstr);
58 
59  return result;
60 }
61 
62 /*
63  * citext_pattern_cmp()
64  * Internal character-by-character comparison function for citext strings.
65  * Returns int32 negative, zero, or positive.
66  */
67 static int32
68 internal_citext_pattern_cmp(text *left, text *right, Oid collid)
69 {
70  char *lcstr,
71  *rcstr;
72  int llen,
73  rlen;
74  int32 result;
75 
78 
79  llen = strlen(lcstr);
80  rlen = strlen(rcstr);
81 
82  result = memcmp((void *) lcstr, (void *) rcstr, Min(llen, rlen));
83  if (result == 0)
84  {
85  if (llen < rlen)
86  result = -1;
87  else if (llen > rlen)
88  result = 1;
89  }
90 
91  pfree(lcstr);
92  pfree(rcstr);
93 
94  return result;
95 }
96 
97 /*
98  * ==================
99  * INDEXING FUNCTIONS
100  * ==================
101  */
102 
104 
105 Datum
107 {
108  text *left = PG_GETARG_TEXT_PP(0);
109  text *right = PG_GETARG_TEXT_PP(1);
110  int32 result;
111 
112  result = citextcmp(left, right, PG_GET_COLLATION());
113 
114  PG_FREE_IF_COPY(left, 0);
115  PG_FREE_IF_COPY(right, 1);
116 
117  PG_RETURN_INT32(result);
118 }
119 
121 
122 Datum
124 {
125  text *left = PG_GETARG_TEXT_PP(0);
126  text *right = PG_GETARG_TEXT_PP(1);
127  int32 result;
128 
129  result = internal_citext_pattern_cmp(left, right, PG_GET_COLLATION());
130 
131  PG_FREE_IF_COPY(left, 0);
132  PG_FREE_IF_COPY(right, 1);
133 
134  PG_RETURN_INT32(result);
135 }
136 
138 
139 Datum
141 {
142  text *txt = PG_GETARG_TEXT_PP(0);
143  char *str;
144  Datum result;
145 
147  result = hash_any((unsigned char *) str, strlen(str));
148  pfree(str);
149 
150  /* Avoid leaking memory for toasted inputs */
151  PG_FREE_IF_COPY(txt, 0);
152 
153  PG_RETURN_DATUM(result);
154 }
155 
156 /*
157  * ==================
158  * OPERATOR FUNCTIONS
159  * ==================
160  */
161 
163 
164 Datum
166 {
167  text *left = PG_GETARG_TEXT_PP(0);
168  text *right = PG_GETARG_TEXT_PP(1);
169  char *lcstr,
170  *rcstr;
171  bool result;
172 
173  /* We can't compare lengths in advance of downcasing ... */
174 
177 
178  /*
179  * Since we only care about equality or not-equality, we can avoid all the
180  * expense of strcoll() here, and just do bitwise comparison.
181  */
182  result = (strcmp(lcstr, rcstr) == 0);
183 
184  pfree(lcstr);
185  pfree(rcstr);
186  PG_FREE_IF_COPY(left, 0);
187  PG_FREE_IF_COPY(right, 1);
188 
189  PG_RETURN_BOOL(result);
190 }
191 
193 
194 Datum
196 {
197  text *left = PG_GETARG_TEXT_PP(0);
198  text *right = PG_GETARG_TEXT_PP(1);
199  char *lcstr,
200  *rcstr;
201  bool result;
202 
203  /* We can't compare lengths in advance of downcasing ... */
204 
207 
208  /*
209  * Since we only care about equality or not-equality, we can avoid all the
210  * expense of strcoll() here, and just do bitwise comparison.
211  */
212  result = (strcmp(lcstr, rcstr) != 0);
213 
214  pfree(lcstr);
215  pfree(rcstr);
216  PG_FREE_IF_COPY(left, 0);
217  PG_FREE_IF_COPY(right, 1);
218 
219  PG_RETURN_BOOL(result);
220 }
221 
223 
224 Datum
226 {
227  text *left = PG_GETARG_TEXT_PP(0);
228  text *right = PG_GETARG_TEXT_PP(1);
229  bool result;
230 
231  result = citextcmp(left, right, PG_GET_COLLATION()) < 0;
232 
233  PG_FREE_IF_COPY(left, 0);
234  PG_FREE_IF_COPY(right, 1);
235 
236  PG_RETURN_BOOL(result);
237 }
238 
240 
241 Datum
243 {
244  text *left = PG_GETARG_TEXT_PP(0);
245  text *right = PG_GETARG_TEXT_PP(1);
246  bool result;
247 
248  result = citextcmp(left, right, PG_GET_COLLATION()) <= 0;
249 
250  PG_FREE_IF_COPY(left, 0);
251  PG_FREE_IF_COPY(right, 1);
252 
253  PG_RETURN_BOOL(result);
254 }
255 
257 
258 Datum
260 {
261  text *left = PG_GETARG_TEXT_PP(0);
262  text *right = PG_GETARG_TEXT_PP(1);
263  bool result;
264 
265  result = citextcmp(left, right, PG_GET_COLLATION()) > 0;
266 
267  PG_FREE_IF_COPY(left, 0);
268  PG_FREE_IF_COPY(right, 1);
269 
270  PG_RETURN_BOOL(result);
271 }
272 
274 
275 Datum
277 {
278  text *left = PG_GETARG_TEXT_PP(0);
279  text *right = PG_GETARG_TEXT_PP(1);
280  bool result;
281 
282  result = citextcmp(left, right, PG_GET_COLLATION()) >= 0;
283 
284  PG_FREE_IF_COPY(left, 0);
285  PG_FREE_IF_COPY(right, 1);
286 
287  PG_RETURN_BOOL(result);
288 }
289 
291 
292 Datum
294 {
295  text *left = PG_GETARG_TEXT_PP(0);
296  text *right = PG_GETARG_TEXT_PP(1);
297  bool result;
298 
299  result = internal_citext_pattern_cmp(left, right, PG_GET_COLLATION()) < 0;
300 
301  PG_FREE_IF_COPY(left, 0);
302  PG_FREE_IF_COPY(right, 1);
303 
304  PG_RETURN_BOOL(result);
305 }
306 
308 
309 Datum
311 {
312  text *left = PG_GETARG_TEXT_PP(0);
313  text *right = PG_GETARG_TEXT_PP(1);
314  bool result;
315 
316  result = internal_citext_pattern_cmp(left, right, PG_GET_COLLATION()) <= 0;
317 
318  PG_FREE_IF_COPY(left, 0);
319  PG_FREE_IF_COPY(right, 1);
320 
321  PG_RETURN_BOOL(result);
322 }
323 
325 
326 Datum
328 {
329  text *left = PG_GETARG_TEXT_PP(0);
330  text *right = PG_GETARG_TEXT_PP(1);
331  bool result;
332 
333  result = internal_citext_pattern_cmp(left, right, PG_GET_COLLATION()) > 0;
334 
335  PG_FREE_IF_COPY(left, 0);
336  PG_FREE_IF_COPY(right, 1);
337 
338  PG_RETURN_BOOL(result);
339 }
340 
342 
343 Datum
345 {
346  text *left = PG_GETARG_TEXT_PP(0);
347  text *right = PG_GETARG_TEXT_PP(1);
348  bool result;
349 
350  result = internal_citext_pattern_cmp(left, right, PG_GET_COLLATION()) >= 0;
351 
352  PG_FREE_IF_COPY(left, 0);
353  PG_FREE_IF_COPY(right, 1);
354 
355  PG_RETURN_BOOL(result);
356 }
357 
358 /*
359  * ===================
360  * AGGREGATE FUNCTIONS
361  * ===================
362  */
363 
365 
366 Datum
368 {
369  text *left = PG_GETARG_TEXT_PP(0);
370  text *right = PG_GETARG_TEXT_PP(1);
371  text *result;
372 
373  result = citextcmp(left, right, PG_GET_COLLATION()) < 0 ? left : right;
374  PG_RETURN_TEXT_P(result);
375 }
376 
378 
379 Datum
381 {
382  text *left = PG_GETARG_TEXT_PP(0);
383  text *right = PG_GETARG_TEXT_PP(1);
384  text *result;
385 
386  result = citextcmp(left, right, PG_GET_COLLATION()) > 0 ? left : right;
387  PG_RETURN_TEXT_P(result);
388 }
#define VARDATA_ANY(PTR)
Definition: postgres.h:347
static int32 internal_citext_pattern_cmp(text *left, text *right, Oid collid)
Definition: citext.c:68
Datum citext_smaller(PG_FUNCTION_ARGS)
Definition: citext.c:367
char * str_tolower(const char *buff, size_t nbytes, Oid collid)
Definition: formatting.c:1508
PG_FUNCTION_INFO_V1(citext_cmp)
Datum citext_pattern_lt(PG_FUNCTION_ARGS)
Definition: citext.c:293
#define Min(x, y)
Definition: c.h:802
#define PG_RETURN_INT32(x)
Definition: fmgr.h:314
static int32 citextcmp(text *left, text *right, Oid collid)
Definition: citext.c:35
Datum citext_hash(PG_FUNCTION_ARGS)
Definition: citext.c:140
unsigned int Oid
Definition: postgres_ext.h:31
#define PG_GET_COLLATION()
Definition: fmgr.h:163
Datum citext_ge(PG_FUNCTION_ARGS)
Definition: citext.c:276
signed int int32
Definition: c.h:284
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:273
void pfree(void *pointer)
Definition: mcxt.c:949
int varstr_cmp(const char *arg1, int len1, const char *arg2, int len2, Oid collid)
Definition: varlena.c:1382
Datum citext_larger(PG_FUNCTION_ARGS)
Definition: citext.c:380
Datum citext_pattern_ge(PG_FUNCTION_ARGS)
Definition: citext.c:344
Datum citext_cmp(PG_FUNCTION_ARGS)
Definition: citext.c:106
PG_MODULE_MAGIC
Definition: citext.c:12
#define DEFAULT_COLLATION_OID
Definition: pg_collation.h:75
Datum citext_pattern_cmp(PG_FUNCTION_ARGS)
Definition: citext.c:123
Datum citext_pattern_gt(PG_FUNCTION_ARGS)
Definition: citext.c:327
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:319
uintptr_t Datum
Definition: postgres.h:372
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:313
Datum citext_gt(PG_FUNCTION_ARGS)
Definition: citext.c:259
#define PG_RETURN_TEXT_P(x)
Definition: fmgr.h:331
Datum hash_any(register const unsigned char *k, register int keylen)
Definition: hashfunc.c:428
Datum citext_ne(PG_FUNCTION_ARGS)
Definition: citext.c:195
Datum citext_le(PG_FUNCTION_ARGS)
Definition: citext.c:242
#define PG_FREE_IF_COPY(ptr, n)
Definition: fmgr.h:225
Datum citext_eq(PG_FUNCTION_ARGS)
Definition: citext.c:165
Datum citext_lt(PG_FUNCTION_ARGS)
Definition: citext.c:225
#define VARSIZE_ANY_EXHDR(PTR)
Definition: postgres.h:340
Definition: c.h:487
#define PG_FUNCTION_ARGS
Definition: fmgr.h:158
Datum citext_pattern_le(PG_FUNCTION_ARGS)
Definition: citext.c:310