Age Owner Branch data TLA 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
9383 tgl@sss.pgh.pa.us 49 :CBC 75463 : lower(PG_FUNCTION_ARGS)
50 : : {
6121 bruce@momjian.us 51 : 75463 : text *in_string = PG_GETARG_TEXT_PP(0);
52 : : char *out_string;
53 : : text *result;
54 : :
6455 tgl@sss.pgh.pa.us 55 [ + + ]: 75463 : out_string = str_tolower(VARDATA_ANY(in_string),
5514 peter_e@gmx.net 56 [ - + - - :ECB (90938) : VARSIZE_ANY_EXHDR(in_string),
- - - - +
+ ]
57 : : PG_GET_COLLATION());
6474 bruce@momjian.us 58 :CBC 75463 : result = cstring_to_text(out_string);
59 : 75463 : pfree(out_string);
60 : :
61 : 75463 : 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
9383 tgl@sss.pgh.pa.us 80 : 527651 : upper(PG_FUNCTION_ARGS)
81 : : {
6121 bruce@momjian.us 82 : 527651 : text *in_string = PG_GETARG_TEXT_PP(0);
83 : : char *out_string;
84 : : text *result;
85 : :
6455 tgl@sss.pgh.pa.us 86 [ + + ]: 527651 : out_string = str_toupper(VARDATA_ANY(in_string),
5514 peter_e@gmx.net 87 [ - + - - :ECB (525480) : VARSIZE_ANY_EXHDR(in_string),
- - - - +
+ ]
88 : : PG_GET_COLLATION());
6474 bruce@momjian.us 89 :CBC 527651 : result = cstring_to_text(out_string);
90 : 527651 : pfree(out_string);
91 : :
92 : 527651 : 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
9383 tgl@sss.pgh.pa.us 114 : 113 : initcap(PG_FUNCTION_ARGS)
115 : : {
6121 bruce@momjian.us 116 : 113 : text *in_string = PG_GETARG_TEXT_PP(0);
117 : : char *out_string;
118 : : text *result;
119 : :
6455 tgl@sss.pgh.pa.us 120 [ + + ]: 113 : out_string = str_initcap(VARDATA_ANY(in_string),
5514 peter_e@gmx.net 121 [ - + - - :ECB (113) : VARSIZE_ANY_EXHDR(in_string),
- - - - +
+ ]
122 : : PG_GET_COLLATION());
6474 bruce@momjian.us 123 :CBC 113 : result = cstring_to_text(out_string);
124 : 113 : pfree(out_string);
125 : :
126 : 113 : PG_RETURN_TEXT_P(result);
127 : : }
128 : :
129 : : Datum
415 jdavis@postgresql.or 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),
415 jdavis@postgresql.or 137 [ - + - - :ECB (12) : VARSIZE_ANY_EXHDR(in_string),
- - - - -
+ ]
138 : : PG_GET_COLLATION());
415 jdavis@postgresql.or 139 :CBC 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
9406 tgl@sss.pgh.pa.us 163 : 16655 : lpad(PG_FUNCTION_ARGS)
164 : : {
6750 165 : 16655 : text *string1 = PG_GETARG_TEXT_PP(0);
9406 166 : 16655 : int32 len = PG_GETARG_INT32(1);
6750 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 */
9229 180 [ + + ]: 16655 : if (len < 0)
181 : 3 : len = 0;
182 : :
6750 183 [ - + - - : 16655 : s1len = VARSIZE_ANY_EXHDR(string1);
- - - - -
+ ]
9229 184 [ - + ]: 16655 : if (s1len < 0)
9229 tgl@sss.pgh.pa.us 185 :UBC 0 : s1len = 0; /* shouldn't happen */
186 : :
6750 tgl@sss.pgh.pa.us 187 [ - + - - :CBC 16655 : s2len = VARSIZE_ANY_EXHDR(string2);
- - - - -
+ ]
9229 188 [ - + ]: 16655 : if (s2len < 0)
9229 tgl@sss.pgh.pa.us 189 :UBC 0 : s2len = 0; /* shouldn't happen */
190 : :
6750 tgl@sss.pgh.pa.us 191 [ - + ]:CBC 16655 : s1len = pg_mbstrlen_with_len(VARDATA_ANY(string1), s1len);
192 : :
9229 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 */
1389 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)))
8267 tgl@sss.pgh.pa.us 204 [ # # ]:UBC 0 : ereport(ERROR,
205 : : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
206 : : errmsg("requested length too large")));
207 : :
1389 tgl@sss.pgh.pa.us 208 :CBC 16655 : ret = (text *) palloc(bytelen);
209 : :
9229 210 : 16655 : m = len - s1len;
211 : :
6750 212 [ - + ]: 16655 : ptr2 = ptr2start = VARDATA_ANY(string2);
9229 213 : 16655 : ptr2end = ptr2 + s2len;
10416 bruce@momjian.us 214 : 16655 : ptr_ret = VARDATA(ret);
215 : :
8939 ishii@postgresql.org 216 [ + + ]: 17869 : while (m--)
217 : : {
67 tmunro@postgresql.or 218 : 1214 : int mlen = pg_mblen_range(ptr2, ptr2end);
219 : :
8907 bruce@momjian.us 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 */
6750 tgl@sss.pgh.pa.us 224 : 1202 : ptr2 = ptr2start;
225 : : }
226 : :
227 [ - + ]: 16655 : ptr1 = VARDATA_ANY(string1);
228 : :
8939 ishii@postgresql.org 229 [ + + ]: 48955 : while (s1len--)
230 : : {
67 tmunro@postgresql.or 231 : 32300 : int mlen = pg_mblen_unbounded(ptr1);
232 : :
8907 bruce@momjian.us 233 : 32300 : memcpy(ptr_ret, ptr1, mlen);
234 : 32300 : ptr_ret += mlen;
235 : 32300 : ptr1 += mlen;
236 : : }
237 : :
6956 tgl@sss.pgh.pa.us 238 : 16655 : SET_VARSIZE(ret, ptr_ret - (char *) ret);
239 : :
9406 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 : : {
6750 263 : 190 : text *string1 = PG_GETARG_TEXT_PP(0);
9406 264 : 190 : int32 len = PG_GETARG_INT32(1);
6750 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 */
9229 278 [ + + ]: 190 : if (len < 0)
279 : 3 : len = 0;
280 : :
6750 281 [ - + - - : 190 : s1len = VARSIZE_ANY_EXHDR(string1);
- - - - -
+ ]
9229 282 [ - + ]: 190 : if (s1len < 0)
9229 tgl@sss.pgh.pa.us 283 :UBC 0 : s1len = 0; /* shouldn't happen */
284 : :
6750 tgl@sss.pgh.pa.us 285 [ - + - - :CBC 190 : s2len = VARSIZE_ANY_EXHDR(string2);
- - - - -
+ ]
9229 286 [ - + ]: 190 : if (s2len < 0)
9229 tgl@sss.pgh.pa.us 287 :UBC 0 : s2len = 0; /* shouldn't happen */
288 : :
6750 tgl@sss.pgh.pa.us 289 [ - + ]:CBC 190 : s1len = pg_mbstrlen_with_len(VARDATA_ANY(string1), s1len);
290 : :
9229 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 */
1389 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)))
8267 tgl@sss.pgh.pa.us 302 [ # # ]:UBC 0 : ereport(ERROR,
303 : : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
304 : : errmsg("requested length too large")));
305 : :
1389 tgl@sss.pgh.pa.us 306 :CBC 190 : ret = (text *) palloc(bytelen);
307 : :
9229 308 : 190 : m = len - s1len;
309 : :
6750 310 [ - + ]: 190 : ptr1 = VARDATA_ANY(string1);
311 : :
10416 bruce@momjian.us 312 : 190 : ptr_ret = VARDATA(ret);
313 : :
8939 ishii@postgresql.org 314 [ + + ]: 3234 : while (s1len--)
315 : : {
67 tmunro@postgresql.or 316 : 3044 : int mlen = pg_mblen_unbounded(ptr1);
317 : :
8907 bruce@momjian.us 318 : 3044 : memcpy(ptr_ret, ptr1, mlen);
319 : 3044 : ptr_ret += mlen;
320 : 3044 : ptr1 += mlen;
321 : : }
322 : :
6750 tgl@sss.pgh.pa.us 323 [ - + ]: 190 : ptr2 = ptr2start = VARDATA_ANY(string2);
9229 324 : 190 : ptr2end = ptr2 + s2len;
325 : :
8939 ishii@postgresql.org 326 [ + + ]: 961912 : while (m--)
327 : : {
67 tmunro@postgresql.or 328 : 961722 : int mlen = pg_mblen_range(ptr2, ptr2end);
329 : :
8907 bruce@momjian.us 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 */
6750 tgl@sss.pgh.pa.us 334 : 961710 : ptr2 = ptr2start;
335 : : }
336 : :
6956 337 : 190 : SET_VARSIZE(ret, ptr_ret - (char *) ret);
338 : :
9406 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
9383 359 : 10 : btrim(PG_FUNCTION_ARGS)
360 : : {
6750 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 : :
8332 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 : : {
6750 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 : :
8332 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;
67 tmunro@postgresql.or 432 : 17156 : pend = p + len;
8332 tgl@sss.pgh.pa.us 433 [ + + ]: 152714 : while (len > 0)
434 : : {
435 : 135558 : stringchars[stringnchars] = p;
67 tmunro@postgresql.or 436 : 135558 : stringmblen[stringnchars] = mblen = pg_mblen_range(p, pend);
8332 tgl@sss.pgh.pa.us 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;
67 tmunro@postgresql.or 447 : 17156 : setend = set + setlen;
8332 tgl@sss.pgh.pa.us 448 [ + + ]: 34759 : while (len > 0)
449 : : {
450 : 17603 : setchars[setnchars] = p;
67 tmunro@postgresql.or 451 : 17603 : setmblen[setnchars] = mblen = pg_mblen_range(p, setend);
8332 tgl@sss.pgh.pa.us 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 [ + + ]: 41657 : for (i = 0; i < setnchars; i++)
488 : : {
489 [ + - ]: 38461 : if (str_len == setmblen[i] &&
490 [ + + ]: 38461 : 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 : : {
8332 tgl@sss.pgh.pa.us 512 [ # # ]:UBC 0 : while (stringlen > 0)
513 : : {
8259 bruce@momjian.us 514 : 0 : char str_ch = *string;
515 : :
8332 tgl@sss.pgh.pa.us 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 : :
8332 tgl@sss.pgh.pa.us 528 [ + - ]:CBC 11 : if (dortrim)
529 : : {
530 [ + - ]: 22 : while (stringlen > 0)
531 : : {
8259 bruce@momjian.us 532 : 22 : char str_ch = string[stringlen - 1];
533 : :
8332 tgl@sss.pgh.pa.us 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 */
6564 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 *
1882 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 : :
6750 567 [ - + - - : 18 : stringlen = VARSIZE_ANY_EXHDR(string);
- - - - -
+ ]
568 [ - + - - : 18 : setlen = VARSIZE_ANY_EXHDR(set);
- - - - -
+ ]
569 : :
570 [ + + + + ]: 18 : if (stringlen <= 0 || setlen <= 0)
1882 571 : 6 : return string;
572 : :
6750 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 : :
1882 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)
8948 bruce@momjian.us 591 : 9 : break;
1882 tgl@sss.pgh.pa.us 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)
8948 bruce@momjian.us 609 : 9 : break;
1882 tgl@sss.pgh.pa.us 610 : 9 : end--;
611 : 9 : m--;
612 : : }
613 : : }
614 : :
8948 bruce@momjian.us 615 : 12 : ret = (bytea *) palloc(VARHDRSZ + m);
6956 tgl@sss.pgh.pa.us 616 : 12 : SET_VARSIZE(ret, VARHDRSZ + m);
8948 bruce@momjian.us 617 : 12 : memcpy(VARDATA(ret), ptr, m);
1882 tgl@sss.pgh.pa.us 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 : :
8948 bruce@momjian.us 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
9383 tgl@sss.pgh.pa.us 719 : 13956 : ltrim(PG_FUNCTION_ARGS)
720 : : {
6750 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 : :
8332 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 : : {
6750 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 : :
9383 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 : : {
6750 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 : :
8332 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 : : {
6750 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 : :
9383 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 : : {
6750 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)
9383 843 : 3 : PG_RETURN_TEXT_P(string);
6749 844 [ - + ]: 14 : source = VARDATA_ANY(string);
67 tmunro@postgresql.or 845 : 14 : source_end = source + m;
846 : :
6750 tgl@sss.pgh.pa.us 847 [ - + - - : 14 : fromlen = VARSIZE_ANY_EXHDR(from);
- - - - -
+ ]
848 [ - + ]: 14 : from_ptr = VARDATA_ANY(from);
67 tmunro@postgresql.or 849 : 14 : from_end = from_ptr + fromlen;
6750 tgl@sss.pgh.pa.us 850 [ - + - - : 14 : tolen = VARSIZE_ANY_EXHDR(to);
- - - - -
+ ]
851 [ - + ]: 14 : to_ptr = VARDATA_ANY(to);
1110 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 : : */
1389 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)))
6749 tgl@sss.pgh.pa.us 862 [ # # ]:UBC 0 : ereport(ERROR,
863 : : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
864 : : errmsg("requested length too large")));
865 : :
1389 tgl@sss.pgh.pa.us 866 :CBC 14 : result = (text *) palloc(bytelen);
867 : :
9496 868 : 14 : target = VARDATA(result);
9497 lockhart@fourpalms.o 869 : 14 : retlen = 0;
870 : :
8939 ishii@postgresql.org 871 [ + + ]: 140 : while (m > 0)
872 : : {
67 tmunro@postgresql.or 873 : 126 : source_len = pg_mblen_range(source, source_end);
8939 ishii@postgresql.org 874 : 126 : from_index = 0;
875 : :
876 [ + + ]: 342 : for (i = 0; i < fromlen; i += len)
877 : : {
67 tmunro@postgresql.or 878 : 247 : len = pg_mblen_range(&from_ptr[i], from_end);
8907 bruce@momjian.us 879 [ + - ]: 247 : if (len == source_len &&
880 [ + + ]: 247 : memcmp(source, &from_ptr[i], len) == 0)
881 : 31 : break;
882 : :
883 : 216 : from_index++;
884 : : }
8939 ishii@postgresql.org 885 [ + + ]: 126 : if (i < fromlen)
886 : : {
887 : : /* substitute, or delete if no corresponding "to" character */
8907 bruce@momjian.us 888 : 31 : char *p = to_ptr;
889 : :
890 [ + + ]: 48 : for (i = 0; i < from_index; i++)
891 : : {
1110 tgl@sss.pgh.pa.us 892 [ + + ]: 20 : if (p >= to_end)
8907 bruce@momjian.us 893 : 3 : break;
67 tmunro@postgresql.or 894 : 17 : p += pg_mblen_range(p, to_end);
895 : : }
1110 tgl@sss.pgh.pa.us 896 [ + + ]: 31 : if (p < to_end)
897 : : {
67 tmunro@postgresql.or 898 : 25 : len = pg_mblen_range(p, to_end);
8907 bruce@momjian.us 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 : :
8939 ishii@postgresql.org 912 : 126 : source += source_len;
913 : 126 : m -= source_len;
914 : : }
915 : :
6956 tgl@sss.pgh.pa.us 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 : :
9383 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 : : {
6750 952 : 29 : text *string = PG_GETARG_TEXT_PP(0);
6695 bruce@momjian.us 953 : 29 : int encoding = GetDatabaseEncoding();
954 : : unsigned char *data;
955 : :
6750 tgl@sss.pgh.pa.us 956 [ + + - - : 29 : if (VARSIZE_ANY_EXHDR(string) <= 0)
- - - - +
+ + + ]
9383 957 : 3 : PG_RETURN_INT32(0);
958 : :
6750 959 [ + + ]: 26 : data = (unsigned char *) VARDATA_ANY(string);
960 : :
6753 andrew@dunslane.net 961 [ + - - + ]: 26 : if (encoding == PG_UTF8 && *data > 127)
962 : : {
963 : : /* return the code point for Unicode */
964 : :
6695 bruce@momjian.us 965 :UBC 0 : int result = 0,
966 : 0 : tbytes = 0,
967 : : i;
968 : :
6753 andrew@dunslane.net 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 : : {
6695 bruce@momjian.us 981 [ # # ]: 0 : Assert(*data > 0xC0);
6753 andrew@dunslane.net 982 : 0 : result = *data & 0x1f;
983 : 0 : tbytes = 1;
984 : : }
985 : :
6695 bruce@momjian.us 986 [ # # ]: 0 : Assert(tbytes > 0);
987 : :
6753 andrew@dunslane.net 988 [ # # ]: 0 : for (i = 1; i <= tbytes; i++)
989 : : {
6695 bruce@momjian.us 990 [ # # ]: 0 : Assert((data[i] & 0xC0) == 0x80);
6753 andrew@dunslane.net 991 : 0 : result = (result << 6) + (data[i] & 0x3f);
992 : : }
993 : :
994 : 0 : PG_RETURN_INT32(result);
995 : : }
996 : : else
997 : : {
6753 andrew@dunslane.net 998 [ + - - + ]:CBC 26 : if (pg_encoding_max_length(encoding) > 1 && *data > 127)
6753 andrew@dunslane.net 999 [ # # ]:UBC 0 : ereport(ERROR,
1000 : : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1001 : : errmsg("requested character too large")));
1002 : :
1003 : :
6753 andrew@dunslane.net 1004 :CBC 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
6695 bruce@momjian.us 1031 : 272573 : chr (PG_FUNCTION_ARGS)
1032 : : {
1560 peter@eisentraut.org 1033 : 272573 : int32 arg = PG_GETARG_INT32(0);
1034 : : uint32 cvalue;
1035 : : text *result;
6695 bruce@momjian.us 1036 : 272573 : 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 : : */
1560 peter@eisentraut.org 1042 [ - + ]: 272573 : if (arg < 0)
1560 peter@eisentraut.org 1043 [ # # ]:UBC 0 : ereport(ERROR,
1044 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1045 : : errmsg("character number must be positive")));
1560 peter@eisentraut.org 1046 [ + + ]:CBC 272573 : else if (arg == 0)
1047 [ + - ]: 3 : ereport(ERROR,
1048 : : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1049 : : errmsg("null character not permitted")));
1050 : :
1051 : 272570 : cvalue = arg;
1052 : :
6753 andrew@dunslane.net 1053 [ + - - + ]: 272570 : if (encoding == PG_UTF8 && cvalue > 127)
6753 andrew@dunslane.net 1054 :UBC 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 : : */
4321 tgl@sss.pgh.pa.us 1064 [ # # ]: 0 : if (cvalue > 0x0010ffff)
6753 andrew@dunslane.net 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);
4321 tgl@sss.pgh.pa.us 1079 : 0 : wch = (unsigned char *) VARDATA(result);
1080 : :
6753 andrew@dunslane.net 1081 [ # # ]: 0 : if (bytes == 2)
1082 : : {
1083 : 0 : wch[0] = 0xC0 | ((cvalue >> 6) & 0x1F);
4002 heikki.linnakangas@i 1084 : 0 : wch[1] = 0x80 | (cvalue & 0x3F);
1085 : : }
6753 andrew@dunslane.net 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 : : */
4321 tgl@sss.pgh.pa.us 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 : :
6753 andrew@dunslane.net 1115 :CBC 272570 : is_mb = pg_encoding_max_length(encoding) > 1;
1116 : :
6662 1117 [ + - + - : 272570 : if ((is_mb && (cvalue > 127)) || (!is_mb && (cvalue > 255)))
- + - - ]
6753 andrew@dunslane.net 1118 [ # # ]:UBC 0 : ereport(ERROR,
1119 : : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1120 : : errmsg("requested character too large for encoding: %u",
1121 : : cvalue)));
1122 : :
6753 andrew@dunslane.net 1123 :CBC 272570 : result = (text *) palloc(VARHDRSZ + 1);
1124 : 272570 : SET_VARSIZE(result, VARHDRSZ + 1);
1125 : 272570 : *VARDATA(result) = (char) cvalue;
1126 : : }
1127 : :
9406 tgl@sss.pgh.pa.us 1128 : 272570 : 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 : 24966 : repeat(PG_FUNCTION_ARGS)
1147 : : {
6750 1148 : 24966 : text *string = PG_GETARG_TEXT_PP(0);
9124 bruce@momjian.us 1149 : 24966 : int32 count = PG_GETARG_INT32(1);
1150 : : text *result;
1151 : : int slen,
1152 : : tlen;
1153 : : int i;
1154 : : char *cp,
1155 : : *sp;
1156 : :
9473 lockhart@fourpalms.o 1157 [ + + ]: 24966 : if (count < 0)
1158 : 3 : count = 0;
1159 : :
6750 tgl@sss.pgh.pa.us 1160 [ - + - - : 24966 : slen = VARSIZE_ANY_EXHDR(string);
- - - - -
+ ]
1161 : :
3015 andres@anarazel.de 1162 [ + - ]: 24966 : if (unlikely(pg_mul_s32_overflow(count, slen, &tlen)) ||
1389 tgl@sss.pgh.pa.us 1163 [ + - ]: 24966 : unlikely(pg_add_s32_overflow(tlen, VARHDRSZ, &tlen)) ||
1164 [ - + ]: 24966 : unlikely(!AllocSizeIsValid(tlen)))
3015 andres@anarazel.de 1165 [ # # ]:UBC 0 : ereport(ERROR,
1166 : : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1167 : : errmsg("requested length too large")));
1168 : :
9473 lockhart@fourpalms.o 1169 :CBC 24966 : result = (text *) palloc(tlen);
1170 : :
6956 tgl@sss.pgh.pa.us 1171 : 24966 : SET_VARSIZE(result, tlen);
9473 lockhart@fourpalms.o 1172 : 24966 : cp = VARDATA(result);
6750 tgl@sss.pgh.pa.us 1173 [ - + ]: 24966 : sp = VARDATA_ANY(string);
9473 lockhart@fourpalms.o 1174 [ + + ]: 24068622 : for (i = 0; i < count; i++)
1175 : : {
6750 tgl@sss.pgh.pa.us 1176 : 24043656 : memcpy(cp, sp, slen);
9473 lockhart@fourpalms.o 1177 : 24043656 : cp += slen;
2117 mail@joeconway.com 1178 [ - + ]: 24043656 : CHECK_FOR_INTERRUPTS();
1179 : : }
1180 : :
9406 tgl@sss.pgh.pa.us 1181 : 24966 : PG_RETURN_TEXT_P(result);
1182 : : }
|