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

Commit cedae13

Browse files
author
Michael Meskes
committed
Fixed NaN/Infinity problems in ECPG for float/double/numeric/decimal by making it OS independant.
Patch done by Zoltán Böszörményi.
1 parent 63f9282 commit cedae13

14 files changed

+859
-15
lines changed

src/interfaces/ecpg/ecpglib/data.c

+57-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
/* $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/data.c,v 1.47 2009/12/31 19:41:36 tgl Exp $ */
1+
/* $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/data.c,v 1.48 2010/02/02 16:09:11 meskes Exp $ */
22

33
#define POSTGRES_ECPG_INTERNAL
44
#include "postgres_fe.h"
55

66
#include <stdlib.h>
77
#include <string.h>
8+
#include <math.h>
89

910
#include "ecpgtype.h"
1011
#include "ecpglib.h"
@@ -38,6 +39,58 @@ garbage_left(enum ARRAY_TYPE isarray, char *scan_length, enum COMPAT_MODE compat
3839
return false;
3940
}
4041

42+
/* stolen code from src/backend/utils/adt/float.c */
43+
#if defined(WIN32) && !defined(NAN)
44+
static const uint32 nan[2] = {0xffffffff, 0x7fffffff};
45+
46+
#define NAN (*(const double *) nan)
47+
#endif
48+
49+
static double
50+
get_float8_infinity(void)
51+
{
52+
#ifdef INFINITY
53+
return (double) INFINITY;
54+
#else
55+
return (double) (HUGE_VAL * HUGE_VAL);
56+
#endif
57+
}
58+
59+
static double
60+
get_float8_nan(void)
61+
{
62+
#ifdef NAN
63+
return (double) NAN;
64+
#else
65+
return (double) (0.0 / 0.0);
66+
#endif
67+
}
68+
69+
static bool
70+
check_special_value(char *ptr, double *retval, char **endptr)
71+
{
72+
if (!pg_strncasecmp(ptr, "NaN", 3))
73+
{
74+
*retval = get_float8_nan();
75+
*endptr = ptr + 3;
76+
return true;
77+
}
78+
else if (!pg_strncasecmp(ptr, "Infinity", 8))
79+
{
80+
*retval = get_float8_infinity();
81+
*endptr = ptr + 8;
82+
return true;
83+
}
84+
else if (!pg_strncasecmp(ptr, "-Infinity", 9))
85+
{
86+
*retval = -get_float8_infinity();
87+
*endptr = ptr + 9;
88+
return true;
89+
}
90+
91+
return false;
92+
}
93+
4194
bool
4295
ecpg_get_data(const PGresult *results, int act_tuple, int act_field, int lineno,
4396
enum ECPGttype type, enum ECPGttype ind_type,
@@ -300,8 +353,9 @@ ecpg_get_data(const PGresult *results, int act_tuple, int act_field, int lineno,
300353
case ECPGt_float:
301354
case ECPGt_double:
302355
if (isarray && *pval == '"')
303-
dres = strtod(pval + 1, &scan_length);
304-
else
356+
pval++;
357+
358+
if (!check_special_value(pval, &dres, &scan_length))
305359
dres = strtod(pval, &scan_length);
306360

307361
if (isarray && *scan_length == '"')

src/interfaces/ecpg/ecpglib/execute.c

+38-5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/execute.c,v 1.90 2010/01/29 15:57:01 meskes Exp $ */
1+
/* $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/execute.c,v 1.91 2010/02/02 16:09:11 meskes Exp $ */
22

33
/*
44
* The aim is to get a simpler inteface to the database routines.
@@ -17,6 +17,7 @@
1717
#include "postgres_fe.h"
1818

1919
#include <locale.h>
20+
#include <math.h>
2021

2122
#include "pg_type.h"
2223

@@ -463,6 +464,38 @@ ecpg_store_result(const PGresult *results, int act_field,
463464
return status;
464465
}
465466

467+
static void
468+
sprintf_double_value(char *ptr, double value, const char *delim)
469+
{
470+
if (isinf(value))
471+
{
472+
if (value < 0)
473+
sprintf(ptr, "%s%s", "-Infinity", delim);
474+
else
475+
sprintf(ptr, "%s%s", "Infinity", delim);
476+
}
477+
else if (isnan(value))
478+
sprintf(ptr, "%s%s", "NaN", delim);
479+
else
480+
sprintf(ptr, "%.14g%s", value, delim);
481+
}
482+
483+
static void
484+
sprintf_float_value(char *ptr, float value, const char *delim)
485+
{
486+
if (isinf(value))
487+
{
488+
if (value < 0)
489+
sprintf(ptr, "%s%s", "-Infinity", delim);
490+
else
491+
sprintf(ptr, "%s%s", "Infinity", delim);
492+
}
493+
else if (isnan(value))
494+
sprintf(ptr, "%s%s", "NaN", delim);
495+
else
496+
sprintf(ptr, "%.14g%s", value, delim);
497+
}
498+
466499
bool
467500
ecpg_store_input(const int lineno, const bool force_indicator, const struct variable * var,
468501
char **tobeinserted_p, bool quote)
@@ -693,12 +726,12 @@ ecpg_store_input(const int lineno, const bool force_indicator, const struct vari
693726
strcpy(mallocedval, "array [");
694727

695728
for (element = 0; element < asize; element++)
696-
sprintf(mallocedval + strlen(mallocedval), "%.14g,", ((float *) var->value)[element]);
729+
sprintf_float_value(mallocedval + strlen(mallocedval), ((float *) var->value)[element], ",");
697730

698731
strcpy(mallocedval + strlen(mallocedval) - 1, "]");
699732
}
700733
else
701-
sprintf(mallocedval, "%.14g", *((float *) var->value));
734+
sprintf_float_value(mallocedval, *((float *) var->value), "");
702735

703736
*tobeinserted_p = mallocedval;
704737
break;
@@ -712,12 +745,12 @@ ecpg_store_input(const int lineno, const bool force_indicator, const struct vari
712745
strcpy(mallocedval, "array [");
713746

714747
for (element = 0; element < asize; element++)
715-
sprintf(mallocedval + strlen(mallocedval), "%.14g,", ((double *) var->value)[element]);
748+
sprintf_double_value(mallocedval + strlen(mallocedval), ((double *) var->value)[element], ",");
716749

717750
strcpy(mallocedval + strlen(mallocedval) - 1, "]");
718751
}
719752
else
720-
sprintf(mallocedval, "%.14g", *((double *) var->value));
753+
sprintf_double_value(mallocedval, *((double *) var->value), "");
721754

722755
*tobeinserted_p = mallocedval;
723756
break;

src/interfaces/ecpg/ecpglib/misc.c

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/misc.c,v 1.54 2010/01/26 09:07:31 meskes Exp $ */
1+
/* $PostgreSQL: pgsql/src/interfaces/ecpg/ecpglib/misc.c,v 1.55 2010/02/02 16:09:11 meskes Exp $ */
22

33
#define POSTGRES_ECPG_INTERNAL
44
#include "postgres_fe.h"
@@ -344,11 +344,11 @@ ECPGset_noind_null(enum ECPGttype type, void *ptr)
344344
break;
345345
case ECPGt_decimal:
346346
memset((char *) ptr, 0, sizeof(decimal));
347-
((decimal *) ptr)->sign = NUMERIC_NAN;
347+
((decimal *) ptr)->sign = NUMERIC_NULL;
348348
break;
349349
case ECPGt_numeric:
350350
memset((char *) ptr, 0, sizeof(numeric));
351-
((numeric *) ptr)->sign = NUMERIC_NAN;
351+
((numeric *) ptr)->sign = NUMERIC_NULL;
352352
break;
353353
case ECPGt_interval:
354354
memset((char *) ptr, 0xff, sizeof(interval));
@@ -416,11 +416,11 @@ ECPGis_noind_null(enum ECPGttype type, void *ptr)
416416
return true;
417417
break;
418418
case ECPGt_decimal:
419-
if (((decimal *) ptr)->sign == NUMERIC_NAN)
419+
if (((decimal *) ptr)->sign == NUMERIC_NULL)
420420
return true;
421421
break;
422422
case ECPGt_numeric:
423-
if (((numeric *) ptr)->sign == NUMERIC_NAN)
423+
if (((numeric *) ptr)->sign == NUMERIC_NULL)
424424
return true;
425425
break;
426426
case ECPGt_interval:

src/interfaces/ecpg/include/pgtypes_numeric.h

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#define NUMERIC_POS 0x0000
55
#define NUMERIC_NEG 0x4000
66
#define NUMERIC_NAN 0xC000
7+
#define NUMERIC_NULL 0xF000
78
#define NUMERIC_MAX_PRECISION 1000
89
#define NUMERIC_MAX_DISPLAY_SCALE NUMERIC_MAX_PRECISION
910
#define NUMERIC_MIN_DISPLAY_SCALE 0

src/interfaces/ecpg/pgtypeslib/numeric.c

+29-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* $PostgreSQL: pgsql/src/interfaces/ecpg/pgtypeslib/numeric.c,v 1.34 2009/09/03 09:59:20 meskes Exp $ */
1+
/* $PostgreSQL: pgsql/src/interfaces/ecpg/pgtypeslib/numeric.c,v 1.35 2010/02/02 16:09:12 meskes Exp $ */
22

33
#include "postgres_fe.h"
44
#include <ctype.h>
@@ -173,6 +173,25 @@ set_var_from_str(char *str, char **ptr, numeric *dest)
173173
(*ptr)++;
174174
}
175175

176+
if (pg_strncasecmp(*ptr, "NaN", 3) == 0)
177+
{
178+
*ptr += 3;
179+
dest->sign = NUMERIC_NAN;
180+
181+
/* Should be nothing left but spaces */
182+
while (*(*ptr))
183+
{
184+
if (!isspace((unsigned char) *(*ptr)))
185+
{
186+
errno = PGTYPES_NUM_BAD_NUMERIC;
187+
return -1;
188+
}
189+
(*ptr)++;
190+
}
191+
192+
return 0;
193+
}
194+
176195
if (alloc_var(dest, strlen((*ptr))) < 0)
177196
return -1;
178197
dest->weight = -1;
@@ -296,6 +315,15 @@ get_str_from_var(numeric *var, int dscale)
296315
int i;
297316
int d;
298317

318+
if (var->sign == NUMERIC_NAN)
319+
{
320+
str = (char *) pgtypes_alloc(4);
321+
if (str == NULL)
322+
return NULL;
323+
sprintf(str, "NaN");
324+
return str;
325+
}
326+
299327
/*
300328
* Check if we must round up before printing the value and do so.
301329
*/

src/interfaces/ecpg/test/ecpg_schedule

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ test: pgtypeslib/dt_test
1515
test: pgtypeslib/dt_test2
1616
test: pgtypeslib/num_test
1717
test: pgtypeslib/num_test2
18+
test: pgtypeslib/nan_test
1819
test: preproc/array_of_struct
1920
test: preproc/autoprep
2021
test: preproc/comment

src/interfaces/ecpg/test/ecpg_schedule_tcp

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ test: pgtypeslib/dt_test
1515
test: pgtypeslib/dt_test2
1616
test: pgtypeslib/num_test
1717
test: pgtypeslib/num_test2
18+
test: pgtypeslib/nan_test
1819
test: preproc/array_of_struct
1920
test: preproc/autoprep
2021
test: preproc/comment

0 commit comments

Comments
 (0)