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

File tree

14 files changed

+859
-15
lines changed

14 files changed

+859
-15
lines changed

src/interfaces/ecpg/ecpglib/data.c

Lines changed: 57 additions & 3 deletions
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

Lines changed: 38 additions & 5 deletions
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

Lines changed: 5 additions & 5 deletions
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

Lines changed: 1 addition & 0 deletions
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

Lines changed: 29 additions & 1 deletion
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

Lines changed: 1 addition & 0 deletions
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

Lines changed: 1 addition & 0 deletions
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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy