diff options
author | Sergei Golubchik <sergii@pisem.net> | 2011-11-27 17:46:20 +0100 |
---|---|---|
committer | Sergei Golubchik <sergii@pisem.net> | 2011-11-27 17:46:20 +0100 |
commit | effed09bd7d8081704eaa017060da84c32e3bf29 (patch) | |
tree | 9dd712312526cdbac1ab622efcdfc28e3fce965a /sql/spatial.cc | |
parent | 7189f09aa6d434fc889cb6d819e97c09f8cc0bcf (diff) | |
parent | 12e60c4989ce0214da88faad7c08d2f046885327 (diff) | |
download | mariadb-git-effed09bd7d8081704eaa017060da84c32e3bf29.tar.gz |
5.3->5.5 merge
Diffstat (limited to 'sql/spatial.cc')
-rw-r--r-- | sql/spatial.cc | 738 |
1 files changed, 679 insertions, 59 deletions
diff --git a/sql/spatial.cc b/sql/spatial.cc index ee701d82657..4dfc20716fc 100644 --- a/sql/spatial.cc +++ b/sql/spatial.cc @@ -1,5 +1,6 @@ /* - Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved. + Copyright (c) 2002, 2011, Oracle and/or its affiliates. + Copyright (c) 2011, Monty Program Ab This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -22,6 +23,27 @@ #ifdef HAVE_SPATIAL +/* + exponential notation : + 1 sign + 1 number before the decimal point + 1 decimal point + 14 number of significant digits (see String::qs_append(double)) + 1 'e' sign + 1 exponent sign + 3 exponent digits + == + 22 + + "f" notation : + 1 optional 0 + 1 sign + 14 number significant digits (see String::qs_append(double) ) + 1 decimal point + == + 17 +*/ + #define MAX_DIGITS_IN_DOUBLE MY_GCVT_MAX_FIELD_WIDTH /***************************** Gis_class_info *******************************/ @@ -162,6 +184,7 @@ Geometry *Geometry::create_from_wkt(Geometry_buffer *buffer, { LEX_STRING name; Class_info *ci; + char next_sym; if (trs->get_next_word(&name)) { @@ -174,9 +197,13 @@ Geometry *Geometry::create_from_wkt(Geometry_buffer *buffer, Geometry *result= (*ci->m_create_func)(buffer->data); wkt->q_append((char) wkb_ndr); wkt->q_append((uint32) result->get_class_info()->m_type_id); - if (trs->check_next_symbol('(') || + if (!(next_sym= trs->next_symbol())) + return NULL; + if (!(next_sym= trs->next_symbol())) + return NULL; + if ((next_sym == '(' && trs->check_next_symbol('(')) || result->init_from_wkt(trs, wkt) || - trs->check_next_symbol(')')) + (next_sym == '(' && trs->check_next_symbol(')'))) return NULL; if (init_stream) { @@ -187,6 +214,22 @@ Geometry *Geometry::create_from_wkt(Geometry_buffer *buffer, } +int Geometry::as_wkt(String *wkt, const char **end) +{ + uint32 len= (uint) get_class_info()->m_name.length; + if (wkt->reserve(len + 2, 512)) + return 1; + wkt->qs_append(get_class_info()->m_name.str, len); + if (get_class_info() != &geometrycollection_class) + wkt->qs_append('('); + if (get_data_as_wkt(wkt, end)) + return 1; + if (get_class_info() != &geometrycollection_class) + wkt->qs_append(')'); + return 0; +} + + static double wkb_get_double(const char *ptr, Geometry::wkbByteOrder bo) { double res; @@ -248,12 +291,37 @@ Geometry *Geometry::create_from_wkb(Geometry_buffer *buffer, } +int Geometry::create_from_opresult(Geometry_buffer *g_buf, + String *res, Gcalc_result_receiver &rr) +{ + uint32 geom_type= rr.get_result_typeid(); + Geometry *obj= create_by_typeid(g_buf, geom_type); + + if (!obj || res->reserve(WKB_HEADER_SIZE, 512)) + return 1; + + res->q_append((char) wkb_ndr); + res->q_append(geom_type); + return obj->init_from_opresult(res, rr.result(), rr.length()); +} + + bool Geometry::envelope(String *result) const { MBR mbr; const char *end; - if (get_mbr(&mbr, &end) || result->reserve(1+4*3+SIZEOF_STORED_DOUBLE*10)) + if (get_mbr(&mbr, &end)) + { + /* Empty geometry */ + if (result->reserve(1 + 4*2)) + return 1; + result->q_append((char) wkb_ndr); + result->q_append((uint32) wkb_geometrycollection); + result->q_append((uint32) 0); + return 0; + } + if (result->reserve(1 + 4 * 3 + SIZEOF_STORED_DOUBLE * 10)) return 1; result->q_append((char) wkb_ndr); @@ -290,13 +358,13 @@ bool Geometry::envelope(String *result) const bool Geometry::create_point(String *result, const char *data) const { - if (no_data(data, SIZEOF_STORED_DOUBLE * 2) || - result->reserve(1 + 4 + SIZEOF_STORED_DOUBLE * 2)) + if (no_data(data, POINT_DATA_SIZE) || + result->reserve(1 + 4 + POINT_DATA_SIZE)) return 1; result->q_append((char) wkb_ndr); result->q_append((uint32) wkb_point); /* Copy two double in same format */ - result->q_append(data, SIZEOF_STORED_DOUBLE*2); + result->q_append(data, POINT_DATA_SIZE); return 0; } @@ -316,7 +384,7 @@ bool Geometry::create_point(String *result, const char *data) const bool Geometry::create_point(String *result, double x, double y) const { - if (result->reserve(1 + 4 + SIZEOF_STORED_DOUBLE * 2)) + if (result->reserve(1 + 4 + POINT_DATA_SIZE)) return 1; result->q_append((char) wkb_ndr); @@ -348,7 +416,7 @@ const char *Geometry::append_points(String *txt, uint32 n_points, double x,y; data+= offset; get_point(&x, &y, data); - data+= SIZEOF_STORED_DOUBLE * 2; + data+= POINT_DATA_SIZE; txt->qs_append(x); txt->qs_append(' '); txt->qs_append(y); @@ -383,7 +451,7 @@ const char *Geometry::get_mbr_for_points(MBR *mbr, const char *data, points= uint4korr(data); data+= 4; - if (no_data(data, (SIZEOF_STORED_DOUBLE * 2 + offset) * points)) + if (no_data(data, (POINT_DATA_SIZE + offset) * points)) return 0; /* Calculate MBR for points */ @@ -391,7 +459,7 @@ const char *Geometry::get_mbr_for_points(MBR *mbr, const char *data, { data+= offset; mbr->add_xy(data, data + SIZEOF_STORED_DOUBLE); - data+= SIZEOF_STORED_DOUBLE * 2; + data+= POINT_DATA_SIZE; } return data; } @@ -409,7 +477,7 @@ bool Gis_point::init_from_wkt(Gis_read_stream *trs, String *wkb) { double x, y; if (trs->get_next_number(&x) || trs->get_next_number(&y) || - wkb->reserve(SIZEOF_STORED_DOUBLE * 2)) + wkb->reserve(POINT_DATA_SIZE)) return 1; wkb->q_append(x); wkb->q_append(y); @@ -456,6 +524,31 @@ bool Gis_point::get_mbr(MBR *mbr, const char **end) const return 0; } + +int Gis_point::area(double *ar, const char **end) const +{ + *ar= 0; + *end= m_data+ POINT_DATA_SIZE; + return 0; +} + + +int Gis_point::geom_length(double *len, const char **end) const +{ + *len= 0; + *end= m_data+ POINT_DATA_SIZE; + return 0; +} + + +int Gis_point::store_shapes(Gcalc_shape_transporter *trn) const +{ + double x, y; + + return get_xy(&x, &y) || trn->single_point(x, y); +} + + const Geometry::Class_info *Gis_point::get_class_info() const { return &point_class; @@ -507,12 +600,12 @@ uint Gis_line_string::init_from_wkb(const char *wkb, uint len, const char *wkb_end; Gis_point p; - if (len < 4) + if (len < 4 || + (n_points= wkb_get_uint(wkb, bo))<1) return 0; - n_points= wkb_get_uint(wkb, bo); proper_length= 4 + n_points * POINT_DATA_SIZE; - if (!n_points || len < proper_length || res->reserve(proper_length)) + if (len < proper_length || res->reserve(proper_length)) return 0; res->q_append(n_points); @@ -538,7 +631,7 @@ bool Gis_line_string::get_data_as_wkt(String *txt, const char **end) const data += 4; if (n_points < 1 || - no_data(data, SIZEOF_STORED_DOUBLE * 2 * n_points) || + no_data(data, POINT_DATA_SIZE * n_points) || txt->reserve(((MAX_DIGITS_IN_DOUBLE + 1)*2 + 1) * n_points)) return 1; @@ -546,7 +639,7 @@ bool Gis_line_string::get_data_as_wkt(String *txt, const char **end) const { double x, y; get_point(&x, &y, data); - data+= SIZEOF_STORED_DOUBLE * 2; + data+= POINT_DATA_SIZE; txt->qs_append(x); txt->qs_append(' '); txt->qs_append(y); @@ -564,7 +657,7 @@ bool Gis_line_string::get_mbr(MBR *mbr, const char **end) const } -int Gis_line_string::geom_length(double *len) const +int Gis_line_string::geom_length(double *len, const char **end) const { uint32 n_points; double prev_x, prev_y; @@ -575,21 +668,35 @@ int Gis_line_string::geom_length(double *len) const return 1; n_points= uint4korr(data); data+= 4; - if (n_points < 1 || no_data(data, SIZEOF_STORED_DOUBLE * 2 * n_points)) + if (n_points < 1 || no_data(data, POINT_DATA_SIZE * n_points)) return 1; get_point(&prev_x, &prev_y, data); - data+= SIZEOF_STORED_DOUBLE*2; - + data+= POINT_DATA_SIZE; while (--n_points) { double x, y; get_point(&x, &y, data); - data+= SIZEOF_STORED_DOUBLE * 2; + data+= POINT_DATA_SIZE; *len+= sqrt(pow(prev_x-x,2)+pow(prev_y-y,2)); prev_x= x; prev_y= y; } + *end= data; + return 0; +} + + +int Gis_line_string::area(double *ar, const char **end) const +{ + uint32 n_points; + *ar= 0.0; + + /* read number of points */ + if (no_data(m_data, 4)) + return 1; + n_points= uint4korr(m_data); + *end= m_data + 4 + POINT_DATA_SIZE * n_points; return 0; } @@ -609,14 +716,14 @@ int Gis_line_string::is_closed(int *closed) const return 0; } data+= 4; - if (no_data(data, SIZEOF_STORED_DOUBLE * 2 * n_points)) + if (no_data(data, POINT_DATA_SIZE * n_points)) return 1; /* Get first point */ get_point(&x1, &y1, data); /* get last point */ - data+= SIZEOF_STORED_DOUBLE*2 + (n_points-2)*POINT_DATA_SIZE; + data+= POINT_DATA_SIZE + (n_points-2)*POINT_DATA_SIZE; get_point(&x2, &y2, data); *closed= (x1==x2) && (y1==y2); @@ -660,6 +767,41 @@ int Gis_line_string::point_n(uint32 num, String *result) const return create_point(result, m_data + 4 + (num - 1) * POINT_DATA_SIZE); } + +int Gis_line_string::store_shapes(Gcalc_shape_transporter *trn) const +{ + uint32 n_points; + double x, y; + double UNINIT_VAR(prev_x), UNINIT_VAR(prev_y); + int first_point= 1; + const char *data= m_data; + + if (no_data(m_data, 4)) + return 1; + n_points= uint4korr(data); + data+= 4; + if (n_points < 1 || no_data(data, POINT_DATA_SIZE * n_points)) + return 1; + + trn->start_line(); + + while (n_points--) + { + get_point(&x, &y, data); + data+= POINT_DATA_SIZE; + if (!first_point && x == prev_x && y == prev_y) + continue; + if (trn->add_point(x, y)) + return 1; + first_point= 0; + prev_x= x; + prev_y= y; + } + + return trn->complete_line(); +} + + const Geometry::Class_info *Gis_line_string::get_class_info() const { return &linestring_class; @@ -721,6 +863,52 @@ bool Gis_polygon::init_from_wkt(Gis_read_stream *trs, String *wkb) } +uint Gis_polygon::init_from_opresult(String *bin, + const char *opres, uint res_len) +{ + const char *opres_orig= opres; + uint32 position= bin->length(); + uint32 poly_shapes= 0; + + if (bin->reserve(4, 512)) + return 0; + bin->q_append(poly_shapes); + + while (opres_orig + res_len > opres) + { + uint32 n_points, proper_length; + const char *op_end, *p1_position; + Gis_point p; + Gcalc_function::shape_type st; + + st= (Gcalc_function::shape_type) uint4korr(opres); + if (poly_shapes && st != Gcalc_function::shape_hole) + break; + poly_shapes++; + n_points= uint4korr(opres + 4) + 1; /* skip shape type id */ + proper_length= 4 + n_points * POINT_DATA_SIZE; + + if (bin->reserve(proper_length, 512)) + return 0; + + bin->q_append(n_points); + op_end= opres + 8 + (n_points-1) * 8 * 2; + p1_position= (opres+= 8); + for (; opres<op_end; opres+= POINT_DATA_SIZE) + { + if (!p.init_from_wkb(opres, POINT_DATA_SIZE, wkb_ndr, bin)) + return 0; + } + if (!p.init_from_wkb(p1_position, POINT_DATA_SIZE, wkb_ndr, bin)) + return 0; + } + + bin->write_at_position(position, poly_shapes); + + return (uint) (opres - opres_orig); +} + + uint Gis_polygon::init_from_wkb(const char *wkb, uint len, wkbByteOrder bo, String *res) { @@ -730,9 +918,7 @@ uint Gis_polygon::init_from_wkb(const char *wkb, uint len, wkbByteOrder bo, if (len < 4) return 0; - if (!(n_linear_rings= wkb_get_uint(wkb, bo))) - return 0; - + n_linear_rings= wkb_get_uint(wkb, bo); if (res->reserve(4, 512)) return 0; wkb+= 4; @@ -778,7 +964,7 @@ bool Gis_polygon::get_data_as_wkt(String *txt, const char **end) const return 1; n_points= uint4korr(data); data+= 4; - if (no_data(data, (SIZEOF_STORED_DOUBLE*2) * n_points) || + if (no_data(data, POINT_DATA_SIZE * n_points) || txt->reserve(2 + ((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points)) return 1; txt->qs_append('('); @@ -832,16 +1018,16 @@ int Gis_polygon::area(double *ar, const char **end_of_data) const if (no_data(data, 4)) return 1; n_points= uint4korr(data); - if (no_data(data, (SIZEOF_STORED_DOUBLE*2) * n_points)) + if (no_data(data, POINT_DATA_SIZE * n_points)) return 1; get_point(&prev_x, &prev_y, data+4); - data+= (4+SIZEOF_STORED_DOUBLE*2); + data+= (4+POINT_DATA_SIZE); while (--n_points) // One point is already read { double x, y; get_point(&x, &y, data); - data+= (SIZEOF_STORED_DOUBLE*2); + data+= POINT_DATA_SIZE; lr_area+= (prev_x + x)* (prev_y - y); prev_x= x; prev_y= y; @@ -868,7 +1054,7 @@ int Gis_polygon::exterior_ring(String *result) const n_points= uint4korr(data); data+= 4; length= n_points * POINT_DATA_SIZE; - if (no_data(data, length) || result->reserve(1+4+4+ length)) + if (no_data(data, length) || result->reserve(1 + 4 + 4 + length)) return 1; result->q_append((char) wkb_ndr); @@ -914,7 +1100,7 @@ int Gis_polygon::interior_ring_n(uint32 num, String *result) const n_points= uint4korr(data); points_size= n_points * POINT_DATA_SIZE; data+= 4; - if (no_data(data, points_size) || result->reserve(1+4+4+ points_size)) + if (no_data(data, points_size) || result->reserve(1 + 4 + 4 + points_size)) return 1; result->q_append((char) wkb_ndr); @@ -953,16 +1139,16 @@ int Gis_polygon::centroid_xy(double *x, double *y) const return 1; org_n_points= n_points= uint4korr(data); data+= 4; - if (no_data(data, (SIZEOF_STORED_DOUBLE*2) * n_points)) + if (no_data(data, POINT_DATA_SIZE * n_points)) return 1; get_point(&prev_x, &prev_y, data); - data+= (SIZEOF_STORED_DOUBLE*2); + data+= POINT_DATA_SIZE; while (--n_points) // One point is already read { double tmp_x, tmp_y; get_point(&tmp_x, &tmp_y, data); - data+= (SIZEOF_STORED_DOUBLE*2); + data+= POINT_DATA_SIZE; cur_area+= (prev_x + tmp_x) * (prev_y - tmp_y); cur_cx+= tmp_x; cur_cy+= tmp_y; @@ -1002,6 +1188,74 @@ int Gis_polygon::centroid(String *result) const return create_point(result, x, y); } + +int Gis_polygon::store_shapes(Gcalc_shape_transporter *trn) const +{ + uint32 n_linear_rings; + const char *data= m_data; + double first_x, first_y; + double prev_x, prev_y; + int was_equal_first= 0; + + if (trn->start_poly()) + return 1; + + if (no_data(data, 4)) + return 1; + n_linear_rings= uint4korr(data); + data+= 4; + + while (n_linear_rings--) + { + uint32 n_points; + + if (no_data(data, 4)) + return 1; + n_points= uint4korr(data); + data+= 4; + if (!n_points || no_data(data, POINT_DATA_SIZE * n_points)) + return 1; + + trn->start_ring(); + get_point(&first_x, &first_y, data); + data+= POINT_DATA_SIZE; + n_points--; + prev_x= first_x; + prev_y= first_y; + if (trn->add_point(first_x, first_y)) + return 1; + while (--n_points) + { + double x, y; + get_point(&x, &y, data); + data+= POINT_DATA_SIZE; + if (x == prev_x && y == prev_y) + continue; + prev_x= x; + prev_y= y; + if (was_equal_first) + { + if (trn->add_point(first_x, first_y)) + return 1; + was_equal_first= 0; + } + if (x == first_x && y == first_y) + { + was_equal_first= 1; + continue; + } + if (trn->add_point(x, y)) + return 1; + } + data+= POINT_DATA_SIZE; + trn->complete_ring(); + } + + trn->complete_poly(); + return 0; +} + + const Geometry::Class_info *Gis_polygon::get_class_info() const { return &polygon_class; @@ -1030,7 +1284,7 @@ bool Gis_multi_point::init_from_wkt(Gis_read_stream *trs, String *wkb) for (;;) { - if (wkb->reserve(1+4, 512)) + if (wkb->reserve(1 + 4, 512)) return 1; wkb->q_append((char) wkb_ndr); wkb->q_append((uint32) wkb_point); @@ -1045,6 +1299,32 @@ bool Gis_multi_point::init_from_wkt(Gis_read_stream *trs, String *wkb) } +uint Gis_multi_point::init_from_opresult(String *bin, + const char *opres, uint res_len) +{ + uint bin_size, n_points; + Gis_point p; + const char *opres_end; + + n_points= res_len/(4+8*2); + bin_size= n_points * (WKB_HEADER_SIZE + POINT_DATA_SIZE) + 4; + + if (bin->reserve(bin_size, 512)) + return 0; + + bin->q_append(n_points); + opres_end= opres + res_len; + for (; opres < opres_end; opres+= (4 + 8*2)) + { + bin->q_append((char)wkb_ndr); + bin->q_append((uint32)wkb_point); + if (!p.init_from_wkb(opres + 4, POINT_DATA_SIZE, wkb_ndr, bin)) + return 0; + } + return res_len; +} + + uint Gis_multi_point::init_from_wkb(const char *wkb, uint len, wkbByteOrder bo, String *res) { @@ -1083,7 +1363,7 @@ bool Gis_multi_point::get_data_as_wkt(String *txt, const char **end) const n_points= uint4korr(m_data); if (no_data(m_data+4, - n_points * (SIZEOF_STORED_DOUBLE * 2 + WKB_HEADER_SIZE)) || + n_points * (POINT_DATA_SIZE + WKB_HEADER_SIZE)) || txt->reserve(((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points)) return 1; *end= append_points(txt, n_points, m_data+4, WKB_HEADER_SIZE); @@ -1124,6 +1404,35 @@ int Gis_multi_point::geometry_n(uint32 num, String *result) const return 0; } + +int Gis_multi_point::store_shapes(Gcalc_shape_transporter *trn) const +{ + uint32 n_points; + Gis_point pt; + const char *data= m_data; + + if (no_data(data, 4)) + return 1; + n_points= uint4korr(data); + data+= 4; + + if (trn->start_collection(n_points)) + return 1; + + while (n_points--) + { + if (no_data(data, WKB_HEADER_SIZE)) + return 1; + data+= WKB_HEADER_SIZE; + pt.set_data_ptr(data, (uint32) (m_data_end - data)); + if (pt.store_shapes(trn)) + return 1; + data+= pt.get_data_size(); + } + return 0; +} + + const Geometry::Class_info *Gis_multi_point::get_class_info() const { return &multipoint_class; @@ -1166,10 +1475,9 @@ bool Gis_multi_line_string::init_from_wkt(Gis_read_stream *trs, String *wkb) { Gis_line_string ls; - if (wkb->reserve(1+4, 512)) + if (wkb->reserve(1 + 4, 512)) return 1; - wkb->q_append((char) wkb_ndr); - wkb->q_append((uint32) wkb_linestring); + wkb->q_append((char) wkb_ndr); wkb->q_append((uint32) wkb_linestring); if (trs->check_next_symbol('(') || ls.init_from_wkt(trs, wkb) || @@ -1184,15 +1492,48 @@ bool Gis_multi_line_string::init_from_wkt(Gis_read_stream *trs, String *wkb) } +uint Gis_multi_line_string::init_from_opresult(String *bin, + const char *opres, uint res_len) +{ + const char *opres_orig= opres; + int ns_pos= bin->length(); + uint n_linestring= 0; + + if (bin->reserve(4, 512)) + return 0; + bin->q_append(n_linestring); + + while (res_len) + { + Gis_line_string ls; + int ls_len; + + if (bin->reserve(WKB_HEADER_SIZE, 512)) + return 0; + + bin->q_append((char) wkb_ndr); + bin->q_append((uint32) wkb_linestring); + + if (!(ls_len= ls.init_from_opresult(bin, opres, res_len))) + return 0; + opres+= ls_len; + res_len-= ls_len; + n_linestring++; + } + bin->write_at_position(ns_pos, n_linestring); + return (uint) (opres - opres_orig); +} + + uint Gis_multi_line_string::init_from_wkb(const char *wkb, uint len, wkbByteOrder bo, String *res) { uint32 n_line_strings; const char *wkb_orig= wkb; - if (len < 4) + if (len < 4 || + (n_line_strings= wkb_get_uint(wkb, bo))< 1) return 0; - n_line_strings= wkb_get_uint(wkb, bo); if (res->reserve(4, 512)) return 0; @@ -1240,7 +1581,7 @@ bool Gis_multi_line_string::get_data_as_wkt(String *txt, return 1; n_points= uint4korr(data + WKB_HEADER_SIZE); data+= WKB_HEADER_SIZE + 4; - if (no_data(data, n_points * (SIZEOF_STORED_DOUBLE*2)) || + if (no_data(data, n_points * POINT_DATA_SIZE) || txt->reserve(2 + ((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points)) return 1; txt->qs_append('('); @@ -1311,10 +1652,11 @@ int Gis_multi_line_string::geometry_n(uint32 num, String *result) const } -int Gis_multi_line_string::geom_length(double *len) const +int Gis_multi_line_string::geom_length(double *len, const char **end) const { uint32 n_line_strings; const char *data= m_data; + const char *line_end; if (no_data(data, 4)) return 1; @@ -1328,7 +1670,7 @@ int Gis_multi_line_string::geom_length(double *len) const Gis_line_string ls; data+= WKB_HEADER_SIZE; ls.set_data_ptr(data, (uint32) (m_data_end - data)); - if (ls.geom_length(&ls_len)) + if (ls.geom_length(&ls_len, &line_end)) return 1; *len+= ls_len; /* @@ -1337,6 +1679,7 @@ int Gis_multi_line_string::geom_length(double *len) const */ data+= ls.get_data_size(); } + *end= data; return 0; } @@ -1370,6 +1713,35 @@ int Gis_multi_line_string::is_closed(int *closed) const return 0; } + +int Gis_multi_line_string::store_shapes(Gcalc_shape_transporter *trn) const +{ + uint32 n_lines; + Gis_line_string ls; + const char *data= m_data; + + if (no_data(data, 4)) + return 1; + n_lines= uint4korr(data); + data+= 4; + + if (trn->start_collection(n_lines)) + return 1; + + while (n_lines--) + { + if (no_data(data, WKB_HEADER_SIZE)) + return 1; + data+= WKB_HEADER_SIZE; + ls.set_data_ptr(data, (uint32) (m_data_end - data)); + if (ls.store_shapes(trn)) + return 1; + data+= ls.get_data_size(); + } + return 0; +} + + const Geometry::Class_info *Gis_multi_line_string::get_class_info() const { return &multilinestring_class; @@ -1420,7 +1792,7 @@ bool Gis_multi_polygon::init_from_wkt(Gis_read_stream *trs, String *wkb) for (;;) { - if (wkb->reserve(1+4, 512)) + if (wkb->reserve(1 + 4, 512)) return 1; wkb->q_append((char) wkb_ndr); wkb->q_append((uint32) wkb_polygon); @@ -1475,6 +1847,36 @@ uint Gis_multi_polygon::init_from_wkb(const char *wkb, uint len, } +uint Gis_multi_polygon::init_from_opresult(String *bin, + const char *opres, uint res_len) +{ + Gis_polygon p; + const char *opres_orig= opres; + uint p_len; + uint32 n_poly= 0; + uint32 np_pos= bin->length(); + + if (bin->reserve(4, 512)) + return 0; + + bin->q_append(n_poly); + while (res_len) + { + if (bin->reserve(1 + 4, 512)) + return 0; + bin->q_append((char)wkb_ndr); + bin->q_append((uint32)wkb_polygon); + if (!(p_len= p.init_from_opresult(bin, opres, res_len))) + return 0; + opres+= p_len; + res_len-= p_len; + n_poly++; + } + bin->write_at_position(np_pos, n_poly); + return opres - opres_orig; +} + + bool Gis_multi_polygon::get_data_as_wkt(String *txt, const char **end) const { uint32 n_polygons; @@ -1501,7 +1903,7 @@ bool Gis_multi_polygon::get_data_as_wkt(String *txt, const char **end) const return 1; uint32 n_points= uint4korr(data); data+= 4; - if (no_data(data, (SIZEOF_STORED_DOUBLE * 2) * n_points) || + if (no_data(data, POINT_DATA_SIZE * n_points) || txt->reserve(2 + ((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points, 512)) return 1; @@ -1654,6 +2056,35 @@ int Gis_multi_polygon::centroid(String *result) const return create_point(result, res_cx, res_cy); } + +int Gis_multi_polygon::store_shapes(Gcalc_shape_transporter *trn) const +{ + uint32 n_polygons; + Gis_polygon p; + const char *data= m_data; + + if (no_data(data, 4)) + return 1; + n_polygons= uint4korr(data); + data+= 4; + + if (trn->start_collection(n_polygons)) + return 1; + + while (n_polygons--) + { + if (no_data(data, WKB_HEADER_SIZE)) + return 1; + data+= WKB_HEADER_SIZE; + p.set_data_ptr(data, (uint32) (m_data_end - data)); + if (p.store_shapes(trn)) + return 1; + data+= p.get_data_size(); + } + return 0; +} + + const Geometry::Class_info *Gis_multi_polygon::get_class_info() const { return &multipolygon_class; @@ -1700,24 +2131,41 @@ bool Gis_geometry_collection::init_from_wkt(Gis_read_stream *trs, String *wkb) uint32 no_pos= wkb->length(); Geometry_buffer buffer; Geometry *g; + char next_sym; if (wkb->reserve(4, 512)) return 1; wkb->length(wkb->length()+4); // Reserve space for points - for (;;) + if (!(next_sym= trs->next_symbol())) + return 1; + + if (next_sym != ')') { - if (!(g= create_from_wkt(&buffer, trs, wkb))) + LEX_STRING next_word; + if (trs->lookup_next_word(&next_word)) return 1; - if (g->get_class_info()->m_type_id == wkb_geometrycollection) + if (next_word.length != 5 || + (my_strnncoll(&my_charset_latin1, + (const uchar*) "empty", 5, + (const uchar*) next_word.str, 5) != 0)) { - trs->set_error_msg("Unexpected GEOMETRYCOLLECTION"); - return 1; + for (;;) + { + if (!(g= create_from_wkt(&buffer, trs, wkb))) + return 1; + + if (g->get_class_info()->m_type_id == wkb_geometrycollection) + { + trs->set_error_msg("Unexpected GEOMETRYCOLLECTION"); + return 1; + } + n_objects++; + if (trs->skip_char(',')) // Didn't find ',' + break; + } } - n_objects++; - if (trs->skip_char(',')) // Didn't find ',' - break; } wkb->write_at_position(no_pos, n_objects); @@ -1725,6 +2173,50 @@ bool Gis_geometry_collection::init_from_wkt(Gis_read_stream *trs, String *wkb) } +uint Gis_geometry_collection::init_from_opresult(String *bin, + const char *opres, + uint res_len) +{ + const char *opres_orig= opres; + Geometry_buffer buffer; + Geometry *geom; + int g_len; + uint32 wkb_type; + int no_pos= bin->length(); + uint32 n_objects= 0; + + if (bin->reserve(4, 512)) + return 0; + bin->q_append(n_objects); + + while (res_len) + { + switch ((Gcalc_function::shape_type) uint4korr(opres)) + { + case Gcalc_function::shape_point: wkb_type= wkb_point; break; + case Gcalc_function::shape_line: wkb_type= wkb_linestring; break; + case Gcalc_function::shape_polygon: wkb_type= wkb_polygon; break; + default: wkb_type= 0; DBUG_ASSERT(FALSE); + }; + + if (bin->reserve(WKB_HEADER_SIZE, 512)) + return 0; + + bin->q_append((char) wkb_ndr); + bin->q_append(wkb_type); + + if (!(geom= create_by_typeid(&buffer, wkb_type)) || + !(g_len= geom->init_from_opresult(bin, opres, res_len))) + return 0; + opres+= g_len; + res_len-= g_len; + n_objects++; + } + bin->write_at_position(no_pos, n_objects); + return (uint) (opres - opres_orig); +} + + uint Gis_geometry_collection::init_from_wkb(const char *wkb, uint len, wkbByteOrder bo, String *res) { @@ -1780,6 +2272,13 @@ bool Gis_geometry_collection::get_data_as_wkt(String *txt, n_objects= uint4korr(data); data+= 4; + if (n_objects == 0) + { + txt->append(STRING_WITH_LEN(" EMPTY"), 512); + goto exit; + } + + txt->qs_append('('); while (n_objects--) { uint32 wkb_type; @@ -1794,10 +2293,11 @@ bool Gis_geometry_collection::get_data_as_wkt(String *txt, geom->set_data_ptr(data, (uint) (m_data_end - data)); if (geom->as_wkt(txt, &data)) return 1; - if (txt->append(STRING_WITH_LEN(","), 512)) + if (n_objects && txt->append(STRING_WITH_LEN(","), 512)) return 1; } - txt->length(txt->length() - 1); + txt->qs_append(')'); +exit: *end= data; return 0; } @@ -1814,6 +2314,8 @@ bool Gis_geometry_collection::get_mbr(MBR *mbr, const char **end) const return 1; n_objects= uint4korr(data); data+= 4; + if (n_objects == 0) + return 1; while (n_objects--) { @@ -1835,6 +2337,82 @@ bool Gis_geometry_collection::get_mbr(MBR *mbr, const char **end) const } +int Gis_geometry_collection::area(double *ar, const char **end) const +{ + uint32 n_objects; + const char *data= m_data; + Geometry_buffer buffer; + Geometry *geom; + double result; + + if (no_data(data, 4)) + return 1; + n_objects= uint4korr(data); + data+= 4; + if (n_objects == 0) + return 1; + + result= 0.0; + while (n_objects--) + { + uint32 wkb_type; + + if (no_data(data, WKB_HEADER_SIZE)) + return 1; + wkb_type= uint4korr(data + 1); + data+= WKB_HEADER_SIZE; + + if (!(geom= create_by_typeid(&buffer, wkb_type))) + return 1; + geom->set_data_ptr(data, (uint32) (m_data_end - data)); + if (geom->area(ar, &data)) + return 1; + result+= *ar; + } + *end= data; + *ar= result; + return 0; +} + + +int Gis_geometry_collection::geom_length(double *len, const char **end) const +{ + uint32 n_objects; + const char *data= m_data; + Geometry_buffer buffer; + Geometry *geom; + double result; + + if (no_data(data, 4)) + return 1; + n_objects= uint4korr(data); + data+= 4; + if (n_objects == 0) + return 1; + + result= 0.0; + while (n_objects--) + { + uint32 wkb_type; + + if (no_data(data, WKB_HEADER_SIZE)) + return 1; + wkb_type= uint4korr(data + 1); + data+= WKB_HEADER_SIZE; + + if (!(geom= create_by_typeid(&buffer, wkb_type))) + return 1; + geom->set_data_ptr(data, (uint32) (m_data_end - data)); + if (geom->geom_length(len, &data)) + return 1; + result+= *len; + } + *end= data; + *len= result; + return 0; +} + + int Gis_geometry_collection::num_geometries(uint32 *num) const { if (no_data(m_data, 4)) @@ -1874,7 +2452,7 @@ int Gis_geometry_collection::geometry_n(uint32 num, String *result) const } while (--num); /* Copy found object to result */ - if (result->reserve(1+4+length)) + if (result->reserve(1 + 4 + length)) return 1; result->q_append((char) wkb_ndr); result->q_append((uint32) wkb_type); @@ -1935,6 +2513,48 @@ bool Gis_geometry_collection::dimension(uint32 *res_dim, const char **end) const return 0; } + +int Gis_geometry_collection::store_shapes(Gcalc_shape_transporter *trn) const +{ + uint32 n_objects; + const char *data= m_data; + Geometry_buffer buffer; + Geometry *geom; + + if (no_data(data, 4)) + return 1; + n_objects= uint4korr(data); + data+= 4; + + if (!n_objects) + { + trn->empty_shape(); + return 0; + } + + if (trn->start_collection(n_objects)) + return 1; + + while (n_objects--) + { + uint32 wkb_type; + + if (no_data(data, WKB_HEADER_SIZE)) + return 1; + wkb_type= uint4korr(data + 1); + data+= WKB_HEADER_SIZE; + if (!(geom= create_by_typeid(&buffer, wkb_type))) + return 1; + geom->set_data_ptr(data, (uint32) (m_data_end - data)); + if (geom->store_shapes(trn)) + return 1; + + data+= geom->get_data_size(); + } + return 0; +} + + const Geometry::Class_info *Gis_geometry_collection::get_class_info() const { return &geometrycollection_class; |