Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit50861cd

Browse files
committed
Improve portability of I/O behavior for the geometric types.
Formerly, the geometric I/O routines such as box_in and point_out relieddirectly on strtod() and sprintf() for conversion of the float8 componentvalues of their data types. However, the behavior of those functions ispretty platform-dependent, especially for edge-case values such asinfinities and NaNs. This was exposed by commitacdf2a8, whichadded test cases involving boxes with infinity endpoints, and immediatelyfailed on Windows and AIX buildfarm members. We solved these problemsyears ago in the main float8in and float8out functions, so let's fix itby making the geometric types use that code instead of depending directlyon the platform-supplied functions.To do this, refactor the float8in code so that it can be used to parsejust part of a string, and as a convenience make the guts of float8outusable without going through DirectFunctionCall.While at it, get rid of geo_ops.c's fairly shaky assumptions about themaximum output string length for a double, by having it build results inStringInfo buffers instead of fixed-length strings.In passing, convert all the "invalid input syntax for type foo" messagesin this area of the code into "invalid input syntax for type %s" to reducethe number of distinct translatable strings, per recent discussion.We would have needed a fair number of the latter anyway for code-sharingreasons, so we might as well just go whole hog.Note: this patch is by no means intended to guarantee that the geometrictypes uniformly behave sanely for infinity or NaN component values.But any bugs we have in that line were there all along, they were justharder to reach in a platform-independent way.
1 parent818e593 commit50861cd

File tree

4 files changed

+272
-314
lines changed

4 files changed

+272
-314
lines changed

‎src/backend/utils/adt/float.c

Lines changed: 63 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -411,17 +411,35 @@ Datum
411411
float8in(PG_FUNCTION_ARGS)
412412
{
413413
char*num=PG_GETARG_CSTRING(0);
414-
char*orig_num;
414+
415+
PG_RETURN_FLOAT8(float8in_internal(num,NULL,"double precision",num));
416+
}
417+
418+
/*
419+
* float8in_internal - guts of float8in()
420+
*
421+
* This is exposed for use by functions that want a reasonably
422+
* platform-independent way of inputting doubles. The behavior is
423+
* essentially like strtod + ereport on error, but note the following
424+
* differences:
425+
* 1. Both leading and trailing whitespace are skipped.
426+
* 2. If endptr_p is NULL, we throw error if there's trailing junk.
427+
* Otherwise, it's up to the caller to complain about trailing junk.
428+
* 3. In event of a syntax error, the report mentions the given type_name
429+
* and prints orig_string as the input; this is meant to support use of
430+
* this function with types such as "box" and "point", where what we are
431+
* parsing here is just a substring of orig_string.
432+
*
433+
* "num" could validly be declared "const char *", but that results in an
434+
* unreasonable amount of extra casting both here and in callers, so we don't.
435+
*/
436+
double
437+
float8in_internal(char*num,char**endptr_p,
438+
constchar*type_name,constchar*orig_string)
439+
{
415440
doubleval;
416441
char*endptr;
417442

418-
/*
419-
* endptr points to the first character _after_ the sequence we recognized
420-
* as a valid floating point number. orig_num points to the original input
421-
* string.
422-
*/
423-
orig_num=num;
424-
425443
/* skip leading whitespace */
426444
while (*num!='\0'&&isspace((unsignedchar)*num))
427445
num++;
@@ -433,8 +451,8 @@ float8in(PG_FUNCTION_ARGS)
433451
if (*num=='\0')
434452
ereport(ERROR,
435453
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
436-
errmsg("invalid input syntax for typedouble precision: \"%s\"",
437-
orig_num)));
454+
errmsg("invalid input syntax for type%s: \"%s\"",
455+
type_name,orig_string)));
438456

439457
errno=0;
440458
val=strtod(num,&endptr);
@@ -497,18 +515,27 @@ float8in(PG_FUNCTION_ARGS)
497515
* precision). We'd prefer not to throw error for that, so try to
498516
* detect whether it's a "real" out-of-range condition by checking
499517
* to see if the result is zero or huge.
518+
*
519+
* On error, we intentionally complain about double precision not
520+
* the given type name, and we print only the part of the string
521+
* that is the current number.
500522
*/
501523
if (val==0.0||val >=HUGE_VAL||val <=-HUGE_VAL)
524+
{
525+
char*errnumber=pstrdup(num);
526+
527+
errnumber[endptr-num]='\0';
502528
ereport(ERROR,
503529
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
504530
errmsg("\"%s\" is out of range for type double precision",
505-
orig_num)));
531+
errnumber)));
532+
}
506533
}
507534
else
508535
ereport(ERROR,
509536
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
510-
errmsg("invalid input syntax for typedouble precision: \"%s\"",
511-
orig_num)));
537+
errmsg("invalid input syntax for type%s: \"%s\"",
538+
type_name,orig_string)));
512539
}
513540
#ifdefHAVE_BUGGY_SOLARIS_STRTOD
514541
else
@@ -527,16 +554,16 @@ float8in(PG_FUNCTION_ARGS)
527554
while (*endptr!='\0'&&isspace((unsignedchar)*endptr))
528555
endptr++;
529556

530-
/* if there is any junk left at the end of the string, bail out */
531-
if (*endptr!='\0')
557+
/* report stopping point if wanted, else complain if not end of string */
558+
if (endptr_p)
559+
*endptr_p=endptr;
560+
elseif (*endptr!='\0')
532561
ereport(ERROR,
533562
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
534-
errmsg("invalid input syntax for typedouble precision: \"%s\"",
535-
orig_num)));
563+
errmsg("invalid input syntax for type%s: \"%s\"",
564+
type_name,orig_string)));
536565

537-
CHECKFLOATVAL(val, true, true);
538-
539-
PG_RETURN_FLOAT8(val);
566+
returnval;
540567
}
541568

542569
/*
@@ -547,10 +574,24 @@ Datum
547574
float8out(PG_FUNCTION_ARGS)
548575
{
549576
float8num=PG_GETARG_FLOAT8(0);
577+
578+
PG_RETURN_CSTRING(float8out_internal(num));
579+
}
580+
581+
/*
582+
* float8out_internal - guts of float8out()
583+
*
584+
* This is exposed for use by functions that want a reasonably
585+
* platform-independent way of outputting doubles.
586+
* The result is always palloc'd.
587+
*/
588+
char*
589+
float8out_internal(doublenum)
590+
{
550591
char*ascii= (char*)palloc(MAXDOUBLEWIDTH+1);
551592

552593
if (isnan(num))
553-
PG_RETURN_CSTRING(strcpy(ascii,"NaN"));
594+
returnstrcpy(ascii,"NaN");
554595

555596
switch (is_infinite(num))
556597
{
@@ -571,7 +612,7 @@ float8out(PG_FUNCTION_ARGS)
571612
}
572613
}
573614

574-
PG_RETURN_CSTRING(ascii);
615+
returnascii;
575616
}
576617

577618
/*

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp