~ubuntu-branches/ubuntu/oneiric/postgresql-9.1/oneiric-security

« back to all changes in this revision

Viewing changes to src/backend/utils/adt/numutils.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2011-05-11 10:41:53 UTC
  • Revision ID: james.westby@ubuntu.com-20110511104153-psbh2o58553fv1m0
Tags: upstream-9.1~beta1
ImportĀ upstreamĀ versionĀ 9.1~beta1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*-------------------------------------------------------------------------
 
2
 *
 
3
 * numutils.c
 
4
 *        utility functions for I/O of built-in numeric types.
 
5
 *
 
6
 * Portions Copyright (c) 1996-2011, 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 "utils/builtins.h"
 
22
 
 
23
/*
 
24
 * pg_atoi: convert string to integer
 
25
 *
 
26
 * allows any number of leading or trailing whitespace characters.
 
27
 *
 
28
 * 'size' is the sizeof() the desired integral result (1, 2, or 4 bytes).
 
29
 *
 
30
 * c, if not 0, is a terminator character that may appear after the
 
31
 * integer (plus whitespace).  If 0, the string must end after the integer.
 
32
 *
 
33
 * Unlike plain atoi(), this will throw ereport() upon bad input format or
 
34
 * overflow.
 
35
 */
 
36
int32
 
37
pg_atoi(char *s, int size, int c)
 
38
{
 
39
        long            l;
 
40
        char       *badp;
 
41
 
 
42
        /*
 
43
         * Some versions of strtol treat the empty string as an error, but some
 
44
         * seem not to.  Make an explicit test to be sure we catch it.
 
45
         */
 
46
        if (s == NULL)
 
47
                elog(ERROR, "NULL pointer");
 
48
        if (*s == 0)
 
49
                ereport(ERROR,
 
50
                                (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 
51
                                 errmsg("invalid input syntax for integer: \"%s\"",
 
52
                                                s)));
 
53
 
 
54
        errno = 0;
 
55
        l = strtol(s, &badp, 10);
 
56
 
 
57
        /* We made no progress parsing the string, so bail out */
 
58
        if (s == badp)
 
59
                ereport(ERROR,
 
60
                                (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 
61
                                 errmsg("invalid input syntax for integer: \"%s\"",
 
62
                                                s)));
 
63
 
 
64
        switch (size)
 
65
        {
 
66
                case sizeof(int32):
 
67
                        if (errno == ERANGE
 
68
#if defined(HAVE_LONG_INT_64)
 
69
                        /* won't get ERANGE on these with 64-bit longs... */
 
70
                                || l < INT_MIN || l > INT_MAX
 
71
#endif
 
72
                                )
 
73
                                ereport(ERROR,
 
74
                                                (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 
75
                                errmsg("value \"%s\" is out of range for type integer", s)));
 
76
                        break;
 
77
                case sizeof(int16):
 
78
                        if (errno == ERANGE || l < SHRT_MIN || l > SHRT_MAX)
 
79
                                ereport(ERROR,
 
80
                                                (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 
81
                                errmsg("value \"%s\" is out of range for type smallint", s)));
 
82
                        break;
 
83
                case sizeof(int8):
 
84
                        if (errno == ERANGE || l < SCHAR_MIN || l > SCHAR_MAX)
 
85
                                ereport(ERROR,
 
86
                                                (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
 
87
                                errmsg("value \"%s\" is out of range for 8-bit integer", s)));
 
88
                        break;
 
89
                default:
 
90
                        elog(ERROR, "unsupported result size: %d", size);
 
91
        }
 
92
 
 
93
        /*
 
94
         * Skip any trailing whitespace; if anything but whitespace remains before
 
95
         * the terminating character, bail out
 
96
         */
 
97
        while (*badp && *badp != c && isspace((unsigned char) *badp))
 
98
                badp++;
 
99
 
 
100
        if (*badp && *badp != c)
 
101
                ereport(ERROR,
 
102
                                (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
 
103
                                 errmsg("invalid input syntax for integer: \"%s\"",
 
104
                                                s)));
 
105
 
 
106
        return (int32) l;
 
107
}
 
