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);
242242static void free_var (NumericVar * var );
243243static 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 );
246247static void set_var_from_num (Numeric value ,NumericVar * dest );
247248static void set_var_from_var (NumericVar * value ,NumericVar * dest );
248249static char * get_str_from_var (NumericVar * var ,int dscale );
@@ -321,26 +322,69 @@ numeric_in(PG_FUNCTION_ARGS)
321322Oid typelem = PG_GETARG_OID (1 );
322323#endif
323324int32 typmod = PG_GETARG_INT32 (2 );
324- NumericVar value ;
325325Numeric res ;
326+ const char * cp ;
327+
328+ /* Skip leading spaces */
329+ cp = str ;
330+ while (* cp )
331+ {
332+ if (!isspace ((unsignedchar )* 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 ((unsignedchar )* 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 ((unsignedchar )* 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
345389PG_RETURN_NUMERIC (res );
346390}
@@ -2121,7 +2165,9 @@ float8_numeric(PG_FUNCTION_ARGS)
21212165
21222166init_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+
21252171res = make_result (& result );
21262172
21272173free_var (& result );
@@ -2181,7 +2227,9 @@ float4_numeric(PG_FUNCTION_ARGS)
21812227
21822228init_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+
21852233res = make_result (& result );
21862234
21872235free_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 ;
29803034bool have_dp = FALSE;
29813035int i ;
29823036unsignedchar * 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 ((unsignedchar )* cp ))
3001- break ;
3002- cp ++ ;
3003- }
3004-
30053050switch (* cp )
30063051{
30073052case '+' :
@@ -3086,17 +3131,6 @@ set_var_from_str(const char *str, NumericVar *dest)
30863131dscale = 0 ;
30873132}
30883133
3089- /* Should be nothing left but spaces */
3090- while (* cp )
3091- {
3092- if (!isspace ((unsignedchar )* 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 */
31393173strip_var (dest );
3174+
3175+ /* Return end+1 position for caller */
3176+ return cp ;
31403177}
31413178
31423179