diff options
author | unknown <paul@teton.kitebird.com> | 2004-03-05 11:16:32 -0600 |
---|---|---|
committer | unknown <paul@teton.kitebird.com> | 2004-03-05 11:16:32 -0600 |
commit | 7e535dceb4d0b4d17c7e8b1e95aa4121012238d8 (patch) | |
tree | 17d1664fbd4de82ae64a6f2657437743f41f5542 /sql | |
parent | 9721346aebbc50dacae57f4c0b77d6757e66bc1a (diff) | |
parent | e3af1fab8c2932ec02861cee5b06d0ad51c45cad (diff) | |
download | mariadb-git-7e535dceb4d0b4d17c7e8b1e95aa4121012238d8.tar.gz |
Merge paul@bk-internal.mysql.com:/home/bk/mysql-4.1
into teton.kitebird.com:/home/paul/mysql-4.1
sql/share/czech/errmsg.txt:
Auto merged
sql/share/danish/errmsg.txt:
Auto merged
sql/share/dutch/errmsg.txt:
Auto merged
sql/share/english/errmsg.txt:
Auto merged
sql/share/estonian/errmsg.txt:
Auto merged
sql/share/french/errmsg.txt:
Auto merged
sql/share/german/errmsg.txt:
Auto merged
sql/share/greek/errmsg.txt:
Auto merged
sql/share/hungarian/errmsg.txt:
Auto merged
sql/share/italian/errmsg.txt:
Auto merged
sql/share/japanese/errmsg.txt:
Auto merged
sql/share/korean/errmsg.txt:
Auto merged
sql/share/norwegian-ny/errmsg.txt:
Auto merged
sql/share/norwegian/errmsg.txt:
Auto merged
sql/share/polish/errmsg.txt:
Auto merged
sql/share/portuguese/errmsg.txt:
Auto merged
sql/share/romanian/errmsg.txt:
Auto merged
sql/share/russian/errmsg.txt:
Auto merged
sql/share/serbian/errmsg.txt:
Auto merged
sql/share/slovak/errmsg.txt:
Auto merged
sql/share/spanish/errmsg.txt:
Auto merged
sql/share/ukrainian/errmsg.txt:
Auto merged
Diffstat (limited to 'sql')
52 files changed, 1934 insertions, 1761 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/ha_myisam.h b/sql/ha_myisam.h index ddffcfecc29..4d66639690d 100644 --- a/sql/ha_myisam.h +++ b/sql/ha_myisam.h @@ -37,7 +37,7 @@ extern ulong myisam_recover_options; class ha_myisam: public handler { MI_INFO *file; - uint int_table_flags; + ulong int_table_flags; char *data_file_name, *index_file_name; bool enable_activate_all_index; int repair(THD *thd, MI_CHECK ¶m, bool optimize); diff --git a/sql/handler.cc b/sql/handler.cc index a81c43fc16c..8a4a6005d85 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -124,7 +124,7 @@ enum db_type ha_checktype(enum db_type database_type) for (types= sys_table_types; types->type; types++) { if ((database_type == types->db_type) && - (SHOW_OPTION_YES == *types->value)) + (*types->value == SHOW_OPTION_YES)) return database_type; } diff --git a/sql/item.h b/sql/item.h index fb93e0ef8ab..727132916f0 100644 --- a/sql/item.h +++ b/sql/item.h @@ -375,9 +375,9 @@ public: bool get_time(TIME *tm); void reset() {} #ifndef EMBEDDED_LIBRARY - void (*setup_param_func)(Item_param *param, uchar **pos); + void (*set_param_func)(Item_param *param, uchar **pos); #else - void (*setup_param_func)(Item_param *param, uchar **pos, ulong data_len); + void (*set_param_func)(Item_param *param, uchar **pos, ulong data_len); #endif enum Item_result result_type () const { return item_result_type; } @@ -533,7 +533,8 @@ public: bool eq(const Item *item, bool binary_cmp) const; Item *new_item() { - return new Item_string(name, str_value.ptr(), max_length, &my_charset_bin); + return new Item_string(name, str_value.ptr(), + str_value.length(), &my_charset_bin); } String *const_string() { return &str_value; } inline void append(char *str, uint length) { str_value.append(str, length); } diff --git a/sql/item_create.cc b/sql/item_create.cc index eda3d43afdc..74f36de11ac 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -426,6 +426,11 @@ Item *create_func_ucase(Item* a) return new Item_func_ucase(a); } +Item *create_func_unhex(Item* a) +{ + return new Item_func_unhex(a); +} + Item *create_func_uuid(void) { return new Item_func_uuid(); @@ -460,6 +465,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_create.h b/sql/item_create.h index a6a3c9e1841..7577627ef04 100644 --- a/sql/item_create.h +++ b/sql/item_create.h @@ -92,6 +92,7 @@ Item *create_func_time_format(Item *a, Item *b); Item *create_func_time_to_sec(Item* a); Item *create_func_to_days(Item* a); Item *create_func_ucase(Item* a); +Item *create_func_unhex(Item* a); Item *create_func_uuid(void); Item *create_func_version(void); Item *create_func_weekday(Item* a); 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/item_strfunc.cc b/sql/item_strfunc.cc index 216df5c17d6..b9604cf900b 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -2231,7 +2231,7 @@ String *Item_func_hex::val_str(String *str) null_value=0; tmp_value.length(res->length()*2); for (from=res->ptr(), end=from+res->length(), to= (char*) tmp_value.ptr(); - from != end ; + from < end ; from++, to+=2) { uint tmp=(uint) (uchar) *from; @@ -2241,6 +2241,48 @@ String *Item_func_hex::val_str(String *str) return &tmp_value; } +int inline hexchar_to_int(char c) +{ + if (c <= '9' && c >= '0') + return c-'0'; + c|=32; + if (c <= 'f' && c >= 'a') + return c-'a'+10; + return -1; +} + +String *Item_func_unhex::val_str(String *str) +{ + /* Convert given hex string to a binary string */ + String *res= args[0]->val_str(str); + const char *from=res->ptr(), *end; + char *to; + int r; + if (!res || tmp_value.alloc((1+res->length())/2)) + { + null_value=1; + return 0; + } + null_value=0; + tmp_value.length((1+res->length())/2); + to= (char*) tmp_value.ptr(); + if (res->length() % 2) + { + *to++= r= hexchar_to_int(*from++); + if ((null_value= (r == -1))) + return 0; + } + for (end=res->ptr()+res->length(); from < end ; from+=2, to++) + { + *to= (r= hexchar_to_int(from[0])) << 4; + if ((null_value= (r == -1))) + return 0; + *to|= r= hexchar_to_int(from[1]); + if ((null_value= (r == -1))) + return 0; + } + return &tmp_value; +} void Item_func_binary::print(String *str) { @@ -2654,14 +2696,6 @@ static const char hex[] = "0123456789abcdef"; #define UUID_VERSION 0x1000 #define UUID_VARIANT 0x8000 -static ulonglong get_uuid_time() -{ - struct timeval tv; - gettimeofday(&tv,NULL); - return (ulonglong)tv.tv_sec*10000000 + - (ulonglong)tv.tv_usec*10 + UUID_TIME_OFFSET + nanoseq; -} - static void tohex(char *to, uint from, uint len) { to+= len; @@ -2710,7 +2744,7 @@ String *Item_func_uuid::val_str(String *str) set_clock_seq_str(); } - ulonglong tv=get_uuid_time(); + ulonglong tv=my_getsystime() + UUID_TIME_OFFSET + nanoseq; if (unlikely(tv < uuid_time)) set_clock_seq_str(); else diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index 7eb0750711f..5b9c442b5db 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -500,10 +500,10 @@ public: Item_func_conv(Item *a,Item *b,Item *c) :Item_str_func(a,b,c) {} const char *func_name() const { return "conv"; } String *val_str(String *); - void fix_length_and_dec() - { + void fix_length_and_dec() + { collation.set(default_charset()); - decimals=0; max_length=64; + decimals=0; max_length=64; } }; @@ -515,14 +515,29 @@ public: Item_func_hex(Item *a) :Item_str_func(a) {} const char *func_name() const { return "hex"; } String *val_str(String *); - void fix_length_and_dec() - { + void fix_length_and_dec() + { collation.set(default_charset()); decimals=0; max_length=args[0]->max_length*2*collation.collation->mbmaxlen; } }; +class Item_func_unhex :public Item_str_func +{ + String tmp_value; +public: + Item_func_unhex(Item *a) :Item_str_func(a) {} + const char *func_name() const { return "unhex"; } + String *val_str(String *); + void fix_length_and_dec() + { + collation.set(&my_charset_bin); + decimals=0; + max_length=(1+args[0]->max_length)/2; + } +}; + class Item_func_binary :public Item_str_func { @@ -536,10 +551,10 @@ public: tmp->set_charset(&my_charset_bin); return tmp; } - void fix_length_and_dec() - { - collation.set(&my_charset_bin); - max_length=args[0]->max_length; + void fix_length_and_dec() + { + collation.set(&my_charset_bin); + max_length=args[0]->max_length; } void print(String *str); }; @@ -553,7 +568,7 @@ public: String *val_str(String *); const char *func_name() const { return "load_file"; } void fix_length_and_dec() - { + { collation.set(&my_charset_bin, DERIVATION_COERCIBLE); maybe_null=1; max_length=MAX_BLOB_WIDTH; diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index bfe41726f72..372f086d464 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -198,6 +198,12 @@ bool Item_subselect::const_item() const return const_item_cache; } +Item *Item_subselect::get_tmp_table_item(THD *thd) +{ + if (!with_sum_func && !const_item()) + return new Item_field(result_field); + return copy_or_same(thd); +} void Item_subselect::update_used_tables() { diff --git a/sql/item_subselect.h b/sql/item_subselect.h index d550cde64b7..e68c882ba3e 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -99,6 +99,7 @@ public: bool const_item() const; inline table_map get_used_tables_cache() { return used_tables_cache; } inline bool get_const_item_cache() { return const_item_cache; } + Item *get_tmp_table_item(THD *thd); void update_used_tables(); void print(String *str); bool change_engine(subselect_engine *eng) diff --git a/sql/lex.h b/sql/lex.h index 9cdb1067d91..3b32d2bcd3b 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -671,6 +671,7 @@ static SYMBOL sql_functions[] = { { "UCASE", F_SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_ucase)}, { "UNCOMPRESS", F_SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_uncompress)}, { "UNCOMPRESSED_LENGTH", F_SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_uncompressed_length)}, + { "UNHEX", F_SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_unhex)}, { "UNIQUE_USERS", SYM(UNIQUE_USERS)}, { "UNIX_TIMESTAMP", SYM(UNIX_TIMESTAMP)}, { "UPPER", F_SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_ucase)}, diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 535c1cb16be..2d22d9c5891 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -620,14 +620,13 @@ int mysqld_show_column_types(THD *thd); int mysqld_help (THD *thd, const char *text); /* sql_prepare.cc */ -bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length); +void mysql_stmt_prepare(THD *thd, char *packet, uint packet_length); void mysql_stmt_execute(THD *thd, char *packet); void mysql_stmt_free(THD *thd, char *packet); void mysql_stmt_reset(THD *thd, char *packet); void mysql_stmt_get_longdata(THD *thd, char *pos, ulong packet_length); int check_insert_fields(THD *thd,TABLE *table,List<Item> &fields, List<Item> &values, ulong counter); -void setup_param_functions(Item_param *param, uchar param_type); /* sql_error.cc */ MYSQL_ERROR *push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level, uint code, diff --git a/sql/protocol.h b/sql/protocol.h index 67ae4ed01b4..17c8f0d321d 100644 --- a/sql/protocol.h +++ b/sql/protocol.h @@ -178,8 +178,3 @@ char *net_store_data(char *to,const char *from, uint length); char *net_store_data(char *to,int32 from); char *net_store_data(char *to,longlong from); -#ifdef EMBEDDED_LIBRARY -bool setup_params_data(struct st_prep_stmt *stmt); -bool setup_params_data_withlog(struct st_prep_stmt *stmt); -#endif - diff --git a/sql/share/czech/errmsg.txt b/sql/share/czech/errmsg.txt index 074aa71fb4e..e05e21e22a5 100644 --- a/sql/share/czech/errmsg.txt +++ b/sql/share/czech/errmsg.txt @@ -301,5 +301,5 @@ character-set=latin2 "Unknown table engine '%s'", "'%s' is deprecated, use '%s' instead", "The target table %-.100s of the %s is not updatable", -"The '%s' feature was disabled; you need MySQL built with '%s' define to have it working", +"The '%s' feature was disabled; you need MySQL built with '%s' to have it working", "The MySQL server is running with the %s option so it cannot execute this statement", diff --git a/sql/share/danish/errmsg.txt b/sql/share/danish/errmsg.txt index eef22418fe6..45de00cfc39 100644 --- a/sql/share/danish/errmsg.txt +++ b/sql/share/danish/errmsg.txt @@ -295,5 +295,5 @@ character-set=latin1 "Unknown table engine '%s'", "'%s' is deprecated, use '%s' instead", "The target table %-.100s of the %s is not updateable", -"The '%s' feature was disabled; you need MySQL built with '%s' define to have it working", +"The '%s' feature was disabled; you need MySQL built with '%s' to have it working", "The MySQL server is running with the %s option so it cannot execute this statement", diff --git a/sql/share/dutch/errmsg.txt b/sql/share/dutch/errmsg.txt index 7b9eeb5f7f9..73386f49ab2 100644 --- a/sql/share/dutch/errmsg.txt +++ b/sql/share/dutch/errmsg.txt @@ -303,5 +303,5 @@ character-set=latin1 "Unknown table engine '%s'", "'%s' is deprecated, use '%s' instead", "The target table %-.100s of the %s is not updateable", -"The '%s' feature was disabled; you need MySQL built with '%s' define to have it working", +"The '%s' feature was disabled; you need MySQL built with '%s' to have it working", "The MySQL server is running with the %s option so it cannot execute this statement", diff --git a/sql/share/english/errmsg.txt b/sql/share/english/errmsg.txt index c1ed2ec050c..196b55495ed 100644 --- a/sql/share/english/errmsg.txt +++ b/sql/share/english/errmsg.txt @@ -292,5 +292,5 @@ character-set=latin1 "Unknown table engine '%s'", "'%s' is deprecated, use '%s' instead", "The target table %-.100s of the %s is not updatable", -"The '%s' feature was disabled; you need MySQL built with '%s' define to have it working", +"The '%s' feature was disabled; you need MySQL built with '%s' to have it working", "The MySQL server is running with the %s option so it cannot execute this statement", diff --git a/sql/share/estonian/errmsg.txt b/sql/share/estonian/errmsg.txt index 5b2a8bd5edb..8b6d0b4cea4 100644 --- a/sql/share/estonian/errmsg.txt +++ b/sql/share/estonian/errmsg.txt @@ -297,5 +297,5 @@ character-set=latin7 "Unknown table engine '%s'", "'%s' is deprecated, use '%s' instead", "The target table %-.100s of the %s is not updateable", -"The '%s' feature was disabled; you need MySQL built with '%s' define to have it working", +"The '%s' feature was disabled; you need MySQL built with '%s' to have it working", "The MySQL server is running with the %s option so it cannot execute this statement", diff --git a/sql/share/french/errmsg.txt b/sql/share/french/errmsg.txt index a0f8926c5a8..307bf841eab 100644 --- a/sql/share/french/errmsg.txt +++ b/sql/share/french/errmsg.txt @@ -292,5 +292,5 @@ character-set=latin1 "Unknown table engine '%s'", "'%s' is deprecated, use '%s' instead", "The target table %-.100s of the %s is not updateable", -"The '%s' feature was disabled; you need MySQL built with '%s' define to have it working", +"The '%s' feature was disabled; you need MySQL built with '%s' to have it working", "The MySQL server is running with the %s option so it cannot execute this statement", diff --git a/sql/share/german/errmsg.txt b/sql/share/german/errmsg.txt index 12e0b7d1cd2..11dc38e6449 100644 --- a/sql/share/german/errmsg.txt +++ b/sql/share/german/errmsg.txt @@ -304,5 +304,5 @@ character-set=latin1 "Unknown table engine '%s'", "'%s' is deprecated, use '%s' instead", "The target table %-.100s of the %s is not updateable", -"The '%s' feature was disabled; you need MySQL built with '%s' define to have it working", +"The '%s' feature was disabled; you need MySQL built with '%s' to have it working", "The MySQL server is running with the %s option so it cannot execute this statement", diff --git a/sql/share/greek/errmsg.txt b/sql/share/greek/errmsg.txt index f2e3fe617a3..0aa6796751b 100644 --- a/sql/share/greek/errmsg.txt +++ b/sql/share/greek/errmsg.txt @@ -292,5 +292,5 @@ character-set=greek "Unknown table engine '%s'", "'%s' is deprecated, use '%s' instead", "The target table %-.100s of the %s is not updateable", -"The '%s' feature was disabled; you need MySQL built with '%s' define to have it working", +"The '%s' feature was disabled; you need MySQL built with '%s' to have it working", "The MySQL server is running with the %s option so it cannot execute this statement", diff --git a/sql/share/hungarian/errmsg.txt b/sql/share/hungarian/errmsg.txt index bf2d1d6316c..31514de6455 100644 --- a/sql/share/hungarian/errmsg.txt +++ b/sql/share/hungarian/errmsg.txt @@ -294,5 +294,5 @@ character-set=latin2 "Unknown table engine '%s'", "'%s' is deprecated, use '%s' instead", "The target table %-.100s of the %s is not updateable", -"The '%s' feature was disabled; you need MySQL built with '%s' define to have it working", +"The '%s' feature was disabled; you need MySQL built with '%s' to have it working", "The MySQL server is running with the %s option so it cannot execute this statement", diff --git a/sql/share/italian/errmsg.txt b/sql/share/italian/errmsg.txt index 8a70fdb09e5..61f62a9e7e7 100644 --- a/sql/share/italian/errmsg.txt +++ b/sql/share/italian/errmsg.txt @@ -292,5 +292,5 @@ character-set=latin1 "Unknown table engine '%s'", "'%s' is deprecated, use '%s' instead", "The target table %-.100s of the %s is not updateable", -"The '%s' feature was disabled; you need MySQL built with '%s' define to have it working", +"The '%s' feature was disabled; you need MySQL built with '%s' to have it working", "The MySQL server is running with the %s option so it cannot execute this statement", diff --git a/sql/share/japanese/errmsg.txt b/sql/share/japanese/errmsg.txt index e3589fdd287..89d98d994e5 100644 --- a/sql/share/japanese/errmsg.txt +++ b/sql/share/japanese/errmsg.txt @@ -294,5 +294,5 @@ character-set=ujis "Unknown table engine '%s'", "'%s' is deprecated, use '%s' instead", "The target table %-.100s of the %s is not updateable", -"The '%s' feature was disabled; you need MySQL built with '%s' define to have it working", +"The '%s' feature was disabled; you need MySQL built with '%s' to have it working", "The MySQL server is running with the %s option so it cannot execute this statement", diff --git a/sql/share/korean/errmsg.txt b/sql/share/korean/errmsg.txt index 1857aca10ff..1ad548ae878 100644 --- a/sql/share/korean/errmsg.txt +++ b/sql/share/korean/errmsg.txt @@ -292,5 +292,5 @@ character-set=euckr "Unknown table engine '%s'", "'%s' is deprecated, use '%s' instead", "The target table %-.100s of the %s is not updateable", -"The '%s' feature was disabled; you need MySQL built with '%s' define to have it working", +"The '%s' feature was disabled; you need MySQL built with '%s' to have it working", "The MySQL server is running with the %s option so it cannot execute this statement", diff --git a/sql/share/norwegian-ny/errmsg.txt b/sql/share/norwegian-ny/errmsg.txt index 3959f270012..b82648ce210 100644 --- a/sql/share/norwegian-ny/errmsg.txt +++ b/sql/share/norwegian-ny/errmsg.txt @@ -294,5 +294,5 @@ character-set=latin1 "Unknown table engine '%s'", "'%s' is deprecated, use '%s' instead", "The target table %-.100s of the %s is not updateable", -"The '%s' feature was disabled; you need MySQL built with '%s' define to have it working", +"The '%s' feature was disabled; you need MySQL built with '%s' to have it working", "The MySQL server is running with the %s option so it cannot execute this statement", diff --git a/sql/share/norwegian/errmsg.txt b/sql/share/norwegian/errmsg.txt index 96aeb9cdae6..2198113876f 100644 --- a/sql/share/norwegian/errmsg.txt +++ b/sql/share/norwegian/errmsg.txt @@ -294,5 +294,5 @@ character-set=latin1 "Unknown table engine '%s'", "'%s' is deprecated, use '%s' instead", "The target table %-.100s of the %s is not updateable", -"The '%s' feature was disabled; you need MySQL built with '%s' define to have it working", +"The '%s' feature was disabled; you need MySQL built with '%s' to have it working", "The MySQL server is running with the %s option so it cannot execute this statement", diff --git a/sql/share/polish/errmsg.txt b/sql/share/polish/errmsg.txt index 5994a5e0b0f..5dfe6e251ad 100644 --- a/sql/share/polish/errmsg.txt +++ b/sql/share/polish/errmsg.txt @@ -296,5 +296,5 @@ character-set=latin2 "Unknown table engine '%s'", "'%s' is deprecated, use '%s' instead", "The target table %-.100s of the %s is not updateable", -"The '%s' feature was disabled; you need MySQL built with '%s' define to have it working", +"The '%s' feature was disabled; you need MySQL built with '%s' to have it working", "The MySQL server is running with the %s option so it cannot execute this statement", diff --git a/sql/share/portuguese/errmsg.txt b/sql/share/portuguese/errmsg.txt index 2ebee11237d..508a7880749 100644 --- a/sql/share/portuguese/errmsg.txt +++ b/sql/share/portuguese/errmsg.txt @@ -293,5 +293,5 @@ character-set=latin1 "Motor de tabela desconhecido '%s'", "'%s' é desatualizado. Use '%s' em seu lugar", "The target table %-.100s of the %s is not updateable", -"The '%s' feature was disabled; you need MySQL built with '%s' define to have it working", +"The '%s' feature was disabled; you need MySQL built with '%s' to have it working", "The MySQL server is running with the %s option so it cannot execute this statement", diff --git a/sql/share/romanian/errmsg.txt b/sql/share/romanian/errmsg.txt index 7e1dcb9eddd..42027b3915b 100644 --- a/sql/share/romanian/errmsg.txt +++ b/sql/share/romanian/errmsg.txt @@ -296,5 +296,5 @@ character-set=latin2 "Unknown table engine '%s'", "'%s' is deprecated, use '%s' instead", "The target table %-.100s of the %s is not updateable", -"The '%s' feature was disabled; you need MySQL built with '%s' define to have it working", +"The '%s' feature was disabled; you need MySQL built with '%s' to have it working", "The MySQL server is running with the %s option so it cannot execute this statement", diff --git a/sql/share/russian/errmsg.txt b/sql/share/russian/errmsg.txt index cd32d591712..50ee6416070 100644 --- a/sql/share/russian/errmsg.txt +++ b/sql/share/russian/errmsg.txt @@ -294,5 +294,5 @@ character-set=koi8r "Unknown table engine '%s'", "'%s' is deprecated, use '%s' instead", "ôÁÂÌÉÃÁ %-.100s × %s ÎÅ ÍÏÖÅÔ ÉÚÍÅÎÑÔÓÑ", -"The '%s' feature was disabled; you need MySQL built with '%s' define to have it working", +"The '%s' feature was disabled; you need MySQL built with '%s' to have it working", "The MySQL server is running with the %s option so it cannot execute this statement", diff --git a/sql/share/serbian/errmsg.txt b/sql/share/serbian/errmsg.txt index 58d8db4df13..d51a2d4450d 100644 --- a/sql/share/serbian/errmsg.txt +++ b/sql/share/serbian/errmsg.txt @@ -286,5 +286,5 @@ character-set=cp1250 "Unknown table engine '%s'", "'%s' is deprecated, use '%s' instead", "The target table %-.100s of the %s is not updatable", -"The '%s' feature was disabled; you need MySQL built with '%s' define to have it working" +"The '%s' feature was disabled; you need MySQL built with '%s' to have it working" "The MySQL server is running with the %s option so it cannot execute this statement" diff --git a/sql/share/slovak/errmsg.txt b/sql/share/slovak/errmsg.txt index 78048c9e34b..6f6b743862c 100644 --- a/sql/share/slovak/errmsg.txt +++ b/sql/share/slovak/errmsg.txt @@ -300,5 +300,5 @@ character-set=latin2 "Unknown table engine '%s'", "'%s' is deprecated, use '%s' instead", "The target table %-.100s of the %s is not updateable", -"The '%s' feature was disabled; you need MySQL built with '%s' define to have it working", +"The '%s' feature was disabled; you need MySQL built with '%s' to have it working", "The MySQL server is running with the %s option so it cannot execute this statement", diff --git a/sql/share/spanish/errmsg.txt b/sql/share/spanish/errmsg.txt index f9336272162..da0633edb74 100644 --- a/sql/share/spanish/errmsg.txt +++ b/sql/share/spanish/errmsg.txt @@ -294,5 +294,5 @@ character-set=latin1 "Unknown table engine '%s'", "'%s' is deprecated, use '%s' instead", "The target table %-.100s of the %s is not updateable", -"The '%s' feature was disabled; you need MySQL built with '%s' define to have it working", +"The '%s' feature was disabled; you need MySQL built with '%s' to have it working", "The MySQL server is running with the %s option so it cannot execute this statement", diff --git a/sql/share/ukrainian/errmsg.txt b/sql/share/ukrainian/errmsg.txt index 1c9101d5173..cb949e2d026 100644 --- a/sql/share/ukrainian/errmsg.txt +++ b/sql/share/ukrainian/errmsg.txt @@ -297,5 +297,5 @@ character-set=koi8u "Unknown table engine '%s'", "'%s' is deprecated, use '%s' instead", "ôÁÂÌÉÃÑ %-.100s Õ %s ÎÅ ÍÏÖÅ ÏÎÏ×ÌÀ×ÁÔÉÓØ", -"The '%s' feature was disabled; you need MySQL built with '%s' define to have it working", +"The '%s' feature was disabled; you need MySQL built with '%s' to have it working", "The MySQL server is running with the %s option so it cannot execute this statement", diff --git a/sql/slave.cc b/sql/slave.cc index bbf1741183b..e737febdd8a 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -2060,10 +2060,29 @@ int show_master_info(THD* thd, MASTER_INFO* mi) protocol->store(mi->ssl_key, &my_charset_bin); if (mi->rli.last_master_timestamp) - protocol->store((ulonglong) - (long)((time_t)time((time_t*) 0) - - mi->rli.last_master_timestamp) - - mi->clock_diff_with_master); + { + long tmp= (long)((time_t)time((time_t*) 0) + - mi->rli.last_master_timestamp) + - mi->clock_diff_with_master; + /* + Apparently on some systems tmp can be <0. Here are possible reasons + related to MySQL: + - the master is itself a slave of another master whose time is ahead. + - somebody used an explicit SET TIMESTAMP on the master. + Possible reason related to granularity-to-second of time functions + (nothing to do with MySQL), which can explain a value of -1: + assume the master's and slave's time are perfectly synchronized, and + that at slave's connection time, when the master's timestamp is read, + it is at the very end of second 1, and (a very short time later) when + the slave's timestamp is read it is at the very beginning of second + 2. Then the recorded value for master is 1 and the recorded value for + slave is 2. At SHOW SLAVE STATUS time, assume that the difference + between timestamp of slave and rli->last_master_timestamp is 0 + (i.e. they are in the same second), then we get 0-(2-1)=-1 as a result. + This confuses users, so we don't go below 0. + */ + protocol->store((longlong)(max(0, tmp))); + } else protocol->store_null(); 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_class.cc b/sql/sql_class.cc index 6fe0521b07a..95374b691c8 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -145,8 +145,7 @@ THD::THD():user_time(0), current_statement(0), is_fatal_error(0), init(); /* Initialize sub structures */ - bzero((char*) &transaction.mem_root,sizeof(transaction.mem_root)); - bzero((char*) &warn_root,sizeof(warn_root)); + clear_alloc_root(&transaction.mem_root); init_alloc_root(&warn_root, WARN_ALLOC_BLOCK_SIZE, WARN_ALLOC_PREALLOC_SIZE); user_connect=(USER_CONN *)0; hash_init(&user_vars, &my_charset_bin, USER_VARS_HASH_SIZE, 0, 0, @@ -331,7 +330,7 @@ THD::~THD() dbug_sentry = THD_SENTRY_GONE; #endif /* Reset stmt_backup.mem_root to not double-free memory from thd.mem_root */ - init_alloc_root(&stmt_backup.mem_root, 0, 0); + clear_alloc_root(&stmt_backup.mem_root); DBUG_VOID_RETURN; } @@ -1185,10 +1184,8 @@ int select_dumpvar::prepare(List<Item> &list, SELECT_LEX_UNIT *u) Statement::Statement(THD *thd) :id(++thd->statement_id_counter), - query_id(thd->query_id), set_query_id(1), allow_sum_func(0), - command(thd->command), lex(&main_lex), query(0), query_length(0), @@ -1207,10 +1204,8 @@ Statement::Statement(THD *thd) Statement::Statement() :id(0), - query_id(0), /* initialized later */ set_query_id(1), allow_sum_func(0), /* initialized later */ - command(COM_SLEEP), /* initialized later */ lex(&main_lex), query(0), /* these two are set */ query_length(0), /* in alloc_query() */ @@ -1229,15 +1224,11 @@ Statement::Type Statement::type() const void Statement::set_statement(Statement *stmt) { id= stmt->id; - query_id= stmt->query_id; set_query_id= stmt->set_query_id; allow_sum_func= stmt->allow_sum_func; - command= stmt->command; lex= stmt->lex; query= stmt->query; query_length= stmt->query_length; - free_list= stmt->free_list; - mem_root= stmt->mem_root; } diff --git a/sql/sql_class.h b/sql/sql_class.h index d0ad8a4e681..567135b1378 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -435,15 +435,6 @@ public: ulong id; /* - Id of current query. Statement can be reused to execute several queries - query_id is global in context of the whole MySQL server. - ID is automatically generated from mutex-protected counter. - It's used in handler code for various purposes: to check which columns - from table are necessary for this select, to check if it's necessary to - update auto-updatable fields (like auto_increment and timestamp). - */ - ulong query_id; - /* - if set_query_id=1, we set field->query_id for all fields. In that case field list can not contain duplicates. */ @@ -461,11 +452,6 @@ public: See item_sum.cc for details. */ bool allow_sum_func; - /* - Type of current query: COM_PREPARE, COM_QUERY, etc. Set from - first byte of the packet in do_command() - */ - enum enum_server_command command; LEX *lex; // parse tree descriptor /* @@ -676,6 +662,11 @@ public: uint dbug_sentry; // watch out for memory corruption #endif struct st_my_thread_var *mysys_var; + /* + Type of current query: COM_PREPARE, COM_QUERY, etc. Set from + first byte of the packet in do_command() + */ + enum enum_server_command command; uint32 server_id; uint32 file_id; // for LOAD DATA INFILE /* @@ -751,6 +742,15 @@ public: List <MYSQL_ERROR> warn_list; uint warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_END]; uint total_warn_count; + /* + Id of current query. Statement can be reused to execute several queries + query_id is global in context of the whole MySQL server. + ID is automatically generated from mutex-protected counter. + It's used in handler code for various purposes: to check which columns + from table are necessary for this select, to check if it's necessary to + update auto-updatable fields (like auto_increment and timestamp). + */ + ulong query_id; ulong warn_id, version, options, thread_id, col_access; /* Statement id is thread-wide. This counter is used to generate ids */ diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 17cccd75697..ba8fe0d8792 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -552,7 +552,7 @@ typedef struct st_lex List<Item> *insert_list,field_list,value_list; List<List_item> many_values; List<set_var_base> var_list; - List<Item> param_list; + List<Item_param> param_list; SQL_LIST proc_list, auxilliary_table_list, save_list; TYPELIB *interval; create_field *last_field; @@ -577,7 +577,6 @@ typedef struct st_lex uint uint_geom_type; uint grant, grant_tot_col, which_columns; uint fk_delete_opt, fk_update_opt, fk_match_option; - uint param_count; uint slave_thd_opt; uint8 describe; bool drop_if_exists, drop_temporary, local_file; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index a09f3d28a0f..99a8a248d24 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1232,10 +1232,34 @@ bool do_command(THD *thd) command_name[command])); } net->read_timeout=old_timeout; // restore it + /* + packet_length contains length of data, as it was stored in packet + header. In case of malformed header, packet_length can be zero. + If packet_length is not zero, my_net_read ensures that this number + of bytes was actually read from network. Additionally my_net_read + sets packet[packet_length]= 0 (thus if packet_length == 0, + command == packet[0] == COM_SLEEP). + In dispatch_command packet[packet_length] points beyond the end of packet. + */ DBUG_RETURN(dispatch_command(command,thd, packet+1, (uint) packet_length)); } #endif /* EMBEDDED_LIBRARY */ +/* + Perform one connection-level (COM_XXXX) command. + SYNOPSIS + dispatch_command() + thd connection handle + command type of command to perform + packet data for the command, packet is always null-terminated + packet_length length of packet + 1 (to show that data is + null-terminated) except for COM_SLEEP, where it + can be zero. + RETURN VALUE + 0 ok + 1 request of thread shutdown, i. e. if command is + COM_QUIT/COM_SHUTDOWN +*/ bool dispatch_command(enum enum_server_command command, THD *thd, char* packet, uint packet_length) diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 7c2913bc495..ac5b7847647 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -39,7 +39,7 @@ Prepare-execute: - Server gets the command 'COM_EXECUTE' to execute the previously prepared query. If there is any param markers; then client - will send the data in the following format: + will send the data in the following format: [COM_EXECUTE:1] [STMT_ID:4] [NULL_BITS:(param_count+7)/8)] @@ -86,16 +86,17 @@ class Prepared_statement: public Statement { public: THD *thd; - Item_param **param; /* array of all placeholders */ + Item_param **param_array; uint param_count; uint last_errno; char last_error[MYSQL_ERRMSG_SIZE]; - bool error_in_prepare, long_data_used; + bool get_longdata_error; + bool long_data_used; bool log_full_query; #ifndef EMBEDDED_LIBRARY - bool (*setup_params)(Prepared_statement *st, uchar *pos, uchar *read_pos); + bool (*set_params)(Prepared_statement *st, uchar *pos, uchar *read_pos); #else - bool (*setup_params_data)(Prepared_statement *st); + bool (*set_params_data)(Prepared_statement *st); #endif public: Prepared_statement(THD *thd_arg); @@ -117,13 +118,14 @@ inline bool is_param_null(const uchar *pos, ulong param_no) enum { STMT_QUERY_LOG_LENGTH= 8192 }; #ifdef EMBEDDED_LIBRARY -#define SETUP_PARAM_FUNCTION(fn_name) \ +#define SET_PARAM_FUNCTION(fn_name) \ static void fn_name(Item_param *param, uchar **pos, ulong data_len) #else -#define SETUP_PARAM_FUNCTION(fn_name) \ +#define SET_PARAM_FUNCTION(fn_name) \ static void fn_name(Item_param *param, uchar **pos) #endif +enum enum_send_error { DONT_SEND_ERROR= 0, SEND_ERROR }; /* Seek prepared statement in statement map by id: returns zero if statement @@ -131,14 +133,16 @@ static void fn_name(Item_param *param, uchar **pos) */ static Prepared_statement * -find_prepared_statement(THD *thd, ulong id, const char *where) +find_prepared_statement(THD *thd, ulong id, const char *where, + enum enum_send_error se) { Statement *stmt= thd->stmt_map.find(id); if (stmt == 0 || stmt->type() != Statement::PREPARED_STATEMENT) { my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), id, where); - send_error(thd); + if (se == SEND_ERROR) + send_error(thd); return 0; } return (Prepared_statement *) stmt; @@ -154,11 +158,11 @@ static bool send_prep_stmt(Prepared_statement *stmt, uint columns) { NET *net= &stmt->thd->net; char buff[9]; - buff[0]= 0; + buff[0]= 0; /* OK packet indicator */ int4store(buff+1, stmt->id); int2store(buff+5, columns); int2store(buff+7, stmt->param_count); - /* This should be fixed to work with prepared statements */ + /* TODO: send types of placeholders here */ return (my_net_write(net, buff, sizeof(buff)) || net_flush(net)); } #else @@ -177,8 +181,8 @@ static bool send_prep_stmt(Prepared_statement *stmt, /* - Read the length of the parameter data and retun back to - caller by positing the pointer to param data + Read the length of the parameter data and return back to + caller by positing the pointer to param data. */ #ifndef EMBEDDED_LIBRARY @@ -208,49 +212,49 @@ static ulong get_param_length(uchar **packet) #endif /*!EMBEDDED_LIBRARY*/ /* - Setup param conversion routines - - setup_param_xx() - param Parameter Item - pos Input data buffer + Data conversion routines + SYNOPSIS + set_param_xx() + param parameter item + pos input data buffer + len length of data in the buffer - All these functions reads the data from pos and sets up that data - through 'param' and advances the buffer position to predifined - length position. + All these functions read the data from pos, convert it to requested type + and assign to param; pos is advanced to predefined length. Make a note that the NULL handling is examined at first execution (i.e. when input types altered) and for all subsequent executions we don't read any values for this. - RETURN VALUES - + RETURN VALUE + none */ -SETUP_PARAM_FUNCTION(setup_param_tiny) +SET_PARAM_FUNCTION(set_param_tiny) { param->set_int((longlong)(**pos)); *pos+= 1; } -SETUP_PARAM_FUNCTION(setup_param_short) +SET_PARAM_FUNCTION(set_param_short) { param->set_int((longlong)sint2korr(*pos)); *pos+= 2; } -SETUP_PARAM_FUNCTION(setup_param_int32) +SET_PARAM_FUNCTION(set_param_int32) { param->set_int((longlong)sint4korr(*pos)); *pos+= 4; } -SETUP_PARAM_FUNCTION(setup_param_int64) +SET_PARAM_FUNCTION(set_param_int64) { param->set_int((longlong)sint8korr(*pos)); *pos+= 8; } -SETUP_PARAM_FUNCTION(setup_param_float) +SET_PARAM_FUNCTION(set_param_float) { float data; float4get(data,*pos); @@ -258,7 +262,7 @@ SETUP_PARAM_FUNCTION(setup_param_float) *pos+= 4; } -SETUP_PARAM_FUNCTION(setup_param_double) +SET_PARAM_FUNCTION(set_param_double) { double data; float8get(data,*pos); @@ -266,14 +270,14 @@ SETUP_PARAM_FUNCTION(setup_param_double) *pos+= 8; } -SETUP_PARAM_FUNCTION(setup_param_time) +SET_PARAM_FUNCTION(set_param_time) { ulong length; if ((length= get_param_length(pos))) { uchar *to= *pos; - TIME tm; + TIME tm; tm.second_part= (length > 8 ) ? (ulong) sint4korr(to+7): 0; @@ -290,11 +294,11 @@ SETUP_PARAM_FUNCTION(setup_param_time) *pos+= length; } -SETUP_PARAM_FUNCTION(setup_param_datetime) +SET_PARAM_FUNCTION(set_param_datetime) { - uint length= get_param_length(pos); + uint length; - if (length) + if ((length= get_param_length(pos))) { uchar *to= *pos; TIME tm; @@ -320,7 +324,7 @@ SETUP_PARAM_FUNCTION(setup_param_datetime) *pos+= length; } -SETUP_PARAM_FUNCTION(setup_param_date) +SET_PARAM_FUNCTION(set_param_date) { ulong length; @@ -342,55 +346,55 @@ SETUP_PARAM_FUNCTION(setup_param_date) *pos+= length; } -SETUP_PARAM_FUNCTION(setup_param_str) +SET_PARAM_FUNCTION(set_param_str) { ulong len= get_param_length(pos); param->set_value((const char *)*pos, len); - *pos+= len; + *pos+= len; } -void setup_param_functions(Item_param *param, uchar param_type) +static void setup_one_conversion_function(Item_param *param, uchar param_type) { switch (param_type) { case FIELD_TYPE_TINY: - param->setup_param_func= setup_param_tiny; + param->set_param_func= set_param_tiny; param->item_result_type= INT_RESULT; break; case FIELD_TYPE_SHORT: - param->setup_param_func= setup_param_short; + param->set_param_func= set_param_short; param->item_result_type= INT_RESULT; break; case FIELD_TYPE_LONG: - param->setup_param_func= setup_param_int32; + param->set_param_func= set_param_int32; param->item_result_type= INT_RESULT; break; case FIELD_TYPE_LONGLONG: - param->setup_param_func= setup_param_int64; + param->set_param_func= set_param_int64; param->item_result_type= INT_RESULT; break; case FIELD_TYPE_FLOAT: - param->setup_param_func= setup_param_float; + param->set_param_func= set_param_float; param->item_result_type= REAL_RESULT; break; case FIELD_TYPE_DOUBLE: - param->setup_param_func= setup_param_double; + param->set_param_func= set_param_double; param->item_result_type= REAL_RESULT; break; case FIELD_TYPE_TIME: - param->setup_param_func= setup_param_time; + param->set_param_func= set_param_time; param->item_result_type= STRING_RESULT; break; case FIELD_TYPE_DATE: - param->setup_param_func= setup_param_date; + param->set_param_func= set_param_date; param->item_result_type= STRING_RESULT; break; case MYSQL_TYPE_DATETIME: case MYSQL_TYPE_TIMESTAMP: - param->setup_param_func= setup_param_datetime; + param->set_param_func= set_param_datetime; param->item_result_type= STRING_RESULT; break; default: - param->setup_param_func= setup_param_str; + param->set_param_func= set_param_str; param->item_result_type= STRING_RESULT; } } @@ -404,11 +408,11 @@ void setup_param_functions(Item_param *param, uchar param_type) static bool insert_params_withlog(Prepared_statement *stmt, uchar *pos, uchar *read_pos) { - THD *thd= stmt->thd; - List<Item> ¶ms= stmt->lex->param_list; - List_iterator<Item> param_iterator(params); - Item_param *param; - + THD *thd= stmt->thd; + Item_param **begin= stmt->param_array; + Item_param **end= begin + stmt->param_count; + uint32 length= 0; + String str, query; const String *res; @@ -417,16 +421,14 @@ static bool insert_params_withlog(Prepared_statement *stmt, uchar *pos, if (query.copy(stmt->query, stmt->query_length, default_charset_info)) DBUG_RETURN(1); - ulong param_no= 0; - uint32 length= 0; - - while ((param= (Item_param *)param_iterator++)) + for (Item_param **it= begin; it < end; ++it) { + Item_param *param= *it; if (param->long_data_supplied) - res= param->query_val_str(&str); + res= param->query_val_str(&str); else { - if (is_param_null(pos,param_no)) + if (is_param_null(pos, it - begin)) { param->maybe_null= param->null_value= 1; res= &my_null_string; @@ -434,7 +436,7 @@ static bool insert_params_withlog(Prepared_statement *stmt, uchar *pos, else { param->maybe_null= param->null_value= 0; - param->setup_param_func(param,&read_pos); + param->set_param_func(param, &read_pos); res= param->query_val_str(&str); } } @@ -442,7 +444,6 @@ static bool insert_params_withlog(Prepared_statement *stmt, uchar *pos, DBUG_RETURN(1); length+= res->length()-1; - param_no++; } if (alloc_query(thd, (char *)query.ptr(), query.length()+1)) DBUG_RETURN(1); @@ -454,73 +455,68 @@ static bool insert_params_withlog(Prepared_statement *stmt, uchar *pos, static bool insert_params(Prepared_statement *stmt, uchar *pos, uchar *read_pos) { - List<Item> ¶ms= stmt->lex->param_list; - List_iterator<Item> param_iterator(params); - Item_param *param; - ulong param_no= 0; + Item_param **begin= stmt->param_array; + Item_param **end= begin + stmt->param_count; DBUG_ENTER("insert_params"); - while ((param= (Item_param *)param_iterator++)) + for (Item_param **it= begin; it < end; ++it) { - if (!param->long_data_supplied) + Item_param *param= *it; + if (!param->long_data_supplied) { - if (is_param_null(pos,param_no)) + if (is_param_null(pos, it - begin)) param->maybe_null= param->null_value= 1; else { param->maybe_null= param->null_value= 0; - param->setup_param_func(param,&read_pos); + param->set_param_func(param, &read_pos); } } - param_no++; } DBUG_RETURN(0); } -static bool setup_params_data(Prepared_statement *stmt) -{ - List<Item> ¶ms= stmt->lex->param_list; - List_iterator<Item> param_iterator(params); - Item_param *param; - - uchar *pos= (uchar*) stmt->thd->net.read_pos + 1 + - MYSQL_STMT_HEADER; //skip header - uchar *read_pos= pos+(stmt->param_count+7) / 8; //skip null bits +static bool setup_conversion_functions(Prepared_statement *stmt, + uchar **data) +{ + /* skip null bits */ + uchar *read_pos= *data + (stmt->param_count+7) / 8; - DBUG_ENTER("setup_params_data"); + DBUG_ENTER("setup_conversion_functions"); if (*read_pos++) //types supplied / first execute - { + { /* First execute or types altered by the client, setup the conversion routines for all parameters (one time) */ - while ((param= (Item_param *)param_iterator++)) - { - setup_param_functions(param,*read_pos); + Item_param **it= stmt->param_array; + Item_param **end= it + stmt->param_count; + for (; it < end; ++it) + { + setup_one_conversion_function(*it, *read_pos); read_pos+= 2; } - param_iterator.rewind(); - } - stmt->setup_params(stmt,pos,read_pos); + } + *data= read_pos; DBUG_RETURN(0); } #else -bool setup_params_data(Prepared_statement *stmt) -{ - List<Item> ¶ms= stmt->lex->param_list; - List_iterator<Item> param_iterator(params); - Item_param *param; +static bool emb_insert_params(Prepared_statement *stmt) +{ + Item_param **it= stmt->param_array; + Item_param **end= it + stmt->param_count; MYSQL_BIND *client_param= stmt->thd->client_params; - DBUG_ENTER("setup_params_data"); + DBUG_ENTER("emb_insert_params"); - for (;(param= (Item_param *)param_iterator++); client_param++) - { - setup_param_functions(param, client_param->buffer_type); + for (; it < end; ++it, ++client_param) + { + Item_param *param= *it; + setup_one_conversion_function(param, client_param->buffer_type); if (!param->long_data_supplied) { if (*client_param->is_null) @@ -529,39 +525,39 @@ bool setup_params_data(Prepared_statement *stmt) { uchar *buff= (uchar*)client_param->buffer; param->maybe_null= param->null_value= 0; - param->setup_param_func(param,&buff, - client_param->length ? - *client_param->length : - client_param->buffer_length); + param->set_param_func(param, &buff, + client_param->length ? + *client_param->length : + client_param->buffer_length); } } } DBUG_RETURN(0); } -bool setup_params_data_withlog(Prepared_statement *stmt) -{ + +static bool emb_insert_params_withlog(Prepared_statement *stmt) +{ THD *thd= stmt->thd; - List<Item> ¶ms= stmt->lex->param_list; - List_iterator<Item> param_iterator(params); - Item_param *param; + Item_param **it= stmt->param_array; + Item_param **end= it + stmt->param_count; MYSQL_BIND *client_param= thd->client_params; String str, query; const String *res; + uint32 length= 0; - DBUG_ENTER("setup_params_data_withlog"); + DBUG_ENTER("emb_insert_params_withlog"); if (query.copy(stmt->query, stmt->query_length, default_charset_info)) DBUG_RETURN(1); - uint32 length= 0; - - for (;(param= (Item_param *)param_iterator++); client_param++) - { - setup_param_functions(param, client_param->buffer_type); + for (; it < end; ++it, ++client_param) + { + Item_param *param= *it; + setup_one_conversion_function(param, client_param->buffer_type); if (param->long_data_supplied) - res= param->query_val_str(&str); + res= param->query_val_str(&str); else { if (*client_param->is_null) @@ -573,16 +569,15 @@ bool setup_params_data_withlog(Prepared_statement *stmt) { uchar *buff= (uchar*)client_param->buffer; param->maybe_null= param->null_value= 0; - param->setup_param_func(param,&buff, - client_param->length ? - *client_param->length : - client_param->buffer_length); + param->set_param_func(param, &buff, + client_param->length ? + *client_param->length : + client_param->buffer_length); res= param->query_val_str(&str); } } if (query.replace(param->pos_in_query+length, 1, *res)) DBUG_RETURN(1); - length+= res->length()-1; } @@ -595,15 +590,21 @@ bool setup_params_data_withlog(Prepared_statement *stmt) #endif /*!EMBEDDED_LIBRARY*/ /* - Validate the following information for INSERT statement: - - field existance - - fields count + Validate the following information for INSERT statement: + - field existence + - fields count + SYNOPSIS + mysql_test_insert_fields() + RETURN VALUE + 0 ok + 1 error, sent to the client + -1 error, not sent to client */ -static bool mysql_test_insert_fields(Prepared_statement *stmt, - TABLE_LIST *table_list, - List<Item> &fields, - List<List_item> &values_list) +static int mysql_test_insert_fields(Prepared_statement *stmt, + TABLE_LIST *table_list, + List<Item> &fields, + List<List_item> &values_list) { THD *thd= stmt->thd; TABLE *table; @@ -630,7 +631,7 @@ static bool mysql_test_insert_fields(Prepared_statement *stmt, if (open_and_lock_tables(thd, table_list)) { thd->free_temporary_memory_pool_for_ps_preparing(); - DBUG_RETURN(1); + DBUG_RETURN(-1); } table= table_list->table; @@ -643,7 +644,7 @@ static bool mysql_test_insert_fields(Prepared_statement *stmt, if (check_insert_fields(thd,table,fields,*values,1)) { thd->free_temporary_memory_pool_for_ps_preparing(); - DBUG_RETURN(1); + DBUG_RETURN(-1); } thd->free_temporary_memory_pool_for_ps_preparing(); @@ -658,7 +659,7 @@ static bool mysql_test_insert_fields(Prepared_statement *stmt, my_printf_error(ER_WRONG_VALUE_COUNT_ON_ROW, ER(ER_WRONG_VALUE_COUNT_ON_ROW), MYF(0), counter); - DBUG_RETURN(1); + DBUG_RETURN(-1); } } } @@ -666,25 +667,26 @@ static bool mysql_test_insert_fields(Prepared_statement *stmt, { thd->free_temporary_memory_pool_for_ps_preparing(); } - if (send_prep_stmt(stmt, 0)) - DBUG_RETURN(1); DBUG_RETURN(0); } /* - Validate the following information - UPDATE - set and where clause DELETE - where clause - - And send update-set clause column list fields info - back to client. For DELETE, just validate where clause - and return no fields information back to client. + Validate the following information: + UPDATE - set and where clause + DELETE - where clause + SYNOPSIS + mysql_test_upd_fields() + RETURN VALUE + 0 success + 1 error, sent to client + -1 error, not sent to client */ -static bool mysql_test_upd_fields(Prepared_statement *stmt, - TABLE_LIST *table_list, - List<Item> &fields, List<Item> &values, - COND *conds) +static int mysql_test_upd_fields(Prepared_statement *stmt, + TABLE_LIST *table_list, + List<Item> &fields, List<Item> &values, + COND *conds) { THD *thd= stmt->thd; @@ -711,44 +713,43 @@ static bool mysql_test_upd_fields(Prepared_statement *stmt, thd->free_temporary_memory_pool_for_ps_preparing(); - /* - Currently return only column list info only, and we are not - sending any info on where clause. - */ - if (send_prep_stmt(stmt, 0)) - DBUG_RETURN(1); + /* TODO: here we should send types of placeholders to the client. */ DBUG_RETURN(0); err: thd->free_temporary_memory_pool_for_ps_preparing(); - DBUG_RETURN(1); + DBUG_RETURN(-1); } /* - Validate the following information: - + Validate the following information: SELECT - column list - where clause - order clause - having clause - group by clause - if no column spec i.e. '*', then setup all fields - - And send column list fields info back to client. + In case of success, if this query is not EXPLAIN, send column list info + back to client. + SYNOPSIS + mysql_test_select_fields() + RETURN VALUE + 0 success + 1 error, sent to client + -1 error, not sent to client */ -static bool mysql_test_select_fields(Prepared_statement *stmt, - TABLE_LIST *tables, - uint wild_num, - List<Item> &fields, COND *conds, - uint og_num, ORDER *order, ORDER *group, - Item *having, ORDER *proc, - ulong select_options, - SELECT_LEX_UNIT *unit, - SELECT_LEX *select_lex) +static int mysql_test_select_fields(Prepared_statement *stmt, + TABLE_LIST *tables, + uint wild_num, + List<Item> &fields, COND *conds, + uint og_num, ORDER *order, ORDER *group, + Item *having, ORDER *proc, + ulong select_options, + SELECT_LEX_UNIT *unit, + SELECT_LEX *select_lex) { THD *thd= stmt->thd; LEX *lex= stmt->lex; - select_result *result= lex->result; DBUG_ENTER("mysql_test_select_fields"); @@ -772,7 +773,10 @@ static bool mysql_test_select_fields(Prepared_statement *stmt, */ thd->allocate_temporary_memory_pool_for_ps_preparing(); if (open_and_lock_tables(thd, tables)) + { + send_error(thd); goto err; + } if (lex->describe) { @@ -781,23 +785,27 @@ static bool mysql_test_select_fields(Prepared_statement *stmt, } else { + select_result *result= lex->result; if (!result && !(result= new select_send())) { send_error(thd, ER_OUT_OF_RESOURCES); goto err; } - thd->used_tables= 0; // Updated by setup_fields + thd->used_tables= 0; // Updated by setup_fields if (unit->prepare(thd, result, 0)) + { + send_error(thd); goto err_prep; + } if (send_prep_stmt(stmt, fields.elements) || thd->protocol_simple.send_fields(&fields, 0) #ifndef EMBEDDED_LIBRARY - || net_flush(&thd->net) + || net_flush(&thd->net) #endif - ) + ) goto err_prep; unit->cleanup(); @@ -814,97 +822,104 @@ err: /* - Send the prepare query results back to client + Send the prepare query results back to client + SYNOPSIS + send_prepare_results() + stmt prepared statement + RETURN VALUE + 0 success + 1 error, sent to client */ -static bool send_prepare_results(Prepared_statement *stmt) +static int send_prepare_results(Prepared_statement *stmt) { THD *thd= stmt->thd; LEX *lex= stmt->lex; + SELECT_LEX *select_lex= &lex->select_lex; + TABLE_LIST *tables=(TABLE_LIST*) select_lex->table_list.first; enum enum_sql_command sql_command= lex->sql_command; + int res; DBUG_ENTER("send_prepare_results"); DBUG_PRINT("enter",("command: %d, param_count: %ld", - sql_command, lex->param_count)); - - /* Setup prepared stmt */ - stmt->param_count= lex->param_count; - - SELECT_LEX *select_lex= &lex->select_lex; - TABLE_LIST *tables=(TABLE_LIST*) select_lex->table_list.first; + sql_command, stmt->param_count)); switch (sql_command) { case SQLCOM_INSERT: - if (mysql_test_insert_fields(stmt, tables, lex->field_list, - lex->many_values)) - goto abort; + if ((res= mysql_test_insert_fields(stmt, tables, lex->field_list, + lex->many_values))) + goto error; break; case SQLCOM_UPDATE: - if (mysql_test_upd_fields(stmt, tables, select_lex->item_list, - lex->value_list, select_lex->where)) - goto abort; - break; - + /* XXX: fallthrough */ case SQLCOM_DELETE: - if (mysql_test_upd_fields(stmt, tables, select_lex->item_list, - lex->value_list, select_lex->where)) - goto abort; + if ((res= mysql_test_upd_fields(stmt, tables, select_lex->item_list, + lex->value_list, select_lex->where))) + goto error; break; case SQLCOM_SELECT: - if (mysql_test_select_fields(stmt, tables, select_lex->with_wild, - select_lex->item_list, - select_lex->where, - select_lex->order_list.elements + - select_lex->group_list.elements, - (ORDER*) select_lex->order_list.first, - (ORDER*) select_lex->group_list.first, - select_lex->having, - (ORDER*)lex->proc_list.first, - select_lex->options | thd->options, - &(lex->unit), select_lex)) - goto abort; - break; + if ((res= mysql_test_select_fields(stmt, tables, select_lex->with_wild, + select_lex->item_list, + select_lex->where, + select_lex->order_list.elements + + select_lex->group_list.elements, + (ORDER*) select_lex->order_list.first, + (ORDER*) select_lex->group_list.first, + select_lex->having, + (ORDER*)lex->proc_list.first, + select_lex->options | thd->options, + &(lex->unit), select_lex))) + goto error; + /* Statement and field info has already been sent */ + DBUG_RETURN(0); default: - { - /* - Rest fall through to default category, no parsing - for non-DML statements - */ - if (send_prep_stmt(stmt, 0)) - goto abort; - } + /* + Rest fall through to default category, no parsing + for non-DML statements + */ + break; } - DBUG_RETURN(0); + DBUG_RETURN(send_prep_stmt(stmt, 0)); -abort: - send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN : 0); +error: + if (res < 0) + send_error(thd, thd->killed ? ER_SERVER_SHUTDOWN : 0); DBUG_RETURN(1); } /* - Initialize parameter items in statement + Initialize array of parametes in statement from LEX. + (We need to have quick access to items by number in mysql_send_longdata). + This is to avoid using malloc/realloc in the parser. */ -static bool init_param_items(Prepared_statement *stmt) +static bool init_param_array(Prepared_statement *stmt) { - Item_param **to; - - if (!stmt->param_count) - stmt->param= (Item_param **)0; - else - { - if (!(stmt->param= to= (Item_param **) - my_malloc(sizeof(Item_param *)*(stmt->param_count+1), - MYF(MY_WME)))) + LEX *lex= stmt->lex; + if ((stmt->param_count= lex->param_list.elements)) + { + Item_param **to; + List_iterator<Item_param> param_iterator(lex->param_list); + /* Use thd->mem_root as it points at statement mem_root */ + stmt->param_array= (Item_param **) + alloc_root(&stmt->thd->mem_root, + sizeof(Item_param*) * stmt->param_count); + if (!stmt->param_array) + { + send_error(stmt->thd, ER_OUT_OF_RESOURCES); return 1; - - List_iterator<Item> param_iterator(stmt->lex->param_list); - while ((*(to++)= (Item_param *)param_iterator++)); - } + } + for (to= stmt->param_array; + to < stmt->param_array + stmt->param_count; + ++to) + { + *to= param_iterator++; + } + } return 0; } @@ -912,137 +927,104 @@ static bool init_param_items(Prepared_statement *stmt) /* Parse the query and send the total number of parameters and resultset metadata information back to client (if any), - without executing the query i.e. with out any log/disk + without executing the query i.e. without any log/disk writes. This will allow the queries to be re-executed - without re-parsing during execute. - - If parameter markers are found in the query, then store - the information using Item_param along with maintaining a - list in lex->param_list, so that a fast and direct - retrieval can be made without going through all field - items. + without re-parsing during execute. + + If parameter markers are found in the query, then store + the information using Item_param along with maintaining a + list in lex->param_array, so that a fast and direct + retrieval can be made without going through all field + items. */ -bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length) +void mysql_stmt_prepare(THD *thd, char *packet, uint packet_length) { LEX *lex; Prepared_statement *stmt= new Prepared_statement(thd); - SELECT_LEX *sl; + int error; DBUG_ENTER("mysql_stmt_prepare"); if (stmt == 0) - DBUG_RETURN(0); + { + send_error(thd, ER_OUT_OF_RESOURCES); + DBUG_VOID_RETURN; + } if (thd->stmt_map.insert(stmt)) - goto insert_stmt_err; + { + delete stmt; + send_error(thd, ER_OUT_OF_RESOURCES); + DBUG_VOID_RETURN; + } thd->stmt_backup.set_statement(thd); + thd->stmt_backup.set_item_arena(thd); thd->set_statement(stmt); - thd->current_statement= stmt; + thd->set_item_arena(stmt); if (alloc_query(thd, packet, packet_length)) - goto alloc_query_err; + { + stmt->set_statement(thd); + stmt->set_item_arena(thd); + thd->set_statement(&thd->stmt_backup); + thd->set_item_arena(&thd->stmt_backup); + /* Statement map deletes statement on erase */ + thd->stmt_map.erase(stmt); + send_error(thd, ER_OUT_OF_RESOURCES); + DBUG_VOID_RETURN; + } - mysql_log.write(thd, COM_PREPARE, "%s", packet); + mysql_log.write(thd, COM_PREPARE, "%s", packet); + thd->current_statement= stmt; lex= lex_start(thd, (uchar *) thd->query, thd->query_length); mysql_init_query(thd); lex->safe_to_cache_query= 0; - lex->param_count= 0; - if (yyparse((void *)thd) || thd->is_fatal_error || send_prepare_results(stmt)) - goto yyparse_err; - - lex_end(lex); + error= yyparse((void *)thd) || thd->is_fatal_error || + init_param_array(stmt) || + send_prepare_results(stmt); + /* restore to WAIT_PRIOR: QUERY_PRIOR is set inside alloc_query */ if (!(specialflag & SPECIAL_NO_PRIOR)) my_pthread_setprio(pthread_self(),WAIT_PRIOR); - - // save WHERE clause pointers to avoid damaging they by optimisation - for (sl= thd->lex->all_selects_list; - sl; - sl= sl->next_select_in_list()) - { - sl->prep_where= sl->where; - } - - stmt->set_statement(thd); - thd->set_statement(&thd->stmt_backup); - thd->current_statement= 0; - - if (init_param_items(stmt)) - goto init_param_err; - - stmt->command= COM_EXECUTE; // set it only once here - - DBUG_RETURN(0); - -yyparse_err: lex_end(lex); stmt->set_statement(thd); + stmt->set_item_arena(thd); thd->set_statement(&thd->stmt_backup); -init_param_err: -alloc_query_err: - /* Statement map deletes statement on erase */ - thd->stmt_map.erase(stmt); - thd->current_statement= 0; - DBUG_RETURN(1); -insert_stmt_err: - stmt->set_statement(thd); - thd->set_statement(&thd->stmt_backup); - /* Statement map deletes statement on erase */ - thd->stmt_map.erase(stmt); + thd->set_item_arena(&thd->stmt_backup); thd->current_statement= 0; - delete stmt; - DBUG_RETURN(1); -} - - -/* - Executes previously prepared query - If there is any parameters (stmt->param_count), then replace - markers with the data supplied from client, and then - execute the query -*/ - -void mysql_stmt_execute(THD *thd, char *packet) -{ - ulong stmt_id= uint4korr(packet); - Prepared_statement *stmt; - - DBUG_ENTER("mysql_stmt_execute"); - - if (!(stmt= find_prepared_statement(thd, stmt_id, "execute"))) - DBUG_VOID_RETURN; - - /* Check if we got an error when sending long data */ - if (stmt->error_in_prepare) + if (error) { - send_error(thd, stmt->last_errno, stmt->last_error); - DBUG_VOID_RETURN; + /* Statement map deletes statement on erase */ + thd->stmt_map.erase(stmt); + /* error is sent inside yyparse/send_prepare_results */ } + else + { + SELECT_LEX *sl= stmt->lex->all_selects_list; + /* + Save WHERE clause pointers, because they may be changed during query + optimisation. + */ + for (; sl; sl= sl->next_select_in_list()) + { + sl->prep_where= sl->where; + } + } + DBUG_VOID_RETURN; +} - stmt->query_id= thd->query_id; - thd->stmt_backup.set_statement(thd); - thd->set_statement(stmt); - thd->free_list= 0; - - /* - To make sure that all runtime data is stored in its own memory root and - does not interfere with data possibly present in thd->mem_root. - This root is cleaned up in the end of execution. - FIXME: to be replaced with more efficient approach, and verified why we - can not use thd->mem_root safely. - */ - init_sql_alloc(&thd->mem_root, - thd->variables.query_alloc_block_size, - thd->variables.query_prealloc_size); +/* Reinit statement before execution */ +static void reset_stmt_for_execute(Prepared_statement *stmt) +{ + THD *thd= stmt->thd; + SELECT_LEX *sl= stmt->lex->all_selects_list; - for (SELECT_LEX *sl= stmt->lex->all_selects_list; - sl; - sl= sl->next_select_in_list()) + for (; sl; sl= sl->next_select_in_list()) { /* Copy WHERE clause pointers to avoid damaging they by optimisation @@ -1075,58 +1057,104 @@ void mysql_stmt_execute(THD *thd, char *packet) SELECT_LEX_UNIT *unit= sl->master_unit(); unit->unclean(); unit->types.empty(); - // for derived tables & PS (which can't be reset by Item_subquery) + /* for derived tables & PS (which can't be reset by Item_subquery) */ unit->reinit_exec_mechanism(); } } +} + +/* + Executes previously prepared query. + If there is any parameters, then replace markers with the data supplied + from client, and then execute the query. + SYNOPSYS + mysql_stmt_execute() +*/ + + +void mysql_stmt_execute(THD *thd, char *packet) +{ + ulong stmt_id= uint4korr(packet); + Prepared_statement *stmt; + + DBUG_ENTER("mysql_stmt_execute"); + + if (!(stmt= find_prepared_statement(thd, stmt_id, "execute", SEND_ERROR))) + DBUG_VOID_RETURN; + + /* Check if we got an error when sending long data */ + if (stmt->get_longdata_error) + { + send_error(thd, stmt->last_errno, stmt->last_error); + DBUG_VOID_RETURN; + } + + thd->stmt_backup.set_statement(thd); + thd->set_statement(stmt); + reset_stmt_for_execute(stmt); #ifndef EMBEDDED_LIBRARY - if (stmt->param_count && setup_params_data(stmt)) - goto end; + if (stmt->param_count) + { + packet+= 4; + uchar *null_array= (uchar *) packet; + if (setup_conversion_functions(stmt, (uchar **) &packet) || + stmt->set_params(stmt, null_array, (uchar *) packet)) + goto set_params_data_err; + } #else - if (stmt->param_count && (*stmt->setup_params_data)(stmt)) - goto end; + /* + In embedded library we re-install conversion routines each time + we set params, and also we don't need to parse packet. + So we do it in one function. + */ + if (stmt->param_count && stmt->set_params_data(stmt)) + goto set_params_data_err; #endif if (!(specialflag & SPECIAL_NO_PRIOR)) - my_pthread_setprio(pthread_self(),QUERY_PRIOR); + my_pthread_setprio(pthread_self(),QUERY_PRIOR); /* TODO: Also, have checks on basic executions such as mysql_insert(), mysql_delete(), mysql_update() and mysql_select() to not to have re-check on setup_* and other things .. - */ - thd->protocol= &thd->protocol_prep; // Switch to binary protocol + */ + thd->protocol= &thd->protocol_prep; // Switch to binary protocol mysql_execute_command(thd); - thd->protocol= &thd->protocol_simple; // Use normal protocol + thd->protocol= &thd->protocol_simple; // Use normal protocol if (!(specialflag & SPECIAL_NO_PRIOR)) my_pthread_setprio(pthread_self(), WAIT_PRIOR); - free_items(thd->free_list); cleanup_items(stmt->free_list); close_thread_tables(thd); // to close derived tables - free_root(&thd->mem_root, MYF(0)); thd->set_statement(&thd->stmt_backup); -end: + DBUG_VOID_RETURN; + +set_params_data_err: + thd->set_statement(&thd->stmt_backup); + my_error(ER_WRONG_ARGUMENTS, MYF(0), "mysql_execute"); + send_error(thd); DBUG_VOID_RETURN; } /* - Reset a prepared statement - + Reset a prepared statement, in case there was an error in send_longdata. + Note: we don't send any reply to that command. SYNOPSIS mysql_stmt_reset() thd Thread handle - packet Packet with stmt handle + packet Packet with stmt id DESCRIPTION This function is useful when one gets an error after calling - mysql_stmt_getlongdata() and one wants to reset the handle + mysql_stmt_getlongdata() and wants to reset the handle so that one can call execute again. + See also bug #1664 */ void mysql_stmt_reset(THD *thd, char *packet) @@ -1136,25 +1164,27 @@ void mysql_stmt_reset(THD *thd, char *packet) DBUG_ENTER("mysql_stmt_reset"); - if (!(stmt= find_prepared_statement(thd, stmt_id, "reset"))) + if (!(stmt= find_prepared_statement(thd, stmt_id, "reset", DONT_SEND_ERROR))) DBUG_VOID_RETURN; - stmt->error_in_prepare= 0; - Item_param *item= *stmt->param, *end= item + stmt->param_count; + stmt->get_longdata_error= 0; /* Free long data if used */ if (stmt->long_data_used) { + Item_param **item= stmt->param_array; + Item_param **end= item + stmt->param_count; stmt->long_data_used= 0; for (; item < end ; item++) - item->reset(); + (**item).reset(); } DBUG_VOID_RETURN; } /* - Delete a prepared statement from memory + Delete a prepared statement from memory. + Note: we don't send any reply to that command. */ void mysql_stmt_free(THD *thd, char *packet) @@ -1164,7 +1194,7 @@ void mysql_stmt_free(THD *thd, char *packet) DBUG_ENTER("mysql_stmt_free"); - if (!(stmt= find_prepared_statement(thd, stmt_id, "close"))) + if (!(stmt= find_prepared_statement(thd, stmt_id, "close", DONT_SEND_ERROR))) DBUG_VOID_RETURN; /* Statement map deletes statement on erase */ @@ -1174,7 +1204,7 @@ void mysql_stmt_free(THD *thd, char *packet) /* - Long data in pieces from client + Long data in pieces from client SYNOPSIS mysql_stmt_get_longdata() @@ -1210,14 +1240,15 @@ void mysql_stmt_get_longdata(THD *thd, char *pos, ulong packet_length) ulong stmt_id= uint4korr(pos); uint param_number= uint2korr(pos+4); - if (!(stmt=find_prepared_statement(thd, stmt_id, "get_longdata"))) + if (!(stmt=find_prepared_statement(thd, stmt_id, "get_longdata", + DONT_SEND_ERROR))) DBUG_VOID_RETURN; #ifndef EMBEDDED_LIBRARY if (param_number >= stmt->param_count) { /* Error will be sent in execute call */ - stmt->error_in_prepare= 1; + stmt->get_longdata_error= 1; stmt->last_errno= ER_WRONG_ARGUMENTS; sprintf(stmt->last_error, ER(ER_WRONG_ARGUMENTS), "get_longdata"); DBUG_VOID_RETURN; @@ -1225,7 +1256,7 @@ void mysql_stmt_get_longdata(THD *thd, char *pos, ulong packet_length) pos+= MYSQL_LONG_DATA_HEADER; // Point to data #endif - Item_param *param= *(stmt->param+param_number); + Item_param *param= stmt->param_array[param_number]; #ifndef EMBEDDED_LIBRARY param->set_longdata(pos, packet_length-MYSQL_LONG_DATA_HEADER-1); #else @@ -1239,10 +1270,10 @@ void mysql_stmt_get_longdata(THD *thd, char *pos, ulong packet_length) Prepared_statement::Prepared_statement(THD *thd_arg) :Statement(thd_arg), thd(thd_arg), - param(0), + param_array(0), param_count(0), last_errno(0), - error_in_prepare(0), + get_longdata_error(0), long_data_used(0), log_full_query(0) { @@ -1251,23 +1282,22 @@ Prepared_statement::Prepared_statement(THD *thd_arg) { log_full_query= 1; #ifndef EMBEDDED_LIBRARY - setup_params= insert_params_withlog; + set_params= insert_params_withlog; #else - setup_params_data= setup_params_data_withlog; + set_params_data= emb_insert_params_withlog; #endif } else #ifndef EMBEDDED_LIBRARY - setup_params= insert_params; // not fully qualified query + set_params= insert_params; #else - setup_params_data= ::setup_params_data; + set_params_data= emb_insert_params; #endif } Prepared_statement::~Prepared_statement() { - my_free((char *) param, MYF(MY_ALLOW_ZERO_PTR)); free_items(free_list); } @@ -1277,4 +1307,3 @@ Statement::Type Prepared_statement::type() const return PREPARED_STATEMENT; } - diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 7c1a5ad67b4..7605016dbe1 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -5762,7 +5762,15 @@ sub_select(JOIN *join,JOIN_TAB *join_tab,bool end_of_records) return 0; } else + { + /* + This row failed selection, release lock on it. + XXX: There is no table handler in MySQL which makes use of this + call. It's kept from Gemini times. A lot of new code was added + recently (i. e. subselects) without having it in mind. + */ info->file->unlock_row(); + } } } while (!(error=info->read_record(info)) && !(*report_error)); } 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/sql_yacc.yy b/sql/sql_yacc.yy index 4a098cc6fc0..7df1973132a 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -4478,11 +4478,17 @@ text_string: param_marker: '?' { - LEX *lex=Lex; - if (YYTHD->command == COM_PREPARE) + THD *thd=YYTHD; + LEX *lex= thd->lex; + if (thd->command == COM_PREPARE) { - lex->param_list.push_back($$=new Item_param((uint)(lex->tok_start-(uchar *)YYTHD->query))); - lex->param_count++; + Item_param *item= new Item_param((uint) (lex->tok_start - + (uchar *) thd->query)); + if (!($$= item) || lex->param_list.push_back(item)) + { + send_error(thd, ER_OUT_OF_RESOURCES); + YYABORT; + } } else { 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]; |