summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/Makefile.am5
-rw-r--r--sql/convert.cc12
-rw-r--r--sql/des_key_file.cc5
-rw-r--r--sql/field.cc171
-rw-r--r--sql/field.h52
-rw-r--r--sql/field_conv.cc2
-rw-r--r--sql/filesort.cc34
-rw-r--r--sql/gen_lex_hash.cc2
-rw-r--r--sql/gstream.cc137
-rw-r--r--sql/gstream.h61
-rw-r--r--sql/ha_berkeley.cc2
-rw-r--r--sql/ha_innodb.cc10
-rw-r--r--sql/ha_myisam.cc8
-rw-r--r--sql/hash_filo.h4
-rw-r--r--sql/hostname.cc4
-rw-r--r--sql/init.cc17
-rw-r--r--sql/item.cc4
-rw-r--r--sql/item.h1
-rw-r--r--sql/item_cmpfunc.cc90
-rw-r--r--sql/item_cmpfunc.h79
-rw-r--r--sql/item_create.cc155
-rw-r--r--sql/item_create.h38
-rw-r--r--sql/item_func.cc146
-rw-r--r--sql/item_func.h87
-rw-r--r--sql/item_strfunc.cc523
-rw-r--r--sql/item_strfunc.h216
-rw-r--r--sql/item_sum.cc3
-rw-r--r--sql/item_timefunc.cc8
-rw-r--r--sql/key.cc5
-rw-r--r--sql/lex.h50
-rw-r--r--sql/log.cc4
-rw-r--r--sql/mysql_priv.h7
-rw-r--r--sql/mysqld.cc11
-rw-r--r--sql/opt_range.cc128
-rw-r--r--sql/opt_range.h9
-rw-r--r--sql/opt_sum.cc2
-rw-r--r--sql/procedure.cc3
-rw-r--r--sql/repl_failsafe.cc2
-rw-r--r--sql/share/charsets/Index2
-rw-r--r--sql/share/charsets/armscii8.conf74
-rw-r--r--sql/slave.cc11
-rw-r--r--sql/spatial.cc1435
-rw-r--r--sql/spatial.h476
-rw-r--r--sql/sql_acl.cc56
-rw-r--r--sql/sql_analyse.cc10
-rw-r--r--sql/sql_base.cc21
-rw-r--r--sql/sql_cache.cc9
-rw-r--r--sql/sql_class.cc2
-rw-r--r--sql/sql_class.h12
-rw-r--r--sql/sql_db.cc6
-rw-r--r--sql/sql_derived.cc121
-rw-r--r--sql/sql_handler.cc2
-rw-r--r--sql/sql_lex.cc78
-rw-r--r--sql/sql_lex.h8
-rw-r--r--sql/sql_parse.cc40
-rw-r--r--sql/sql_select.cc15
-rw-r--r--sql/sql_show.cc16
-rw-r--r--sql/sql_string.cc116
-rw-r--r--sql/sql_string.h85
-rw-r--r--sql/sql_table.cc90
-rw-r--r--sql/sql_udf.cc3
-rw-r--r--sql/sql_yacc.yy144
-rw-r--r--sql/structs.h1
-rw-r--r--sql/table.cc39
-rw-r--r--sql/table.h1
-rw-r--r--sql/time.cc53
66 files changed, 4618 insertions, 405 deletions
diff --git a/sql/Makefile.am b/sql/Makefile.am
index e1ed9ad8915..f58075358b6 100644
--- a/sql/Makefile.am
+++ b/sql/Makefile.am
@@ -79,9 +79,10 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc \
sql_db.cc sql_table.cc sql_rename.cc sql_crypt.cc \
sql_load.cc mf_iocache.cc field_conv.cc sql_show.cc \
sql_udf.cc sql_analyse.cc sql_analyse.h sql_cache.cc \
- slave.cc sql_repl.cc sql_union.cc \
+ slave.cc sql_repl.cc sql_union.cc sql_derived.cc \
mini_client.cc mini_client_errors.c \
- stacktrace.c repl_failsafe.h repl_failsafe.cc
+ stacktrace.c repl_failsafe.h repl_failsafe.cc \
+ gstream.cc spatial.cc
gen_lex_hash_SOURCES = gen_lex_hash.cc
gen_lex_hash_LDADD = $(LDADD) $(CXXLDFLAGS)
diff --git a/sql/convert.cc b/sql/convert.cc
index 75af13e0939..c2868cac848 100644
--- a/sql/convert.cc
+++ b/sql/convert.cc
@@ -433,7 +433,17 @@ CONVERT *get_convert_set(const char *name)
{
for (CONVERT **ptr=convert_tables ; *ptr ; ptr++)
{
- if (!my_strcasecmp((*ptr)->name,name))
+ /*
+ BAR TODO: Monty's comments:
+ Why is this using system_charset_info ?
+ Isn't the character-set string given in the users default charset?
+ Please add a TODO note to the code that this has to be fixed when the user
+ will be able to cast strings to different character sets...
+ The current code will also not work if/when we introduce support for
+ 16 bit characters...
+ (I know that there is a LOT of changes to do if we ever want do this...)
+ */
+ if (!my_strcasecmp(system_charset_info,(*ptr)->name,name))
return (*ptr);
}
return 0;
diff --git a/sql/des_key_file.cc b/sql/des_key_file.cc
index d9c924b5a3c..ca92e38279b 100644
--- a/sql/des_key_file.cc
+++ b/sql/des_key_file.cc
@@ -70,9 +70,10 @@ load_des_key_file(const char *file_name)
{
offset=(char) (offset - '0');
// Remove newline and possible other control characters
- for (start=buf+1 ; isspace(*start) ; start++) ;
+ for (start=buf+1 ; my_isspace(system_charset_info, *start) ; start++) ;
end=buf+length;
- for (end=strend(buf) ; end > start && !isgraph(end[-1]) ; end--) ;
+ for (end=strend(buf) ;
+ end > start && !my_isgraph(system_charset_info, end[-1]) ; end--) ;
if (start != end)
{
diff --git a/sql/field.cc b/sql/field.cc
index 23419a53d3d..bd4b8e9f29d 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -68,7 +68,8 @@ const char field_separator=',';
*/
static bool
-number_dec(struct st_decstr *sdec, const char *str, const char *end)
+number_dec(CHARSET_INFO *cs, struct st_decstr *sdec,
+ const char *str, const char *end)
{
sdec->sign=sdec->extra=0;
if (str == end)
@@ -86,7 +87,7 @@ number_dec(struct st_decstr *sdec, const char *str, const char *end)
str++;
}
const char *start=str;
- while (str != end && isdigit(*str))
+ while (str != end && my_isdigit(cs,*str))
str++;
if (!(sdec->nr_length=(uint) (str-start)))
sdec->extra=1; // We must put one 0 before .
@@ -95,13 +96,13 @@ number_dec(struct st_decstr *sdec, const char *str, const char *end)
{
str++;
start=str;
- while (str != end && isdigit(*str))
+ while (str != end && my_isdigit(cs,*str))
str++;
}
sdec->nr_dec=(uint) (str-start);
if (current_thd->count_cuted_fields)
{
- while (str != end && isspace(*str))
+ while (str != end && my_isspace(cs,*str))
str++; /* purecov: inspected */
if (str != end)
{
@@ -135,7 +136,8 @@ bool test_if_int(const char *str,int length)
{
const char *end=str+length;
- while (str != end && isspace(*str)) // Allow start space
+ // Allow start space
+ while (str != end && my_isspace(system_charset_info,*str))
str++; /* purecov: inspected */
if (str != end && (*str == '-' || *str == '+'))
str++;
@@ -143,7 +145,7 @@ bool test_if_int(const char *str,int length)
return 0; // Error: Empty string
for ( ; str != end ; str++)
{
- if (!isdigit(*str))
+ if (!my_isdigit(system_charset_info,*str))
{
if (*str == '.')
{ // Allow '.0000'
@@ -151,10 +153,10 @@ bool test_if_int(const char *str,int length)
if (str == end)
return 1;
}
- if (!isspace(*str))
+ if (!my_isspace(system_charset_info,*str))
return 0;
for (str++ ; str != end ; str++)
- if (!isspace(*str))
+ if (!my_isspace(system_charset_info,*str))
return 0;
return 1;
}
@@ -165,7 +167,7 @@ bool test_if_int(const char *str,int length)
static bool test_if_real(const char *str,int length)
{
- while (length && isspace(*str))
+ while (length && my_isspace(system_charset_info,*str))
{ // Allow start space
length--; str++;
}
@@ -174,10 +176,10 @@ static bool test_if_real(const char *str,int length)
if (*str == '+' || *str == '-')
{
length--; str++;
- if (!length || !(isdigit(*str) || *str == '.'))
+ if (!length || !(my_isdigit(system_charset_info,*str) || *str == '.'))
return 0;
}
- while (length && isdigit(*str))
+ while (length && my_isdigit(system_charset_info,*str))
{
length--; str++;
}
@@ -186,7 +188,7 @@ static bool test_if_real(const char *str,int length)
if (*str == '.')
{
length--; str++;
- while (length && isdigit(*str))
+ while (length && my_isdigit(system_charset_info,*str))
{
length--; str++;
}
@@ -195,18 +197,19 @@ static bool test_if_real(const char *str,int length)
return 1;
if (*str == 'E' || *str == 'e')
{
- if (length < 3 || (str[1] != '+' && str[1] != '-') || !isdigit(str[2]))
+ if (length < 3 || (str[1] != '+' && str[1] != '-') ||
+ !my_isdigit(system_charset_info,str[2]))
return 0;
length-=3;
str+=3;
- while (length && isdigit(*str))
+ while (length && my_isdigit(system_charset_info,*str))
{
length--; str++;
}
}
for ( ; length ; length--, str++)
{ // Allow end space
- if (!isspace(*str))
+ if (!my_isspace(system_charset_info,*str))
return 0;
}
return 1;
@@ -405,7 +408,7 @@ void Field_decimal::store(const char *from,uint len)
if ((tmp_dec= dec))
tmp_dec++; // Calculate pos of '.'
- while (from != end && isspace(*from))
+ while (from != end && my_isspace(system_charset_info,*from))
from++;
if (zerofill)
{
@@ -416,7 +419,7 @@ void Field_decimal::store(const char *from,uint len)
}
else
fyllchar=' ';
- error=number_dec(&decstr,from,end);
+ error=number_dec(system_charset_info,&decstr,from,end);
if (decstr.sign)
{
from++;
@@ -479,7 +482,7 @@ void Field_decimal::store(const char *from,uint len)
{
if (*from != '0')
{
- if (!isspace(*from)) // Space is ok
+ if (!my_isspace(system_charset_info,*from)) // Space is ok
current_thd->cuted_fields++;
break;
}
@@ -603,8 +606,10 @@ int Field_decimal::cmp(const char *a_ptr,const char *b_ptr)
for (end=a_ptr+field_length;
a_ptr != end &&
(*a_ptr == *b_ptr ||
- ((isspace(*a_ptr) || *a_ptr == '+' || *a_ptr == '0') &&
- (isspace(*b_ptr) || *b_ptr == '+' || *b_ptr == '0')));
+ ((my_isspace(system_charset_info,*a_ptr) || *a_ptr == '+' ||
+ *a_ptr == '0') &&
+ (my_isspace(system_charset_info,*b_ptr) || *b_ptr == '+' ||
+ *b_ptr == '0')));
a_ptr++,b_ptr++)
{
if (*a_ptr == '-') // If both numbers are negative
@@ -631,7 +636,7 @@ void Field_decimal::sort_string(char *to,uint length)
char *str,*end;
for (str=ptr,end=ptr+length;
str != end &&
- ((isspace(*str) || *str == '+' || *str == '0')) ;
+ ((my_isspace(system_charset_info,*str) || *str == '+' || *str == '0')) ;
str++)
*to++=' ';
@@ -643,7 +648,7 @@ void Field_decimal::sort_string(char *to,uint length)
*to++=1; // Smaller than any number
str++;
while (str != end)
- if (isdigit(*str))
+ if (my_isdigit(system_charset_info,*str))
*to++= (char) ('9' - *str++);
else
*to++= *str++;
@@ -1265,7 +1270,7 @@ void Field_medium::sql_type(String &res) const
void Field_long::store(const char *from,uint len)
{
- while (len && isspace(*from))
+ while (len && my_isspace(system_charset_info,*from))
{
len--; from++;
}
@@ -1493,7 +1498,7 @@ void Field_long::sql_type(String &res) const
void Field_longlong::store(const char *from,uint len)
{
- while (len && isspace(*from))
+ while (len && my_isspace(system_charset_info,*from))
{ // For easy error check
len--; from++;
}
@@ -3331,7 +3336,7 @@ void Field_string::store(const char *from,uint length)
const char *end=from+length;
for (from+=field_length ; from != end ; from++)
{
- if (!isspace(*from))
+ if (!my_isspace(field_charset,*from))
{
current_thd->cuted_fields++;
break;
@@ -3402,7 +3407,7 @@ int Field_string::cmp(const char *a_ptr, const char *b_ptr)
if (binary_flag)
return memcmp(a_ptr,b_ptr,field_length);
else
- return my_sortcmp(a_ptr,b_ptr,field_length);
+ return my_sortcmp(field_charset,a_ptr,b_ptr,field_length);
}
void Field_string::sort_string(char *to,uint length)
@@ -3412,17 +3417,17 @@ void Field_string::sort_string(char *to,uint length)
else
{
#ifdef USE_STRCOLL
- if (use_strcoll(default_charset_info)) {
- uint tmp=my_strnxfrm(default_charset_info,
- (unsigned char *)to, (unsigned char *) ptr,
- length, field_length);
+ if (use_strcoll(field_charset)) {
+ uint tmp=my_strnxfrm(field_charset,
+ (unsigned char *)to, length,
+ (unsigned char *) ptr, field_length);
if (tmp < length)
bzero(to + tmp, length - tmp);
}
else
#endif
for (char *from=ptr,*end=ptr+length ; from != end ;)
- *to++=(char) my_sort_order[(uint) (uchar) *from++];
+ *to++=(char) field_charset->sort_order[(uint) (uchar) *from++];
}
}
@@ -3471,7 +3476,7 @@ int Field_string::pack_cmp(const char *a, const char *b, uint length)
int cmp= memcmp(a,b,min(a_length,b_length));
return cmp ? cmp : (int) (a_length - b_length);
}
- return my_sortncmp(a,a_length, b,b_length);
+ return my_sortncmp(field_charset, a,a_length, b,b_length);
}
@@ -3488,7 +3493,7 @@ int Field_string::pack_cmp(const char *b, uint length)
int cmp= memcmp(ptr,b,min(a_length,b_length));
return cmp ? cmp : (int) (a_length - b_length);
}
- return my_sortncmp(ptr,a_length, b, b_length);
+ return my_sortncmp(field_charset, ptr,a_length, b, b_length);
}
@@ -3593,7 +3598,7 @@ int Field_varstring::cmp(const char *a_ptr, const char *b_ptr)
if (binary_flag)
diff=memcmp(a_ptr+2,b_ptr+2,min(a_length,b_length));
else
- diff=my_sortcmp(a_ptr+2,b_ptr+2,min(a_length,b_length));
+ diff=my_sortcmp(field_charset, a_ptr+2,b_ptr+2,min(a_length,b_length));
return diff ? diff : (int) (a_length - b_length);
}
@@ -3605,10 +3610,10 @@ void Field_varstring::sort_string(char *to,uint length)
else
{
#ifdef USE_STRCOLL
- if (use_strcoll(default_charset_info))
- tot_length=my_strnxfrm(default_charset_info,
- (unsigned char *) to, (unsigned char *)ptr+2,
- length, tot_length);
+ if (use_strcoll(field_charset))
+ tot_length=my_strnxfrm(field_charset,
+ (unsigned char *) to, length,
+ (unsigned char *)ptr+2, tot_length);
else
{
#endif
@@ -3616,7 +3621,7 @@ void Field_varstring::sort_string(char *to,uint length)
if (tot_length > length)
tot_length=length;
for (char *from=ptr+2,*end=from+tot_length ; from != end ;)
- *tmp++=(char) my_sort_order[(uint) (uchar) *from++];
+ *tmp++=(char) field_charset->sort_order[(uint) (uchar) *from++];
#ifdef USE_STRCOLL
}
#endif
@@ -3687,7 +3692,7 @@ int Field_varstring::pack_cmp(const char *a, const char *b, uint key_length)
int cmp= memcmp(a,b,min(a_length,b_length));
return cmp ? cmp : (int) (a_length - b_length);
}
- return my_sortncmp(a,a_length, b,b_length);
+ return my_sortncmp(field_charset, a,a_length, b,b_length);
}
int Field_varstring::pack_cmp(const char *b, uint key_length)
@@ -3708,7 +3713,7 @@ int Field_varstring::pack_cmp(const char *b, uint key_length)
int cmp= memcmp(a,b,min(a_length,b_length));
return cmp ? cmp : (int) (a_length - b_length);
}
- return my_sortncmp(a,a_length, b,b_length);
+ return my_sortncmp(field_charset, a,a_length, b,b_length);
}
uint Field_varstring::packed_col_length(const char *ptr, uint length)
@@ -3737,7 +3742,7 @@ Field_blob::Field_blob(char *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
:Field_str(ptr_arg, (1L << min(blob_pack_length,3)*8)-1L,
null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg,
table_arg),
- packlength(blob_pack_length),binary_flag(binary_arg)
+ packlength(blob_pack_length),binary_flag(binary_arg), geom_flag(true)
{
flags|= BLOB_FLAG;
if (binary_arg)
@@ -3931,7 +3936,7 @@ int Field_blob::cmp(const char *a,uint32 a_length, const char *b,
if (binary_flag)
diff=memcmp(a,b,min(a_length,b_length));
else
- diff=my_sortcmp(a,b,min(a_length,b_length));
+ diff=my_sortcmp(field_charset, a,b,min(a_length,b_length));
return diff ? diff : (int) (a_length - b_length);
}
@@ -3979,8 +3984,30 @@ int Field_blob::cmp_binary(const char *a_ptr, const char *b_ptr,
/* The following is used only when comparing a key */
-void Field_blob::get_key_image(char *buff,uint length)
+void Field_blob::get_key_image(char *buff,uint length, imagetype type)
{
+ if(type == itMBR)
+ {
+ length-=HA_KEY_BLOB_LENGTH;
+ ulong blob_length=get_length(ptr);
+ char *blob;
+ get_ptr(&blob);
+ if(!blob_length)
+ {
+ return;
+ }
+
+ MBR mbr;
+ Geometry gobj;
+ gobj.create_from_wkb(blob,blob_length);
+ gobj.get_mbr(&mbr);
+ float8store(buff, mbr.xmin);
+ float8store(buff+8, mbr.xmax);
+ float8store(buff+16, mbr.ymin);
+ float8store(buff+24, mbr.ymax);
+ return;
+ }
+
length-=HA_KEY_BLOB_LENGTH;
uint32 blob_length=get_length(ptr);
char *blob;
@@ -4002,6 +4029,31 @@ void Field_blob::set_key_image(char *buff,uint length)
Field_blob::store(buff+2,length);
}
+void Field_geom::get_key_image(char *buff,uint length, imagetype type)
+{
+ length-=HA_KEY_BLOB_LENGTH;
+ ulong blob_length=get_length(ptr);
+ char *blob;
+ get_ptr(&blob);
+ memcpy(buff+2,blob,length);
+
+ MBR mbr;
+ Geometry gobj;
+ gobj.create_from_wkb(blob,blob_length);
+ gobj.get_mbr(&mbr);
+ float8store(buff, mbr.xmin);
+ float8store(buff+8, mbr.xmax);
+ float8store(buff+16, mbr.ymin);
+ float8store(buff+24, mbr.ymax);
+ return;
+}
+
+void Field_geom::set_key_image(char *buff,uint length)
+{
+}
+
+
+
int Field_blob::key_cmp(const byte *key_ptr, uint max_key_length)
{
char *blob1;
@@ -4041,11 +4093,11 @@ void Field_blob::sort_string(char *to,uint length)
else
{
#ifdef USE_STRCOLL
- if (use_strcoll(default_charset_info))
+ if (use_strcoll(field_charset))
{
- blob_length=my_strnxfrm(default_charset_info,
- (unsigned char *)to,(unsigned char *)blob,
- length,blob_org_length);
+ blob_length=my_strnxfrm(field_charset,
+ (unsigned char *)to, length,
+ (unsigned char *)blob, blob_org_length);
if (blob_length >= length)
return;
to+=blob_length;
@@ -4053,7 +4105,7 @@ void Field_blob::sort_string(char *to,uint length)
else
#endif
for (char *end=blob+blob_length ; blob != end ;)
- *to++=(char) my_sort_order[(uint) (uchar) *blob++];
+ *to++=(char) field_charset->sort_order[(uint) (uchar) *blob++];
}
bzero(to,length-blob_length);
}
@@ -4131,7 +4183,7 @@ int Field_blob::pack_cmp(const char *a, const char *b, uint key_length)
int cmp= memcmp(a,b,min(a_length,b_length));
return cmp ? cmp : (int) (a_length - b_length);
}
- return my_sortncmp(a,a_length, b,b_length);
+ return my_sortncmp(field_charset, a,a_length, b,b_length);
}
@@ -4157,7 +4209,7 @@ int Field_blob::pack_cmp(const char *b, uint key_length)
int cmp= memcmp(a,b,min(a_length,b_length));
return cmp ? cmp : (int) (a_length - b_length);
}
- return my_sortncmp(a,a_length, b,b_length);
+ return my_sortncmp(field_charset, a,a_length, b,b_length);
}
/* Create a packed key that will be used for storage from a MySQL row */
@@ -4268,14 +4320,16 @@ void Field_enum::store_type(ulonglong value)
uint find_enum(TYPELIB *lib,const char *x, uint length)
{
const char *end=x+length;
- while (end > x && isspace(end[-1]))
+ while (end > x && my_isspace(system_charset_info,end[-1]))
end--;
const char *i;
const char *j;
for (uint pos=0 ; (j=lib->type_names[pos]) ; pos++)
{
- for (i=x ; i != end && toupper(*i) == toupper(*j) ; i++, j++) ;
+ for (i=x ; i != end &&
+ my_toupper(system_charset_info,*i) ==
+ my_toupper(system_charset_info,*j) ; i++, j++) ;
if (i == end && ! *j)
return(pos+1);
}
@@ -4452,7 +4506,7 @@ void Field_enum::sql_type(String &res) const
ulonglong find_set(TYPELIB *lib,const char *x,uint length)
{
const char *end=x+length;
- while (end > x && isspace(end[-1]))
+ while (end > x && my_isspace(system_charset_info, end[-1]))
end--;
ulonglong found=0;
@@ -4578,7 +4632,8 @@ bool Field_enum::eq_def(Field *field)
if (typelib->count < from_lib->count)
return 0;
for (uint i=0 ; i < from_lib->count ; i++)
- if (my_strcasecmp(typelib->type_names[i],from_lib->type_names[i]))
+ if (my_strcasecmp(field_charset,
+ typelib->type_names[i],from_lib->type_names[i]))
return 0;
return 1;
}
@@ -4631,6 +4686,7 @@ uint32 calc_pack_length(enum_field_types type,uint32 length)
case FIELD_TYPE_LONG_BLOB: return 4+portable_sizeof_char_ptr;
case FIELD_TYPE_SET:
case FIELD_TYPE_ENUM: abort(); return 0; // This shouldn't happen
+ default: return 0;
}
return 0; // This shouldn't happen
}
@@ -4677,6 +4733,11 @@ Field *make_field(char *ptr, uint32 field_length,
return new Field_blob(ptr,null_pos,null_bit,
unireg_check, field_name, table,
pack_length,f_is_binary(pack_flag) != 0);
+ if (f_is_geom(pack_flag))
+ return new Field_geom(ptr,null_pos,null_bit,
+ unireg_check, field_name, table,
+ pack_length,f_is_binary(pack_flag) != 0);
+
if (interval)
{
if (f_is_enum(pack_flag))
diff --git a/sql/field.h b/sql/field.h
index df31721186e..baedf9e78e7 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -47,6 +47,9 @@ public:
enum utype { NONE,DATE,SHIELD,NOEMPTY,CASEUP,PNR,BGNR,PGNR,YES,NO,REL,
CHECK,EMPTY,UNKNOWN_FIELD,CASEDN,NEXT_NUMBER,INTERVAL_FIELD,
BIT_FIELD, TIMESTAMP_FIELD,CAPITALIZE,BLOB_FIELD};
+
+ enum imagetype { itRAW, itMBR};
+
utype unireg_check;
uint32 field_length; // Length of field
uint16 flags;
@@ -137,17 +140,12 @@ public:
{ memcpy(buff,ptr,length); }
inline void set_image(char *buff,uint length)
{ memcpy(ptr,buff,length); }
- virtual void get_key_image(char *buff,uint length)
+ virtual void get_key_image(char *buff,uint length, imagetype type)
{ get_image(buff,length); }
virtual void set_key_image(char *buff,uint length)
{ set_image(buff,length); }
inline int cmp_image(char *buff,uint length)
- {
- if (binary())
- return memcmp(ptr,buff,length);
- else
- return my_casecmp(ptr,buff,length);
- }
+ { return memcmp(ptr,buff,length); }
inline longlong val_int_offset(uint row_offset)
{
ptr+=row_offset;
@@ -238,6 +236,8 @@ public:
class Field_str :public Field {
+protected:
+ CHARSET_INFO *field_charset;
public:
Field_str(char *ptr_arg,uint32 len_arg, uchar *null_ptr_arg,
uchar null_bit_arg, utype unireg_check_arg,
@@ -245,12 +245,21 @@ public:
struct st_table *table_arg)
:Field(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
unireg_check_arg, field_name_arg, table_arg)
- {}
+ { field_charset=default_charset_info; }
Item_result result_type () const { return STRING_RESULT; }
uint decimals() const { return NOT_FIXED_DEC; }
friend class create_field;
void make_field(Send_field *);
uint size_of() const { return sizeof(*this); }
+ inline CHARSET_INFO *charset() const { return field_charset; }
+ inline int cmp_image(char *buff,uint length)
+ {
+ if (binary())
+ return memcmp(ptr,buff,length);
+ else
+ return my_strncasecmp(field_charset,ptr,buff,length);
+ }
+
};
@@ -825,6 +834,7 @@ class Field_blob :public Field_str {
uint packlength;
String value; // For temporaries
bool binary_flag;
+ bool geom_flag;
public:
Field_blob(char *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
enum utype unireg_check_arg, const char *field_name_arg,
@@ -834,7 +844,7 @@ public:
struct st_table *table_arg, bool binary_arg)
:Field_str((char*) 0,len_arg, maybe_null_arg ? (uchar*) "": 0,0,
NONE, field_name_arg, table_arg),
- packlength(3),binary_flag(binary_arg)
+ packlength(3),binary_flag(binary_arg), geom_flag(true)
{
flags|= BLOB_FLAG;
if (binary_arg)
@@ -881,7 +891,7 @@ public:
store_length(length);
memcpy_fixed(ptr+packlength,&data,sizeof(char*));
}
- void get_key_image(char *buff,uint length);
+ void get_key_image(char *buff,uint length, imagetype type);
void set_key_image(char *buff,uint length);
void sql_type(String &str) const;
inline bool copy()
@@ -910,6 +920,25 @@ public:
};
+class Field_geom :public Field_blob {
+public:
+ Field_geom(char *ptr_arg, uchar *null_ptr_arg, uint null_bit_arg,
+ enum utype unireg_check_arg, const char *field_name_arg,
+ struct st_table *table_arg,uint blob_pack_length,
+ bool binary_arg)
+ :Field_blob(ptr_arg, null_ptr_arg, null_bit_arg, unireg_check_arg,
+ field_name_arg, table_arg, blob_pack_length,binary_arg) {}
+ Field_geom(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg,
+ struct st_table *table_arg, bool binary_arg)
+ :Field_blob(len_arg, maybe_null_arg, field_name_arg,
+ table_arg, binary_arg) {}
+ enum ha_base_keytype key_type() const { return HA_KEYTYPE_VARBINARY; }
+
+ void get_key_image(char *buff,uint length, imagetype type);
+ void set_key_image(char *buff,uint length);
+};
+
+
class Field_enum :public Field_str {
protected:
uint packlength;
@@ -1059,6 +1088,8 @@ bool test_if_int(const char *str,int length);
#define FIELDFLAG_INTERVAL 256
#define FIELDFLAG_BITFIELD 512 // mangled with dec!
#define FIELDFLAG_BLOB 1024 // mangled with dec!
+#define FIELDFLAG_GEOM 2048
+
#define FIELDFLAG_LEFT_FULLSCREEN 8192
#define FIELDFLAG_RIGHT_FULLSCREEN 16384
#define FIELDFLAG_FORMAT_NUMBER 16384 // predit: ###,,## in output
@@ -1085,6 +1116,7 @@ bool test_if_int(const char *str,int length);
#define f_is_enum(x) ((x) & FIELDFLAG_INTERVAL)
#define f_is_bitfield(x) ((x) & FIELDFLAG_BITFIELD)
#define f_is_blob(x) (((x) & (FIELDFLAG_BLOB | FIELDFLAG_NUMBER)) == FIELDFLAG_BLOB)
+#define f_is_geom(x) ((x) & FIELDFLAG_GEOM)
#define f_is_equ(x) ((x) & (1+2+FIELDFLAG_PACK+31*256))
#define f_settype(x) (((int) x) << FIELDFLAG_PACK_SHIFT)
#define f_maybe_null(x) (x & FIELDFLAG_MAYBE_NULL)
diff --git a/sql/field_conv.cc b/sql/field_conv.cc
index c7a6d778953..02be0365002 100644
--- a/sql/field_conv.cc
+++ b/sql/field_conv.cc
@@ -276,7 +276,7 @@ static void do_cut_string(Copy_field *copy)
ptr != end ;
ptr++)
{
- if (!isspace(*ptr))
+ if (!my_isspace(system_charset_info, *ptr))
{
current_thd->cuted_fields++; // Give a warning
break;
diff --git a/sql/filesort.cc b/sql/filesort.cc
index 8f3e8b10629..3bde4eeae14 100644
--- a/sql/filesort.cc
+++ b/sql/filesort.cc
@@ -205,7 +205,7 @@ ha_rows filesort(TABLE *table, SORT_FIELD *sortorder, uint s_length,
err:
#ifdef USE_STRCOLL
- if (use_strcoll(default_charset_info))
+ if (param.tmp_buffer)
x_free(param.tmp_buffer);
#endif
x_free((gptr) sort_keys);
@@ -467,6 +467,8 @@ static void make_sortkey(register SORTPARAM *param,
switch (sort_field->result_type) {
case STRING_RESULT:
{
+ CHARSET_INFO *cs=item->str_value.charset();
+
if (item->maybe_null)
*to++=1;
/* All item->str() to use some extra byte for end null.. */
@@ -492,7 +494,7 @@ static void make_sortkey(register SORTPARAM *param,
length=sort_field->length;
}
#ifdef USE_STRCOLL
- if (use_strcoll(default_charset_info))
+ if(use_strcoll(cs))
{
if (item->binary)
{
@@ -509,10 +511,8 @@ static void make_sortkey(register SORTPARAM *param,
memcpy(param->tmp_buffer,from,length);
from=param->tmp_buffer;
}
- uint tmp_length=my_strnxfrm(default_charset_info,
- to,(unsigned char *) from,
- sort_field->length,
- length);
+ uint tmp_length=my_strnxfrm(cs,to,sort_field->length,
+ (unsigned char *) from, length);
if (tmp_length < sort_field->length)
bzero((char*) to+tmp_length,sort_field->length-tmp_length);
}
@@ -524,7 +524,7 @@ static void make_sortkey(register SORTPARAM *param,
memcpy(to,res->ptr(),length);
bzero((char *)to+length,diff);
if (!item->binary)
- case_sort((char*) to,length);
+ case_sort(cs, (char*) to,length);
#ifdef USE_STRCOLL
}
#endif
@@ -921,8 +921,13 @@ sortlength(SORT_FIELD *sortorder, uint s_length)
{
sortorder->length=sortorder->field->pack_length();
#ifdef USE_STRCOLL
- if (use_strcoll(default_charset_info) && !sortorder->field->binary())
- sortorder->length= sortorder->length*MY_STRXFRM_MULTIPLY;
+ if (!sortorder->field->binary())
+ {
+ // BAR TODO: need checking that it is really Field_str based class
+ CHARSET_INFO *cs=((Field_str*)(sortorder->field))->charset();
+ if (use_strcoll(cs))
+ sortorder->length= sortorder->length*cs->strxfrm_multiply;
+ }
#endif
}
if (sortorder->field->maybe_null())
@@ -930,12 +935,19 @@ sortlength(SORT_FIELD *sortorder, uint s_length)
}
else
{
+#ifdef USE_STRCOLL
+
+#endif
switch ((sortorder->result_type=sortorder->item->result_type())) {
case STRING_RESULT:
sortorder->length=sortorder->item->max_length;
#ifdef USE_STRCOLL
- if (use_strcoll(default_charset_info) && !sortorder->item->binary)
- sortorder->length= sortorder->length*MY_STRXFRM_MULTIPLY;
+ if (!sortorder->item->binary)
+ {
+ CHARSET_INFO *cs=sortorder->item->str_value.charset();
+ if (use_strcoll(cs))
+ sortorder->length= sortorder->length*cs->strxfrm_multiply;
+ }
#endif
break;
case INT_RESULT:
diff --git a/sql/gen_lex_hash.cc b/sql/gen_lex_hash.cc
index 7ebdbcd8ba8..918ec753f68 100644
--- a/sql/gen_lex_hash.cc
+++ b/sql/gen_lex_hash.cc
@@ -30,7 +30,7 @@ bool opt_search=0;
int opt_verbose=0;
ulong opt_count=100000;
-#define max_allowed_array 8000 // Don't generate bigger arrays than this
+#define max_allowed_array 16000 // Don't generate bigger arrays than this
#define max_symbol 32767 // Use this for 'not found'
#define how_much_for_plus 8 // 2-8
#define type_count 1 // 1-5
diff --git a/sql/gstream.cc b/sql/gstream.cc
new file mode 100644
index 00000000000..5a58fef6744
--- /dev/null
+++ b/sql/gstream.cc
@@ -0,0 +1,137 @@
+#include "mysql_priv.h"
+
+int GTextReadStream::get_next_toc_type() const
+{
+ const char *cur = m_cur;
+ while((*cur)&&(strchr(" \t\r\n",*cur)))
+ {
+ cur++;
+ }
+ if(!(*cur))
+ {
+ return eostream;
+ }
+
+ if(((*cur>='a') && (*cur<='z')) || ((*cur>='A') && (*cur<='Z')) || (*cur=='_'))
+ {
+ return word;
+ }
+
+ if(((*cur>='0') && (*cur<='9')) || (*cur=='-') || (*cur=='+') || (*cur=='.'))
+ {
+ return numeric;
+ }
+
+ if(*cur == '(')
+ {
+ return l_bra;
+ }
+
+ if(*cur == ')')
+ {
+ return r_bra;
+ }
+
+ if(*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;
+ }
+
+ ++cur;
+
+ while(((*cur>='a') && (*cur<='z')) || ((*cur>='A') && (*cur<='Z')) || (*cur=='_') ||
+ ((*cur>='0') && (*cur<='9')))
+ {
+ ++cur;
+ }
+
+ *word_len = cur - wd_start;
+
+ m_cur = cur;
+
+ return wd_start;
+}
+
+int GTextReadStream::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;
+ }
+
+ if(((*cur<'0') || (*cur>'9')) && (*cur!='-') && (*cur!='+') && (*cur!='.'))
+ {
+ set_error_msg("Numeric constant expected");
+ return 1;
+ }
+
+ char *endptr;
+
+ *d = strtod(cur, &endptr);
+
+ if(endptr)
+ {
+ m_cur = endptr;
+ }
+
+ return 0;
+}
+
+char GTextReadStream::get_next_symbol()
+{
+ const char *cur = m_cur;
+ while((*cur)&&(strchr(" \t\r\n",*cur)))
+ {
+ cur++;
+ }
+ if(!(*cur))
+ {
+ return 0;
+ }
+
+ m_cur = cur + 1;
+ m_last_text_position = cur;
+
+ return *cur;
+}
+
+void GTextReadStream::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));
+ memcpy(m_err_msg, msg, len + 1);
+}
+
+
diff --git a/sql/gstream.h b/sql/gstream.h
new file mode 100644
index 00000000000..f8df6e337b0
--- /dev/null
+++ b/sql/gstream.h
@@ -0,0 +1,61 @@
+#ifndef GSTREAM_H
+#define GSTREAM_H
+
+#ifdef WITHOUT_MYSQL
+ #include ".\rtree\myisamdef.h"
+#else
+ #include "mysql_priv.h"
+#endif
+
+class GTextReadStream
+{
+public:
+ enum TokTypes
+ {
+ unknown,
+ eostream,
+ word,
+ numeric,
+ l_bra,
+ r_bra,
+ comma,
+ };
+ GTextReadStream(const char *buffer, int size) :
+ m_cur(buffer), m_limit(buffer + size), m_last_text_position(buffer), m_err_msg(NULL) {}
+ GTextReadStream() : m_cur(NULL), m_limit(NULL), m_err_msg(NULL) {}
+
+ ~GTextReadStream()
+ {
+ 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();
+
+ const char *get_last_text_position() const
+ {
+ return m_last_text_position;
+ }
+
+ 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;
+ return err_msg;
+ }
+protected:
+ const char *m_cur;
+ const char *m_limit;
+ const char *m_last_text_position;
+ char *m_err_msg;
+};
+
+#endif
+
+
+
diff --git a/sql/ha_berkeley.cc b/sql/ha_berkeley.cc
index 614d1b5abf5..58a090a8aed 100644
--- a/sql/ha_berkeley.cc
+++ b/sql/ha_berkeley.cc
@@ -168,7 +168,7 @@ bool berkeley_init(void)
db_env=0; /* purecov: inspected */
}
- (void) hash_init(&bdb_open_tables,32,0,0,
+ (void) hash_init(&bdb_open_tables,system_charset_info,32,0,0,
(hash_get_key) bdb_get_key,0,0);
pthread_mutex_init(&bdb_mutex,MY_MUTEX_INIT_FAST);
DBUG_RETURN(db_env == 0);
diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc
index aa8ce0f3c18..b93d9fa0108 100644
--- a/sql/ha_innodb.cc
+++ b/sql/ha_innodb.cc
@@ -471,9 +471,8 @@ innobase_init(void)
DBUG_RETURN(1);
}
-
- (void) hash_init(&innobase_open_tables,32,0,0,
- (hash_get_key) innobase_get_key,0,0);
+ (void) hash_init(&innobase_open_tables,system_charset_info,32,0,0,
+ (hash_get_key) innobase_get_key,0,0);
pthread_mutex_init(&innobase_mutex,MY_MUTEX_INIT_FAST);
DBUG_RETURN(0);
}
@@ -1000,7 +999,10 @@ innobase_mysql_cmp(
case FIELD_TYPE_STRING:
case FIELD_TYPE_VAR_STRING:
- ret = my_sortncmp((const char*) a, a_length,
+ // BAR TODO: Discuss with heikki.tuuri@innodb.com
+ // so that he sends CHARSET_INFO for the field to this function.
+ ret = my_sortncmp(default_charset_info,
+ (const char*) a, a_length,
(const char*) b, b_length);
if (ret < 0) {
return(-1);
diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc
index 50088c238e0..df4de96b6c5 100644
--- a/sql/ha_myisam.cc
+++ b/sql/ha_myisam.cc
@@ -28,6 +28,7 @@
#include "../srclib/myisam/myisamdef.h"
#else
#include "../myisam/myisamdef.h"
+#include "../myisam/rt_index.h"
#endif
ulong myisam_sort_buffer_size;
@@ -759,7 +760,7 @@ int ha_myisam::index_read(byte * buf, const byte * key,
uint key_len, enum ha_rkey_function find_flag)
{
statistic_increment(ha_read_key_count,&LOCK_status);
- int error=mi_rkey(file,buf,active_index, key, key_len, find_flag);
+ int error=mi_rkey(file,buf,active_index, key, key_len, (enum ha_rkey_function)find_flag);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
}
@@ -768,7 +769,7 @@ int ha_myisam::index_read_idx(byte * buf, uint index, const byte * key,
uint key_len, enum ha_rkey_function find_flag)
{
statistic_increment(ha_read_key_count,&LOCK_status);
- int error=mi_rkey(file,buf,index, key, key_len, find_flag);
+ int error=mi_rkey(file,buf,index, key, key_len, (enum ha_rkey_function)find_flag);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
}
@@ -1004,7 +1005,8 @@ int ha_myisam::create(const char *name, register TABLE *table,
pos=table->key_info;
for (i=0; i < table->keys ; i++, pos++)
{
- keydef[i].flag= (pos->flags & (HA_NOSAME | HA_FULLTEXT));
+ keydef[i].flag= (pos->flags & (HA_NOSAME | HA_FULLTEXT | HA_SPATIAL));
+ keydef[i].key_alg=pos->key_alg; // +BAR
keydef[i].seg=keyseg;
keydef[i].keysegs=pos->key_parts;
for (j=0 ; j < pos->key_parts ; j++)
diff --git a/sql/hash_filo.h b/sql/hash_filo.h
index b8d45f0d3be..4d746d9b9bd 100644
--- a/sql/hash_filo.h
+++ b/sql/hash_filo.h
@@ -75,8 +75,8 @@ public:
if (!locked)
(void) pthread_mutex_lock(&lock);
(void) hash_free(&cache);
- (void) hash_init(&cache,size,key_offset, key_length, get_key, free_element,
- 0);
+ (void) hash_init(&cache,system_charset_info,size,key_offset,
+ key_length, get_key, free_element,0);
if (!locked)
(void) pthread_mutex_unlock(&lock);
first_link=last_link=0;
diff --git a/sql/hostname.cc b/sql/hostname.cc
index 7d4e4a8ca75..0b35f970c42 100644
--- a/sql/hostname.cc
+++ b/sql/hostname.cc
@@ -213,10 +213,10 @@ my_string ip_to_hostname(struct in_addr *in, uint *errors)
/* Don't accept hostnames that starts with digits because they may be
false ip:s */
- if (isdigit(name[0]))
+ if (my_isdigit(system_charset_info,name[0]))
{
char *pos;
- for (pos= name+1 ; isdigit(*pos); pos++) ;
+ for (pos= name+1 ; my_isdigit(system_charset_info,*pos); pos++) ;
if (*pos == '.')
{
DBUG_PRINT("error",("mysqld doesn't accept hostnames that starts with a number followed by a '.'"));
diff --git a/sql/init.cc b/sql/init.cc
index df06ddd41ef..ac0ff701649 100644
--- a/sql/init.cc
+++ b/sql/init.cc
@@ -24,6 +24,7 @@ void unireg_init(ulong options)
{
uint i;
double nr;
+ CHARSET_INFO *cs;
DBUG_ENTER("unireg_init");
MYSYS_PROGRAM_DONT_USE_CURSES();
@@ -54,13 +55,19 @@ void unireg_init(ulong options)
// The following is needed because of like optimization in select.cc
- uchar max_char=my_sort_order[(uchar) max_sort_char];
- for (i = 0; i < 256; i++)
+ for (cs=compiled_charsets; cs->number; cs++)
{
- if ((uchar) my_sort_order[i] > max_char)
+ uchar max_char;
+ if (!cs->sort_order)
+ continue;
+ max_char=cs->sort_order[(uchar) cs->max_sort_char];
+ for (i = 0; i < 256; i++)
{
- max_char=(uchar) my_sort_order[i];
- max_sort_char= (char) i;
+ if ((uchar) cs->sort_order[i] > max_char)
+ {
+ max_char=(uchar) cs->sort_order[i];
+ cs->max_sort_char= (char) i;
+ }
}
}
thread_stack_min=thread_stack - STACK_MIN_SIZE;
diff --git a/sql/item.cc b/sql/item.cc
index dac10eafafb..84f4624a248 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -50,7 +50,7 @@ void Item::set_name(char *str,uint length)
name=str; // Used by AS
else
{
- while (length && !isgraph(*str))
+ while (length && !my_isgraph(system_charset_info,*str))
{ // Fix problem with yacc
length--;
str++;
@@ -66,7 +66,7 @@ void Item::set_name(char *str,uint length)
bool Item::eq(const Item *item, bool binary_cmp) const
{
return type() == item->type() && name && item->name &&
- !my_strcasecmp(name,item->name);
+ !my_strcasecmp(system_charset_info,name,item->name);
}
bool Item_string::eq(const Item *item, bool binary_cmp) const
diff --git a/sql/item.h b/sql/item.h
index 575af197e7d..97f2862bb8b 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -364,6 +364,7 @@ public:
};
+#include "spatial.h"
#include "item_sum.h"
#include "item_func.h"
#include "item_cmpfunc.h"
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index bb773af1ddf..c34440d92d4 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -24,6 +24,7 @@
#include "mysql_priv.h"
#include <m_ctype.h>
+
/*
** Test functions
** These returns 0LL if false and 1LL if true and null if some arg is null
@@ -890,6 +891,9 @@ void in_string::set(uint pos,Item *item)
String *res=item->val_str(str);
if (res && res != str)
*str= *res;
+ // BAR TODO: I'm not sure this is absolutely correct
+ if (!str->charset())
+ str->set_charset(default_charset_info);
}
byte *in_string::get_value(Item *item)
@@ -1278,7 +1282,8 @@ Item_func_regex::fix_fields(THD *thd,TABLE_LIST *tables)
int error;
if ((error=regcomp(&preg,res->c_ptr(),
binary ? REG_EXTENDED | REG_NOSUB :
- REG_EXTENDED | REG_NOSUB | REG_ICASE)))
+ REG_EXTENDED | REG_NOSUB | REG_ICASE,
+ res->charset())))
{
(void) regerror(error,&preg,buff,sizeof(buff));
my_printf_error(ER_REGEXP_ERROR,ER(ER_REGEXP_ERROR),MYF(0),buff);
@@ -1325,7 +1330,8 @@ longlong Item_func_regex::val_int()
}
if (regcomp(&preg,res2->c_ptr(),
binary ? REG_EXTENDED | REG_NOSUB :
- REG_EXTENDED | REG_NOSUB | REG_ICASE))
+ REG_EXTENDED | REG_NOSUB | REG_ICASE,
+ res->charset()))
{
null_value=1;
@@ -1349,3 +1355,83 @@ Item_func_regex::~Item_func_regex()
}
#endif /* USE_REGEX */
+
+
+/****************************************************************
+ Classes and functions for spatial relations
+*****************************************************************/
+
+longlong Item_func_spatial_rel::val_int()
+{
+ String *res1=args[0]->val_str(&tmp_value1);
+ String *res2=args[1]->val_str(&tmp_value2);
+ Geometry g1, g2;
+ MBR mbr1,mbr2;
+
+ if ((null_value=(args[0]->null_value ||
+ args[1]->null_value ||
+ g1.create_from_wkb(res1->ptr(),res1->length()) ||
+ g2.create_from_wkb(res2->ptr(),res2->length()) ||
+ g1.get_mbr(&mbr1) ||
+ g2.get_mbr(&mbr2))))
+ return 0;
+
+ switch (spatial_rel)
+ {
+ case SP_CONTAINS_FUNC:
+ return mbr1.contains(&mbr2);
+ case SP_WITHIN_FUNC:
+ return mbr1.within(&mbr2);
+ case SP_EQUALS_FUNC:
+ return mbr1.equals(&mbr2);
+ case SP_DISJOINT_FUNC:
+ return mbr1.disjoint(&mbr2);
+ case SP_INTERSECTS_FUNC:
+ return mbr1.intersects(&mbr2);
+ case SP_TOUCHES_FUNC:
+ return mbr1.touches(&mbr2);
+ case SP_OVERLAPS_FUNC:
+ return mbr1.overlaps(&mbr2);
+ case SP_CROSSES_FUNC:
+ return 0;
+ default:
+ break;
+ }
+
+ null_value=1;
+ return 0;
+}
+
+longlong Item_func_isempty::val_int()
+{
+ String tmp;
+ null_value=0;
+ 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 )))
+ return 0;
+ /* TODO: Ramil or Holyfoot, add real IsSimple calculation */
+ return 0;
+}
+
+longlong Item_func_isclosed::val_int()
+{
+ String tmp;
+ String *wkb=args[0]->val_str(&tmp);
+ Geometry geom;
+ int isclosed;
+
+ null_value= (!wkb ||
+ args[0]->null_value ||
+ geom.create_from_wkb(wkb->ptr(),wkb->length()) ||
+ !GEOM_METHOD_PRESENT(geom,is_closed) ||
+ geom.is_closed(&isclosed));
+
+ return (longlong) isclosed;
+}
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index c9c7d5654d6..b8f21f21008 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -570,3 +570,82 @@ inline Item *and_conds(Item *a,Item *b)
cond->update_used_tables();
return cond;
}
+
+
+/**************************************************************
+Spatial relations
+***************************************************************/
+
+class Item_func_spatial_rel :public Item_bool_func2
+{
+ enum Functype spatial_rel;
+public:
+ Item_func_spatial_rel(Item *a,Item *b, enum Functype sp_rel) :
+ Item_bool_func2(a,b) { spatial_rel = sp_rel; }
+ longlong val_int();
+ enum Functype functype() const
+ {
+ switch (spatial_rel)
+ {
+ case SP_CONTAINS_FUNC:
+ return SP_WITHIN_FUNC;
+ case SP_WITHIN_FUNC:
+ return SP_CONTAINS_FUNC;
+ default:
+ return spatial_rel;
+ }
+ }
+ enum Functype rev_functype() const { return spatial_rel; }
+ const char *func_name() const
+ {
+ switch (spatial_rel)
+ {
+ case SP_CONTAINS_FUNC:
+ return "contains";
+ case SP_WITHIN_FUNC:
+ return "within";
+ case SP_EQUALS_FUNC:
+ return "equals";
+ case SP_DISJOINT_FUNC:
+ return "disjoint";
+ case SP_INTERSECTS_FUNC:
+ return "intersects";
+ case SP_TOUCHES_FUNC:
+ return "touches";
+ case SP_CROSSES_FUNC:
+ return "crosses";
+ case SP_OVERLAPS_FUNC:
+ return "overlaps";
+ default:
+ return "sp_unknown";
+ }
+ }
+};
+
+
+class Item_func_isempty :public Item_bool_func
+{
+public:
+ Item_func_isempty(Item *a) :Item_bool_func(a) {}
+ longlong val_int();
+ optimize_type select_optimize() const { return OPTIMIZE_NONE; }
+ const char *func_name() const { return "isempty"; }
+};
+
+class Item_func_issimple :public Item_bool_func
+{
+public:
+ Item_func_issimple(Item *a) :Item_bool_func(a) {}
+ longlong val_int();
+ optimize_type select_optimize() const { return OPTIMIZE_NONE; }
+ const char *func_name() const { return "issimple"; }
+};
+
+class Item_func_isclosed :public Item_bool_func
+{
+public:
+ Item_func_isclosed(Item *a) :Item_bool_func(a) {}
+ longlong val_int();
+ optimize_type select_optimize() const { return OPTIMIZE_NONE; }
+ const char *func_name() const { return "isclosed"; }
+};
diff --git a/sql/item_create.cc b/sql/item_create.cc
index 6f64e9517ba..79d7fcfe230 100644
--- a/sql/item_create.cc
+++ b/sql/item_create.cc
@@ -413,3 +413,158 @@ Item *create_func_cast(Item *a, Item_cast cast_type)
}
return res;
}
+
+Item *create_func_geometry_from_text(Item* a)
+{
+ return new Item_func_geometry_from_text(a);
+}
+
+Item *create_func_as_text(Item* a)
+{
+ return new Item_func_as_text(a);
+}
+
+Item *create_func_startpoint(Item* a)
+{
+ return new Item_func_spatial_decomp(a, Item_func::SP_STARTPOINT);
+}
+
+Item *create_func_endpoint(Item* a)
+{
+ return new Item_func_spatial_decomp(a, Item_func::SP_ENDPOINT);
+}
+
+Item *create_func_exteriorring(Item* a)
+{
+ return new Item_func_spatial_decomp(a, Item_func::SP_EXTERIORRING);
+}
+
+Item *create_func_pointn(Item* a, Item* b)
+{
+ return new Item_func_spatial_decomp_n(a,b,Item_func::SP_POINTN);
+}
+
+Item *create_func_interiorringn(Item* a, Item* b)
+{
+ return new Item_func_spatial_decomp_n(a,b,Item_func::SP_INTERIORRINGN);
+}
+
+Item *create_func_geometryn(Item* a, Item* b)
+{
+ return new Item_func_spatial_decomp_n(a,b,Item_func::SP_GEOMETRYN);
+}
+
+Item *create_func_centroid(Item* a)
+{
+ return new Item_func_centroid(a);
+}
+
+Item *create_func_envelope(Item* a)
+{
+ return new Item_func_envelope(a);
+}
+
+Item *create_func_equals(Item* a, Item* b)
+{
+ return new Item_func_spatial_rel(a, b, Item_func::SP_EQUALS_FUNC);
+}
+
+Item *create_func_disjoint(Item* a, Item* b)
+{
+ return new Item_func_spatial_rel(a, b, Item_func::SP_DISJOINT_FUNC);
+}
+
+Item *create_func_intersects(Item* a, Item* b)
+{
+ return new Item_func_spatial_rel(a, b, Item_func::SP_INTERSECTS_FUNC);
+}
+
+Item *create_func_touches(Item* a, Item* b)
+{
+ return new Item_func_spatial_rel(a, b, Item_func::SP_TOUCHES_FUNC);
+}
+
+Item *create_func_crosses(Item* a, Item* b)
+{
+ return new Item_func_spatial_rel(a, b, Item_func::SP_CROSSES_FUNC);
+}
+
+Item *create_func_within(Item* a, Item* b)
+{
+ return new Item_func_spatial_rel(a, b, Item_func::SP_WITHIN_FUNC);
+}
+
+Item *create_func_contains(Item* a, Item* b)
+{
+ return new Item_func_spatial_rel(a, b, Item_func::SP_CONTAINS_FUNC);
+}
+
+Item *create_func_overlaps(Item* a, Item* b)
+{
+ return new Item_func_spatial_rel(a, b, Item_func::SP_OVERLAPS_FUNC);
+}
+
+Item *create_func_isempty(Item* a)
+{
+ return new Item_func_isempty(a);
+}
+
+Item *create_func_issimple(Item* a)
+{
+ return new Item_func_issimple(a);
+}
+
+Item *create_func_isclosed(Item* a)
+{
+ return new Item_func_isclosed(a);
+}
+
+Item *create_func_geometry_type(Item* a)
+{
+ return new Item_func_geometry_type(a);
+}
+
+Item *create_func_dimension(Item* a)
+{
+ return new Item_func_dimension(a);
+}
+
+Item *create_func_x(Item* a)
+{
+ return new Item_func_x(a);
+}
+
+Item *create_func_y(Item* a)
+{
+ return new Item_func_y(a);
+}
+
+Item *create_func_numpoints(Item* a)
+{
+ return new Item_func_numpoints(a);
+}
+
+Item *create_func_numinteriorring(Item* a)
+{
+ return new Item_func_numinteriorring(a);
+}
+
+Item *create_func_numgeometries(Item* a)
+{
+ return new Item_func_numgeometries(a);
+}
+
+Item *create_func_area(Item* a)
+{
+ return new Item_func_area(a);
+}
+
+Item *create_func_glength(Item* a)
+{
+ return new Item_func_glength(a);
+}
+
+Item *create_func_point(Item* a, Item* b)
+{
+ return new Item_func_point(a,b);
+}
diff --git a/sql/item_create.h b/sql/item_create.h
index 580596505da..6f7e8ebf89a 100644
--- a/sql/item_create.h
+++ b/sql/item_create.h
@@ -88,3 +88,41 @@ Item *create_func_version(void);
Item *create_func_weekday(Item* a);
Item *create_load_file(Item* a);
Item *create_wait_for_master_pos(Item* a, Item* b);
+
+Item *create_func_geometry_from_text(Item* a);
+Item *create_func_as_text(Item* a);
+Item *create_func_startpoint(Item* a);
+Item *create_func_endpoint(Item* a);
+Item *create_func_exteriorring(Item* a);
+Item *create_func_centroid(Item* a);
+Item *create_func_envelope(Item* a);
+Item *create_func_pointn(Item* a, Item* b);
+Item *create_func_interiorringn(Item* a, Item* b);
+Item *create_func_geometryn(Item* a, Item* b);
+
+Item *create_func_equals(Item* a, Item* b);
+Item *create_func_disjoint(Item* a, Item* b);
+Item *create_func_intersects(Item* a, Item* b);
+Item *create_func_touches(Item* a, Item* b);
+Item *create_func_crosses(Item* a, Item* b);
+Item *create_func_within(Item* a, Item* b);
+Item *create_func_contains(Item* a, Item* b);
+Item *create_func_overlaps(Item* a, Item* b);
+
+Item *create_func_isempty(Item* a);
+Item *create_func_issimple(Item* a);
+Item *create_func_isclosed(Item* a);
+
+Item *create_func_geometry_type(Item* a);
+Item *create_func_dimension(Item* a);
+Item *create_func_x(Item* a);
+Item *create_func_y(Item* a);
+Item *create_func_area(Item* a);
+Item *create_func_glength(Item* a);
+
+Item *create_func_numpoints(Item* a);
+Item *create_func_numinteriorring(Item* a);
+Item *create_func_numgeometries(Item* a);
+
+Item *create_func_point(Item* a,Item* b);
+
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 90e7a5a6477..9d4895788fc 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -27,6 +27,8 @@
#include <time.h>
#include <ft_global.h>
#include "slave.h" // for wait_for_master_pos
+#include "gstream.h"
+
/* return TRUE if item is a constant */
@@ -828,7 +830,7 @@ longlong Item_func_locate::val_int()
{
start=(uint) args[2]->val_int()-1;
#ifdef USE_MB
- if (use_mb(default_charset_info))
+ if (use_mb(a->charset()))
{
start0=start;
if (!binary_str)
@@ -841,7 +843,7 @@ longlong Item_func_locate::val_int()
if (!b->length()) // Found empty string at start
return (longlong) (start+1);
#ifdef USE_MB
- if (use_mb(default_charset_info) && !binary_str)
+ if (use_mb(a->charset()) && !binary_str)
{
const char *ptr=a->ptr()+start;
const char *search=b->ptr();
@@ -860,7 +862,7 @@ longlong Item_func_locate::val_int()
return (longlong) start0+1;
}
skipp:
- if ((l=my_ismbchar(default_charset_info,ptr,strend))) ptr+=l;
+ if ((l=my_ismbchar(a->charset(),ptr,strend))) ptr+=l;
else ++ptr;
++start0;
}
@@ -911,11 +913,10 @@ longlong Item_func_ord::val_int()
null_value=0;
if (!res->length()) return 0;
#ifdef USE_MB
- if (use_mb(default_charset_info) && !args[0]->binary)
+ if (use_mb(res->charset()) && !args[0]->binary)
{
register const char *str=res->ptr();
- register uint32 n=0, l=my_ismbchar(default_charset_info,
- str,str+res->length());
+ register uint32 n=0, l=my_ismbchar(res->charset(),str,str+res->length());
if (!l) return (longlong)((uchar) *str);
while (l--)
n=(n<<8)|(uint32)((uchar) *str++);
@@ -989,7 +990,8 @@ longlong Item_func_find_in_set::val_int()
const char *pos= f_pos;
while (pos != f_end)
{
- if (toupper(*str) != toupper(*pos))
+ if (my_toupper(find->charset(),*str) !=
+ my_toupper(find->charset(),*pos))
goto not_found;
str++;
pos++;
@@ -1419,7 +1421,8 @@ char *ull_get_key(const ULL *ull,uint *length,
void item_user_lock_init(void)
{
pthread_mutex_init(&LOCK_user_locks,MY_MUTEX_INIT_SLOW);
- hash_init(&hash_user_locks,16,0,0,(hash_get_key) ull_get_key,NULL,0);
+ hash_init(&hash_user_locks,system_charset_info,
+ 16,0,0,(hash_get_key) ull_get_key,NULL,0);
}
void item_user_lock_free(void)
@@ -2254,3 +2257,130 @@ Item *get_system_var(LEX_STRING name)
my_error(ER_UNKNOWN_SYSTEM_VARIABLE,MYF(0),name);
return 0;
}
+
+
+/**************************************************************************
+Spatial functions
+***************************************************************************/
+
+longlong Item_func_dimension::val_int()
+{
+ uint32 dim;
+ String *wkb=args[0]->val_str(&value);
+ Geometry geom;
+
+ null_value= (!wkb ||
+ args[0]->null_value ||
+ geom.create_from_wkb(wkb->ptr(),wkb->length()) ||
+ geom.dimension(&dim));
+
+ return (longlong) dim;
+}
+
+longlong Item_func_numinteriorring::val_int()
+{
+ uint32 num;
+ String *wkb=args[0]->val_str(&value);
+ Geometry geom;
+
+ null_value= (!wkb ||
+ args[0]->null_value ||
+ geom.create_from_wkb(wkb->ptr(),wkb->length()) ||
+ !GEOM_METHOD_PRESENT(geom,num_interior_ring) ||
+ geom.num_interior_ring(&num));
+
+ return (longlong) num;
+}
+
+longlong Item_func_numgeometries::val_int()
+{
+ uint32 num;
+ String *wkb=args[0]->val_str(&value);
+ Geometry geom;
+
+ null_value= (!wkb ||
+ args[0]->null_value ||
+ geom.create_from_wkb(wkb->ptr(),wkb->length()) ||
+ !GEOM_METHOD_PRESENT(geom,num_geometries) ||
+ geom.num_geometries(&num));
+
+ return (longlong) num;
+}
+
+longlong Item_func_numpoints::val_int()
+{
+ uint32 num;
+ String *wkb=args[0]->val_str(&value);
+ Geometry geom;
+
+ null_value= (!wkb ||
+ args[0]->null_value ||
+ geom.create_from_wkb(wkb->ptr(),wkb->length()) ||
+ !GEOM_METHOD_PRESENT(geom,num_points) ||
+ geom.num_points(&num));
+
+ return (longlong) num;
+}
+
+
+double Item_func_x::val()
+{
+ double res;
+ String *wkb=args[0]->val_str(&value);
+ Geometry geom;
+
+ null_value= (!wkb ||
+ args[0]->null_value ||
+ geom.create_from_wkb(wkb->ptr(),wkb->length()) ||
+ !GEOM_METHOD_PRESENT(geom,get_x) ||
+ geom.get_x(&res));
+
+ return res;
+}
+
+
+double Item_func_y::val()
+{
+ double res;
+ String *wkb=args[0]->val_str(&value);
+ Geometry geom;
+
+ null_value= (!wkb ||
+ args[0]->null_value ||
+ geom.create_from_wkb(wkb->ptr(),wkb->length()) ||
+ !GEOM_METHOD_PRESENT(geom,get_y) ||
+ geom.get_y(&res));
+
+ return res;
+}
+
+
+double Item_func_area::val()
+{
+ double res;
+ String *wkb=args[0]->val_str(&value);
+ Geometry geom;
+
+ null_value= (!wkb ||
+ args[0]->null_value ||
+ geom.create_from_wkb(wkb->ptr(),wkb->length()) ||
+ !GEOM_METHOD_PRESENT(geom,area) ||
+ geom.area(&res));
+
+ return res;
+}
+
+
+double Item_func_glength::val()
+{
+ double res;
+ String *wkb=args[0]->val_str(&value);
+ Geometry geom;
+
+ null_value= (!wkb ||
+ args[0]->null_value ||
+ geom.create_from_wkb(wkb->ptr(),wkb->length()) ||
+ !GEOM_METHOD_PRESENT(geom,length) ||
+ geom.length(&res));
+ return res;
+}
diff --git a/sql/item_func.h b/sql/item_func.h
index c3e437712ee..0056126d50e 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -39,7 +39,12 @@ public:
enum Functype { UNKNOWN_FUNC,EQ_FUNC,EQUAL_FUNC,NE_FUNC,LT_FUNC,LE_FUNC,
GE_FUNC,GT_FUNC,FT_FUNC,
LIKE_FUNC,NOTLIKE_FUNC,ISNULL_FUNC,ISNOTNULL_FUNC,
- COND_AND_FUNC,COND_OR_FUNC,BETWEEN,IN_FUNC,INTERVAL_FUNC};
+ COND_AND_FUNC,COND_OR_FUNC,BETWEEN,IN_FUNC,INTERVAL_FUNC,
+ SP_EQUALS_FUNC, SP_DISJOINT_FUNC,SP_INTERSECTS_FUNC,
+ SP_TOUCHES_FUNC,SP_CROSSES_FUNC,SP_WITHIN_FUNC,
+ SP_CONTAINS_FUNC,SP_OVERLAPS_FUNC,
+ SP_STARTPOINT,SP_ENDPOINT,SP_EXTERIORRING,
+ SP_POINTN,SP_GEOMETRYN,SP_INTERIORRINGN};
enum optimize_type { OPTIMIZE_NONE,OPTIMIZE_KEY,OPTIMIZE_OP, OPTIMIZE_NULL };
enum Type type() const { return FUNC_ITEM; }
virtual enum Functype functype() const { return UNKNOWN_FUNC; }
@@ -945,6 +950,86 @@ public:
void init_search(bool no_order);
};
+
+class Item_func_dimension :public Item_int_func
+{
+ String value;
+public:
+ Item_func_dimension(Item *a) :Item_int_func(a) {}
+ longlong val_int();
+ const char *func_name() const { return "dimension"; }
+ void fix_length_and_dec() { max_length=10; }
+};
+
+
+class Item_func_x :public Item_real_func
+{
+ String value;
+public:
+ Item_func_x(Item *a) :Item_real_func(a) {}
+ double val();
+ const char *func_name() const { return "x"; }
+};
+
+
+class Item_func_y :public Item_real_func
+{
+ String value;
+public:
+ Item_func_y(Item *a) :Item_real_func(a) {}
+ double val();
+ const char *func_name() const { return "y"; }
+};
+
+
+class Item_func_numgeometries :public Item_int_func
+{
+ String value;
+public:
+ Item_func_numgeometries(Item *a) :Item_int_func(a) {}
+ longlong val_int();
+ const char *func_name() const { return "numgeometries"; }
+ void fix_length_and_dec() { max_length=10; }
+};
+
+class Item_func_numinteriorring :public Item_int_func
+{
+ String value;
+public:
+ Item_func_numinteriorring(Item *a) :Item_int_func(a) {}
+ longlong val_int();
+ const char *func_name() const { return "numinteriorring"; }
+ void fix_length_and_dec() { max_length=10; }
+};
+
+class Item_func_numpoints :public Item_int_func
+{
+ String value;
+public:
+ Item_func_numpoints(Item *a) :Item_int_func(a) {}
+ longlong val_int();
+ const char *func_name() const { return "numpoints"; }
+ void fix_length_and_dec() { max_length=10; }
+};
+
+class Item_func_area :public Item_real_func
+{
+ String value;
+public:
+ Item_func_area(Item *a) :Item_real_func(a) {}
+ double val();
+ const char *func_name() const { return "area"; }
+};
+
+class Item_func_glength :public Item_real_func
+{
+ String value;
+public:
+ Item_func_glength(Item *a) :Item_real_func(a) {}
+ double val();
+ const char *func_name() const { return "glength"; }
+};
+
class Item_func_match_nl :public Item_func_match
{
public:
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index 9d24ca19b4c..4a7e5dfe33f 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -42,7 +42,7 @@ uint nr_of_decimals(const char *str)
if ((str=strchr(str,'.')))
{
const char *start= ++str;
- for ( ; isdigit(*str) ; str++) ;
+ for ( ; my_isdigit(system_charset_info,*str) ; str++) ;
return (uint) (str-start);
}
return 0;
@@ -510,7 +510,7 @@ String *Item_func_reverse::val_str(String *str)
ptr = (char *) res->ptr();
end=ptr+res->length();
#ifdef USE_MB
- if (use_mb(default_charset_info) && !binary)
+ if (use_mb(res->charset()) && !binary)
{
String tmpstr;
tmpstr.copy(*res);
@@ -518,7 +518,7 @@ String *Item_func_reverse::val_str(String *str)
register uint32 l;
while (ptr < end)
{
- if ((l=my_ismbchar(default_charset_info, ptr,end)))
+ if ((l=my_ismbchar(res->charset(), ptr,end)))
tmp-=l, memcpy(tmp,ptr,l), ptr+=l;
else
*--tmp=*ptr++;
@@ -561,8 +561,7 @@ String *Item_func_replace::val_str(String *str)
#ifdef USE_MB
const char *ptr,*end,*strend,*search,*search_end;
register uint32 l;
- bool binary_str = (args[0]->binary || args[1]->binary ||
- !use_mb(default_charset_info));
+ bool binary_str;
#endif
null_value=0;
@@ -573,6 +572,10 @@ String *Item_func_replace::val_str(String *str)
if (args[1]->null_value)
goto null;
+#ifdef USE_MB
+ binary_str = (args[0]->binary || args[1]->binary || !use_mb(res->charset()));
+#endif
+
if (res2->length() == 0)
return res;
#ifndef USE_MB
@@ -618,7 +621,7 @@ redo:
goto redo;
}
skipp:
- if ((l=my_ismbchar(default_charset_info, ptr,strend))) ptr+=l;
+ if ((l=my_ismbchar(res->charset(), ptr,strend))) ptr+=l;
else ++ptr;
}
}
@@ -676,7 +679,7 @@ String *Item_func_insert::val_str(String *str)
args[3]->null_value)
goto null; /* purecov: inspected */
#ifdef USE_MB
- if (use_mb(default_charset_info) && !args[0]->binary)
+ if (use_mb(res->charset()) && !args[0]->binary)
{
start=res->charpos(start);
length=res->charpos(length,start);
@@ -748,7 +751,7 @@ String *Item_func_left::val_str(String *str)
if (length <= 0)
return &empty_string;
#ifdef USE_MB
- if (use_mb(default_charset_info) && !binary)
+ if (use_mb(res->charset()) && !binary)
length = res->charpos(length);
#endif
if (res->length() > (ulong) length)
@@ -796,7 +799,7 @@ String *Item_func_right::val_str(String *str)
if (res->length() <= (uint) length)
return res; /* purecov: inspected */
#ifdef USE_MB
- if (use_mb(default_charset_info) && !binary)
+ if (use_mb(res->charset()) && !binary)
{
uint start=res->numchars()-(uint) length;
if (start<=0) return res;
@@ -829,7 +832,7 @@ String *Item_func_substr::val_str(String *str)
(arg_count == 3 && args[2]->null_value))))
return 0; /* purecov: inspected */
#ifdef USE_MB
- if (use_mb(default_charset_info) && !binary)
+ if (use_mb(res->charset()) && !binary)
{
start=res->charpos(start);
length=res->charpos(length,start);
@@ -889,7 +892,7 @@ String *Item_func_substr_index::val_str(String *str)
return &empty_string; // Wrong parameters
#ifdef USE_MB
- if (use_mb(default_charset_info) && !binary)
+ if (use_mb(res->charset()) && !binary)
{
const char *ptr=res->ptr();
const char *strend = ptr+res->length();
@@ -914,7 +917,7 @@ String *Item_func_substr_index::val_str(String *str)
continue;
}
skipp:
- if ((l=my_ismbchar(default_charset_info, ptr,strend))) ptr+=l;
+ if ((l=my_ismbchar(res->charset(), ptr,strend))) ptr+=l;
else ++ptr;
} /* either not found or got total number when count<0 */
if (pass == 0) /* count<0 */
@@ -1043,11 +1046,11 @@ String *Item_func_rtrim::val_str(String *str)
{
char chr=(*remove_str)[0];
#ifdef USE_MB
- if (use_mb(default_charset_info) && !binary)
+ if (use_mb(res->charset()) && !binary)
{
while (ptr < end)
{
- if ((l=my_ismbchar(default_charset_info, ptr,end))) ptr+=l,p=ptr;
+ if ((l=my_ismbchar(res->charset(), ptr,end))) ptr+=l,p=ptr;
else ++ptr;
}
ptr=p;
@@ -1060,12 +1063,12 @@ String *Item_func_rtrim::val_str(String *str)
{
const char *r_ptr=remove_str->ptr();
#ifdef USE_MB
- if (use_mb(default_charset_info) && !binary)
+ if (use_mb(res->charset()) && !binary)
{
loop:
while (ptr + remove_length < end)
{
- if ((l=my_ismbchar(default_charset_info, ptr,end))) ptr+=l;
+ if ((l=my_ismbchar(res->charset(), ptr,end))) ptr+=l;
else ++ptr;
}
if (ptr + remove_length == end && !memcmp(ptr,r_ptr,remove_length))
@@ -1111,14 +1114,14 @@ String *Item_func_trim::val_str(String *str)
while (ptr+remove_length <= end && !memcmp(ptr,r_ptr,remove_length))
ptr+=remove_length;
#ifdef USE_MB
- if (use_mb(default_charset_info) && !binary)
+ if (use_mb(res->charset()) && !binary)
{
char *p=ptr;
register uint32 l;
loop:
while (ptr + remove_length < end)
{
- if ((l=my_ismbchar(default_charset_info, ptr,end))) ptr+=l;
+ if ((l=my_ismbchar(res->charset(), ptr,end))) ptr+=l;
else ++ptr;
}
if (ptr + remove_length == end && !memcmp(ptr,r_ptr,remove_length))
@@ -1268,9 +1271,9 @@ extern "C" {
extern const char *soundex_map; // In mysys/static.c
}
-static char get_scode(char *ptr)
+static char get_scode(CHARSET_INFO *cs,char *ptr)
{
- uchar ch=toupper(*ptr);
+ uchar ch=my_toupper(cs,*ptr);
if (ch < 'A' || ch > 'Z')
{
// Thread extended alfa (country spec)
@@ -1292,21 +1295,21 @@ String *Item_func_soundex::val_str(String *str)
char *to= (char *) tmp_value.ptr();
char *from= (char *) res->ptr(), *end=from+res->length();
- while (from != end && isspace(*from)) // Skip pre-space
+ while (from != end && my_isspace(str->charset(),*from)) // Skip pre-space
from++; /* purecov: inspected */
if (from == end)
return &empty_string; // No alpha characters.
- *to++ = toupper(*from); // Copy first letter
- last_ch = get_scode(from); // code of the first letter
+ *to++ = my_toupper(str->charset(),*from);// Copy first letter
+ last_ch = get_scode(str->charset(),from);// code of the first letter
// for the first 'double-letter check.
// Loop on input letters until
// end of input (null) or output
// letter code count = 3
for (from++ ; from < end ; from++)
{
- if (!isalpha(*from))
+ if (!my_isalpha(str->charset(),*from))
continue;
- ch=get_scode(from);
+ ch=get_scode(str->charset(),from);
if ((ch != '0') && (ch != last_ch)) // if not skipped or double
{
*to++ = ch; // letter, copy to output
@@ -1773,6 +1776,146 @@ String *Item_func_conv::val_str(String *str)
}
+String *Item_func_conv_charset::val_str(String *str)
+{
+ my_wc_t wc;
+ int cnvres;
+ const uchar *s, *se;
+ uchar *d, *d0, *de;
+ uint32 dmaxlen;
+ String *arg= args[0]->val_str(str);
+ CHARSET_INFO *from,*to;
+
+ if (!arg)
+ {
+ null_value=1;
+ return 0;
+ }
+
+ from=arg->charset();
+ to=conv_charset;
+
+ s=(const uchar*)arg->ptr();
+ se=s+arg->length();
+
+ dmaxlen=arg->length()*(conv_charset->mbmaxlen?conv_charset->mbmaxlen:1)+1;
+ str->alloc(dmaxlen);
+ d0=d=(unsigned char*)str->ptr();
+ de=d+dmaxlen;
+
+ while( s < se && d < de){
+
+ cnvres=from->mb_wc(from,&wc,s,se);
+ if (cnvres>0)
+ {
+ s+=cnvres;
+ }
+ else if (cnvres==MY_CS_ILSEQ)
+ {
+ s++;
+ wc='?';
+ }
+ else
+ break;
+
+outp:
+ cnvres=to->wc_mb(to,wc,d,de);
+ if (cnvres>0)
+ {
+ d+=cnvres;
+ }
+ else if (cnvres==MY_CS_ILUNI && wc!='?')
+ {
+ wc='?';
+ goto outp;
+ }
+ else
+ break;
+ };
+
+ str->length((uint32) (d-d0));
+ str->set_charset(to);
+ return str;
+}
+
+void Item_func_conv_charset::fix_length_and_dec()
+{
+ /* BAR TODO: What to do here??? */
+}
+
+
+String *Item_func_conv_charset3::val_str(String *str)
+{
+ my_wc_t wc;
+ int cnvres;
+ const uchar *s, *se;
+ uchar *d, *d0, *de;
+ uint32 dmaxlen;
+ String *arg= args[0]->val_str(str);
+ String *to_cs= args[1]->val_str(str);
+ String *from_cs= args[2]->val_str(str);
+ CHARSET_INFO *from_charset;
+ CHARSET_INFO *to_charset;
+
+ if (!arg || args[0]->null_value ||
+ !to_cs || args[1]->null_value ||
+ !from_cs || args[2]->null_value ||
+ !(from_charset=find_compiled_charset_by_name(from_cs->ptr())) ||
+ !(to_charset=find_compiled_charset_by_name(to_cs->ptr())))
+ {
+ null_value=1;
+ return 0;
+ }
+
+ s=(const uchar*)arg->ptr();
+ se=s+arg->length();
+
+ dmaxlen=arg->length()*(to_charset->mbmaxlen?to_charset->mbmaxlen:1)+1;
+ str->alloc(dmaxlen);
+ d0=d=(unsigned char*)str->ptr();
+ de=d+dmaxlen;
+
+ while( s < se && d < de){
+
+ cnvres=from_charset->mb_wc(from_charset,&wc,s,se);
+ if (cnvres>0)
+ {
+ s+=cnvres;
+ }
+ else if (cnvres==MY_CS_ILSEQ)
+ {
+ s++;
+ wc='?';
+ }
+ else
+ break;
+
+outp:
+ cnvres=to_charset->wc_mb(to_charset,wc,d,de);
+ if (cnvres>0)
+ {
+ d+=cnvres;
+ }
+ else if (cnvres==MY_CS_ILUNI && wc!='?')
+ {
+ wc='?';
+ goto outp;
+ }
+ else
+ break;
+ };
+
+ str->length((uint32) (d-d0));
+ str->set_charset(to_charset);
+ return str;
+}
+
+void Item_func_conv_charset3::fix_length_and_dec()
+{
+ /* BAR TODO: What to do here??? */
+}
+
+
String *Item_func_hex::val_str(String *str)
{
if (args[0]->result_type() != STRING_RESULT)
@@ -1955,3 +2098,333 @@ String* Item_func_inet_ntoa::val_str(String* str)
str->length(str->length()-1); // Remove last '.';
return str;
}
+
+/*******************************************************
+General functions for spatial objects
+********************************************************/
+
+#include "gstream.h"
+
+String *Item_func_geometry_from_text::val_str(String *str)
+{
+ Geometry geom;
+ String *wkt = args[0]->val_str(str);
+ GTextReadStream trs(wkt->ptr(), wkt->length());
+
+ str->length(0);
+ if ((null_value=(args[0]->null_value || geom.create_from_wkt(&trs, str, 0))))
+ return 0;
+ return str;
+}
+
+
+void Item_func_geometry_from_text::fix_length_and_dec()
+{
+ max_length=MAX_BLOB_WIDTH;
+}
+
+
+String *Item_func_as_text::val_str(String *str)
+{
+ String *wkt = args[0]->val_str(str);
+ Geometry geom;
+
+ str->length(0);
+ if ((null_value=(args[0]->null_value ||
+ geom.create_from_wkb(wkt->ptr(),wkt->length()) ||
+ geom.as_wkt(str))))
+ return 0;
+ return str;
+}
+
+void Item_func_as_text::fix_length_and_dec()
+{
+ max_length=MAX_BLOB_WIDTH;
+}
+
+String *Item_func_geometry_type::val_str(String *str)
+{
+ String *wkt = args[0]->val_str(str);
+ Geometry geom;
+
+ if ((null_value=(args[0]->null_value ||
+ geom.create_from_wkb(wkt->ptr(),wkt->length()))))
+ return 0;
+ str->copy(geom.get_class_info()->m_name);
+ return str;
+}
+
+
+String *Item_func_envelope::val_str(String *str)
+{
+ String *wkb = args[0]->val_str(str);
+ Geometry geom;
+
+ null_value = args[0]->null_value ||
+ geom.create_from_wkb(wkb->ptr(),wkb->length()) ||
+ geom.envelope(str);
+
+ return null_value ? 0 : str;
+}
+
+
+String *Item_func_centroid::val_str(String *str)
+{
+ String *wkb = args[0]->val_str(str);
+ Geometry geom;
+
+ null_value = args[0]->null_value ||
+ geom.create_from_wkb(wkb->ptr(),wkb->length()) ||
+ !GEOM_METHOD_PRESENT(geom,centroid) ||
+ geom.centroid(str);
+
+ return null_value ? 0: str;
+}
+
+
+/***********************************************
+ Spatial decomposition functions
+***********************************************/
+
+String *Item_func_spatial_decomp::val_str(String *str)
+{
+ String *wkb = args[0]->val_str(str);
+ Geometry geom;
+
+ if ((null_value = (args[0]->null_value ||
+ geom.create_from_wkb(wkb->ptr(),wkb->length()))))
+ return 0;
+
+ null_value=1;
+ switch(decomp_func)
+ {
+ case SP_STARTPOINT:
+ if (!GEOM_METHOD_PRESENT(geom,start_point) || geom.start_point(str))
+ goto ret;
+ break;
+
+ case SP_ENDPOINT:
+ if (!GEOM_METHOD_PRESENT(geom,end_point) || geom.end_point(str))
+ goto ret;
+ break;
+
+ case SP_EXTERIORRING:
+ if (!GEOM_METHOD_PRESENT(geom,exterior_ring) || geom.exterior_ring(str))
+ goto ret;
+ break;
+
+ default:
+ goto ret;
+ }
+ null_value=0;
+
+ret:
+ return null_value ? 0 : str;
+}
+
+
+String *Item_func_spatial_decomp_n::val_str(String *str)
+{
+ String *wkb = args[0]->val_str(str);
+ long n = (long) args[1]->val_int();
+ Geometry geom;
+
+ if ((null_value = (args[0]->null_value ||
+ args[1]->null_value ||
+ geom.create_from_wkb(wkb->ptr(),wkb->length()) )))
+ return 0;
+
+ null_value=1;
+
+ switch(decomp_func_n)
+ {
+ case SP_POINTN:
+ if (!GEOM_METHOD_PRESENT(geom,point_n) ||
+ geom.point_n(n,str))
+ goto ret;
+ break;
+
+ case SP_GEOMETRYN:
+ if (!GEOM_METHOD_PRESENT(geom,geometry_n) ||
+ geom.geometry_n(n,str))
+ goto ret;
+ break;
+
+ case SP_INTERIORRINGN:
+ if (!GEOM_METHOD_PRESENT(geom,interior_ring_n) ||
+ geom.interior_ring_n(n,str))
+ goto ret;
+ break;
+
+ default:
+ goto ret;
+ }
+ null_value=0;
+
+ret:
+ return null_value ? 0 : str;
+}
+
+
+
+/***********************************************
+Functions to concatinate various spatial objects
+************************************************/
+
+
+/*
+* Concatinate doubles into Point
+*/
+
+
+String *Item_func_point::val_str(String *str)
+{
+ if ( (null_value = (args[0]->null_value ||
+ args[1]->null_value ||
+ str->realloc(1+4+8+8))))
+ return 0;
+
+ str->length(0);
+ str->q_append((char)Geometry::wkbNDR);
+ str->q_append((uint32)Geometry::wkbPoint);
+ str->q_append((double)args[0]->val());
+ str->q_append((double)args[1]->val());
+ return str;
+}
+
+
+/*
+ Concatinates various items into various collections
+ with checkings for valid wkb type of items.
+ For example, MultiPoint can be a collection of Points only.
+ coll_type contains wkb type of target collection.
+ item_type contains a valid wkb type of items.
+ In the case when coll_type is wkbGeometryCollection,
+ we do not check wkb type of items, any is valid.
+*/
+
+String *Item_func_spatial_collection::val_str(String *str)
+{
+ uint i;
+
+ null_value=1;
+
+ str->length(0);
+ if(str->reserve(9,512))
+ return 0;
+
+ str->q_append((char)Geometry::wkbNDR);
+ str->q_append((uint32)coll_type);
+ str->q_append((uint32)arg_count);
+
+ for (i = 0; i < arg_count; ++i)
+ {
+ if (args[i]->null_value)
+ goto ret;
+
+ String *res = args[i]->val_str(str);
+
+ 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
+ */
+ if ((null_value=(str->reserve(res->length(),512))))
+ goto ret;
+
+ str->q_append(res->ptr(),res->length());
+ }
+ else
+ {
+ uint32 wkb_type, len=res->length();
+ 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
+ */
+
+ if (len<5)
+ goto ret;
+ wkb_type=uint4korr(data);
+ data+=4;
+ len-=5;
+ if ( wkb_type != item_type )
+ goto ret;
+
+ 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);
+ break;
+
+ case Geometry::wkbLineString:
+ if (str->reserve(POINT_DATA_SIZE,512))
+ goto ret;
+ str->q_append(data,POINT_DATA_SIZE);
+ break;
+
+ case Geometry::wkbPolygon:
+ {
+ uint32 n_points;
+ double x1, y1, x2, y2;
+
+ if (len < WKB_HEADER_SIZE + 4 + 8 + 8)
+ goto ret;
+ data+=WKB_HEADER_SIZE;
+ len-=WKB_HEADER_SIZE;
+
+ uint32 llen=len;
+ const char *ldata=data;
+
+ n_points=uint4korr(data);
+ data+=4;
+ float8get(x1,data);
+ data+=8;
+ float8get(y1,data);
+ data+=8;
+
+ len-= 4 + 8 + 8;
+
+ if (len < n_points * POINT_DATA_SIZE)
+ goto ret;
+ data+=(n_points-2) * POINT_DATA_SIZE;
+
+ float8get(x2,data);
+ float8get(y2,data+8);
+
+ if ((x1 != x2) || (y1 != y2))
+ goto ret;
+
+ if (str->reserve(llen,512))
+ goto ret;
+ str->q_append(ldata, llen);
+ }
+ break;
+
+ default:
+ goto ret;
+ }
+ }
+ }
+
+ if (str->length() > max_allowed_packet)
+ goto ret;
+
+ null_value = 0;
+
+ret:
+ return null_value ? 0 : str;
+}
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index 1279a5099d5..091289fd040 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -475,3 +475,219 @@ public:
const char *func_name() const { return "inet_ntoa"; }
void fix_length_and_dec() { decimals = 0; max_length=3*8+7; }
};
+
+class Item_func_conv_charset :public Item_str_func
+{
+ CHARSET_INFO *conv_charset;
+public:
+ Item_func_conv_charset(Item *a, CHARSET_INFO *cs) :Item_str_func(a)
+ {
+ conv_charset=cs;
+ }
+ String *val_str(String *);
+ void fix_length_and_dec();
+ const char *func_name() const { return "conv_charset"; }
+};
+
+class Item_func_conv_charset3 :public Item_str_func
+{
+public:
+ Item_func_conv_charset3(Item *arg1,Item *arg2,Item *arg3)
+ :Item_str_func(arg1,arg2,arg3) {}
+ String *val_str(String *);
+ void fix_length_and_dec();
+ const char *func_name() const { return "conv_charset3"; }
+};
+
+
+/*******************************************************
+Spatial functions
+********************************************************/
+
+class Item_func_geometry_from_text :public Item_str_func
+{
+public:
+ Item_func_geometry_from_text(Item *a) :Item_str_func(a) {}
+ const char *func_name() const { return "geometryfromtext"; }
+ String *val_str(String *);
+ void fix_length_and_dec();
+};
+
+class Item_func_as_text :public Item_str_func
+{
+public:
+ Item_func_as_text(Item *a) :Item_str_func(a) {}
+ const char *func_name() const { return "astext"; }
+ String *val_str(String *);
+ void fix_length_and_dec();
+};
+
+class Item_func_geometry_type :public Item_str_func
+{
+public:
+ Item_func_geometry_type(Item *a) :Item_str_func(a) {}
+ String *val_str(String *);
+ const char *func_name() const { return "geometrytype"; }
+ void fix_length_and_dec()
+ {
+ max_length=20; // "GeometryCollection" is the most long
+ };
+};
+
+class Item_func_centroid :public Item_str_func
+{
+public:
+ Item_func_centroid(Item *a) :Item_str_func(a) {}
+ const char *func_name() const { return "centroid"; }
+ String *val_str(String *);
+ void fix_length_and_dec(){max_length=MAX_BLOB_WIDTH;}
+};
+
+class Item_func_envelope :public Item_str_func
+{
+public:
+ Item_func_envelope(Item *a) :Item_str_func(a) {}
+ const char *func_name() const { return "envelope"; }
+ String *val_str(String *);
+ void fix_length_and_dec(){max_length=MAX_BLOB_WIDTH;}
+};
+
+class Item_func_point :public Item_str_func
+{
+public:
+ Item_func_point(Item *a,Item *b) :Item_str_func(a,b) {}
+ const char *func_name() const { return "point"; }
+ String *val_str(String *);
+ void fix_length_and_dec(){max_length=MAX_BLOB_WIDTH;}
+};
+
+class Item_func_spatial_decomp :public Item_str_func
+{
+ enum Functype decomp_func;
+public:
+ Item_func_spatial_decomp(Item *a, Item_func::Functype ft) :
+ Item_str_func(a) { decomp_func = ft; }
+ const char *func_name() const
+ {
+ switch (decomp_func)
+ {
+ case SP_STARTPOINT:
+ return "startpoint";
+ case SP_ENDPOINT:
+ return "endpoint";
+ case SP_EXTERIORRING:
+ return "exteriorring";
+ default:
+ return "spatial_decomp_unknown";
+ }
+ }
+ String *val_str(String *);
+ void fix_length_and_dec(){max_length=MAX_BLOB_WIDTH;}
+};
+
+class Item_func_spatial_decomp_n :public Item_str_func
+{
+ enum Functype decomp_func_n;
+public:
+ Item_func_spatial_decomp_n(Item *a, Item *b, Item_func::Functype ft) :
+ Item_str_func(a, b) { decomp_func_n = ft; }
+ const char *func_name() const
+ {
+ switch (decomp_func_n)
+ {
+ case SP_POINTN:
+ return "pointn";
+ case SP_GEOMETRYN:
+ return "geometryn";
+ case SP_INTERIORRINGN:
+ return "interiorringn";
+ default:
+ return "spatial_decomp_n_unknown";
+ }
+ }
+ String *val_str(String *);
+ void fix_length_and_dec(){max_length=MAX_BLOB_WIDTH;}
+};
+
+
+class Item_func_spatial_collection :public Item_str_func
+{
+ String tmp_value;
+ enum Geometry::wkbType coll_type;
+ enum Geometry::wkbType item_type;
+public:
+ Item_func_spatial_collection(
+ List<Item> &list, enum Geometry::wkbType ct, enum Geometry::wkbType it) :
+ Item_str_func(list)
+ {
+ coll_type=ct;
+ item_type=it;
+ }
+ String *val_str(String *);
+ void fix_length_and_dec(){max_length=MAX_BLOB_WIDTH;}
+ const char *func_name() const { return "multipoint"; }
+};
+
+
+/*
+class Item_func_multipoint :public Item_str_func
+{
+ String tmp_value;
+public:
+ Item_func_multipoint(List<Item> &list) :Item_str_func(list) {}
+ String *val_str(String *);
+ void fix_length_and_dec(){max_length=MAX_BLOB_WIDTH;}
+ const char *func_name() const { return "multipoint"; }
+};
+
+class Item_func_linestring :public Item_str_func
+{
+ String tmp_value;
+public:
+ Item_func_linestring(List<Item> &list) :Item_str_func(list) {}
+ String *val_str(String *);
+ void fix_length_and_dec(){max_length=MAX_BLOB_WIDTH;}
+ const char *func_name() const { return "linestring"; }
+};
+
+class Item_func_multilinestring :public Item_str_func
+{
+ String tmp_value;
+public:
+ Item_func_multilinestring(List<Item> &list) :Item_str_func(list) {}
+ String *val_str(String *);
+ void fix_length_and_dec(){max_length=MAX_BLOB_WIDTH;}
+ const char *func_name() const { return "multilinestring"; }
+};
+
+class Item_func_polygon :public Item_str_func
+{
+ String tmp_value;
+public:
+ Item_func_polygon(List<Item> &list) :Item_str_func(list) {}
+ String *val_str(String *);
+ void fix_length_and_dec(){max_length=MAX_BLOB_WIDTH;}
+ const char *func_name() const { return "polygon"; }
+};
+
+class Item_func_multipolygon :public Item_str_func
+{
+ String tmp_value;
+public:
+ Item_func_multipolygon(List<Item> &list) :Item_str_func(list) {}
+ String *val_str(String *);
+ void fix_length_and_dec(){max_length=MAX_BLOB_WIDTH;}
+ const char *func_name() const { return "multipolygon"; }
+};
+
+class Item_func_geometrycollection :public Item_str_func
+{
+ String tmp_value;
+public:
+ Item_func_geometrycollection(List<Item> &list) :Item_str_func(list) {}
+ String *val_str(String *);
+ void fix_length_and_dec(){max_length=MAX_BLOB_WIDTH;}
+ const char *func_name() const { return "geometrycollection"; }
+};
+
+*/
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index e8f16e3ed56..7ebeda19993 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -864,7 +864,8 @@ static int simple_raw_key_cmp(void* arg, byte* key1, byte* key2)
static int simple_str_key_cmp(void* arg, byte* key1, byte* key2)
{
- return my_sortcmp((char*) key1, (char*) key2, *(uint*) arg);
+ /* BAR TODO: remove default_charset_info */
+ return my_sortcmp(default_charset_info,(char*) key1, (char*) key2, *(uint*) arg);
}
/*
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index 9a003b79609..404d44d7122 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -49,16 +49,16 @@ bool get_interval_info(const char *str,uint length,uint count,
{
const char *end=str+length;
uint i;
- while (str != end && !isdigit(*str))
+ while (str != end && !my_isdigit(system_charset_info,*str))
str++;
for (i=0 ; i < count ; i++)
{
long value;
- for (value=0; str != end && isdigit(*str) ; str++)
+ for (value=0; str != end && my_isdigit(system_charset_info,*str) ; str++)
value=value*10L + (long) (*str - '0');
values[i]= value;
- while (str != end && !isdigit(*str))
+ while (str != end && !my_isdigit(system_charset_info,*str))
str++;
if (str == end && i != count-1)
{
@@ -289,7 +289,7 @@ static bool get_interval_value(Item *args,interval_type int_type,
/* record negative intervalls in t->neg */
str=res->ptr();
const char *end=str+res->length();
- while (str != end && isspace(*str))
+ while (str != end && my_isspace(system_charset_info,*str))
str++;
if (str != end && *str == '-')
{
diff --git a/sql/key.cc b/sql/key.cc
index d2f483e3d73..a5d3d0a65b9 100644
--- a/sql/key.cc
+++ b/sql/key.cc
@@ -192,8 +192,9 @@ int key_cmp(TABLE *table,const byte *key,uint idx,uint key_length)
if (!(key_part->key_type & (FIELDFLAG_NUMBER+FIELDFLAG_BINARY+
FIELDFLAG_PACK)))
{
- if (my_sortcmp((char*) key,(char*) table->record[0]+key_part->offset,
- length))
+ /* BAR TODO: I'm not sure this should be system_charset_info */
+ if (my_sortcmp(system_charset_info,(char*) key,
+ (char*) table->record[0]+key_part->offset,length))
return 1;
}
else if (memcmp(key,table->record[0]+key_part->offset,length))
diff --git a/sql/lex.h b/sql/lex.h
index 8c7beb64b9b..ea712523993 100644
--- a/sql/lex.h
+++ b/sql/lex.h
@@ -75,6 +75,7 @@ static SYMBOL symbols[] = {
{ "BOOL", SYM(BOOL_SYM),0,0},
{ "BOOLEAN", SYM(BOOLEAN_SYM),0,0},
{ "BOTH", SYM(BOTH),0,0},
+ { "BTREE", SYM(BTREE_SYM),0,0},
{ "BY", SYM(BY),0,0},
{ "CACHE", SYM(CACHE_SYM),0,0},
{ "CASCADE", SYM(CASCADE),0,0},
@@ -158,12 +159,14 @@ static SYMBOL symbols[] = {
{ "FULL", SYM(FULL),0,0},
{ "FULLTEXT", SYM(FULLTEXT_SYM),0,0},
{ "FUNCTION", SYM(UDF_SYM),0,0},
+ { "GEOMETRY", SYM(GEOMETRY_SYM),0,0},
{ "GLOBAL", SYM(GLOBAL_SYM),0,0},
{ "GRANT", SYM(GRANT),0,0},
{ "GRANTS", SYM(GRANTS),0,0},
{ "GROUP", SYM(GROUP),0,0},
{ "HAVING", SYM(HAVING),0,0},
{ "HANDLER", SYM(HANDLER_SYM),0,0},
+ { "HASH", SYM(HASH_SYM),0,0},
{ "HEAP", SYM(HEAP_SYM),0,0},
{ "HIGH_PRIORITY", SYM(HIGH_PRIORITY),0,0},
{ "HOUR", SYM(HOUR_SYM),0,0},
@@ -299,6 +302,7 @@ static SYMBOL symbols[] = {
{ "ROLLBACK", SYM(ROLLBACK_SYM),0,0},
{ "ROW", SYM(ROW_SYM),0,0},
{ "ROWS", SYM(ROWS_SYM),0,0},
+ { "RTREE", SYM(RTREE_SYM),0,0},
{ "SECOND", SYM(SECOND_SYM),0,0},
{ "SELECT", SYM(SELECT_SYM),0,0},
{ "SERIALIZABLE", SYM(SERIALIZABLE_SYM),0,0},
@@ -311,6 +315,7 @@ static SYMBOL symbols[] = {
{ "SLAVE", SYM(SLAVE),0,0},
{ "SMALLINT", SYM(SMALLINT),0,0},
{ "SONAME", SYM(UDF_SONAME_SYM),0,0},
+ { "SPATIAL", SYM(SPATIAL_SYM),0,0},
{ "SQL_AUTO_IS_NULL", SYM(SQL_AUTO_IS_NULL),0,0},
{ "SQL_BIG_RESULT", SYM(SQL_BIG_RESULT),0,0},
{ "SQL_BIG_SELECTS", SYM(SQL_BIG_SELECTS),0,0},
@@ -389,8 +394,10 @@ static SYMBOL sql_functions[] = {
{ "ABS", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_abs)},
{ "ACOS", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_acos)},
{ "ADDDATE", SYM(DATE_ADD_INTERVAL),0,0},
+ { "AREA", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_area)},
{ "ASCII", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_ascii)},
{ "ASIN", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_asin)},
+ { "ASTEXT", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_as_text)},
{ "ATAN", SYM(ATAN),0,0},
{ "ATAN2", SYM(ATAN),0,0},
{ "BENCHMARK", SYM(BENCHMARK_SYM),0,0},
@@ -401,17 +408,20 @@ static SYMBOL sql_functions[] = {
{ "CAST", SYM(CAST_SYM),0,0},
{ "CEILING", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_ceiling)},
{ "BIT_LENGTH", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_bit_length)},
+ { "CENTROID", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_centroid)},
{ "CHAR_LENGTH", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_char_length)},
{ "CHARACTER_LENGTH", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_char_length)},
{ "COALESCE", SYM(COALESCE),0,0},
{ "CONCAT", SYM(CONCAT),0,0},
{ "CONCAT_WS", SYM(CONCAT_WS),0,0},
{ "CONNECTION_ID", SYM(FUNC_ARG0),0,CREATE_FUNC(create_func_connection_id)},
+ { "CONTAINS", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_contains)},
{ "CONV", SYM(FUNC_ARG3),0,CREATE_FUNC(create_func_conv)},
{ "CONVERT", SYM(CONVERT_SYM),0,0},
{ "COUNT", SYM(COUNT_SYM),0,0},
{ "COS", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_cos)},
{ "COT", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_cot)},
+ { "CROSSES", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_crosses)},
{ "CURDATE", SYM(CURDATE),0,0},
{ "CURTIME", SYM(CURTIME),0,0},
{ "DATE_ADD", SYM(DATE_ADD_INTERVAL),0,0},
@@ -425,9 +435,15 @@ static SYMBOL sql_functions[] = {
{ "DEGREES", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_degrees)},
{ "DES_ENCRYPT", SYM(DES_ENCRYPT_SYM),0,0},
{ "DES_DECRYPT", SYM(DES_DECRYPT_SYM),0,0},
+ { "DIMENSION", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_dimension)},
+ { "DISJOINT", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_disjoint)},
{ "ELT", SYM(ELT_FUNC),0,0},
{ "ENCODE", SYM(ENCODE_SYM),0,0},
{ "ENCRYPT", SYM(ENCRYPT),0,0},
+ { "ENDPOINT", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_endpoint)},
+ { "ENVELOPE", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_envelope)},
+ { "EQUALS", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_equals)},
+ { "EXTERIORRING", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_exteriorring)},
{ "EXTRACT", SYM(EXTRACT_SYM),0,0},
{ "EXP", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_exp)},
{ "EXPORT_SET", SYM(EXPORT_SET),0,0},
@@ -439,6 +455,12 @@ static SYMBOL sql_functions[] = {
{ "FROM_DAYS", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_from_days)},
{ "FROM_UNIXTIME", SYM(FROM_UNIXTIME),0,0},
{ "GET_LOCK", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_get_lock)},
+ { "GEOMETRYCOLLECTION",SYM(GEOMETRYCOLLECTION),0,0},
+ { "GEOMETRYN", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_geometryn)},
+ { "GEOMETRYTYPE", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_geometry_type)},
+ { "GEOMCOLLFROMTEXT", SYM(GEOMCOLLFROMTEXT),0,0},
+ { "GEOMFROMTEXT", SYM(GEOMFROMTEXT),0,0},
+ { "GLENGTH", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_glength)},
{ "GREATEST", SYM(GREATEST_SYM),0,0},
{ "GROUP_UNIQUE_USERS", SYM(GROUP_UNIQUE_USERS),0,0},
{ "HEX", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_hex)},
@@ -446,10 +468,17 @@ static SYMBOL sql_functions[] = {
{ "INET_ATON", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_inet_aton)},
{ "INET_NTOA", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_inet_ntoa)},
{ "INSTR", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_instr)},
+ { "INTERIORRINGN", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_interiorringn)},
+ { "INTERSECTS", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_intersects)},
+ { "ISCLOSED", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_isclosed)},
+ { "ISEMPTY", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_isempty)},
{ "ISNULL", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_isnull)},
+ { "ISSIMPLE", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_issimple)},
{ "LCASE", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_lcase)},
{ "LEAST", SYM(LEAST_SYM),0,0},
{ "LENGTH", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_length)},
+ { "LINEFROMTEXT", SYM(LINEFROMTEXT),0,0},
+ { "LINESTRING", SYM(LINESTRING),0,0},
{ "LOAD_FILE", SYM(FUNC_ARG1),0,CREATE_FUNC(create_load_file)},
{ "LOCATE", SYM(LOCATE),0,0},
{ "LOG", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_log)},
@@ -465,15 +494,30 @@ static SYMBOL sql_functions[] = {
{ "MID", SYM(SUBSTRING),0,0}, /* unireg function */
{ "MIN", SYM(MIN_SYM),0,0},
{ "MOD", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_mod)},
+ { "MLINEFROMTEXT", SYM(MLINEFROMTEXT),0,0},
+ { "MPOINTFROMTEXT", SYM(MPOINTFROMTEXT),0,0},
+ { "MPOLYFROMTEXT", SYM(MPOLYFROMTEXT),0,0},
+ { "MULTILINESTRING", SYM(MULTILINESTRING),0,0},
+ { "MULTIPOINT", SYM(MULTIPOINT),0,0},
+ { "MULTIPOLYGON", SYM(MULTIPOLYGON),0,0},
{ "MONTHNAME", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_monthname)},
{ "NOW", SYM(NOW_SYM),0,0},
{ "NULLIF", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_nullif)},
+ { "NUMGEOMETRIES", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_numgeometries)},
+ { "NUMINTERIORRING", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_numinteriorring)},
+ { "NUMPOINTS", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_numpoints)},
{ "OCTET_LENGTH", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_length)},
{ "OCT", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_oct)},
{ "ORD", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_ord)},
+ { "OVERLAPS", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_overlaps)},
{ "PERIOD_ADD", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_period_add)},
{ "PERIOD_DIFF", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_period_diff)},
{ "PI", SYM(FUNC_ARG0),0,CREATE_FUNC(create_func_pi)},
+ { "POINT", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_point)},
+ { "POINTFROMTEXT", SYM(POINTFROMTEXT),0,0},
+ { "POINTN", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_pointn)},
+ { "POLYFROMTEXT", SYM(POLYFROMTEXT),0,0},
+ { "POLYGON", SYM(POLYGON),0,0},
{ "POSITION", SYM(POSITION_SYM),0,0},
{ "POW", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_pow)},
{ "POWER", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_pow)},
@@ -494,6 +538,7 @@ static SYMBOL sql_functions[] = {
{ "SOUNDEX", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_soundex)},
{ "SPACE", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_space)},
{ "SQRT", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_sqrt)},
+ { "STARTPOINT", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_startpoint)},
{ "STD", SYM(STD_SYM),0,0},
{ "STDDEV", SYM(STD_SYM),0,0},
{ "STRCMP", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_strcmp)},
@@ -506,6 +551,7 @@ static SYMBOL sql_functions[] = {
{ "TIME_FORMAT", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_time_format)},
{ "TIME_TO_SEC", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_time_to_sec)},
{ "TO_DAYS", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_to_days)},
+ { "TOUCHES", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_touches)},
{ "TRIM", SYM(TRIM),0,0},
{ "UCASE", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_ucase)},
{ "UNIQUE_USERS", SYM(UNIQUE_USERS),0,0},
@@ -515,5 +561,9 @@ static SYMBOL sql_functions[] = {
{ "VERSION", SYM(FUNC_ARG0),0,CREATE_FUNC(create_func_version)},
{ "WEEK", SYM(WEEK_SYM),0,0},
{ "WEEKDAY", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_weekday)},
+ { "WITHIN", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_within)},
+ { "X", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_x)},
+ { "Y", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_y)},
{ "YEARWEEK", SYM(YEARWEEK),0,0}
+
};
diff --git a/sql/log.cc b/sql/log.cc
index 40cafeeaad1..39a8ff3f81f 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -1227,7 +1227,7 @@ static bool test_if_number(register const char *str,
while (*str++ == ' ') ;
if (*--str == '-' || *str == '+')
str++;
- while (isdigit(*str) || (allow_wildcards &&
+ while (my_isdigit(system_charset_info,*str) || (allow_wildcards &&
(*str == wild_many || *str == wild_one)))
{
flag=1;
@@ -1236,7 +1236,7 @@ static bool test_if_number(register const char *str,
if (*str == '.')
{
for (str++ ;
- isdigit(*str) ||
+ my_isdigit(system_charset_info,*str) ||
(allow_wildcards && (*str == wild_many || *str == wild_one)) ;
str++, flag=1) ;
}
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 12249d2292c..4c71e845207 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -361,6 +361,7 @@ int mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &list,COND *conds,
ORDER *order, ORDER *group,Item *having,ORDER *proc_param,
ulong select_type,select_result *result);
int mysql_union(THD *thd,LEX *lex,select_result *result);
+int mysql_derived(THD *thd,LEX *lex,SELECT_LEX *s, TABLE_LIST *t);
Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
Item_result_field ***copy_func, Field **from_field,
bool group,bool modify_item);
@@ -575,7 +576,7 @@ void open_log(MYSQL_LOG *log, const char *hostname,
extern uint32 server_id;
extern char *mysql_data_home,server_version[SERVER_VERSION_LENGTH],
- max_sort_char, mysql_real_data_home[];
+ mysql_real_data_home[];
extern my_string mysql_tmpdir;
extern const char *first_keyword, *localhost, *delayed_user;
extern ulong refresh_version,flush_version, thread_id,query_id,opened_tables,
@@ -734,10 +735,10 @@ bool check_db_name(const char *db);
bool check_column_name(const char *name);
bool check_table_name(const char *name, uint length);
char *get_field(MEM_ROOT *mem,TABLE *table,uint fieldnr);
-int wild_case_compare(const char *str,const char *wildstr);
+int wild_case_compare(CHARSET_INFO *cs, const char *str,const char *wildstr);
int wild_compare(const char *str,const char *str_end,
const char *wildstr,const char *wildend,char escape);
-int wild_case_compare(const char *str,const char *str_end,
+int wild_case_compare(CHARSET_INFO *cs, const char *str,const char *str_end,
const char *wildstr,const char *wildend,char escape);
/* from hostname.cc */
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 99f0a463a42..19ff66b24fc 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -898,7 +898,7 @@ static void set_user(const char *user)
{
// allow a numeric uid to be used
const char *pos;
- for (pos=user; isdigit(*pos); pos++) ;
+ for (pos=user; my_isdigit(system_charset_info,*pos); pos++) ;
if (*pos) // Not numeric id
{
fprintf(stderr,"Fatal error: Can't change to run as user '%s' ; Please check that the user exists!\n",user);
@@ -3847,7 +3847,7 @@ static void get_options(int argc,char **argv)
exit(1);
}
val = p--;
- while(isspace(*p) && p > optarg) *p-- = 0;
+ while(my_isspace(system_charset_info,*p) && p > optarg) *p-- = 0;
if(p == optarg)
{
fprintf(stderr,
@@ -3856,7 +3856,7 @@ static void get_options(int argc,char **argv)
}
*val = 0;
val += 2;
- while(*val && isspace(*val)) *val++;
+ while(*val && my_isspace(system_charset_info,*val)) *val++;
if (!*val)
{
fprintf(stderr,
@@ -4017,7 +4017,7 @@ static void get_options(int argc,char **argv)
have_symlink=SHOW_OPTION_DISABLED;
break;
case (int) OPT_BIND_ADDRESS:
- if (optarg && isdigit(optarg[0]))
+ if (optarg && my_isdigit(system_charset_info,optarg[0]))
{
my_bind_addr = (ulong) inet_addr(optarg);
}
@@ -4524,7 +4524,8 @@ static ulong find_bit_type(const char *x, TYPELIB *bit_lib)
j=pos;
while (j != end)
{
- if (toupper(*i++) != toupper(*j++))
+ if (my_toupper(system_charset_info,*i++) !=
+ my_toupper(system_charset_info,*j++))
goto skipp;
}
found_int=bit;
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 7d2d04dbdf1..9f547c6e0ca 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -172,8 +172,9 @@ public:
void store(uint length,char **min_key,uint min_key_flag,
char **max_key, uint max_key_flag)
{
- if (!(min_flag & NO_MIN_RANGE) &&
- !(min_key_flag & (NO_MIN_RANGE | NEAR_MIN)))
+ if ((min_flag & GEOM_FLAG) ||
+ (!(min_flag & NO_MIN_RANGE) &&
+ !(min_key_flag & (NO_MIN_RANGE | NEAR_MIN))))
{
if (maybe_null && *min_value)
{
@@ -659,6 +660,8 @@ int SQL_SELECT::test_quick_select(key_map keys_to_use, table_map prev_tables,
key_parts->null_bit= key_info->key_part[part].null_bit;
if (key_parts->field->type() == FIELD_TYPE_BLOB)
key_parts->part_length+=HA_KEY_BLOB_LENGTH;
+ key_parts->image_type =
+ (key_info->flags & HA_SPATIAL) ? Field::itMBR : Field::itRAW;
}
param.real_keynr[param.keys++]=idx;
}
@@ -676,6 +679,7 @@ int SQL_SELECT::test_quick_select(key_map keys_to_use, table_map prev_tables,
{
SEL_ARG **key,**end,**best_key=0;
+
for (idx=0,key=tree->keys, end=key+param.keys ;
key != end ;
key++,idx++)
@@ -970,9 +974,10 @@ get_mm_leaf(PARAM *param, Field *field, KEY_PART *key_part,
&min_length,&max_length);
else
{
+ CHARSET_INFO *charset=((Field_str*)(field))->charset();
#ifdef USE_STRCOLL
- if (use_strcoll(default_charset_info))
- like_error= my_like_range(default_charset_info,
+ if (use_strcoll(charset))
+ like_error= my_like_range(charset,
res->ptr(),res->length(),wild_prefix,
field_length, min_str+maybe_null,
max_str+maybe_null,&min_length,&max_length);
@@ -981,7 +986,8 @@ get_mm_leaf(PARAM *param, Field *field, KEY_PART *key_part,
like_error=like_range(res->ptr(),res->length(),wild_prefix,
field_length,
min_str+offset,max_str+offset,
- max_sort_char,&min_length,&max_length);
+ charset->max_sort_char,
+ &min_length,&max_length);
}
if (like_error) // Can't optimize with LIKE
DBUG_RETURN(0);
@@ -1043,7 +1049,7 @@ get_mm_leaf(PARAM *param, Field *field, KEY_PART *key_part,
DBUG_RETURN(0);
if (maybe_null)
*str=0; // Not NULL
- field->get_key_image(str+maybe_null,key_part->part_length);
+ field->get_key_image(str+maybe_null,key_part->part_length, key_part->image_type);
if (!(tree=new SEL_ARG(field,str,str)))
DBUG_RETURN(0);
@@ -1068,6 +1074,41 @@ get_mm_leaf(PARAM *param, Field *field, KEY_PART *key_part,
case Item_func::GE_FUNC:
tree->max_flag=NO_MAX_RANGE;
break;
+ case Item_func::SP_EQUALS_FUNC:
+ tree->min_flag=GEOM_FLAG | HA_READ_MBR_EQUAL;// NEAR_MIN;//512;
+ tree->max_flag=NO_MAX_RANGE;
+ break;
+ case Item_func::SP_DISJOINT_FUNC:
+ tree->min_flag=GEOM_FLAG | HA_READ_MBR_DISJOINT;// NEAR_MIN;//512;
+ tree->max_flag=NO_MAX_RANGE;
+ break;
+ case Item_func::SP_INTERSECTS_FUNC:
+ tree->min_flag=GEOM_FLAG | HA_READ_MBR_INTERSECT;// NEAR_MIN;//512;
+ tree->max_flag=NO_MAX_RANGE;
+ break;
+ case Item_func::SP_TOUCHES_FUNC:
+ tree->min_flag=GEOM_FLAG | HA_READ_MBR_INTERSECT;// NEAR_MIN;//512;
+ tree->max_flag=NO_MAX_RANGE;
+ break;
+
+ case Item_func::SP_CROSSES_FUNC:
+ tree->min_flag=GEOM_FLAG | HA_READ_MBR_INTERSECT;// NEAR_MIN;//512;
+ tree->max_flag=NO_MAX_RANGE;
+ break;
+ case Item_func::SP_WITHIN_FUNC:
+ tree->min_flag=GEOM_FLAG | HA_READ_MBR_WITHIN;// NEAR_MIN;//512;
+ tree->max_flag=NO_MAX_RANGE;
+ break;
+
+ case Item_func::SP_CONTAINS_FUNC:
+ tree->min_flag=GEOM_FLAG | HA_READ_MBR_CONTAIN;// NEAR_MIN;//512;
+ tree->max_flag=NO_MAX_RANGE;
+ break;
+ case Item_func::SP_OVERLAPS_FUNC:
+ tree->min_flag=GEOM_FLAG | HA_READ_MBR_INTERSECT;// NEAR_MIN;//512;
+ tree->max_flag=NO_MAX_RANGE;
+ break;
+
default:
break;
}
@@ -2188,18 +2229,30 @@ check_quick_keys(PARAM *param,uint idx,SEL_ARG *key_tree,
!memcmp(param->min_key,param->max_key,min_key_length))
tmp=1; // Max one record
else
+ {
+ if(tmp_min_flag & GEOM_FLAG)
+ {
+ tmp=param->table->file->
+ records_in_range((int) keynr,(byte*)(param->min_key + 1),
+ min_key_length, (ha_rkey_function)(tmp_min_flag ^ GEOM_FLAG),
+ (byte *)NullS,0,HA_READ_KEY_EXACT);
+ }
+ else
+ {
tmp=param->table->file->
records_in_range((int) keynr,
(byte*) (!min_key_length ? NullS :
param->min_key),
min_key_length,
- (tmp_min_flag & NEAR_MIN ?
- HA_READ_AFTER_KEY : HA_READ_KEY_EXACT),
+ tmp_min_flag & NEAR_MIN ?
+ HA_READ_AFTER_KEY : HA_READ_KEY_EXACT,
(byte*) (!max_key_length ? NullS :
param->max_key),
max_key_length,
(tmp_max_flag & NEAR_MAX ?
HA_READ_BEFORE_KEY : HA_READ_AFTER_KEY));
+ }
+ }
end:
if (tmp == HA_POS_ERROR) // Impossible range
return tmp;
@@ -2295,19 +2348,24 @@ get_quick_keys(PARAM *param,QUICK_SELECT *quick,KEY_PART *key,
}
}
else
- flag=key_tree->min_flag | key_tree->max_flag;
+ {
+ flag = (key_tree->min_flag & GEOM_FLAG) ?
+ key_tree->min_flag : key_tree->min_flag | key_tree->max_flag;
+ }
/* Ensure that some part of min_key and max_key are used. If not,
regard this as no lower/upper range */
- if (tmp_min_key != param->min_key)
- flag&= ~NO_MIN_RANGE;
- else
- flag|= NO_MIN_RANGE;
- if (tmp_max_key != param->max_key)
- flag&= ~NO_MAX_RANGE;
- else
- flag|= NO_MAX_RANGE;
-
+ if((flag & GEOM_FLAG) == 0)
+ {
+ if (tmp_min_key != param->min_key)
+ flag&= ~NO_MIN_RANGE;
+ else
+ flag|= NO_MIN_RANGE;
+ if (tmp_max_key != param->max_key)
+ flag&= ~NO_MAX_RANGE;
+ else
+ flag|= NO_MAX_RANGE;
+ }
if (flag == 0)
{
uint length= (uint) (tmp_min_key - param->min_key);
@@ -2440,13 +2498,19 @@ int QUICK_SELECT::get_next()
int result;
if (range)
{ // Already read through key
- result=((range->flag & EQ_RANGE) ?
+/* result=((range->flag & EQ_RANGE) ?
file->index_next_same(record, (byte*) range->min_key,
range->min_length) :
file->index_next(record));
+*/
+ result=((range->flag & (EQ_RANGE | GEOM_FLAG) ) ?
+ file->index_next_same(record, (byte*) range->min_key,
+ range->min_length) :
+ file->index_next(record));
+
if (!result)
{
- if (!cmp_next(*it.ref()))
+ if ((range->flag & GEOM_FLAG) || !cmp_next(*it.ref()))
DBUG_RETURN(0);
}
else if (result != HA_ERR_END_OF_FILE)
@@ -2455,6 +2519,23 @@ int QUICK_SELECT::get_next()
if (!(range=it++))
DBUG_RETURN(HA_ERR_END_OF_FILE); // All ranges used
+
+ if(range->flag & GEOM_FLAG)
+ {
+ if ((result = file->index_read(record,
+ (byte*) (range->min_key + ((range->flag & GEOM_FLAG) > 0)),
+ range->min_length,
+ (ha_rkey_function)(range->flag ^ GEOM_FLAG))))
+
+ {
+ if (result != HA_ERR_KEY_NOT_FOUND)
+ DBUG_RETURN(result);
+ range=0; // Not found, to next range
+ continue;
+ }
+ DBUG_RETURN(0);
+ }
+
if (range->flag & NO_MIN_RANGE) // Read first record
{
int error;
@@ -2465,13 +2546,14 @@ int QUICK_SELECT::get_next()
range=0; // No matching records; go to next range
continue;
}
- if ((result = file->index_read(record,(byte*) range->min_key,
+ if ((result = file->index_read(record,
+ (byte*) (range->min_key + ((range->flag & GEOM_FLAG) > 0)),
range->min_length,
- ((range->flag & NEAR_MIN) ?
+ (range->flag & NEAR_MIN) ?
HA_READ_AFTER_KEY:
(range->flag & EQ_RANGE) ?
HA_READ_KEY_EXACT :
- HA_READ_KEY_OR_NEXT))))
+ HA_READ_KEY_OR_NEXT)))
{
if (result != HA_ERR_KEY_NOT_FOUND)
diff --git a/sql/opt_range.h b/sql/opt_range.h
index f48a3936a17..e9694b4820f 100644
--- a/sql/opt_range.h
+++ b/sql/opt_range.h
@@ -31,11 +31,14 @@
#define UNIQUE_RANGE 16
#define EQ_RANGE 32
#define NULL_RANGE 64
+#define GEOM_FLAG 128
+
typedef struct st_key_part {
- uint16 key,part,part_length;
- uint8 null_bit;
- Field *field;
+ uint16 key,part,part_length;
+ uint8 null_bit;
+ Field *field;
+ Field::imagetype image_type;
} KEY_PART;
class QUICK_RANGE :public Sql_alloc {
diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc
index efb4c4916a5..f399390da4b 100644
--- a/sql/opt_sum.cc
+++ b/sql/opt_sum.cc
@@ -351,7 +351,7 @@ static bool find_range_key(TABLE_REF *ref, Field* field, COND *cond)
// Save found constant
if (part->null_bit)
*key_ptr++= (byte) test(part->field->is_null());
- part->field->get_key_image((char*) key_ptr,part->length);
+ part->field->get_key_image((char*) key_ptr,part->length, Field::itRAW);
key_ptr+=part->store_length - test(part->null_bit);
left_length-=part->store_length;
}
diff --git a/sql/procedure.cc b/sql/procedure.cc
index 437bd82d6e5..7779f5ce085 100644
--- a/sql/procedure.cc
+++ b/sql/procedure.cc
@@ -57,7 +57,8 @@ setup_procedure(THD *thd,ORDER *param,select_result *result,
DBUG_RETURN(0);
for (i=0 ; i < array_elements(sql_procs) ; i++)
{
- if (!my_strcasecmp((*param->item)->name,sql_procs[i].name))
+ if (!my_strcasecmp(system_charset_info,
+ (*param->item)->name,sql_procs[i].name))
{
Procedure *proc=(*sql_procs[i].init)(thd,param,result,field_list);
*error= !proc;
diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc
index 257418d1682..3f16880c18e 100644
--- a/sql/repl_failsafe.cc
+++ b/sql/repl_failsafe.cc
@@ -184,7 +184,7 @@ static void slave_info_free(void *s)
void init_slave_list()
{
- hash_init(&slave_list, SLAVE_LIST_CHUNK, 0, 0,
+ hash_init(&slave_list, system_charset_info, SLAVE_LIST_CHUNK, 0, 0,
(hash_get_key) slave_list_key, slave_info_free, 0);
pthread_mutex_init(&LOCK_slave_list, MY_MUTEX_INIT_FAST);
}
diff --git a/sql/share/charsets/Index b/sql/share/charsets/Index
index 5cf30682cc0..565b98a1c60 100644
--- a/sql/share/charsets/Index
+++ b/sql/share/charsets/Index
@@ -36,3 +36,5 @@ gbk 28
cp1257 29
latin5 30
latin1_de 31
+armscii8 32
+utf8 33
diff --git a/sql/share/charsets/armscii8.conf b/sql/share/charsets/armscii8.conf
new file mode 100644
index 00000000000..15c232c7e94
--- /dev/null
+++ b/sql/share/charsets/armscii8.conf
@@ -0,0 +1,74 @@
+# Configuration file for the armscii8 (armenian) character set
+
+# ctype array (must have 257 elements)
+ 00
+ 20 20 20 20 20 20 20 20 20 28 28 28 28 28 20 20
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 84 84 84 84 84 84 84 84 84 84 10 10 10 10 10 10
+ 10 81 81 81 81 81 81 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 01 01 01 01 10 10 10 10 10
+ 10 82 82 82 82 82 82 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 10 10 10 10 20
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 10 10 01 02 01 02 01 02 01 02 01 02 01 02 01 02
+ 01 02 01 02 01 02 01 02 01 02 01 02 01 02 01 02
+ 01 02 01 02 01 02 01 02 01 02 01 02 01 02 01 02
+ 01 02 01 02 01 02 01 02 01 02 01 02 01 02 01 02
+ 01 02 01 02 01 02 01 02 01 02 01 02 01 02 10 10
+
+# to_lower array (must have 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 5B 5C 5D 5E 5F
+ 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 B8 A9 AA AB AC AD AE AF
+ B0 B1 B3 B3 B5 B5 B7 B7 B9 B9 BB BB BD BD BF BF
+ C1 C1 C3 C3 C5 C5 C7 C7 C9 C9 CB CB CD CD CF CF
+ D1 D1 D3 D3 D5 D5 D7 D7 D9 D9 DB DB DD DD DF DF
+ E1 E1 E3 E3 E5 E5 E7 E7 E9 E9 EB EB ED ED EF EF
+ F1 F1 F3 F3 F5 F5 F7 F7 F9 F9 FB FB FD FD FE FF
+
+# to_upper array (must have 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B2 B4 B4 B6 B6 B8 B8 BA BA BC BC BE BE
+ C0 C0 C2 C2 C4 C4 C6 C6 C8 C8 CA CA CC CC CE CE
+ D0 D0 D2 D2 D4 D4 D6 D6 D8 D8 DA DA DC DC DE DE
+ E0 E0 E2 E2 E4 E4 E6 E6 E8 E8 EA EA EC EC EE EE
+ F0 F0 F2 F2 F4 F4 F6 F6 F8 F8 FA FA FC FC FE FF
+
+# sort_order array (must have 256 elements)
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
diff --git a/sql/slave.cc b/sql/slave.cc
index 25b29732000..8461b72f4c6 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -245,9 +245,9 @@ void init_slave_skip_errors(char* arg)
exit(1);
}
use_slave_mask = 1;
- for (;isspace(*arg);++arg)
+ for (;my_isspace(system_charset_info,*arg);++arg)
/* empty */;
- if (!my_casecmp(arg,"all",3))
+ if (!my_strncasecmp(system_charset_info,arg,"all",3))
{
bitmap_set_all(&slave_error_mask);
return;
@@ -259,7 +259,7 @@ void init_slave_skip_errors(char* arg)
break;
if (err_code < MAX_SLAVE_ERROR)
bitmap_set_bit(&slave_error_mask,(uint)err_code);
- while (!isdigit(*p) && *p)
+ while (!my_isdigit(system_charset_info,*p) && *p)
p++;
}
}
@@ -495,7 +495,7 @@ int start_slave_threads(bool need_slave_mutex, bool wait_for_start,
void init_table_rule_hash(HASH* h, bool* h_inited)
{
- hash_init(h, TABLE_RULE_HASH_SIZE,0,0,
+ hash_init(h, system_charset_info,TABLE_RULE_HASH_SIZE,0,0,
(hash_get_key) get_table_key,
(void (*)(void*)) free_table_ent, 0);
*h_inited = 1;
@@ -517,7 +517,8 @@ static TABLE_RULE_ENT* find_wild(DYNAMIC_ARRAY *a, const char* key, int len)
{
TABLE_RULE_ENT* e ;
get_dynamic(a, (gptr)&e, i);
- if (!wild_case_compare(key, key_end, (const char*)e->db,
+ if (!wild_case_compare(system_charset_info, key, key_end,
+ (const char*)e->db,
(const char*)(e->db + e->key_len),'\\'))
return e;
}
diff --git a/sql/spatial.cc b/sql/spatial.cc
new file mode 100644
index 00000000000..32942a70dc2
--- /dev/null
+++ b/sql/spatial.cc
@@ -0,0 +1,1435 @@
+#include "mysql_priv.h"
+
+
+#define MAX_DIGITS_IN_DOUBLE 16
+
+/***************************** GClassInfo *******************************/
+
+#define IMPLEMENT_GEOM(class_name, type_id, name) \
+{ \
+ (GF_InitFromText) &class_name::init_from_text, \
+ (GF_GetDataAsText) &class_name::get_data_as_text, \
+ (GF_GetDataSize) &class_name::get_data_size, \
+ (GF_GetMBR) &class_name::get_mbr, \
+ (GF_GetD) &class_name::get_x, \
+ (GF_GetD) &class_name::get_y, \
+ (GF_GetD) &class_name::length, \
+ (GF_GetD) &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_GetWS) &class_name::start_point, \
+ (GF_GetWS) &class_name::end_point, \
+ (GF_GetWS) &class_name::exterior_ring, \
+ (GF_GetWS) &class_name::centroid, \
+ (GF_GetUIWS) &class_name::point_n, \
+ (GF_GetUIWS) &class_name::interior_ring_n, \
+ (GF_GetUIWS) &class_name::geometry_n, \
+ class_name::type_id, \
+ name, \
+ NULL \
+},
+
+
+static Geometry::GClassInfo 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")
+};
+
+static Geometry::GClassInfo *ci_collection_end = ci_collection + sizeof(ci_collection);
+
+/***************************** Geometry *******************************/
+
+Geometry::GClassInfo *Geometry::find_class(int type_id)
+{
+ for (GClassInfo *cur_rt = ci_collection; cur_rt < ci_collection_end; ++cur_rt)
+ {
+ if (cur_rt->m_type_id == type_id)
+ {
+ return cur_rt;
+ }
+ }
+ return NULL;
+}
+
+Geometry::GClassInfo *Geometry::find_class(const char *name, size_t len)
+{
+ for (GClassInfo *cur_rt = ci_collection;
+ cur_rt < ci_collection_end; ++cur_rt)
+ {
+ if ((cur_rt->m_name[len] == 0) &&
+ (strncmp(cur_rt->m_name, name, len) == 0))
+ {
+ return cur_rt;
+ }
+ }
+ return NULL;
+}
+
+int Geometry::create_from_wkb(const char *data, uint32 data_len)
+{
+ uint32 geom_type;
+
+ if (data_len < 1+4)
+ return 1;
+ data += sizeof(char);
+
+//FIXME: check byte ordering
+ geom_type = uint4korr(data);
+ data += 4;
+ m_vmt = find_class(geom_type);
+ if (!m_vmt) 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 name_len;
+ const char *name = trs->get_next_word(&name_len);
+ if (!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_text(trs, wkt)) return 1;
+ if (trs->get_next_symbol() != ')')
+ {
+ trs->set_error_msg("')' expected");
+ return -1;
+ }
+ if (init_stream)
+ {
+ init_from_wkb(wkt->ptr(), wkt->length());
+ shift_wkb_header();
+ }
+ return 0;
+}
+
+int Geometry::envelope(String *result) const
+{
+ MBR mbr;
+
+ get_mbr(&mbr);
+
+ if (result->reserve(1+4*3+sizeof(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(mbr.xmin);
+ result->q_append(mbr.ymin);
+ result->q_append(mbr.xmax);
+ result->q_append(mbr.ymin);
+ result->q_append(mbr.xmax);
+ result->q_append(mbr.ymax);
+ result->q_append(mbr.xmin);
+ result->q_append(mbr.ymax);
+ result->q_append(mbr.xmin);
+ result->q_append(mbr.ymin);
+
+ return 0;
+}
+
+/***************************** Point *******************************/
+
+size_t GPoint::get_data_size() const
+{
+ return POINT_DATA_SIZE;
+}
+
+int GPoint::init_from_text(GTextReadStream *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))
+ return 1;
+ wkb->q_append(x);
+ wkb->q_append(y);
+
+ return 0;
+}
+
+int GPoint::get_data_as_text(String *txt) const
+{
+ double x, y;
+ if (get_xy(&x, &y))
+ return 1;
+ if (txt->reserve(MAX_DIGITS_IN_DOUBLE * 2 + 1))
+ return 1;
+ txt->qs_append(x);
+ txt->qs_append(' ');
+ txt->qs_append(y);
+ return 0;
+}
+
+int GPoint::get_mbr(MBR *mbr) const
+{
+ double x, y;
+ if (get_xy(&x, &y))
+ return 1;
+ mbr->add_xy(x, y);
+ return 0;
+}
+
+/***************************** LineString *******************************/
+
+size_t GLineString::get_data_size() const
+{
+ uint32 n_points = uint4korr(m_data);
+
+ return 4 + n_points*POINT_DATA_SIZE;
+}
+
+int GLineString::init_from_text(GTextReadStream *trs, String *wkb)
+{
+ uint32 n_points = 0;
+ int np_pos = wkb->length();
+ GPoint p;
+
+ if (wkb->reserve(4, 512))
+ return 1;
+
+ wkb->q_append((uint32)n_points);
+
+ for (;;)
+ {
+ if (p.init_from_text(trs, wkb))
+ return 1;
+ ++n_points;
+ if (trs->get_next_toc_type() == GTextReadStream::comma)
+ trs->get_next_symbol();
+ else break;
+ }
+
+ if (n_points<2)
+ {
+ trs->set_error_msg("Too few points in LINESTRING");
+ return 1;
+ }
+
+ wkb->WriteAtPosition(np_pos, n_points);
+
+ return 0;
+}
+
+int GLineString::get_data_as_text(String *txt) 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;
+
+ if (txt->reserve(((MAX_DIGITS_IN_DOUBLE + 1)*2 + 1) * n_points))
+ return 1;
+ for (; n_points>0; --n_points)
+ {
+ double x, y;
+ float8get(x, data);
+ data += sizeof(double);
+ float8get(y, data);
+ data += sizeof(double);
+ txt->qs_append(x);
+ txt->qs_append(' ');
+ txt->qs_append(y);
+ txt->qs_append(',');
+ }
+ txt->length(txt->length() - 1);
+ 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((double *)data, (double *)(data + 8));
+ data += 8+8;
+ }
+
+ return 0;
+}
+
+int GLineString::length(double *len) const
+{
+ uint32 n_points;
+ double prev_x, prev_y;
+ const char *data = m_data;
+
+ *len=0;
+ if (no_data(data, 4))
+ return 1;
+ n_points = uint4korr(data);
+ data += 4;
+
+ if (no_data(data, sizeof(double) * 2 * n_points))
+ return 1;
+
+ --n_points;
+ float8get(prev_x, data);
+ data += 8;
+ float8get(prev_y, data);
+ data += 8;
+
+ for (; n_points>0; --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;
+ }
+ return 0;
+}
+
+int GLineString::is_closed(int *closed) const
+
+{
+ uint32 n_points;
+ double x1, y1, x2, y2;
+
+ 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))
+ return 1;
+ float8get(x1, data);
+ data += 8;
+ float8get(y1, data);
+ data += 8 + (n_points-2)*POINT_DATA_SIZE;
+ float8get(x2, data);
+ data += 8;
+ float8get(y2, data);
+
+ *closed=(x1==x2)&&(y1==y2);
+
+ return 0;
+}
+
+int GLineString::num_points(uint32 *n_points) const
+{
+ *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);
+ result->q_append((double *)data);
+ result->q_append((double *)(data + 8));
+
+ return 0;
+}
+
+int GLineString::end_point(String *result) const
+{
+ const char *data = m_data;
+ uint32 n_points;
+
+ if (no_data(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);
+ result->q_append((double *)data);
+ result->q_append((double *)(data + 8));
+
+ return 0;
+}
+
+
+int GLineString::point_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);
+
+ if ((uint32)(num-1) >= n_points) // really 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);
+ result->q_append((double *)data);
+ result->q_append((double *)(data + 8));
+
+ return 0;
+}
+
+/***************************** Polygon *******************************/
+
+size_t GPolygon::get_data_size() const
+{
+ uint32 n_linear_rings = 0;
+ 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)
+ {
+ if (no_data(data, 4))
+ return 1;
+ data += 4 + uint4korr(data)*POINT_DATA_SIZE;
+ }
+ return data - m_data;
+}
+
+int GPolygon::init_from_text(GTextReadStream *trs, String *wkb)
+{
+ uint32 n_linear_rings = 0;
+ int lr_pos = wkb->length();
+
+ if (wkb->reserve(4, 512))
+ return 1;
+
+ wkb->q_append((uint32)n_linear_rings);
+
+ 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_text(trs, wkb))
+ return 1;
+ if (trs->get_next_symbol() != ')')
+ {
+ trs->set_error_msg("')' expected");
+ return 1;
+ }
+ ls.init_from_wkb(wkb->ptr()+ls_pos, wkb->length()-ls_pos);
+ int closed;
+ ls.is_closed(&closed);
+ if (!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
+ break;
+ }
+ wkb->WriteAtPosition(lr_pos, n_linear_rings);
+ return 0;
+}
+
+int GPolygon::get_data_as_text(String *txt) const
+{
+ uint32 n_linear_rings;
+ 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)
+ {
+ 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))
+ return 1;
+ txt->qs_append('(');
+ for (; n_points>0; --n_points)
+ {
+ txt->qs_append((double *)data);
+ txt->qs_append(' ');
+ txt->qs_append((double *)(data + 8));
+ txt->qs_append(',');
+
+ data += 8+8;
+ }
+ (*txt)[txt->length()-1] = ')';
+ txt->qs_append(',');
+ }
+ txt->length(txt->length() - 1);
+ return 0;
+}
+
+int GPolygon::get_mbr(MBR *mbr) const
+{
+ uint32 n_linear_rings;
+
+ 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)
+ {
+ 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((double *)data, (double *)(data + 8));
+ data += 8+8;
+ }
+ }
+ return 0;
+}
+
+int GPolygon::area(double *ar) const
+{
+ uint32 n_linear_rings;
+ double result = -1.0;
+
+ 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)
+ {
+ double prev_x, prev_y;
+ double lr_area=0;
+ if (no_data(data, 4))
+ return 1;
+ uint32 n_points = uint4korr(data);
+ if (no_data(data, (8+8) * n_points))
+ return 1;
+ float8get(prev_x, data+4);
+ float8get(prev_y, data+(4+8));
+ data += (4+8+8);
+
+ --n_points;
+ for (; n_points>0; --n_points)
+ {
+ 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);
+ }
+ lr_area=fabs(lr_area)/2;
+ if(result==-1) result=lr_area;
+ else result-=lr_area;
+ }
+ *ar=fabs(result);
+ return 0;
+}
+
+
+int GPolygon::exterior_ring(String *result) const
+{
+ uint32 n_points;
+ 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))
+ return 1;
+
+ 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
+{
+ const char *data = m_data;
+ if (no_data(data, 4))
+ return 1;
+ *n_int_rings = uint4korr(data);
+ --(*n_int_rings);
+
+ return 0;
+}
+
+int GPolygon::interior_ring_n(uint32 num, String *result) const
+{
+ const char *data = m_data;
+ uint32 n_linear_rings;
+ uint32 n_points;
+
+ if (no_data(data, 4))
+ return 1;
+
+ n_linear_rings = uint4korr(data);
+ data += 4;
+ if ((num >= n_linear_rings) || (num < 1))
+ return -1;
+
+ for (; num > 0; --num)
+ {
+ if (no_data(data, 4))
+ return 1;
+ 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))
+ return 1;
+
+ 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
+{
+ uint32 n_linear_rings;
+ uint32 i;
+ double res_area, res_cx, res_cy;
+ const char *data = m_data;
+
+ if (no_data(data, 4))
+ return 1;
+ n_linear_rings = uint4korr(data);
+ data += 4;
+
+ for(i = 0; i < n_linear_rings; ++i)
+ {
+ if (no_data(data, 4))
+ return 1;
+ uint32 n_points = uint4korr(data);
+ double prev_x, prev_y;
+ double cur_area = 0;
+ double cur_cx = 0;
+ double cur_cy = 0;
+
+ data += 4;
+ if (no_data(data, (8+8) * n_points))
+ return 1;
+ float8get(prev_x, data);
+ float8get(prev_y, data+8);
+ data += (8+8);
+
+ uint32 n = n_points - 1;
+ for (; n > 0; --n)
+ {
+ 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);
+ }
+ cur_area = fabs(cur_area) / 2;
+ cur_cx = cur_cx / (n_points - 1);
+ cur_cy = cur_cy / (n_points - 1);
+ if(i)
+ {
+ 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;
+ }
+ else
+ {
+ res_area = cur_area;
+ res_cx = cur_cx;
+ res_cy = cur_cy;
+ }
+ }
+
+ *x = res_cx;
+ *y = res_cy;
+
+ return 0;
+}
+
+int GPolygon::centroid(String *result) const
+{
+ double x, y;
+
+ this->centroid_xy(&x, &y);
+ if (result->reserve(1 + 4 + sizeof(double) * 2))
+ return 1;
+
+ result->q_append((char)wkbNDR);
+ result->q_append((uint32)wkbPoint);
+ result->q_append(x);
+ result->q_append(y);
+
+ return 0;
+}
+
+
+/***************************** MultiPoint *******************************/
+
+size_t GMultiPoint::get_data_size() const
+{
+ return 4 + uint4korr(m_data)*(POINT_DATA_SIZE + WKB_HEADER_SIZE);
+}
+
+int GMultiPoint::init_from_text(GTextReadStream *trs, String *wkb)
+{
+ uint32 n_points = 0;
+ int np_pos = wkb->length();
+ GPoint p;
+
+ if (wkb->reserve(4, 512))
+ return 1;
+ wkb->q_append((uint32)n_points);
+
+ for (;;)
+ {
+ if (wkb->reserve(1+4, 512))
+ return 1;
+ wkb->q_append((char)wkbNDR);
+ wkb->q_append((uint32)wkbPoint);
+ if (p.init_from_text(trs, wkb))
+ return 1;
+ ++n_points;
+ if (trs->get_next_toc_type() == GTextReadStream::comma)
+ trs->get_next_symbol();
+ else
+ break;
+ }
+ wkb->WriteAtPosition(np_pos, n_points);
+
+ return 0;
+}
+
+int GMultiPoint::get_data_as_text(String *txt) 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;
+
+ if (txt->reserve(((MAX_DIGITS_IN_DOUBLE + 1)*2 + 1) * n_points))
+ return 1;
+
+ for (; n_points>0; --n_points)
+ {
+ txt->qs_append((double *)(data + WKB_HEADER_SIZE));
+ txt->qs_append(' ');
+ txt->qs_append((double *)(data + (8 + WKB_HEADER_SIZE)));
+ txt->qs_append(',');
+ data += 8+8+WKB_HEADER_SIZE;
+ }
+ txt->length(txt->length()-1);
+ return 0;
+}
+
+int GMultiPoint::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, n_points * (8+8+WKB_HEADER_SIZE)))
+ return 1;
+ for (; n_points>0; --n_points)
+ {
+ mbr->add_xy((double *)(data + WKB_HEADER_SIZE),
+ (double *)(data + 8 + WKB_HEADER_SIZE));
+ data += (8+8+WKB_HEADER_SIZE);
+ }
+ return 0;
+}
+
+/***************************** MultiLineString *******************************/
+
+size_t GMultiLineString::get_data_size() const
+{
+ uint32 n_line_strings = 0;
+ 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)
+ {
+ if (no_data(data, WKB_HEADER_SIZE + 4))
+ return 1;
+ data += WKB_HEADER_SIZE + 4 + uint4korr(data + WKB_HEADER_SIZE) * POINT_DATA_SIZE;
+ }
+ return data - m_data;
+}
+
+int GMultiLineString::init_from_text(GTextReadStream *trs, String *wkb)
+{
+ uint32 n_line_strings = 0;
+ int ls_pos = wkb->length();
+
+ if (wkb->reserve(4, 512))
+ return 1;
+
+ wkb->q_append((uint32)n_line_strings);
+
+ for (;;)
+ {
+ GLineString 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_text(trs, wkb))
+ return 1;
+
+ if (trs->get_next_symbol() != ')')
+ {
+ trs->set_error_msg("')' expected");
+ return 1;
+ }
+ ++n_line_strings;
+ if (trs->get_next_toc_type() == GTextReadStream::comma)
+ trs->get_next_symbol();
+ else
+ break;
+ }
+ wkb->WriteAtPosition(ls_pos, n_line_strings);
+
+ return 0;
+}
+
+int GMultiLineString::get_data_as_text(String *txt) const
+{
+ 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)
+ {
+ if (no_data(data, (WKB_HEADER_SIZE + 4)))
+ return 1;
+ uint32 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))
+ return 1;
+ txt->qs_append('(');
+ for (; n_points>0; --n_points)
+ {
+ txt->qs_append((double *)data);
+ txt->qs_append(' ');
+ txt->qs_append((double *)(data + 8));
+ txt->qs_append(',');
+ data += 8+8;
+ }
+ (*txt)[txt->length()-1] = ')';
+ txt->qs_append(',');
+ }
+ txt->length(txt->length() - 1);
+ return 0;
+}
+
+int GMultiLineString::get_mbr(MBR *mbr) const
+{
+ 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)
+ {
+ 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))
+ return 1;
+
+ for (; n_points>0; --n_points)
+ {
+ mbr->add_xy((double *)data, (double *)(data + 8));
+ data += 8+8;
+ }
+ }
+ return 0;
+}
+
+int GMultiLineString::length(double *len) const
+{
+ uint32 n_line_strings;
+ const char *data = m_data;
+ if (no_data(data, 4))
+ return 1;
+ n_line_strings = uint4korr(data);
+ data += 4;
+ *len=0;
+ for (; n_line_strings>0; --n_line_strings)
+ {
+ double ls_len;
+ GLineString ls;
+ data += WKB_HEADER_SIZE;
+ ls.init_from_wkb(data, m_data_end - data);
+ if (ls.length(&ls_len))
+ return 1;
+ *len+=ls_len;
+ data += ls.get_data_size();
+ }
+ return 0;
+}
+
+int GMultiLineString::is_closed(int *closed) const
+{
+ uint32 n_line_strings;
+ const char *data = m_data;
+ if (no_data(data, 1))
+ return 1;
+ n_line_strings = uint4korr(data);
+ data += 4 + WKB_HEADER_SIZE;
+ for (; n_line_strings>0; --n_line_strings)
+ {
+ GLineString ls;
+ ls.init_from_wkb(data, m_data_end - data);
+ if (ls.is_closed(closed))
+ return 1;
+ if (!*closed)
+ return 0;
+ data += ls.get_data_size() + WKB_HEADER_SIZE;
+ }
+ return 0;
+}
+
+/***************************** MultiPolygon *******************************/
+
+size_t GMultiPolygon::get_data_size() const
+{
+ 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)
+ {
+ if (no_data(data, 4 + WKB_HEADER_SIZE))
+ return 1;
+ uint32 n_linear_rings = uint4korr(data + WKB_HEADER_SIZE);
+ data += 4 + WKB_HEADER_SIZE;
+
+ for (; n_linear_rings > 0; --n_linear_rings)
+ {
+ data += 4 + uint4korr(data) * POINT_DATA_SIZE;
+ }
+ }
+ return data - m_data;
+}
+
+int GMultiPolygon::init_from_text(GTextReadStream *trs, String *wkb)
+{
+ uint32 n_polygons = 0;
+ int np_pos = wkb->length();
+ GPolygon p;
+
+ if (wkb->reserve(4, 512))
+ return 1;
+
+ wkb->q_append((uint32)n_polygons);
+
+ for (;;)
+ {
+ if (wkb->reserve(1+4, 512))
+ return 1;
+ 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_text(trs, wkb))
+ return 1;
+ if (trs->get_next_symbol() != ')')
+ {
+ trs->set_error_msg("')' expected");
+ return 1;
+ }
+ ++n_polygons;
+ if (trs->get_next_toc_type() == GTextReadStream::comma)
+ trs->get_next_symbol();
+ else
+ break;
+ }
+ wkb->WriteAtPosition(np_pos, n_polygons);
+ return 0;
+}
+
+int GMultiPolygon::get_data_as_text(String *txt) const
+{
+ 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)
+ {
+ 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))
+ return 1;
+ txt->q_append('(');
+ for (; n_linear_rings>0; --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;
+ txt->qs_append('(');
+ for (; n_points>0; --n_points)
+ {
+ txt->qs_append((double *)data);
+ txt->qs_append(' ');
+ txt->qs_append((double *)(data + 8));
+ txt->qs_append(',');
+ data += 8+8;
+ }
+ (*txt)[txt->length()-1] = ')';
+ txt->qs_append(',');
+ }
+ (*txt)[txt->length()-1] = ')';
+ txt->qs_append(',');
+ }
+ txt->length(txt->length() - 1);
+ return 0;
+}
+
+int GMultiPolygon::get_mbr(MBR *mbr) const
+{
+ 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)
+ {
+ if (no_data(data, 4+WKB_HEADER_SIZE))
+ return 1;
+ uint32 n_linear_rings = uint4korr(data + WKB_HEADER_SIZE);
+ data += WKB_HEADER_SIZE + 4;
+
+ for (; n_linear_rings>0; --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((double *)data, (double *)(data + 8));
+ data += 8+8;
+ }
+ }
+ }
+ return 0;
+}
+
+
+int GMultiPolygon::area(double *ar) const
+{
+ uint32 n_polygons;
+ const char *data = m_data;
+ double result = 0;
+ if (no_data(data, 4))
+ return 1;
+ n_polygons = uint4korr(data);
+ data += 4;
+
+ for (; n_polygons>0; --n_polygons)
+ {
+ double p_area;
+
+ GPolygon p;
+ data += WKB_HEADER_SIZE;
+ p.init_from_wkb(data, m_data_end - data);
+ if (p.area(&p_area))
+ return 1;
+ result += p_area;
+ data += p.get_data_size();
+ }
+ *ar = result;
+ return 0;
+}
+
+int GMultiPolygon::centroid(String *result) const
+{
+ uint32 n_polygons;
+ uint i;
+ GPolygon p;
+ double res_area, res_cx, res_cy;
+ double cur_area, cur_cx, cur_cy;
+
+ const char *data = m_data;
+ if (no_data(data, 4))
+ return 1;
+ n_polygons = uint4korr(data);
+ data += 4;
+
+ for (i = 0; i < n_polygons; ++i)
+ {
+ 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))
+ return 1;
+
+ if(i)
+ {
+ 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;
+ }
+
+ 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;
+}
+
+/***************************** GeometryCollection *******************************/
+
+size_t GGeometryCollection::get_data_size() const
+{
+ uint32 n_objects;
+ const char *data = m_data;
+ if (no_data(data, 4))
+ return 1;
+ n_objects = uint4korr(data);
+ data += 4;
+
+ for (; n_objects>0; --n_objects)
+ {
+ if (no_data(data, WKB_HEADER_SIZE))
+ return 1;
+ uint32 wkb_type = uint4korr(data + sizeof(char));
+ data += WKB_HEADER_SIZE;
+
+ Geometry geom;
+
+ if (geom.init(wkb_type))
+ return 0;
+
+ geom.init_from_wkb(data, m_data_end - data);
+ size_t object_size=geom.get_data_size();
+ data += object_size;
+ }
+ return data - m_data;
+}
+
+int GGeometryCollection::init_from_text(GTextReadStream *trs, String *wkb)
+{
+ uint32 n_objects = 0;
+ int no_pos = wkb->length();
+ Geometry g;
+
+ if (wkb->reserve(4, 512))
+ return 1;
+ wkb->q_append((uint32)n_objects);
+
+ for (;;)
+ {
+ if (g.create_from_wkt(trs, wkb))
+ return 1;
+
+ 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;
+ }
+ wkb->WriteAtPosition(no_pos, n_objects);
+
+ return 0;
+}
+
+int GGeometryCollection::get_data_as_text(String *txt) const
+{
+ uint32 n_objects;
+ const char *data = m_data;
+ Geometry geom;
+ if (no_data(data, 4))
+ return 1;
+ n_objects = uint4korr(data);
+ data += 4;
+
+ for (; n_objects>0; --n_objects)
+ {
+ if (no_data(data, WKB_HEADER_SIZE))
+ return 1;
+ uint32 wkb_type = uint4korr(data + sizeof(char));
+ 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))
+ return 1;
+ data += geom.get_data_size();
+ txt->reserve(1, 512);
+ txt->q_append(',');
+ }
+ txt->length(txt->length() - 1);
+ return 0;
+}
+
+int GGeometryCollection::get_mbr(MBR *mbr) const
+{
+ uint32 n_objects;
+ const char *data = m_data;
+ if (no_data(data, 4))
+ return 1;
+ n_objects = uint4korr(data);
+ data += 4;
+ for (; n_objects>0; --n_objects)
+ {
+ if(no_data(data, WKB_HEADER_SIZE))
+ return 1;
+ uint32 wkb_type = uint4korr(data + sizeof(char));
+ data += WKB_HEADER_SIZE;
+ Geometry geom;
+
+ 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();
+ }
+ return 0;
+}
+
+int GGeometryCollection::num_geometries(uint32 *num) const
+{
+ *num = uint4korr(m_data);
+ return 0;
+}
+
+int GGeometryCollection::geometry_n(uint32 num, String *result) const
+{
+ const char *data = m_data;
+ uint32 n_objects;
+ if (no_data(data, 4))
+ return 1;
+ n_objects = uint4korr(data);
+ data += 4;
+
+ if ((num > n_objects) || (num < 1))
+ {
+ return -1;
+ }
+ for (; num > 0; --num)
+ {
+ if (no_data(data, WKB_HEADER_SIZE))
+ return 1;
+ uint32 wkb_type = uint4korr(data + sizeof(char));
+ 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();
+ }
+ }
+ return 0;
+}
+
+int GGeometryCollection::dimension(uint32 *dim) const
+{
+ uint32 n_objects;
+ *dim = 0;
+ const char *data = m_data;
+ if (no_data(data, 4))
+ return 1;
+ n_objects = uint4korr(data);
+ data += 4;
+
+ for (; n_objects > 0; --n_objects)
+ {
+ if (no_data(data, WKB_HEADER_SIZE))
+ return 1;
+ uint32 wkb_type = uint4korr(data + sizeof(char));
+ data += WKB_HEADER_SIZE;
+
+ uint32 d;
+
+ Geometry geom;
+ if (geom.init(wkb_type))
+ return 1;
+ geom.init_from_wkb(data, m_data_end - data);
+ if (geom.dimension(&d))
+ return 1;
+
+ if (d > *dim)
+ *dim = d;
+ data += geom.get_data_size();
+ }
+ return 0;
+}
+
+/***************************** /objects *******************************/
diff --git a/sql/spatial.h b/sql/spatial.h
new file mode 100644
index 00000000000..09e8722a85e
--- /dev/null
+++ b/sql/spatial.h
@@ -0,0 +1,476 @@
+#ifndef _spatial_h
+#define _spatial_h
+
+#include "gstream.h"
+
+const int POINT_DATA_SIZE = 8+8;
+const int WKB_HEADER_SIZE = 1+4;
+
+struct stPoint2D
+{
+ double x;
+ double y;
+};
+
+struct stLinearRing
+{
+ size_t n_points;
+ stPoint2D points;
+};
+
+/***************************** MBR *******************************/
+
+struct MBR
+{
+ MBR()
+ {
+ xmin=DBL_MAX;
+ ymin=DBL_MAX;
+ xmax=-DBL_MAX;
+ 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 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)
+ { /* 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;
+ }
+ }
+
+ void add_xy(double *px, double *py)
+ { /* Not using "else" for proper one point MBR calculation */
+ double x, y;
+ float8get(x, px);
+ float8get(y, py);
+ if (x<xmin)
+ {
+ xmin=x;
+ }
+ if (x>xmax)
+ {
+ xmax=x;
+ }
+ if (y<ymin)
+ {
+ ymin=y;
+ }
+ if (y>ymax)
+ {
+ ymax=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;
+ }
+ }
+
+ int equals(const MBR *mbr)
+ {
+ return (mbr->xmin==xmin)&&(mbr->ymin==ymin)&&(mbr->xmax==xmax)&&(mbr->ymax==ymax);
+ }
+
+ int disjoint(const MBR *mbr)
+ {
+ return (mbr->xmin>xmax)||(mbr->ymin>ymax)||(mbr->xmax<xmin)||(mbr->ymax<ymin);
+ }
+
+ int intersects(const MBR *mbr)
+ {
+ return !disjoint(mbr);
+ }
+
+ int touches(const MBR *mbr)
+ {
+ return (((mbr->xmin==xmax) || (mbr->xmax==xmin)) &&
+ ((mbr->ymin>=ymin) && (mbr->ymin<=ymax) ||
+ (mbr->ymax>=ymin) && (mbr->ymax<=ymax))) ||
+ (((mbr->ymin==ymax) || (mbr->ymax==ymin)) &&
+ ((mbr->xmin>=xmin) && (mbr->xmin<=xmax) ||
+ (mbr->xmax>=xmin)&&(mbr->xmax<=xmax)));
+ }
+
+ int within(const MBR *mbr)
+ {
+ return (mbr->xmin<=xmin) && (mbr->ymin<=ymin) &&
+ (mbr->xmax>=xmax) && (mbr->ymax>=ymax);
+ }
+
+ int contains(const MBR *mbr)
+ {
+ return (mbr->xmin>=xmin) && (mbr->ymin>=ymin) &&
+ (mbr->xmax<=xmax) && (mbr->ymax<=ymax);
+ }
+
+ bool inner_point(double x, double y) const
+ {
+ return (xmin<x) && (xmax>x) && (ymin<y) && (ymax>x);
+ }
+
+ 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 a = lb+rb+rt+lt;
+ return (a>0) && (a<4) && (!within(mbr));
+ }
+};
+
+
+/***************************** Geometry *******************************/
+
+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 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;
+
+#define GEOM_METHOD_PRESENT(geom_obj, method)\
+ (geom_obj.m_vmt->method != &Geometry::method)
+
+class Geometry
+{
+public:
+ enum wkbType
+ {
+ wkbPoint = 1,
+ wkbLineString = 2,
+ wkbPolygon = 3,
+ wkbMultiPoint = 4,
+ wkbMultiLineString = 5,
+ wkbMultiPolygon = 6,
+ wkbGeometryCollection = 7
+ };
+ enum wkbByteOrder
+ {
+ wkbXDR = 0, /* Big Endian */
+ wkbNDR = 1 /* Little Endian */
+ };
+
+
+ class GClassInfo
+ {
+ public:
+ GF_InitFromText init_from_text;
+ GF_GetDataAsText get_data_as_text;
+ GF_GetDataSize get_data_size;
+ GF_GetMBR get_mbr;
+ GF_GetD get_x;
+ GF_GetD get_y;
+ GF_GetD length;
+ GF_GetD area;
+
+ GF_GetI is_closed;
+
+ GF_GetUI num_interior_ring;
+ GF_GetUI num_points;
+ GF_GetUI num_geometries;
+ GF_GetUI dimension;
+
+ GF_GetWS start_point;
+ GF_GetWS end_point;
+ GF_GetWS exterior_ring;
+ GF_GetWS centroid;
+
+ GF_GetUIWS point_n;
+ GF_GetUIWS interior_ring_n;
+ GF_GetUIWS geometry_n;
+
+ int m_type_id;
+ const char *m_name;
+ GClassInfo *m_next_rt;
+ };
+ GClassInfo *m_vmt;
+
+ const GClassInfo *get_class_info() const { return m_vmt; }
+ size_t get_data_size() const { return (this->*m_vmt->get_data_size)(); }
+
+ int init_from_text(GTextReadStream *trs, String *wkb)
+ { return (this->*m_vmt->init_from_text)(trs, wkb); }
+
+ int get_data_as_text(String *txt) const
+ { return (this->*m_vmt->get_data_as_text)(txt); }
+
+ 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_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); }
+
+ int is_closed(int *closed) const { return (this->*m_vmt->is_closed)(closed); }
+
+ int 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
+ { return (this->*m_vmt->num_points)(n_points); }
+
+ int num_geometries(uint32 *num) const
+ { return (this->*m_vmt->num_geometries)(num); }
+
+ int start_point(String *point) const
+ { return (this->*m_vmt->start_point)(point); }
+ int end_point(String *point) const
+ { return (this->*m_vmt->end_point)(point); }
+ int exterior_ring(String *ring) const
+ { return (this->*m_vmt->exterior_ring)(ring); }
+ int centroid(String *point) const
+ { return (this->*m_vmt->centroid)(point); }
+
+ int point_n(uint32 num, String *result) const
+ { return (this->*m_vmt->point_n)(num, result); }
+ int 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
+ { 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 init(int type_id)
+ {
+ m_vmt = find_class(type_id);
+ return !m_vmt;
+ }
+ int new_geometry(const char *name, size_t len)
+ {
+ m_vmt = find_class(name, len);
+ return !m_vmt;
+ }
+
+ int as_wkt(String *wkt) const
+ {
+ if(wkt->reserve(strlen(get_class_info()->m_name) + 2, 512))
+ return 1;
+ wkt->qs_append(get_class_info()->m_name);
+ wkt->qs_append('(');
+ if(get_data_as_text(wkt))
+ return 1;
+ wkt->qs_append(')');
+ return 0;
+ }
+
+ void init_from_wkb(const char *data, uint32 data_len)
+ {
+ m_data = data;
+ m_data_end = data + data_len;
+ }
+
+ void shift_wkb_header()
+ {
+ m_data += WKB_HEADER_SIZE;
+ }
+
+ int 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
+ {
+ return cur_data + data_amount > m_data_end;
+ }
+
+ const char *m_data;
+ const char *m_data_end;
+};
+
+/***************************** Point *******************************/
+
+class GPoint: public Geometry
+{
+public:
+ size_t get_data_size() const;
+ int init_from_text(GTextReadStream *trs, String *wkb);
+ int get_data_as_text(String *txt) const;
+ int get_mbr(MBR *mbr) const;
+
+ int get_xy(double *x, double *y) const
+ {
+ const char *data = m_data;
+ if(no_data(data, sizeof(double)) * 2) return 1;
+ float8get(*x, data);
+ float8get(*y, data + sizeof(double));
+ return 0;
+ }
+
+ int get_x(double *x) const
+ {
+ if(no_data(m_data, sizeof(double))) return 1;
+ float8get(*x, m_data);
+ return 0;
+ }
+
+ int get_y(double *y) const
+ {
+ const char *data = m_data;
+ if(no_data(data, sizeof(double)) * 2) return 1;
+ float8get(*y, data + sizeof(double));
+ return 0;
+ }
+
+ int dimension(uint32 *dim) const { *dim = 0; return 0; }
+};
+
+/***************************** LineString *******************************/
+
+class GLineString: public Geometry
+{
+public:
+ size_t get_data_size() const;
+ int init_from_text(GTextReadStream *trs, String *wkb);
+ int get_data_as_text(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; }
+// IsRing
+};
+
+/***************************** Polygon *******************************/
+
+class GPolygon: public Geometry
+{
+public:
+ size_t get_data_size() const;
+ int init_from_text(GTextReadStream *trs, String *wkb);
+ int get_data_as_text(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; }
+// PointOnSurface
+};
+
+/***************************** MultiPoint *******************************/
+
+class GMultiPoint: public Geometry
+{
+public:
+ size_t get_data_size() const;
+ int init_from_text(GTextReadStream *trs, String *wkb);
+ int get_data_as_text(String *txt) const;
+ int get_mbr(MBR *mbr) const;
+ int dimension(uint32 *dim) const { *dim = 0; return 0; }
+};
+
+/***************************** MultiLineString *******************************/
+
+class GMultiLineString: public Geometry
+{
+public:
+ size_t get_data_size() const;
+ int init_from_text(GTextReadStream *trs, String *wkb);
+ int get_data_as_text(String *txt) const;
+ int get_mbr(MBR *mbr) const;
+
+ int length(double *len) const;
+ int is_closed(int *closed) const;
+ int dimension(uint32 *dim) const { *dim = 1; return 0; }
+};
+
+/***************************** MultiPolygon *******************************/
+
+class GMultiPolygon: public Geometry
+{
+public:
+ size_t get_data_size() const;
+ int init_from_text(GTextReadStream *trs, String *wkb);
+ int get_data_as_text(String *txt) const;
+ int get_mbr(MBR *mbr) const;
+
+ int area(double *ar) const;
+ int centroid(String *result) const;
+ int dimension(uint32 *dim) const { *dim = 2; return 0; }
+// PointOnSurface
+};
+
+/***************************** GeometryCollection *******************************/
+
+class GGeometryCollection: public Geometry
+{
+public:
+ size_t get_data_size() const;
+ int init_from_text(GTextReadStream *trs, String *wkb);
+ int get_data_as_text(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;
+};
+
+#endif
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 104b431bdbb..403d08ad0ab 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -383,7 +383,7 @@ static uint get_access(TABLE *form,uint fieldnr)
for (pos=form->field+fieldnr,bit=1 ; *pos ; pos++ , bit<<=1)
{
(*pos)->val_str(&res,&res);
- if (toupper(res[0]) == 'Y')
+ if (my_toupper(system_charset_info, res[0]) == 'Y')
access_bits|=bit;
}
return access_bits;
@@ -731,7 +731,7 @@ uint acl_get(const char *host, const char *ip, const char *bin_ip,
end=strmov((tmp_db=strmov(key+sizeof(struct in_addr),user)+1),db);
if (lower_case_table_names)
{
- casedn_str(tmp_db);
+ my_casedn_str(system_charset_info, tmp_db);
db=tmp_db;
}
key_length=(uint) (end-key);
@@ -795,7 +795,7 @@ exit:
}
-int wild_case_compare(const char *str,const char *wildstr)
+int wild_case_compare(CHARSET_INFO *cs, const char *str,const char *wildstr)
{
reg3 int flag;
DBUG_ENTER("wild_case_compare");
@@ -806,7 +806,8 @@ int wild_case_compare(const char *str,const char *wildstr)
{
if (*wildstr == wild_prefix && wildstr[1])
wildstr++;
- if (toupper(*wildstr++) != toupper(*str++)) DBUG_RETURN(1);
+ if (my_toupper(cs, *wildstr++) !=
+ my_toupper(cs, *str++)) DBUG_RETURN(1);
}
if (! *wildstr ) DBUG_RETURN (*str != 0);
if (*wildstr++ == wild_one)
@@ -824,12 +825,12 @@ int wild_case_compare(const char *str,const char *wildstr)
char cmp;
if ((cmp= *wildstr) == wild_prefix && wildstr[1])
cmp=wildstr[1];
- cmp=toupper(cmp);
- while (*str && toupper(*str) != cmp)
+ cmp=my_toupper(cs, cmp);
+ while (*str && my_toupper(cs, *str) != cmp)
str++;
if (!*str) DBUG_RETURN (1);
}
- if (wild_case_compare(str,wildstr) == 0) DBUG_RETURN (0);
+ if (wild_case_compare(cs, str,wildstr) == 0) DBUG_RETURN (0);
} while (*str++);
DBUG_RETURN(1);
}
@@ -848,7 +849,7 @@ static void init_check_host(void)
DBUG_ENTER("init_check_host");
VOID(init_dynamic_array(&acl_wild_hosts,sizeof(struct acl_host_and_ip),
acl_users.elements,1));
- VOID(hash_init(&acl_check_hosts,acl_users.elements,0,0,
+ VOID(hash_init(&acl_check_hosts,system_charset_info,acl_users.elements,0,0,
(hash_get_key) check_get_key,0,HASH_CASE_INSENSITIVE));
if (!allow_all_hosts)
{
@@ -864,7 +865,8 @@ static void init_check_host(void)
{ // Check if host already exists
acl_host_and_ip *acl=dynamic_element(&acl_wild_hosts,j,
acl_host_and_ip *);
- if (!my_strcasecmp(acl_user->host.hostname,acl->hostname))
+ if (!my_strcasecmp(system_charset_info,
+ acl_user->host.hostname, acl->hostname))
break; // already stored
}
if (j == acl_wild_hosts.elements) // If new
@@ -939,7 +941,7 @@ bool change_password(THD *thd, const char *host, const char *user,
if (!thd->slave_thread &&
(strcmp(thd->user,user) ||
- my_strcasecmp(host,thd->host ? thd->host : thd->ip)))
+ my_strcasecmp(system_charset_info, host,thd->host_or_ip))
{
if (check_access(thd, UPDATE_ACL, "mysql",0,1))
DBUG_RETURN(1);
@@ -1065,7 +1067,8 @@ static bool compare_hostname(const acl_host_and_ip *host, const char *hostname,
return (tmp & host->ip_mask) == host->ip;
}
return (!host->hostname ||
- (hostname && !wild_case_compare(hostname,host->hostname)) ||
+ (hostname && !wild_case_compare(system_charset_info,
+ hostname,host->hostname)) ||
(ip && !wild_compare(ip,host->hostname)));
}
@@ -1418,13 +1421,14 @@ public:
tname= strdup_root(&memex,t);
if (lower_case_table_names)
{
- casedn_str(db);
- casedn_str(tname);
+ my_casedn_str(system_charset_info, db);
+ my_casedn_str(system_charset_info, tname);
}
key_length =(uint) strlen(d)+(uint) strlen(u)+(uint) strlen(t)+3;
hash_key = (char*) alloc_root(&memex,key_length);
strmov(strmov(strmov(hash_key,user)+1,db)+1,tname);
- (void) hash_init(&hash_columns,0,0,0, (hash_get_key) get_key_column,0,
+ (void) hash_init(&hash_columns,system_charset_info,
+ 0,0,0, (hash_get_key) get_key_column,0,
HASH_CASE_INSENSITIVE);
}
@@ -1444,8 +1448,8 @@ public:
}
if (lower_case_table_names)
{
- casedn_str(db);
- casedn_str(tname);
+ my_casedn_str(system_charset_info, db);
+ my_casedn_str(system_charset_info, tname);
}
key_length = ((uint) strlen(db) + (uint) strlen(user) +
(uint) strlen(tname) + 3);
@@ -1456,7 +1460,8 @@ public:
privs = fix_rights_for_table(privs);
cols = fix_rights_for_column(cols);
- (void) hash_init(&hash_columns,0,0,0, (hash_get_key) get_key_column,0,
+ (void) hash_init(&hash_columns,system_charset_info,
+ 0,0,0, (hash_get_key) get_key_column,0,
HASH_CASE_INSENSITIVE);
if (cols)
{
@@ -1538,8 +1543,10 @@ static GRANT_TABLE *table_hash_search(const char *host,const char* ip,
}
else
{
- if ((host && !wild_case_compare(host,grant_table->host)) ||
- (ip && !wild_case_compare(ip,grant_table->host)))
+ if ((host && !wild_case_compare(system_charset_info,
+ host,grant_table->host)) ||
+ (ip && !wild_case_compare(system_charset_info,
+ ip,grant_table->host)))
found=grant_table; // Host ok
}
}
@@ -2055,7 +2062,7 @@ int mysql_grant (THD *thd, const char *db, List <LEX_USER> &list, uint rights,
if (lower_case_table_names && db)
{
strmov(tmp_db,db);
- casedn_str(tmp_db);
+ my_casedn_str(system_charset_info, tmp_db);
db=tmp_db;
}
@@ -2141,7 +2148,8 @@ int grant_init (void)
DBUG_ENTER("grant_init");
grant_option = FALSE;
- (void) hash_init(&hash_tables,0,0,0, (hash_get_key) get_grant_table,
+ (void) hash_init(&hash_tables,system_charset_info,
+ 0,0,0, (hash_get_key) get_grant_table,
(hash_free_key) free_grant_table,0);
init_sql_alloc(&memex,1024,0);
@@ -2480,8 +2488,10 @@ bool check_grant_db(THD *thd,const char *db)
GRANT_TABLE *grant_table = (GRANT_TABLE*) hash_element(&hash_tables,idx);
if (len < grant_table->key_length &&
!memcmp(grant_table->hash_key,helping,len) &&
- (thd->host && !wild_case_compare(thd->host,grant_table->host) ||
- (thd->ip && !wild_case_compare(thd->ip,grant_table->host))))
+ (thd->host && !wild_case_compare(system_charset_info,
+ thd->host,grant_table->host) ||
+ (thd->ip && !wild_case_compare(system_charset_info,
+ thd->ip,grant_table->host))))
{
error=0; // Found match
break;
diff --git a/sql/sql_analyse.cc b/sql/sql_analyse.cc
index df8a8f1fdde..fc764333916 100644
--- a/sql/sql_analyse.cc
+++ b/sql/sql_analyse.cc
@@ -163,7 +163,7 @@ bool test_if_number(NUM_INFO *info, const char *str, uint str_len)
// MySQL removes any endspaces of a string, so we must take care only of
// spaces in front of a string
- for (; str != end && isspace(*str); str++) ;
+ for (; str != end && my_isspace(system_charset_info, *str); str++) ;
if (str == end)
return 0;
@@ -176,10 +176,10 @@ bool test_if_number(NUM_INFO *info, const char *str, uint str_len)
else
info->negative = 0;
begin = str;
- for (; str != end && isdigit(*str); str++)
+ for (; str != end && my_isdigit(system_charset_info,*str); str++)
{
if (!info->integers && *str == '0' && (str + 1) != end &&
- isdigit(*(str + 1)))
+ my_isdigit(system_charset_info,*(str + 1)))
info->zerofill = 1; // could be a postnumber for example
info->integers++;
}
@@ -205,7 +205,7 @@ bool test_if_number(NUM_INFO *info, const char *str, uint str_len)
str++;
if (*str != '-' && *str != '+')
return 0;
- for (str++; str != end && isdigit(*str); str++) ;
+ for (str++; str != end && my_isdigit(system_charset_info,*str); str++) ;
if (str == end)
{
info->is_float = 1; // we can't use variable decimals here
@@ -220,7 +220,7 @@ bool test_if_number(NUM_INFO *info, const char *str, uint str_len)
info->ullval = (ulonglong) strtoull(begin, NULL, 10);
return 1;
}
- for (; str != end && isdigit(*str); str++)
+ for (; str != end && my_isdigit(system_charset_info,*str); str++)
info->decimals++;
if (str == end)
{
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 88854396ae3..031c83a2aeb 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -50,7 +50,8 @@ static byte *cache_key(const byte *record,uint *length,
void table_cache_init(void)
{
- VOID(hash_init(&open_cache,table_cache_size+16,0,0,cache_key,
+ VOID(hash_init(&open_cache,system_charset_info,
+ table_cache_size+16,0,0,cache_key,
(void (*)(void*)) free_cache_entry,0));
mysql_rm_tmp_tables();
}
@@ -781,7 +782,7 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name,
{
if (table->key_length == key_length &&
!memcmp(table->table_cache_key,key,key_length) &&
- !my_strcasecmp(table->table_name,alias))
+ !my_strcasecmp(system_charset_info,table->table_name,alias))
goto reset;
}
my_printf_error(ER_TABLE_NOT_LOCKED,ER(ER_TABLE_NOT_LOCKED),MYF(0),alias);
@@ -1560,11 +1561,12 @@ Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length,
Field **ptr=table->field;
while ((field = *ptr++))
{
- if (!my_strcasecmp(field->field_name, name))
+ if (!my_strcasecmp(system_charset_info, field->field_name, name))
goto found;
}
}
- if (allow_rowid && !my_strcasecmp(name,"_rowid") &&
+ if (allow_rowid &&
+ !my_strcasecmp(system_charset_info, name, "_rowid") &&
(field=table->rowid_field))
goto found;
return (Field*) 0;
@@ -1687,7 +1689,8 @@ find_item_in_list(Item *find,List<Item> &items)
{
if (field_name && item->type() == Item::FIELD_ITEM)
{
- if (!my_strcasecmp(((Item_field*) item)->name,field_name))
+ if (!my_strcasecmp(system_charset_info,
+ ((Item_field*) item)->name,field_name))
{
if (!table_name)
{
@@ -1710,8 +1713,9 @@ find_item_in_list(Item *find,List<Item> &items)
}
}
else if (!table_name && (item->eq(find,0) ||
- find->name &&
- !my_strcasecmp(item->name,find->name)))
+ find->name &&
+ !my_strcasecmp(system_charset_info,
+ item->name,find->name)))
{
found=li.ref();
break;
@@ -1939,7 +1943,8 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
// TODO: This could be optimized to use hashed names if t2 had a hash
for (j=0 ; j < t2->fields ; j++)
{
- if (!my_strcasecmp(t1->field[i]->field_name,
+ if (!my_strcasecmp(system_charset_info,
+ t1->field[i]->field_name,
t2->field[j]->field_name))
{
Item_func_eq *tmp=new Item_func_eq(new Item_field(t1->field[i]),
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc
index 588d60462b0..d7549732798 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -893,8 +893,9 @@ Query_cache::send_result_to_client(THD *thd, char *sql, uint query_length)
Test if the query is a SELECT
(pre-space is removed in dispatch_command)
*/
- if (toupper(sql[0]) != 'S' || toupper(sql[1]) != 'E' ||
- toupper(sql[2]) !='L')
+ if (my_toupper(system_charset_info, sql[0]) != 'S' ||
+ my_toupper(system_charset_info, sql[1]) != 'E' ||
+ my_toupper(system_charset_info,sql[2]) !='L')
{
DBUG_PRINT("qcache", ("The statement is not a SELECT; Not cached"));
goto err;
@@ -1347,9 +1348,9 @@ ulong Query_cache::init_cache()
DUMP(this);
- VOID(hash_init(&queries,def_query_hash_size, 0, 0,
+ VOID(hash_init(&queries,system_charset_info,def_query_hash_size, 0, 0,
query_cache_query_get_key, 0, 0));
- VOID(hash_init(&tables,def_table_hash_size, 0, 0,
+ VOID(hash_init(&tables,system_charset_info,def_table_hash_size, 0, 0,
query_cache_table_get_key, 0, 0));
queries_in_cache = 0;
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 03bb8ae2c97..29cdaa676d6 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -148,7 +148,7 @@ THD::THD():user_time(0),fatal_error(0),last_insert_id_used(0),
bzero((char*) &mem_root,sizeof(mem_root));
bzero((char*) &transaction.mem_root,sizeof(transaction.mem_root));
user_connect=(UC *)0;
- hash_init(&user_vars, USER_VARS_HASH_SIZE, 0, 0,
+ hash_init(&user_vars, system_charset_info, USER_VARS_HASH_SIZE, 0, 0,
(hash_get_key) get_var_key,
(void (*)(void*)) free_var,0);
#ifdef USING_TRANSACTIONS
diff --git a/sql/sql_class.h b/sql/sql_class.h
index e755deeea61..d111ff3df8e 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -215,14 +215,16 @@ public:
class Key :public Sql_alloc {
public:
- enum Keytype { PRIMARY, UNIQUE, MULTIPLE, FULLTEXT };
+ enum Keytype { PRIMARY, UNIQUE, MULTIPLE, FULLTEXT, SPATIAL };
enum Keytype type;
enum ha_key_alg algorithm;
List<key_part_spec> columns;
const char *Name;
Key(enum Keytype type_par,const char *name_arg,List<key_part_spec> &cols)
- :type(type_par), algorithm(HA_KEY_ALG_UNDEF), columns(cols), Name(name_arg)
+
+ Key(enum Keytype type_par, enum ha_key_alg alg_par, const char *name_arg, List<key_part_spec> &cols)
+ :type(type_par), algorithm(alg_par), columns(cols), Name(name_arg)
{}
~Key() {}
const char *name() { return Name; }
@@ -703,15 +705,17 @@ class Table_ident :public Sql_alloc {
public:
LEX_STRING db;
LEX_STRING table;
+ SELECT_LEX *sel;
inline Table_ident(LEX_STRING db_arg,LEX_STRING table_arg,bool force)
- :table(table_arg)
+ :table(table_arg), sel((SELECT_LEX *)0)
{
if (!force && (current_thd->client_capabilities & CLIENT_NO_SCHEMA))
db.str=0;
else
db= db_arg;
}
- inline Table_ident(LEX_STRING table_arg) :table(table_arg) {db.str=0;}
+ inline Table_ident(LEX_STRING table_arg) :table(table_arg), sel((SELECT_LEX *)0) {db.str=0;}
+ inline Table_ident(SELECT_LEX *s) : sel(s) {db.str=0; table.str=(char *)""; table.length=0;}
inline void change_db(char *db_name)
{ db.str= db_name; db.length=(uint) strlen(db_name); }
};
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index 9f521ac5ffd..032cbf3d6a3 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -218,7 +218,8 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db,
DBUG_PRINT("info",("Examining: %s", file->name));
/* Check if file is a raid directory */
- if (isdigit(file->name[0]) && isdigit(file->name[1]) &&
+ if (my_isdigit(system_charset_info,file->name[0]) &&
+ my_isdigit(system_charset_info,file->name[1]) &&
!file->name[2] && !level)
{
char newpath[FN_REFLEN];
@@ -243,7 +244,8 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db,
continue;
}
strxmov(filePath,org_path,"/",file->name,NullS);
- if (db && !my_strcasecmp(fn_ext(file->name), reg_ext))
+ if (db && !my_strcasecmp(system_charset_info,
+ fn_ext(file->name), reg_ext))
{
/* Drop the table nicely */
*fn_ext(file->name)=0; // Remove extension
diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc
new file mode 100644
index 00000000000..f1b60dd9b84
--- /dev/null
+++ b/sql/sql_derived.cc
@@ -0,0 +1,121 @@
+/* Copyright (C) 2000 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 */
+
+
+/*
+ Derived tables
+ These were introduced by Monty and Sinisa <sinisa@mysql.com>
+*/
+
+
+#include "mysql_priv.h"
+#include "sql_select.h"
+#include "sql_acl.h"
+
+static const char *any_db="*any*"; // Special symbol for check_access
+
+
+int mysql_derived(THD *thd, LEX *lex,SELECT_LEX *s, TABLE_LIST *t)
+{
+ SELECT_LEX *sl=s;
+ List<Item> item_list;
+ TABLE *table;
+ int res;
+ select_union *derived_result;
+ TABLE_LIST *tables=(TABLE_LIST *)sl->table_list.first;
+ TMP_TABLE_PARAM tmp_table_param;
+ DBUG_ENTER("mysql_derived");
+
+ if (tables)
+ res=check_table_access(thd,SELECT_ACL, tables);
+ else
+ res=check_access(thd, SELECT_ACL, any_db);
+ if (res)
+ DBUG_RETURN(-1);
+
+ for (TABLE_LIST *cursor= (TABLE_LIST *)tables;
+ cursor;
+ cursor=cursor->next)
+ {
+ if (cursor->derived)
+ {
+ res=mysql_derived(thd,lex,(SELECT_LEX *)cursor->derived,cursor);
+ if (res) DBUG_RETURN(res);
+ }
+ }
+ Item *item;
+ List_iterator<Item> it(sl->item_list);
+
+ while ((item= it++))
+ item_list.push_back(item);
+
+ if (!(res=open_and_lock_tables(thd,tables)))
+ {
+ if (tables && setup_fields(thd,tables,item_list,0,0,1))
+ {
+ res=-1;
+ goto exit;
+ }
+ bzero((char*) &tmp_table_param,sizeof(tmp_table_param));
+ tmp_table_param.field_count=item_list.elements;
+ if (!(table=create_tmp_table(thd, &tmp_table_param, sl->item_list,
+ (ORDER*) 0, 0, 1, 0,
+ (sl->options | thd->options | TMP_TABLE_ALL_COLUMNS))))
+ {
+ res=-1;
+ goto exit;
+ }
+
+ if ((derived_result=new select_union(table)))
+ {
+ thd->offset_limit=sl->offset_limit;
+ thd->select_limit=sl->select_limit+sl->offset_limit;
+ if (thd->select_limit < sl->select_limit)
+ thd->select_limit= HA_POS_ERROR;
+ if (thd->select_limit == HA_POS_ERROR)
+ sl->options&= ~OPTION_FOUND_ROWS;
+
+ res=mysql_select(thd, tables, sl->item_list,
+ sl->where, (ORDER *) sl->order_list.first,
+ (ORDER*) sl->group_list.first,
+ sl->having, (ORDER*) NULL,
+ sl->options | thd->options | SELECT_NO_UNLOCK,
+ derived_result);
+ if (!res)
+ {
+// Here we entirely fix both TABLE_LIST and list of SELECT's as there were no derived tables
+ if (derived_result->flush())
+ res=1;
+ else
+ {
+ t->real_name=table->real_name;
+ t->table=table;
+ sl->prev->next=sl->next;
+ t->derived=(SELECT_LEX *)0; // just in case ...
+ if (!sl->next) lex->last_select = sl;
+ }
+ }
+ delete derived_result;
+ }
+ if (res)
+ free_tmp_table(thd,table);
+exit:
+ close_thread_tables(thd);
+ if (res > 0)
+ send_error(&thd->net, ER_UNKNOWN_COM_ERROR); // temporary only ...
+ }
+ DBUG_RETURN(res);
+}
diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc
index f1dc5599f46..4ecd5dbca36 100644
--- a/sql/sql_handler.cc
+++ b/sql/sql_handler.cc
@@ -270,7 +270,7 @@ static TABLE **find_table_ptr_by_name(THD *thd, const char *db,
for (TABLE *table=*ptr; table ; table=*ptr)
{
if (!memcmp(table->table_cache_key, db, dblen) &&
- !my_strcasecmp(table->table_name,table_name))
+ !my_strcasecmp(system_charset_info,table->table_name,table_name))
break;
ptr=&(table->next);
}
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 42a8a700da3..31ec6d1cecc 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -92,15 +92,15 @@ void lex_init(void)
/* Fill state_map with states to get a faster parser */
for (i=0; i < 256 ; i++)
{
- if (isalpha(i))
+ if (my_isalpha(system_charset_info,i))
state_map[i]=(uchar) STATE_IDENT;
- else if (isdigit(i))
+ else if (my_isdigit(system_charset_info,i))
state_map[i]=(uchar) STATE_NUMBER_IDENT;
#if defined(USE_MB) && defined(USE_MB_IDENT)
- else if (use_mb(default_charset_info) && my_ismbhead(default_charset_info, i))
+ else if (use_mb(system_charset_info) && my_ismbhead(system_charset_info, i))
state_map[i]=(uchar) STATE_IDENT;
#endif
- else if (!isgraph(i))
+ else if (!my_isgraph(system_charset_info,i))
state_map[i]=(uchar) STATE_SKIP;
else
state_map[i]=(uchar) STATE_CHAR;
@@ -222,8 +222,8 @@ static char *get_text(LEX *lex)
c = yyGet();
#ifdef USE_MB
int l;
- if (use_mb(default_charset_info) &&
- (l = my_ismbchar(default_charset_info,
+ if (use_mb(system_charset_info) &&
+ (l = my_ismbchar(system_charset_info,
(const char *)lex->ptr-1,
(const char *)lex->end_of_query))) {
lex->ptr += l-1;
@@ -267,8 +267,8 @@ static char *get_text(LEX *lex)
{
#ifdef USE_MB
int l;
- if (use_mb(default_charset_info) &&
- (l = my_ismbchar(default_charset_info,
+ if (use_mb(system_charset_info) &&
+ (l = my_ismbchar(system_charset_info,
(const char *)str, (const char *)end))) {
while (l--)
*to++ = *str++;
@@ -473,11 +473,11 @@ int yylex(void *arg)
break;
}
#if defined(USE_MB) && defined(USE_MB_IDENT)
- if (use_mb(default_charset_info))
+ if (use_mb(system_charset_info))
{
- if (my_ismbhead(default_charset_info, yyGetLast()))
+ if (my_ismbhead(system_charset_info, yyGetLast()))
{
- int l = my_ismbchar(default_charset_info,
+ int l = my_ismbchar(system_charset_info,
(const char *)lex->ptr-1,
(const char *)lex->end_of_query);
if (l == 0) {
@@ -489,10 +489,10 @@ int yylex(void *arg)
while (state_map[c=yyGet()] == STATE_IDENT ||
state_map[c] == STATE_NUMBER_IDENT)
{
- if (my_ismbhead(default_charset_info, c))
+ if (my_ismbhead(system_charset_info, c))
{
int l;
- if ((l = my_ismbchar(default_charset_info,
+ if ((l = my_ismbchar(system_charset_info,
(const char *)lex->ptr-1,
(const char *)lex->end_of_query)) == 0)
break;
@@ -535,7 +535,7 @@ int yylex(void *arg)
return((int) c);
case STATE_NUMBER_IDENT: // number or ident which num-start
- while (isdigit((c = yyGet()))) ;
+ while (my_isdigit(system_charset_info,(c = yyGet()))) ;
if (state_map[c] != STATE_IDENT)
{ // Can't be identifier
state=STATE_INT_OR_REAL;
@@ -544,12 +544,13 @@ int yylex(void *arg)
if (c == 'e' || c == 'E')
{
// The following test is written this way to allow numbers of type 1e1
- if (isdigit(yyPeek()) || (c=(yyGet())) == '+' || c == '-')
+ if (my_isdigit(system_charset_info,yyPeek()) ||
+ (c=(yyGet())) == '+' || c == '-')
{ // Allow 1E+10
- if (isdigit(yyPeek())) // Number must have digit after sign
+ if (my_isdigit(system_charset_info,yyPeek())) // Number must have digit after sign
{
yySkip();
- while (isdigit(yyGet())) ;
+ while (my_isdigit(system_charset_info,yyGet())) ;
yylval->lex_str=get_token(lex,yyLength());
return(FLOAT_NUM);
}
@@ -559,7 +560,7 @@ int yylex(void *arg)
else if (c == 'x' && (lex->ptr - lex->tok_start) == 2 &&
lex->tok_start[0] == '0' )
{ // Varbinary
- while (isxdigit((c = yyGet()))) ;
+ while (my_isxdigit(system_charset_info,(c = yyGet()))) ;
if ((lex->ptr - lex->tok_start) >= 4 && state_map[c] != STATE_IDENT)
{
yylval->lex_str=get_token(lex,yyLength());
@@ -573,11 +574,11 @@ int yylex(void *arg)
// fall through
case STATE_IDENT_START: // Incomplete ident
#if defined(USE_MB) && defined(USE_MB_IDENT)
- if (use_mb(default_charset_info))
+ if (use_mb(system_charset_info))
{
- if (my_ismbhead(default_charset_info, yyGetLast()))
+ if (my_ismbhead(system_charset_info, yyGetLast()))
{
- int l = my_ismbchar(default_charset_info,
+ int l = my_ismbchar(system_charset_info,
(const char *)lex->ptr-1,
(const char *)lex->end_of_query);
if (l == 0)
@@ -590,10 +591,10 @@ int yylex(void *arg)
while (state_map[c=yyGet()] == STATE_IDENT ||
state_map[c] == STATE_NUMBER_IDENT)
{
- if (my_ismbhead(default_charset_info, c))
+ if (my_ismbhead(system_charset_info, c))
{
int l;
- if ((l = my_ismbchar(default_charset_info,
+ if ((l = my_ismbchar(system_charset_info,
(const char *)lex->ptr-1,
(const char *)lex->end_of_query)) == 0)
break;
@@ -620,15 +621,15 @@ int yylex(void *arg)
case STATE_USER_VARIABLE_DELIMITER:
lex->tok_start=lex->ptr; // Skip first `
#ifdef USE_MB
- if (use_mb(default_charset_info))
+ if (use_mb(system_charset_info))
{
while ((c=yyGet()) && state_map[c] != STATE_USER_VARIABLE_DELIMITER &&
c != (uchar) NAMES_SEP_CHAR)
{
- if (my_ismbhead(default_charset_info, c))
+ if (my_ismbhead(system_charset_info, c))
{
int l;
- if ((l = my_ismbchar(default_charset_info,
+ if ((l = my_ismbchar(system_charset_info,
(const char *)lex->ptr-1,
(const char *)lex->end_of_query)) == 0)
break;
@@ -653,17 +654,18 @@ int yylex(void *arg)
if (prev_state == STATE_OPERATOR_OR_IDENT)
{
if (c == '-' && yyPeek() == '-' &&
- (isspace(yyPeek2()) || iscntrl(yyPeek2())))
+ (my_isspace(system_charset_info,yyPeek2()) ||
+ my_iscntrl(system_charset_info,yyPeek2())))
state=STATE_COMMENT;
else
state= STATE_CHAR; // Must be operator
break;
}
- if (!isdigit(c=yyGet()) || yyPeek() == 'x')
+ if (!my_isdigit(system_charset_info,c=yyGet()) || yyPeek() == 'x')
{
if (c != '.')
{
- if (c == '-' && isspace(yyPeek()))
+ if (c == '-' && my_isspace(system_charset_info,yyPeek()))
state=STATE_COMMENT;
else
state = STATE_CHAR; // Return sign as single char
@@ -671,9 +673,9 @@ int yylex(void *arg)
}
yyUnget(); // Fix for next loop
}
- while (isdigit(c=yyGet())) ; // Incomplete real or int number
+ while (my_isdigit(system_charset_info,c=yyGet())) ; // Incomplete real or int number
if ((c == 'e' || c == 'E') &&
- (yyPeek() == '+' || yyPeek() == '-' || isdigit(yyPeek())))
+ (yyPeek() == '+' || yyPeek() == '-' || my_isdigit(system_charset_info,yyPeek())))
{ // Real number
yyUnget();
c= '.'; // Fool next test
@@ -687,19 +689,19 @@ int yylex(void *arg)
}
// fall through
case STATE_REAL: // Incomplete real number
- while (isdigit(c = yyGet())) ;
+ while (my_isdigit(system_charset_info,c = yyGet())) ;
if (c == 'e' || c == 'E')
{
c = yyGet();
if (c == '-' || c == '+')
c = yyGet(); // Skip sign
- if (!isdigit(c))
+ if (!my_isdigit(system_charset_info,c))
{ // No digit after sign
state= STATE_CHAR;
break;
}
- while (isdigit(yyGet())) ;
+ while (my_isdigit(system_charset_info,yyGet())) ;
yylval->lex_str=get_token(lex,yyLength());
return(FLOAT_NUM);
}
@@ -708,7 +710,7 @@ int yylex(void *arg)
case STATE_HEX_NUMBER: // Found x'hexstring'
yyGet(); // Skip '
- while (isxdigit((c = yyGet()))) ;
+ while (my_isxdigit(system_charset_info,(c = yyGet()))) ;
length=(lex->ptr - lex->tok_start); // Length of hexnum+3
if (!(length & 1) || c != '\'')
{
@@ -788,7 +790,7 @@ int yylex(void *arg)
ulong version=MYSQL_VERSION_ID;
yySkip();
state=STATE_START;
- if (isdigit(yyPeek()))
+ if (my_isdigit(system_charset_info,yyPeek()))
{ // Version number
version=strtol((char*) lex->ptr,(char**) &lex->ptr,10);
}
@@ -843,7 +845,7 @@ int yylex(void *arg)
// Actually real shouldn't start
// with . but allow them anyhow
case STATE_REAL_OR_POINT:
- if (isdigit(yyPeek()))
+ if (my_isdigit(system_charset_info,yyPeek()))
state = STATE_REAL; // Real
else
{
@@ -870,7 +872,7 @@ int yylex(void *arg)
return((int) '@');
case STATE_HOSTNAME: // end '@' of user@hostname
for (c=yyGet() ;
- isalnum(c) || c == '.' || c == '_' || c == '$';
+ my_isalnum(system_charset_info,c) || c == '.' || c == '_' || c == '$';
c= yyGet()) ;
yylval->lex_str=get_token(lex,yyLength());
return(LEX_HOSTNAME);
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 6961ab8c712..53422b050a3 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -103,7 +103,7 @@ typedef struct st_lex_master_info
} LEX_MASTER_INFO;
-enum sub_select_type {UNSPECIFIED_TYPE,UNION_TYPE, INTERSECT_TYPE, EXCEPT_TYPE, NOT_A_SELECT};
+enum sub_select_type {UNSPECIFIED_TYPE,UNION_TYPE, INTERSECT_TYPE, EXCEPT_TYPE, NOT_A_SELECT, DERIVED_TABLE_TYPE};
/* The state of the lex parsing for selects */
@@ -122,7 +122,7 @@ typedef struct st_select_lex {
List<Item_func_match> ftfunc_list;
uint in_sum_expr, sort_default;
bool create_refs, braces;
- st_select_lex *next;
+ st_select_lex *next, *prev;
} SELECT_LEX;
@@ -143,7 +143,7 @@ public:
typedef struct st_lex {
uint yylineno,yytoklen; /* Simulate lex */
LEX_YYSTYPE yylval;
- SELECT_LEX select_lex, *select;
+ SELECT_LEX select_lex, *select, *last_select;
uchar *ptr,*tok_start,*tok_end,*end_of_query;
char *length,*dec,*change,*name;
char *backup_dir; /* For RESTORE/BACKUP */
@@ -187,7 +187,7 @@ typedef struct st_lex {
uint grant,grant_tot_col,which_columns, union_option, mqh;
thr_lock_type lock_option;
bool drop_primary,drop_if_exists,local_file;
- bool in_comment,ignore_space,verbose,simple_alter, option_type;
+ bool in_comment,ignore_space,verbose,simple_alter, option_type, derived_tables;
uint slave_thd_opt;
} LEX;
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index dc89888a1a5..06431124356 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -273,7 +273,8 @@ static void free_user(struct user_conn *uc)
void init_max_user_conn(void)
{
- (void) hash_init(&hash_user_connections,max_connections,0,0,
+ (void) hash_init(&hash_user_connections,system_charset_info,max_connections,
+ 0,0,
(hash_get_key) get_key_conn, (void (*)(void*)) free_user,
0);
}
@@ -700,7 +701,8 @@ pthread_handler_decl(handle_bootstrap,arg)
while (fgets(buff, thd->net.max_packet, file))
{
uint length=(uint) strlen(buff);
- while (length && (isspace(buff[length-1]) || buff[length-1] == ';'))
+ while (length && (my_isspace(system_charset_info, buff[length-1]) ||
+ buff[length-1] == ';'))
length--;
buff[length]=0;
thd->current_tablenr=0;
@@ -926,13 +928,14 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
{
packet_length--; // Remove end null
/* Remove garage at start and end of query */
- while (isspace(packet[0]) && packet_length > 0)
+ while (my_isspace(system_charset_info,packet[0]) && packet_length > 0)
{
packet++;
packet_length--;
}
char *pos=packet+packet_length; // Point at end null
- while (packet_length > 0 && (pos[-1] == ';' || isspace(pos[-1])))
+ while (packet_length > 0 &&
+ (pos[-1] == ';' || my_isspace(system_charset_info,pos[-1])))
{
pos--;
packet_length--;
@@ -1233,6 +1236,14 @@ mysql_execute_command(void)
Skip if we are in the slave thread, some table rules have been given
and the table list says the query should not be replicated
*/
+ if (lex->derived_tables)
+ {
+ for (TABLE_LIST *cursor= tables;
+ cursor;
+ cursor=cursor->next)
+ if (cursor->derived && mysql_derived(thd,lex,(SELECT_LEX *)cursor->derived,cursor))
+ DBUG_VOID_RETURN;
+ }
if ((lex->select_lex.next && create_total_list(thd,lex,&tables)) ||
(table_rules_on && tables && thd->slave_thread &&
!tables_ok(thd,tables)))
@@ -2271,7 +2282,8 @@ mysql_execute_command(void)
if (user->password.str &&
(strcmp(thd->user,user->user.str) ||
user->host.str &&
- my_strcasecmp(user->host.str, thd->host_or_ip)))
+ my_strcasecmp(system_charset_info,
+ user->host.str, thd->host_or_ip)))
{
if (check_access(thd, UPDATE_ACL, "mysql",0,1))
goto error;
@@ -2656,7 +2668,7 @@ mysql_init_query(THD *thd)
thd->lex.value_list.empty();
thd->lex.select_lex.table_list.elements=0;
thd->free_list=0; thd->lex.union_option=0;
- thd->lex.select = &thd->lex.select_lex;
+ thd->lex.select = thd->lex.last_select = &thd->lex.select_lex;
thd->lex.select_lex.table_list.first=0;
thd->lex.select_lex.table_list.next= (byte**) &thd->lex.select_lex.table_list.first;
thd->lex.select_lex.next=0;
@@ -2683,7 +2695,7 @@ mysql_init_select(LEX *lex)
select_lex->order_list.next= (byte**) &select_lex->order_list.first;
select_lex->group_list.first=0;
select_lex->group_list.next= (byte**) &select_lex->group_list.first;
- select_lex->next = (SELECT_LEX *)NULL;
+ select_lex->next = select_lex->prev = (SELECT_LEX *)NULL;
}
bool
@@ -2692,8 +2704,9 @@ mysql_new_select(LEX *lex)
SELECT_LEX *select_lex = (SELECT_LEX *) lex->thd->calloc(sizeof(SELECT_LEX));
if (!select_lex)
return 1;
+ lex->select=lex->last_select;
lex->select->next=select_lex;
- lex->select=select_lex;
+ lex->select=lex->last_select=select_lex;
select_lex->table_list.next= (byte**) &select_lex->table_list.first;
select_lex->item_list.empty();
select_lex->when_list.empty();
@@ -3052,8 +3065,8 @@ static void remove_escape(char *name)
#ifdef USE_MB
int l;
/* if ((l = ismbchar(name, name+MBMAXLEN))) { Wei He: I think it's wrong */
- if (use_mb(default_charset_info) &&
- (l = my_ismbchar(default_charset_info, name, strend)))
+ if (use_mb(system_charset_info) &&
+ (l = my_ismbchar(system_charset_info, name, strend)))
{
while (l--)
*to++ = *name++;
@@ -3107,7 +3120,7 @@ TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias,
DBUG_RETURN(0); // End of memory
alias_str= alias ? alias->str : table->table.str;
if (table->table.length > NAME_LEN ||
- check_table_name(table->table.str,table->table.length) ||
+ (table->table.length && check_table_name(table->table.str,table->table.length)) ||
table->db.str && check_db_name(table->db.str))
{
net_printf(&thd->net,ER_WRONG_TABLE_NAME,table->table.str);
@@ -3139,13 +3152,14 @@ TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias,
ptr->name=alias_str;
if (lower_case_table_names)
{
- casedn_str(ptr->db);
- casedn_str(table->table.str);
+ my_casedn_str(system_charset_info,ptr->db);
+ my_casedn_str(system_charset_info,table->table.str);
}
ptr->real_name=table->table.str;
ptr->real_name_length=table->table.length;
ptr->lock_type=flags;
ptr->updating=updating;
+ ptr->derived=(SELECT_LEX *)table->sel;
if (use_index)
ptr->use_index=(List<String> *) thd->memdup((gptr) use_index,
sizeof(*use_index));
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 18f256d9edb..2abefe0aac5 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -5892,8 +5892,10 @@ static int remove_dup_with_hash_index(THD *thd, TABLE *table,
(uint) (field_count*sizeof(*field_lengths)),
NullS))
DBUG_RETURN(1);
- if (hash_init(&hash, (uint) file->records, 0, key_length,
- (hash_get_key) 0, 0, 0))
+
+ // BAR TODO: this must be fixed to use charset from "table" argument
+ if (hash_init(&hash, default_charset_info, (uint) file->records, 0,
+ key_length,(hash_get_key) 0, 0, 0))
{
my_free((char*) key_buffer,MYF(0));
DBUG_RETURN(1);
@@ -7057,9 +7059,8 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
item_list.push_back(new Item_null());
if (tab->ref.key_parts)
{
- item_list.push_back(new Item_string(table->key_info[tab->ref.key].name,
- strlen(table->key_info[tab->ref.key].name)));
- item_list.push_back(new Item_int((int32) tab->ref.key_length));
+ item_list.push_back(new Item_string(table->key_info[tab->ref.key].name,strlen(table->key_info[tab->ref.key].name)));
+ item_list.push_back(new Item_int((int) tab->ref.key_length));
for (store_key **ref=tab->ref.key_copy ; *ref ; ref++)
{
if (tmp2.length())
@@ -7071,13 +7072,13 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
else if (tab->type == JT_NEXT)
{
item_list.push_back(new Item_string(table->key_info[tab->index].name,strlen(table->key_info[tab->index].name)));
- item_list.push_back(new Item_int((int32) table->key_info[tab->index].key_length));
+ item_list.push_back(new Item_int((int) table->key_info[tab->index].key_length));
item_list.push_back(new Item_null());
}
else if (tab->select && tab->select->quick)
{
item_list.push_back(new Item_string(table->key_info[tab->select->quick->index].name,strlen(table->key_info[tab->select->quick->index].name)));
- item_list.push_back(new Item_int((int32) tab->select->quick->max_used_key_length));
+ item_list.push_back(new Item_int((int) tab->select->quick->max_used_key_length));
item_list.push_back(new Item_null());
}
else
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index 8d7df7eb8e9..0aa0c643ba9 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -209,7 +209,7 @@ mysql_find_files(THD *thd,List<char> *files, const char *db,const char *path,
else
{
// Return only .frm files which aren't temp files.
- if (my_strcasecmp(ext=fn_ext(file->name),reg_ext) ||
+ if (my_strcasecmp(system_charset_info, ext=fn_ext(file->name),reg_ext) ||
is_prefix(file->name,tmp_file_prefix))
continue;
*ext=0;
@@ -217,7 +217,7 @@ mysql_find_files(THD *thd,List<char> *files, const char *db,const char *path,
{
if (lower_case_table_names)
{
- if (wild_case_compare(file->name,wild))
+ if (wild_case_compare(system_charset_info,file->name,wild))
continue;
}
else if (wild_compare(file->name,wild))
@@ -472,7 +472,8 @@ mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild,
String *packet= &thd->packet;
for (ptr=table->field; (field= *ptr) ; ptr++)
{
- if (!wild || !wild[0] || !wild_case_compare(field->field_name,wild))
+ if (!wild || !wild[0] ||
+ !wild_case_compare(system_charset_info, field->field_name,wild))
{
#ifdef NOT_USED
if (thd->col_access & TABLE_ACLS ||
@@ -744,7 +745,8 @@ mysqld_list_fields(THD *thd, TABLE_LIST *table_list, const char *wild)
Field **ptr,*field;
for (ptr=table->field ; (field= *ptr); ptr++)
{
- if (!wild || !wild[0] || !wild_case_compare(field->field_name,wild))
+ if (!wild || !wild[0] ||
+ !wild_case_compare(system_charset_info, field->field_name,wild))
field_list.push_back(new Item_field(field));
}
restore_record(table,2); // Get empty record
@@ -880,11 +882,17 @@ store_create_info(THD *thd, TABLE *table, String *packet)
packet->append("UNIQUE ", 7);
else if (key_info->flags & HA_FULLTEXT)
packet->append("FULLTEXT ", 9);
+ else if (key_info->flags & HA_SPATIAL)
+ packet->append("SPATIAL ", 8);
packet->append("KEY ", 4);
if (!found_primary)
append_identifier(thd,packet,key_info->name);
+ // +BAR: send USING only in non-default case: non-spatial rtree
+ if((key_info->key_alg == HA_KEY_ALG_RTREE) && !(key_info->flags & HA_SPATIAL))
+ packet->append(" USING RTREE",12);
+
packet->append(" (", 2);
for (uint j=0 ; j < key_info->key_parts ; j++,key_part++)
diff --git a/sql/sql_string.cc b/sql/sql_string.cc
index 8fe84947ac2..cf9e9f62507 100644
--- a/sql/sql_string.cc
+++ b/sql/sql_string.cc
@@ -234,7 +234,7 @@ bool String::fill(uint32 max_length,char fill_char)
void String::strip_sp()
{
- while (str_length && isspace(Ptr[str_length-1]))
+ while (str_length && my_isspace(str_charset,Ptr[str_length-1]))
str_length--;
}
@@ -296,10 +296,10 @@ uint32 String::numchars()
register uint32 n=0,mblen;
register const char *mbstr=Ptr;
register const char *end=mbstr+str_length;
- if (use_mb(default_charset_info))
+ if (use_mb(str_charset))
{
while (mbstr < end) {
- if ((mblen=my_ismbchar(default_charset_info, mbstr,end))) mbstr+=mblen;
+ if ((mblen=my_ismbchar(str_charset, mbstr,end))) mbstr+=mblen;
else ++mbstr;
++n;
}
@@ -316,11 +316,11 @@ int String::charpos(int i,uint32 offset)
register uint32 mblen;
register const char *mbstr=Ptr+offset;
register const char *end=Ptr+str_length;
- if (use_mb(default_charset_info))
+ if (use_mb(str_charset))
{
if (i<=0) return i;
while (i && mbstr < end) {
- if ((mblen=my_ismbchar(default_charset_info, mbstr,end))) mbstr+=mblen;
+ if ((mblen=my_ismbchar(str_charset, mbstr,end))) mbstr+=mblen;
else ++mbstr;
--i;
}
@@ -380,12 +380,14 @@ int String::strstr_case(const String &s,uint32 offset)
skipp:
while (str != end)
{
- if (my_sort_order[*str++] == my_sort_order[*search])
+ if (str_charset->sort_order[*str++] == str_charset->sort_order[*search])
{
register char *i,*j;
i=(char*) str; j=(char*) search+1;
while (j != search_end)
- if (my_sort_order[*i++] != my_sort_order[*j++]) goto skipp;
+ if (str_charset->sort_order[*i++] !=
+ str_charset->sort_order[*j++])
+ goto skipp;
return (int) (str-Ptr) -1;
}
}
@@ -459,6 +461,44 @@ bool String::replace(uint32 offset,uint32 arg_length,const String &to)
return FALSE;
}
+// added by Holyfoot for "geometry" needs
+int String::reserve(uint32 space_needed, uint32 grow_by)
+{
+ if (Alloced_length < str_length + space_needed)
+ {
+ if (realloc(Alloced_length + max(space_needed, grow_by) - 1))
+ return TRUE;
+ }
+ return FALSE;
+}
+
+void String::qs_append(const char *str)
+{
+ int len = strlen(str);
+ memcpy(Ptr + str_length, str, len + 1);
+ str_length += len;
+}
+
+void String::qs_append(double d)
+{
+ char *buff = Ptr + str_length;
+ sprintf(buff,"%.14g", d);
+ str_length += strlen(buff);
+}
+
+void String::qs_append(double *d)
+{
+ double ld;
+ float8get(ld, d);
+ qs_append(ld);
+}
+
+void String::qs_append(const char &c)
+{
+ Ptr[str_length] = c;
+ str_length += sizeof(c);
+}
+
int sortcmp(const String *x,const String *y)
{
@@ -467,15 +507,15 @@ int sortcmp(const String *x,const String *y)
uint32 x_len=x->length(),y_len=y->length(),len=min(x_len,y_len);
#ifdef USE_STRCOLL
- if (use_strcoll(default_charset_info))
+ if (use_strcoll(x->str_charset))
{
#ifndef CMP_ENDSPACE
- while (x_len && isspace(s[x_len-1]))
+ while (x_len && my_isspace(x->str_charset,s[x_len-1]))
x_len--;
- while (y_len && isspace(t[y_len-1]))
+ while (y_len && my_isspace(x->str_charset,t[y_len-1]))
y_len--;
#endif
- return my_strnncoll(default_charset_info,
+ return my_strnncoll(x->str_charset,
(unsigned char *)s,x_len,(unsigned char *)t,y_len);
}
else
@@ -485,9 +525,10 @@ int sortcmp(const String *x,const String *y)
y_len-=len;
while (len--)
{
- if (my_sort_order[(uchar) *s++] != my_sort_order[(uchar) *t++])
- return ((int) my_sort_order[(uchar) s[-1]] -
- (int) my_sort_order[(uchar) t[-1]]);
+ if (x->str_charset->sort_order[(uchar) *s++] !=
+ x->str_charset->sort_order[(uchar) *t++])
+ return ((int) x->str_charset->sort_order[(uchar) s[-1]] -
+ (int) x->str_charset->sort_order[(uchar) t[-1]]);
}
#ifndef CMP_ENDSPACE
/* Don't compare end space in strings */
@@ -496,14 +537,14 @@ int sortcmp(const String *x,const String *y)
{
const char *end=t+y_len;
for (; t != end ; t++)
- if (!isspace(*t))
+ if (!my_isspace(x->str_charset,*t))
return -1;
}
else
{
const char *end=s+x_len;
for (; s != end ; s++)
- if (!isspace(*s))
+ if (!my_isspace(x->str_charset,*s))
return 1;
}
return 0;
@@ -551,11 +592,10 @@ String *copy_if_not_alloced(String *to,String *from,uint32 from_length)
/* Make it easier to handle different charactersets */
#ifdef USE_MB
-#define INC_PTR(A,B) A+=((use_mb_flag && \
- my_ismbchar(default_charset_info,A,B)) ? \
- my_ismbchar(default_charset_info,A,B) : 1)
+#define INC_PTR(cs,A,B) A+=((use_mb_flag && \
+ my_ismbchar(cs,A,B)) ? my_ismbchar(cs,A,B) : 1)
#else
-#define INC_PTR(A,B) A++
+#define INC_PTR(cs,A,B) A++
#endif
/*
@@ -566,18 +606,18 @@ String *copy_if_not_alloced(String *to,String *from,uint32 from_length)
*/
#ifdef LIKE_CMP_TOUPPER
-#define likeconv(A) (uchar) toupper(A)
+#define likeconv(s,A) (uchar) my_toupper(s,A)
#else
-#define likeconv(A) (uchar) my_sort_order[(uchar) (A)]
+#define likeconv(s,A) (uchar) (s)->sort_order[(uchar) (A)]
#endif
-int wild_case_compare(const char *str,const char *str_end,
+int wild_case_compare(CHARSET_INFO *cs, const char *str,const char *str_end,
const char *wildstr,const char *wildend,
char escape)
{
int result= -1; // Not found, using wildcards
#ifdef USE_MB
- bool use_mb_flag=use_mb(default_charset_info);
+ bool use_mb_flag=use_mb(cs);
#endif
while (wildstr != wildend)
{
@@ -588,7 +628,7 @@ int wild_case_compare(const char *str,const char *str_end,
#ifdef USE_MB
int l;
if (use_mb_flag &&
- (l = my_ismbchar(default_charset_info, wildstr, wildend)))
+ (l = my_ismbchar(cs, wildstr, wildend)))
{
if (str+l > str_end || memcmp(str, wildstr, l) != 0)
return 1;
@@ -597,7 +637,7 @@ int wild_case_compare(const char *str,const char *str_end,
}
else
#endif
- if (str == str_end || likeconv(*wildstr++) != likeconv(*str++))
+ if (str == str_end || likeconv(cs,*wildstr++) != likeconv(cs,*str++))
return(1); // No match
if (wildstr == wildend)
return (str != str_end); // Match if both are at end
@@ -609,7 +649,7 @@ int wild_case_compare(const char *str,const char *str_end,
{
if (str == str_end) // Skip one char if possible
return (result);
- INC_PTR(str,str_end);
+ INC_PTR(cs,str,str_end);
} while (++wildstr < wildend && *wildstr == wild_one);
if (wildstr == wildend)
break;
@@ -626,7 +666,7 @@ int wild_case_compare(const char *str,const char *str_end,
{
if (str == str_end)
return (-1);
- INC_PTR(str,str_end);
+ INC_PTR(cs,str,str_end);
continue;
}
break; // Not a wild character
@@ -644,10 +684,10 @@ int wild_case_compare(const char *str,const char *str_end,
int mblen;
LINT_INIT(mblen);
if (use_mb_flag)
- mblen = my_ismbchar(default_charset_info, wildstr, wildend);
+ mblen = my_ismbchar(cs, wildstr, wildend);
#endif
- INC_PTR(wildstr,wildend); // This is compared trough cmp
- cmp=likeconv(cmp);
+ INC_PTR(cs,wildstr,wildend); // This is compared trough cmp
+ cmp=likeconv(cs,cmp);
do
{
#ifdef USE_MB
@@ -665,26 +705,26 @@ int wild_case_compare(const char *str,const char *str_end,
break;
}
}
- else if (!my_ismbchar(default_charset_info, str, str_end) &&
- likeconv(*str) == cmp)
+ else if (!my_ismbchar(cs, str, str_end) &&
+ likeconv(cs,*str) == cmp)
{
str++;
break;
}
- INC_PTR(str, str_end);
+ INC_PTR(cs,str, str_end);
}
}
else
{
#endif /* USE_MB */
- while (str != str_end && likeconv(*str) != cmp)
+ while (str != str_end && likeconv(cs,*str) != cmp)
str++;
if (str++ == str_end) return (-1);
#ifdef USE_MB
}
#endif
{
- int tmp=wild_case_compare(str,str_end,wildstr,wildend,escape);
+ int tmp=wild_case_compare(cs,str,str_end,wildstr,wildend,escape);
if (tmp <= 0)
return (tmp);
}
@@ -701,7 +741,7 @@ int wild_case_compare(String &match,String &wild, char escape)
DBUG_ENTER("wild_case_compare");
DBUG_PRINT("enter",("match='%s', wild='%s', escape='%c'"
,match.ptr(),wild.ptr(),escape));
- DBUG_RETURN(wild_case_compare(match.ptr(),match.ptr()+match.length(),
+ DBUG_RETURN(wild_case_compare(match.str_charset,match.ptr(),match.ptr()+match.length(),
wild.ptr(), wild.ptr()+wild.length(),escape));
}
@@ -805,3 +845,5 @@ int wild_compare(String &match,String &wild, char escape)
DBUG_RETURN(wild_compare(match.ptr(),match.ptr()+match.length(),
wild.ptr(), wild.ptr()+wild.length(),escape));
}
+
+
diff --git a/sql/sql_string.h b/sql/sql_string.h
index ad7455ecbf1..9bf13b93628 100644
--- a/sql/sql_string.h
+++ b/sql/sql_string.h
@@ -36,26 +36,46 @@ class String
char *Ptr;
uint32 str_length,Alloced_length;
bool alloced;
+ CHARSET_INFO *str_charset;
public:
String()
- { Ptr=0; str_length=Alloced_length=0; alloced=0; }
+ {
+ Ptr=0; str_length=Alloced_length=0; alloced=0;
+ str_charset=default_charset_info;
+ }
String(uint32 length_arg)
- { alloced=0; Alloced_length=0; (void) real_alloc(length_arg); }
+ {
+ alloced=0; Alloced_length=0; (void) real_alloc(length_arg);
+ str_charset=default_charset_info;
+ }
String(const char *str)
- { Ptr=(char*) str; str_length=(uint) strlen(str); Alloced_length=0; alloced=0;}
+ {
+ Ptr=(char*) str; str_length=(uint) strlen(str); Alloced_length=0; alloced=0;
+ str_charset=default_charset_info;
+ }
String(const char *str,uint32 len)
- { Ptr=(char*) str; str_length=len; Alloced_length=0; alloced=0;}
+ {
+ Ptr=(char*) str; str_length=len; Alloced_length=0; alloced=0;
+ str_charset=default_charset_info;
+ }
String(char *str,uint32 len)
- { Ptr=(char*) str; Alloced_length=str_length=len; alloced=0;}
+ {
+ Ptr=(char*) str; Alloced_length=str_length=len; alloced=0;
+ str_charset=default_charset_info;
+ }
String(const String &str)
- { Ptr=str.Ptr ; str_length=str.str_length ;
- Alloced_length=str.Alloced_length; alloced=0; }
-
+ {
+ Ptr=str.Ptr ; str_length=str.str_length ;
+ Alloced_length=str.Alloced_length; alloced=0;
+ str_charset=str.str_charset;
+ }
static void *operator new(size_t size) { return (void*) sql_alloc((uint) size); }
static void operator delete(void *ptr_arg,size_t size) /*lint -e715 */
{ sql_element_free(ptr_arg); }
~String() { free(); }
+ inline void set_charset(CHARSET_INFO *charset) { str_charset=charset; }
+ inline CHARSET_INFO *charset() const { return str_charset; }
inline uint32 length() const { return str_length;}
inline uint32 alloced_length() const { return Alloced_length;}
inline char& operator [] (uint32 i) const { return Ptr[i]; }
@@ -179,8 +199,8 @@ public:
}
bool fill(uint32 max_length,char fill);
void strip_sp();
- inline void caseup() { ::caseup(Ptr,str_length); }
- inline void casedn() { ::casedn(Ptr,str_length); }
+ inline void caseup() { my_caseup(str_charset,Ptr,str_length); }
+ inline void casedn() { my_casedn(str_charset,Ptr,str_length); }
friend int sortcmp(const String *a,const String *b);
friend int stringcmp(const String *a,const String *b);
friend String *copy_if_not_alloced(String *a,String *b,uint32 arg_length);
@@ -188,4 +208,49 @@ public:
friend int wild_compare(String &match,String &wild,char escape);
uint32 numchars();
int charpos(int i,uint32 offset=0);
+
+// added by Holyfoot for "geometry" needs
+ int reserve(uint32 space_needed)
+ {
+ return realloc(str_length + space_needed);
+ }
+ int reserve(uint32 space_needed, uint32 grow_by);
+
+// these append operations do NOT check alloced memory
+// q_*** methods writes values of parameters itself
+// qs_*** methods writes string representation of value
+ void q_append(const char &c)
+ {
+ Ptr[str_length++] = c;
+ }
+ void q_append(const uint32 &n)
+ {
+ int4store(Ptr + str_length, n);
+ str_length += 4;
+ }
+ void q_append(double d)
+ {
+ float8store(Ptr + str_length, d);
+ str_length += 8;
+ }
+ void q_append(double *d)
+ {
+ float8store(Ptr + str_length, *d);
+ str_length += 8;
+ }
+ void q_append(const char *data, uint32 data_len)
+ {
+ memcpy(Ptr + str_length, data, data_len);
+ str_length += data_len;
+ }
+
+ void WriteAtPosition(int position, uint32 value)
+ {
+ int4store(Ptr + position,value);
+ }
+
+ void qs_append(const char *str);
+ void qs_append(double d);
+ void qs_append(double *d);
+ void qs_append(const char &c);
};
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index dcbfd709f97..b88db94c767 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -302,7 +302,9 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
null_fields++;
while ((dup_field=it2++) != sql_field)
{
- if (my_strcasecmp(sql_field->field_name, dup_field->field_name) == 0)
+ if (my_strcasecmp(system_charset_info,
+ sql_field->field_name,
+ dup_field->field_name) == 0)
{
my_error(ER_DUP_FIELDNAME,MYF(0),sql_field->field_name);
DBUG_RETURN(-1);
@@ -438,8 +440,21 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
uint key_length=0;
key_part_spec *column;
- key_info->flags= (key->type == Key::MULTIPLE) ? 0 :
- (key->type == Key::FULLTEXT) ? HA_FULLTEXT : HA_NOSAME;
+ switch(key->type){
+ case Key::MULTIPLE:
+ key_info->flags = 0;
+ break;
+ case Key::FULLTEXT:
+ key_info->flags = HA_FULLTEXT;
+ break;
+ case Key::SPATIAL:
+ key_info->flags = HA_SPATIAL;
+ break;
+ default:
+ key_info->flags = HA_NOSAME;
+ }
+
+ key_info->key_alg = key->alg;
key_info->key_parts=(uint8) key->columns.elements;
key_info->key_part=key_part_info;
key_info->usable_key_parts= key_number;
@@ -454,14 +469,40 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
DBUG_RETURN(-1);
}
}
-
+ /*
+ Make SPATIAL to be RTREE by default
+ SPATIAL only on BLOB or at least BINARY, this
+ actually should be replaced by special GEOM type
+ in near future when new frm file is ready
+ checking for proper key parts number:
+ */
+
+ if(key_info->flags == HA_SPATIAL){
+ if(key_info->key_parts!=1){
+ my_printf_error(ER_WRONG_ARGUMENTS,
+ ER(ER_WRONG_ARGUMENTS),MYF(0),"SPATIAL INDEX");
+ DBUG_RETURN(-1);
+ }
+ }else
+ {
+ if(key_info->key_alg == HA_KEY_ALG_RTREE){
+ if((key_info->key_parts&1)==1){
+ my_printf_error(ER_WRONG_ARGUMENTS,
+ ER(ER_WRONG_ARGUMENTS),MYF(0),"RTREE INDEX");
+ DBUG_RETURN(-1);
+ }
+ }
+ }
+
List_iterator<key_part_spec> cols(key->columns);
for (uint column_nr=0 ; (column=cols++) ; column_nr++)
{
it.rewind();
field=0;
while ((sql_field=it++) &&
- my_strcasecmp(column->field_name,sql_field->field_name))
+ my_strcasecmp(system_charset_info,
+ column->field_name,
+ sql_field->field_name))
field++;
if (!sql_field)
{
@@ -482,6 +523,14 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
{
if (key->type == Key::FULLTEXT)
column->length=1; /* ft-code ignores it anyway :-) */
+ else if (key->type == Key::SPATIAL)
+ {
+ /*
+ BAR: 4 is: (Xmin,Xmax,Ymin,Ymax), this is for 2D case
+ Lately we'll extend this code to support more dimensions
+ */
+ column->length=4*sizeof(double);
+ }
else
{
my_printf_error(ER_BLOB_KEY_WITHOUT_LENGTH,
@@ -684,7 +733,7 @@ static bool
check_if_keyname_exists(const char *name, KEY *start, KEY *end)
{
for (KEY *key=start ; key != end ; key++)
- if (!my_strcasecmp(name,key->name))
+ if (!my_strcasecmp(system_charset_info,name,key->name))
return 1;
return 0;
}
@@ -1245,9 +1294,9 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
strmov(new_name_buff,new_name);
fn_same(new_name_buff,table_name,3);
if (lower_case_table_names)
- casedn_str(new_name);
+ my_casedn_str(system_charset_info,new_name);
if ((lower_case_table_names &&
- !my_strcasecmp(new_name_buff,table_name)) ||
+ !my_strcasecmp(system_charset_info, new_name_buff,table_name)) ||
(!lower_case_table_names &&
!strcmp(new_name_buff,table_name)))
new_name=table_name; // No. Make later check easier
@@ -1358,7 +1407,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
while ((drop=drop_it++))
{
if (drop->type == Alter_drop::COLUMN &&
- !my_strcasecmp(field->field_name, drop->name))
+ !my_strcasecmp(system_charset_info,field->field_name, drop->name))
{
/* Reset auto_increment value if it was dropped */
if (MTYP_TYPENR(field->unireg_check) == Field::NEXT_NUMBER &&
@@ -1379,7 +1428,8 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
def_it.rewind();
while ((def=def_it++))
{
- if (def->change && !my_strcasecmp(field->field_name, def->change))
+ if (def->change &&
+ !my_strcasecmp(system_charset_info,field->field_name, def->change))
break;
}
if (def)
@@ -1403,7 +1453,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
Alter_column *alter;
while ((alter=alter_it++))
{
- if (!my_strcasecmp(field->field_name, alter->name))
+ if (!my_strcasecmp(system_charset_info,field->field_name, alter->name))
break;
}
if (alter)
@@ -1437,7 +1487,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
find_it.rewind();
while ((find=find_it++)) // Add new columns
{
- if (!my_strcasecmp(def->after, find->field_name))
+ if (!my_strcasecmp(system_charset_info,def->after, find->field_name))
break;
}
if (!find)
@@ -1483,7 +1533,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
while ((drop=drop_it++))
{
if (drop->type == Alter_drop::KEY &&
- !my_strcasecmp(key_name, drop->name))
+ !my_strcasecmp(system_charset_info,key_name, drop->name))
break;
}
if (drop)
@@ -1505,10 +1555,11 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
{
if (cfield->change)
{
- if (!my_strcasecmp(key_part_name, cfield->change))
+ if (!my_strcasecmp(system_charset_info,key_part_name, cfield->change))
break;
}
- else if (!my_strcasecmp(key_part_name, cfield->field_name))
+ else if (!my_strcasecmp(system_charset_info,
+ key_part_name, cfield->field_name))
break;
}
if (!cfield)
@@ -1526,11 +1577,14 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
key_part_length));
}
if (key_parts.elements)
- key_list.push_back(new Key(key_info->flags & HA_NOSAME ?
- (!my_strcasecmp(key_name, "PRIMARY") ?
+ key_list.push_back(new Key(key_info->flags & HA_SPATIAL ? Key::SPATIAL :
+ (key_info->flags & HA_NOSAME ?
+ (!my_strcasecmp(system_charset_info,
+ key_name, "PRIMARY") ?
Key::PRIMARY : Key::UNIQUE) :
(key_info->flags & HA_FULLTEXT ?
- Key::FULLTEXT : Key::MULTIPLE),
+ Key::FULLTEXT : Key::MULTIPLE)),
+ key_info->key_alg,
key_name,key_parts));
}
key_it.rewind();
diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc
index 9493f969802..f44fa3b7321 100644
--- a/sql/sql_udf.cc
+++ b/sql/sql_udf.cc
@@ -127,7 +127,8 @@ void udf_init()
init_sql_alloc(&mem, 1024,0);
THD *new_thd = new THD;
if (!new_thd ||
- hash_init(&udf_hash,32,0,0,get_hash_key, NULL, HASH_CASE_INSENSITIVE))
+ hash_init(&udf_hash,system_charset_info,
+ 32,0,0,get_hash_key, NULL, HASH_CASE_INSENSITIVE))
{
sql_print_error("Can't allocate memory for udf structures");
hash_free(&udf_hash);
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 8012768e508..18b8e5bb824 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -54,6 +54,7 @@ inline Item *or_or_concat(Item* A, Item* B)
List<Item> *item_list;
List<String> *string_list;
Key::Keytype key_type;
+ enum ha_key_alg key_alg;
enum db_type db_type;
enum row_type row_type;
enum ha_rkey_function ha_rkey_mode;
@@ -156,6 +157,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token BOOL_SYM
%token BOOLEAN_SYM
%token BOTH
+%token BTREE_SYM
%token BY
%token CACHE_SYM
%token CASCADE
@@ -202,6 +204,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token GREATEST_SYM
%token GROUP
%token HAVING
+%token HASH_SYM
%token HEAP_SYM
%token HEX_NUM
%token HIGH_PRIORITY
@@ -295,10 +298,12 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token ROWS_SYM
%token ROW_FORMAT_SYM
%token ROW_SYM
+%token RTREE_SYM
%token SET
%token SERIALIZABLE_SYM
%token SESSION_SYM
%token SHUTDOWN
+%token SPATIAL_SYM
%token SQL_CACHE_SYM
%token SQL_NO_CACHE_SYM
%token SSL_SYM
@@ -349,6 +354,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token ENUM
%token FAST_SYM
%token FLOAT_SYM
+%token GEOMETRY_SYM
%token INT_SYM
%token LIMIT
%token LONGBLOB
@@ -406,6 +412,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token FORMAT_SYM
%token FOR_SYM
%token FROM_UNIXTIME
+%token GEOMCOLLFROMTEXT
+%token GEOMFROMTEXT
+%token GEOMETRYCOLLECTION
%token GROUP_UNIQUE_USERS
%token HOUR_MINUTE_SYM
%token HOUR_SECOND_SYM
@@ -417,6 +426,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token INTERVAL_SYM
%token LAST_INSERT_ID
%token LEFT
+%token LINEFROMTEXT
+%token LINESTRING
%token LOCATE
%token MAKE_SET_SYM
%token MINUTE_SECOND_SYM
@@ -424,8 +435,17 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token MODE_SYM
%token MODIFY_SYM
%token MONTH_SYM
+%token MLINEFROMTEXT
+%token MPOINTFROMTEXT
+%token MPOLYFROMTEXT
+%token MULTILINESTRING
+%token MULTIPOINT
+%token MULTIPOLYGON
%token NOW_SYM
%token PASSWORD
+%token POINTFROMTEXT
+%token POLYFROMTEXT
+%token POLYGON
%token POSITION_SYM
%token PROCEDURE
%token RAND
@@ -532,6 +552,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%type <key_type>
key_type opt_unique_or_fulltext
+%type <key_alg>
+ key_alg opt_btree_or_rtree
+
%type <string_list>
key_usage_list
@@ -736,21 +759,22 @@ create:
}
create2
- | CREATE opt_unique_or_fulltext INDEX ident ON table_ident
+ | CREATE opt_unique_or_fulltext INDEX ident key_alg ON table_ident
{
LEX *lex=Lex;
lex->sql_command= SQLCOM_CREATE_INDEX;
- if (!add_table_to_list($6,NULL,1))
+ if (!add_table_to_list($7,NULL,1))
YYABORT;
lex->create_list.empty();
lex->key_list.empty();
lex->col_list.empty();
lex->change=NullS;
}
- '(' key_list ')'
+ '(' key_list ')'
{
LEX *lex=Lex;
- lex->key_list.push_back(new Key($2,$4.str,lex->col_list));
+
+ lex->key_list.push_back(new Key($2,$5,$4.str,lex->col_list));
lex->col_list.empty();
}
| CREATE DATABASE opt_if_not_exists ident
@@ -897,10 +921,10 @@ field_list_item:
{
Lex->col_list.empty(); /* Alloced by sql_alloc */
}
- | key_type opt_ident '(' key_list ')'
+ | key_type opt_ident key_alg '(' key_list ')'
{
LEX *lex=Lex;
- lex->key_list.push_back(new Key($1,$2,lex->col_list));
+ lex->key_list.push_back(new Key($1,$3,$2,lex->col_list));
lex->col_list.empty(); /* Alloced by sql_alloc */
}
| opt_constraint FOREIGN KEY_SYM opt_ident '(' key_list ')' references
@@ -965,6 +989,8 @@ type:
$$=FIELD_TYPE_TINY_BLOB; }
| BLOB_SYM { Lex->type|=BINARY_FLAG;
$$=FIELD_TYPE_BLOB; }
+ | GEOMETRY_SYM { Lex->type|=BINARY_FLAG;
+ $$=FIELD_TYPE_GEOMETRY; }
| MEDIUMBLOB { Lex->type|=BINARY_FLAG;
$$=FIELD_TYPE_MEDIUM_BLOB; }
| LONGBLOB { Lex->type|=BINARY_FLAG;
@@ -1106,6 +1132,8 @@ key_type:
| key_or_index { $$= Key::MULTIPLE; }
| FULLTEXT_SYM { $$= Key::FULLTEXT; }
| FULLTEXT_SYM key_or_index { $$= Key::FULLTEXT; }
+ | SPATIAL_SYM { $$= Key::SPATIAL; }
+ | SPATIAL_SYM key_or_index { $$= Key::SPATIAL; }
| opt_constraint UNIQUE_SYM { $$= Key::UNIQUE; }
| opt_constraint UNIQUE_SYM key_or_index { $$= Key::UNIQUE; }
@@ -1122,6 +1150,16 @@ opt_unique_or_fulltext:
/* empty */ { $$= Key::MULTIPLE; }
| UNIQUE_SYM { $$= Key::UNIQUE; }
| FULLTEXT_SYM { $$= Key::FULLTEXT; }
+ | SPATIAL_SYM { $$= Key::SPATIAL; }
+
+key_alg:
+ /* empty */ { $$= HA_KEY_ALG_BTREE; }
+ | USING opt_btree_or_rtree { $$= $2 }
+
+opt_btree_or_rtree:
+ BTREE_SYM { $$= HA_KEY_ALG_BTREE; }
+ | RTREE_SYM { $$= HA_KEY_ALG_RTREE; }
+ | HASH_SYM { $$= HA_KEY_ALG_HASH; }
key_list:
key_list ',' key_part order_dir { Lex->col_list.push_back($3); }
@@ -1655,6 +1693,20 @@ simple_expr:
| CASE_SYM opt_expr WHEN_SYM when_list opt_else END
{ $$= new Item_func_case(* $4, $2, $5 ); }
| CONVERT_SYM '(' expr ',' cast_type ')' { $$= create_func_cast($3, $5); }
+ | CONVERT_SYM '(' expr USING IDENT ')'
+ {
+ CHARSET_INFO *cs=find_compiled_charset_by_name($5.str);
+ if (!cs)
+ {
+ net_printf(&current_thd->net,ER_UNKNOWN_CHARACTER_SET,$5);
+ YYABORT;
+ }
+ $$= new Item_func_conv_charset($3,cs);
+ }
+ | CONVERT_SYM '(' expr ',' expr ',' expr ')'
+ {
+ $$= new Item_func_conv_charset3($3,$5,$7);
+ }
| FUNC_ARG0 '(' ')'
{ $$= ((Item*(*)(void))($1.symbol->create_func))();}
| FUNC_ARG1 '(' expr ')'
@@ -1731,6 +1783,14 @@ simple_expr:
}
| FIELD_FUNC '(' expr ',' expr_list ')'
{ $$= new Item_func_field($3, *$5); }
+ | GEOMFROMTEXT '(' expr ')'
+ { $$= new Item_func_geometry_from_text($3) }
+ | GEOMFROMTEXT '(' expr ',' expr ')'
+ { $$= new Item_func_geometry_from_text($3) }
+ | GEOMETRYCOLLECTION '(' expr_list ')'
+ { $$= new Item_func_spatial_collection(* $3,
+ Geometry::wkbGeometryCollection,
+ Geometry::wkbPoint); }
| HOUR_SYM '(' expr ')'
{ $$= new Item_func_hour($3); }
| IF '(' expr ',' expr ',' expr ')'
@@ -1755,18 +1815,50 @@ simple_expr:
}
| LEFT '(' expr ',' expr ')'
{ $$= new Item_func_left($3,$5); }
+ | LINESTRING '(' expr_list ')'
+ { $$= new Item_func_spatial_collection(* $3,
+ Geometry::wkbLineString, Geometry::wkbPoint); }
| LOCATE '(' expr ',' expr ')'
{ $$= new Item_func_locate($5,$3); }
| LOCATE '(' expr ',' expr ',' expr ')'
{ $$= new Item_func_locate($5,$3,$7); }
- | GREATEST_SYM '(' expr ',' expr_list ')'
+ | GEOMCOLLFROMTEXT '(' expr ')'
+ { $$= new Item_func_geometry_from_text($3) }
+ | GEOMCOLLFROMTEXT '(' expr ',' expr ')'
+ { $$= new Item_func_geometry_from_text($3) }
+ | GREATEST_SYM '(' expr ',' expr_list ')'
{ $5->push_front($3); $$= new Item_func_max(*$5); }
| LEAST_SYM '(' expr ',' expr_list ')'
{ $5->push_front($3); $$= new Item_func_min(*$5); }
+ | LINEFROMTEXT '(' expr ')'
+ { $$= new Item_func_geometry_from_text($3) }
+ | LINEFROMTEXT '(' expr ',' expr ')'
+ { $$= new Item_func_geometry_from_text($3) }
| MINUTE_SYM '(' expr ')'
{ $$= new Item_func_minute($3); }
| MONTH_SYM '(' expr ')'
{ $$= new Item_func_month($3); }
+ | MULTILINESTRING '(' expr_list ')'
+ { $$= new Item_func_spatial_collection(* $3,
+ Geometry::wkbMultiLineString, Geometry::wkbLineString); }
+ | MLINEFROMTEXT '(' expr ')'
+ { $$= new Item_func_geometry_from_text($3) }
+ | MLINEFROMTEXT '(' expr ',' expr ')'
+ { $$= new Item_func_geometry_from_text($3) }
+ | MPOINTFROMTEXT '(' expr ')'
+ { $$= new Item_func_geometry_from_text($3) }
+ | MPOINTFROMTEXT '(' expr ',' expr ')'
+ { $$= new Item_func_geometry_from_text($3) }
+ | MPOLYFROMTEXT '(' expr ')'
+ { $$= new Item_func_geometry_from_text($3) }
+ | MPOLYFROMTEXT '(' expr ',' expr ')'
+ { $$= new Item_func_geometry_from_text($3) }
+ | MULTIPOINT '(' expr_list ')'
+ { $$= new Item_func_spatial_collection(* $3,
+ Geometry::wkbMultiPoint, Geometry::wkbPoint); }
+ | MULTIPOLYGON '(' expr_list ')'
+ { $$= new Item_func_spatial_collection(* $3,
+ Geometry::wkbMultiPolygon, Geometry::wkbPolygon ); }
| NOW_SYM optional_braces
{ $$= new Item_func_now(); current_thd->safe_to_cache_query=0;}
| NOW_SYM '(' expr ')'
@@ -1775,6 +1867,17 @@ simple_expr:
{
$$= new Item_func_password($3);
}
+ | POINTFROMTEXT '(' expr ')'
+ { $$= new Item_func_geometry_from_text($3) }
+ | POINTFROMTEXT '(' expr ',' expr ')'
+ { $$= new Item_func_geometry_from_text($3) }
+ | POLYFROMTEXT '(' expr ')'
+ { $$= new Item_func_geometry_from_text($3) }
+ | POLYFROMTEXT '(' expr ',' expr ')'
+ { $$= new Item_func_geometry_from_text($3) }
+ | POLYGON '(' expr_list ')'
+ { $$= new Item_func_spatial_collection(* $3,
+ Geometry::wkbPolygon, Geometry::wkbLineString); }
| POSITION_SYM '(' no_in_expr IN_SYM expr ')'
{ $$ = new Item_func_locate($5,$3); }
| RAND '(' expr ')'
@@ -2049,6 +2152,30 @@ join_table:
}
| '{' ident join_table LEFT OUTER JOIN_SYM join_table ON expr '}'
{ add_join_on($7,$9); $7->outer_join|=JOIN_TYPE_LEFT; $$=$7; }
+ | '(' SELECT_SYM select_part3 ')' opt_table_alias
+ {
+ LEX *lex=Lex;
+ lex->select=lex->select->prev;
+ if (!($$=add_table_to_list(new Table_ident(Lex->last_select),$5,0,TL_UNLOCK)))
+ YYABORT;
+ }
+
+select_part3:
+ {
+ LEX *lex=Lex;
+ lex->derived_tables=true;
+ SELECT_LEX *tmp=lex->select;
+ if (lex->select->linkage == NOT_A_SELECT || mysql_new_select(lex))
+ YYABORT;
+ mysql_init_select(lex);
+ lex->select->linkage=DERIVED_TABLE_TYPE;
+ lex->select->prev=tmp;
+ }
+ select_options select_item_list select_intoto
+
+select_intoto:
+ limit_clause {}
+ | select_from
opt_outer:
/* empty */ {}
@@ -3608,7 +3735,8 @@ column_list_id:
LEX *lex=Lex;
while ((point=iter++))
{
- if (!my_strcasecmp(point->column.ptr(),new_str->ptr()))
+ if (!my_strcasecmp(system_charset_info,
+ point->column.ptr(), new_str->ptr()))
break;
}
lex->grant_tot_col|= lex->which_columns;
diff --git a/sql/structs.h b/sql/structs.h
index 2250ea784f2..978a523df7f 100644
--- a/sql/structs.h
+++ b/sql/structs.h
@@ -64,6 +64,7 @@ typedef struct st_key_part_info { /* Info about a key part */
typedef struct st_key {
uint key_length; /* Tot length of key */
uint flags; /* dupp key and pack flags */
+ enum ha_key_alg key_alg; /* +BAR Algorithm BTREE or RTREE */
uint key_parts; /* How many key_parts */
uint extra_length;
uint usable_key_parts; /* Should normally be = key_parts */
diff --git a/sql/table.cc b/sql/table.cc
index 315f8bacf34..122357a1fb1 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -155,7 +155,9 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
{
keyinfo->flags= ((uint) strpos[0]) ^ HA_NOSAME;
keyinfo->key_length= (uint) uint2korr(strpos+1);
- keyinfo->key_parts= (uint) strpos[3]; strpos+=4;
+ keyinfo->key_parts= (uint) strpos[3];
+ strpos+=4;
+
keyinfo->key_part= key_part;
keyinfo->rec_per_key= rec_per_key;
for (j=keyinfo->key_parts ; j-- ; key_part++)
@@ -327,6 +329,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
use_hash= outparam->fields >= MAX_FIELDS_BEFORE_HASH;
if (use_hash)
use_hash= !hash_init(&outparam->name_hash,
+ system_charset_info,
outparam->fields,0,0,
(hash_get_key) get_field_name,0,
HASH_CASE_INSENSITIVE);
@@ -405,6 +408,26 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
}
}
+ keyinfo->key_alg=HA_KEY_ALG_BTREE; // BAR : btree by default
+
+#define BAR_DIRTY_HACK
+#ifdef BAR_DIRTY_HACK
+ // BAR FIXME: Dirty hack while waiting for new .frm format
+ switch(keyinfo->name[0]){
+ case 'R':
+ keyinfo->key_alg=HA_KEY_ALG_RTREE;
+ break;
+ case 'S':
+ keyinfo->key_alg = HA_KEY_ALG_RTREE;
+ keyinfo->flags |= HA_SPATIAL;
+ break;
+ case 'B':
+ default:
+ keyinfo->key_alg=HA_KEY_ALG_BTREE;
+ break;
+ }
+#endif
+
for (i=0 ; i < keyinfo->key_parts ; key_part++,i++)
{
if (new_field_pack_flag <= 1)
@@ -1058,9 +1081,10 @@ bool check_db_name(const char *name)
while (*name)
{
#if defined(USE_MB) && defined(USE_MB_IDENT)
- if (use_mb(default_charset_info))
+ if (use_mb(system_charset_info))
{
- int len=my_ismbchar(default_charset_info, name, name+MBMAXLEN);
+ int len=my_ismbchar(system_charset_info, name,
+ name+system_charset_info->mbmaxlen);
if (len)
{
name += len;
@@ -1090,9 +1114,9 @@ bool check_table_name(const char *name, uint length)
while (name != end)
{
#if defined(USE_MB) && defined(USE_MB_IDENT)
- if (use_mb(default_charset_info))
+ if (use_mb(system_charset_info))
{
- int len=my_ismbchar(default_charset_info, name, end);
+ int len=my_ismbchar(system_charset_info, name, end);
if (len)
{
name += len;
@@ -1112,9 +1136,10 @@ bool check_column_name(const char *name)
while (*name)
{
#if defined(USE_MB) && defined(USE_MB_IDENT)
- if (use_mb(default_charset_info))
+ if (use_mb(system_charset_info))
{
- int len=my_ismbchar(default_charset_info, name, name+MBMAXLEN);
+ int len=my_ismbchar(system_charset_info, name,
+ name+system_charset_info->mbmaxlen);
if (len)
{
name += len;
diff --git a/sql/table.h b/sql/table.h
index 209333c24b7..59cb28038bf 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -150,6 +150,7 @@ typedef struct st_table_list {
bool straight; /* optimize with prev table */
bool updating; /* for replicate-do/ignore table */
bool shared; /* Used twice in union */
+ void *derived;
} TABLE_LIST;
typedef struct st_changed_table_list {
diff --git a/sql/time.cc b/sql/time.cc
index aab886648e3..2a791ccc30e 100644
--- a/sql/time.cc
+++ b/sql/time.cc
@@ -268,13 +268,13 @@ void find_date(string pos,uint *vek,uint flag)
DBUG_PRINT("enter",("pos: '%s' flag: %d",pos,flag));
bzero((char*) vek,sizeof(int)*4);
- while (*pos && !isdigit(*pos))
+ while (*pos && !my_isdigit(system_charset_info,*pos))
pos++;
length=(uint) strlen(pos);
for (uint i=0 ; i< 3; i++)
{
start=pos; value=0;
- while (isdigit(pos[0]) &&
+ while (my_isdigit(system_charset_info,pos[0]) &&
((pos-start) < 2 || ((pos-start) < 4 && length >= 8 &&
!(flag & 3))))
{
@@ -282,7 +282,8 @@ void find_date(string pos,uint *vek,uint flag)
pos++;
}
vek[flag & 3]=value; flag>>=2;
- while (*pos && (ispunct(*pos) || isspace(*pos)))
+ while (*pos && (my_ispunct(system_charset_info,*pos) ||
+ my_isspace(system_charset_info,*pos)))
pos++;
}
DBUG_PRINT("exit",("year: %d month: %d day: %d",vek[0],vek[1],vek[2]));
@@ -434,7 +435,8 @@ str_to_TIME(const char *str, uint length, TIME *l_time,bool fuzzy_date)
DBUG_ENTER("str_to_TIME");
DBUG_PRINT("enter",("str: %.*s",length,str));
- for (; str != end && !isdigit(*str) ; str++) ; // Skip garbage
+ // Skip garbage
+ for (; str != end && !my_isdigit(system_charset_info, *str) ; str++) ;
if (str == end)
DBUG_RETURN(TIMESTAMP_NONE);
/*
@@ -442,14 +444,14 @@ str_to_TIME(const char *str, uint length, TIME *l_time,bool fuzzy_date)
** If length= 8 or >= 14 then year is of format YYYY.
(YYYY-MM-DD, YYYYMMDD, YYYYYMMDDHHMMSS)
*/
- for (pos=str; pos != end && isdigit(*pos) ; pos++) ;
+ for (pos=str; pos != end && my_isdigit(system_charset_info,*pos) ; pos++) ;
digits= (uint) (pos-str);
year_length= (digits == 4 || digits == 8 || digits >= 14) ? 4 : 2;
field_length=year_length-1;
- for (i=0 ; i < 6 && str != end && isdigit(*str) ; i++)
+ for (i=0 ; i < 6 && str != end && my_isdigit(system_charset_info,*str) ; i++)
{
uint tmp_value=(uint) (uchar) (*str++ - '0');
- while (str != end && isdigit(str[0]) && field_length--)
+ while (str != end && my_isdigit(system_charset_info,str[0]) && field_length--)
{
tmp_value=tmp_value*10 + (uint) (uchar) (*str - '0');
str++;
@@ -459,10 +461,12 @@ str_to_TIME(const char *str, uint length, TIME *l_time,bool fuzzy_date)
str++; // ISO8601: CCYYMMDDThhmmss
else if ( i != 5 ) // Skip inter-field delimiters
{
- while (str != end && (ispunct(*str) || isspace(*str)))
+ while (str != end &&
+ (my_ispunct(system_charset_info,*str) ||
+ my_isspace(system_charset_info,*str)))
{
// Only allow space between days and hours
- if (isspace(*str) && i != 2)
+ if (my_isspace(system_charset_info,*str) && i != 2)
DBUG_RETURN(TIMESTAMP_NONE);
str++;
}
@@ -470,12 +474,13 @@ str_to_TIME(const char *str, uint length, TIME *l_time,bool fuzzy_date)
field_length=1; // Rest fields can only be 2
}
/* Handle second fractions */
- if (i == 6 && (uint) (end-str) >= 2 && *str == '.' && isdigit(str[1]))
+ if (i == 6 && (uint) (end-str) >= 2 && *str == '.' &&
+ my_isdigit(system_charset_info,str[1]))
{
str++;
uint tmp_value=(uint) (uchar) (*str - '0');
field_length=3;
- while (str++ != end && isdigit(str[0]) && field_length--)
+ while (str++ != end && my_isdigit(system_charset_info,str[0]) && field_length--)
tmp_value=tmp_value*10 + (uint) (uchar) (*str - '0');
date[6]=tmp_value;
}
@@ -498,7 +503,7 @@ str_to_TIME(const char *str, uint length, TIME *l_time,bool fuzzy_date)
{
for ( ; str != end ; str++)
{
- if (!isspace(*str))
+ if (!my_isspace(system_charset_info,*str))
{
current_thd->cuted_fields++;
break;
@@ -559,7 +564,8 @@ bool str_to_time(const char *str,uint length,TIME *l_time)
uint state;
l_time->neg=0;
- for (; str != end && !isdigit(*str) && *str != '-' ; str++)
+ for (; str != end &&
+ !my_isdigit(system_charset_info,*str) && *str != '-' ; str++)
length--;
if (str != end && *str == '-')
{
@@ -578,7 +584,7 @@ bool str_to_time(const char *str,uint length,TIME *l_time)
}
/* Not a timestamp. Try to get this as a DAYS_TO_SECOND string */
- for (value=0; str != end && isdigit(*str) ; str++)
+ for (value=0; str != end && my_isdigit(system_charset_info,*str) ; str++)
value=value*10L + (long) (*str - '0');
if (*str == ' ')
@@ -589,14 +595,16 @@ bool str_to_time(const char *str,uint length,TIME *l_time)
LINT_INIT(state);
found_days=found_hours=0;
- if ((uint) (end-str) > 1 && (*str == ' ' && isdigit(str[1])))
+ if ((uint) (end-str) > 1 && (*str == ' ' &&
+ my_isdigit(system_charset_info,str[1])))
{ // days !
date[0]=value;
state=1; // Assume next is hours
found_days=1;
str++; // Skip space;
}
- else if ((end-str) > 1 && *str == ':' && isdigit(str[1]))
+ else if ((end-str) > 1 && *str == ':' &&
+ my_isdigit(system_charset_info,str[1]))
{
date[0]=0; // Assume we found hours
date[1]=value;
@@ -618,10 +626,11 @@ bool str_to_time(const char *str,uint length,TIME *l_time)
/* Read hours, minutes and seconds */
for (;;)
{
- for (value=0; str != end && isdigit(*str) ; str++)
+ for (value=0; str != end && my_isdigit(system_charset_info,*str) ; str++)
value=value*10L + (long) (*str - '0');
date[state++]=value;
- if (state == 4 || (end-str) < 2 || *str != ':' || !isdigit(str[1]))
+ if (state == 4 || (end-str) < 2 || *str != ':' ||
+ !my_isdigit(system_charset_info,str[1]))
break;
str++; // Skip ':'
}
@@ -641,11 +650,13 @@ bool str_to_time(const char *str,uint length,TIME *l_time)
fractional:
/* Get fractional second part */
- if ((end-str) >= 2 && *str == '.' && isdigit(str[1]))
+ if ((end-str) >= 2 && *str == '.' && my_isdigit(system_charset_info,str[1]))
{
uint field_length=3;
str++; value=(uint) (uchar) (*str - '0');
- while (++str != end && isdigit(str[0]) && field_length--)
+ while (++str != end &&
+ my_isdigit(system_charset_info,str[0]) &&
+ field_length--)
value=value*10 + (uint) (uchar) (*str - '0');
date[4]=value;
}
@@ -670,7 +681,7 @@ bool str_to_time(const char *str,uint length,TIME *l_time)
{
do
{
- if (!isspace(*str))
+ if (!my_isspace(system_charset_info,*str))
{
current_thd->cuted_fields++;
break;