Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit e2ded82

Browse files
author
Neil Conway
committed
Revise int2/int4/int8/float4/float8 input routines to allow for
any amount of leading or trailing whitespace (where "whitespace" is defined by isspace()). This is for SQL conformance, as well as consistency with other numeric types (e.g. oid, numeric). Also refactor pg_atoi() to avoid looking at errno where not necessary, and add a bunch of regression tests for the input to these types.
1 parent 0b86ade commit e2ded82

File tree

19 files changed

+457
-138
lines changed

19 files changed

+457
-138
lines changed

src/backend/utils/adt/float.c

+75-46
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/utils/adt/float.c,v 1.97 2004/03/04 21:47:18 neilc Exp $
11+
* $PostgreSQL: pgsql/src/backend/utils/adt/float.c,v 1.98 2004/03/11 02:11:13 neilc Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -185,41 +185,55 @@ float4in(PG_FUNCTION_ARGS)
185185

186186
errno = 0;
187187
val = strtod(num, &endptr);
188-
if (*endptr != '\0')
188+
189+
if (errno == ERANGE)
190+
ereport(ERROR,
191+
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
192+
errmsg("\"%s\" is out of range for type real", num)));
193+
194+
if (num == endptr)
189195
{
190196
/*
191-
* XXX we should accept "Infinity" and "-Infinity" too, but what
192-
* are the correct values to assign? HUGE_VAL will provoke an
193-
* error from CheckFloat4Val.
197+
* We didn't find anything that looks like a float in the input
198+
*
199+
* In releases prior to 7.5, we accepted an empty string as
200+
* valid input (yielding a float8 of 0). In 7.5, we accept
201+
* empty strings, but emit a warning noting that the feature
202+
* is deprecated. In 7.6+, the warning should be replaced by
203+
* an error.
204+
*
205+
* XXX we should accept "Infinity" and "-Infinity" too, but
206+
* what are the correct values to assign? HUGE_VAL will
207+
* provoke an error from CheckFloat4Val.
194208
*/
195-
if (strcasecmp(num, "NaN") == 0)
209+
if (*num == '\0')
210+
{
211+
ereport(WARNING,
212+
(errcode(ERRCODE_WARNING_DEPRECATED_FEATURE),
213+
errmsg("deprecated input syntax for type real: \"\""),
214+
errdetail("This input will be rejected in "
215+
"a future release of PostgreSQL.")));
216+
Assert(val == 0.0);
217+
}
218+
else if (strcasecmp(num, "NaN") == 0)
196219
val = NAN;
197220
else
198221
ereport(ERROR,
199222
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
200223
errmsg("invalid input syntax for type real: \"%s\"",
201224
num)));
202225
}
203-
else
204-
{
205-
if (errno == ERANGE)
206-
ereport(ERROR,
207-
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
208-
errmsg("\"%s\" is out of range for type real", num)));
209-
}
210226

211-
/*
212-
* In releases prior to 7.5, we accepted an empty string as valid
213-
* input (yielding a float4 of 0). In 7.5, we accept empty
214-
* strings, but emit a warning noting that the feature is
215-
* deprecated. In 7.6+, the warning should be replaced by an error.
216-
*/
217-
if (num == endptr)
218-
ereport(WARNING,
219-
(errcode(ERRCODE_WARNING_DEPRECATED_FEATURE),
220-
errmsg("deprecated input syntax for type real: \"\""),
221-
errdetail("This input will be rejected in "
222-
"a future release of PostgreSQL.")));
227+
/* skip trailing whitespace */
228+
while (*endptr != '\0' && isspace(*endptr))
229+
endptr++;
230+
231+
/* if there is any junk left at the end of the string, bail out */
232+
if (*endptr != '\0')
233+
ereport(ERROR,
234+
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
235+
errmsg("invalid input syntax for type real: \"%s\"",
236+
num)));
223237

