mirror of
https://git.postgresql.org/git/postgresql.git
synced 2025-01-06 15:24:56 +08:00
Allow leading and trailing spaces around NaN in numeric_in.
Sam Mason, rewritten a bit by Tom.
This commit is contained in:
parent
77d67a4a3b
commit
e0daf7fc3c
@ -14,7 +14,7 @@
|
||||
* Copyright (c) 1998-2009, PostgreSQL Global Development Group
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/utils/adt/numeric.c,v 1.116 2009/01/01 17:23:49 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/utils/adt/numeric.c,v 1.117 2009/04/08 22:08:40 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -242,7 +242,8 @@ static void alloc_var(NumericVar *var, int ndigits);
|
||||
static void free_var(NumericVar *var);
|
||||
static void zero_var(NumericVar *var);
|
||||
|
||||
static void set_var_from_str(const char *str, NumericVar *dest);
|
||||
static const char *set_var_from_str(const char *str, const char *cp,
|
||||
NumericVar *dest);
|
||||
static void set_var_from_num(Numeric value, NumericVar *dest);
|
||||
static void set_var_from_var(NumericVar *value, NumericVar *dest);
|
||||
static char *get_str_from_var(NumericVar *var, int dscale);
|
||||
@ -321,26 +322,69 @@ numeric_in(PG_FUNCTION_ARGS)
|
||||
Oid typelem = PG_GETARG_OID(1);
|
||||
#endif
|
||||
int32 typmod = PG_GETARG_INT32(2);
|
||||
NumericVar value;
|
||||
Numeric res;
|
||||
const char *cp;
|
||||
|
||||
/* Skip leading spaces */
|
||||
cp = str;
|
||||
while (*cp)
|
||||
{
|
||||
if (!isspace((unsigned char) *cp))
|
||||
break;
|
||||
cp++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for NaN
|
||||
*/
|
||||
if (pg_strcasecmp(str, "NaN") == 0)
|
||||
PG_RETURN_NUMERIC(make_result(&const_nan));
|
||||
if (pg_strncasecmp(cp, "NaN", 3) == 0)
|
||||
{
|
||||
res = make_result(&const_nan);
|
||||
|
||||
/*
|
||||
* Use set_var_from_str() to parse the input string and return it in the
|
||||
* packed DB storage format
|
||||
*/
|
||||
init_var(&value);
|
||||
set_var_from_str(str, &value);
|
||||
/* Should be nothing left but spaces */
|
||||
cp += 3;
|
||||
while (*cp)
|
||||
{
|
||||
if (!isspace((unsigned char) *cp))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||
errmsg("invalid input syntax for type numeric: \"%s\"",
|
||||
str)));
|
||||
cp++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* Use set_var_from_str() to parse a normal numeric value
|
||||
*/
|
||||
NumericVar value;
|
||||
|
||||
apply_typmod(&value, typmod);
|
||||
init_var(&value);
|
||||
|
||||
res = make_result(&value);
|
||||
free_var(&value);
|
||||
cp = set_var_from_str(str, cp, &value);
|
||||
|
||||
/*
|
||||
* We duplicate a few lines of code here because we would like to
|
||||
* throw any trailing-junk syntax error before any semantic error
|
||||
* resulting from apply_typmod. We can't easily fold the two
|
||||
* cases together because we mustn't apply apply_typmod to a NaN.
|
||||
*/
|
||||
while (*cp)
|
||||
{
|
||||
if (!isspace((unsigned char) *cp))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||
errmsg("invalid input syntax for type numeric: \"%s\"",
|
||||
str)));
|
||||
cp++;
|
||||
}
|
||||
|
||||
apply_typmod(&value, typmod);
|
||||
|
||||
res = make_result(&value);
|
||||
free_var(&value);
|
||||
}
|
||||
|
||||
PG_RETURN_NUMERIC(res);
|
||||
}
|
||||
@ -2121,7 +2165,9 @@ float8_numeric(PG_FUNCTION_ARGS)
|
||||
|
||||
init_var(&result);
|
||||
|
||||
set_var_from_str(buf, &result);
|
||||
/* Assume we need not worry about leading/trailing spaces */
|
||||
(void) set_var_from_str(buf, buf, &result);
|
||||
|
||||
res = make_result(&result);
|
||||
|
||||
free_var(&result);
|
||||
@ -2181,7 +2227,9 @@ float4_numeric(PG_FUNCTION_ARGS)
|
||||
|
||||
init_var(&result);
|
||||
|
||||
set_var_from_str(buf, &result);
|
||||
/* Assume we need not worry about leading/trailing spaces */
|
||||
(void) set_var_from_str(buf, buf, &result);
|
||||
|
||||
res = make_result(&result);
|
||||
|
||||
free_var(&result);
|
||||
@ -2972,11 +3020,17 @@ zero_var(NumericVar *var)
|
||||
* set_var_from_str()
|
||||
*
|
||||
* Parse a string and put the number into a variable
|
||||
*
|
||||
* This function does not handle leading or trailing spaces, and it doesn't
|
||||
* accept "NaN" either. It returns the end+1 position so that caller can
|
||||
* check for trailing spaces/garbage if deemed necessary.
|
||||
*
|
||||
* cp is the place to actually start parsing; str is what to use in error
|
||||
* reports. (Typically cp would be the same except advanced over spaces.)
|
||||
*/
|
||||
static void
|
||||
set_var_from_str(const char *str, NumericVar *dest)
|
||||
static const char *
|
||||
set_var_from_str(const char *str, const char *cp, NumericVar *dest)
|
||||
{
|
||||
const char *cp = str;
|
||||
bool have_dp = FALSE;
|
||||
int i;
|
||||
unsigned char *decdigits;
|
||||
@ -2993,15 +3047,6 @@ set_var_from_str(const char *str, NumericVar *dest)
|
||||
* We first parse the string to extract decimal digits and determine the
|
||||
* correct decimal weight. Then convert to NBASE representation.
|
||||
*/
|
||||
|
||||
/* skip leading spaces */
|
||||
while (*cp)
|
||||
{
|
||||
if (!isspace((unsigned char) *cp))
|
||||
break;
|
||||
cp++;
|
||||
}
|
||||
|
||||
switch (*cp)
|
||||
{
|
||||
case '+':
|
||||
@ -3086,17 +3131,6 @@ set_var_from_str(const char *str, NumericVar *dest)
|
||||
dscale = 0;
|
||||
}
|
||||
|
||||
/* Should be nothing left but spaces */
|
||||
while (*cp)
|
||||
{
|
||||
if (!isspace((unsigned char) *cp))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||
errmsg("invalid input syntax for type numeric: \"%s\"",
|
||||
str)));
|
||||
cp++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Okay, convert pure-decimal representation to base NBASE. First we need
|
||||
* 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)
|
||||
|
||||
/* Strip any leading/trailing zeroes, and normalize weight if zero */
|
||||
strip_var(dest);
|
||||
|
||||
/* Return end+1 position for caller */
|
||||
return cp;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1230,13 +1230,7 @@ INSERT INTO num_input_test(n1) VALUES (' -93853');
|
||||
INSERT INTO num_input_test(n1) VALUES ('555.50');
|
||||
INSERT INTO num_input_test(n1) VALUES ('-555.50');
|
||||
INSERT INTO num_input_test(n1) VALUES ('NaN ');
|
||||
ERROR: invalid input syntax for type numeric: "NaN "
|
||||
LINE 1: INSERT INTO num_input_test(n1) VALUES ('NaN ');
|
||||
^
|
||||
INSERT INTO num_input_test(n1) VALUES (' nan');
|
||||
ERROR: invalid input syntax for type numeric: " nan"
|
||||
LINE 1: INSERT INTO num_input_test(n1) VALUES (' nan');
|
||||
^
|
||||
-- bad inputs
|
||||
INSERT INTO num_input_test(n1) VALUES (' ');
|
||||
ERROR: invalid input syntax for type numeric: " "
|
||||
@ -1278,7 +1272,9 @@ SELECT * FROM num_input_test;
|
||||
-93853
|
||||
555.50
|
||||
-555.50
|
||||
(5 rows)
|
||||
NaN
|
||||
NaN
|
||||
(7 rows)
|
||||
|
||||
--
|
||||
-- Test some corner cases for division
|
||||
|
Loading…
Reference in New Issue
Block a user