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