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-2024, 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
6315 tgl@sss.pgh.pa.us 33 :CBC 1749 : anychar_typmodin(ArrayType *ta, const char *typename)
34 : : {
35 : : int32 typmod;
36 : : int32 *tl;
37 : : int n;
38 : :
6148 39 : 1749 : 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 : : */
6315 45 [ - + ]: 1749 : if (n != 1)
6315 tgl@sss.pgh.pa.us 46 [ # # ]:UBC 0 : ereport(ERROR,
47 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
48 : : errmsg("invalid type modifier")));
49 : :
6315 tgl@sss.pgh.pa.us 50 [ - + ]:CBC 1749 : if (*tl < 1)
6315 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)));
6315 tgl@sss.pgh.pa.us 54 [ - + ]:CBC 1749 : if (*tl > MaxAttrSize)
6315 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 : : */
6315 tgl@sss.pgh.pa.us 65 :CBC 1749 : typmod = VARHDRSZ + *tl;
66 : :
67 : 1749 : return typmod;
68 : : }
69 : :
70 : : /* common code for bpchartypmodout and varchartypmodout */
71 : : static char *
72 : 503 : anychar_typmodout(int32 typmod)
73 : : {
5995 bruce@momjian.us 74 : 503 : char *res = (char *) palloc(64);
75 : :
6315 tgl@sss.pgh.pa.us 76 [ + - ]: 503 : if (typmod > VARHDRSZ)
77 : 503 : snprintf(res, 64, "(%d)", (int) (typmod - VARHDRSZ));
78 : : else
6315 tgl@sss.pgh.pa.us 79 :UBC 0 : *res = '\0';
80 : :
6315 tgl@sss.pgh.pa.us 81 :CBC 503 : 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 *
487 130 : 210618 : 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 */
8353 137 [ + + ]: 210618 : if (atttypmod < (int32) VARHDRSZ)
6895 138 : 4346 : maxlen = len;
139 : : else
140 : : {
141 : : size_t charlen; /* number of CHARACTERS in the input */
142 : :
143 : 206272 : maxlen = atttypmod - VARHDRSZ;
6853 144 : 206272 : charlen = pg_mbstrlen_with_len(s, len);
6895 145 [ + + ]: 206272 : if (charlen > maxlen)
146 : : {
147 : : /* Verify that extra characters are spaces, and clip them off */
148 : 27 : 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 : : */
6853 156 [ + + ]: 33 : for (j = mbmaxlen; j < len; j++)
157 : : {
158 [ + + ]: 30 : if (s[j] != ' ')
487 159 [ + + ]: 24 : ereturn(escontext, NULL,
160 : : (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION),
161 : : errmsg("value too long for type character(%d)",
162 : : (int) maxlen)));
163 : : }
164 : :
165 : : /*
166 : : * Now we set maxlen to the necessary byte length, not the number
167 : : * of CHARACTERS!
168 : : */
6853 169 : 3 : 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 : : */
6895 177 : 206245 : maxlen = len + (maxlen - charlen);
178 : : }
179 : : }
180 : :
6853 181 : 210594 : result = (BpChar *) palloc(maxlen + VARHDRSZ);
6256 182 : 210594 : SET_VARSIZE(result, maxlen + VARHDRSZ);
9594 bruce@momjian.us 183 : 210594 : r = VARDATA(result);
6895 tgl@sss.pgh.pa.us 184 : 210594 : memcpy(r, s, len);
185 : :
186 : : /* blank pad the string if necessary */
187 [ + + ]: 210594 : if (maxlen > len)
188 : 201086 : memset(r + len, ' ', maxlen - len);
189 : :
6853 190 : 210594 : 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 : 210618 : bpcharin(PG_FUNCTION_ARGS)
199 : : {
200 : 210618 : char *s = PG_GETARG_CSTRING(0);
201 : : #ifdef NOT_USED
202 : : Oid typelem = PG_GETARG_OID(1);
203 : : #endif
204 : 210618 : int32 atttypmod = PG_GETARG_INT32(2);
205 : : BpChar *result;
206 : :
487 207 : 210618 : result = bpchar_input(s, strlen(s), atttypmod, fcinfo->context);
8706 208 : 210603 : 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 : 22257 : bpcharout(PG_FUNCTION_ARGS)
220 : : {
5864 221 : 22257 : Datum txt = PG_GETARG_DATUM(0);
222 : :
223 : 22257 : PG_RETURN_CSTRING(TextDatumGetCString(txt));
224 : : }
225 : :
226 : : /*
227 : : * bpcharrecv - converts external binary format to bpchar
228 : : */
229 : : Datum
7643 tgl@sss.pgh.pa.us 230 :UBC 0 : bpcharrecv(PG_FUNCTION_ARGS)
231 : : {
6853 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);
487 242 : 0 : result = bpchar_input(str, nbytes, atttypmod, NULL);
6853 243 : 0 : pfree(str);
244 : 0 : PG_RETURN_BPCHAR_P(result);
245 : : }
246 : :
247 : : /*
248 : : * bpcharsend - converts bpchar to binary format
249 : : */
250 : : Datum
7643 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
8706 271 : 6107 : bpchar(PG_FUNCTION_ARGS)
272 : : {
6218 273 : 6107 : BpChar *source = PG_GETARG_BPCHAR_PP(0);
8364 peter_e@gmx.net 274 : 6107 : int32 maxlen = PG_GETARG_INT32(1);
7879 tgl@sss.pgh.pa.us 275 : 6107 : 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 */
6895 285 [ - + ]: 6107 : if (maxlen < (int32) VARHDRSZ)
6895 tgl@sss.pgh.pa.us 286 :UBC 0 : PG_RETURN_BPCHAR_P(source);
287 : :
6218 tgl@sss.pgh.pa.us 288 :CBC 6107 : maxlen -= VARHDRSZ;
289 : :
290 [ - + - - : 6107 : len = VARSIZE_ANY_EXHDR(source);
- - - - +
+ ]
291 [ + + ]: 6107 : s = VARDATA_ANY(source);
292 : :
293 : 6107 : charlen = pg_mbstrlen_with_len(s, len);
294 : :
295 : : /* No work if supplied data matches typmod already */
6895 296 [ + + ]: 6107 : if (charlen == maxlen)
8364 peter_e@gmx.net 297 : 2796 : PG_RETURN_BPCHAR_P(source);
298 : :
8309 ishii@postgresql.org 299 [ + + ]: 3311 : if (charlen > maxlen)
300 : : {
301 : : /* Verify that extra characters are spaces, and clip them off */
302 : : size_t maxmblen;
303 : :
6218 tgl@sss.pgh.pa.us 304 : 69 : maxmblen = pg_mbcharcliplen(s, len, maxlen);
305 : :
7879 306 [ + + ]: 69 : if (!isExplicit)
307 : : {
6218 308 [ + + ]: 42 : for (i = maxmblen; i < len; i++)
309 [ + + ]: 36 : if (s[i] != ' ')
7567 310 [ + - ]: 9 : ereport(ERROR,
311 : : (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION),
312 : : errmsg("value too long for type character(%d)",
313 : : maxlen)));
314 : : }
315 : :
8364 peter_e@gmx.net 316 : 60 : len = maxmblen;
317 : :
318 : : /*
319 : : * At this point, maxlen is the necessary byte length, not the number
320 : : * of CHARACTERS!
321 : : */
8309 ishii@postgresql.org 322 : 60 : 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 : 3242 : maxlen = len + (maxlen - charlen);
331 : : }
332 : :
6218 tgl@sss.pgh.pa.us 333 [ - + ]: 3302 : Assert(maxlen >= len);
334 : :
5995 bruce@momjian.us 335 : 3302 : result = palloc(maxlen + VARHDRSZ);
336 : 3302 : SET_VARSIZE(result, maxlen + VARHDRSZ);
8364 peter_e@gmx.net 337 : 3302 : r = VARDATA(result);
338 : :
6218 tgl@sss.pgh.pa.us 339 : 3302 : memcpy(r, s, len);
340 : :
341 : : /* blank pad the string if necessary */
6895 342 [ + + ]: 3302 : if (maxlen > len)
6218 343 : 3242 : memset(r + len, ' ', maxlen - len);
344 : :
8706 345 : 3302 : PG_RETURN_BPCHAR_P(result);
346 : : }
347 : :
348 : :
349 : : /* char_bpchar()
350 : : * Convert char to bpchar(1).
351 : : */
352 : : Datum
8714 tgl@sss.pgh.pa.us 353 :UBC 0 : char_bpchar(PG_FUNCTION_ARGS)
354 : : {
355 : 0 : char c = PG_GETARG_CHAR(0);
356 : : BpChar *result;
357 : :
8706 358 : 0 : result = (BpChar *) palloc(VARHDRSZ + 1);
359 : :
6256 360 : 0 : SET_VARSIZE(result, VARHDRSZ + 1);
8714 361 : 0 : *(VARDATA(result)) = c;
362 : :
363 : 0 : PG_RETURN_BPCHAR_P(result);
364 : : }
365 : :
366 : :
367 : : /* bpchar_name()
368 : : * Converts a bpchar() type to a NameData type.
369 : : */
370 : : Datum
8660 371 : 0 : bpchar_name(PG_FUNCTION_ARGS)
372 : : {
6218 373 : 0 : BpChar *s = PG_GETARG_BPCHAR_PP(0);
374 : : char *s_data;
375 : : Name result;
376 : : int len;
377 : :
378 [ # # # # : 0 : len = VARSIZE_ANY_EXHDR(s);
# # # # #
# ]
379 [ # # ]: 0 : s_data = VARDATA_ANY(s);
380 : :
381 : : /* Truncate oversize input */
8682 382 [ # # ]: 0 : if (len >= NAMEDATALEN)
4342 383 : 0 : len = pg_mbcliplen(s_data, len, NAMEDATALEN - 1);
384 : :
385 : : /* Remove trailing blanks */
9357 bruce@momjian.us 386 [ # # ]: 0 : while (len > 0)
387 : : {
6218 tgl@sss.pgh.pa.us 388 [ # # ]: 0 : if (s_data[len - 1] != ' ')
9357 bruce@momjian.us 389 : 0 : break;
9452 lockhart@fourpalms.o 390 : 0 : len--;
391 : : }
392 : :
393 : : /* We use palloc0 here to ensure result is zero-padded */
4342 tgl@sss.pgh.pa.us 394 : 0 : result = (Name) palloc0(NAMEDATALEN);
6218 395 : 0 : memcpy(NameStr(*result), s_data, len);
396 : :
8660 397 : 0 : PG_RETURN_NAME(result);
398 : : }
399 : :
400 : : /* name_bpchar()
401 : : * Converts a NameData type to a bpchar type.
402 : : *
403 : : * Uses the text conversion functions, which is only appropriate if BpChar
404 : : * and text are equivalent types.
405 : : */
406 : : Datum
8660 tgl@sss.pgh.pa.us 407 :CBC 3 : name_bpchar(PG_FUNCTION_ARGS)
408 : : {
409 : 3 : Name s = PG_GETARG_NAME(0);
410 : : BpChar *result;
411 : :
5864 412 : 3 : result = (BpChar *) cstring_to_text(NameStr(*s));
8660 413 : 3 : PG_RETURN_BPCHAR_P(result);
414 : : }
415 : :
416 : : Datum
6315 417 : 1044 : bpchartypmodin(PG_FUNCTION_ARGS)
418 : : {
5995 bruce@momjian.us 419 : 1044 : ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0);
420 : :
6315 tgl@sss.pgh.pa.us 421 : 1044 : PG_RETURN_INT32(anychar_typmodin(ta, "char"));
422 : : }
423 : :
424 : : Datum
425 : 407 : bpchartypmodout(PG_FUNCTION_ARGS)
426 : : {
5995 bruce@momjian.us 427 : 407 : int32 typmod = PG_GETARG_INT32(0);
428 : :
6315 tgl@sss.pgh.pa.us 429 : 407 : PG_RETURN_CSTRING(anychar_typmodout(typmod));
430 : : }
431 : :
432 : :
433 : : /*****************************************************************************
434 : : * varchar - varchar(n)
435 : : *
436 : : * Note: varchar piggybacks on type text for most operations, and so has no
437 : : * C-coded functions except for I/O and typmod checking.
438 : : *****************************************************************************/
439 : :
440 : : /*
441 : : * varchar_input -- common guts of varcharin and varcharrecv
442 : : *
443 : : * s is the input text of length len (may not be null-terminated)
444 : : * atttypmod is the typmod value to apply
445 : : *
446 : : * Note that atttypmod is measured in characters, which
447 : : * is not necessarily the same as the number of bytes.
448 : : *
449 : : * If the input string is too long, raise an error, unless the extra
450 : : * characters are spaces, in which case they're truncated. (per SQL)
451 : : *
452 : : * If escontext points to an ErrorSaveContext node, that is filled instead
453 : : * of throwing an error; the caller must check SOFT_ERROR_OCCURRED()
454 : : * to detect errors.
455 : : */
456 : : static VarChar *
487 457 : 239239 : varchar_input(const char *s, size_t len, int32 atttypmod, Node *escontext)
458 : : {
459 : : VarChar *result;
460 : : size_t maxlen;
461 : :
8364 peter_e@gmx.net 462 : 239239 : maxlen = atttypmod - VARHDRSZ;
463 : :
464 [ + + + + ]: 239239 : if (atttypmod >= (int32) VARHDRSZ && len > maxlen)
465 : : {
466 : : /* Verify that extra characters are spaces, and clip them off */
8207 bruce@momjian.us 467 : 15 : size_t mbmaxlen = pg_mbcharcliplen(s, len, maxlen);
468 : : size_t j;
469 : :
6853 tgl@sss.pgh.pa.us 470 [ + + ]: 21 : for (j = mbmaxlen; j < len; j++)
471 : : {
472 [ + + ]: 18 : if (s[j] != ' ')
487 473 [ + + ]: 12 : ereturn(escontext, NULL,
474 : : (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION),
475 : : errmsg("value too long for type character varying(%d)",
476 : : (int) maxlen)));
477 : : }
478 : :
6853 479 : 3 : len = mbmaxlen;
480 : : }
481 : :
482 : : /*
483 : : * We can use cstring_to_text_with_len because VarChar and text are
484 : : * binary-compatible types.
485 : : */
5864 486 : 239227 : result = (VarChar *) cstring_to_text_with_len(s, len);
6853 487 : 239227 : return result;
488 : : }
489 : :
490 : : /*
491 : : * Convert a C string to VARCHAR internal representation. atttypmod
492 : : * is the declared length of the type plus VARHDRSZ.
493 : : */
494 : : Datum
495 : 239238 : varcharin(PG_FUNCTION_ARGS)
496 : : {
497 : 239238 : char *s = PG_GETARG_CSTRING(0);
498 : : #ifdef NOT_USED
499 : : Oid typelem = PG_GETARG_OID(1);
500 : : #endif
501 : 239238 : int32 atttypmod = PG_GETARG_INT32(2);
502 : : VarChar *result;
503 : :
487 504 : 239238 : result = varchar_input(s, strlen(s), atttypmod, fcinfo->context);
8706 505 : 239232 : PG_RETURN_VARCHAR_P(result);
506 : : }
507 : :
508 : :
509 : : /*
510 : : * Convert a VARCHAR value to a C string.
511 : : *
512 : : * Uses the text to C string conversion function, which is only appropriate
513 : : * if VarChar and text are equivalent types.
514 : : */
515 : : Datum
516 : 91120 : varcharout(PG_FUNCTION_ARGS)
517 : : {
5864 518 : 91120 : Datum txt = PG_GETARG_DATUM(0);
519 : :
520 : 91120 : PG_RETURN_CSTRING(TextDatumGetCString(txt));
521 : : }
522 : :
523 : : /*
524 : : * varcharrecv - converts external binary format to varchar
525 : : */
526 : : Datum
7643 527 : 1 : varcharrecv(PG_FUNCTION_ARGS)
528 : : {
6853 529 : 1 : StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
530 : : #ifdef NOT_USED
531 : : Oid typelem = PG_GETARG_OID(1);
532 : : #endif
533 : 1 : int32 atttypmod = PG_GETARG_INT32(2);
534 : : VarChar *result;
535 : : char *str;
536 : : int nbytes;
537 : :
538 : 1 : str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
487 539 : 1 : result = varchar_input(str, nbytes, atttypmod, NULL);
6853 540 : 1 : pfree(str);
541 : 1 : PG_RETURN_VARCHAR_P(result);
542 : : }
543 : :
544 : : /*
545 : : * varcharsend - converts varchar to binary format
546 : : */
547 : : Datum
7643 548 : 1 : varcharsend(PG_FUNCTION_ARGS)
549 : : {
550 : : /* Exactly the same as textsend, so share code */
551 : 1 : return textsend(fcinfo);
552 : : }
553 : :
554 : :
555 : : /*
556 : : * varchar_support()
557 : : *
558 : : * Planner support function for the varchar() length coercion function.
559 : : *
560 : : * Currently, the only interesting thing we can do is flatten calls that set
561 : : * the new maximum length >= the previous maximum length. We can ignore the
562 : : * isExplicit argument, since that only affects truncation cases.
563 : : */
564 : : Datum
1891 565 : 1157 : varchar_support(PG_FUNCTION_ARGS)
566 : : {
567 : 1157 : Node *rawreq = (Node *) PG_GETARG_POINTER(0);
4681 rhaas@postgresql.org 568 : 1157 : Node *ret = NULL;
569 : :
1891 tgl@sss.pgh.pa.us 570 [ + + ]: 1157 : if (IsA(rawreq, SupportRequestSimplify))
571 : : {
572 : 517 : SupportRequestSimplify *req = (SupportRequestSimplify *) rawreq;
573 : 517 : FuncExpr *expr = req->fcall;
574 : : Node *typmod;
575 : :
576 [ - + ]: 517 : Assert(list_length(expr->args) >= 2);
577 : :
578 : 517 : typmod = (Node *) lsecond(expr->args);
579 : :
1429 580 [ + - + - ]: 517 : if (IsA(typmod, Const) && !((Const *) typmod)->constisnull)
581 : : {
1891 582 : 517 : Node *source = (Node *) linitial(expr->args);
583 : 517 : int32 old_typmod = exprTypmod(source);
584 : 517 : int32 new_typmod = DatumGetInt32(((Const *) typmod)->constvalue);
585 : 517 : int32 old_max = old_typmod - VARHDRSZ;
586 : 517 : int32 new_max = new_typmod - VARHDRSZ;
587 : :
588 [ + - + + : 517 : if (new_typmod < 0 || (old_typmod >= 0 && old_max <= new_max))
+ - ]
589 : 15 : ret = relabel_to_typmod(source, new_typmod);
590 : : }
591 : : }
592 : :
4681 rhaas@postgresql.org 593 : 1157 : PG_RETURN_POINTER(ret);
594 : : }
595 : :
596 : : /*
597 : : * Converts a VARCHAR type to the specified size.
598 : : *
599 : : * maxlen is the typmod, ie, declared length plus VARHDRSZ bytes.
600 : : * isExplicit is true if this is for an explicit cast to varchar(N).
601 : : *
602 : : * Truncation rules: for an explicit cast, silently truncate to the given
603 : : * length; for an implicit cast, raise error unless extra characters are
604 : : * all spaces. (This is sort-of per SQL: the spec would actually have us
605 : : * raise a "completion condition" for the explicit cast case, but Postgres
606 : : * hasn't got such a concept.)
607 : : */
608 : : Datum
8706 tgl@sss.pgh.pa.us 609 : 11780 : varchar(PG_FUNCTION_ARGS)
610 : : {
6218 611 : 11780 : VarChar *source = PG_GETARG_VARCHAR_PP(0);
612 : 11780 : int32 typmod = PG_GETARG_INT32(1);
7879 613 : 11780 : bool isExplicit = PG_GETARG_BOOL(2);
614 : : int32 len,
615 : : maxlen;
616 : : size_t maxmblen;
617 : : int i;
618 : : char *s_data;
619 : :
6218 620 [ - + - - : 11780 : len = VARSIZE_ANY_EXHDR(source);
- - - - +
+ ]
621 [ + + ]: 11780 : s_data = VARDATA_ANY(source);
622 : 11780 : maxlen = typmod - VARHDRSZ;
623 : :
624 : : /* No work if typmod is invalid or supplied data fits it already */
625 [ + - + + ]: 11780 : if (maxlen < 0 || len <= maxlen)
8364 peter_e@gmx.net 626 : 11714 : PG_RETURN_VARCHAR_P(source);
627 : :
628 : : /* only reach here if string is too long... */
629 : :
630 : : /* truncate multibyte string preserving multibyte boundary */
6218 tgl@sss.pgh.pa.us 631 : 66 : maxmblen = pg_mbcharcliplen(s_data, len, maxlen);
632 : :
7879 633 [ + + ]: 66 : if (!isExplicit)
634 : : {
6218 635 [ + + ]: 63 : for (i = maxmblen; i < len; i++)
636 [ + + ]: 57 : if (s_data[i] != ' ')
7567 637 [ + - ]: 27 : ereport(ERROR,
638 : : (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION),
639 : : errmsg("value too long for type character varying(%d)",
640 : : maxlen)));
641 : : }
642 : :
5421 bruce@momjian.us 643 : 39 : PG_RETURN_VARCHAR_P((VarChar *) cstring_to_text_with_len(s_data,
644 : : maxmblen));
645 : : }
646 : :
647 : : Datum
6315 tgl@sss.pgh.pa.us 648 : 705 : varchartypmodin(PG_FUNCTION_ARGS)
649 : : {
5995 bruce@momjian.us 650 : 705 : ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0);
651 : :
6315 tgl@sss.pgh.pa.us 652 : 705 : PG_RETURN_INT32(anychar_typmodin(ta, "varchar"));
653 : : }
654 : :
655 : : Datum
656 : 96 : varchartypmodout(PG_FUNCTION_ARGS)
657 : : {
5995 bruce@momjian.us 658 : 96 : int32 typmod = PG_GETARG_INT32(0);
659 : :
6315 tgl@sss.pgh.pa.us 660 : 96 : PG_RETURN_CSTRING(anychar_typmodout(typmod));
661 : : }
662 : :
663 : :
664 : : /*****************************************************************************
665 : : * Exported functions
666 : : *****************************************************************************/
667 : :
668 : : /* "True" length (not counting trailing blanks) of a BpChar */
669 : : static inline int
8660 670 : 137329 : bcTruelen(BpChar *arg)
671 : : {
2993 rhaas@postgresql.org 672 [ - + - - : 137329 : return bpchartruelen(VARDATA_ANY(arg), VARSIZE_ANY_EXHDR(arg));
- - - - +
+ + + ]
673 : : }
674 : :
675 : : int
676 : 236270 : bpchartruelen(char *s, int len)
677 : : {
678 : : int i;
679 : :
680 : : /*
681 : : * Note that we rely on the assumption that ' ' is a singleton unit on
682 : : * every supported multibyte server encoding.
683 : : */
9716 bruce@momjian.us 684 [ + + ]: 6353510 : for (i = len - 1; i >= 0; i--)
685 : : {
686 [ + + ]: 6286475 : if (s[i] != ' ')
687 : 169235 : break;
688 : : }
9357 689 : 236270 : return i + 1;
690 : : }
691 : :
692 : : Datum
8660 tgl@sss.pgh.pa.us 693 : 9 : bpcharlen(PG_FUNCTION_ARGS)
694 : : {
6218 695 : 9 : BpChar *arg = PG_GETARG_BPCHAR_PP(0);
696 : : int len;
697 : :
698 : : /* get number of bytes, ignoring trailing spaces */
7378 699 : 9 : len = bcTruelen(arg);
700 : :
701 : : /* in multibyte encoding, convert to number of characters */
702 [ + - ]: 9 : if (pg_database_encoding_max_length() != 1)
6218 703 [ + + ]: 9 : len = pg_mbstrlen_with_len(VARDATA_ANY(arg), len);
704 : :
7378 705 : 9 : PG_RETURN_INT32(len);
706 : : }
707 : :
708 : : Datum
8660 tgl@sss.pgh.pa.us 709 :UBC 0 : bpcharoctetlen(PG_FUNCTION_ARGS)
710 : : {
5995 bruce@momjian.us 711 : 0 : Datum arg = PG_GETARG_DATUM(0);
712 : :
713 : : /* We need not detoast the input at all */
6218 tgl@sss.pgh.pa.us 714 : 0 : PG_RETURN_INT32(toast_raw_datum_size(arg) - VARHDRSZ);
715 : : }
716 : :
717 : :
718 : : /*****************************************************************************
719 : : * Comparison Functions used for bpchar
720 : : *
721 : : * Note: btree indexes need these routines not to leak memory; therefore,
722 : : * be careful to free working copies of toasted datums. Most places don't
723 : : * need to be so careful.
724 : : *****************************************************************************/
725 : :
726 : : static void
1850 peter@eisentraut.org 727 :CBC 14497 : check_collation_set(Oid collid)
728 : : {
729 [ - + ]: 14497 : if (!OidIsValid(collid))
730 : : {
731 : : /*
732 : : * This typically means that the parser could not resolve a conflict
733 : : * of implicit collations, so report it that way.
734 : : */
1850 peter@eisentraut.org 735 [ # # ]:UBC 0 : ereport(ERROR,
736 : : (errcode(ERRCODE_INDETERMINATE_COLLATION),
737 : : errmsg("could not determine which collation to use for string comparison"),
738 : : errhint("Use the COLLATE clause to set the collation explicitly.")));
739 : : }
1850 peter@eisentraut.org 740 :CBC 14497 : }
741 : :
742 : : Datum
8660 tgl@sss.pgh.pa.us 743 : 11293 : bpchareq(PG_FUNCTION_ARGS)
744 : : {
6218 745 : 11293 : BpChar *arg1 = PG_GETARG_BPCHAR_PP(0);
746 : 11293 : BpChar *arg2 = PG_GETARG_BPCHAR_PP(1);
747 : : int len1,
748 : : len2;
749 : : bool result;
1850 peter@eisentraut.org 750 : 11293 : Oid collid = PG_GET_COLLATION();
815 751 : 11293 : bool locale_is_c = false;
703 tgl@sss.pgh.pa.us 752 : 11293 : pg_locale_t mylocale = 0;
753 : :
1850 peter@eisentraut.org 754 : 11293 : check_collation_set(collid);
755 : :
9716 bruce@momjian.us 756 : 11293 : len1 = bcTruelen(arg1);
757 : 11293 : len2 = bcTruelen(arg2);
758 : :
815 peter@eisentraut.org 759 [ + + ]: 11293 : if (lc_collate_is_c(collid))
760 : 3375 : locale_is_c = true;
761 : : else
762 : 7918 : mylocale = pg_newlocale_from_collation(collid);
763 : :
416 jdavis@postgresql.or 764 [ + + + + ]: 11293 : if (locale_is_c || pg_locale_deterministic(mylocale))
765 : : {
766 : : /*
767 : : * Since we only care about equality or not-equality, we can avoid all
768 : : * the expense of strcoll() here, and just do bitwise comparison.
769 : : */
1850 peter@eisentraut.org 770 [ + + ]: 11209 : if (len1 != len2)
771 : 1281 : result = false;
772 : : else
773 [ + + + + ]: 9928 : result = (memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), len1) == 0);
774 : : }
775 : : else
776 : : {
777 [ + + + - ]: 84 : result = (varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2,
778 : : collid) == 0);
779 : : }
780 : :
8660 tgl@sss.pgh.pa.us 781 [ - + ]: 11293 : PG_FREE_IF_COPY(arg1, 0);
782 [ - + ]: 11293 : PG_FREE_IF_COPY(arg2, 1);
783 : :
784 : 11293 : PG_RETURN_BOOL(result);
785 : : }
786 : :
787 : : Datum
788 : 3204 : bpcharne(PG_FUNCTION_ARGS)
789 : : {
6218 790 : 3204 : BpChar *arg1 = PG_GETARG_BPCHAR_PP(0);
791 : 3204 : BpChar *arg2 = PG_GETARG_BPCHAR_PP(1);
792 : : int len1,
793 : : len2;
794 : : bool result;
1850 peter@eisentraut.org 795 : 3204 : Oid collid = PG_GET_COLLATION();
815 796 : 3204 : bool locale_is_c = false;
703 tgl@sss.pgh.pa.us 797 : 3204 : pg_locale_t mylocale = 0;
798 : :
1614 799 : 3204 : check_collation_set(collid);
800 : :
9716 bruce@momjian.us 801 : 3204 : len1 = bcTruelen(arg1);
802 : 3204 : len2 = bcTruelen(arg2);
803 : :
815 peter@eisentraut.org 804 [ + + ]: 3204 : if (lc_collate_is_c(collid))
815 peter@eisentraut.org 805 :GBC 1064 : locale_is_c = true;
806 : : else
815 peter@eisentraut.org 807 :CBC 2140 : mylocale = pg_newlocale_from_collation(collid);
808 : :
416 jdavis@postgresql.or 809 [ + + + + ]: 3204 : if (locale_is_c || pg_locale_deterministic(mylocale))
810 : : {
811 : : /*
812 : : * Since we only care about equality or not-equality, we can avoid all
813 : : * the expense of strcoll() here, and just do bitwise comparison.
814 : : */
1850 peter@eisentraut.org 815 [ + + ]: 3192 : if (len1 != len2)
816 : 1011 : result = true;
817 : : else
818 [ + + + - ]: 2181 : result = (memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), len1) != 0);
819 : : }
820 : : else
821 : : {
822 [ - + + - ]: 12 : result = (varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2,
823 : : collid) != 0);
824 : : }
825 : :
8660 tgl@sss.pgh.pa.us 826 [ - + ]: 3204 : PG_FREE_IF_COPY(arg1, 0);
827 [ - + ]: 3204 : PG_FREE_IF_COPY(arg2, 1);
828 : :
829 : 3204 : PG_RETURN_BOOL(result);
830 : : }
831 : :
832 : : Datum
833 : 3017 : bpcharlt(PG_FUNCTION_ARGS)
834 : : {
6218 835 : 3017 : BpChar *arg1 = PG_GETARG_BPCHAR_PP(0);
836 : 3017 : BpChar *arg2 = PG_GETARG_BPCHAR_PP(1);
837 : : int len1,
838 : : len2;
839 : : int cmp;
840 : :
9716 bruce@momjian.us 841 : 3017 : len1 = bcTruelen(arg1);
842 : 3017 : len2 = bcTruelen(arg2);
843 : :
4814 peter_e@gmx.net 844 [ + + + + ]: 3017 : cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2,
845 : : PG_GET_COLLATION());
846 : :
8660 tgl@sss.pgh.pa.us 847 [ - + ]: 3017 : PG_FREE_IF_COPY(arg1, 0);
848 [ - + ]: 3017 : PG_FREE_IF_COPY(arg2, 1);
849 : :
850 : 3017 : PG_RETURN_BOOL(cmp < 0);
851 : : }
852 : :
853 : : Datum
854 : 2773 : bpcharle(PG_FUNCTION_ARGS)
855 : : {
6218 856 : 2773 : BpChar *arg1 = PG_GETARG_BPCHAR_PP(0);
857 : 2773 : BpChar *arg2 = PG_GETARG_BPCHAR_PP(1);
858 : : int len1,
859 : : len2;
860 : : int cmp;
861 : :
9716 bruce@momjian.us 862 : 2773 : len1 = bcTruelen(arg1);
863 : 2773 : len2 = bcTruelen(arg2);
864 : :
4814 peter_e@gmx.net 865 [ - + + + ]: 2773 : cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2,
866 : : PG_GET_COLLATION());
867 : :
8660 tgl@sss.pgh.pa.us 868 [ - + ]: 2773 : PG_FREE_IF_COPY(arg1, 0);
869 [ - + ]: 2773 : PG_FREE_IF_COPY(arg2, 1);
870 : :
871 : 2773 : PG_RETURN_BOOL(cmp <= 0);
872 : : }
873 : :
874 : : Datum
875 : 3129 : bpchargt(PG_FUNCTION_ARGS)
876 : : {
6218 877 : 3129 : BpChar *arg1 = PG_GETARG_BPCHAR_PP(0);
878 : 3129 : BpChar *arg2 = PG_GETARG_BPCHAR_PP(1);
879 : : int len1,
880 : : len2;
881 : : int cmp;
882 : :
9716 bruce@momjian.us 883 : 3129 : len1 = bcTruelen(arg1);
884 : 3129 : len2 = bcTruelen(arg2);
885 : :
4814 peter_e@gmx.net 886 [ + + + + ]: 3129 : cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2,
887 : : PG_GET_COLLATION());
888 : :
8660 tgl@sss.pgh.pa.us 889 [ - + ]: 3129 : PG_FREE_IF_COPY(arg1, 0);
890 [ - + ]: 3129 : PG_FREE_IF_COPY(arg2, 1);
891 : :
892 : 3129 : PG_RETURN_BOOL(cmp > 0);
893 : : }
894 : :
895 : : Datum
896 : 2860 : bpcharge(PG_FUNCTION_ARGS)
897 : : {
6218 898 : 2860 : BpChar *arg1 = PG_GETARG_BPCHAR_PP(0);
899 : 2860 : BpChar *arg2 = PG_GETARG_BPCHAR_PP(1);
900 : : int len1,
901 : : len2;
902 : : int cmp;
903 : :
9716 bruce@momjian.us 904 : 2860 : len1 = bcTruelen(arg1);
905 : 2860 : len2 = bcTruelen(arg2);
906 : :
4814 peter_e@gmx.net 907 [ - + + + ]: 2860 : cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2,
908 : : PG_GET_COLLATION());
909 : :
8660 tgl@sss.pgh.pa.us 910 [ - + ]: 2860 : PG_FREE_IF_COPY(arg1, 0);
911 [ - + ]: 2860 : PG_FREE_IF_COPY(arg2, 1);
912 : :
913 : 2860 : PG_RETURN_BOOL(cmp >= 0);
914 : : }
915 : :
916 : : Datum
917 : 41226 : bpcharcmp(PG_FUNCTION_ARGS)
918 : : {
6218 919 : 41226 : BpChar *arg1 = PG_GETARG_BPCHAR_PP(0);
920 : 41226 : BpChar *arg2 = PG_GETARG_BPCHAR_PP(1);
921 : : int len1,
922 : : len2;
923 : : int cmp;
924 : :
9716 bruce@momjian.us 925 : 41226 : len1 = bcTruelen(arg1);
926 : 41226 : len2 = bcTruelen(arg2);
927 : :
4814 peter_e@gmx.net 928 [ + + + + ]: 41226 : cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2,
929 : : PG_GET_COLLATION());
930 : :
8660 tgl@sss.pgh.pa.us 931 [ - + ]: 41226 : PG_FREE_IF_COPY(arg1, 0);
932 [ - + ]: 41226 : PG_FREE_IF_COPY(arg2, 1);
933 : :
934 : 41226 : PG_RETURN_INT32(cmp);
935 : : }
936 : :
937 : : Datum
2993 rhaas@postgresql.org 938 : 410 : bpchar_sortsupport(PG_FUNCTION_ARGS)
939 : : {
940 : 410 : SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
941 : 410 : Oid collid = ssup->ssup_collation;
942 : : MemoryContext oldcontext;
943 : :
944 : 410 : oldcontext = MemoryContextSwitchTo(ssup->ssup_cxt);
945 : :
946 : : /* Use generic string SortSupport */
1943 tgl@sss.pgh.pa.us 947 : 410 : varstr_sortsupport(ssup, BPCHAROID, collid);
948 : :
2993 rhaas@postgresql.org 949 : 410 : MemoryContextSwitchTo(oldcontext);
950 : :
951 : 410 : PG_RETURN_VOID();
952 : : }
953 : :
954 : : Datum
6942 tgl@sss.pgh.pa.us 955 :UBC 0 : bpchar_larger(PG_FUNCTION_ARGS)
956 : : {
6218 957 : 0 : BpChar *arg1 = PG_GETARG_BPCHAR_PP(0);
958 : 0 : BpChar *arg2 = PG_GETARG_BPCHAR_PP(1);
959 : : int len1,
960 : : len2;
961 : : int cmp;
962 : :
6942 963 : 0 : len1 = bcTruelen(arg1);
964 : 0 : len2 = bcTruelen(arg2);
965 : :
4814 peter_e@gmx.net 966 [ # # # # ]: 0 : cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2,
967 : : PG_GET_COLLATION());
968 : :
6942 tgl@sss.pgh.pa.us 969 [ # # ]: 0 : PG_RETURN_BPCHAR_P((cmp >= 0) ? arg1 : arg2);
970 : : }
971 : :
972 : : Datum
973 : 0 : bpchar_smaller(PG_FUNCTION_ARGS)
974 : : {
6218 975 : 0 : BpChar *arg1 = PG_GETARG_BPCHAR_PP(0);
976 : 0 : BpChar *arg2 = PG_GETARG_BPCHAR_PP(1);
977 : : int len1,
978 : : len2;
979 : : int cmp;
980 : :
6942 981 : 0 : len1 = bcTruelen(arg1);
982 : 0 : len2 = bcTruelen(arg2);
983 : :
4814 peter_e@gmx.net 984 [ # # # # ]: 0 : cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2,
985 : : PG_GET_COLLATION());
986 : :
6942 tgl@sss.pgh.pa.us 987 [ # # ]: 0 : PG_RETURN_BPCHAR_P((cmp <= 0) ? arg1 : arg2);
988 : : }
989 : :
990 : :
991 : : /*
992 : : * bpchar needs a specialized hash function because we want to ignore
993 : : * trailing blanks in comparisons.
994 : : */
995 : : Datum
8660 tgl@sss.pgh.pa.us 996 :CBC 2196 : hashbpchar(PG_FUNCTION_ARGS)
997 : : {
6218 998 : 2196 : BpChar *key = PG_GETARG_BPCHAR_PP(0);
1850 peter@eisentraut.org 999 : 2196 : Oid collid = PG_GET_COLLATION();
1000 : : char *keydata;
1001 : : int keylen;
1789 tgl@sss.pgh.pa.us 1002 : 2196 : pg_locale_t mylocale = 0;
1003 : : Datum result;
1004 : :
1850 peter@eisentraut.org 1005 [ - + ]: 2196 : if (!collid)
1850 peter@eisentraut.org 1006 [ # # ]:UBC 0 : ereport(ERROR,
1007 : : (errcode(ERRCODE_INDETERMINATE_COLLATION),
1008 : : errmsg("could not determine which collation to use for string hashing"),
1009 : : errhint("Use the COLLATE clause to set the collation explicitly.")));
1010 : :
6218 tgl@sss.pgh.pa.us 1011 [ + + ]:CBC 2196 : keydata = VARDATA_ANY(key);
8660 1012 : 2196 : keylen = bcTruelen(key);
1013 : :
815 peter@eisentraut.org 1014 [ + + ]: 2196 : if (!lc_collate_is_c(collid))
1850 1015 : 1492 : mylocale = pg_newlocale_from_collation(collid);
1016 : :
416 jdavis@postgresql.or 1017 [ + + ]: 2196 : if (pg_locale_deterministic(mylocale))
1018 : : {
1850 peter@eisentraut.org 1019 : 2112 : result = hash_any((unsigned char *) keydata, keylen);
1020 : : }
1021 : : else
1022 : : {
1023 : : Size bsize,
1024 : : rsize;
1025 : : char *buf;
1026 : :
416 jdavis@postgresql.or 1027 : 84 : bsize = pg_strnxfrm(NULL, 0, keydata, keylen, mylocale);
1028 : 84 : buf = palloc(bsize + 1);
1029 : :
1030 : 84 : rsize = pg_strnxfrm(buf, bsize + 1, keydata, keylen, mylocale);
1031 [ - + ]: 84 : if (rsize != bsize)
416 jdavis@postgresql.or 1032 [ # # ]:UBC 0 : elog(ERROR, "pg_strnxfrm() returned unexpected result");
1033 : :
1034 : : /*
1035 : : * In principle, there's no reason to include the terminating NUL
1036 : : * character in the hash, but it was done before and the behavior must
1037 : : * be preserved.
1038 : : */
416 jdavis@postgresql.or 1039 :CBC 84 : result = hash_any((uint8_t *) buf, bsize + 1);
1040 : :
1041 : 84 : pfree(buf);
1042 : : }
1043 : :
1044 : : /* Avoid leaking memory for toasted inputs */
8528 tgl@sss.pgh.pa.us 1045 [ - + ]: 2196 : PG_FREE_IF_COPY(key, 0);
1046 : :
1047 : 2196 : return result;
1048 : : }
1049 : :
1050 : : Datum
2418 rhaas@postgresql.org 1051 : 42 : hashbpcharextended(PG_FUNCTION_ARGS)
1052 : : {
1053 : 42 : BpChar *key = PG_GETARG_BPCHAR_PP(0);
1850 peter@eisentraut.org 1054 : 42 : Oid collid = PG_GET_COLLATION();
1055 : : char *keydata;
1056 : : int keylen;
1789 tgl@sss.pgh.pa.us 1057 : 42 : pg_locale_t mylocale = 0;
1058 : : Datum result;
1059 : :
1850 peter@eisentraut.org 1060 [ - + ]: 42 : if (!collid)
1850 peter@eisentraut.org 1061 [ # # ]:UBC 0 : ereport(ERROR,
1062 : : (errcode(ERRCODE_INDETERMINATE_COLLATION),
1063 : : errmsg("could not determine which collation to use for string hashing"),
1064 : : errhint("Use the COLLATE clause to set the collation explicitly.")));
1065 : :
2418 rhaas@postgresql.org 1066 [ - + ]:CBC 42 : keydata = VARDATA_ANY(key);
1067 : 42 : keylen = bcTruelen(key);
1068 : :
815 peter@eisentraut.org 1069 [ + + ]: 42 : if (!lc_collate_is_c(collid))
1850 1070 : 32 : mylocale = pg_newlocale_from_collation(collid);
1071 : :
416 jdavis@postgresql.or 1072 [ + + ]: 42 : if (pg_locale_deterministic(mylocale))
1073 : : {
1850 peter@eisentraut.org 1074 : 36 : result = hash_any_extended((unsigned char *) keydata, keylen,
1075 : 36 : PG_GETARG_INT64(1));
1076 : : }
1077 : : else
1078 : : {
1079 : : Size bsize,
1080 : : rsize;
1081 : : char *buf;
1082 : :
416 jdavis@postgresql.or 1083 : 6 : bsize = pg_strnxfrm(NULL, 0, keydata, keylen, mylocale);
1084 : 6 : buf = palloc(bsize + 1);
1085 : :
1086 : 6 : rsize = pg_strnxfrm(buf, bsize + 1, keydata, keylen, mylocale);
1087 [ - + ]: 6 : if (rsize != bsize)
416 jdavis@postgresql.or 1088 [ # # ]:UBC 0 : elog(ERROR, "pg_strnxfrm() returned unexpected result");
1089 : :
1090 : : /*
1091 : : * In principle, there's no reason to include the terminating NUL
1092 : : * character in the hash, but it was done before and the behavior must
1093 : : * be preserved.
1094 : : */
416 jdavis@postgresql.or 1095 :CBC 6 : result = hash_any_extended((uint8_t *) buf, bsize + 1,
1096 : 6 : PG_GETARG_INT64(1));
1097 : :
1098 : 6 : pfree(buf);
1099 : : }
1100 : :
2418 rhaas@postgresql.org 1101 [ - + ]: 42 : PG_FREE_IF_COPY(key, 0);
1102 : :
1103 : 42 : return result;
1104 : : }
1105 : :
1106 : : /*
1107 : : * The following operators support character-by-character comparison
1108 : : * of bpchar datums, to allow building indexes suitable for LIKE clauses.
1109 : : * Note that the regular bpchareq/bpcharne comparison operators, and
1110 : : * regular support functions 1 and 2 with "C" collation are assumed to be
1111 : : * compatible with these!
1112 : : */
1113 : :
1114 : : static int
1667 tgl@sss.pgh.pa.us 1115 : 39 : internal_bpchar_pattern_compare(BpChar *arg1, BpChar *arg2)
1116 : : {
1117 : : int result;
1118 : : int len1,
1119 : : len2;
1120 : :
5801 1121 : 39 : len1 = bcTruelen(arg1);
1122 : 39 : len2 = bcTruelen(arg2);
1123 : :
4863 rhaas@postgresql.org 1124 [ + - + - ]: 39 : result = memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), Min(len1, len2));
5801 tgl@sss.pgh.pa.us 1125 [ + + ]: 39 : if (result != 0)
1126 : 24 : return result;
1127 [ - + ]: 15 : else if (len1 < len2)
5801 tgl@sss.pgh.pa.us 1128 :UBC 0 : return -1;
5801 tgl@sss.pgh.pa.us 1129 [ - + ]:CBC 15 : else if (len1 > len2)
5801 tgl@sss.pgh.pa.us 1130 :UBC 0 : return 1;
1131 : : else
5801 tgl@sss.pgh.pa.us 1132 :CBC 15 : return 0;
1133 : : }
1134 : :
1135 : :
1136 : : Datum
5801 tgl@sss.pgh.pa.us 1137 :UBC 0 : bpchar_pattern_lt(PG_FUNCTION_ARGS)
1138 : : {
1139 : 0 : BpChar *arg1 = PG_GETARG_BPCHAR_PP(0);
1140 : 0 : BpChar *arg2 = PG_GETARG_BPCHAR_PP(1);
1141 : : int result;
1142 : :
1667 1143 : 0 : result = internal_bpchar_pattern_compare(arg1, arg2);
1144 : :
5801 1145 [ # # ]: 0 : PG_FREE_IF_COPY(arg1, 0);
1146 [ # # ]: 0 : PG_FREE_IF_COPY(arg2, 1);
1147 : :
1148 : 0 : PG_RETURN_BOOL(result < 0);
1149 : : }
1150 : :
1151 : :
1152 : : Datum
1153 : 0 : bpchar_pattern_le(PG_FUNCTION_ARGS)
1154 : : {
1155 : 0 : BpChar *arg1 = PG_GETARG_BPCHAR_PP(0);
1156 : 0 : BpChar *arg2 = PG_GETARG_BPCHAR_PP(1);
1157 : : int result;
1158 : :
1667 1159 : 0 : result = internal_bpchar_pattern_compare(arg1, arg2);
1160 : :
5801 1161 [ # # ]: 0 : PG_FREE_IF_COPY(arg1, 0);
1162 [ # # ]: 0 : PG_FREE_IF_COPY(arg2, 1);
1163 : :
1164 : 0 : PG_RETURN_BOOL(result <= 0);
1165 : : }
1166 : :
1167 : :
1168 : : Datum
1169 : 0 : bpchar_pattern_ge(PG_FUNCTION_ARGS)
1170 : : {
1171 : 0 : BpChar *arg1 = PG_GETARG_BPCHAR_PP(0);
1172 : 0 : BpChar *arg2 = PG_GETARG_BPCHAR_PP(1);
1173 : : int result;
1174 : :
1667 1175 : 0 : result = internal_bpchar_pattern_compare(arg1, arg2);
1176 : :
5801 1177 [ # # ]: 0 : PG_FREE_IF_COPY(arg1, 0);
1178 [ # # ]: 0 : PG_FREE_IF_COPY(arg2, 1);
1179 : :
1180 : 0 : PG_RETURN_BOOL(result >= 0);
1181 : : }
1182 : :
1183 : :
1184 : : Datum
1185 : 0 : bpchar_pattern_gt(PG_FUNCTION_ARGS)
1186 : : {
1187 : 0 : BpChar *arg1 = PG_GETARG_BPCHAR_PP(0);
1188 : 0 : BpChar *arg2 = PG_GETARG_BPCHAR_PP(1);
1189 : : int result;
1190 : :
1667 1191 : 0 : result = internal_bpchar_pattern_compare(arg1, arg2);
1192 : :
5801 1193 [ # # ]: 0 : PG_FREE_IF_COPY(arg1, 0);
1194 [ # # ]: 0 : PG_FREE_IF_COPY(arg2, 1);
1195 : :
1196 : 0 : PG_RETURN_BOOL(result > 0);
1197 : : }
1198 : :
1199 : :
1200 : : Datum
5801 tgl@sss.pgh.pa.us 1201 :CBC 39 : btbpchar_pattern_cmp(PG_FUNCTION_ARGS)
1202 : : {
1203 : 39 : BpChar *arg1 = PG_GETARG_BPCHAR_PP(0);
1204 : 39 : BpChar *arg2 = PG_GETARG_BPCHAR_PP(1);
1205 : : int result;
1206 : :
1667 1207 : 39 : result = internal_bpchar_pattern_compare(arg1, arg2);
1208 : :
5801 1209 [ - + ]: 39 : PG_FREE_IF_COPY(arg1, 0);
1210 [ - + ]: 39 : PG_FREE_IF_COPY(arg2, 1);
1211 : :
1212 : 39 : PG_RETURN_INT32(result);
1213 : : }
1214 : :
1215 : :
1216 : : Datum
2993 rhaas@postgresql.org 1217 : 6 : btbpchar_pattern_sortsupport(PG_FUNCTION_ARGS)
1218 : : {
1219 : 6 : SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
1220 : : MemoryContext oldcontext;
1221 : :
1222 : 6 : oldcontext = MemoryContextSwitchTo(ssup->ssup_cxt);
1223 : :
1224 : : /* Use generic string SortSupport, forcing "C" collation */
1943 tgl@sss.pgh.pa.us 1225 : 6 : varstr_sortsupport(ssup, BPCHAROID, C_COLLATION_OID);
1226 : :
2993 rhaas@postgresql.org 1227 : 6 : MemoryContextSwitchTo(oldcontext);
1228 : :
1229 : 6 : PG_RETURN_VOID();
1230 : : }
|