Line data Source code
1 : /*-------------------------------------------------------------------------
2 : * oracle_compat.c
3 : * Oracle compatible functions.
4 : *
5 : * Copyright (c) 1996-2026, PostgreSQL Global Development Group
6 : *
7 : * Author: Edmund Mergl <E.Mergl@bawue.de>
8 : * Multibyte enhancement: Tatsuo Ishii <ishii@postgresql.org>
9 : *
10 : *
11 : * IDENTIFICATION
12 : * src/backend/utils/adt/oracle_compat.c
13 : *
14 : *-------------------------------------------------------------------------
15 : */
16 : #include "postgres.h"
17 :
18 : #include "common/int.h"
19 : #include "mb/pg_wchar.h"
20 : #include "miscadmin.h"
21 : #include "utils/builtins.h"
22 : #include "utils/formatting.h"
23 : #include "utils/memutils.h"
24 : #include "varatt.h"
25 :
26 :
27 : static text *dotrim(const char *string, int stringlen,
28 : const char *set, int setlen,
29 : bool doltrim, bool dortrim);
30 : static bytea *dobyteatrim(bytea *string, bytea *set,
31 : bool doltrim, bool dortrim);
32 :
33 :
34 : /********************************************************************
35 : *
36 : * lower
37 : *
38 : * Syntax:
39 : *
40 : * text lower(text string)
41 : *
42 : * Purpose:
43 : *
44 : * Returns string, with all letters forced to lowercase.
45 : *
46 : ********************************************************************/
47 :
48 : Datum
49 75468 : lower(PG_FUNCTION_ARGS)
50 : {
51 75468 : text *in_string = PG_GETARG_TEXT_PP(0);
52 : char *out_string;
53 : text *result;
54 :
55 75468 : out_string = str_tolower(VARDATA_ANY(in_string),
56 : VARSIZE_ANY_EXHDR(in_string),
57 : PG_GET_COLLATION());
58 75468 : result = cstring_to_text(out_string);
59 75468 : pfree(out_string);
60 :
61 75468 : PG_RETURN_TEXT_P(result);
62 : }
63 :
64 :
65 : /********************************************************************
66 : *
67 : * upper
68 : *
69 : * Syntax:
70 : *
71 : * text upper(text string)
72 : *
73 : * Purpose:
74 : *
75 : * Returns string, with all letters forced to uppercase.
76 : *
77 : ********************************************************************/
78 :
79 : Datum
80 527302 : upper(PG_FUNCTION_ARGS)
81 : {
82 527302 : text *in_string = PG_GETARG_TEXT_PP(0);
83 : char *out_string;
84 : text *result;
85 :
86 527302 : out_string = str_toupper(VARDATA_ANY(in_string),
87 : VARSIZE_ANY_EXHDR(in_string),
88 : PG_GET_COLLATION());
89 527302 : result = cstring_to_text(out_string);
90 527302 : pfree(out_string);
91 :
92 527302 : PG_RETURN_TEXT_P(result);
93 : }
94 :
95 :
96 : /********************************************************************
97 : *
98 : * initcap
99 : *
100 : * Syntax:
101 : *
102 : * text initcap(text string)
103 : *
104 : * Purpose:
105 : *
106 : * Returns string, with first letter of each word in uppercase, all
107 : * other letters in lowercase. A word is defined as a sequence of
108 : * alphanumeric characters, delimited by non-alphanumeric
109 : * characters.
110 : *
111 : ********************************************************************/
112 :
113 : Datum
114 113 : initcap(PG_FUNCTION_ARGS)
115 : {
116 113 : text *in_string = PG_GETARG_TEXT_PP(0);
117 : char *out_string;
118 : text *result;
119 :
120 113 : out_string = str_initcap(VARDATA_ANY(in_string),
121 : VARSIZE_ANY_EXHDR(in_string),
122 : PG_GET_COLLATION());
123 113 : result = cstring_to_text(out_string);
124 113 : pfree(out_string);
125 :
126 113 : PG_RETURN_TEXT_P(result);
127 : }
128 :
129 : Datum
130 12 : casefold(PG_FUNCTION_ARGS)
131 : {
132 12 : text *in_string = PG_GETARG_TEXT_PP(0);
133 : char *out_string;
134 : text *result;
135 :
136 12 : out_string = str_casefold(VARDATA_ANY(in_string),
137 : VARSIZE_ANY_EXHDR(in_string),
138 : PG_GET_COLLATION());
139 12 : result = cstring_to_text(out_string);
140 12 : pfree(out_string);
141 :
142 12 : PG_RETURN_TEXT_P(result);
143 : }
144 :
145 :
146 : /********************************************************************
147 : *
148 : * lpad
149 : *
150 : * Syntax:
151 : *
152 : * text lpad(text string1, int4 len, text string2)
153 : *
154 : * Purpose:
155 : *
156 : * Returns string1, left-padded to length len with the sequence of
157 : * characters in string2. If len is less than the length of string1,
158 : * instead truncate (on the right) to len.
159 : *
160 : ********************************************************************/
161 :
162 : Datum
163 16655 : lpad(PG_FUNCTION_ARGS)
164 : {
165 16655 : text *string1 = PG_GETARG_TEXT_PP(0);
166 16655 : int32 len = PG_GETARG_INT32(1);
167 16655 : text *string2 = PG_GETARG_TEXT_PP(2);
168 : text *ret;
169 : char *ptr1,
170 : *ptr2,
171 : *ptr2start,
172 : *ptr_ret;
173 : const char *ptr2end;
174 : int m,
175 : s1len,
176 : s2len;
177 : int bytelen;
178 :
179 : /* Negative len is silently taken as zero */
180 16655 : if (len < 0)
181 3 : len = 0;
182 :
183 16655 : s1len = VARSIZE_ANY_EXHDR(string1);
184 16655 : if (s1len < 0)
185 0 : s1len = 0; /* shouldn't happen */
186 :
187 16655 : s2len = VARSIZE_ANY_EXHDR(string2);
188 16655 : if (s2len < 0)
189 0 : s2len = 0; /* shouldn't happen */
190 :
191 16655 : s1len = pg_mbstrlen_with_len(VARDATA_ANY(string1), s1len);
192 :
193 16655 : if (s1len > len)
194 35 : s1len = len; /* truncate string1 to len chars */
195 :
196 16655 : if (s2len <= 0)
197 3 : len = s1len; /* nothing to pad with, so don't pad */
198 :
199 : /* compute worst-case output length */
200 16655 : if (unlikely(pg_mul_s32_overflow(pg_database_encoding_max_length(), len,
201 16655 : &bytelen)) ||
202 16655 : unlikely(pg_add_s32_overflow(bytelen, VARHDRSZ, &bytelen)) ||
203 16655 : unlikely(!AllocSizeIsValid(bytelen)))
204 0 : ereport(ERROR,
205 : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
206 : errmsg("requested length too large")));
207 :
208 16655 : ret = (text *) palloc(bytelen);
209 :
210 16655 : m = len - s1len;
211 :
212 16655 : ptr2 = ptr2start = VARDATA_ANY(string2);
213 16655 : ptr2end = ptr2 + s2len;
214 16655 : ptr_ret = VARDATA(ret);
215 :
216 17869 : while (m--)
217 : {
218 1214 : int mlen = pg_mblen_range(ptr2, ptr2end);
219 :
220 1214 : memcpy(ptr_ret, ptr2, mlen);
221 1214 : ptr_ret += mlen;
222 1214 : ptr2 += mlen;
223 1214 : if (ptr2 == ptr2end) /* wrap around at end of s2 */
224 1202 : ptr2 = ptr2start;
225 : }
226 :
227 16655 : ptr1 = VARDATA_ANY(string1);
228 :
229 48955 : while (s1len--)
230 : {
231 32300 : int mlen = pg_mblen_unbounded(ptr1);
232 :
233 32300 : memcpy(ptr_ret, ptr1, mlen);
234 32300 : ptr_ret += mlen;
235 32300 : ptr1 += mlen;
236 : }
237 :
238 16655 : SET_VARSIZE(ret, ptr_ret - (char *) ret);
239 :
240 16655 : PG_RETURN_TEXT_P(ret);
241 : }
242 :
243 :
244 : /********************************************************************
245 : *
246 : * rpad
247 : *
248 : * Syntax:
249 : *
250 : * text rpad(text string1, int4 len, text string2)
251 : *
252 : * Purpose:
253 : *
254 : * Returns string1, right-padded to length len with the sequence of
255 : * characters in string2. If len is less than the length of string1,
256 : * instead truncate (on the right) to len.
257 : *
258 : ********************************************************************/
259 :
260 : Datum
261 190 : rpad(PG_FUNCTION_ARGS)
262 : {
263 190 : text *string1 = PG_GETARG_TEXT_PP(0);
264 190 : int32 len = PG_GETARG_INT32(1);
265 190 : text *string2 = PG_GETARG_TEXT_PP(2);
266 : text *ret;
267 : char *ptr1,
268 : *ptr2,
269 : *ptr2start,
270 : *ptr_ret;
271 : const char *ptr2end;
272 : int m,
273 : s1len,
274 : s2len;
275 : int bytelen;
276 :
277 : /* Negative len is silently taken as zero */
278 190 : if (len < 0)
279 3 : len = 0;
280 :
281 190 : s1len = VARSIZE_ANY_EXHDR(string1);
282 190 : if (s1len < 0)
283 0 : s1len = 0; /* shouldn't happen */
284 :
285 190 : s2len = VARSIZE_ANY_EXHDR(string2);
286 190 : if (s2len < 0)
287 0 : s2len = 0; /* shouldn't happen */
288 :
289 190 : s1len = pg_mbstrlen_with_len(VARDATA_ANY(string1), s1len);
290 :
291 190 : if (s1len > len)
292 6 : s1len = len; /* truncate string1 to len chars */
293 :
294 190 : if (s2len <= 0)
295 3 : len = s1len; /* nothing to pad with, so don't pad */
296 :
297 : /* compute worst-case output length */
298 190 : if (unlikely(pg_mul_s32_overflow(pg_database_encoding_max_length(), len,
299 190 : &bytelen)) ||
300 190 : unlikely(pg_add_s32_overflow(bytelen, VARHDRSZ, &bytelen)) ||
301 190 : unlikely(!AllocSizeIsValid(bytelen)))
302 0 : ereport(ERROR,
303 : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
304 : errmsg("requested length too large")));
305 :
306 190 : ret = (text *) palloc(bytelen);
307 :
308 190 : m = len - s1len;
309 :
310 190 : ptr1 = VARDATA_ANY(string1);
311 :
312 190 : ptr_ret = VARDATA(ret);
313 :
314 3234 : while (s1len--)
315 : {
316 3044 : int mlen = pg_mblen_unbounded(ptr1);
317 :
318 3044 : memcpy(ptr_ret, ptr1, mlen);
319 3044 : ptr_ret += mlen;
320 3044 : ptr1 += mlen;
321 : }
322 :
323 190 : ptr2 = ptr2start = VARDATA_ANY(string2);
324 190 : ptr2end = ptr2 + s2len;
325 :
326 961912 : while (m--)
327 : {
328 961722 : int mlen = pg_mblen_range(ptr2, ptr2end);
329 :
330 961722 : memcpy(ptr_ret, ptr2, mlen);
331 961722 : ptr_ret += mlen;
332 961722 : ptr2 += mlen;
333 961722 : if (ptr2 == ptr2end) /* wrap around at end of s2 */
334 961710 : ptr2 = ptr2start;
335 : }
336 :
337 190 : SET_VARSIZE(ret, ptr_ret - (char *) ret);
338 :
339 190 : PG_RETURN_TEXT_P(ret);
340 : }
341 :
342 :
343 : /********************************************************************
344 : *
345 : * btrim
346 : *
347 : * Syntax:
348 : *
349 : * text btrim(text string, text set)
350 : *
351 : * Purpose:
352 : *
353 : * Returns string with characters removed from the front and back
354 : * up to the first character not in set.
355 : *
356 : ********************************************************************/
357 :
358 : Datum
359 10 : btrim(PG_FUNCTION_ARGS)
360 : {
361 10 : text *string = PG_GETARG_TEXT_PP(0);
362 10 : text *set = PG_GETARG_TEXT_PP(1);
363 : text *ret;
364 :
365 10 : ret = dotrim(VARDATA_ANY(string), VARSIZE_ANY_EXHDR(string),
366 10 : VARDATA_ANY(set), VARSIZE_ANY_EXHDR(set),
367 : true, true);
368 :
369 10 : PG_RETURN_TEXT_P(ret);
370 : }
371 :
372 : /********************************************************************
373 : *
374 : * btrim1 --- btrim with set fixed as ' '
375 : *
376 : ********************************************************************/
377 :
378 : Datum
379 281 : btrim1(PG_FUNCTION_ARGS)
380 : {
381 281 : text *string = PG_GETARG_TEXT_PP(0);
382 : text *ret;
383 :
384 281 : ret = dotrim(VARDATA_ANY(string), VARSIZE_ANY_EXHDR(string),
385 : " ", 1,
386 : true, true);
387 :
388 281 : PG_RETURN_TEXT_P(ret);
389 : }
390 :
391 : /*
392 : * Common implementation for btrim, ltrim, rtrim
393 : */
394 : static text *
395 17167 : dotrim(const char *string, int stringlen,
396 : const char *set, int setlen,
397 : bool doltrim, bool dortrim)
398 : {
399 : int i;
400 :
401 : /* Nothing to do if either string or set is empty */
402 17167 : if (stringlen > 0 && setlen > 0)
403 : {
404 17167 : if (pg_database_encoding_max_length() > 1)
405 : {
406 : /*
407 : * In the multibyte-encoding case, build arrays of pointers to
408 : * character starts, so that we can avoid inefficient checks in
409 : * the inner loops.
410 : */
411 : const char **stringchars;
412 : const char **setchars;
413 : const char *setend;
414 : int *stringmblen;
415 : int *setmblen;
416 : int stringnchars;
417 : int setnchars;
418 : int resultndx;
419 : int resultnchars;
420 : const char *p;
421 : const char *pend;
422 : int len;
423 : int mblen;
424 : const char *str_pos;
425 : int str_len;
426 :
427 17156 : stringchars = (const char **) palloc(stringlen * sizeof(char *));
428 17156 : stringmblen = (int *) palloc(stringlen * sizeof(int));
429 17156 : stringnchars = 0;
430 17156 : p = string;
431 17156 : len = stringlen;
432 17156 : pend = p + len;
433 152714 : while (len > 0)
434 : {
435 135558 : stringchars[stringnchars] = p;
436 135558 : stringmblen[stringnchars] = mblen = pg_mblen_range(p, pend);
437 135558 : stringnchars++;
438 135558 : p += mblen;
439 135558 : len -= mblen;
440 : }
441 :
442 17156 : setchars = (const char **) palloc(setlen * sizeof(char *));
443 17156 : setmblen = (int *) palloc(setlen * sizeof(int));
444 17156 : setnchars = 0;
445 17156 : p = set;
446 17156 : len = setlen;
447 17156 : setend = set + setlen;
448 34759 : while (len > 0)
449 : {
450 17603 : setchars[setnchars] = p;
451 17603 : setmblen[setnchars] = mblen = pg_mblen_range(p, setend);
452 17603 : setnchars++;
453 17603 : p += mblen;
454 17603 : len -= mblen;
455 : }
456 :
457 17156 : resultndx = 0; /* index in stringchars[] */
458 17156 : resultnchars = stringnchars;
459 :
460 17156 : if (doltrim)
461 : {
462 28294 : while (resultnchars > 0)
463 : {
464 28294 : str_pos = stringchars[resultndx];
465 28294 : str_len = stringmblen[resultndx];
466 42605 : for (i = 0; i < setnchars; i++)
467 : {
468 28354 : if (str_len == setmblen[i] &&
469 28354 : memcmp(str_pos, setchars[i], str_len) == 0)
470 14043 : break;
471 : }
472 28294 : if (i >= setnchars)
473 14251 : break; /* no match here */
474 14043 : string += str_len;
475 14043 : stringlen -= str_len;
476 14043 : resultndx++;
477 14043 : resultnchars--;
478 : }
479 : }
480 :
481 17156 : if (dortrim)
482 : {
483 37356 : while (resultnchars > 0)
484 : {
485 37356 : str_pos = stringchars[resultndx + resultnchars - 1];
486 37356 : str_len = stringmblen[resultndx + resultnchars - 1];
487 42001 : for (i = 0; i < setnchars; i++)
488 : {
489 38805 : if (str_len == setmblen[i] &&
490 38805 : memcmp(str_pos, setchars[i], str_len) == 0)
491 34160 : break;
492 : }
493 37356 : if (i >= setnchars)
494 3196 : break; /* no match here */
495 34160 : stringlen -= str_len;
496 34160 : resultnchars--;
497 : }
498 : }
499 :
500 17156 : pfree(stringchars);
501 17156 : pfree(stringmblen);
502 17156 : pfree(setchars);
503 17156 : pfree(setmblen);
504 : }
505 : else
506 : {
507 : /*
508 : * In the single-byte-encoding case, we don't need such overhead.
509 : */
510 11 : if (doltrim)
511 : {
512 0 : while (stringlen > 0)
513 : {
514 0 : char str_ch = *string;
515 :
516 0 : for (i = 0; i < setlen; i++)
517 : {
518 0 : if (str_ch == set[i])
519 0 : break;
520 : }
521 0 : if (i >= setlen)
522 0 : break; /* no match here */
523 0 : string++;
524 0 : stringlen--;
525 : }
526 : }
527 :
528 11 : if (dortrim)
529 : {
530 22 : while (stringlen > 0)
531 : {
532 22 : char str_ch = string[stringlen - 1];
533 :
534 33 : for (i = 0; i < setlen; i++)
535 : {
536 22 : if (str_ch == set[i])
537 11 : break;
538 : }
539 22 : if (i >= setlen)
540 11 : break; /* no match here */
541 11 : stringlen--;
542 : }
543 : }
544 : }
545 : }
546 :
547 : /* Return selected portion of string */
548 17167 : return cstring_to_text_with_len(string, stringlen);
549 : }
550 :
551 : /*
552 : * Common implementation for bytea versions of btrim, ltrim, rtrim
553 : */
554 : bytea *
555 18 : dobyteatrim(bytea *string, bytea *set, bool doltrim, bool dortrim)
556 : {
557 : bytea *ret;
558 : char *ptr,
559 : *end,
560 : *ptr2,
561 : *ptr2start,
562 : *end2;
563 : int m,
564 : stringlen,
565 : setlen;
566 :
567 18 : stringlen = VARSIZE_ANY_EXHDR(string);
568 18 : setlen = VARSIZE_ANY_EXHDR(set);
569 :
570 18 : if (stringlen <= 0 || setlen <= 0)
571 6 : return string;
572 :
573 12 : m = stringlen;
574 12 : ptr = VARDATA_ANY(string);
575 12 : end = ptr + stringlen - 1;
576 12 : ptr2start = VARDATA_ANY(set);
577 12 : end2 = ptr2start + setlen - 1;
578 :
579 12 : if (doltrim)
580 : {
581 18 : while (m > 0)
582 : {
583 18 : ptr2 = ptr2start;
584 27 : while (ptr2 <= end2)
585 : {
586 18 : if (*ptr == *ptr2)
587 9 : break;
588 9 : ++ptr2;
589 : }
590 18 : if (ptr2 > end2)
591 9 : break;
592 9 : ptr++;
593 9 : m--;
594 : }
595 : }
596 :
597 12 : if (dortrim)
598 : {
599 18 : while (m > 0)
600 : {
601 18 : ptr2 = ptr2start;
602 27 : while (ptr2 <= end2)
603 : {
604 18 : if (*end == *ptr2)
605 9 : break;
606 9 : ++ptr2;
607 : }
608 18 : if (ptr2 > end2)
609 9 : break;
610 9 : end--;
611 9 : m--;
612 : }
613 : }
614 :
615 12 : ret = (bytea *) palloc(VARHDRSZ + m);
616 12 : SET_VARSIZE(ret, VARHDRSZ + m);
617 12 : memcpy(VARDATA(ret), ptr, m);
618 12 : return ret;
619 : }
620 :
621 : /********************************************************************
622 : *
623 : * byteatrim
624 : *
625 : * Syntax:
626 : *
627 : * bytea byteatrim(bytea string, bytea set)
628 : *
629 : * Purpose:
630 : *
631 : * Returns string with characters removed from the front and back
632 : * up to the first character not in set.
633 : *
634 : * Cloned from btrim and modified as required.
635 : ********************************************************************/
636 :
637 : Datum
638 12 : byteatrim(PG_FUNCTION_ARGS)
639 : {
640 12 : bytea *string = PG_GETARG_BYTEA_PP(0);
641 12 : bytea *set = PG_GETARG_BYTEA_PP(1);
642 : bytea *ret;
643 :
644 12 : ret = dobyteatrim(string, set, true, true);
645 :
646 12 : PG_RETURN_BYTEA_P(ret);
647 : }
648 :
649 : /********************************************************************
650 : *
651 : * bytealtrim
652 : *
653 : * Syntax:
654 : *
655 : * bytea bytealtrim(bytea string, bytea set)
656 : *
657 : * Purpose:
658 : *
659 : * Returns string with initial characters removed up to the first
660 : * character not in set.
661 : *
662 : ********************************************************************/
663 :
664 : Datum
665 3 : bytealtrim(PG_FUNCTION_ARGS)
666 : {
667 3 : bytea *string = PG_GETARG_BYTEA_PP(0);
668 3 : bytea *set = PG_GETARG_BYTEA_PP(1);
669 : bytea *ret;
670 :
671 3 : ret = dobyteatrim(string, set, true, false);
672 :
673 3 : PG_RETURN_BYTEA_P(ret);
674 : }
675 :
676 : /********************************************************************
677 : *
678 : * byteartrim
679 : *
680 : * Syntax:
681 : *
682 : * bytea byteartrim(bytea string, bytea set)
683 : *
684 : * Purpose:
685 : *
686 : * Returns string with final characters removed after the last
687 : * character not in set.
688 : *
689 : ********************************************************************/
690 :
691 : Datum
692 3 : byteartrim(PG_FUNCTION_ARGS)
693 : {
694 3 : bytea *string = PG_GETARG_BYTEA_PP(0);
695 3 : bytea *set = PG_GETARG_BYTEA_PP(1);
696 : bytea *ret;
697 :
698 3 : ret = dobyteatrim(string, set, false, true);
699 :
700 3 : PG_RETURN_BYTEA_P(ret);
701 : }
702 :
703 : /********************************************************************
704 : *
705 : * ltrim
706 : *
707 : * Syntax:
708 : *
709 : * text ltrim(text string, text set)
710 : *
711 : * Purpose:
712 : *
713 : * Returns string with initial characters removed up to the first
714 : * character not in set.
715 : *
716 : ********************************************************************/
717 :
718 : Datum
719 13956 : ltrim(PG_FUNCTION_ARGS)
720 : {
721 13956 : text *string = PG_GETARG_TEXT_PP(0);
722 13956 : text *set = PG_GETARG_TEXT_PP(1);
723 : text *ret;
724 :
725 13956 : ret = dotrim(VARDATA_ANY(string), VARSIZE_ANY_EXHDR(string),
726 13956 : VARDATA_ANY(set), VARSIZE_ANY_EXHDR(set),
727 : true, false);
728 :
729 13956 : PG_RETURN_TEXT_P(ret);
730 : }
731 :
732 : /********************************************************************
733 : *
734 : * ltrim1 --- ltrim with set fixed as ' '
735 : *
736 : ********************************************************************/
737 :
738 : Datum
739 4 : ltrim1(PG_FUNCTION_ARGS)
740 : {
741 4 : text *string = PG_GETARG_TEXT_PP(0);
742 : text *ret;
743 :
744 4 : ret = dotrim(VARDATA_ANY(string), VARSIZE_ANY_EXHDR(string),
745 : " ", 1,
746 : true, false);
747 :
748 4 : PG_RETURN_TEXT_P(ret);
749 : }
750 :
751 : /********************************************************************
752 : *
753 : * rtrim
754 : *
755 : * Syntax:
756 : *
757 : * text rtrim(text string, text set)
758 : *
759 : * Purpose:
760 : *
761 : * Returns string with final characters removed after the last
762 : * character not in set.
763 : *
764 : ********************************************************************/
765 :
766 : Datum
767 154 : rtrim(PG_FUNCTION_ARGS)
768 : {
769 154 : text *string = PG_GETARG_TEXT_PP(0);
770 154 : text *set = PG_GETARG_TEXT_PP(1);
771 : text *ret;
772 :
773 154 : ret = dotrim(VARDATA_ANY(string), VARSIZE_ANY_EXHDR(string),
774 154 : VARDATA_ANY(set), VARSIZE_ANY_EXHDR(set),
775 : false, true);
776 :
777 154 : PG_RETURN_TEXT_P(ret);
778 : }
779 :
780 : /********************************************************************
781 : *
782 : * rtrim1 --- rtrim with set fixed as ' '
783 : *
784 : ********************************************************************/
785 :
786 : Datum
787 2762 : rtrim1(PG_FUNCTION_ARGS)
788 : {
789 2762 : text *string = PG_GETARG_TEXT_PP(0);
790 : text *ret;
791 :
792 2762 : ret = dotrim(VARDATA_ANY(string), VARSIZE_ANY_EXHDR(string),
793 : " ", 1,
794 : false, true);
795 :
796 2762 : PG_RETURN_TEXT_P(ret);
797 : }
798 :
799 :
800 : /********************************************************************
801 : *
802 : * translate
803 : *
804 : * Syntax:
805 : *
806 : * text translate(text string, text from, text to)
807 : *
808 : * Purpose:
809 : *
810 : * Returns string after replacing all occurrences of characters in from
811 : * with the corresponding character in to. If from is longer than to,
812 : * occurrences of the extra characters in from are deleted.
813 : * Improved by Edwin Ramirez <ramirez@doc.mssm.edu>.
814 : *
815 : ********************************************************************/
816 :
817 : Datum
818 17 : translate(PG_FUNCTION_ARGS)
819 : {
820 17 : text *string = PG_GETARG_TEXT_PP(0);
821 17 : text *from = PG_GETARG_TEXT_PP(1);
822 17 : text *to = PG_GETARG_TEXT_PP(2);
823 : text *result;
824 : char *from_ptr,
825 : *to_ptr,
826 : *to_end;
827 : char *source,
828 : *target;
829 : const char *source_end;
830 : const char *from_end;
831 : int m,
832 : fromlen,
833 : tolen,
834 : retlen,
835 : i;
836 : int bytelen;
837 : int len;
838 : int source_len;
839 : int from_index;
840 :
841 17 : m = VARSIZE_ANY_EXHDR(string);
842 17 : if (m <= 0)
843 3 : PG_RETURN_TEXT_P(string);
844 14 : source = VARDATA_ANY(string);
845 14 : source_end = source + m;
846 :
847 14 : fromlen = VARSIZE_ANY_EXHDR(from);
848 14 : from_ptr = VARDATA_ANY(from);
849 14 : from_end = from_ptr + fromlen;
850 14 : tolen = VARSIZE_ANY_EXHDR(to);
851 14 : to_ptr = VARDATA_ANY(to);
852 14 : to_end = to_ptr + tolen;
853 :
854 : /*
855 : * The worst-case expansion is to substitute a max-length character for a
856 : * single-byte character at each position of the string.
857 : */
858 14 : if (unlikely(pg_mul_s32_overflow(pg_database_encoding_max_length(), m,
859 14 : &bytelen)) ||
860 14 : unlikely(pg_add_s32_overflow(bytelen, VARHDRSZ, &bytelen)) ||
861 14 : unlikely(!AllocSizeIsValid(bytelen)))
862 0 : ereport(ERROR,
863 : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
864 : errmsg("requested length too large")));
865 :
866 14 : result = (text *) palloc(bytelen);
867 :
868 14 : target = VARDATA(result);
869 14 : retlen = 0;
870 :
871 140 : while (m > 0)
872 : {
873 126 : source_len = pg_mblen_range(source, source_end);
874 126 : from_index = 0;
875 :
876 342 : for (i = 0; i < fromlen; i += len)
877 : {
878 247 : len = pg_mblen_range(&from_ptr[i], from_end);
879 247 : if (len == source_len &&
880 247 : memcmp(source, &from_ptr[i], len) == 0)
881 31 : break;
882 :
883 216 : from_index++;
884 : }
885 126 : if (i < fromlen)
886 : {
887 : /* substitute, or delete if no corresponding "to" character */
888 31 : char *p = to_ptr;
889 :
890 48 : for (i = 0; i < from_index; i++)
891 : {
892 20 : if (p >= to_end)
893 3 : break;
894 17 : p += pg_mblen_range(p, to_end);
895 : }
896 31 : if (p < to_end)
897 : {
898 25 : len = pg_mblen_range(p, to_end);
899 25 : memcpy(target, p, len);
900 25 : target += len;
901 25 : retlen += len;
902 : }
903 : }
904 : else
905 : {
906 : /* no match, so copy */
907 95 : memcpy(target, source, source_len);
908 95 : target += source_len;
909 95 : retlen += source_len;
910 : }
911 :
912 126 : source += source_len;
913 126 : m -= source_len;
914 : }
915 :
916 14 : SET_VARSIZE(result, retlen + VARHDRSZ);
917 :
918 : /*
919 : * The function result is probably much bigger than needed, if we're using
920 : * a multibyte encoding, but it's not worth reallocating it; the result
921 : * probably won't live long anyway.
922 : */
923 :
924 14 : PG_RETURN_TEXT_P(result);
925 : }
926 :
927 : /********************************************************************
928 : *
929 : * ascii
930 : *
931 : * Syntax:
932 : *
933 : * int ascii(text string)
934 : *
935 : * Purpose:
936 : *
937 : * Returns the decimal representation of the first character from
938 : * string.
939 : * If the string is empty we return 0.
940 : * If the database encoding is UTF8, we return the Unicode codepoint.
941 : * If the database encoding is any other multi-byte encoding, we
942 : * return the value of the first byte if it is an ASCII character
943 : * (range 1 .. 127), or raise an error.
944 : * For all other encodings we return the value of the first byte,
945 : * (range 1..255).
946 : *
947 : ********************************************************************/
948 :
949 : Datum
950 29 : ascii(PG_FUNCTION_ARGS)
951 : {
952 29 : text *string = PG_GETARG_TEXT_PP(0);
953 29 : int encoding = GetDatabaseEncoding();
954 : unsigned char *data;
955 :
956 29 : if (VARSIZE_ANY_EXHDR(string) <= 0)
957 3 : PG_RETURN_INT32(0);
958 :
959 26 : data = (unsigned char *) VARDATA_ANY(string);
960 :
961 26 : if (encoding == PG_UTF8 && *data > 127)
962 : {
963 : /* return the code point for Unicode */
964 :
965 0 : int result = 0,
966 0 : tbytes = 0,
967 : i;
968 :
969 0 : if (*data >= 0xF0)
970 : {
971 0 : result = *data & 0x07;
972 0 : tbytes = 3;
973 : }
974 0 : else if (*data >= 0xE0)
975 : {
976 0 : result = *data & 0x0F;
977 0 : tbytes = 2;
978 : }
979 : else
980 : {
981 : Assert(*data > 0xC0);
982 0 : result = *data & 0x1f;
983 0 : tbytes = 1;
984 : }
985 :
986 : Assert(tbytes > 0);
987 :
988 0 : for (i = 1; i <= tbytes; i++)
989 : {
990 : Assert((data[i] & 0xC0) == 0x80);
991 0 : result = (result << 6) + (data[i] & 0x3f);
992 : }
993 :
994 0 : PG_RETURN_INT32(result);
995 : }
996 : else
997 : {
998 26 : if (pg_encoding_max_length(encoding) > 1 && *data > 127)
999 0 : ereport(ERROR,
1000 : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1001 : errmsg("requested character too large")));
1002 :
1003 :
1004 26 : PG_RETURN_INT32((int32) *data);
1005 : }
1006 : }
1007 :
1008 : /********************************************************************
1009 : *
1010 : * chr
1011 : *
1012 : * Syntax:
1013 : *
1014 : * text chr(int val)
1015 : *
1016 : * Purpose:
1017 : *
1018 : * Returns the character having the binary equivalent to val.
1019 : *
1020 : * For UTF8 we treat the argument as a Unicode code point.
1021 : * For other multi-byte encodings we raise an error for arguments
1022 : * outside the strict ASCII range (1..127).
1023 : *
1024 : * It's important that we don't ever return a value that is not valid
1025 : * in the database encoding, so that this doesn't become a way for
1026 : * invalid data to enter the database.
1027 : *
1028 : ********************************************************************/
1029 :
1030 : Datum
1031 272536 : chr (PG_FUNCTION_ARGS)
1032 : {
1033 272536 : int32 arg = PG_GETARG_INT32(0);
1034 : uint32 cvalue;
1035 : text *result;
1036 272536 : int encoding = GetDatabaseEncoding();
1037 :
1038 : /*
1039 : * Error out on arguments that make no sense or that we can't validly
1040 : * represent in the encoding.
1041 : */
1042 272536 : if (arg < 0)
1043 0 : ereport(ERROR,
1044 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1045 : errmsg("character number must be positive")));
1046 272536 : else if (arg == 0)
1047 3 : ereport(ERROR,
1048 : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1049 : errmsg("null character not permitted")));
1050 :
1051 272533 : cvalue = arg;
1052 :
1053 272533 : if (encoding == PG_UTF8 && cvalue > 127)
1054 0 : {
1055 : /* for Unicode we treat the argument as a code point */
1056 : int bytes;
1057 : unsigned char *wch;
1058 :
1059 : /*
1060 : * We only allow valid Unicode code points; per RFC3629 that stops at
1061 : * U+10FFFF, even though 4-byte UTF8 sequences can hold values up to
1062 : * U+1FFFFF.
1063 : */
1064 0 : if (cvalue > 0x0010ffff)
1065 0 : ereport(ERROR,
1066 : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1067 : errmsg("requested character too large for encoding: %u",
1068 : cvalue)));
1069 :
1070 0 : if (cvalue > 0xffff)
1071 0 : bytes = 4;
1072 0 : else if (cvalue > 0x07ff)
1073 0 : bytes = 3;
1074 : else
1075 0 : bytes = 2;
1076 :
1077 0 : result = (text *) palloc(VARHDRSZ + bytes);
1078 0 : SET_VARSIZE(result, VARHDRSZ + bytes);
1079 0 : wch = (unsigned char *) VARDATA(result);
1080 :
1081 0 : if (bytes == 2)
1082 : {
1083 0 : wch[0] = 0xC0 | ((cvalue >> 6) & 0x1F);
1084 0 : wch[1] = 0x80 | (cvalue & 0x3F);
1085 : }
1086 0 : else if (bytes == 3)
1087 : {
1088 0 : wch[0] = 0xE0 | ((cvalue >> 12) & 0x0F);
1089 0 : wch[1] = 0x80 | ((cvalue >> 6) & 0x3F);
1090 0 : wch[2] = 0x80 | (cvalue & 0x3F);
1091 : }
1092 : else
1093 : {
1094 0 : wch[0] = 0xF0 | ((cvalue >> 18) & 0x07);
1095 0 : wch[1] = 0x80 | ((cvalue >> 12) & 0x3F);
1096 0 : wch[2] = 0x80 | ((cvalue >> 6) & 0x3F);
1097 0 : wch[3] = 0x80 | (cvalue & 0x3F);
1098 : }
1099 :
1100 : /*
1101 : * The preceding range check isn't sufficient, because UTF8 excludes
1102 : * Unicode "surrogate pair" codes. Make sure what we created is valid
1103 : * UTF8.
1104 : */
1105 0 : if (!pg_utf8_islegal(wch, bytes))
1106 0 : ereport(ERROR,
1107 : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1108 : errmsg("requested character not valid for encoding: %u",
1109 : cvalue)));
1110 : }
1111 : else
1112 : {
1113 : bool is_mb;
1114 :
1115 272533 : is_mb = pg_encoding_max_length(encoding) > 1;
1116 :
1117 272533 : if ((is_mb && (cvalue > 127)) || (!is_mb && (cvalue > 255)))
1118 0 : ereport(ERROR,
1119 : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1120 : errmsg("requested character too large for encoding: %u",
1121 : cvalue)));
1122 :
1123 272533 : result = (text *) palloc(VARHDRSZ + 1);
1124 272533 : SET_VARSIZE(result, VARHDRSZ + 1);
1125 272533 : *VARDATA(result) = (char) cvalue;
1126 : }
1127 :
1128 272533 : PG_RETURN_TEXT_P(result);
1129 : }
1130 :
1131 : /********************************************************************
1132 : *
1133 : * repeat
1134 : *
1135 : * Syntax:
1136 : *
1137 : * text repeat(text string, int val)
1138 : *
1139 : * Purpose:
1140 : *
1141 : * Repeat string by val.
1142 : *
1143 : ********************************************************************/
1144 :
1145 : Datum
1146 115196 : repeat(PG_FUNCTION_ARGS)
1147 : {
1148 115196 : text *string = PG_GETARG_TEXT_PP(0);
1149 115196 : int32 count = PG_GETARG_INT32(1);
1150 : text *result;
1151 : int slen,
1152 : tlen;
1153 : int i;
1154 : char *cp,
1155 : *sp;
1156 :
1157 115196 : if (count < 0)
1158 3 : count = 0;
1159 :
1160 115196 : slen = VARSIZE_ANY_EXHDR(string);
1161 :
1162 115196 : if (unlikely(pg_mul_s32_overflow(count, slen, &tlen)) ||
1163 115196 : unlikely(pg_add_s32_overflow(tlen, VARHDRSZ, &tlen)) ||
1164 115196 : unlikely(!AllocSizeIsValid(tlen)))
1165 0 : ereport(ERROR,
1166 : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1167 : errmsg("requested length too large")));
1168 :
1169 115196 : result = (text *) palloc(tlen);
1170 :
1171 115196 : SET_VARSIZE(result, tlen);
1172 115196 : cp = VARDATA(result);
1173 115196 : sp = VARDATA_ANY(string);
1174 25073019 : for (i = 0; i < count; i++)
1175 : {
1176 24957823 : memcpy(cp, sp, slen);
1177 24957823 : cp += slen;
1178 24957823 : CHECK_FOR_INTERRUPTS();
1179 : }
1180 :
1181 115196 : PG_RETURN_TEXT_P(result);
1182 : }
|