108
 
 
109
/*
 
110
 * pg_itoa: converts a signed 16-bit integer to its string representation
 
111
 *
 
112
 * Caller must ensure that 'a' points to enough memory to hold the result
 
113
 * (at least 7 bytes, counting a leading sign and trailing NUL).
 
114
 *
 
115
 * It doesn't seem worth implementing this separately.
 
116
 */
 
117
void
 
118
pg_itoa(int16 i, char *a)
 
119
{
 
120
        pg_ltoa((int32) i, a);
 
121
}
 
122
 
 
123
/*
 
124
 * pg_ltoa: converts a signed 32-bit integer to its string representation
 
125
 *
 
126
 * Caller must ensure that 'a' points to enough memory to hold the result
 
127
 * (at least 12 bytes, counting a leading sign and trailing NUL).
 
128
 */
 
129
void
 
130
pg_ltoa(int32 value, char *a)
 
131
{
 
132
        char       *start = a;
 
133
        bool            neg = false;
 
134
 
 
135
        /*
 
136
         * Avoid problems with the most negative integer not being representable
 
137
         * as a positive integer.
 
138
         */
 
139
        if (value == (-2147483647 - 1))
 
140
        {
 
141
                memcpy(a, "-2147483648", 12);
 
142
                return;
 
143
        }
 
144
        else if (value < 0)
 
145
        {
 
146
                value = -value;
 
147
                neg = true;
 
148
        }
 
149
 
 
150
        /* Compute the result string backwards. */
 
151
        do
 
152
        {
 
153
                int32           remainder;
 
154
                int32           oldval = value;
 
155
 
 
156
                value /= 10;
 
157
                remainder = oldval - value * 10;
 
158
                *a++ = '0' + remainder;
 
159
        } while (value != 0);
 
160
 
 
161
        if (neg)
 
162
                *a++ = '-';
 
163
 
 
164
        /* Add trailing NUL byte, and back up 'a' to the last character. */
 
165
        *a-- = '\0';
 
166
 
 
167
        /* Reverse string. */
 
168
        while (start < a)
 
169
        {
 
170
                char            swap = *start;
 
171
 
 
172
                *start++ = *a;
 
173
                *a-- = swap;
 
174
        }
 
175
}
 
176
 
 
177
/*
 
178
 * pg_lltoa: convert a signed 64-bit integer to its string representation
 
179
 *
 
180
 * Caller must ensure that 'a' points to enough memory to hold the result
 
181
 * (at least MAXINT8LEN+1 bytes, counting a leading sign and trailing NUL).
 
182
 */
 
183
void
 
184
pg_lltoa(int64 value, char *a)
 
185
{
 
186
        char       *start = a;
 
187
        bool            neg = false;
 
188
 
 
189
        /*
 
190
         * Avoid problems with the most negative integer not being representable
 
191
         * as a positive integer.
 
192
         */
 
193
        if (value == (-INT64CONST(0x7FFFFFFFFFFFFFFF) - 1))
 
194
        {
 
195
                memcpy(a, "-9223372036854775808", 21);
 
196
                return;
 
197
        }
 
198
        else if (value < 0)
 
199
        {
 
200
                value = -value;
 
201
                neg = true;
 
202
        }
 
203
 
 
204
        /* Compute the result string backwards. */
 
205
        do
 
206
        {
 
207
                int64           remainder;
 
208
                int64           oldval = value;
 
209
 
 
210
                value /= 10;
 
211
                remainder = oldval - value * 10;
 
212
                *a++ = '0' + remainder;
 
213
        } while (value != 0);
 
214
 
 
215
        if (neg)
 
216
                *a++ = '-';
 
217
 
 
218
        /* Add trailing NUL byte, and back up 'a' to the last character. */
 
219
        *a-- = '\0';
 
220
 
 
221
        /* Reverse string. */
 
222
        while (start < a)
 
223
        {
 
224
                char            swap = *start;
 
225
 
 
226
                *start++ = *a;
 
227
                *a-- = swap;
 
228
        }
 
229
}