224238
/*
225239
* if we get here, we have a legal double, still need to check to see
@@ -300,9 +314,33 @@ float8in(PG_FUNCTION_ARGS)
300314

301315
errno = 0;
302316
val = strtod(num, &endptr);
303-
if (*endptr != '\0')
317+
318+
if (errno == ERANGE)
319+
ereport(ERROR,
320+
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
321+
errmsg("\"%s\" is out of range for type double precision", num)));
322+
323+
if (num == endptr)
304324
{
305-
if (strcasecmp(num, "NaN") == 0)
325+
/*
326+
* We didn't find anything that looks like a float in the input
327+
*
328+
* In releases prior to 7.5, we accepted an empty string as
329+
* valid input (yielding a float8 of 0). In 7.5, we accept
330+
* empty strings, but emit a warning noting that the feature
331+
* is deprecated. In 7.6+, the warning should be replaced by
332+
* an error.
333+
*/
334+
if (*num == '\0')
335+
{
336+
ereport(WARNING,
337+
(errcode(ERRCODE_WARNING_DEPRECATED_FEATURE),
338+
errmsg("deprecated input syntax for type double precision: \"\""),
339+
errdetail("This input will be rejected in "
340+
"a future release of PostgreSQL.")));
341+
Assert(val == 0.0);
342+
}
343+
else if (strcasecmp(num, "NaN") == 0)
306344
val = NAN;
307345
else if (strcasecmp(num, "Infinity") == 0)
308346
val = HUGE_VAL;
@@ -314,26 +352,17 @@ float8in(PG_FUNCTION_ARGS)
314352
errmsg("invalid input syntax for type double precision: \"%s\"",
315353
num)));
316354
}
317-
else
318-
{
319-
if (errno == ERANGE)
320-
ereport(ERROR,
321-
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
322-
errmsg("\"%s\" is out of range for type double precision", num)));
323-
}
324355

325-
/*
326-
* In releases prior to 7.5, we accepted an empty string as valid
327-
* input (yielding a float8 of 0). In 7.5, we accept empty
328-
* strings, but emit a warning noting that the feature is
329-
* deprecated. In 7.6+, the warning should be replaced by an error.
330-
*/
331-
if (num == endptr)
332-
ereport(WARNING,
333-
(errcode(ERRCODE_WARNING_DEPRECATED_FEATURE),
334-
errmsg("deprecated input syntax for type double precision: \"\""),
335-
errdetail("This input will be rejected in "
336-
"a future release of PostgreSQL.")));
356+
/* skip trailing whitespace */
357+
while (*endptr != '\0' && isspace(*endptr))
358+
endptr++;
359+
360+
/* if there is any junk left at the end of the string, bail out */
361+
if (*endptr != '\0')
362+
ereport(ERROR,
363+
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
364+
errmsg("invalid input syntax for type double precision: \"%s\"",
365+
num)));
337366

338367
CheckFloat8Val(val);
339368

src/backend/utils/adt/int8.c

+6-3
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1994, Regents of the University of California
88
*
99
* IDENTIFICATION
10-
* $PostgreSQL: pgsql/src/backend/utils/adt/int8.c,v 1.51 2004/02/03 08:29:56 joe Exp $
10+
* $PostgreSQL: pgsql/src/backend/utils/adt/int8.c,v 1.52 2004/03/11 02:11:13 neilc Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -113,8 +113,11 @@ scanint8(const char *str, bool errorOK, int64 *result)
113113
tmp = newtmp;
114114
}
115115

