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

Commit e0daf7f

Browse files
committed
Allow leading and trailing spaces around NaN in numeric_in.
Sam Mason, rewritten a bit by Tom.
1 parent 77d67a4 commit e0daf7f

File tree

2 files changed

+79
-46
lines changed

2 files changed

+79
-46
lines changed

src/backend/utils/adt/numeric.c

+76-39
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
* Copyright (c) 1998-2009, PostgreSQL Global Development Group
1515
*
1616
* IDENTIFICATION
17-
* $PostgreSQL: pgsql/src/backend/utils/adt/numeric.c,v 1.116 2009/01/01 17:23:49 momjian Exp $
17+
* $PostgreSQL: pgsql/src/backend/utils/adt/numeric.c,v 1.117 2009/04/08 22:08:40 tgl Exp $
1818
*
1919
*-------------------------------------------------------------------------
2020
*/
@@ -242,7 +242,8 @@ static void alloc_var(NumericVar *var, int ndigits);
242242
static void free_var(NumericVar *var);
243243
static void zero_var(NumericVar *var);
244244

245-
static void set_var_from_str(const char *str, NumericVar *dest);
245+
static const char *set_var_from_str(const char *str, const char *cp,
246+
NumericVar *dest);
246247
static void set_var_from_num(Numeric value, NumericVar *dest);
247248
static void set_var_from_var(NumericVar *value, NumericVar *dest);
248249
static char *get_str_from_var(NumericVar *var, int dscale);
@@ -321,26 +322,69 @@ numeric_in(PG_FUNCTION_ARGS)
321322
Oid typelem = PG_GETARG_OID(1);
322323
#endif
323324
int32 typmod = PG_GETARG_INT32(2);
324-
NumericVar value;
325325
Numeric res;
326+
const char *cp;
327+
328+
/* Skip leading spaces */
329+
cp = str;
330+
while (*cp)
331+
{
332+
if (!isspace((unsigned char) *cp))
333+
break;
334+
cp++;
335+
}
326336

327337
/*
328338
* Check for NaN
329339
*/
330-
if (pg_strcasecmp(str, "NaN") == 0)
331-
PG_RETURN_NUMERIC(make_result(&const_nan));
340+
if (pg_strncasecmp(cp, "NaN", 3) == 0)
341+
{
342+
res = make_result(&const_nan);
332343

333-
/*
334-
* Use set_var_from_str() to parse the input string and return it in the
335-
* packed DB storage format
336-
*/
337-
init_var(&value);
338-
set_var_from_str(str, &value);
344+
/* Should be nothing left but spaces */
345+
cp += 3;
346+
while (*cp)
347+
{
348+
if (!isspace((unsigned char) *cp))
349+
ereport(ERROR,
350+
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
351+
errmsg("invalid input syntax for type numeric: \"%s\"",
352+
str)));
353+
cp++;
354+
}
355+
}
356+
else
357+
{
358+
/*
359+
* Use set_var_from_str() to parse a normal numeric value
360+
*/
361+
NumericVar value;
339362

340-
apply_typmod(&value, typmod);
363+
init_var(&value);
341364

342-
res = make_result(&value);
343-
free_var(&value);
365+
cp = set_var_from_str(str, cp, &value);
366+
367+
/*
368+
* We duplicate a few lines of code here because we would like to
369+
* throw any trailing-junk syntax error before any semantic error
370+
* resulting from apply_typmod. We can't easily fold the two
371+
* cases together because we mustn't apply apply_typmod to a NaN.
372+
*/
373+
while (*cp)
374+
{
375+
if (!isspace((unsigned char) *cp))
376+
ereport(ERROR,
377+
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
378+
errmsg("invalid input syntax for type numeric: \"%s\"",
379+
str)));
380+
cp++;
381+
}
382+
383+
apply_typmod(&value, typmod);
384+
385+
res = make_result(&value);
386+
free_var(&value);
387+
}
344388

345389
PG_RETURN_NUMERIC(res);
346390
}
@@ -2121,7 +2165,9 @@ float8_numeric(PG_FUNCTION_ARGS)
21212165

21222166
init_var(&result);
21232167

2124-
set_var_from_str(buf, &result);
2168+
/* Assume we need not worry about leading/trailing spaces */
2169+
(void) set_var_from_str(buf, buf, &result);
2170+
21252171
res = make_result(&result);
21262172

