Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * varchar.c
4 : : * Functions for the built-in types char(n) and varchar(n).
5 : : *
6 : : * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
7 : : * Portions Copyright (c) 1994, Regents of the University of California
8 : : *
9 : : *
10 : : * IDENTIFICATION
11 : : * src/backend/utils/adt/varchar.c
12 : : *
13 : : *-------------------------------------------------------------------------
14 : : */
15 : : #include "postgres.h"
16 : :
17 : : #include "access/detoast.h"
18 : : #include "access/htup_details.h"
19 : : #include "catalog/pg_collation.h"
20 : : #include "catalog/pg_type.h"
21 : : #include "common/hashfn.h"
22 : : #include "libpq/pqformat.h"
23 : : #include "mb/pg_wchar.h"
24 : : #include "nodes/nodeFuncs.h"
25 : : #include "nodes/supportnodes.h"
26 : : #include "utils/array.h"
27 : : #include "utils/builtins.h"
28 : : #include "utils/pg_locale.h"
29 : : #include "utils/varlena.h"
30 : :
31 : : /* common code for bpchartypmodin and varchartypmodin */
32 : : static int32
7091 tgl@sss.pgh.pa.us 33 :CBC 2428 : anychar_typmodin(ArrayType *ta, const char *typename)
34 : : {
35 : : int32 typmod;
36 : : int32 *tl;
37 : : int n;
38 : :
6924 39 : 2428 : tl = ArrayGetIntegerTypmods(ta, &n);
40 : :
41 : : /*
42 : : * we're not too tense about good error message here because grammar
43 : : * shouldn't allow wrong number of modifiers for CHAR
44 : : */
7091 45 [ - + ]: 2428 : if (n != 1)
7091 tgl@sss.pgh.pa.us 46 [ # # ]:UBC 0 : ereport(ERROR,
47 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
48 : : errmsg("invalid type modifier")));
49 : :
7091 tgl@sss.pgh.pa.us 50 [ - + ]:CBC 2428 : if (*tl < 1)
7091 tgl@sss.pgh.pa.us 51 [ # # ]:UBC 0 : ereport(ERROR,
52 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
53 : : errmsg("length for type %s must be at least 1", typename)));
7091 tgl@sss.pgh.pa.us 54 [ - + ]:CBC 2428 : if (*tl > MaxAttrSize)
7091 tgl@sss.pgh.pa.us 55 [ # # ]:UBC 0 : ereport(ERROR,
56 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
57 : : errmsg("length for type %s cannot exceed %d",
58 : : typename, MaxAttrSize)));
59 : :
60 : : /*
61 : : * For largely historical reasons, the typmod is VARHDRSZ plus the number
62 : : * of characters; there is enough client-side code that knows about that
63 : : * that we'd better not change it.
64 : : */
7091 tgl@sss.pgh.pa.us 65 :CBC 2428 : typmod = VARHDRSZ + *tl;
66 : :
67 : 2428 : return typmod;
68 : : }
69 : :
70 : : /* common code for bpchartypmodout and varchartypmodout */
71 : : static char *
72 : 655 : anychar_typmodout(int32 typmod)
73 : : {
6771 bruce@momjian.us 74 : 655 : char *res = (char *) palloc(64);
75 : :
7091 tgl@sss.pgh.pa.us 76 [ + - ]: 655 : if (typmod > VARHDRSZ)
77 : 655 : snprintf(res, 64, "(%d)", (int) (typmod - VARHDRSZ));
78 : : else
7091 tgl@sss.pgh.pa.us 79 :UBC 0 : *res = '\0';
80 : :
7091 tgl@sss.pgh.pa.us 81 :CBC 655 : return res;
82 : : }
83 : :
84 : :
85 : : /*
86 : : * CHAR() and VARCHAR() types are part of the SQL standard. CHAR()
87 : : * is for blank-padded string whose length is specified in CREATE TABLE.
88 : : * VARCHAR is for storing string whose length is at most the length specified
89 : : * at CREATE TABLE time.
90 : : *
91 : : * It's hard to implement these types because we cannot figure out
92 : : * the length of the type from the type itself. I changed (hopefully all) the
93 : : * fmgr calls that invoke input functions of a data type to supply the
94 : : * length also. (eg. in INSERTs, we have the tupleDescriptor which contains
95 : : * the length of the attributes and hence the exact length of the char() or
96 : : * varchar(). We pass this to bpcharin() or varcharin().) In the case where
97 : : * we cannot determine the length, we pass in -1 instead and the input
98 : : * converter does not enforce any length check.
99 : : *
100 : : * We actually implement this as a varlena so that we don't have to pass in
101 : : * the length for the comparison functions. (The difference between these
102 : : * types and "text" is that we truncate and possibly blank-pad the string
103 : : * at insertion time.)
104 : : *
105 : : * - ay 6/95
106 : : */
107 : :
108 : :
109 : : /*****************************************************************************
110 : : * bpchar - char() *
111 : : *****************************************************************************/
112 : :
113 : : /*
114 : : * bpchar_input -- common guts of bpcharin and bpcharrecv
115 : : *
116 : : * s is the input text of length len (may not be null-terminated)
117 : : * atttypmod is the typmod value to apply
118 : : *
119 : : * Note that atttypmod is measured in characters, which
120 : : * is not necessarily the same as the number of bytes.
121 : : *
122 : : * If the input string is too long, raise an error, unless the extra
123 : : * characters are spaces, in which case they're truncated. (per SQL)
124 : : *
125 : : * If escontext points to an ErrorSaveContext node, that is filled instead
126 : : * of throwing an error; the caller must check SOFT_ERROR_OCCURRED()
127 : : * to detect errors.
128 : : */
129 : : static BpChar *
1263 130 : 212404 : bpchar_input(const char *s, size_t len, int32 atttypmod, Node *escontext)
131 : : {
132 : : BpChar *result;
133 : : char *r;
134 : : size_t maxlen;
135 : :
136 : : /* If typmod is -1 (or invalid), use the actual string length */
9129 137 [ + + ]: 212404 : if (atttypmod < (int32) VARHDRSZ)
7671 138 : 5471 : maxlen = len;
139 : : else
140 : : {
141 : : size_t charlen; /* number of CHARACTERS in the input */
142 : :
143 : 206933 : maxlen = atttypmod - VARHDRSZ;
7629 144 : 206933 : charlen = pg_mbstrlen_with_len(s, len);
7671 145 [ + + ]: 206933 : if (charlen > maxlen)
146 : : {
147 : : /* Verify that extra characters are spaces, and clip them off */
148 : 132 : size_t mbmaxlen = pg_mbcharcliplen(s, len, maxlen);
149 : : size_t j;
150 : :
151 : : /*
152 : : * at this point, len is the actual BYTE length of the input
153 : : * string, maxlen is the max number of CHARACTERS allowed for this
154 : : * bpchar type, mbmaxlen is the length in BYTES of those chars.
155 : : */
7629 156 [ + + ]: 140 : for (j = mbmaxlen; j < len; j++)
157 : : {
158 [ + + ]: 136 : if (s[j] != ' ')
1263 159 [ + + ]: 128 : ereturn(escontext, NULL,
160 : : (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION),
161 : : errmsg("value too long for type character(%zu)",
162 : : maxlen)));
163 : : }
164 : :
165 : : /*
166 : : * Now we set maxlen to the necessary byte length, not the number
167 : : * of CHARACTERS!
168 : : */
7629 169 : 4 : maxlen = len = mbmaxlen;
170 : : }
171 : : else
172 : : {
173 : : /*
174 : : * Now we set maxlen to the necessary byte length, not the number
175 : : * of CHARACTERS!
176 : : */
7671 177 : 206801 : maxlen = len + (maxlen - charlen);
178 : : }
179 : : }
180 : :
7629 181 : 212276 : result = (BpChar *) palloc(maxlen + VARHDRSZ);
7032 182 : 212276 : SET_VARSIZE(result, maxlen + VARHDRSZ);
10370 bruce@momjian.us 183 : 212276 : r = VARDATA(result);
7671 tgl@sss.pgh.pa.us 184 : 212276 : memcpy(r, s, len);
185 : :
186 : : /* blank pad the string if necessary */
187 [ + + ]: 212276 : if (maxlen > len)
188 : 201152 : memset(r + len, ' ', maxlen - len);
189 : :
7629 190 : 212276 : return result;
191 : : }
192 : :
193 : : /*
194 : : * Convert a C string to CHARACTER internal representation. atttypmod
195 : : * is the declared length of the type plus VARHDRSZ.
196 : : */
197 : : Datum
198 : 212404 : bpcharin(PG_FUNCTION_ARGS)
199 : : {
200 : 212404 : char *s = PG_GETARG_CSTRING(0);
201 : : #ifdef NOT_USED
202 : : Oid typelem = PG_GETARG_OID(1);
203 : : #endif
204 : 212404 : int32 atttypmod = PG_GETARG_INT32(2);
205 : : BpChar *result;
206 : :
1263 207 : 212404 : result = bpchar_input(s, strlen(s), atttypmod, fcinfo->context);
9482 208 : 212356 : PG_RETURN_BPCHAR_P(result);
209 : : }
210 : :
211 : :
212 : : /*
213 : : * Convert a CHARACTER value to a C string.
214 : : *
215 : : * Uses the text conversion functions, which is only appropriate if BpChar
216 : : * and text are equivalent types.
217 : : */
218 : : Datum
219 : 24458 : bpcharout(PG_FUNCTION_ARGS)
220 : : {
6640 221 : 24458 : Datum txt = PG_GETARG_DATUM(0);
222 : :
223 : 24458 : PG_RETURN_CSTRING(TextDatumGetCString(txt));
224 : : }
225 : :
226 : : /*
227 : : * bpcharrecv - converts external binary format to bpchar
228 : : */
229 : : Datum
8419 tgl@sss.pgh.pa.us 230 :UBC 0 : bpcharrecv(PG_FUNCTION_ARGS)
231 : : {
7629 232 : 0 : StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
233 : : #ifdef NOT_USED
234 : : Oid typelem = PG_GETARG_OID(1);
235 : : #endif
236 : 0 : int32 atttypmod = PG_GETARG_INT32(2);
237 : : BpChar *result;
238 : : char *str;
239 : : int nbytes;
240 : :
241 : 0 : str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
1263 242 : 0 : result = bpchar_input(str, nbytes, atttypmod, NULL);
7629 243 : 0 : pfree(str);
244 : 0 : PG_RETURN_BPCHAR_P(result);
245 : : }
246 : :
247 : : /*
248 : : * bpcharsend - converts bpchar to binary format
249 : : */
250 : : Datum
8419 tgl@sss.pgh.pa.us 251 :CBC 1 : bpcharsend(PG_FUNCTION_ARGS)
252 : : {
253 : : /* Exactly the same as textsend, so share code */
254 : 1 : return textsend(fcinfo);
255 : : }
256 : :
257 : :
258 : : /*
259 : : * Converts a CHARACTER type to the specified size.
260 : : *
261 : : * maxlen is the typmod, ie, declared length plus VARHDRSZ bytes.
262 : : * isExplicit is true if this is for an explicit cast to char(N).
263 : : *
264 : : * Truncation rules: for an explicit cast, silently truncate to the given
265 : : * length; for an implicit cast, raise error unless extra characters are
266 : : * all spaces. (This is sort-of per SQL: the spec would actually have us
267 : : * raise a "completion condition" for the explicit cast case, but Postgres
268 : : * hasn't got such a concept.)
269 : : */
270 : : Datum
9482 271 : 8501 : bpchar(PG_FUNCTION_ARGS)
272 : : {
6994 273 : 8501 : BpChar *source = PG_GETARG_BPCHAR_PP(0);
9140 peter_e@gmx.net 274 : 8501 : int32 maxlen = PG_GETARG_INT32(1);
8655 tgl@sss.pgh.pa.us 275 : 8501 : bool isExplicit = PG_GETARG_BOOL(2);
276 : : BpChar *result;
277 : : int32 len;
278 : : char *r;
279 : : char *s;
280 : : int i;
281 : : int charlen; /* number of characters in the input string +
282 : : * VARHDRSZ */
283 : :
284 : : /* No work if typmod is invalid */
7671 285 [ - + ]: 8501 : if (maxlen < (int32) VARHDRSZ)
7671 tgl@sss.pgh.pa.us 286 :UBC 0 : PG_RETURN_BPCHAR_P(source);
287 : :
6994 tgl@sss.pgh.pa.us 288 :CBC 8501 : maxlen -= VARHDRSZ;
289 : :
290 [ - + - - : 8501 : len = VARSIZE_ANY_EXHDR(source);
- - - - +
+ ]
291 [ + + ]: 8501 : s = VARDATA_ANY(source);
292 : :
293 : 8501 : charlen = pg_mbstrlen_with_len(s, len);
294 : :
295 : : /* No work if supplied data matches typmod already */
7671 296 [ + + ]: 8501 : if (charlen == maxlen)
9140 peter_e@gmx.net 297 : 3929 : PG_RETURN_BPCHAR_P(source);
298 : :
9085 ishii@postgresql.org 299 [ + + ]: 4572 : if (charlen > maxlen)
300 : : {
301 : : /* Verify that extra characters are spaces, and clip them off */
302 : : size_t maxmblen;
303 : :
6994 tgl@sss.pgh.pa.us 304 : 30 : maxmblen = pg_mbcharcliplen(s, len, maxlen);
305 : :
8655 306 [ + + ]: 30 : if (!isExplicit)
307 : : {
6994 308 [ + + ]: 71 : for (i = maxmblen; i < len; i++)
309 [ + + ]: 61 : if (s[i] != ' ')
67 peter@eisentraut.org 310 [ + - ]:GNC 16 : ereturn(fcinfo->context, (Datum) 0,
311 : : (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION),
312 : : errmsg("value too long for type character(%d)",
313 : : maxlen)));
314 : : }
315 : :
9140 peter_e@gmx.net 316 :CBC 14 : len = maxmblen;
317 : :
318 : : /*
319 : : * At this point, maxlen is the necessary byte length, not the number
320 : : * of CHARACTERS!
321 : : */
9085 ishii@postgresql.org 322 : 14 : maxlen = len;
323 : : }
324 : : else
325 : : {
326 : : /*
327 : : * At this point, maxlen is the necessary byte length, not the number
328 : : * of CHARACTERS!
329 : : */
330 : 4542 : maxlen = len + (maxlen - charlen);
331 : : }
332 : :
6994 tgl@sss.pgh.pa.us 333 [ - + ]: 4556 : Assert(maxlen >= len);
334 : :
6771 bruce@momjian.us 335 : 4556 : result = palloc(maxlen + VARHDRSZ);
336 : 4556 : SET_VARSIZE(result, maxlen + VARHDRSZ);
9140 peter_e@gmx.net 337 : 4556 : r = VARDATA(result);
338 : :
6994 tgl@sss.pgh.pa.us 339 : 4556 : memcpy(r, s, len);
340 : :
341 : : /* blank pad the string if necessary */
7671 342 [ + + ]: 4556 : if (maxlen > len)
6994 343 : 4542 : memset(r + len, ' ', maxlen - len);
344 : :
9482 345 : 4556 : PG_RETURN_BPCHAR_P(result);
346 : : }
347 : :
348 : :
349 : : /*
350 : : * char_bpchar()
351 : : * Convert char to bpchar(1).
352 : : */
353 : : Datum
9490 tgl@sss.pgh.pa.us 354 :UBC 0 : char_bpchar(PG_FUNCTION_ARGS)
355 : : {
356 : 0 : char c = PG_GETARG_CHAR(0);
357 : : BpChar *result;
358 : :
9482 359 : 0 : result = (BpChar *) palloc(VARHDRSZ + 1);
360 : :
7032 361 : 0 : SET_VARSIZE(result, VARHDRSZ + 1);
9490 362 : 0 : *(VARDATA(result)) = c;
363 : :
364 : 0 : PG_RETURN_BPCHAR_P(result);
365 : : }
366 : :
367 : :
368 : : /*
369 : : * bpchar_name()
370 : : * Converts a bpchar() type to a NameData type.
371 : : */
372 : : Datum
9436 373 : 0 : bpchar_name(PG_FUNCTION_ARGS)
374 : : {
6994 375 : 0 : BpChar *s = PG_GETARG_BPCHAR_PP(0);
376 : : char *s_data;
377 : : Name result;
378 : : int len;
379 : :
380 [ # # # # : 0 : len = VARSIZE_ANY_EXHDR(s);
# # # # #
# ]
381 [ # # ]: 0 : s_data = VARDATA_ANY(s);
382 : :
383 : : /* Truncate oversize input */
9458 384 [ # # ]: 0 : if (len >= NAMEDATALEN)
5118 385 : 0 : len = pg_mbcliplen(s_data, len, NAMEDATALEN - 1);
386 : :
387 : : /* Remove trailing blanks */
10133 bruce@momjian.us 388 [ # # ]: 0 : while (len > 0)
389 : : {
6994 tgl@sss.pgh.pa.us 390 [ # # ]: 0 : if (s_data[len - 1] != ' ')
10133 bruce@momjian.us 391 : 0 : break;
10228 lockhart@fourpalms.o 392 : 0 : len--;
393 : : }
394 : :
395 : : /* We use palloc0 here to ensure result is zero-padded */
5118 tgl@sss.pgh.pa.us 396 : 0 : result = (Name) palloc0(NAMEDATALEN);
6994 397 : 0 : memcpy(NameStr(*result), s_data, len);
398 : :
9436 399 : 0 : PG_RETURN_NAME(result);
400 : : }
401 : :
402 : : /*
403 : : * name_bpchar()
404 : : * Converts a NameData type to a bpchar type.
405 : : *
406 : : * Uses the text conversion functions, which is only appropriate if BpChar
407 : : * and text are equivalent types.
408 : : */
409 : : Datum
9436 tgl@sss.pgh.pa.us 410 :CBC 5 : name_bpchar(PG_FUNCTION_ARGS)
411 : : {
412 : 5 : Name s = PG_GETARG_NAME(0);
413 : : BpChar *result;
414 : :
6640 415 : 5 : result = (BpChar *) cstring_to_text(NameStr(*s));
9436 416 : 5 : PG_RETURN_BPCHAR_P(result);
417 : : }
418 : :
419 : : Datum
7091 420 : 1348 : bpchartypmodin(PG_FUNCTION_ARGS)
421 : : {
6771 bruce@momjian.us 422 : 1348 : ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0);
423 : :
7091 tgl@sss.pgh.pa.us 424 : 1348 : PG_RETURN_INT32(anychar_typmodin(ta, "char"));
425 : : }
426 : :
427 : : Datum
428 : 442 : bpchartypmodout(PG_FUNCTION_ARGS)
429 : : {
6771 bruce@momjian.us 430 : 442 : int32 typmod = PG_GETARG_INT32(0);
431 : :
7091 tgl@sss.pgh.pa.us 432 : 442 : PG_RETURN_CSTRING(anychar_typmodout(typmod));
433 : : }
434 : :
435 : :
436 : : /*****************************************************************************
437 : : * varchar - varchar(n)
438 : : *
439 : : * Note: varchar piggybacks on type text for most operations, and so has no
440 : : * C-coded functions except for I/O and typmod checking.
441 : : *****************************************************************************/
442 : :
443 : : /*
444 : : * varchar_input -- common guts of varcharin and varcharrecv
445 : : *
446 : : * s is the input text of length len (may not be null-terminated)
447 : : * atttypmod is the typmod value to apply
448 : : *
449 : : * Note that atttypmod is measured in characters, which
450 : : * is not necessarily the same as the number of bytes.
451 : : *
452 : : * If the input string is too long, raise an error, unless the extra
453 : : * characters are spaces, in which case they're truncated. (per SQL)
454 : : *
455 : : * If escontext points to an ErrorSaveContext node, that is filled instead
456 : : * of throwing an error; the caller must check SOFT_ERROR_OCCURRED()
457 : : * to detect errors.
458 : : */
459 : : static VarChar *
1263 460 : 375338 : varchar_input(const char *s, size_t len, int32 atttypmod, Node *escontext)
461 : : {
462 : : VarChar *result;
463 : : size_t maxlen;
464 : :
9140 peter_e@gmx.net 465 : 375338 : maxlen = atttypmod - VARHDRSZ;
466 : :
467 [ + + + + ]: 375338 : if (atttypmod >= (int32) VARHDRSZ && len > maxlen)
468 : : {
469 : : /* Verify that extra characters are spaces, and clip them off */
8983 bruce@momjian.us 470 : 52 : size_t mbmaxlen = pg_mbcharcliplen(s, len, maxlen);
471 : : size_t j;
472 : :
7629 tgl@sss.pgh.pa.us 473 [ + + ]: 60 : for (j = mbmaxlen; j < len; j++)
474 : : {
475 [ + + ]: 56 : if (s[j] != ' ')
1263 476 [ + + ]: 48 : ereturn(escontext, NULL,
477 : : (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION),
478 : : errmsg("value too long for type character varying(%zu)",
479 : : maxlen)));
480 : : }
481 : :
7629 482 : 4 : len = mbmaxlen;
483 : : }
484 : :
485 : : /*
486 : : * We can use cstring_to_text_with_len because VarChar and text are
487 : : * binary-compatible types.
488 : : */
6640 489 : 375290 : result = (VarChar *) cstring_to_text_with_len(s, len);
7629 490 : 375290 : return result;
491 : : }
492 : :
493 : : /*
494 : : * Convert a C string to VARCHAR internal representation. atttypmod
495 : : * is the declared length of the type plus VARHDRSZ.
496 : : */
497 : : Datum
498 : 375337 : varcharin(PG_FUNCTION_ARGS)
499 : : {
500 : 375337 : char *s = PG_GETARG_CSTRING(0);
501 : : #ifdef NOT_USED
502 : : Oid typelem = PG_GETARG_OID(1);
503 : : #endif
504 : 375337 : int32 atttypmod = PG_GETARG_INT32(2);
505 : : VarChar *result;
506 : :
1263 507 : 375337 : result = varchar_input(s, strlen(s), atttypmod, fcinfo->context);
9482 508 : 375321 : PG_RETURN_VARCHAR_P(result);
509 : : }
510 : :
511 : :
512 : : /*
513 : : * Convert a VARCHAR value to a C string.
514 : : *
515 : : * Uses the text to C string conversion function, which is only appropriate
516 : : * if VarChar and text are equivalent types.
517 : : */
518 : : Datum
519 : 111329 : varcharout(PG_FUNCTION_ARGS)
520 : : {
6640 521 : 111329 : Datum txt = PG_GETARG_DATUM(0);
522 : :
523 : 111329 : PG_RETURN_CSTRING(TextDatumGetCString(txt));
524 : : }
525 : :
526 : : /*
527 : : * varcharrecv - converts external binary format to varchar
528 : : */
529 : : Datum
8419 530 : 1 : varcharrecv(PG_FUNCTION_ARGS)
531 : : {
7629 532 : 1 : StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
533 : : #ifdef NOT_USED
534 : : Oid typelem = PG_GETARG_OID(1);
535 : : #endif
536 : 1 : int32 atttypmod = PG_GETARG_INT32(2);
537 : : VarChar *result;
538 : : char *str;
539 : : int nbytes;
540 : :
541 : 1 : str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
1263 542 : 1 : result = varchar_input(str, nbytes, atttypmod, NULL);
7629 543 : 1 : pfree(str);
544 : 1 : PG_RETURN_VARCHAR_P(result);
545 : : }
546 : :
547 : : /*
548 : : * varcharsend - converts varchar to binary format
549 : : */
550 : : Datum
8419 551 : 1 : varcharsend(PG_FUNCTION_ARGS)
552 : : {
553 : : /* Exactly the same as textsend, so share code */
554 : 1 : return textsend(fcinfo);
555 : : }
556 : :
557 : :
558 : : /*
559 : : * varchar_support()
560 : : *
561 : : * Planner support function for the varchar() length coercion function.
562 : : *
563 : : * Currently, the only interesting thing we can do is flatten calls that set
564 : : * the new maximum length >= the previous maximum length. We can ignore the
565 : : * isExplicit argument, since that only affects truncation cases.
566 : : */
567 : : Datum
2667 568 : 2147 : varchar_support(PG_FUNCTION_ARGS)
569 : : {
570 : 2147 : Node *rawreq = (Node *) PG_GETARG_POINTER(0);
5457 rhaas@postgresql.org 571 : 2147 : Node *ret = NULL;
572 : :
2667 tgl@sss.pgh.pa.us 573 [ + + ]: 2147 : if (IsA(rawreq, SupportRequestSimplify))
574 : : {
575 : 923 : SupportRequestSimplify *req = (SupportRequestSimplify *) rawreq;
576 : 923 : FuncExpr *expr = req->fcall;
577 : : Node *typmod;
578 : :
579 [ - + ]: 923 : Assert(list_length(expr->args) >= 2);
580 : :
581 : 923 : typmod = (Node *) lsecond(expr->args);
582 : :
2205 583 [ + - + - ]: 923 : if (IsA(typmod, Const) && !((Const *) typmod)->constisnull)
584 : : {
2667 585 : 923 : Node *source = (Node *) linitial(expr->args);
586 : 923 : int32 old_typmod = exprTypmod(source);
587 : 923 : int32 new_typmod = DatumGetInt32(((Const *) typmod)->constvalue);
588 : 923 : int32 old_max = old_typmod - VARHDRSZ;
589 : 923 : int32 new_max = new_typmod - VARHDRSZ;
590 : :
591 [ + - + + : 923 : if (new_typmod < 0 || (old_typmod >= 0 && old_max <= new_max))
+ + ]
592 : 20 : ret = relabel_to_typmod(source, new_typmod);
593 : : }
594 : : }
595 : :
5457 rhaas@postgresql.org 596 : 2147 : PG_RETURN_POINTER(ret);
597 : : }
598 : :
599 : : /*
600 : : * Converts a VARCHAR type to the specified size.
601 : : *
602 : : * maxlen is the typmod, ie, declared length plus VARHDRSZ bytes.
603 : : * isExplicit is true if this is for an explicit cast to varchar(N).
604 : : *
605 : : * Truncation rules: for an explicit cast, silently truncate to the given
606 : : * length; for an implicit cast, raise error unless extra characters are
607 : : * all spaces. (This is sort-of per SQL: the spec would actually have us
608 : : * raise a "completion condition" for the explicit cast case, but Postgres
609 : : * hasn't got such a concept.)
610 : : */
611 : : Datum
9482 tgl@sss.pgh.pa.us 612 : 17164 : varchar(PG_FUNCTION_ARGS)
613 : : {
6994 614 : 17164 : VarChar *source = PG_GETARG_VARCHAR_PP(0);
615 : 17164 : int32 typmod = PG_GETARG_INT32(1);
8655 616 : 17164 : bool isExplicit = PG_GETARG_BOOL(2);
617 : : int32 len,
618 : : maxlen;
619 : : size_t maxmblen;
620 : : int i;
621 : : char *s_data;
622 : :
6994 623 [ - + - - : 17164 : len = VARSIZE_ANY_EXHDR(source);
- - - - +
+ ]
624 [ + + ]: 17164 : s_data = VARDATA_ANY(source);
625 : 17164 : maxlen = typmod - VARHDRSZ;
626 : :
627 : : /* No work if typmod is invalid or supplied data fits it already */
628 [ + - + + ]: 17164 : if (maxlen < 0 || len <= maxlen)
9140 peter_e@gmx.net 629 : 17074 : PG_RETURN_VARCHAR_P(source);
630 : :
631 : : /* only reach here if string is too long... */
632 : :
633 : : /* truncate multibyte string preserving multibyte boundary */
6994 tgl@sss.pgh.pa.us 634 : 90 : maxmblen = pg_mbcharcliplen(s_data, len, maxlen);
635 : :
8655 636 [ + + ]: 90 : if (!isExplicit)
637 : : {
6994 638 [ + + ]: 115 : for (i = maxmblen; i < len; i++)
639 [ + + ]: 105 : if (s_data[i] != ' ')
67 peter@eisentraut.org 640 [ + - ]:GNC 56 : ereturn(fcinfo->context, (Datum) 0,
641 : : (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION),
642 : : errmsg("value too long for type character varying(%d)",
643 : : maxlen)));
644 : : }
645 : :
6197 bruce@momjian.us 646 :CBC 34 : PG_RETURN_VARCHAR_P((VarChar *) cstring_to_text_with_len(s_data,
647 : : maxmblen));
648 : : }
649 : :
650 : : Datum
7091 tgl@sss.pgh.pa.us 651 : 1080 : varchartypmodin(PG_FUNCTION_ARGS)
652 : : {
6771 bruce@momjian.us 653 : 1080 : ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0);
654 : :
7091 tgl@sss.pgh.pa.us 655 : 1080 : PG_RETURN_INT32(anychar_typmodin(ta, "varchar"));
656 : : }
657 : :
658 : : Datum
659 : 213 : varchartypmodout(PG_FUNCTION_ARGS)
660 : : {
6771 bruce@momjian.us 661 : 213 : int32 typmod = PG_GETARG_INT32(0);
662 : :
7091 tgl@sss.pgh.pa.us 663 : 213 : PG_RETURN_CSTRING(anychar_typmodout(typmod));
664 : : }
665 : :
666 : :
667 : : /*****************************************************************************
668 : : * Exported functions
669 : : *****************************************************************************/
670 : :
671 : : /* "True" length (not counting trailing blanks) of a BpChar */
672 : : static inline int
9436 673 : 196834 : bcTruelen(BpChar *arg)
674 : : {
3769 rhaas@postgresql.org 675 : 196834 : return bpchartruelen(VARDATA_ANY(arg), VARSIZE_ANY_EXHDR(arg));
[ - + - -
- - - - +
+ + + ]
676 : : }
677 : :
678 : : int
679 : 305256 : bpchartruelen(char *s, int len)
680 : : {
681 : : int i;
682 : :
683 : : /*
684 : : * Note that we rely on the assumption that ' ' is a singleton unit on
685 : : * every supported multibyte server encoding.
686 : : */
10492 bruce@momjian.us 687 [ + + ]: 7128546 : for (i = len - 1; i >= 0; i--)
688 : : {
689 [ + + ]: 7048197 : if (s[i] != ' ')
690 : 224907 : break;
691 : : }
10133 692 : 305256 : return i + 1;
693 : : }
694 : :
695 : : Datum
9436 tgl@sss.pgh.pa.us 696 : 10 : bpcharlen(PG_FUNCTION_ARGS)
697 : : {
6994 698 : 10 : BpChar *arg = PG_GETARG_BPCHAR_PP(0);
699 : : int len;
700 : :
701 : : /* get number of bytes, ignoring trailing spaces */
8154 702 : 10 : len = bcTruelen(arg);
703 : :
704 : : /* in multibyte encoding, convert to number of characters */
705 [ + - ]: 10 : if (pg_database_encoding_max_length() != 1)
6994 706 [ + + ]: 10 : len = pg_mbstrlen_with_len(VARDATA_ANY(arg), len);
707 : :
8154 708 : 10 : PG_RETURN_INT32(len);
709 : : }
710 : :
711 : : Datum
9436 tgl@sss.pgh.pa.us 712 :UBC 0 : bpcharoctetlen(PG_FUNCTION_ARGS)
713 : : {
6771 bruce@momjian.us 714 : 0 : Datum arg = PG_GETARG_DATUM(0);
715 : :
716 : : /* We need not detoast the input at all */
6994 tgl@sss.pgh.pa.us 717 : 0 : PG_RETURN_INT32(toast_raw_datum_size(arg) - VARHDRSZ);
718 : : }
719 : :
720 : :
721 : : /*****************************************************************************
722 : : * Comparison Functions used for bpchar
723 : : *
724 : : * Note: btree indexes need these routines not to leak memory; therefore,
725 : : * be careful to free working copies of toasted datums. Most places don't
726 : : * need to be so careful.
727 : : *****************************************************************************/
728 : :
729 : : static void
2626 peter@eisentraut.org 730 :CBC 16887 : check_collation_set(Oid collid)
731 : : {
732 [ - + ]: 16887 : if (!OidIsValid(collid))
733 : : {
734 : : /*
735 : : * This typically means that the parser could not resolve a conflict
736 : : * of implicit collations, so report it that way.
737 : : */
2626 peter@eisentraut.org 738 [ # # ]:UBC 0 : ereport(ERROR,
739 : : (errcode(ERRCODE_INDETERMINATE_COLLATION),
740 : : errmsg("could not determine which collation to use for string comparison"),
741 : : errhint("Use the COLLATE clause to set the collation explicitly.")));
742 : : }
2626 peter@eisentraut.org 743 :CBC 16887 : }
744 : :
745 : : Datum
9436 tgl@sss.pgh.pa.us 746 : 12591 : bpchareq(PG_FUNCTION_ARGS)
747 : : {
6994 748 : 12591 : BpChar *arg1 = PG_GETARG_BPCHAR_PP(0);
749 : 12591 : BpChar *arg2 = PG_GETARG_BPCHAR_PP(1);
750 : : int len1,
751 : : len2;
752 : : bool result;
2626 peter@eisentraut.org 753 : 12591 : Oid collid = PG_GET_COLLATION();
754 : : pg_locale_t mylocale;
755 : :
756 : 12591 : check_collation_set(collid);
757 : :
10492 bruce@momjian.us 758 : 12591 : len1 = bcTruelen(arg1);
759 : 12591 : len2 = bcTruelen(arg2);
760 : :
633 jdavis@postgresql.or 761 : 12591 : mylocale = pg_newlocale_from_collation(collid);
762 : :
625 763 [ + + ]: 12591 : if (mylocale->deterministic)
764 : : {
765 : : /*
766 : : * Since we only care about equality or not-equality, we can avoid all
767 : : * the expense of strcoll() here, and just do bitwise comparison.
768 : : */
2626 peter@eisentraut.org 769 [ + + ]: 12479 : if (len1 != len2)
770 : 1406 : result = false;
771 : : else
772 [ + + + + ]: 11073 : result = (memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), len1) == 0);
773 : : }
774 : : else
775 : : {
776 [ + + + - ]: 112 : result = (varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2,
777 : : collid) == 0);
778 : : }
779 : :
9436 tgl@sss.pgh.pa.us 780 [ - + ]: 12591 : PG_FREE_IF_COPY(arg1, 0);
781 [ - + ]: 12591 : PG_FREE_IF_COPY(arg2, 1);
782 : :
783 : 12591 : PG_RETURN_BOOL(result);
784 : : }
785 : :
786 : : Datum
787 : 4296 : bpcharne(PG_FUNCTION_ARGS)
788 : : {
6994 789 : 4296 : BpChar *arg1 = PG_GETARG_BPCHAR_PP(0);
790 : 4296 : BpChar *arg2 = PG_GETARG_BPCHAR_PP(1);
791 : : int len1,
792 : : len2;
793 : : bool result;
2626 peter@eisentraut.org 794 : 4296 : Oid collid = PG_GET_COLLATION();
795 : : pg_locale_t mylocale;
796 : :
2390 tgl@sss.pgh.pa.us 797 : 4296 : check_collation_set(collid);
798 : :
10492 bruce@momjian.us 799 : 4296 : len1 = bcTruelen(arg1);
800 : 4296 : len2 = bcTruelen(arg2);
801 : :
633 jdavis@postgresql.or 802 : 4296 : mylocale = pg_newlocale_from_collation(collid);
803 : :
625 804 [ + + ]: 4296 : if (mylocale->deterministic)
805 : : {
806 : : /*
807 : : * Since we only care about equality or not-equality, we can avoid all
808 : : * the expense of strcoll() here, and just do bitwise comparison.
809 : : */
2626 peter@eisentraut.org 810 [ + + ]: 4280 : if (len1 != len2)
811 : 1364 : result = true;
812 : : else
813 [ + + + + ]: 2916 : result = (memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), len1) != 0);
814 : : }
815 : : else
816 : : {
817 [ - + + - ]: 16 : result = (varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2,
818 : : collid) != 0);
819 : : }
820 : :
9436 tgl@sss.pgh.pa.us 821 [ - + ]: 4296 : PG_FREE_IF_COPY(arg1, 0);
822 [ - + ]: 4296 : PG_FREE_IF_COPY(arg2, 1);
823 : :
824 : 4296 : PG_RETURN_BOOL(result);
825 : : }
826 : :
827 : : Datum
828 : 3590 : bpcharlt(PG_FUNCTION_ARGS)
829 : : {
6994 830 : 3590 : BpChar *arg1 = PG_GETARG_BPCHAR_PP(0);
831 : 3590 : BpChar *arg2 = PG_GETARG_BPCHAR_PP(1);
832 : : int len1,
833 : : len2;
834 : : int cmp;
835 : :
10492 bruce@momjian.us 836 : 3590 : len1 = bcTruelen(arg1);
837 : 3590 : len2 = bcTruelen(arg2);
838 : :
5590 peter_e@gmx.net 839 [ + + + + ]: 3590 : cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2,
840 : : PG_GET_COLLATION());
841 : :
9436 tgl@sss.pgh.pa.us 842 [ - + ]: 3590 : PG_FREE_IF_COPY(arg1, 0);
843 [ - + ]: 3590 : PG_FREE_IF_COPY(arg2, 1);
844 : :
845 : 3590 : PG_RETURN_BOOL(cmp < 0);
846 : : }
847 : :
848 : : Datum
849 : 3342 : bpcharle(PG_FUNCTION_ARGS)
850 : : {
6994 851 : 3342 : BpChar *arg1 = PG_GETARG_BPCHAR_PP(0);
852 : 3342 : BpChar *arg2 = PG_GETARG_BPCHAR_PP(1);
853 : : int len1,
854 : : len2;
855 : : int cmp;
856 : :
10492 bruce@momjian.us 857 : 3342 : len1 = bcTruelen(arg1);
858 : 3342 : len2 = bcTruelen(arg2);
859 : :
5590 peter_e@gmx.net 860 [ - + + + ]: 3342 : cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2,
861 : : PG_GET_COLLATION());
862 : :
9436 tgl@sss.pgh.pa.us 863 [ - + ]: 3342 : PG_FREE_IF_COPY(arg1, 0);
864 [ - + ]: 3342 : PG_FREE_IF_COPY(arg2, 1);
865 : :
866 : 3342 : PG_RETURN_BOOL(cmp <= 0);
867 : : }
868 : :
869 : : Datum
870 : 3668 : bpchargt(PG_FUNCTION_ARGS)
871 : : {
6994 872 : 3668 : BpChar *arg1 = PG_GETARG_BPCHAR_PP(0);
873 : 3668 : BpChar *arg2 = PG_GETARG_BPCHAR_PP(1);
874 : : int len1,
875 : : len2;
876 : : int cmp;
877 : :
10492 bruce@momjian.us 878 : 3668 : len1 = bcTruelen(arg1);
879 : 3668 : len2 = bcTruelen(arg2);
880 : :
5590 peter_e@gmx.net 881 [ + + + + ]: 3668 : cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2,
882 : : PG_GET_COLLATION());
883 : :
9436 tgl@sss.pgh.pa.us 884 [ - + ]: 3668 : PG_FREE_IF_COPY(arg1, 0);
885 [ - + ]: 3668 : PG_FREE_IF_COPY(arg2, 1);
886 : :
887 : 3668 : PG_RETURN_BOOL(cmp > 0);
888 : : }
889 : :
890 : : Datum
891 : 3338 : bpcharge(PG_FUNCTION_ARGS)
892 : : {
6994 893 : 3338 : BpChar *arg1 = PG_GETARG_BPCHAR_PP(0);
894 : 3338 : BpChar *arg2 = PG_GETARG_BPCHAR_PP(1);
895 : : int len1,
896 : : len2;
897 : : int cmp;
898 : :
10492 bruce@momjian.us 899 : 3338 : len1 = bcTruelen(arg1);
900 : 3338 : len2 = bcTruelen(arg2);
901 : :
5590 peter_e@gmx.net 902 [ - + + + ]: 3338 : cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2,
903 : : PG_GET_COLLATION());
904 : :
9436 tgl@sss.pgh.pa.us 905 [ - + ]: 3338 : PG_FREE_IF_COPY(arg1, 0);
906 [ - + ]: 3338 : PG_FREE_IF_COPY(arg2, 1);
907 : :
908 : 3338 : PG_RETURN_BOOL(cmp >= 0);
909 : : }
910 : :
911 : : Datum
912 : 66021 : bpcharcmp(PG_FUNCTION_ARGS)
913 : : {
6994 914 : 66021 : BpChar *arg1 = PG_GETARG_BPCHAR_PP(0);
915 : 66021 : BpChar *arg2 = PG_GETARG_BPCHAR_PP(1);
916 : : int len1,
917 : : len2;
918 : : int cmp;
919 : :
10492 bruce@momjian.us 920 : 66021 : len1 = bcTruelen(arg1);
921 : 66021 : len2 = bcTruelen(arg2);
922 : :
5590 peter_e@gmx.net 923 [ + + + + ]: 66021 : cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2,
924 : : PG_GET_COLLATION());
925 : :
9436 tgl@sss.pgh.pa.us 926 [ - + ]: 66021 : PG_FREE_IF_COPY(arg1, 0);
927 [ - + ]: 66021 : PG_FREE_IF_COPY(arg2, 1);
928 : :
929 : 66021 : PG_RETURN_INT32(cmp);
930 : : }
931 : :
932 : : Datum
3769 rhaas@postgresql.org 933 : 603 : bpchar_sortsupport(PG_FUNCTION_ARGS)
934 : : {
935 : 603 : SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
936 : 603 : Oid collid = ssup->ssup_collation;
937 : : MemoryContext oldcontext;
938 : :
939 : 603 : oldcontext = MemoryContextSwitchTo(ssup->ssup_cxt);
940 : :
941 : : /* Use generic string SortSupport */
2719 tgl@sss.pgh.pa.us 942 : 603 : varstr_sortsupport(ssup, BPCHAROID, collid);
943 : :
3769 rhaas@postgresql.org 944 : 603 : MemoryContextSwitchTo(oldcontext);
945 : :
946 : 603 : PG_RETURN_VOID();
947 : : }
948 : :
949 : : Datum
7718 tgl@sss.pgh.pa.us 950 :UBC 0 : bpchar_larger(PG_FUNCTION_ARGS)
951 : : {
6994 952 : 0 : BpChar *arg1 = PG_GETARG_BPCHAR_PP(0);
953 : 0 : BpChar *arg2 = PG_GETARG_BPCHAR_PP(1);
954 : : int len1,
955 : : len2;
956 : : int cmp;
957 : :
7718 958 : 0 : len1 = bcTruelen(arg1);
959 : 0 : len2 = bcTruelen(arg2);
960 : :
5590 peter_e@gmx.net 961 [ # # # # ]: 0 : cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2,
962 : : PG_GET_COLLATION());
963 : :
7718 tgl@sss.pgh.pa.us 964 [ # # ]: 0 : PG_RETURN_BPCHAR_P((cmp >= 0) ? arg1 : arg2);
965 : : }
966 : :
967 : : Datum
968 : 0 : bpchar_smaller(PG_FUNCTION_ARGS)
969 : : {
6994 970 : 0 : BpChar *arg1 = PG_GETARG_BPCHAR_PP(0);
971 : 0 : BpChar *arg2 = PG_GETARG_BPCHAR_PP(1);
972 : : int len1,
973 : : len2;
974 : : int cmp;
975 : :
7718 976 : 0 : len1 = bcTruelen(arg1);
977 : 0 : len2 = bcTruelen(arg2);
978 : :
5590 peter_e@gmx.net 979 [ # # # # ]: 0 : cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2,
980 : : PG_GET_COLLATION());
981 : :
7718 tgl@sss.pgh.pa.us 982 [ # # ]: 0 : PG_RETURN_BPCHAR_P((cmp <= 0) ? arg1 : arg2);
983 : : }
984 : :
985 : :
986 : : /*
987 : : * bpchar needs a specialized hash function because we want to ignore
988 : : * trailing blanks in comparisons.
989 : : */
990 : : Datum
9436 tgl@sss.pgh.pa.us 991 :CBC 2924 : hashbpchar(PG_FUNCTION_ARGS)
992 : : {
6994 993 : 2924 : BpChar *key = PG_GETARG_BPCHAR_PP(0);
2626 peter@eisentraut.org 994 : 2924 : Oid collid = PG_GET_COLLATION();
995 : : char *keydata;
996 : : int keylen;
997 : : pg_locale_t mylocale;
998 : : Datum result;
999 : :
1000 [ - + ]: 2924 : if (!collid)
2626 peter@eisentraut.org 1001 [ # # ]:UBC 0 : ereport(ERROR,
1002 : : (errcode(ERRCODE_INDETERMINATE_COLLATION),
1003 : : errmsg("could not determine which collation to use for string hashing"),
1004 : : errhint("Use the COLLATE clause to set the collation explicitly.")));
1005 : :
6994 tgl@sss.pgh.pa.us 1006 [ + + ]:CBC 2924 : keydata = VARDATA_ANY(key);
9436 1007 : 2924 : keylen = bcTruelen(key);
1008 : :
663 jdavis@postgresql.or 1009 : 2924 : mylocale = pg_newlocale_from_collation(collid);
1010 : :
625 1011 [ + + ]: 2924 : if (mylocale->deterministic)
1012 : : {
2626 peter@eisentraut.org 1013 : 2812 : result = hash_any((unsigned char *) keydata, keylen);
1014 : : }
1015 : : else
1016 : : {
1017 : : Size bsize,
1018 : : rsize;
1019 : : char *buf;
1020 : :
1192 jdavis@postgresql.or 1021 : 112 : bsize = pg_strnxfrm(NULL, 0, keydata, keylen, mylocale);
1022 : 112 : buf = palloc(bsize + 1);
1023 : :
1024 : 112 : rsize = pg_strnxfrm(buf, bsize + 1, keydata, keylen, mylocale);
1025 : :
1026 : : /* the second call may return a smaller value than the first */
669 1027 [ - + ]: 112 : if (rsize > bsize)
1192 jdavis@postgresql.or 1028 [ # # ]:UBC 0 : elog(ERROR, "pg_strnxfrm() returned unexpected result");
1029 : :
1030 : : /*
1031 : : * In principle, there's no reason to include the terminating NUL
1032 : : * character in the hash, but it was done before and the behavior must
1033 : : * be preserved.
1034 : : */
1192 jdavis@postgresql.or 1035 :CBC 112 : result = hash_any((uint8_t *) buf, bsize + 1);
1036 : :
1037 : 112 : pfree(buf);
1038 : : }
1039 : :
1040 : : /* Avoid leaking memory for toasted inputs */
9304 tgl@sss.pgh.pa.us 1041 [ - + ]: 2924 : PG_FREE_IF_COPY(key, 0);
1042 : :
1043 : 2924 : return result;
1044 : : }
1045 : :
1046 : : Datum
3194 rhaas@postgresql.org 1047 : 56 : hashbpcharextended(PG_FUNCTION_ARGS)
1048 : : {
1049 : 56 : BpChar *key = PG_GETARG_BPCHAR_PP(0);
2626 peter@eisentraut.org 1050 : 56 : Oid collid = PG_GET_COLLATION();
1051 : : char *keydata;
1052 : : int keylen;
1053 : : pg_locale_t mylocale;
1054 : : Datum result;
1055 : :
1056 [ - + ]: 56 : if (!collid)
2626 peter@eisentraut.org 1057 [ # # ]:UBC 0 : ereport(ERROR,
1058 : : (errcode(ERRCODE_INDETERMINATE_COLLATION),
1059 : : errmsg("could not determine which collation to use for string hashing"),
1060 : : errhint("Use the COLLATE clause to set the collation explicitly.")));
1061 : :
3194 rhaas@postgresql.org 1062 [ - + ]:CBC 56 : keydata = VARDATA_ANY(key);
1063 : 56 : keylen = bcTruelen(key);
1064 : :
663 jdavis@postgresql.or 1065 : 56 : mylocale = pg_newlocale_from_collation(collid);
1066 : :
625 1067 [ + + ]: 56 : if (mylocale->deterministic)
1068 : : {
2626 peter@eisentraut.org 1069 : 48 : result = hash_any_extended((unsigned char *) keydata, keylen,
1070 : 48 : PG_GETARG_INT64(1));
1071 : : }
1072 : : else
1073 : : {
1074 : : Size bsize,
1075 : : rsize;
1076 : : char *buf;
1077 : :
1192 jdavis@postgresql.or 1078 : 8 : bsize = pg_strnxfrm(NULL, 0, keydata, keylen, mylocale);
1079 : 8 : buf = palloc(bsize + 1);
1080 : :
1081 : 8 : rsize = pg_strnxfrm(buf, bsize + 1, keydata, keylen, mylocale);
1082 : :
1083 : : /* the second call may return a smaller value than the first */
669 1084 [ - + ]: 8 : if (rsize > bsize)
1192 jdavis@postgresql.or 1085 [ # # ]:UBC 0 : elog(ERROR, "pg_strnxfrm() returned unexpected result");
1086 : :
1087 : : /*
1088 : : * In principle, there's no reason to include the terminating NUL
1089 : : * character in the hash, but it was done before and the behavior must
1090 : : * be preserved.
1091 : : */
1192 jdavis@postgresql.or 1092 :CBC 8 : result = hash_any_extended((uint8_t *) buf, bsize + 1,
1093 : 8 : PG_GETARG_INT64(1));
1094 : :
1095 : 8 : pfree(buf);
1096 : : }
1097 : :
3194 rhaas@postgresql.org 1098 [ - + ]: 56 : PG_FREE_IF_COPY(key, 0);
1099 : :
1100 : 56 : return result;
1101 : : }
1102 : :
1103 : : /*
1104 : : * The following operators support character-by-character comparison
1105 : : * of bpchar datums, to allow building indexes suitable for LIKE clauses.
1106 : : * Note that the regular bpchareq/bpcharne comparison operators, and
1107 : : * regular support functions 1 and 2 with "C" collation are assumed to be
1108 : : * compatible with these!
1109 : : */
1110 : :
1111 : : static int
2443 tgl@sss.pgh.pa.us 1112 : 76 : internal_bpchar_pattern_compare(BpChar *arg1, BpChar *arg2)
1113 : : {
1114 : : int result;
1115 : : int len1,
1116 : : len2;
1117 : :
6577 1118 : 76 : len1 = bcTruelen(arg1);
1119 : 76 : len2 = bcTruelen(arg2);
1120 : :
5639 rhaas@postgresql.org 1121 [ + - + - ]: 76 : result = memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), Min(len1, len2));
6577 tgl@sss.pgh.pa.us 1122 [ + + ]: 76 : if (result != 0)
1123 : 44 : return result;
1124 [ - + ]: 32 : else if (len1 < len2)
6577 tgl@sss.pgh.pa.us 1125 :UBC 0 : return -1;
6577 tgl@sss.pgh.pa.us 1126 [ - + ]:CBC 32 : else if (len1 > len2)
6577 tgl@sss.pgh.pa.us 1127 :UBC 0 : return 1;
1128 : : else
6577 tgl@sss.pgh.pa.us 1129 :CBC 32 : return 0;
1130 : : }
1131 : :
1132 : :
1133 : : Datum
6577 tgl@sss.pgh.pa.us 1134 :UBC 0 : bpchar_pattern_lt(PG_FUNCTION_ARGS)
1135 : : {
1136 : 0 : BpChar *arg1 = PG_GETARG_BPCHAR_PP(0);
1137 : 0 : BpChar *arg2 = PG_GETARG_BPCHAR_PP(1);
1138 : : int result;
1139 : :
2443 1140 : 0 : result = internal_bpchar_pattern_compare(arg1, arg2);
1141 : :
6577 1142 [ # # ]: 0 : PG_FREE_IF_COPY(arg1, 0);
1143 [ # # ]: 0 : PG_FREE_IF_COPY(arg2, 1);
1144 : :
1145 : 0 : PG_RETURN_BOOL(result < 0);
1146 : : }
1147 : :
1148 : :
1149 : : Datum
1150 : 0 : bpchar_pattern_le(PG_FUNCTION_ARGS)
1151 : : {
1152 : 0 : BpChar *arg1 = PG_GETARG_BPCHAR_PP(0);
1153 : 0 : BpChar *arg2 = PG_GETARG_BPCHAR_PP(1);
1154 : : int result;
1155 : :
2443 1156 : 0 : result = internal_bpchar_pattern_compare(arg1, arg2);
1157 : :
6577 1158 [ # # ]: 0 : PG_FREE_IF_COPY(arg1, 0);
1159 [ # # ]: 0 : PG_FREE_IF_COPY(arg2, 1);
1160 : :
1161 : 0 : PG_RETURN_BOOL(result <= 0);
1162 : : }
1163 : :
1164 : :
1165 : : Datum
1166 : 0 : bpchar_pattern_ge(PG_FUNCTION_ARGS)
1167 : : {
1168 : 0 : BpChar *arg1 = PG_GETARG_BPCHAR_PP(0);
1169 : 0 : BpChar *arg2 = PG_GETARG_BPCHAR_PP(1);
1170 : : int result;
1171 : :
2443 1172 : 0 : result = internal_bpchar_pattern_compare(arg1, arg2);
1173 : :
6577 1174 [ # # ]: 0 : PG_FREE_IF_COPY(arg1, 0);
1175 [ # # ]: 0 : PG_FREE_IF_COPY(arg2, 1);
1176 : :
1177 : 0 : PG_RETURN_BOOL(result >= 0);
1178 : : }
1179 : :
1180 : :
1181 : : Datum
1182 : 0 : bpchar_pattern_gt(PG_FUNCTION_ARGS)
1183 : : {
1184 : 0 : BpChar *arg1 = PG_GETARG_BPCHAR_PP(0);
1185 : 0 : BpChar *arg2 = PG_GETARG_BPCHAR_PP(1);
1186 : : int result;
1187 : :
2443 1188 : 0 : result = internal_bpchar_pattern_compare(arg1, arg2);
1189 : :
6577 1190 [ # # ]: 0 : PG_FREE_IF_COPY(arg1, 0);
1191 [ # # ]: 0 : PG_FREE_IF_COPY(arg2, 1);
1192 : :
1193 : 0 : PG_RETURN_BOOL(result > 0);
1194 : : }
1195 : :
1196 : :
1197 : : Datum
6577 tgl@sss.pgh.pa.us 1198 :CBC 76 : btbpchar_pattern_cmp(PG_FUNCTION_ARGS)
1199 : : {
1200 : 76 : BpChar *arg1 = PG_GETARG_BPCHAR_PP(0);
1201 : 76 : BpChar *arg2 = PG_GETARG_BPCHAR_PP(1);
1202 : : int result;
1203 : :
2443 1204 : 76 : result = internal_bpchar_pattern_compare(arg1, arg2);
1205 : :
6577 1206 [ - + ]: 76 : PG_FREE_IF_COPY(arg1, 0);
1207 [ - + ]: 76 : PG_FREE_IF_COPY(arg2, 1);
1208 : :
1209 : 76 : PG_RETURN_INT32(result);
1210 : : }
1211 : :
1212 : :
1213 : : Datum
3769 rhaas@postgresql.org 1214 : 8 : btbpchar_pattern_sortsupport(PG_FUNCTION_ARGS)
1215 : : {
1216 : 8 : SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
1217 : : MemoryContext oldcontext;
1218 : :
1219 : 8 : oldcontext = MemoryContextSwitchTo(ssup->ssup_cxt);
1220 : :
1221 : : /* Use generic string SortSupport, forcing "C" collation */
2719 tgl@sss.pgh.pa.us 1222 : 8 : varstr_sortsupport(ssup, BPCHAROID, C_COLLATION_OID);
1223 : :
3769 rhaas@postgresql.org 1224 : 8 : MemoryContextSwitchTo(oldcontext);
1225 : :
1226 : 8 : PG_RETURN_VOID();
1227 : : }
|