summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <paul@teton.kitebird.com>2004-03-05 11:16:32 -0600
committerunknown <paul@teton.kitebird.com>2004-03-05 11:16:32 -0600
commit7e535dceb4d0b4d17c7e8b1e95aa4121012238d8 (patch)
tree17d1664fbd4de82ae64a6f2657437743f41f5542 /sql
parent9721346aebbc50dacae57f4c0b77d6757e66bc1a (diff)
parente3af1fab8c2932ec02861cee5b06d0ad51c45cad (diff)
downloadmariadb-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')
-rw-r--r--sql/field.cc70
-rw-r--r--sql/gstream.cc174
-rw-r--r--sql/gstream.h40
-rw-r--r--sql/ha_myisam.h2
-rw-r--r--sql/handler.cc2
-rw-r--r--sql/item.h7
-rw-r--r--sql/item_create.cc6
-rw-r--r--sql/item_create.h1
-rw-r--r--sql/item_geofunc.cc226
-rw-r--r--sql/item_geofunc.h2
-rw-r--r--sql/item_strfunc.cc54
-rw-r--r--sql/item_strfunc.h35
-rw-r--r--sql/item_subselect.cc6
-rw-r--r--sql/item_subselect.h1
-rw-r--r--sql/lex.h1
-rw-r--r--sql/mysql_priv.h3
-rw-r--r--sql/protocol.h5
-rw-r--r--sql/share/czech/errmsg.txt2
-rw-r--r--sql/share/danish/errmsg.txt2
-rw-r--r--sql/share/dutch/errmsg.txt2
-rw-r--r--sql/share/english/errmsg.txt2
-rw-r--r--sql/share/estonian/errmsg.txt2
-rw-r--r--sql/share/french/errmsg.txt2
-rw-r--r--sql/share/german/errmsg.txt2
-rw-r--r--sql/share/greek/errmsg.txt2
-rw-r--r--sql/share/hungarian/errmsg.txt2
-rw-r--r--sql/share/italian/errmsg.txt2
-rw-r--r--sql/share/japanese/errmsg.txt2
-rw-r--r--sql/share/korean/errmsg.txt2
-rw-r--r--sql/share/norwegian-ny/errmsg.txt2
-rw-r--r--sql/share/norwegian/errmsg.txt2
-rw-r--r--sql/share/polish/errmsg.txt2
-rw-r--r--sql/share/portuguese/errmsg.txt2
-rw-r--r--sql/share/romanian/errmsg.txt2
-rw-r--r--sql/share/russian/errmsg.txt2
-rw-r--r--sql/share/serbian/errmsg.txt2
-rw-r--r--sql/share/slovak/errmsg.txt2
-rw-r--r--sql/share/spanish/errmsg.txt2
-rw-r--r--sql/share/ukrainian/errmsg.txt2
-rw-r--r--sql/slave.cc27
-rw-r--r--sql/spatial.cc1646
-rw-r--r--sql/spatial.h480
-rw-r--r--sql/sql_class.cc13
-rw-r--r--sql/sql_class.h28
-rw-r--r--sql/sql_lex.h3
-rw-r--r--sql/sql_parse.cc24
-rw-r--r--sql/sql_prepare.cc733
-rw-r--r--sql/sql_select.cc8
-rw-r--r--sql/sql_string.cc16
-rw-r--r--sql/sql_string.h12
-rw-r--r--sql/sql_yacc.yy14
-rw-r--r--sql/structs.h12
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 &param, 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> &params= 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> &params= 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> &params= 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> &params= 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> &params= 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];