mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-10-03 01:46:57 +02: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
|
* Copyright (c) 1998-2009, PostgreSQL Global Development Group
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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 free_var(NumericVar *var);
|
||||||
static void zero_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_num(Numeric value, NumericVar *dest);
|
||||||
static void set_var_from_var(NumericVar *value, NumericVar *dest);
|
static void set_var_from_var(NumericVar *value, NumericVar *dest);
|
||||||
static char *get_str_from_var(NumericVar *var, int dscale);
|
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);
|
Oid typelem = PG_GETARG_OID(1);
|
||||||
#endif
|
#endif
|
||||||
int32 typmod = PG_GETARG_INT32(2);
|
int32 typmod = PG_GETARG_INT32(2);
|
||||||
NumericVar value;
|
|
||||||
Numeric res;
|
Numeric res;
|
||||||
|
const char *cp;
|
||||||
|
|
||||||
|
/* Skip leading spaces */
|
||||||
|
cp = str;
|
||||||
|
while (*cp)
|
||||||
|
{
|
||||||
|
if (!isspace((unsigned char) *cp))
|
||||||
|
break;
|
||||||
|
cp++;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check for NaN
|
* Check for NaN
|
||||||
*/
|
*/
|
||||||
if (pg_strcasecmp(str, "NaN") == 0)
|
if (pg_strncasecmp(cp, "NaN", 3) == 0)
|
||||||
PG_RETURN_NUMERIC(make_result(&const_nan));
|
{
|
||||||
|
res = make_result(&const_nan);
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
|
||||||
|
init_var(&value);
|
||||||
|
|
||||||
|
cp = set_var_from_str(str, cp, &value);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Use set_var_from_str() to parse the input string and return it in the
|
* We duplicate a few lines of code here because we would like to
|
||||||
* packed DB storage format
|
* 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.
|
||||||
*/
|
*/
|
||||||
init_var(&value);
|
while (*cp)
|
||||||
set_var_from_str(str, &value);
|
{
|
||||||
|
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);
|
apply_typmod(&value, typmod);
|
||||||
|
|
||||||
res = make_result(&value);
|
res = make_result(&value);
|
||||||
free_var(&value);
|
free_var(&value);
|
||||||
|
}
|
||||||
|
|
||||||
PG_RETURN_NUMERIC(res);
|
PG_RETURN_NUMERIC(res);
|
||||||
}
|
}
|
||||||
@ -2121,7 +2165,9 @@ float8_numeric(PG_FUNCTION_ARGS)
|
|||||||
|
|
||||||
init_var(&result);
|
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);
|
res = make_result(&result);
|
||||||
|
|
||||||
free_var(&result);
|
free_var(&result);
|
||||||
@ -2181,7 +2227,9 @@ float4_numeric(PG_FUNCTION_ARGS)
|
|||||||
|
|
||||||
init_var(&result);
|
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);
|
res = make_result(&result);
|
||||||
|
|
||||||
free_var(&result);
|
free_var(&result);
|
||||||
@ -2972,11 +3020,17 @@ zero_var(NumericVar *var)
|
|||||||
* set_var_from_str()
|
* set_var_from_str()
|
||||||
*
|
*
|
||||||
* Parse a string and put the number into a variable
|
* 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
|
static const char *
|
||||||
set_var_from_str(const char *str, NumericVar *dest)
|
set_var_from_str(const char *str, const char *cp, NumericVar *dest)
|
||||||
{
|
{
|
||||||
const char *cp = str;
|
|
||||||
bool have_dp = FALSE;
|
bool have_dp = FALSE;
|
||||||
int i;
|
int i;
|
||||||
unsigned char *decdigits;
|
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
|
* We first parse the string to extract decimal digits and determine the
|
||||||
* correct decimal weight. Then convert to NBASE representation.
|
* correct decimal weight. Then convert to NBASE representation.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* skip leading spaces */
|
|
||||||
while (*cp)
|
|
||||||
{
|
|
||||||
if (!isspace((unsigned char) *cp))
|
|
||||||
break;
|
|
||||||
cp++;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (*cp)
|
switch (*cp)
|
||||||
{
|
{
|
||||||
case '+':
|
case '+':
|
||||||
@ -3086,17 +3131,6 @@ set_var_from_str(const char *str, NumericVar *dest)
|
|||||||
dscale = 0;
|
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
|
* Okay, convert pure-decimal representation to base NBASE. First we need
|
||||||
* to determine the converted weight and ndigits. offset is the number of
|
* 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 any leading/trailing zeroes, and normalize weight if zero */
|
||||||
strip_var(dest);
|
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 ('-555.50');
|
INSERT INTO num_input_test(n1) VALUES ('-555.50');
|
||||||
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 ');
|
|
||||||
^
|
|
||||||
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
|
-- bad inputs
|
||||||
INSERT INTO num_input_test(n1) VALUES (' ');
|
INSERT INTO num_input_test(n1) VALUES (' ');
|
||||||
ERROR: invalid input syntax for type numeric: " "
|
ERROR: invalid input syntax for type numeric: " "
|
||||||
@ -1278,7 +1272,9 @@ SELECT * FROM num_input_test;
|
|||||||
-93853
|
-93853
|
||||||
555.50
|
555.50
|
||||||
-555.50
|
-555.50
|
||||||
(5 rows)
|
NaN
|
||||||
|
NaN
|
||||||
|
(7 rows)
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Test some corner cases for division
|
-- Test some corner cases for division
|
||||||
|
Loading…
Reference in New Issue
Block a user