diff options
Diffstat (limited to 'src/backend/utils/adt/geo_ops.c')
-rw-r--r-- | src/backend/utils/adt/geo_ops.c | 458 |
1 files changed, 186 insertions, 272 deletions
diff --git a/src/backend/utils/adt/geo_ops.c b/src/backend/utils/adt/geo_ops.c index b84673d64c1..657bcee4fd4 100644 --- a/src/backend/utils/adt/geo_ops.c +++ b/src/backend/utils/adt/geo_ops.c @@ -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"))); - - result = palloc(size); + initStringInfo(&str); - 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++ != '{') - return false; - line->A = strtod(str, &tail); - if (tail <= str) - return false; - str = tail; - while (isspace((unsigned char) *str)) - str++; - if (*str++ != DELIM) - return false; - line->B = strtod(str, &tail); - if (tail <= str) + /* s was already advanced over leading '{' */ + line->A = single_decode(s, &s, "line", str); + if (*s++ != DELIM) return false; - str = tail; - while (isspace((unsigned char) *str)) - str++; - if (*str++ != DELIM) + line->B = single_decode(s, &s, "line", str); + if (*s++ != DELIM) return false; - line->C = strtod(str, &tail); - if (tail <= str) - return false; - str = tail; - while (isspace((unsigned char) *str)) - str++; - if (*str++ != '}') + line->C = single_decode(s, &s, "line", str); + if (*s++ != '}') return false; - while (isspace((unsigned char) *str)) - str++; - if (*str) + while (isspace((unsigned char) *s)) + s++; + if (*s != '\0') 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; - - result = palloc(2 * P_MAXLEN + 6); + StringInfoData 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"))); - - 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"))); + initStringInfo(&str); - cp += strlen(cp); - *cp++ = RDELIM_C; - *cp = '\0'; + 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); - PG_RETURN_CSTRING(result); + PG_RETURN_CSTRING(str.data); } /* |