Improve portability of I/O behavior for the geometric types.

Formerly, the geometric I/O routines such as box_in and point_out relied
directly on strtod() and sprintf() for conversion of the float8 component
values of their data types.  However, the behavior of those functions is
pretty platform-dependent, especially for edge-case values such as
infinities and NaNs.  This was exposed by commit acdf2a8b37, which
added test cases involving boxes with infinity endpoints, and immediately
failed on Windows and AIX buildfarm members.  We solved these problems
years ago in the main float8in and float8out functions, so let's fix it
by making the geometric types use that code instead of depending directly
on the platform-supplied functions.

To do this, refactor the float8in code so that it can be used to parse
just part of a string, and as a convenience make the guts of float8out
usable without going through DirectFunctionCall.

While at it, get rid of geo_ops.c's fairly shaky assumptions about the
maximum output string length for a double, by having it build results in
StringInfo buffers instead of fixed-length strings.

In passing, convert all the "invalid input syntax for type foo" messages
in this area of the code into "invalid input syntax for type %s" to reduce
the number of distinct translatable strings, per recent discussion.
We would have needed a fair number of the latter anyway for code-sharing
reasons, so we might as well just go whole hog.

Note: this patch is by no means intended to guarantee that the geometric
types uniformly behave sanely for infinity or NaN component values.
But any bugs we have in that line were there all along, they were just
harder to reach in a platform-independent way.
This commit is contained in:
Tom Lane 2016-03-30 17:25:03 -04:00
parent 818e593736
commit 50861cd683
4 changed files with 272 additions and 314 deletions

View File

