Age Owner Branch data TLA 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
8683 tgl@sss.pgh.pa.us 49 :CBC 90325 : lower(PG_FUNCTION_ARGS)
50 : : {
5421 bruce@momjian.us 51 : 90325 : text *in_string = PG_GETARG_TEXT_PP(0);
52 : : char *out_string;
53 : : text *result;
54 : :
5755 tgl@sss.pgh.pa.us 55 [ + + ]: 90325 : out_string = str_tolower(VARDATA_ANY(in_string),
4814 peter_e@gmx.net 56 [ - + - - : 90325 : VARSIZE_ANY_EXHDR(in_string),
- - - - +
+ ]
57 : : PG_GET_COLLATION());
5774 bruce@momjian.us 58 : 90325 : result = cstring_to_text(out_string);
59 : 90325 : pfree(out_string);
60 : :
61 : 90325 : 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
8683 tgl@sss.pgh.pa.us 80 : 523781 : upper(PG_FUNCTION_ARGS)
81 : : {
5421 bruce@momjian.us 82 : 523781 : text *in_string = PG_GETARG_TEXT_PP(0);
83 : : char *out_string;
84 : : text *result;
85 : :
5755 tgl@sss.pgh.pa.us 86 [ + + ]: 523781 : out_string = str_toupper(VARDATA_ANY(in_string),
4814 peter_e@gmx.net 87 [ - + - - : 523781 : VARSIZE_ANY_EXHDR(in_string),
- - - - +
+ ]
88 : : PG_GET_COLLATION());
5774 bruce@momjian.us 89 : 523781 : result = cstring_to_text(out_string);
90 : 523781 : pfree(out_string);
91 : :
92 : 523781 : 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
8683 tgl@sss.pgh.pa.us 114 : 65 : initcap(PG_FUNCTION_ARGS)
115 : : {
5421 bruce@momjian.us 116 : 65 : text *in_string = PG_GETARG_TEXT_PP(0);
117 : : char *out_string;
118 : : text *result;
119 : :
5755 tgl@sss.pgh.pa.us 120 [ + + ]: 65 : out_string = str_initcap(VARDATA_ANY(in_string),
4814 peter_e@gmx.net 121 [ - + - - : 65 : VARSIZE_ANY_EXHDR(in_string),
- - - - +
+ ]
122 : : PG_GET_COLLATION());
5774 bruce@momjian.us 123 : 65 : result = cstring_to_text(out_string);
124 : 65 : pfree(out_string);
125 : :
126 : 65 : 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
8706 tgl@sss.pgh.pa.us 147 : 16583 : lpad(PG_FUNCTION_ARGS)
148 : : {
6050 149 : 16583 : text *string1 = PG_GETARG_TEXT_PP(0);
8706 150 : 16583 : int32 len = PG_GETARG_INT32(1);
6050 151 : 16583 : 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 */
8529 164 [ + + ]: 16583 : if (len < 0)
165 : 3 : len = 0;
166 : :
6050 167 [ - + - - : 16583 : s1len = VARSIZE_ANY_EXHDR(string1);
- - - - -
+ ]
8529 168 [ - + ]: 16583 : if (s1len < 0)
8529 tgl@sss.pgh.pa.us 169 :UBC 0 : s1len = 0; /* shouldn't happen */
170 : :
6050 tgl@sss.pgh.pa.us 171 [ - + - - :CBC 16583 : s2len = VARSIZE_ANY_EXHDR(string2);
- - - - -
+ ]
8529 172 [ - + ]: 16583 : if (s2len < 0)
8529 tgl@sss.pgh.pa.us 173 :UBC 0 : s2len = 0; /* shouldn't happen */
174 : :
6050 tgl@sss.pgh.pa.us 175 [ - + ]:CBC 16583 : s1len = pg_mbstrlen_with_len(VARDATA_ANY(string1), s1len);
176 : :
8529 177 [ + + ]: 16583 : if (s1len > len)
178 : 35 : s1len = len; /* truncate string1 to len chars */
179 : :
180 [ + + ]: 16583 : if (s2len <= 0)
181 : 3 : len = s1len; /* nothing to pad with, so don't pad */
182 : :
183 : : /* compute worst-case output length */
689 184 [ + - ]: 16583 : if (unlikely(pg_mul_s32_overflow(pg_database_encoding_max_length(), len,
185 : 16583 : &bytelen)) ||
186 [ + - ]: 16583 : unlikely(pg_add_s32_overflow(bytelen, VARHDRSZ, &bytelen)) ||
187 [ - + ]: 16583 : unlikely(!AllocSizeIsValid(bytelen)))
7567 tgl@sss.pgh.pa.us 188 [ # # ]:UBC 0 : ereport(ERROR,
189 : : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
190 : : errmsg("requested length too large")));
191 : :
689 tgl@sss.pgh.pa.us 192 :CBC 16583 : ret = (text *) palloc(bytelen);
193 : :
8529 194 : 16583 : m = len - s1len;
195 : :
6050 196 [ - + ]: 16583 : ptr2 = ptr2start = VARDATA_ANY(string2);
8529 197 : 16583 : ptr2end = ptr2 + s2len;
9716 bruce@momjian.us 198 : 16583 : ptr_ret = VARDATA(ret);
199 : :
8239 ishii@postgresql.org 200 [ + + ]: 17749 : while (m--)
201 : : {
8207 bruce@momjian.us 202 : 1166 : int mlen = pg_mblen(ptr2);
203 : :
204 : 1166 : memcpy(ptr_ret, ptr2, mlen);
205 : 1166 : ptr_ret += mlen;
206 : 1166 : ptr2 += mlen;
207 [ + + ]: 1166 : if (ptr2 == ptr2end) /* wrap around at end of s2 */
6050 tgl@sss.pgh.pa.us 208 : 1154 : ptr2 = ptr2start;
209 : : }
210 : :
211 [ - + ]: 16583 : ptr1 = VARDATA_ANY(string1);
212 : :
8239 ishii@postgresql.org 213 [ + + ]: 48739 : while (s1len--)
214 : : {
8207 bruce@momjian.us 215 : 32156 : int mlen = pg_mblen(ptr1);
216 : :
217 : 32156 : memcpy(ptr_ret, ptr1, mlen);
218 : 32156 : ptr_ret += mlen;
219 : 32156 : ptr1 += mlen;
220 : : }
221 : :
6256 tgl@sss.pgh.pa.us 222 : 16583 : SET_VARSIZE(ret, ptr_ret - (char *) ret);
223 : :
8706 224 : 16583 : 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 : 22 : rpad(PG_FUNCTION_ARGS)
246 : : {
6050 247 : 22 : text *string1 = PG_GETARG_TEXT_PP(0);
8706 248 : 22 : int32 len = PG_GETARG_INT32(1);
6050 249 : 22 : 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 */
8529 262 [ + + ]: 22 : if (len < 0)
263 : 3 : len = 0;
264 : :
6050 265 [ - + - - : 22 : s1len = VARSIZE_ANY_EXHDR(string1);
- - - - -
+ ]
8529 266 [ - + ]: 22 : if (s1len < 0)
8529 tgl@sss.pgh.pa.us 267 :UBC 0 : s1len = 0; /* shouldn't happen */
268 : :
6050 tgl@sss.pgh.pa.us 269 [ - + - - :CBC 22 : s2len = VARSIZE_ANY_EXHDR(string2);
- - - - -
+ ]
8529 270 [ - + ]: 22 : if (s2len < 0)
8529 tgl@sss.pgh.pa.us 271 :UBC 0 : s2len = 0; /* shouldn't happen */
272 : :
6050 tgl@sss.pgh.pa.us 273 [ - + ]:CBC 22 : s1len = pg_mbstrlen_with_len(VARDATA_ANY(string1), s1len);
274 : :
8529 275 [ + + ]: 22 : if (s1len > len)
276 : 6 : s1len = len; /* truncate string1 to len chars */
277 : :
278 [ + + ]: 22 : if (s2len <= 0)
279 : 3 : len = s1len; /* nothing to pad with, so don't pad */
280 : :
281 : : /* compute worst-case output length */
689 282 [ + - ]: 22 : if (unlikely(pg_mul_s32_overflow(pg_database_encoding_max_length(), len,
283 : 22 : &bytelen)) ||
284 [ + - ]: 22 : unlikely(pg_add_s32_overflow(bytelen, VARHDRSZ, &bytelen)) ||
285 [ - + ]: 22 : unlikely(!AllocSizeIsValid(bytelen)))
7567 tgl@sss.pgh.pa.us 286 [ # # ]:UBC 0 : ereport(ERROR,
287 : : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
288 : : errmsg("requested length too large")));
289 : :
689 tgl@sss.pgh.pa.us 290 :CBC 22 : ret = (text *) palloc(bytelen);
291 : :
8529 292 : 22 : m = len - s1len;
293 : :
6050 294 [ - + ]: 22 : ptr1 = VARDATA_ANY(string1);
9716 bruce@momjian.us 295 : 22 : ptr_ret = VARDATA(ret);
296 : :
8239 ishii@postgresql.org 297 [ + + ]: 54 : while (s1len--)
298 : : {
8207 bruce@momjian.us 299 : 32 : int mlen = pg_mblen(ptr1);
300 : :
301 : 32 : memcpy(ptr_ret, ptr1, mlen);
302 : 32 : ptr_ret += mlen;
303 : 32 : ptr1 += mlen;
304 : : }
305 : :
6050 tgl@sss.pgh.pa.us 306 [ - + ]: 22 : ptr2 = ptr2start = VARDATA_ANY(string2);
8529 307 : 22 : ptr2end = ptr2 + s2len;
308 : :
8239 ishii@postgresql.org 309 [ + + ]: 960052 : while (m--)
310 : : {
8207 bruce@momjian.us 311 : 960030 : int mlen = pg_mblen(ptr2);
312 : :
313 : 960030 : memcpy(ptr_ret, ptr2, mlen);
314 : 960030 : ptr_ret += mlen;
315 : 960030 : ptr2 += mlen;
316 [ + + ]: 960030 : if (ptr2 == ptr2end) /* wrap around at end of s2 */
6050 tgl@sss.pgh.pa.us 317 : 960018 : ptr2 = ptr2start;
318 : : }
319 : :
6256 320 : 22 : SET_VARSIZE(ret, ptr_ret - (char *) ret);
321 : :
8706 322 : 22 : 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
8683 342 : 10 : btrim(PG_FUNCTION_ARGS)
343 : : {
6050 344 : 10 : text *string = PG_GETARG_TEXT_PP(0);
345 : 10 : text *set = PG_GETARG_TEXT_PP(1);
346 : : text *ret;
347 : :
348 [ - + - - : 20 : ret = dotrim(VARDATA_ANY(string), VARSIZE_ANY_EXHDR(string),
- - - - -
+ - + ]
349 [ - + - - : 20 : VARDATA_ANY(set), VARSIZE_ANY_EXHDR(set),
- - - - -
+ - + ]
350 : : true, true);
351 : :
7632 352 : 10 : PG_RETURN_TEXT_P(ret);
353 : : }
354 : :
355 : : /********************************************************************
356 : : *
357 : : * btrim1 --- btrim with set fixed as ' '
358 : : *
359 : : ********************************************************************/
360 : :
361 : : Datum
362 : 281 : btrim1(PG_FUNCTION_ARGS)
363 : : {
6050 364 : 281 : text *string = PG_GETARG_TEXT_PP(0);
365 : : text *ret;
366 : :
367 [ - + - - : 281 : ret = dotrim(VARDATA_ANY(string), VARSIZE_ANY_EXHDR(string),
- - - - -
+ - + ]
368 : : " ", 1,
369 : : true, true);
370 : :
7632 371 : 281 : PG_RETURN_TEXT_P(ret);
372 : : }
373 : :
374 : : /*
375 : : * Common implementation for btrim, ltrim, rtrim
376 : : */
377 : : static text *
378 : 17143 : 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 [ + - + - ]: 17143 : if (stringlen > 0 && setlen > 0)
386 : : {
387 [ + + ]: 17143 : 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 : 17132 : stringchars = (const char **) palloc(stringlen * sizeof(char *));
409 : 17132 : stringmblen = (int *) palloc(stringlen * sizeof(int));
410 : 17132 : stringnchars = 0;
411 : 17132 : p = string;
412 : 17132 : len = stringlen;
413 [ + + ]: 152222 : while (len > 0)
414 : : {
415 : 135090 : stringchars[stringnchars] = p;
416 : 135090 : stringmblen[stringnchars] = mblen = pg_mblen(p);
417 : 135090 : stringnchars++;
418 : 135090 : p += mblen;
419 : 135090 : len -= mblen;
420 : : }
421 : :
422 : 17132 : setchars = (const char **) palloc(setlen * sizeof(char *));
423 : 17132 : setmblen = (int *) palloc(setlen * sizeof(int));
424 : 17132 : setnchars = 0;
425 : 17132 : p = set;
426 : 17132 : len = setlen;
427 [ + + ]: 34603 : while (len > 0)
428 : : {
429 : 17471 : setchars[setnchars] = p;
430 : 17471 : setmblen[setnchars] = mblen = pg_mblen(p);
431 : 17471 : setnchars++;
432 : 17471 : p += mblen;
433 : 17471 : len -= mblen;
434 : : }
435 : :
436 : 17132 : resultndx = 0; /* index in stringchars[] */
437 : 17132 : resultnchars = stringnchars;
438 : :
439 [ + + ]: 17132 : if (doltrim)
440 : : {
441 [ + - ]: 28294 : while (resultnchars > 0)
442 : : {
443 : 28294 : str_pos = stringchars[resultndx];
444 : 28294 : str_len = stringmblen[resultndx];
445 [ + + ]: 42605 : for (i = 0; i < setnchars; i++)
446 : : {
447 [ + - ]: 28354 : if (str_len == setmblen[i] &&
448 [ + + ]: 28354 : memcmp(str_pos, setchars[i], str_len) == 0)
449 : 14043 : break;
450 : : }
451 [ + + ]: 28294 : if (i >= setnchars)
452 : 14251 : break; /* no match here */
453 : 14043 : string += str_len;
454 : 14043 : stringlen -= str_len;
455 : 14043 : resultndx++;
456 : 14043 : resultnchars--;
457 : : }
458 : : }
459 : :
460 [ + + ]: 17132 : if (dortrim)
461 : : {
462 [ + - ]: 37260 : while (resultnchars > 0)
463 : : {
464 : 37260 : str_pos = stringchars[resultndx + resultnchars - 1];
465 : 37260 : str_len = stringmblen[resultndx + resultnchars - 1];
466 [ + + ]: 41505 : for (i = 0; i < setnchars; i++)
467 : : {
468 [ + - ]: 38333 : if (str_len == setmblen[i] &&
469 [ + + ]: 38333 : memcmp(str_pos, setchars[i], str_len) == 0)
470 : 34088 : break;
471 : : }
472 [ + + ]: 37260 : if (i >= setnchars)
473 : 3172 : break; /* no match here */
474 : 34088 : stringlen -= str_len;
475 : 34088 : resultnchars--;
476 : : }
477 : : }
478 : :
479 : 17132 : pfree(stringchars);
480 : 17132 : pfree(stringmblen);
481 : 17132 : pfree(setchars);
482 : 17132 : pfree(setmblen);
483 : : }
484 : : else
485 : : {
486 : : /*
487 : : * In the single-byte-encoding case, we don't need such overhead.
488 : : */
489 [ - + ]: 11 : if (doltrim)
490 : : {
7632 tgl@sss.pgh.pa.us 491 [ # # ]:UBC 0 : while (stringlen > 0)
492 : : {
7559 bruce@momjian.us 493 : 0 : char str_ch = *string;
494 : :
7632 tgl@sss.pgh.pa.us 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 : :
7632 tgl@sss.pgh.pa.us 507 [ + - ]:CBC 11 : if (dortrim)
508 : : {
509 [ + - ]: 22 : while (stringlen > 0)
510 : : {
7559 bruce@momjian.us 511 : 22 : char str_ch = string[stringlen - 1];
512 : :
7632 tgl@sss.pgh.pa.us 513 [ + + ]: 33 : for (i = 0; i < setlen; i++)
514 : : {
515 [ + + ]: 22 : if (str_ch == set[i])
516 : 11 : break;
517 : : }
518 [ + + ]: 22 : if (i >= setlen)
519 : 11 : break; /* no match here */
520 : 11 : stringlen--;
521 : : }
522 : : }
523 : : }
524 : : }
525 : :
526 : : /* Return selected portion of string */
5864 527 : 17143 : return cstring_to_text_with_len(string, stringlen);
528 : : }
529 : :
530 : : /*
531 : : * Common implementation for bytea versions of btrim, ltrim, rtrim
532 : : */
533 : : bytea *
1182 534 : 18 : 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 : :
6050 546 [ - + - - : 18 : stringlen = VARSIZE_ANY_EXHDR(string);
- - - - -
+ ]
547 [ - + - - : 18 : setlen = VARSIZE_ANY_EXHDR(set);
- - - - -
+ ]
548 : :
549 [ + + + + ]: 18 : if (stringlen <= 0 || setlen <= 0)
1182 550 : 6 : return string;
551 : :
6050 552 : 12 : m = stringlen;
553 [ - + ]: 12 : ptr = VARDATA_ANY(string);
554 : 12 : end = ptr + stringlen - 1;
555 [ - + ]: 12 : ptr2start = VARDATA_ANY(set);
556 : 12 : end2 = ptr2start + setlen - 1;
557 : :
1182 558 [ + + ]: 12 : if (doltrim)
559 : : {
560 [ + - ]: 18 : while (m > 0)
561 : : {
562 : 18 : ptr2 = ptr2start;
563 [ + + ]: 27 : while (ptr2 <= end2)
564 : : {
565 [ + + ]: 18 : if (*ptr == *ptr2)
566 : 9 : break;
567 : 9 : ++ptr2;
568 : : }
569 [ + + ]: 18 : if (ptr2 > end2)
8248 bruce@momjian.us 570 : 9 : break;
1182 tgl@sss.pgh.pa.us 571 : 9 : ptr++;
572 : 9 : m--;
573 : : }
574 : : }
575 : :
576 [ + + ]: 12 : if (dortrim)
577 : : {
578 [ + - ]: 18 : while (m > 0)
579 : : {
580 : 18 : ptr2 = ptr2start;
581 [ + + ]: 27 : while (ptr2 <= end2)
582 : : {
583 [ + + ]: 18 : if (*end == *ptr2)
584 : 9 : break;
585 : 9 : ++ptr2;
586 : : }
587 [ + + ]: 18 : if (ptr2 > end2)
8248 bruce@momjian.us 588 : 9 : break;
1182 tgl@sss.pgh.pa.us 589 : 9 : end--;
590 : 9 : m--;
591 : : }
592 : : }
593 : :
8248 bruce@momjian.us 594 : 12 : ret = (bytea *) palloc(VARHDRSZ + m);
6256 tgl@sss.pgh.pa.us 595 : 12 : SET_VARSIZE(ret, VARHDRSZ + m);
8248 bruce@momjian.us 596 : 12 : memcpy(VARDATA(ret), ptr, m);
1182 tgl@sss.pgh.pa.us 597 : 12 : 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 : 12 : byteatrim(PG_FUNCTION_ARGS)
618 : : {
619 : 12 : bytea *string = PG_GETARG_BYTEA_PP(0);
620 : 12 : bytea *set = PG_GETARG_BYTEA_PP(1);
621 : : bytea *ret;
622 : :
623 : 12 : ret = dobyteatrim(string, set, true, true);
624 : :
625 : 12 : 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 : 3 : bytealtrim(PG_FUNCTION_ARGS)
645 : : {
646 : 3 : bytea *string = PG_GETARG_BYTEA_PP(0);
647 : 3 : bytea *set = PG_GETARG_BYTEA_PP(1);
648 : : bytea *ret;
649 : :
650 : 3 : ret = dobyteatrim(string, set, true, false);
651 : :
652 : 3 : 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 : 3 : byteartrim(PG_FUNCTION_ARGS)
672 : : {
673 : 3 : bytea *string = PG_GETARG_BYTEA_PP(0);
674 : 3 : bytea *set = PG_GETARG_BYTEA_PP(1);
675 : : bytea *ret;
676 : :
677 : 3 : ret = dobyteatrim(string, set, false, true);
678 : :
8248 bruce@momjian.us 679 : 3 : 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
8683 tgl@sss.pgh.pa.us 698 : 13956 : ltrim(PG_FUNCTION_ARGS)
699 : : {
6050 700 : 13956 : text *string = PG_GETARG_TEXT_PP(0);
701 : 13956 : text *set = PG_GETARG_TEXT_PP(1);
702 : : text *ret;
703 : :
704 [ - + - - : 27912 : ret = dotrim(VARDATA_ANY(string), VARSIZE_ANY_EXHDR(string),
- - - - +
+ + + ]
705 [ - + - - : 27912 : VARDATA_ANY(set), VARSIZE_ANY_EXHDR(set),
- - - - -
+ - + ]
706 : : true, false);
707 : :
7632 708 : 13956 : PG_RETURN_TEXT_P(ret);
709 : : }
710 : :
711 : : /********************************************************************
712 : : *
713 : : * ltrim1 --- ltrim with set fixed as ' '
714 : : *
715 : : ********************************************************************/
716 : :
717 : : Datum
718 : 4 : ltrim1(PG_FUNCTION_ARGS)
719 : : {
6050 720 : 4 : text *string = PG_GETARG_TEXT_PP(0);
721 : : text *ret;
722 : :
723 [ - + - - : 4 : ret = dotrim(VARDATA_ANY(string), VARSIZE_ANY_EXHDR(string),
- - - - -
+ - + ]
724 : : " ", 1,
725 : : true, false);
726 : :
8683 727 : 4 : 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 : 130 : rtrim(PG_FUNCTION_ARGS)
747 : : {
6050 748 : 130 : text *string = PG_GETARG_TEXT_PP(0);
749 : 130 : text *set = PG_GETARG_TEXT_PP(1);
750 : : text *ret;
751 : :
752 [ - + - - : 260 : ret = dotrim(VARDATA_ANY(string), VARSIZE_ANY_EXHDR(string),
- - - - -
+ - + ]
753 [ - + - - : 260 : VARDATA_ANY(set), VARSIZE_ANY_EXHDR(set),
- - - - -
+ - + ]
754 : : false, true);
755 : :
7632 756 : 130 : PG_RETURN_TEXT_P(ret);
757 : : }
758 : :
759 : : /********************************************************************
760 : : *
761 : : * rtrim1 --- rtrim with set fixed as ' '
762 : : *
763 : : ********************************************************************/
764 : :
765 : : Datum
766 : 2762 : rtrim1(PG_FUNCTION_ARGS)
767 : : {
6050 768 : 2762 : text *string = PG_GETARG_TEXT_PP(0);
769 : : text *ret;
770 : :
771 [ - + - - : 2762 : ret = dotrim(VARDATA_ANY(string), VARSIZE_ANY_EXHDR(string),
- - - - +
+ + + ]
772 : : " ", 1,
773 : : false, true);
774 : :
8683 775 : 2762 : 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 : 17 : translate(PG_FUNCTION_ARGS)
798 : : {
6050 799 : 17 : text *string = PG_GETARG_TEXT_PP(0);
800 : 17 : text *from = PG_GETARG_TEXT_PP(1);
801 : 17 : 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 [ - + - - : 17 : m = VARSIZE_ANY_EXHDR(string);
- - - - -
+ ]
819 [ + + ]: 17 : if (m <= 0)
8683 820 : 3 : PG_RETURN_TEXT_P(string);
6049 821 [ - + ]: 14 : source = VARDATA_ANY(string);
822 : :
6050 823 [ - + - - : 14 : fromlen = VARSIZE_ANY_EXHDR(from);
- - - - -
+ ]
824 [ - + ]: 14 : from_ptr = VARDATA_ANY(from);
825 [ - + - - : 14 : tolen = VARSIZE_ANY_EXHDR(to);
- - - - -
+ ]
826 [ - + ]: 14 : to_ptr = VARDATA_ANY(to);
410 827 : 14 : 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 : : */
689 833 [ + - ]: 14 : if (unlikely(pg_mul_s32_overflow(pg_database_encoding_max_length(), m,
834 : 14 : &bytelen)) ||
835 [ + - ]: 14 : unlikely(pg_add_s32_overflow(bytelen, VARHDRSZ, &bytelen)) ||
836 [ - + ]: 14 : unlikely(!AllocSizeIsValid(bytelen)))
6049 tgl@sss.pgh.pa.us 837 [ # # ]:UBC 0 : ereport(ERROR,
838 : : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
839 : : errmsg("requested length too large")));
840 : :
689 tgl@sss.pgh.pa.us 841 :CBC 14 : result = (text *) palloc(bytelen);
842 : :
8796 843 : 14 : target = VARDATA(result);
8797 lockhart@fourpalms.o 844 : 14 : retlen = 0;
845 : :
8239 ishii@postgresql.org 846 [ + + ]: 140 : while (m > 0)
847 : : {
848 : 126 : source_len = pg_mblen(source);
849 : 126 : from_index = 0;
850 : :
851 [ + + ]: 342 : for (i = 0; i < fromlen; i += len)
852 : : {
8207 bruce@momjian.us 853 : 247 : len = pg_mblen(&from_ptr[i]);
854 [ + - ]: 247 : if (len == source_len &&
855 [ + + ]: 247 : memcmp(source, &from_ptr[i], len) == 0)
856 : 31 : break;
857 : :
858 : 216 : from_index++;
859 : : }
8239 ishii@postgresql.org 860 [ + + ]: 126 : if (i < fromlen)
861 : : {
862 : : /* substitute, or delete if no corresponding "to" character */
8207 bruce@momjian.us 863 : 31 : char *p = to_ptr;
864 : :
865 [ + + ]: 48 : for (i = 0; i < from_index; i++)
866 : : {
410 tgl@sss.pgh.pa.us 867 [ + + ]: 20 : if (p >= to_end)
8207 bruce@momjian.us 868 : 3 : break;
410 tgl@sss.pgh.pa.us 869 : 17 : p += pg_mblen(p);
870 : : }
871 [ + + ]: 31 : if (p < to_end)
872 : : {
8207 bruce@momjian.us 873 : 25 : len = pg_mblen(p);
874 : 25 : memcpy(target, p, len);
875 : 25 : target += len;
876 : 25 : retlen += len;
877 : : }
878 : : }
879 : : else
880 : : {
881 : : /* no match, so copy */
882 : 95 : memcpy(target, source, source_len);
883 : 95 : target += source_len;
884 : 95 : retlen += source_len;
885 : : }
886 : :
8239 ishii@postgresql.org 887 : 126 : source += source_len;
888 : 126 : m -= source_len;
889 : : }
890 : :
6256 tgl@sss.pgh.pa.us 891 : 14 : 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 : :
8683 899 : 14 : 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 : 29 : ascii(PG_FUNCTION_ARGS)
926 : : {
6050 927 : 29 : text *string = PG_GETARG_TEXT_PP(0);
5995 bruce@momjian.us 928 : 29 : int encoding = GetDatabaseEncoding();
929 : : unsigned char *data;
930 : :
6050 tgl@sss.pgh.pa.us 931 [ - + - - : 29 : if (VARSIZE_ANY_EXHDR(string) <= 0)
- - - - +
+ + + ]
8683 932 : 3 : PG_RETURN_INT32(0);
933 : :
6050 934 [ + + ]: 26 : data = (unsigned char *) VARDATA_ANY(string);
935 : :
6053 andrew@dunslane.net 936 [ + - - + ]: 26 : if (encoding == PG_UTF8 && *data > 127)
937 : : {
938 : : /* return the code point for Unicode */
939 : :
5995 bruce@momjian.us 940 :UBC 0 : int result = 0,
941 : 0 : tbytes = 0,
942 : : i;
943 : :
6053 andrew@dunslane.net 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 : : {
5995 bruce@momjian.us 956 [ # # ]: 0 : Assert(*data > 0xC0);
6053 andrew@dunslane.net 957 : 0 : result = *data & 0x1f;
958 : 0 : tbytes = 1;
959 : : }
960 : :
5995 bruce@momjian.us 961 [ # # ]: 0 : Assert(tbytes > 0);
962 : :
6053 andrew@dunslane.net 963 [ # # ]: 0 : for (i = 1; i <= tbytes; i++)
964 : : {
5995 bruce@momjian.us 965 [ # # ]: 0 : Assert((data[i] & 0xC0) == 0x80);
6053 andrew@dunslane.net 966 : 0 : result = (result << 6) + (data[i] & 0x3f);
967 : : }
968 : :
969 : 0 : PG_RETURN_INT32(result);
970 : : }
971 : : else
972 : : {
6053 andrew@dunslane.net 973 [ + - - + ]:CBC 26 : if (pg_encoding_max_length(encoding) > 1 && *data > 127)
6053 andrew@dunslane.net 974 [ # # ]:UBC 0 : ereport(ERROR,
975 : : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
976 : : errmsg("requested character too large")));
977 : :
978 : :
6053 andrew@dunslane.net 979 :CBC 26 : 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
5995 bruce@momjian.us 1006 : 272330 : chr (PG_FUNCTION_ARGS)
1007 : : {
860 peter@eisentraut.org 1008 : 272330 : int32 arg = PG_GETARG_INT32(0);
1009 : : uint32 cvalue;
1010 : : text *result;
5995 bruce@momjian.us 1011 : 272330 : 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 : : */
860 peter@eisentraut.org 1017 [ - + ]: 272330 : if (arg < 0)
860 peter@eisentraut.org 1018 [ # # ]:UBC 0 : ereport(ERROR,
1019 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1020 : : errmsg("character number must be positive")));
860 peter@eisentraut.org 1021 [ + + ]:CBC 272330 : else if (arg == 0)
1022 [ + - ]: 3 : ereport(ERROR,
1023 : : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1024 : : errmsg("null character not permitted")));
1025 : :
1026 : 272327 : cvalue = arg;
1027 : :
6053 andrew@dunslane.net 1028 [ + - - + ]: 272327 : if (encoding == PG_UTF8 && cvalue > 127)
6053 andrew@dunslane.net 1029 :UBC 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 : : */
3621 tgl@sss.pgh.pa.us 1039 [ # # ]: 0 : if (cvalue > 0x0010ffff)
6053 andrew@dunslane.net 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);
3621 tgl@sss.pgh.pa.us 1054 : 0 : wch = (unsigned char *) VARDATA(result);
1055 : :
6053 andrew@dunslane.net 1056 [ # # ]: 0 : if (bytes == 2)
1057 : : {
1058 : 0 : wch[0] = 0xC0 | ((cvalue >> 6) & 0x1F);
3302 heikki.linnakangas@i 1059 : 0 : wch[1] = 0x80 | (cvalue & 0x3F);
1060 : : }
6053 andrew@dunslane.net 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 : : */
3621 tgl@sss.pgh.pa.us 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 : :
6053 andrew@dunslane.net 1090 :CBC 272327 : is_mb = pg_encoding_max_length(encoding) > 1;
1091 : :
5962 1092 [ + - + - : 272327 : if ((is_mb && (cvalue > 127)) || (!is_mb && (cvalue > 255)))
- + - - ]
6053 andrew@dunslane.net 1093 [ # # ]:UBC 0 : ereport(ERROR,
1094 : : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1095 : : errmsg("requested character too large for encoding: %u",
1096 : : cvalue)));
1097 : :
6053 andrew@dunslane.net 1098 :CBC 272327 : result = (text *) palloc(VARHDRSZ + 1);
1099 : 272327 : SET_VARSIZE(result, VARHDRSZ + 1);
1100 : 272327 : *VARDATA(result) = (char) cvalue;
1101 : : }
1102 : :
8706 tgl@sss.pgh.pa.us 1103 : 272327 : 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 : 118888 : repeat(PG_FUNCTION_ARGS)
1122 : : {
6050 1123 : 118888 : text *string = PG_GETARG_TEXT_PP(0);
8424 bruce@momjian.us 1124 : 118888 : int32 count = PG_GETARG_INT32(1);
1125 : : text *result;
1126 : : int slen,
1127 : : tlen;
1128 : : int i;
1129 : : char *cp,
1130 : : *sp;
1131 : :
8773 lockhart@fourpalms.o 1132 [ + + ]: 118888 : if (count < 0)
1133 : 3 : count = 0;
1134 : :
6050 tgl@sss.pgh.pa.us 1135 [ - + - - : 118888 : slen = VARSIZE_ANY_EXHDR(string);
- - - - -
+ ]
1136 : :
2315 andres@anarazel.de 1137 [ + - ]: 118888 : if (unlikely(pg_mul_s32_overflow(count, slen, &tlen)) ||
689 tgl@sss.pgh.pa.us 1138 [ + - ]: 118888 : unlikely(pg_add_s32_overflow(tlen, VARHDRSZ, &tlen)) ||
1139 [ - + ]: 118888 : unlikely(!AllocSizeIsValid(tlen)))
2315 andres@anarazel.de 1140 [ # # ]:UBC 0 : ereport(ERROR,
1141 : : (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1142 : : errmsg("requested length too large")));
1143 : :
8773 lockhart@fourpalms.o 1144 :CBC 118888 : result = (text *) palloc(tlen);
1145 : :
6256 tgl@sss.pgh.pa.us 1146 : 118888 : SET_VARSIZE(result, tlen);
8773 lockhart@fourpalms.o 1147 : 118888 : cp = VARDATA(result);
6050 tgl@sss.pgh.pa.us 1148 [ - + ]: 118888 : sp = VARDATA_ANY(string);
8773 lockhart@fourpalms.o 1149 [ + + ]: 20231337 : for (i = 0; i < count; i++)
1150 : : {
6050 tgl@sss.pgh.pa.us 1151 : 20112449 : memcpy(cp, sp, slen);
8773 lockhart@fourpalms.o 1152 : 20112449 : cp += slen;
1417 mail@joeconway.com 1153 [ - + ]: 20112449 : CHECK_FOR_INTERRUPTS();
1154 : : }
1155 : :
8706 tgl@sss.pgh.pa.us 1156 : 118888 : PG_RETURN_TEXT_P(result);
1157 : : }
|