diff options
author | unknown <monty@mashka.mysql.fi> | 2004-03-04 08:50:37 +0200 |
---|---|---|
committer | unknown <monty@mashka.mysql.fi> | 2004-03-04 08:50:37 +0200 |
commit | afa6728a9f7c00582b3dc9e96b2dce5c4ac1e56c (patch) | |
tree | f335ad0e2c6634a947a95d62cbee9a54ee9303e8 /sql | |
parent | f96960f9e1605189cc49397c64ff1cff97faedf1 (diff) | |
download | mariadb-git-afa6728a9f7c00582b3dc9e96b2dce5c4ac1e56c.tar.gz |
Optimized GIS functions
heap/hp_delete.c:
Added comments
mysql-test/r/gis.result:
Updated results after name changes (all results line are unchanged)
mysql-test/r/show_check.result:
Update test results after fix in hp_delete.cc
mysql-test/t/gis.test:
Changed table names to longer, hopefully non conflicting ones.
Added missing drop table
mysys/hash.c:
Inendation cleanup
mysys/tree.c:
Updated comments
Decrease tree->allocated on delete (for status)
sql/field.cc:
Added safety checking for GIS objects
sql/gstream.cc:
Added copyright message
Made a lot of speed/space optimizations
Changed class names to be MySQL compliant
sql/gstream.h:
Made a lot of speed/space optimizations
Changed class names to be MySQL compliant
sql/item_create.cc:
Indentation fixup
sql/item_geofunc.cc:
Use new gis interface functions and new gis class names.
Simple optimizations
Indentation fixups
Fixed a lot of unlikely but possible errors.
sql/item_geofunc.h:
Moved SRID_SIZE to spatial.h
sql/spatial.cc:
Added copyright message
Made a lot of speed/space optimizations
Changed class names to be MySQL compliant
sql/spatial.h:
Made a lot of speed/space optimizations
Changed class names to be MySQL compliant
Indentation fixes
Use bool instead of int as result type for functions that only return 0 or 1
sql/sql_string.cc:
Simple optimizations
sql/sql_string.h:
Simple cleanups
sql/structs.h:
Added LEX_STRING_WITH_INIT (needed by spatial.cc)
Diffstat (limited to 'sql')
-rw-r--r-- | sql/field.cc | 70 | ||||
-rw-r--r-- | sql/gstream.cc | 174 | ||||
-rw-r--r-- | sql/gstream.h | 40 | ||||
-rw-r--r-- | sql/item_create.cc | 1 | ||||
-rw-r--r-- | sql/item_geofunc.cc | 226 | ||||
-rw-r--r-- | sql/item_geofunc.h | 2 | ||||
-rw-r--r-- | sql/spatial.cc | 1646 | ||||
-rw-r--r-- | sql/spatial.h | 480 | ||||
-rw-r--r-- | sql/sql_string.cc | 16 | ||||
-rw-r--r-- | sql/sql_string.h | 12 | ||||
-rw-r--r-- | sql/structs.h | 12 |
11 files changed, 1359 insertions, 1320 deletions
diff --git a/sql/field.cc b/sql/field.cc index 4632fbc5c69..48e7dbb32ca 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -4715,18 +4715,26 @@ void Field_blob::get_key_image(char *buff,uint length, #ifdef HAVE_SPATIAL if (type == itMBR) { - if (!blob_length) - return; - get_ptr(&blob); - + const char *dummy; MBR mbr; Geometry gobj; + + if (blob_length < SRID_SIZE) + { + bzero(buff, SIZEOF_STORED_DOUBLE*4); + return; + } + get_ptr(&blob); gobj.create_from_wkb(blob + SRID_SIZE, blob_length - SRID_SIZE); - gobj.get_mbr(&mbr); - float8store(buff, mbr.xmin); - float8store(buff+8, mbr.xmax); - float8store(buff+16, mbr.ymin); - float8store(buff+24, mbr.ymax); + if (gobj.get_mbr(&mbr, &dummy)) + bzero(buff, SIZEOF_STORED_DOUBLE*4); + else + { + float8store(buff, mbr.xmin); + float8store(buff+8, mbr.xmax); + float8store(buff+16, mbr.ymin); + float8store(buff+24, mbr.ymax); + } return; } #endif /*HAVE_SPATIAL*/ @@ -4939,6 +4947,7 @@ uint Field_blob::max_packed_col_length(uint max_length) return (max_length > 255 ? 2 : 1)+max_length; } + #ifdef HAVE_SPATIAL void Field_geom::get_key_image(char *buff, uint length, CHARSET_INFO *cs, @@ -4947,17 +4956,26 @@ void Field_geom::get_key_image(char *buff, uint length, CHARSET_INFO *cs, length-= HA_KEY_BLOB_LENGTH; ulong blob_length= get_length(ptr); char *blob; - get_ptr(&blob); - + const char *dummy; MBR mbr; + + if (blob_length < SRID_SIZE) + { + bzero(buff, SIZEOF_STORED_DOUBLE*4); + return; + } + get_ptr(&blob); Geometry gobj; gobj.create_from_wkb(blob + SRID_SIZE, blob_length - SRID_SIZE); - gobj.get_mbr(&mbr); - float8store(buff, mbr.xmin); - float8store(buff + 8, mbr.xmax); - float8store(buff + 16, mbr.ymin); - float8store(buff + 24, mbr.ymax); - return; + if (gobj.get_mbr(&mbr, &dummy)) + bzero(buff, SIZEOF_STORED_DOUBLE*4); + else + { + float8store(buff, mbr.xmin); + float8store(buff + 8, mbr.xmax); + float8store(buff + 16, mbr.ymin); + float8store(buff + 24, mbr.ymax); + } } @@ -5001,16 +5019,16 @@ void Field_geom::sql_type(String &res) const int Field_geom::store(const char *from, uint length, CHARSET_INFO *cs) { if (!length) - { bzero(ptr, Field_blob::pack_length()); - } else { - // Should check given WKB - if (length < 4 + 1 + 4 + 8 + 8) // SRID + WKB_HEADER + X + Y - return 1; - uint32 wkb_type= uint4korr(from + 5); - if (wkb_type < 1 || wkb_type > 7) + // Check given WKB + uint32 wkb_type; + if (length < SRID_SIZE + WKB_HEADER_SIZE + SIZEOF_STORED_DOUBLE*2) + goto err; + wkb_type= uint4korr(from + WKB_HEADER_SIZE); + if (wkb_type < (uint32) Geometry::wkbPoint || + wkb_type > (uint32) Geometry::wkb_end) return 1; Field_blob::store_length(length); if (table->copy_blobs || length <= MAX_FIELD_WIDTH) @@ -5021,6 +5039,10 @@ int Field_geom::store(const char *from, uint length, CHARSET_INFO *cs) bmove(ptr + packlength, (char*) &from, sizeof(char*)); } return 0; + +err: + bzero(ptr, Field_blob::pack_length()); + return 1; } #endif /*HAVE_SPATIAL*/ diff --git a/sql/gstream.cc b/sql/gstream.cc index 17b85af22bd..6b1e12ec733 100644 --- a/sql/gstream.cc +++ b/sql/gstream.cc @@ -1,139 +1,115 @@ +/* Copyright (C) 2004 MySQL 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +/* + Functions to read and parse geometrical data. + NOTE: These functions assumes that the string is end \0 terminated! +*/ + #include "mysql_priv.h" -int GTextReadStream::get_next_toc_type() const +enum Gis_read_stream::enum_tok_types Gis_read_stream::get_next_toc_type() { - const char *cur = m_cur; - while ((*cur)&&(strchr(" \t\r\n",*cur))) - { - cur++; - } - if (!(*cur)) - { + skip_space(); + if (!*m_cur) return eostream; - } - - if (((*cur>='a') && (*cur<='z')) || ((*cur>='A') && (*cur<='Z')) || - (*cur=='_')) - { + if (my_isvar_start(&my_charset_bin, *m_cur)) return word; - } - - if (((*cur>='0') && (*cur<='9')) || (*cur=='-') || (*cur=='+') || - (*cur=='.')) - { + if ((*m_cur >= '0' && *m_cur <= '9') || *m_cur == '-' || *m_cur == '+') return numeric; - } - - if (*cur == '(') - { + if (*m_cur == '(') return l_bra; - } - - if (*cur == ')') - { + if (*m_cur == ')') return r_bra; - } - - if (*cur == ',') - { + if (*m_cur == ',') return comma; - } - return unknown; } -const char *GTextReadStream::get_next_word(int *word_len) -{ - const char *cur = m_cur; - while ((*cur)&&(strchr(" \t\r\n",*cur))) - { - cur++; - } - m_last_text_position = cur; - - if (!(*cur)) - { - return 0; - } - const char *wd_start = cur; - - if (((*cur<'a') || (*cur>'z')) && ((*cur<'A') || (*cur>'Z')) && (*cur!='_')) - { - return NULL; - } +bool Gis_read_stream::get_next_word(LEX_STRING *res) +{ + skip_space(); + res->str= (char*) m_cur; + /* The following will also test for \0 */ + if (!my_isvar_start(&my_charset_bin, *m_cur)) + return 1; - ++cur; + /* + We can't combine the following increment with my_isvar() because + my_isvar() is a macro that would cause side effects + */ + m_cur++; + while (my_isvar(&my_charset_bin, *m_cur)) + m_cur++; - while (((*cur>='a') && (*cur<='z')) || ((*cur>='A') && (*cur<='Z')) || - (*cur=='_') || ((*cur>='0') && (*cur<='9'))) - { - ++cur; - } + res->length= (uint32) (m_cur - res->str); + return 0; +} - *word_len = cur - wd_start; - m_cur = cur; +/* + Read a floating point number - return wd_start; -} + NOTE: Number must start with a digit or sign. It can't start with a decimal + point +*/ -int GTextReadStream::get_next_number(double *d) +bool Gis_read_stream::get_next_number(double *d) { - const char *cur = m_cur; - while ((*cur)&&(strchr(" \t\r\n",*cur))) - { - cur++; - } - - m_last_text_position = cur; - if (!(*cur)) - { - set_error_msg("Numeric constant expected"); - return 1; - } + char *endptr; - if (((*cur<'0') || (*cur>'9')) && (*cur!='-') && (*cur!='+') && (*cur!='.')) + skip_space(); + /* The following will also test for end \0 */ + if ((*m_cur < '0' || *m_cur > '9') && *m_cur != '-' && *m_cur != '+') { set_error_msg("Numeric constant expected"); return 1; } - char *endptr; - - *d = my_strtod(cur, &endptr); - + *d = my_strtod(m_cur, &endptr); if (endptr) - { m_cur = endptr; - } - return 0; } -char GTextReadStream::get_next_symbol() + +bool Gis_read_stream::check_next_symbol(char symbol) { - const char *cur = m_cur; - while ((*cur)&&(strchr(" \t\r\n",*cur))) + skip_space(); + if (*m_cur != symbol) { - cur++; - } - if (!(*cur)) - { - return 0; + char buff[32]; + strmov(buff, "'?' expected"); + buff[2]= symbol; + set_error_msg(buff); + return 1; } + m_cur++; + return 0; +} - m_cur = cur + 1; - m_last_text_position = cur; - return *cur; -} +/* + Remember error message. +*/ -void GTextReadStream::set_error_msg(const char *msg) +void Gis_read_stream::set_error_msg(const char *msg) { - size_t len = strlen(msg); - m_err_msg = (char *)my_realloc(m_err_msg, len + 1, MYF(MY_ALLOW_ZERO_PTR)); + size_t len= strlen(msg); // ok in this context + m_err_msg= (char *) my_realloc(m_err_msg, len + 1, MYF(MY_ALLOW_ZERO_PTR)); memcpy(m_err_msg, msg, len + 1); } - - diff --git a/sql/gstream.h b/sql/gstream.h index a3914a534dd..2e9513d2639 100644 --- a/sql/gstream.h +++ b/sql/gstream.h @@ -15,10 +15,10 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -class GTextReadStream +class Gis_read_stream { public: - enum TokTypes + enum enum_tok_types { unknown, eostream, @@ -29,41 +29,47 @@ public: comma }; - GTextReadStream(const char *buffer, int size) - :m_cur(buffer), m_limit(buffer + size), m_last_text_position(buffer), - m_err_msg(NULL) + Gis_read_stream(const char *buffer, int size) + :m_cur(buffer), m_limit(buffer + size), m_err_msg(NULL) {} - GTextReadStream(): m_cur(NULL), m_limit(NULL), m_err_msg(NULL) + Gis_read_stream(): m_cur(NullS), m_limit(NullS), m_err_msg(NullS) {} - - ~GTextReadStream() + ~Gis_read_stream() { my_free(m_err_msg, MYF(MY_ALLOW_ZERO_PTR)); } - int get_next_toc_type() const; - const char *get_next_word(int *word_len); - int get_next_number(double *d); - char get_next_symbol(); + enum enum_tok_types get_next_toc_type(); + bool get_next_word(LEX_STRING *); + bool get_next_number(double *); + bool check_next_symbol(char); - const char *get_last_text_position() const + inline void skip_space() { - return m_last_text_position; + while (my_isspace(&my_charset_latin1, *m_cur)) + m_cur++; + } + /* Skip next character, if match. Return 1 if no match */ + inline bool skip_char(char skip) + { + skip_space(); + if (*m_cur != skip) + return 1; /* Didn't find char */ + m_cur++; + return 0; } - void set_error_msg(const char *msg); // caller should free this pointer char *get_error_msg() { char *err_msg = m_err_msg; - m_err_msg = NULL; + m_err_msg= NullS; return err_msg; } protected: const char *m_cur; const char *m_limit; - const char *m_last_text_position; char *m_err_msg; }; diff --git a/sql/item_create.cc b/sql/item_create.cc index 4ed8182305d..b013e4747bb 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -455,6 +455,7 @@ Item *create_func_cast(Item *a, Cast_target cast_type, int len, { Item *res; LINT_INIT(res); + switch (cast_type) { case ITEM_CAST_BINARY: res= new Item_func_binary(a); break; case ITEM_CAST_SIGNED_INT: res= new Item_func_signed(a); break; diff --git a/sql/item_geofunc.cc b/sql/item_geofunc.cc index 6934ad9d3b0..cbf286a2101 100644 --- a/sql/item_geofunc.cc +++ b/sql/item_geofunc.cc @@ -27,18 +27,17 @@ #include "sql_acl.h" #include <m_ctype.h> + String *Item_func_geometry_from_text::val_str(String *str) { Geometry geom; String arg_val; String *wkt= args[0]->val_str(&arg_val); - GTextReadStream trs(wkt->ptr(), wkt->length()); - uint32 srid; + Gis_read_stream trs(wkt->c_ptr(), wkt->length()); + uint32 srid= 0; if ((arg_count == 2) && !args[1]->null_value) srid= (uint32)args[1]->val_int(); - else - srid= 0; if (str->reserve(SRID_SIZE, 512)) return 0; @@ -61,22 +60,19 @@ String *Item_func_geometry_from_wkb::val_str(String *str) String arg_val; String *wkb= args[0]->val_str(&arg_val); Geometry geom; - uint32 srid; + uint32 srid= 0; if ((arg_count == 2) && !args[1]->null_value) srid= (uint32)args[1]->val_int(); - else - srid= 0; if (str->reserve(SRID_SIZE, 512)) return 0; str->length(0); str->q_append(srid); if ((null_value= (args[0]->null_value || - geom.create_from_wkb(wkb->ptr(), wkb->length())))) + geom.create_from_wkb(wkb->ptr(), wkb->length()))) || + str->append(*wkb)) return 0; - - str->append(*wkb); return str; } @@ -92,6 +88,7 @@ String *Item_func_as_wkt::val_str(String *str) String arg_val; String *swkb= args[0]->val_str(&arg_val); Geometry geom; + const char *dummy; if ((null_value= (args[0]->null_value || geom.create_from_wkb(swkb->ptr() + SRID_SIZE, @@ -99,18 +96,19 @@ String *Item_func_as_wkt::val_str(String *str) return 0; str->length(0); - - if ((null_value= geom.as_wkt(str))) + if ((null_value= geom.as_wkt(str, &dummy))) return 0; return str; } + void Item_func_as_wkt::fix_length_and_dec() { max_length=MAX_BLOB_WIDTH; } + String *Item_func_as_wkb::val_str(String *str) { String arg_val; @@ -127,11 +125,13 @@ String *Item_func_as_wkb::val_str(String *str) return str; } + void Item_func_as_wkb::fix_length_and_dec() { max_length= MAX_BLOB_WIDTH; } + String *Item_func_geometry_type::val_str(String *str) { String *swkb= args[0]->val_str(str); @@ -141,9 +141,10 @@ String *Item_func_geometry_type::val_str(String *str) geom.create_from_wkb(swkb->ptr() + SRID_SIZE, swkb->length() - SRID_SIZE)))) return 0; - str->copy(geom.get_class_info()->m_name, - strlen(geom.get_class_info()->m_name), - default_charset()); + /* String will not move */ + str->set(geom.get_class_info()->m_name.str, + geom.get_class_info()->m_name.length, + default_charset()); return str; } @@ -153,13 +154,14 @@ String *Item_func_envelope::val_str(String *str) String arg_val; String *swkb= args[0]->val_str(&arg_val); Geometry geom; + uint32 srid; if ((null_value= args[0]->null_value || geom.create_from_wkb(swkb->ptr() + SRID_SIZE, swkb->length() - SRID_SIZE))) return 0; - uint32 srid= uint4korr(swkb->ptr()); + srid= uint4korr(swkb->ptr()); str->length(0); if (str->reserve(SRID_SIZE, 512)) return 0; @@ -173,20 +175,21 @@ String *Item_func_centroid::val_str(String *str) String arg_val; String *swkb= args[0]->val_str(&arg_val); Geometry geom; + uint32 srid; if ((null_value= args[0]->null_value || - geom.create_from_wkb(swkb->ptr() + SRID_SIZE, - swkb->length() - SRID_SIZE) || - !GEOM_METHOD_PRESENT(geom, centroid))) + geom.create_from_wkb(swkb->ptr() + SRID_SIZE, + swkb->length() - SRID_SIZE) || + !GEOM_METHOD_PRESENT(geom, centroid))) return 0; if (str->reserve(SRID_SIZE, 512)) return 0; str->length(0); - uint32 srid= uint4korr(swkb->ptr()); + srid= uint4korr(swkb->ptr()); str->q_append(srid); - return (null_value= geom.centroid(str)) ? 0 : str; + return (null_value= test(geom.centroid(str))) ? 0 : str; } @@ -199,42 +202,42 @@ String *Item_func_spatial_decomp::val_str(String *str) String arg_val; String *swkb= args[0]->val_str(&arg_val); Geometry geom; + uint32 srid; if ((null_value= (args[0]->null_value || geom.create_from_wkb(swkb->ptr() + SRID_SIZE, swkb->length() - SRID_SIZE)))) return 0; - null_value= 1; + srid= uint4korr(swkb->ptr()); if (str->reserve(SRID_SIZE, 512)) - return 0; + goto err; str->length(0); - uint32 srid= uint4korr(swkb->ptr()); str->q_append(srid); - switch(decomp_func) - { + switch (decomp_func) { case SP_STARTPOINT: if (!GEOM_METHOD_PRESENT(geom,start_point) || geom.start_point(str)) - goto ret; + goto err; break; case SP_ENDPOINT: if (!GEOM_METHOD_PRESENT(geom,end_point) || geom.end_point(str)) - goto ret; + goto err; break; case SP_EXTERIORRING: if (!GEOM_METHOD_PRESENT(geom,exterior_ring) || geom.exterior_ring(str)) - goto ret; + goto err; break; default: - goto ret; + goto err; } - null_value= 0; + return str; -ret: - return null_value ? 0 : str; +err: + null_value= 1; + return 0; } @@ -244,43 +247,44 @@ String *Item_func_spatial_decomp_n::val_str(String *str) String *swkb= args[0]->val_str(&arg_val); long n= (long) args[1]->val_int(); Geometry geom; + uint32 srid; if ((null_value= (args[0]->null_value || args[1]->null_value || geom.create_from_wkb(swkb->ptr() + SRID_SIZE, swkb->length() - SRID_SIZE)))) return 0; - null_value= 1; if (str->reserve(SRID_SIZE, 512)) - return 0; + goto err; + srid= uint4korr(swkb->ptr()); str->length(0); - uint32 srid= uint4korr(swkb->ptr()); str->q_append(srid); - switch(decomp_func_n) + switch (decomp_func_n) { case SP_POINTN: if (!GEOM_METHOD_PRESENT(geom,point_n) || geom.point_n(n,str)) - goto ret; + goto err; break; case SP_GEOMETRYN: if (!GEOM_METHOD_PRESENT(geom,geometry_n) || geom.geometry_n(n,str)) - goto ret; + goto err; break; case SP_INTERIORRINGN: if (!GEOM_METHOD_PRESENT(geom,interior_ring_n) || geom.interior_ring_n(n,str)) - goto ret; + goto err; break; default: - goto ret; + goto err; } - null_value= 0; + return str; -ret: - return null_value ? 0 : str; +err: + null_value=1; + return 0; } @@ -299,9 +303,9 @@ String *Item_func_point::val_str(String *str) double x= args[0]->val(); double y= args[1]->val(); - if ( (null_value= (args[0]->null_value || - args[1]->null_value || - str->realloc(1 + 4 + 8 + 8)))) + if ((null_value= (args[0]->null_value || + args[1]->null_value || + str->realloc(1 + 4 + SIZEOF_STORED_DOUBLE*2)))) return 0; str->length(0); @@ -328,11 +332,9 @@ String *Item_func_spatial_collection::val_str(String *str) String arg_value; uint i; - null_value= 1; - str->length(0); if (str->reserve(1 + 4 + 4, 512)) - return 0; + goto err; str->q_append((char) Geometry::wkbNDR); str->q_append((uint32) coll_type); @@ -342,19 +344,16 @@ String *Item_func_spatial_collection::val_str(String *str) { String *res= args[i]->val_str(&arg_value); if (args[i]->null_value) - goto ret; + goto err; - if ( coll_type == Geometry::wkbGeometryCollection ) + if (coll_type == Geometry::wkbGeometryCollection) { /* - In the case of GeometryCollection we don't need - any checkings for item types, so just copy them - into target collection + In the case of GeometryCollection we don't need any checkings + for item types, so just copy them into target collection */ - if ((null_value= str->reserve(res->length(), 512))) - goto ret; - - str->q_append(res->ptr(), res->length()); + if (str->append(res->ptr(), res->length(), (uint32) 512)) + goto err; } else { @@ -363,86 +362,75 @@ String *Item_func_spatial_collection::val_str(String *str) const char *data= res->ptr() + 1; /* - In the case of named collection we must to - check that items are of specific type, let's - do this checking now + In the case of named collection we must to check that items + are of specific type, let's do this checking now */ if (len < 5) - goto ret; + goto err; wkb_type= (Geometry::wkbType) uint4korr(data); data+= 4; len-= 5; if (wkb_type != item_type) - goto ret; + goto err; switch (coll_type) { case Geometry::wkbMultiPoint: case Geometry::wkbMultiLineString: case Geometry::wkbMultiPolygon: - if (len < WKB_HEADER_SIZE) - goto ret; - - data-= WKB_HEADER_SIZE; - len+= WKB_HEADER_SIZE; - if (str->reserve(len, 512)) - goto ret; - str->q_append(data, len); + if (len < WKB_HEADER_SIZE || + str->append(data-WKB_HEADER_SIZE, len+WKB_HEADER_SIZE, 512)) + goto err; break; case Geometry::wkbLineString: - if (str->reserve(POINT_DATA_SIZE, 512)) - goto ret; - str->q_append(data, POINT_DATA_SIZE); + if (str->append(data, POINT_DATA_SIZE, 512)) + goto err; break; - case Geometry::wkbPolygon: { uint32 n_points; double x1, y1, x2, y2; + const char *org_data= data; if (len < 4 + 2 * POINT_DATA_SIZE) - goto ret; - - uint32 llen= len; - const char *ldata= data; + goto err; n_points= uint4korr(data); data+= 4; float8get(x1, data); - data+= 8; + data+= SIZEOF_STORED_DOUBLE; float8get(y1, data); - data+= 8; + data+= SIZEOF_STORED_DOUBLE; data+= (n_points - 2) * POINT_DATA_SIZE; float8get(x2, data); - float8get(y2, data + 8); + float8get(y2, data + SIZEOF_STORED_DOUBLE); - if ((x1 != x2) || (y1 != y2)) - goto ret; - - if (str->reserve(llen, 512)) - goto ret; - str->q_append(ldata, llen); + if ((x1 != x2) || (y1 != y2) || + str->append(org_data, len, 512)) + goto err; } break; default: - goto ret; + goto err; } } } - if (str->length() > current_thd->variables.max_allowed_packet) - goto ret; + goto err; null_value = 0; + return str; -ret: - return null_value ? 0 : str; +err: + null_value= 1; + return 0; } + /* Functions for spatial relations */ @@ -453,6 +441,7 @@ longlong Item_func_spatial_rel::val_int() String *res2= args[1]->val_str(&tmp_value2); Geometry g1, g2; MBR mbr1, mbr2; + const char *dummy; if ((null_value= (args[0]->null_value || args[1]->null_value || @@ -460,12 +449,11 @@ longlong Item_func_spatial_rel::val_int() res1->length() - SRID_SIZE) || g2.create_from_wkb(res2->ptr() + SRID_SIZE, res2->length() - SRID_SIZE) || - g1.get_mbr(&mbr1) || - g2.get_mbr(&mbr2)))) + g1.get_mbr(&mbr1, &dummy) || + g2.get_mbr(&mbr2, &dummy)))) return 0; - switch (spatial_rel) - { + switch (spatial_rel) { case SP_CONTAINS_FUNC: return mbr1.contains(&mbr2); case SP_WITHIN_FUNC: @@ -490,6 +478,7 @@ longlong Item_func_spatial_rel::val_int() return 0; } + longlong Item_func_isempty::val_int() { String tmp; @@ -497,23 +486,25 @@ longlong Item_func_isempty::val_int() return args[0]->null_value ? 1 : 0; } + longlong Item_func_issimple::val_int() { String tmp; String *wkb=args[0]->val_str(&tmp); - if ((null_value= (!wkb || args[0]->null_value ))) + if ((null_value= (!wkb || args[0]->null_value))) return 0; /* TODO: Ramil or Holyfoot, add real IsSimple calculation */ return 0; } + longlong Item_func_isclosed::val_int() { String tmp; String *swkb= args[0]->val_str(&tmp); Geometry geom; - int isclosed; + int isclosed= 0; // In case of error null_value= (!swkb || args[0]->null_value || @@ -529,23 +520,26 @@ longlong Item_func_isclosed::val_int() Numerical functions */ + longlong Item_func_dimension::val_int() { - uint32 dim; + uint32 dim= 0; // In case of error String *swkb= args[0]->val_str(&value); Geometry geom; + const char *dummy; null_value= (!swkb || args[0]->null_value || geom.create_from_wkb(swkb->ptr() + SRID_SIZE, swkb->length() - SRID_SIZE) || - geom.dimension(&dim)); + geom.dimension(&dim, &dummy)); return (longlong) dim; } + longlong Item_func_numinteriorring::val_int() { - uint32 num; + uint32 num= 0; // In case of error String *swkb= args[0]->val_str(&value); Geometry geom; @@ -557,9 +551,10 @@ longlong Item_func_numinteriorring::val_int() return (longlong) num; } + longlong Item_func_numgeometries::val_int() { - uint32 num= 0; + uint32 num= 0; // In case of errors String *swkb= args[0]->val_str(&value); Geometry geom; @@ -571,9 +566,10 @@ longlong Item_func_numgeometries::val_int() return (longlong) num; } + longlong Item_func_numpoints::val_int() { - uint32 num; + uint32 num= 0; // In case of errors String *swkb= args[0]->val_str(&value); Geometry geom; @@ -586,9 +582,10 @@ longlong Item_func_numpoints::val_int() return (longlong) num; } + double Item_func_x::val() { - double res; + double res= 0.0; // In case of errors String *swkb= args[0]->val_str(&value); Geometry geom; @@ -600,9 +597,10 @@ double Item_func_x::val() return res; } + double Item_func_y::val() { - double res; + double res= 0; // In case of errors String *swkb= args[0]->val_str(&value); Geometry geom; @@ -614,23 +612,25 @@ double Item_func_y::val() return res; } + double Item_func_area::val() { - double res; + double res= 0; // In case of errors String *swkb= args[0]->val_str(&value); Geometry geom; + const char *dummy; null_value= (!swkb || geom.create_from_wkb(swkb->ptr() + SRID_SIZE, swkb->length() - SRID_SIZE) || !GEOM_METHOD_PRESENT(geom, area) || - geom.area(&res)); + geom.area(&res, &dummy)); return res; } double Item_func_glength::val() { - double res; + double res= 0; // In case of errors String *swkb= args[0]->val_str(&value); Geometry geom; @@ -650,8 +650,10 @@ longlong Item_func_srid::val_int() null_value= (!swkb || geom.create_from_wkb(swkb->ptr() + SRID_SIZE, swkb->length() - SRID_SIZE)); - uint32 res= uint4korr(swkb->ptr()); - return (longlong) res; + if (null_value) + return 0; + + return (longlong) (uint4korr(swkb->ptr())); } #endif /*HAVE_SPATIAL*/ diff --git a/sql/item_geofunc.h b/sql/item_geofunc.h index 545052807ec..a1f36130152 100644 --- a/sql/item_geofunc.h +++ b/sql/item_geofunc.h @@ -23,8 +23,6 @@ #pragma interface /* gcc class implementation */ #endif -#define SRID_SIZE sizeof(uint32) - class Item_func_geometry_from_text: public Item_str_func { public: diff --git a/sql/spatial.cc b/sql/spatial.cc index d19429fdd9c..908fe6b8af4 100644 --- a/sql/spatial.cc +++ b/sql/spatial.cc @@ -1,9 +1,23 @@ -#include "mysql_priv.h" +/* Copyright (C) 2004 MySQL 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include "mysql_priv.h" #define MAX_DIGITS_IN_DOUBLE 16 -/***************************** GClassInfo *******************************/ +/***************************** Gis_class_info *******************************/ #define IMPLEMENT_GEOM(class_name, type_id, name) \ { \ @@ -14,12 +28,12 @@ (GF_GetD) &class_name::get_x, \ (GF_GetD) &class_name::get_y, \ (GF_GetD) &class_name::length, \ - (GF_GetD) &class_name::area, \ + (GF_GetD_AND_END) &class_name::area, \ (GF_GetI) &class_name::is_closed, \ (GF_GetUI) &class_name::num_interior_ring, \ (GF_GetUI) &class_name::num_points, \ (GF_GetUI) &class_name::num_geometries, \ - (GF_GetUI) &class_name::dimension, \ + (GF_GetUI_AND_END) &class_name::dimension, \ (GF_GetWS) &class_name::start_point, \ (GF_GetWS) &class_name::end_point, \ (GF_GetWS) &class_name::exterior_ring, \ @@ -27,54 +41,63 @@ (GF_GetUIWS) &class_name::point_n, \ (GF_GetUIWS) &class_name::interior_ring_n, \ (GF_GetUIWS) &class_name::geometry_n, \ - class_name::type_id, \ name, \ + class_name::type_id, \ NULL \ -}, +} + +static LEX_STRING_WITH_INIT point_name("POINT", 5); +static LEX_STRING_WITH_INIT linestring_name("LINESTRING", 10); +static LEX_STRING_WITH_INIT polygon_name("POLYGON",7); +static LEX_STRING_WITH_INIT multipoint_name("MULTIPOINT",10); +static LEX_STRING_WITH_INIT multilinestring_name("MULTILINESTRING",15); +static LEX_STRING_WITH_INIT multipolygon_name("MULTIPOLYGON",12); +static LEX_STRING_WITH_INIT geometrycollection_name("GEOMETRYCOLLECTION",18); -static Geometry::GClassInfo ci_collection[] = +static Geometry::Gis_class_info ci_collection[]= { - IMPLEMENT_GEOM(GPoint, wkbPoint, "POINT") - IMPLEMENT_GEOM(GLineString, wkbLineString, "LINESTRING") - IMPLEMENT_GEOM(GPolygon, wkbPolygon, "POLYGON") - IMPLEMENT_GEOM(GMultiPoint, wkbMultiPoint, "MULTIPOINT") - IMPLEMENT_GEOM(GMultiLineString, wkbMultiLineString, "MULTILINESTRING") - IMPLEMENT_GEOM(GMultiPolygon, wkbMultiPolygon, "MULTIPOLYGON") - IMPLEMENT_GEOM(GGeometryCollection, wkbGeometryCollection, "GEOMETRYCOLLECTION") + IMPLEMENT_GEOM(Gis_point, wkbPoint, point_name), + IMPLEMENT_GEOM(Gis_line_string, wkbLineString, linestring_name), + IMPLEMENT_GEOM(Gis_polygon, wkbPolygon, polygon_name), + IMPLEMENT_GEOM(Gis_multi_point, wkbMultiPoint, multipoint_name), + IMPLEMENT_GEOM(Gis_multi_line_stringg, wkbMultiLineString, multilinestring_name), + IMPLEMENT_GEOM(Gis_multi_polygon, wkbMultiPolygon, multipolygon_name), + IMPLEMENT_GEOM(Gis_geometry_collection, wkbGeometryCollection, + geometrycollection_name) }; -static Geometry::GClassInfo *ci_collection_end = ci_collection + sizeof(ci_collection)/sizeof(ci_collection[0]); +static Geometry::Gis_class_info *ci_collection_end= +(ci_collection + array_elements(ci_collection)); + /***************************** Geometry *******************************/ -Geometry::GClassInfo *Geometry::find_class(int type_id) +Geometry::Gis_class_info *Geometry::find_class(int type_id) { - for (GClassInfo *cur_rt = ci_collection; cur_rt < ci_collection_end; ++cur_rt) + for (Gis_class_info *cur_rt= ci_collection; cur_rt < ci_collection_end; cur_rt++) { if (cur_rt->m_type_id == type_id) - { return cur_rt; - } } - return NULL; + return 0; } -Geometry::GClassInfo *Geometry::find_class(const char *name, size_t len) + +Geometry::Gis_class_info *Geometry::find_class(const char *name, uint32 len) { - for (GClassInfo *cur_rt = ci_collection; - cur_rt < ci_collection_end; ++cur_rt) + for (Gis_class_info *cur_rt= ci_collection; cur_rt < ci_collection_end; cur_rt++) { - if ((cur_rt->m_name[len] == 0) && - (my_strnncoll(&my_charset_latin1, (const uchar*)cur_rt->m_name, len, - (const uchar*)name, len) == 0)) - { + if ((cur_rt->m_name.length == len) && + (my_strnncoll(&my_charset_latin1, + (const uchar*) cur_rt->m_name.str, len, + (const uchar*) name, len) == 0)) return cur_rt; - } } - return NULL; + return 0; } + int Geometry::create_from_wkb(const char *data, uint32 data_len) { uint32 geom_type; @@ -82,43 +105,39 @@ int Geometry::create_from_wkb(const char *data, uint32 data_len) if (data_len < 1 + 4) return 1; data++; -//FIXME: check byte ordering + /* + FIXME: check byte ordering + Also check if we could replace this with one byte + */ geom_type= uint4korr(data); data+= 4; - m_vmt= find_class(geom_type); - if (!m_vmt) - return -1; + if (!(m_vmt= find_class((int) geom_type))) + return 1; m_data= data; m_data_end= data + data_len; return 0; } -int Geometry::create_from_wkt(GTextReadStream *trs, String *wkt, int init_stream) + +int Geometry::create_from_wkt(Gis_read_stream *trs, String *wkt, + bool init_stream) { - int name_len; - const char *name = trs->get_next_word(&name_len); - if (!name) + LEX_STRING name; + + if (trs->get_next_word(&name)) { trs->set_error_msg("Geometry name expected"); - return -1; - } - if (!(m_vmt = find_class(name, name_len))) - return -1; - if (wkt->reserve(1 + 4, 512)) return 1; - wkt->q_append((char)wkbNDR); - wkt->q_append((uint32)get_class_info()->m_type_id); - if (trs->get_next_symbol() != '(') - { - trs->set_error_msg("'(' expected"); - return -1; } - if (init_from_wkt(trs, wkt)) return 1; - if (trs->get_next_symbol() != ')') - { - trs->set_error_msg("')' expected"); - return -1; - } + if (!(m_vmt= find_class(name.str, name.length)) || + wkt->reserve(1 + 4, 512)) + return 1; + wkt->q_append((char) wkbNDR); + wkt->q_append((uint32) get_class_info()->m_type_id); + if (trs->check_next_symbol('(') || + init_from_wkt(trs, wkt) || + trs->check_next_symbol(')')) + return 1; if (init_stream) { init_from_wkb(wkt->ptr(), wkt->length()); @@ -127,19 +146,19 @@ int Geometry::create_from_wkt(GTextReadStream *trs, String *wkt, int init_stream return 0; } -int Geometry::envelope(String *result) const + +bool Geometry::envelope(String *result) const { MBR mbr; + const char *end; - get_mbr(&mbr); - - if (result->reserve(1+4*3+sizeof(double)*10)) + if (get_mbr(&mbr, &end) || result->reserve(1+4*3+SIZEOF_STORED_DOUBLE*10)) return 1; - result->q_append((char)wkbNDR); - result->q_append((uint32)wkbPolygon); - result->q_append((uint32)1); - result->q_append((uint32)5); + result->q_append((char) wkbNDR); + result->q_append((uint32) wkbPolygon); + result->q_append((uint32) 1); + result->q_append((uint32) 5); result->q_append(mbr.xmin); result->q_append(mbr.ymin); result->q_append(mbr.xmax); @@ -154,29 +173,151 @@ int Geometry::envelope(String *result) const return 0; } + +/* + Create a point from data. + + SYNPOSIS + create_point() + result Put result here + data Data for point is here. + + RETURN + 0 ok + 1 Can't reallocate 'result' +*/ + +bool Geometry::create_point(String *result, const char *data) +{ + if (no_data(data, SIZEOF_STORED_DOUBLE * 2) || + result->reserve(1 + 4 + SIZEOF_STORED_DOUBLE * 2)) + return 1; + result->q_append((char) wkbNDR); + result->q_append((uint32) wkbPoint); + /* Copy two double in same format */ + result->q_append(data, SIZEOF_STORED_DOUBLE*2); + return 0; +} + +/* + Create a point from coordinates. + + SYNPOSIS + create_point() + result Put result here + x x coordinate for point + y y coordinate for point + + RETURN + 0 ok + 1 Can't reallocate 'result' +*/ + +bool Geometry::create_point(String *result, double x, double y) +{ + if (result->reserve(1 + 4 + SIZEOF_STORED_DOUBLE * 2)) + return 1; + + result->q_append((char) wkbNDR); + result->q_append((uint32) wkbPoint); + result->q_append(x); + result->q_append(y); + return 0; +} + +/* + Append N points from packed format to text + + SYNOPSIS + append_points() + txt Append points here + n_points Number of points + data Packed data + offset Offset between points + + RETURN + # end of data +*/ + +const char *Geometry::append_points(String *txt, uint32 n_points, + const char *data, uint32 offset) +{ + while (n_points--) + { + double d; + data+= offset; + float8get(d, data); + txt->qs_append(d); + txt->qs_append(' '); + float8get(d, data + SIZEOF_STORED_DOUBLE); + data+= SIZEOF_STORED_DOUBLE * 2; + txt->qs_append(d); + txt->qs_append(','); + } + return data; +} + + +/* + Get most bounding rectangle (mbr) for X points + + SYNOPSIS + get_mbr_for_points() + mbr MBR (store rectangle here) + points Number of points + data Packed data + offset Offset between points + + RETURN + 0 Wrong data + # end of data +*/ + +const char *Geometry::get_mbr_for_points(MBR *mbr, const char *data, + uint offset) const +{ + uint32 points; + /* read number of points */ + if (no_data(data, 4)) + return 0; + points= uint4korr(data); + data+= 4; + + if (no_data(data, (SIZEOF_STORED_DOUBLE * 2 + offset) * points)) + return 0; + + /* Calculate MBR for points */ + while (points--) + { + data+= offset; + mbr->add_xy(data, data + SIZEOF_STORED_DOUBLE); + data+= SIZEOF_STORED_DOUBLE * 2; + } + return data; +} + + /***************************** Point *******************************/ -size_t GPoint::get_data_size() const +uint32 Gis_point::get_data_size() const { return POINT_DATA_SIZE; } -int GPoint::init_from_wkt(GTextReadStream *trs, String *wkb) + +bool Gis_point::init_from_wkt(Gis_read_stream *trs, String *wkb) { double x, y; - if (wkb->reserve(sizeof(double)*2)) - return 1; - if (trs->get_next_number(&x)) - return 1; - if (trs->get_next_number(&y)) + if (trs->get_next_number(&x) || trs->get_next_number(&y) || + wkb->reserve(SIZEOF_STORED_DOUBLE * 2)) return 1; wkb->q_append(x); wkb->q_append(y); - return 0; } -int GPoint::get_data_as_wkt(String *txt) const + +bool Gis_point::get_data_as_wkt(String *txt, const char **end) { double x, y; if (get_xy(&x, &y)) @@ -186,324 +327,250 @@ int GPoint::get_data_as_wkt(String *txt) const txt->qs_append(x); txt->qs_append(' '); txt->qs_append(y); + *end= m_data+ POINT_DATA_SIZE; return 0; } -int GPoint::get_mbr(MBR *mbr) const + +int Gis_point::get_mbr(MBR *mbr, const char **end) const { double x, y; if (get_xy(&x, &y)) return 1; mbr->add_xy(x, y); + *end= m_data+ POINT_DATA_SIZE; return 0; } + /***************************** LineString *******************************/ -size_t GLineString::get_data_size() const +uint32 Gis_line_string::get_data_size() const { - uint32 n_points = uint4korr(m_data); - - return 4 + n_points*POINT_DATA_SIZE; + if (no_data(m_data, 4)) + return GET_SIZE_ERROR; + return 4 + uint4korr(m_data) * POINT_DATA_SIZE; } -int GLineString::init_from_wkt(GTextReadStream *trs, String *wkb) + +bool Gis_line_string::init_from_wkt(Gis_read_stream *trs, String *wkb) { - uint32 n_points = 0; - int np_pos = wkb->length(); - GPoint p; + uint32 n_points= 0; + uint32 np_pos= wkb->length(); + Gis_point p; if (wkb->reserve(4, 512)) return 1; - - wkb->q_append((uint32)n_points); + wkb->length(wkb->length()+4); // Reserve space for points for (;;) { if (p.init_from_wkt(trs, wkb)) return 1; - ++n_points; - if (trs->get_next_toc_type() == GTextReadStream::comma) - trs->get_next_symbol(); - else break; + n_points++; + if (trs->skip_char(',')) // Didn't find ',' + break; } - - if (n_points<2) + if (n_points < 2) { trs->set_error_msg("Too few points in LINESTRING"); return 1; } - - wkb->WriteAtPosition(np_pos, n_points); - + wkb->write_at_position(np_pos, n_points); return 0; } -int GLineString::get_data_as_wkt(String *txt) const + +bool Gis_line_string::get_data_as_wkt(String *txt, const char **end) { uint32 n_points; - const char *data = m_data; + const char *data= m_data; if (no_data(data, 4)) return 1; - - n_points = uint4korr(data); + n_points= uint4korr(data); data += 4; - if (no_data(data, sizeof(double) * 2 * n_points)) + if (n_points < 1 || + no_data(data, SIZEOF_STORED_DOUBLE * 2 * n_points) || + txt->reserve(((MAX_DIGITS_IN_DOUBLE + 1)*2 + 1) * n_points)) return 1; - if (txt->reserve(((MAX_DIGITS_IN_DOUBLE + 1)*2 + 1) * n_points)) - return 1; - for (; n_points>0; --n_points) + while (n_points--) { double x, y; float8get(x, data); - data += sizeof(double); - float8get(y, data); - data += sizeof(double); + float8get(y, data + SIZEOF_STORED_DOUBLE); + data+= SIZEOF_STORED_DOUBLE * 2; txt->qs_append(x); txt->qs_append(' '); txt->qs_append(y); txt->qs_append(','); } - txt->length(txt->length() - 1); + txt->length(txt->length() - 1); // Remove end ',' + *end= data; return 0; } -int GLineString::get_mbr(MBR *mbr) const -{ - uint32 n_points; - const char *data = m_data; - - if (no_data(data, 4)) - return 1; - - n_points = uint4korr(data); - data += 4; - - if (no_data(data, sizeof(double) * 2 * n_points)) - return 1; - for (; n_points>0; --n_points) - { - mbr->add_xy(data, data + 8); - data += 8+8; - } - return 0; +bool Gis_line_string::get_mbr(MBR *mbr, const char **end) const +{ + return (*end=get_mbr_for_points(mbr, m_data, 0)) == 0; } -int GLineString::length(double *len) const + +bool Gis_line_string::length(double *len) const { uint32 n_points; double prev_x, prev_y; - const char *data = m_data; + const char *data= m_data; - *len=0; + *len= 0; // In case of errors if (no_data(data, 4)) return 1; - n_points = uint4korr(data); - data += 4; - - if (no_data(data, sizeof(double) * 2 * n_points)) + n_points= uint4korr(data); + data+= 4; + if (n_points < 1 || no_data(data, SIZEOF_STORED_DOUBLE * 2 * n_points)) return 1; - --n_points; float8get(prev_x, data); - data += 8; - float8get(prev_y, data); - data += 8; + float8get(prev_y, data + SIZEOF_STORED_DOUBLE); + data+= SIZEOF_STORED_DOUBLE*2; - for (; n_points>0; --n_points) + while (--n_points) { double x, y; float8get(x, data); - data += 8; - float8get(y, data); - data += 8; - *len+=sqrt(pow(prev_x-x,2)+pow(prev_y-y,2)); - prev_x=x; - prev_y=y; + float8get(y, data + SIZEOF_STORED_DOUBLE); + data+= SIZEOF_STORED_DOUBLE * 2; + *len+= sqrt(pow(prev_x-x,2)+pow(prev_y-y,2)); + prev_x= x; + prev_y= y; } return 0; } -int GLineString::is_closed(int *closed) const +bool Gis_line_string::is_closed(int *closed) const { uint32 n_points; double x1, y1, x2, y2; - - const char *data = m_data; + const char *data= m_data; if (no_data(data, 4)) return 1; - n_points = uint4korr(data); - data += 4; - if (no_data(data, (8+8) * n_points)) + n_points= uint4korr(data); + data+= 4; + if (no_data(data, SIZEOF_STORED_DOUBLE * 2 * n_points)) return 1; + + /* Get first point */ float8get(x1, data); - data += 8; - float8get(y1, data); - data += 8 + (n_points-2)*POINT_DATA_SIZE; - float8get(x2, data); - data += 8; - float8get(y2, data); + float8get(y1, data + SIZEOF_STORED_DOUBLE); - *closed=(x1==x2)&&(y1==y2); + /* get last point */ + data+= SIZEOF_STORED_DOUBLE*2 + (n_points-2)*POINT_DATA_SIZE; + float8get(x2, data); + float8get(y2, data + SIZEOF_STORED_DOUBLE); + *closed= (x1==x2) && (y1==y2); return 0; } -int GLineString::num_points(uint32 *n_points) const + +bool Gis_line_string::num_points(uint32 *n_points) const { - *n_points = uint4korr(m_data); + *n_points= uint4korr(m_data); return 0; } -int GLineString::start_point(String *result) const -{ - const char *data= m_data + 4; - if (no_data(data, 8 + 8)) - return 1; - - if (result->reserve(1 + 4 + sizeof(double) * 2)) - return 1; - - result->q_append((char) wkbNDR); - result->q_append((uint32) wkbPoint); - double d; - float8get(d, data); - result->q_append(d); - float8get(d, data + 8); - result->q_append(d); - return 0; +bool Gis_line_string::start_point(String *result) +{ + /* +4 is for skipping over number of points */ + return create_point(result, m_data + 4); } -int GLineString::end_point(String *result) const + +bool Gis_line_string::end_point(String *result) { - const char *data= m_data; uint32 n_points; - - if (no_data(data, 4)) + if (no_data(m_data, 4)) return 1; - n_points= uint4korr(data); - - data+= 4 + (n_points - 1) * POINT_DATA_SIZE; - - if (no_data(data, 8 + 8)) - return 1; - - if (result->reserve(1 + 4 + sizeof(double) * 2)) - return 1; - result->q_append((char) wkbNDR); - result->q_append((uint32) wkbPoint); - double d; - float8get(d, data); - result->q_append(d); - float8get(d, data + 8); - result->q_append(d); - - return 0; + n_points= uint4korr(m_data); + return create_point(result, m_data + 4 + (n_points - 1) * POINT_DATA_SIZE); } -int GLineString::point_n(uint32 num, String *result) const +bool Gis_line_string::point_n(uint32 num, String *result) { - const char *data= m_data; uint32 n_points; - - if (no_data(data, 4)) + if (no_data(m_data, 4)) return 1; - n_points= uint4korr(data); - + n_points= uint4korr(m_data); if ((uint32) (num - 1) >= n_points) // means (num > n_points || num < 1) return 1; - data+= 4 + (num - 1) * POINT_DATA_SIZE; - - if (no_data(data, 8 + 8)) - return 1; - if (result->reserve(1 + 4 + sizeof(double) * 2)) - return 1; - - result->q_append((char) wkbNDR); - result->q_append((uint32) wkbPoint); - double d; - float8get(d, data); - result->q_append(d); - float8get(d, data + 8); - result->q_append(d); - - return 0; + return create_point(result, m_data + 4 + (num - 1) * POINT_DATA_SIZE); } + /***************************** Polygon *******************************/ -size_t GPolygon::get_data_size() const +uint32 Gis_polygon::get_data_size() const { - uint32 n_linear_rings = 0; - const char *data = m_data; + uint32 n_linear_rings; + const char *data= m_data; + if (no_data(data, 4)) - return 1; + return GET_SIZE_ERROR; + n_linear_rings= uint4korr(data); + data+= 4; - n_linear_rings = uint4korr(data); - data += 4; - for (; n_linear_rings>0; --n_linear_rings) + while (n_linear_rings--) { if (no_data(data, 4)) - return 1; - data += 4 + uint4korr(data)*POINT_DATA_SIZE; + return GET_SIZE_ERROR; + data+= 4 + uint4korr(data)*POINT_DATA_SIZE; } - return data - m_data; + return (uint32) (data - m_data); } -int GPolygon::init_from_wkt(GTextReadStream *trs, String *wkb) + +bool Gis_polygon::init_from_wkt(Gis_read_stream *trs, String *wkb) { - uint32 n_linear_rings = 0; - int lr_pos = wkb->length(); + uint32 n_linear_rings= 0; + uint32 lr_pos= wkb->length(); + int closed; if (wkb->reserve(4, 512)) return 1; - - wkb->q_append((uint32)n_linear_rings); - + wkb->length(wkb->length()+4); // Reserve space for points for (;;) { - GLineString ls; - size_t ls_pos=wkb->length(); - if (trs->get_next_symbol() != '(') - { - trs->set_error_msg("'(' expected"); - return 1; - } - if (ls.init_from_wkt(trs, wkb)) - return 1; - if (trs->get_next_symbol() != ')') - { - trs->set_error_msg("')' expected"); + Gis_line_string ls; + uint32 ls_pos=wkb->length(); + if (trs->check_next_symbol('(') || + ls.init_from_wkt(trs, wkb) || + trs->check_next_symbol(')')) return 1; - } + ls.init_from_wkb(wkb->ptr()+ls_pos, wkb->length()-ls_pos); - int closed; - ls.is_closed(&closed); - if (!closed) + if (ls.is_closed(&closed) || !closed) { trs->set_error_msg("POLYGON's linear ring isn't closed"); return 1; } - ++n_linear_rings; - if (trs->get_next_toc_type() == GTextReadStream::comma) - trs->get_next_symbol(); - else + n_linear_rings++; + if (trs->skip_char(',')) // Didn't find ',' break; } - wkb->WriteAtPosition(lr_pos, n_linear_rings); + wkb->write_at_position(lr_pos, n_linear_rings); return 0; } -int GPolygon::get_data_as_wkt(String *txt) const + +bool Gis_polygon::get_data_as_wkt(String *txt, const char **end) { uint32 n_linear_rings; const char *data= m_data; @@ -514,1059 +581,1012 @@ int GPolygon::get_data_as_wkt(String *txt) const n_linear_rings= uint4korr(data); data+= 4; - for (; n_linear_rings > 0; --n_linear_rings) + while (n_linear_rings--) { + uint32 n_points; if (no_data(data, 4)) return 1; - uint32 n_points= uint4korr(data); + n_points= uint4korr(data); data+= 4; - if (no_data(data, (8 + 8) * n_points)) - return 1; - - if (txt->reserve(2 + ((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points)) + if (no_data(data, (SIZEOF_STORED_DOUBLE*2) * n_points) || + txt->reserve(2 + ((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points)) return 1; txt->qs_append('('); - for (; n_points>0; --n_points) - { - double d; - float8get(d, data); - txt->qs_append(d); - txt->qs_append(' '); - float8get(d, data + 8); - txt->qs_append(d); - txt->qs_append(','); - - data+= 8 + 8; - } - (*txt) [txt->length() - 1]= ')'; + data= append_points(txt, n_points, data, 0); + (*txt) [txt->length() - 1]= ')'; // Replace end ',' txt->qs_append(','); } - txt->length(txt->length() - 1); + txt->length(txt->length() - 1); // Remove end ',' + *end= data; return 0; } -int GPolygon::get_mbr(MBR *mbr) const + +bool Gis_polygon::get_mbr(MBR *mbr, const char **end) const { uint32 n_linear_rings; + const char *data= m_data; - const char *data = m_data; if (no_data(data, 4)) return 1; - n_linear_rings = uint4korr(data); - data += 4; - for (; n_linear_rings>0; --n_linear_rings) + n_linear_rings= uint4korr(data); + data+= 4; + + while (n_linear_rings--) { - if (no_data(data, 4)) + if (!(data= get_mbr_for_points(mbr, data, 0))) return 1; - uint32 n_points = uint4korr(data); - data += 4; - if (no_data(data, (8+8) * n_points)) - return 1; - for (; n_points>0; --n_points) - { - mbr->add_xy(data, data + 8); - data += 8+8; - } } + *end= data; return 0; } -int GPolygon::area(double *ar) const + +bool Gis_polygon::area(double *ar, const char **end_of_data) const { uint32 n_linear_rings; - double result = -1.0; + double result= -1.0; + const char *data= m_data; - const char *data = m_data; if (no_data(data, 4)) return 1; - n_linear_rings = uint4korr(data); - data += 4; - for (; n_linear_rings>0; --n_linear_rings) + n_linear_rings= uint4korr(data); + data+= 4; + + while (n_linear_rings--) { double prev_x, prev_y; - double lr_area=0; + double lr_area= 0; + uint32 n_points; + if (no_data(data, 4)) return 1; - uint32 n_points = uint4korr(data); - if (no_data(data, (8+8) * n_points)) + n_points= uint4korr(data); + if (no_data(data, (SIZEOF_STORED_DOUBLE*2) * n_points)) return 1; float8get(prev_x, data+4); - float8get(prev_y, data+(4+8)); - data += (4+8+8); + float8get(prev_y, data+(4+SIZEOF_STORED_DOUBLE)); + data+= (4+SIZEOF_STORED_DOUBLE*2); - --n_points; - for (; n_points>0; --n_points) + while (--n_points) // One point is already read { double x, y; float8get(x, data); - float8get(y, data + 8); - lr_area+=(prev_x+x)*(prev_y-y); - prev_x=x; - prev_y=y; - data += (8+8); + float8get(y, data + SIZEOF_STORED_DOUBLE); + data+= (SIZEOF_STORED_DOUBLE*2); + /* QQ: Is the following prev_x+x right ? */ + lr_area+= (prev_x + x)* (prev_y - y); + prev_x= x; + prev_y= y; } - lr_area=fabs(lr_area)/2; - if (result==-1) result=lr_area; - else result-=lr_area; + lr_area= fabs(lr_area)/2; + if (result == -1.0) + result= lr_area; + else + result-= lr_area; } - *ar=fabs(result); + *ar= fabs(result); + *end_of_data= data; return 0; } -int GPolygon::exterior_ring(String *result) const +bool Gis_polygon::exterior_ring(String *result) { - uint32 n_points; - const char *data = m_data + 4; // skip n_linerings + uint32 n_points, length; + const char *data= m_data + 4; // skip n_linerings if (no_data(data, 4)) return 1; - n_points = uint4korr(data); - data += 4; - if (no_data(data, n_points * POINT_DATA_SIZE)) - return 1; - - if (result->reserve(1+4+4+ n_points * POINT_DATA_SIZE)) + n_points= uint4korr(data); + data+= 4; + length= n_points * POINT_DATA_SIZE; + if (no_data(data, length) || result->reserve(1+4+4+ length)) return 1; - result->q_append((char)wkbNDR); - result->q_append((uint32)wkbLineString); + result->q_append((char) wkbNDR); + result->q_append((uint32) wkbLineString); result->q_append(n_points); result->q_append(data, n_points * POINT_DATA_SIZE); - return 0; } -int GPolygon::num_interior_ring(uint32 *n_int_rings) const + +bool Gis_polygon::num_interior_ring(uint32 *n_int_rings) const { - const char *data = m_data; - if (no_data(data, 4)) + if (no_data(m_data, 4)) return 1; - *n_int_rings = uint4korr(data); - --(*n_int_rings); - + *n_int_rings= uint4korr(m_data)-1; return 0; } -int GPolygon::interior_ring_n(uint32 num, String *result) const + +bool Gis_polygon::interior_ring_n(uint32 num, String *result) const { - const char *data = m_data; + const char *data= m_data; uint32 n_linear_rings; uint32 n_points; + uint32 points_size; if (no_data(data, 4)) return 1; + n_linear_rings= uint4korr(data); + data+= 4; - n_linear_rings = uint4korr(data); - data += 4; - if ((num >= n_linear_rings) || (num < 1)) - return -1; + if (num >= n_linear_rings || num < 1) + return 1; - for (; num > 0; --num) + while (num--) { if (no_data(data, 4)) return 1; - data += 4 + uint4korr(data) * POINT_DATA_SIZE; + data+= 4 + uint4korr(data) * POINT_DATA_SIZE; } if (no_data(data, 4)) return 1; - n_points = uint4korr(data); - int points_size = n_points * POINT_DATA_SIZE; - data += 4; - if (no_data(data, points_size)) - return 1; - - if (result->reserve(1+4+4+ points_size)) + 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)) return 1; - result->q_append((char)wkbNDR); - result->q_append((uint32)wkbLineString); + result->q_append((char) wkbNDR); + result->q_append((uint32) wkbLineString); result->q_append(n_points); result->q_append(data, points_size); return 0; } -int GPolygon::centroid_xy(double *x, double *y) const + +bool Gis_polygon::centroid_xy(double *x, double *y) const { uint32 n_linear_rings; - uint32 i; double res_area, res_cx, res_cy; - const char *data = m_data; + const char *data= m_data; + bool first_loop= 1; LINT_INIT(res_area); LINT_INIT(res_cx); LINT_INIT(res_cy); if (no_data(data, 4)) return 1; - n_linear_rings = uint4korr(data); - data += 4; + n_linear_rings= uint4korr(data); + data+= 4; - for (i = 0; i < n_linear_rings; ++i) + while (n_linear_rings--) { - if (no_data(data, 4)) - return 1; - uint32 n_points = uint4korr(data); + uint32 n_points, org_n_points; double prev_x, prev_y; - double cur_area = 0; - double cur_cx = 0; - double cur_cy = 0; + double cur_area= 0; + double cur_cx= 0; + double cur_cy= 0; - data += 4; - if (no_data(data, (8+8) * n_points)) + if (no_data(data, 4)) + return 1; + org_n_points= n_points= uint4korr(data); + data+= 4; + if (no_data(data, (SIZEOF_STORED_DOUBLE*2) * n_points)) return 1; float8get(prev_x, data); - float8get(prev_y, data+8); - data += (8+8); + float8get(prev_y, data+SIZEOF_STORED_DOUBLE); + data+= (SIZEOF_STORED_DOUBLE*2); - uint32 n = n_points - 1; - for (; n > 0; --n) + while (--n_points) // One point is already read { double x, y; float8get(x, data); - float8get(y, data + 8); - - cur_area += (prev_x + x) * (prev_y - y); - cur_cx += x; - cur_cy += y; - prev_x = x; - prev_y = y; - data += (8+8); + float8get(y, data + SIZEOF_STORED_DOUBLE); + data+= (SIZEOF_STORED_DOUBLE*2); + /* QQ: Is the following prev_x+x right ? */ + cur_area+= (prev_x + x) * (prev_y - y); + cur_cx+= x; + cur_cy+= y; + prev_x= x; + prev_y= y; } - cur_area = fabs(cur_area) / 2; - cur_cx = cur_cx / (n_points - 1); - cur_cy = cur_cy / (n_points - 1); + cur_area= fabs(cur_area) / 2; + cur_cx= cur_cx / (org_n_points - 1); + cur_cy= cur_cy / (org_n_points - 1); - if (i) + if (!first_loop) { - double d_area = res_area - cur_area; + double d_area= res_area - cur_area; if (d_area <= 0) return 1; - res_cx = (res_area * res_cx - cur_area * cur_cx) / d_area; - res_cy = (res_area * res_cy - cur_area * cur_cy) / d_area; + res_cx= (res_area * res_cx - cur_area * cur_cx) / d_area; + res_cy= (res_area * res_cy - cur_area * cur_cy) / d_area; } else { - res_area = cur_area; - res_cx = cur_cx; - res_cy = cur_cy; + first_loop= 0; + res_area= cur_area; + res_cx= cur_cx; + res_cy= cur_cy; } } - *x = res_cx; - *y = res_cy; - + *x= res_cx; + *y= res_cy; return 0; } -int GPolygon::centroid(String *result) const + +bool Gis_polygon::centroid(String *result) { double x, y; - - this->centroid_xy(&x, &y); - if (result->reserve(1 + 4 + sizeof(double) * 2)) + if (centroid_xy(&x, &y)) return 1; - - result->q_append((char)wkbNDR); - result->q_append((uint32)wkbPoint); - result->q_append(x); - result->q_append(y); - - return 0; + return create_point(result, x, y); } /***************************** MultiPoint *******************************/ -size_t GMultiPoint::get_data_size() const +uint32 Gis_multi_point::get_data_size() const { + if (no_data(m_data, 4)) + return GET_SIZE_ERROR; return 4 + uint4korr(m_data)*(POINT_DATA_SIZE + WKB_HEADER_SIZE); } -int GMultiPoint::init_from_wkt(GTextReadStream *trs, String *wkb) + +bool Gis_multi_point::init_from_wkt(Gis_read_stream *trs, String *wkb) { - uint32 n_points = 0; - int np_pos = wkb->length(); - GPoint p; + uint32 n_points= 0; + uint32 np_pos= wkb->length(); + Gis_point p; if (wkb->reserve(4, 512)) return 1; - wkb->q_append((uint32)n_points); + wkb->length(wkb->length()+4); // Reserve space for points for (;;) { if (wkb->reserve(1+4, 512)) return 1; - wkb->q_append((char)wkbNDR); - wkb->q_append((uint32)wkbPoint); + wkb->q_append((char) wkbNDR); + wkb->q_append((uint32) wkbPoint); if (p.init_from_wkt(trs, wkb)) return 1; - ++n_points; - if (trs->get_next_toc_type() == GTextReadStream::comma) - trs->get_next_symbol(); - else + n_points++; + if (trs->skip_char(',')) // Didn't find ',' break; } - wkb->WriteAtPosition(np_pos, n_points); - + wkb->write_at_position(np_pos, n_points); // Store number of found points return 0; } -int GMultiPoint::get_data_as_wkt(String *txt) const + +bool Gis_multi_point::get_data_as_wkt(String *txt, const char **end) { uint32 n_points; - const char *data= m_data; - if (no_data(data, 4)) - return 1; - - n_points= uint4korr(data); - data+= 4; - if (no_data(data, n_points * (8 + 8 + WKB_HEADER_SIZE))) + if (no_data(m_data, 4)) return 1; - if (txt->reserve(((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points)) + n_points= uint4korr(m_data); + if (no_data(m_data+4, + n_points * (SIZEOF_STORED_DOUBLE * 2 + WKB_HEADER_SIZE)) || + txt->reserve(((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points)) return 1; - - for (; n_points>0; --n_points) - { - double d; - float8get(d, data + WKB_HEADER_SIZE); - txt->qs_append(d); - txt->qs_append(' '); - float8get(d, data + WKB_HEADER_SIZE + 8); - txt->qs_append(d); - txt->qs_append(','); - data+= WKB_HEADER_SIZE + 8 + 8; - } - txt->length(txt->length()-1); + *end= append_points(txt, n_points, m_data+4, WKB_HEADER_SIZE); + txt->length(txt->length()-1); // Remove end ',' return 0; } -int GMultiPoint::get_mbr(MBR *mbr) const + +bool Gis_multi_point::get_mbr(MBR *mbr, const char **end) const { - uint32 n_points; - const char *data = m_data; - if (no_data(data, 4)) - return 1; - n_points = uint4korr(data); - data += 4; - if (no_data(data, n_points * (8+8+WKB_HEADER_SIZE))) - return 1; - for (; n_points>0; --n_points) - { - mbr->add_xy(data + WKB_HEADER_SIZE, data + 8 + WKB_HEADER_SIZE); - data += (8+8+WKB_HEADER_SIZE); - } - return 0; + return (*end= get_mbr_for_points(mbr, m_data, WKB_HEADER_SIZE)) == 0; } -int GMultiPoint::num_geometries(uint32 *num) const + +bool Gis_multi_point::num_geometries(uint32 *num) const { - *num = uint4korr(m_data); + *num= uint4korr(m_data); return 0; } -int GMultiPoint::geometry_n(uint32 num, String *result) const + +bool Gis_multi_point::geometry_n(uint32 num, String *result) const { const char *data= m_data; uint32 n_points; + if (no_data(data, 4)) return 1; n_points= uint4korr(data); - data+= 4; - if ((num > n_points) || (num < 1)) - return -1; - data+= (num - 1) * (WKB_HEADER_SIZE + POINT_DATA_SIZE); - if (result->reserve(WKB_HEADER_SIZE + POINT_DATA_SIZE)) + data+= 4+ (num - 1) * (WKB_HEADER_SIZE + POINT_DATA_SIZE); + + if (num > n_points || num < 1 || + no_data(data, WKB_HEADER_SIZE + POINT_DATA_SIZE) || + result->reserve(WKB_HEADER_SIZE + POINT_DATA_SIZE)) return 1; - result->q_append(data, WKB_HEADER_SIZE + POINT_DATA_SIZE); + result->q_append(data, WKB_HEADER_SIZE + POINT_DATA_SIZE); return 0; } + /***************************** MultiLineString *******************************/ -size_t GMultiLineString::get_data_size() const +uint32 Gis_multi_line_stringg::get_data_size() const { - uint32 n_line_strings = 0; - const char *data = m_data; + uint32 n_line_strings; + const char *data= m_data; + if (no_data(data, 4)) - return 1; - n_line_strings = uint4korr(data); - data += 4; + return GET_SIZE_ERROR; + n_line_strings= uint4korr(data); + data+= 4; - for (; n_line_strings>0; --n_line_strings) + while (n_line_strings--) { if (no_data(data, WKB_HEADER_SIZE + 4)) - return 1; - data += WKB_HEADER_SIZE + 4 + uint4korr(data + WKB_HEADER_SIZE) * POINT_DATA_SIZE; + return GET_SIZE_ERROR; + data+= (WKB_HEADER_SIZE + 4 + uint4korr(data + WKB_HEADER_SIZE) * + POINT_DATA_SIZE); } - return data - m_data; + return (uint32) (data - m_data); } -int GMultiLineString::init_from_wkt(GTextReadStream *trs, String *wkb) + +bool Gis_multi_line_stringg::init_from_wkt(Gis_read_stream *trs, String *wkb) { - uint32 n_line_strings = 0; - int ls_pos = wkb->length(); + uint32 n_line_strings= 0; + uint32 ls_pos= wkb->length(); if (wkb->reserve(4, 512)) return 1; - - wkb->q_append((uint32)n_line_strings); + wkb->length(wkb->length()+4); // Reserve space for points for (;;) { - GLineString ls; + Gis_line_string ls; if (wkb->reserve(1+4, 512)) return 1; - wkb->q_append((char)wkbNDR); - wkb->q_append((uint32)wkbLineString); - - if (trs->get_next_symbol() != '(') - { - trs->set_error_msg("'(' expected"); - return 1; - } - if (ls.init_from_wkt(trs, wkb)) - return 1; + wkb->q_append((char) wkbNDR); + wkb->q_append((uint32) wkbLineString); - if (trs->get_next_symbol() != ')') - { - trs->set_error_msg("')' expected"); + if (trs->check_next_symbol('(') || + ls.init_from_wkt(trs, wkb) || + trs->check_next_symbol(')')) return 1; - } - ++n_line_strings; - if (trs->get_next_toc_type() == GTextReadStream::comma) - trs->get_next_symbol(); - else + n_line_strings++; + if (trs->skip_char(',')) // Didn't find ',' break; } - wkb->WriteAtPosition(ls_pos, n_line_strings); - + wkb->write_at_position(ls_pos, n_line_strings); return 0; } -int GMultiLineString::get_data_as_wkt(String *txt) const + +bool Gis_multi_line_stringg::get_data_as_wkt(String *txt, const char **end) { uint32 n_line_strings; const char *data= m_data; + if (no_data(data, 4)) return 1; n_line_strings= uint4korr(data); data+= 4; - for (; n_line_strings > 0; --n_line_strings) + + while (n_line_strings--) { + uint32 n_points; if (no_data(data, (WKB_HEADER_SIZE + 4))) return 1; - uint32 n_points= uint4korr(data + WKB_HEADER_SIZE); + n_points= uint4korr(data + WKB_HEADER_SIZE); data+= WKB_HEADER_SIZE + 4; - if (no_data(data, n_points * (8 + 8))) - return 1; - - if (txt->reserve(2 + ((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points)) + if (no_data(data, n_points * (SIZEOF_STORED_DOUBLE*2)) || + txt->reserve(2 + ((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points)) return 1; txt->qs_append('('); - for (; n_points>0; --n_points) - { - double d; - float8get(d, data); - txt->qs_append(d); - txt->qs_append(' '); - float8get(d, data + 8); - txt->qs_append(d); - txt->qs_append(','); - data+= 8 + 8; - } - (*txt) [txt->length() - 1] = ')'; + data= append_points(txt, n_points, data, 0); + (*txt) [txt->length() - 1]= ')'; txt->qs_append(','); } txt->length(txt->length() - 1); + *end= data; return 0; } -int GMultiLineString::get_mbr(MBR *mbr) const + +bool Gis_multi_line_stringg::get_mbr(MBR *mbr, const char **end) const { uint32 n_line_strings; - const char *data = m_data; + const char *data= m_data; + if (no_data(data, 4)) return 1; - n_line_strings = uint4korr(data); - data += 4; + n_line_strings= uint4korr(data); + data+= 4; - for (; n_line_strings>0; --n_line_strings) + while (n_line_strings--) { - if (no_data(data, WKB_HEADER_SIZE + 4)) - return 1; - uint32 n_points = uint4korr(data + WKB_HEADER_SIZE); - data += 4+WKB_HEADER_SIZE; - if (no_data(data, (8+8)*n_points)) + data+= WKB_HEADER_SIZE; + if (!(data= get_mbr_for_points(mbr, data, 0))) return 1; - - for (; n_points>0; --n_points) - { - mbr->add_xy(data, data + 8); - data += 8+8; - } } + *end= data; return 0; } -int GMultiLineString::num_geometries(uint32 *num) const + +bool Gis_multi_line_stringg::num_geometries(uint32 *num) const { - *num = uint4korr(m_data); + *num= uint4korr(m_data); return 0; } -int GMultiLineString::geometry_n(uint32 num, String *result) const + +bool Gis_multi_line_stringg::geometry_n(uint32 num, String *result) const { - uint32 n_line_strings; + uint32 n_line_strings, n_points, length; const char *data= m_data; + if (no_data(data, 4)) return 1; n_line_strings= uint4korr(data); data+= 4; if ((num > n_line_strings) || (num < 1)) - return -1; + return 1; - for (; num > 0; --num) + for (;;) { if (no_data(data, WKB_HEADER_SIZE + 4)) return 1; - uint32 n_points= uint4korr(data + WKB_HEADER_SIZE); - if (num == 1) - { - if (result->reserve(WKB_HEADER_SIZE + 4 + POINT_DATA_SIZE * n_points)) - return 1; - result->q_append(data, WKB_HEADER_SIZE + 4 + POINT_DATA_SIZE *n_points); + n_points= uint4korr(data + WKB_HEADER_SIZE); + length= WKB_HEADER_SIZE + 4+ POINT_DATA_SIZE * n_points; + if (no_data(data, length)) + return 1; + if (!--num) break; - } - else - { - data+= WKB_HEADER_SIZE + 4 + POINT_DATA_SIZE * n_points; - } + data+= length; } - return 0; + return result->append(data, length, (uint32) 0); } -int GMultiLineString::length(double *len) const + +bool Gis_multi_line_stringg::length(double *len) const { uint32 n_line_strings; - const char *data = m_data; + const char *data= m_data; + if (no_data(data, 4)) return 1; - n_line_strings = uint4korr(data); - data += 4; + n_line_strings= uint4korr(data); + data+= 4; + *len=0; - for (; n_line_strings>0; --n_line_strings) + while (n_line_strings--) { double ls_len; - GLineString ls; - data += WKB_HEADER_SIZE; - ls.init_from_wkb(data, m_data_end - data); + Gis_line_string ls; + data+= WKB_HEADER_SIZE; + ls.init_from_wkb(data, (uint32) (m_data_end - data)); if (ls.length(&ls_len)) return 1; - *len+=ls_len; - data += ls.get_data_size(); + *len+= ls_len; + /* + We know here that ls was ok, so we can call the trivial function + Gis_line_string::get_data_size without error checking + */ + data+= ls.get_data_size(); } return 0; } -int GMultiLineString::is_closed(int *closed) const + +bool Gis_multi_line_stringg::is_closed(int *closed) const { uint32 n_line_strings; - const char *data = m_data; - if (no_data(data, 1)) + const char *data= m_data; + + if (no_data(data, 4 + WKB_HEADER_SIZE)) return 1; - n_line_strings = uint4korr(data); - data += 4 + WKB_HEADER_SIZE; - for (; n_line_strings>0; --n_line_strings) + n_line_strings= uint4korr(data); + data+= 4 + WKB_HEADER_SIZE; + + while (n_line_strings--) { - GLineString ls; - ls.init_from_wkb(data, m_data_end - data); + Gis_line_string ls; + if (no_data(data, 0)) + return 1; + ls.init_from_wkb(data, (uint32) (m_data_end - data)); if (ls.is_closed(closed)) return 1; if (!*closed) return 0; - data += ls.get_data_size() + WKB_HEADER_SIZE; + /* + We know here that ls was ok, so we can call the trivial function + Gis_line_string::get_data_size without error checking + */ + data+= ls.get_data_size() + WKB_HEADER_SIZE; } return 0; } + /***************************** MultiPolygon *******************************/ -size_t GMultiPolygon::get_data_size() const +uint32 Gis_multi_polygon::get_data_size() const { uint32 n_polygons; - const char *data = m_data; + const char *data= m_data; + if (no_data(data, 4)) - return 1; - n_polygons = uint4korr(data); - data += 4; + return GET_SIZE_ERROR; + n_polygons= uint4korr(data); + data+= 4; - for (; n_polygons>0; --n_polygons) + while (n_polygons--) { + uint32 n_linear_rings; if (no_data(data, 4 + WKB_HEADER_SIZE)) - return 1; - uint32 n_linear_rings = uint4korr(data + WKB_HEADER_SIZE); - data += 4 + WKB_HEADER_SIZE; + return GET_SIZE_ERROR; - for (; n_linear_rings > 0; --n_linear_rings) + n_linear_rings= uint4korr(data + WKB_HEADER_SIZE); + data+= 4 + WKB_HEADER_SIZE; + + while (n_linear_rings--) { - data += 4 + uint4korr(data) * POINT_DATA_SIZE; + if (no_data(data, 4)) + return GET_SIZE_ERROR; + data+= 4 + uint4korr(data) * POINT_DATA_SIZE; } } - return data - m_data; + return (uint32) (data - m_data); } -int GMultiPolygon::init_from_wkt(GTextReadStream *trs, String *wkb) + +bool Gis_multi_polygon::init_from_wkt(Gis_read_stream *trs, String *wkb) { - uint32 n_polygons = 0; - int np_pos = wkb->length(); - GPolygon p; + uint32 n_polygons= 0; + int np_pos= wkb->length(); + Gis_polygon p; if (wkb->reserve(4, 512)) return 1; - - wkb->q_append((uint32)n_polygons); + wkb->length(wkb->length()+4); // Reserve space for points for (;;) { if (wkb->reserve(1+4, 512)) return 1; - wkb->q_append((char)wkbNDR); - wkb->q_append((uint32)wkbPolygon); + wkb->q_append((char) wkbNDR); + wkb->q_append((uint32) wkbPolygon); - if (trs->get_next_symbol() != '(') - { - trs->set_error_msg("'(' expected"); - return 1; - } - if (p.init_from_wkt(trs, wkb)) - return 1; - if (trs->get_next_symbol() != ')') - { - trs->set_error_msg("')' expected"); + if (trs->check_next_symbol('(') || + p.init_from_wkt(trs, wkb) || + trs->check_next_symbol(')')) return 1; - } - ++n_polygons; - if (trs->get_next_toc_type() == GTextReadStream::comma) - trs->get_next_symbol(); - else + n_polygons++; + if (trs->skip_char(',')) // Didn't find ',' break; } - wkb->WriteAtPosition(np_pos, n_polygons); + wkb->write_at_position(np_pos, n_polygons); return 0; } -int GMultiPolygon::get_data_as_wkt(String *txt) const + +bool Gis_multi_polygon::get_data_as_wkt(String *txt, const char **end) { uint32 n_polygons; const char *data= m_data; + if (no_data(data, 4)) return 1; n_polygons= uint4korr(data); data+= 4; - for (; n_polygons>0; --n_polygons) + while (n_polygons--) { - if (no_data(data, 4 + WKB_HEADER_SIZE)) - return 1; - data+= WKB_HEADER_SIZE; - uint32 n_linear_rings= uint4korr(data); - data+= 4; - - if (txt->reserve(1, 512)) + uint32 n_linear_rings; + if (no_data(data, 4 + WKB_HEADER_SIZE) || + txt->reserve(1, 512)) return 1; + n_linear_rings= uint4korr(data+WKB_HEADER_SIZE); + data+= 4 + WKB_HEADER_SIZE; txt->q_append('('); - for (; n_linear_rings>0; --n_linear_rings) + + while (n_linear_rings--) { if (no_data(data, 4)) return 1; uint32 n_points= uint4korr(data); data+= 4; - if (no_data(data, (8 + 8) * n_points)) return 1; - - if (txt->reserve(2 + ((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points, - 512)) return 1; + if (no_data(data, (SIZEOF_STORED_DOUBLE * 2) * n_points) || + txt->reserve(2 + ((MAX_DIGITS_IN_DOUBLE + 1) * 2 + 1) * n_points, + 512)) + return 1; txt->qs_append('('); - for (; n_points>0; --n_points) - { - double d; - float8get(d, data); - txt->qs_append(d); - txt->qs_append(' '); - float8get(d, data + 8); - txt->qs_append(d); - txt->qs_append(','); - data+= 8 + 8; - } - (*txt) [txt->length() - 1] = ')'; + data= append_points(txt, n_points, data, 0); + (*txt) [txt->length() - 1]= ')'; txt->qs_append(','); } - (*txt) [txt->length() - 1] = ')'; + (*txt) [txt->length() - 1]= ')'; txt->qs_append(','); } txt->length(txt->length() - 1); + *end= data; return 0; } -int GMultiPolygon::get_mbr(MBR *mbr) const + +bool Gis_multi_polygon::get_mbr(MBR *mbr, const char **end) const { uint32 n_polygons; - const char *data = m_data; + const char *data= m_data; + if (no_data(data, 4)) return 1; - n_polygons = uint4korr(data); - data += 4; + n_polygons= uint4korr(data); + data+= 4; - for (; n_polygons>0; --n_polygons) + while (n_polygons--) { + uint32 n_linear_rings; if (no_data(data, 4+WKB_HEADER_SIZE)) return 1; - uint32 n_linear_rings = uint4korr(data + WKB_HEADER_SIZE); - data += WKB_HEADER_SIZE + 4; + n_linear_rings= uint4korr(data + WKB_HEADER_SIZE); + data+= WKB_HEADER_SIZE + 4; - for (; n_linear_rings>0; --n_linear_rings) + while (n_linear_rings--) { - if (no_data(data, 4)) - return 1; - uint32 n_points = uint4korr(data); - data += 4; - if (no_data(data, (8+8)*n_points)) - return 1; - - for (; n_points>0; --n_points) - { - mbr->add_xy(data, data + 8); - data += 8+8; - } + if (!(data= get_mbr_for_points(mbr, data, 0))) + return 1; } } + *end= data; return 0; } -int GMultiPolygon::num_geometries(uint32 *num) const + +bool Gis_multi_polygon::num_geometries(uint32 *num) const { - *num = uint4korr(m_data); + *num= uint4korr(m_data); return 0; } -int GMultiPolygon::geometry_n(uint32 num, String *result) const + +bool Gis_multi_polygon::geometry_n(uint32 num, String *result) const { uint32 n_polygons; - const char *data= m_data, *polygon_n; - LINT_INIT(polygon_n); + const char *data= m_data, *start_of_polygon; if (no_data(data, 4)) return 1; n_polygons= uint4korr(data); data+= 4; - if ((num > n_polygons) || (num < 1)) + if (num > n_polygons || num < 1) return -1; - for (; num > 0; --num) + do { + uint32 n_linear_rings; + start_of_polygon= data; + if (no_data(data, WKB_HEADER_SIZE + 4)) return 1; - uint32 n_linear_rings= uint4korr(data + WKB_HEADER_SIZE); - - if (num == 1) - polygon_n= data; + n_linear_rings= uint4korr(data + WKB_HEADER_SIZE); data+= WKB_HEADER_SIZE + 4; - for (; n_linear_rings > 0; --n_linear_rings) + + while (n_linear_rings--) { + uint32 n_points; if (no_data(data, 4)) return 1; - uint32 n_points= uint4korr(data); + n_points= uint4korr(data); data+= 4 + POINT_DATA_SIZE * n_points; } - if (num == 1) - { - if (result->reserve(data - polygon_n)) - return -1; - result->q_append(polygon_n, data - polygon_n); - break; - } - } - return 0; + } while (--num); + if (no_data(data, 0)) // We must check last segment + return 1; + return result->append(start_of_polygon, (uint32) (data - start_of_polygon), + (uint32) 0); } -int GMultiPolygon::area(double *ar) const + +bool Gis_multi_polygon::area(double *ar, const char **end_of_data) const { uint32 n_polygons; - const char *data = m_data; - double result = 0; + const char *data= m_data; + double result= 0; + if (no_data(data, 4)) return 1; - n_polygons = uint4korr(data); - data += 4; + n_polygons= uint4korr(data); + data+= 4; - for (; n_polygons>0; --n_polygons) + while (n_polygons--) { double p_area; + Gis_polygon p; - GPolygon p; - data += WKB_HEADER_SIZE; - p.init_from_wkb(data, m_data_end - data); - if (p.area(&p_area)) + data+= WKB_HEADER_SIZE; + p.init_from_wkb(data, (uint32) (m_data_end - data)); + if (p.area(&p_area, &data)) return 1; - result += p_area; - data += p.get_data_size(); + result+= p_area; } - *ar = result; + *ar= result; + *end_of_data= data; return 0; } -int GMultiPolygon::centroid(String *result) const + +bool Gis_multi_polygon::centroid(String *result) { uint32 n_polygons; - uint i; - GPolygon p; + bool first_loop= 1; + Gis_polygon p; double res_area, res_cx, res_cy; double cur_area, cur_cx, cur_cy; + const char *data= m_data; LINT_INIT(res_area); LINT_INIT(res_cx); LINT_INIT(res_cy); - const char *data = m_data; if (no_data(data, 4)) return 1; - n_polygons = uint4korr(data); - data += 4; + n_polygons= uint4korr(data); + data+= 4; - for (i = 0; i < n_polygons; ++i) + while (n_polygons--) { - data += WKB_HEADER_SIZE; - p.init_from_wkb(data, m_data_end - data); - if (p.area(&cur_area)) - return 1; - - if (p.centroid_xy(&cur_cx, &cur_cy)) + data+= WKB_HEADER_SIZE; + p.init_from_wkb(data, (uint32) (m_data_end - data)); + if (p.area(&cur_area, &data) || + p.centroid_xy(&cur_cx, &cur_cy)) return 1; - if (i) + if (!first_loop) { - double sum_area = res_area + cur_area; - res_cx = (res_area * res_cx + cur_area * cur_cx) / sum_area; - res_cy = (res_area * res_cy + cur_area * cur_cy) / sum_area; + double sum_area= res_area + cur_area; + res_cx= (res_area * res_cx + cur_area * cur_cx) / sum_area; + res_cy= (res_area * res_cy + cur_area * cur_cy) / sum_area; } else { - res_area = cur_area; - res_cx = cur_cx; - res_cy = cur_cy; + first_loop= 0; + res_area= cur_area; + res_cx= cur_cx; + res_cy= cur_cy; } - - data += p.get_data_size(); } - if (result->reserve(1 + 4 + sizeof(double) * 2)) - return 1; - result->q_append((char)wkbNDR); - result->q_append((uint32)wkbPoint); - result->q_append(res_cx); - result->q_append(res_cy); - - return 0; + return create_point(result, res_cx, res_cy); } -/***************************** GeometryCollection *******************************/ -size_t GGeometryCollection::get_data_size() const +/************************* GeometryCollection ****************************/ + +uint32 Gis_geometry_collection::get_data_size() const { uint32 n_objects; - const char *data = m_data; + const char *data= m_data; + if (no_data(data, 4)) - return 1; - n_objects = uint4korr(data); - data += 4; + return GET_SIZE_ERROR; + n_objects= uint4korr(data); + data+= 4; - for (; n_objects>0; --n_objects) + while (n_objects--) { - if (no_data(data, WKB_HEADER_SIZE)) - return 1; - uint32 wkb_type = uint4korr(data + sizeof(char)); - data += WKB_HEADER_SIZE; - + uint32 wkb_type,object_size; Geometry geom; - if (geom.init(wkb_type)) - return 0; + if (no_data(data, WKB_HEADER_SIZE)) + return GET_SIZE_ERROR; + wkb_type= uint4korr(data + 1); + data+= WKB_HEADER_SIZE; - geom.init_from_wkb(data, m_data_end - data); - size_t object_size=geom.get_data_size(); - data += object_size; + if (geom.init(wkb_type)) + return GET_SIZE_ERROR; + geom.init_from_wkb(data, (uint) (m_data_end - data)); + if ((object_size= geom.get_data_size()) == GET_SIZE_ERROR) + return GET_SIZE_ERROR; + data+= object_size; } - return data - m_data; + return (uint32) (data - m_data); } -int GGeometryCollection::init_from_wkt(GTextReadStream *trs, String *wkb) + +bool Gis_geometry_collection::init_from_wkt(Gis_read_stream *trs, String *wkb) { - uint32 n_objects = 0; - int no_pos = wkb->length(); + uint32 n_objects= 0; + uint32 no_pos= wkb->length(); Geometry g; if (wkb->reserve(4, 512)) return 1; - wkb->q_append((uint32)n_objects); + wkb->length(wkb->length()+4); // Reserve space for points for (;;) { if (g.create_from_wkt(trs, wkb)) return 1; - if (g.get_class_info()->m_type_id==wkbGeometryCollection) + if (g.get_class_info()->m_type_id == wkbGeometryCollection) { trs->set_error_msg("Unexpected GEOMETRYCOLLECTION"); return 1; } - ++n_objects; - if (trs->get_next_toc_type() == GTextReadStream::comma) - trs->get_next_symbol(); - else break; + n_objects++; + if (trs->skip_char(',')) // Didn't find ',' + break; } - wkb->WriteAtPosition(no_pos, n_objects); + wkb->write_at_position(no_pos, n_objects); return 0; } -int GGeometryCollection::get_data_as_wkt(String *txt) const + +bool Gis_geometry_collection::get_data_as_wkt(String *txt, const char **end) { uint32 n_objects; - const char *data = m_data; Geometry geom; + const char *data= m_data; + if (no_data(data, 4)) return 1; - n_objects = uint4korr(data); - data += 4; + n_objects= uint4korr(data); + data+= 4; - for (; n_objects>0; --n_objects) + while (n_objects--) { + uint32 wkb_type; + if (no_data(data, WKB_HEADER_SIZE)) return 1; - uint32 wkb_type = uint4korr(data + sizeof(char)); - data += WKB_HEADER_SIZE; + wkb_type= uint4korr(data + 1); + data+= WKB_HEADER_SIZE; if (geom.init(wkb_type)) return 1; - geom.init_from_wkb(data, m_data_end - data); - if (geom.as_wkt(txt)) + geom.init_from_wkb(data, (uint) (m_data_end - data)); + if (geom.as_wkt(txt, &data)) + return 1; + if (txt->append(",", 1, 512)) return 1; - data += geom.get_data_size(); - txt->reserve(1, 512); - txt->q_append(','); } txt->length(txt->length() - 1); + *end= data; return 0; } -int GGeometryCollection::get_mbr(MBR *mbr) const + +bool Gis_geometry_collection::get_mbr(MBR *mbr, const char **end) const { uint32 n_objects; - const char *data = m_data; + const char *data= m_data; + if (no_data(data, 4)) return 1; - n_objects = uint4korr(data); - data += 4; - for (; n_objects>0; --n_objects) + n_objects= uint4korr(data); + data+= 4; + + while (n_objects--) { + uint32 wkb_type; + Geometry geom; + if (no_data(data, WKB_HEADER_SIZE)) return 1; - uint32 wkb_type = uint4korr(data + sizeof(char)); - data += WKB_HEADER_SIZE; - Geometry geom; + wkb_type= uint4korr(data + 1); + data+= WKB_HEADER_SIZE; if (geom.init(wkb_type)) return 1; - geom.init_from_wkb(data, m_data_end - data); - geom.get_mbr(mbr); - data += geom.get_data_size(); + geom.init_from_wkb(data, (uint32) (m_data_end - data)); + if (geom.get_mbr(mbr, &data)) + return 1; } + *end= data; return 0; } -int GGeometryCollection::num_geometries(uint32 *num) const + +bool Gis_geometry_collection::num_geometries(uint32 *num) const { - *num = uint4korr(m_data); + if (no_data(m_data, 4)) + return 1; + *num= uint4korr(m_data); return 0; } -int GGeometryCollection::geometry_n(uint32 num, String *result) const + +bool Gis_geometry_collection::geometry_n(uint32 num, String *result) const { - const char *data = m_data; - uint32 n_objects; + uint32 n_objects, wkb_type, length; + const char *data= m_data; + if (no_data(data, 4)) return 1; - n_objects = uint4korr(data); - data += 4; + n_objects= uint4korr(data); + data+= 4; + if (num > n_objects || num < 1) + return 1; - if ((num > n_objects) || (num < 1)) - { - return -1; - } - for (; num > 0; --num) + do { + Geometry geom; + if (no_data(data, WKB_HEADER_SIZE)) return 1; - uint32 wkb_type = uint4korr(data + sizeof(char)); - data += WKB_HEADER_SIZE; + wkb_type= uint4korr(data + 1); + data+= WKB_HEADER_SIZE; - Geometry geom; if (geom.init(wkb_type)) return 1; - geom.init_from_wkb(data, m_data_end - data); - if (num == 1) - { - if (result->reserve(1+4+geom.get_data_size())) - return 1; - result->q_append((char)wkbNDR); - result->q_append((uint32)wkb_type); - result->q_append(data, geom.get_data_size()); - break; - } - else - { - data += geom.get_data_size(); - } - } + geom.init_from_wkb(data, (uint) (m_data_end - data)); + if ((length= geom.get_data_size()) == GET_SIZE_ERROR) + return 1; + data+= length; + } while (--num); + + /* Copy found object to result */ + if (result->reserve(1+4+length)) + return 1; + result->q_append((char) wkbNDR); + result->q_append((uint32) wkb_type); + result->q_append(data-length, length); // data-length = start_of_data return 0; } -int GGeometryCollection::dimension(uint32 *dim) const + +/* + Return dimension for object + + SYNOPSIS + dimension() + res_dim Result dimension + end End of object will be stored here. May be 0 for + simple objects! + RETURN + 0 ok + 1 error +*/ + +bool Gis_geometry_collection::dimension(uint32 *res_dim, const char **end) const { uint32 n_objects; - *dim = 0; - const char *data = m_data; + const char *data= m_data; + if (no_data(data, 4)) return 1; - n_objects = uint4korr(data); - data += 4; + n_objects= uint4korr(data); + data+= 4; - for (; n_objects > 0; --n_objects) + *res_dim= 0; + while (n_objects--) { + uint32 wkb_type, length, dim; + const char *end_data; + Geometry geom; + if (no_data(data, WKB_HEADER_SIZE)) return 1; - uint32 wkb_type = uint4korr(data + sizeof(char)); - data += WKB_HEADER_SIZE; - - uint32 d; - - Geometry geom; + wkb_type= uint4korr(data + 1); + data+= WKB_HEADER_SIZE; if (geom.init(wkb_type)) return 1; - geom.init_from_wkb(data, m_data_end - data); - if (geom.dimension(&d)) + geom.init_from_wkb(data, (uint32) (m_data_end - data)); + if (geom.dimension(&dim, &end_data)) return 1; - - if (d > *dim) - *dim = d; - data += geom.get_data_size(); + set_if_bigger(*res_dim, dim); + if (end_data) // Complex object + data= end_data; + else if ((length= geom.get_data_size()) == GET_SIZE_ERROR) + return 1; + else + data+= length; } + *end= data; return 0; } - -/***************************** /objects *******************************/ diff --git a/sql/spatial.h b/sql/spatial.h index 5fda257f1b1..bc064724ab7 100644 --- a/sql/spatial.h +++ b/sql/spatial.h @@ -17,118 +17,80 @@ #ifndef _spatial_h #define _spatial_h -const uint POINT_DATA_SIZE = 8+8; -const uint WKB_HEADER_SIZE = 1+4; +const uint SRID_SIZE= 4; +const uint SIZEOF_STORED_DOUBLE= 8; +const uint POINT_DATA_SIZE= SIZEOF_STORED_DOUBLE*2; +const uint WKB_HEADER_SIZE= 1+4; +const uint32 GET_SIZE_ERROR= ((uint32) -1); -struct stPoint2D +struct st_point_2d { double x; double y; }; -struct stLinearRing +struct st_linear_ring { - size_t n_points; - stPoint2D points; + uint32 n_points; + st_point_2d points; }; /***************************** MBR *******************************/ + +/* + It's ok that a lot of the functions are inline as these are only used once + in MySQL +*/ + struct MBR { + double xmin, ymin, xmax, ymax; + MBR() { - xmin=DBL_MAX; - ymin=DBL_MAX; - xmax=-DBL_MAX; - ymax=-DBL_MAX; + xmin= ymin= DBL_MAX; + xmax= ymax= -DBL_MAX; } - MBR(const double &_xmin, const double &_ymin, - const double &_xmax, const double &_ymax) - { - xmin=_xmin; - ymin=_ymin; - xmax=_xmax; - ymax=_ymax; - } + MBR(const double xmin_arg, const double ymin_arg, + const double xmax_arg, const double ymax_arg) + :xmin(xmin_arg), ymin(ymin_arg), xmax(xmax_arg), ymax(ymax_arg) + {} - MBR(const stPoint2D &min, const stPoint2D &max) - { - xmin=min.x; - ymin=min.y; - xmax=max.x; - ymax=max.y; - } - - double xmin; - double ymin; - double xmax; - double ymax; - - void add_xy(double x, double y) + MBR(const st_point_2d &min, const st_point_2d &max) + :xmin(min.x), ymin(min.y), xmax(max.x), ymax(max.y) + {} + + inline void add_xy(double x, double y) { /* Not using "else" for proper one point MBR calculation */ - if (x<xmin) - { - xmin=x; - } - if (x>xmax) - { - xmax=x; - } - if (y<ymin) - { - ymin=y; - } - if (y>ymax) - { - ymax=y; - } + if (x < xmin) + xmin= x; + if (x > xmax) + xmax= x; + if (y < ymin) + ymin= y; + if (y > ymax) + ymax= y; } - void add_xy(const char *px, const char *py) { double x, y; float8get(x, px); float8get(y, py); - /* Not using "else" for proper one point MBR calculation */ - if (x<xmin) - { - xmin=x; - } - if (x>xmax) - { - xmax=x; - } - if (y<ymin) - { - ymin=y; - } - if (y>ymax) - { - ymax=y; - } + add_xy(x,y); } - void add_mbr(const MBR *mbr) { - if (mbr->xmin<xmin) - { - xmin=mbr->xmin; - } - if (mbr->xmax>xmax) - { - xmax=mbr->xmax; - } - if (mbr->ymin<ymin) - { - ymin=mbr->ymin; - } - if (mbr->ymax>ymax) - { - ymax=mbr->ymax; - } + if (mbr->xmin < xmin) + xmin= mbr->xmin; + if (mbr->xmax > xmax) + xmax= mbr->xmax; + if (mbr->ymin < ymin) + ymin= mbr->ymin; + if (mbr->ymax > ymax) + ymax= mbr->ymax; } int equals(const MBR *mbr) @@ -177,12 +139,12 @@ struct MBR int overlaps(const MBR *mbr) { - int lb = mbr->inner_point(xmin, ymin); - int rb = mbr->inner_point(xmax, ymin); - int rt = mbr->inner_point(xmax, ymax); - int lt = mbr->inner_point(xmin, ymax); + int lb= mbr->inner_point(xmin, ymin); + int rb= mbr->inner_point(xmax, ymin); + int rt= mbr->inner_point(xmax, ymax); + int lt= mbr->inner_point(xmin, ymax); - int a = lb+rb+rt+lt; + int a = lb+rb+rt+lt; return (a>0) && (a<4) && (!within(mbr)); } }; @@ -192,16 +154,18 @@ struct MBR class Geometry; -typedef int (Geometry::*GF_InitFromText)(GTextReadStream *, String *); -typedef int (Geometry::*GF_GetDataAsText)(String *) const; -typedef size_t (Geometry::*GF_GetDataSize)() const; -typedef int (Geometry::*GF_GetMBR)(MBR *) const; +typedef bool (Geometry::*GF_InitFromText)(Gis_read_stream *, String *); +typedef bool (Geometry::*GF_GetDataAsText)(String *, const char **); +typedef uint32 (Geometry::*GF_GetDataSize)() const; +typedef bool (Geometry::*GF_GetMBR)(MBR *, const char **end) const; -typedef int (Geometry::*GF_GetD)(double *) const; -typedef int (Geometry::*GF_GetI)(int *) const; -typedef int (Geometry::*GF_GetUI)(uint32 *) const; -typedef int (Geometry::*GF_GetWS)(String *) const; -typedef int (Geometry::*GF_GetUIWS)(uint32, String *) const; +typedef bool (Geometry::*GF_GetD)(double *) const; +typedef bool (Geometry::*GF_GetD_AND_END)(double *, const char **) const; +typedef bool (Geometry::*GF_GetI)(int *) const; +typedef bool (Geometry::*GF_GetUI)(uint32 *) const; +typedef bool (Geometry::*GF_GetUI_AND_END)(uint32 *, const char **) const; +typedef bool (Geometry::*GF_GetWS)(String *); +typedef bool (Geometry::*GF_GetUIWS)(uint32, String *) const; #define GEOM_METHOD_PRESENT(geom_obj, method)\ (geom_obj.m_vmt->method != &Geometry::method) @@ -211,21 +175,22 @@ class Geometry public: enum wkbType { - wkbPoint = 1, - wkbLineString = 2, - wkbPolygon = 3, - wkbMultiPoint = 4, - wkbMultiLineString = 5, - wkbMultiPolygon = 6, - wkbGeometryCollection = 7 + wkbPoint= 1, + wkbLineString= 2, + wkbPolygon= 3, + wkbMultiPoint= 4, + wkbMultiLineString= 5, + wkbMultiPolygon= 6, + wkbGeometryCollection= 7, + wkb_end=8 }; enum wkbByteOrder { - wkbXDR = 0, /* Big Endian */ - wkbNDR = 1 /* Little Endian */ + wkbXDR= 0, /* Big Endian */ + wkbNDR= 1 /* Little Endian */ }; - class GClassInfo + class Gis_class_info { public: GF_InitFromText init_from_wkt; @@ -235,14 +200,14 @@ public: GF_GetD get_x; GF_GetD get_y; GF_GetD length; - GF_GetD area; + GF_GetD_AND_END area; GF_GetI is_closed; GF_GetUI num_interior_ring; GF_GetUI num_points; GF_GetUI num_geometries; - GF_GetUI dimension; + GF_GetUI_AND_END dimension; GF_GetWS start_point; GF_GetWS end_point; @@ -253,248 +218,291 @@ public: GF_GetUIWS interior_ring_n; GF_GetUIWS geometry_n; + LEX_STRING m_name; int m_type_id; - const char *m_name; - GClassInfo *m_next_rt; + Gis_class_info *m_next_rt; }; - GClassInfo *m_vmt; + Gis_class_info *m_vmt; - const GClassInfo *get_class_info() const { return m_vmt; } - size_t get_data_size() const { return (this->*m_vmt->get_data_size)(); } + const Gis_class_info *get_class_info() const { return m_vmt; } + uint32 get_data_size() const { return (this->*m_vmt->get_data_size)(); } - int init_from_wkt(GTextReadStream *trs, String *wkb) + bool init_from_wkt(Gis_read_stream *trs, String *wkb) { return (this->*m_vmt->init_from_wkt)(trs, wkb); } - int get_data_as_wkt(String *txt) const - { return (this->*m_vmt->get_data_as_wkt)(txt); } + bool get_data_as_wkt(String *txt, const char **end) + { return (this->*m_vmt->get_data_as_wkt)(txt, end); } - int get_mbr(MBR *mbr) const { return (this->*m_vmt->get_mbr)(mbr); } - int dimension(uint32 *dim) const - { return (this->*m_vmt->dimension)(dim); } + int get_mbr(MBR *mbr, const char **end) const + { return (this->*m_vmt->get_mbr)(mbr, end); } + bool dimension(uint32 *dim, const char **end) const + { + return (this->*m_vmt->dimension)(dim, end); + } - int get_x(double *x) const { return (this->*m_vmt->get_x)(x); } - int get_y(double *y) const { return (this->*m_vmt->get_y)(y); } - int length(double *len) const { return (this->*m_vmt->length)(len); } - int area(double *ar) const { return (this->*m_vmt->area)(ar); } + bool get_x(double *x) const { return (this->*m_vmt->get_x)(x); } + bool get_y(double *y) const { return (this->*m_vmt->get_y)(y); } + bool length(double *len) const { return (this->*m_vmt->length)(len); } + bool area(double *ar, const char **end) const + { + return (this->*m_vmt->area)(ar, end); + } - int is_closed(int *closed) const + bool is_closed(int *closed) const { return (this->*m_vmt->is_closed)(closed); } - int num_interior_ring(uint32 *n_int_rings) const + bool num_interior_ring(uint32 *n_int_rings) const { return (this->*m_vmt->num_interior_ring)(n_int_rings); } - int num_points(uint32 *n_points) const + bool num_points(uint32 *n_points) const { return (this->*m_vmt->num_points)(n_points); } - int num_geometries(uint32 *num) const + bool num_geometries(uint32 *num) const { return (this->*m_vmt->num_geometries)(num); } - int start_point(String *point) const + bool start_point(String *point) { return (this->*m_vmt->start_point)(point); } - int end_point(String *point) const + bool end_point(String *point) { return (this->*m_vmt->end_point)(point); } - int exterior_ring(String *ring) const + bool exterior_ring(String *ring) { return (this->*m_vmt->exterior_ring)(ring); } - int centroid(String *point) const + bool centroid(String *point) { return (this->*m_vmt->centroid)(point); } - int point_n(uint32 num, String *result) const + bool point_n(uint32 num, String *result) const { return (this->*m_vmt->point_n)(num, result); } - int interior_ring_n(uint32 num, String *result) const + bool interior_ring_n(uint32 num, String *result) const { return (this->*m_vmt->interior_ring_n)(num, result); } - int geometry_n(uint32 num, String *result) const + bool geometry_n(uint32 num, String *result) const { return (this->*m_vmt->geometry_n)(num, result); } public: int create_from_wkb(const char *data, uint32 data_len); - int create_from_wkt(GTextReadStream *trs, String *wkt, int init_stream=1); + int create_from_wkt(Gis_read_stream *trs, String *wkt, bool init_stream=1); int init(int type_id) { - m_vmt = find_class(type_id); + m_vmt= find_class(type_id); return !m_vmt; } - int new_geometry(const char *name, size_t len) + int new_geometry(const char *name, uint32 len) { - m_vmt = find_class(name, len); + m_vmt= find_class(name, len); return !m_vmt; } - - int as_wkt(String *wkt) const + int as_wkt(String *wkt, const char **end) { - if (wkt->reserve(strlen(get_class_info()->m_name) + 2, 512)) + uint32 len= get_class_info()->m_name.length; + if (wkt->reserve(len + 2, 512)) return 1; - wkt->qs_append(get_class_info()->m_name); + wkt->qs_append(get_class_info()->m_name.str, len); wkt->qs_append('('); - if (get_data_as_wkt(wkt)) + if (get_data_as_wkt(wkt, end)) return 1; wkt->qs_append(')'); return 0; } - void init_from_wkb(const char *data, uint32 data_len) + inline void init_from_wkb(const char *data, uint32 data_len) { - m_data = data; - m_data_end = data + data_len; + m_data= data; + m_data_end= data + data_len; } - void shift_wkb_header() + inline void shift_wkb_header() { - m_data += WKB_HEADER_SIZE; + m_data+= WKB_HEADER_SIZE; } - int envelope(String *result) const; + bool envelope(String *result) const; protected: - static GClassInfo *find_class(int type_id); - static GClassInfo *find_class(const char *name, size_t len); - - bool no_data(const char *cur_data, uint32 data_amount) const + static Gis_class_info *find_class(int type_id); + static Gis_class_info *find_class(const char *name, uint32 len); + const char *append_points(String *txt, uint32 n_points, + const char *data, uint32 offset); + bool create_point(String *result, const char *data); + bool create_point(String *result, double x, double y); + const char *get_mbr_for_points(MBR *mbr, const char *data, uint offset) + const; + + inline bool no_data(const char *cur_data, uint32 data_amount) const { return (cur_data + data_amount > m_data_end); } - const char *m_data; const char *m_data_end; }; -#define SIZEOF_STORED_DOUBLE 8 /***************************** Point *******************************/ -class GPoint: public Geometry +class Gis_point: public Geometry { public: - size_t get_data_size() const; - int init_from_wkt(GTextReadStream *trs, String *wkb); - int get_data_as_wkt(String *txt) const; - int get_mbr(MBR *mbr) const; + uint32 get_data_size() const; + bool init_from_wkt(Gis_read_stream *trs, String *wkb); + bool get_data_as_wkt(String *txt, const char **end); + int get_mbr(MBR *mbr, const char **end) const; - int get_xy(double *x, double *y) const + bool get_xy(double *x, double *y) const { - const char *data = m_data; - if (no_data(data, SIZEOF_STORED_DOUBLE * 2)) return 1; + const char *data= m_data; + if (no_data(data, SIZEOF_STORED_DOUBLE * 2)) + return 1; float8get(*x, data); float8get(*y, data + SIZEOF_STORED_DOUBLE); return 0; } - int get_x(double *x) const + bool get_x(double *x) const { - if (no_data(m_data, SIZEOF_STORED_DOUBLE)) return 1; + if (no_data(m_data, SIZEOF_STORED_DOUBLE)) + return 1; float8get(*x, m_data); return 0; } - int get_y(double *y) const + bool get_y(double *y) const { - const char *data = m_data; + const char *data= m_data; if (no_data(data, SIZEOF_STORED_DOUBLE * 2)) return 1; float8get(*y, data + SIZEOF_STORED_DOUBLE); return 0; } - int dimension(uint32 *dim) const { *dim = 0; return 0; } + bool dimension(uint32 *dim, const char **end) const + { + *dim= 0; + *end= 0; /* No default end */ + return 0; + } }; + /***************************** LineString *******************************/ -class GLineString: public Geometry +class Gis_line_string: public Geometry { public: - size_t get_data_size() const; - int init_from_wkt(GTextReadStream *trs, String *wkb); - int get_data_as_wkt(String *txt) const; - int get_mbr(MBR *mbr) const; - - int length(double *len) const; - int is_closed(int *closed) const; - int num_points(uint32 *n_points) const; - int start_point(String *point) const; - int end_point(String *point) const; - int point_n(uint32 n, String *result) const; - int dimension(uint32 *dim) const { *dim = 1; return 0; } + uint32 get_data_size() const; + bool init_from_wkt(Gis_read_stream *trs, String *wkb); + bool get_data_as_wkt(String *txt, const char **end); + bool get_mbr(MBR *mbr, const char **end) const; + bool length(double *len) const; + bool is_closed(int *closed) const; + bool num_points(uint32 *n_points) const; + bool start_point(String *point); + bool end_point(String *point); + bool point_n(uint32 n, String *result); + bool dimension(uint32 *dim, const char **end) const + { + *dim= 1; + *end= 0; /* No default end */ + return 0; + } }; + /***************************** Polygon *******************************/ -class GPolygon: public Geometry +class Gis_polygon: public Geometry { public: - size_t get_data_size() const; - int init_from_wkt(GTextReadStream *trs, String *wkb); - int get_data_as_wkt(String *txt) const; - int get_mbr(MBR *mbr) const; - - int area(double *ar) const; - int exterior_ring(String *result) const; - int num_interior_ring(uint32 *n_int_rings) const; - int interior_ring_n(uint32 num, String *result) const; - int centroid_xy(double *x, double *y) const; - int centroid(String *result) const; - int dimension(uint32 *dim) const { *dim = 2; return 0; } + uint32 get_data_size() const; + bool init_from_wkt(Gis_read_stream *trs, String *wkb); + bool get_data_as_wkt(String *txt, const char **end); + bool get_mbr(MBR *mbr, const char **end) const; + bool area(double *ar, const char **end) const; + bool exterior_ring(String *result); + bool num_interior_ring(uint32 *n_int_rings) const; + bool interior_ring_n(uint32 num, String *result) const; + bool centroid_xy(double *x, double *y) const; + bool centroid(String *result); + bool dimension(uint32 *dim, const char **end) const + { + *dim= 2; + *end= 0; /* No default end */ + return 0; + } }; + /***************************** MultiPoint *******************************/ -class GMultiPoint: public Geometry +class Gis_multi_point: public Geometry { public: - size_t get_data_size() const; - int init_from_wkt(GTextReadStream *trs, String *wkb); - int get_data_as_wkt(String *txt) const; - int get_mbr(MBR *mbr) const; - - int num_geometries(uint32 *num) const; - int geometry_n(uint32 num, String *result) const; - int dimension(uint32 *dim) const { *dim = 0; return 0; } + uint32 get_data_size() const; + bool init_from_wkt(Gis_read_stream *trs, String *wkb); + bool get_data_as_wkt(String *txt, const char **end); + bool get_mbr(MBR *mbr, const char **end) const; + bool num_geometries(uint32 *num) const; + bool geometry_n(uint32 num, String *result) const; + bool dimension(uint32 *dim, const char **end) const + { + *dim= 0; + *end= 0; /* No default end */ + return 0; + } }; + /***************************** MultiLineString *******************************/ -class GMultiLineString: public Geometry +class Gis_multi_line_stringg: public Geometry { public: - size_t get_data_size() const; - int init_from_wkt(GTextReadStream *trs, String *wkb); - int get_data_as_wkt(String *txt) const; - int get_mbr(MBR *mbr) const; - - int num_geometries(uint32 *num) const; - int geometry_n(uint32 num, String *result) const; - int length(double *len) const; - int is_closed(int *closed) const; - int dimension(uint32 *dim) const { *dim = 1; return 0; } + uint32 get_data_size() const; + bool init_from_wkt(Gis_read_stream *trs, String *wkb); + bool get_data_as_wkt(String *txt, const char **end); + bool get_mbr(MBR *mbr, const char **end) const; + bool num_geometries(uint32 *num) const; + bool geometry_n(uint32 num, String *result) const; + bool length(double *len) const; + bool is_closed(int *closed) const; + bool dimension(uint32 *dim, const char **end) const + { + *dim= 1; + *end= 0; /* No default end */ + return 0; + } }; + /***************************** MultiPolygon *******************************/ -class GMultiPolygon: public Geometry +class Gis_multi_polygon: public Geometry { public: - size_t get_data_size() const; - int init_from_wkt(GTextReadStream *trs, String *wkb); - int get_data_as_wkt(String *txt) const; - int get_mbr(MBR *mbr) const; - - int num_geometries(uint32 *num) const; - int geometry_n(uint32 num, String *result) const; - int area(double *ar) const; - int centroid(String *result) const; - int dimension(uint32 *dim) const { *dim = 2; return 0; } + uint32 get_data_size() const; + bool init_from_wkt(Gis_read_stream *trs, String *wkb); + bool get_data_as_wkt(String *txt, const char **end); + bool get_mbr(MBR *mbr, const char **end) const; + bool num_geometries(uint32 *num) const; + bool geometry_n(uint32 num, String *result) const; + bool area(double *ar, const char **end) const; + bool centroid(String *result); + bool dimension(uint32 *dim, const char **end) const + { + *dim= 2; + *end= 0; /* No default end */ + return 0; + } + }; -/***************************** GeometryCollection *******************************/ -class GGeometryCollection: public Geometry +/*********************** GeometryCollection *******************************/ + +class Gis_geometry_collection: public Geometry { public: - size_t get_data_size() const; - int init_from_wkt(GTextReadStream *trs, String *wkb); - int get_data_as_wkt(String *txt) const; - int get_mbr(MBR *mbr) const; - - int num_geometries(uint32 *num) const; - int geometry_n(uint32 num, String *result) const; - int dimension(uint32 *dim) const; + uint32 get_data_size() const; + bool init_from_wkt(Gis_read_stream *trs, String *wkb); + bool get_data_as_wkt(String *txt, const char **end); + bool get_mbr(MBR *mbr, const char **end) const; + bool num_geometries(uint32 *num) const; + bool geometry_n(uint32 num, String *result) const; + bool dimension(uint32 *dim, const char **end) const; }; #endif diff --git a/sql/sql_string.cc b/sql/sql_string.cc index c6eda5f9fb2..e15beac90b0 100644 --- a/sql/sql_string.cc +++ b/sql/sql_string.cc @@ -126,8 +126,8 @@ bool String::set(double num,uint decimals, CHARSET_INFO *cs) str_charset=cs; if (decimals >= NOT_FIXED_DEC) { - sprintf(buff,"%.14g",num); // Enough for a DATETIME - return copy(buff, (uint32) strlen(buff), &my_charset_latin1, cs); + uint32 len= my_sprintf(buff,(buff, "%.14g",num));// Enough for a DATETIME + return copy(buff, len, &my_charset_latin1, cs); } #ifdef HAVE_FCONVERT int decpt,sign; @@ -671,9 +671,8 @@ int String::reserve(uint32 space_needed, uint32 grow_by) return FALSE; } -void String::qs_append(const char *str) +void String::qs_append(const char *str, uint32 len) { - int len = strlen(str); memcpy(Ptr + str_length, str, len + 1); str_length += len; } @@ -681,8 +680,7 @@ void String::qs_append(const char *str) void String::qs_append(double d) { char *buff = Ptr + str_length; - sprintf(buff,"%.14g", d); - str_length += strlen(buff); + str_length+= my_sprintf(buff, (buff, "%.14g", d)); } void String::qs_append(double *d) @@ -692,12 +690,6 @@ void String::qs_append(double *d) qs_append(ld); } -void String::qs_append(const char &c) -{ - Ptr[str_length] = c; - str_length += sizeof(c); -} - /* Compare strings according to collation, without end space. diff --git a/sql/sql_string.h b/sql/sql_string.h index cdfb00276d4..7f1c56dbfe7 100644 --- a/sql/sql_string.h +++ b/sql/sql_string.h @@ -237,7 +237,7 @@ public: q_*** methods writes values of parameters itself qs_*** methods writes string representation of value */ - void q_append(const char &c) + void q_append(const char c) { Ptr[str_length++] = c; } @@ -262,15 +262,19 @@ public: str_length += data_len; } - void WriteAtPosition(int position, uint32 value) + void write_at_position(int position, uint32 value) { int4store(Ptr + position,value); } - void qs_append(const char *str); + void qs_append(const char *str, uint32 len); void qs_append(double d); void qs_append(double *d); - void qs_append(const char &c); + inline void qs_append(const char c) + { + Ptr[str_length]= c; + str_length++; + } /* Inline (general) functions used by the protocol functions */ diff --git a/sql/structs.h b/sql/structs.h index 37208e63400..0e69bca305c 100644 --- a/sql/structs.h +++ b/sql/structs.h @@ -20,11 +20,21 @@ struct st_table; class Field; -typedef struct lex_string { +typedef struct st_lex_string +{ char *str; uint length; } LEX_STRING; +typedef struct st_lex_string_with_init :public st_lex_string +{ + st_lex_string_with_init(const char *str_arg, uint length_arg) + { + str= (char*) str_arg; + length= length_arg; + } +} LEX_STRING_WITH_INIT; + typedef struct st_date_time_format { uchar positions[8]; |