@ -411,17 +411,35 @@ Datum
float8in(PG_FUNCTION_ARGS)
{
char *num = PG_GETARG_CSTRING(0);
char *orig_num;
PG_RETURN_FLOAT8(float8in_internal(num, NULL, "double precision", num));
}
/*
* float8in_internal - guts of float8in()
*
* This is exposed for use by functions that want a reasonably
* platform-independent way of inputting doubles. The behavior is
* essentially like strtod + ereport on error, but note the following
* differences:
* 1. Both leading and trailing whitespace are skipped.
* 2. If endptr_p is NULL, we throw error if there's trailing junk.
* Otherwise, it's up to the caller to complain about trailing junk.
* 3. In event of a syntax error, the report mentions the given type_name
* and prints orig_string as the input; this is meant to support use of
* this function with types such as "box" and "point", where what we are
* parsing here is just a substring of orig_string.
*
* "num" could validly be declared "const char *", but that results in an
* unreasonable amount of extra casting both here and in callers, so we don't.
*/
double
float8in_internal(char *num, char **endptr_p,
const char *type_name, const char *orig_string)
{
double val;
char *endptr;
/*
* endptr points to the first character _after_ the sequence we recognized
* as a valid floating point number. orig_num points to the original input
* string.
*/
orig_num = num;
/* skip leading whitespace */
while (*num != '\0' && isspace((unsigned char) *num))
num++;
@ -433,8 +451,8 @@ float8in(PG_FUNCTION_ARGS)
if (*num == '\0')
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type double precision: \"%s\"",
orig_num)));
errmsg("invalid input syntax for type %s: \"%s\"",
type_name, orig_string)));
errno = 0;
val = strtod(num, &endptr);
@ -497,18 +515,27 @@ float8in(PG_FUNCTION_ARGS)
* precision). We'd prefer not to throw error for that, so try to
* detect whether it's a "real" out-of-range condition by checking
* to see if the result is zero or huge.
*
* On error, we intentionally complain about double precision not
* the given type name, and we print only the part of the string
* that is the current number.
*/
if (val == 0.0 || val >= HUGE_VAL || val <= -HUGE_VAL)
{
char *errnumber = pstrdup(num);
errnumber[endptr - num] = '\0';
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("\"%s\" is out of range for type double precision",
orig_num)));
errnumber)));
}
}
else
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type double precision: \"%s\"",
orig_num)));
errmsg("invalid input syntax for type %s: \"%s\"",
type_name, orig_string)));
}
#ifdef HAVE_BUGGY_SOLARIS_STRTOD
else
@ -527,16 +554,16 @@ float8in(PG_FUNCTION_ARGS)
while (*endptr != '\0' && isspace((unsigned char) *endptr))
endptr++;
/* if there is any junk left at the end of the string, bail out */
if (*endptr != '\0')
/* report stopping point if wanted, else complain if not end of string */
if (endptr_p)
*endptr_p = endptr;
else if (*endptr != '\0')
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type double precision: \"%s\"",
orig_num)));
errmsg("invalid input syntax for type %s: \"%s\"",
type_name, orig_string)));
CHECKFLOATVAL(val, true, true);
PG_RETURN_FLOAT8(val);
return val;
}
/*
@ -547,10 +574,24 @@ Datum
float8out(PG_FUNCTION_ARGS)
{
float8 num = PG_GETARG_FLOAT8(0);
PG_RETURN_CSTRING(float8out_internal(num));
}
/*
* float8out_internal - guts of float8out()
*
* This is exposed for use by functions that want a reasonably
* platform-independent way of outputting doubles.
* The result is always palloc'd.
*/
char *
float8out_internal(double num)
{
char *ascii = (char *) palloc(MAXDOUBLEWIDTH + 1);
if (isnan(num))
PG_RETURN_CSTRING(strcpy(ascii, "NaN"));
return strcpy(ascii, "NaN");
switch (is_infinite(num))
{
@ -571,7 +612,7 @@ float8out(PG_FUNCTION_ARGS)
}
}
PG_RETURN_CSTRING(ascii);
return ascii;
}
/*

View File

@ -57,12 +57,16 @@ static void make_bound_box(POLYGON *poly);
static bool plist_same(int npts, Point *p1, Point *p2);
static Point *point_construct(double x, double y);
static Point *point_copy(Point *pt);
static int single_decode(char *str, float8 *x, char **ss);
static int single_encode(float8 x, char *str);
static int pair_decode(char *str, float8 *x, float8 *y, char **s);
static int pair_encode(float8 x, float8 y, char *str);
static double single_decode(char *num, char **endptr_p,
const char *type_name, const char *orig_string);
static void single_encode(float8 x, StringInfo str);
static void pair_decode(char *str, double *x, double *y, char **endptr_p,
const char *type_name, const char *orig_string);
static void pair_encode(float8 x, float8 y, StringInfo str);
static int pair_count(char *s, char delim);
static int path_decode(int opentype, int npts, char *str, int *isopen, char **ss, Point *p);
static void path_decode(char *str, bool opentype, int npts, Point *p,
bool *isopen, char **endptr_p,
const char *type_name, const char *orig_string);
static char *path_encode(enum path_delim path_delim, int npts, Point *pt);
static void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
static double box_ar(BOX *box);
@ -91,10 +95,6 @@ static double dist_ppoly_internal(Point *pt, POLYGON *poly);
#define LDELIM_C '<'
#define RDELIM_C '>'
/* Maximum number of characters printed by pair_encode() */
/* ...+3+7 : 3 accounts for extra_float_digits max value */
#define P_MAXLEN (2*(DBL_DIG+3+7)+1)
/*
* Geometric data types are composed of points.
@ -121,195 +121,166 @@ static double dist_ppoly_internal(Point *pt, POLYGON *poly);
* and restore that order for text output - tgl 97/01/16
*/
static int
single_decode(char *str, float8 *x, char **s)
static double
single_decode(char *num, char **endptr_p,
const char *type_name, const char *orig_string)
{
char *cp;
if (!PointerIsValid(str))
return FALSE;
*x = strtod(str, &cp);
#ifdef GEODEBUG
printf("single_decode- decoded first %d chars of \"%s\" to %g\n",
(int) (cp - str), str, *x);
#endif
if (s != NULL)
{
while (isspace((unsigned char) *cp))
cp++;
*s = cp;
}
return TRUE;
return float8in_internal(num, endptr_p, type_name, orig_string);
} /* single_decode() */
static int
single_encode(float8 x, char *str)
static void
single_encode(float8 x, StringInfo str)
{
int ndig = DBL_DIG + extra_float_digits;
char *xstr = float8out_internal(x);
if (ndig < 1)
ndig = 1;
sprintf(str, "%.*g", ndig, x);
return TRUE;
appendStringInfoString(str, xstr);
pfree(xstr);
} /* single_encode() */
static int
pair_decode(char *str, float8 *x, float8 *y, char **s)
static void
pair_decode(char *str, double *x, double *y, char **endptr_p,
const char *type_name, const char *orig_string)
{
int has_delim;
char *cp;
if (!PointerIsValid(str))
return FALSE;
bool has_delim;
while (isspace((unsigned char) *str))
str++;
if ((has_delim = (*str == LDELIM)))
str++;
while (isspace((unsigned char) *str))
str++;
*x = strtod(str, &cp);
if (cp <= str)
return FALSE;
while (isspace((unsigned char) *cp))
cp++;
if (*cp++ != DELIM)
return FALSE;
while (isspace((unsigned char) *cp))
cp++;
*y = strtod(cp, &str);
if (str <= cp)
return FALSE;
while (isspace((unsigned char) *str))
str++;
*x = float8in_internal(str, &str, type_name, orig_string);
if (*str++ != DELIM)
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type %s: \"%s\"",
type_name, orig_string)));
*y = float8in_internal(str, &str, type_name, orig_string);
if (has_delim)
{
if (*str != RDELIM)
return FALSE;
str++;
if (*str++ != RDELIM)
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type %s: \"%s\"",
type_name, orig_string)));
while (isspace((unsigned char) *str))
str++;
}
if (s != NULL)
*s = str;
return TRUE;
/* report stopping point if wanted, else complain if not end of string */
if (endptr_p)
*endptr_p = str;
else if (*str != '\0')
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type %s: \"%s\"",
type_name, orig_string)));
}
static int
pair_encode(float8 x, float8 y, char *str)
static void
pair_encode(float8 x, float8 y, StringInfo str)
{
int ndig = DBL_DIG + extra_float_digits;
char *xstr = float8out_internal(x);
char *ystr = float8out_internal(y);
if (ndig < 1)
ndig = 1;
sprintf(str, "%.*g,%.*g", ndig, x, ndig, y);
return TRUE;
appendStringInfo(str, "%s,%s", xstr, ystr);
pfree(xstr);
pfree(ystr);
}
static int
path_decode(int opentype, int npts, char *str, int *isopen, char **ss, Point *p)
static void
path_decode(char *str, bool opentype, int npts, Point *p,
bool *isopen, char **endptr_p,
const char *type_name, const char *orig_string)
{
int depth = 0;
char *s,
*cp;
char *cp;
int i;
s = str;
while (isspace((unsigned char) *s))
s++;
if ((*isopen = (*s == LDELIM_EP)))
while (isspace((unsigned char) *str))
str++;
if ((*isopen = (*str == LDELIM_EP)))
{
/* no open delimiter allowed? */
if (!opentype)
return FALSE;
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type %s: \"%s\"",
type_name, orig_string)));
depth++;
s++;
while (isspace((unsigned char) *s))
s++;
str++;
}
else if (*s == LDELIM)
else if (*str == LDELIM)
{
cp = (s + 1);
cp = (str + 1);
while (isspace((unsigned char) *cp))
cp++;
if (*cp == LDELIM)
{
#ifdef NOT_USED
/* nested delimiters with only one point? */
if (npts <= 1)
return FALSE;
#endif
depth++;
s = cp;
str = cp;
}
else if (strrchr(s, LDELIM) == s)
else if (strrchr(str, LDELIM) == str)
{
depth++;
s = cp;
str = cp;
}
}
for (i = 0; i < npts; i++)
{
if (!pair_decode(s, &(p->x), &(p->y), &s))
return FALSE;
if (*s == DELIM)
s++;
pair_decode(str, &(p->x), &(p->y), &str, type_name, orig_string);
if (*str == DELIM)
str++;
p++;
}
while (isspace((unsigned char) *str))
str++;
while (depth > 0)
{
if ((*s == RDELIM)
|| ((*s == RDELIM_EP) && (*isopen) && (depth == 1)))
if ((*str == RDELIM)
|| ((*str == RDELIM_EP) && (*isopen) && (depth == 1)))
{
depth--;
s++;
while (isspace((unsigned char) *s))
s++;
str++;
while (isspace((unsigned char) *str))
str++;
}
else
return FALSE;
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type %s: \"%s\"",
type_name, orig_string)));
}
*ss = s;
return TRUE;
/* report stopping point if wanted, else complain if not end of string */
if (endptr_p)
*endptr_p = str;
else if (*str != '\0')
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type %s: \"%s\"",
type_name, orig_string)));
} /* path_decode() */
static char *
path_encode(enum path_delim path_delim, int npts, Point *pt)
{
int size = npts * (P_MAXLEN + 3) + 2;
char *result;
char *cp;
StringInfoData str;
int i;
/* Check for integer overflow */
if ((size - 2) / npts != (P_MAXLEN + 3))
ereport(ERROR,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("too many points requested")));
initStringInfo(&str);
result = palloc(size);
cp = result;
switch (path_delim)
{
case PATH_CLOSED:
*cp++ = LDELIM;
appendStringInfoChar(&str, LDELIM);
break;
case PATH_OPEN:
*cp++ = LDELIM_EP;
appendStringInfoChar(&str, LDELIM_EP);
break;
case PATH_NONE:
break;
@ -317,32 +288,27 @@ path_encode(enum path_delim path_delim, int npts, Point *pt)
for (i = 0; i < npts; i++)
{
*cp++ = LDELIM;
if (!pair_encode(pt->x, pt->y, cp))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("could not format \"path\" value")));
cp += strlen(cp);
*cp++ = RDELIM;
*cp++ = DELIM;
if (i > 0)
appendStringInfoChar(&str, DELIM);
appendStringInfoChar(&str, LDELIM);
pair_encode(pt->x, pt->y, &str);
appendStringInfoChar(&str, RDELIM);
pt++;
}
cp--;
switch (path_delim)
{
case PATH_CLOSED:
*cp++ = RDELIM;
appendStringInfoChar(&str, RDELIM);
break;
case PATH_OPEN:
*cp++ = RDELIM_EP;
appendStringInfoChar(&str, RDELIM_EP);
break;
case PATH_NONE:
break;
}
*cp = '\0';
return result;
return str.data;
} /* path_encode() */
/*-------------------------------------------------------------
@ -387,16 +353,11 @@ box_in(PG_FUNCTION_ARGS)
{
char *str = PG_GETARG_CSTRING(0);
BOX *box = (BOX *) palloc(sizeof(BOX));
int isopen;
char *s;
bool isopen;
double x,
y;
if ((!path_decode(FALSE, 2, str, &isopen, &s, &(box->high)))
|| (*s != '\0'))
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type box: \"%s\"", str)));
path_decode(str, false, 2, &(box->high), &isopen, NULL, "box", str);
/* reorder corners if necessary... */
if (box->high.x < box->low.x)
@ -935,43 +896,22 @@ box_diagonal(PG_FUNCTION_ARGS)
***********************************************************************/
static bool
line_decode(const char *str, LINE *line)
line_decode(char *s, const char *str, LINE *line)
{
char *tail;
while (isspace((unsigned char) *str))
str++;
if (*str++ != '{')
/* s was already advanced over leading '{' */
line->A = single_decode(s, &s, "line", str);
if (*s++ != DELIM)
return false;
line->A = strtod(str, &tail);
if (tail <= str)
line->B = single_decode(s, &s, "line", str);
if (*s++ != DELIM)
return false;
str = tail;
while (isspace((unsigned char) *str))
str++;
if (*str++ != DELIM)
line->C = single_decode(s, &s, "line", str);
if (*s++ != '}')
return false;
line->B = strtod(str, &tail);
if (tail <= str)
while (isspace((unsigned char) *s))
s++;
if (*s != '\0')
return false;
str = tail;
while (isspace((unsigned char) *str))
str++;
if (*str++ != DELIM)
return false;
line->C = strtod(str, &tail);
if (tail <= str)
return false;
str = tail;
while (isspace((unsigned char) *str))
str++;
if (*str++ != '}')
return false;
while (isspace((unsigned char) *str))
str++;
if (*str)
return false;
return true;
}
@ -979,33 +919,35 @@ Datum
line_in(PG_FUNCTION_ARGS)
{
char *str = PG_GETARG_CSTRING(0);
LINE *line;
LINE *line = (LINE *) palloc(sizeof(LINE));
LSEG lseg;
int isopen;
bool isopen;
char *s;
line = (LINE *) palloc(sizeof(LINE));
if (path_decode(TRUE, 2, str, &isopen, &s, &(lseg.p[0])) && *s == '\0')
s = str;
while (isspace((unsigned char) *s))
s++;
if (*s == '{')
{
if (FPeq(lseg.p[0].x, lseg.p[1].x) && FPeq(lseg.p[0].y, lseg.p[1].y))
if (!line_decode(s + 1, str, line))
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid line specification: must be two distinct points")));
line_construct_pts(line, &lseg.p[0], &lseg.p[1]);
}
else if (line_decode(str, line))
{
errmsg("invalid input syntax for type %s: \"%s\"",
"line", str)));
if (FPzero(line->A) && FPzero(line->B))
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid line specification: A and B cannot both be zero")));
}
else
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type line: \"%s\"", str)));
{
path_decode(s, true, 2, &(lseg.p[0]), &isopen, NULL, "line", str);
if (FPeq(lseg.p[0].x, lseg.p[1].x) && FPeq(lseg.p[0].y, lseg.p[1].y))
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid line specification: must be two distinct points")));
line_construct_pts(line, &lseg.p[0], &lseg.p[1]);
}
PG_RETURN_LINE_P(line);
}
@ -1015,12 +957,11 @@ Datum
line_out(PG_FUNCTION_ARGS)
{
LINE *line = PG_GETARG_LINE_P(0);
int ndig = DBL_DIG + extra_float_digits;
char *astr = float8out_internal(line->A);
char *bstr = float8out_internal(line->B);
char *cstr = float8out_internal(line->C);
if (ndig < 1)
ndig = 1;
PG_RETURN_CSTRING(psprintf("{%.*g,%.*g,%.*g}", ndig, line->A, ndig, line->B, ndig, line->C));
PG_RETURN_CSTRING(psprintf("{%s,%s,%s}", astr, bstr, cstr));
}
/*
@ -1367,7 +1308,7 @@ path_in(PG_FUNCTION_ARGS)
{
char *str = PG_GETARG_CSTRING(0);
PATH *path;
int isopen;
bool isopen;
char *s;
int npts;
int size;
@ -1377,7 +1318,8 @@ path_in(PG_FUNCTION_ARGS)
if ((npts = pair_count(str, ',')) <= 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type path: \"%s\"", str)));
errmsg("invalid input syntax for type %s: \"%s\"",
"path", str)));
s = str;
while (isspace((unsigned char) *s))
@ -1404,11 +1346,23 @@ path_in(PG_FUNCTION_ARGS)
SET_VARSIZE(path, size);
path->npts = npts;
if ((!path_decode(TRUE, npts, s, &isopen, &s, &(path->p[0])))
&& (!((depth == 0) && (*s == '\0'))) && !((depth >= 1) && (*s == RDELIM)))
path_decode(s, true, npts, &(path->p[0]), &isopen, &s, "path", str);
if (depth >= 1)
{
if (*s++ != RDELIM)
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type %s: \"%s\"",
"path", str)));
while (isspace((unsigned char) *s))
s++;
}
if (*s != '\0')
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type path: \"%s\"", str)));
errmsg("invalid input syntax for type %s: \"%s\"",
"path", str)));
path->closed = (!isopen);
/* prevent instability in unused pad bytes */
@ -1782,21 +1736,9 @@ Datum
point_in(PG_FUNCTION_ARGS)
{
char *str = PG_GETARG_CSTRING(0);
Point *point;
double x,
y;
char *s;
if (!pair_decode(str, &x, &y, &s) || (*s != '\0'))
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type point: \"%s\"", str)));
point = (Point *) palloc(sizeof(Point));
point->x = x;
point->y = y;
Point *point = (Point *) palloc(sizeof(Point));
pair_decode(str, &point->x, &point->y, NULL, "point", str);
PG_RETURN_POINT_P(point);
}
@ -2008,18 +1950,10 @@ Datum
lseg_in(PG_FUNCTION_ARGS)
{
char *str = PG_GETARG_CSTRING(0);
LSEG *lseg;
int isopen;
char *s;
lseg = (LSEG *) palloc(sizeof(LSEG));
if ((!path_decode(TRUE, 2, str, &isopen, &s, &(lseg->p[0])))
|| (*s != '\0'))
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type lseg: \"%s\"", str)));
LSEG *lseg = (LSEG *) palloc(sizeof(LSEG));
bool isopen;
path_decode(str, true, 2, &(lseg->p[0]), &isopen, NULL, "lseg", str);
PG_RETURN_LSEG_P(lseg);
}
@ -3480,13 +3414,13 @@ poly_in(PG_FUNCTION_ARGS)
int npts;
int size;
int base_size;
int isopen;
char *s;
bool isopen;
if ((npts = pair_count(str, ',')) <= 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type polygon: \"%s\"", str)));
errmsg("invalid input syntax for type %s: \"%s\"",
"polygon", str)));
base_size = sizeof(poly->p[0]) * npts;
size = offsetof(POLYGON, p) +base_size;
@ -3502,11 +3436,7 @@ poly_in(PG_FUNCTION_ARGS)
SET_VARSIZE(poly, size);
poly->npts = npts;
if ((!path_decode(FALSE, npts, str, &isopen, &s, &(poly->p[0])))
|| (*s != '\0'))
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type polygon: \"%s\"", str)));
path_decode(str, false, npts, &(poly->p[0]), &isopen, NULL, "polygon", str);
make_bound_box(poly);
@ -4595,13 +4525,11 @@ Datum
circle_in(PG_FUNCTION_ARGS)
{
char *str = PG_GETARG_CSTRING(0);
CIRCLE *circle;
CIRCLE *circle = (CIRCLE *) palloc(sizeof(CIRCLE));
char *s,
*cp;
int depth = 0;
circle = (CIRCLE *) palloc(sizeof(CIRCLE));
s = str;
while (isspace((unsigned char) *s))
s++;
@ -4615,20 +4543,17 @@ circle_in(PG_FUNCTION_ARGS)
s = cp;
}
if (!pair_decode(s, &circle->center.x, &circle->center.y, &s))
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type circle: \"%s\"", str)));
pair_decode(s, &circle->center.x, &circle->center.y, &s, "circle", str);
if (*s == DELIM)
s++;
while (isspace((unsigned char) *s))
s++;
if ((!single_decode(s, &circle->radius, &s)) || (circle->radius < 0))
circle->radius = single_decode(s, &s, "circle", str);
if (circle->radius < 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type circle: \"%s\"", str)));
errmsg("invalid input syntax for type %s: \"%s\"",
"circle", str)));
while (depth > 0)
{
@ -4643,13 +4568,15 @@ circle_in(PG_FUNCTION_ARGS)
else
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type circle: \"%s\"", str)));
errmsg("invalid input syntax for type %s: \"%s\"",
"circle", str)));
}
if (*s != '\0')
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type circle: \"%s\"", str)));
errmsg("invalid input syntax for type %s: \"%s\"",
"circle", str)));
PG_RETURN_CIRCLE_P(circle);
}
@ -4660,32 +4587,19 @@ Datum
circle_out(PG_FUNCTION_ARGS)
{
CIRCLE *circle = PG_GETARG_CIRCLE_P(0);
char *result;
char *cp;
StringInfoData str;
result = palloc(2 * P_MAXLEN + 6);
initStringInfo(&str);
cp = result;
*cp++ = LDELIM_C;
*cp++ = LDELIM;
if (!pair_encode(circle->center.x, circle->center.y, cp))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("could not format \"circle\" value")));
appendStringInfoChar(&str, LDELIM_C);
appendStringInfoChar(&str, LDELIM);
pair_encode(circle->center.x, circle->center.y, &str);
appendStringInfoChar(&str, RDELIM);
appendStringInfoChar(&str, DELIM);
single_encode(circle->radius, &str);
appendStringInfoChar(&str, RDELIM_C);
cp += strlen(cp);
*cp++ = RDELIM;
*cp++ = DELIM;
if (!single_encode(circle->radius, cp))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("could not format \"circle\" value")));
cp += strlen(cp);
*cp++ = RDELIM_C;
*cp = '\0';
PG_RETURN_CSTRING(result);
PG_RETURN_CSTRING(str.data);
}
/*

View File

@ -343,6 +343,9 @@ extern float get_float4_infinity(void);
extern double get_float8_nan(void);
extern float get_float4_nan(void);
extern int is_infinite(double val);
extern double float8in_internal(char *num, char **endptr_p,
const char *type_name, const char *orig_string);
extern char *float8out_internal(double num);
extern Datum float4in(PG_FUNCTION_ARGS);
extern Datum float4out(PG_FUNCTION_ARGS);

View File

@ -232,15 +232,15 @@ INSERT INTO box_temp
('(-infinity,-infinity)(infinity,infinity)');
SET enable_seqscan = false;
SELECT * FROM box_temp WHERE f1 << '(10,20),(30,40)';
f1
------------------
f1
----------------------------
(2,2),(1,1)
(4,4),(2,2)
(6,6),(3,3)
(8,8),(4,4)
(-0,100),(0,0)
(0,inf),(0,100)
(0,inf),(-inf,0)
(0,Infinity),(0,100)
(0,Infinity),(-Infinity,0)
(7 rows)
EXPLAIN (COSTS OFF) SELECT * FROM box_temp WHERE f1 << '(10,20),(30,40)';
@ -251,16 +251,16 @@ EXPLAIN (COSTS OFF) SELECT * FROM box_temp WHERE f1 << '(10,20),(30,40)';
(2 rows)
SELECT * FROM box_temp WHERE f1 &< '(10,4.333334),(5,100)';
f1
------------------
f1
----------------------------
(2,2),(1,1)
(4,4),(2,2)
(6,6),(3,3)
(8,8),(4,4)
(10,10),(5,5)
(-0,100),(0,0)
(0,inf),(0,100)
(0,inf),(-inf,0)
(0,Infinity),(0,100)
(0,Infinity),(-Infinity,0)
(8 rows)
EXPLAIN (COSTS OFF) SELECT * FROM box_temp WHERE f1 &< '(10,4.333334),(5,100)';
@ -271,8 +271,8 @@ EXPLAIN (COSTS OFF) SELECT * FROM box_temp WHERE f1 &< '(10,4.333334),(5,100)';
(2 rows)
SELECT * FROM box_temp WHERE f1 && '(15,20),(25,30)';
f1
-----------------------
f1
-------------------------------------------
(20,20),(10,10)
(22,22),(11,11)
(24,24),(12,12)
@ -289,7 +289,7 @@ SELECT * FROM box_temp WHERE f1 && '(15,20),(25,30)';
(46,46),(23,23)
(48,48),(24,24)
(50,50),(25,25)
(inf,inf),(-inf,-inf)
(Infinity,Infinity),(-Infinity,-Infinity)
(17 rows)
EXPLAIN (COSTS OFF) SELECT * FROM box_temp WHERE f1 && '(15,20),(25,30)';
@ -375,10 +375,10 @@ EXPLAIN (COSTS OFF) SELECT * FROM box_temp WHERE f1 &<| '(10,4.3333334),(5,1)';
(2 rows)
SELECT * FROM box_temp WHERE f1 |&> '(49.99,49.99),(49.99,49.99)';
f1
-------------------
f1
----------------------
(100,100),(50,50)
(0,inf),(0,100)
(0,Infinity),(0,100)
(2 rows)
EXPLAIN (COSTS OFF) SELECT * FROM box_temp WHERE f1 |&> '(49.99,49.99),(49.99,49.99)';
@ -389,8 +389,8 @@ EXPLAIN (COSTS OFF) SELECT * FROM box_temp WHERE f1 |&> '(49.99,49.99),(49.99,49
(2 rows)
SELECT * FROM box_temp WHERE f1 |>> '(37,38),(39,40)';
f1
-------------------
f1
----------------------
(82,82),(41,41)
(84,84),(42,42)
(86,86),(43,43)
@ -401,7 +401,7 @@ SELECT * FROM box_temp WHERE f1 |>> '(37,38),(39,40)';
(96,96),(48,48)
(98,98),(49,49)
(100,100),(50,50)
(0,inf),(0,100)
(0,Infinity),(0,100)
(11 rows)
EXPLAIN (COSTS OFF) SELECT * FROM box_temp WHERE f1 |>> '(37,38),(39,40)';
@ -412,12 +412,12 @@ EXPLAIN (COSTS OFF) SELECT * FROM box_temp WHERE f1 |>> '(37,38),(39,40)';
(2 rows)
SELECT * FROM box_temp WHERE f1 @> '(10,11),(15,16)';
f1
-----------------------
f1
-------------------------------------------
(16,16),(8,8)
(18,18),(9,9)
(20,20),(10,10)
(inf,inf),(-inf,-inf)
(Infinity,Infinity),(-Infinity,-Infinity)
(4 rows)
EXPLAIN (COSTS OFF) SELECT * FROM box_temp WHERE f1 @> '(10,11),(15,15)';