Age Owner TLA Line data Source code
1 : /*-------------------------------------------------------------------------
2 : * oracle_compat.c
3 : * Oracle compatible functions.
4 : *
5 : * Copyright (c) 1996-2023, 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
8312 tgl 49 GIC 97762 : lower(PG_FUNCTION_ARGS)
9532 scrappy 50 ECB : {
5050 bruce 51 GIC 97762 : text *in_string = PG_GETARG_TEXT_PP(0);
5050 bruce 52 ECB : char *out_string;
53 : text *result;
54 :
5384 tgl 55 GIC 97762 : out_string = str_tolower(VARDATA_ANY(in_string),
4443 peter_e 56 CBC 97762 : VARSIZE_ANY_EXHDR(in_string),
4443 peter_e 57 ECB : PG_GET_COLLATION());
5403 bruce 58 GIC 97762 : result = cstring_to_text(out_string);
5403 bruce 59 CBC 97762 : pfree(out_string);
6896 tgl 60 ECB :
5403 bruce 61 GIC 97762 : PG_RETURN_TEXT_P(result);
9532 scrappy 62 ECB : }
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
8312 tgl 80 GIC 521129 : upper(PG_FUNCTION_ARGS)
9532 scrappy 81 ECB : {
5050 bruce 82 GIC 521129 : text *in_string = PG_GETARG_TEXT_PP(0);
5050 bruce 83 ECB : char *out_string;
84 : text *result;
85 :
5384 tgl 86 GIC 521129 : out_string = str_toupper(VARDATA_ANY(in_string),
4443 peter_e 87 CBC 521129 : VARSIZE_ANY_EXHDR(in_string),
4443 peter_e 88 ECB : PG_GET_COLLATION());
5403 bruce 89 GIC 521129 : result = cstring_to_text(out_string);
5403 bruce 90 CBC 521129 : pfree(out_string);
6896 tgl 91 ECB :
5403 bruce 92 GIC 521129 : PG_RETURN_TEXT_P(result);
9532 scrappy 93 ECB : }
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
8312 tgl 114 GIC 41 : initcap(PG_FUNCTION_ARGS)
9532 scrappy 115 ECB : {
5050 bruce 116 GIC 41 : text *in_string = PG_GETARG_TEXT_PP(0);
5050 bruce 117 ECB : char *out_string;
118 : text *result;
119 :
5384 tgl 120 GIC 41 : out_string = str_initcap(VARDATA_ANY(in_string),
4443 peter_e 121 CBC 41 : VARSIZE_ANY_EXHDR(in_string),
4443 peter_e 122 ECB : PG_GET_COLLATION());
5403 bruce 123 GIC 41 : result = cstring_to_text(out_string);
5403 bruce 124 CBC 41 : pfree(out_string);
6881 tgl 125 ECB :
5403 bruce 126 GIC 41 : PG_RETURN_TEXT_P(result);
9532 scrappy 127 ECB : }
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
8335 tgl 147 GIC 16385 : lpad(PG_FUNCTION_ARGS)
9532 scrappy 148 ECB : {
5679 tgl 149 GIC 16385 : text *string1 = PG_GETARG_TEXT_PP(0);
8335 tgl 150 CBC 16385 : int32 len = PG_GETARG_INT32(1);
5679 151 16385 : text *string2 = PG_GETARG_TEXT_PP(2);
9344 bruce 152 ECB : 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 */
8158 tgl 164 GIC 16385 : if (len < 0)
8158 tgl 165 CBC 3 : len = 0;
8158 tgl 166 ECB :
5679 tgl 167 GIC 16385 : s1len = VARSIZE_ANY_EXHDR(string1);
8158 tgl 168 CBC 16385 : if (s1len < 0)
8158 tgl 169 LBC 0 : s1len = 0; /* shouldn't happen */
8158 tgl 170 EUB :
5679 tgl 171 GIC 16385 : s2len = VARSIZE_ANY_EXHDR(string2);
8158 tgl 172 CBC 16385 : if (s2len < 0)
8158 tgl 173 LBC 0 : s2len = 0; /* shouldn't happen */
9345 bruce 174 EUB :
5679 tgl 175 GIC 16385 : s1len = pg_mbstrlen_with_len(VARDATA_ANY(string1), s1len);
7528 ishii 176 ECB :
8158 tgl 177 GIC 16385 : if (s1len > len)
8158 tgl 178 CBC 35 : s1len = len; /* truncate string1 to len chars */
8158 tgl 179 ECB :
8158 tgl 180 GIC 16385 : if (s2len <= 0)
8158 tgl 181 CBC 3 : len = s1len; /* nothing to pad with, so don't pad */
9345 bruce 182 ECB :
183 : /* compute worst-case output length */
318 tgl 184 GIC 16385 : if (unlikely(pg_mul_s32_overflow(pg_database_encoding_max_length(), len,
318 tgl 185 CBC 16385 : &bytelen)) ||
186 16385 : unlikely(pg_add_s32_overflow(bytelen, VARHDRSZ, &bytelen)) ||
187 16385 : unlikely(!AllocSizeIsValid(bytelen)))
7196 tgl 188 LBC 0 : ereport(ERROR,
7196 tgl 189 EUB : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
190 : errmsg("requested length too large")));
191 :
318 tgl 192 GIC 16385 : ret = (text *) palloc(bytelen);
7528 ishii 193 ECB :
8158 tgl 194 GIC 16385 : m = len - s1len;
8158 tgl 195 ECB :
5679 tgl 196 GIC 16385 : ptr2 = ptr2start = VARDATA_ANY(string2);
8158 tgl 197 CBC 16385 : ptr2end = ptr2 + s2len;
9345 bruce 198 16385 : ptr_ret = VARDATA(ret);
9345 bruce 199 ECB :
7868 ishii 200 GIC 17443 : while (m--)
7868 ishii 201 ECB : {
7836 bruce 202 GIC 1058 : int mlen = pg_mblen(ptr2);
7836 bruce 203 ECB :
7836 bruce 204 GIC 1058 : memcpy(ptr_ret, ptr2, mlen);
7836 bruce 205 CBC 1058 : ptr_ret += mlen;
206 1058 : ptr2 += mlen;
207 1058 : if (ptr2 == ptr2end) /* wrap around at end of s2 */
5679 tgl 208 1046 : ptr2 = ptr2start;
7868 ishii 209 ECB : }
210 :
5679 tgl 211 GIC 16385 : ptr1 = VARDATA_ANY(string1);
9345 bruce 212 ECB :
7868 ishii 213 GIC 48121 : while (s1len--)
7868 ishii 214 ECB : {
7836 bruce 215 GIC 31736 : int mlen = pg_mblen(ptr1);
7836 bruce 216 ECB :
7836 bruce 217 GIC 31736 : memcpy(ptr_ret, ptr1, mlen);
7836 bruce 218 CBC 31736 : ptr_ret += mlen;
219 31736 : ptr1 += mlen;
7868 ishii 220 ECB : }
221 :
5885 tgl 222 GIC 16385 : SET_VARSIZE(ret, ptr_ret - (char *) ret);
7761 tgl 223 ECB :
8335 tgl 224 GIC 16385 : PG_RETURN_TEXT_P(ret);
9532 scrappy 225 ECB : }
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
8335 tgl 245 GIC 22 : rpad(PG_FUNCTION_ARGS)
9532 scrappy 246 ECB : {
5679 tgl 247 GIC 22 : text *string1 = PG_GETARG_TEXT_PP(0);
8335 tgl 248 CBC 22 : int32 len = PG_GETARG_INT32(1);
5679 249 22 : text *string2 = PG_GETARG_TEXT_PP(2);
9344 bruce 250 ECB : 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 */
8158 tgl 262 GIC 22 : if (len < 0)
8158 tgl 263 CBC 3 : len = 0;
8158 tgl 264 ECB :
5679 tgl 265 GIC 22 : s1len = VARSIZE_ANY_EXHDR(string1);
8158 tgl 266 CBC 22 : if (s1len < 0)
8158 tgl 267 LBC 0 : s1len = 0; /* shouldn't happen */
9345 bruce 268 EUB :
5679 tgl 269 GIC 22 : s2len = VARSIZE_ANY_EXHDR(string2);
8158 tgl 270 CBC 22 : if (s2len < 0)
8158 tgl 271 LBC 0 : s2len = 0; /* shouldn't happen */
8158 tgl 272 EUB :
5679 tgl 273 GIC 22 : s1len = pg_mbstrlen_with_len(VARDATA_ANY(string1), s1len);
7868 ishii 274 ECB :
8158 tgl 275 GIC 22 : if (s1len > len)
8158 tgl 276 CBC 6 : s1len = len; /* truncate string1 to len chars */
8158 tgl 277 ECB :
8158 tgl 278 GIC 22 : if (s2len <= 0)
8158 tgl 279 CBC 3 : len = s1len; /* nothing to pad with, so don't pad */
9345 bruce 280 ECB :
281 : /* compute worst-case output length */
318 tgl 282 GIC 22 : if (unlikely(pg_mul_s32_overflow(pg_database_encoding_max_length(), len,
318 tgl 283 CBC 22 : &bytelen)) ||
284 22 : unlikely(pg_add_s32_overflow(bytelen, VARHDRSZ, &bytelen)) ||
285 22 : unlikely(!AllocSizeIsValid(bytelen)))
7196 tgl 286 LBC 0 : ereport(ERROR,
7196 tgl 287 EUB : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
288 : errmsg("requested length too large")));
289 :
318 tgl 290 GIC 22 : ret = (text *) palloc(bytelen);
318 tgl 291 ECB :
8158 tgl 292 GIC 22 : m = len - s1len;
8158 tgl 293 ECB :
5679 tgl 294 GIC 22 : ptr1 = VARDATA_ANY(string1);
9345 bruce 295 CBC 22 : ptr_ret = VARDATA(ret);
9345 bruce 296 ECB :
7868 ishii 297 GIC 54 : while (s1len--)
7868 ishii 298 ECB : {
7836 bruce 299 GIC 32 : int mlen = pg_mblen(ptr1);
7836 bruce 300 ECB :
7836 bruce 301 GIC 32 : memcpy(ptr_ret, ptr1, mlen);
7836 bruce 302 CBC 32 : ptr_ret += mlen;
303 32 : ptr1 += mlen;
7868 ishii 304 ECB : }
305 :
5679 tgl 306 GIC 22 : ptr2 = ptr2start = VARDATA_ANY(string2);
8158 tgl 307 CBC 22 : ptr2end = ptr2 + s2len;
9345 bruce 308 ECB :
7868 ishii 309 GIC 960052 : while (m--)
7868 ishii 310 ECB : {
7836 bruce 311 GIC 960030 : int mlen = pg_mblen(ptr2);
7836 bruce 312 ECB :
7836 bruce 313 GIC 960030 : memcpy(ptr_ret, ptr2, mlen);
7836 bruce 314 CBC 960030 : ptr_ret += mlen;
315 960030 : ptr2 += mlen;
316 960030 : if (ptr2 == ptr2end) /* wrap around at end of s2 */
5679 tgl 317 960018 : ptr2 = ptr2start;
7868 ishii 318 ECB : }
319 :
5885 tgl 320 GIC 22 : SET_VARSIZE(ret, ptr_ret - (char *) ret);
7761 tgl 321 ECB :
8335 tgl 322 GIC 22 : PG_RETURN_TEXT_P(ret);
9532 scrappy 323 ECB : }
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
8312 tgl 342 GIC 10 : btrim(PG_FUNCTION_ARGS)
9385 lockhart 343 ECB : {
5679 tgl 344 GIC 10 : text *string = PG_GETARG_TEXT_PP(0);
5679 tgl 345 CBC 10 : text *set = PG_GETARG_TEXT_PP(1);
9344 bruce 346 ECB : text *ret;
347 :
5679 tgl 348 GIC 20 : ret = dotrim(VARDATA_ANY(string), VARSIZE_ANY_EXHDR(string),
5679 tgl 349 CBC 20 : VARDATA_ANY(set), VARSIZE_ANY_EXHDR(set),
7261 tgl 350 ECB : true, true);
351 :
7261 tgl 352 GIC 10 : PG_RETURN_TEXT_P(ret);
7261 tgl 353 ECB : }
354 :
355 : /********************************************************************
356 : *
357 : * btrim1 --- btrim with set fixed as ' '
358 : *
359 : ********************************************************************/
360 :
361 : Datum
7261 tgl 362 GIC 281 : btrim1(PG_FUNCTION_ARGS)
7261 tgl 363 ECB : {
5679 tgl 364 GIC 281 : text *string = PG_GETARG_TEXT_PP(0);
7261 tgl 365 ECB : text *ret;
366 :
5679 tgl 367 GIC 281 : ret = dotrim(VARDATA_ANY(string), VARSIZE_ANY_EXHDR(string),
7261 tgl 368 ECB : " ", 1,
369 : true, true);
370 :
7261 tgl 371 GIC 281 : PG_RETURN_TEXT_P(ret);
7261 tgl 372 ECB : }
373 :
374 : /*
375 : * Common implementation for btrim, ltrim, rtrim
376 : */
377 : static text *
7261 tgl 378 GIC 17397 : dotrim(const char *string, int stringlen,
7261 tgl 379 ECB : 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 */
7261 tgl 385 GIC 17397 : if (stringlen > 0 && setlen > 0)
7869 ishii 386 ECB : {
7261 tgl 387 GIC 17397 : if (pg_database_encoding_max_length() > 1)
7869 ishii 388 ECB : {
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 :
7261 tgl 408 GIC 17391 : stringchars = (const char **) palloc(stringlen * sizeof(char *));
7261 tgl 409 CBC 17391 : stringmblen = (int *) palloc(stringlen * sizeof(int));
410 17391 : stringnchars = 0;
411 17391 : p = string;
412 17391 : len = stringlen;
413 154217 : while (len > 0)
7261 tgl 414 ECB : {
7261 tgl 415 GIC 136826 : stringchars[stringnchars] = p;
7261 tgl 416 CBC 136826 : stringmblen[stringnchars] = mblen = pg_mblen(p);
417 136826 : stringnchars++;
418 136826 : p += mblen;
419 136826 : len -= mblen;
7261 tgl 420 ECB : }
421 :
7261 tgl 422 GIC 17391 : setchars = (const char **) palloc(setlen * sizeof(char *));
7261 tgl 423 CBC 17391 : setmblen = (int *) palloc(setlen * sizeof(int));
424 17391 : setnchars = 0;
425 17391 : p = set;
426 17391 : len = setlen;
427 35121 : while (len > 0)
7261 tgl 428 ECB : {
7261 tgl 429 GIC 17730 : setchars[setnchars] = p;
7261 tgl 430 CBC 17730 : setmblen[setnchars] = mblen = pg_mblen(p);
431 17730 : setnchars++;
432 17730 : p += mblen;
433 17730 : len -= mblen;
7261 tgl 434 ECB : }
435 :
7261 tgl 436 GIC 17391 : resultndx = 0; /* index in stringchars[] */
7261 tgl 437 CBC 17391 : resultnchars = stringnchars;
7261 tgl 438 ECB :
7261 tgl 439 GIC 17391 : if (doltrim)
7261 tgl 440 ECB : {
7261 tgl 441 GIC 28294 : while (resultnchars > 0)
7261 tgl 442 ECB : {
7261 tgl 443 GIC 28294 : str_pos = stringchars[resultndx];
7261 tgl 444 CBC 28294 : str_len = stringmblen[resultndx];
445 42605 : for (i = 0; i < setnchars; i++)
7261 tgl 446 ECB : {
7261 tgl 447 GIC 28354 : if (str_len == setmblen[i] &&
7261 tgl 448 CBC 28354 : memcmp(str_pos, setchars[i], str_len) == 0)
449 14043 : break;
7261 tgl 450 ECB : }
7261 tgl 451 GIC 28294 : if (i >= setnchars)
7261 tgl 452 CBC 14251 : break; /* no match here */
453 14043 : string += str_len;
454 14043 : stringlen -= str_len;
455 14043 : resultndx++;
456 14043 : resultnchars--;
7261 tgl 457 ECB : }
458 : }
459 :
7261 tgl 460 GIC 17391 : if (dortrim)
7261 tgl 461 ECB : {
7261 tgl 462 GIC 37781 : while (resultnchars > 0)
7261 tgl 463 ECB : {
7261 tgl 464 GIC 37781 : str_pos = stringchars[resultndx + resultnchars - 1];
7261 tgl 465 CBC 37781 : str_len = stringmblen[resultndx + resultnchars - 1];
466 42019 : for (i = 0; i < setnchars; i++)
7261 tgl 467 ECB : {
7261 tgl 468 GIC 38588 : if (str_len == setmblen[i] &&
7261 tgl 469 CBC 38588 : memcmp(str_pos, setchars[i], str_len) == 0)
470 34350 : break;
7261 tgl 471 ECB : }
7261 tgl 472 GIC 37781 : if (i >= setnchars)
7261 tgl 473 CBC 3431 : break; /* no match here */
474 34350 : stringlen -= str_len;
475 34350 : resultnchars--;
7261 tgl 476 ECB : }
477 : }
478 :
7261 tgl 479 GIC 17391 : pfree(stringchars);
7261 tgl 480 CBC 17391 : pfree(stringmblen);
481 17391 : pfree(setchars);
482 17391 : pfree(setmblen);
7261 tgl 483 ECB : }
484 : else
485 : {
486 : /*
487 : * In the single-byte-encoding case, we don't need such overhead.
488 : */
7261 tgl 489 GIC 6 : if (doltrim)
7261 tgl 490 ECB : {
7261 tgl 491 UIC 0 : while (stringlen > 0)
7261 tgl 492 EUB : {
7188 bruce 493 UIC 0 : char str_ch = *string;
7261 tgl 494 EUB :
7261 tgl 495 UIC 0 : for (i = 0; i < setlen; i++)
7261 tgl 496 EUB : {
7261 tgl 497 UIC 0 : if (str_ch == set[i])
7261 tgl 498 UBC 0 : break;
7261 tgl 499 EUB : }
7261 tgl 500 UIC 0 : if (i >= setlen)
7261 tgl 501 UBC 0 : break; /* no match here */
502 0 : string++;
503 0 : stringlen--;
7261 tgl 504 EUB : }
505 : }
506 :
7261 tgl 507 GIC 6 : if (dortrim)
7261 tgl 508 ECB : {
7261 tgl 509 GIC 12 : while (stringlen > 0)
7261 tgl 510 ECB : {
7188 bruce 511 GIC 12 : char str_ch = string[stringlen - 1];
7261 tgl 512 ECB :
7261 tgl 513 GIC 18 : for (i = 0; i < setlen; i++)
7261 tgl 514 ECB : {
7261 tgl 515 GIC 12 : if (str_ch == set[i])
7261 tgl 516 CBC 6 : break;
7261 tgl 517 ECB : }
7261 tgl 518 GIC 12 : if (i >= setlen)
7261 tgl 519 CBC 6 : break; /* no match here */
520 6 : stringlen--;
7261 tgl 521 ECB : }
522 : }
523 : }
524 : }
525 :
526 : /* Return selected portion of string */
5493 tgl 527 GIC 17397 : return cstring_to_text_with_len(string, stringlen);
8312 tgl 528 ECB : }
529 :
530 : /*
531 : * Common implementation for bytea versions of btrim, ltrim, rtrim
532 : */
533 : bytea *
811 tgl 534 GIC 18 : dobyteatrim(bytea *string, bytea *set, bool doltrim, bool dortrim)
7877 bruce 535 ECB : {
536 : bytea *ret;
537 : char *ptr,
538 : *end,
539 : *ptr2,
540 : *ptr2start,
541 : *end2;
542 : int m,
543 : stringlen,
544 : setlen;
545 :
5679 tgl 546 GIC 18 : stringlen = VARSIZE_ANY_EXHDR(string);
5679 tgl 547 CBC 18 : setlen = VARSIZE_ANY_EXHDR(set);
5624 bruce 548 ECB :
5679 tgl 549 GIC 18 : if (stringlen <= 0 || setlen <= 0)
811 tgl 550 CBC 6 : return string;
7877 bruce 551 ECB :
5679 tgl 552 GIC 12 : m = stringlen;
5679 tgl 553 CBC 12 : ptr = VARDATA_ANY(string);
554 12 : end = ptr + stringlen - 1;
555 12 : ptr2start = VARDATA_ANY(set);
556 12 : end2 = ptr2start + setlen - 1;
7877 bruce 557 ECB :
811 tgl 558 GIC 12 : if (doltrim)
7877 bruce 559 ECB : {
811 tgl 560 GIC 18 : while (m > 0)
7877 bruce 561 ECB : {
811 tgl 562 GIC 18 : ptr2 = ptr2start;
811 tgl 563 CBC 27 : while (ptr2 <= end2)
811 tgl 564 ECB : {
811 tgl 565 GIC 18 : if (*ptr == *ptr2)
811 tgl 566 CBC 9 : break;
567 9 : ++ptr2;
811 tgl 568 ECB : }
811 tgl 569 GIC 18 : if (ptr2 > end2)
7877 bruce 570 CBC 9 : break;
811 tgl 571 9 : ptr++;
572 9 : m--;
7877 bruce 573 ECB : }
574 : }
575 :
811 tgl 576 GIC 12 : if (dortrim)
7877 bruce 577 ECB : {
811 tgl 578 GIC 18 : while (m > 0)
7877 bruce 579 ECB : {
811 tgl 580 GIC 18 : ptr2 = ptr2start;
811 tgl 581 CBC 27 : while (ptr2 <= end2)
811 tgl 582 ECB : {
811 tgl 583 GIC 18 : if (*end == *ptr2)
811 tgl 584 CBC 9 : break;
585 9 : ++ptr2;
811 tgl 586 ECB : }
811 tgl 587 GIC 18 : if (ptr2 > end2)
7877 bruce 588 CBC 9 : break;
811 tgl 589 9 : end--;
590 9 : m--;
7877 bruce 591 ECB : }
592 : }
593 :
7877 bruce 594 GIC 12 : ret = (bytea *) palloc(VARHDRSZ + m);
5885 tgl 595 CBC 12 : SET_VARSIZE(ret, VARHDRSZ + m);
7877 bruce 596 12 : memcpy(VARDATA(ret), ptr, m);
811 tgl 597 12 : return ret;
811 tgl 598 ECB : }
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
811 tgl 617 GIC 12 : byteatrim(PG_FUNCTION_ARGS)
811 tgl 618 ECB : {
811 tgl 619 GIC 12 : bytea *string = PG_GETARG_BYTEA_PP(0);
811 tgl 620 CBC 12 : bytea *set = PG_GETARG_BYTEA_PP(1);
811 tgl 621 ECB : bytea *ret;
622 :
811 tgl 623 GIC 12 : ret = dobyteatrim(string, set, true, true);
811 tgl 624 ECB :
811 tgl 625 GIC 12 : PG_RETURN_BYTEA_P(ret);
811 tgl 626 ECB : }
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
811 tgl 644 GIC 3 : bytealtrim(PG_FUNCTION_ARGS)
811 tgl 645 ECB : {
811 tgl 646 GIC 3 : bytea *string = PG_GETARG_BYTEA_PP(0);
811 tgl 647 CBC 3 : bytea *set = PG_GETARG_BYTEA_PP(1);
811 tgl 648 ECB : bytea *ret;
649 :
811 tgl 650 GIC 3 : ret = dobyteatrim(string, set, true, false);
811 tgl 651 ECB :
811 tgl 652 GIC 3 : PG_RETURN_BYTEA_P(ret);
811 tgl 653 ECB : }
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
811 tgl 671 GIC 3 : byteartrim(PG_FUNCTION_ARGS)
811 tgl 672 ECB : {
811 tgl 673 GIC 3 : bytea *string = PG_GETARG_BYTEA_PP(0);
811 tgl 674 CBC 3 : bytea *set = PG_GETARG_BYTEA_PP(1);
811 tgl 675 ECB : bytea *ret;
676 :
811 tgl 677 GIC 3 : ret = dobyteatrim(string, set, false, true);
7877 bruce 678 ECB :
7877 bruce 679 GIC 3 : PG_RETURN_BYTEA_P(ret);
7877 bruce 680 ECB : }
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
8312 tgl 698 GIC 13956 : ltrim(PG_FUNCTION_ARGS)
9532 scrappy 699 ECB : {
5679 tgl 700 GIC 13956 : text *string = PG_GETARG_TEXT_PP(0);
5679 tgl 701 CBC 13956 : text *set = PG_GETARG_TEXT_PP(1);
9344 bruce 702 ECB : text *ret;
703 :
5679 tgl 704 GIC 27912 : ret = dotrim(VARDATA_ANY(string), VARSIZE_ANY_EXHDR(string),
5679 tgl 705 CBC 27912 : VARDATA_ANY(set), VARSIZE_ANY_EXHDR(set),
7261 tgl 706 ECB : true, false);
707 :
7261 tgl 708 GIC 13956 : PG_RETURN_TEXT_P(ret);
7261 tgl 709 ECB : }
710 :
711 : /********************************************************************
712 : *
713 : * ltrim1 --- ltrim with set fixed as ' '
714 : *
715 : ********************************************************************/
716 :
717 : Datum
7261 tgl 718 GIC 4 : ltrim1(PG_FUNCTION_ARGS)
7261 tgl 719 ECB : {
5679 tgl 720 GIC 4 : text *string = PG_GETARG_TEXT_PP(0);
7261 tgl 721 ECB : text *ret;
722 :
5679 tgl 723 GIC 4 : ret = dotrim(VARDATA_ANY(string), VARSIZE_ANY_EXHDR(string),
7261 tgl 724 ECB : " ", 1,
725 : true, false);
726 :
8312 tgl 727 GIC 4 : PG_RETURN_TEXT_P(ret);
9532 scrappy 728 ECB : }
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
8312 tgl 746 GIC 387 : rtrim(PG_FUNCTION_ARGS)
9532 scrappy 747 ECB : {
5679 tgl 748 GIC 387 : text *string = PG_GETARG_TEXT_PP(0);
5679 tgl 749 CBC 387 : text *set = PG_GETARG_TEXT_PP(1);
9344 bruce 750 ECB : text *ret;
751 :
5679 tgl 752 GIC 774 : ret = dotrim(VARDATA_ANY(string), VARSIZE_ANY_EXHDR(string),
5679 tgl 753 CBC 774 : VARDATA_ANY(set), VARSIZE_ANY_EXHDR(set),
7261 tgl 754 ECB : false, true);
755 :
7261 tgl 756 GIC 387 : PG_RETURN_TEXT_P(ret);
7261 tgl 757 ECB : }
758 :
759 : /********************************************************************
760 : *
761 : * rtrim1 --- rtrim with set fixed as ' '
762 : *
763 : ********************************************************************/
764 :
765 : Datum
7261 tgl 766 GIC 2759 : rtrim1(PG_FUNCTION_ARGS)
7261 tgl 767 ECB : {
5679 tgl 768 GIC 2759 : text *string = PG_GETARG_TEXT_PP(0);
7261 tgl 769 ECB : text *ret;
770 :
5679 tgl 771 GIC 2759 : ret = dotrim(VARDATA_ANY(string), VARSIZE_ANY_EXHDR(string),
7261 tgl 772 ECB : " ", 1,
773 : false, true);
774 :
8312 tgl 775 GIC 2759 : PG_RETURN_TEXT_P(ret);
9532 scrappy 776 ECB : }
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
8312 tgl 797 GIC 17 : translate(PG_FUNCTION_ARGS)
9532 scrappy 798 ECB : {
5679 tgl 799 GIC 17 : text *string = PG_GETARG_TEXT_PP(0);
5679 tgl 800 CBC 17 : text *from = PG_GETARG_TEXT_PP(1);
801 17 : text *to = PG_GETARG_TEXT_PP(2);
8397 bruce 802 ECB : 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 :
5679 tgl 818 GIC 17 : m = VARSIZE_ANY_EXHDR(string);
5679 tgl 819 CBC 17 : if (m <= 0)
8312 820 3 : PG_RETURN_TEXT_P(string);
5678 821 14 : source = VARDATA_ANY(string);
9521 scrappy 822 ECB :
5679 tgl 823 GIC 14 : fromlen = VARSIZE_ANY_EXHDR(from);
5679 tgl 824 CBC 14 : from_ptr = VARDATA_ANY(from);
825 14 : tolen = VARSIZE_ANY_EXHDR(to);
826 14 : to_ptr = VARDATA_ANY(to);
39 827 14 : to_end = to_ptr + tolen;
5679 tgl 828 ECB :
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 : */
318 tgl 833 GIC 14 : if (unlikely(pg_mul_s32_overflow(pg_database_encoding_max_length(), m,
318 tgl 834 CBC 14 : &bytelen)) ||
835 14 : unlikely(pg_add_s32_overflow(bytelen, VARHDRSZ, &bytelen)) ||
836 14 : unlikely(!AllocSizeIsValid(bytelen)))
5678 tgl 837 LBC 0 : ereport(ERROR,
5678 tgl 838 EUB : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
839 : errmsg("requested length too large")));
840 :
318 tgl 841 GIC 14 : result = (text *) palloc(bytelen);
318 tgl 842 ECB :
8425 tgl 843 GIC 14 : target = VARDATA(result);
8426 lockhart 844 CBC 14 : retlen = 0;
8425 tgl 845 ECB :
7868 ishii 846 GIC 140 : while (m > 0)
7868 ishii 847 ECB : {
7868 ishii 848 GIC 126 : source_len = pg_mblen(source);
7868 ishii 849 CBC 126 : from_index = 0;
7868 ishii 850 ECB :
7868 ishii 851 GIC 342 : for (i = 0; i < fromlen; i += len)
7868 ishii 852 ECB : {
7836 bruce 853 GIC 247 : len = pg_mblen(&from_ptr[i]);
7836 bruce 854 CBC 247 : if (len == source_len &&
855 247 : memcmp(source, &from_ptr[i], len) == 0)
856 31 : break;
7868 ishii 857 ECB :
7836 bruce 858 GIC 216 : from_index++;
7868 ishii 859 ECB : }
7868 ishii 860 GIC 126 : if (i < fromlen)
7868 ishii 861 ECB : {
862 : /* substitute, or delete if no corresponding "to" character */
7836 bruce 863 GIC 31 : char *p = to_ptr;
7836 bruce 864 ECB :
7836 bruce 865 GIC 48 : for (i = 0; i < from_index; i++)
7836 bruce 866 ECB : {
39 tgl 867 GIC 20 : if (p >= to_end)
7836 bruce 868 CBC 3 : break;
39 tgl 869 17 : p += pg_mblen(p);
7836 bruce 870 ECB : }
39 tgl 871 GIC 31 : if (p < to_end)
7836 bruce 872 ECB : {
7836 bruce 873 GIC 25 : len = pg_mblen(p);
7836 bruce 874 CBC 25 : memcpy(target, p, len);
875 25 : target += len;
876 25 : retlen += len;
7836 bruce 877 ECB : }
878 : }
879 : else
880 : {
881 : /* no match, so copy */
7836 bruce 882 GIC 95 : memcpy(target, source, source_len);
7836 bruce 883 CBC 95 : target += source_len;
884 95 : retlen += source_len;
7868 ishii 885 ECB : }
886 :
7868 ishii 887 GIC 126 : source += source_len;
7868 ishii 888 CBC 126 : m -= source_len;
7868 ishii 889 ECB : }
890 :
5885 tgl 891 GIC 14 : SET_VARSIZE(result, retlen + VARHDRSZ);
8397 bruce 892 ECB :
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 :
8312 tgl 899 GIC 14 : PG_RETURN_TEXT_P(result);
8425 tgl 900 ECB : }
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
8312 tgl 925 GIC 29 : ascii(PG_FUNCTION_ARGS)
8402 lockhart 926 ECB : {
5679 tgl 927 GIC 29 : text *string = PG_GETARG_TEXT_PP(0);
5624 bruce 928 CBC 29 : int encoding = GetDatabaseEncoding();
5682 andrew 929 ECB : unsigned char *data;
930 :
5679 tgl 931 GIC 29 : if (VARSIZE_ANY_EXHDR(string) <= 0)
8312 tgl 932 CBC 3 : PG_RETURN_INT32(0);
8402 lockhart 933 ECB :
5679 tgl 934 GIC 26 : data = (unsigned char *) VARDATA_ANY(string);
5682 andrew 935 ECB :
5682 andrew 936 GIC 26 : if (encoding == PG_UTF8 && *data > 127)
5682 andrew 937 ECB : {
938 : /* return the code point for Unicode */
939 :
5624 bruce 940 UIC 0 : int result = 0,
5624 bruce 941 UBC 0 : tbytes = 0,
5624 bruce 942 EUB : i;
943 :
5682 andrew 944 UIC 0 : if (*data >= 0xF0)
5682 andrew 945 EUB : {
5682 andrew 946 UIC 0 : result = *data & 0x07;
5682 andrew 947 UBC 0 : tbytes = 3;
5682 andrew 948 EUB : }
5682 andrew 949 UIC 0 : else if (*data >= 0xE0)
5682 andrew 950 EUB : {
5682 andrew 951 UIC 0 : result = *data & 0x0F;
5682 andrew 952 UBC 0 : tbytes = 2;
5682 andrew 953 EUB : }
954 : else
955 : {
5624 bruce 956 UIC 0 : Assert(*data > 0xC0);
5682 andrew 957 UBC 0 : result = *data & 0x1f;
958 0 : tbytes = 1;
5682 andrew 959 EUB : }
960 :
5624 bruce 961 UIC 0 : Assert(tbytes > 0);
5682 andrew 962 EUB :
5682 andrew 963 UIC 0 : for (i = 1; i <= tbytes; i++)
5682 andrew 964 EUB : {
5624 bruce 965 UIC 0 : Assert((data[i] & 0xC0) == 0x80);
5682 andrew 966 UBC 0 : result = (result << 6) + (data[i] & 0x3f);
5682 andrew 967 EUB : }
968 :
5682 andrew 969 UIC 0 : PG_RETURN_INT32(result);
5682 andrew 970 EUB : }
971 : else
972 : {
5682 andrew 973 GIC 26 : if (pg_encoding_max_length(encoding) > 1 && *data > 127)
5682 andrew 974 LBC 0 : ereport(ERROR,
5682 andrew 975 EUB : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
976 : errmsg("requested character too large")));
977 :
978 :
5682 andrew 979 GIC 26 : PG_RETURN_INT32((int32) *data);
5682 andrew 980 ECB : }
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
5624 bruce 1006 GIC 272598 : chr (PG_FUNCTION_ARGS)
8402 lockhart 1007 ECB : {
489 peter 1008 GIC 272598 : int32 arg = PG_GETARG_INT32(0);
489 peter 1009 ECB : uint32 cvalue;
1010 : text *result;
5624 bruce 1011 GIC 272598 : int encoding = GetDatabaseEncoding();
8402 lockhart 1012 ECB :
1013 : /*
1014 : * Error out on arguments that make no sense or that we can't validly
1015 : * represent in the encoding.
1016 : */
489 peter 1017 GIC 272598 : if (arg < 0)
489 peter 1018 LBC 0 : ereport(ERROR,
489 peter 1019 EUB : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1020 : errmsg("character number must be positive")));
489 peter 1021 GIC 272598 : else if (arg == 0)
489 peter 1022 CBC 3 : ereport(ERROR,
489 peter 1023 ECB : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1024 : errmsg("null character not permitted")));
1025 :
489 peter 1026 GIC 272595 : cvalue = arg;
489 peter 1027 ECB :
5682 andrew 1028 GIC 272595 : if (encoding == PG_UTF8 && cvalue > 127)
5682 andrew 1029 LBC 0 : {
5682 andrew 1030 EUB : /* 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 : */
3250 tgl 1039 UIC 0 : if (cvalue > 0x0010ffff)
5682 andrew 1040 UBC 0 : ereport(ERROR,
5682 andrew 1041 EUB : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1042 : errmsg("requested character too large for encoding: %u",
1043 : cvalue)));
1044 :
5682 andrew 1045 UIC 0 : if (cvalue > 0xffff)
5682 andrew 1046 UBC 0 : bytes = 4;
1047 0 : else if (cvalue > 0x07ff)
1048 0 : bytes = 3;
5682 andrew 1049 EUB : else
5682 andrew 1050 UIC 0 : bytes = 2;
5682 andrew 1051 EUB :
5682 andrew 1052 UIC 0 : result = (text *) palloc(VARHDRSZ + bytes);
5682 andrew 1053 UBC 0 : SET_VARSIZE(result, VARHDRSZ + bytes);
3250 tgl 1054 0 : wch = (unsigned char *) VARDATA(result);
5682 andrew 1055 EUB :
5682 andrew 1056 UIC 0 : if (bytes == 2)
5682 andrew 1057 EUB : {
5682 andrew 1058 UIC 0 : wch[0] = 0xC0 | ((cvalue >> 6) & 0x1F);
2931 heikki.linnakangas 1059 UBC 0 : wch[1] = 0x80 | (cvalue & 0x3F);
5682 andrew 1060 EUB : }
5682 andrew 1061 UIC 0 : else if (bytes == 3)
5682 andrew 1062 EUB : {
5682 andrew 1063 UIC 0 : wch[0] = 0xE0 | ((cvalue >> 12) & 0x0F);
5682 andrew 1064 UBC 0 : wch[1] = 0x80 | ((cvalue >> 6) & 0x3F);
1065 0 : wch[2] = 0x80 | (cvalue & 0x3F);
5682 andrew 1066 EUB : }
1067 : else
1068 : {
5682 andrew 1069 UIC 0 : wch[0] = 0xF0 | ((cvalue >> 18) & 0x07);
5682 andrew 1070 UBC 0 : wch[1] = 0x80 | ((cvalue >> 12) & 0x3F);
1071 0 : wch[2] = 0x80 | ((cvalue >> 6) & 0x3F);
1072 0 : wch[3] = 0x80 | (cvalue & 0x3F);
5682 andrew 1073 EUB : }
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 : */
3250 tgl 1080 UIC 0 : if (!pg_utf8_islegal(wch, bytes))
3250 tgl 1081 UBC 0 : ereport(ERROR,
3250 tgl 1082 EUB : (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 :
5682 andrew 1090 GIC 272595 : is_mb = pg_encoding_max_length(encoding) > 1;
5682 andrew 1091 ECB :
5591 andrew 1092 GIC 272595 : if ((is_mb && (cvalue > 127)) || (!is_mb && (cvalue > 255)))
5682 andrew 1093 LBC 0 : ereport(ERROR,
5682 andrew 1094 EUB : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1095 : errmsg("requested character too large for encoding: %u",
1096 : cvalue)));
1097 :
5682 andrew 1098 GIC 272595 : result = (text *) palloc(VARHDRSZ + 1);
5682 andrew 1099 CBC 272595 : SET_VARSIZE(result, VARHDRSZ + 1);
1100 272595 : *VARDATA(result) = (char) cvalue;
5682 andrew 1101 ECB : }
1102 :
8335 tgl 1103 GIC 272595 : PG_RETURN_TEXT_P(result);
8335 tgl 1104 ECB : }
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
8335 tgl 1121 GIC 21002 : repeat(PG_FUNCTION_ARGS)
8402 lockhart 1122 ECB : {
5679 tgl 1123 GIC 21002 : text *string = PG_GETARG_TEXT_PP(0);
8053 bruce 1124 CBC 21002 : int32 count = PG_GETARG_INT32(1);
8053 bruce 1125 ECB : text *result;
1126 : int slen,
1127 : tlen;
1128 : int i;
1129 : char *cp,
1130 : *sp;
1131 :
8402 lockhart 1132 GIC 21002 : if (count < 0)
8402 lockhart 1133 CBC 3 : count = 0;
8402 lockhart 1134 ECB :
5679 tgl 1135 GIC 21002 : slen = VARSIZE_ANY_EXHDR(string);
8402 lockhart 1136 ECB :
1944 andres 1137 GIC 21002 : if (unlikely(pg_mul_s32_overflow(count, slen, &tlen)) ||
318 tgl 1138 CBC 21002 : unlikely(pg_add_s32_overflow(tlen, VARHDRSZ, &tlen)) ||
1139 21002 : unlikely(!AllocSizeIsValid(tlen)))
1944 andres 1140 LBC 0 : ereport(ERROR,
1944 andres 1141 EUB : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1142 : errmsg("requested length too large")));
1143 :
8402 lockhart 1144 GIC 21002 : result = (text *) palloc(tlen);
8402 lockhart 1145 ECB :
5885 tgl 1146 GIC 21002 : SET_VARSIZE(result, tlen);
8402 lockhart 1147 CBC 21002 : cp = VARDATA(result);
5679 tgl 1148 21002 : sp = VARDATA_ANY(string);
8402 lockhart 1149 19076835 : for (i = 0; i < count; i++)
8402 lockhart 1150 ECB : {
5679 tgl 1151 GIC 19055833 : memcpy(cp, sp, slen);
8402 lockhart 1152 CBC 19055833 : cp += slen;
1046 mail 1153 19055833 : CHECK_FOR_INTERRUPTS();
8402 lockhart 1154 ECB : }
1155 :
8335 tgl 1156 GIC 21002 : PG_RETURN_TEXT_P(result);
8335 tgl 1157 ECB : }
|