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