diff options
Diffstat (limited to 'sql')
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(¤t_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; |