14
14
* Copyright (c) 1998-2009, PostgreSQL Global Development Group
15
15
*
16
16
* 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 $
18
18
*
19
19
*-------------------------------------------------------------------------
20
20
*/
@@ -242,7 +242,8 @@ static void alloc_var(NumericVar *var, int ndigits);
242
242
static void free_var (NumericVar * var );
243
243
static void zero_var (NumericVar * var );
244
244
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 );
246
247
static void set_var_from_num (Numeric value , NumericVar * dest );
247
248
static void set_var_from_var (NumericVar * value , NumericVar * dest );
248
249
static char * get_str_from_var (NumericVar * var , int dscale );
@@ -321,26 +322,69 @@ numeric_in(PG_FUNCTION_ARGS)
321
322
Oid typelem = PG_GETARG_OID (1 );
322
323
#endif
323
324
int32 typmod = PG_GETARG_INT32 (2 );
324
- NumericVar value ;
325
325
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
+ }
326
336
327
337
/*
328
338
* Check for NaN
329
339
*/
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 );
332
343
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 ;
339
362
340
- apply_typmod (& value , typmod );
363
+ init_var (& value );
341
364
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
+ }
344
388
345
389
PG_RETURN_NUMERIC (res );
346
390
}
@@ -2121,7 +2165,9 @@ float8_numeric(PG_FUNCTION_ARGS)
2121
2165
2122
2166
init_var (& result );
2123
2167
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
+
2125
2171
res = make_result (& result );
2126
2172
2127
2173
free_var (& result );
@@ -2181,7 +2227,9 @@ float4_numeric(PG_FUNCTION_ARGS)
2181
2227
2182
2228
init_var (& result );
2183
2229
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
+
2185
2233
res = make_result (& result );
2186
2234
2187
2235
free_var (& result );
@@ -2972,11 +3020,17 @@ zero_var(NumericVar *var)
2972
3020
* set_var_from_str()
2973
3021
*
2974
3022
* 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.)
2975
3030
*/
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 )
2978
3033
{
2979
- const char * cp = str ;
2980
3034
bool have_dp = FALSE;
2981
3035
int i ;
2982
3036
unsigned char * decdigits ;
@@ -2993,15 +3047,6 @@ set_var_from_str(const char *str, NumericVar *dest)
2993
3047
* We first parse the string to extract decimal digits and determine the
2994
3048
* correct decimal weight. Then convert to NBASE representation.
2995
3049
*/
2996
-
2997
- /* skip leading spaces */
2998
- while (* cp )
2999
- {
3000
- if (!isspace ((unsigned char ) * cp ))
3001
- break ;
3002
- cp ++ ;
3003
- }
3004
-
3005
3050
switch (* cp )
3006
3051
{
3007
3052
case '+' :
@@ -3086,17 +3131,6 @@ set_var_from_str(const char *str, NumericVar *dest)
3086
3131
dscale = 0 ;
3087
3132
}
3088
3133
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
-
3100
3134
/*
3101
3135
* Okay, convert pure-decimal representation to base NBASE. First we need
3102
3136
* 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)
3137
3171
3138
3172
/* Strip any leading/trailing zeroes, and normalize weight if zero */
3139
3173
strip_var (dest );
3174
+
3175
+ /* Return end+1 position for caller */
3176
+ return cp ;
3140
3177
}
3141
3178
3142
3179
0 commit comments