21272173
free_var(&result);
@@ -2181,7 +2227,9 @@ float4_numeric(PG_FUNCTION_ARGS)
21812227

21822228
init_var(&result);
21832229

2184-
set_var_from_str(buf, &result);
2230+
/* Assume we need not worry about leading/trailing spaces */
2231+
(void) set_var_from_str(buf, buf, &result);
2232+
21852233
res = make_result(&result);
21862234

21872235
free_var(&result);
@@ -2972,11 +3020,17 @@ zero_var(NumericVar *var)
29723020
* set_var_from_str()
29733021
*
29743022
* Parse a string and put the number into a variable
3023+
*
3024+
* This function does not handle leading or trailing spaces, and it doesn't
3025+
* accept "NaN" either. It returns the end+1 position so that caller can
3026+
* check for trailing spaces/garbage if deemed necessary.
3027+
*
3028+
* cp is the place to actually start parsing; str is what to use in error
3029+
* reports. (Typically cp would be the same except advanced over spaces.)
29753030
*/
2976-
static void
2977-
set_var_from_str(const char *str, NumericVar *dest)
3031+
static const char *
3032+
set_var_from_str(const char *str, const char *cp, NumericVar *dest)
29783033
{
2979-
const char *cp = str;
29803034
bool have_dp = FALSE;
29813035
int i;
29823036
unsigned char *decdigits;
@@ -2993,15 +3047,6 @@ set_var_from_str(const char *str, NumericVar *dest)
29933047
* We first parse the string to extract decimal digits and determine the
29943048
* correct decimal weight. Then convert to NBASE representation.
29953049
*/
2996-
2997-
/* skip leading spaces */
2998-
while (*cp)
2999-
{
3000-
if (!isspace((unsigned char) *cp))
3001-
break;
3002-
cp++;
3003-
}
3004-
30053050
switch (*cp)
30063051
{
30073052
case '+':
@@ -3086,17 +3131,6 @@ set_var_from_str(const char *str, NumericVar *dest)
30863131
dscale = 0;
30873132
}
30883133

3089-
/* Should be nothing left but spaces */
3090-
while (*cp)
3091-
{
3092-
if (!isspace((unsigned char) *cp))
3093-
ereport(ERROR,
3094-
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
3095-
errmsg("invalid input syntax for type numeric: \"%s\"",
3096-
str)));
3097-
cp++;
3098-
}
3099-
31003134
/*
31013135
* Okay, convert pure-decimal representation to base NBASE. First we need
31023136
* to determine the converted weight and ndigits. offset is the number of
@@ -3137,6 +3171,9 @@ set_var_from_str(const char *str, NumericVar *dest)
31373171

31383172
/* Strip any leading/trailing zeroes, and normalize weight if zero */
31393173
strip_var(dest);
3174+
3175+
/* Return end+1 position for caller */
3176+
return cp;
31403177
}
31413178

31423179

src/test/regress/expected/numeric.out

+3-7
Original file line numberDiff line numberDiff line change
@@ -1230,13 +1230,7 @@ INSERT INTO num_input_test(n1) VALUES (' -93853');
12301230
INSERT INTO num_input_test(n1) VALUES ('555.50');
12311231
INSERT INTO num_input_test(n1) VALUES ('-555.50');
12321232
INSERT INTO num_input_test(n1) VALUES ('NaN ');
1233-
ERROR: invalid input syntax for type numeric: "NaN "
1234-
LINE 1: INSERT INTO num_input_test(n1) VALUES ('NaN ');
1235-
^
12361233
INSERT INTO num_input_test(n1) VALUES (' nan');
1237-
ERROR: invalid input syntax for type numeric: " nan"
1238-
LINE 1: INSERT INTO num_input_test(n1) VALUES (' nan');
1239-
^
12401234
-- bad inputs
12411235
INSERT INTO num_input_test(n1) VALUES (' ');
12421236
ERROR: invalid input syntax for type numeric: " "
@@ -1278,7 +1272,9 @@ SELECT * FROM num_input_test;
12781272
-93853
12791273
555.50
12801274
-555.50
1281-
(5 rows)
1275+
NaN
1276+
NaN
1277+
(7 rows)
12821278

12831279
--
12841280
-- Test some corner cases for division

0 commit comments

Comments
 (0)