116-
/* trailing junk? */
117-
if (*ptr)
116+
/* allow trailing whitespace, but not other trailing chars */
117+
while (*ptr != '\0' && isspace(*ptr))
118+
ptr++;
119+
120+
if (*ptr != '\0')
118121
{
119122
if (errorOK)
120123
return false;

src/backend/utils/adt/numutils.c

+19-12
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
*
1111
*
1212
* IDENTIFICATION
13-
* $PostgreSQL: pgsql/src/backend/utils/adt/numutils.c,v 1.61 2004/02/18 00:01:33 neilc Exp $
13+
* $PostgreSQL: pgsql/src/backend/utils/adt/numutils.c,v 1.62 2004/03/11 02:11:13 neilc Exp $
1414
*
1515
*-------------------------------------------------------------------------
1616
*/
@@ -19,6 +19,7 @@
1919
#include <errno.h>
2020
#include <math.h>
2121
#include <limits.h>
22+
#include <ctype.h>
2223

2324
#include "utils/builtins.h"
2425

@@ -45,10 +46,12 @@
4546
/*
4647
* pg_atoi: convert string to integer
4748
*
48-
* size is the sizeof() the desired integral result (1, 2, or 4 bytes).
49+
* 'size' is the sizeof() the desired integral result (1, 2, or 4 bytes).
4950
*
50-
* c, if not 0, is the terminator character that may appear after the
51-
* integer. If 0, the string must end after the integer.
51+
* allows any number of leading or trailing whitespace characters.
52+
*
53+
* 'c' is the character that terminates the input string (after any
54+
* number of whitespace characters).
5255
*
5356
* Unlike plain atoi(), this will throw ereport() upon bad input format or
5457
* overflow.
@@ -57,7 +60,7 @@ int32
5760
pg_atoi(char *s, int size, int c)
5861
{
5962
long l;
60-
char *badp = NULL;
63+
char *badp;
6164

6265
/*
6366
* Some versions of strtol treat the empty string as an error, but
@@ -74,17 +77,21 @@ pg_atoi(char *s, int size, int c)
7477
errno = 0;
7578
l = strtol(s, &badp, 10);
7679

77-
/*
78-
* strtol() normally only sets ERANGE. On some systems it also may
79-
* set EINVAL, which simply means it couldn't parse the input string.
80-
* This is handled by the second "if" consistent across platforms.
81-
*/
82-
if (errno && errno != ERANGE && errno != EINVAL)
80+
/* We made no progress parsing the string, so bail out */
81+
if (s == badp)
8382
ereport(ERROR,
8483
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
8584
errmsg("invalid input syntax for integer: \"%s\"",
8685
s)));
87-
if (badp && *badp && *badp != c)
86+
87+
/*
88+
* Skip any trailing whitespace; if anything but whitespace
89+
* remains before the terminating character, bail out
90+
*/
91+
while (*badp != c && isspace(*badp))
92+
badp++;
93+
94+
if (*badp != c)
8895
ereport(ERROR,
8996
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
9097
errmsg("invalid input syntax for integer: \"%s\"",

src/backend/utils/adt/oid.c

+15-15
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/utils/adt/oid.c,v 1.55 2004/03/04 21:47:18 neilc Exp $
11+
* $PostgreSQL: pgsql/src/backend/utils/adt/oid.c,v 1.56 2004/03/11 02:11:13 neilc Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -33,6 +33,19 @@ oidin_subr(const char *funcname, const char *s, char **endloc)
3333
char *endptr;
3434
Oid result;
3535

36+
/*
37+
* In releases prior to 7.5, we accepted an empty string as valid
38+
* input (yielding an OID of 0). In 7.5, we accept empty strings,
39+
* but emit a warning noting that the feature is deprecated. In
40+
* 7.6+, the warning should be replaced by an error.
41+
*/
42+
if (*s == '\0')
43+
ereport(WARNING,
44+
(errcode(ERRCODE_WARNING_DEPRECATED_FEATURE),
45+
errmsg("deprecated input syntax for type oid: \"\""),
46+
errdetail("This input will be rejected in "
47+
"a future release of PostgreSQL.")));
48+
3649
errno = 0;
3750
cvt = strtoul(s, &endptr, 10);
3851

@@ -47,20 +60,7 @@ oidin_subr(const char *funcname, const char *s, char **endloc)
4760
errmsg("invalid input syntax for type oid: \"%s\"",
4861
s)));
4962

