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