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