50-
/*
51-
* In releases prior to 7.5, we accepted an empty string as valid
52-
* input (yielding an OID of 0). In 7.5, we accept empty strings,
53-
* but emit a warning noting that the feature is deprecated. In
54-
* 7.6+, the warning should be replaced by an error.
55-
*/
56-
if (*s == '\0')
57-
ereport(WARNING,
58-
(errcode(ERRCODE_WARNING_DEPRECATED_FEATURE),
59-
errmsg("deprecated input syntax for type oid: \"\""),
60-
errdetail("This input will be rejected in "
61-
"a future release of PostgreSQL.")));
62-
63-
if (endptr == s && *s)
63+
if (endptr == s && *s != '\0')
6464
ereport(ERROR,
6565
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
6666
errmsg("invalid input syntax for type oid: \"%s\"",

src/test/regress/expected/float4.out

+40-3
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
-- FLOAT4
33
--
44
CREATE TABLE FLOAT4_TBL (f1 float4);
5-
INSERT INTO FLOAT4_TBL(f1) VALUES ('0.0');
6-
INSERT INTO FLOAT4_TBL(f1) VALUES ('1004.30');
7-
INSERT INTO FLOAT4_TBL(f1) VALUES ('-34.84');
5+
INSERT INTO FLOAT4_TBL(f1) VALUES (' 0.0');
6+
INSERT INTO FLOAT4_TBL(f1) VALUES ('1004.30 ');
7+
INSERT INTO FLOAT4_TBL(f1) VALUES (' -34.84 ');
88
INSERT INTO FLOAT4_TBL(f1) VALUES ('1.2345678901234e+20');
99
INSERT INTO FLOAT4_TBL(f1) VALUES ('1.2345678901234e-20');
1010
-- test for over and under flow
@@ -16,6 +16,43 @@ INSERT INTO FLOAT4_TBL(f1) VALUES ('10e-40');
1616
ERROR: type "real" value out of range: underflow
1717
INSERT INTO FLOAT4_TBL(f1) VALUES ('-10e-40');
1818
ERROR: type "real" value out of range: underflow
19+
-- bad input
20+
INSERT INTO FLOAT4_TBL(f1) VALUES (' ');
21+
ERROR: invalid input syntax for type real: " "
22+
INSERT INTO FLOAT4_TBL(f1) VALUES ('xyz');
23+
ERROR: invalid input syntax for type real: "xyz"
24+
INSERT INTO FLOAT4_TBL(f1) VALUES ('5.0.0');
25+
ERROR: invalid input syntax for type real: "5.0.0"
26+
INSERT INTO FLOAT4_TBL(f1) VALUES ('5 . 0');
27+
ERROR: invalid input syntax for type real: "5 . 0"
28+
INSERT INTO FLOAT4_TBL(f1) VALUES ('5. 0');
29+
ERROR: invalid input syntax for type real: "5. 0"
30+
INSERT INTO FLOAT4_TBL(f1) VALUES (' - 3.0');
31+
ERROR: invalid input syntax for type real: " - 3.0"
32+
INSERT INTO FLOAT4_TBL(f1) VALUES ('123 5');
33+
ERROR: invalid input syntax for type real: "123 5"
34+
-- special inputs
35+
SELECT 'NaN'::float4;
36+
float4
37+
--------
38+
NaN
39+
(1 row)
40+
41+
SELECT 'nan'::float4;
42+
float4
43+
--------
44+
NaN
45+
(1 row)
46+
47+
SELECT ' NAN '::float4;
48+
float4
49+
--------
50+
NaN
51+
(1 row)
52+
53+
-- bad special inputs
54+
SELECT 'N A N'::float4;
55+
ERROR: invalid input syntax for type real: "N A N"
1956
SELECT '' AS five, FLOAT4_TBL.*;
2057
five | f1
2158
------+-------------

0 commit comments

Comments
 (0)