Branch data Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * numutils.c
4 : : * utility functions for I/O of built-in numeric types.
5 : : *
6 : : * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
7 : : * Portions Copyright (c) 1994, Regents of the University of California
8 : : *
9 : : *
10 : : * IDENTIFICATION
11 : : * src/backend/utils/adt/numutils.c
12 : : *
13 : : *-------------------------------------------------------------------------
14 : : */
15 : : #include "postgres.h"
16 : :
17 : : #include <limits.h>
18 : : #include <ctype.h>
19 : :
20 : : #include "common/int.h"
21 : : #include "port/pg_bitutils.h"
22 : : #include "utils/builtins.h"
23 : :
24 : : /*
25 : : * A table of all two-digit numbers. This is used to speed up decimal digit
26 : : * generation by copying pairs of digits into the final output.
27 : : */
28 : : static const char DIGIT_TABLE[200] =
29 : : "00" "01" "02" "03" "04" "05" "06" "07" "08" "09"
30 : : "10" "11" "12" "13" "14" "15" "16" "17" "18" "19"
31 : : "20" "21" "22" "23" "24" "25" "26" "27" "28" "29"
32 : : "30" "31" "32" "33" "34" "35" "36" "37" "38" "39"
33 : : "40" "41" "42" "43" "44" "45" "46" "47" "48" "49"
34 : : "50" "51" "52" "53" "54" "55" "56" "57" "58" "59"
35 : : "60" "61" "62" "63" "64" "65" "66" "67" "68" "69"
36 : : "70" "71" "72" "73" "74" "75" "76" "77" "78" "79"
37 : : "80" "81" "82" "83" "84" "85" "86" "87" "88" "89"
38 : : "90" "91" "92" "93" "94" "95" "96" "97" "98" "99";
39 : :
40 : : /*
41 : : * Adapted from http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
42 : : */
43 : : static inline int
44 : 704655 : decimalLength32(const uint32 v)
45 : : {
46 : 704655 : int t;
47 : : static const uint32 PowersOfTen[] = {
48 : : 1, 10, 100,
49 : : 1000, 10000, 100000,
50 : : 1000000, 10000000, 100000000,
51 : : 1000000000
52 : : };
53 : :
54 : : /*
55 : : * Compute base-10 logarithm by dividing the base-2 logarithm by a
56 : : * good-enough approximation of the base-2 logarithm of 10
57 : : */
58 : 704655 : t = (pg_leftmost_one_pos32(v) + 1) * 1233 / 4096;
59 : 1409310 : return t + (v >= PowersOfTen[t]);
60 : 704655 : }
61 : :
62 : : static inline int
63 : 33988 : decimalLength64(const uint64 v)
64 : : {
65 : 33988 : int t;
66 : : static const uint64 PowersOfTen[] = {
67 : : UINT64CONST(1), UINT64CONST(10),
68 : : UINT64CONST(100), UINT64CONST(1000),
69 : : UINT64CONST(10000), UINT64CONST(100000),
70 : : UINT64CONST(1000000), UINT64CONST(10000000),
71 : : UINT64CONST(100000000), UINT64CONST(1000000000),
72 : : UINT64CONST(10000000000), UINT64CONST(100000000000),
73 : : UINT64CONST(1000000000000), UINT64CONST(10000000000000),
74 : : UINT64CONST(100000000000000), UINT64CONST(1000000000000000),
75 : : UINT64CONST(10000000000000000), UINT64CONST(100000000000000000),
76 : : UINT64CONST(1000000000000000000), UINT64CONST(10000000000000000000)
77 : : };
78 : :
79 : : /*
80 : : * Compute base-10 logarithm by dividing the base-2 logarithm by a
81 : : * good-enough approximation of the base-2 logarithm of 10
82 : : */
83 : 33988 : t = (pg_leftmost_one_pos64(v) + 1) * 1233 / 4096;
84 : 67976 : return t + (v >= PowersOfTen[t]);
85 : 33988 : }
86 : :
87 : : static const int8 hexlookup[128] = {
88 : : -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
89 : : -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
90 : : -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
91 : : 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
92 : : -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
93 : : -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
94 : : -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
95 : : -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
96 : : };
97 : :
98 : : /*
99 : : * Convert input string to a signed 16 bit integer. Input strings may be
100 : : * expressed in base-10, hexadecimal, octal, or binary format, all of which
101 : : * can be prefixed by an optional sign character, either '+' (the default) or
102 : : * '-' for negative numbers. Hex strings are recognized by the digits being
103 : : * prefixed by 0x or 0X while octal strings are recognized by the 0o or 0O
104 : : * prefix. The binary representation is recognized by the 0b or 0B prefix.
105 : : *
106 : : * Allows any number of leading or trailing whitespace characters. Digits may
107 : : * optionally be separated by a single underscore character. These can only
108 : : * come between digits and not before or after the digits. Underscores have
109 : : * no effect on the return value and are supported only to assist in improving
110 : : * the human readability of the input strings.
111 : : *
112 : : * pg_strtoint16() will throw ereport() upon bad input format or overflow;
113 : : * while pg_strtoint16_safe() instead returns such complaints in *escontext,
114 : : * if it's an ErrorSaveContext.
115 : : *
116 : : * NB: Accumulate input as an unsigned number, to deal with two's complement
117 : : * representation of the most negative number, which can't be represented as a
118 : : * signed positive number.
119 : : */
120 : : int16
121 : 0 : pg_strtoint16(const char *s)
122 : : {
123 : 0 : return pg_strtoint16_safe(s, NULL);
124 : : }
125 : :
126 : : int16
127 : 10171 : pg_strtoint16_safe(const char *s, Node *escontext)
128 : : {
129 : 10171 : const char *ptr = s;
130 : 10171 : const char *firstdigit;
131 : 10171 : uint16 tmp = 0;
132 : 10171 : bool neg = false;
133 : 10171 : unsigned char digit;
134 : 10171 : int16 result;
135 : :
136 : : /*
137 : : * The majority of cases are likely to be base-10 digits without any
138 : : * underscore separator characters. We'll first try to parse the string
139 : : * with the assumption that's the case and only fallback on a slower
140 : : * implementation which handles hex, octal and binary strings and
141 : : * underscores if the fastpath version cannot parse the string.
142 : : */
143 : :
144 : : /* leave it up to the slow path to look for leading spaces */
145 : :
146 [ + + ]: 10171 : if (*ptr == '-')
147 : : {
148 : 240 : ptr++;
149 : 240 : neg = true;
150 : 240 : }
151 : :
152 : : /* a leading '+' is uncommon so leave that for the slow path */
153 : :
154 : : /* process the first digit */
155 : 10171 : digit = (*ptr - '0');
156 : :
157 : : /*
158 : : * Exploit unsigned arithmetic to save having to check both the upper and
159 : : * lower bounds of the digit.
160 : : */
161 [ + + ]: 10171 : if (likely(digit < 10))
162 : : {
163 : 10151 : ptr++;
164 : 10151 : tmp = digit;
165 : 10151 : }
166 : : else
167 : : {
168 : : /* we need at least one digit */
169 : 20 : goto slow;
170 : : }
171 : :
172 : : /* process remaining digits */
173 : 10631 : for (;;)
174 : : {
175 : 10631 : digit = (*ptr - '0');
176 : :
177 [ + + ]: 10631 : if (digit >= 10)
178 : 10148 : break;
179 : :
180 : 483 : ptr++;
181 : :
182 [ + + ]: 483 : if (unlikely(tmp > -(PG_INT16_MIN / 10)))
183 : 3 : goto out_of_range;
184 : :
185 : 480 : tmp = tmp * 10 + digit;
186 : : }
187 : :
188 : : /* when the string does not end in a digit, let the slow path handle it */
189 [ + + ]: 10148 : if (unlikely(*ptr != '\0'))
190 : 30 : goto slow;
191 : :
192 [ + + ]: 10118 : if (neg)
193 : : {
194 [ + - ]: 233 : if (unlikely(pg_neg_u16_overflow(tmp, &result)))
195 : 0 : goto out_of_range;
196 : 233 : return result;
197 : : }
198 : :
199 [ + - ]: 9885 : if (unlikely(tmp > PG_INT16_MAX))
200 : 0 : goto out_of_range;
201 : :
202 : 9885 : return (int16) tmp;
203 : :
204 : : slow:
205 : 50 : tmp = 0;
206 : 50 : ptr = s;
207 : : /* no need to reset neg */
208 : :
209 : : /* skip leading spaces */
210 [ + + ]: 60 : while (isspace((unsigned char) *ptr))
211 : 10 : ptr++;
212 : :
213 : : /* handle sign */
214 [ + + ]: 50 : if (*ptr == '-')
215 : : {
216 : 8 : ptr++;
217 : 8 : neg = true;
218 : 8 : }
219 [ + - ]: 42 : else if (*ptr == '+')
220 : 0 : ptr++;
221 : :
222 : : /* process digits */
223 [ + + + + : 50 : if (ptr[0] == '0' && (ptr[1] == 'x' || ptr[1] == 'X'))
- + ]
224 : : {
225 : 7 : firstdigit = ptr += 2;
226 : :
227 : 30 : for (;;)
228 : : {
229 [ + + ]: 30 : if (isxdigit((unsigned char) *ptr))
230 : : {
231 [ - + ]: 22 : if (unlikely(tmp > -(PG_INT16_MIN / 16)))
232 : 0 : goto out_of_range;
233 : :
234 : 22 : tmp = tmp * 16 + hexlookup[(unsigned char) *ptr++];
235 : 22 : }
236 [ + + ]: 8 : else if (*ptr == '_')
237 : : {
238 : : /* underscore must be followed by more digits */
239 : 1 : ptr++;
240 [ + - + - ]: 1 : if (*ptr == '\0' || !isxdigit((unsigned char) *ptr))
241 : 0 : goto invalid_syntax;
242 : 1 : }
243 : : else
244 : 7 : break;
245 : : }
246 : 7 : }
247 [ + + + + : 43 : else if (ptr[0] == '0' && (ptr[1] == 'o' || ptr[1] == 'O'))
- + ]
248 : : {
249 : 7 : firstdigit = ptr += 2;
250 : :
251 : 37 : for (;;)
252 : : {
253 [ + + + + ]: 37 : if (*ptr >= '0' && *ptr <= '7')
254 : : {
255 [ + - ]: 29 : if (unlikely(tmp > -(PG_INT16_MIN / 8)))
256 : 0 : goto out_of_range;
257 : :
258 : 29 : tmp = tmp * 8 + (*ptr++ - '0');
259 : 29 : }
260 [ + + ]: 8 : else if (*ptr == '_')
261 : : {
262 : : /* underscore must be followed by more digits */
263 : 1 : ptr++;
264 [ + - + - : 1 : if (*ptr == '\0' || *ptr < '0' || *ptr > '7')
+ - ]
265 : 0 : goto invalid_syntax;
266 : 1 : }
267 : : else
268 : 7 : break;
269 : : }
270 : 7 : }
271 [ + + + + : 36 : else if (ptr[0] == '0' && (ptr[1] == 'b' || ptr[1] == 'B'))
- + ]
272 : : {
273 : 7 : firstdigit = ptr += 2;
274 : :
275 : 84 : for (;;)
276 : : {
277 [ + + + + ]: 84 : if (*ptr >= '0' && *ptr <= '1')
278 : : {
279 [ + - ]: 75 : if (unlikely(tmp > -(PG_INT16_MIN / 2)))
280 : 0 : goto out_of_range;
281 : :
282 : 75 : tmp = tmp * 2 + (*ptr++ - '0');
283 : 75 : }
284 [ + + ]: 9 : else if (*ptr == '_')
285 : : {
286 : : /* underscore must be followed by more digits */
287 : 2 : ptr++;
288 [ + - + - : 2 : if (*ptr == '\0' || *ptr < '0' || *ptr > '1')
+ - ]
289 : 0 : goto invalid_syntax;
290 : 2 : }
291 : : else
292 : 7 : break;
293 : : }
294 : 7 : }
295 : : else
296 : : {
297 : 29 : firstdigit = ptr;
298 : :
299 : 62 : for (;;)
300 : : {
301 [ + + + + ]: 62 : if (*ptr >= '0' && *ptr <= '9')
302 : : {
303 [ + - ]: 30 : if (unlikely(tmp > -(PG_INT16_MIN / 10)))
304 : 0 : goto out_of_range;
305 : :
306 : 30 : tmp = tmp * 10 + (*ptr++ - '0');
307 : 30 : }
308 [ + + ]: 32 : else if (*ptr == '_')
309 : : {
310 : : /* underscore may not be first */
311 [ + + ]: 6 : if (unlikely(ptr == firstdigit))
312 : 1 : goto invalid_syntax;
313 : : /* and it must be followed by more digits */
314 : 5 : ptr++;
315 [ + + + + ]: 5 : if (*ptr == '\0' || !isdigit((unsigned char) *ptr))
316 : 2 : goto invalid_syntax;
317 : 3 : }
318 : : else
319 : 26 : break;
320 : : }
321 : : }
322 : :
323 : : /* require at least one digit */
324 [ + + ]: 47 : if (unlikely(ptr == firstdigit))
325 : 20 : goto invalid_syntax;
326 : :
327 : : /* allow trailing whitespace, but not other trailing chars */
328 [ + + ]: 33 : while (isspace((unsigned char) *ptr))
329 : 6 : ptr++;
330 : :
331 [ + + ]: 27 : if (unlikely(*ptr != '\0'))
332 : 4 : goto invalid_syntax;
333 : :
334 [ + + ]: 23 : if (neg)
335 : : {
336 [ + + ]: 7 : if (unlikely(pg_neg_u16_overflow(tmp, &result)))
337 : 3 : goto out_of_range;
338 : 4 : return result;
339 : : }
340 : :
341 [ + + ]: 16 : if (tmp > PG_INT16_MAX)
342 : 3 : goto out_of_range;
343 : :
344 : 13 : return (int16) tmp;
345 : :
346 : : out_of_range:
347 [ + + ]: 9 : ereturn(escontext, 0,
348 : : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
349 : : errmsg("value \"%s\" is out of range for type %s",
350 : : s, "smallint")));
351 : :
352 : : invalid_syntax:
353 [ + + ]: 27 : ereturn(escontext, 0,
354 : : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
355 : : errmsg("invalid input syntax for type %s: \"%s\"",
356 : : "smallint", s)));
357 [ - + ]: 10171 : }
358 : :
359 : : /*
360 : : * Convert input string to a signed 32 bit integer. Input strings may be
361 : : * expressed in base-10, hexadecimal, octal, or binary format, all of which
362 : : * can be prefixed by an optional sign character, either '+' (the default) or
363 : : * '-' for negative numbers. Hex strings are recognized by the digits being
364 : : * prefixed by 0x or 0X while octal strings are recognized by the 0o or 0O
365 : : * prefix. The binary representation is recognized by the 0b or 0B prefix.
366 : : *
367 : : * Allows any number of leading or trailing whitespace characters. Digits may
368 : : * optionally be separated by a single underscore character. These can only
369 : : * come between digits and not before or after the digits. Underscores have
370 : : * no effect on the return value and are supported only to assist in improving
371 : : * the human readability of the input strings.
372 : : *
373 : : * pg_strtoint32() will throw ereport() upon bad input format or overflow;
374 : : * while pg_strtoint32_safe() instead returns such complaints in *escontext,
375 : : * if it's an ErrorSaveContext.
376 : : *
377 : : * NB: Accumulate input as an unsigned number, to deal with two's complement
378 : : * representation of the most negative number, which can't be represented as a
379 : : * signed positive number.
380 : : */
381 : : int32
382 : 1158 : pg_strtoint32(const char *s)
383 : : {
384 : 1158 : return pg_strtoint32_safe(s, NULL);
385 : : }
386 : :
387 : : int32
388 : 386865 : pg_strtoint32_safe(const char *s, Node *escontext)
389 : : {
390 : 386865 : const char *ptr = s;
391 : 386865 : const char *firstdigit;
392 : 386865 : uint32 tmp = 0;
393 : 386865 : bool neg = false;
394 : 386865 : unsigned char digit;
395 : 386865 : int32 result;
396 : :
397 : : /*
398 : : * The majority of cases are likely to be base-10 digits without any
399 : : * underscore separator characters. We'll first try to parse the string
400 : : * with the assumption that's the case and only fallback on a slower
401 : : * implementation which handles hex, octal and binary strings and
402 : : * underscores if the fastpath version cannot parse the string.
403 : : */
404 : :
405 : : /* leave it up to the slow path to look for leading spaces */
406 : :
407 [ + + ]: 386865 : if (*ptr == '-')
408 : : {
409 : 412 : ptr++;
410 : 412 : neg = true;
411 : 412 : }
412 : :
413 : : /* a leading '+' is uncommon so leave that for the slow path */
414 : :
415 : : /* process the first digit */
416 : 386865 : digit = (*ptr - '0');
417 : :
418 : : /*
419 : : * Exploit unsigned arithmetic to save having to check both the upper and
420 : : * lower bounds of the digit.
421 : : */
422 [ + + ]: 386865 : if (likely(digit < 10))
423 : : {
424 : 386787 : ptr++;
425 : 386787 : tmp = digit;
426 : 386787 : }
427 : : else
428 : : {
429 : : /* we need at least one digit */
430 : 78 : goto slow;
431 : : }
432 : :
433 : : /* process remaining digits */
434 : 1371100 : for (;;)
435 : : {
436 : 1371100 : digit = (*ptr - '0');
437 : :
438 [ + + ]: 1371100 : if (digit >= 10)
439 : 386616 : break;
440 : :
441 : 984484 : ptr++;
442 : :
443 [ + + ]: 984484 : if (unlikely(tmp > -(PG_INT32_MIN / 10)))
444 : 171 : goto out_of_range;
445 : :
446 : 984313 : tmp = tmp * 10 + digit;
447 : : }
448 : :
449 : : /* when the string does not end in a digit, let the slow path handle it */
450 [ + + ]: 386616 : if (unlikely(*ptr != '\0'))
451 : 94 : goto slow;
452 : :
453 [ + + ]: 386522 : if (neg)
454 : : {
455 [ + - ]: 403 : if (unlikely(pg_neg_u32_overflow(tmp, &result)))
456 : 0 : goto out_of_range;
457 : 403 : return result;
458 : : }
459 : :
460 [ + + ]: 386119 : if (unlikely(tmp > PG_INT32_MAX))
461 : 28 : goto out_of_range;
462 : :
463 : 386091 : return (int32) tmp;
464 : :
465 : : slow:
466 : 172 : tmp = 0;
467 : 172 : ptr = s;
468 : : /* no need to reset neg */
469 : :
470 : : /* skip leading spaces */
471 [ + + ]: 194 : while (isspace((unsigned char) *ptr))
472 : 22 : ptr++;
473 : :
474 : : /* handle sign */
475 [ + + ]: 172 : if (*ptr == '-')
476 : : {
477 : 10 : ptr++;
478 : 10 : neg = true;
479 : 10 : }
480 [ + + ]: 162 : else if (*ptr == '+')
481 : 1 : ptr++;
482 : :
483 : : /* process digits */
484 [ + + + + : 172 : if (ptr[0] == '0' && (ptr[1] == 'x' || ptr[1] == 'X'))
- + ]
485 : : {
486 : 28 : firstdigit = ptr += 2;
487 : :
488 : 208 : for (;;)
489 : : {
490 [ + + ]: 208 : if (isxdigit((unsigned char) *ptr))
491 : : {
492 [ + + ]: 184 : if (unlikely(tmp > -(PG_INT32_MIN / 16)))
493 : 6 : goto out_of_range;
494 : :
495 : 178 : tmp = tmp * 16 + hexlookup[(unsigned char) *ptr++];
496 : 178 : }
497 [ + + ]: 24 : else if (*ptr == '_')
498 : : {
499 : : /* underscore must be followed by more digits */
500 : 2 : ptr++;
501 [ + - + - ]: 2 : if (*ptr == '\0' || !isxdigit((unsigned char) *ptr))
502 : 0 : goto invalid_syntax;
503 : 2 : }
504 : : else
505 : 22 : break;
506 : : }
507 : 22 : }
508 [ + + + + : 144 : else if (ptr[0] == '0' && (ptr[1] == 'o' || ptr[1] == 'O'))
- + ]
509 : : {
510 : 17 : firstdigit = ptr += 2;
511 : :
512 : 162 : for (;;)
513 : : {
514 [ + + + + ]: 162 : if (*ptr >= '0' && *ptr <= '7')
515 : : {
516 [ + + ]: 147 : if (unlikely(tmp > -(PG_INT32_MIN / 8)))
517 : 4 : goto out_of_range;
518 : :
519 : 143 : tmp = tmp * 8 + (*ptr++ - '0');
520 : 143 : }
521 [ + + ]: 15 : else if (*ptr == '_')
522 : : {
523 : : /* underscore must be followed by more digits */
524 : 2 : ptr++;
525 [ + - + - : 2 : if (*ptr == '\0' || *ptr < '0' || *ptr > '7')
+ - ]
526 : 0 : goto invalid_syntax;
527 : 2 : }
528 : : else
529 : 13 : break;
530 : : }
531 : 13 : }
532 [ + + + + : 127 : else if (ptr[0] == '0' && (ptr[1] == 'b' || ptr[1] == 'B'))
- + ]
533 : : {
534 : 17 : firstdigit = ptr += 2;
535 : :
536 : 426 : for (;;)
537 : : {
538 [ + + + + ]: 426 : if (*ptr >= '0' && *ptr <= '1')
539 : : {
540 [ + + ]: 409 : if (unlikely(tmp > -(PG_INT32_MIN / 2)))
541 : 4 : goto out_of_range;
542 : :
543 : 405 : tmp = tmp * 2 + (*ptr++ - '0');
544 : 405 : }
545 [ + + ]: 17 : else if (*ptr == '_')
546 : : {
547 : : /* underscore must be followed by more digits */
548 : 4 : ptr++;
549 [ + - + - : 4 : if (*ptr == '\0' || *ptr < '0' || *ptr > '1')
+ - ]
550 : 0 : goto invalid_syntax;
551 : 4 : }
552 : : else
553 : 13 : break;
554 : : }
555 : 13 : }
556 : : else
557 : : {
558 : 110 : firstdigit = ptr;
559 : :
560 : 303 : for (;;)
561 : : {
562 [ + + + + ]: 303 : if (*ptr >= '0' && *ptr <= '9')
563 : : {
564 [ + + ]: 166 : if (unlikely(tmp > -(PG_INT32_MIN / 10)))
565 : 3 : goto out_of_range;
566 : :
567 : 163 : tmp = tmp * 10 + (*ptr++ - '0');
568 : 163 : }
569 [ + + ]: 137 : else if (*ptr == '_')
570 : : {
571 : : /* underscore may not be first */
572 [ + + ]: 33 : if (unlikely(ptr == firstdigit))
573 : 1 : goto invalid_syntax;
574 : : /* and it must be followed by more digits */
575 : 32 : ptr++;
576 [ + + + + ]: 32 : if (*ptr == '\0' || !isdigit((unsigned char) *ptr))
577 : 2 : goto invalid_syntax;
578 : 30 : }
579 : : else
580 : 104 : break;
581 : : }
582 : : }
583 : :
584 : : /* require at least one digit */
585 [ + + ]: 152 : if (unlikely(ptr == firstdigit))
586 : 72 : goto invalid_syntax;
587 : :
588 : : /* allow trailing whitespace, but not other trailing chars */
589 [ + + ]: 94 : while (isspace((unsigned char) *ptr))
590 : 14 : ptr++;
591 : :
592 [ + + ]: 80 : if (unlikely(*ptr != '\0'))
593 : 13 : goto invalid_syntax;
594 : :
595 [ + + ]: 67 : if (neg)
596 : : {
597 [ + + ]: 7 : if (unlikely(pg_neg_u32_overflow(tmp, &result)))
598 : 3 : goto out_of_range;
599 : 4 : return result;
600 : : }
601 : :
602 [ + + ]: 60 : if (tmp > PG_INT32_MAX)
603 : 12 : goto out_of_range;
604 : :
605 : 48 : return (int32) tmp;
606 : :
607 : : out_of_range:
608 [ + + ]: 231 : ereturn(escontext, 0,
609 : : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
610 : : errmsg("value \"%s\" is out of range for type %s",
611 : : s, "integer")));
612 : :
613 : : invalid_syntax:
614 [ + + ]: 88 : ereturn(escontext, 0,
615 : : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
616 : : errmsg("invalid input syntax for type %s: \"%s\"",
617 : : "integer", s)));
618 [ - + ]: 386865 : }
619 : :
620 : : /*
621 : : * Convert input string to a signed 64 bit integer. Input strings may be
622 : : * expressed in base-10, hexadecimal, octal, or binary format, all of which
623 : : * can be prefixed by an optional sign character, either '+' (the default) or
624 : : * '-' for negative numbers. Hex strings are recognized by the digits being
625 : : * prefixed by 0x or 0X while octal strings are recognized by the 0o or 0O
626 : : * prefix. The binary representation is recognized by the 0b or 0B prefix.
627 : : *
628 : : * Allows any number of leading or trailing whitespace characters. Digits may
629 : : * optionally be separated by a single underscore character. These can only
630 : : * come between digits and not before or after the digits. Underscores have
631 : : * no effect on the return value and are supported only to assist in improving
632 : : * the human readability of the input strings.
633 : : *
634 : : * pg_strtoint64() will throw ereport() upon bad input format or overflow;
635 : : * while pg_strtoint64_safe() instead returns such complaints in *escontext,
636 : : * if it's an ErrorSaveContext.
637 : : *
638 : : * NB: Accumulate input as an unsigned number, to deal with two's complement
639 : : * representation of the most negative number, which can't be represented as a
640 : : * signed positive number.
641 : : */
642 : : int64
643 : 0 : pg_strtoint64(const char *s)
644 : : {
645 : 0 : return pg_strtoint64_safe(s, NULL);
646 : : }
647 : :
648 : : int64
649 : 7195 : pg_strtoint64_safe(const char *s, Node *escontext)
650 : : {
651 : 7195 : const char *ptr = s;
652 : 7195 : const char *firstdigit;
653 : 7195 : uint64 tmp = 0;
654 : 7195 : bool neg = false;
655 : 7195 : unsigned char digit;
656 : 7195 : int64 result;
657 : :
658 : : /*
659 : : * The majority of cases are likely to be base-10 digits without any
660 : : * underscore separator characters. We'll first try to parse the string
661 : : * with the assumption that's the case and only fallback on a slower
662 : : * implementation which handles hex, octal and binary strings and
663 : : * underscores if the fastpath version cannot parse the string.
664 : : */
665 : :
666 : : /* leave it up to the slow path to look for leading spaces */
667 : :
668 [ + + ]: 7195 : if (*ptr == '-')
669 : : {
670 : 178 : ptr++;
671 : 178 : neg = true;
672 : 178 : }
673 : :
674 : : /* a leading '+' is uncommon so leave that for the slow path */
675 : :
676 : : /* process the first digit */
677 : 7195 : digit = (*ptr - '0');
678 : :
679 : : /*
680 : : * Exploit unsigned arithmetic to save having to check both the upper and
681 : : * lower bounds of the digit.
682 : : */
683 [ + + ]: 7195 : if (likely(digit < 10))
684 : : {
685 : 7163 : ptr++;
686 : 7163 : tmp = digit;
687 : 7163 : }
688 : : else
689 : : {
690 : : /* we need at least one digit */
691 : 32 : goto slow;
692 : : }
693 : :
694 : : /* process remaining digits */
695 : 11880 : for (;;)
696 : : {
697 : 11880 : digit = (*ptr - '0');
698 : :
699 [ + + ]: 11880 : if (digit >= 10)
700 : 7123 : break;
701 : :
702 : 4757 : ptr++;
703 : :
704 [ + + ]: 4757 : if (unlikely(tmp > -(PG_INT64_MIN / 10)))
705 : 40 : goto out_of_range;
706 : :
707 : 4717 : tmp = tmp * 10 + digit;
708 : : }
709 : :
710 : : /* when the string does not end in a digit, let the slow path handle it */
711 [ + + ]: 7123 : if (unlikely(*ptr != '\0'))
712 : 1426 : goto slow;
713 : :
714 [ + + ]: 5697 : if (neg)
715 : : {
716 [ + + ]: 77 : if (unlikely(pg_neg_u64_overflow(tmp, &result)))
717 : 3 : goto out_of_range;
718 : 74 : return result;
719 : : }
720 : :
721 [ + + ]: 5620 : if (unlikely(tmp > PG_INT64_MAX))
722 : 3 : goto out_of_range;
723 : :
724 : 5617 : return (int64) tmp;
725 : :
726 : : slow:
727 : 1458 : tmp = 0;
728 : 1458 : ptr = s;
729 : : /* no need to reset neg */
730 : :
731 : : /* skip leading spaces */
732 [ + + ]: 1470 : while (isspace((unsigned char) *ptr))
733 : 12 : ptr++;
734 : :
735 : : /* handle sign */
736 [ + + ]: 1458 : if (*ptr == '-')
737 : : {
738 : 100 : ptr++;
739 : 100 : neg = true;
740 : 100 : }
741 [ + + ]: 1358 : else if (*ptr == '+')
742 : 8 : ptr++;
743 : :
744 : : /* process digits */
745 [ + + + + : 1458 : if (ptr[0] == '0' && (ptr[1] == 'x' || ptr[1] == 'X'))
- + ]
746 : : {
747 : 16 : firstdigit = ptr += 2;
748 : :
749 : 212 : for (;;)
750 : : {
751 [ + + ]: 212 : if (isxdigit((unsigned char) *ptr))
752 : : {
753 [ - + ]: 195 : if (unlikely(tmp > -(PG_INT64_MIN / 16)))
754 : 0 : goto out_of_range;
755 : :
756 : 195 : tmp = tmp * 16 + hexlookup[(unsigned char) *ptr++];
757 : 195 : }
758 [ + + ]: 17 : else if (*ptr == '_')
759 : : {
760 : : /* underscore must be followed by more digits */
761 : 1 : ptr++;
762 [ + - + - ]: 1 : if (*ptr == '\0' || !isxdigit((unsigned char) *ptr))
763 : 0 : goto invalid_syntax;
764 : 1 : }
765 : : else
766 : 16 : break;
767 : : }
768 : 16 : }
769 [ + + + + : 1442 : else if (ptr[0] == '0' && (ptr[1] == 'o' || ptr[1] == 'O'))
- + ]
770 : : {
771 : 14 : firstdigit = ptr += 2;
772 : :
773 : 228 : for (;;)
774 : : {
775 [ + + + + ]: 228 : if (*ptr >= '0' && *ptr <= '7')
776 : : {
777 [ + - ]: 213 : if (unlikely(tmp > -(PG_INT64_MIN / 8)))
778 : 0 : goto out_of_range;
779 : :
780 : 213 : tmp = tmp * 8 + (*ptr++ - '0');
781 : 213 : }
782 [ + + ]: 15 : else if (*ptr == '_')
783 : : {
784 : : /* underscore must be followed by more digits */
785 : 1 : ptr++;
786 [ + - + - : 1 : if (*ptr == '\0' || *ptr < '0' || *ptr > '7')
+ - ]
787 : 0 : goto invalid_syntax;
788 : 1 : }
789 : : else
790 : 14 : break;
791 : : }
792 : 14 : }
793 [ + + + + : 1428 : else if (ptr[0] == '0' && (ptr[1] == 'b' || ptr[1] == 'B'))
- + ]
794 : : {
795 : 14 : firstdigit = ptr += 2;
796 : :
797 : 634 : for (;;)
798 : : {
799 [ + + + + ]: 634 : if (*ptr >= '0' && *ptr <= '1')
800 : : {
801 [ + - ]: 618 : if (unlikely(tmp > -(PG_INT64_MIN / 2)))
802 : 0 : goto out_of_range;
803 : :
804 : 618 : tmp = tmp * 2 + (*ptr++ - '0');
805 : 618 : }
806 [ + + ]: 16 : else if (*ptr == '_')
807 : : {
808 : : /* underscore must be followed by more digits */
809 : 2 : ptr++;
810 [ + - + - : 2 : if (*ptr == '\0' || *ptr < '0' || *ptr > '1')
+ - ]
811 : 0 : goto invalid_syntax;
812 : 2 : }
813 : : else
814 : 14 : break;
815 : : }
816 : 14 : }
817 : : else
818 : : {
819 : 1414 : firstdigit = ptr;
820 : :
821 : 3631 : for (;;)
822 : : {
823 [ + + + + ]: 3631 : if (*ptr >= '0' && *ptr <= '9')
824 : : {
825 [ + - ]: 2198 : if (unlikely(tmp > -(PG_INT64_MIN / 10)))
826 : 0 : goto out_of_range;
827 : :
828 : 2198 : tmp = tmp * 10 + (*ptr++ - '0');
829 : 2198 : }
830 [ + + ]: 1433 : else if (*ptr == '_')
831 : : {
832 : : /* underscore may not be first */
833 [ + + ]: 22 : if (unlikely(ptr == firstdigit))
834 : 1 : goto invalid_syntax;
835 : : /* and it must be followed by more digits */
836 : 21 : ptr++;
837 [ + + + + ]: 21 : if (*ptr == '\0' || !isdigit((unsigned char) *ptr))
838 : 2 : goto invalid_syntax;
839 : 19 : }
840 : : else
841 : 1411 : break;
842 : : }
843 : : }
844 : :
845 : : /* require at least one digit */
846 [ + + ]: 1455 : if (unlikely(ptr == firstdigit))
847 : 23 : goto invalid_syntax;
848 : :
849 : : /* allow trailing whitespace, but not other trailing chars */
850 [ + + ]: 1443 : while (isspace((unsigned char) *ptr))
851 : 11 : ptr++;
852 : :
853 [ + + ]: 1432 : if (unlikely(*ptr != '\0'))
854 : 1375 : goto invalid_syntax;
855 : :
856 [ + + ]: 57 : if (neg)
857 : : {
858 [ + + ]: 19 : if (unlikely(pg_neg_u64_overflow(tmp, &result)))
859 : 6 : goto out_of_range;
860 : 13 : return result;
861 : : }
862 : :
863 [ + + ]: 38 : if (tmp > PG_INT64_MAX)
864 : 6 : goto out_of_range;
865 : :
866 : 32 : return (int64) tmp;
867 : :
868 : : out_of_range:
869 [ + + ]: 58 : ereturn(escontext, 0,
870 : : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
871 : : errmsg("value \"%s\" is out of range for type %s",
872 : : s, "bigint")));
873 : :
874 : : invalid_syntax:
875 [ + + ]: 1401 : ereturn(escontext, 0,
876 : : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
877 : : errmsg("invalid input syntax for type %s: \"%s\"",
878 : : "bigint", s)));
879 [ - + ]: 7195 : }
880 : :
881 : : /*
882 : : * Convert input string to an unsigned 32 bit integer.
883 : : *
884 : : * Allows any number of leading or trailing whitespace characters.
885 : : *
886 : : * If endloc isn't NULL, store a pointer to the rest of the string there,
887 : : * so that caller can parse the rest. Otherwise, it's an error if anything
888 : : * but whitespace follows.
889 : : *
890 : : * typname is what is reported in error messages.
891 : : *
892 : : * If escontext points to an ErrorSaveContext node, that is filled instead
893 : : * of throwing an error; the caller must check SOFT_ERROR_OCCURRED()
894 : : * to detect errors.
895 : : */
896 : : uint32
897 : 77611 : uint32in_subr(const char *s, char **endloc,
898 : : const char *typname, Node *escontext)
899 : : {
900 : 77611 : uint32 result;
901 : 77611 : unsigned long cvt;
902 : 77611 : char *endptr;
903 : :
904 : 77611 : errno = 0;
905 : 77611 : cvt = strtoul(s, &endptr, 0);
906 : :
907 : : /*
908 : : * strtoul() normally only sets ERANGE. On some systems it may also set
909 : : * EINVAL, which simply means it couldn't parse the input string. Be sure
910 : : * to report that the same way as the standard error indication (that
911 : : * endptr == s).
912 : : */
913 [ + + + + ]: 77611 : if ((errno && errno != ERANGE) || endptr == s)
914 [ + + ]: 13 : ereturn(escontext, 0,
915 : : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
916 : : errmsg("invalid input syntax for type %s: \"%s\"",
917 : : typname, s)));
918 : :
919 [ + + ]: 77600 : if (errno == ERANGE)
920 [ + + ]: 4 : ereturn(escontext, 0,
921 : : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
922 : : errmsg("value \"%s\" is out of range for type %s",
923 : : s, typname)));
924 : :
925 [ + + ]: 77596 : if (endloc)
926 : : {
927 : : /* caller wants to deal with rest of string */
928 : 6328 : *endloc = endptr;
929 : 6328 : }
930 : : else
931 : : {
932 : : /* allow only whitespace after number */
933 [ + + + + ]: 71287 : while (*endptr && isspace((unsigned char) *endptr))
934 : 19 : endptr++;
935 [ + + ]: 71268 : if (*endptr)
936 [ + + ]: 6 : ereturn(escontext, 0,
937 : : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
938 : : errmsg("invalid input syntax for type %s: \"%s\"",
939 : : typname, s)));
940 : : }
941 : :
942 : 77590 : result = (uint32) cvt;
943 : :
944 : : /*
945 : : * Cope with possibility that unsigned long is wider than uint32, in which
946 : : * case strtoul will not raise an error for some values that are out of
947 : : * the range of uint32.
948 : : *
949 : : * For backwards compatibility, we want to accept inputs that are given
950 : : * with a minus sign, so allow the input value if it matches after either
951 : : * signed or unsigned extension to long.
952 : : *
953 : : * To ensure consistent results on 32-bit and 64-bit platforms, make sure
954 : : * the error message is the same as if strtoul() had returned ERANGE.
955 : : */
956 : : #if PG_UINT32_MAX != ULONG_MAX
957 [ + + + + ]: 77590 : if (cvt != (unsigned long) result &&
958 : 7 : cvt != (unsigned long) ((int) result))
959 [ + + ]: 5 : ereturn(escontext, 0,
960 : : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
961 : : errmsg("value \"%s\" is out of range for type %s",
962 : : s, typname)));
963 : : #endif
964 : :
965 : 77585 : return result;
966 : 77599 : }
967 : :
968 : : /*
969 : : * Convert input string to an unsigned 64 bit integer.
970 : : *
971 : : * Allows any number of leading or trailing whitespace characters.
972 : : *
973 : : * If endloc isn't NULL, store a pointer to the rest of the string there,
974 : : * so that caller can parse the rest. Otherwise, it's an error if anything
975 : : * but whitespace follows.
976 : : *
977 : : * typname is what is reported in error messages.
978 : : *
979 : : * If escontext points to an ErrorSaveContext node, that is filled instead
980 : : * of throwing an error; the caller must check SOFT_ERROR_OCCURRED()
981 : : * to detect errors.
982 : : */
983 : : uint64
984 : 680 : uint64in_subr(const char *s, char **endloc,
985 : : const char *typname, Node *escontext)
986 : : {
987 : 680 : uint64 result;
988 : 680 : char *endptr;
989 : :
990 : 680 : errno = 0;
991 : 680 : result = strtou64(s, &endptr, 0);
992 : :
993 : : /*
994 : : * strtoul[l] normally only sets ERANGE. On some systems it may also set
995 : : * EINVAL, which simply means it couldn't parse the input string. Be sure
996 : : * to report that the same way as the standard error indication (that
997 : : * endptr == s).
998 : : */
999 [ + + + + ]: 680 : if ((errno && errno != ERANGE) || endptr == s)
1000 [ + + ]: 11 : ereturn(escontext, 0,
1001 : : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1002 : : errmsg("invalid input syntax for type %s: \"%s\"",
1003 : : typname, s)));
1004 : :
1005 [ + + ]: 669 : if (errno == ERANGE)
1006 [ + + ]: 7 : ereturn(escontext, 0,
1007 : : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1008 : : errmsg("value \"%s\" is out of range for type %s",
1009 : : s, typname)));
1010 : :
1011 [ - + ]: 662 : if (endloc)
1012 : : {
1013 : : /* caller wants to deal with rest of string */
1014 : 0 : *endloc = endptr;
1015 : 0 : }
1016 : : else
1017 : : {
1018 : : /* allow only whitespace after number */
1019 [ + + + + ]: 681 : while (*endptr && isspace((unsigned char) *endptr))
1020 : 19 : endptr++;
1021 [ + + ]: 662 : if (*endptr)
1022 [ + + ]: 6 : ereturn(escontext, 0,
1023 : : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1024 : : errmsg("invalid input syntax for type %s: \"%s\"",
1025 : : typname, s)));
1026 : : }
1027 : :
1028 : 656 : return result;
1029 : 666 : }
1030 : :
1031 : : /*
1032 : : * pg_itoa: converts a signed 16-bit integer to its string representation
1033 : : * and returns strlen(a).
1034 : : *
1035 : : * Caller must ensure that 'a' points to enough memory to hold the result
1036 : : * (at least 7 bytes, counting a leading sign and trailing NUL).
1037 : : *
1038 : : * It doesn't seem worth implementing this separately.
1039 : : */
1040 : : int
1041 : 5896 : pg_itoa(int16 i, char *a)
1042 : : {
1043 : 5896 : return pg_ltoa((int32) i, a);
1044 : : }
1045 : :
1046 : : /*
1047 : : * pg_ultoa_n: converts an unsigned 32-bit integer to its string representation,
1048 : : * not NUL-terminated, and returns the length of that string representation
1049 : : *
1050 : : * Caller must ensure that 'a' points to enough memory to hold the result (at
1051 : : * least 10 bytes)
1052 : : */
1053 : : int
1054 : 722654 : pg_ultoa_n(uint32 value, char *a)
1055 : : {
1056 : 722654 : int olength,
1057 : 722654 : i = 0;
1058 : :
1059 : : /* Degenerate case */
1060 [ + + ]: 722654 : if (value == 0)
1061 : : {
1062 : 17999 : *a = '0';
1063 : 17999 : return 1;
1064 : : }
1065 : :
1066 : 704655 : olength = decimalLength32(value);
1067 : :
1068 : : /* Compute the result string. */
1069 [ + + ]: 898011 : while (value >= 10000)
1070 : : {
1071 : 193356 : const uint32 c = value - 10000 * (value / 10000);
1072 : 193356 : const uint32 c0 = (c % 100) << 1;
1073 : 193356 : const uint32 c1 = (c / 100) << 1;
1074 : :
1075 : 193356 : char *pos = a + olength - i;
1076 : :
1077 : 193356 : value /= 10000;
1078 : :
1079 : 193356 : memcpy(pos - 2, DIGIT_TABLE + c0, 2);
1080 : 193356 : memcpy(pos - 4, DIGIT_TABLE + c1, 2);
1081 : 193356 : i += 4;
1082 : 193356 : }
1083 [ + + ]: 704655 : if (value >= 100)
1084 : : {
1085 : 343230 : const uint32 c = (value % 100) << 1;
1086 : :
1087 : 343230 : char *pos = a + olength - i;
1088 : :
1089 : 343230 : value /= 100;
1090 : :
1091 : 343230 : memcpy(pos - 2, DIGIT_TABLE + c, 2);
1092 : 343230 : i += 2;
1093 : 343230 : }
1094 [ + + ]: 704655 : if (value >= 10)
1095 : : {
1096 : 337179 : const uint32 c = value << 1;
1097 : :
1098 : 337179 : char *pos = a + olength - i;
1099 : :
1100 : 337179 : memcpy(pos - 2, DIGIT_TABLE + c, 2);
1101 : 337179 : }
1102 : : else
1103 : : {
1104 : 367476 : *a = (char) ('0' + value);
1105 : : }
1106 : :
1107 : 704655 : return olength;
1108 : 722654 : }
1109 : :
1110 : : /*
1111 : : * pg_ltoa: converts a signed 32-bit integer to its string representation and
1112 : : * returns strlen(a).
1113 : : *
1114 : : * It is the caller's responsibility to ensure that a is at least 12 bytes long,
1115 : : * which is enough room to hold a minus sign, a maximally long int32, and the
1116 : : * above terminating NUL.
1117 : : */
1118 : : int
1119 : 716134 : pg_ltoa(int32 value, char *a)
1120 : : {
1121 : 716134 : uint32 uvalue = (uint32) value;
1122 : 716134 : int len = 0;
1123 : :
1124 [ + + ]: 716134 : if (value < 0)
1125 : : {
1126 : 2267 : uvalue = (uint32) 0 - uvalue;
1127 : 2267 : a[len++] = '-';
1128 : 2267 : }
1129 : 716134 : len += pg_ultoa_n(uvalue, a + len);
1130 : 716134 : a[len] = '\0';
1131 : 1432268 : return len;
1132 : 716134 : }
1133 : :
1134 : : /*
1135 : : * Get the decimal representation, not NUL-terminated, and return the length of
1136 : : * same. Caller must ensure that a points to at least MAXINT8LEN bytes.
1137 : : */
1138 : : int
1139 : 39080 : pg_ulltoa_n(uint64 value, char *a)
1140 : : {
1141 : 39080 : int olength,
1142 : 39080 : i = 0;
1143 : 39080 : uint32 value2;
1144 : :
1145 : : /* Degenerate case */
1146 [ + + ]: 39080 : if (value == 0)
1147 : : {
1148 : 5092 : *a = '0';
1149 : 5092 : return 1;
1150 : : }
1151 : :
1152 : 33988 : olength = decimalLength64(value);
1153 : :
1154 : : /* Compute the result string. */
1155 [ + + ]: 36025 : while (value >= 100000000)
1156 : : {
1157 : 2037 : const uint64 q = value / 100000000;
1158 : 2037 : uint32 value3 = (uint32) (value - 100000000 * q);
1159 : :
1160 : 2037 : const uint32 c = value3 % 10000;
1161 : 2037 : const uint32 d = value3 / 10000;
1162 : 2037 : const uint32 c0 = (c % 100) << 1;
1163 : 2037 : const uint32 c1 = (c / 100) << 1;
1164 : 2037 : const uint32 d0 = (d % 100) << 1;
1165 : 2037 : const uint32 d1 = (d / 100) << 1;
1166 : :
1167 : 2037 : char *pos = a + olength - i;
1168 : :
1169 : 2037 : value = q;
1170 : :
1171 : 2037 : memcpy(pos - 2, DIGIT_TABLE + c0, 2);
1172 : 2037 : memcpy(pos - 4, DIGIT_TABLE + c1, 2);
1173 : 2037 : memcpy(pos - 6, DIGIT_TABLE + d0, 2);
1174 : 2037 : memcpy(pos - 8, DIGIT_TABLE + d1, 2);
1175 : 2037 : i += 8;
1176 : 2037 : }
1177 : :
1178 : : /* Switch to 32-bit for speed */
1179 : 33988 : value2 = (uint32) value;
1180 : :
1181 [ + + ]: 33988 : if (value2 >= 10000)
1182 : : {
1183 : 2302 : const uint32 c = value2 - 10000 * (value2 / 10000);
1184 : 2302 : const uint32 c0 = (c % 100) << 1;
1185 : 2302 : const uint32 c1 = (c / 100) << 1;
1186 : :
1187 : 2302 : char *pos = a + olength - i;
1188 : :
1189 : 2302 : value2 /= 10000;
1190 : :
1191 : 2302 : memcpy(pos - 2, DIGIT_TABLE + c0, 2);
1192 : 2302 : memcpy(pos - 4, DIGIT_TABLE + c1, 2);
1193 : 2302 : i += 4;
1194 : 2302 : }
1195 [ + + ]: 33988 : if (value2 >= 100)
1196 : : {
1197 : 4630 : const uint32 c = (value2 % 100) << 1;
1198 : 4630 : char *pos = a + olength - i;
1199 : :
1200 : 4630 : value2 /= 100;
1201 : :
1202 : 4630 : memcpy(pos - 2, DIGIT_TABLE + c, 2);
1203 : 4630 : i += 2;
1204 : 4630 : }
1205 [ + + ]: 33988 : if (value2 >= 10)
1206 : : {
1207 : 5335 : const uint32 c = value2 << 1;
1208 : 5335 : char *pos = a + olength - i;
1209 : :
1210 : 5335 : memcpy(pos - 2, DIGIT_TABLE + c, 2);
1211 : 5335 : }
1212 : : else
1213 : 28653 : *a = (char) ('0' + value2);
1214 : :
1215 : 33988 : return olength;
1216 : 39080 : }
1217 : :
1218 : : /*
1219 : : * pg_lltoa: converts a signed 64-bit integer to its string representation and
1220 : : * returns strlen(a).
1221 : : *
1222 : : * Caller must ensure that 'a' points to enough memory to hold the result
1223 : : * (at least MAXINT8LEN + 1 bytes, counting a leading sign and trailing NUL).
1224 : : */
1225 : : int
1226 : 9608 : pg_lltoa(int64 value, char *a)
1227 : : {
1228 : 9608 : uint64 uvalue = value;
1229 : 9608 : int len = 0;
1230 : :
1231 [ + + ]: 9608 : if (value < 0)
1232 : : {
1233 : 382 : uvalue = (uint64) 0 - uvalue;
1234 : 382 : a[len++] = '-';
1235 : 382 : }
1236 : :
1237 : 9608 : len += pg_ulltoa_n(uvalue, a + len);
1238 : 9608 : a[len] = '\0';
1239 : 19216 : return len;
1240 : 9608 : }
1241 : :
1242 : :
1243 : : /*
1244 : : * pg_ultostr_zeropad
1245 : : * Converts 'value' into a decimal string representation stored at 'str'.
1246 : : * 'minwidth' specifies the minimum width of the result; any extra space
1247 : : * is filled up by prefixing the number with zeros.
1248 : : *
1249 : : * Returns the ending address of the string result (the last character written
1250 : : * plus 1). Note that no NUL terminator is written.
1251 : : *
1252 : : * The intended use-case for this function is to build strings that contain
1253 : : * multiple individual numbers, for example:
1254 : : *
1255 : : * str = pg_ultostr_zeropad(str, hours, 2);
1256 : : * *str++ = ':';
1257 : : * str = pg_ultostr_zeropad(str, mins, 2);
1258 : : * *str++ = ':';
1259 : : * str = pg_ultostr_zeropad(str, secs, 2);
1260 : : * *str = '\0';
1261 : : *
1262 : : * Note: Caller must ensure that 'str' points to enough memory to hold the
1263 : : * result.
1264 : : */
1265 : : char *
1266 : 32306 : pg_ultostr_zeropad(char *str, uint32 value, int32 minwidth)
1267 : : {
1268 : 32306 : int len;
1269 : :
1270 [ + - ]: 32306 : Assert(minwidth > 0);
1271 : :
1272 [ + + + + ]: 32306 : if (value < 100 && minwidth == 2) /* Short cut for common case */
1273 : : {
1274 : 26325 : memcpy(str, DIGIT_TABLE + value * 2, 2);
1275 : 26325 : return str + 2;
1276 : : }
1277 : :
1278 : 5981 : len = pg_ultoa_n(value, str);
1279 [ + + ]: 5981 : if (len >= minwidth)
1280 : 5876 : return str + len;
1281 : :
1282 : 105 : memmove(str + minwidth - len, str, len);
1283 : 105 : memset(str, '0', minwidth - len);
1284 : 105 : return str + minwidth;
1285 : 32306 : }
1286 : :
1287 : : /*
1288 : : * pg_ultostr
1289 : : * Converts 'value' into a decimal string representation stored at 'str'.
1290 : : *
1291 : : * Returns the ending address of the string result (the last character written
1292 : : * plus 1). Note that no NUL terminator is written.
1293 : : *
1294 : : * The intended use-case for this function is to build strings that contain
1295 : : * multiple individual numbers, for example:
1296 : : *
1297 : : * str = pg_ultostr(str, a);
1298 : : * *str++ = ' ';
1299 : : * str = pg_ultostr(str, b);
1300 : : * *str = '\0';
1301 : : *
1302 : : * Note: Caller must ensure that 'str' points to enough memory to hold the
1303 : : * result.
1304 : : */
1305 : : char *
1306 : 539 : pg_ultostr(char *str, uint32 value)
1307 : : {
1308 : 539 : int len = pg_ultoa_n(value, str);
1309 : :
1310 : 1078 : return str + len;
1311 : 539 : }
|