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