diff options
Diffstat (limited to 'sql')
175 files changed, 20410 insertions, 5658 deletions
diff --git a/sql/Makefile.am b/sql/Makefile.am index 28abf407f3f..09fedd393c2 100644 --- a/sql/Makefile.am +++ b/sql/Makefile.am @@ -46,7 +46,7 @@ mysqld_LDADD = @MYSQLD_EXTRA_LDFLAGS@ \ $(LDADD) $(CXXLDFLAGS) $(WRAPLIBS) @LIBDL@ @openssl_libs@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \ item_strfunc.h item_timefunc.h item_uniq.h \ - item_create.h mysql_priv.h \ + item_create.h item_subselect.h mysql_priv.h \ procedure.h sql_class.h sql_lex.h sql_list.h \ sql_manager.h sql_map.h sql_string.h unireg.h \ field.h handler.h \ @@ -56,17 +56,19 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \ sql_select.h structs.h table.h sql_udf.h hash_filo.h\ lex.h lex_symbol.h sql_acl.h sql_crypt.h \ log_event.h mini_client.h sql_repl.h slave.h \ - stacktrace.h sql_sort.h sql_cache.h set_var.h + stacktrace.h sql_sort.h sql_cache.h set_var.h \ + spatial.h gstream.h mysqld_SOURCES = sql_lex.cc sql_handler.cc \ item.cc item_sum.cc item_buff.cc item_func.cc \ item_cmpfunc.cc item_strfunc.cc item_timefunc.cc \ - thr_malloc.cc item_create.cc \ + thr_malloc.cc item_create.cc item_subselect.cc\ field.cc key.cc sql_class.cc sql_list.cc \ net_serv.cc net_pkg.cc lock.cc my_lock.c \ sql_string.cc sql_manager.cc sql_map.cc \ mysqld.cc password.c hash_filo.cc hostname.cc \ convert.cc set_var.cc sql_parse.cc sql_yacc.yy \ sql_base.cc table.cc sql_select.cc sql_insert.cc \ + sql_prepare.cc sql_error.cc \ sql_update.cc sql_delete.cc uniques.cc sql_do.cc \ procedure.cc item_uniq.cc sql_test.cc \ log.cc log_event.cc init.cc derror.cc sql_acl.cc \ @@ -79,9 +81,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 sql_olap.cc + stacktrace.c repl_failsafe.h repl_failsafe.cc sql_olap.cc\ + gstream.cc spatial.cc sql_help.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 e4ae13d1e07..13a6dfe0392 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 e631ade16b1..f2324a0a331 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -84,7 +84,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++; @@ -92,7 +93,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' @@ -100,10 +101,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; } @@ -114,7 +115,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++; } @@ -123,10 +124,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++; } @@ -135,7 +136,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++; } @@ -144,18 +145,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; @@ -179,6 +181,8 @@ Field::Field(char *ptr_arg,uint32 length_arg,uchar *null_ptr_arg, field_length(length_arg),null_bit(null_bit_arg) { flags=null_ptr ? 0: NOT_NULL_FLAG; + comment.str= (char*) ""; + comment.length=0; } uint Field::offset() @@ -203,7 +207,7 @@ bool Field::send(THD *thd, String *packet) if (is_null()) return net_store_null(packet); char buff[MAX_FIELD_WIDTH]; - String tmp(buff,sizeof(buff)); + String tmp(buff,sizeof(buff),default_charset_info); val_str(&tmp,&tmp); CONVERT *convert; if ((convert=thd->variables.convert_set)) @@ -223,8 +227,11 @@ void Field_num::add_zerofill_and_unsigned(String &res) const void Field_num::make_field(Send_field *field) { + /* table_cache_key is not set for temp tables */ + field->db_name=table->table_cache_key ? table->table_cache_key : ""; + field->org_table_name=table->real_name; field->table_name=table_name; - field->col_name=field_name; + field->col_name=field->org_col_name=field_name; field->length=field_length; field->type=type(); field->flags=table->maybe_null ? (flags & ~NOT_NULL_FLAG) : flags; @@ -234,8 +241,11 @@ void Field_num::make_field(Send_field *field) void Field_str::make_field(Send_field *field) { + /* table_cache_key is not set for temp tables */ + field->db_name=table->table_cache_key ? table->table_cache_key : ""; + field->org_table_name=table->real_name; field->table_name=table_name; - field->col_name=field_name; + field->col_name=field->org_col_name=field_name; field->length=field_length; field->type=type(); field->flags=table->maybe_null ? (flags & ~NOT_NULL_FLAG) : flags; @@ -266,7 +276,7 @@ uint Field::fill_cache_field(CACHE_FIELD *copy) bool Field::get_date(TIME *ltime,bool fuzzydate) { char buff[40]; - String tmp(buff,sizeof(buff)),tmp2,*res; + String tmp(buff,sizeof(buff),default_charset_info),tmp2,*res; if (!(res=val_str(&tmp,&tmp2)) || str_to_TIME(res->ptr(),res->length(),ltime,fuzzydate) == TIMESTAMP_NONE) return 1; @@ -276,7 +286,7 @@ bool Field::get_date(TIME *ltime,bool fuzzydate) bool Field::get_time(TIME *ltime) { char buff[40]; - String tmp(buff,sizeof(buff)),tmp2,*res; + String tmp(buff,sizeof(buff),default_charset_info),tmp2,*res; if (!(res=val_str(&tmp,&tmp2)) || str_to_time(res->ptr(),res->length(),ltime)) return 1; @@ -290,24 +300,26 @@ void Field::store_time(TIME *ltime,timestamp_type type) char buff[25]; switch (type) { case TIMESTAMP_NONE: - store("",0); // Probably an error + store("",0,default_charset_info); // Probably an error break; case TIMESTAMP_DATE: sprintf(buff,"%04d-%02d-%02d", ltime->year,ltime->month,ltime->day); - store(buff,10); + store(buff,10,default_charset_info); break; case TIMESTAMP_FULL: sprintf(buff,"%04d-%02d-%02d %02d:%02d:%02d", ltime->year,ltime->month,ltime->day, ltime->hour,ltime->minute,ltime->second); - store(buff,19); + store(buff,19,default_charset_info); break; case TIMESTAMP_TIME: - sprintf(buff, "%02d:%02d:%02d", - ltime->hour,ltime->minute,ltime->second); - store(buff,(uint) strlen(buff)); + { + ulong length= my_sprintf(buff, (buff, "%02d:%02d:%02d", + ltime->hour,ltime->minute,ltime->second)); + store(buff,(uint) length, default_charset_info); break; } + } } @@ -324,7 +336,7 @@ bool Field::optimize_range(uint idx) void Field_decimal::reset(void) { - Field_decimal::store("0",1); + Field_decimal::store("0",1,default_charset_info); } void Field_decimal::overflow(bool negative) @@ -366,7 +378,7 @@ void Field_decimal::overflow(bool negative) } -void Field_decimal::store(const char *from,uint len) +int Field_decimal::store(const char *from, uint len, CHARSET_INFO *cs) { const char *end= from+len; /* The pointer where the field value starts (i.e., "where to write") */ @@ -377,13 +389,13 @@ void Field_decimal::store(const char *from,uint len) specified), '+' or '-' */ char sign_char=0; - /* The pointers where prezeros start and stop */ + /* The pointers where prezeros start and stop */ const char *pre_zeros_from, *pre_zeros_end; - /* The pointers where digits at the left of '.' start and stop */ + /* The pointers where digits at the left of '.' start and stop */ const char *int_digits_from, *int_digits_end; - /* The pointers where digits at the right of '.' start and stop */ + /* The pointers where digits at the right of '.' start and stop */ const char *frac_digits_from, *frac_digits_end; - /* The sign of the exponent : will be 0 (means no exponent), '+' or '-' */ + /* The sign of the exponent : will be 0 (means no exponent), '+' or '-' */ char expo_sign_char=0; uint exponent=0; // value of the exponent /* @@ -393,21 +405,21 @@ void Field_decimal::store(const char *from,uint len) const char *int_digits_tail_from; /* Number of 0 that need to be added at the left of the '.' (1E3: 3 zeros) */ uint int_digits_added_zeros; - /* - Pointer used when digits move from the right of the '.' to the left - of the '.' - */ + /* + Pointer used when digits move from the right of the '.' to the left + of the '.' + */ const char *frac_digits_head_end; - /* Number of 0 that need to be added at the right of the '.' (for 1E-3) */ + /* Number of 0 that need to be added at the right of the '.' (for 1E-3) */ uint frac_digits_added_zeros; char *pos,*tmp_left_pos,*tmp_right_pos; /* Pointers that are used as limits (begin and end of the field buffer) */ char *left_wall,*right_wall; char tmp_char; - /* - To remember if current_thd->cuted_fields has already been incremented, - to do that only once - */ + /* + To remember if current_thd->cuted_fields has already been incremented, + to do that only once + */ bool is_cuted_fields_incr=0; LINT_INIT(int_digits_tail_from); @@ -417,16 +429,18 @@ void Field_decimal::store(const char *from,uint len) /* There are three steps in this function : - - parse the input string - - modify the position of digits around the decimal dot '.' - according to the exponent value (if specified) - - write the formatted number + - parse the input string + - modify the position of digits around the decimal dot '.' + according to the exponent value (if specified) + - write the formatted number */ if ((tmp_dec=dec)) tmp_dec++; - for (; from !=end && isspace(*from); from++) ; // Read spaces + /* skip pre-space */ + while (from != end && my_isspace(system_charset_info,*from)) + from++; if (from == end) { current_thd->cuted_fields++; @@ -445,11 +459,11 @@ void Field_decimal::store(const char *from,uint len) if (sign_char=='-') { Field_decimal::overflow(1); - return; + return 1; } /* - Defining this will not store "+" for unsigned decimal type even if - it is passed in numeric string. This will make some tests to fail + Defining this will not store "+" for unsigned decimal type even if + it is passed in numeric string. This will make some tests to fail */ #ifdef DONT_ALLOW_UNSIGNED_PLUS else @@ -462,13 +476,13 @@ void Field_decimal::store(const char *from,uint len) for (; from!=end && *from == '0'; from++) ; // Read prezeros pre_zeros_end=int_digits_from=from; /* Read non zero digits at the left of '.'*/ - for (; from!=end && isdigit(*from);from++) ; + for (; from != end && my_isdigit(system_charset_info, *from) ; from++) ; int_digits_end=from; if (from!=end && *from == '.') // Some '.' ? from++; frac_digits_from= from; /* Read digits at the right of '.' */ - for (;from!=end && isdigit(*from); from++) ; + for (;from!=end && my_isdigit(system_charset_info, *from); from++) ; frac_digits_end=from; // Some exponentiation symbol ? if (from != end && (*from == 'e' || *from == 'E')) @@ -484,7 +498,7 @@ void Field_decimal::store(const char *from,uint len) exponents will become small (e.g. 1e4294967296 will become 1e0, and the field will finally contain 1 instead of its max possible value). */ - for (;from!=end && isdigit(*from); from++) + for (;from!=end && my_isdigit(system_charset_info, *from); from++) { exponent=10*exponent+(*from-'0'); if (exponent>MAX_EXPONENT) @@ -501,7 +515,8 @@ void Field_decimal::store(const char *from,uint len) if (current_thd->count_cuted_fields) { - for (;from != end && isspace(*from); from++) ; // Read end spaces + // Skip end spaces + for (;from != end && my_isspace(system_charset_info, *from); from++) ; if (from != end) // If still something left, warn { current_thd->cuted_fields++; @@ -513,21 +528,21 @@ void Field_decimal::store(const char *from,uint len) Now "move" digits around the decimal dot according to the exponent value, and add necessary zeros. Examples : - - 1E+3 : needs 3 more zeros at the left of '.' (int_digits_added_zeros=3) - - 1E-3 : '1' moves at the right of '.', and 2 more zeros are needed - between '.' and '1' + - 1E+3 : needs 3 more zeros at the left of '.' (int_digits_added_zeros=3) + - 1E-3 : '1' moves at the right of '.', and 2 more zeros are needed + between '.' and '1' - 1234.5E-3 : '234' moves at the right of '.' - These moves are implemented with pointers which point at the begin - and end of each moved segment. Examples : + These moves are implemented with pointers which point at the begin + and end of each moved segment. Examples : - 1234.5E-3 : before the code below is executed, the int_digits part is - from '1' to '4' and the frac_digits part from '5' to '5'. After the code - below, the int_digits part is from '1' to '1', the frac_digits_head - part is from '2' to '4', and the frac_digits part from '5' to '5'. + from '1' to '4' and the frac_digits part from '5' to '5'. After the code + below, the int_digits part is from '1' to '1', the frac_digits_head + part is from '2' to '4', and the frac_digits part from '5' to '5'. - 1234.5E3 : before the code below is executed, the int_digits part is - from '1' to '4' and the frac_digits part from '5' to '5'. After the code - below, the int_digits part is from '1' to '4', the int_digits_tail - part is from '5' to '5', the frac_digits part is empty, and - int_digits_added_zeros=2 (to make 1234500). + from '1' to '4' and the frac_digits part from '5' to '5'. After the code + below, the int_digits part is from '1' to '4', the int_digits_tail + part is from '5' to '5', the frac_digits part is empty, and + int_digits_added_zeros=2 (to make 1234500). */ /* @@ -589,7 +604,7 @@ void Field_decimal::store(const char *from,uint len) { // too big number, change to max or min number Field_decimal::overflow(sign_char == '-'); - return; + return 1; } /* @@ -670,7 +685,7 @@ void Field_decimal::store(const char *from,uint len) { if (current_thd->count_cuted_fields && !is_cuted_fields_incr) break; // Go on below to see if we lose non zero digits - return; + return 0; } *pos++='0'; } @@ -683,7 +698,7 @@ void Field_decimal::store(const char *from,uint len) { if (!is_cuted_fields_incr) current_thd->cuted_fields++; - return; + return 0; } continue; } @@ -700,7 +715,7 @@ void Field_decimal::store(const char *from,uint len) { if (!is_cuted_fields_incr) current_thd->cuted_fields++; - return; + return 0; } continue; } @@ -709,26 +724,26 @@ void Field_decimal::store(const char *from,uint len) while (pos != right_wall) *pos++='0'; // Fill with zeros at right of '.' - + return 0; } -void Field_decimal::store(double nr) +int Field_decimal::store(double nr) { if (unsigned_flag && nr < 0) { overflow(1); - return; + return 1; } #ifdef HAVE_FINITE if (!finite(nr)) // Handle infinity as special case { overflow(nr < 0.0); - return; + return 1; } #endif - + reg4 uint i,length; char fyllchar,*to; char buff[320]; @@ -737,36 +752,43 @@ void Field_decimal::store(double nr) #ifdef HAVE_SNPRINTF_ buff[sizeof(buff)-1]=0; // Safety snprintf(buff,sizeof(buff)-1, "%.*f",(int) dec,nr); + length=(uint) strlen(buff); #else - sprintf(buff,"%.*f",dec,nr); + length=(uint) my_sprintf(buff,(buff,"%.*f",dec,nr)); #endif - length=(uint) strlen(buff); if (length > field_length) + { overflow(nr < 0.0); + return 1; + } else { to=ptr; for (i=field_length-length ; i-- > 0 ;) *to++ = fyllchar; memcpy(to,buff,length); + return 0; } } -void Field_decimal::store(longlong nr) +int Field_decimal::store(longlong nr) { if (unsigned_flag && nr < 0) { overflow(1); - return; + return 1; } char buff[22]; uint length=(uint) (longlong10_to_str(nr,buff,-10)-buff); uint int_part=field_length- (dec ? dec+1 : 0); if (length > int_part) + { overflow(test(nr < 0L)); /* purecov: inspected */ + return 1; + } else { char fyllchar = zerofill ? (char) '0' : (char) ' '; @@ -779,6 +801,7 @@ void Field_decimal::store(longlong nr) to[length]='.'; bfill(to+length+1,dec,'0'); } + return 0; } } @@ -812,7 +835,7 @@ String *Field_decimal::val_str(String *val_buffer __attribute__((unused)), if (field_length < tmp_length) // Error in data val_ptr->length(0); else - val_ptr->set((const char*) str,field_length-tmp_length); + val_ptr->set((const char*) str,field_length-tmp_length,default_charset_info); return val_ptr; } @@ -829,8 +852,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 @@ -857,8 +882,8 @@ 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++=' '; if (str == end) @@ -869,7 +894,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++; @@ -877,6 +902,7 @@ void Field_decimal::sort_string(char *to,uint length) else memcpy(to,str,(uint) (end-str)); } + void Field_decimal::sql_type(String &res) const { uint tmp=field_length; @@ -893,10 +919,11 @@ void Field_decimal::sql_type(String &res) const ** tiny int ****************************************************************************/ -void Field_tiny::store(const char *from,uint len) +int Field_tiny::store(const char *from,uint len,CHARSET_INFO *cs) { - String tmp_str(from,len); + String tmp_str(from,len,default_charset_info); long tmp= strtol(tmp_str.c_ptr(),NULL,10); + int error= 0; if (unsigned_flag) { @@ -904,14 +931,19 @@ void Field_tiny::store(const char *from,uint len) { tmp=0; /* purecov: inspected */ current_thd->cuted_fields++; /* purecov: inspected */ + error= 1; } else if (tmp > 255) { tmp= 255; current_thd->cuted_fields++; + error= 1; } else if (current_thd->count_cuted_fields && !test_if_int(from,len)) + { current_thd->cuted_fields++; + error= 1; + } } else { @@ -919,21 +951,28 @@ void Field_tiny::store(const char *from,uint len) { tmp= -128; current_thd->cuted_fields++; + error= 1; } else if (tmp >= 128) { tmp= 127; current_thd->cuted_fields++; + error= 1; } else if (current_thd->count_cuted_fields && !test_if_int(from,len)) + { current_thd->cuted_fields++; + error= 1; + } } ptr[0]= (char) tmp; + return error; } -void Field_tiny::store(double nr) +int Field_tiny::store(double nr) { + int error= 0; nr=rint(nr); if (unsigned_flag) { @@ -941,11 +980,13 @@ void Field_tiny::store(double nr) { *ptr=0; current_thd->cuted_fields++; + error= 1; } else if (nr > 255.0) { *ptr=(char) 255; current_thd->cuted_fields++; + error= 1; } else *ptr=(char) nr; @@ -956,30 +997,36 @@ void Field_tiny::store(double nr) { *ptr= (char) -128; current_thd->cuted_fields++; + error= 1; } else if (nr > 127.0) { *ptr=127; current_thd->cuted_fields++; + error= 1; } else *ptr=(char) nr; } + return error; } -void Field_tiny::store(longlong nr) +int Field_tiny::store(longlong nr) { + int error= 0; if (unsigned_flag) { if (nr < 0L) { *ptr=0; current_thd->cuted_fields++; + error= 1; } else if (nr > 255L) { *ptr= (char) 255; current_thd->cuted_fields++; + error= 1; } else *ptr=(char) nr; @@ -990,15 +1037,18 @@ void Field_tiny::store(longlong nr) { *ptr= (char) -128; current_thd->cuted_fields++; + error= 1; } else if (nr > 127L) { *ptr=127; current_thd->cuted_fields++; + error= 1; } else *ptr=(char) nr; } + return error; } @@ -1064,24 +1114,30 @@ void Field_tiny::sql_type(String &res) const // Note: Sometimes this should be fixed to use one strtol() to use // len and check for garbage after number. -void Field_short::store(const char *from,uint len) +int Field_short::store(const char *from,uint len,CHARSET_INFO *cs) { - String tmp_str(from,len); + String tmp_str(from,len,default_charset_info); long tmp= strtol(tmp_str.c_ptr(),NULL,10); + int error= 0; if (unsigned_flag) { if (tmp < 0) { tmp=0; current_thd->cuted_fields++; + error= 1; } else if (tmp > (uint16) ~0) { tmp=(uint16) ~0; current_thd->cuted_fields++; + error= 1; } else if (current_thd->count_cuted_fields && !test_if_int(from,len)) + { current_thd->cuted_fields++; + error= 1; + } } else { @@ -1089,14 +1145,19 @@ void Field_short::store(const char *from,uint len) { tmp= INT_MIN16; current_thd->cuted_fields++; + error= 1; } else if (tmp > INT_MAX16) { tmp=INT_MAX16; current_thd->cuted_fields++; + error= 1; } else if (current_thd->count_cuted_fields && !test_if_int(from,len)) + { current_thd->cuted_fields++; + error= 1; + } } #ifdef WORDS_BIGENDIAN if (table->db_low_byte_first) @@ -1106,11 +1167,13 @@ void Field_short::store(const char *from,uint len) else #endif shortstore(ptr,(short) tmp); + return error; } -void Field_short::store(double nr) +int Field_short::store(double nr) { + int error= 0; int16 res; nr=rint(nr); if (unsigned_flag) @@ -1119,11 +1182,13 @@ void Field_short::store(double nr) { res=0; current_thd->cuted_fields++; + error= 1; } else if (nr > (double) (uint16) ~0) { res=(int16) (uint16) ~0; current_thd->cuted_fields++; + error= 1; } else res=(int16) (uint16) nr; @@ -1134,11 +1199,13 @@ void Field_short::store(double nr) { res=INT_MIN16; current_thd->cuted_fields++; + error= 1; } else if (nr > (double) INT_MAX16) { res=INT_MAX16; current_thd->cuted_fields++; + error= 1; } else res=(int16) nr; @@ -1151,10 +1218,12 @@ void Field_short::store(double nr) else #endif shortstore(ptr,res); + return error; } -void Field_short::store(longlong nr) +int Field_short::store(longlong nr) { + int error= 0; int16 res; if (unsigned_flag) { @@ -1162,11 +1231,13 @@ void Field_short::store(longlong nr) { res=0; current_thd->cuted_fields++; + error= 1; } else if (nr > (longlong) (uint16) ~0) { res=(int16) (uint16) ~0; current_thd->cuted_fields++; + error= 1; } else res=(int16) (uint16) nr; @@ -1177,11 +1248,13 @@ void Field_short::store(longlong nr) { res=INT_MIN16; current_thd->cuted_fields++; + error= 1; } else if (nr > INT_MAX16) { res=INT_MAX16; current_thd->cuted_fields++; + error= 1; } else res=(int16) nr; @@ -1194,6 +1267,7 @@ void Field_short::store(longlong nr) else #endif shortstore(ptr,res); + return error; } @@ -1304,10 +1378,11 @@ void Field_short::sql_type(String &res) const // Note: Sometimes this should be fixed to use one strtol() to use // len and check for garbage after number. -void Field_medium::store(const char *from,uint len) +int Field_medium::store(const char *from,uint len,CHARSET_INFO *cs) { - String tmp_str(from,len); + String tmp_str(from,len,default_charset_info); long tmp= strtol(tmp_str.c_ptr(),NULL,10); + int error= 0; if (unsigned_flag) { @@ -1315,14 +1390,19 @@ void Field_medium::store(const char *from,uint len) { tmp=0; current_thd->cuted_fields++; + error= 1; } else if (tmp >= (long) (1L << 24)) { tmp=(long) (1L << 24)-1L; current_thd->cuted_fields++; + error= 1; } else if (current_thd->count_cuted_fields && !test_if_int(from,len)) + { current_thd->cuted_fields++; + error= 1; + } } else { @@ -1330,22 +1410,29 @@ void Field_medium::store(const char *from,uint len) { tmp= INT_MIN24; current_thd->cuted_fields++; + error= 1; } else if (tmp > INT_MAX24) { tmp=INT_MAX24; current_thd->cuted_fields++; + error= 1; } else if (current_thd->count_cuted_fields && !test_if_int(from,len)) + { current_thd->cuted_fields++; + error= 1; + } } int3store(ptr,tmp); + return error; } -void Field_medium::store(double nr) +int Field_medium::store(double nr) { + int error= 0; nr=rint(nr); if (unsigned_flag) { @@ -1353,12 +1440,14 @@ void Field_medium::store(double nr) { int3store(ptr,0); current_thd->cuted_fields++; + error= 1; } else if (nr >= (double) (long) (1L << 24)) { uint32 tmp=(uint32) (1L << 24)-1L; int3store(ptr,tmp); current_thd->cuted_fields++; + error= 1; } else int3store(ptr,(uint32) nr); @@ -1370,32 +1459,38 @@ void Field_medium::store(double nr) long tmp=(long) INT_MIN24; int3store(ptr,tmp); current_thd->cuted_fields++; + error= 1; } else if (nr > (double) INT_MAX24) { long tmp=(long) INT_MAX24; int3store(ptr,tmp); current_thd->cuted_fields++; + error= 1; } else int3store(ptr,(long) nr); } + return error; } -void Field_medium::store(longlong nr) +int Field_medium::store(longlong nr) { + int error= 0; if (unsigned_flag) { if (nr < 0L) { int3store(ptr,0); current_thd->cuted_fields++; + error= 1; } else if (nr >= (longlong) (long) (1L << 24)) { long tmp=(long) (1L << 24)-1L;; int3store(ptr,tmp); current_thd->cuted_fields++; + error= 1; } else int3store(ptr,(uint32) nr); @@ -1407,16 +1502,19 @@ void Field_medium::store(longlong nr) long tmp=(long) INT_MIN24; int3store(ptr,tmp); current_thd->cuted_fields++; + error= 1; } else if (nr > (longlong) INT_MAX24) { long tmp=(long) INT_MAX24; int3store(ptr,tmp); current_thd->cuted_fields++; + error= 1; } else int3store(ptr,(long) nr); } + return error; } @@ -1489,14 +1587,15 @@ void Field_medium::sql_type(String &res) const // Note: Sometimes this should be fixed to use one strtol() to use // len and check for garbage after number. -void Field_long::store(const char *from,uint len) +int Field_long::store(const char *from,uint len,CHARSET_INFO *cs) { - while (len && isspace(*from)) + while (len && my_isspace(system_charset_info,*from)) { len--; from++; } long tmp; - String tmp_str(from,len); + int error= 0; + String tmp_str(from,len,default_charset_info); errno=0; if (unsigned_flag) { @@ -1504,6 +1603,7 @@ void Field_long::store(const char *from,uint len) { tmp=0; // Set negative to 0 errno=ERANGE; + error= 1; } else tmp=(long) strtoul(tmp_str.c_ptr(),NULL,10); @@ -1511,7 +1611,10 @@ void Field_long::store(const char *from,uint len) else tmp=strtol(tmp_str.c_ptr(),NULL,10); if (errno || current_thd->count_cuted_fields && !test_if_int(from,len)) + { current_thd->cuted_fields++; + error= 1; + } #ifdef WORDS_BIGENDIAN if (table->db_low_byte_first) { @@ -1520,11 +1623,13 @@ void Field_long::store(const char *from,uint len) else #endif longstore(ptr,tmp); + return error; } -void Field_long::store(double nr) +int Field_long::store(double nr) { + int error= 0; int32 res; nr=rint(nr); if (unsigned_flag) @@ -1533,11 +1638,13 @@ void Field_long::store(double nr) { res=0; current_thd->cuted_fields++; + error= 1; } else if (nr > (double) (ulong) ~0L) { res=(int32) (uint32) ~0L; current_thd->cuted_fields++; + error= 1; } else res=(int32) (ulong) nr; @@ -1548,11 +1655,13 @@ void Field_long::store(double nr) { res=(int32) INT_MIN32; current_thd->cuted_fields++; + error= 1; } else if (nr > (double) INT_MAX32) { res=(int32) INT_MAX32; current_thd->cuted_fields++; + error= 1; } else res=(int32) nr; @@ -1565,11 +1674,13 @@ void Field_long::store(double nr) else #endif longstore(ptr,res); + return error; } -void Field_long::store(longlong nr) +int Field_long::store(longlong nr) { + int error= 0; int32 res; if (unsigned_flag) { @@ -1577,11 +1688,13 @@ void Field_long::store(longlong nr) { res=0; current_thd->cuted_fields++; + error= 1; } else if (nr >= (LL(1) << 32)) { res=(int32) (uint32) ~0L; current_thd->cuted_fields++; + error= 1; } else res=(int32) (uint32) nr; @@ -1592,11 +1705,13 @@ void Field_long::store(longlong nr) { res=(int32) INT_MIN32; current_thd->cuted_fields++; + error= 1; } else if (nr > (longlong) INT_MAX32) { res=(int32) INT_MAX32; current_thd->cuted_fields++; + error= 1; } else res=(int32) nr; @@ -1609,6 +1724,7 @@ void Field_long::store(longlong nr) else #endif longstore(ptr,res); + return error; } @@ -1717,14 +1833,15 @@ void Field_long::sql_type(String &res) const ** longlong int ****************************************************************************/ -void Field_longlong::store(const char *from,uint len) +int Field_longlong::store(const char *from,uint len,CHARSET_INFO *cs) { - while (len && isspace(*from)) + while (len && my_isspace(system_charset_info,*from)) { // For easy error check len--; from++; } longlong tmp; - String tmp_str(from,len); + String tmp_str(from,len,default_charset_info); + int error= 0; errno=0; if (unsigned_flag) { @@ -1732,6 +1849,7 @@ void Field_longlong::store(const char *from,uint len) { tmp=0; // Set negative to 0 errno=ERANGE; + error= 1; } else tmp=(longlong) strtoull(tmp_str.c_ptr(),NULL,10); @@ -1739,7 +1857,10 @@ void Field_longlong::store(const char *from,uint len) else tmp=strtoll(tmp_str.c_ptr(),NULL,10); if (errno || current_thd->count_cuted_fields && !test_if_int(from,len)) + { current_thd->cuted_fields++; + error= 1; + } #ifdef WORDS_BIGENDIAN if (table->db_low_byte_first) { @@ -1748,11 +1869,13 @@ void Field_longlong::store(const char *from,uint len) else #endif longlongstore(ptr,tmp); + return error; } -void Field_longlong::store(double nr) +int Field_longlong::store(double nr) { + int error= 0; longlong res; nr=rint(nr); if (unsigned_flag) @@ -1761,11 +1884,13 @@ void Field_longlong::store(double nr) { res=0; current_thd->cuted_fields++; + error= 1; } else if (nr >= (double) ~ (ulonglong) 0) { res= ~(longlong) 0; current_thd->cuted_fields++; + error= 1; } else res=(longlong) (ulonglong) nr; @@ -1776,11 +1901,13 @@ void Field_longlong::store(double nr) { res=(longlong) LONGLONG_MIN; current_thd->cuted_fields++; + error= 1; } else if (nr >= (double) LONGLONG_MAX) { res=(longlong) LONGLONG_MAX; current_thd->cuted_fields++; + error= 1; } else res=(longlong) nr; @@ -1793,10 +1920,11 @@ void Field_longlong::store(double nr) else #endif longlongstore(ptr,res); + return error; } -void Field_longlong::store(longlong nr) +int Field_longlong::store(longlong nr) { #ifdef WORDS_BIGENDIAN if (table->db_low_byte_first) @@ -1806,6 +1934,7 @@ void Field_longlong::store(longlong nr) else #endif longlongstore(ptr,nr); + return 0; } @@ -1924,35 +2053,43 @@ void Field_longlong::sql_type(String &res) const ** single precision float ****************************************************************************/ -void Field_float::store(const char *from,uint len) +int Field_float::store(const char *from,uint len,CHARSET_INFO *cs) { - String tmp_str(from,len); + String tmp_str(from,len,default_charset_info); errno=0; Field_float::store(atof(tmp_str.c_ptr())); if (errno || current_thd->count_cuted_fields && !test_if_real(from,len)) + { current_thd->cuted_fields++; + return 1; + } + return (errno) ? 1 : 0; } -void Field_float::store(double nr) +int Field_float::store(double nr) { float j; + int error= 0; if (dec < NOT_FIXED_DEC) nr=floor(nr*log_10[dec]+0.5)/log_10[dec]; // To fixed point if (unsigned_flag && nr < 0) { current_thd->cuted_fields++; nr=0; + error= 1; } if (nr < -FLT_MAX) { j= -FLT_MAX; current_thd->cuted_fields++; + error= 1; } else if (nr > FLT_MAX) { j=FLT_MAX; current_thd->cuted_fields++; + error= 1; } else j= (float) nr; @@ -1964,16 +2101,19 @@ void Field_float::store(double nr) else #endif memcpy_fixed(ptr,(byte*) &j,sizeof(j)); + return error; } -void Field_float::store(longlong nr) +int Field_float::store(longlong nr) { + int error= 0; float j= (float) nr; if (unsigned_flag && j < 0) { current_thd->cuted_fields++; j=0; + error= 1; } #ifdef WORDS_BIGENDIAN if (table->db_low_byte_first) @@ -1983,6 +2123,7 @@ void Field_float::store(longlong nr) else #endif memcpy_fixed(ptr,(byte*) &j,sizeof(j)); + return error; } @@ -2082,10 +2223,10 @@ String *Field_float::val_str(String *val_buffer, #ifdef HAVE_SNPRINTF to[to_length-1]=0; // Safety snprintf(to,to_length-1,"%.*f",dec,nr); + to=strend(to); #else - sprintf(to,"%.*f",dec,nr); + to+= my_sprintf(to,(to,"%.*f",dec,nr)); #endif - to=strend(to); #endif } #ifdef HAVE_FCONVERT @@ -2174,17 +2315,22 @@ void Field_float::sql_type(String &res) const ** double precision floating point numbers ****************************************************************************/ -void Field_double::store(const char *from,uint len) +int Field_double::store(const char *from,uint len,CHARSET_INFO *cs) { - String tmp_str(from,len); + String tmp_str(from,len,default_charset_info); errno=0; + int error= 0; double j= atof(tmp_str.c_ptr()); if (errno || current_thd->count_cuted_fields && !test_if_real(from,len)) + { current_thd->cuted_fields++; + error= 1; + } if (unsigned_flag && j < 0) { current_thd->cuted_fields++; j=0; + error= 1; } #ifdef WORDS_BIGENDIAN if (table->db_low_byte_first) @@ -2194,17 +2340,20 @@ void Field_double::store(const char *from,uint len) else #endif doublestore(ptr,j); + return error; } -void Field_double::store(double nr) +int Field_double::store(double nr) { + int error= 0; if (dec < NOT_FIXED_DEC) nr=floor(nr*log_10[dec]+0.5)/log_10[dec]; // To fixed point if (unsigned_flag && nr < 0) { current_thd->cuted_fields++; nr=0; + error= 1; } #ifdef WORDS_BIGENDIAN if (table->db_low_byte_first) @@ -2214,15 +2363,18 @@ void Field_double::store(double nr) else #endif doublestore(ptr,nr); + return error; } -void Field_double::store(longlong nr) +int Field_double::store(longlong nr) { double j= (double) nr; + int error= 0; if (unsigned_flag && j < 0) { current_thd->cuted_fields++; + error= 1; j=0; } #ifdef WORDS_BIGENDIAN @@ -2233,6 +2385,7 @@ void Field_double::store(longlong nr) else #endif doublestore(ptr,j); + return error; } @@ -2331,10 +2484,10 @@ String *Field_double::val_str(String *val_buffer, #ifdef HAVE_SNPRINTF to[to_length-1]=0; // Safety snprintf(to,to_length-1,"%.*f",dec,nr); + to=strend(to); #else - sprintf(to,"%.*f",dec,nr); + to+= my_sprintf(to,(to,"%.*f",dec,nr)); #endif - to=strend(to); #endif } #ifdef HAVE_FCONVERT @@ -2430,7 +2583,7 @@ Field_timestamp::Field_timestamp(char *ptr_arg, uint32 len_arg, } -void Field_timestamp::store(const char *from,uint len) +int Field_timestamp::store(const char *from,uint len,CHARSET_INFO *cs) { long tmp=(long) str_to_timestamp(from,len); #ifdef WORDS_BIGENDIAN @@ -2441,6 +2594,7 @@ void Field_timestamp::store(const char *from,uint len) else #endif longstore(ptr,tmp); + return 0; } void Field_timestamp::fill_and_store(char *from,uint len) @@ -2472,14 +2626,17 @@ void Field_timestamp::fill_and_store(char *from,uint len) } -void Field_timestamp::store(double nr) +int Field_timestamp::store(double nr) { + int error= 0; if (nr < 0 || nr > 99991231235959.0) { - nr=0; // Avoid overflow on buff + nr= 0; // Avoid overflow on buff current_thd->cuted_fields++; + error= 1; } - Field_timestamp::store((longlong) rint(nr)); + error|= Field_timestamp::store((longlong) rint(nr)); + return error; } @@ -2520,7 +2677,7 @@ static longlong fix_datetime(longlong nr) } -void Field_timestamp::store(longlong nr) +int Field_timestamp::store(longlong nr) { TIME l_time; time_t timestamp; @@ -2548,6 +2705,7 @@ void Field_timestamp::store(longlong nr) else #endif longstore(ptr,(uint32) timestamp); + return 0; } @@ -2744,8 +2902,10 @@ void Field_timestamp::sort_string(char *to,uint length __attribute__((unused))) void Field_timestamp::sql_type(String &res) const { - sprintf((char*) res.ptr(),"timestamp(%d)",(int) field_length); - res.length((uint) strlen(res.ptr())); + ulong length= my_sprintf((char*) res.ptr(), + ((char*) res.ptr(),"timestamp(%d)", + (int) field_length)); + res.length(length); } @@ -2769,12 +2929,16 @@ void Field_timestamp::set_time() ** Stored as a 3 byte unsigned int ****************************************************************************/ -void Field_time::store(const char *from,uint len) +int Field_time::store(const char *from,uint len,CHARSET_INFO *cs) { TIME ltime; long tmp; + int error= 0; if (str_to_time(from,len,<ime)) + { tmp=0L; + error= 1; + } else { if (ltime.month) @@ -2784,26 +2948,31 @@ void Field_time::store(const char *from,uint len) { tmp=8385959; current_thd->cuted_fields++; + error= 1; } } if (ltime.neg) tmp= -tmp; - Field_time::store((longlong) tmp); + error |= Field_time::store((longlong) tmp); + return error; } -void Field_time::store(double nr) +int Field_time::store(double nr) { long tmp; + int error= 0; if (nr > 8385959.0) { tmp=8385959L; current_thd->cuted_fields++; + error= 1; } else if (nr < -8385959.0) { tmp= -8385959L; current_thd->cuted_fields++; + error= 1; } else { @@ -2814,24 +2983,29 @@ void Field_time::store(double nr) { tmp=0; current_thd->cuted_fields++; + error= 1; } } int3store(ptr,tmp); + return error; } -void Field_time::store(longlong nr) +int Field_time::store(longlong nr) { long tmp; + int error= 0; if (nr > (longlong) 8385959L) { tmp=8385959L; current_thd->cuted_fields++; + error= 1; } else if (nr < (longlong) -8385959L) { tmp= -8385959L; current_thd->cuted_fields++; + error= 1; } else { @@ -2840,9 +3014,11 @@ void Field_time::store(longlong nr) { tmp=0; current_thd->cuted_fields++; + error= 1; } } int3store(ptr,tmp); + return error; } @@ -2868,10 +3044,11 @@ String *Field_time::val_str(String *val_buffer, tmp= -tmp; sign= "-"; } - sprintf((char*) val_buffer->ptr(),"%s%02d:%02d:%02d", - sign,(int) (tmp/10000), (int) (tmp/100 % 100), - (int) (tmp % 100)); - val_buffer->length((uint) strlen(val_buffer->ptr())); + long length= my_sprintf((char*) val_buffer->ptr(), + ((char*) val_buffer->ptr(),"%s%02d:%02d:%02d", + sign,(int) (tmp/10000), (int) (tmp/100 % 100), + (int) (tmp % 100))); + val_buffer->length(length); return val_buffer; } @@ -2909,7 +3086,7 @@ void Field_time::sort_string(char *to,uint length __attribute__((unused))) void Field_time::sql_type(String &res) const { - res.set("time",4); + res.set("time",4,default_charset_info); } /**************************************************************************** @@ -2918,16 +3095,16 @@ void Field_time::sql_type(String &res) const ** Can handle 2 byte or 4 byte years! ****************************************************************************/ -void Field_year::store(const char *from, uint len) +int Field_year::store(const char *from, uint len,CHARSET_INFO *cs) { - String tmp_str(from,len); + String tmp_str(from,len,default_charset_info); long nr= strtol(tmp_str.c_ptr(),NULL,10); if (nr < 0 || nr >= 100 && nr <= 1900 || nr > 2155) { *ptr=0; current_thd->cuted_fields++; - return; + return 1; } else if (current_thd->count_cuted_fields && !test_if_int(from,len)) current_thd->cuted_fields++; @@ -2939,23 +3116,27 @@ void Field_year::store(const char *from, uint len) nr-= 1900; } *ptr= (char) (unsigned char) nr; + return 0; } -void Field_year::store(double nr) +int Field_year::store(double nr) { if (nr < 0.0 || nr >= 2155.0) - Field_year::store((longlong) -1); + { + (void) Field_year::store((longlong) -1); + return 1; + } else - Field_year::store((longlong) nr); + return Field_year::store((longlong) nr); } -void Field_year::store(longlong nr) +int Field_year::store(longlong nr) { if (nr < 0 || nr >= 100 && nr <= 1900 || nr > 2155) { *ptr=0; current_thd->cuted_fields++; - return; + return 1; } if (nr != 0 || field_length != 4) // 0000 -> 0; 00 -> 2000 { @@ -2965,6 +3146,7 @@ void Field_year::store(longlong nr) nr-= 1900; } *ptr= (char) (unsigned char) nr; + return 0; } @@ -2995,8 +3177,9 @@ String *Field_year::val_str(String *val_buffer, void Field_year::sql_type(String &res) const { - sprintf((char*) res.ptr(),"year(%d)",(int) field_length); - res.length((uint) strlen(res.ptr())); + ulong length=my_sprintf((char*) res.ptr(), + ((char*) res.ptr(),"year(%d)",(int) field_length)); + res.length(length); } @@ -3007,12 +3190,16 @@ void Field_year::sql_type(String &res) const ** Stored as a 4 byte unsigned int ****************************************************************************/ -void Field_date::store(const char *from, uint len) +int Field_date::store(const char *from, uint len,CHARSET_INFO *cs) { TIME l_time; uint32 tmp; + int error= 0; if (str_to_TIME(from,len,&l_time,1) == TIMESTAMP_NONE) + { tmp=0; + error= 1; + } else tmp=(uint32) l_time.year*10000L + (uint32) (l_time.month*100+l_time.day); #ifdef WORDS_BIGENDIAN @@ -3023,18 +3210,21 @@ void Field_date::store(const char *from, uint len) else #endif longstore(ptr,tmp); + return error; } -void Field_date::store(double nr) +int Field_date::store(double nr) { long tmp; + int error= 0; if (nr >= 19000000000000.0 && nr <= 99991231235959.0) nr=floor(nr/1000000.0); // Timestamp to date if (nr < 0.0 || nr > 99991231.0) { tmp=0L; current_thd->cuted_fields++; + error= 1; } else tmp=(long) rint(nr); @@ -3046,18 +3236,21 @@ void Field_date::store(double nr) else #endif longstore(ptr,tmp); + return error; } -void Field_date::store(longlong nr) +int Field_date::store(longlong nr) { long tmp; + int error= 0; if (nr >= LL(19000000000000) && nr < LL(99991231235959)) nr=nr/LL(1000000); // Timestamp to date if (nr < 0 || nr > LL(99991231)) { tmp=0L; current_thd->cuted_fields++; + error= 1; } else tmp=(long) nr; @@ -3069,6 +3262,7 @@ void Field_date::store(longlong nr) else #endif longstore(ptr,tmp); + return error; } @@ -3155,7 +3349,7 @@ void Field_date::sort_string(char *to,uint length __attribute__((unused))) void Field_date::sql_type(String &res) const { - res.set("date",4); + res.set("date",4,default_charset_info); } /**************************************************************************** @@ -3164,35 +3358,45 @@ void Field_date::sql_type(String &res) const ** In number context: YYYYMMDD ****************************************************************************/ -void Field_newdate::store(const char *from,uint len) +int Field_newdate::store(const char *from,uint len,CHARSET_INFO *cs) { TIME l_time; long tmp; + int error= 0; if (str_to_TIME(from,len,&l_time,1) == TIMESTAMP_NONE) + { tmp=0L; + error= 1; + } else tmp= l_time.day + l_time.month*32 + l_time.year*16*32; int3store(ptr,tmp); + return error; } -void Field_newdate::store(double nr) +int Field_newdate::store(double nr) { if (nr < 0.0 || nr > 99991231235959.0) - Field_newdate::store((longlong) -1); + { + (void) Field_newdate::store((longlong) -1); + return 1; + } else - Field_newdate::store((longlong) rint(nr)); + return Field_newdate::store((longlong) rint(nr)); } -void Field_newdate::store(longlong nr) +int Field_newdate::store(longlong nr) { int32 tmp; + int error= 0; if (nr >= LL(100000000) && nr <= LL(99991231235959)) nr=nr/LL(1000000); // Timestamp to date if (nr < 0L || nr > 99991231L) { tmp=0; current_thd->cuted_fields++; + error= 1; } else { @@ -3210,11 +3414,13 @@ void Field_newdate::store(longlong nr) { tmp=0L; // Don't allow date to change current_thd->cuted_fields++; + error= 1; } else tmp= day + month*32 + (tmp/10000)*16*32; } int3store(ptr,(int32) tmp); + return error; } void Field_newdate::store_time(TIME *ltime,timestamp_type type) @@ -3306,7 +3512,7 @@ void Field_newdate::sort_string(char *to,uint length __attribute__((unused))) void Field_newdate::sql_type(String &res) const { - res.set("date",4); + res.set("date",4,default_charset_info); } @@ -3317,7 +3523,7 @@ void Field_newdate::sql_type(String &res) const ** Stored as a 8 byte unsigned int. Should sometimes be change to a 6 byte int. ****************************************************************************/ -void Field_datetime::store(const char *from,uint len) +int Field_datetime::store(const char *from,uint len,CHARSET_INFO *cs) { longlong tmp=str_to_datetime(from,len,1); #ifdef WORDS_BIGENDIAN @@ -3328,26 +3534,32 @@ void Field_datetime::store(const char *from,uint len) else #endif longlongstore(ptr,tmp); + return 0; } -void Field_datetime::store(double nr) +int Field_datetime::store(double nr) { + int error= 0; if (nr < 0.0 || nr > 99991231235959.0) { nr=0.0; current_thd->cuted_fields++; + error= 1; } - Field_datetime::store((longlong) rint(nr)); + error |= Field_datetime::store((longlong) rint(nr)); + return error; } -void Field_datetime::store(longlong nr) +int Field_datetime::store(longlong nr) { + int error= 0; if (nr < 0 || nr > LL(99991231235959)) { nr=0; current_thd->cuted_fields++; + error= 1; } else nr=fix_datetime(nr); @@ -3359,6 +3571,7 @@ void Field_datetime::store(longlong nr) else #endif longlongstore(ptr,nr); + return error; } void Field_datetime::store_time(TIME *ltime,timestamp_type type) @@ -3523,7 +3736,7 @@ void Field_datetime::sort_string(char *to,uint length __attribute__((unused))) void Field_datetime::sql_type(String &res) const { - res.set("datetime",8); + res.set("datetime",8,default_charset_info); } /**************************************************************************** @@ -3533,10 +3746,11 @@ void Field_datetime::sql_type(String &res) const /* Copy a string and fill with space */ -void Field_string::store(const char *from,uint length) +int Field_string::store(const char *from,uint length,CHARSET_INFO *cs) { + int error= 0; #ifdef USE_TIS620 - if (!binary_flag) { + if (!binary()) { ThNormalize((uchar *)ptr, field_length, (uchar *)from, length); if (length < field_length) { bfill(ptr + length, field_length - length, ' '); @@ -3557,33 +3771,35 @@ 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++; + error=1; break; } } } } #endif /* USE_TIS620 */ + return error; } -void Field_string::store(double nr) +int Field_string::store(double nr) { char buff[MAX_FIELD_WIDTH],*end; int width=min(field_length,DBL_DIG+5); sprintf(buff,"%-*.*g",width,max(width-5,0),nr); end=strcend(buff,' '); - Field_string::store(buff,(uint) (end - buff)); + return Field_string::store(buff,(uint) (end - buff), default_charset_info); } -void Field_string::store(longlong nr) +int Field_string::store(longlong nr) { char buff[22]; char *end=longlong10_to_str(nr,buff,-10); - Field_string::store(buff,(uint) (end-buff)); + return Field_string::store(buff,(uint) (end-buff), default_charset_info); } @@ -3618,51 +3834,57 @@ String *Field_string::val_str(String *val_buffer __attribute__((unused)), #endif while (end > ptr && end[-1] == ' ') end--; - val_ptr->set((const char*) ptr,(uint) (end - ptr)); + val_ptr->set((const char*) ptr,(uint) (end - ptr),field_charset); return val_ptr; } 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_strnncoll(field_charset, + (const uchar*)a_ptr,field_length, + (const uchar*)b_ptr,field_length); } void Field_string::sort_string(char *to,uint length) { - if (binary_flag) + if (binary()) memcpy((byte*) to,(byte*) ptr,(size_t) 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_strnxfrm(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++]; } } void Field_string::sql_type(String &res) const { - sprintf((char*) res.ptr(),"%s(%d)", - field_length > 3 && - (table->db_options_in_use & HA_OPTION_PACK_RECORD) ? - "varchar" : "char", - (int) field_length); - res.length((uint) strlen(res.ptr())); - if (binary_flag) + ulong length= my_sprintf((char*) res.ptr(), + ((char*) res.ptr(), "%s(%d)", + (field_length > 3 && + (table->db_options_in_use & + HA_OPTION_PACK_RECORD) ? + "varchar" : "char"), + (int) field_length)); + res.length((uint) length); + if (binary()) res.append(" binary"); + else + { + res.append(" character set "); + res.append(field_charset->name); + } } @@ -3692,12 +3914,14 @@ int Field_string::pack_cmp(const char *a, const char *b, uint length) uint a_length= (uint) (uchar) *a++; uint b_length= (uint) (uchar) *b++; - if (binary_flag) + if (binary()) { 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_strnncoll(field_charset, + (const uchar*)a,a_length, + (const uchar*)b,b_length); } @@ -3709,12 +3933,14 @@ int Field_string::pack_cmp(const char *b, uint length) end--; uint a_length = (uint) (end - ptr); - if (binary_flag) + if (binary()) { 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_strnncoll(field_charset, + (const uchar*)ptr,a_length, + (const uchar*)b, b_length); } @@ -3737,10 +3963,11 @@ uint Field_string::max_packed_col_length(uint max_length) ****************************************************************************/ -void Field_varstring::store(const char *from,uint length) +int Field_varstring::store(const char *from,uint length,CHARSET_INFO *cs) { + int error= 0; #ifdef USE_TIS620 - if (!binary_flag) + if (!binary()) { ThNormalize((uchar *) ptr+2, field_length, (uchar *) from, length); } @@ -3754,27 +3981,29 @@ void Field_varstring::store(const char *from,uint length) length=field_length; memcpy(ptr+2,from,field_length); current_thd->cuted_fields++; + error= 1; } #endif /* USE_TIS620 */ int2store(ptr,length); + return error; } -void Field_varstring::store(double nr) +int Field_varstring::store(double nr) { char buff[MAX_FIELD_WIDTH],*end; int width=min(field_length,DBL_DIG+5); sprintf(buff,"%-*.*g",width,max(width-5,0),nr); end=strcend(buff,' '); - Field_varstring::store(buff,(uint) (end - buff)); + return Field_varstring::store(buff,(uint) (end - buff), default_charset_info); } -void Field_varstring::store(longlong nr) +int Field_varstring::store(longlong nr) { char buff[22]; char *end=longlong10_to_str(nr,buff,-10); - Field_varstring::store(buff,(uint) (end-buff)); + return Field_varstring::store(buff,(uint) (end-buff), default_charset_info); } @@ -3806,7 +4035,7 @@ String *Field_varstring::val_str(String *val_buffer __attribute__((unused)), String *val_ptr) { uint length=uint2korr(ptr); - val_ptr->set((const char*) ptr+2,length); + val_ptr->set((const char*) ptr+2,length,field_charset); return val_ptr; } @@ -3816,25 +4045,24 @@ int Field_varstring::cmp(const char *a_ptr, const char *b_ptr) uint a_length=uint2korr(a_ptr); uint b_length=uint2korr(b_ptr); int diff; - 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_strnncoll(field_charset, + (const uchar*)a_ptr+2,min(a_length,b_length), + (const uchar*)b_ptr+2,min(a_length,b_length)); return diff ? diff : (int) (a_length - b_length); } void Field_varstring::sort_string(char *to,uint length) { uint tot_length=uint2korr(ptr); - if (binary_flag) + if (binary()) memcpy((byte*) to,(byte*) ptr+2,(size_t) tot_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_strnxfrm(field_charset)) + tot_length=my_strnxfrm(field_charset, + (unsigned char *) to, length, + (unsigned char *)ptr+2, tot_length); else { #endif @@ -3842,7 +4070,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 @@ -3854,10 +4082,17 @@ void Field_varstring::sort_string(char *to,uint length) void Field_varstring::sql_type(String &res) const { - sprintf((char*) res.ptr(),"varchar(%d)",(int) field_length); - res.length((uint) strlen(res.ptr())); - if (binary_flag) + ulong length= my_sprintf((char*) res.ptr(), + ((char*) res.ptr(),"varchar(%u)", + field_length)); + res.length((uint) length); + if (binary()) res.append(" binary"); + else + { + res.append(" character set "); + res.append(field_charset->name); + } } char *Field_varstring::pack(char *to, const char *from, uint max_length) @@ -3908,12 +4143,14 @@ int Field_varstring::pack_cmp(const char *a, const char *b, uint key_length) a_length= (uint) (uchar) *a++; b_length= (uint) (uchar) *b++; } - if (binary_flag) + if (binary()) { 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_strnncoll(field_charset, + (const uchar *)a,a_length, + (const uchar *)b,b_length); } int Field_varstring::pack_cmp(const char *b, uint key_length) @@ -3929,12 +4166,14 @@ int Field_varstring::pack_cmp(const char *b, uint key_length) { b_length= (uint) (uchar) *b++; } - if (binary_flag) + if (binary()) { 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_strnncoll(field_charset, + (const uchar *)a,a_length, + (const uchar *)b,b_length); } uint Field_varstring::packed_col_length(const char *data_ptr, uint length) @@ -3959,15 +4198,13 @@ uint Field_varstring::max_packed_col_length(uint max_length) Field_blob::Field_blob(char *ptr_arg, uchar *null_ptr_arg, uchar 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) + CHARSET_INFO *cs) :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) + table_arg, cs), + packlength(blob_pack_length), geom_flag(true) { flags|= BLOB_FLAG; - if (binary_arg) - flags|=BINARY_FLAG; if (table) table->blob_fields++; } @@ -4054,7 +4291,7 @@ uint32 Field_blob::get_length(const char *pos) } -void Field_blob::store(const char *from,uint len) +int Field_blob::store(const char *from,uint len,CHARSET_INFO *cs) { if (!len) { @@ -4069,7 +4306,7 @@ void Field_blob::store(const char *from,uint len) if (table->copy_blobs || len <= MAX_FIELD_WIDTH) { // Must make a copy #ifdef USE_TIS620 - if (!binary_flag) + if (!binary()) { /* If there isn't enough memory, use original string */ if ((th_ptr=(char * ) my_malloc(sizeof(char) * len,MYF(0)))) @@ -4079,7 +4316,7 @@ void Field_blob::store(const char *from,uint len) } } #endif /* USE_TIS620 */ - value.copy(from,len); + value.copy(from,len,charset()); from=value.ptr(); #ifdef USE_TIS620 my_free(th_ptr,MYF(MY_ALLOW_ZERO_PTR)); @@ -4087,20 +4324,21 @@ void Field_blob::store(const char *from,uint len) } bmove(ptr+packlength,(char*) &from,sizeof(char*)); } + return 0; } -void Field_blob::store(double nr) +int Field_blob::store(double nr) { - value.set(nr); - Field_blob::store(value.ptr(),(uint) value.length()); + value.set(nr,2,current_thd->thd_charset); + return Field_blob::store(value.ptr(),(uint) value.length(), value.charset()); } -void Field_blob::store(longlong nr) +int Field_blob::store(longlong nr) { - value.set(nr); - Field_blob::store(value.ptr(), (uint) value.length()); + value.set(nr,current_thd->thd_charset); + return Field_blob::store(value.ptr(), (uint) value.length(), value.charset()); } @@ -4143,9 +4381,9 @@ String *Field_blob::val_str(String *val_buffer __attribute__((unused)), char *blob; memcpy_fixed(&blob,ptr+packlength,sizeof(char*)); if (!blob) - val_ptr->set("",0); // A bit safer than ->length(0) + val_ptr->set("",0,field_charset); // A bit safer than ->length(0) else - val_ptr->set((const char*) blob,get_length(ptr)); + val_ptr->set((const char*) blob,get_length(ptr),field_charset); return val_ptr; } @@ -4153,11 +4391,9 @@ String *Field_blob::val_str(String *val_buffer __attribute__((unused)), int Field_blob::cmp(const char *a,uint32 a_length, const char *b, uint32 b_length) { - int diff; - if (binary_flag) - diff=memcmp(a,b,min(a_length,b_length)); - else - diff=my_sortcmp(a,b,min(a_length,b_length)); + int diff=my_strnncoll(field_charset, + (const uchar*)a,min(a_length,b_length), + (const uchar*)b,min(a_length,b_length)); return diff ? diff : (int) (a_length - b_length); } @@ -4205,11 +4441,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) { - length-=HA_KEY_BLOB_LENGTH; - uint32 blob_length=get_length(ptr); + length-= HA_KEY_BLOB_LENGTH; + uint32 blob_length= get_length(ptr); char *blob; + + if (type == itMBR) + { + if (!blob_length) + return; + get_ptr(&blob); + + 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; if ((uint32) length > blob_length) { #ifdef HAVE_purify @@ -4225,9 +4480,34 @@ void Field_blob::get_key_image(char *buff,uint length) void Field_blob::set_key_image(char *buff,uint length) { length=uint2korr(buff); - Field_blob::store(buff+2,length); + (void) Field_blob::store(buff+2,length, default_charset_info); +} + + +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; @@ -4259,7 +4539,7 @@ void Field_blob::sort_string(char *to,uint length) if (blob_length > length) blob_length=length; memcpy_fixed(&blob,ptr+packlength,sizeof(char*)); - if (binary_flag) + if (binary()) { memcpy(to,blob,blob_length); to+=blob_length; @@ -4267,11 +4547,11 @@ void Field_blob::sort_string(char *to,uint length) else { #ifdef USE_STRCOLL - if (use_strcoll(default_charset_info)) + if (use_strnxfrm(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; @@ -4279,7 +4559,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); } @@ -4295,8 +4575,13 @@ void Field_blob::sql_type(String &res) const case 3: str="medium"; break; case 4: str="long"; break; } - res.set(str,(uint) strlen(str)); - res.append(binary_flag ? "blob" : "text"); + res.set(str,(uint) strlen(str),default_charset_info); + res.append(binary() ? "blob" : "text"); + if (!binary()) + { + res.append(" character set "); + res.append(field_charset->name); + } } @@ -4352,12 +4637,14 @@ int Field_blob::pack_cmp(const char *a, const char *b, uint key_length) a_length= (uint) (uchar) *a++; b_length= (uint) (uchar) *b++; } - if (binary_flag) + if (binary()) { 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_strnncoll(field_charset, + (const uchar *)a,a_length, + (const uchar *)b,b_length); } @@ -4378,12 +4665,14 @@ int Field_blob::pack_cmp(const char *b, uint key_length) { b_length= (uint) (uchar) *b++; } - if (binary_flag) + if (binary()) { 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_strnncoll(field_charset, + (const uchar *)a,a_length, + (const uchar *)b,b_length); } /* Create a packed key that will be used for storage from a MySQL row */ @@ -4494,14 +4783,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); } @@ -4514,8 +4805,9 @@ uint find_enum(TYPELIB *lib,const char *x, uint length) ** (if there isn't a empty value in the enum) */ -void Field_enum::store(const char *from,uint length) +int Field_enum::store(const char *from,uint length,CHARSET_INFO *cs) { + int error= 0; uint tmp=find_enum(typelib,from,length); if (!tmp) { @@ -4535,29 +4827,34 @@ void Field_enum::store(const char *from,uint length) { tmp=0; current_thd->cuted_fields++; + error=1; } } else current_thd->cuted_fields++; } store_type((ulonglong) tmp); + return error; } -void Field_enum::store(double nr) +int Field_enum::store(double nr) { - Field_enum::store((longlong) nr); + return Field_enum::store((longlong) nr); } -void Field_enum::store(longlong nr) +int Field_enum::store(longlong nr) { + int error= 0; if ((uint) nr > typelib->count || nr == 0) { current_thd->cuted_fields++; nr=0; + error=1; } store_type((ulonglong) (uint) nr); + return error; } @@ -4620,7 +4917,8 @@ String *Field_enum::val_str(String *val_buffer __attribute__((unused)), val_ptr->length(0); else val_ptr->set((const char*) typelib->type_names[tmp-1], - (uint) strlen(typelib->type_names[tmp-1])); + (uint) strlen(typelib->type_names[tmp-1]), + field_charset); return val_ptr; } @@ -4657,12 +4955,19 @@ void Field_enum::sql_type(String &res) const { if (flag) res.append(','); - res.append('\''); - append_unescaped(&res,*pos); - res.append('\''); + append_unescaped(&res, *pos, strlen(*pos)); flag=1; } res.append(')'); + if (binary()) + { + res.append(" binary"); + } + else + { + res.append(" character set "); + res.append(field_charset->name); + } } @@ -4678,14 +4983,14 @@ 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; if (x != end) { const char *start=x; - bool error=0; + bool error= 0; for (;;) { const char *pos=start; @@ -4706,8 +5011,9 @@ ulonglong find_set(TYPELIB *lib,const char *x,uint length) } -void Field_set::store(const char *from,uint length) +int Field_set::store(const char *from,uint length,CHARSET_INFO *cs) { + int error= 0; ulonglong tmp=find_set(typelib,from,length); if (!tmp && length && length < 22) { @@ -4723,23 +5029,30 @@ void Field_set::store(const char *from,uint length) tmp=strtoull(conv,&end,10); if (my_errno || end != conv+length || tmp > (ulonglong) (((longlong) 1 << typelib->count) - (longlong) 1)) + { tmp=0; + error=1; + } else current_thd->cuted_fields--; // Remove warning from find_set } store_type(tmp); + return error; } -void Field_set::store(longlong nr) +int Field_set::store(longlong nr) { + int error= 0; if ((ulonglong) nr > (ulonglong) (((longlong) 1 << typelib->count) - (longlong) 1)) { nr&= (longlong) (((longlong) 1 << typelib->count) - (longlong) 1); current_thd->cuted_fields++; + error=1; } store_type((ulonglong) nr); + return error; } @@ -4757,7 +5070,8 @@ String *Field_set::val_str(String *val_buffer, if (val_buffer->length()) val_buffer->append(field_separator); String str(typelib->type_names[bitnr], - (uint) strlen(typelib->type_names[bitnr])); + (uint) strlen(typelib->type_names[bitnr]), + field_charset); val_buffer->append(str); } tmp>>=1; @@ -4777,12 +5091,19 @@ void Field_set::sql_type(String &res) const { if (flag) res.append(','); - res.append('\''); - append_unescaped(&res,*pos); - res.append('\''); + append_unescaped(&res, *pos, strlen(*pos)); flag=1; } res.append(')'); + if (binary()) + { + res.append(" binary"); + } + else + { + res.append(" character set "); + res.append(field_charset->name); + } } /* returns 1 if the fields are equally defined */ @@ -4804,7 +5125,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; } @@ -4880,6 +5202,7 @@ Field *make_field(char *ptr, uint32 field_length, uchar *null_pos, uchar null_bit, uint pack_flag, enum_field_types field_type, + CHARSET_INFO *field_charset, Field::utype unireg_check, TYPELIB *interval, const char *field_name, @@ -4894,8 +5217,7 @@ Field *make_field(char *ptr, uint32 field_length, { if (!f_is_packed(pack_flag)) return new Field_string(ptr,field_length,null_pos,null_bit, - unireg_check, field_name, table, - f_is_binary(pack_flag) != 0); + unireg_check, field_name, table, field_charset); uint pack_length=calc_pack_length((enum_field_types) f_packtype(pack_flag), @@ -4904,20 +5226,22 @@ Field *make_field(char *ptr, uint32 field_length, if (f_is_blob(pack_flag)) return new Field_blob(ptr,null_pos,null_bit, unireg_check, field_name, table, - pack_length,f_is_binary(pack_flag) != 0); + pack_length, field_charset); if (f_is_geom(pack_flag)) - return 0; + return new Field_geom(ptr,null_pos,null_bit, + unireg_check, field_name, table, + pack_length); if (interval) { if (f_is_enum(pack_flag)) return new Field_enum(ptr,field_length,null_pos,null_bit, unireg_check, field_name, table, - pack_length, interval); + pack_length, interval, field_charset); else return new Field_set(ptr,field_length,null_pos,null_bit, unireg_check, field_name, table, - pack_length, interval); + pack_length, interval, field_charset); } } @@ -4973,22 +5297,22 @@ Field *make_field(char *ptr, uint32 field_length, unireg_check, field_name, table); case FIELD_TYPE_DATE: return new Field_date(ptr,null_pos,null_bit, - unireg_check, field_name, table); + unireg_check, field_name, table, field_charset); case FIELD_TYPE_NEWDATE: return new Field_newdate(ptr,null_pos,null_bit, - unireg_check, field_name, table); + unireg_check, field_name, table, field_charset); case FIELD_TYPE_TIME: return new Field_time(ptr,null_pos,null_bit, - unireg_check, field_name, table); + unireg_check, field_name, table, field_charset); case FIELD_TYPE_DATETIME: return new Field_datetime(ptr,null_pos,null_bit, - unireg_check, field_name, table); + unireg_check, field_name, table, field_charset); case FIELD_TYPE_NULL: - return new Field_null(ptr,field_length,unireg_check,field_name,table); + return new Field_null(ptr,field_length,unireg_check,field_name,table, field_charset); default: // Impossible (Wrong version) break; } - return 0; // Impossible + return 0; } @@ -5003,6 +5327,8 @@ create_field::create_field(Field *old_field,Field *orig_field) unireg_check=old_field->unireg_check; pack_length=old_field->pack_length(); sql_type= old_field->real_type(); + charset= old_field->charset(); // May be NULL ptr + comment= old_field->comment; /* Fix if the original table had 4 byte pointer blobs */ if (flags & BLOB_FLAG) @@ -5011,6 +5337,7 @@ create_field::create_field(Field *old_field,Field *orig_field) decimals= old_field->decimals(); if (sql_type == FIELD_TYPE_STRING) { + /* Change CHAR -> VARCHAR if dynamic record length */ sql_type=old_field->type(); decimals=0; } @@ -5024,7 +5351,8 @@ create_field::create_field(Field *old_field,Field *orig_field) orig_field) { char buff[MAX_FIELD_WIDTH],*pos; - String tmp(buff,sizeof(buff)); + CHARSET_INFO *field_charset= charset ? charset : default_charset_info; + String tmp(buff,sizeof(buff),field_charset); /* Get the value from record[2] (the default value row) */ my_ptrdiff_t diff= (my_ptrdiff_t) (orig_field->table->rec_buff_length*2); @@ -5036,7 +5364,7 @@ create_field::create_field(Field *old_field,Field *orig_field) { pos= (char*) sql_memdup(tmp.ptr(),tmp.length()+1); pos[tmp.length()]=0; - def=new Item_string(pos,tmp.length()); + def=new Item_string(pos,tmp.length(),field_charset); } } } diff --git a/sql/field.h b/sql/field.h index ba28a6a872e..8c4c48968c4 100644 --- a/sql/field.h +++ b/sql/field.h @@ -41,12 +41,16 @@ public: uchar *null_ptr; // Byte where null_bit is struct st_table *table; // Pointer for table const char *table_name,*field_name; + LEX_STRING comment; ulong query_id; // For quick test of used fields /* Field is part of the following keys */ key_map key_start,part_of_key,part_of_sortkey; 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; @@ -56,9 +60,9 @@ public: utype unireg_check_arg, const char *field_name_arg, struct st_table *table_arg); virtual ~Field() {} - virtual void store(const char *to,uint length)=0; - virtual void store(double nr)=0; - virtual void store(longlong nr)=0; + virtual int store(const char *to,uint length,CHARSET_INFO *cs)=0; + virtual int store(double nr)=0; + virtual int store(longlong nr)=0; virtual void store_time(TIME *ltime,timestamp_type t_type); virtual double val_real(void)=0; virtual longlong val_int(void)=0; @@ -125,7 +129,7 @@ public: tmp->table=new_table; tmp->key_start=tmp->part_of_key=tmp->part_of_sortkey=0; tmp->unireg_check=Field::NONE; - tmp->flags&= (NOT_NULL_FLAG | BLOB_FLAG | UNSIGNED_FLAG | ZEROFILL_FLAG | BINARY_FLAG | ENUM_FLAG | SET_FLAG); + tmp->flags&= (NOT_NULL_FLAG | BLOB_FLAG | UNSIGNED_FLAG | ZEROFILL_FLAG | ENUM_FLAG | SET_FLAG); tmp->reset_fields(); } return tmp; @@ -145,17 +149,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; @@ -199,6 +198,8 @@ public: uint fill_cache_field(struct st_cache_field *copy); virtual bool get_date(TIME *ltime,bool fuzzydate); virtual bool get_time(TIME *ltime); + virtual CHARSET_INFO *charset(void) const { return my_charset_bin; } + virtual void set_charset(CHARSET_INFO *charset) { } friend bool reopen_table(THD *,struct st_table *,bool); friend int cre_myisam(my_string name, register TABLE *form, uint options, ulonglong auto_increment_value); @@ -246,19 +247,32 @@ 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, const char *field_name_arg, - struct st_table *table_arg) + struct st_table *table_arg,CHARSET_INFO *charset) :Field(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg, table_arg) - {} + { field_charset=charset; } 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); } + CHARSET_INFO *charset(void) const { return field_charset; } + + void set_charset(CHARSET_INFO *charset) { field_charset=charset; } + bool binary() const { return field_charset->state & MY_CS_BINSORT ? 1 : 0; } + inline int cmp_image(char *buff,uint length) + { + if (binary()) + return memcmp(ptr,buff,length); + else + return my_strncasecmp(field_charset,ptr,buff,length); + } + friend class create_field; }; @@ -277,9 +291,9 @@ public: enum ha_base_keytype key_type() const { return zerofill ? HA_KEYTYPE_BINARY : HA_KEYTYPE_NUM; } void reset(void); - void store(const char *to,uint length); - void store(double nr); - void store(longlong nr); + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr); double val_real(void); longlong val_int(void); String *val_str(String*,String *); @@ -306,9 +320,9 @@ public: enum_field_types type() const { return FIELD_TYPE_TINY;} enum ha_base_keytype key_type() const { return unsigned_flag ? HA_KEYTYPE_BINARY : HA_KEYTYPE_INT8; } - void store(const char *to,uint length); - void store(double nr); - void store(longlong nr); + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr); void reset(void) { ptr[0]=0; } double val_real(void); longlong val_int(void); @@ -335,9 +349,9 @@ public: enum_field_types type() const { return FIELD_TYPE_SHORT;} enum ha_base_keytype key_type() const { return unsigned_flag ? HA_KEYTYPE_USHORT_INT : HA_KEYTYPE_SHORT_INT;} - void store(const char *to,uint length); - void store(double nr); - void store(longlong nr); + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr); void reset(void) { ptr[0]=ptr[1]=0; } double val_real(void); longlong val_int(void); @@ -364,9 +378,9 @@ public: enum_field_types type() const { return FIELD_TYPE_INT24;} enum ha_base_keytype key_type() const { return unsigned_flag ? HA_KEYTYPE_UINT24 : HA_KEYTYPE_INT24; } - void store(const char *to,uint length); - void store(double nr); - void store(longlong nr); + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr); void reset(void) { ptr[0]=ptr[1]=ptr[2]=0; } double val_real(void); longlong val_int(void); @@ -398,9 +412,9 @@ public: enum_field_types type() const { return FIELD_TYPE_LONG;} enum ha_base_keytype key_type() const { return unsigned_flag ? HA_KEYTYPE_ULONG_INT : HA_KEYTYPE_LONG_INT; } - void store(const char *to,uint length); - void store(double nr); - void store(longlong nr); + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr); void reset(void) { ptr[0]=ptr[1]=ptr[2]=ptr[3]=0; } double val_real(void); longlong val_int(void); @@ -434,9 +448,9 @@ public: enum_field_types type() const { return FIELD_TYPE_LONGLONG;} enum ha_base_keytype key_type() const { return unsigned_flag ? HA_KEYTYPE_ULONGLONG : HA_KEYTYPE_LONGLONG; } - void store(const char *to,uint length); - void store(double nr); - void store(longlong nr); + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr); void reset(void) { ptr[0]=ptr[1]=ptr[2]=ptr[3]=ptr[4]=ptr[5]=ptr[6]=ptr[7]=0; } double val_real(void); longlong val_int(void); @@ -462,9 +476,9 @@ public: {} enum_field_types type() const { return FIELD_TYPE_FLOAT;} enum ha_base_keytype key_type() const { return HA_KEYTYPE_FLOAT; } - void store(const char *to,uint length); - void store(double nr); - void store(longlong nr); + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr); void reset(void) { bzero(ptr,sizeof(float)); } double val_real(void); longlong val_int(void); @@ -494,9 +508,9 @@ public: {} enum_field_types type() const { return FIELD_TYPE_DOUBLE;} enum ha_base_keytype key_type() const { return HA_KEYTYPE_DOUBLE; } - void store(const char *to,uint length); - void store(double nr); - void store(longlong nr); + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr); void reset(void) { bzero(ptr,sizeof(double)); } double val_real(void); longlong val_int(void); @@ -515,14 +529,14 @@ class Field_null :public Field_str { public: Field_null(char *ptr_arg, uint32 len_arg, enum utype unireg_check_arg, const char *field_name_arg, - struct st_table *table_arg) + struct st_table *table_arg, CHARSET_INFO *cs) :Field_str(ptr_arg, len_arg, null, 1, - unireg_check_arg, field_name_arg, table_arg) + unireg_check_arg, field_name_arg, table_arg, cs) {} enum_field_types type() const { return FIELD_TYPE_NULL;} - void store(const char *to, uint length) { null[0]=1; } - void store(double nr) { null[0]=1; } - void store(longlong nr) { null[0]=1; } + int store(const char *to, uint length, CHARSET_INFO *cs) { null[0]=1; return 0; } + int store(double nr) { null[0]=1; return 0; } + int store(longlong nr) { null[0]=1; return 0; } void reset(void) {} double val_real(void) { return 0.0;} longlong val_int(void) { return 0;} @@ -531,7 +545,7 @@ public: int cmp(const char *a, const char *b) { return 0;} void sort_string(char *buff, uint length) {} uint32 pack_length() const { return 0; } - void sql_type(String &str) const { str.set("null",4); } + void sql_type(String &str) const { str.set("null",4,my_thd_charset); } uint size_of() const { return sizeof(*this); } }; @@ -544,9 +558,9 @@ public: enum Item_result result_type () const { return field_length == 8 || field_length == 14 ? INT_RESULT : STRING_RESULT; } enum_field_types type() const { return FIELD_TYPE_TIMESTAMP;} enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONG_INT; } - void store(const char *to,uint length); - void store(double nr); - void store(longlong nr); + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr); void reset(void) { ptr[0]=ptr[1]=ptr[2]=ptr[3]=0; } double val_real(void); longlong val_int(void); @@ -588,9 +602,9 @@ public: unireg_check_arg, field_name_arg, table_arg, 1, 1) {} enum_field_types type() const { return FIELD_TYPE_YEAR;} - void store(const char *to,uint length); - void store(double nr); - void store(longlong nr); + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr); double val_real(void); longlong val_int(void); String *val_str(String*,String *); @@ -602,20 +616,20 @@ class Field_date :public Field_str { public: Field_date(char *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const char *field_name_arg, - struct st_table *table_arg) + struct st_table *table_arg, CHARSET_INFO *cs) :Field_str(ptr_arg, 10, null_ptr_arg, null_bit_arg, - unireg_check_arg, field_name_arg, table_arg) + unireg_check_arg, field_name_arg, table_arg, cs) {} Field_date(bool maybe_null_arg, const char *field_name_arg, - struct st_table *table_arg) + struct st_table *table_arg, CHARSET_INFO *cs) :Field_str((char*) 0,10, maybe_null_arg ? (uchar*) "": 0,0, - NONE, field_name_arg, table_arg) {} + NONE, field_name_arg, table_arg, cs) {} enum_field_types type() const { return FIELD_TYPE_DATE;} enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONG_INT; } enum Item_result cmp_type () const { return INT_RESULT; } - void store(const char *to,uint length); - void store(double nr); - void store(longlong nr); + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr); void reset(void) { ptr[0]=ptr[1]=ptr[2]=ptr[3]=0; } double val_real(void); longlong val_int(void); @@ -632,17 +646,17 @@ class Field_newdate :public Field_str { public: Field_newdate(char *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const char *field_name_arg, - struct st_table *table_arg) + struct st_table *table_arg, CHARSET_INFO *cs) :Field_str(ptr_arg, 10, null_ptr_arg, null_bit_arg, - unireg_check_arg, field_name_arg, table_arg) + unireg_check_arg, field_name_arg, table_arg, cs) {} enum_field_types type() const { return FIELD_TYPE_DATE;} enum_field_types real_type() const { return FIELD_TYPE_NEWDATE; } enum ha_base_keytype key_type() const { return HA_KEYTYPE_UINT24; } enum Item_result cmp_type () const { return INT_RESULT; } - void store(const char *to,uint length); - void store(double nr); - void store(longlong nr); + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr); void store_time(TIME *ltime,timestamp_type type); void reset(void) { ptr[0]=ptr[1]=ptr[2]=0; } double val_real(void); @@ -663,20 +677,20 @@ class Field_time :public Field_str { public: Field_time(char *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const char *field_name_arg, - struct st_table *table_arg) + struct st_table *table_arg, CHARSET_INFO *cs) :Field_str(ptr_arg, 8, null_ptr_arg, null_bit_arg, - unireg_check_arg, field_name_arg, table_arg) + unireg_check_arg, field_name_arg, table_arg, cs) {} Field_time(bool maybe_null_arg, const char *field_name_arg, - struct st_table *table_arg) + struct st_table *table_arg, CHARSET_INFO *cs) :Field_str((char*) 0,8, maybe_null_arg ? (uchar*) "": 0,0, - NONE, field_name_arg, table_arg) {} + NONE, field_name_arg, table_arg, cs) {} enum_field_types type() const { return FIELD_TYPE_TIME;} enum ha_base_keytype key_type() const { return HA_KEYTYPE_INT24; } enum Item_result cmp_type () const { return INT_RESULT; } - void store(const char *to,uint length); - void store(double nr); - void store(longlong nr); + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr); void reset(void) { ptr[0]=ptr[1]=ptr[2]=0; } double val_real(void); longlong val_int(void); @@ -695,22 +709,22 @@ class Field_datetime :public Field_str { public: Field_datetime(char *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const char *field_name_arg, - struct st_table *table_arg) + struct st_table *table_arg, CHARSET_INFO *cs) :Field_str(ptr_arg, 19, null_ptr_arg, null_bit_arg, - unireg_check_arg, field_name_arg, table_arg) + unireg_check_arg, field_name_arg, table_arg, cs) {} Field_datetime(bool maybe_null_arg, const char *field_name_arg, - struct st_table *table_arg) + struct st_table *table_arg, CHARSET_INFO *cs) :Field_str((char*) 0,19, maybe_null_arg ? (uchar*) "": 0,0, - NONE, field_name_arg, table_arg) {} + NONE, field_name_arg, table_arg, cs) {} enum_field_types type() const { return FIELD_TYPE_DATETIME;} #ifdef HAVE_LONG_LONG enum ha_base_keytype key_type() const { return HA_KEYTYPE_ULONGLONG; } #endif enum Item_result cmp_type () const { return INT_RESULT; } - void store(const char *to,uint length); - void store(double nr); - void store(longlong nr); + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr); void store_time(TIME *ltime,timestamp_type type); void reset(void) { ptr[0]=ptr[1]=ptr[2]=ptr[3]=ptr[4]=ptr[5]=ptr[6]=ptr[7]=0; } double val_real(void); @@ -728,28 +742,17 @@ public: class Field_string :public Field_str { - bool binary_flag; public: Field_string(char *ptr_arg, uint32 len_arg,uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const char *field_name_arg, - struct st_table *table_arg,bool binary_arg) + struct st_table *table_arg, CHARSET_INFO *cs) :Field_str(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, - unireg_check_arg, field_name_arg, table_arg), - binary_flag(binary_arg) - { - if (binary_arg) - flags|=BINARY_FLAG; - } + unireg_check_arg, field_name_arg, table_arg,cs) {}; Field_string(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg, - struct st_table *table_arg, bool binary_arg) + struct st_table *table_arg, CHARSET_INFO *cs) :Field_str((char*) 0,len_arg, maybe_null_arg ? (uchar*) "": 0,0, - NONE, field_name_arg, table_arg), - binary_flag(binary_arg) - { - if (binary_arg) - flags|=BINARY_FLAG; - } + NONE, field_name_arg, table_arg, cs) {}; enum_field_types type() const { @@ -758,13 +761,12 @@ public: FIELD_TYPE_VAR_STRING : FIELD_TYPE_STRING); } enum ha_base_keytype key_type() const - { return binary_flag ? HA_KEYTYPE_BINARY : HA_KEYTYPE_TEXT; } + { return binary() ? HA_KEYTYPE_BINARY : HA_KEYTYPE_TEXT; } bool zero_pack() const { return 0; } - bool binary() const { return binary_flag; } void reset(void) { bfill(ptr,field_length,' '); } - void store(const char *to,uint length); - void store(double nr); - void store(longlong nr); + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr); double val_real(void); longlong val_int(void); String *val_str(String*,String *); @@ -783,40 +785,28 @@ public: class Field_varstring :public Field_str { - bool binary_flag; public: Field_varstring(char *ptr_arg, uint32 len_arg,uchar *null_ptr_arg, uchar null_bit_arg, enum utype unireg_check_arg, const char *field_name_arg, - struct st_table *table_arg,bool binary_arg) + struct st_table *table_arg, CHARSET_INFO *cs) :Field_str(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, - unireg_check_arg, field_name_arg, table_arg), - binary_flag(binary_arg) - { - if (binary_arg) - flags|=BINARY_FLAG; - } + unireg_check_arg, field_name_arg, table_arg, cs) {}; Field_varstring(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg, - struct st_table *table_arg, bool binary_arg) + struct st_table *table_arg, CHARSET_INFO *cs) :Field_str((char*) 0,len_arg, maybe_null_arg ? (uchar*) "": 0,0, - NONE, field_name_arg, table_arg), - binary_flag(binary_arg) - { - if (binary_arg) - flags|=BINARY_FLAG; - } + NONE, field_name_arg, table_arg, cs) {}; enum_field_types type() const { return FIELD_TYPE_VAR_STRING; } enum ha_base_keytype key_type() const - { return binary_flag ? HA_KEYTYPE_VARBINARY : HA_KEYTYPE_VARTEXT; } + { return binary() ? HA_KEYTYPE_VARBINARY : HA_KEYTYPE_VARTEXT; } bool zero_pack() const { return 0; } - bool binary() const { return binary_flag; } void reset(void) { bzero(ptr,field_length+2); } uint32 pack_length() const { return (uint32) field_length+2; } uint32 key_length() const { return (uint32) field_length; } - void store(const char *to,uint length); - void store(double nr); - void store(longlong nr); + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr); double val_real(void); longlong val_int(void); String *val_str(String*,String *); @@ -837,28 +827,26 @@ public: 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, struct st_table *table_arg,uint blob_pack_length, - bool binary_arg); + CHARSET_INFO *cs); Field_blob(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg, - struct st_table *table_arg, bool binary_arg) + struct st_table *table_arg, CHARSET_INFO *cs) :Field_str((char*) 0,len_arg, maybe_null_arg ? (uchar*) "": 0,0, - NONE, field_name_arg, table_arg), - packlength(3),binary_flag(binary_arg) + NONE, field_name_arg, table_arg, cs), + packlength(3), geom_flag(true) { flags|= BLOB_FLAG; - if (binary_arg) - flags|=BINARY_FLAG; } enum_field_types type() const { return FIELD_TYPE_BLOB;} enum ha_base_keytype key_type() const - { return binary_flag ? HA_KEYTYPE_VARBINARY : HA_KEYTYPE_VARTEXT; } - void store(const char *to,uint length); - void store(double nr); - void store(longlong nr); + { return binary() ? HA_KEYTYPE_VARBINARY : HA_KEYTYPE_VARTEXT; } + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr); double val_real(void); longlong val_int(void); String *val_str(String*,String *); @@ -879,7 +867,6 @@ public: inline uint32 get_length(uint row_offset=0) { return get_length(ptr+row_offset); } uint32 get_length(const char *ptr); - bool binary() const { return binary_flag; } inline void get_ptr(char **str) { memcpy_fixed(str,ptr+packlength,sizeof(char*)); @@ -894,13 +881,13 @@ 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() { char *tmp; get_ptr(&tmp); - if (value.copy(tmp,get_length())) + if (value.copy(tmp,get_length(),charset())) { Field_blob::reset(); return 1; @@ -923,6 +910,24 @@ 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) + :Field_blob(ptr_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, + field_name_arg, table_arg, blob_pack_length,my_charset_bin) {} + Field_geom(uint32 len_arg,bool maybe_null_arg, const char *field_name_arg, + struct st_table *table_arg) + :Field_blob(len_arg, maybe_null_arg, field_name_arg, + table_arg, my_charset_bin) {} + 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; @@ -932,9 +937,10 @@ public: uchar null_bit_arg, enum utype unireg_check_arg, const char *field_name_arg, struct st_table *table_arg,uint packlength_arg, - TYPELIB *typelib_arg) + TYPELIB *typelib_arg, + CHARSET_INFO *charset_arg) :Field_str(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, - unireg_check_arg, field_name_arg, table_arg), + unireg_check_arg, field_name_arg, table_arg, charset_arg), packlength(packlength_arg),typelib(typelib_arg) { flags|=ENUM_FLAG; @@ -942,9 +948,9 @@ public: enum_field_types type() const { return FIELD_TYPE_STRING; } enum Item_result cmp_type () const { return INT_RESULT; } enum ha_base_keytype key_type() const; - void store(const char *to,uint length); - void store(double nr); - void store(longlong nr); + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr); + int store(longlong nr); void reset() { bzero(ptr,packlength); } double val_real(void); longlong val_int(void); @@ -958,7 +964,6 @@ public: enum_field_types real_type() const { return FIELD_TYPE_ENUM; } virtual bool zero_pack() const { return 0; } bool optimize_range(uint idx) { return 0; } - bool binary() const { return 0; } bool eq_def(Field *field); }; @@ -969,17 +974,17 @@ public: uchar null_bit_arg, enum utype unireg_check_arg, const char *field_name_arg, struct st_table *table_arg,uint32 packlength_arg, - TYPELIB *typelib_arg) + TYPELIB *typelib_arg, CHARSET_INFO *charset_arg) :Field_enum(ptr_arg, len_arg, null_ptr_arg, null_bit_arg, unireg_check_arg, field_name_arg, table_arg, packlength_arg, - typelib_arg) + typelib_arg,charset_arg) { flags=(flags & ~ENUM_FLAG) | SET_FLAG; } - void store(const char *to,uint length); - void store(double nr) { Field_set::store((longlong) nr); } - void store(longlong nr); + int store(const char *to,uint length,CHARSET_INFO *charset); + int store(double nr) { return Field_set::store((longlong) nr); } + int store(longlong nr); virtual bool zero_pack() const { return 1; } String *val_str(String*,String *); void sql_type(String &str) const; @@ -996,12 +1001,14 @@ public: const char *field_name; const char *change; // If done with alter table const char *after; // Put column after this one + LEX_STRING comment; // Comment for field Item *def; // Default value enum enum_field_types sql_type; uint32 length; uint decimals,flags,pack_length; Field::utype unireg_check; TYPELIB *interval; // Which interval to use + CHARSET_INFO *charset; Field *field; // For alter table uint8 row,col,sc_length,interval_id; // For rea_create_table @@ -1017,7 +1024,9 @@ public: class Send_field { public: - const char *table_name,*col_name; + const char *db_name; + const char *table_name,*org_table_name; + const char *col_name,*org_col_name; uint length,flags,decimals; enum_field_types type; Send_field() {} @@ -1050,8 +1059,8 @@ public: Field *make_field(char *ptr, uint32 field_length, uchar *null_pos, uchar null_bit, - uint pack_flag, - enum_field_types field_type, + uint pack_flag, enum_field_types field_type, + CHARSET_INFO *cs, Field::utype unireg_check, TYPELIB *interval, const char *field_name, struct st_table *table); @@ -1076,6 +1085,7 @@ bool test_if_int(const char *str,int length); #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 @@ -1098,7 +1108,6 @@ bool test_if_int(const char *str,int length); #define f_packtype(x) (((x) >> FIELDFLAG_PACK_SHIFT) & 15) #define f_decimals(x) ((uint8) (((x) >> FIELDFLAG_DEC_SHIFT) & FIELDFLAG_MAX_DEC)) #define f_is_alpha(x) (!f_is_num(x)) -#define f_is_binary(x) ((x) & FIELDFLAG_BINARY) #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) diff --git a/sql/field_conv.cc b/sql/field_conv.cc index 53b26920c14..ab71f324732 100644 --- a/sql/field_conv.cc +++ b/sql/field_conv.cc @@ -245,7 +245,7 @@ static void do_conv_blob(Copy_field *copy) { copy->from_field->val_str(©->tmp,©->tmp); ((Field_blob *) copy->to_field)->store(copy->tmp.ptr(), - copy->tmp.length()); + copy->tmp.length(),default_charset_info); } /* Save blob in copy->tmp for GROUP BY */ @@ -253,20 +253,20 @@ static void do_conv_blob(Copy_field *copy) static void do_save_blob(Copy_field *copy) { char buff[MAX_FIELD_WIDTH]; - String res(buff,sizeof(buff)); + String res(buff,sizeof(buff),default_charset_info); copy->from_field->val_str(&res,&res); copy->tmp.copy(res); ((Field_blob *) copy->to_field)->store(copy->tmp.ptr(), - copy->tmp.length()); + copy->tmp.length(),default_charset_info); } static void do_field_string(Copy_field *copy) { char buff[MAX_FIELD_WIDTH]; - copy->tmp.set_quick(buff,sizeof(buff)); + copy->tmp.set_quick(buff,sizeof(buff),default_charset_info); copy->from_field->val_str(©->tmp,©->tmp); - copy->to_field->store(copy->tmp.c_ptr_quick(),copy->tmp.length()); + copy->to_field->store(copy->tmp.c_ptr_quick(),copy->tmp.length(),default_charset_info); } @@ -293,7 +293,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; @@ -525,7 +525,7 @@ void field_conv(Field *to,Field *from) if (!blob->value.is_alloced() && from->real_type() != FIELD_TYPE_STRING) blob->value.copy(); - blob->store(blob->value.ptr(),blob->value.length()); + blob->store(blob->value.ptr(),blob->value.length(),to->charset()); return; } if ((from->result_type() == STRING_RESULT && @@ -535,9 +535,10 @@ void field_conv(Field *to,Field *from) to->type() == FIELD_TYPE_DECIMAL) { char buff[MAX_FIELD_WIDTH]; - String result(buff,sizeof(buff)); + String result(buff,sizeof(buff),default_charset_info); from->val_str(&result,&result); - to->store(result.c_ptr_quick(),result.length()); + to->store(result.c_ptr_quick(),result.length(),to->charset()); + // QQ: what to do if "from" and "to" are of dirrent charsets? } else if (from->result_type() == REAL_RESULT) to->store(from->val_real()); diff --git a/sql/filesort.cc b/sql/filesort.cc index ad16c16db3e..fab666a1203 100644 --- a/sql/filesort.cc +++ b/sql/filesort.cc @@ -63,26 +63,31 @@ static uint sortlength(SORT_FIELD *sortorder,uint length); table->record_pointers */ -ha_rows filesort(TABLE *table, SORT_FIELD *sortorder, uint s_length, - SQL_SELECT *select, ha_rows special, ha_rows max_rows, - ha_rows *examined_rows) +ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length, + SQL_SELECT *select, ha_rows max_rows, ha_rows *examined_rows) { int error; ulong memavl; uint maxbuffer; + uint i; BUFFPEK *buffpek; ha_rows records; uchar **sort_keys; IO_CACHE tempfile, buffpek_pointers, *selected_records_file, *outfile; SORTPARAM param; - THD *thd= current_thd; - + CHARSET_INFO *charset=my_charset_bin; DBUG_ENTER("filesort"); - DBUG_EXECUTE("info",TEST_filesort(sortorder,s_length,special);); + DBUG_EXECUTE("info",TEST_filesort(sortorder,s_length);); #ifdef SKIP_DBUG_IN_FILESORT DBUG_PUSH(""); /* No DBUG here */ #endif + // BAR TODO: this is not absolutely correct, but OK for now + for(i=0;i<table->fields;i++) + if (!table->field[i]->binary()) + charset=table->field[i]->charset(); + // /BAR TODO + outfile= table->io_cache; my_b_clear(&tempfile); my_b_clear(&buffpek_pointers); @@ -102,27 +107,15 @@ ha_rows filesort(TABLE *table, SORT_FIELD *sortorder, uint s_length, { statistic_increment(filesort_scan_count, &LOCK_status); } - if (select && my_b_inited(&select->file)) - { - records=special=select->records; /* purecov: deadcode */ - selected_records_file= &select->file; /* purecov: deadcode */ - reinit_io_cache(selected_records_file,READ_CACHE,0L,0,0); /* purecov: deadcode */ - } - else if (special) - { - records=special; /* purecov: deadcode */ - selected_records_file= outfile; /* purecov: deadcode */ - reinit_io_cache(selected_records_file,READ_CACHE,0L,0,0); /* purecov: deadcode */ - } #ifdef CAN_TRUST_RANGE - else if (select && select->quick && select->quick->records > 0L) + if (select && select->quick && select->quick->records > 0L) { records=min((ha_rows) (select->quick->records*2+EXTRA_RECORDS*2), table->file->records)+EXTRA_RECORDS; selected_records_file=0; } -#endif else +#endif { records=table->file->estimate_number_of_rows(); selected_records_file= 0; @@ -131,7 +124,7 @@ ha_rows filesort(TABLE *table, SORT_FIELD *sortorder, uint s_length, records=param.max_rows; /* purecov: inspected */ #ifdef USE_STRCOLL - if (use_strcoll(default_charset_info) && + if (use_strnxfrm(charset) && !(param.tmp_buffer=my_malloc(param.sort_length,MYF(MY_WME)))) goto err; #endif @@ -208,7 +201,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); @@ -479,7 +472,7 @@ static void make_sortkey(register SORTPARAM *param, if (item->maybe_null) *to++=1; /* All item->str() to use some extra byte for end null.. */ - String tmp((char*) to,sort_field->length+4); + String tmp((char*) to,sort_field->length+4,default_charset_info); String *res=item->val_str(&tmp); if (!res) { @@ -494,6 +487,7 @@ static void make_sortkey(register SORTPARAM *param, break; } length=res->length(); + CHARSET_INFO *cs=res->charset(); int diff=(int) (sort_field->length-length); if (diff < 0) { @@ -501,9 +495,9 @@ static void make_sortkey(register SORTPARAM *param, length=sort_field->length; } #ifdef USE_STRCOLL - if (use_strcoll(default_charset_info)) + if(use_strnxfrm(cs)) { - if (item->binary) + if (item->binary()) { if (res->ptr() != (char*) to) memcpy(to,res->ptr(),length); @@ -518,10 +512,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); } @@ -532,8 +524,8 @@ static void make_sortkey(register SORTPARAM *param, if (res->ptr() != (char*) to) memcpy(to,res->ptr(),length); bzero((char *)to+length,diff); - if (!item->binary) - case_sort((char*) to,length); + if (!item->binary()) + my_tosort(cs, (char*) to,length); #ifdef USE_STRCOLL } #endif @@ -935,8 +927,12 @@ 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()) + { + CHARSET_INFO *cs=sortorder->field->charset(); + if (use_strnxfrm(cs)) + sortorder->length= sortorder->length*cs->strxfrm_multiply; + } #endif } if (sortorder->field->maybe_null()) @@ -944,12 +940,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->charset(); + if (use_strnxfrm(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 8139cf4fdb0..7daab228093 100644 --- a/sql/gen_lex_hash.cc +++ b/sql/gen_lex_hash.cc @@ -14,11 +14,68 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* + +The idea of presented algorithm see in +"The Art of Computer Programming" by Donald E. Knuth +Volume 3 "Sorting and searching" +(chapter 6.3 "Digital searching" - name and number of chapter + is back translation from Russian edition :)) + +as illustration of data structures, imagine next table: + +static SYMBOL symbols[] = { + { "ADD", SYM(ADD),0,0}, + { "AND", SYM(AND),0,0}, + { "DAY", SYM(DAY_SYM),0,0}, +}; + +for this structure, presented program generate next searching-structure: + ++-----------+-+-+-+ +| len |1|2|3| ++-----------+-+-+-+ +|first_char |0|0|a| +|last_char |0|0|d| +|link |0|0|+| + | + V + +----------+-+-+-+--+ + | 1 char|a|b|c|d | + +----------+-+-+-+--+ + |first_char|b|0|0|0 | + |last_char |n|0|0|-1| + |link |+|0|0|+ | + | | + | V + | symbols[2] ( "DAY" ) + V ++----------+--+-+-+-+-+-+-+-+-+-+--+ +| 2 char|d |e|f|j|h|i|j|k|l|m|n | ++----------+--+-+-+-+-+-+-+-+-+-+--+ +|first_char|0 |0|0|0|0|0|0|0|0|0|0 | +|last_char |-1|0|0|0|0|0|0|0|0|0|-1| +|link |+ |0|0|0|0|0|0|0|0|0|+ | + | | + V V + symbols[0] ( "ADD" ) symbols[1] ( "AND" ) + +for optimization, link is the 16-bit index in 'symbols' or 'sql_functions' +or search-array.. + +So, we can read full search-structure as 32-bit word + +TODO: +1. use instead to_upper_lex, special array + (substitute chars) without skip codes.. +2. try use reverse order of comparing.. + +*/ #define NO_YACC_SYMBOLS -#include <my_global.h> -#include <my_sys.h> -#include <m_string.h> +#include "my_global.h" +#include "my_sys.h" +#include "m_string.h" #ifndef __GNU_LIBRARY__ #define __GNU_LIBRARY__ // Skip warnings in getopt.h #endif @@ -26,324 +83,228 @@ #include "mysql_version.h" #include "lex.h" -my_bool opt_search; -int opt_verbose; -ulong opt_count; - -#define max_allowed_array 8000 // 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 -#define char_table_count 5 -#define total_symbols (sizeof(symbols)/sizeof(SYMBOL) +\ - sizeof(sql_functions)/sizeof(SYMBOL)) - -#define how_much_and INT_MAX24 - -/* - The following only have to work with characters in the set - used by SQL commands -*/ - -#undef tolower -#define tolower(a) ((a) >= 'A' && (a) <= 'Z') ? ((a)- 'A' + 'a') : (a) - -static uint how_long_symbols,function_plus,function_mod,function_type; -static uint char_table[256]; -static uchar unique_length[256]; -static uchar bits[how_much_and/8+1]; -static uint primes[max_allowed_array+1]; -static ulong hash_results[type_count][how_much_for_plus+1][total_symbols]; -static ulong start_value=0; -static uint best_type; -static ulong best_t1,best_t2, best_start_value; - static struct my_option my_long_options[] = { {"help", '?', "Display help and exit", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"count", 'c', "Try count times to find a optimal hash table", - (gptr*) &opt_count, (gptr*) &opt_count, 0, GET_ULONG, REQUIRED_ARG, - 100000, 0, 0, 0, 0, 0}, - {"search", 'S', "Search after good rnd1 and rnd2 values", - (gptr*) &opt_search, (gptr*) &opt_search, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, - 0, 0}, - {"verbose", 'v', "Write some information while the program executes", - (gptr*) &opt_verbose, (gptr*) &opt_verbose, 0, GET_INT, NO_ARG, 0, 0, 0, - 0, 0, 0}, {"version", 'V', "Output version information and exit", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, - { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} }; -struct rand_struct { - unsigned long seed1,seed2,max_value; - double max_value_dbl; +struct hash_lex_struct +{ + char first_char; + char last_char; + union{ + hash_lex_struct *char_tails; + int iresult; + }; + int ithis; }; - -void randominit(struct rand_struct *rand_st,ulong seed1, ulong seed2) -{ /* For mysql 3.21.# */ - rand_st->max_value= 0x3FFFFFFFL; - rand_st->max_value_dbl=(double) rand_st->max_value; - rand_st->seed1=seed1%rand_st->max_value ; - rand_st->seed2=seed2%rand_st->max_value; -} - -double rnd(struct rand_struct *rand_st) + +hash_lex_struct *get_hash_struct_by_len(hash_lex_struct **root_by_len, + int len, int *max_len) { - rand_st->seed1=(rand_st->seed1*3+rand_st->seed2) % rand_st->max_value; - rand_st->seed2=(rand_st->seed1+rand_st->seed2+33) % rand_st->max_value; - return (((double) rand_st->seed1)/rand_st->max_value_dbl); + if (*max_len<len){ + *root_by_len= (hash_lex_struct *)realloc((char*)*root_by_len, + sizeof(hash_lex_struct)*len); + hash_lex_struct *cur, *end= *root_by_len + len; + for (cur= *root_by_len + *max_len; cur<end; cur++) + cur->first_char= 0; + *max_len= len; + } + return (*root_by_len)+(len-1); } - -static void make_char_table(ulong t1,ulong t2,int type) +void insert_into_hash(hash_lex_struct *root, const char *name, + int len_from_begin, int index, int function) { - uint i; - struct rand_struct rand_st; - randominit(&rand_st,t1,t2); + hash_lex_struct *end, *cur, *tails; - for (i=0 ; i < 256 ; i++) - { - switch (type) { - case 0: char_table[i]= i + (i << 8); break; - case 1: char_table[i]= i + ((i ^255 ) << 8); break; - case 2: char_table[i]= i; break; - case 3: char_table[i]= i + ((uint) (rnd(&rand_st)*255) << 8); break; - case 4: char_table[i]= (uint) (rnd(&rand_st)*255) + (i << 8); break; - } - } - char_table[0]|=1+257; // Avoid problems with 0 - for (i=0 ; i < 256 ; i++) - { - uint tmp=(uint) (rnd(&rand_st)*255); - swap(uint,char_table[i],char_table[tmp]); - } - /* lower characters should be mapped to upper */ - for (i= 'a' ; i <= 'z' ; i++) - { - /* This loop is coded with extra variables to avoid a bug in gcc 2.96 */ - uchar tmp= (uchar) (i - 'a'); // Assume ascii - tmp+='A'; - char_table[i]=char_table[tmp]; + if (!root->first_char){ + root->first_char= -1; + root->iresult= index; + return; } -} -/* Fill array primes with primes between start and 'max_allowed_array' */ - -static void make_prime_array(uint start) -{ - uint i,j,*to; - uint max_index=(uint) sqrt((double) max_allowed_array); + if (root->first_char==-1){ + int index2= root->iresult; + const char *name2= + (index2<0 ? sql_functions[-index2-1] : symbols[index2]).name + len_from_begin; + root->first_char= name2[0]; + root->last_char= root->first_char; + tails= (hash_lex_struct*)malloc(sizeof(hash_lex_struct)); + root->char_tails= tails; + tails->first_char= -1; + tails->iresult= index2; + } - bzero((char*) primes,sizeof(primes[0])*max_allowed_array); + size_t real_size= (root->last_char-root->first_char+1); + + if (root->first_char>(*name)){ + size_t new_size= root->last_char-(*name)+1; + if (new_size<real_size) printf("error!!!!\n"); + tails= root->char_tails; + tails= (hash_lex_struct*)realloc((char*)tails, + sizeof(hash_lex_struct)*new_size); + root->char_tails= tails; + memmove(tails+(new_size-real_size),tails,real_size*sizeof(hash_lex_struct)); + end= tails + new_size - real_size; + for (cur= tails; cur<end; cur++) + cur->first_char= 0; + root->first_char= (*name); + } - i=2; - while (i < max_index) - { - for (j=i+i ; j <= max_allowed_array ; j+=i) - primes[j]=1; - while (primes[++i]) ; + if (root->last_char<(*name)){ + size_t new_size= (*name)-root->first_char+1; + if (new_size<real_size) printf("error!!!!\n"); + tails= root->char_tails; + tails= (hash_lex_struct*)realloc((char*)tails, + sizeof(hash_lex_struct)*new_size); + root->char_tails= tails; + end= tails + new_size; + for (cur= tails+real_size; cur<end; cur++) + cur->first_char= 0; + root->last_char= (*name); } - to=primes; - for (i=start ; i <= max_allowed_array ; i++) - if (!primes[i]) - *to++=i; - *to=0; // end marker + insert_into_hash (root->char_tails+(*name)-root->first_char, + name+1,len_from_begin+1,index,function); } -#define USE_char_table +hash_lex_struct *root_by_len= 0; +int max_len=0; -static ulong tab_index_function(const char *s,uint add, uint type) +hash_lex_struct *root_by_len2= 0; +int max_len2=0; + +void insert_symbols() { - register ulong nr=start_value+char_table[(uchar) *s]; // Nice value - ulong pos=3; - uint tmp_length=unique_length[(uchar) *s]-1; - while (*++s && tmp_length-- > 0) - { - switch (type) { - case 0: - nr= (nr ^ (char_table[(uchar) *s] + (nr << add))); - break; - case 1: - nr= (nr + (char_table[(uchar) *s] + (nr << add))); - break; - case 2: - nr= (nr ^ (char_table[(uchar) *s] ^ (nr << add))); - break; - case 3: - nr= (char_table[(uchar) *s] ^ (nr << add)); - break; - case 4: - nr+= nr+nr+((nr & 63)+pos)*((ulong) char_table[(uchar) *s]); - pos+=add; - break; - } + size_t i= 0; + SYMBOL *cur; + for (cur= symbols; i<array_elements(symbols); cur++, i++){ + hash_lex_struct *root= + get_hash_struct_by_len(&root_by_len,cur->length,&max_len); + insert_into_hash(root,cur->name,0,i,0); } - return nr & INT_MAX24; } -static int search(bool write_warning) +void insert_sql_functions() { - uint size_symbols = sizeof(symbols)/sizeof(SYMBOL); - uint size_functions = sizeof(sql_functions)/sizeof(SYMBOL); - uint size=size_symbols + size_functions; - uint i=0,found,*prime,type; - int igra[max_allowed_array],test_count=INT_MAX; - uint possible_plus[how_much_for_plus*type_count+type_count]; + size_t i= 0; + SYMBOL *cur; + for (cur= sql_functions; i<array_elements(sql_functions); cur++, i++){ + hash_lex_struct *root= + get_hash_struct_by_len(&root_by_len,cur->length,&max_len); + insert_into_hash(root,cur->name,0,-i-1,1); + } +} - how_long_symbols = sizeof(symbols)/sizeof(SYMBOL); +void generate_find_structs() +{ + root_by_len= 0; + max_len=0; + size_t i; + + SYMBOL *cur, *end= symbols + array_elements(symbols); + for (cur= symbols; cur < end; cur++) + cur->length=(uchar) strlen(cur->name); + end= sql_functions + array_elements(sql_functions); + for (cur= sql_functions; cur<end; cur++) + cur->length=(uchar) strlen(cur->name); + + insert_symbols(); + + root_by_len2= root_by_len; + max_len2= max_len; + + root_by_len= 0; + max_len= 0; + + insert_symbols(); + insert_sql_functions(); +} - bzero((char*) possible_plus,sizeof(possible_plus)); - found=0; +char *hash_map= 0; +int size_hash_map= 0; - /* Check first which function_plus are possible */ - for (type=0 ; type < type_count ; type ++) +void add_struct_to_map(hash_lex_struct *st) +{ + st->ithis= size_hash_map/4; + size_hash_map+= 4; + hash_map= (char*)realloc((char*)hash_map,size_hash_map); + hash_map[size_hash_map-4]= st->first_char==-1 ? 0 : st->first_char; + hash_map[size_hash_map-3]= + st->first_char==-1 || st->first_char==0 ? 0 : st->last_char; + if (st->first_char==-1) { - for (function_plus = 1; - function_plus <= how_much_for_plus; - function_plus++) - { - bzero((char*) bits,sizeof(bits)); - for (i=0; i < size; i++) - { - ulong order= tab_index_function ((i < how_long_symbols) ? - symbols[i].name : - sql_functions[i-how_long_symbols].name, - function_plus, type); - hash_results[type][function_plus][i]=order; - uint pos=order/8; - uint bit=order & 7; - if (bits[pos] & (1 << bit)) - break; - bits[pos]|=1 << bit; - } - if (i == size) - { - possible_plus[found++]=function_plus; - } - } - possible_plus[found++]=0; // End marker + hash_map[size_hash_map-2]= ((unsigned int)(int16)st->iresult)&255; + hash_map[size_hash_map-1]= ((unsigned int)(int16)st->iresult)>>8; } - if (found == type_count) + else if (st->first_char==0) { - if (write_warning) - fprintf(stderr,"\ -The hash function didn't return a unique value for any parameter\n\ -You have to change gen_lex_code.cc, function 'tab_index_function' to\n\ -generate unique values for some parameter. When you have succeeded in this,\n\ -you have to change 'main' to print out the new function\n"); - return(1); + hash_map[size_hash_map-2]= ((unsigned int)(int16)array_elements(symbols))&255; + hash_map[size_hash_map-1]= ((unsigned int)(int16)array_elements(symbols))>>8; } +}; - if (opt_verbose > 1) - fprintf (stderr,"Info: Possible add values: %d\n",found-type_count); +void add_structs_to_map(hash_lex_struct *st, int len) +{ + hash_lex_struct *cur, *end= st+len; + for (cur= st; cur<end; cur++) + add_struct_to_map(cur); + for (cur= st; cur<end; cur++) + if (cur->first_char && cur->first_char!=-1) + add_structs_to_map(cur->char_tails,cur->last_char-cur->first_char+1); +} - for (prime=primes; (function_mod=*prime) ; prime++) - { - uint *plus_ptr=possible_plus; - for (type=0 ; type < type_count ; type++ ) - { - while ((function_plus= *plus_ptr++)) - { - ulong *order_pos= &hash_results[type][function_plus][0]; - if (test_count++ == INT_MAX) - { - test_count=1; - bzero((char*) igra,sizeof(igra)); - } - for (i=0; i<size ;i++) - { - ulong order; - order = *order_pos++ % function_mod; - if (igra[order] == test_count) - break; - igra[order] = test_count; - } - if (i == size) - { - *prime=0; // Mark this used - function_type=type; - return 0; // Found ok value - } - } +void set_links(hash_lex_struct *st, int len) +{ + hash_lex_struct *cur, *end= st+len; + for (cur= st; cur<end; cur++) + if (cur->first_char!=0 && cur->first_char!=-1){ + int ilink= cur->char_tails->ithis; + hash_map[cur->ithis*4+2]= ilink%256; + hash_map[cur->ithis*4+3]= ilink/256; + set_links(cur->char_tails,cur->last_char-cur->first_char+1); } - } - - function_mod=max_allowed_array; - if (write_warning) - fprintf (stderr,"Fatal error when generating hash for symbols\n\ -Didn't find suitable values for perfect hashing:\n\ -You have to edit gen_lex_hash.cc to generate a new hashing function.\n\ -You can try running gen_lex_hash with --search to find a suitable value\n\ -Symbol array size = %d\n",function_mod); - return -1; } - -void print_arrays() +void print_hash_map(const char *name) { - uint size_symbols = sizeof(symbols)/sizeof(SYMBOL); - uint size_functions = sizeof(sql_functions)/sizeof(SYMBOL); - uint size=size_symbols + size_functions; - uint i; - - fprintf(stderr,"Symbols: %d Functions: %d; Total: %d\nShifts per char: %d, Array size: %d\n", - size_symbols,size_functions,size_symbols+size_functions, - function_plus,function_mod); - - int *prva= (int*) my_alloca(sizeof(int)*function_mod); - for (i=0 ; i <= function_mod; i++) - prva[i]= max_symbol; - - for (i=0;i<size;i++) - { - const char *name= ((i < how_long_symbols) ? - symbols[i].name : - sql_functions[i - how_long_symbols].name); - ulong order = tab_index_function(name,function_plus,function_type); - order %= function_mod; - /* This should never be true */ - if (prva[order] != max_symbol) - { - fprintf(stderr,"Error: Got duplicate value for symbol '%s'\n",name); - exit(1); + printf("uchar %s[%d]= {\n",name,size_hash_map); + char *cur; + int i; + for (i=0, cur= hash_map; i<size_hash_map; i++, cur++){ + switch(i%4){ + case 0: case 1: + if (!*cur) + printf("0, "); + else + printf("\'%c\', ",*cur); + break; + case 2: printf("%u, ",(uint)(uchar)*cur); break; + case 3: printf("%u,\n",(uint)(uchar)*cur); break; } - prva [order] = i; } + printf("};\n"); +} -#ifdef USE_char_table - printf("static uint16 char_table[] = {\n"); - for (i=0; i < 255 ;i++) // < 255 is correct - { - printf("%u,",char_table[i]); - if (((i+1) & 15) == 0) - puts(""); - } - printf("%d\n};\n\n\n",char_table[i]); -#endif +void print_find_structs() +{ + add_structs_to_map(root_by_len,max_len); + set_links(root_by_len,max_len); + print_hash_map("sql_functions_map"); - printf("static uchar unique_length[] = {\n"); - for (i=0; i < 255 ;i++) // < 255 is correct - { - printf("%u,",unique_length[i]); - if (((i+1) & 15) == 0) - puts(""); - } - printf("%d\n};\n\n\n",unique_length[i]); + hash_map= 0; + size_hash_map= 0; - printf("static uint16 my_function_table[] = {\n"); - for (i=0; i < function_mod-1 ;i++) - { - printf("%d,",prva[i]); - if (((i+1) % 12) == 0) - puts(""); - } - printf("%d\n};\n\n\n",prva[i]); - my_afree((gptr) prva); -} + printf("\n"); + add_structs_to_map(root_by_len2,max_len2); + set_links(root_by_len2,max_len2); + print_hash_map("symbols_map"); +} static void usage(int version) { @@ -351,23 +312,19 @@ static void usage(int version) my_progname, MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE); if (version) return; - puts("Copyright (C) 2001 MySQL AB, by Sinisa and Monty"); - puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,\nand you are welcome to modify and redistribute it under the GPL license\n"); + puts("Copyright (C) 2001 MySQL AB, by VVA and Monty"); + puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,\n\ +and you are welcome to modify and redistribute it under the GPL license\n"); puts("This program generates a perfect hashing function for the sql_lex.cc"); printf("Usage: %s [OPTIONS]\n\n", my_progname); my_print_help(my_long_options); - my_print_variables(my_long_options); } - extern "C" my_bool get_one_option(int optid, const struct my_option *opt __attribute__((unused)), char *argument __attribute__((unused))) { - switch (optid) { - case 'v': - opt_verbose++; - break; + switch(optid) { case 'V': usage(1); exit(0); @@ -379,7 +336,6 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), return 0; } - static int get_options(int argc, char **argv) { int ho_error; @@ -389,139 +345,19 @@ static int get_options(int argc, char **argv) if (argc >= 1) { - fprintf(stderr,"%s: Too many arguments\n", my_progname); usage(0); - exit(1); + exit(1); } return(0); } -static uint max_prefix(const char *name) -{ - uint i; - uint max_length=1; - for (i=0 ; i < sizeof(symbols)/sizeof(SYMBOL) ; i++) - { - const char *str=symbols[i].name; - if (str != name) - { - const char *str2=name; - uint length; - while (*str && *str == *str2) - { - str++; - str2++; - } - length=(uint) (str2 - name)+1; - if (length > max_length) - max_length=length; - } - } - for (i=0 ; i < sizeof(sql_functions)/sizeof(SYMBOL) ; i++) - { - const char *str=sql_functions[i].name; - if (str != name) - { - const char *str2=name; - uint length; - while (*str && *str == *str2) - { - str++; - str2++; - } - length=(uint) (str2 - name)+1; - if (length > max_length) - max_length=length; - } - } - return max_length; -} - - -static void make_max_length_table(void) -{ - uint i; - for (i=0 ; i < sizeof(symbols)/sizeof(SYMBOL) ; i++) - { - uint length=max_prefix(symbols[i].name); - if (length > unique_length[(uchar) symbols[i].name[0]]) - { - unique_length[(uchar) symbols[i].name[0]]=length; - unique_length[(uchar) tolower(symbols[i].name[0])]=length; - } - } - for (i=0 ; i < sizeof(sql_functions)/sizeof(SYMBOL) ; i++) - { - uint length=max_prefix(sql_functions[i].name); - if (length > unique_length[(uchar) sql_functions[i].name[0]]) - { - unique_length[(uchar) sql_functions[i].name[0]]=length; - unique_length[(uchar) tolower(sql_functions[i].name[0])]=length; - } - } -} - - int main(int argc,char **argv) { - struct rand_struct rand_st; - static uint best_mod,best_add,best_functype; - int error; - MY_INIT(argv[0]); - start_value=2925024L; best_t1=654916L; best_t2=1723390L; best_type=3; /* mode=4943 add=1 type: 0 */ + if (get_options(argc,(char **) argv)) exit(1); - make_max_length_table(); - make_char_table(best_t1,best_t2,best_type); - make_prime_array(sizeof(symbols)/sizeof(SYMBOL) + - sizeof(sql_functions)/sizeof(SYMBOL)); - - if ((error=search(1)) > 0 || error && !opt_search) - exit(1); // This should work - best_mod=function_mod; best_add=function_plus; best_functype=function_type; - - if (opt_search) - { - time_t start_time=time((time_t*) 0); - randominit(&rand_st,start_time,start_time/2); // Some random values - printf("start_value=%ldL; best_t1=%ldL; best_t2=%ldL; best_type=%d; /* mode=%d add=%d type: %d */\n", - start_value, best_t1,best_t2,best_type,best_mod,best_add, - best_functype); - best_start_value=start_value; - for (uint i=1 ; i <= opt_count ; i++) - { - if (i % 10 == 0) - { - putchar('.'); - fflush(stdout); - } - ulong t1=(ulong) (rnd(&rand_st)*INT_MAX24); - ulong t2=(ulong) (rnd(&rand_st)*INT_MAX24); - uint type=(int) (rnd(&rand_st)*char_table_count); - start_value=(ulong) (rnd(&rand_st)*INT_MAX24); - make_char_table(t1,t2,type); - if (!search(0)) - { - best_mod=function_mod; best_add=function_plus; - best_functype=function_type; - best_t1=t1; best_t2=t2; best_type=type; - best_start_value=start_value; - printf("\nstart_value=%ldL; best_t1=%ldL; best_t2=%ldL; best_type=%d; /* mode=%d add=%d type: %d */\n", - best_start_value,best_t1,best_t2,best_type,best_mod,best_add, - best_functype); - } - if (opt_verbose && (i % 20000) == 0) - printf("\nstart_value=%ldL; best_t1=%ldL; best_t2=%ldL; best_type=%d; /* mode=%d add=%d type: %d */\n", - best_start_value,best_t1,best_t2,best_type,best_mod,best_add, - best_functype); - } - } - - function_mod=best_mod; function_plus=best_add; - make_char_table(best_t1,best_t2,best_type); - printf("/* Copyright (C) 2001 MySQL AB\n\ This program is free software; you can redistribute it and/or modify\n\ it under the terms of the GNU General Public License as published by\n\ @@ -533,38 +369,84 @@ int main(int argc,char **argv) GNU General Public License for more details.\n\n\ You should have received a copy of the GNU General Public License\n\ along with this program; if not, write to the Free Software\n\ - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */\n\n"); + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307\ + USA */\n\n"); -printf("/* This code is generated by gen_lex_hash.cc that seeks for a perfect\nhash function */\n\n"); + printf("/* This code is generated by gen_lex_hash.cc that seeks for\ + a perfect\nhash function */\n\n"); printf("#include \"lex.h\"\n\n"); - print_arrays(); + generate_find_structs(); + print_find_structs(); - printf("/* start_value=%ldL; best_t1=%ldL; best_t2=%ldL; best_type=%d; */ /* mode=%d add=%d type: %d */\n\n", - best_start_value, best_t1, best_t2, best_type, - best_mod, best_add, best_functype); + printf("\nunsigned int sql_functions_max_len=%d;\n",max_len); + printf("\nunsigned int symbols_max_len=%d;\n\n",max_len2); - printf("inline SYMBOL *get_hash_symbol(const char *s,unsigned int length,bool function)\n\ + printf +( +"inline SYMBOL *get_hash_symbol(const char *s,\n\ + unsigned int len,bool function)\n\ {\n\ - ulong idx = %lu+char_table[(uchar) *s];\n\ - SYMBOL *sim;\n\ - const char *start=s;\n\ - int i=unique_length[(uchar) *s++];\n\ - if (i > (int) length) i=(int) length;\n\ - while (--i > 0)\n\ - idx= (idx ^ (char_table[(uchar) *s++] + (idx << %d)));\n\ - idx=my_function_table[(idx & %d) %% %d];\n\ - if (idx >= %d)\n\ - {\n\ - if (!function || idx >= %d) return (SYMBOL*) 0;\n\ - sim=sql_functions + (idx - %d);\n\ + register uchar *hash_map;\n\ + register const char *cur_str= s;\n\ + if (function){\n\ + if (len>sql_functions_max_len) return 0;\n\ + hash_map= sql_functions_map;\n\ + register uint32 cur_struct= uint4korr(hash_map+((len-1)*4));\n\ +\n\ + for(;;){\n\ + register uchar first_char= (uchar)cur_struct;\n\ +\n\ + if (first_char==0){\n\ + register int16 ires= (int16)(cur_struct>>16);\n\ + if (ires==array_elements(symbols)) return 0;\n\ + register SYMBOL *res;\n\ + if (ires>=0) \n\ + res= symbols+ires;\n\ + else\n\ + res= sql_functions-ires-1;\n\ + register uint count= cur_str-s;\n\ + return lex_casecmp(cur_str,res->name+count,len-count) ? 0 : res;\n\ + }\n\ +\n\ + register uchar cur_char= (uchar)to_upper_lex[(uchar)*cur_str];\n\ + if (cur_char<first_char) return 0;\n\ + cur_struct>>=8;\n\ + if (cur_char>(uchar)cur_struct) return 0;\n\ +\n\ + cur_struct>>=8;\n\ + cur_struct= uint4korr(hash_map+\n\ + (((uint16)cur_struct + cur_char - first_char)*4));\n\ + cur_str++;\n\ + }\n\ + }else{\n\ + if (len>symbols_max_len) return 0;\n\ + hash_map= symbols_map;\n\ + register uint32 cur_struct= uint4korr(hash_map+((len-1)*4));\n\ +\n\ + for(;;){\n\ + register uchar first_char= (uchar)cur_struct;\n\ +\n\ + if (first_char==0){\n\ + register int16 ires= (int16)(cur_struct>>16);\n\ + if (ires==array_elements(symbols)) return 0;\n\ + register SYMBOL *res= symbols+ires;\n\ + register uint count= cur_str-s;\n\ + return lex_casecmp(cur_str,res->name+count,len-count)!=0 ? 0 : res;\n\ + }\n\ +\n\ + register uchar cur_char= (uchar)to_upper_lex[(uchar)*cur_str];\n\ + if (cur_char<first_char) return 0;\n\ + cur_struct>>=8;\n\ + if (cur_char>(uchar)cur_struct) return 0;\n\ +\n\ + cur_struct>>=8;\n\ + cur_struct= uint4korr(hash_map+\n\ + (((uint16)cur_struct + cur_char - first_char)*4));\n\ + cur_str++;\n\ + }\n\ }\n\ - else\n\ - sim=symbols + idx;\n\ - if ((length != sim->length) || lex_casecmp(start,sim->name,length))\n\ - return (SYMBOL *)0;\n\ - return sim;\n\ -}\n",(ulong) start_value,(int) function_plus,(int) how_much_and,function_mod,how_long_symbols,max_symbol,how_long_symbols); - exit(0); - return 0; +}\n" +); } + diff --git a/sql/gstream.cc b/sql/gstream.cc new file mode 100644 index 00000000000..bd2345212c3 --- /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 = my_strtod(my_charset_latin1, 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..f26ef8899f8 --- /dev/null +++ b/sql/gstream.h @@ -0,0 +1,69 @@ +/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */ + + +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; +}; diff --git a/sql/ha_berkeley.cc b/sql/ha_berkeley.cc index 06acf4fa2e3..679642ca949 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); @@ -194,12 +194,12 @@ bool berkeley_flush_logs() int error; bool result=0; DBUG_ENTER("berkeley_flush_logs"); - if ((error=log_flush(db_env,0))) + if ((error=db_env->log_flush(db_env,0))) { my_error(ER_ERROR_DURING_FLUSH_LOGS,MYF(0),error); /* purecov: inspected */ result=1; /* purecov: inspected */ } - if ((error=txn_checkpoint(db_env,0,0,0))) + if ((error=db_env->txn_checkpoint(db_env,0,0,0))) { my_error(ER_ERROR_DURING_CHECKPOINT,MYF(0),error); /* purecov: inspected */ result=1; /* purecov: inspected */ @@ -243,10 +243,8 @@ int berkeley_show_logs(THD *thd) init_alloc_root(&show_logs_root, 1024, 1024); my_pthread_setspecific_ptr(THR_MALLOC,&show_logs_root); - if ((error= log_archive(db_env, &all_logs, DB_ARCH_ABS | DB_ARCH_LOG, - (void* (*)(size_t)) sql_alloc)) || - (error= log_archive(db_env, &free_logs, DB_ARCH_ABS, - (void* (*)(size_t)) sql_alloc))) + if ((error= db_env->log_archive(db_env, &all_logs, DB_ARCH_ABS | DB_ARCH_LOG)) + || (error= db_env->log_archive(db_env, &free_logs, DB_ARCH_ABS))) { DBUG_PRINT("error", ("log_archive failed (error %d)", error)); db_env->err(db_env, error, "log_archive: DB_ARCH_ABS"); @@ -309,10 +307,10 @@ void berkeley_cleanup_log_files(void) /* XXX: Probably this should be done somewhere else, and * should be tunable by the user. */ - if ((error = txn_checkpoint(db_env, 0, 0, 0))) + if ((error = db_env->txn_checkpoint(db_env, 0, 0, 0))) my_error(ER_ERROR_DURING_CHECKPOINT, MYF(0), error); /* purecov: inspected */ - if ((error = log_archive(db_env, &names, DB_ARCH_ABS, NULL)) != 0) + if ((error = db_env->log_archive(db_env, &names, DB_ARCH_ABS)) != 0) { DBUG_PRINT("error", ("log_archive failed (error %d)", error)); /* purecov: inspected */ db_env->err(db_env, error, "log_archive: DB_ARCH_ABS"); /* purecov: inspected */ @@ -512,9 +510,11 @@ int ha_berkeley::open(const char *name, int mode, uint test_if_locked) berkeley_cmp_packed_key)); if (!hidden_primary_key) file->app_private= (void*) (table->key_info+table->primary_key); - if ((error=(file->open(file, fn_format(name_buff,name,"", ha_berkeley_ext, - 2 | 4), - "main", DB_BTREE, open_mode,0)))) + if ((error= txn_begin(db_env, 0, (DB_TXN**) &transaction, 0)) || + (error= (file->open(file, transaction, + fn_format(name_buff, name, "", ha_berkeley_ext, 2 | 4), + "main", DB_BTREE, open_mode, 0))) || + (error= transaction->commit(transaction, 0))) { free_share(share,table, hidden_primary_key,1); /* purecov: inspected */ my_free((char*) rec_buff,MYF(0)); /* purecov: inspected */ @@ -545,8 +545,10 @@ int ha_berkeley::open(const char *name, int mode, uint test_if_locked) (*ptr)->app_private= (void*) (table->key_info+i); if (!(table->key_info[i].flags & HA_NOSAME)) (*ptr)->set_flags(*ptr, DB_DUP); - if ((error=((*ptr)->open(*ptr, name_buff, part, DB_BTREE, - open_mode, 0)))) + if ((error= txn_begin(db_env, 0, (DB_TXN**) &transaction, 0)) || + (error=((*ptr)->open(*ptr, transaction, name_buff, part, DB_BTREE, + open_mode, 0))) || + (error= transaction->commit(transaction, 0))) { close(); /* purecov: inspected */ my_errno=error; /* purecov: inspected */ @@ -1836,7 +1838,7 @@ static int create_sub_table(const char *table_name, const char *sub_name, if (!(error=db_create(&file, db_env, 0))) { file->set_flags(file, flags); - error=(file->open(file, table_name, sub_name, type, + error=(file->open(file, NULL, table_name, sub_name, type, DB_THREAD | DB_CREATE, my_umask)); if (error) { @@ -1892,7 +1894,7 @@ int ha_berkeley::create(const char *name, register TABLE *form, DB *status_block; if (!db_create(&status_block, db_env, 0)) { - if (!status_block->open(status_block, name_buff, + if (!status_block->open(status_block, NULL, name_buff, "status", DB_BTREE, DB_CREATE, 0)) { char rec_buff[4+MAX_KEY*4]; @@ -2080,7 +2082,7 @@ int ha_berkeley::analyze(THD* thd, HA_CHECK_OPT* check_opt) free(stat); stat=0; } - if (key_file[i]->stat(key_file[i], (void*) &stat, 0, 0)) + if (key_file[i]->stat(key_file[i], (void*) &stat, 0)) goto err; /* purecov: inspected */ share->rec_per_key[i]= (stat->bt_ndata / (stat->bt_nkeys ? stat->bt_nkeys : 1)); @@ -2093,7 +2095,7 @@ int ha_berkeley::analyze(THD* thd, HA_CHECK_OPT* check_opt) free(stat); stat=0; } - if (file->stat(file, (void*) &stat, 0, 0)) + if (file->stat(file, (void*) &stat, 0)) goto err; /* purecov: inspected */ } pthread_mutex_lock(&share->mutex); @@ -2296,7 +2298,7 @@ void ha_berkeley::get_status() fn_format(name_buff, share->table_name,"", ha_berkeley_ext, 2 | 4); if (!db_create(&share->status_block, db_env, 0)) { - if (share->status_block->open(share->status_block, name_buff, + if (share->status_block->open(share->status_block, NULL, name_buff, "status", DB_BTREE, open_mode, 0)) { share->status_block->close(share->status_block, 0); /* purecov: inspected */ @@ -2372,7 +2374,7 @@ static void update_status(BDB_SHARE *share, TABLE *table) if (db_create(&share->status_block, db_env, 0)) /* purecov: inspected */ goto end; /* purecov: inspected */ share->status_block->set_flags(share->status_block,0); /* purecov: inspected */ - if (share->status_block->open(share->status_block, + if (share->status_block->open(share->status_block, NULL, fn_format(name_buff,share->table_name,"", ha_berkeley_ext,2 | 4), "status", DB_BTREE, diff --git a/sql/ha_heap.cc b/sql/ha_heap.cc index 2edc3b1478e..4a3b9495f6f 100644 --- a/sql/ha_heap.cc +++ b/sql/ha_heap.cc @@ -33,69 +33,14 @@ const char **ha_heap::bas_ext() const int ha_heap::open(const char *name, int mode, uint test_if_locked) { - uint key,parts,mem_per_row=0; - ulong max_rows; - HP_KEYDEF *keydef; - HP_KEYSEG *seg; - THD *thd= current_thd; - - for (key=parts=0 ; key < table->keys ; key++) - parts+=table->key_info[key].key_parts; - - if (!(keydef=(HP_KEYDEF*) my_malloc(table->keys*sizeof(HP_KEYDEF)+ - parts*sizeof(HP_KEYSEG),MYF(MY_WME)))) - return my_errno; - seg=my_reinterpret_cast(HP_KEYSEG*) (keydef+table->keys); - for (key=0 ; key < table->keys ; key++) + if (!(file= heap_open(name, mode)) && my_errno == ENOENT) { - KEY *pos=table->key_info+key; - KEY_PART_INFO *key_part= pos->key_part; - KEY_PART_INFO *key_part_end= key_part+pos->key_parts; - - mem_per_row += (pos->key_length + (sizeof(char*) * 2)); - - keydef[key].keysegs=(uint) pos->key_parts; - keydef[key].flag = (pos->flags & (HA_NOSAME | HA_NULL_ARE_EQUAL)); - keydef[key].seg=seg; - - for (; key_part != key_part_end ; key_part++, seg++) - { - uint flag=key_part->key_type; - Field *field=key_part->field; - if (!f_is_packed(flag) && - f_packtype(flag) == (int) FIELD_TYPE_DECIMAL && - !(flag & FIELDFLAG_BINARY)) - seg->type= (int) HA_KEYTYPE_TEXT; - else - seg->type= (int) HA_KEYTYPE_BINARY; - seg->start=(uint) key_part->offset; - seg->length=(uint) key_part->length; - if (field->null_ptr) - { - seg->null_bit=field->null_bit; - seg->null_pos= (uint) (field->null_ptr- - (uchar*) table->record[0]); - } - else - { - seg->null_bit=0; - seg->null_pos=0; - } - } + HA_CREATE_INFO create_info; + bzero(&create_info, sizeof(create_info)); + if (!create(name, table, &create_info)) + file= heap_open(name, mode); } - mem_per_row += MY_ALIGN(table->reclength+1, sizeof(char*)); - max_rows = (ulong) (thd->variables.max_heap_table_size / mem_per_row); - file=heap_open(name,mode, - table->keys,keydef, - table->reclength, - (ulong) ((table->max_rows < max_rows && table->max_rows) ? - table->max_rows : max_rows), - (ulong) table->min_rows); - my_free((gptr) keydef,MYF(0)); - if (file) - info(HA_STATUS_NO_LOCK | HA_STATUS_CONST | HA_STATUS_VARIABLE); - ref_length=sizeof(HEAP_PTR); - return (!file ? errno : 0); + return (file ? 0 : 1); } int ha_heap::close(void) @@ -108,6 +53,8 @@ int ha_heap::write_row(byte * buf) statistic_increment(ha_write_count,&LOCK_status); if (table->time_stamp) update_timestamp(buf+table->time_stamp-1); + if (table->next_number_field && buf == table->record[0]) + update_auto_increment(); return heap_write(file,buf); } @@ -125,25 +72,21 @@ int ha_heap::delete_row(const byte * buf) return heap_delete(file,buf); } -int ha_heap::index_read(byte * buf, const byte * key, - uint key_len __attribute__((unused)), - enum ha_rkey_function find_flag - __attribute__((unused))) +int ha_heap::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=heap_rkey(file,buf,active_index, key); - table->status=error ? STATUS_NOT_FOUND: 0; + statistic_increment(ha_read_key_count, &LOCK_status); + int error = heap_rkey(file,buf,active_index, key, key_len, find_flag); + table->status = error ? STATUS_NOT_FOUND : 0; return error; } int ha_heap::index_read_idx(byte * buf, uint index, const byte * key, - uint key_len __attribute__((unused)), - enum ha_rkey_function find_flag - __attribute__((unused))) + uint key_len, enum ha_rkey_function find_flag) { - statistic_increment(ha_read_key_count,&LOCK_status); - int error=heap_rkey(file, buf, index, key); - table->status=error ? STATUS_NOT_FOUND: 0; + statistic_increment(ha_read_key_count, &LOCK_status); + int error = heap_rkey(file, buf, index, key, key_len, find_flag); + table->status = error ? STATUS_NOT_FOUND : 0; return error; } @@ -167,7 +110,7 @@ int ha_heap::index_prev(byte * buf) int ha_heap::index_first(byte * buf) { statistic_increment(ha_read_first_count,&LOCK_status); - int error=heap_rfirst(file, buf); + int error=heap_rfirst(file, buf, active_index); table->status=error ? STATUS_NOT_FOUND: 0; return error; } @@ -175,7 +118,7 @@ int ha_heap::index_first(byte * buf) int ha_heap::index_last(byte * buf) { statistic_increment(ha_read_last_count,&LOCK_status); - int error=heap_rlast(file, buf); + int error=heap_rlast(file, buf, active_index); table->status=error ? STATUS_NOT_FOUND: 0; return error; } @@ -222,6 +165,8 @@ void ha_heap::info(uint flag) index_file_length=info.index_length; max_data_file_length= info.max_records* info.reclength; delete_length= info.deleted * info.reclength; + if (flag & HA_STATUS_AUTO) + auto_increment_value= info.auto_increment; } int ha_heap::extra(enum ha_extra_function operation) @@ -255,7 +200,6 @@ THR_LOCK_DATA **ha_heap::store_lock(THD *thd, return to; } - /* We have to ignore ENOENT entries as the HEAP table is created on open and not when doing a CREATE on the table. @@ -272,7 +216,6 @@ int ha_heap::rename_table(const char * from, const char * to) return heap_rename(from,to); } - ha_rows ha_heap::records_in_range(int inx, const byte *start_key,uint start_key_len, enum ha_rkey_function start_search_flag, @@ -280,18 +223,121 @@ ha_rows ha_heap::records_in_range(int inx, enum ha_rkey_function end_search_flag) { KEY *pos=table->key_info+inx; - if (start_key_len != end_key_len || - start_key_len != pos->key_length || - start_search_flag != HA_READ_KEY_EXACT || - end_search_flag != HA_READ_AFTER_KEY) - return HA_POS_ERROR; // Can't only use exact keys - return 10; // Good guess + if (pos->algorithm == HA_KEY_ALG_BTREE) + { + return hp_rb_records_in_range(file, inx, start_key, start_key_len, + start_search_flag, end_key, end_key_len, + end_search_flag); + } + else + { + if (start_key_len != end_key_len || + start_key_len != pos->key_length || + start_search_flag != HA_READ_KEY_EXACT || + end_search_flag != HA_READ_AFTER_KEY) + return HA_POS_ERROR; // Can't only use exact keys + return 10; // Good guess + } } +int ha_heap::create(const char *name, TABLE *table, + HA_CREATE_INFO *create_info) +{ + uint key, parts, mem_per_row= 0; + uint auto_key= 0, auto_key_type= 0; + ha_rows max_rows; + HP_KEYDEF *keydef; + HA_KEYSEG *seg; + char buff[FN_REFLEN]; + int error; + + for (key= parts= 0; key < table->keys; key++) + parts+= table->key_info[key].key_parts; + + if (!(keydef= (HP_KEYDEF*) my_malloc(table->keys * sizeof(HP_KEYDEF) + + parts * sizeof(HA_KEYSEG), + MYF(MY_WME)))) + return my_errno; + seg= my_reinterpret_cast(HA_KEYSEG*) (keydef + table->keys); + for (key= 0; key < table->keys; key++) + { + KEY *pos= table->key_info+key; + KEY_PART_INFO *key_part= pos->key_part; + KEY_PART_INFO *key_part_end= key_part + pos->key_parts; -int ha_heap::create(const char *name, TABLE *form, HA_CREATE_INFO *create_info) + mem_per_row+= (pos->key_length + (sizeof(char*) * 2)); + keydef[key].keysegs= (uint) pos->key_parts; + keydef[key].flag= (pos->flags & (HA_NOSAME | HA_NULL_ARE_EQUAL)); + keydef[key].seg= seg; + keydef[key].algorithm= ((pos->algorithm == HA_KEY_ALG_UNDEF) ? + HA_KEY_ALG_HASH : pos->algorithm); + + for (; key_part != key_part_end; key_part++, seg++) + { + uint flag= key_part->key_type; + Field *field= key_part->field; + if (pos->algorithm == HA_KEY_ALG_BTREE) + seg->type= field->key_type(); + else + { + if (!f_is_packed(flag) && + f_packtype(flag) == (int) FIELD_TYPE_DECIMAL && + !(flag & FIELDFLAG_BINARY)) + seg->type= (int) HA_KEYTYPE_TEXT; + else + seg->type= (int) HA_KEYTYPE_BINARY; + } + seg->start= (uint) key_part->offset; + seg->length= (uint) key_part->length; + seg->flag = 0; + seg->charset= field->charset(); + if (field->null_ptr) + { + seg->null_bit= field->null_bit; + seg->null_pos= (uint) (field->null_ptr - (uchar*) table->record[0]); + } + else + { + seg->null_bit= 0; + seg->null_pos= 0; + } + if (field->flags & AUTO_INCREMENT_FLAG) + { + auto_key= key + 1; + auto_key_type= field->key_type(); + } + } + } + mem_per_row+= MY_ALIGN(table->reclength + 1, sizeof(char*)); + max_rows = (ha_rows) (current_thd->variables.max_heap_table_size / + mem_per_row); + HP_CREATE_INFO hp_create_info; + hp_create_info.auto_key= auto_key; + hp_create_info.auto_key_type= auto_key_type; + hp_create_info.auto_increment= (create_info->auto_increment_value ? + create_info->auto_increment_value - 1 : 0); + error= heap_create(fn_format(buff,name,"","",4+2), + table->keys,keydef, table->reclength, + (ulong) ((table->max_rows < max_rows && table->max_rows) ? + table->max_rows : max_rows), + (ulong) table->min_rows, &hp_create_info); + my_free((gptr) keydef, MYF(0)); + if (file) + info(HA_STATUS_NO_LOCK | HA_STATUS_CONST | HA_STATUS_VARIABLE); + ref_length= sizeof(HEAP_PTR); + return (error); +} + +void ha_heap::update_create_info(HA_CREATE_INFO *create_info) { - char buff[FN_REFLEN]; - return heap_create(fn_format(buff,name,"","",4+2)); + table->file->info(HA_STATUS_AUTO); + if (!(create_info->used_fields & HA_CREATE_USED_AUTO)) + create_info->auto_increment_value= auto_increment_value; +} + +longlong ha_heap::get_auto_increment() +{ + ha_heap::info(HA_STATUS_AUTO); + return auto_increment_value; } diff --git a/sql/ha_heap.h b/sql/ha_heap.h index 504f5262bf3..f82a1a460d8 100644 --- a/sql/ha_heap.h +++ b/sql/ha_heap.h @@ -40,8 +40,7 @@ class ha_heap: public handler ulong table_flags() const { return (HA_READ_RND_SAME | HA_NO_INDEX | HA_KEYPOS_TO_RNDPOS | - HA_NO_BLOBS | HA_NULL_KEY | HA_REC_NOT_IN_SEQ | - HA_NO_AUTO_INCREMENT); + HA_NO_BLOBS | HA_NULL_KEY | HA_REC_NOT_IN_SEQ); } ulong index_flags(uint inx) const { @@ -63,6 +62,7 @@ class ha_heap: public handler int write_row(byte * buf); int update_row(const byte * old_data, byte * new_data); int delete_row(const byte * buf); + longlong get_auto_increment(); int index_read(byte * buf, const byte * key, uint key_len, enum ha_rkey_function find_flag); int index_read_idx(byte * buf, uint idx, const byte * key, @@ -87,6 +87,7 @@ class ha_heap: public handler int delete_table(const char *from); int rename_table(const char * from, const char * to); int create(const char *name, TABLE *form, HA_CREATE_INFO *create_info); + void update_create_info(HA_CREATE_INFO *create_info); THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to, enum thr_lock_type lock_type); diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 95bf8e8eb75..7787b543f34 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -765,9 +765,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); /* If this is a replication slave and we needed to do a crash recovery, @@ -1384,8 +1383,11 @@ innobase_mysql_cmp( case FIELD_TYPE_STRING: case FIELD_TYPE_VAR_STRING: - ret = my_sortncmp((const char*) a, a_length, - (const char*) b, b_length); + // BAR TODO: Discuss with heikki.tuuri@innodb.com + // so that he sends CHARSET_INFO for the field to this function. + ret = my_strnncoll(default_charset_info, + a, a_length, + b, b_length); if (ret < 0) { return(-1); } else if (ret > 0) { @@ -1421,7 +1423,7 @@ get_innobase_type_from_mysql_type( DBUG_ASSERT((ulint)FIELD_TYPE_DECIMAL < 256); switch (field->type()) { - case FIELD_TYPE_VAR_STRING: if (field->flags & BINARY_FLAG) { + case FIELD_TYPE_VAR_STRING: if (field->binary()) { return(DATA_BINARY); } else if (strcmp( @@ -1431,7 +1433,7 @@ get_innobase_type_from_mysql_type( } else { return(DATA_VARMYSQL); } - case FIELD_TYPE_STRING: if (field->flags & BINARY_FLAG) { + case FIELD_TYPE_STRING: if (field->binary()) { return(DATA_FIXBINARY); } else if (strcmp( @@ -3210,8 +3212,8 @@ innobase_drop_database( memcpy(namebuf, ptr, len); namebuf[len] = '/'; namebuf[len + 1] = '\0'; -#ifdef __WIN__ - casedn_str(namebuf); +#ifdef FN_NO_CASE_SENCE + my_casedn_str(system_charset_info, namebuf); #endif trx = trx_allocate_for_mysql(); @@ -3937,7 +3939,7 @@ innodb_show_status( ut_free(buf); - send_eof(&thd->net); + send_eof(thd); DBUG_RETURN(0); } diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc index 0c472ea6a45..ae71e362875 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_recover_options= HA_RECOVER_NONE; @@ -86,6 +87,11 @@ static void mi_check_print_msg(MI_CHECK *param, const char* msg_type, extern "C" { +volatile bool *killed_ptr(MI_CHECK *param) +{ + return &(((THD *)(param->thd))->killed); +} + void mi_check_print_error(MI_CHECK *param, const char *fmt,...) { param->error_printed|=1; @@ -122,8 +128,12 @@ const char **ha_myisam::bas_ext() const const char *ha_myisam::index_type(uint key_number) { - return ((table->key_info[key_number].flags & HA_FULLTEXT) ? + return ((table->key_info[key_number].flags & HA_FULLTEXT) ? "FULLTEXT" : + (table->key_info[key_number].flags & HA_SPATIAL) ? + "SPATIAL" : + (table->key_info[key_number].algorithm == HA_KEY_ALG_RTREE) ? + "RTREE" : "BTREE"); } @@ -554,7 +564,7 @@ int ha_myisam::repair(THD *thd, MI_CHECK ¶m, bool optimize) param.tmpfile_createflag = O_RDWR | O_TRUNC; param.using_global_keycache = 1; param.thd=thd; - param.tmpdir=mysql_tmpdir; + param.tmpdir=&mysql_tmpdir_list; param.out_flag=0; strmov(fixed_name,file->filename); @@ -717,7 +727,7 @@ bool ha_myisam::activate_all_index(THD *thd) T_CREATE_MISSING_KEYS); param.myf_rw&= ~MY_WAIT_IF_FULL; param.sort_buffer_length= thd->variables.myisam_sort_buff_size; - param.tmpdir=mysql_tmpdir; + param.tmpdir=&mysql_tmpdir_list; error=repair(thd,param,0) != HA_ADMIN_OK; thd->proc_info=save_proc_info; } @@ -778,7 +788,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; } @@ -787,7 +797,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; } @@ -1019,7 +1029,7 @@ int ha_myisam::create(const char *name, register TABLE *table_arg, KEY *pos; MI_KEYDEF *keydef; MI_COLUMNDEF *recinfo,*recinfo_pos; - MI_KEYSEG *keyseg; + HA_KEYSEG *keyseg; uint options=table_arg->db_options_in_use; DBUG_ENTER("ha_myisam::create"); @@ -1028,14 +1038,16 @@ int ha_myisam::create(const char *name, register TABLE *table_arg, &recinfo,(table_arg->fields*2+2)*sizeof(MI_COLUMNDEF), &keydef, table_arg->keys*sizeof(MI_KEYDEF), &keyseg, - ((table_arg->key_parts + table_arg->keys) * sizeof(MI_KEYSEG)), + ((table_arg->key_parts + table_arg->keys) * sizeof(HA_KEYSEG)), 0))) DBUG_RETURN(1); pos=table_arg->key_info; for (i=0; i < table_arg->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->algorithm == HA_KEY_ALG_UNDEF ? + HA_KEY_ALG_BTREE : pos->algorithm; keydef[i].seg=keyseg; keydef[i].keysegs=pos->key_parts; for (j=0 ; j < pos->key_parts ; j++) @@ -1070,7 +1082,7 @@ int ha_myisam::create(const char *name, register TABLE *table_arg, keydef[i].seg[j].start= pos->key_part[j].offset; keydef[i].seg[j].length= pos->key_part[j].length; keydef[i].seg[j].bit_start=keydef[i].seg[j].bit_end=0; - keydef[i].seg[j].language=MY_CHARSET_CURRENT; + keydef[i].seg[j].language = field->charset()->number; if (field->null_ptr) { diff --git a/sql/handler.cc b/sql/handler.cc index f07e90d2eb9..b2cf86a6abc 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -689,7 +689,7 @@ void handler::print_error(int error, myf errflag) { /* Write the dupplicated key in the error message */ char key[MAX_KEY_LENGTH]; - String str(key,sizeof(key)); + String str(key,sizeof(key),default_charset_info); key_unpack(&str,table,(uint) key_nr); uint max_length=MYSQL_ERRMSG_SIZE-(uint) strlen(ER(ER_DUP_ENTRY)); if (str.length() >= max_length) diff --git a/sql/handler.h b/sql/handler.h index b9209d087a0..6cbd83af282 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -137,6 +137,7 @@ enum row_type { ROW_TYPE_NOT_USED=-1, ROW_TYPE_DEFAULT, ROW_TYPE_FIXED, #define HA_CREATE_USED_MAX_ROWS 32 #define HA_CREATE_USED_AVG_ROW_LENGTH 64 #define HA_CREATE_USED_PACK_KEYS 128 +#define HA_CREATE_USED_CHARSET 256 typedef struct st_thd_trans { void *bdb_tid; @@ -149,21 +150,22 @@ enum enum_tx_isolation { ISO_READ_UNCOMMITTED, ISO_READ_COMMITTED, typedef struct st_ha_create_information { - ulong table_options; - enum db_type db_type; - enum row_type row_type; - ulong avg_row_length; - ulonglong max_rows,min_rows; - ulonglong auto_increment_value; + CHARSET_INFO *table_charset; char *comment,*password; char *data_file_name, *index_file_name; - uint options; /* OR of HA_CREATE_ options */ - uint raid_type,raid_chunks; + ulonglong max_rows,min_rows; + ulonglong auto_increment_value; + ulong table_options; + ulong avg_row_length; ulong raid_chunksize; - bool if_not_exists; ulong used_fields; SQL_LIST merge_list; + enum db_type db_type; + enum row_type row_type; + uint options; /* OR of HA_CREATE_ options */ + uint raid_type,raid_chunks; uint merge_insert_method; + bool if_not_exists; } HA_CREATE_INFO; diff --git a/sql/hash_filo.h b/sql/hash_filo.h index 34584b45d8c..f7384cc6e32 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 be035e52ac1..609532a67d6 100644 --- a/sql/hostname.cc +++ b/sql/hostname.cc @@ -221,10 +221,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..8834fd3a89c 100644 --- a/sql/init.cc +++ b/sql/init.cc @@ -52,17 +52,6 @@ void unireg_init(ulong options) } specialflag|=options; /* Set options from argv */ - // 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++) - { - if ((uchar) my_sort_order[i] > max_char) - { - max_char=(uchar) my_sort_order[i]; - max_sort_char= (char) i; - } - } thread_stack_min=thread_stack - STACK_MIN_SIZE; DBUG_VOID_RETURN; } diff --git a/sql/item.cc b/sql/item.cc index b3b4e99e28a..48ec11d02c2 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -37,20 +37,34 @@ void item_init(void) Item::Item() { marker=0; - binary=maybe_null=null_value=with_sum_func=unsigned_flag=0; + maybe_null=null_value=with_sum_func=unsigned_flag=0; name=0; decimals=0; max_length=0; next=current_thd->free_list; // Put in free list current_thd->free_list=this; + loop_id= 0; } -void Item::set_name(char *str,uint length) +bool Item::check_loop(uint id) +{ + DBUG_ENTER("Item::check_loop"); + DBUG_PRINT("info", ("id %u, name %s", id, name)); + if (loop_id == id) + { + DBUG_PRINT("info", ("id match")); + DBUG_RETURN(1); + } + loop_id= id; + DBUG_RETURN(0); +} + +void Item::set_name(const char *str,uint length) { if (!length) - name=str; // Used by AS + name= (char*) 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 +80,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 @@ -89,7 +103,7 @@ bool Item_string::eq(const Item *item, bool binary_cmp) const bool Item::get_date(TIME *ltime,bool fuzzydate) { char buff[40]; - String tmp(buff,sizeof(buff)),*res; + String tmp(buff,sizeof(buff),default_charset_info),*res; if (!(res=val_str(&tmp)) || str_to_TIME(res->ptr(),res->length(),ltime,fuzzydate) == TIMESTAMP_NONE) { @@ -107,7 +121,7 @@ bool Item::get_date(TIME *ltime,bool fuzzydate) bool Item::get_time(TIME *ltime) { char buff[40]; - String tmp(buff,sizeof(buff)),*res; + String tmp(buff,sizeof(buff),default_charset_info),*res; if (!(res=val_str(&tmp)) || str_to_time(res->ptr(),res->length(),ltime)) { @@ -117,6 +131,11 @@ bool Item::get_time(TIME *ltime) return 0; } +CHARSET_INFO * Item::thd_charset() const +{ + return current_thd->thd_charset; +} + Item_field::Item_field(Field *f) :Item_ident(NullS,f->table_name,f->field_name) { set_field(f); @@ -131,8 +150,8 @@ void Item_field::set_field(Field *field_par) decimals= field->decimals(); table_name=field_par->table_name; field_name=field_par->field_name; - binary=field_par->binary(); unsigned_flag=test(field_par->flags & UNSIGNED_FLAG); + set_charset(field_par->charset()); } const char *Item_ident::full_name() const @@ -234,7 +253,7 @@ table_map Item_field::used_tables() const String *Item_int::val_str(String *str) { - str->set(value); + str->set(value, thd_charset()); return str; } @@ -242,7 +261,7 @@ void Item_int::print(String *str) { if (!name) { - str_value.set(value); + str_value.set(value, thd_charset()); name=str_value.c_ptr(); } str->append(name); @@ -250,7 +269,7 @@ void Item_int::print(String *str) String *Item_uint::val_str(String *str) { - str->set((ulonglong) value); + str->set((ulonglong) value, thd_charset()); return str; } @@ -258,7 +277,7 @@ void Item_uint::print(String *str) { if (!name) { - str_value.set((ulonglong) value); + str_value.set((ulonglong) value, thd_charset()); name=str_value.c_ptr(); } str->append(name); @@ -267,7 +286,7 @@ void Item_uint::print(String *str) String *Item_real::val_str(String *str) { - str->set(value,decimals); + str->set(value,decimals,thd_charset()); return str; } @@ -287,6 +306,113 @@ String *Item_null::val_str(String *str) { null_value=1; return 0;} +/* Item_param related */ +void Item_param::set_null() +{ + maybe_null=null_value=1; +} + +void Item_param::set_int(longlong i) +{ + int_value=(longlong)i; + item_result_type = INT_RESULT; + item_type = INT_ITEM; +} + +void Item_param::set_double(double value) +{ + real_value=value; + item_result_type = REAL_RESULT; + item_type = REAL_ITEM; +} + + +void Item_param::set_value(const char *str, uint length, CHARSET_INFO *cs) +{ + str_value.set(str,length,cs); + item_result_type = STRING_RESULT; + item_type = STRING_ITEM; +} + + +void Item_param::set_longdata(const char *str, ulong length, CHARSET_INFO *cs) +{ + /* TODO: Fix this for binary handling by making use of + buffer_type.. + */ + str_value.append(str,length); +} + + +int Item_param::save_in_field(Field *field) +{ + if (null_value) + return (int) set_field_to_null(field); + + field->set_notnull(); + if (item_result_type == INT_RESULT) + { + longlong nr=val_int(); + return (field->store(nr)) ? -1 : 0; + } + if (item_result_type == REAL_RESULT) + { + double nr=val(); + return (field->store(nr)) ? -1 : 0; + } + String *result=val_str(&str_value); + return (field->store(result->ptr(),result->length(),field->charset())) ? -1 : 0; +} + + +void Item_param::make_field(Send_field *tmp_field) +{ + init_make_field(tmp_field,FIELD_TYPE_STRING); +} + + +double Item_param::val() +{ + switch (item_result_type) { + case STRING_RESULT: + return (double)atof(str_value.ptr()); + case INT_RESULT: + return (double)int_value; + default: + return real_value; + } +} + + +longlong Item_param::val_int() +{ + switch (item_result_type) { + case STRING_RESULT: + return strtoll(str_value.ptr(),(char**) 0,10); + case REAL_RESULT: + return (longlong) (real_value+(real_value > 0 ? 0.5 : -0.5)); + default: + return int_value; + } +} + + +String *Item_param::val_str(String* str) +{ + switch (item_result_type) { + case INT_RESULT: + str->set(int_value, thd_charset()); + return str; + case REAL_RESULT: + str->set(real_value, 2, thd_charset()); + return str; + default: + return (String*) &str_value; + } +} +/* End of Item_param related */ + + void Item_copy_string::copy() { String *res=item->val_str(&str_value); @@ -304,23 +430,65 @@ String *Item_copy_string::val_str(String *str) } /* -** Functions to convert item to field (for send_fields) + Functions to convert item to field (for send_fields) */ /* ARGSUSED */ bool Item::fix_fields(THD *thd, - struct st_table_list *list) + struct st_table_list *list, + Item ** ref) { return 0; } -bool Item_field::fix_fields(THD *thd,TABLE_LIST *tables) +bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) { if (!field) // If field is not checked { Field *tmp; - if (!(tmp=find_field_in_tables(thd,this,tables))) - return 1; + if ((tmp= find_field_in_tables(thd, this, tables, 0)) == not_found_field) + { + /* + We can't find table field in table list of current select, + consequently we have to find it in outer subselect(s). + We can't join lists of outer & current select, because of scope + of view rules. For example if both tables (outer & current) have + field 'field' it is not mistake to refer to this field without + mention of table name, but if we join tables in one list it will + cause error ER_NON_UNIQ_ERROR in find_field_in_tables. + */ + SELECT_LEX *last= 0; + + // Prevent using outer fields in subselects, that is not supported now + if (thd->lex.current_select->linkage != DERIVED_TABLE_TYPE) + for (SELECT_LEX *sl= thd->lex.current_select->outer_select(); + sl; + sl= sl->outer_select()) + if ((tmp= find_field_in_tables(thd, this, + (last= sl)->get_table_list(), + 0)) != not_found_field) + break; + if (!tmp) + return -1; + else if (tmp == not_found_field) + { + // call to return error code + find_field_in_tables(thd, this, tables, 1); + return -1; + } + else + { + depended_from= last; + /* + Mark all selects from resolved to 1 before select where was + found table as depended (of select where was found table) + */ + thd->lex.current_select->mark_as_dependent(last); + } + } + else if (!tmp) + return -1; + set_field(tmp); } else if (thd && thd->set_query_id && field->query_id != thd->query_id) @@ -331,13 +499,24 @@ bool Item_field::fix_fields(THD *thd,TABLE_LIST *tables) table->used_fields++; table->used_keys&=field->part_of_key; } + if (depended_from != 0 && depended_from->having_fix_field) + { + *ref= new Item_ref((char *)db_name, (char *)table_name, + (char *)field_name); + if (!*ref) + return 1; + return (*ref)->fix_fields(thd, tables, ref); + } return 0; } void Item::init_make_field(Send_field *tmp_field, enum enum_field_types field_type) -{ +{ + tmp_field->db_name=(char*) ""; + tmp_field->org_table_name=(char*) ""; + tmp_field->org_col_name=(char*) ""; tmp_field->table_name=(char*) ""; tmp_field->col_name=name; tmp_field->flags=maybe_null ? 0 : NOT_NULL_FLAG; @@ -429,7 +608,7 @@ void Item_field::save_org_in_field(Field *to) } } -bool Item_field::save_in_field(Field *to) +int Item_field::save_in_field(Field *to) { if (result_field->is_null()) { @@ -445,6 +624,7 @@ bool Item_field::save_in_field(Field *to) return 0; } + /* Store null in field @@ -461,7 +641,7 @@ bool Item_field::save_in_field(Field *to) 1 Field doesn't support NULL values and can't handle 'field = NULL' */ -bool Item_null::save_in_field(Field *field) +int Item_null::save_in_field(Field *field) { return set_field_to_null_with_conversions(field); } @@ -479,27 +659,29 @@ bool Item_null::save_in_field(Field *field) 1 Field doesn't support NULL values */ -bool Item_null::save_safe_in_field(Field *field) +int Item_null::save_safe_in_field(Field *field) { return set_field_to_null(field); } -bool Item::save_in_field(Field *field) +int Item::save_in_field(Field *field) { + int error; if (result_type() == STRING_RESULT || result_type() == REAL_RESULT && field->result_type() == STRING_RESULT) { String *result; + CHARSET_INFO *cs=field->charset(); char buff[MAX_FIELD_WIDTH]; // Alloc buffer for small columns - str_value.set_quick(buff,sizeof(buff)); + str_value.set_quick(buff,sizeof(buff),cs); result=val_str(&str_value); if (null_value) return set_field_to_null_with_conversions(field); field->set_notnull(); - field->store(result->ptr(),result->length()); - str_value.set_quick(0, 0); + error=field->store(result->ptr(),result->length(),cs); + str_value.set_quick(0, 0, cs); } else if (result_type() == REAL_RESULT) { @@ -507,7 +689,7 @@ bool Item::save_in_field(Field *field) if (null_value) return set_field_to_null(field); field->set_notnull(); - field->store(nr); + error=field->store(nr); } else { @@ -515,41 +697,38 @@ bool Item::save_in_field(Field *field) if (null_value) return set_field_to_null_with_conversions(field); field->set_notnull(); - field->store(nr); + error=field->store(nr); } - return 0; + return (error) ? -1 : 0; } - -bool Item_string::save_in_field(Field *field) +int Item_string::save_in_field(Field *field) { String *result; + CHARSET_INFO *cs=field->charset(); result=val_str(&str_value); if (null_value) return set_field_to_null(field); field->set_notnull(); - field->store(result->ptr(),result->length()); - return 0; + return (field->store(result->ptr(),result->length(),cs)) ? -1 : 0; } -bool Item_int::save_in_field(Field *field) +int Item_int::save_in_field(Field *field) { longlong nr=val_int(); if (null_value) return set_field_to_null(field); field->set_notnull(); - field->store(nr); - return 0; + return (field->store(nr)) ? -1 : 0; } -bool Item_real::save_in_field(Field *field) +int Item_real::save_in_field(Field *field) { double nr=val(); if (null_value) return set_field_to_null(field); field->set_notnull(); - field->store(nr); - return 0; + return (field->store(nr)) ? -1 : 0; } /**************************************************************************** @@ -572,7 +751,7 @@ Item_varbinary::Item_varbinary(const char *str, uint str_length) char *ptr=(char*) sql_alloc(max_length+1); if (!ptr) return; - str_value.set(ptr,max_length); + str_value.set(ptr,max_length,my_charset_bin); char *end=ptr+max_length; if (max_length*2 != str_length) *ptr++=char_val(*str++); // Not even, assume 0 prefix @@ -582,7 +761,6 @@ Item_varbinary::Item_varbinary(const char *str, uint str_length) str+=2; } *ptr=0; // Keep purify happy - binary=1; // Binary is default } longlong Item_varbinary::val_int() @@ -597,19 +775,21 @@ longlong Item_varbinary::val_int() } -bool Item_varbinary::save_in_field(Field *field) +int Item_varbinary::save_in_field(Field *field) { + int error; + CHARSET_INFO *cs=field->charset(); field->set_notnull(); if (field->result_type() == STRING_RESULT) { - field->store(str_value.ptr(),str_value.length()); + error=field->store(str_value.ptr(),str_value.length(),cs); } else { longlong nr=val_int(); - field->store(nr); + error=field->store(nr); } - return 0; + return (error) ? -1 : 0; } @@ -626,7 +806,7 @@ bool Item::send(THD *thd, String *packet) { char buff[MAX_FIELD_WIDTH]; CONVERT *convert; - String s(buff,sizeof(buff)),*res; + String s(buff,sizeof(buff),packet->charset()),*res; if (!(res=val_str(&s))) return net_store_null(packet); if ((convert=thd->variables.convert_set)) @@ -644,20 +824,78 @@ bool Item_null::send(THD *thd, String *packet) Find field in select list having the same name */ -bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables) +bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference) { if (!ref) { - if (!(ref=find_item_in_list(this,thd->lex.select->item_list))) + SELECT_LEX *sl= thd->lex.current_select->outer_select(); + /* + Finding only in current select will be performed for selects that have + not outer one and for derived tables (which not support using outer + fields for now) + */ + if ((ref= find_item_in_list(this, + *(thd->lex.current_select->get_item_list()), + ((sl && + thd->lex.current_select->linkage != + DERIVED_TABLE_TYPE) ? + REPORT_EXCEPT_NOT_FOUND : + REPORT_ALL_ERRORS))) == + (Item **)not_found_item) + { + /* + We can't find table field in table list of current select, + consequently we have to find it in outer subselect(s). + We can't join lists of outer & current select, because of scope + of view rules. For example if both tables (outer & current) have + field 'field' it is not mistake to refer to this field without + mention of table name, but if we join tables in one list it will + cause error ER_NON_UNIQ_ERROR in find_item_in_list. + */ + SELECT_LEX *last=0; + for ( ; sl ; sl= sl->outer_select()) + if((ref= find_item_in_list(this, (last= sl)->item_list, + REPORT_EXCEPT_NOT_FOUND)) != + (Item **)not_found_item) + break; + + if (!ref) + { + return 1; + } + else if (ref == (Item **)not_found_item) + { + // Call to report error + find_item_in_list(this, + *(thd->lex.current_select->get_item_list()), + REPORT_ALL_ERRORS); + ref= 0; + return 1; + } + else + { + depended_from= last; + thd->lex.current_select->mark_as_dependent(last); + thd->add_possible_loop(this); + } + } + else if (!ref) return 1; max_length= (*ref)->max_length; maybe_null= (*ref)->maybe_null; decimals= (*ref)->decimals; - binary= (*ref)->binary; } return 0; } +bool Item_ref::check_loop(uint id) +{ + DBUG_ENTER("Item_ref::check_loop"); + if (Item_ident::check_loop(id)) + DBUG_RETURN(1); + DBUG_RETURN((*ref)->check_loop(id)); +} + /* ** If item is a const function, calculate it and return a const item ** The original item is freed if not returned @@ -685,7 +923,7 @@ Item *resolve_const_item(Item *item,Item *comp_item) if (res_type == STRING_RESULT) { char buff[MAX_FIELD_WIDTH]; - String tmp(buff,sizeof(buff)),*result; + String tmp(buff,sizeof(buff),default_charset_info),*result; result=item->val_str(&tmp); if (item->null_value) { @@ -699,7 +937,7 @@ Item *resolve_const_item(Item *item,Item *comp_item) #ifdef DELETE_ITEMS delete item; #endif - return new Item_string(name,tmp_str,length); + return new Item_string(name,tmp_str,length,default_charset_info); } if (res_type == INT_RESULT) { @@ -740,8 +978,8 @@ bool field_is_equal_to_item(Field *field,Item *item) { char item_buff[MAX_FIELD_WIDTH]; char field_buff[MAX_FIELD_WIDTH]; - String item_tmp(item_buff,sizeof(item_buff)),*item_result; - String field_tmp(field_buff,sizeof(field_buff)); + String item_tmp(item_buff,sizeof(item_buff),default_charset_info),*item_result; + String field_tmp(field_buff,sizeof(field_buff),default_charset_info); item_result=item->val_str(&item_tmp); if (item->null_value) return 1; // This must be true diff --git a/sql/item.h b/sql/item.h index 563db2291fb..5eeaa22a2a2 100644 --- a/sql/item.h +++ b/sql/item.h @@ -20,10 +20,11 @@ #endif struct st_table_list; -void item_init(void); /* Init item functions */ +void item_init(void); /* Init item functions */ class Item { - Item(const Item &); /* Prevent use of these */ + uint loop_id; /* Used to find selfrefering loops */ + Item(const Item &); /* Prevent use of these */ void operator=(Item &); public: static void *operator new(size_t size) {return (void*) sql_alloc((uint) size); } @@ -32,7 +33,8 @@ public: enum Type {FIELD_ITEM,FUNC_ITEM,SUM_FUNC_ITEM,STRING_ITEM, INT_ITEM,REAL_ITEM,NULL_ITEM,VARBIN_ITEM, COPY_STR_ITEM,FIELD_AVG_ITEM, DEFAULT_ITEM, - PROC_ITEM,COND_ITEM,REF_ITEM,FIELD_STD_ITEM, CONST_ITEM}; + PROC_ITEM,COND_ITEM,REF_ITEM,FIELD_STD_ITEM, CONST_ITEM, + SUBSELECT_ITEM}; enum cond_result { COND_UNDEF,COND_OK,COND_TRUE,COND_FALSE }; String str_value; /* used to store value */ @@ -42,21 +44,19 @@ public: uint8 marker,decimals; my_bool maybe_null; /* If item may be null */ my_bool null_value; /* if item is null */ - my_bool binary; my_bool unsigned_flag; my_bool with_sum_func; - // alloc & destruct is done as start of select using sql_alloc Item(); virtual ~Item() { name=0; } /*lint -e1509 */ - void set_name(char* str,uint length=0); + void set_name(const char *str,uint length=0); void init_make_field(Send_field *tmp_field,enum enum_field_types type); - virtual bool fix_fields(THD *,struct st_table_list *); - virtual bool save_in_field(Field *field); + virtual bool fix_fields(THD *, struct st_table_list *, Item **); + virtual int save_in_field(Field *field); virtual void save_org_in_field(Field *field) { (void) save_in_field(field); } - virtual bool save_safe_in_field(Field *field) + virtual int save_safe_in_field(Field *field) { return save_in_field(field); } virtual bool send(THD *thd, String *str); virtual bool eq(const Item *, bool binary_cmp) const; @@ -71,6 +71,7 @@ public: virtual double val_result() { return val(); } virtual longlong val_int_result() { return val_int(); } virtual String *str_result(String* tmp) { return val_str(tmp); } + virtual bool is_null_result() { return is_null(); } virtual table_map used_tables() const { return (table_map) 0L; } virtual bool basic_const_item() const { return 0; } virtual Item *new_item() { return 0; } /* Only for const items */ @@ -83,24 +84,30 @@ public: virtual void split_sum_func(List<Item> &fields) {} virtual bool get_date(TIME *ltime,bool fuzzydate); virtual bool get_time(TIME *ltime); - virtual bool is_null() { return 0; } - virtual unsigned int size_of()= 0; + virtual bool is_null() { return 0; }; + virtual CHARSET_INFO *thd_charset() const; + virtual CHARSET_INFO *charset() const { return str_value.charset(); }; + virtual bool binary() const { return str_value.charset()->state & MY_CS_BINSORT ? 1 : 0 ; } + virtual void set_charset(CHARSET_INFO *cs) { str_value.set_charset(cs); } + virtual bool check_loop(uint id); virtual void top_level_item() {} }; +class st_select_lex; class Item_ident :public Item { public: const char *db_name; const char *table_name; const char *field_name; + st_select_lex *depended_from; Item_ident(const char *db_name_par,const char *table_name_par, const char *field_name_par) - :db_name(db_name_par),table_name(table_name_par),field_name(field_name_par) + :db_name(db_name_par),table_name(table_name_par), + field_name(field_name_par), depended_from(0) { name = (char*) field_name_par; } const char *full_name() const; - unsigned int size_of() { return sizeof(*this);} }; @@ -124,13 +131,14 @@ public: double val_result(); longlong val_int_result(); String *str_result(String* tmp); + bool is_null_result() { return result_field->is_null(); } bool send(THD *thd, String *str_arg) { return result_field->send(thd,str_arg); } void make_field(Send_field *field); - bool fix_fields(THD *,struct st_table_list *); - bool save_in_field(Field *field); + bool fix_fields(THD *, struct st_table_list *, Item **); + int save_in_field(Field *field); void save_org_in_field(Field *field); table_map used_tables() const; enum Item_result result_type () const @@ -141,7 +149,6 @@ public: bool get_date(TIME *ltime,bool fuzzydate); bool get_time(TIME *ltime); bool is_null() { return field->is_null(); } - unsigned int size_of() { return sizeof(*this);} }; @@ -156,17 +163,52 @@ public: longlong val_int(); String *val_str(String *str); void make_field(Send_field *field); - bool save_in_field(Field *field); - bool save_safe_in_field(Field *field); + int save_in_field(Field *field); + int save_safe_in_field(Field *field); enum Item_result result_type () const { return STRING_RESULT; } bool send(THD *thd, String *str); bool basic_const_item() const { return 1; } Item *new_item() { return new Item_null(name); } bool is_null() { return 1; } - unsigned int size_of() { return sizeof(*this);} }; +class Item_param :public Item +{ +public: + longlong int_value; + double real_value; + enum Item_result item_result_type; + enum Type item_type; + enum enum_field_types buffer_type; + my_bool long_data_supplied; + + Item_param(char *name_par=0) + { + name= name_par ? name_par : (char*) "?"; + long_data_supplied = false; + item_type = STRING_ITEM; + item_result_type = STRING_RESULT; + } + enum Type type() const { return item_type; } + double val(); + longlong val_int(); + String *val_str(String*); + void make_field(Send_field *field); + int save_in_field(Field *field); + void set_null(); + void set_int(longlong i); + void set_double(double i); + void set_value(const char *str, uint length, CHARSET_INFO *cs); + void set_long_str(const char *str, ulong length, CHARSET_INFO *cs); + void set_long_binary(const char *str, ulong length, CHARSET_INFO *cs); + void set_longdata(const char *str, ulong length, CHARSET_INFO *cs); + void set_long_end(); + void reset() {} + enum Item_result result_type () const + { return item_result_type; } + Item *new_item() { return new Item_param(name); } +}; class Item_int :public Item { @@ -190,11 +232,10 @@ public: double val() { return (double) value; } String *val_str(String*); void make_field(Send_field *field); - bool save_in_field(Field *field); + int save_in_field(Field *field); bool basic_const_item() const { return 1; } Item *new_item() { return new Item_int(name,value,max_length); } void print(String *str); - unsigned int size_of() { return sizeof(*this);} }; @@ -209,7 +250,6 @@ public: void make_field(Send_field *field); Item *new_item() { return new Item_uint(name,max_length); } void print(String *str); - unsigned int size_of() { return sizeof(*this);} }; @@ -232,7 +272,7 @@ public: max_length=length; } Item_real(double value_par) :value(value_par) {} - bool save_in_field(Field *field); + int save_in_field(Field *field); enum Type type() const { return REAL_ITEM; } double val() { return value; } longlong val_int() { return (longlong) (value+(value > 0 ? 0.5 : -0.5));} @@ -240,7 +280,6 @@ public: void make_field(Send_field *field); bool basic_const_item() const { return 1; } Item *new_item() { return new Item_real(name,value,decimals,max_length); } - unsigned int size_of() { return sizeof(*this);} }; @@ -252,22 +291,21 @@ public: decimals=NOT_FIXED_DEC; max_length=DBL_DIG+8; } - unsigned int size_of() { return sizeof(*this);} }; class Item_string :public Item { public: - Item_string(const char *str,uint length) + Item_string(const char *str,uint length,CHARSET_INFO *cs) { - str_value.set(str,length); + str_value.set(str,length,cs); max_length=length; name=(char*) str_value.ptr(); decimals=NOT_FIXED_DEC; } - Item_string(const char *name_par,const char *str,uint length) + Item_string(const char *name_par,const char *str,uint length,CHARSET_INFO *cs) { - str_value.set(str,length); + str_value.set(str,length,cs); max_length=length; name=(char*) name_par; decimals=NOT_FIXED_DEC; @@ -277,16 +315,15 @@ public: double val() { return atof(str_value.ptr()); } longlong val_int() { return strtoll(str_value.ptr(),(char**) 0,10); } String *val_str(String*) { return (String*) &str_value; } - bool save_in_field(Field *field); + int save_in_field(Field *field); void make_field(Send_field *field); enum Item_result result_type () const { return STRING_RESULT; } bool basic_const_item() const { return 1; } bool eq(const Item *item, bool binary_cmp) const; - Item *new_item() { return new Item_string(name,str_value.ptr(),max_length); } + Item *new_item() { return new Item_string(name,str_value.ptr(),max_length,default_charset_info); } String *const_string() { return &str_value; } inline void append(char *str,uint length) { str_value.append(str,length); } void print(String *str); - unsigned int size_of() { return sizeof(*this);} }; @@ -298,7 +335,7 @@ public: Item_default() { name= (char*) "DEFAULT"; } enum Type type() const { return DEFAULT_ITEM; } void make_field(Send_field *field) {} - bool save_in_field(Field *field) + int save_in_field(Field *field) { field->set_default(); return 0; @@ -307,7 +344,6 @@ public: virtual longlong val_int() { return 0; } virtual String *val_str(String *str) { return 0; } bool basic_const_item() const { return 1; } - unsigned int size_of() { return sizeof(*this);} }; @@ -316,18 +352,16 @@ public: class Item_datetime :public Item_string { public: - Item_datetime(const char *item_name): Item_string(item_name,"",0) + Item_datetime(const char *item_name): Item_string(item_name,"",0,default_charset_info) { max_length=19;} void make_field(Send_field *field); - unsigned int size_of() { return sizeof(*this);} }; class Item_empty_string :public Item_string { public: - Item_empty_string(const char *header,uint length) :Item_string("",0) + Item_empty_string(const char *header,uint length) :Item_string("",0,default_charset_info) { name=(char*) header; max_length=length;} - unsigned int size_of() { return sizeof(*this);} }; class Item_varbinary :public Item @@ -339,10 +373,9 @@ public: double val() { return (double) Item_varbinary::val_int(); } longlong val_int(); String *val_str(String*) { return &str_value; } - bool save_in_field(Field *field); + int save_in_field(Field *field); void make_field(Send_field *field); enum Item_result result_type () const { return INT_RESULT; } - unsigned int size_of() { return sizeof(*this);} }; @@ -355,7 +388,6 @@ public: Field *tmp_table_field(TABLE *t_arg=(TABLE *)0) { return result_field; } table_map used_tables() const { return 1; } virtual void fix_length_and_dec()=0; - unsigned int size_of() { return sizeof(*this);} }; @@ -374,25 +406,25 @@ public: double val() { double tmp=(*ref)->val_result(); - null_value=(*ref)->null_value; + null_value=(*ref)->is_null_result(); return tmp; } longlong val_int() { longlong tmp=(*ref)->val_int_result(); - null_value=(*ref)->null_value; + null_value=(*ref)->is_null_result(); return tmp; } String *val_str(String* tmp) { tmp=(*ref)->str_result(tmp); - null_value=(*ref)->null_value; + null_value=(*ref)->is_null_result(); return tmp; } bool is_null() { (void) (*ref)->val_int_result(); - return (*ref)->null_value; + return (*ref)->is_null_result(); } bool get_date(TIME *ltime,bool fuzzydate) { @@ -400,12 +432,12 @@ public: } bool send(THD *thd, String *tmp) { return (*ref)->send(thd, tmp); } void make_field(Send_field *field) { (*ref)->make_field(field); } - bool fix_fields(THD *,struct st_table_list *); - bool save_in_field(Field *field) { return (*ref)->save_in_field(field); } + bool fix_fields(THD *, struct st_table_list *, Item **); + int save_in_field(Field *field) { return (*ref)->save_in_field(field); } void save_org_in_field(Field *field) { (*ref)->save_org_in_field(field); } enum Item_result result_type () const { return (*ref)->result_type(); } table_map used_tables() const { return (*ref)->used_tables(); } - unsigned int size_of() { return sizeof(*this);} + bool check_loop(uint id); }; @@ -421,20 +453,22 @@ class Item_int_with_ref :public Item_int public: Item_int_with_ref(longlong i, Item *ref_arg) :Item_int(i), ref(ref_arg) {} - bool save_in_field(Field *field) + int save_in_field(Field *field) { return ref->save_in_field(field); } - unsigned int size_of() { return sizeof(*this);} }; +#include "gstream.h" +#include "spatial.h" #include "item_sum.h" #include "item_func.h" #include "item_cmpfunc.h" #include "item_strfunc.h" #include "item_timefunc.h" #include "item_uniq.h" +#include "item_subselect.h" class Item_copy_string :public Item { @@ -460,7 +494,6 @@ public: table_map used_tables() const { return (table_map) 1L; } bool const_item() const { return 0; } bool is_null() { return null_value; } - unsigned int size_of() { return sizeof(*this);} }; @@ -471,7 +504,6 @@ public: Item_buff() :null_value(0) {} virtual bool cmp(void)=0; virtual ~Item_buff(); /*line -e1509 */ - unsigned int size_of() { return sizeof(*this);} }; class Item_str_buff :public Item_buff @@ -482,7 +514,6 @@ public: Item_str_buff(Item *arg) :item(arg),value(arg->max_length) {} bool cmp(void); ~Item_str_buff(); // Deallocate String:s - unsigned int size_of() { return sizeof(*this);} }; @@ -493,7 +524,6 @@ class Item_real_buff :public Item_buff public: Item_real_buff(Item *item_par) :item(item_par),value(0.0) {} bool cmp(void); - unsigned int size_of() { return sizeof(*this);} }; class Item_int_buff :public Item_buff @@ -503,7 +533,6 @@ class Item_int_buff :public Item_buff public: Item_int_buff(Item *item_par) :item(item_par),value(0) {} bool cmp(void); - unsigned int size_of() { return sizeof(*this);} }; @@ -520,7 +549,6 @@ public: buff= (char*) sql_calloc(length=field->pack_length()); } bool cmp(void); - unsigned int size_of() { return sizeof(*this);} }; extern Item_buff *new_Item_buff(Item *item); diff --git a/sql/item_buff.cc b/sql/item_buff.cc index b55a4dc66a0..7b8976bb572 100644 --- a/sql/item_buff.cc +++ b/sql/item_buff.cc @@ -56,7 +56,7 @@ bool Item_str_buff::cmp(void) } else if (null_value) return 0; // new and old value was null - else if (!item->binary) + else if (!item->binary()) tmp= sortcmp(&value,res) != 0; else tmp= stringcmp(&value,res) != 0; diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index ee587289168..1065c8cf023 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 Most of these returns 0LL if false and 1LL if true and @@ -42,14 +43,17 @@ longlong Item_func_not::val_int() This is done when comparing DATE's of different formats and also when comparing bigint to strings (in which case the string is converted once to a bigint). + + RESULT VALUES + 0 Can't convert item + 1 Item was replaced with an integer version of the item */ static bool convert_constant_item(Field *field, Item **item) { if ((*item)->const_item() && (*item)->type() != Item::INT_ITEM) { - if (!(*item)->save_in_field(field) && - !((*item)->null_value)) + if (!(*item)->save_in_field(field) && !((*item)->null_value)) { Item *tmp=new Item_int_with_ref(field->val_int(), *item); if (tmp) @@ -124,7 +128,7 @@ int Item_bool_func2::compare_string() if ((res2=args[1]->val_str(&tmp_value2))) { null_value=0; - return binary ? stringcmp(res1,res2) : sortcmp(res1,res2); + return binary() ? stringcmp(res1,res2) : sortcmp(res1,res2); } } null_value=1; @@ -195,7 +199,7 @@ longlong Item_func_equal::val_int() res2=args[1]->val_str(&tmp_value2); if (!res1 || !res2) return test(res1 == res2); - return (binary ? test(stringcmp(res1,res2) == 0) : + return (binary() ? test(stringcmp(res1,res2) == 0) : test(sortcmp(res1,res2) == 0)); } case REAL_RESULT: @@ -262,7 +266,7 @@ longlong Item_func_strcmp::val_int() null_value=1; return 0; } - int value= binary ? stringcmp(a,b) : sortcmp(a,b); + int value= binary() ? stringcmp(a,b) : sortcmp(a,b); null_value=0; return !value ? 0 : (value < 0 ? (longlong) -1 : (longlong) 1); } @@ -340,6 +344,14 @@ void Item_func_interval::update_used_tables() const_item_cache&=item->const_item(); } +bool Item_func_interval::check_loop(uint id) +{ + DBUG_ENTER("Item_func_interval::check_loop"); + if (Item_func::check_loop(id)) + DBUG_RETURN(1); + DBUG_RETURN(item->check_loop(id)); +} + void Item_func_between::fix_length_and_dec() { max_length=1; @@ -353,7 +365,7 @@ void Item_func_between::fix_length_and_dec() cmp_type=item_cmp_type(args[0]->result_type(), item_cmp_type(args[1]->result_type(), args[2]->result_type())); - if (args[0]->binary | args[1]->binary | args[2]->binary) + if (args[0]->binary() | args[1]->binary() | args[2]->binary()) string_compare=stringcmp; else string_compare=sortcmp; @@ -513,21 +525,22 @@ Item_func_if::fix_length_and_dec() if (null1) { cached_result_type= arg2_type; - binary= args[2]->binary; + set_charset(args[2]->charset()); } else if (null2) { cached_result_type= arg1_type; - binary= args[1]->binary; + set_charset(args[1]->charset()); } else if (arg1_type == STRING_RESULT || arg2_type == STRING_RESULT) { cached_result_type = STRING_RESULT; - binary=args[1]->binary | args[2]->binary; + set_charset( (args[1]->binary() || args[2]->binary()) ? + my_charset_bin : args[1]->charset()); } else { - binary=1; // Number + set_charset(my_charset_bin); // Number if (arg1_type == REAL_RESULT || arg2_type == REAL_RESULT) cached_result_type = REAL_RESULT; else @@ -665,7 +678,7 @@ Item *Item_func_case::find_item(String *str) } if ((tmp=args[i]->val_str(str))) // If not null { - if (first_expr->binary || args[i]->binary) + if (first_expr->binary() || args[i]->binary()) { if (stringcmp(tmp,first_expr_str)==0) return args[i+1]; @@ -722,7 +735,7 @@ String *Item_func_case::val_str(String *str) longlong Item_func_case::val_int() { char buff[MAX_FIELD_WIDTH]; - String dummy_str(buff,sizeof(buff)); + String dummy_str(buff,sizeof(buff),default_charset_info); Item *item=find_item(&dummy_str); longlong res; @@ -739,7 +752,7 @@ longlong Item_func_case::val_int() double Item_func_case::val() { char buff[MAX_FIELD_WIDTH]; - String dummy_str(buff,sizeof(buff)); + String dummy_str(buff,sizeof(buff),default_charset_info); Item *item=find_item(&dummy_str); double res; @@ -755,12 +768,12 @@ double Item_func_case::val() bool -Item_func_case::fix_fields(THD *thd,TABLE_LIST *tables) +Item_func_case::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) { - if (first_expr && first_expr->fix_fields(thd,tables) || - else_expr && else_expr->fix_fields(thd,tables)) + if (first_expr && first_expr->fix_fields(thd, tables, &first_expr) || + else_expr && else_expr->fix_fields(thd, tables, &else_expr)) return 1; - if (Item_func::fix_fields(thd,tables)) + if (Item_func::fix_fields(thd, tables, ref)) return 1; if (first_expr) { @@ -777,6 +790,16 @@ Item_func_case::fix_fields(THD *thd,TABLE_LIST *tables) return 0; } +bool Item_func_case::check_loop(uint id) +{ + DBUG_ENTER("Item_func_case::check_loop"); + if (Item_func::check_loop(id)) + DBUG_RETURN(1); + + DBUG_RETURN((first_expr && first_expr->check_loop(id)) || + (else_expr && else_expr->check_loop(id))); +} + void Item_func_case::update_used_tables() { Item_func::update_used_tables(); @@ -911,7 +934,7 @@ int in_vector::find(Item *item) in_string::in_string(uint elements,qsort_cmp cmp_func) - :in_vector(elements,sizeof(String),cmp_func),tmp(buff,sizeof(buff)) + :in_vector(elements,sizeof(String),cmp_func),tmp(buff,sizeof(buff),default_charset_info) {} in_string::~in_string() @@ -926,6 +949,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) @@ -976,7 +1002,7 @@ void Item_func_in::fix_length_and_dec() { switch (item->result_type()) { case STRING_RESULT: - if (item->binary) + if (item->binary()) array=new in_string(arg_count,(qsort_cmp) stringcmp); /* purecov: inspected */ else array=new in_string(arg_count,(qsort_cmp) sortcmp); @@ -1002,7 +1028,7 @@ void Item_func_in::fix_length_and_dec() { switch (item->result_type()) { case STRING_RESULT: - if (item->binary) + if (item->binary()) in_item= new cmp_item_binary_string; else in_item= new cmp_item_sort_string; @@ -1099,7 +1125,7 @@ longlong Item_func_bit_and::val_int() bool -Item_cond::fix_fields(THD *thd,TABLE_LIST *tables) +Item_cond::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) { List_iterator<Item> li(list); Item *item; @@ -1123,7 +1149,7 @@ Item_cond::fix_fields(THD *thd,TABLE_LIST *tables) } if (abort_on_null) item->top_level_item(); - if (item->fix_fields(thd,tables)) + if (item->fix_fields(thd, tables, li.ref())) return 1; /* purecov: inspected */ used_tables_cache|=item->used_tables(); with_sum_func= with_sum_func || item->with_sum_func; @@ -1137,6 +1163,20 @@ Item_cond::fix_fields(THD *thd,TABLE_LIST *tables) return 0; } +bool Item_cond::check_loop(uint id) +{ + DBUG_ENTER("Item_cond::check_loop"); + if (Item_func::check_loop(id)) + DBUG_RETURN(1); + List_iterator<Item> li(list); + Item *item; + while ((item= li++)) + { + if (item->check_loop(id)) + DBUG_RETURN(1); + } + DBUG_RETURN(0); +} void Item_cond::split_sum_func(List<Item> &fields) { @@ -1328,12 +1368,15 @@ longlong Item_func_like::val_int() return 0; } null_value=0; + if ((res->charset()->state & MY_CS_BINSORT) || + (res2->charset()->state & MY_CS_BINSORT)) + set_charset(my_charset_bin); if (canDoTurboBM) return turboBM_matches(res->ptr(), res->length()) ? 1 : 0; - if (binary) - return wild_compare(*res,*res2,escape) ? 0 : 1; - else - return wild_case_compare(*res,*res2,escape) ? 0 : 1; + return my_wildcmp(charset(), + res->ptr(),res->ptr()+res->length(), + res2->ptr(),res2->ptr()+res2->length(), + escape,wild_one,wild_many) ? 0 : 1; } @@ -1353,9 +1396,9 @@ Item_func::optimize_type Item_func_like::select_optimize() const return OPTIMIZE_NONE; } -bool Item_func_like::fix_fields(THD *thd,struct st_table_list *tlist) +bool Item_func_like::fix_fields(THD *thd, TABLE_LIST *tlist, Item ** ref) { - if (Item_bool_func2::fix_fields(thd, tlist)) + if (Item_bool_func2::fix_fields(thd, tlist, ref)) return 1; /* @@ -1405,19 +1448,22 @@ bool Item_func_like::fix_fields(THD *thd,struct st_table_list *tlist) #ifdef USE_REGEX bool -Item_func_regex::fix_fields(THD *thd,TABLE_LIST *tables) +Item_func_regex::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) { - if (args[0]->fix_fields(thd,tables) || args[1]->fix_fields(thd,tables)) + if (args[0]->fix_fields(thd, tables, args) || + args[1]->fix_fields(thd,tables, args + 1)) return 1; /* purecov: inspected */ with_sum_func=args[0]->with_sum_func || args[1]->with_sum_func; max_length=1; decimals=0; - binary=args[0]->binary || args[1]->binary; + if (args[0]->binary() || args[1]->binary()) + set_charset(my_charset_bin); + used_tables_cache=args[0]->used_tables() | args[1]->used_tables(); const_item_cache=args[0]->const_item() && args[1]->const_item(); if (!regex_compiled && args[1]->const_item()) { char buff[MAX_FIELD_WIDTH]; - String tmp(buff,sizeof(buff)); + String tmp(buff,sizeof(buff),default_charset_info); String *res=args[1]->val_str(&tmp); if (args[1]->null_value) { // Will always return NULL @@ -1426,8 +1472,9 @@ 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))) + binary() ? REG_EXTENDED | REG_NOSUB : + 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); @@ -1444,7 +1491,7 @@ Item_func_regex::fix_fields(THD *thd,TABLE_LIST *tables) longlong Item_func_regex::val_int() { char buff[MAX_FIELD_WIDTH]; - String *res, tmp(buff,sizeof(buff)); + String *res, tmp(buff,sizeof(buff),default_charset_info); res=args[0]->val_str(&tmp); if (args[0]->null_value) @@ -1455,7 +1502,7 @@ longlong Item_func_regex::val_int() if (!regex_is_const) { char buff2[MAX_FIELD_WIDTH]; - String *res2, tmp2(buff2,sizeof(buff2)); + String *res2, tmp2(buff2,sizeof(buff2),default_charset_info); res2= args[1]->val_str(&tmp2); if (args[1]->null_value) @@ -1472,8 +1519,9 @@ longlong Item_func_regex::val_int() regex_compiled=0; } if (regcomp(&preg,res2->c_ptr(), - binary ? REG_EXTENDED | REG_NOSUB : - REG_EXTENDED | REG_NOSUB | REG_ICASE)) + binary() ? REG_EXTENDED | REG_NOSUB : + REG_EXTENDED | REG_NOSUB | REG_ICASE, + res->charset())) { null_value=1; @@ -1500,9 +1548,9 @@ Item_func_regex::~Item_func_regex() #ifdef LIKE_CMP_TOUPPER -#define likeconv(A) (uchar) toupper(A) +#define likeconv(cs,A) (uchar) (cs)->toupper(A) #else -#define likeconv(A) (uchar) my_sort_order[(uchar) (A)] +#define likeconv(cs,A) (uchar) (cs)->sort_order[(uchar) (A)] #endif @@ -1516,11 +1564,12 @@ void Item_func_like::turboBM_compute_suffixes(int* suff) const int plm1 = pattern_len - 1; int f = 0; int g = plm1; - int* const splm1 = suff + plm1; + int *const splm1 = suff + plm1; + CHARSET_INFO *cs=system_charset_info; // QQ Needs to be fixed *splm1 = pattern_len; - if (binary) + if (binary()) { int i; for (i = pattern_len - 2; i >= 0; i--) @@ -1552,7 +1601,8 @@ void Item_func_like::turboBM_compute_suffixes(int* suff) if (i < g) g = i; // g = min(i, g) f = i; - while (g >= 0 && likeconv(pattern[g]) == likeconv(pattern[g + plm1 - f])) + while (g >= 0 && likeconv(cs, pattern[g]) == + likeconv(cs, pattern[g + plm1 - f])) g--; suff[i] = f - g; } @@ -1613,19 +1663,25 @@ void Item_func_like::turboBM_compute_good_suffix_shifts(int* suff) void Item_func_like::turboBM_compute_bad_character_shifts() { - int* i; - int* end = bmBc + alphabet_size; + int *i; + int *end = bmBc + alphabet_size; + int j; + const int plm1 = pattern_len - 1; + CHARSET_INFO *cs=system_charset_info; // QQ Needs to be fixed + for (i = bmBc; i < end; i++) *i = pattern_len; - int j; - const int plm1 = pattern_len - 1; - if (binary) + if (binary()) + { for (j = 0; j < plm1; j++) bmBc[pattern[j]] = plm1 - j; + } else + { for (j = 0; j < plm1; j++) - bmBc[likeconv(pattern[j])] = plm1 - j; + bmBc[likeconv(cs,pattern[j])] = plm1 - j; + } } @@ -1641,12 +1697,13 @@ bool Item_func_like::turboBM_matches(const char* text, int text_len) const int shift = pattern_len; int j = 0; int u = 0; + CHARSET_INFO *cs=system_charset_info; // QQ Needs to be fixed const int plm1 = pattern_len - 1; const int tlmpl = text_len - pattern_len; /* Searching */ - if (binary) + if (binary()) { while (j <= tlmpl) { @@ -1682,7 +1739,7 @@ bool Item_func_like::turboBM_matches(const char* text, int text_len) const while (j <= tlmpl) { register int i = plm1; - while (i >= 0 && likeconv(pattern[i]) == likeconv(text[i + j])) + while (i >= 0 && likeconv(cs,pattern[i]) == likeconv(cs,text[i + j])) { i--; if (i == plm1 - shift) @@ -1693,7 +1750,7 @@ bool Item_func_like::turboBM_matches(const char* text, int text_len) const register const int v = plm1 - i; turboShift = u - v; - bcShift = bmBc[likeconv(text[i + j])] - plm1 + i; + bcShift = bmBc[likeconv(cs, text[i + j])] - plm1 + i; shift = max(turboShift, bcShift); shift = max(shift, bmGs[i]); if (shift == bmGs[i]) @@ -1748,3 +1805,82 @@ longlong Item_cond_xor::val_int() } return (longlong) result; } + +/**************************************************************** + 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 e163bc40a6e..a9dc6c87f95 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -28,7 +28,6 @@ public: Item_bool_func(Item *a) :Item_int_func(a) {} Item_bool_func(Item *a,Item *b) :Item_int_func(a,b) {} void fix_length_and_dec() { decimals=0; max_length=1; } - unsigned int size_of() { return sizeof(*this);} }; class Item_bool_func2 :public Item_int_func @@ -48,7 +47,6 @@ public: bool have_rev_func() const { return rev_functype() != UNKNOWN_FUNC; } void print(String *str) { Item_func::print_op(str); } bool is_null() { return test(args[0]->is_null() || args[1]->is_null()); } - unsigned int size_of() { return sizeof(*this);} }; @@ -82,7 +80,6 @@ public: enum Functype rev_functype() const { return EQUAL_FUNC; } cond_result eq_cmp_result() const { return COND_TRUE; } const char *func_name() const { return "<=>"; } - unsigned int size_of() { return sizeof(*this);} }; @@ -180,15 +177,16 @@ public: Item_func_interval(Item *a,List<Item> &list) :Item_int_func(list),item(a),intervals(0) {} longlong val_int(); - bool fix_fields(THD *thd,struct st_table_list *tlist) + bool fix_fields(THD *thd, struct st_table_list *tlist, Item **ref) { - return (item->fix_fields(thd,tlist) || Item_func::fix_fields(thd,tlist)); + return (item->fix_fields(thd, tlist, &item) || + Item_func::fix_fields(thd, tlist, ref)); } void fix_length_and_dec(); ~Item_func_interval() { delete item; } const char *func_name() const { return "interval"; } void update_used_tables(); - unsigned int size_of() { return sizeof(*this);} + bool check_loop(uint id); }; @@ -203,7 +201,6 @@ public: enum Item_result result_type () const { return cached_result_type; } void fix_length_and_dec(); const char *func_name() const { return "ifnull"; } - unsigned int size_of() { return sizeof(*this);} }; @@ -223,7 +220,6 @@ public: } void fix_length_and_dec(); const char *func_name() const { return "if"; } - unsigned int size_of() { return sizeof(*this);} }; @@ -238,7 +234,6 @@ public: enum Item_result result_type () const { return cached_result_type; } void fix_length_and_dec(); const char *func_name() const { return "nullif"; } - unsigned int size_of() { return sizeof(*this);} }; @@ -253,7 +248,6 @@ public: void fix_length_and_dec(); enum Item_result result_type () const { return cached_result_type; } const char *func_name() const { return "coalesce"; } - unsigned int size_of() { return sizeof(*this);} }; class Item_func_case :public Item_func @@ -272,9 +266,9 @@ public: enum Item_result result_type () const { return cached_result_type; } const char *func_name() const { return "case"; } void print(String *str); - bool fix_fields(THD *thd,struct st_table_list *tlist); + bool fix_fields(THD *thd, struct st_table_list *tlist, Item **ref); Item *find_item(String *str); - unsigned int size_of() { return sizeof(*this);} + bool check_loop(uint id); }; @@ -355,7 +349,7 @@ class cmp_item_sort_string :public cmp_item { char value_buff[80]; String value,*value_res; public: - cmp_item_sort_string() :value(value_buff,sizeof(value_buff)) {} + cmp_item_sort_string() :value(value_buff,sizeof(value_buff),default_charset_info) {} void store_value(Item *item) { value_res=item->val_str(&value); @@ -363,7 +357,7 @@ public: int cmp(Item *arg) { char buff[80]; - String tmp(buff,sizeof(buff)),*res; + String tmp(buff,sizeof(buff),default_charset_info),*res; if (!(res=arg->val_str(&tmp))) return 1; /* Can't be right */ return sortcmp(value_res,res); @@ -376,7 +370,7 @@ public: int cmp(Item *arg) { char buff[80]; - String tmp(buff,sizeof(buff)),*res; + String tmp(buff,sizeof(buff),default_charset_info),*res; if (!(res=arg->val_str(&tmp))) return 1; /* Can't be right */ return stringcmp(value_res,res); @@ -423,9 +417,10 @@ class Item_func_in :public Item_int_func Item_func_in(Item *a,List<Item> &list) :Item_int_func(list),item(a),array(0),in_item(0) {} longlong val_int(); - bool fix_fields(THD *thd,struct st_table_list *tlist) + bool fix_fields(THD *thd, struct st_table_list *tlist, Item **ref) { - return (item->fix_fields(thd,tlist) || Item_func::fix_fields(thd,tlist)); + return (item->fix_fields(thd, tlist, &item) || + Item_func::fix_fields(thd, tlist, ref)); } void fix_length_and_dec(); ~Item_func_in() { delete item; delete array; delete in_item; } @@ -436,7 +431,13 @@ class Item_func_in :public Item_int_func enum Functype functype() const { return IN_FUNC; } const char *func_name() const { return " IN "; } void update_used_tables(); - unsigned int size_of() { return sizeof(*this);} + bool check_loop(uint id) + { + DBUG_ENTER("Item_func_in::check_loop"); + if (Item_func::check_loop(id)) + DBUG_RETURN(1); + DBUG_RETURN(item->check_loop(id)); + } }; @@ -474,7 +475,6 @@ public: } } optimize_type select_optimize() const { return OPTIMIZE_NULL; } - unsigned int size_of() { return sizeof(*this);} }; class Item_func_isnotnull :public Item_bool_func @@ -489,7 +489,6 @@ public: } const char *func_name() const { return "isnotnull"; } optimize_type select_optimize() const { return OPTIMIZE_NULL; } - unsigned int size_of() { return sizeof(*this);} }; class Item_func_like :public Item_bool_func2 @@ -522,8 +521,7 @@ public: cond_result eq_cmp_result() const { return COND_TRUE; } const char *func_name() const { return "like"; } void fix_length_and_dec(); - bool fix_fields(THD *thd,struct st_table_list *tlist); - unsigned int size_of() { return sizeof(*this);} + bool fix_fields(THD *thd, struct st_table_list *tlist, Item **ref); }; #ifdef USE_REGEX @@ -541,9 +539,8 @@ public: regex_compiled(0),regex_is_const(0) {} ~Item_func_regex(); longlong val_int(); - bool fix_fields(THD *thd,struct st_table_list *tlist); + bool fix_fields(THD *thd, struct st_table_list *tlist, Item **ref); const char *func_name() const { return "regex"; } - unsigned int size_of() { return sizeof(*this);} }; #else @@ -573,7 +570,7 @@ public: { list.push_back(i1); list.push_back(i2); } ~Item_cond() { list.delete_elements(); } bool add(Item *item) { return list.push_back(item); } - bool fix_fields(THD *,struct st_table_list *); + bool fix_fields(THD *, struct st_table_list *, Item **ref); enum Type type() const { return COND_ITEM; } List<Item>* argument_list() { return &list; } @@ -582,7 +579,7 @@ public: void print(String *str); void split_sum_func(List<Item> &fields); friend int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds); - unsigned int size_of() { return sizeof(*this);} + bool check_loop(uint id); void top_level_item() { abort_on_null=1; } }; @@ -608,6 +605,17 @@ public: }; +class Item_cond_xor :public Item_cond +{ +public: + Item_cond_xor() :Item_cond() {} + Item_cond_xor(Item *i1,Item *i2) :Item_cond(i1,i2) {} + enum Functype functype() const { return COND_XOR_FUNC; } + longlong val_int(); + const char *func_name() const { return "xor"; } +}; + + /* Some usefull inline functions */ inline Item *and_conds(Item *a,Item *b) @@ -620,15 +628,80 @@ inline Item *and_conds(Item *a,Item *b) return cond; } -class Item_cond_xor :public Item_cond +Item *and_expressions(Item *a, Item *b, Item **org_item); + +/************************************************************** + Spatial relations +***************************************************************/ + +class Item_func_spatial_rel :public Item_bool_func2 { + enum Functype spatial_rel; public: - Item_cond_xor() :Item_cond() {} - Item_cond_xor(Item *i1,Item *i2) :Item_cond(i1,i2) {} - enum Functype functype() const { return COND_XOR_FUNC; } + Item_func_spatial_rel(Item *a,Item *b, enum Functype sp_rel) : + Item_bool_func2(a,b) { spatial_rel = sp_rel; } longlong val_int(); - const char *func_name() const { return "xor"; } + 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"; + } + } }; -Item *and_expressions(Item *a, Item *b, Item **org_item); +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 f28e3248c61..e4c9a160686 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -96,6 +96,11 @@ Item *create_func_cot(Item* a) new Item_func_tan(a)); } +Item *create_func_crc32(Item* a) +{ + return new Item_func_crc32(a); +} + Item *create_func_date_format(Item* a,Item *b) { return new Item_func_date_format(a,b,0); @@ -242,7 +247,7 @@ Item *create_func_lpad(Item* a, Item *b, Item *c) Item *create_func_ltrim(Item* a) { - return new Item_func_ltrim(a,new Item_string(" ",1)); + return new Item_func_ltrim(a,new Item_string(" ",1,default_charset_info)); } Item *create_func_md5(Item* a) @@ -324,7 +329,7 @@ Item *create_func_rpad(Item* a, Item *b, Item *c) Item *create_func_rtrim(Item* a) { - return new Item_func_rtrim(a,new Item_string(" ",1)); + return new Item_func_rtrim(a,new Item_string(" ",1,default_charset_info)); } Item *create_func_sec_to_time(Item* a) @@ -349,7 +354,7 @@ Item *create_func_sha(Item* a) Item *create_func_space(Item *a) { - return new Item_func_repeat(new Item_string(" ",1),a); + return new Item_func_repeat(new Item_string(" ",1,default_charset_info),a); } Item *create_func_soundex(Item* a) @@ -394,7 +399,9 @@ Item *create_func_ucase(Item* a) Item *create_func_version(void) { - return new Item_string(NullS,server_version, (uint) strlen(server_version)); + return new Item_string(NullS,server_version, + (uint) strlen(server_version), + default_charset_info); } Item *create_func_weekday(Item* a) @@ -444,3 +451,158 @@ Item *create_func_quote(Item* a) { return new Item_func_quote(a); } + +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 28fbd61df8f..6d9cef04c13 100644 --- a/sql/item_create.h +++ b/sql/item_create.h @@ -27,10 +27,12 @@ Item *create_func_bit_count(Item* a); Item *create_func_bit_length(Item* a); Item *create_func_ceiling(Item* a); Item *create_func_char_length(Item* a); +Item *create_func_cast(Item *a, Item_cast cast_type); Item *create_func_connection_id(void); Item *create_func_conv(Item* a, Item *b, Item *c); Item *create_func_cos(Item* a); Item *create_func_cot(Item* a); +Item *create_func_crc32(Item* a); Item *create_func_date_format(Item* a,Item *b); Item *create_func_dayname(Item* a); Item *create_func_dayofmonth(Item* a); @@ -94,3 +96,41 @@ Item *create_load_file(Item* a); Item *create_wait_for_master_pos(Item* a, Item* b); Item *create_func_is_free_lock(Item* a); Item *create_func_quote(Item* a); + +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 5721a2f5e8c..75260065be6 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -22,11 +22,13 @@ #endif #include "mysql_priv.h" +#include "slave.h" // for wait_for_master_pos #include <m_ctype.h> #include <hash.h> #include <time.h> #include <ft_global.h> -#include "slave.h" // for wait_for_master_pos +#include <zlib.h> +#include <assert.h> /* return TRUE if item is a constant */ @@ -55,12 +57,45 @@ Item_func::Item_func(List<Item> &list) list.empty(); // Fields are used } + +/* + Resolve references to table column for a function and it's argument + + SYNOPSIS: + fix_fields() + thd Thread object + tables List of all open tables involved in the query + ref Pointer to where this object is used. This reference + is used if we want to replace this object with another + one (for example in the summary functions). + + DESCRIPTION + Call fix_fields() for all arguments to the function. The main intention + is to allow all Item_field() objects to setup pointers to the table fields. + + Sets as a side effect the following class variables: + maybe_null Set if any argument may return NULL + with_sum_func Set if any of the arguments contains a sum function + used_table_cache Set to union of the arguments used table + + str_value.charset If this is a string function, set this to the + character set for the first argument. + + If for any item any of the defaults are wrong, then this can + be fixed in the fix_length_and_dec() function that is called + after this one or by writing a specialized fix_fields() for the + item. + + RETURN VALUES + 0 ok + 1 Got error. Stored with my_error(). +*/ + bool -Item_func::fix_fields(THD *thd,TABLE_LIST *tables) +Item_func::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) { Item **arg,**arg_end; char buff[STACK_BUFF_ALLOC]; // Max argument in function - binary=0; used_tables_cache=0; const_item_cache=1; @@ -68,14 +103,20 @@ Item_func::fix_fields(THD *thd,TABLE_LIST *tables) return 0; // Fatal error if flag is set! if (arg_count) { // Print purify happy + /* + Set return character set to first argument if we are returning a + string. + */ + if (result_type() == STRING_RESULT) + set_charset((*args)->charset()); for (arg=args, arg_end=args+arg_count; arg != arg_end ; arg++) { - if ((*arg)->fix_fields(thd,tables)) + if ((*arg)->fix_fields(thd, tables, arg)) return 1; /* purecov: inspected */ if ((*arg)->maybe_null) maybe_null=1; - if ((*arg)->binary) - binary=1; + if ((*arg)->binary()) + set_charset(my_charset_bin); with_sum_func= with_sum_func || (*arg)->with_sum_func; used_tables_cache|=(*arg)->used_tables(); const_item_cache&= (*arg)->const_item(); @@ -85,6 +126,22 @@ Item_func::fix_fields(THD *thd,TABLE_LIST *tables) return 0; } +bool Item_func::check_loop(uint id) +{ + DBUG_ENTER("Item_func::check_loop"); + if (Item_result_field::check_loop(id)) + DBUG_RETURN(1); + if (arg_count) + { + Item **arg,**arg_end; + for (arg= args, arg_end= args+arg_count; arg != arg_end; arg++) + { + if ((*arg)->check_loop(id)) + DBUG_RETURN(1); + } + } + DBUG_RETURN(0); +} void Item_func::split_sum_func(List<Item> &fields) { @@ -187,9 +244,9 @@ Field *Item_func::tmp_table_field(TABLE *t_arg) break; case STRING_RESULT: if (max_length > 255) - res= new Field_blob(max_length, maybe_null, name, t_arg, binary); + res= new Field_blob(max_length, maybe_null, name, t_arg, charset()); else - res= new Field_string(max_length, maybe_null, name, t_arg, binary); + res= new Field_string(max_length, maybe_null, name, t_arg, charset()); break; } return res; @@ -202,7 +259,7 @@ String *Item_real_func::val_str(String *str) if (null_value) return 0; /* purecov: inspected */ else - str->set(nr,decimals); + str->set(nr,decimals,thd_charset()); return str; } @@ -215,9 +272,9 @@ String *Item_num_func::val_str(String *str) if (null_value) return 0; /* purecov: inspected */ else if (!unsigned_flag) - str->set(nr); + str->set(nr,thd_charset()); else - str->set((ulonglong) nr); + str->set((ulonglong) nr,thd_charset()); } else { @@ -225,7 +282,7 @@ String *Item_num_func::val_str(String *str) if (null_value) return 0; /* purecov: inspected */ else - str->set(nr,decimals); + str->set(nr,decimals,thd_charset()); } return str; } @@ -245,9 +302,9 @@ String *Item_int_func::val_str(String *str) if (null_value) return 0; else if (!unsigned_flag) - str->set(nr); + str->set(nr,thd_charset()); else - str->set((ulonglong) nr); + str->set((ulonglong) nr,thd_charset()); return str; } @@ -274,9 +331,9 @@ String *Item_num_op::val_str(String *str) if (null_value) return 0; /* purecov: inspected */ else if (!unsigned_flag) - str->set(nr); + str->set(nr,thd_charset()); else - str->set((ulonglong) nr); + str->set((ulonglong) nr,thd_charset()); } else { @@ -284,7 +341,7 @@ String *Item_num_op::val_str(String *str) if (null_value) return 0; /* purecov: inspected */ else - str->set(nr,decimals); + str->set(nr,decimals,thd_charset()); } return str; } @@ -398,6 +455,25 @@ void Item_func_div::fix_length_and_dec() maybe_null=1; } + +/* Integer division */ +longlong Item_func_int_div::val_int() +{ + longlong value=args[0]->val_int(); + longlong val2=args[1]->val_int(); + if ((null_value= val2 == 0 || args[0]->null_value || args[1]->null_value)) + return 0; + return value/val2; +} + + +void Item_func_int_div::fix_length_and_dec() +{ + max_length=args[0]->max_length - args[0]->decimals; + maybe_null=1; +} + + double Item_func_mod::val() { double value= floor(args[0]->val()+0.5); @@ -748,7 +824,6 @@ void Item_func_min_max::fix_length_and_dec() decimals=0; max_length=0; maybe_null=1; - binary=0; cmp_type=args[0]->result_type(); for (uint i=0 ; i < arg_count ; i++) { @@ -759,8 +834,8 @@ void Item_func_min_max::fix_length_and_dec() if (!args[i]->maybe_null) maybe_null=0; cmp_type=item_cmp_type(cmp_type,args[i]->result_type()); - if (args[i]->binary) - binary=1; + if (args[i]->binary()) + set_charset(my_charset_bin); } } @@ -774,9 +849,9 @@ String *Item_func_min_max::val_str(String *str) if (null_value) return 0; else if (!unsigned_flag) - str->set(nr); + str->set(nr,thd_charset()); else - str->set((ulonglong) nr); + str->set((ulonglong) nr,thd_charset()); return str; } case REAL_RESULT: @@ -785,7 +860,7 @@ String *Item_func_min_max::val_str(String *str) if (null_value) return 0; /* purecov: inspected */ else - str->set(nr,decimals); + str->set(nr,decimals,thd_charset()); return str; } case STRING_RESULT: @@ -806,7 +881,7 @@ String *Item_func_min_max::val_str(String *str) res2= args[i]->val_str(res == str ? &tmp_value : str); if (res2) { - int cmp=binary ? stringcmp(res,res2) : sortcmp(res,res2); + int cmp=binary() ? stringcmp(res,res2) : sortcmp(res,res2); if ((cmp_sign < 0 ? cmp : -cmp) < 0) res=res2; } @@ -862,6 +937,18 @@ longlong Item_func_min_max::val_int() return value; } +longlong Item_func_crc32::val_int() +{ + String *res=args[0]->val_str(&value); + if (!res) + { + null_value=1; + return 0; /* purecov: inspected */ + } + null_value=0; + return (longlong) crc32(0L, (Bytef*)res->ptr(), res->length()); +} + longlong Item_func_length::val_int() { @@ -884,7 +971,7 @@ longlong Item_func_char_length::val_int() return 0; /* purecov: inspected */ } null_value=0; - return (longlong) (!args[0]->binary) ? res->numchars() : res->length(); + return (longlong) (!args[0]->binary()) ? res->numchars() : res->length(); } @@ -892,7 +979,7 @@ longlong Item_func_locate::val_int() { String *a=args[0]->val_str(&value1); String *b=args[1]->val_str(&value2); - bool binary_str = args[0]->binary || args[1]->binary; + bool binary_str = args[0]->binary() || args[1]->binary(); if (!a || !b) { null_value=1; @@ -907,7 +994,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) @@ -920,7 +1007,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(); @@ -939,14 +1026,15 @@ 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; } return 0; } #endif /* USE_MB */ - return (longlong) (binary ? a->strstr(*b,start) : + return (longlong) (binary() ? a->strstr(*b,start) : (a->strstr_case(*b,start)))+1; } @@ -990,12 +1078,12 @@ 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()); - if (!l) return (longlong)((uchar) *str); + 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++); return (longlong) n; @@ -1055,6 +1143,7 @@ longlong Item_func_find_in_set::val_int() null_value=0; int diff; + CHARSET_INFO *charset= find->charset(); if ((diff=buffer->length() - find->length()) >= 0) { const char *f_pos=find->ptr(); @@ -1068,7 +1157,7 @@ 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(charset,*str) != my_toupper(charset,*pos)) goto not_found; str++; pos++; @@ -1163,7 +1252,7 @@ udf_handler::~udf_handler() bool -udf_handler::fix_fields(THD *thd,TABLE_LIST *tables,Item_result_field *func, +udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func, uint arg_count, Item **arguments) { char buff[STACK_BUFF_ALLOC]; // Max argument in function @@ -1188,7 +1277,7 @@ udf_handler::fix_fields(THD *thd,TABLE_LIST *tables,Item_result_field *func, args=arguments; /* Fix all arguments */ - func->binary=func->maybe_null=0; + func->maybe_null=0; used_tables_cache=0; const_item_cache=1; @@ -1207,10 +1296,10 @@ udf_handler::fix_fields(THD *thd,TABLE_LIST *tables,Item_result_field *func, arg != arg_end ; arg++,i++) { - if ((*arg)->fix_fields(thd,tables)) + if ((*arg)->fix_fields(thd, tables, arg)) return 1; - if ((*arg)->binary) - func->binary=1; + if ((*arg)->binary()) + func->set_charset(my_charset_bin); if ((*arg)->maybe_null) func->maybe_null=1; func->with_sum_func= func->with_sum_func || (*arg)->with_sum_func; @@ -1373,7 +1462,7 @@ String *udf_handler::val_str(String *str,String *save_str) str->length(res_length); return str; } - save_str->set(res, res_length); + save_str->set(res, res_length, default_charset_info); return save_str; } @@ -1394,7 +1483,7 @@ String *Item_func_udf_float::val_str(String *str) if (null_value) return 0; /* purecov: inspected */ else - str->set(nr,decimals); + str->set(nr,decimals,thd_charset()); return str; } @@ -1415,9 +1504,9 @@ String *Item_func_udf_int::val_str(String *str) if (null_value) return 0; else if (!unsigned_flag) - str->set(nr); + str->set(nr,thd_charset()); else - str->set((ulonglong) nr); + str->set((ulonglong) nr,thd_charset()); return str; } @@ -1498,7 +1587,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) @@ -1512,9 +1602,9 @@ void item_user_lock_release(ULL *ull) if (mysql_bin_log.is_open()) { char buf[256]; - String tmp(buf,sizeof(buf)); - tmp.length(0); - tmp.append("DO RELEASE_LOCK(\""); + const char *command="DO RELEASE_LOCK(\""; + String tmp(buf,sizeof(buf), system_charset_info); + tmp.copy(command, strlen(command), tmp.charset()); tmp.append(ull->key,ull->key_length); tmp.append("\")"); Query_log_event qev(current_thd, tmp.ptr(), tmp.length(),1); @@ -1772,7 +1862,7 @@ longlong Item_func_set_last_insert_id::val_int() longlong Item_func_benchmark::val_int() { char buff[MAX_FIELD_WIDTH]; - String tmp(buff,sizeof(buff)); + String tmp(buff,sizeof(buff), default_charset_info); THD *thd=current_thd; for (ulong loop=0 ; loop < loop_count && !thd->killed; loop++) @@ -1827,11 +1917,12 @@ static user_var_entry *get_variable(HASH *hash, LEX_STRING &name, } -bool Item_func_set_user_var::fix_fields(THD *thd,TABLE_LIST *tables) +bool Item_func_set_user_var::fix_fields(THD *thd, TABLE_LIST *tables, + Item **ref) { if (!thd) thd=current_thd; // Should never happen - if (Item_func::fix_fields(thd,tables) || + if (Item_func::fix_fields(thd, tables, ref) || !(entry= get_variable(&thd->user_vars, name, 1))) return 1; entry->update_query_id=thd->query_id; @@ -1849,7 +1940,8 @@ Item_func_set_user_var::fix_length_and_dec() } void Item_func_set_user_var::update_hash(void *ptr, uint length, - Item_result type) + Item_result type, + CHARSET_INFO *cs) { if ((null_value=args[0]->null_value)) { @@ -1858,6 +1950,7 @@ void Item_func_set_user_var::update_hash(void *ptr, uint length, my_free(entry->value,MYF(0)); entry->value=0; entry->length=0; + entry->var_charset=cs; } else { @@ -1888,6 +1981,7 @@ void Item_func_set_user_var::update_hash(void *ptr, uint length, memcpy(entry->value,ptr,length); entry->length= length; entry->type=type; + entry->var_charset=cs; } return; @@ -1910,7 +2004,7 @@ Item_func_set_user_var::update() break; case STRING_RESULT: char buffer[MAX_FIELD_WIDTH]; - String tmp(buffer,sizeof(buffer)); + String tmp(buffer,sizeof(buffer),default_charset_info); (void) val_str(&tmp); break; } @@ -1922,7 +2016,7 @@ double Item_func_set_user_var::val() { double value=args[0]->val(); - update_hash((void*) &value,sizeof(value), REAL_RESULT); + update_hash((void*) &value,sizeof(value), REAL_RESULT, default_charset_info); return value; } @@ -1930,7 +2024,7 @@ longlong Item_func_set_user_var::val_int() { longlong value=args[0]->val_int(); - update_hash((void*) &value,sizeof(longlong),INT_RESULT); + update_hash((void*) &value,sizeof(longlong),INT_RESULT, default_charset_info); return value; } @@ -1939,9 +2033,9 @@ Item_func_set_user_var::val_str(String *str) { String *res=args[0]->val_str(str); if (!res) // Null value - update_hash((void*) 0,0,STRING_RESULT); + update_hash((void*) 0,0,STRING_RESULT, default_charset_info); else - update_hash(res->c_ptr(),res->length()+1,STRING_RESULT); + update_hash(res->c_ptr(),res->length()+1,STRING_RESULT,res->charset()); return res; } @@ -1976,13 +2070,13 @@ Item_func_get_user_var::val_str(String *str) return NULL; switch (entry->type) { case REAL_RESULT: - str->set(*(double*) entry->value,decimals); + str->set(*(double*) entry->value,decimals,thd_charset()); break; case INT_RESULT: - str->set(*(longlong*) entry->value); + str->set(*(longlong*) entry->value,thd_charset()); break; case STRING_RESULT: - if (str->copy(entry->value, entry->length-1)) + if (str->copy(entry->value, entry->length-1, entry->var_charset)) { null_value=1; return NULL; @@ -2085,7 +2179,7 @@ longlong Item_func_inet_aton::val_int() char c = '.'; // we mark c to indicate invalid IP in case length is 0 char buff[36]; - String *s,tmp(buff,sizeof(buff)); + String *s,tmp(buff,sizeof(buff),default_charset_info); if (!(s = args[0]->val_str(&tmp))) // If null value goto err; null_value=0; @@ -2124,7 +2218,9 @@ void Item_func_match::init_search(bool no_order) DBUG_VOID_RETURN; if (key == NO_SUCH_KEY) - concat= new Item_func_concat_ws(new Item_string(" ",1), fields); + concat=new Item_func_concat_ws(new Item_string(" ",1, + default_charset_info), + fields); if (master) { @@ -2135,15 +2231,15 @@ void Item_func_match::init_search(bool no_order) DBUG_VOID_RETURN; } - String *ft_tmp=0; + String *ft_tmp= 0; char tmp1[FT_QUERY_MAXLEN]; - String tmp2(tmp1,sizeof(tmp1)); + String tmp2(tmp1,sizeof(tmp1),default_charset_info); // MATCH ... AGAINST (NULL) is meaningless, but possible if (!(ft_tmp=key_item()->val_str(&tmp2))) { ft_tmp= &tmp2; - tmp2.set("",0); + tmp2.set("",0,default_charset_info); } ft_handler=table->file->ft_init_ext(mode, key, @@ -2158,7 +2254,7 @@ void Item_func_match::init_search(bool no_order) } -bool Item_func_match::fix_fields(THD *thd,struct st_table_list *tlist) +bool Item_func_match::fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref) { List_iterator<Item> li(fields); Item *item; @@ -2172,7 +2268,7 @@ bool Item_func_match::fix_fields(THD *thd,struct st_table_list *tlist) modifications to find_best and auto_close as complement to auto_init code above. */ - if (Item_func::fix_fields(thd,tlist) || !const_item()) + if (Item_func::fix_fields(thd, tlist, ref) || !const_item()) { my_error(ER_WRONG_ARGUMENTS,MYF(0),"AGAINST"); return 1; @@ -2180,7 +2276,7 @@ bool Item_func_match::fix_fields(THD *thd,struct st_table_list *tlist) while ((item=li++)) { - if (item->fix_fields(thd,tlist)) + if (item->fix_fields(thd, tlist, li.ref())) return 1; if (item->type() == Item::REF_ITEM) li.replace(item= *((Item_ref *)item)->ref); @@ -2204,6 +2300,19 @@ bool Item_func_match::fix_fields(THD *thd,struct st_table_list *tlist) return 0; } +bool Item_func_match::check_loop(uint id) +{ + DBUG_ENTER("Item_func_match::check_loop"); + if (Item_real_func::check_loop(id)) + DBUG_RETURN(1); + + List_iterator<Item> li(fields); + Item *item; + while ((item= li++)) + if (item->check_loop(id)) + DBUG_RETURN(1); + DBUG_RETURN(0); +} bool Item_func_match::fix_index() { @@ -2327,6 +2436,7 @@ double Item_func_match::val() DBUG_RETURN(ft_handler->please->find_relevance(ft_handler, record, 0)); } + longlong Item_func_bit_xor::val_int() { ulonglong arg1= (ulonglong) args[0]->val_int(); @@ -2343,18 +2453,19 @@ longlong Item_func_bit_xor::val_int() Item *get_system_var(enum_var_type var_type, LEX_STRING name) { - if (!my_strcasecmp(name.str,"VERSION")) - return new Item_string("@@VERSION",server_version, - (uint) strlen(server_version)); + if (!my_strcasecmp(system_charset_info, name.str, "VERSION")) + return new Item_string("@@VERSION", server_version, + (uint) strlen(server_version), + system_charset_info); THD *thd=current_thd; Item *item; sys_var *var; char buff[MAX_SYS_VAR_LENGTH+3+8], *pos; - if (!(var= find_sys_var(name.str))) + if (!(var= find_sys_var(name.str, name.length))) { - net_printf(&thd->net, ER_UNKNOWN_SYSTEM_VARIABLE, name.str); + net_printf(thd, ER_UNKNOWN_SYSTEM_VARIABLE, name.str); return 0; } if (!(item=var->item(thd, var_type))) @@ -2374,6 +2485,23 @@ Item *get_system_var(enum_var_type var_type, LEX_STRING name) } +Item *get_system_var(enum_var_type var_type, const char *var_name, uint length, + const char *item_name) +{ + THD *thd=current_thd; + Item *item; + sys_var *var; + + var= find_sys_var(var_name, length); + DBUG_ASSERT(var != 0); + if (!(item=var->item(thd, var_type))) + return 0; // Impossible + thd->safe_to_cache_query=0; + item->set_name(item_name); // Will use original name + return item; +} + + /* Check a user level lock. @@ -2408,3 +2536,124 @@ longlong Item_func_is_free_lock::val_int() return 1; 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 || + 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=0; + String *wkb=args[0]->val_str(&value); + Geometry geom; + + null_value= (!wkb || + 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=0; + 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=0; + String *wkb=args[0]->val_str(&value); + Geometry geom; + + null_value= (!wkb || + 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=0; + String *wkb=args[0]->val_str(&value); + Geometry geom; + + null_value= (!wkb || + 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=0; + String *wkb=args[0]->val_str(&value); + Geometry geom; + + null_value= (!wkb || + 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=0; + String *wkb=args[0]->val_str(&value); + Geometry geom; + + null_value= (!wkb || + 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 2e02d7cfd28..b659a6d69d2 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -39,7 +39,13 @@ 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,COND_XOR_FUNC,BETWEEN,IN_FUNC,INTERVAL_FUNC}; + COND_AND_FUNC, COND_OR_FUNC, COND_XOR_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; } @@ -94,7 +100,7 @@ public: } Item_func(List<Item> &list); ~Item_func() {} /* Nothing to do; Items are freed automaticly */ - bool fix_fields(THD *,struct st_table_list *); + bool fix_fields(THD *,struct st_table_list *, Item **ref); void make_field(Send_field *field); table_map used_tables() const; void update_used_tables(); @@ -121,8 +127,8 @@ public: } bool is_null() { (void) val_int(); return null_value; } friend class udf_handler; - unsigned int size_of() { return sizeof(*this);} Field *tmp_table_field(TABLE *t_arg); + bool check_loop(uint id); }; @@ -137,7 +143,6 @@ public: longlong val_int() { return (longlong) val(); } enum Item_result result_type () const { return REAL_RESULT; } void fix_length_and_dec() { decimals=NOT_FIXED_DEC; max_length=float_length(decimals); } - unsigned int size_of() { return sizeof(*this);} }; @@ -153,7 +158,6 @@ public: enum Item_result result_type () const { return hybrid_type; } void fix_length_and_dec() { fix_num_length_and_dec(); } bool is_null() { (void) val(); return null_value; } - unsigned int size_of() { return sizeof(*this);} }; @@ -169,7 +173,6 @@ class Item_num_op :public Item_func void fix_length_and_dec() { fix_num_length_and_dec(); find_num_type(); } void find_num_type(void); bool is_null() { (void) val(); return null_value; } - unsigned int size_of() { return sizeof(*this);} }; @@ -251,6 +254,18 @@ public: }; +class Item_func_int_div :public Item_num_op +{ +public: + Item_func_int_div(Item *a,Item *b) :Item_num_op(a,b) + { hybrid_type=INT_RESULT; } + double val() { return (double) val_int(); } + longlong val_int(); + const char *func_name() const { return "DIV"; } + void fix_length_and_dec(); +}; + + class Item_func_mod :public Item_num_op { public: @@ -459,7 +474,6 @@ public: const char *func_name() const { return truncate ? "truncate" : "round"; } double val(); void fix_length_and_dec(); - unsigned int size_of() { return sizeof(*this);} }; @@ -495,7 +509,6 @@ class Item_func_units :public Item_real_func double val(); const char *func_name() const { return name; } void fix_length_and_dec() { decimals=NOT_FIXED_DEC; max_length=float_length(decimals); } - unsigned int size_of() { return sizeof(*this);} }; @@ -512,7 +525,6 @@ public: String *val_str(String *); void fix_length_and_dec(); enum Item_result result_type () const { return cmp_type; } - unsigned int size_of() { return sizeof(*this);} }; class Item_func_min :public Item_func_min_max @@ -529,6 +541,16 @@ public: const char *func_name() const { return "greatest"; } }; +class Item_func_crc32 :public Item_int_func +{ + String value; +public: + Item_func_crc32(Item *a) :Item_int_func(a) {} + longlong val_int(); + const char *func_name() const { return "crc32"; } + void fix_length_and_dec() { max_length=10; } +}; + class Item_func_length :public Item_int_func { @@ -538,7 +560,6 @@ public: longlong val_int(); const char *func_name() const { return "length"; } void fix_length_and_dec() { max_length=10; } - unsigned int size_of() { return sizeof(*this);} }; class Item_func_bit_length :public Item_func_length @@ -557,7 +578,6 @@ public: longlong val_int(); const char *func_name() const { return "char_length"; } void fix_length_and_dec() { max_length=10; } - unsigned int size_of() { return sizeof(*this);} }; class Item_func_locate :public Item_int_func @@ -569,7 +589,6 @@ public: const char *func_name() const { return "locate"; } longlong val_int(); void fix_length_and_dec() { maybe_null=0; max_length=11; } - unsigned int size_of() { return sizeof(*this);} }; @@ -581,9 +600,10 @@ public: Item_func_field(Item *a,List<Item> &list) :Item_int_func(list),item(a) {} ~Item_func_field() { delete item; } longlong val_int(); - bool fix_fields(THD *thd,struct st_table_list *tlist) + bool fix_fields(THD *thd,struct st_table_list *tlist, Item **ref) { - return (item->fix_fields(thd,tlist) || Item_func::fix_fields(thd,tlist)); + return (item->fix_fields(thd, tlist, &item) || + Item_func::fix_fields(thd, tlist, ref)); } void update_used_tables() { @@ -599,7 +619,13 @@ public: const_item_cache&= item->const_item(); with_sum_func= with_sum_func || item->with_sum_func; } - unsigned int size_of() { return sizeof(*this);} + bool check_loop(uint id) + { + DBUG_ENTER("Item_func_field::check_loop"); + if (Item_int_func::check_loop(id)) + DBUG_RETURN(1); + DBUG_RETURN(item->check_loop(id)); + } }; @@ -611,7 +637,6 @@ public: longlong val_int(); const char *func_name() const { return "ascii"; } void fix_length_and_dec() { max_length=3; } - unsigned int size_of() { return sizeof(*this);} }; class Item_func_ord :public Item_int_func @@ -621,7 +646,6 @@ public: Item_func_ord(Item *a) :Item_int_func(a) {} longlong val_int(); const char *func_name() const { return "ord"; } - unsigned int size_of() { return sizeof(*this);} }; class Item_func_find_in_set :public Item_int_func @@ -634,7 +658,6 @@ public: longlong val_int(); const char *func_name() const { return "find_in_set"; } void fix_length_and_dec(); - unsigned int size_of() { return sizeof(*this);} }; @@ -710,7 +733,6 @@ class Item_func_benchmark :public Item_int_func longlong val_int(); const char *func_name() const { return "benchmark"; } void fix_length_and_dec() { max_length=1; maybe_null=0; } - unsigned int size_of() { return sizeof(*this);} }; @@ -727,15 +749,14 @@ public: :Item_func(list), udf(udf_arg) {} ~Item_udf_func() {} const char *func_name() const { return udf.name(); } - bool fix_fields(THD *thd,struct st_table_list *tables) + bool fix_fields(THD *thd, struct st_table_list *tables, Item **ref) { - bool res=udf.fix_fields(thd,tables,this,arg_count,args); - used_tables_cache=udf.used_tables_cache; - const_item_cache=udf.const_item_cache; + bool res= udf.fix_fields(thd, tables, this, arg_count, args); + used_tables_cache= udf.used_tables_cache; + const_item_cache= udf.const_item_cache; return res; } Item_result result_type () const { return udf.result_type(); } - unsigned int size_of() { return sizeof(*this);} }; @@ -844,7 +865,6 @@ class Item_func_get_lock :public Item_int_func longlong val_int(); const char *func_name() const { return "get_lock"; } void fix_length_and_dec() { max_length=1; maybe_null=1;} - unsigned int size_of() { return sizeof(*this);} }; class Item_func_release_lock :public Item_int_func @@ -855,7 +875,6 @@ class Item_func_release_lock :public Item_int_func longlong val_int(); const char *func_name() const { return "release_lock"; } void fix_length_and_dec() { max_length=1; maybe_null=1;} - unsigned int size_of() { return sizeof(*this);} }; /* replication functions */ @@ -868,7 +887,6 @@ class Item_master_pos_wait :public Item_int_func longlong val_int(); const char *func_name() const { return "master_pos_wait"; } void fix_length_and_dec() { max_length=1; maybe_null=1;} - unsigned int size_of() { return sizeof(*this);} }; @@ -887,14 +905,13 @@ public: double val(); longlong val_int(); String *val_str(String *str); - void update_hash(void *ptr, uint length, enum Item_result type); + void update_hash(void *ptr, uint length, enum Item_result type, CHARSET_INFO *cs); bool update(); enum Item_result result_type () const { return cached_result_type; } - bool fix_fields(THD *thd,struct st_table_list *tables); + bool fix_fields(THD *thd, struct st_table_list *tables, Item **ref); void fix_length_and_dec(); void print(String *str); const char *func_name() const { return "set_user_var"; } - unsigned int size_of() { return sizeof(*this);} }; @@ -919,7 +936,6 @@ public: table_map used_tables() const { return const_var_flag ? 0 : RAND_TABLE_BIT; } bool eq(const Item *item, bool binary_cmp) const; - unsigned int size_of() { return sizeof(*this);} }; @@ -968,14 +984,98 @@ public: } enum Functype functype() const { return FT_FUNC; } void update_used_tables() {} - bool fix_fields(THD *thd,struct st_table_list *tlist); + bool fix_fields(THD *thd, struct st_table_list *tlist, Item **ref); bool eq(const Item *, bool binary_cmp) const; longlong val_int() { return val()!=0.0; } double val(); bool fix_index(); void init_search(bool no_order); - unsigned int size_of() { return sizeof(*this);} + bool check_loop(uint id); +}; + + +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"; } }; @@ -998,16 +1098,6 @@ public: const char *func_name() const { return "match_bool"; } }; -/* For type casts */ - -enum Item_cast -{ - ITEM_CAST_BINARY, ITEM_CAST_SIGNED_INT, ITEM_CAST_UNSIGNED_INT, - ITEM_CAST_DATE, ITEM_CAST_TIME, ITEM_CAST_DATETIME -}; - -Item *create_func_cast(Item *a, Item_cast cast_type); - class Item_func_bit_xor : public Item_int_func { @@ -1026,5 +1116,12 @@ public: longlong val_int(); const char *func_name() const { return "check_lock"; } void fix_length_and_dec() { decimals=0; max_length=1; maybe_null=1;} - unsigned int size_of() { return sizeof(*this);} +}; + +/* For type casts */ + +enum Item_cast +{ + ITEM_CAST_BINARY, ITEM_CAST_SIGNED_INT, ITEM_CAST_UNSIGNED_INT, + ITEM_CAST_DATE, ITEM_CAST_TIME, ITEM_CAST_DATETIME }; diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index af533eefe9a..1a561c9eb34 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -37,14 +37,14 @@ #include "sha1.h" #include "my_aes.h" -String empty_string(""); +String empty_string("",default_charset_info); 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; @@ -145,7 +145,7 @@ void Item_func_sha::fix_length_and_dec() String *Item_func_aes_encrypt::val_str(String *str) { char key_buff[80]; - String tmp_key_value(key_buff, sizeof(key_buff)); + String tmp_key_value(key_buff, sizeof(key_buff), system_charset_info); String *sptr= args[0]->val_str(str); // String to encrypt String *key= args[1]->val_str(&tmp_key_value); // key int aes_length; @@ -180,7 +180,8 @@ void Item_func_aes_encrypt::fix_length_and_dec() String *Item_func_aes_decrypt::val_str(String *str) { char key_buff[80]; - String tmp_key_value(key_buff, sizeof(key_buff)), *sptr, *key; + String tmp_key_value(key_buff, sizeof(key_buff), system_charset_info); + String *sptr, *key; DBUG_ENTER("Item_func_aes_decrypt::val_str"); sptr= args[0]->val_str(str); // String to decrypt @@ -231,6 +232,8 @@ String *Item_func_concat::val_str(String *str) use_as_buff= &tmp_value; for (i=1 ; i < arg_count ; i++) { + if (args[i]->binary()) + set_charset(my_charset_bin); if (res->length() == 0) { if (!(res=args[i]->val_str(str))) @@ -259,6 +262,7 @@ String *Item_func_concat::val_str(String *str) str->append(*res2); } res=str; + res->set_charset(charset()); } else if (res == &tmp_value) { @@ -270,6 +274,7 @@ String *Item_func_concat::val_str(String *str) if (tmp_value.replace(0,0,*res)) goto null; res= &tmp_value; + res->set_charset(charset()); use_as_buff=str; // Put next arg here } else if (tmp_value.is_alloced() && res2->ptr() >= tmp_value.ptr() && @@ -288,6 +293,7 @@ String *Item_func_concat::val_str(String *str) *res)) goto null; res= &tmp_value; + res->set_charset(charset()); use_as_buff=str; // Put next arg here } else @@ -297,6 +303,7 @@ String *Item_func_concat::val_str(String *str) tmp_value.append(*res2)) goto null; res= &tmp_value; + res->set_charset(charset()); use_as_buff=str; } } @@ -486,7 +493,7 @@ error: String *Item_func_concat_ws::val_str(String *str) { char tmp_str_buff[10]; - String tmp_sep_str(tmp_str_buff, sizeof(tmp_str_buff)), + String tmp_sep_str(tmp_str_buff, sizeof(tmp_str_buff),default_charset_info), *sep_str, *res, *res2,*use_as_buff; uint i; @@ -625,7 +632,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); @@ -633,7 +640,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++; @@ -676,8 +683,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; @@ -688,6 +694,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 @@ -734,7 +744,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; } } @@ -793,7 +803,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); @@ -866,7 +876,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) @@ -874,6 +884,7 @@ String *Item_func_left::val_str(String *str) if (!res->alloced_length()) { // Don't change const str str_value= *res; // Not malloced string + set_charset(res->charset()); res= &str_value; } res->length((uint) length); @@ -914,7 +925,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; @@ -947,7 +958,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); @@ -1007,7 +1018,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(); @@ -1032,7 +1043,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 */ @@ -1104,7 +1115,7 @@ String *Item_func_ltrim::val_str(String *str) if ((null_value=args[0]->null_value)) return 0; /* purecov: inspected */ char buff[MAX_FIELD_WIDTH]; - String tmp(buff,sizeof(buff)); + String tmp(buff,sizeof(buff),res->charset()); String *remove_str=args[1]->val_str(&tmp); uint remove_length; LINT_INIT(remove_length); @@ -1142,7 +1153,7 @@ String *Item_func_rtrim::val_str(String *str) if ((null_value=args[0]->null_value)) return 0; /* purecov: inspected */ char buff[MAX_FIELD_WIDTH]; - String tmp(buff,sizeof(buff)); + String tmp(buff,sizeof(buff),res->charset()); String *remove_str=args[1]->val_str(&tmp); uint remove_length; LINT_INIT(remove_length); @@ -1161,11 +1172,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; @@ -1178,12 +1189,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)) @@ -1214,7 +1225,7 @@ String *Item_func_trim::val_str(String *str) if ((null_value=args[0]->null_value)) return 0; /* purecov: inspected */ char buff[MAX_FIELD_WIDTH]; - String tmp(buff,sizeof(buff)); + String tmp(buff,sizeof(buff),res->charset()); String *remove_str=args[1]->val_str(&tmp); uint remove_length; LINT_INIT(remove_length); @@ -1229,14 +1240,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)) @@ -1269,7 +1280,7 @@ String *Item_func_password::val_str(String *str) if (res->length() == 0) return &empty_string; make_scrambled_password(tmp_value,res->c_ptr()); - str->set(tmp_value,16); + str->set(tmp_value,16,res->charset()); return str; } @@ -1303,7 +1314,7 @@ String *Item_func_encrypt::val_str(String *str) } pthread_mutex_lock(&LOCK_crypt); char *tmp=crypt(res->c_ptr(),salt_ptr); - str->set(tmp,(uint) strlen(tmp)); + str->set(tmp,(uint) strlen(tmp),res->charset()); str->copy(); pthread_mutex_unlock(&LOCK_crypt); return str; @@ -1355,17 +1366,25 @@ String *Item_func_database::val_str(String *str) if (!current_thd->db) str->length(0); else - str->set((const char*) current_thd->db,(uint) strlen(current_thd->db)); + str->copy((const char*) current_thd->db,(uint) strlen(current_thd->db), system_charset_info, thd_charset()); return str; } String *Item_func_user::val_str(String *str) { - THD *thd=current_thd; - if (str->copy((const char*) thd->user,(uint) strlen(thd->user)) || - str->append('@') || - str->append(thd->host ? thd->host : thd->ip ? thd->ip : "")) - return &empty_string; + THD *thd=current_thd; + CHARSET_INFO *cs=thd_charset(); + const char *host=thd->host ? thd->host : thd->ip ? thd->ip : ""; + uint32 res_length=(strlen(thd->user)+strlen(host)+10) * cs->mbmaxlen; + + if (str->alloc(res_length)) + { + null_value=1; + return 0; + } + res_length=cs->snprintf(cs, (char*)str->ptr(), res_length, "%s@%s",thd->user,host); + str->length(res_length); + str->set_charset(cs); return str; } @@ -1386,9 +1405,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) @@ -1410,21 +1429,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 @@ -1458,7 +1477,7 @@ String *Item_func_format::val_str(String *str) if ((null_value=args[0]->null_value)) return 0; /* purecov: inspected */ dec= decimals ? decimals+1 : 0; - str->set(nr,decimals); + str->set(nr,decimals,thd_charset()); str_length=str->length(); if (nr < 0) str_length--; // Don't count sign @@ -1626,7 +1645,7 @@ String *Item_func_char::val_str(String *str) int32 num=(int32) args[i]->val_int(); if (!args[i]->null_value) #ifdef USE_MB - if (use_mb(default_charset_info)) + if (use_mb(charset())) { if (num&0xFF000000L) { str->append((char)(num>>24)); @@ -1888,12 +1907,232 @@ String *Item_func_conv::val_str(String *str) else dec= (longlong) strtoull(res->c_ptr(),&endptr,from_base); ptr= longlong2str(dec,ans,to_base); - if (str->copy(ans,(uint32) (ptr-ans))) + if (str->copy(ans,(uint32) (ptr-ans), thd_charset())) return &empty_string; return 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; + } + null_value=0; + + from=arg->charset(); + to=conv_charset; + + s=(const uchar*)arg->ptr(); + se=s+arg->length(); + + dmaxlen=arg->length()*to->mbmaxlen+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() +{ + max_length = args[0]->max_length*conv_charset->mbmaxlen; + set_charset(conv_charset); +} + + + +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=get_charset_by_name(from_cs->ptr(), MYF(MY_WME))) || + !(to_charset=get_charset_by_name(to_cs->ptr(), MYF(MY_WME)))) + { + null_value=1; + return 0; + } + + s=(const uchar*)arg->ptr(); + se=s+arg->length(); + + dmaxlen=arg->length()*to_charset->mbmaxlen+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; +} + + +bool Item_func_conv_charset::fix_fields(THD *thd,struct st_table_list *tables, Item **ref) +{ + char buff[STACK_BUFF_ALLOC]; // Max argument in function + used_tables_cache=0; + const_item_cache=1; + + if (thd && check_stack_overrun(thd,buff)) + return 0; // Fatal error if flag is set! + if (args[0]->fix_fields(thd, tables, args)) + return 1; + maybe_null=args[0]->maybe_null; + const_item_cache=args[0]->const_item(); + set_charset(conv_charset); + fix_length_and_dec(); + return 0; +} + + +void Item_func_conv_charset3::fix_length_and_dec() +{ + max_length = args[0]->max_length; +} + +String *Item_func_set_collation::val_str(String *str) +{ + str=args[0]->val_str(str); + if ((null_value=args[0]->null_value)) + return 0; + str->set_charset(set_collation); + return str; +} + +bool Item_func_set_collation::fix_fields(THD *thd,struct st_table_list *tables, Item **ref) +{ + char buff[STACK_BUFF_ALLOC]; // Max argument in function + used_tables_cache=0; + const_item_cache=1; + + if (thd && check_stack_overrun(thd,buff)) + return 0; // Fatal error if flag is set! + if (args[0]->fix_fields(thd, tables, args)) + return 1; + maybe_null=args[0]->maybe_null; + set_charset(set_collation); + with_sum_func= with_sum_func || args[0]->with_sum_func; + used_tables_cache=args[0]->used_tables(); + const_item_cache=args[0]->const_item(); + fix_length_and_dec(); + return 0; +} + +bool Item_func_set_collation::eq(const Item *item, bool binary_cmp) const +{ + /* Assume we don't have rtti */ + if (this == item) + return 1; + if (item->type() != FUNC_ITEM) + return 0; + Item_func *item_func=(Item_func*) item; + if (arg_count != item_func->arg_count || + func_name() != item_func->func_name()) + return 0; + Item_func_set_collation *item_func_sc=(Item_func_set_collation*) item; + if (set_collation != item_func_sc->set_collation) + return 0; + for (uint i=0; i < arg_count ; i++) + if (!args[i]->eq(item_func_sc->args[i], binary_cmp)) + return 0; + return 1; +} + +String *Item_func_charset::val_str(String *str) +{ + String *res = args[0]->val_str(str); + + if ((null_value=(args[0]->null_value || !res->charset()))) + return 0; + str->copy(res->charset()->name,strlen(res->charset()->name),my_charset_latin1,thd_charset()); + return str; +} + + String *Item_func_hex::val_str(String *str) { if (args[0]->result_type() != STRING_RESULT) @@ -1904,7 +2143,7 @@ String *Item_func_hex::val_str(String *str) if ((null_value= args[0]->null_value)) return 0; ptr= longlong2str(dec,ans,16); - if (str->copy(ans,(uint32) (ptr-ans))) + if (str->copy(ans,(uint32) (ptr-ans),default_charset_info)) return &empty_string; // End of memory return str; } @@ -2013,7 +2252,7 @@ String* Item_func_export_set::val_str(String* str) } break; case 3: - sep_buf.set(",", 1); + sep_buf.set(",", 1, default_charset_info); sep = &sep_buf; } null_value=0; @@ -2077,6 +2316,7 @@ String* Item_func_inet_ntoa::val_str(String* str) return str; } + /* QUOTE() function returns argument string in single quotes suitable for using in a SQL statement. @@ -2167,3 +2407,338 @@ null: null_value= 1; return 0; } + + +/******************************************************* +General functions for spatial objects +********************************************************/ + +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; + + if ((null_value=(args[0]->null_value || + geom.create_from_wkb(wkt->ptr(),wkt->length())))) + return 0; + + str->length(0); + + if ((null_value=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, + strlen(geom.get_class_info()->m_name), + default_charset_info); + 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 + { + enum Geometry::wkbType wkb_type; + uint32 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= (Geometry::wkbType) 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() > current_thd->variables.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 181aa8fb6ba..2b308630b48 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -35,10 +35,8 @@ public: double val(); enum Item_result result_type () const { return STRING_RESULT; } void left_right_max_length(); - unsigned int size_of() { return sizeof(*this);} }; - class Item_func_md5 :public Item_str_func { String tmp_value; @@ -47,7 +45,6 @@ public: String *val_str(String *); void fix_length_and_dec(); const char *func_name() const { return "md5"; } - unsigned int size_of() { return sizeof(*this);} }; @@ -88,7 +85,6 @@ public: String *val_str(String *); void fix_length_and_dec(); const char *func_name() const { return "concat"; } - unsigned int size_of() { return sizeof(*this);} }; class Item_func_concat_ws :public Item_str_func @@ -103,13 +99,19 @@ public: String *val_str(String *); void fix_length_and_dec(); void update_used_tables(); - bool fix_fields(THD *thd,struct st_table_list *tlist) + bool fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref) { - return (separator->fix_fields(thd,tlist) - || Item_func::fix_fields(thd,tlist)); + return (separator->fix_fields(thd, tlist, &separator) + || Item_func::fix_fields(thd, tlist, ref)); } const char *func_name() const { return "concat_ws"; } - unsigned int size_of() { return sizeof(*this);} + bool check_loop(uint id) + { + DBUG_ENTER("Item_func_concat_ws::check_loop"); + if (Item_str_func::check_loop(id)) + DBUG_RETURN(1); + DBUG_RETURN(separator->check_loop(id)); + } }; class Item_func_reverse :public Item_str_func @@ -130,7 +132,6 @@ public: String *val_str(String *); void fix_length_and_dec(); const char *func_name() const { return "replace"; } - unsigned int size_of() { return sizeof(*this);} }; @@ -143,7 +144,6 @@ public: String *val_str(String *); void fix_length_and_dec(); const char *func_name() const { return "insert"; } - unsigned int size_of() { return sizeof(*this);} }; @@ -190,7 +190,6 @@ public: String *val_str(String *); void fix_length_and_dec(); const char *func_name() const { return "right"; } - unsigned int size_of() { return sizeof(*this);} }; @@ -203,7 +202,6 @@ public: String *val_str(String *); void fix_length_and_dec(); const char *func_name() const { return "substr"; } - unsigned int size_of() { return sizeof(*this);} }; @@ -215,7 +213,6 @@ public: String *val_str(String *); void fix_length_and_dec() { max_length= args[0]->max_length; } const char *func_name() const { return "substr_index"; } - unsigned int size_of() { return sizeof(*this);} }; @@ -227,7 +224,6 @@ public: String *val_str(String *); void fix_length_and_dec() { max_length= args[0]->max_length; } const char *func_name() const { return "ltrim"; } - unsigned int size_of() { return sizeof(*this);} }; @@ -239,7 +235,6 @@ public: String *val_str(String *); void fix_length_and_dec() { max_length= args[0]->max_length; } const char *func_name() const { return "rtrim"; } - unsigned int size_of() { return sizeof(*this);} }; class Item_func_trim :public Item_str_func @@ -250,7 +245,6 @@ public: String *val_str(String *); void fix_length_and_dec() { max_length= args[0]->max_length; } const char *func_name() const { return "trim"; } - unsigned int size_of() { return sizeof(*this);} }; @@ -262,7 +256,6 @@ public: String *val_str(String *); void fix_length_and_dec() { max_length = 16; } const char *func_name() const { return "password"; } - unsigned int size_of() { return sizeof(*this);} }; class Item_func_des_encrypt :public Item_str_func @@ -275,7 +268,6 @@ public: void fix_length_and_dec() { maybe_null=1; max_length = args[0]->max_length+8; } const char *func_name() const { return "des_encrypt"; } - unsigned int size_of() { return sizeof(*this);} }; class Item_func_des_decrypt :public Item_str_func @@ -287,7 +279,6 @@ public: String *val_str(String *); void fix_length_and_dec() { maybe_null=1; max_length = args[0]->max_length; } const char *func_name() const { return "des_decrypt"; } - unsigned int size_of() { return sizeof(*this);} }; class Item_func_encrypt :public Item_str_func @@ -298,7 +289,6 @@ public: Item_func_encrypt(Item *a, Item *b): Item_str_func(a,b) {} String *val_str(String *); void fix_length_and_dec() { maybe_null=1; max_length = 13; } - unsigned int size_of() { return sizeof(*this);} }; #include "sql_crypt.h" @@ -312,7 +302,6 @@ public: Item_str_func(a),sql_crypt(seed) {} String *val_str(String *); void fix_length_and_dec(); - unsigned int size_of() { return sizeof(*this);} }; class Item_func_decode :public Item_func_encode @@ -328,7 +317,11 @@ class Item_func_database :public Item_str_func public: Item_func_database() {} String *val_str(String *); - void fix_length_and_dec() { max_length= MAX_FIELD_NAME; } + void fix_length_and_dec() + { + max_length= MAX_FIELD_NAME * thd_charset()->mbmaxlen; + set_charset(thd_charset()); + } const char *func_name() const { return "database"; } }; @@ -337,7 +330,11 @@ class Item_func_user :public Item_str_func public: Item_func_user() {} String *val_str(String *); - void fix_length_and_dec() { max_length= USERNAME_LENGTH+HOSTNAME_LENGTH+1; } + void fix_length_and_dec() + { + max_length= (USERNAME_LENGTH+HOSTNAME_LENGTH+1)*thd_charset()->mbmaxlen; + set_charset(thd_charset()); + } const char *func_name() const { return "user"; } }; @@ -350,7 +347,6 @@ public: String *val_str(String *); void fix_length_and_dec(); const char *func_name() const { return "soundex"; } - unsigned int size_of() { return sizeof(*this);} }; @@ -364,14 +360,21 @@ public: double val(); longlong val_int(); String *val_str(String *str); - bool fix_fields(THD *thd,struct st_table_list *tlist) + bool fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref) { - return (item->fix_fields(thd,tlist) || Item_func::fix_fields(thd,tlist)); + return (item->fix_fields(thd, tlist, &item) || + Item_func::fix_fields(thd, tlist, ref)); } void fix_length_and_dec(); void update_used_tables(); const char *func_name() const { return "elt"; } - unsigned int size_of() { return sizeof(*this);} + bool check_loop(uint id) + { + DBUG_ENTER("Item_func_elt::check_loop"); + if (Item_str_func::check_loop(id)) + DBUG_RETURN(1); + DBUG_RETURN(item->check_loop(id)); + } }; @@ -384,14 +387,21 @@ public: Item_func_make_set(Item *a,List<Item> &list) :Item_str_func(list),item(a) {} ~Item_func_make_set() { delete item; } String *val_str(String *str); - bool fix_fields(THD *thd,struct st_table_list *tlist) + bool fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref) { - return (item->fix_fields(thd,tlist) || Item_func::fix_fields(thd,tlist)); + return (item->fix_fields(thd, tlist, &item) || + Item_func::fix_fields(thd, tlist, ref)); } void fix_length_and_dec(); void update_used_tables(); const char *func_name() const { return "make_set"; } - unsigned int size_of() { return sizeof(*this);} + bool check_loop(uint id) + { + DBUG_ENTER("Item_func_make_set::check_loop"); + if (Item_str_func::check_loop(id)) + DBUG_RETURN(1); + DBUG_RETURN(item->check_loop(id)); + } }; @@ -406,7 +416,6 @@ public: max_length=args[0]->max_length+(args[0]->max_length-args[0]->decimals)/3; } const char *func_name() const { return "format"; } - unsigned int size_of() { return sizeof(*this);} }; @@ -415,7 +424,7 @@ class Item_func_char :public Item_str_func public: Item_func_char(List<Item> &list) :Item_str_func(list) {} String *val_str(String *); - void fix_length_and_dec() { maybe_null=0; max_length=arg_count; binary=0;} + void fix_length_and_dec() { maybe_null=0; max_length=arg_count; } const char *func_name() const { return "char"; } }; @@ -428,7 +437,6 @@ public: String *val_str(String *); void fix_length_and_dec(); const char *func_name() const { return "repeat"; } - unsigned int size_of() { return sizeof(*this);} }; @@ -441,7 +449,6 @@ public: String *val_str(String *); void fix_length_and_dec(); const char *func_name() const { return "rpad"; } - unsigned int size_of() { return sizeof(*this);} }; @@ -454,7 +461,6 @@ public: String *val_str(String *); void fix_length_and_dec(); const char *func_name() const { return "lpad"; } - unsigned int size_of() { return sizeof(*this);} }; @@ -476,7 +482,6 @@ public: const char *func_name() const { return "hex"; } String *val_str(String *); void fix_length_and_dec() { decimals=0; max_length=args[0]->max_length*2; } - unsigned int size_of() { return sizeof(*this);} }; @@ -491,7 +496,11 @@ public: null_value=args[0]->null_value; return tmp; } - void fix_length_and_dec() { binary=1; max_length=args[0]->max_length; } + void fix_length_and_dec() + { + set_charset(my_charset_bin); + max_length=args[0]->max_length; + } void print(String *str) { print_op(str); } }; @@ -504,8 +513,11 @@ public: String *val_str(String *); const char *func_name() const { return "load_file"; } void fix_length_and_dec() - { binary=1; maybe_null=1; max_length=MAX_BLOB_WIDTH;} - unsigned int size_of() { return sizeof(*this);} + { + set_charset(my_charset_bin); + maybe_null=1; + max_length=MAX_BLOB_WIDTH; + } }; @@ -520,7 +532,7 @@ class Item_func_export_set: public Item_str_func const char *func_name() const { return "export_set"; } }; - class Item_func_inet_ntoa : public Item_str_func +class Item_func_inet_ntoa : public Item_str_func { public: Item_func_inet_ntoa(Item *a) :Item_str_func(a) @@ -539,3 +551,245 @@ public: String *val_str(String *); void fix_length_and_dec() { max_length= args[0]->max_length * 2 + 2; } }; + +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; } + bool fix_fields(THD *thd,struct st_table_list *tables,Item **ref); + String *val_str(String *); + void fix_length_and_dec(); + const char *func_name() const { return "conv_charset"; } +}; + +class Item_func_set_collation :public Item_str_func +{ + CHARSET_INFO *set_collation; +public: + Item_func_set_collation(Item *a, CHARSET_INFO *cs) :Item_str_func(a) + { set_collation=cs; } + bool fix_fields(THD *thd,struct st_table_list *tables, Item **ref); + String *val_str(String *); + void fix_length_and_dec() + { max_length = args[0]->max_length; } + bool eq(const Item *item, bool binary_cmp) const; + const char *func_name() const { return "set_collation"; } +}; + +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"; } +}; + +class Item_func_charset :public Item_str_func +{ +public: + Item_func_charset(Item *a) :Item_str_func(a) {} + String *val_str(String *); + const char *func_name() const { return "charset"; } + void fix_length_and_dec() + { + max_length=40; // should be enough + set_charset(thd_charset()); + }; +}; + + +/******************************************************* +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_subselect.cc b/sql/item_subselect.cc new file mode 100644 index 00000000000..1f1944026ef --- /dev/null +++ b/sql/item_subselect.cc @@ -0,0 +1,380 @@ +/* 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 */ + +/* + subselect Item + +SUBSELECT TODO: + - add function from mysql_select that use JOIN* as parameter to JOIN methods + (sql_select.h/sql_select.cc) + - remove double 'having' & 'having_list' from JOIN + (sql_select.h/sql_select.cc) + +*/ + +#ifdef __GNUC__ +#pragma implementation // gcc: Class implementation +#endif + +#include "mysql_priv.h" +#include "sql_select.h" + +Item_subselect::Item_subselect(): + Item_result_field(), engine_owner(1), value_assigned(0) +{ + assign_null(); + /* + item value is NULL if select_subselect not changed this value + (i.e. some rows will be found returned) + */ + null_value= 1; +} + +void Item_subselect::init(THD *thd, st_select_lex *select_lex, + select_subselect *result) +{ + + DBUG_ENTER("Item_subselect::init"); + DBUG_PRINT("subs", ("select_lex 0x%xl", (long) select_lex)); + + if (select_lex->next_select()) + engine= new subselect_union_engine(thd, select_lex->master_unit(), result, + this); + else + engine= new subselect_single_select_engine(thd, select_lex, result, + this); + DBUG_VOID_RETURN; +} + +Item_subselect::~Item_subselect() +{ + if (engine_owner) + delete engine; +} + +void Item_subselect::make_field (Send_field *tmp_field) +{ + if (null_value) + { + init_make_field(tmp_field,FIELD_TYPE_NULL); + tmp_field->length=4; + } else { + init_make_field(tmp_field, ((result_type() == STRING_RESULT) ? + FIELD_TYPE_VAR_STRING : + (result_type() == INT_RESULT) ? + FIELD_TYPE_LONGLONG : FIELD_TYPE_DOUBLE)); + } +} + +bool Item_subselect::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) +{ + int res= engine->prepare(); + if (!res) + { + // Is it one field subselect? + if (engine->cols() > max_columns) + { + my_message(ER_SUBSELECT_NO_1_COL, ER(ER_SUBSELECT_NO_1_COL), MYF(0)); + return 1; + } + fix_length_and_dec(); + } + return res; +} + +bool Item_subselect::check_loop(uint id) +{ + DBUG_ENTER("Item_subselect::check_loop"); + if (Item_result_field::check_loop(id)) + DBUG_RETURN(1); + + DBUG_RETURN(engine->check_loop(id)); +} + +void Item_subselect::fix_length_and_dec() +{ + engine->fix_length_and_dec(); +} + +inline table_map Item_subselect::used_tables() const +{ + return (table_map) engine->depended() ? 1L : 0L; +} + +Item_singleval_subselect::Item_singleval_subselect(THD *thd, + st_select_lex *select_lex): + Item_subselect() +{ + init(thd, select_lex, new select_singleval_subselect(this)); + max_columns= 1; + maybe_null= 1; +} + +void Item_singleval_subselect::fix_length_and_dec() +{ + engine->fix_length_and_dec(); + res_type= engine->type(); +} + +Item::Type Item_subselect::type() const +{ + return SUBSELECT_ITEM; +} + +double Item_singleval_subselect::val () +{ + if (engine->exec()) + { + assign_null(); + return 0; + } + return real_value; +} + +longlong Item_singleval_subselect::val_int () +{ + if (engine->exec()) + { + assign_null(); + return 0; + } + return int_value; +} + +String *Item_singleval_subselect::val_str (String *str) +{ + if (engine->exec() || null_value) + { + assign_null(); + return 0; + } + return &string_value; +} + +Item_exists_subselect::Item_exists_subselect(THD *thd, + st_select_lex *select_lex): + Item_subselect() +{ + init(thd, select_lex, new select_exists_subselect(this)); + max_columns= UINT_MAX; + null_value= 0; //can't be NULL + maybe_null= 0; //can't be NULL + value= 0; + select_lex->select_limit= 1; // we need only 1 row to determinate existence +} + +void Item_exists_subselect::fix_length_and_dec() +{ + max_length= 1; + +} + +double Item_exists_subselect::val () +{ + if (engine->exec()) + { + assign_null(); + return 0; + } + return (double) value; +} + +longlong Item_exists_subselect::val_int () +{ + if (engine->exec()) + { + assign_null(); + return 0; + } + return value; +} + +String *Item_exists_subselect::val_str(String *str) +{ + if (engine->exec()) + { + assign_null(); + return 0; + } + str->set(value,thd_charset()); + return str; +} + + +subselect_single_select_engine::subselect_single_select_engine(THD *thd, + st_select_lex *select, + select_subselect *result, + Item_subselect *item): + subselect_engine(thd, item, result), + prepared(0), optimized(0), executed(0) +{ + select_lex= select; + SELECT_LEX_UNIT *unit= select_lex->master_unit(); + unit->offset_limit_cnt= unit->global_parameters->offset_limit; + unit->select_limit_cnt= unit->global_parameters->select_limit+ + unit->global_parameters ->offset_limit; + if (unit->select_limit_cnt < unit->global_parameters->select_limit) + unit->select_limit_cnt= HA_POS_ERROR; // no limit + if (unit->select_limit_cnt == HA_POS_ERROR) + select_lex->options&= ~OPTION_FOUND_ROWS; + join= new JOIN(thd, select_lex->item_list, select_lex->options, result); + if (!join || !result) + { + //out of memory + thd->fatal_error= 1; + my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); + } + unit->item= item; + this->select_lex= select_lex; +} + +subselect_union_engine::subselect_union_engine(THD *thd, + st_select_lex_unit *u, + select_subselect *result, + Item_subselect *item): + subselect_engine(thd, item, result) +{ + unit= u; + if( !result) + { + //out of memory + thd->fatal_error= 1; + my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); + } + unit->item= item; +} + +int subselect_single_select_engine::prepare() +{ + if (prepared) + return 0; + prepared= 1; + SELECT_LEX_NODE *save_select= thd->lex.current_select; + thd->lex.current_select= select_lex; + if(join->prepare((TABLE_LIST*) select_lex->table_list.first, + select_lex->where, + (ORDER*) select_lex->order_list.first, + (ORDER*) select_lex->group_list.first, + select_lex->having, + (ORDER*) 0, select_lex, + select_lex->master_unit(), 0)) + return 1; + thd->lex.current_select= save_select; + return 0; +} + +int subselect_union_engine::prepare() +{ + return unit->prepare(thd, result); +} + +void subselect_single_select_engine::fix_length_and_dec() +{ + List_iterator_fast<Item> li(select_lex->item_list); + Item *sel_item= li++; + item->max_length= sel_item->max_length; + res_type= sel_item->result_type(); + item->decimals= sel_item->decimals; +} + +void subselect_union_engine::fix_length_and_dec() +{ + uint32 mlen= 0, len; + Item *sel_item= 0; + for(SELECT_LEX *sl= unit->first_select(); sl; sl= sl->next_select()) + { + List_iterator_fast<Item> li(sl->item_list); + Item *s_item= li++; + if ((len= s_item->max_length)) + mlen= len; + if (!sel_item) + sel_item= s_item; + } + item->max_length= mlen; + res_type= sel_item->result_type(); + item->decimals= sel_item->decimals; +} + +int subselect_single_select_engine::exec() +{ + DBUG_ENTER("subselect_single_select_engine::exec"); + if (!optimized) + { + optimized=1; + if (join->optimize()) + { + executed= 1; + DBUG_RETURN(join->error?join->error:1); + } + } + if (select_lex->dependent && executed) + { + if (join->reinit()) + DBUG_RETURN(1); + item->assign_null(); + item->assigned((executed= 0)); + } + if (!executed) + { + SELECT_LEX_NODE *save_select= join->thd->lex.current_select; + join->thd->lex.current_select= select_lex; + join->exec(); + join->thd->lex.current_select= save_select; + executed= 1; + DBUG_RETURN(join->error||thd->fatal_error); + } + DBUG_RETURN(0); +} + +int subselect_union_engine::exec() +{ + return unit->exec(); +} + +uint subselect_single_select_engine::cols() +{ + return select_lex->item_list.elements; +} + +uint subselect_union_engine::cols() +{ + return unit->first_select()->item_list.elements; +} + +bool subselect_single_select_engine::depended() +{ + return select_lex->dependent; +} + +bool subselect_union_engine::depended() +{ + return unit->dependent; +} + +bool subselect_single_select_engine::check_loop(uint id) +{ + DBUG_ENTER("subselect_single_select_engine::check_loop"); + DBUG_RETURN(join->check_loop(id)); +} + +bool subselect_union_engine::check_loop(uint id) +{ + DBUG_ENTER("subselect_union_engine::check_loop"); + for (SELECT_LEX *sl= unit->first_select(); sl; sl= sl->next_select()) + if (sl->join && sl->join->check_loop(id)) + DBUG_RETURN(1); + DBUG_RETURN(0); +} diff --git a/sql/item_subselect.h b/sql/item_subselect.h new file mode 100644 index 00000000000..3ad6c68a6ba --- /dev/null +++ b/sql/item_subselect.h @@ -0,0 +1,216 @@ +/* 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 */ + +/* subselect Item */ + +#ifdef __GNUC__ +#pragma interface /* gcc class implementation */ +#endif + +class st_select_lex; +class st_select_lex_unit; +class JOIN; +class select_subselect; +class subselect_engine; + +/* base class for subselects */ + +class Item_subselect :public Item_result_field +{ + my_bool engine_owner; /* Is this item owner of engine */ + my_bool value_assigned; /* value already assigned to subselect */ +protected: + /* engine that perform execution of subselect (single select or union) */ + subselect_engine *engine; + /* allowed number of columns (1 for single value subqueries) */ + uint max_columns; + +public: + Item_subselect(); + Item_subselect(Item_subselect *item) + { + null_value= item->null_value; + decimals= item->decimals; + max_columns= item->max_columns; + engine= item->engine; + engine_owner= 0; + name= item->name; + } + + /* + We need this method, because some compilers do not allow 'this' + pointer in constructor initialization list, but we need pass pointer + to subselect Item class to select_subselect classes constructor. + */ + void init (THD *thd, st_select_lex *select_lex, select_subselect *result); + + ~Item_subselect(); + virtual void assign_null() + { + null_value= 1; + } + bool assigned() { return value_assigned; } + void assigned(bool a) { value_assigned= a; } + enum Type type() const; + bool is_null() { return null_value; } + void make_field (Send_field *); + bool fix_fields(THD *thd, TABLE_LIST *tables, Item **ref); + virtual void fix_length_and_dec(); + table_map used_tables() const; + bool check_loop(uint id); + + friend class select_subselect; +}; + + +/* single value subselect */ + +class Item_singleval_subselect :public Item_subselect +{ +protected: + longlong int_value; /* Here stored integer value of this item */ + double real_value; /* Here stored real value of this item */ + /* + Here stored string value of this item. + (str_value used only as temporary buffer, because it can be changed + by Item::save_field) + */ + String string_value; + enum Item_result res_type; /* type of results */ + +public: + Item_singleval_subselect(THD *thd, st_select_lex *select_lex); + Item_singleval_subselect(Item_singleval_subselect *item): + Item_subselect(item) + { + int_value= item->int_value; + real_value= item->real_value; + string_value.set(item->string_value, 0, item->string_value.length()); + max_length= item->max_length; + decimals= item->decimals; + res_type= item->res_type; + } + virtual void assign_null() + { + null_value= 1; + int_value= 0; + real_value= 0; + max_length= 4; + res_type= STRING_RESULT; + } + double val (); + longlong val_int (); + String *val_str (String *); + Item *new_item() { return new Item_singleval_subselect(this); } + enum Item_result result_type() const { return res_type; } + void fix_length_and_dec(); + + friend class select_singleval_subselect; +}; + +/* exists subselect */ + +class Item_exists_subselect :public Item_subselect +{ +protected: + longlong value; /* value of this item (boolean: exists/not-exists) */ + +public: + Item_exists_subselect(THD *thd, st_select_lex *select_lex); + Item_exists_subselect(Item_exists_subselect *item): + Item_subselect(item) + { + value= item->value; + } + virtual void assign_null() + { + value= 0; + } + + Item *new_item() { return new Item_exists_subselect(this); } + enum Item_result result_type() const { return INT_RESULT;} + longlong val_int(); + double val(); + String *val_str(String*); + void fix_length_and_dec(); + friend class select_exists_subselect; +}; + +class subselect_engine +{ +protected: + select_subselect *result; /* results storage class */ + THD *thd; /* pointer to current THD */ + Item_subselect *item; /* item, that use this engine */ + enum Item_result res_type; /* type of results */ +public: + static void *operator new(size_t size) + { + return (void*) sql_alloc((uint) size); + } + static void operator delete(void *ptr, size_t size) {} + + subselect_engine(THD *thd, Item_subselect *si, select_subselect *res) + { + result= res; + item= si; + this->thd= thd; + res_type= STRING_RESULT; + } + + virtual int prepare()= 0; + virtual void fix_length_and_dec()= 0; + virtual int exec()= 0; + virtual uint cols()= 0; /* return number of columnss in select */ + virtual bool depended()= 0; /* depended from outer select */ + enum Item_result type() { return res_type; } + virtual bool check_loop(uint id)= 0; +}; + +class subselect_single_select_engine: public subselect_engine +{ + my_bool prepared; /* simple subselect is prepared */ + my_bool optimized; /* simple subselect is optimized */ + my_bool executed; /* simple subselect is executed */ + st_select_lex *select_lex; /* corresponding select_lex */ + JOIN * join; /* corresponding JOIN structure */ +public: + subselect_single_select_engine(THD *thd, st_select_lex *select, + select_subselect *result, + Item_subselect *item); + int prepare(); + void fix_length_and_dec(); + int exec(); + uint cols(); + bool depended(); + bool check_loop(uint id); +}; + +class subselect_union_engine: public subselect_engine +{ + st_select_lex_unit *unit; /* corresponding unit structure */ +public: + subselect_union_engine(THD *thd, + st_select_lex_unit *u, + select_subselect *result, + Item_subselect *item); + int prepare(); + void fix_length_and_dec(); + int exec(); + uint cols(); + bool depended(); + bool check_loop(uint id); +}; diff --git a/sql/item_sum.cc b/sql/item_sum.cc index bdf48b3ac54..db4c45fc412 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -60,8 +60,9 @@ void Item_sum::make_field(Send_field *tmp_field) result_type() == REAL_RESULT ? FIELD_TYPE_DOUBLE : FIELD_TYPE_VAR_STRING); } - tmp_field->table_name=(char*)""; - tmp_field->col_name=name; + tmp_field->db_name=(char*)""; + tmp_field->org_table_name=tmp_field->table_name=(char*)""; + tmp_field->org_col_name=tmp_field->col_name=name; } void Item_sum::print(String *str) @@ -92,7 +93,7 @@ Item_sum_num::val_str(String *str) double nr=val(); if (null_value) return 0; - str->set(nr,decimals); + str->set(nr,decimals,thd_charset()); return str; } @@ -105,13 +106,13 @@ Item_sum_int::val_str(String *str) return 0; char buff[21]; uint length= (uint) (longlong10_to_str(nr,buff,-10)-buff); - str->copy(buff,length); + str->copy(buff,length,thd_charset()); return str; } bool -Item_sum_num::fix_fields(THD *thd,TABLE_LIST *tables) +Item_sum_num::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) { if (!thd->allow_sum_func) { @@ -123,7 +124,7 @@ Item_sum_num::fix_fields(THD *thd,TABLE_LIST *tables) maybe_null=0; for (uint i=0 ; i < arg_count ; i++) { - if (args[i]->fix_fields(thd,tables)) + if (args[i]->fix_fields(thd, tables, args + i)) return 1; if (decimals < args[i]->decimals) decimals=args[i]->decimals; @@ -139,7 +140,7 @@ Item_sum_num::fix_fields(THD *thd,TABLE_LIST *tables) bool -Item_sum_hybrid::fix_fields(THD *thd,TABLE_LIST *tables) +Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) { Item *item=args[0]; if (!thd->allow_sum_func) @@ -148,7 +149,7 @@ Item_sum_hybrid::fix_fields(THD *thd,TABLE_LIST *tables) return 1; } thd->allow_sum_func=0; // No included group funcs - if (item->fix_fields(thd,tables)) + if (item->fix_fields(thd, tables, args)) return 1; hybrid_type=item->result_type(); if (hybrid_type == INT_RESULT) @@ -159,7 +160,6 @@ Item_sum_hybrid::fix_fields(THD *thd,TABLE_LIST *tables) max_length=item->max_length; decimals=item->decimals; maybe_null=item->maybe_null; - binary=item->binary; unsigned_flag=item->unsigned_flag; result_field=0; null_value=1; @@ -359,13 +359,13 @@ Item_sum_hybrid::val_str(String *str) case STRING_RESULT: return &value; case REAL_RESULT: - str->set(sum,decimals); + str->set(sum,decimals,thd_charset()); break; case INT_RESULT: if (unsigned_flag) - str->set((ulonglong) sum_int); + str->set((ulonglong) sum_int,thd_charset()); else - str->set((longlong) sum_int); + str->set((longlong) sum_int,thd_charset()); break; } return str; // Keep compiler happy @@ -379,7 +379,7 @@ bool Item_sum_min::add() String *result=args[0]->val_str(&tmp_value); if (!args[0]->null_value && (null_value || - (binary ? stringcmp(&value,result) : sortcmp(&value,result)) > 0)) + (binary() ? stringcmp(&value,result) : sortcmp(&value,result)) > 0)) { value.copy(*result); null_value=0; @@ -422,7 +422,7 @@ bool Item_sum_max::add() String *result=args[0]->val_str(&tmp_value); if (!args[0]->null_value && (null_value || - (binary ? stringcmp(&value,result) : sortcmp(&value,result)) < 0)) + (binary() & MY_CS_BINSORT ? stringcmp(&value,result) : sortcmp(&value,result)) < 0)) { value.copy(*result); null_value=0; @@ -513,7 +513,7 @@ void Item_sum_hybrid::reset_field() if (hybrid_type == STRING_RESULT) { char buff[MAX_FIELD_WIDTH]; - String tmp(buff,sizeof(buff)),*res; + String tmp(buff,sizeof(buff),default_charset_info),*res; res=args[0]->val_str(&tmp); if (args[0]->null_value) @@ -524,7 +524,7 @@ void Item_sum_hybrid::reset_field() else { result_field->set_notnull(); - result_field->store(res->ptr(),res->length()); + result_field->store(res->ptr(),res->length(),tmp.charset()); } } else if (hybrid_type == INT_RESULT) @@ -692,9 +692,9 @@ Item_sum_hybrid::min_max_update_str_field(int offset) result_field->ptr-=offset; if (result_field->is_null() || - (cmp_sign * (binary ? stringcmp(res_str,&tmp_value) : + (cmp_sign * (binary() ? stringcmp(res_str,&tmp_value) : sortcmp(res_str,&tmp_value)) < 0)) - result_field->store(res_str->ptr(),res_str->length()); + result_field->store(res_str->ptr(),res_str->length(),res_str->charset()); else { // Use old value char *res=result_field->ptr; @@ -810,7 +810,7 @@ String *Item_avg_field::val_str(String *str) double nr=Item_avg_field::val(); if (null_value) return 0; - str->set(nr,decimals); + str->set(nr,decimals,thd_charset()); return str; } @@ -847,7 +847,7 @@ String *Item_std_field::val_str(String *str) double nr=val(); if (null_value) return 0; - str->set(nr,decimals); + str->set(nr,decimals,thd_charset()); return str; } @@ -864,7 +864,10 @@ 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_strnncoll(default_charset_info, + (const uchar*) key1, *(uint*) arg, + (const uchar*) key2, *(uint*) arg); } /* @@ -928,9 +931,10 @@ Item_sum_count_distinct::~Item_sum_count_distinct() } -bool Item_sum_count_distinct::fix_fields(THD *thd,TABLE_LIST *tables) +bool Item_sum_count_distinct::fix_fields(THD *thd, TABLE_LIST *tables, + Item **ref) { - if (Item_sum_num::fix_fields(thd,tables) || + if (Item_sum_num::fix_fields(thd, tables, ref) || !(tmp_table_param= new TMP_TABLE_PARAM)) return 1; return 0; @@ -939,6 +943,10 @@ bool Item_sum_count_distinct::fix_fields(THD *thd,TABLE_LIST *tables) bool Item_sum_count_distinct::setup(THD *thd) { List<Item> list; + SELECT_LEX *select_lex= current_lex->current_select->select_lex(); + if (select_lex->linkage == GLOBAL_OPTIONS_TYPE) + return 1; + /* Create a table with an unique key over all parameters */ for (uint i=0; i < arg_count ; i++) { @@ -960,9 +968,10 @@ bool Item_sum_count_distinct::setup(THD *thd) free_tmp_table(thd, table); tmp_table_param->cleanup(); } - if (!(table=create_tmp_table(thd, tmp_table_param, list, (ORDER*) 0, 1, - 0, 0, - current_lex->select->options | thd->options))) + if (!(table= create_tmp_table(thd, tmp_table_param, list, (ORDER*) 0, 1, + 0, 0, + select_lex->options | thd->options, + select_lex->master_unit()))) return 1; table->file->extra(HA_EXTRA_NO_ROWS); // Don't update rows table->no_rows=1; @@ -1106,7 +1115,7 @@ bool Item_sum_count_distinct::add() if (tree_to_myisam()) return 1; } - else if (!tree_insert(&tree, table->record[0] + rec_offset, 0)) + else if (!tree_insert(&tree, table->record[0] + rec_offset, 0, tree.custom_arg)) return 1; } else if ((error=table->file->write_row(table->record[0]))) @@ -1168,7 +1177,7 @@ String *Item_sum_udf_float::val_str(String *str) if (null_value) return 0; /* purecov: inspected */ else - str->set(nr,decimals); + str->set(nr,decimals,thd_charset()); return str; } @@ -1187,7 +1196,7 @@ String *Item_sum_udf_int::val_str(String *str) if (null_value) return 0; else - str->set(nr); + str->set(nr,thd_charset()); return str; } diff --git a/sql/item_sum.h b/sql/item_sum.h index 2cf92343ebb..3e67f1e3624 100644 --- a/sql/item_sum.h +++ b/sql/item_sum.h @@ -70,7 +70,6 @@ public: void print(String *str); void fix_num_length_and_dec(); virtual bool setup(THD *thd) {return 0;} - unsigned int size_of() { return sizeof(*this);} }; @@ -81,11 +80,10 @@ public: Item_sum_num(Item *item_par) :Item_sum(item_par) {} Item_sum_num(Item *a, Item* b) :Item_sum(a,b) {} Item_sum_num(List<Item> &list) :Item_sum(list) {} - bool fix_fields(THD *,struct st_table_list *); + bool fix_fields(THD *, TABLE_LIST *, Item **); longlong val_int() { return (longlong) val(); } /* Real as default */ String *val_str(String*str); void reset_field(); - unsigned int size_of() { return sizeof(*this);} }; @@ -100,7 +98,6 @@ public: double val() { return (double) val_int(); } String *val_str(String*str); enum Item_result result_type () const { return INT_RESULT; } - unsigned int size_of() { return sizeof(*this);} }; @@ -118,7 +115,6 @@ class Item_sum_sum :public Item_sum_num void reset_field(); void update_field(int offset); const char *func_name() const { return "sum"; } - unsigned int size_of() { return sizeof(*this);} }; @@ -141,7 +137,6 @@ class Item_sum_count :public Item_sum_int void reset_field(); void update_field(int offset); const char *func_name() const { return "count"; } - unsigned int size_of() { return sizeof(*this);} }; @@ -151,7 +146,7 @@ class Item_sum_count_distinct :public Item_sum_int { TABLE *table; table_map used_table_cache; - bool fix_fields(THD *thd,TABLE_LIST *tables); + bool fix_fields(THD *thd, TABLE_LIST *tables, Item **ref); uint32 *field_lengths; TMP_TABLE_PARAM *tmp_table_param; TREE tree; @@ -193,7 +188,6 @@ class Item_sum_count_distinct :public Item_sum_int void update_field(int offset) { return ; } // Never called const char *func_name() const { return "count_distinct"; } bool setup(THD *thd); - unsigned int size_of() { return sizeof(*this);} }; @@ -213,7 +207,6 @@ public: String *val_str(String*); void make_field(Send_field *field); void fix_length_and_dec() {} - unsigned int size_of() { return sizeof(*this);} }; @@ -235,7 +228,6 @@ class Item_sum_avg :public Item_sum_num Item *result_item(Field *field) { return new Item_avg_field(this); } const char *func_name() const { return "avg"; } - unsigned int size_of() { return sizeof(*this);} }; class Item_sum_std; @@ -252,7 +244,6 @@ public: bool is_null() { (void) val_int(); return null_value; } void make_field(Send_field *field); void fix_length_and_dec() {} - unsigned int size_of() { return sizeof(*this);} }; class Item_sum_std :public Item_sum_num @@ -273,7 +264,6 @@ class Item_sum_std :public Item_sum_num Item *result_item(Field *field) { return new Item_std_field(this); } const char *func_name() const { return "std"; } - unsigned int size_of() { return sizeof(*this);} }; @@ -293,7 +283,7 @@ class Item_sum_hybrid :public Item_sum Item_sum_hybrid(Item *item_par,int sign) :Item_sum(item_par),cmp_sign(sign), used_table_cache(~(table_map) 0) {} - bool fix_fields(THD *,struct st_table_list *); + bool fix_fields(THD *, TABLE_LIST *, Item **); table_map used_tables() const { return used_table_cache; } bool const_item() const { return !used_table_cache; } @@ -316,7 +306,6 @@ class Item_sum_hybrid :public Item_sum void min_max_update_str_field(int offset); void min_max_update_real_field(int offset); void min_max_update_int_field(int offset); - unsigned int size_of() { return sizeof(*this);} }; @@ -328,7 +317,6 @@ public: bool add(); const char *func_name() const { return "min"; } - unsigned int size_of() { return sizeof(*this);} }; @@ -340,7 +328,6 @@ public: bool add(); const char *func_name() const { return "max"; } - unsigned int size_of() { return sizeof(*this);} }; @@ -356,7 +343,6 @@ class Item_sum_bit :public Item_sum_int void reset(); longlong val_int(); void reset_field(); - unsigned int size_of() { return sizeof(*this);} }; @@ -367,7 +353,6 @@ class Item_sum_or :public Item_sum_bit bool add(); void update_field(int offset); const char *func_name() const { return "bit_or"; } - unsigned int size_of() { return sizeof(*this);} }; @@ -378,7 +363,6 @@ class Item_sum_and :public Item_sum_bit bool add(); void update_field(int offset); const char *func_name() const { return "bit_and"; } - unsigned int size_of() { return sizeof(*this);} }; /* @@ -398,7 +382,7 @@ public: { quick_group=0;} ~Item_udf_sum() {} const char *func_name() const { return udf.name(); } - bool fix_fields(THD *thd,struct st_table_list *tables) + bool fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) { return udf.fix_fields(thd,tables,this,this->arg_count,this->args); } @@ -409,7 +393,6 @@ public: bool add(); void reset_field() {}; void update_field(int offset_arg) {}; - unsigned int size_of() { return sizeof(*this);} }; diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc index ccbba3777c4..7c085a1b25a 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -29,11 +29,31 @@ ** Todo: Move month and days to language files */ -static String month_names[] = { "January", "February", "March", "April", - "May", "June", "July", "August", - "September", "October", "November", "December" }; -static String day_names[] = { "Monday", "Tuesday", "Wednesday", - "Thursday", "Friday", "Saturday" ,"Sunday" }; +static String month_names[] = +{ + String("January", my_charset_latin1), + String("February", my_charset_latin1), + String("March", my_charset_latin1), + String("April", my_charset_latin1), + String("May", my_charset_latin1), + String("June", my_charset_latin1), + String("July", my_charset_latin1), + String("August", my_charset_latin1), + String("September", my_charset_latin1), + String("October", my_charset_latin1), + String("November", my_charset_latin1), + String("December", my_charset_latin1) +}; +static String day_names[] = +{ + String("Monday", my_charset_latin1), + String("Tuesday", my_charset_latin1), + String("Wednesday", my_charset_latin1), + String("Thursday", my_charset_latin1), + String("Friday", my_charset_latin1), + String("Saturday", my_charset_latin1), + String("Sunday", my_charset_latin1) +}; /* ** Get a array of positive numbers from a string object. @@ -49,16 +69,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) { @@ -133,14 +153,17 @@ longlong Item_func_month::val_int() String* Item_func_monthname::val_str(String* str) { - uint month=(uint) Item_func_month::val_int(); + uint month=(uint) Item_func_month::val_int(); if (!month) // This is also true for NULL { null_value=1; return (String*) 0; } null_value=0; - return &month_names[month-1]; + + String *m=&month_names[month-1]; + str->copy(m->ptr(), m->length(), m->charset(), thd_charset()); + return str; } // Returns the quarter of the year @@ -227,7 +250,10 @@ String* Item_func_dayname::val_str(String* str) uint weekday=(uint) val_int(); // Always Item_func_daynr() if (null_value) return (String*) 0; - return &day_names[weekday]; + + String *d=&day_names[weekday]; + str->copy(d->ptr(), d->length(), d->charset(), thd_charset()); + return str; } @@ -302,7 +328,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 == '-') { @@ -389,21 +415,21 @@ String *Item_date::val_str(String *str) return (String*) 0; if (!value) // zero daynr { - str->copy("0000-00-00"); + str->copy("0000-00-00",10,my_charset_latin1,thd_charset()); return str; } - if (str->alloc(11)) - return &empty_string; /* purecov: inspected */ - sprintf((char*) str->ptr(),"%04d-%02d-%02d", + + char tmpbuff[11]; + sprintf(tmpbuff,"%04d-%02d-%02d", (int) (value/10000L) % 10000, (int) (value/100)%100, (int) (value%100)); - str->length(10); + str->copy(tmpbuff,10,my_charset_latin1,thd_charset()); return str; } -bool Item_date::save_in_field(Field *field) +int Item_date::save_in_field(Field *field) { TIME ltime; timestamp_type t_type=TIMESTAMP_FULL; @@ -435,7 +461,10 @@ void Item_func_curdate::fix_length_and_dec() { struct tm tm_tmp,*start; time_t query_start=current_thd->query_start(); - decimals=0; max_length=10; + + set_charset(thd_charset()); + decimals=0; + max_length=10*thd_charset()->mbmaxlen; localtime_r(&query_start,&tm_tmp); start=&tm_tmp; value=(longlong) ((ulong) ((uint) start->tm_year+1900)*10000L+ @@ -460,28 +489,48 @@ bool Item_func_curdate::get_date(TIME *res, return 0; } +String *Item_func_curtime::val_str(String *str) +{ + str_value.set(buff,buff_length,thd_charset()); + return &str_value; +} + void Item_func_curtime::fix_length_and_dec() { struct tm tm_tmp,*start; time_t query_start=current_thd->query_start(); - decimals=0; max_length=8; + CHARSET_INFO *cs=thd_charset(); + + decimals=0; + max_length=8*cs->mbmaxlen; localtime_r(&query_start,&tm_tmp); start=&tm_tmp; + set_charset(cs); value=(longlong) ((ulong) ((uint) start->tm_hour)*10000L+ (ulong) (((uint) start->tm_min)*100L+ (uint) start->tm_sec)); - sprintf(buff,"%02d:%02d:%02d", - (int) start->tm_hour, - (int) start->tm_min, - (int) start->tm_sec); - buff_length=(uint) strlen(buff); + + buff_length=cs->snprintf(cs,buff,sizeof(buff),"%02d:%02d:%02d", + (int) start->tm_hour, + (int) start->tm_min, + (int) start->tm_sec); +} + +String *Item_func_now::val_str(String *str) +{ + str_value.set(buff,buff_length,thd_charset()); + return &str_value; } void Item_func_now::fix_length_and_dec() { struct tm tm_tmp,*start; time_t query_start=current_thd->query_start(); - decimals=0; max_length=19; + CHARSET_INFO *cs=thd_charset(); + + decimals=0; + max_length=19*cs->mbmaxlen; + set_charset(cs); localtime_r(&query_start,&tm_tmp); start=&tm_tmp; value=((longlong) ((ulong) ((uint) start->tm_year+1900)*10000L+ @@ -490,14 +539,14 @@ void Item_func_now::fix_length_and_dec() (longlong) ((ulong) ((uint) start->tm_hour)*10000L+ (ulong) (((uint) start->tm_min)*100L+ (uint) start->tm_sec))); - sprintf(buff,"%04d-%02d-%02d %02d:%02d:%02d", - ((int) (start->tm_year+1900)) % 10000, - (int) start->tm_mon+1, - (int) start->tm_mday, - (int) start->tm_hour, - (int) start->tm_min, - (int) start->tm_sec); - buff_length=(uint) strlen(buff); + + buff_length= (uint) cs->snprintf(cs,buff, sizeof(buff),"%04d-%02d-%02d %02d:%02d:%02d", + ((int) (start->tm_year+1900)) % 10000, + (int) start->tm_mon+1, + (int) start->tm_mday, + (int) start->tm_hour, + (int) start->tm_min, + (int) start->tm_sec); /* For getdate */ ltime.year= start->tm_year+1900; ltime.month= start->tm_mon+1; @@ -518,7 +567,7 @@ bool Item_func_now::get_date(TIME *res, } -bool Item_func_now::save_in_field(Field *to) +int Item_func_now::save_in_field(Field *to) { to->set_notnull(); to->store_time(<ime,TIMESTAMP_FULL); @@ -528,9 +577,10 @@ bool Item_func_now::save_in_field(Field *to) String *Item_func_sec_to_time::val_str(String *str) { - char buff[23]; + char buff[23*2]; const char *sign=""; longlong seconds=(longlong) args[0]->val_int(); + ulong length; if ((null_value=args[0]->null_value)) return (String*) 0; if (seconds < 0) @@ -539,9 +589,9 @@ String *Item_func_sec_to_time::val_str(String *str) sign= "-"; } uint sec= (uint) ((ulonglong) seconds % 3600); - sprintf(buff,"%s%02lu:%02u:%02u",sign,(long) (seconds/3600), - sec/60, sec % 60); - str->copy(buff,(uint) strlen(buff)); + length= my_sprintf(buff,(buff,"%s%02lu:%02u:%02u",sign,(long) (seconds/3600), + sec/60, sec % 60)); + str->copy(buff, length, my_charset_latin1, thd_charset()); return str; } @@ -651,6 +701,7 @@ String *Item_func_date_format::val_str(String *str) TIME l_time; char intbuff[15]; uint size,weekday; + ulong length; if (!date_or_time) { @@ -743,40 +794,39 @@ String *Item_func_date_format::val_str(String *str) null_value=1; return 0; } - sprintf(intbuff,"%d",l_time.day); - str->append(intbuff); + length= my_sprintf(intbuff, (intbuff,"%d",l_time.day)); + str->append(intbuff, length); if (l_time.day >= 10 && l_time.day <= 19) str->append("th"); else { - switch (l_time.day %10) - { + switch (l_time.day %10) { case 1: - str->append("st"); + str->append("st",2); break; case 2: - str->append("nd"); + str->append("nd",2); break; case 3: - str->append("rd"); + str->append("rd",2); break; default: - str->append("th"); + str->append("th",2); break; } } break; case 'Y': sprintf(intbuff,"%04d",l_time.year); - str->append(intbuff); + str->append(intbuff,4); break; case 'y': sprintf(intbuff,"%02d",l_time.year%100); - str->append(intbuff); + str->append(intbuff,2); break; case 'm': sprintf(intbuff,"%02d",l_time.month); - str->append(intbuff); + str->append(intbuff,2); break; case 'c': sprintf(intbuff,"%d",l_time.month); @@ -784,7 +834,7 @@ String *Item_func_date_format::val_str(String *str) break; case 'd': sprintf(intbuff,"%02d",l_time.day); - str->append(intbuff); + str->append(intbuff,2); break; case 'e': sprintf(intbuff,"%d",l_time.day); @@ -792,16 +842,16 @@ String *Item_func_date_format::val_str(String *str) break; case 'H': sprintf(intbuff,"%02d",l_time.hour); - str->append(intbuff); + str->append(intbuff,2); break; case 'h': case 'I': sprintf(intbuff,"%02d", (l_time.hour+11)%12+1); - str->append(intbuff); + str->append(intbuff,2); break; case 'i': /* minutes */ sprintf(intbuff,"%02d",l_time.minute); - str->append(intbuff); + str->append(intbuff,2); break; case 'j': if (date_or_time) @@ -812,7 +862,7 @@ String *Item_func_date_format::val_str(String *str) sprintf(intbuff,"%03d", (int) (calc_daynr(l_time.year,l_time.month,l_time.day) - calc_daynr(l_time.year,1,1)) + 1); - str->append(intbuff); + str->append(intbuff,3); break; case 'k': sprintf(intbuff,"%d",l_time.hour); @@ -823,7 +873,7 @@ String *Item_func_date_format::val_str(String *str) str->append(intbuff); break; case 'p': - str->append(l_time.hour < 12 ? "AM" : "PM"); + str->append(l_time.hour < 12 ? "AM" : "PM",2); break; case 'r': sprintf(intbuff,(l_time.hour < 12) ? "%02d:%02d:%02d AM" : @@ -837,7 +887,8 @@ String *Item_func_date_format::val_str(String *str) str->append(intbuff); break; case 'T': - sprintf(intbuff,"%02d:%02d:%02d",l_time.hour,l_time.minute,l_time.second); + sprintf(intbuff,"%02d:%02d:%02d", l_time.hour, l_time.minute, + l_time.second); str->append(intbuff); break; case 'U': @@ -845,7 +896,7 @@ String *Item_func_date_format::val_str(String *str) { uint year; sprintf(intbuff,"%02d",calc_week(&l_time, 0, (*ptr) == 'U', &year)); - str->append(intbuff); + str->append(intbuff,2); } break; case 'v': @@ -853,7 +904,7 @@ String *Item_func_date_format::val_str(String *str) { uint year; sprintf(intbuff,"%02d",calc_week(&l_time, 1, (*ptr) == 'V', &year)); - str->append(intbuff); + str->append(intbuff,2); } break; case 'x': @@ -862,13 +913,13 @@ String *Item_func_date_format::val_str(String *str) uint year; (void) calc_week(&l_time, 1, (*ptr) == 'X', &year); sprintf(intbuff,"%04d",year); - str->append(intbuff); + str->append(intbuff,4); } break; case 'w': weekday=calc_weekday(calc_daynr(l_time.year,l_time.month,l_time.day),1); - sprintf(intbuff,"%01d",weekday); - str->append(intbuff); + sprintf(intbuff,"%d",weekday); + str->append(intbuff,1); break; default: str->append(*ptr); @@ -884,20 +935,26 @@ String *Item_func_from_unixtime::val_str(String *str) { struct tm tm_tmp,*start; time_t tmp=(time_t) args[0]->val_int(); + uint32 l; + CHARSET_INFO *cs=thd_charset(); + if ((null_value=args[0]->null_value)) return 0; localtime_r(&tmp,&tm_tmp); start=&tm_tmp; - if (str->alloc(20)) + + l=20*cs->mbmaxlen+32; + if (str->alloc(l)) return str; /* purecov: inspected */ - sprintf((char*) str->ptr(),"%04d-%02d-%02d %02d:%02d:%02d", + l=cs->snprintf(cs,(char*) str->ptr(),l,"%04d-%02d-%02d %02d:%02d:%02d", (int) start->tm_year+1900, (int) start->tm_mon+1, (int) start->tm_mday, (int) start->tm_hour, (int) start->tm_min, (int) start->tm_sec); - str->length(19); + str->length(l); + str->set_charset(cs); return str; } @@ -1028,26 +1085,31 @@ bool Item_date_add_interval::get_date(TIME *ltime, bool fuzzy_date) String *Item_date_add_interval::val_str(String *str) { TIME ltime; + CHARSET_INFO *cs=thd_charset(); + uint32 l; if (Item_date_add_interval::get_date(<ime,0)) return 0; if (ltime.time_type == TIMESTAMP_DATE) { - if (str->alloc(11)) + l=11*cs->mbmaxlen+32; + if (str->alloc(l)) goto null_date; - sprintf((char*) str->ptr(),"%04d-%02d-%02d", + l=cs->snprintf(cs,(char*) str->ptr(),l,"%04d-%02d-%02d", ltime.year,ltime.month,ltime.day); - str->length(10); + str->length(l); } else { - if (str->alloc(20)) + l=20*cs->mbmaxlen+32; + if (str->alloc(l)) goto null_date; - sprintf((char*) str->ptr(),"%04d-%02d-%02d %02d:%02d:%02d", + l=cs->snprintf(cs,(char*) str->ptr(),l,"%04d-%02d-%02d %02d:%02d:%02d", ltime.year,ltime.month,ltime.day, ltime.hour,ltime.minute,ltime.second); - str->length(19); + str->length(l); } + str->set_charset(cs); return str; null_date: diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h index 0fe487b7983..07cdfde115b 100644 --- a/sql/item_timefunc.h +++ b/sql/item_timefunc.h @@ -27,7 +27,10 @@ public: Item_func_period_add(Item *a,Item *b) :Item_int_func(a,b) {} longlong val_int(); const char *func_name() const { return "period_add"; } - void fix_length_and_dec() { max_length=6; } + void fix_length_and_dec() + { + max_length=6*thd_charset()->mbmaxlen; + } }; @@ -37,7 +40,11 @@ public: Item_func_period_diff(Item *a,Item *b) :Item_int_func(a,b) {} longlong val_int(); const char *func_name() const { return "period_diff"; } - void fix_length_and_dec() { decimals=0; max_length=6; } + void fix_length_and_dec() + { + decimals=0; + max_length=6*thd_charset()->mbmaxlen; + } }; @@ -47,7 +54,12 @@ public: Item_func_to_days(Item *a) :Item_int_func(a) {} longlong val_int(); const char *func_name() const { return "to_days"; } - void fix_length_and_dec() { decimals=0; max_length=6; maybe_null=1; } + void fix_length_and_dec() + { + decimals=0; + max_length=6*thd_charset()->mbmaxlen; + maybe_null=1; + } }; @@ -57,7 +69,12 @@ public: Item_func_dayofmonth(Item *a) :Item_int_func(a) {} longlong val_int(); const char *func_name() const { return "dayofmonth"; } - void fix_length_and_dec() { decimals=0; max_length=2; maybe_null=1; } + void fix_length_and_dec() + { + decimals=0; + max_length=2*thd_charset()->mbmaxlen; + maybe_null=1; + } }; @@ -67,10 +84,20 @@ public: Item_func_month(Item *a) :Item_func(a) {} longlong val_int(); double val() { return (double) Item_func_month::val_int(); } - String *val_str(String *str) { str->set(val_int()); return null_value ? 0 : str;} + String *val_str(String *str) + { + str->set(val_int(), thd_charset()); + return null_value ? 0 : str; + } const char *func_name() const { return "month"; } enum Item_result result_type () const { return INT_RESULT; } - void fix_length_and_dec() { decimals=0; max_length=2; maybe_null=1; } + void fix_length_and_dec() + { + set_charset(thd_charset()); + decimals=0; + max_length=2*thd_charset()->mbmaxlen; + maybe_null=1; + } }; @@ -81,7 +108,13 @@ public: const char *func_name() const { return "monthname"; } String *val_str(String *str); enum Item_result result_type () const { return STRING_RESULT; } - void fix_length_and_dec() { decimals=0; max_length=10; maybe_null=1; } + void fix_length_and_dec() + { + set_charset(thd_charset()); + decimals=0; + max_length=10*thd_charset()->mbmaxlen; + maybe_null=1; + } }; @@ -91,7 +124,12 @@ public: Item_func_dayofyear(Item *a) :Item_int_func(a) {} longlong val_int(); const char *func_name() const { return "dayofyear"; } - void fix_length_and_dec() { decimals=0; max_length=3; maybe_null=1; } + void fix_length_and_dec() + { + decimals=0; + max_length=3*thd_charset()->mbmaxlen; + maybe_null=1; + } }; @@ -101,7 +139,12 @@ public: Item_func_hour(Item *a) :Item_int_func(a) {} longlong val_int(); const char *func_name() const { return "hour"; } - void fix_length_and_dec() { decimals=0; max_length=2; maybe_null=1; } + void fix_length_and_dec() + { + decimals=0; + max_length=2*thd_charset()->mbmaxlen; + maybe_null=1; + } }; @@ -111,7 +154,12 @@ public: Item_func_minute(Item *a) :Item_int_func(a) {} longlong val_int(); const char *func_name() const { return "minute"; } - void fix_length_and_dec() { decimals=0; max_length=2; maybe_null=1; } + void fix_length_and_dec() + { + decimals=0; + max_length=2*thd_charset()->mbmaxlen; + maybe_null=1; + } }; @@ -121,7 +169,12 @@ public: Item_func_quarter(Item *a) :Item_int_func(a) {} longlong val_int(); const char *func_name() const { return "quarter"; } - void fix_length_and_dec() { decimals=0; max_length=1; maybe_null=1; } + void fix_length_and_dec() + { + decimals=0; + max_length=1*thd_charset()->mbmaxlen; + maybe_null=1; + } }; @@ -131,7 +184,12 @@ public: Item_func_second(Item *a) :Item_int_func(a) {} longlong val_int(); const char *func_name() const { return "second"; } - void fix_length_and_dec() { decimals=0; max_length=2; maybe_null=1; } + void fix_length_and_dec() + { + decimals=0; + max_length=2*thd_charset()->mbmaxlen; + maybe_null=1; + } }; @@ -141,7 +199,12 @@ public: Item_func_week(Item *a,Item *b) :Item_int_func(a,b) {} longlong val_int(); const char *func_name() const { return "week"; } - void fix_length_and_dec() { decimals=0; max_length=2; maybe_null=1; } + void fix_length_and_dec() + { + decimals=0; + max_length=2*thd_charset()->mbmaxlen; + maybe_null=1; + } }; class Item_func_yearweek :public Item_int_func @@ -150,7 +213,12 @@ public: Item_func_yearweek(Item *a,Item *b) :Item_int_func(a,b) {} longlong val_int(); const char *func_name() const { return "yearweek"; } - void fix_length_and_dec() { decimals=0; max_length=6; maybe_null=1; } + void fix_length_and_dec() + { + decimals=0; + max_length=6*thd_charset()->mbmaxlen; + maybe_null=1; + } }; @@ -160,7 +228,12 @@ public: Item_func_year(Item *a) :Item_int_func(a) {} longlong val_int(); const char *func_name() const { return "year"; } - void fix_length_and_dec() { decimals=0; max_length=4; maybe_null=1; } + void fix_length_and_dec() + { + decimals=0; + max_length=4*thd_charset()->mbmaxlen; + maybe_null=1; + } }; @@ -172,11 +245,20 @@ public: :Item_func(a), odbc_type(type_arg) {} longlong val_int(); double val() { return (double) val_int(); } - String *val_str(String *str) { str->set(val_int()); return null_value ? 0 : str;} + String *val_str(String *str) + { + str->set(val_int(), thd_charset()); + return null_value ? 0 : str; + } const char *func_name() const { return "weekday"; } enum Item_result result_type () const { return INT_RESULT; } - void fix_length_and_dec() { decimals=0; max_length=1; maybe_null=1; } - unsigned int size_of() { return sizeof(*this);} + void fix_length_and_dec() + { + set_charset(thd_charset()); + decimals=0; + max_length=1*thd_charset()->mbmaxlen; + maybe_null=1; + } }; class Item_func_dayname :public Item_func_weekday @@ -186,7 +268,13 @@ class Item_func_dayname :public Item_func_weekday const char *func_name() const { return "dayname"; } String *val_str(String *str); enum Item_result result_type () const { return STRING_RESULT; } - void fix_length_and_dec() { decimals=0; max_length=9; maybe_null=1; } + void fix_length_and_dec() + { + set_charset(thd_charset()); + decimals=0; + max_length=9*thd_charset()->mbmaxlen; + maybe_null=1; + } }; @@ -200,9 +288,9 @@ public: const char *func_name() const { return "timestamp"; } void fix_length_and_dec() { - decimals=0; max_length=10; + decimals=0; + max_length=10*thd_charset()->mbmaxlen; } - unsigned int size_of() { return sizeof(*this);} }; @@ -214,7 +302,8 @@ public: const char *func_name() const { return "time_to_sec"; } void fix_length_and_dec() { - decimals=0; max_length=10; + decimals=0; + max_length=10*thd_charset()->mbmaxlen; } }; @@ -230,17 +319,21 @@ public: String *val_str(String *str); double val() { return (double) val_int(); } const char *func_name() const { return "date"; } - void fix_length_and_dec() { decimals=0; max_length=10; } - bool save_in_field(Field *to); + void fix_length_and_dec() + { + set_charset(thd_charset()); + decimals=0; + max_length=10*thd_charset()->mbmaxlen; + } + int save_in_field(Field *to); void make_field(Send_field *tmp_field) { init_make_field(tmp_field,FIELD_TYPE_DATE); } Field *tmp_table_field(TABLE *t_arg) { - return (!t_arg) ? result_field : new Field_date(maybe_null, name, t_arg); + return (!t_arg) ? result_field : new Field_date(maybe_null, name, t_arg, thd_charset()); } - unsigned int size_of() { return sizeof(*this);} }; @@ -257,16 +350,15 @@ public: Field *tmp_table_field(TABLE *t_arg) { return (!t_arg) ? result_field : new Field_datetime(maybe_null, name, - t_arg); + t_arg, thd_charset()); } - unsigned int size_of() { return sizeof(*this);} }; class Item_func_curtime :public Item_func { longlong value; - char buff[9]; + char buff[9*2+32]; uint buff_length; public: Item_func_curtime() :Item_func() {} @@ -274,8 +366,7 @@ public: enum Item_result result_type () const { return STRING_RESULT; } double val() { return (double) value; } longlong val_int() { return value; } - String *val_str(String *str) - { str_value.set(buff,buff_length); return &str_value; } + String *val_str(String *str); const char *func_name() const { return "curtime"; } void fix_length_and_dec(); void make_field(Send_field *tmp_field) @@ -284,9 +375,9 @@ public: } Field *tmp_table_field(TABLE *t_arg) { - return (!t_arg) ? result_field : new Field_time(maybe_null, name, t_arg); + return (!t_arg) ? result_field : + new Field_time(maybe_null, name, t_arg, thd_charset()); } - unsigned int size_of() { return sizeof(*this);} }; @@ -300,14 +391,13 @@ public: const char *func_name() const { return "curdate"; } void fix_length_and_dec(); /* Retrieves curtime */ bool get_date(TIME *res,bool fuzzy_date); - unsigned int size_of() { return sizeof(*this);} }; class Item_func_now :public Item_date_func { longlong value; - char buff[20]; + char buff[20*2+32]; // +32 to make my_snprintf_{8bit|ucs2} happy uint buff_length; TIME ltime; public: @@ -316,13 +406,11 @@ public: enum Item_result result_type () const { return STRING_RESULT; } double val() { return (double) value; } longlong val_int() { return value; } - bool save_in_field(Field *to); - String *val_str(String *str) - { str_value.set(buff,buff_length); return &str_value; } + int save_in_field(Field *to); + String *val_str(String *str); const char *func_name() const { return "now"; } void fix_length_and_dec(); bool get_date(TIME *res,bool fuzzy_date); - unsigned int size_of() { return sizeof(*this);} }; @@ -347,7 +435,6 @@ public: const char *func_name() const { return "date_format"; } void fix_length_and_dec(); uint format_length(const String *format); - unsigned int size_of() { return sizeof(*this);} }; @@ -359,7 +446,12 @@ class Item_func_from_unixtime :public Item_date_func longlong val_int(); String *val_str(String *str); const char *func_name() const { return "from_unixtime"; } - void fix_length_and_dec() { decimals=0; max_length=19; } + void fix_length_and_dec() + { + set_charset(thd_charset()); + decimals=0; + max_length=19*thd_charset()->mbmaxlen; + } // enum Item_result result_type () const { return STRING_RESULT; } bool get_date(TIME *res,bool fuzzy_date); }; @@ -372,7 +464,12 @@ public: double val() { return (double) Item_func_sec_to_time::val_int(); } longlong val_int(); String *val_str(String *); - void fix_length_and_dec() { maybe_null=1; max_length=13; } + void fix_length_and_dec() + { + set_charset(thd_charset()); + maybe_null=1; + max_length=13*thd_charset()->mbmaxlen; + } const char *func_name() const { return "sec_to_time"; } void make_field(Send_field *tmp_field) { @@ -380,7 +477,8 @@ public: } Field *tmp_table_field(TABLE *t_arg) { - return (!t_arg) ? result_field : new Field_time(maybe_null, name, t_arg); + return (!t_arg) ? result_field : + new Field_time(maybe_null, name, t_arg, thd_charset()); } }; @@ -403,11 +501,16 @@ public: :Item_date_func(a,b),int_type(type_arg), date_sub_interval(neg_arg) {} String *val_str(String *); const char *func_name() const { return "date_add_interval"; } - void fix_length_and_dec() { maybe_null=1; max_length=19; value.alloc(32);} + void fix_length_and_dec() + { + set_charset(thd_charset()); + maybe_null=1; + max_length=19*thd_charset()->mbmaxlen; + value.alloc(32); + } double val() { return (double) val_int(); } longlong val_int(); bool get_date(TIME *res,bool fuzzy_date); - unsigned int size_of() { return sizeof(*this);} }; class Item_extract :public Item_int_func @@ -421,7 +524,6 @@ class Item_extract :public Item_int_func longlong val_int(); const char *func_name() const { return "extract"; } void fix_length_and_dec(); - unsigned int size_of() { return sizeof(*this);} }; class Item_typecast :public Item_str_func @@ -446,7 +548,8 @@ public: } Field *tmp_table_field(TABLE *t_arg) { - return (!t_arg) ? result_field : new Field_date(maybe_null, name, t_arg); + return (!t_arg) ? result_field : + new Field_date(maybe_null, name, t_arg, thd_charset()); } }; @@ -461,7 +564,8 @@ public: } Field *tmp_table_field(TABLE *t_arg) { - return (!t_arg) ? result_field : new Field_time(maybe_null, name, t_arg); + return (!t_arg) ? result_field : + new Field_time(maybe_null, name, t_arg, thd_charset()); } }; @@ -477,6 +581,6 @@ public: Field *tmp_table_field(TABLE *t_arg) { return (!t_arg) ? result_field : new Field_datetime(maybe_null, name, - t_arg); + t_arg, thd_charset()); } }; diff --git a/sql/item_uniq.h b/sql/item_uniq.h index cc087832f49..f0d1d353cfb 100644 --- a/sql/item_uniq.h +++ b/sql/item_uniq.h @@ -29,9 +29,9 @@ public: :Item_real_func(list) {} double val() { return 0.0; } void fix_length_and_dec() { decimals=0; max_length=6; } - unsigned int size_of() { return sizeof(*this);} }; + class Item_sum_unique_users :public Item_sum_num { public: @@ -43,6 +43,5 @@ public: bool add() { return 0; } void reset_field() {} void update_field(int offset) {} - bool fix_fields(THD *thd,struct st_table_list *tlist) { return 0;} - unsigned int size_of() { return sizeof(*this);} + bool fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref) { return 0;} }; diff --git a/sql/key.cc b/sql/key.cc index d103c07eb72..84669808b92 100644 --- a/sql/key.cc +++ b/sql/key.cc @@ -192,8 +192,10 @@ 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_strnncoll(system_charset_info, + (const uchar*) key, length, + (const uchar*) 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 49b6a3811e5..0d0d60fe204 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* Copyright (C) 2000-2002 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 @@ -74,12 +74,15 @@ 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}, + { "BYTE", SYM(BYTE_SYM), 0, 0}, { "CACHE", SYM(CACHE_SYM),0,0}, { "CASCADE", SYM(CASCADE),0,0}, { "CASE", SYM(CASE_SYM),0,0}, { "CHAR", SYM(CHAR_SYM),0,0}, { "CHARACTER", SYM(CHAR_SYM),0,0}, + { "CHARSET", SYM(CHARSET),0,0}, { "CHANGE", SYM(CHANGE),0,0}, { "CHANGED", SYM(CHANGED),0,0}, { "CHECK", SYM(CHECK_SYM),0,0}, @@ -87,6 +90,7 @@ static SYMBOL symbols[] = { { "CIPHER", SYM(CIPHER_SYM),0,0}, { "CLIENT", SYM(CLIENT_SYM),0,0}, { "CLOSE", SYM(CLOSE_SYM),0,0}, + { "COLLATE", SYM(COLLATE_SYM),0,0}, { "COLUMN", SYM(COLUMN_SYM),0,0}, { "COLUMNS", SYM(COLUMNS),0,0}, { "COMMENT", SYM(COMMENT_SYM),0,0}, @@ -123,11 +127,14 @@ static SYMBOL symbols[] = { { "DISABLE", SYM(DISABLE_SYM),0,0}, { "DISTINCT", SYM(DISTINCT),0,0}, { "DISTINCTROW", SYM(DISTINCT),0,0}, /* Access likes this */ + { "DIV", SYM(DIV_SYM),0,0}, { "DO", SYM(DO_SYM),0,0}, { "DOUBLE", SYM(DOUBLE_SYM),0,0}, + { "DUAL", SYM(DUAL_SYM),0,0}, { "DROP", SYM(DROP),0,0}, { "DUMPFILE", SYM(DUMPFILE),0,0}, { "DYNAMIC", SYM(DYNAMIC_SYM),0,0}, + { "ERRORS", SYM(ERRORS),0,0}, { "END", SYM(END),0,0}, { "ELSE", SYM(ELSE),0,0}, { "ESCAPE", SYM(ESCAPE_SYM),0,0}, @@ -149,6 +156,7 @@ static SYMBOL symbols[] = { { "FLOAT4", SYM(FLOAT_SYM),0,0}, { "FLOAT8", SYM(DOUBLE_SYM),0,0}, { "FLUSH", SYM(FLUSH_SYM),0,0}, + { "FALSE", SYM(FALSE_SYM),0,0}, { "FOREIGN", SYM(FOREIGN),0,0}, { "RAID_TYPE", SYM(RAID_TYPE),0,0}, { "RAID_CHUNKS", SYM(RAID_CHUNKS),0,0}, @@ -159,13 +167,16 @@ 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}, + { "HELP", SYM(HELP),0,0}, { "HIGH_PRIORITY", SYM(HIGH_PRIORITY),0,0}, { "HOUR", SYM(HOUR_SYM),0,0}, { "HOUR_MINUTE", SYM(HOUR_MINUTE_SYM),0,0}, @@ -240,6 +251,7 @@ static SYMBOL symbols[] = { { "MIN_ROWS", SYM(MIN_ROWS),0,0}, { "MINUTE", SYM(MINUTE_SYM),0,0}, { "MINUTE_SECOND", SYM(MINUTE_SECOND_SYM),0,0}, + { "MOD", SYM(MOD_SYM),0,0}, { "MODE", SYM(MODE_SYM),0,0}, { "MODIFY", SYM(MODIFY_SYM),0,0}, { "MONTH", SYM(MONTH_SYM),0,0}, @@ -304,18 +316,22 @@ static SYMBOL symbols[] = { { "ROLLUP", SYM(ROLLUP_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}, + { "SERIAL", SYM(SERIAL_SYM),0,0}, { "SERIALIZABLE", SYM(SERIALIZABLE_SYM),0,0}, { "SESSION", SYM(SESSION_SYM),0,0}, { "SET", SYM(SET),0,0}, { "SIGNED", SYM(SIGNED_SYM),0,0}, + { "SIMPLE", SYM(SIMPLE_SYM),0,0}, { "SHARE", SYM(SHARE_SYM),0,0}, { "SHOW", SYM(SHOW),0,0}, { "SHUTDOWN", SYM(SHUTDOWN),0,0}, { "SLAVE", SYM(SLAVE),0,0}, { "SMALLINT", SYM(SMALLINT),0,0}, { "SONAME", SYM(UDF_SONAME_SYM),0,0}, + { "SPATIAL", SYM(SPATIAL_SYM),0,0}, { "SQL_BIG_RESULT", SYM(SQL_BIG_RESULT),0,0}, { "SQL_BUFFER_RESULT", SYM(SQL_BUFFER_RESULT),0,0}, { "SQL_CACHE", SYM(SQL_CACHE_SYM), 0, 0}, @@ -347,8 +363,10 @@ static SYMBOL symbols[] = { { "TRAILING", SYM(TRAILING),0,0}, { "TRANSACTION", SYM(TRANSACTION_SYM),0,0}, { "TRUNCATE", SYM(TRUNCATE_SYM),0,0}, + { "TRUE", SYM(TRUE_SYM),0,0}, { "TO", SYM(TO_SYM),0,0}, { "TYPE", SYM(TYPE_SYM),0,0}, + { "TYPES", SYM(TYPES_SYM),0,0}, { "UNCOMMITTED", SYM(UNCOMMITTED_SYM),0,0}, { "UNION", SYM(UNION_SYM),0,0}, { "UNIQUE", SYM(UNIQUE_SYM),0,0}, @@ -359,11 +377,14 @@ static SYMBOL symbols[] = { { "USING", SYM(USING),0,0}, { "UPDATE", SYM(UPDATE_SYM),0,0}, { "USAGE", SYM(USAGE),0,0}, + { "VALUE", SYM(VALUE_SYM),0,0}, { "VALUES", SYM(VALUES),0,0}, { "VARCHAR", SYM(VARCHAR),0,0}, + { "VARCHARACTER", SYM(VARCHAR),0,0}, { "VARIABLES", SYM(VARIABLES),0,0}, { "VARYING", SYM(VARYING),0,0}, { "VARBINARY", SYM(VARBINARY),0,0}, + { "WARNINGS", SYM(WARNINGS),0,0}, { "WITH", SYM(WITH),0,0}, { "WORK", SYM(WORK_SYM),0,0}, { "WRITE", SYM(WRITE_SYM),0,0}, @@ -384,8 +405,10 @@ static SYMBOL sql_functions[] = { { "ADDDATE", SYM(DATE_ADD_INTERVAL),0,0}, { "AES_ENCRYPT", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_aes_encrypt)}, { "AES_DECRYPT", SYM(FUNC_ARG2),0,CREATE_FUNC(create_func_aes_decrypt)}, + { "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}, @@ -396,17 +419,21 @@ 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)}, + { "CRC32", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_crc32)}, + { "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}, @@ -420,9 +447,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}, @@ -434,6 +467,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)}, @@ -441,13 +480,20 @@ 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)}, { "IS_FREE_LOCK", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_is_free_lock)}, { "LAST_INSERT_ID", SYM(LAST_INSERT_ID),0,0}, + { "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)}, { "LN", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_ln)}, + { "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(LOG_SYM),0,0}, @@ -463,16 +509,30 @@ static SYMBOL sql_functions[] = { { "MD5", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_md5)}, { "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)}, @@ -496,6 +556,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)}, @@ -508,6 +569,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}, @@ -517,5 +579,8 @@ 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/lock.cc b/sql/lock.cc index 4c84bbb6e69..74d1109b203 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -69,6 +69,12 @@ TODO: #include "mysql_priv.h" #include <hash.h> #include <assert.h> +#include <ha_myisammrg.h> +#ifndef MASTER +#include "../srclib/myisammrg/myrg_def.h" +#else +#include "../myisammrg/myrg_def.h" +#endif extern HASH open_cache; @@ -156,6 +162,7 @@ retry: sql_lock=0; } } + thd->lock_time(); DBUG_RETURN (sql_lock); } @@ -412,8 +419,12 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count, return 0; } } + THR_LOCK_DATA **org_locks = locks; locks=table->file->store_lock(thd, locks, get_old_locks ? TL_IGNORE : lock_type); + if (locks) + for ( ; org_locks != locks ; org_locks++) + (*org_locks)->debug_print_param= (void *) table; } return sql_lock; } diff --git a/sql/log.cc b/sql/log.cc index 597985e8796..0e1af8e5dae 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -45,16 +45,19 @@ static bool test_if_number(const char *str, static int find_uniq_filename(char *name) { - long number; - uint i,length; - char buff[FN_REFLEN]; - struct st_my_dir *dir_info; + long number; + uint i; + char buff[FN_REFLEN]; + struct st_my_dir *dir_info; reg1 struct fileinfo *file_info; - ulong max_found=0; + ulong max_found=0; + DBUG_ENTER("find_uniq_filename"); - length=dirname_part(buff,name); - char *start=name+length,*end=strend(start); + uint length = dirname_part(buff,name); + char *start = name + length; + char *end = strend(start); + *end='.'; length= (uint) (end-start+1); @@ -75,7 +78,7 @@ static int find_uniq_filename(char *name) my_dirend(dir_info); *end++='.'; - sprintf(end,"%03ld",max_found+1); + sprintf(end,"%06ld",max_found+1); DBUG_RETURN(0); } @@ -213,15 +216,18 @@ bool MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg, time_t skr=time(NULL); struct tm tm_tmp; localtime_r(&skr,&tm_tmp); - sprintf(buff,"# %s, Version: %s at %02d%02d%02d %2d:%02d:%02d\n", - my_progname,server_version, - tm_tmp.tm_year % 100, - tm_tmp.tm_mon+1, - tm_tmp.tm_mday, - tm_tmp.tm_hour, - tm_tmp.tm_min, - tm_tmp.tm_sec); - if (my_b_write(&log_file, (byte*) buff,(uint) strlen(buff)) || + ulong length; + length= my_sprintf(buff, + (buff, + "# %s, Version: %s at %02d%02d%02d %2d:%02d:%02d\n", + my_progname,server_version, + tm_tmp.tm_year % 100, + tm_tmp.tm_mon+1, + tm_tmp.tm_mday, + tm_tmp.tm_hour, + tm_tmp.tm_min, + tm_tmp.tm_sec)); + if (my_b_write(&log_file, (byte*) buff, length) || flush_io_cache(&log_file)) goto err; break; @@ -935,7 +941,8 @@ bool MYSQL_LOG::write(THD *thd,enum enum_server_command command, { if (is_open() && (what_to_log & (1L << (uint) command))) { - int error=0; + uint length; + int error= 0; VOID(pthread_mutex_lock(&LOCK_log)); /* Test if someone closed between the is_open test and lock */ @@ -984,8 +991,10 @@ bool MYSQL_LOG::write(THD *thd,enum enum_server_command command, } else if (my_b_write(&log_file, (byte*) "\t\t",2) < 0) error=errno; - sprintf(buff,"%7ld %-11.11s", id,command_name[(uint) command]); - if (my_b_write(&log_file, (byte*) buff,strlen(buff))) + length=my_sprintf(buff, + (buff, "%7ld %-11.11s", id, + command_name[(uint) command])); + if (my_b_write(&log_file, (byte*) buff,length)) error=errno; if (format) { @@ -1235,11 +1244,7 @@ err: /* Write update log in a format suitable for incremental backup - - NOTE - - This code should be deleted in MySQL 5,0 as the binary log - is a full replacement for the update log. - + This is also used by the slow query log. */ bool MYSQL_LOG::write(THD *thd,const char *query, uint query_length, @@ -1474,7 +1479,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; @@ -1483,7 +1488,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/log_event.cc b/sql/log_event.cc index 373e50b84f7..3747af22922 100644 --- a/sql/log_event.cc +++ b/sql/log_event.cc @@ -26,6 +26,11 @@ #include <assert.h> +/***************************************************************************** + + my_b_safe_write() + + ****************************************************************************/ inline int my_b_safe_write(IO_CACHE* file, const byte *buf, int len) { @@ -40,6 +45,11 @@ inline int my_b_safe_write(IO_CACHE* file, const byte *buf, return my_b_write(file, buf,len); } +/***************************************************************************** + + pretty_print_str() + + ****************************************************************************/ #ifdef MYSQL_CLIENT static void pretty_print_str(FILE* file, char* str, int len) { @@ -63,16 +73,26 @@ static void pretty_print_str(FILE* file, char* str, int len) } fputc('\'', file); } -#endif +#endif // MYSQL_CLIENT -#ifndef MYSQL_CLIENT +/***************************************************************************** + + ignored_error_code() + ****************************************************************************/ +#ifndef MYSQL_CLIENT inline int ignored_error_code(int err_code) { return use_slave_mask && bitmap_is_set(&slave_error_mask, err_code); } +#endif // !MYSQL_CLIENT + +/***************************************************************************** + pretty_print_str() + ****************************************************************************/ +#ifndef MYSQL_CLIENT static void pretty_print_str(String* packet, char* str, int len) { char* end = str + len; @@ -95,8 +115,14 @@ static void pretty_print_str(String* packet, char* str, int len) } packet->append('\''); } +#endif // !MYSQL_CLIENT +/***************************************************************************** + slave_load_file_stem() + + ****************************************************************************/ +#ifndef MYSQL_CLIENT static inline char* slave_load_file_stem(char*buf, uint file_id, int event_server_id) { @@ -108,9 +134,81 @@ static inline char* slave_load_file_stem(char*buf, uint file_id, *buf++ = '-'; return int10_to_str(file_id, buf, 10); } +#endif // !MYSQL_CLIENT -#endif +/***************************************************************************** + + cleanup_load_tmpdir() + + Delete all temporary files used for SQL_LOAD. + + TODO + - When we get a 'server start' event, we should only remove + the files associated with the server id that just started. + Easily fixable by adding server_id as a prefix to the log files. + + ****************************************************************************/ +#ifndef MYSQL_CLIENT +static void cleanup_load_tmpdir() +{ + MY_DIR *dirp; + FILEINFO *file; + uint i; + if (!(dirp=my_dir(slave_load_tmpdir,MYF(MY_WME)))) + return; + + for (i=0 ; i < (uint)dirp->number_off_files; i++) + { + file=dirp->dir_entry+i; + if (is_prefix(file->name,"SQL_LOAD-")) + my_delete(file->name, MYF(0)); + } + + my_dirend(dirp); +} +#endif // !MYSQL_CLIENT + +/***************************************************************************** + + write_str() + + ****************************************************************************/ +static bool write_str(IO_CACHE *file, char *str, byte length) +{ + return (my_b_safe_write(file, &length, 1) || + my_b_safe_write(file, (byte*) str, (int) length)); +} + +/***************************************************************************** + + read_str() + + ****************************************************************************/ +static inline int read_str(char * &buf, char *buf_end, char * &str, + uint8 &len) +{ + if (buf + (uint) (uchar) *buf >= buf_end) + return 1; + len = (uint8) *buf; + str= buf+1; + buf+= (uint) len+1; + return 0; +} + + +/***************************************************************************** + ***************************************************************************** + + Log_event methods + + ***************************************************************************** + ****************************************************************************/ + +/***************************************************************************** + + Log_event::get_type_str() + ****************************************************************************/ const char* Log_event::get_type_str() { switch(get_type_code()) { @@ -126,20 +224,26 @@ const char* Log_event::get_type_str() case APPEND_BLOCK_EVENT: return "Append_block"; case DELETE_FILE_EVENT: return "Delete_file"; case EXEC_LOAD_EVENT: return "Exec_load"; + case RAND_EVENT: return "RAND"; default: /* impossible */ return "Unknown"; } } +/***************************************************************************** + + Log_event::Log_event() + + ****************************************************************************/ #ifndef MYSQL_CLIENT Log_event::Log_event(THD* thd_arg, uint16 flags_arg, bool using_trans) :temp_buf(0), exec_time(0), cached_event_len(0), flags(flags_arg), thd(thd_arg) { - server_id = thd->server_id; - when = thd->start_time; - log_pos = thd->log_pos; - cache_stmt= (using_trans && - (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))); + server_id= thd->server_id; + when= thd->start_time; + log_pos= thd->log_pos; + cache_stmt= (using_trans && + (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))); } @@ -147,40 +251,17 @@ Log_event::Log_event() :temp_buf(0), exec_time(0), cached_event_len(0), flags(0), cache_stmt(0), thd(0) { - server_id = ::server_id; - when = time(NULL); - log_pos=0; + server_id= ::server_id; + when= time(NULL); + log_pos= 0; } +#endif // !MYSQL_CLIENT -/* - Delete all temporary files used for SQL_LOAD. - - TODO - - When we get a 'server start' event, we should only remove - the files associated with the server id that just started. - Easily fixable by adding server_id as a prefix to the log files. -*/ - -static void cleanup_load_tmpdir() -{ - MY_DIR *dirp; - FILEINFO *file; - uint i; - if (!(dirp=my_dir(slave_load_tmpdir,MYF(MY_WME)))) - return; - - for (i=0 ; i < (uint)dirp->number_off_files; i++) - { - file=dirp->dir_entry+i; - if (is_prefix(file->name,"SQL_LOAD-")) - my_delete(file->name, MYF(0)); - } - - my_dirend(dirp); -} +/***************************************************************************** -#endif + Log_event::Log_event() + ****************************************************************************/ Log_event::Log_event(const char* buf, bool old_format) :temp_buf(0), cached_event_len(0), cache_stmt(0) { @@ -204,6 +285,11 @@ Log_event::Log_event(const char* buf, bool old_format) #ifndef MYSQL_CLIENT +/***************************************************************************** + + Log_event::exec_event() + + ****************************************************************************/ int Log_event::exec_event(struct st_relay_log_info* rli) { if (rli) // QQ When is this not true ? @@ -215,170 +301,21 @@ int Log_event::exec_event(struct st_relay_log_info* rli) return 0; } -void Log_event::pack_info(String* packet) -{ - net_store_data(packet, "", 0); -} - -void Query_log_event::pack_info(String* packet) -{ - char buf[256]; - String tmp(buf, sizeof(buf)); - tmp.length(0); - if (db && db_len) - { - tmp.append("use "); - tmp.append(db, db_len); - tmp.append("; ", 2); - } - - if (query && q_len) - tmp.append(query, q_len); - net_store_data(packet, (char*)tmp.ptr(), tmp.length()); -} - -void Start_log_event::pack_info(String* packet) -{ - char buf1[256]; - String tmp(buf1, sizeof(buf1)); - tmp.length(0); - char buf[22]; - - tmp.append("Server ver: "); - tmp.append(server_version); - tmp.append(", Binlog ver: "); - tmp.append(llstr(binlog_version, buf)); - net_store_data(packet, tmp.ptr(), tmp.length()); -} - -void Load_log_event::pack_info(String* packet) -{ - char buf[256]; - String tmp(buf, sizeof(buf)); - tmp.length(0); - if (db && db_len) - { - tmp.append("use "); - tmp.append(db, db_len); - tmp.append("; ", 2); - } - - tmp.append("LOAD DATA INFILE '"); - tmp.append(fname, fname_len); - tmp.append("' ", 2); - if (sql_ex.opt_flags && REPLACE_FLAG ) - tmp.append(" REPLACE "); - else if (sql_ex.opt_flags && IGNORE_FLAG ) - tmp.append(" IGNORE "); - - tmp.append("INTO TABLE "); - tmp.append(table_name); - if (sql_ex.field_term_len) - { - tmp.append(" FIELDS TERMINATED BY "); - pretty_print_str(&tmp, sql_ex.field_term, sql_ex.field_term_len); - } - - if (sql_ex.enclosed_len) - { - if (sql_ex.opt_flags && OPT_ENCLOSED_FLAG ) - tmp.append(" OPTIONALLY "); - tmp.append( " ENCLOSED BY "); - pretty_print_str(&tmp, sql_ex.enclosed, sql_ex.enclosed_len); - } - - if (sql_ex.escaped_len) - { - tmp.append( " ESCAPED BY "); - pretty_print_str(&tmp, sql_ex.escaped, sql_ex.escaped_len); - } - - if (sql_ex.line_term_len) - { - tmp.append(" LINES TERMINATED BY "); - pretty_print_str(&tmp, sql_ex.line_term, sql_ex.line_term_len); - } - - if (sql_ex.line_start_len) - { - tmp.append(" LINES STARTING BY "); - pretty_print_str(&tmp, sql_ex.line_start, sql_ex.line_start_len); - } - - if ((int)skip_lines > 0) - tmp.append( " IGNORE %ld LINES ", (long) skip_lines); - - if (num_fields) - { - uint i; - const char* field = fields; - tmp.append(" ("); - for (i = 0; i < num_fields; i++) - { - if (i) - tmp.append(" ,"); - tmp.append( field); - - field += field_lens[i] + 1; - } - tmp.append(')'); - } - - net_store_data(packet, tmp.ptr(), tmp.length()); -} - -void Rotate_log_event::pack_info(String* packet) -{ - char buf1[256], buf[22]; - String tmp(buf1, sizeof(buf1)); - tmp.length(0); - tmp.append(new_log_ident, ident_len); - tmp.append(";pos="); - tmp.append(llstr(pos,buf)); - if (flags & LOG_EVENT_FORCED_ROTATE_F) - tmp.append("; forced by master"); - net_store_data(packet, tmp.ptr(), tmp.length()); -} +/***************************************************************************** -void Intvar_log_event::pack_info(String* packet) -{ - char buf1[256], buf[22]; - String tmp(buf1, sizeof(buf1)); - tmp.length(0); - tmp.append(get_var_type_name()); - tmp.append('='); - tmp.append(llstr(val, buf)); - net_store_data(packet, tmp.ptr(), tmp.length()); -} + Log_event::pack_info() -void Rand_log_event::pack_info(String* packet) + ****************************************************************************/ +void Log_event::pack_info(String* packet) { - char buf1[256], *pos; - pos=strmov(buf1,"rand_seed1="); - pos=int10_to_str((long) seed1, pos, 10); - pos=strmov(pos, ",rand_seed2="); - pos=int10_to_str((long) seed2, pos, 10); - net_store_data(packet, buf1, (uint) (pos-buf1)); + net_store_data(packet, "", 0); } -void Slave_log_event::pack_info(String* packet) -{ - char buf1[256], buf[22], *end; - String tmp(buf1, sizeof(buf1)); - tmp.length(0); - tmp.append("host="); - tmp.append(master_host); - tmp.append(",port="); - end= int10_to_str((long) master_port, buf, 10); - tmp.append(buf, (uint32) (end-buf)); - tmp.append(",log="); - tmp.append(master_log); - tmp.append(",pos="); - tmp.append(llstr(master_pos,buf)); - net_store_data(packet, tmp.ptr(), tmp.length()); -} +/***************************************************************************** + Log_event::init_show_field_list() + ****************************************************************************/ void Log_event::init_show_field_list(List<Item>* field_list) { field_list->push_back(new Item_empty_string("Log_name", 20)); @@ -389,14 +326,18 @@ void Log_event::init_show_field_list(List<Item>* field_list) field_list->push_back(new Item_empty_string("Info", 20)); } -/* - * only called by SHOW BINLOG EVENTS - */ +/***************************************************************************** + + Log_event::net_send() + + Only called by SHOW BINLOG EVENTS + + ****************************************************************************/ int Log_event::net_send(THD* thd_arg, const char* log_name, my_off_t pos) { String* packet = &thd_arg->packet; - const char* p = strrchr(log_name, FN_LIBCHAR); - const char* event_type; + const char *p= strrchr(log_name, FN_LIBCHAR); + const char *event_type; if (p) log_name = p + 1; @@ -410,22 +351,23 @@ int Log_event::net_send(THD* thd_arg, const char* log_name, my_off_t pos) pack_info(packet); return my_net_write(&thd_arg->net, (char*) packet->ptr(), packet->length()); } +#endif // !MYSQL_CLIENT -#endif /* MYSQL_CLIENT */ - - -int Query_log_event::write(IO_CACHE* file) -{ - return query ? Log_event::write(file) : -1; -} +/***************************************************************************** + Log_event::write() + ****************************************************************************/ int Log_event::write(IO_CACHE* file) { return (write_header(file) || write_data(file)) ? -1 : 0; } +/***************************************************************************** + Log_event::write_header() + + ****************************************************************************/ int Log_event::write_header(IO_CACHE* file) { char buf[LOG_EVENT_HEADER_LEN]; @@ -445,8 +387,13 @@ int Log_event::write_header(IO_CACHE* file) return (my_b_safe_write(file, (byte*) buf, (uint) (pos - buf))); } -#ifndef MYSQL_CLIENT +/***************************************************************************** + + Log_event::read_log_event() + + ****************************************************************************/ +#ifndef MYSQL_CLIENT int Log_event::read_log_event(IO_CACHE* file, String* packet, pthread_mutex_t* log_lock) { @@ -501,8 +448,7 @@ end: pthread_mutex_unlock(log_lock); DBUG_RETURN(result); } - -#endif // MYSQL_CLIENT +#endif // !MYSQL_CLIENT #ifndef MYSQL_CLIENT #define UNLOCK_MUTEX if (log_lock) pthread_mutex_unlock(log_lock); @@ -513,7 +459,13 @@ end: #define LOCK_MUTEX #endif -// allocates memory - the caller is responsible for clean-up +/***************************************************************************** + + Log_event::read_log_event() + + Allocates memory--the caller is responsible for clean-up + + ****************************************************************************/ #ifndef MYSQL_CLIENT Log_event* Log_event::read_log_event(IO_CACHE* file, pthread_mutex_t* log_lock, @@ -576,7 +528,11 @@ data_len=%d,event_type=%d",error,data_len,head[EVENT_TYPE_OFFSET]); return res; } +/***************************************************************************** + + Log_event::read_log_event() + ****************************************************************************/ Log_event* Log_event::read_log_event(const char* buf, int event_len, const char **error, bool old_format) { @@ -642,8 +598,13 @@ Log_event* Log_event::read_log_event(const char* buf, int event_len, return ev; } - #ifdef MYSQL_CLIENT + +/***************************************************************************** + + Log_event::print_header() + + ****************************************************************************/ void Log_event::print_header(FILE* file) { char llbuff[22]; @@ -653,6 +614,11 @@ void Log_event::print_header(FILE* file) llstr(log_pos,llbuff)); } +/***************************************************************************** + + Log_event::print_timestamp() + + ****************************************************************************/ void Log_event::print_timestamp(FILE* file, time_t* ts) { struct tm *res; @@ -674,113 +640,91 @@ void Log_event::print_timestamp(FILE* file, time_t* ts) res->tm_sec); } +#endif // MYSQL_CLIENT -void Start_log_event::print(FILE* file, bool short_form, char* last_db) -{ - if (short_form) - return; +/***************************************************************************** - print_header(file); - fprintf(file, "\tStart: binlog v %d, server v %s created ", binlog_version, - server_version); - print_timestamp(file, (time_t*)&created); - fputc('\n', file); - fflush(file); -} + Log_event::set_log_pos() -void Stop_log_event::print(FILE* file, bool short_form, char* last_db) + ****************************************************************************/ +#ifndef MYSQL_CLIENT +void Log_event::set_log_pos(MYSQL_LOG* log) { - if (short_form) - return; - - print_header(file); - fprintf(file, "\tStop\n"); - fflush(file); + if (!log_pos) + log_pos = my_b_tell(&log->log_file); } +#endif // !MYSQL_CLIENT -void Rotate_log_event::print(FILE* file, bool short_form, char* last_db) -{ - char buf[22]; - if (short_form) - return; - print_header(file); - fprintf(file, "\tRotate to "); - if (new_log_ident) - my_fwrite(file, (byte*) new_log_ident, (uint)ident_len, - MYF(MY_NABP | MY_WME)); - fprintf(file, " pos: %s", llstr(pos, buf)); - if (flags & LOG_EVENT_FORCED_ROTATE_F) - fprintf(file," forced by master"); - fputc('\n', file); - fflush(file); -} -#endif /* #ifdef MYSQL_CLIENT */ +/***************************************************************************** + ***************************************************************************** + Query_log_event methods -Start_log_event::Start_log_event(const char* buf, - bool old_format) - :Log_event(buf, old_format) -{ - buf += (old_format) ? OLD_HEADER_LEN : LOG_EVENT_HEADER_LEN; - binlog_version = uint2korr(buf+ST_BINLOG_VER_OFFSET); - memcpy(server_version, buf+ST_SERVER_VER_OFFSET, - ST_SERVER_VER_LEN); - created = uint4korr(buf+ST_CREATED_OFFSET); -} + ***************************************************************************** + ****************************************************************************/ -int Start_log_event::write_data(IO_CACHE* file) -{ - char buff[START_HEADER_LEN]; - int2store(buff + ST_BINLOG_VER_OFFSET,binlog_version); - memcpy(buff + ST_SERVER_VER_OFFSET,server_version,ST_SERVER_VER_LEN); - int4store(buff + ST_CREATED_OFFSET,created); - return (my_b_safe_write(file, (byte*) buff, sizeof(buff)) ? -1 : 0); -} +#ifndef MYSQL_CLIENT +/***************************************************************************** + Query_log_event::pack_info() -Rotate_log_event::Rotate_log_event(const char* buf, int event_len, - bool old_format) - :Log_event(buf, old_format),new_log_ident(NULL),alloced(0) + ****************************************************************************/ +void Query_log_event::pack_info(String* packet) { - // The caller will ensure that event_len is what we have at EVENT_LEN_OFFSET - int header_size = (old_format) ? OLD_HEADER_LEN : LOG_EVENT_HEADER_LEN; - uint ident_offset; - if (event_len < header_size) - return; - buf += header_size; - if (old_format) - { - ident_len = (uint)(event_len - OLD_HEADER_LEN); - pos = 4; - ident_offset = 0; - } - else + char buf[256]; + String tmp(buf, sizeof(buf), system_charset_info); + tmp.length(0); + if (db && db_len) { - ident_len = (uint)(event_len - ROTATE_EVENT_OVERHEAD); - pos = uint8korr(buf + R_POS_OFFSET); - ident_offset = ROTATE_HEADER_LEN; + tmp.append("use `", 5); + tmp.append(db, db_len); + tmp.append("`; ", 3); } - set_if_smaller(ident_len,FN_REFLEN-1); - if (!(new_log_ident= my_strdup_with_length((byte*) buf + - ident_offset, - (uint) ident_len, - MYF(MY_WME)))) - return; - alloced = 1; + + if (query && q_len) + tmp.append(query, q_len); + net_store_data(packet, (char*)tmp.ptr(), tmp.length()); } +#endif // !MYSQL_CLIENT +/***************************************************************************** -int Rotate_log_event::write_data(IO_CACHE* file) + Query_log_event::write() + + ****************************************************************************/ +int Query_log_event::write(IO_CACHE* file) { - char buf[ROTATE_HEADER_LEN]; - int8store(buf, pos + R_POS_OFFSET); - return (my_b_safe_write(file, (byte*)buf, ROTATE_HEADER_LEN) || - my_b_safe_write(file, (byte*)new_log_ident, (uint) ident_len)); + return query ? Log_event::write(file) : -1; +} + +/***************************************************************************** + + Query_log_event::write_data() + + ****************************************************************************/ +int Query_log_event::write_data(IO_CACHE* file) +{ + if (!query) + return -1; + + char buf[QUERY_HEADER_LEN]; + int4store(buf + Q_THREAD_ID_OFFSET, thread_id); + int4store(buf + Q_EXEC_TIME_OFFSET, exec_time); + buf[Q_DB_LEN_OFFSET] = (char) db_len; + int2store(buf + Q_ERR_CODE_OFFSET, error_code); + + return (my_b_safe_write(file, (byte*) buf, QUERY_HEADER_LEN) || + my_b_safe_write(file, (db) ? (byte*) db : (byte*)"", db_len + 1) || + my_b_safe_write(file, (byte*) query, q_len)) ? -1 : 0; } +/***************************************************************************** + + Query_log_event::Query_log_event() + ****************************************************************************/ #ifndef MYSQL_CLIENT Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, ulong query_length, bool using_trans) @@ -794,8 +738,13 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, exec_time = (ulong) (end_time - thd->start_time); db_len = (db) ? (uint32) strlen(db) : 0; } -#endif +#endif // MYSQL_CLIENT + +/***************************************************************************** + + Query_log_event::Query_log_event() + ****************************************************************************/ Query_log_event::Query_log_event(const char* buf, int event_len, bool old_format) :Log_event(buf, old_format),data_buf(0), query(NULL), db(NULL) @@ -831,9 +780,12 @@ Query_log_event::Query_log_event(const char* buf, int event_len, *((char*)query+q_len) = 0; } +/***************************************************************************** -#ifdef MYSQL_CLIENT + Query_log_event::print() + ****************************************************************************/ +#ifdef MYSQL_CLIENT void Query_log_event::print(FILE* file, bool short_form, char* last_db) { char buff[40],*end; // Enough for SET TIMESTAMP @@ -861,113 +813,311 @@ void Query_log_event::print(FILE* file, bool short_form, char* last_db) my_fwrite(file, (byte*) query, q_len, MYF(MY_NABP | MY_WME)); fprintf(file, ";\n"); } -#endif - +#endif // MYSQL_CLIENT -int Query_log_event::write_data(IO_CACHE* file) -{ - if (!query) - return -1; - - char buf[QUERY_HEADER_LEN]; - int4store(buf + Q_THREAD_ID_OFFSET, thread_id); - int4store(buf + Q_EXEC_TIME_OFFSET, exec_time); - buf[Q_DB_LEN_OFFSET] = (char) db_len; - int2store(buf + Q_ERR_CODE_OFFSET, error_code); +/***************************************************************************** - return (my_b_safe_write(file, (byte*) buf, QUERY_HEADER_LEN) || - my_b_safe_write(file, (db) ? (byte*) db : (byte*)"", db_len + 1) || - my_b_safe_write(file, (byte*) query, q_len)) ? -1 : 0; -} + Query_log_event::exec_event() -Intvar_log_event::Intvar_log_event(const char* buf, bool old_format) - :Log_event(buf, old_format) + ****************************************************************************/ +#ifndef MYSQL_CLIENT +int Query_log_event::exec_event(struct st_relay_log_info* rli) { - buf += (old_format) ? OLD_HEADER_LEN : LOG_EVENT_HEADER_LEN; - type = buf[I_TYPE_OFFSET]; - val = uint8korr(buf+I_VAL_OFFSET); -} + int expected_error,actual_error = 0; + init_sql_alloc(&thd->mem_root, 8192,0); + thd->db = rewrite_db((char*)db); -const char* Intvar_log_event::get_var_type_name() -{ - switch(type) { - case LAST_INSERT_ID_EVENT: return "LAST_INSERT_ID"; - case INSERT_ID_EVENT: return "INSERT_ID"; - default: /* impossible */ return "UNKNOWN"; + /* + InnoDB internally stores the master log position it has processed so far; + position to store is really pos + pending + event_len + since we must store the pos of the END of the current log event + */ + rli->event_len= get_event_len(); + + if (db_ok(thd->db, replicate_do_db, replicate_ignore_db)) + { + thd->query = (char*)query; + thd->set_time((time_t)when); + thd->current_tablenr = 0; + VOID(pthread_mutex_lock(&LOCK_thread_count)); + thd->query_id = query_id++; + VOID(pthread_mutex_unlock(&LOCK_thread_count)); + thd->query_error= 0; // clear error + thd->clear_error(); + + thd->slave_proxy_id = thread_id; // for temp tables + + /* + Sanity check to make sure the master did not get a really bad + error on the query. + */ + if (ignored_error_code((expected_error = error_code)) || + !check_expected_error(thd,rli,expected_error)) + { + mysql_log.write(thd,COM_QUERY,"%s",thd->query); + DBUG_PRINT("query",("%s",thd->query)); + mysql_parse(thd, thd->query, q_len); + DBUG_PRINT("info",("expected_error: %d last_errno: %d", + expected_error, thd->net.last_errno)); + if ((expected_error != (actual_error= thd->net.last_errno)) && + expected_error && + !ignored_error_code(actual_error) && + !ignored_error_code(expected_error)) + { + const char* errmsg = "Slave: did not get the expected error\ + running query from master - expected: '%s' (%d), got '%s' (%d)"; + sql_print_error(errmsg, ER_SAFE(expected_error), + expected_error, + actual_error ? thd->net.last_error: "no error", + actual_error); + thd->query_error = 1; + } + else if (expected_error == actual_error || + ignored_error_code(actual_error)) + { + DBUG_PRINT("info",("error ignored")); + thd->query_error = 0; + *rli->last_slave_error = 0; + rli->last_slave_errno = 0; + } + } + else + { + // master could be inconsistent, abort and tell DBA to check/fix it + thd->db = thd->query = 0; + thd->variables.convert_set = 0; + close_thread_tables(thd); + free_root(&thd->mem_root,0); + return 1; + } + } + thd->db= 0; // prevent db from being freed + thd->query= 0; // just to be sure + // assume no convert for next query unless set explictly + thd->variables.convert_set = 0; + close_thread_tables(thd); + + if (thd->query_error || thd->fatal_error) + { + slave_print_error(rli,actual_error, "error '%s' on query '%s'", + actual_error ? thd->net.last_error : + "unexpected success or fatal error", query); + free_root(&thd->mem_root,0); + return 1; } + free_root(&thd->mem_root,0); + return Log_event::exec_event(rli); } +#endif // !MYSQL_CLIENT -int Intvar_log_event::write_data(IO_CACHE* file) + +/***************************************************************************** + ***************************************************************************** + + Start_log_event methods + + ***************************************************************************** + ****************************************************************************/ + +/***************************************************************************** + + Start_log_event::pack_info() + + ****************************************************************************/ +#ifndef MYSQL_CLIENT +void Start_log_event::pack_info(String* packet) { - char buf[9]; - buf[I_TYPE_OFFSET] = type; - int8store(buf + I_VAL_OFFSET, val); - return my_b_safe_write(file, (byte*) buf, sizeof(buf)); + char buf1[256]; + String tmp(buf1, sizeof(buf1), system_charset_info); + tmp.length(0); + char buf[22]; + + tmp.append("Server ver: "); + tmp.append(server_version); + tmp.append(", Binlog ver: "); + tmp.append(llstr(binlog_version, buf)); + net_store_data(packet, tmp.ptr(), tmp.length()); } +#endif // !MYSQL_CLIENT +/***************************************************************************** + + Start_log_event::print() + + ****************************************************************************/ #ifdef MYSQL_CLIENT -void Intvar_log_event::print(FILE* file, bool short_form, char* last_db) +void Start_log_event::print(FILE* file, bool short_form, char* last_db) { - char llbuff[22]; - const char *msg; - LINT_INIT(msg); - - if (!short_form) - { - print_header(file); - fprintf(file, "\tIntvar\n"); - } + if (short_form) + return; - fprintf(file, "SET "); - switch (type) { - case LAST_INSERT_ID_EVENT: - msg="LAST_INSERT_ID"; - break; - case INSERT_ID_EVENT: - msg="INSERT_ID"; - break; - } - fprintf(file, "%s=%s;\n", msg, llstr(val,llbuff)); + print_header(file); + fprintf(file, "\tStart: binlog v %d, server v %s created ", binlog_version, + server_version); + print_timestamp(file, (time_t*)&created); + fputc('\n', file); fflush(file); } -#endif +#endif // MYSQL_CLIENT /***************************************************************************** - * - * Rand log event - * + + Start_log_event::Start_log_event() + ****************************************************************************/ -Rand_log_event::Rand_log_event(const char* buf, bool old_format) +Start_log_event::Start_log_event(const char* buf, + bool old_format) :Log_event(buf, old_format) { buf += (old_format) ? OLD_HEADER_LEN : LOG_EVENT_HEADER_LEN; - seed1 = uint8korr(buf+RAND_SEED1_OFFSET); - seed2 = uint8korr(buf+RAND_SEED2_OFFSET); + binlog_version = uint2korr(buf+ST_BINLOG_VER_OFFSET); + memcpy(server_version, buf+ST_SERVER_VER_OFFSET, + ST_SERVER_VER_LEN); + created = uint4korr(buf+ST_CREATED_OFFSET); } -int Rand_log_event::write_data(IO_CACHE* file) +/***************************************************************************** + + Start_log_event::write_data() + + ****************************************************************************/ +int Start_log_event::write_data(IO_CACHE* file) { - char buf[16]; - int8store(buf + RAND_SEED1_OFFSET, seed1); - int8store(buf + RAND_SEED2_OFFSET, seed2); - return my_b_safe_write(file, (byte*) buf, sizeof(buf)); + char buff[START_HEADER_LEN]; + int2store(buff + ST_BINLOG_VER_OFFSET,binlog_version); + memcpy(buff + ST_SERVER_VER_OFFSET,server_version,ST_SERVER_VER_LEN); + int4store(buff + ST_CREATED_OFFSET,created); + return (my_b_safe_write(file, (byte*) buff, sizeof(buff)) ? -1 : 0); } -#ifdef MYSQL_CLIENT -void Rand_log_event::print(FILE* file, bool short_form, char* last_db) +/***************************************************************************** + + Start_log_event::exec_event() + + The master started + + IMPLEMENTATION + - To handle the case where the master died without a stop event, + we clean up all temporary tables + locks that we got. + + TODO + - Remove all active user locks + - If we have an active transaction at this point, the master died + in the middle while writing the transaction to the binary log. + In this case we should stop the slave. + + ****************************************************************************/ +#ifndef MYSQL_CLIENT +int Start_log_event::exec_event(struct st_relay_log_info* rli) { - char llbuff[22]; - if (!short_form) + /* All temporary tables was deleted on the master */ + close_temporary_tables(thd); + /* + If we have old format, load_tmpdir is cleaned up by the I/O thread + */ + if (!rli->mi->old_format) + cleanup_load_tmpdir(); + return Log_event::exec_event(rli); +} +#endif // !MYSQL_CLIENT + + +/***************************************************************************** + ***************************************************************************** + + Load_log_event methods + + ***************************************************************************** + ****************************************************************************/ + +/***************************************************************************** + + Load_log_event::pack_info() + + ****************************************************************************/ +#ifndef MYSQL_CLIENT +void Load_log_event::pack_info(String* packet) +{ + char buf[256]; + String tmp(buf, sizeof(buf), system_charset_info); + tmp.length(0); + if (db && db_len) { - print_header(file); - fprintf(file, "\tRand\n"); + tmp.append("use "); + tmp.append(db, db_len); + tmp.append("; ", 2); } - fprintf(file, "SET @@RAND_SEED1=%s, @@RAND_SEED2=%s;\n", - llstr(seed1, llbuff),llstr(seed2, llbuff)); - fflush(file); + + tmp.append("LOAD DATA INFILE '"); + tmp.append(fname, fname_len); + tmp.append("' ", 2); + if (sql_ex.opt_flags && REPLACE_FLAG ) + tmp.append(" REPLACE "); + else if (sql_ex.opt_flags && IGNORE_FLAG ) + tmp.append(" IGNORE "); + + tmp.append("INTO TABLE "); + tmp.append(table_name); + if (sql_ex.field_term_len) + { + tmp.append(" FIELDS TERMINATED BY "); + pretty_print_str(&tmp, sql_ex.field_term, sql_ex.field_term_len); + } + + if (sql_ex.enclosed_len) + { + if (sql_ex.opt_flags && OPT_ENCLOSED_FLAG ) + tmp.append(" OPTIONALLY "); + tmp.append( " ENCLOSED BY "); + pretty_print_str(&tmp, sql_ex.enclosed, sql_ex.enclosed_len); + } + + if (sql_ex.escaped_len) + { + tmp.append( " ESCAPED BY "); + pretty_print_str(&tmp, sql_ex.escaped, sql_ex.escaped_len); + } + + if (sql_ex.line_term_len) + { + tmp.append(" LINES TERMINATED BY "); + pretty_print_str(&tmp, sql_ex.line_term, sql_ex.line_term_len); + } + + if (sql_ex.line_start_len) + { + tmp.append(" LINES STARTING BY "); + pretty_print_str(&tmp, sql_ex.line_start, sql_ex.line_start_len); + } + + if ((int)skip_lines > 0) + tmp.append( " IGNORE %ld LINES ", (long) skip_lines); + + if (num_fields) + { + uint i; + const char* field = fields; + tmp.append(" ("); + for (i = 0; i < num_fields; i++) + { + if (i) + tmp.append(" ,"); + tmp.append( field); + + field += field_lens[i] + 1; + } + tmp.append(')'); + } + + net_store_data(packet, tmp.ptr(), tmp.length()); } -#endif +#endif // !MYSQL_CLIENT + +/***************************************************************************** + Load_log_event::write_data_header() + + ****************************************************************************/ int Load_log_event::write_data_header(IO_CACHE* file) { char buf[LOAD_HEADER_LEN]; @@ -980,6 +1130,11 @@ int Load_log_event::write_data_header(IO_CACHE* file) return my_b_safe_write(file, (byte*)buf, LOAD_HEADER_LEN); } +/***************************************************************************** + + Load_log_event::write_data_body() + + ****************************************************************************/ int Load_log_event::write_data_body(IO_CACHE* file) { if (sql_ex.write_data(file)) @@ -995,107 +1150,17 @@ int Load_log_event::write_data_body(IO_CACHE* file) my_b_safe_write(file, (byte*)fname, fname_len)); } +/***************************************************************************** + Load_log_event::Load_log_event() -static bool write_str(IO_CACHE *file, char *str, byte length) -{ - return (my_b_safe_write(file, &length, 1) || - my_b_safe_write(file, (byte*) str, (int) length)); -} - - -int sql_ex_info::write_data(IO_CACHE* file) -{ - if (new_format()) - { - return (write_str(file, field_term, field_term_len) || - write_str(file, enclosed, enclosed_len) || - write_str(file, line_term, line_term_len) || - write_str(file, line_start, line_start_len) || - write_str(file, escaped, escaped_len) || - my_b_safe_write(file,(byte*) &opt_flags,1)); - } - else - { - old_sql_ex old_ex; - old_ex.field_term= *field_term; - old_ex.enclosed= *enclosed; - old_ex.line_term= *line_term; - old_ex.line_start= *line_start; - old_ex.escaped= *escaped; - old_ex.opt_flags= opt_flags; - old_ex.empty_flags=empty_flags; - return my_b_safe_write(file, (byte*) &old_ex, sizeof(old_ex)); - } -} - - -static inline int read_str(char * &buf, char *buf_end, char * &str, - uint8 &len) -{ - if (buf + (uint) (uchar) *buf >= buf_end) - return 1; - len = (uint8) *buf; - str= buf+1; - buf+= (uint) len+1; - return 0; -} - - -char* sql_ex_info::init(char* buf,char* buf_end,bool use_new_format) -{ - cached_new_format = use_new_format; - if (use_new_format) - { - empty_flags=0; - /* - The code below assumes that buf will not disappear from - under our feet during the lifetime of the event. This assumption - holds true in the slave thread if the log is in new format, but is not - the case when we have old format because we will be reusing net buffer - to read the actual file before we write out the Create_file event. - */ - if (read_str(buf, buf_end, field_term, field_term_len) || - read_str(buf, buf_end, enclosed, enclosed_len) || - read_str(buf, buf_end, line_term, line_term_len) || - read_str(buf, buf_end, line_start, line_start_len) || - read_str(buf, buf_end, escaped, escaped_len)) - return 0; - opt_flags = *buf++; - } - else - { - field_term_len= enclosed_len= line_term_len= line_start_len= escaped_len=1; - field_term = buf++; // Use first byte in string - enclosed= buf++; - line_term= buf++; - line_start= buf++; - escaped= buf++; - opt_flags = *buf++; - empty_flags= *buf++; - if (empty_flags & FIELD_TERM_EMPTY) - field_term_len=0; - if (empty_flags & ENCLOSED_EMPTY) - enclosed_len=0; - if (empty_flags & LINE_TERM_EMPTY) - line_term_len=0; - if (empty_flags & LINE_START_EMPTY) - line_start_len=0; - if (empty_flags & ESCAPED_EMPTY) - escaped_len=0; - } - return buf; -} - - + ****************************************************************************/ #ifndef MYSQL_CLIENT -Load_log_event::Load_log_event(THD* thd_arg, sql_exchange* ex, - const char* db_arg, const char* table_name_arg, - List<Item>& fields_arg, - enum enum_duplicates handle_dup, - bool using_trans) - :Log_event(thd_arg, 0, using_trans),thread_id(thd_arg->thread_id), - num_fields(0),fields(0), +Load_log_event::Load_log_event(THD *thd_arg, sql_exchange *ex, + const char *db_arg, const char *table_name_arg, + List<Item> &fields_arg, + enum enum_duplicates handle_dup) + :Log_event(thd_arg),thread_id(thd_arg->thread_id), num_fields(0),fields(0), field_lens(0),field_block_len(0), table_name(table_name_arg ? table_name_arg : ""), db(db_arg), fname(ex->file_name) @@ -1162,25 +1227,32 @@ Load_log_event::Load_log_event(THD* thd_arg, sql_exchange* ex, field_lens = (const uchar*)field_lens_buf.ptr(); fields = fields_buf.ptr(); } +#endif // !MYSQL_CLIENT -#endif +/***************************************************************************** + + Load_log_event::Load_log_event() -/* The caller must do buf[event_len] = 0 before he starts using the constructed event. -*/ -Load_log_event::Load_log_event(const char* buf, int event_len, + ****************************************************************************/ +Load_log_event::Load_log_event(const char *buf, int event_len, bool old_format) :Log_event(buf, old_format),num_fields(0),fields(0), - field_lens(0),field_block_len(0), - table_name(0),db(0),fname(0) + field_lens(0),field_block_len(0), + table_name(0),db(0),fname(0) { if (!event_len) // derived class, will call copy_log_event() itself return; copy_log_event(buf, event_len, old_format); } +/***************************************************************************** + + Load_log_event::copy_log_event() + + ****************************************************************************/ int Load_log_event::copy_log_event(const char *buf, ulong event_len, bool old_format) { @@ -1225,8 +1297,12 @@ int Load_log_event::copy_log_event(const char *buf, ulong event_len, return 0; } -#ifdef MYSQL_CLIENT +/***************************************************************************** + Load_log_event::print() + + ****************************************************************************/ +#ifdef MYSQL_CLIENT void Load_log_event::print(FILE* file, bool short_form, char* last_db) { if (!short_form) @@ -1307,33 +1383,531 @@ void Load_log_event::print(FILE* file, bool short_form, char* last_db) fprintf(file, ";\n"); } - #endif /* #ifdef MYSQL_CLIENT */ -#ifndef MYSQL_CLIENT - -void Log_event::set_log_pos(MYSQL_LOG* log) -{ - if (!log_pos) - log_pos = my_b_tell(&log->log_file); -} +/***************************************************************************** + Load_log_event::set_fields() + ****************************************************************************/ +#ifndef MYSQL_CLIENT void Load_log_event::set_fields(List<Item> &field_list) { uint i; - const char *field= fields; + const char* field = fields; for (i= 0; i < num_fields; i++) { field_list.push_back(new Item_field(db, table_name, field)); field+= field_lens[i] + 1; } } +#endif // !MYSQL_CLIENT + +/***************************************************************************** + + Load_log_event::exec_event() + + ****************************************************************************/ +#ifndef MYSQL_CLIENT +int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli) +{ + init_sql_alloc(&thd->mem_root, 8192,0); + thd->db = rewrite_db((char*)db); + thd->query = 0; + thd->query_error = 0; + + if (db_ok(thd->db, replicate_do_db, replicate_ignore_db)) + { + thd->set_time((time_t)when); + thd->current_tablenr = 0; + VOID(pthread_mutex_lock(&LOCK_thread_count)); + thd->query_id = query_id++; + VOID(pthread_mutex_unlock(&LOCK_thread_count)); + + TABLE_LIST tables; + bzero((char*) &tables,sizeof(tables)); + tables.db = thd->db; + tables.alias = tables.real_name = (char*)table_name; + tables.lock_type = TL_WRITE; + // the table will be opened in mysql_load + if (table_rules_on && !tables_ok(thd, &tables)) + { + // TODO: this is a bug - this needs to be moved to the I/O thread + if (net) + skip_load_data_infile(net); + } + else + { + char llbuff[22]; + enum enum_duplicates handle_dup = DUP_IGNORE; + if (sql_ex.opt_flags && REPLACE_FLAG) + handle_dup = DUP_REPLACE; + sql_exchange ex((char*)fname, sql_ex.opt_flags && + DUMPFILE_FLAG ); + String field_term(sql_ex.field_term,sql_ex.field_term_len, + system_charset_info); + String enclosed(sql_ex.enclosed,sql_ex.enclosed_len, + system_charset_info); + String line_term(sql_ex.line_term,sql_ex.line_term_len, + system_charset_info); + String line_start(sql_ex.line_start,sql_ex.line_start_len, + system_charset_info); + String escaped(sql_ex.escaped,sql_ex.escaped_len, system_charset_info); + + ex.opt_enclosed = (sql_ex.opt_flags & OPT_ENCLOSED_FLAG); + if (sql_ex.empty_flags & FIELD_TERM_EMPTY) + ex.field_term->length(0); + + ex.skip_lines = skip_lines; + List<Item> field_list; + set_fields(field_list); + thd->slave_proxy_id = thd->thread_id; + if (net) + { + // mysql_load will use thd->net to read the file + thd->net.vio = net->vio; + /* + Make sure the client does not get confused about the packet sequence + */ + thd->net.pkt_nr = net->pkt_nr; + } + if (mysql_load(thd, &ex, &tables, field_list, handle_dup, net != 0, + TL_WRITE)) + thd->query_error = 1; + if (thd->cuted_fields) + sql_print_error("Slave: load data infile at position %s in log \ +'%s' produced %d warning(s)", llstr(rli->master_log_pos,llbuff), RPL_LOG_NAME, + thd->cuted_fields ); + if (net) + net->pkt_nr= thd->net.pkt_nr; + } + } + else + { + /* + We will just ask the master to send us /dev/null if we do not + want to load the data. + TODO: this a bug - needs to be done in I/O thread + */ + if (net) + skip_load_data_infile(net); + } + + thd->net.vio = 0; + thd->db= 0; // prevent db from being freed + close_thread_tables(thd); + if (thd->query_error) + { + int sql_error = thd->net.last_errno; + if (!sql_error) + sql_error = ER_UNKNOWN_ERROR; + + slave_print_error(rli,sql_error, + "Slave: Error '%s' running load data infile ", + ER_SAFE(sql_error)); + free_root(&thd->mem_root,0); + return 1; + } + free_root(&thd->mem_root,0); + + if (thd->fatal_error) + { + sql_print_error("Slave: Fatal error running LOAD DATA INFILE "); + return 1; + } + + return Log_event::exec_event(rli); +} +#endif // !MYSQL_CLIENT + + +/***************************************************************************** + ***************************************************************************** + + Rotate_log_event methods + ***************************************************************************** + ****************************************************************************/ +/***************************************************************************** + + Rotate_log_event::pack_info() + + ****************************************************************************/ +#ifndef MYSQL_CLIENT +void Rotate_log_event::pack_info(String* packet) +{ + char buf1[256], buf[22]; + String tmp(buf1, sizeof(buf1), system_charset_info); + tmp.length(0); + tmp.append(new_log_ident, ident_len); + tmp.append(";pos="); + tmp.append(llstr(pos,buf)); + if (flags & LOG_EVENT_FORCED_ROTATE_F) + tmp.append("; forced by master"); + net_store_data(packet, tmp.ptr(), tmp.length()); +} +#endif // !MYSQL_CLIENT + +/***************************************************************************** + + Rotate_log_event::print() + + ****************************************************************************/ +#ifdef MYSQL_CLIENT +void Rotate_log_event::print(FILE* file, bool short_form, char* last_db) +{ + char buf[22]; + if (short_form) + return; + + print_header(file); + fprintf(file, "\tRotate to "); + if (new_log_ident) + my_fwrite(file, (byte*) new_log_ident, (uint)ident_len, + MYF(MY_NABP | MY_WME)); + fprintf(file, " pos: %s", llstr(pos, buf)); + if (flags & LOG_EVENT_FORCED_ROTATE_F) + fprintf(file," forced by master"); + fputc('\n', file); + fflush(file); +} +#endif // MYSQL_CLIENT + +/***************************************************************************** + + Rotate_log_event::Rotate_log_event() + + ****************************************************************************/ +Rotate_log_event::Rotate_log_event(const char* buf, int event_len, + bool old_format) + :Log_event(buf, old_format),new_log_ident(NULL),alloced(0) +{ + // The caller will ensure that event_len is what we have at EVENT_LEN_OFFSET + int header_size = (old_format) ? OLD_HEADER_LEN : LOG_EVENT_HEADER_LEN; + uint ident_offset; + if (event_len < header_size) + return; + buf += header_size; + if (old_format) + { + ident_len = (uint)(event_len - OLD_HEADER_LEN); + pos = 4; + ident_offset = 0; + } + else + { + ident_len = (uint)(event_len - ROTATE_EVENT_OVERHEAD); + pos = uint8korr(buf + R_POS_OFFSET); + ident_offset = ROTATE_HEADER_LEN; + } + set_if_smaller(ident_len,FN_REFLEN-1); + if (!(new_log_ident= my_strdup_with_length((byte*) buf + + ident_offset, + (uint) ident_len, + MYF(MY_WME)))) + return; + alloced = 1; +} + +/***************************************************************************** + + Rotate_log_event::write_data() + + ****************************************************************************/ +int Rotate_log_event::write_data(IO_CACHE* file) +{ + char buf[ROTATE_HEADER_LEN]; + int8store(buf, pos + R_POS_OFFSET); + return (my_b_safe_write(file, (byte*)buf, ROTATE_HEADER_LEN) || + my_b_safe_write(file, (byte*)new_log_ident, (uint) ident_len)); +} + +/***************************************************************************** + + Rotate_log_event::exec_event() + + Got a rotate log even from the master + + IMPLEMENTATION + This is mainly used so that we can later figure out the logname and + position for the master. + + We can't rotate the slave as this will cause infinitive rotations + in a A -> B -> A setup. + + RETURN VALUES + 0 ok + + ****************************************************************************/ +#ifndef MYSQL_CLIENT +int Rotate_log_event::exec_event(struct st_relay_log_info* rli) +{ + char* log_name = rli->master_log_name; + DBUG_ENTER("Rotate_log_event::exec_event"); + + pthread_mutex_lock(&rli->data_lock); + memcpy(log_name, new_log_ident, ident_len+1); + rli->master_log_pos = pos; + rli->relay_log_pos += get_event_len(); + DBUG_PRINT("info", ("master_log_pos: %d", (ulong) rli->master_log_pos)); + pthread_mutex_unlock(&rli->data_lock); + pthread_cond_broadcast(&rli->data_cond); + flush_relay_log_info(rli); + DBUG_RETURN(0); +} +#endif // !MYSQL_CLIENT + + +/***************************************************************************** + ***************************************************************************** + + Intvar_log_event methods + + ***************************************************************************** + ****************************************************************************/ + +/***************************************************************************** + + Intvar_log_event::pack_info() + + ****************************************************************************/ +#ifndef MYSQL_CLIENT +void Intvar_log_event::pack_info(String* packet) +{ + char buf1[256], buf[22]; + String tmp(buf1, sizeof(buf1), system_charset_info); + tmp.length(0); + tmp.append(get_var_type_name()); + tmp.append('='); + tmp.append(llstr(val, buf)); + net_store_data(packet, tmp.ptr(), tmp.length()); +} +#endif // !MYSQL_CLIENT + +/***************************************************************************** + + Intvar_log_event::Intvar_log_event() + + ****************************************************************************/ +Intvar_log_event::Intvar_log_event(const char* buf, bool old_format) + :Log_event(buf, old_format) +{ + buf += (old_format) ? OLD_HEADER_LEN : LOG_EVENT_HEADER_LEN; + type = buf[I_TYPE_OFFSET]; + val = uint8korr(buf+I_VAL_OFFSET); +} + +/***************************************************************************** + + Intvar_log_event::get_var_type_name() + + ****************************************************************************/ +const char* Intvar_log_event::get_var_type_name() +{ + switch(type) { + case LAST_INSERT_ID_EVENT: return "LAST_INSERT_ID"; + case INSERT_ID_EVENT: return "INSERT_ID"; + default: /* impossible */ return "UNKNOWN"; + } +} + +/***************************************************************************** + + Intvar_log_event::write_data() + + ****************************************************************************/ +int Intvar_log_event::write_data(IO_CACHE* file) +{ + char buf[9]; + buf[I_TYPE_OFFSET] = type; + int8store(buf + I_VAL_OFFSET, val); + return my_b_safe_write(file, (byte*) buf, sizeof(buf)); +} + +/***************************************************************************** + + Intvar_log_event::print() + + ****************************************************************************/ +#ifdef MYSQL_CLIENT +void Intvar_log_event::print(FILE* file, bool short_form, char* last_db) +{ + char llbuff[22]; + const char *msg; + LINT_INIT(msg); + + if (!short_form) + { + print_header(file); + fprintf(file, "\tIntvar\n"); + } + + fprintf(file, "SET "); + switch (type) { + case LAST_INSERT_ID_EVENT: + msg="LAST_INSERT_ID"; + break; + case INSERT_ID_EVENT: + msg="INSERT_ID"; + break; + } + fprintf(file, "%s=%s;\n", msg, llstr(val,llbuff)); + fflush(file); +} +#endif // MYSQL_CLIENT + +/***************************************************************************** + + Intvar_log_event::exec_event() + + ****************************************************************************/ +#ifndef MYSQL_CLIENT +int Intvar_log_event::exec_event(struct st_relay_log_info* rli) +{ + switch (type) { + case LAST_INSERT_ID_EVENT: + thd->last_insert_id_used = 1; + thd->last_insert_id = val; + break; + case INSERT_ID_EVENT: + thd->next_insert_id = val; + break; + } + rli->inc_pending(get_event_len()); + return 0; +} +#endif // !MYSQL_CLIENT + + +/***************************************************************************** + ***************************************************************************** + + Rand_log_event methods + + ***************************************************************************** + ****************************************************************************/ + +/***************************************************************************** + + Rand_log_event::pack_info() + + ****************************************************************************/ +#ifndef MYSQL_CLIENT +void Rand_log_event::pack_info(String* packet) +{ + char buf1[256], *pos; + pos= strmov(buf1,"rand_seed1="); + pos= int10_to_str((long) seed1, pos, 10); + pos= strmov(pos, ",rand_seed2="); + pos= int10_to_str((long) seed2, pos, 10); + net_store_data(packet, buf1, (uint) (pos-buf1)); +} +#endif // !MYSQL_CLIENT + +/***************************************************************************** + + Rand_log_event::Rand_log_event() + + ****************************************************************************/ +Rand_log_event::Rand_log_event(const char* buf, bool old_format) + :Log_event(buf, old_format) +{ + buf += (old_format) ? OLD_HEADER_LEN : LOG_EVENT_HEADER_LEN; + seed1 = uint8korr(buf+RAND_SEED1_OFFSET); + seed2 = uint8korr(buf+RAND_SEED2_OFFSET); +} + +/***************************************************************************** + + Rand_log_event::write_data() + + ****************************************************************************/ +int Rand_log_event::write_data(IO_CACHE* file) +{ + char buf[16]; + int8store(buf + RAND_SEED1_OFFSET, seed1); + int8store(buf + RAND_SEED2_OFFSET, seed2); + return my_b_safe_write(file, (byte*) buf, sizeof(buf)); +} + +/***************************************************************************** + + Rand_log_event::print() + + ****************************************************************************/ +#ifdef MYSQL_CLIENT +void Rand_log_event::print(FILE* file, bool short_form, char* last_db) +{ + char llbuff[22]; + if (!short_form) + { + print_header(file); + fprintf(file, "\tRand\n"); + } + fprintf(file, "SET @@RAND_SEED1=%s, @@RAND_SEED2=%s;\n", + llstr(seed1, llbuff),llstr(seed2, llbuff)); + fflush(file); +} +#endif // MYSQL_CLIENT + +/***************************************************************************** + + Rand_log_event::exec_event() + + ****************************************************************************/ +#ifndef MYSQL_CLIENT +int Rand_log_event::exec_event(struct st_relay_log_info* rli) +{ + thd->rand.seed1= (ulong) seed1; + thd->rand.seed2= (ulong) seed2; + rli->inc_pending(get_event_len()); + return 0; +} +#endif // !MYSQL_CLIENT + + +/***************************************************************************** + ***************************************************************************** + + Slave_log_event methods + + ***************************************************************************** + ****************************************************************************/ + +/***************************************************************************** + + Slave_log_event::pack_info() + + ****************************************************************************/ +#ifndef MYSQL_CLIENT +void Slave_log_event::pack_info(String* packet) +{ + char buf1[256], buf[22], *end; + String tmp(buf1, sizeof(buf1), system_charset_info); + tmp.length(0); + tmp.append("host="); + tmp.append(master_host); + tmp.append(",port="); + end= int10_to_str((long) master_port, buf, 10); + tmp.append(buf, (uint32) (end-buf)); + tmp.append(",log="); + tmp.append(master_log); + tmp.append(",pos="); + tmp.append(llstr(master_pos,buf)); + net_store_data(packet, tmp.ptr(), tmp.length()); +} +#endif // !MYSQL_CLIENT + +/***************************************************************************** + + Slave_log_event::Slave_log_event() + + ****************************************************************************/ +#ifndef MYSQL_CLIENT Slave_log_event::Slave_log_event(THD* thd_arg, - struct st_relay_log_info* rli): - Log_event(thd_arg,0,0),mem_pool(0),master_host(0) + struct st_relay_log_info* rli) + :Log_event(thd_arg, 0, 0), mem_pool(0), master_host(0) { DBUG_ENTER("Slave_log_event"); if (!rli->inited) // QQ When can this happen ? @@ -1364,17 +1938,24 @@ Slave_log_event::Slave_log_event(THD* thd_arg, pthread_mutex_unlock(&mi->data_lock); DBUG_VOID_RETURN; } +#endif // !MYSQL_CLIENT -#endif /* ! MYSQL_CLIENT */ +/***************************************************************************** + Slave_log_event dtor + ****************************************************************************/ Slave_log_event::~Slave_log_event() { my_free(mem_pool, MYF(MY_ALLOW_ZERO_PTR)); } -#ifdef MYSQL_CLIENT +/***************************************************************************** + Slave_log_event::print() + + ****************************************************************************/ +#ifdef MYSQL_CLIENT void Slave_log_event::print(FILE* file, bool short_form, char* last_db) { char llbuff[22]; @@ -1386,14 +1967,23 @@ void Slave_log_event::print(FILE* file, bool short_form, char* last_db) master_log: '%s' master_pos: %s\n", master_host, master_port, master_log, llstr(master_pos, llbuff)); } +#endif // MYSQL_CLIENT -#endif /* MYSQL_CLIENT */ +/***************************************************************************** + + Slave_log_event::get_data_size() + ****************************************************************************/ int Slave_log_event::get_data_size() { return master_host_len + master_log_len + 1 + SL_MASTER_HOST_OFFSET; } +/***************************************************************************** + + Slave_log_event::write_data() + + ****************************************************************************/ int Slave_log_event::write_data(IO_CACHE* file) { int8store(mem_pool + SL_MASTER_POS_OFFSET, master_pos); @@ -1402,7 +1992,11 @@ int Slave_log_event::write_data(IO_CACHE* file) return my_b_safe_write(file, (byte*)mem_pool, get_data_size()); } +/***************************************************************************** + + Slave_log_event::init_from_mem_pool() + ****************************************************************************/ void Slave_log_event::init_from_mem_pool(int data_size) { master_pos = uint8korr(mem_pool + SL_MASTER_POS_OFFSET); @@ -1419,6 +2013,11 @@ void Slave_log_event::init_from_mem_pool(int data_size) master_log_len = strlen(master_log); } +/***************************************************************************** + + Slave_log_event::Slave_log_event() + + ****************************************************************************/ Slave_log_event::Slave_log_event(const char* buf, int event_len) :Log_event(buf,0),mem_pool(0),master_host(0) { @@ -1432,6 +2031,93 @@ Slave_log_event::Slave_log_event(const char* buf, int event_len) init_from_mem_pool(event_len); } +/***************************************************************************** + + Slave_log_event::exec_event() + + ****************************************************************************/ +#ifndef MYSQL_CLIENT +int Slave_log_event::exec_event(struct st_relay_log_info* rli) +{ + if (mysql_bin_log.is_open()) + mysql_bin_log.write(this); + return Log_event::exec_event(rli); +} +#endif // !MYSQL_CLIENT + + +/***************************************************************************** + ***************************************************************************** + + Stop_log_event methods + + ***************************************************************************** + ****************************************************************************/ + +/***************************************************************************** + + Stop_log_event::print() + + ****************************************************************************/ +#ifdef MYSQL_CLIENT +void Stop_log_event::print(FILE* file, bool short_form, char* last_db) +{ + if (short_form) + return; + + print_header(file); + fprintf(file, "\tStop\n"); + fflush(file); +} +#endif // MYSQL_CLIENT + +/***************************************************************************** + + Stop_log_event::exec_event() + + The master stopped. Clean up all temporary tables + locks that the + master may have set. + + TODO + - Remove all active user locks + + ****************************************************************************/ +#ifndef MYSQL_CLIENT +int Stop_log_event::exec_event(struct st_relay_log_info* rli) +{ + // do not clean up immediately after rotate event + if (rli->master_log_pos > BIN_LOG_HEADER_SIZE) + { + close_temporary_tables(thd); + cleanup_load_tmpdir(); + } + /* + We do not want to update master_log pos because we get a rotate event + before stop, so by now master_log_name is set to the next log. + If we updated it, we will have incorrect master coordinates and this + could give false triggers in MASTER_POS_WAIT() that we have reached + the target position when in fact we have not. + */ + rli->inc_pos(get_event_len(), 0); + flush_relay_log_info(rli); + return 0; +} +#endif // !MYSQL_CLIENT + + +/***************************************************************************** + ***************************************************************************** + + Create_file_log_event methods + + ***************************************************************************** + ****************************************************************************/ + +/***************************************************************************** + + Create_file_log_event ctor + + ****************************************************************************/ #ifndef MYSQL_CLIENT Create_file_log_event:: Create_file_log_event(THD* thd_arg, sql_exchange* ex, @@ -1445,8 +2131,13 @@ Create_file_log_event(THD* thd_arg, sql_exchange* ex, { sql_ex.force_new_format(); } -#endif +#endif // !MYSQL_CLIENT +/***************************************************************************** + + Create_file_log_event::write_data_body() + + ****************************************************************************/ int Create_file_log_event::write_data_body(IO_CACHE* file) { int res; @@ -1456,6 +2147,11 @@ int Create_file_log_event::write_data_body(IO_CACHE* file) my_b_safe_write(file, (byte*) block, block_len)); } +/***************************************************************************** + + Create_file_log_event::write_data_header() + + ****************************************************************************/ int Create_file_log_event::write_data_header(IO_CACHE* file) { int res; @@ -1466,6 +2162,11 @@ int Create_file_log_event::write_data_header(IO_CACHE* file) return my_b_safe_write(file, buf, CREATE_FILE_HEADER_LEN); } +/***************************************************************************** + + Create_file_log_event::write_base() + + ****************************************************************************/ int Create_file_log_event::write_base(IO_CACHE* file) { int res; @@ -1475,6 +2176,11 @@ int Create_file_log_event::write_base(IO_CACHE* file) return res; } +/***************************************************************************** + + Create_file_log_event ctor + + ****************************************************************************/ Create_file_log_event::Create_file_log_event(const char* buf, int len, bool old_format) :Load_log_event(buf,0,old_format),fake_base(0),block(0),inited_from_old(0) @@ -1501,7 +2207,11 @@ Create_file_log_event::Create_file_log_event(const char* buf, int len, } } +/***************************************************************************** + + Create_file_log_event::print() + ****************************************************************************/ #ifdef MYSQL_CLIENT void Create_file_log_event::print(FILE* file, bool short_form, char* last_db) @@ -1511,13 +2221,18 @@ void Create_file_log_event::print(FILE* file, bool short_form, Load_log_event::print(file, 1, last_db); fprintf(file, " file_id: %d block_len: %d\n", file_id, block_len); } -#endif +#endif // MYSQL_CLIENT + +/***************************************************************************** + + Create_file_log_event::pack_info() + ****************************************************************************/ #ifndef MYSQL_CLIENT void Create_file_log_event::pack_info(String* packet) { char buf1[256],buf[22], *end; - String tmp(buf1, sizeof(buf1)); + String tmp(buf1, sizeof(buf1), system_charset_info); tmp.length(0); tmp.append("db="); tmp.append(db, db_len); @@ -1531,8 +2246,86 @@ void Create_file_log_event::pack_info(String* packet) tmp.append(buf, (uint32) (end-buf)); net_store_data(packet, (char*) tmp.ptr(), tmp.length()); } -#endif +#endif // !MYSQL_CLIENT + +/***************************************************************************** + + Create_file_log_event::exec_event() + + ****************************************************************************/ +#ifndef MYSQL_CLIENT +int Create_file_log_event::exec_event(struct st_relay_log_info* rli) +{ + char fname_buf[FN_REFLEN+10]; + char *p; + int fd = -1; + IO_CACHE file; + int error = 1; + + bzero((char*)&file, sizeof(file)); + p = slave_load_file_stem(fname_buf, file_id, server_id); + strmov(p, ".info"); // strmov takes less code than memcpy + if ((fd = my_open(fname_buf, O_WRONLY|O_CREAT|O_BINARY|O_TRUNC, + MYF(MY_WME))) < 0 || + init_io_cache(&file, fd, IO_SIZE, WRITE_CACHE, (my_off_t)0, 0, + MYF(MY_WME|MY_NABP))) + { + slave_print_error(rli,my_errno, "Could not open file '%s'", fname_buf); + goto err; + } + + // a trick to avoid allocating another buffer + strmov(p, ".data"); + fname = fname_buf; + fname_len = (uint)(p-fname) + 5; + if (write_base(&file)) + { + strmov(p, ".info"); // to have it right in the error message + slave_print_error(rli,my_errno, "Could not write to file '%s'", fname_buf); + goto err; + } + end_io_cache(&file); + my_close(fd, MYF(0)); + + // fname_buf now already has .data, not .info, because we did our trick + if ((fd = my_open(fname_buf, O_WRONLY|O_CREAT|O_BINARY|O_TRUNC, + MYF(MY_WME))) < 0) + { + slave_print_error(rli,my_errno, "Could not open file '%s'", fname_buf); + goto err; + } + if (my_write(fd, (byte*) block, block_len, MYF(MY_WME+MY_NABP))) + { + slave_print_error(rli,my_errno, "Write to '%s' failed", fname_buf); + goto err; + } + if (mysql_bin_log.is_open()) + mysql_bin_log.write(this); + error=0; // Everything is ok + +err: + if (error) + end_io_cache(&file); + if (fd >= 0) + my_close(fd, MYF(0)); + return error ? 1 : Log_event::exec_event(rli); +} +#endif // !MYSQL_CLIENT + + +/***************************************************************************** + ***************************************************************************** + + Append_block_log_event methods + + ***************************************************************************** + ****************************************************************************/ + +/***************************************************************************** + Append_block_log_event ctor + + ****************************************************************************/ #ifndef MYSQL_CLIENT Append_block_log_event::Append_block_log_event(THD* thd_arg, char* block_arg, uint block_len_arg, @@ -1541,8 +2334,13 @@ Append_block_log_event::Append_block_log_event(THD* thd_arg, char* block_arg, block_len(block_len_arg), file_id(thd_arg->file_id) { } -#endif - +#endif // !MYSQL_CLIENT + +/***************************************************************************** + + Append_block_log_event ctor + + ****************************************************************************/ Append_block_log_event::Append_block_log_event(const char* buf, int len) :Log_event(buf, 0),block(0) { @@ -1553,6 +2351,11 @@ Append_block_log_event::Append_block_log_event(const char* buf, int len) block_len = len - APPEND_BLOCK_EVENT_OVERHEAD; } +/***************************************************************************** + + Append_block_log_event::write_data() + + ****************************************************************************/ int Append_block_log_event::write_data(IO_CACHE* file) { byte buf[APPEND_BLOCK_HEADER_LEN]; @@ -1561,6 +2364,11 @@ int Append_block_log_event::write_data(IO_CACHE* file) my_b_safe_write(file, (byte*) block, block_len)); } +/***************************************************************************** + + Append_block_log_event::print() + + ****************************************************************************/ #ifdef MYSQL_CLIENT void Append_block_log_event::print(FILE* file, bool short_form, char* last_db) @@ -1572,23 +2380,86 @@ void Append_block_log_event::print(FILE* file, bool short_form, fprintf(file, "#Append_block: file_id: %d block_len: %d\n", file_id, block_len); } -#endif +#endif // MYSQL_CLIENT +/***************************************************************************** + + Append_block_log_event::pack_info() + + ****************************************************************************/ #ifndef MYSQL_CLIENT void Append_block_log_event::pack_info(String* packet) { - char buf1[256]; - sprintf(buf1, ";file_id=%u;block_len=%u", file_id, block_len); - net_store_data(packet, buf1); + char buf[256]; + uint length; + length= (uint) my_sprintf(buf, + (buf, ";file_id=%u;block_len=%u", file_id, + block_len)); + net_store_data(packet, buf, (int32) length); } +#endif // !MYSQL_CLIENT -Delete_file_log_event::Delete_file_log_event(THD* thd_arg, bool using_trans) - :Log_event(thd_arg, 0, using_trans), file_id(thd_arg->file_id) +/***************************************************************************** + + Append_block_log_event::exec_event() + + ****************************************************************************/ +#ifndef MYSQL_CLIENT +int Append_block_log_event::exec_event(struct st_relay_log_info* rli) { + char fname[FN_REFLEN+10]; + char *p= slave_load_file_stem(fname, file_id, server_id); + int fd; + int error = 1; + + memcpy(p, ".data", 6); + if ((fd = my_open(fname, O_WRONLY|O_APPEND|O_BINARY, MYF(MY_WME))) < 0) + { + slave_print_error(rli,my_errno, "Could not open file '%s'", fname); + goto err; + } + if (my_write(fd, (byte*) block, block_len, MYF(MY_WME+MY_NABP))) + { + slave_print_error(rli,my_errno, "Write to '%s' failed", fname); + goto err; + } + if (mysql_bin_log.is_open()) + mysql_bin_log.write(this); + error=0; + +err: + if (fd >= 0) + my_close(fd, MYF(0)); + return error ? error : Log_event::exec_event(rli); } -#endif +#endif // !MYSQL_CLIENT + + +/***************************************************************************** + ***************************************************************************** + + Delete_file_log_event methods + + ***************************************************************************** + ****************************************************************************/ + +/***************************************************************************** + Delete_file_log_event ctor + ****************************************************************************/ +#ifndef MYSQL_CLIENT +Delete_file_log_event::Delete_file_log_event(THD *thd_arg, bool using_trans) + :Log_event(thd_arg, 0, using_trans),file_id(thd_arg->file_id) +{ +} +#endif // !MYSQL_CLIENT + +/***************************************************************************** + + Delete_file_log_event ctor + + ****************************************************************************/ Delete_file_log_event::Delete_file_log_event(const char* buf, int len) :Log_event(buf, 0),file_id(0) { @@ -1597,7 +2468,11 @@ Delete_file_log_event::Delete_file_log_event(const char* buf, int len) file_id = uint4korr(buf + LOG_EVENT_HEADER_LEN + AB_FILE_ID_OFFSET); } +/***************************************************************************** + + Delete_file_log_event::write_data() + ****************************************************************************/ int Delete_file_log_event::write_data(IO_CACHE* file) { byte buf[DELETE_FILE_HEADER_LEN]; @@ -1605,6 +2480,11 @@ int Delete_file_log_event::write_data(IO_CACHE* file) return my_b_safe_write(file, buf, DELETE_FILE_HEADER_LEN); } +/***************************************************************************** + + Delete_file_log_event::print() + + ****************************************************************************/ #ifdef MYSQL_CLIENT void Delete_file_log_event::print(FILE* file, bool short_form, char* last_db) @@ -1615,25 +2495,69 @@ void Delete_file_log_event::print(FILE* file, bool short_form, fputc('\n', file); fprintf(file, "#Delete_file: file_id=%u\n", file_id); } -#endif +#endif // MYSQL_CLIENT + +/***************************************************************************** + + Delete_file_log_event::pack_info() + ****************************************************************************/ #ifndef MYSQL_CLIENT void Delete_file_log_event::pack_info(String* packet) { - char buf1[64]; - sprintf(buf1, ";file_id=%u", (uint) file_id); - net_store_data(packet, buf1); + char buf[64]; + uint length; + length= (uint) my_sprintf(buf, (buf, ";file_id=%u", (uint) file_id)); + net_store_data(packet, buf, (int32) length); } -#endif +#endif // !MYSQL_CLIENT + +/***************************************************************************** + + Delete_file_log_event::exec_event() + + ****************************************************************************/ +#ifndef MYSQL_CLIENT +int Delete_file_log_event::exec_event(struct st_relay_log_info* rli) +{ + char fname[FN_REFLEN+10]; + char *p= slave_load_file_stem(fname, file_id, server_id); + memcpy(p, ".data", 6); + (void) my_delete(fname, MYF(MY_WME)); + memcpy(p, ".info", 6); + (void) my_delete(fname, MYF(MY_WME)); + if (mysql_bin_log.is_open()) + mysql_bin_log.write(this); + return Log_event::exec_event(rli); +} +#endif // !MYSQL_CLIENT + + +/***************************************************************************** + ***************************************************************************** + + Execute_load_log_event methods + + ***************************************************************************** + ****************************************************************************/ + +/***************************************************************************** + Execute_load_log_event ctor + ****************************************************************************/ #ifndef MYSQL_CLIENT -Execute_load_log_event::Execute_load_log_event(THD* thd_arg, bool using_trans) +Execute_load_log_event::Execute_load_log_event(THD *thd_arg, bool using_trans) :Log_event(thd_arg, 0, using_trans), file_id(thd_arg->file_id) { } -#endif +#endif // !MYSQL_CLIENT +/***************************************************************************** + + Execute_load_log_event ctor + + ****************************************************************************/ Execute_load_log_event::Execute_load_log_event(const char* buf, int len) :Log_event(buf, 0), file_id(0) { @@ -1642,6 +2566,11 @@ Execute_load_log_event::Execute_load_log_event(const char* buf, int len) file_id = uint4korr(buf + LOG_EVENT_HEADER_LEN + EL_FILE_ID_OFFSET); } +/***************************************************************************** + + Execute_load_log_event::write_data() + + ****************************************************************************/ int Execute_load_log_event::write_data(IO_CACHE* file) { byte buf[EXEC_LOAD_HEADER_LEN]; @@ -1649,6 +2578,11 @@ int Execute_load_log_event::write_data(IO_CACHE* file) return my_b_safe_write(file, buf, EXEC_LOAD_HEADER_LEN); } +/***************************************************************************** + + Execute_load_log_event::print() + + ****************************************************************************/ #ifdef MYSQL_CLIENT void Execute_load_log_event::print(FILE* file, bool short_form, char* last_db) @@ -1660,426 +2594,29 @@ void Execute_load_log_event::print(FILE* file, bool short_form, fprintf(file, "#Exec_load: file_id=%d\n", file_id); } -#endif -#ifndef MYSQL_CLIENT -void Execute_load_log_event::pack_info(String* packet) -{ - char buf[64]; - sprintf(buf, ";file_id=%u", (uint) file_id); - net_store_data(packet, buf); -} -#endif - -#ifndef MYSQL_CLIENT -int Query_log_event::exec_event(struct st_relay_log_info* rli) -{ - int expected_error,actual_error = 0; - init_sql_alloc(&thd->mem_root, 8192,0); - thd->db = rewrite_db((char*)db); - - /* - InnoDB internally stores the master log position it has processed so far; - position to store is really pos + pending + event_len - since we must store the pos of the END of the current log event - */ - rli->event_len= get_event_len(); - - if (db_ok(thd->db, replicate_do_db, replicate_ignore_db)) - { - thd->query = (char*)query; - thd->set_time((time_t)when); - thd->current_tablenr = 0; - VOID(pthread_mutex_lock(&LOCK_thread_count)); - thd->query_id = query_id++; - VOID(pthread_mutex_unlock(&LOCK_thread_count)); - thd->query_error = 0; // clear error - thd->net.last_errno = 0; - thd->net.last_error[0] = 0; - thd->slave_proxy_id = thread_id; // for temp tables - - /* - Sanity check to make sure the master did not get a really bad - error on the query. - */ - if (ignored_error_code((expected_error = error_code)) || - !check_expected_error(thd,rli,expected_error)) - { - mysql_log.write(thd,COM_QUERY,"%s",thd->query); - DBUG_PRINT("query",("%s",thd->query)); - mysql_parse(thd, thd->query, q_len); - if ((expected_error != (actual_error = thd->net.last_errno)) && - expected_error && - !ignored_error_code(actual_error) && - !ignored_error_code(expected_error)) - { - const char* errmsg = "Slave: did not get the expected error\ - running query from master - expected: '%s' (%d), got '%s' (%d)"; - sql_print_error(errmsg, ER_SAFE(expected_error), - expected_error, - actual_error ? thd->net.last_error: "no error", - actual_error); - thd->query_error = 1; - } - else if (expected_error == actual_error || - ignored_error_code(actual_error)) - { - thd->query_error = 0; - *rli->last_slave_error = 0; - rli->last_slave_errno = 0; - } - } - else - { - // master could be inconsistent, abort and tell DBA to check/fix it - thd->db = thd->query = 0; - thd->variables.convert_set = 0; - close_thread_tables(thd); - free_root(&thd->mem_root,0); - return 1; - } - } - thd->db= 0; // prevent db from being freed - thd->query= 0; // just to be sure - // assume no convert for next query unless set explictly - thd->variables.convert_set = 0; - close_thread_tables(thd); - - if (thd->query_error || thd->fatal_error) - { - slave_print_error(rli,actual_error, "error '%s' on query '%s'", - actual_error ? thd->net.last_error : - "unexpected success or fatal error", query); - free_root(&thd->mem_root,0); - return 1; - } - free_root(&thd->mem_root,0); - return Log_event::exec_event(rli); -} - - -int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli) -{ - init_sql_alloc(&thd->mem_root, 8192,0); - thd->db = rewrite_db((char*)db); - thd->query = 0; - thd->query_error = 0; - - if (db_ok(thd->db, replicate_do_db, replicate_ignore_db)) - { - thd->set_time((time_t)when); - thd->current_tablenr = 0; - VOID(pthread_mutex_lock(&LOCK_thread_count)); - thd->query_id = query_id++; - VOID(pthread_mutex_unlock(&LOCK_thread_count)); - - TABLE_LIST tables; - bzero((char*) &tables,sizeof(tables)); - tables.db = thd->db; - tables.alias = tables.real_name = (char*)table_name; - tables.lock_type = TL_WRITE; - // the table will be opened in mysql_load - if (table_rules_on && !tables_ok(thd, &tables)) - { - // TODO: this is a bug - this needs to be moved to the I/O thread - if (net) - skip_load_data_infile(net); - } - else - { - char llbuff[22]; - enum enum_duplicates handle_dup = DUP_IGNORE; - if (sql_ex.opt_flags && REPLACE_FLAG) - handle_dup = DUP_REPLACE; - sql_exchange ex((char*)fname, sql_ex.opt_flags && - DUMPFILE_FLAG ); - String field_term(sql_ex.field_term,sql_ex.field_term_len); - String enclosed(sql_ex.enclosed,sql_ex.enclosed_len); - String line_term(sql_ex.line_term,sql_ex.line_term_len); - String line_start(sql_ex.line_start,sql_ex.line_start_len); - String escaped(sql_ex.escaped,sql_ex.escaped_len); - - ex.opt_enclosed = (sql_ex.opt_flags & OPT_ENCLOSED_FLAG); - if (sql_ex.empty_flags & FIELD_TERM_EMPTY) - ex.field_term->length(0); - - ex.skip_lines = skip_lines; - List<Item> field_list; - set_fields(field_list); - thd->slave_proxy_id = thd->thread_id; - if (net) - { - // mysql_load will use thd->net to read the file - thd->net.vio = net->vio; - /* - Make sure the client does not get confused about the packet sequence - */ - thd->net.pkt_nr = net->pkt_nr; - } - if (mysql_load(thd, &ex, &tables, field_list, handle_dup, net != 0, - TL_WRITE)) - thd->query_error = 1; - if (thd->cuted_fields) - sql_print_error("Slave: load data infile at position %s in log \ -'%s' produced %d warning(s)", llstr(rli->master_log_pos,llbuff), RPL_LOG_NAME, - thd->cuted_fields ); - if (net) - net->pkt_nr= thd->net.pkt_nr; - } - } - else - { - /* - We will just ask the master to send us /dev/null if we do not - want to load the data. - TODO: this a bug - needs to be done in I/O thread - */ - if (net) - skip_load_data_infile(net); - } - - thd->net.vio = 0; - thd->db= 0; // prevent db from being freed - close_thread_tables(thd); - if (thd->query_error) - { - int sql_error = thd->net.last_errno; - if (!sql_error) - sql_error = ER_UNKNOWN_ERROR; - - slave_print_error(rli,sql_error, - "Slave: Error '%s' running load data infile ", - ER_SAFE(sql_error)); - free_root(&thd->mem_root,0); - return 1; - } - free_root(&thd->mem_root,0); - - if (thd->fatal_error) - { - sql_print_error("Slave: Fatal error running LOAD DATA INFILE "); - return 1; - } - - return Log_event::exec_event(rli); -} - - -/* - The master started - - IMPLEMENTATION - - To handle the case where the master died without a stop event, - we clean up all temporary tables + locks that we got. - - TODO - - Remove all active user locks - - If we have an active transaction at this point, the master died - in the middle while writing the transaction to the binary log. - In this case we should stop the slave. -*/ - -int Start_log_event::exec_event(struct st_relay_log_info* rli) -{ - /* All temporary tables was deleted on the master */ - close_temporary_tables(thd); - /* - If we have old format, load_tmpdir is cleaned up by the I/O thread - */ - if (!rli->mi->old_format) - cleanup_load_tmpdir(); - return Log_event::exec_event(rli); -} - - -/* - The master stopped. Clean up all temporary tables + locks that the - master may have set. - - TODO - - Remove all active user locks -*/ - -int Stop_log_event::exec_event(struct st_relay_log_info* rli) -{ - // do not clean up immediately after rotate event - if (rli->master_log_pos > BIN_LOG_HEADER_SIZE) - { - close_temporary_tables(thd); - cleanup_load_tmpdir(); - } - /* - We do not want to update master_log pos because we get a rotate event - before stop, so by now master_log_name is set to the next log. - If we updated it, we will have incorrect master coordinates and this - could give false triggers in MASTER_POS_WAIT() that we have reached - the target position when in fact we have not. - */ - rli->inc_pos(get_event_len(), 0); - flush_relay_log_info(rli); - return 0; -} - - -/* - Got a rotate log even from the master - - IMPLEMENTATION - This is mainly used so that we can later figure out the logname and - position for the master. - - We can't rotate the slave as this will cause infinitive rotations - in a A -> B -> A setup. - - RETURN VALUES - 0 ok - */ - - -int Rotate_log_event::exec_event(struct st_relay_log_info* rli) -{ - char* log_name = rli->master_log_name; - DBUG_ENTER("Rotate_log_event::exec_event"); - - pthread_mutex_lock(&rli->data_lock); - memcpy(log_name, new_log_ident, ident_len+1); - rli->master_log_pos = pos; - rli->relay_log_pos += get_event_len(); - DBUG_PRINT("info", ("master_log_pos: %d", (ulong) rli->master_log_pos)); - pthread_mutex_unlock(&rli->data_lock); - pthread_cond_broadcast(&rli->data_cond); - flush_relay_log_info(rli); - DBUG_RETURN(0); -} - - -int Intvar_log_event::exec_event(struct st_relay_log_info* rli) -{ - switch (type) { - case LAST_INSERT_ID_EVENT: - thd->last_insert_id_used = 1; - thd->last_insert_id = val; - break; - case INSERT_ID_EVENT: - thd->next_insert_id = val; - break; - } - rli->inc_pending(get_event_len()); - return 0; -} - -int Rand_log_event::exec_event(struct st_relay_log_info* rli) -{ - thd->rand.seed1 = (ulong) seed1; - thd->rand.seed2 = (ulong) seed2; - rli->inc_pending(get_event_len()); - return 0; -} - -int Slave_log_event::exec_event(struct st_relay_log_info* rli) -{ - if (mysql_bin_log.is_open()) - mysql_bin_log.write(this); - return Log_event::exec_event(rli); -} - -int Create_file_log_event::exec_event(struct st_relay_log_info* rli) -{ - char fname_buf[FN_REFLEN+10]; - char *p; - int fd = -1; - IO_CACHE file; - int error = 1; +#endif // MYSQL_CLIENT - bzero((char*)&file, sizeof(file)); - p = slave_load_file_stem(fname_buf, file_id, server_id); - strmov(p, ".info"); // strmov takes less code than memcpy - if ((fd = my_open(fname_buf, O_WRONLY|O_CREAT|O_BINARY|O_TRUNC, - MYF(MY_WME))) < 0 || - init_io_cache(&file, fd, IO_SIZE, WRITE_CACHE, (my_off_t)0, 0, - MYF(MY_WME|MY_NABP))) - { - slave_print_error(rli,my_errno, "Could not open file '%s'", fname_buf); - goto err; - } - - // a trick to avoid allocating another buffer - strmov(p, ".data"); - fname = fname_buf; - fname_len = (uint)(p-fname) + 5; - if (write_base(&file)) - { - strmov(p, ".info"); // to have it right in the error message - slave_print_error(rli,my_errno, "Could not write to file '%s'", fname_buf); - goto err; - } - end_io_cache(&file); - my_close(fd, MYF(0)); - - // fname_buf now already has .data, not .info, because we did our trick - if ((fd = my_open(fname_buf, O_WRONLY|O_CREAT|O_BINARY|O_TRUNC, - MYF(MY_WME))) < 0) - { - slave_print_error(rli,my_errno, "Could not open file '%s'", fname_buf); - goto err; - } - if (my_write(fd, (byte*) block, block_len, MYF(MY_WME+MY_NABP))) - { - slave_print_error(rli,my_errno, "Write to '%s' failed", fname_buf); - goto err; - } - if (mysql_bin_log.is_open()) - mysql_bin_log.write(this); - error=0; // Everything is ok +/***************************************************************************** -err: - if (error) - end_io_cache(&file); - if (fd >= 0) - my_close(fd, MYF(0)); - return error ? 1 : Log_event::exec_event(rli); -} + Execute_load_log_event::pack_info() -int Delete_file_log_event::exec_event(struct st_relay_log_info* rli) + ****************************************************************************/ +#ifndef MYSQL_CLIENT +void Execute_load_log_event::pack_info(String* packet) { - char fname[FN_REFLEN+10]; - char *p= slave_load_file_stem(fname, file_id, server_id); - memcpy(p, ".data", 6); - (void) my_delete(fname, MYF(MY_WME)); - memcpy(p, ".info", 6); - (void) my_delete(fname, MYF(MY_WME)); - if (mysql_bin_log.is_open()) - mysql_bin_log.write(this); - return Log_event::exec_event(rli); + char buf[64]; + uint length; + length= (uint) my_sprintf(buf, (buf, ";file_id=%u", (uint) file_id)); + net_store_data(packet, buf, (int32) length); } +#endif // !MYSQL_CLIENT -int Append_block_log_event::exec_event(struct st_relay_log_info* rli) -{ - char fname[FN_REFLEN+10]; - char *p= slave_load_file_stem(fname, file_id, server_id); - int fd; - int error = 1; - - memcpy(p, ".data", 6); - if ((fd = my_open(fname, O_WRONLY|O_APPEND|O_BINARY, MYF(MY_WME))) < 0) - { - slave_print_error(rli,my_errno, "Could not open file '%s'", fname); - goto err; - } - if (my_write(fd, (byte*) block, block_len, MYF(MY_WME+MY_NABP))) - { - slave_print_error(rli,my_errno, "Write to '%s' failed", fname); - goto err; - } - if (mysql_bin_log.is_open()) - mysql_bin_log.write(this); - error=0; +/***************************************************************************** -err: - if (fd >= 0) - my_close(fd, MYF(0)); - return error ? error : Log_event::exec_event(rli); -} + Execute_load_log_event::exec_event() + ****************************************************************************/ +#ifndef MYSQL_CLIENT int Execute_load_log_event::exec_event(struct st_relay_log_info* rli) { char fname[FN_REFLEN+10]; @@ -2138,5 +2675,100 @@ err: } return error ? error : Log_event::exec_event(rli); } +#endif // !MYSQL_CLIENT + + +/***************************************************************************** + ***************************************************************************** + + sql_ex_info methods + + ***************************************************************************** + ****************************************************************************/ + +/***************************************************************************** + + sql_ex_info::write_data() + + ****************************************************************************/ +int sql_ex_info::write_data(IO_CACHE* file) +{ + if (new_format()) + { + return (write_str(file, field_term, field_term_len) || + write_str(file, enclosed, enclosed_len) || + write_str(file, line_term, line_term_len) || + write_str(file, line_start, line_start_len) || + write_str(file, escaped, escaped_len) || + my_b_safe_write(file,(byte*) &opt_flags,1)); + } + else + { + old_sql_ex old_ex; + old_ex.field_term= *field_term; + old_ex.enclosed= *enclosed; + old_ex.line_term= *line_term; + old_ex.line_start= *line_start; + old_ex.escaped= *escaped; + old_ex.opt_flags= opt_flags; + old_ex.empty_flags=empty_flags; + return my_b_safe_write(file, (byte*) &old_ex, sizeof(old_ex)); + } +} + +/***************************************************************************** + + sql_ex_info::init() + + ****************************************************************************/ +char* sql_ex_info::init(char* buf,char* buf_end,bool use_new_format) +{ + cached_new_format = use_new_format; + if (use_new_format) + { + empty_flags=0; + /* + The code below assumes that buf will not disappear from + under our feet during the lifetime of the event. This assumption + holds true in the slave thread if the log is in new format, but is not + the case when we have old format because we will be reusing net buffer + to read the actual file before we write out the Create_file event. + */ + if (read_str(buf, buf_end, field_term, field_term_len) || + read_str(buf, buf_end, enclosed, enclosed_len) || + read_str(buf, buf_end, line_term, line_term_len) || + read_str(buf, buf_end, line_start, line_start_len) || + read_str(buf, buf_end, escaped, escaped_len)) + return 0; + opt_flags = *buf++; + } + else + { + field_term_len= enclosed_len= line_term_len= line_start_len= escaped_len=1; + field_term = buf++; // Use first byte in string + enclosed= buf++; + line_term= buf++; + line_start= buf++; + escaped= buf++; + opt_flags = *buf++; + empty_flags= *buf++; + if (empty_flags & FIELD_TERM_EMPTY) + field_term_len=0; + if (empty_flags & ENCLOSED_EMPTY) + enclosed_len=0; + if (empty_flags & LINE_TERM_EMPTY) + line_term_len=0; + if (empty_flags & LINE_START_EMPTY) + line_start_len=0; + if (empty_flags & ESCAPED_EMPTY) + escaped_len=0; + } + return buf; +} + + + + + + -#endif /* !MYSQL_CLIENT */ diff --git a/sql/log_event.h b/sql/log_event.h index 69a70d535ec..20a134ab3cc 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -54,6 +54,11 @@ #define LINE_START_EMPTY 0x8 #define ESCAPED_EMPTY 0x10 +/***************************************************************************** + + old_sql_ex struct + + ****************************************************************************/ struct old_sql_ex { char field_term; @@ -67,6 +72,11 @@ struct old_sql_ex #define NUM_LOAD_DELIM_STRS 5 +/***************************************************************************** + + sql_ex_info struct + + ****************************************************************************/ struct sql_ex_info { char* field_term; @@ -99,13 +109,19 @@ struct sql_ex_info } }; -/* - Binary log consists of events. Each event has a fixed length header, - followed by possibly variable ( depending on the type of event) length - data body. The data body consists of an optional fixed length segment - (post-header), and an optional variable length segment. See #defines and - comments below for the format specifics -*/ +/***************************************************************************** + + MySQL Binary Log + + This log consists of events. Each event has a fixed-length header, + possibly followed by a variable length data body. + + The data body consists of an optional fixed length segment (post-header) + and an optional variable length segment. + + See the #defines below for the format specifics. + + ****************************************************************************/ /* event-specific post-header sizes */ #define LOG_EVENT_HEADER_LEN 19 @@ -221,6 +237,13 @@ class THD; struct st_relay_log_info; +/***************************************************************************** + + Log_event class + + This is the abstract base class for binary log events. + + ****************************************************************************/ class Log_event { public: @@ -304,6 +327,13 @@ public: }; +/***************************************************************************** + + Query Log Event class + + Logs SQL queries + + ****************************************************************************/ class Query_log_event: public Log_event { protected: @@ -354,6 +384,11 @@ public: }; +/***************************************************************************** + + Slave Log Event class + + ****************************************************************************/ class Slave_log_event: public Log_event { protected: @@ -383,6 +418,12 @@ public: int write_data(IO_CACHE* file ); }; + +/***************************************************************************** + + Load Log Event class + + ****************************************************************************/ class Load_log_event: public Log_event { protected: @@ -448,6 +489,11 @@ public: extern char server_version[SERVER_VERSION_LENGTH]; +/***************************************************************************** + + Start Log Event class + + ****************************************************************************/ class Start_log_event: public Log_event { public: @@ -479,6 +525,13 @@ public: }; +/***************************************************************************** + + Intvar Log Event class + + Logs special variables such as auto_increment values + + ****************************************************************************/ class Intvar_log_event: public Log_event { public: @@ -505,9 +558,11 @@ public: }; /***************************************************************************** - * - * Rand log event class - * + + Rand Log Event class + + Logs random seed used by the next RAND() + ****************************************************************************/ class Rand_log_event: public Log_event { @@ -534,10 +589,15 @@ class Rand_log_event: public Log_event }; +/***************************************************************************** + + Stop Log Event class + + ****************************************************************************/ class Stop_log_event: public Log_event { public: -#ifndef MYSQL_CLIENT +#ifndef MYSQL_CLIENT Stop_log_event() :Log_event() {} int exec_event(struct st_relay_log_info* rli); @@ -554,6 +614,13 @@ public: }; +/***************************************************************************** + + Rotate Log Event class + + This will be depricated when we move to using sequence ids. + + ****************************************************************************/ class Rotate_log_event: public Log_event { public: @@ -589,6 +656,11 @@ public: /* the classes below are for the new LOAD DATA INFILE logging */ +/***************************************************************************** + + Create File Log Event class + + ****************************************************************************/ class Create_file_log_event: public Load_log_event { protected: @@ -646,6 +718,11 @@ public: }; +/***************************************************************************** + + Append Block Log Event class + + ****************************************************************************/ class Append_block_log_event: public Log_event { public: @@ -670,7 +747,11 @@ public: int write_data(IO_CACHE* file); }; +/***************************************************************************** + Delete File Log Event class + + ****************************************************************************/ class Delete_file_log_event: public Log_event { public: @@ -692,6 +773,11 @@ public: int write_data(IO_CACHE* file); }; +/***************************************************************************** + + Execute Load Log Event class + + ****************************************************************************/ class Execute_load_log_event: public Log_event { public: diff --git a/sql/mini_client.cc b/sql/mini_client.cc index 5600983817b..0f20587ec24 100644 --- a/sql/mini_client.cc +++ b/sql/mini_client.cc @@ -40,6 +40,7 @@ #include "mysql_version.h" #include "mysqld_error.h" #include "errmsg.h" +#include <assert.h> #if defined( OS2) && defined(MYSQL_SERVER) #undef ER @@ -124,7 +125,7 @@ HANDLE create_named_pipe(NET *net, uint connect_timeout, char **arg_host, if (!host || !strcmp(host,LOCAL_HOST)) host=LOCAL_HOST_NAMEDPIPE; - sprintf( szPipeName, "\\\\%s\\pipe\\%s", host, unix_socket); + sprintf(szPipeName, "\\\\%s\\pipe\\%s", host, unix_socket); DBUG_PRINT("info",("Server name: '%s'. Named Pipe: %s", host, unix_socket)); @@ -450,21 +451,21 @@ mc_simple_command(MYSQL *mysql,enum enum_server_command command, mysql->net.last_error[0]=0; mysql->net.last_errno=0; + mysql->net.report_error=0; mysql->info=0; mysql->affected_rows= ~(my_ulonglong) 0; net_clear(net); /* Clear receive buffer */ if (!arg) arg=""; - if (net_write_command(net,(uchar) command,arg, - length ? length :(uint) strlen(arg))) + if (net_write_command(net, (uchar) command, NullS, 0, arg, length)) { - DBUG_PRINT("error",("Can't send command to server. Error: %d",socket_errno)); + DBUG_PRINT("error",("Can't send command to server. Error: %d", + socket_errno)); mc_end_server(mysql); if (mc_mysql_reconnect(mysql)) goto end; - if (net_write_command(net,(uchar) command,arg, - length ? length :(uint) strlen(arg))) + if (net_write_command(net,(uchar) command, NullS, 0, arg, length)) { net->last_errno=CR_SERVER_GONE_ERROR; strmov(net->last_error,ER(net->last_errno)); @@ -1027,18 +1028,19 @@ get_info: DBUG_RETURN(0); } -int mc_mysql_query(MYSQL *mysql, const char *query, uint length) + +int mc_mysql_query(MYSQL *mysql, const char *query, uint length) { - DBUG_ENTER("mysql_real_query"); + DBUG_ENTER("mc_mysql_query"); DBUG_PRINT("enter",("handle: %lx",mysql)); DBUG_PRINT("query",("Query = \"%s\"",query)); - if (!length) - length = strlen(query); + DBUG_ASSERT(length == strlen(query)); if (mc_simple_command(mysql,COM_QUERY,query,length,1)) DBUG_RETURN(-1); DBUG_RETURN(mc_mysql_read_query_result(mysql)); } + static int mc_send_file_to_server(MYSQL *mysql, const char *filename) { int fd, readcount, result= -1; diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 43de81cae00..4317ea05041 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -61,6 +61,8 @@ char* query_table_status(THD *thd,const char *db,const char *table_name); #endif #endif +#define my_thd_charset default_charset_info + /*************************************************************************** Configuration parameters ****************************************************************************/ @@ -200,6 +202,11 @@ char* query_table_status(THD *thd,const char *db,const char *table_name); #define MODE_SERIALIZABLE 16 #define MODE_ONLY_FULL_GROUP_BY 32 #define MODE_NO_UNSIGNED_SUBTRACTION 64 +#define MODE_POSTGRESQL 128 +#define MODE_ORACLE 256 +#define MODE_MSSQL 512 +#define MODE_DB2 1024 +#define MODE_SAPDB 2048 #define RAID_BLOCK_SIZE 1024 @@ -292,7 +299,10 @@ inline THD *_current_thd(void) #define query_cache_invalidate_by_MyISAM_filename_ref NULL #endif /*HAVE_QUERY_CACHE*/ -int mysql_create_db(THD *thd, char *db, uint create_info, bool silent); +#define prepare_execute(A) ((A)->command == COM_EXECUTE) + +int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create, bool silent); +int mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create); int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent); void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos, ushort flags); int mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists); @@ -306,8 +316,13 @@ int quick_rm_table(enum db_type base,const char *db, bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list); bool mysql_change_db(THD *thd,const char *name); void mysql_parse(THD *thd,char *inBuf,uint length); +void free_items(Item *item); +bool alloc_query(THD *thd, char *packet, ulong packet_length); void mysql_init_select(LEX *lex); -bool mysql_new_select(LEX *lex); +void mysql_init_query(THD *thd); +void mysql_reset_errors(THD *thd); +bool mysql_new_select(LEX *lex, bool move_down); +void create_select_for_variable(const char *var_name); void mysql_init_multi_delete(LEX *lex); void init_max_user_conn(void); void init_update_queries(void); @@ -316,7 +331,7 @@ extern "C" pthread_handler_decl(handle_one_connection,arg); extern "C" pthread_handler_decl(handle_bootstrap,arg); void end_thread(THD *thd,bool put_in_cache); void flush_thread_cache(); -void mysql_execute_command(void); +void mysql_execute_command(THD *thd); bool do_command(THD *thd); bool dispatch_command(enum enum_server_command command, THD *thd, char* packet, uint packet_length); @@ -347,11 +362,12 @@ int mysql_optimize_table(THD* thd, TABLE_LIST* table_list, bool check_simple_select(); /* net_pkg.c */ -void send_warning(NET *net, uint sql_errno, const char *err=0); -void net_printf(NET *net,uint sql_errno, ...); -void send_ok(NET *net,ha_rows affected_rows=0L,ulonglong id=0L, +void send_warning(THD *thd, uint sql_errno, const char *err=0); +void net_printf(THD *thd,uint sql_errno, ...); +void send_ok(THD *thd, ha_rows affected_rows=0L, ulonglong id=0L, const char *info=0); -void send_eof(NET *net,bool no_flush=0); +void send_eof(THD *thd, bool no_flush=0); +void net_send_error(NET *net, uint sql_errno, const char *err); char *net_store_length(char *packet,ulonglong length); char *net_store_length(char *packet,uint length); char *net_store_data(char *to,const char *from); @@ -372,19 +388,30 @@ bool net_store_data(String *packet, CONVERT *convert, const char *from); SORT_FIELD * make_unireg_sortorder(ORDER *order, uint *length); int setup_order(THD *thd,TABLE_LIST *tables, List<Item> &fields, List <Item> &all_fields, ORDER *order); +int setup_group(THD *thd,TABLE_LIST *tables,List<Item> &fields, + List<Item> &all_fields, ORDER *order, + bool *hidden_group_fields); int handle_select(THD *thd, LEX *lex, select_result *result); 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); + ulong select_type,select_result *result, + SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex, + bool fake_select_lex); +void fix_tables_pointers(SELECT_LEX *select_lex); +int mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, + select_result *result); +int mysql_explain_select(THD *thd, SELECT_LEX *sl, char const *type, + select_result *result); +int mysql_union(THD *thd, LEX *lex,select_result *result); +int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *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); int mysql_create_table(THD *thd,const char *db, const char *table_name, HA_CREATE_INFO *create_info, List<create_field> &fields, List<Key> &keys, - bool tmp_table, bool no_log); + bool tmp_table, bool no_log, uint select_field_count); TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, const char *db, const char *name, List<create_field> *extra_fields, @@ -435,7 +462,9 @@ bool wait_for_tables(THD *thd); bool table_is_used(TABLE *table, bool wait_for_name_lock); bool drop_locked_tables(THD *thd,const char *db, const char *table_name); void abort_locked_tables(THD *thd,const char *db, const char *table_name); -Field *find_field_in_tables(THD *thd,Item_field *item,TABLE_LIST *tables); +extern const Field *not_found_field; +Field *find_field_in_tables(THD *thd, Item_field *item, TABLE_LIST *tables, + bool report_error); Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length, bool check_grant,bool allow_rowid); #ifdef HAVE_OPENSSL @@ -457,7 +486,7 @@ bool load_des_key_file(const char *file_name); /* sql_do.cc */ int mysql_do(THD *thd, List<Item> &values); -/* sql_list.c */ +/* sql_show.cc */ int mysqld_show_dbs(THD *thd,const char *wild); int mysqld_show_open_tables(THD *thd,const char *wild); int mysqld_show_tables(THD *thd,const char *db,const char *wild); @@ -469,12 +498,33 @@ int mysqld_show_logs(THD *thd); void mysqld_list_fields(THD *thd,TABLE_LIST *table, const char *wild); int mysqld_dump_create_info(THD *thd, TABLE *table, int fd = -1); int mysqld_show_create(THD *thd, TABLE_LIST *table_list); +int mysqld_show_create_db(THD *thd, const char *dbname, HA_CREATE_INFO *create); void mysqld_list_processes(THD *thd,const char *user,bool verbose); int mysqld_show_status(THD *thd); int mysqld_show_variables(THD *thd,const char *wild); int mysqld_show(THD *thd, const char *wild, show_var_st *variables, enum enum_var_type value_type); +int mysqld_show_charsets(THD *thd,const char *wild); +int mysqld_show_table_types(THD *thd); +int mysqld_show_privileges(THD *thd); +int mysqld_show_column_types(THD *thd); +int mysqld_help (THD *thd, const char *text); + +/* sql_prepare.cc */ +int compare_prep_stmt(PREP_STMT *a, PREP_STMT *b, void *not_used); +void free_prep_stmt(PREP_STMT *stmt, TREE_FREE mode, void *not_used); +bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length); +void mysql_stmt_execute(THD *thd, char *packet); +void mysql_stm_close(THD *thd, char *packet); +void mysql_stmt_get_longdata(THD *thd, char *pos, ulong packet_length); +int check_insert_fields(THD *thd,TABLE *table,List<Item> &fields, + List<Item> &values, ulong counter); + +/* sql_error.cc */ +void push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level, uint code, + const char *msg); +my_bool mysqld_show_warnings(THD *thd, ulong levels_to_show); /* sql_handler.cc */ int mysql_ha_open(THD *thd, TABLE_LIST *tables); @@ -486,15 +536,11 @@ int mysql_ha_read(THD *, TABLE_LIST *,enum enum_ha_read_modes,char *, void set_item_name(Item *item,char *pos,uint length); bool add_field_to_list(char *field_name, enum enum_field_types type, char *length, char *decimal, - uint type_modifier, Item *default_value,char *change, - TYPELIB *interval); + uint type_modifier, + Item *default_value, Item *comment, + char *change, TYPELIB *interval,CHARSET_INFO *cs); void store_position_for_column(const char *name); bool add_to_list(SQL_LIST &list,Item *group,bool asc=0); -TABLE_LIST *add_table_to_list(Table_ident *table,LEX_STRING *alias, - bool updating, - thr_lock_type flags=TL_UNLOCK, - List<String> *use_index=0, - List<String> *ignore_index=0); void set_lock_for_tables(thr_lock_type lock_type); void add_join_on(TABLE_LIST *b,Item *expr); void add_join_natural(TABLE_LIST *a,TABLE_LIST *b); @@ -503,7 +549,11 @@ TABLE *unlink_open_table(THD *thd,TABLE *list,TABLE *find); SQL_SELECT *make_select(TABLE *head, table_map const_tables, table_map read_tables, COND *conds, int *error); -Item ** find_item_in_list(Item *item,List<Item> &items); +enum find_item_error_report_type {REPORT_ALL_ERRORS, REPORT_EXCEPT_NOT_FOUND, + IGNORE_ERRORS}; +extern const Item **not_found_item; +Item ** find_item_in_list(Item *item, List<Item> &items, + find_item_error_report_type report_error); bool insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name, const char *table_name, List_iterator<Item> *it); @@ -512,8 +562,8 @@ int setup_fields(THD *thd,TABLE_LIST *tables,List<Item> &item, bool set_query_id,List<Item> *sum_func_list, bool allow_sum_func); int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds); -int setup_ftfuncs(THD *thd); -int init_ftfuncs(THD *thd, bool no_order); +int setup_ftfuncs(SELECT_LEX* select); +int init_ftfuncs(THD *thd, SELECT_LEX* select, bool no_order); void wait_for_refresh(THD *thd); int open_tables(THD *thd,TABLE_LIST *tables); int open_and_lock_tables(THD *thd,TABLE_LIST *tables); @@ -564,7 +614,7 @@ extern "C" pthread_handler_decl(handle_manager, arg); #ifndef DBUG_OFF void print_where(COND *cond,const char *info); void print_cached_tables(void); -void TEST_filesort(SORT_FIELD *sortorder,uint s_length, ha_rows special); +void TEST_filesort(SORT_FIELD *sortorder,uint s_length); #endif void mysql_print_status(THD *thd); /* key.cc */ @@ -595,8 +645,9 @@ void clear_error_message(THD *thd); extern time_t start_time; extern char *mysql_data_home,server_version[SERVER_VERSION_LENGTH], - max_sort_char, mysql_real_data_home[], *charsets_list; -extern my_string mysql_tmpdir; + mysql_real_data_home[], *charsets_list, *opt_mysql_tmpdir; +#define mysql_tmpdir (my_tmpdir(&mysql_tmpdir_list)) +extern MY_TMPDIR mysql_tmpdir_list; extern const char *command_name[]; extern const char *first_keyword, *localhost, *delayed_user; extern const char **errmesg; /* Error messages */ @@ -655,13 +706,13 @@ extern char f_fyllchar; extern MYSQL_LOG mysql_log,mysql_update_log,mysql_slow_log,mysql_bin_log; extern FILE *bootstrap_file; extern pthread_key(MEM_ROOT*,THR_MALLOC); -extern pthread_key(NET*, THR_NET); extern pthread_mutex_t LOCK_mysql_create_db,LOCK_Acl,LOCK_open, LOCK_thread_count,LOCK_mapped_file,LOCK_user_locks, LOCK_status, - LOCK_grant, LOCK_error_log, LOCK_delayed_insert, + LOCK_error_log, LOCK_delayed_insert, LOCK_delayed_status, LOCK_delayed_create, LOCK_crypt, LOCK_timezone, LOCK_slave_list, LOCK_active_mi, LOCK_manager, LOCK_global_system_variables; +extern rw_lock_t LOCK_grant; extern pthread_cond_t COND_refresh, COND_thread_count, COND_manager; extern pthread_attr_t connection_attrib; extern I_List<THD> threads; @@ -669,6 +720,10 @@ extern MY_BITMAP temp_pool; extern DATE_FORMAT dayord; extern String empty_string; extern SHOW_VAR init_vars[],status_vars[], internal_vars[]; +extern struct show_table_type_st table_type_vars[]; +extern SHOW_COMP_OPTION have_isam; +extern SHOW_COMP_OPTION have_innodb; +extern SHOW_COMP_OPTION have_berkeley_db; extern struct system_variables global_system_variables; extern struct system_variables max_system_variables; @@ -709,7 +764,7 @@ bool wait_for_locked_table_names(THD *thd, TABLE_LIST *table_list); void unireg_init(ulong options); void unireg_end(void); -int rea_create_table(my_string file_name,HA_CREATE_INFO *create_info, +int rea_create_table(THD *thd, my_string file_name,HA_CREATE_INFO *create_info, List<create_field> &create_field, uint key_count,KEY *key_info); int format_number(uint inputflag,uint max_length,my_string pos,uint length, @@ -742,9 +797,9 @@ void init_read_record(READ_RECORD *info, THD *thd, TABLE *reg_form, SQL_SELECT *select, int use_record_cache, bool print_errors); void end_read_record(READ_RECORD *info); -ha_rows filesort(TABLE *form,struct st_sort_field *sortorder, uint s_length, - SQL_SELECT *select, ha_rows special,ha_rows max_rows, - ha_rows *examined_rows); +ha_rows filesort(THD *thd, TABLE *form,struct st_sort_field *sortorder, + uint s_length, SQL_SELECT *select, + ha_rows max_rows, ha_rows *examined_rows); void change_double_for_sort(double nr,byte *to); int get_quick_record(SQL_SELECT *select); int calc_weekday(long daynr,bool sunday_first_day_of_week); @@ -758,7 +813,7 @@ ulong get_form_pos(File file, uchar *head, TYPELIB *save_names); ulong make_new_entry(File file,uchar *fileinfo,TYPELIB *formnames, const char *newname); ulong next_io_size(ulong pos); -void append_unescaped(String *res,const char *pos); +void append_unescaped(String *res, const char *pos, uint length); int create_frm(char *name,uint reclength,uchar *fileinfo, HA_CREATE_INFO *create_info, uint keys); void update_create_info_from_table(HA_CREATE_INFO *info, TABLE *form); @@ -767,11 +822,7 @@ 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_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, - const char *wildstr,const char *wildend,char escape); +int wild_case_compare(CHARSET_INFO *cs, const char *str,const char *wildstr); /* from hostname.cc */ struct in_addr; @@ -790,24 +841,26 @@ extern int sql_cache_hit(THD *thd, char *inBuf, uint length); /* item.cc */ Item *get_system_var(enum_var_type var_type, LEX_STRING name); +Item *get_system_var(enum_var_type var_type, const char *var_name, uint length, + const char *item_name); /* Some inline functions for more speed */ inline bool add_item_to_list(Item *item) { - return current_lex->select->item_list.push_back(item); + return current_lex->current_select->add_item_to_list(item); } inline bool add_value_to_list(Item *value) { return current_lex->value_list.push_back(value); } -inline bool add_order_to_list(Item *item,bool asc) +inline bool add_order_to_list(Item *item, bool asc) { - return add_to_list(current_lex->select->order_list,item,asc); + return current_lex->current_select->add_order_to_list(item, asc); } -inline bool add_group_to_list(Item *item,bool asc) +inline bool add_group_to_list(Item *item, bool asc) { - return add_to_list(current_lex->select->group_list,item,asc); + return current_lex->current_select->add_group_to_list(item, asc); } inline void mark_as_null_row(TABLE *table) { diff --git a/sql/mysqld.cc b/sql/mysqld.cc index ffe3d1be47c..ebda24b404a 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -179,10 +179,13 @@ static char szPipeName [ 257 ]; static SECURITY_ATTRIBUTES saPipeSecurity; static SECURITY_DESCRIPTOR sdPipeDescriptor; static HANDLE hPipe = INVALID_HANDLE_VALUE; -static pthread_cond_t COND_handler_count; static uint handler_count; +static bool opt_enable_named_pipe = 0; #endif #ifdef __WIN__ +static bool opt_console=0,start_mode=0; +static pthread_cond_t COND_handler_count; +static uint handler_count; static bool opt_console=0, start_mode=0, use_opt_args; static int opt_argc; static char **opt_argv; @@ -240,6 +243,8 @@ SHOW_COMP_OPTION have_query_cache=SHOW_OPTION_YES; SHOW_COMP_OPTION have_query_cache=SHOW_OPTION_NO; #endif +const char *show_comp_option_name[]= {"YES", "NO", "DISABLED"}; + bool opt_large_files= sizeof(my_off_t) > 4; /* @@ -333,6 +338,11 @@ ulong query_cache_limit=0; Query_cache query_cache; #endif +#ifdef HAVE_SMEM +static char *shared_memory_base_name=default_shared_memory_base_name; +static bool opt_enable_shared_memory = 0; +#endif + volatile ulong cached_thread_count=0; // replication parameters, if master_host is not NULL, we are a slave @@ -393,7 +403,8 @@ const char *myisam_recover_options_str="OFF"; const char *sql_mode_str="OFF"; ulong rpl_recovery_rank=0; -my_string mysql_unix_port=NULL, opt_mysql_tmpdir=NULL, mysql_tmpdir=NULL; +my_string mysql_unix_port=NULL, opt_mysql_tmpdir=NULL; +MY_TMPDIR mysql_tmpdir_list; ulong my_bind_addr; /* the address we bind to */ char *my_bind_addr_str; DATE_FORMAT dayord; @@ -403,8 +414,12 @@ time_t start_time; ulong opt_sql_mode = 0L; const char *sql_mode_names[] = -{ "REAL_AS_FLOAT", "PIPES_AS_CONCAT", "ANSI_QUOTES", "IGNORE_SPACE", - "SERIALIZE","ONLY_FULL_GROUP_BY", "NO_UNSIGNED_SUBTRACTION",NullS }; +{ + "REAL_AS_FLOAT", "PIPES_AS_CONCAT", "ANSI_QUOTES", "IGNORE_SPACE", + "SERIALIZE", "ONLY_FULL_GROUP_BY", "NO_UNSIGNED_SUBTRACTION", + "POSTGRESQL", "ORACLE", "MSSQL", "SAPDB", + NullS +}; TYPELIB sql_mode_typelib= {array_elements(sql_mode_names)-1,"", sql_mode_names}; @@ -413,15 +428,14 @@ my_bool use_temp_pool=0; pthread_key(MEM_ROOT*,THR_MALLOC); pthread_key(THD*, THR_THD); -pthread_key(NET*, THR_NET); pthread_mutex_t LOCK_mysql_create_db, LOCK_Acl, LOCK_open, LOCK_thread_count, - LOCK_mapped_file, LOCK_status, LOCK_grant, + LOCK_mapped_file, LOCK_status, LOCK_error_log, LOCK_delayed_insert, LOCK_delayed_status, LOCK_delayed_create, LOCK_crypt, LOCK_bytes_sent, LOCK_bytes_received, LOCK_global_system_variables, LOCK_user_conn, LOCK_slave_list, LOCK_active_mi; - +rw_lock_t LOCK_grant; pthread_cond_t COND_refresh,COND_thread_count, COND_slave_stopped, COND_slave_start; pthread_cond_t COND_thread_cache,COND_flush_thread_cache; @@ -457,6 +471,9 @@ static bool read_init_file(char *file_name); #ifdef __NT__ extern "C" pthread_handler_decl(handle_connections_namedpipes,arg); #endif +#ifdef HAVE_SMEM +static pthread_handler_decl(handle_connections_shared_memory,arg); +#endif extern "C" pthread_handler_decl(handle_slave,arg); #ifdef SET_RLIMIT_NOFILE static uint set_maximum_open_files(uint max_file_limit); @@ -868,7 +885,7 @@ void clean_up(bool print_message) if (defaults_argv) free_defaults(defaults_argv); my_free(charsets_list, MYF(MY_ALLOW_ZERO_PTR)); - my_free(mysql_tmpdir,MYF(MY_ALLOW_ZERO_PTR)); + free_tmpdir(&mysql_tmpdir_list); my_free(slave_load_tmpdir,MYF(MY_ALLOW_ZERO_PTR)); x_free(opt_bin_logname); x_free(opt_relay_logname); @@ -959,7 +976,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); @@ -1062,7 +1079,7 @@ static void server_init(void) if (Service.IsNT() && mysql_unix_port[0] && !opt_bootstrap && opt_enable_named_pipe) { - sprintf( szPipeName, "\\\\.\\pipe\\%s", mysql_unix_port ); + sprintf(szPipeName, "\\\\.\\pipe\\%s", mysql_unix_port ); ZeroMemory( &saPipeSecurity, sizeof(saPipeSecurity) ); ZeroMemory( &sdPipeDescriptor, sizeof(sdPipeDescriptor) ); if ( !InitializeSecurityDescriptor(&sdPipeDescriptor, @@ -1147,12 +1164,12 @@ static void server_init(void) void yyerror(const char *s) { - NET *net=my_pthread_getspecific_ptr(NET*,THR_NET); - char *yytext=(char*) current_lex->tok_start; + THD *thd=current_thd; + char *yytext=(char*) thd->lex.tok_start; if (!strcmp(s,"parse error")) s=ER(ER_SYNTAX_ERROR); - net_printf(net,ER_PARSE_ERROR, s, yytext ? (char*) yytext : "", - current_lex->yylineno); + net_printf(thd,ER_PARSE_ERROR, s, yytext ? (char*) yytext : "", + thd->lex.yylineno); } @@ -1168,7 +1185,7 @@ void close_connection(NET *net,uint errcode,bool lock) if ((vio=net->vio) != 0) { if (errcode) - send_error(net,errcode,ER(errcode)); /* purecov: inspected */ + net_send_error(net,errcode,ER(errcode)); /* purecov: inspected */ vio_close(vio); /* vio is freed in delete thd */ } if (lock) @@ -1565,8 +1582,8 @@ extern "C" void *signal_hand(void *arg __attribute__((unused))) if ((pidFile = my_create(pidfile_name,0664, O_WRONLY, MYF(MY_WME))) >= 0) { char buff[21]; - sprintf(buff,"%lu",(ulong) getpid()); - (void) my_write(pidFile, buff,strlen(buff),MYF(MY_WME)); + ulong length= my_sprintf(buff, (buff,"%lu",(ulong) getpid())); + (void) my_write(pidFile, buff, length, MYF(MY_WME)); (void) my_close(pidFile,MYF(0)); } } @@ -1664,11 +1681,13 @@ extern "C" void *signal_hand(void *arg __attribute__((unused))) extern "C" int my_message_sql(uint error, const char *str, myf MyFlags __attribute__((unused))) { - NET *net; + THD *thd; DBUG_ENTER("my_message_sql"); DBUG_PRINT("error",("Message: '%s'",str)); - if ((net=my_pthread_getspecific_ptr(NET*,THR_NET))) + if ((thd=current_thd)) { + NET *net= &thd->net; + net->report_error= 1; if (!net->last_error[0]) // Return only first message { strmake(net->last_error,str,sizeof(net->last_error)-1); @@ -1866,17 +1885,6 @@ int main(int argc, char **argv) load_defaults(MYSQL_CONFIG_NAME,load_default_groups,&argc,&argv); defaults_argv=argv; - /* Get default temporary directory */ - opt_mysql_tmpdir=getenv("TMPDIR"); /* Use this if possible */ -#if defined( __WIN__) || defined(OS2) - if (!opt_mysql_tmpdir) - opt_mysql_tmpdir=getenv("TEMP"); - if (!opt_mysql_tmpdir) - opt_mysql_tmpdir=getenv("TMP"); -#endif - if (!opt_mysql_tmpdir || !opt_mysql_tmpdir[0]) - opt_mysql_tmpdir=(char*) P_tmpdir; /* purecov: inspected */ - set_options(); get_options(argc,argv); if (opt_log || opt_update_log || opt_slow_log || opt_bin_log) @@ -1888,7 +1896,6 @@ int main(int argc, char **argv) (void) pthread_mutex_init(&LOCK_mysql_create_db,MY_MUTEX_INIT_SLOW); (void) pthread_mutex_init(&LOCK_Acl,MY_MUTEX_INIT_SLOW); - (void) pthread_mutex_init(&LOCK_grant,MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_open,MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_thread_count,MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_mapped_file,MY_MUTEX_INIT_SLOW); @@ -1906,6 +1913,7 @@ int main(int argc, char **argv) (void) pthread_mutex_init(&LOCK_rpl_status, MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_active_mi, MY_MUTEX_INIT_FAST); (void) pthread_mutex_init(&LOCK_global_system_variables, MY_MUTEX_INIT_FAST); + (void) my_rwlock_init(&LOCK_grant, NULL); (void) pthread_cond_init(&COND_thread_count,NULL); (void) pthread_cond_init(&COND_refresh,NULL); (void) pthread_cond_init(&COND_thread_cache,NULL); @@ -1916,7 +1924,7 @@ int main(int argc, char **argv) if (set_default_charset_by_name(sys_charset.value, MYF(MY_WME))) exit(1); - charsets_list = list_charsets(MYF(MY_COMPILED_SETS|MY_CONFIG_SETS)); + charsets_list= list_charsets(MYF(MY_CS_COMPILED | MY_CS_CONFIG)); #ifdef HAVE_OPENSSL if (opt_use_ssl) @@ -2064,7 +2072,7 @@ int main(int argc, char **argv) After this we can't quit by a simple unireg_abort */ error_handler_hook = my_message_sql; - if (pthread_key_create(&THR_THD,NULL) || pthread_key_create(&THR_NET,NULL) || + if (pthread_key_create(&THR_THD,NULL) || pthread_key_create(&THR_MALLOC,NULL)) { sql_print_error("Can't create thread-keys"); @@ -2173,21 +2181,24 @@ The server will not act as a slave."); printf(ER(ER_READY),my_progname,server_version,""); fflush(stdout); - +#if defined(__NT__) || defined(HAVE_SMEM) #ifdef __NT__ if (hPipe == INVALID_HANDLE_VALUE && - (!have_tcpip || opt_disable_networking)) + (!have_tcpip || opt_disable_networking) && + !opt_enable_shared_memory) { - sql_print_error("TCP/IP or --enable-named-pipe should be configured on NT OS"); + sql_print_error("TCP/IP,--shared-memory or --named-pipe should be configured on NT OS"); unireg_abort(1); } else +#endif { pthread_mutex_lock(&LOCK_thread_count); (void) pthread_cond_init(&COND_handler_count,NULL); { pthread_t hThread; handler_count=0; +#ifdef __NT__ if (hPipe != INVALID_HANDLE_VALUE && opt_enable_named_pipe) { handler_count++; @@ -2198,18 +2209,33 @@ The server will not act as a slave."); handler_count--; } } +#endif +#ifdef HAVE_SMEM + if (opt_enable_shared_memory) + { + handler_count++; + if (pthread_create(&hThread,&connection_attrib, + handle_connections_shared_memory, 0)) + { + sql_print_error("Warning: Can't create thread to handle shared memory"); + handler_count--; + } + } +#endif if (have_tcpip && !opt_disable_networking) { handler_count++; if (pthread_create(&hThread,&connection_attrib, handle_connections_sockets, 0)) { - sql_print_error("Warning: Can't create thread to handle named pipes"); + sql_print_error("Warning: Can't create thread to handle tcp/ip"); handler_count--; } } while (handler_count > 0) + { pthread_cond_wait(&COND_handler_count,&LOCK_thread_count); + } } pthread_mutex_unlock(&LOCK_thread_count); } @@ -2505,7 +2531,7 @@ static void create_new_thread(THD *thd) thread_count--; thd->killed=1; // Safety (void) pthread_mutex_unlock(&LOCK_thread_count); - net_printf(net,ER_CANT_CREATE_THREAD,error); + net_printf(thd,ER_CANT_CREATE_THREAD,error); (void) pthread_mutex_lock(&LOCK_thread_count); close_connection(net,0,0); delete thd; @@ -2827,6 +2853,219 @@ extern "C" pthread_handler_decl(handle_connections_namedpipes,arg) } #endif /* __NT__ */ +/* + Thread of shared memory's service + + SYNOPSIS + pthread_handler_decl() + handle_connections_shared_memory Thread handle + arg Arguments of thread +*/ +#ifdef HAVE_SMEM +pthread_handler_decl(handle_connections_shared_memory,arg) +{ +/* + event_connect_request is event object for start connection actions + event_connect_answer is event object for confirm, that server put data + handle_connect_file_map is file-mapping object, use for create shared memory + handle_connect_map is pointer on shared memory + handle_map is pointer on shared memory for client + event_server_wrote, + event_server_read, + event_client_wrote, + event_client_read are events for transfer data between server and client + handle_file_map is file-mapping object, use for create shared memory +*/ + HANDLE handle_connect_file_map = NULL; + char *handle_connect_map = NULL; + HANDLE event_connect_request = NULL; + HANDLE event_connect_answer = NULL; + ulong smem_buffer_length = shared_memory_buffer_length + 4; + ulong connect_number = 1; + my_bool error_allow; + THD *thd; + char tmp[63]; + char *suffix_pos; + char connect_number_char[22], *p; + + my_thread_init(); + DBUG_ENTER("handle_connections_shared_memorys"); + DBUG_PRINT("general",("Waiting for allocated shared memory.")); + + +/* + The name of event and file-mapping events create agree next rule: + shared_memory_base_name+unique_part + Where: + shared_memory_base_name is unique value for each server + unique_part is unique value for each object (events and file-mapping) +*/ + suffix_pos = strxmov(tmp,shared_memory_base_name,"_",NullS); + strmov(suffix_pos, "CONNECT_REQUEST"); + if ((event_connect_request = CreateEvent(NULL,FALSE,FALSE,tmp)) == 0) + { + sql_perror("Can't create shared memory service ! The request event don't create."); + goto error; + } + strmov(suffix_pos, "CONNECT_ANSWER"); + if ((event_connect_answer = CreateEvent(NULL,FALSE,FALSE,tmp)) == 0) + { + sql_perror("Can't create shared memory service ! The answer event don't create."); + goto error; + } + strmov(suffix_pos, "CONNECT_DATA"); + if ((handle_connect_file_map = CreateFileMapping(INVALID_HANDLE_VALUE,NULL,PAGE_READWRITE, + 0,sizeof(connect_number),tmp)) == 0) + { + sql_perror("Can't create shared memory service ! File mapping don't create."); + goto error; + } + if ((handle_connect_map = (char *)MapViewOfFile(handle_connect_file_map,FILE_MAP_WRITE,0,0, + sizeof(DWORD))) == 0) + { + sql_perror("Can't create shared memory service ! Map of memory don't create."); + goto error; + } + + + while (!abort_loop) + { +/* + Wait a request from client +*/ + WaitForSingleObject(event_connect_request,INFINITE); + error_allow = FALSE; + + HANDLE handle_client_file_map = NULL; + char *handle_client_map = NULL; + HANDLE event_client_wrote = NULL; + HANDLE event_client_read = NULL; + HANDLE event_server_wrote = NULL; + HANDLE event_server_read = NULL; + + p = int2str(connect_number, connect_number_char, 10); +/* + The name of event and file-mapping events create agree next rule: + shared_memory_base_name+unique_part+number_of_connection + Where: + shared_memory_base_name is uniquel value for each server + unique_part is unique value for each object (events and file-mapping) + number_of_connection is number of connection between server and client +*/ + suffix_pos = strxmov(tmp,shared_memory_base_name,"_",connect_number_char,"_",NullS); + strmov(suffix_pos, "DATA"); + if ((handle_client_file_map = CreateFileMapping(INVALID_HANDLE_VALUE,NULL, + PAGE_READWRITE,0,smem_buffer_length,tmp)) == 0) + { + sql_perror("Can't create connection with client in shared memory service ! File mapping don't create."); + error_allow = TRUE; + goto errorconn; + } + if ((handle_client_map = (char*)MapViewOfFile(handle_client_file_map,FILE_MAP_WRITE,0,0,smem_buffer_length)) == 0) + { + sql_perror("Can't create connection with client in shared memory service ! Map of memory don't create."); + error_allow = TRUE; + goto errorconn; + } + + strmov(suffix_pos, "CLIENT_WROTE"); + if ((event_client_wrote = CreateEvent(NULL,FALSE,FALSE,tmp)) == 0) + { + sql_perror("Can't create connection with client in shared memory service ! CW event don't create."); + error_allow = TRUE; + goto errorconn; + } + + strmov(suffix_pos, "CLIENT_READ"); + if ((event_client_read = CreateEvent(NULL,FALSE,FALSE,tmp)) == 0) + { + sql_perror("Can't create connection with client in shared memory service ! CR event don't create."); + error_allow = TRUE; + goto errorconn; + } + + strmov(suffix_pos, "SERVER_READ"); + if ((event_server_read = CreateEvent(NULL,FALSE,FALSE,tmp)) == 0) + { + sql_perror("Can't create connection with client in shared memory service ! SR event don't create."); + error_allow = TRUE; + goto errorconn; + } + + strmov(suffix_pos, "SERVER_WROTE"); + if ((event_server_wrote = CreateEvent(NULL,FALSE,FALSE,tmp)) == 0) + { + sql_perror("Can't create connection with client in shared memory service ! SW event don't create."); + error_allow = TRUE; + goto errorconn; + } + + if (abort_loop) break; + if ( !(thd = new THD)) + { + error_allow = TRUE; + goto errorconn; + } + +/* +Send number of connection to client +*/ + int4store(handle_connect_map, connect_number); + +/* + Send number of connection to client +*/ + if (!SetEvent(event_connect_answer)) + { + sql_perror("Can't create connection with client in shared memory service ! Can't send answer event."); + error_allow = TRUE; + goto errorconn; + } + +/* + Set event that client should receive data +*/ + if (!SetEvent(event_client_read)) + { + sql_perror("Can't create connection with client in shared memory service ! Can't set client to read's mode."); + error_allow = TRUE; + goto errorconn; + } + if (!(thd->net.vio = vio_new_win32shared_memory(&thd->net,handle_client_file_map,handle_client_map,event_client_wrote, + event_client_read,event_server_wrote,event_server_read)) || + my_net_init(&thd->net, thd->net.vio)) + { + close_connection(&thd->net,ER_OUT_OF_RESOURCES); + delete thd; + error_allow = TRUE; + } + /* host name is unknown */ +errorconn: + if (error_allow) + { + if (!handle_client_map) UnmapViewOfFile(handle_client_map); + if (!handle_client_file_map) CloseHandle(handle_client_file_map); + if (!event_server_wrote) CloseHandle(event_server_wrote); + if (!event_server_read) CloseHandle(event_server_read); + if (!event_client_wrote) CloseHandle(event_client_wrote); + if (!event_client_read) CloseHandle(event_client_read); + continue; + } + thd->host = my_strdup(localhost,MYF(0)); /* Host is unknown */ + create_new_thread(thd); + uint4korr(connect_number++); + } +error: + if (!handle_connect_map) UnmapViewOfFile(handle_connect_map); + if (!handle_connect_file_map) CloseHandle(handle_connect_file_map); + if (!event_connect_answer) CloseHandle(event_connect_answer); + if (!event_connect_request) CloseHandle(event_connect_request); + pthread_mutex_lock(&LOCK_thread_count); + pthread_mutex_unlock(&LOCK_thread_count); + DBUG_RETURN(0); +} +#endif /* HAVE_SMEM */ + /****************************************************************************** ** handle start options @@ -2911,6 +3150,7 @@ enum options { OPT_MAX_JOIN_SIZE, OPT_MAX_SORT_LENGTH, OPT_MAX_TMP_TABLES, OPT_MAX_USER_CONNECTIONS, OPT_MAX_WRITE_LOCK_COUNT, OPT_BULK_INSERT_BUFFER_SIZE, + OPT_MAX_ERROR_COUNT, OPT_MAX_PREP_STMT, OPT_MYISAM_BLOCK_SIZE, OPT_MYISAM_MAX_EXTRA_SORT_FILE_SIZE, OPT_MYISAM_MAX_SORT_FILE_SIZE, OPT_MYISAM_SORT_BUFFER_SIZE, OPT_NET_BUFFER_LENGTH, OPT_NET_RETRY_COUNT, @@ -2936,7 +3176,9 @@ enum options { OPT_INNODB_FORCE_RECOVERY, OPT_BDB_CACHE_SIZE, OPT_BDB_LOG_BUFFER_SIZE, - OPT_BDB_MAX_LOCK + OPT_BDB_MAX_LOCK, + OPT_ENABLE_SHARED_MEMORY, + OPT_SHARED_MEMORY_BASE_NAME }; @@ -2973,13 +3215,13 @@ struct my_option my_long_options[] = #endif /* HAVE_BERKELEY_DB */ {"skip-bdb", OPT_BDB_SKIP, "Don't use berkeley db (will save memory)", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, - {"big-tables", OPT_BIG_TABLES, + {"big-tables", OPT_BIG_TABLES, "Allow big result sets by saving all temporary sets on file (Solves most 'table full' errors)", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"binlog-do-db", OPT_BINLOG_DO_DB, "Tells the master it should log updates for the specified database, and exclude all others not explicitly mentioned.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, - {"binlog-ignore-db", OPT_BINLOG_IGNORE_DB, + {"binlog-ignore-db", OPT_BINLOG_IGNORE_DB, "Tells the master that updates to the given database should not be logged tothe binary log", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"bind-address", OPT_BIND_ADDRESS, "IP address to bind to", @@ -3043,6 +3285,11 @@ struct my_option my_long_options[] = {"enable-pstack", OPT_DO_PSTACK, "Print a symbolic stack trace on failure", (gptr*) &opt_do_pstack, (gptr*) &opt_do_pstack, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, +#ifdef HAVE_SMEM + {"shared-memory", OPT_ENABLE_SHARED_MEMORY, + "Enable the shared memory.",(gptr*) &opt_enable_shared_memory, (gptr*) &opt_enable_shared_memory, + 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, +#endif {"exit-info", 'T', "Used for debugging; Use at your own risk!", 0, 0, 0, GET_LONG, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"flush", OPT_FLUSH, "Flush tables to disk between SQL commands", 0, 0, 0, @@ -3291,6 +3538,11 @@ struct my_option my_long_options[] = {"set-variable", 'O', "Change the value of a variable. Please note that this option is deprecated;you can set variables directly with --variable-name=value.", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +#ifdef HAVE_SMEM + {"shared_memory_base_name",OPT_SHARED_MEMORY_BASE_NAME, + "Base name of shared memory", (gptr*) &shared_memory_base_name, (gptr*) &shared_memory_base_name, + 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, +#endif {"show-slave-auth-info", OPT_SHOW_SLAVE_AUTH_INFO, "Show user and password in SHOW SLAVE STATUS", (gptr*) &opt_show_slave_auth_info, (gptr*) &opt_show_slave_auth_info, 0, @@ -3355,11 +3607,19 @@ struct my_option my_long_options[] = #ifdef HAVE_OPENSSL #include "sslopt-longopts.h" #endif - {"temp-pool", OPT_TEMP_POOL, + {"temp-pool", OPT_TEMP_POOL, "Using this option will cause most temporary files created to use a small set of names, rather than a unique name for each new file.", (gptr*) &use_temp_pool, (gptr*) &use_temp_pool, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0}, - {"tmpdir", 't', "Path for temporary files", (gptr*) &opt_mysql_tmpdir, + {"tmpdir", 't', + "Path for temporary files. Several paths may be specified, separated by a " +#if defined( __WIN__) || defined(OS2) + "semicolon (;)" +#else + "colon (:)" +#endif + ", in this case they are used in a round-robin fashion.", + (gptr*) &opt_mysql_tmpdir, (gptr*) &opt_mysql_tmpdir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"transaction-isolation", OPT_TX_ISOLATION, "Default transaction isolation level", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, @@ -3537,6 +3797,11 @@ struct my_option my_long_options[] = "Don't start more than this number of threads to handle INSERT DELAYED statements.", (gptr*) &max_insert_delayed_threads, (gptr*) &max_insert_delayed_threads, 0, GET_ULONG, REQUIRED_ARG, 20, 1, 16384, 0, 1, 0}, + {"max_error_count", OPT_MAX_ERROR_COUNT, + "Max number of errors/warnings to store for a statement", + (gptr*) &global_system_variables.max_error_count, + (gptr*) &max_system_variables.max_error_count, + 0, GET_ULONG, REQUIRED_ARG, DEFAULT_ERROR_COUNT, 1, 65535, 0, 1, 0}, {"max_heap_table_size", OPT_MAX_HEP_TABLE_SIZE, "Don't allow creation of heap tables bigger than this.", (gptr*) &global_system_variables.max_heap_table_size, @@ -3547,6 +3812,11 @@ struct my_option my_long_options[] = (gptr*) &global_system_variables.max_join_size, (gptr*) &max_system_variables.max_join_size, 0, GET_ULONG, REQUIRED_ARG, ~0L, 1, ~0L, 0, 1, 0}, + {"max_prepared_statements", OPT_MAX_PREP_STMT, + "Max number of prepared_statements for a thread", + (gptr*) &global_system_variables.max_prep_stmt_count, + (gptr*) &max_system_variables.max_prep_stmt_count, 0, GET_ULONG, + REQUIRED_ARG, DEFAULT_PREP_STMT_COUNT, 0, ~0L, 0, 1, 0}, {"max_sort_length", OPT_MAX_SORT_LENGTH, "The number of bytes to use when sorting BLOB or TEXT values (only the first max_sort_length bytes of each value are used; the rest are ignored).", (gptr*) &global_system_variables.max_sort_length, @@ -3932,10 +4202,10 @@ static void set_options(void) /* Set default values for some variables */ global_system_variables.table_type=DB_TYPE_MYISAM; global_system_variables.tx_isolation=ISO_REPEATABLE_READ; - global_system_variables.select_limit= (ulong) HA_POS_ERROR; + global_system_variables.select_limit= (ulonglong) HA_POS_ERROR; max_system_variables.select_limit= (ulong) HA_POS_ERROR; - global_system_variables.max_join_size= (ulong) HA_POS_ERROR; - max_system_variables.max_join_size= (ulong) HA_POS_ERROR; + global_system_variables.max_join_size= (ulonglong) HA_POS_ERROR; + max_system_variables.max_join_size= (ulonglong) HA_POS_ERROR; #ifdef __WIN__ /* Allow Win32 users to move MySQL anywhere */ @@ -3971,8 +4241,8 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), break; case 'a': opt_sql_mode = (MODE_REAL_AS_FLOAT | MODE_PIPES_AS_CONCAT | - MODE_ANSI_QUOTES | MODE_IGNORE_SPACE | MODE_SERIALIZABLE - | MODE_ONLY_FULL_GROUP_BY); + MODE_ANSI_QUOTES | MODE_IGNORE_SPACE | MODE_SERIALIZABLE | + MODE_ONLY_FULL_GROUP_BY); global_system_variables.tx_isolation= ISO_SERIALIZABLE; break; case 'b': @@ -4069,7 +4339,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), exit(1); } val= p--; - while (isspace(*p) && p > argument) + while (my_isspace(system_charset_info, *p) && p > argument) *p-- = 0; if (p == argument) { @@ -4079,7 +4349,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), } *val= 0; val+= 2; - while (*val && isspace(*val)) + while (*val && my_isspace(system_charset_info, *val)) *val++; if (!*val) { @@ -4221,7 +4491,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), have_symlink=SHOW_OPTION_DISABLED; break; case (int) OPT_BIND_ADDRESS: - if (argument && isdigit(argument[0])) + if (argument && my_isdigit(system_charset_info, argument[0])) { my_bind_addr = (ulong) inet_addr(argument); } @@ -4534,9 +4804,7 @@ static void fix_paths(void) charsets_dir=mysql_charsets_dir; } - char *end=convert_dirname(buff, opt_mysql_tmpdir, NullS); - if (!(mysql_tmpdir= my_memdup((byte*) buff,(uint) (end-buff)+1, - MYF(MY_FAE)))) + if (init_tmpdir(&mysql_tmpdir_list, opt_mysql_tmpdir)) exit(1); if (!slave_load_tmpdir) { @@ -4637,7 +4905,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/net_pkg.cc b/sql/net_pkg.cc index 8bb601cebcf..1da625e776f 100644 --- a/sql/net_pkg.cc +++ b/sql/net_pkg.cc @@ -20,19 +20,18 @@ /* Send a error string to client */ -void send_error(NET *net, uint sql_errno, const char *err) +void send_error(THD *thd, uint sql_errno, const char *err) { uint length; char buff[MYSQL_ERRMSG_SIZE+2]; - THD *thd=current_thd; + NET *net= &thd->net; DBUG_ENTER("send_error"); DBUG_PRINT("enter",("sql_errno: %d err: %s", sql_errno, err ? err : net->last_error[0] ? - net->last_error : "NULL")); + net->last_error : "NULL")); query_cache_abort(net); - if (thd) - thd->query_error = 1; // needed to catch query errors during replication + thd->query_error= 1; // needed to catch query errors during replication if (!err) { if (sql_errno) @@ -50,7 +49,7 @@ void send_error(NET *net, uint sql_errno, const char *err) } if (net->vio == 0) { - if (thd && thd->bootstrap) + if (thd->bootstrap) { /* In bootstrap it's ok to print on stderr */ fprintf(stderr,"ERROR: %d %s\n",sql_errno,err); @@ -67,46 +66,75 @@ void send_error(NET *net, uint sql_errno, const char *err) else { length=(uint) strlen(err); - set_if_smaller(length,MYSQL_ERRMSG_SIZE); + set_if_smaller(length,MYSQL_ERRMSG_SIZE-1); } - VOID(net_write_command(net,(uchar) 255,(char*) err,length)); - if (thd) - thd->fatal_error=0; // Error message is given + VOID(net_write_command(net,(uchar) 255, "", 0, (char*) err,length)); + thd->fatal_error=0; // Error message is given + thd->net.report_error= 0; DBUG_VOID_RETURN; } /* - At some point we need to be able to distinguish between warnings and - errors; The following function will help make this easier. + Send an error to the client when a connection is forced close + This is used by mysqld.cc, which doesn't have a THD */ -void send_warning(NET *net, uint sql_errno, const char *err) +void net_send_error(NET *net, uint sql_errno, const char *err) { - DBUG_ENTER("send_warning"); - send_error(net,sql_errno,err); + char buff[2]; + uint length; + DBUG_ENTER("send_net_error"); + + int2store(buff,sql_errno); + length=(uint) strlen(err); + set_if_smaller(length,MYSQL_ERRMSG_SIZE-1); + net_write_command(net,(uchar) 255, buff, 2, err, length); + DBUG_VOID_RETURN; +} + + +/* + Send a warning to the end user + + SYNOPSIS + send_warning() + thd Thread handler + sql_errno Warning number (error message) + err Error string. If not set, use ER(sql_errno) + + DESCRIPTION + Register the warning so that the user can get it with mysql_warnings() + Send an ok (+ warning count) to the end user. +*/ + +void send_warning(THD *thd, uint sql_errno, const char *err) +{ + DBUG_ENTER("send_warning"); + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, sql_errno, + err ? err : ER(sql_errno)); + send_ok(thd); DBUG_VOID_RETURN; } /* Write error package and flush to client - It's a little too low level, but I don't want to allow another buffer + It's a little too low level, but I don't want to use another buffer for + this */ -/* VARARGS3 */ void -net_printf(NET *net, uint errcode, ...) +net_printf(THD *thd, uint errcode, ...) { va_list args; uint length,offset; const char *format,*text_pos; int head_length= NET_HEADER_SIZE; - THD *thd=current_thd; + NET *net= &thd->net; DBUG_ENTER("net_printf"); DBUG_PRINT("enter",("message: %u",errcode)); - if (thd) - thd->query_error = 1; // if we are here, something is wrong :-) + thd->query_error= 1; // needed to catch query errors during replication query_cache_abort(net); // Safety va_start(args,errcode); /* @@ -132,7 +160,7 @@ net_printf(NET *net, uint errcode, ...) if (net->vio == 0) { - if (thd && thd->bootstrap) + if (thd->bootstrap) { /* In bootstrap it's ok to print on stderr */ fprintf(stderr,"ERROR: %d %s\n",errcode,text_pos); @@ -147,16 +175,42 @@ net_printf(NET *net, uint errcode, ...) if (offset) int2store(text_pos-2, errcode); VOID(net_real_write(net,(char*) net->buff,length+head_length+1+offset)); - if (thd) - thd->fatal_error=0; // Error message is given + thd->fatal_error=0; // Error message is given DBUG_VOID_RETURN; } +/* + Return ok to the client. + + SYNOPSIS + send_ok() + thd Thread handler + affected_rows Number of rows changed by statement + id Auto_increment id for first row (if used) + message Message to send to the client (Used by mysql_status) + + DESCRIPTION + The ok packet has the following structure + + 0 Marker (1 byte) + affected_rows Stored in 1-9 bytes + id Stored in 1-9 bytes + server_status Copy of thd->server_status; Can be used by client + to check if we are inside an transaction + New in 4.0 protocol + warning_count Stored in 2 bytes; New in 4.1 protocol + message Stored as packed length (1-9 bytes) + message + Is not stored if no message + + If net->no_send_ok return without sending packet +*/ + void -send_ok(NET *net,ha_rows affected_rows,ulonglong id,const char *message) +send_ok(THD *thd, ha_rows affected_rows, ulonglong id, const char *message) { - if (net->no_send_ok) // hack for re-parsing queries + NET *net= &thd->net; + if (net->no_send_ok || !net->vio) // hack for re-parsing queries return; char buff[MYSQL_ERRMSG_SIZE+10],*pos; @@ -164,31 +218,75 @@ send_ok(NET *net,ha_rows affected_rows,ulonglong id,const char *message) buff[0]=0; // No fields pos=net_store_length(buff+1,(ulonglong) affected_rows); pos=net_store_length(pos, (ulonglong) id); - if (net->return_status) + if (thd->client_capabilities & CLIENT_PROTOCOL_41) { - int2store(pos,*net->return_status); + int2store(pos,thd->server_status); pos+=2; + + /* We can only return up to 65535 warnings in two bytes */ + uint tmp= min(thd->total_warn_count, 65535); + int2store(pos, tmp); + pos+= 2; } - if (message) - pos=net_store_data((char*) pos,message); - if (net->vio != 0) + else if (net->return_status) // For 4.0 protocol { - VOID(my_net_write(net,buff,(uint) (pos-buff))); - VOID(net_flush(net)); + int2store(pos,thd->server_status); + pos+=2; } + if (message) + pos=net_store_data((char*) pos,message); + VOID(my_net_write(net,buff,(uint) (pos-buff))); + VOID(net_flush(net)); DBUG_VOID_RETURN; } + +/* + Send eof (= end of result set) to the client + + SYNOPSIS + send_eof() + thd Thread handler + no_flush Set to 1 if there will be more data to the client, + like in send_fields(). + + DESCRIPTION + The eof packet has the following structure + + 254 Marker (1 byte) + warning_count Stored in 2 bytes; New in 4.1 protocol + status_flag Stored in 2 bytes; + For flags like SERVER_STATUS_MORE_RESULTS + + Note that the warning count will not be sent if 'no_flush' is set as + we don't want to report the warning count until all data is sent to the + client. +*/ + void -send_eof(NET *net,bool no_flush) +send_eof(THD *thd, bool no_flush) { static char eof_buff[1]= { (char) 254 }; /* Marker for end of fields */ + NET *net= &thd->net; DBUG_ENTER("send_eof"); if (net->vio != 0) { - VOID(my_net_write(net,eof_buff,1)); - if (!no_flush) + if (!no_flush && (thd->client_capabilities & CLIENT_PROTOCOL_41)) + { + uchar buff[5]; + uint tmp= min(thd->total_warn_count, 65535); + buff[0]=254; + int2store(buff+1, tmp); + int2store(buff+3, 0); // No flags yet + VOID(my_net_write(net,(char*) buff,5)); VOID(net_flush(net)); + } + else + { + VOID(my_net_write(net,eof_buff,1)); + if (!no_flush) + VOID(net_flush(net)); + } } DBUG_VOID_RETURN; } @@ -341,7 +439,7 @@ net_store_data(String *packet,struct tm *tmp) bool net_store_data(String* packet, I_List<i_string>* str_list) { char buf[256]; - String tmp(buf, sizeof(buf)); + String tmp(buf, sizeof(buf), default_charset_info); tmp.length(0); I_List_iterator<i_string> it(*str_list); i_string* s; diff --git a/sql/net_serv.cc b/sql/net_serv.cc index 122793b07a7..d165125eb90 100644 --- a/sql/net_serv.cc +++ b/sql/net_serv.cc @@ -75,12 +75,12 @@ extern pthread_mutex_t LOCK_bytes_sent , LOCK_bytes_received; #define TEST_BLOCKING 8 #define MAX_THREE_BYTES 255L*255L*255L -static int net_write_buff(NET *net,const char *packet,ulong len); +static my_bool net_write_buff(NET *net,const char *packet,ulong len); /* Init with packet info */ -int my_net_init(NET *net, Vio* vio) +my_bool my_net_init(NET *net, Vio* vio) { DBUG_ENTER("my_net_init"); my_net_local_init(net); /* Set some limits */ @@ -99,6 +99,7 @@ int my_net_init(NET *net, Vio* vio) net->where_b = net->remain_in_buf=0; net->last_errno=0; net->query_cache_query=0; + net->report_error= 0; if (vio != 0) /* If real connection */ { @@ -127,15 +128,16 @@ void net_end(NET *net) /* Realloc the packet buffer */ -static my_bool net_realloc(NET *net, ulong length) +my_bool net_realloc(NET *net, ulong length) { uchar *buff; ulong pkt_length; if (length >= net->max_packet_size) { DBUG_PRINT("error",("Packet too large (%lu)", length)); - net->error=1; - net->last_errno=ER_NET_PACKET_TOO_LARGE; + net->error= 1; + net->report_error= 1; + net->last_errno= ER_NET_PACKET_TOO_LARGE; return 1; } pkt_length = (length+IO_SIZE-1) & ~(IO_SIZE-1); @@ -147,9 +149,10 @@ static my_bool net_realloc(NET *net, ulong length) NET_HEADER_SIZE + COMP_HEADER_SIZE, MYF(MY_WME)))) { - net->error=1; + net->error= 1; + net->report_error= 1; #ifdef MYSQL_SERVER - net->last_errno=ER_OUT_OF_RESOURCES; + net->last_errno= ER_OUT_OF_RESOURCES; #endif return 1; } @@ -184,14 +187,14 @@ void net_clear(NET *net) /* Flush write_buffer if not empty. */ -int net_flush(NET *net) +my_bool net_flush(NET *net) { - int error=0; + my_bool error= 0; DBUG_ENTER("net_flush"); if (net->buff != net->write_pos) { - error=net_real_write(net,(char*) net->buff, - (ulong) (net->write_pos - net->buff)); + error=test(net_real_write(net,(char*) net->buff, + (ulong) (net->write_pos - net->buff))); net->write_pos=net->buff; } /* Sync packet number if using compression */ @@ -212,7 +215,7 @@ int net_flush(NET *net) ** NOTE: If compression is used the original package is modified! */ -int +my_bool my_net_write(NET *net,const char *packet,ulong len) { uchar buff[NET_HEADER_SIZE]; @@ -243,17 +246,38 @@ my_net_write(NET *net,const char *packet,ulong len) /* Send a command to the server. - As the command is part of the first data packet, we have to do some data - juggling to put the command in there, without having to create a new - packet. - This function will split big packets into sub-packets if needed. - (Each sub packet can only be 2^24 bytes) + + SYNOPSIS + net_write_command() + net NET handler + command Command in MySQL server (enum enum_server_command) + header Header to write after command + head_len Length of header + packet Query or parameter to query + len Length of packet + + DESCRIPTION + The reason for having both header and packet is so that libmysql + can easy add a header to a special command (like prepared statements) + without having to re-alloc the string. + + As the command is part of the first data packet, we have to do some data + juggling to put the command in there, without having to create a new + packet. + This function will split big packets into sub-packets if needed. + (Each sub packet can only be 2^24 bytes) + + RETURN VALUES + 0 ok + 1 error */ -int -net_write_command(NET *net,uchar command,const char *packet,ulong len) +my_bool +net_write_command(NET *net,uchar command, + const char *header, ulong head_len, + const char *packet, ulong len) { - ulong length=len+1; /* 1 extra byte for command */ + ulong length=len+1+head_len; /* 1 extra byte for command */ uchar buff[NET_HEADER_SIZE+1]; uint header_size=NET_HEADER_SIZE+1; buff[4]=command; /* For first packet */ @@ -261,25 +285,28 @@ net_write_command(NET *net,uchar command,const char *packet,ulong len) if (length >= MAX_THREE_BYTES) { /* Take into account that we have the command in the first header */ - len= MAX_THREE_BYTES -1; + len= MAX_THREE_BYTES - 1 - head_len; do { int3store(buff, MAX_THREE_BYTES); buff[3]= (uchar) net->pkt_nr++; if (net_write_buff(net,(char*) buff, header_size) || - net_write_buff(net,packet,len)) + net_write_buff(net, header, head_len) || + net_write_buff(net, packet, len)) return 1; packet+= len; length-= MAX_THREE_BYTES; len=MAX_THREE_BYTES; + head_len=0; header_size=NET_HEADER_SIZE; } while (length >= MAX_THREE_BYTES); len=length; /* Data left to be written */ } int3store(buff,length); buff[3]= (uchar) net->pkt_nr++; - return test(net_write_buff(net,(char*) buff,header_size) || - net_write_buff(net,packet,len) || net_flush(net)); + return test(net_write_buff(net, (char*) buff, header_size) || + (head_len && net_write_buff(net, (char*) header, head_len)) || + net_write_buff(net, packet, len) || net_flush(net)); } /* @@ -287,7 +314,7 @@ net_write_command(NET *net,uchar command,const char *packet,ulong len) One can force the buffer to be flushed with 'net_flush'. */ -static int +static my_bool net_write_buff(NET *net,const char *packet,ulong len) { ulong left_length=(ulong) (net->buff_end - net->write_pos); @@ -345,10 +372,12 @@ net_real_write(NET *net,const char *packet,ulong len) COMP_HEADER_SIZE, MYF(MY_WME)))) { #ifdef MYSQL_SERVER - net->last_errno=ER_OUT_OF_RESOURCES; - net->error=2; + net->last_errno= ER_OUT_OF_RESOURCES; + net->error= 2; + //TODO is it needed to set this variable if we have no socket + net->report_error= 1; #endif - net->reading_or_writing=0; + net->reading_or_writing= 0; DBUG_RETURN(1); } memcpy(b+header_length,packet,len); @@ -398,9 +427,10 @@ net_real_write(NET *net,const char *packet,ulong len) my_progname,vio_errno(net->vio)); #endif /* EXTRA_DEBUG */ #ifdef MYSQL_SERVER - net->last_errno=ER_NET_ERROR_ON_WRITE; + net->last_errno= ER_NET_ERROR_ON_WRITE; #endif - net->error=2; /* Close socket */ + net->error= 2; /* Close socket */ + net->report_error= 1; goto end; } retry_count=0; @@ -426,7 +456,8 @@ net_real_write(NET *net,const char *packet,ulong len) continue; } #endif /* defined(THREAD_SAFE_CLIENT) && !defined(MYSQL_SERVER) */ - net->error=2; /* Close socket */ + net->error= 2; /* Close socket */ + net->report_error= 1; #ifdef MYSQL_SERVER net->last_errno= (interrupted ? ER_NET_WRITE_INTERRUPTED : ER_NET_ERROR_ON_WRITE); @@ -562,9 +593,10 @@ my_real_read(NET *net, ulong *complen) my_progname,vio_errno(net->vio)); #endif /* EXTRA_DEBUG */ len= packet_error; - net->error=2; /* Close socket */ + net->error= 2; /* Close socket */ + net->report_error= 1; #ifdef MYSQL_SERVER - net->last_errno=ER_NET_FCNTL_ERROR; + net->last_errno= ER_NET_FCNTL_ERROR; #endif goto end; } @@ -594,7 +626,8 @@ my_real_read(NET *net, ulong *complen) remain,vio_errno(net->vio), length, thr_got_alarm(&alarmed))); len= packet_error; - net->error=2; /* Close socket */ + net->error= 2; /* Close socket */ + net->report_error= 1; #ifdef MYSQL_SERVER net->last_errno= (interrupted ? ER_NET_READ_INTERRUPTED : ER_NET_READ_ERROR); @@ -624,6 +657,7 @@ my_real_read(NET *net, ulong *complen) #endif } len= packet_error; + net->report_error= 1; #ifdef MYSQL_SERVER net->last_errno=ER_NET_PACKETS_OUT_OF_ORDER; #endif @@ -797,7 +831,8 @@ my_net_read(NET *net) if (my_uncompress((byte*) net->buff + net->where_b, &packet_len, &complen)) { - net->error=2; /* caller will close socket */ + net->error= 2; /* caller will close socket */ + net->report_error= 1; #ifdef MYSQL_SERVER net->last_errno=ER_NET_UNCOMPRESS_ERROR; #endif @@ -817,13 +852,3 @@ my_net_read(NET *net) #endif /* HAVE_COMPRESS */ return len; } - -bool net_request_file(NET* net, const char* fname) -{ - char tmp [FN_REFLEN+1],*end; - DBUG_ENTER("net_request_file"); - tmp[0] = (char) 251; /* NULL_LENGTH */ - end=strnmov(tmp+1,fname,sizeof(tmp)-2); - DBUG_RETURN(my_net_write(net,tmp,(uint) (end-tmp)) || - net_flush(net)); -} diff --git a/sql/opt_range.cc b/sql/opt_range.cc index f33a2d312b4..b6f81ab07eb 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -174,8 +174,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) { @@ -298,9 +299,6 @@ static SEL_TREE * get_mm_parts(PARAM *param,Field *field, Item_result cmp_type); static SEL_ARG *get_mm_leaf(PARAM *param,Field *field,KEY_PART *key_part, Item_func::Functype type,Item *value); -static bool like_range(const char *ptr,uint length,char wild_prefix, - uint field_length, char *min_str,char *max_str, - char max_sort_char,uint *min_length,uint *max_length); static SEL_TREE *get_mm_tree(PARAM *param,COND *cond); static ha_rows check_quick_select(PARAM *param,uint index,SEL_ARG *key_tree); static ha_rows check_quick_keys(PARAM *param,uint index,SEL_ARG *key_tree, @@ -661,6 +659,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; } @@ -678,6 +678,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++) @@ -928,7 +929,7 @@ get_mm_leaf(PARAM *param, Field *field, KEY_PART *key_part, { bool like_error; char buff1[MAX_FIELD_WIDTH],*min_str,*max_str; - String tmp(buff1,sizeof(buff1)),*res; + String tmp(buff1,sizeof(buff1),default_charset_info),*res; uint length,offset,min_length,max_length; if (!field->optimize_range((uint) key_part->key)) @@ -966,25 +967,14 @@ get_mm_leaf(PARAM *param, Field *field, KEY_PART *key_part, max_str=min_str+length; if (maybe_null) max_str[0]= min_str[0]=0; - if (field->binary()) - like_error=like_range(res->ptr(),res->length(),wild_prefix,field_length, - min_str+offset,max_str+offset,(char) 255, - &min_length,&max_length); - else - { -#ifdef USE_STRCOLL - if (use_strcoll(default_charset_info)) - like_error= my_like_range(default_charset_info, - res->ptr(),res->length(),wild_prefix, - field_length, min_str+maybe_null, - max_str+maybe_null,&min_length,&max_length); - else -#endif - 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); - } + + like_error= my_like_range(field->charset(), + res->ptr(),res->length(), + wild_prefix,wild_one,wild_many, + field_length, + min_str+offset, max_str+offset, + &min_length,&max_length); + if (like_error) // Can't optimize with LIKE DBUG_RETURN(0); if (offset != maybe_null) // Blob @@ -1024,7 +1014,7 @@ get_mm_leaf(PARAM *param, Field *field, KEY_PART *key_part, field->cmp_type() != value->result_type()) DBUG_RETURN(0); - if (value->save_in_field(field)) + if (value->save_in_field(field) > 0) { // TODO; Check if we can we remove the following block. if (type == Item_func::EQUAL_FUNC) @@ -1046,7 +1036,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); @@ -1071,73 +1061,45 @@ get_mm_leaf(PARAM *param, Field *field, KEY_PART *key_part, case Item_func::GE_FUNC: tree->max_flag=NO_MAX_RANGE; break; - default: - break; - } - DBUG_RETURN(tree); -} - + 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; -/* -** Calculate min_str and max_str that ranges a LIKE string. -** Arguments: -** ptr Pointer to LIKE string. -** ptr_length Length of LIKE string. -** escape Escape character in LIKE. (Normally '\'). -** All escape characters should be removed from min_str and max_str -** res_length Length of min_str and max_str. -** min_str Smallest case sensitive string that ranges LIKE. -** Should be space padded to res_length. -** max_str Largest case sensitive string that ranges LIKE. -** Normally padded with the biggest character sort value. -** -** The function should return 0 if ok and 1 if the LIKE string can't be -** optimized ! -*/ + 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; -static bool like_range(const char *ptr,uint ptr_length,char escape, - uint res_length, char *min_str,char *max_str, - char max_sort_chr, uint *min_length, uint *max_length) -{ - const char *end=ptr+ptr_length; - char *min_org=min_str; - char *min_end=min_str+res_length; + 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; - for (; ptr != end && min_str != min_end ; ptr++) - { - if (*ptr == escape && ptr+1 != end) - { - ptr++; // Skip escape - *min_str++= *max_str++ = *ptr; - continue; - } - if (*ptr == wild_one) // '_' in SQL - { - *min_str++='\0'; // This should be min char - *max_str++=max_sort_chr; - continue; - } - if (*ptr == wild_many) // '%' in SQL - { - *min_length= (uint) (min_str - min_org); - *max_length=res_length; - do { - *min_str++ = ' '; // Because if key compression - *max_str++ = max_sort_chr; - } while (min_str != min_end); - return 0; - } - *min_str++= *max_str++ = *ptr; + default: + break; } - *min_length= *max_length = (uint) (min_str - min_org); - - /* Temporary fix for handling wild_one at end of string (key compression) */ - for (char *tmp= min_str ; tmp > min_org && tmp[-1] == '\0';) - *--tmp=' '; - - while (min_str != min_end) - *min_str++ = *max_str++ = ' '; // Because if key compression - return 0; + DBUG_RETURN(tree); } @@ -2192,18 +2154,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; @@ -2299,19 +2273,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); @@ -2444,13 +2423,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) @@ -2459,6 +2444,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 local_error; @@ -2469,13 +2471,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) @@ -2623,20 +2626,28 @@ int QUICK_SELECT_DESC::get_next() } else { + DBUG_ASSERT(range->flag & NEAR_MAX || range_reads_after_key(range)); +#ifdef NOT_IMPLEMENTED_YET + result=file->index_read(record, (byte*) range->max_key, + range->max_length, + ((range->flag & NEAR_MAX) ? + HA_READ_BEFORE_KEY : HA_READ_PREFIX_LAST_OR_PREV)); +#else /* Heikki changed Sept 11, 2002: since InnoDB does not store the cursor position if READ_KEY_EXACT is used to a primary key with all key columns specified, we must use below HA_READ_KEY_OR_NEXT, so that InnoDB stores the cursor position and is able to move the cursor one step backward after the search. */ - DBUG_ASSERT(range->flag & NEAR_MAX || range_reads_after_key(range)); /* Note: even if max_key is only a prefix, HA_READ_AFTER_KEY will * do the right thing - go past all keys which match the prefix */ + result=file->index_read(record, (byte*) range->max_key, range->max_length, ((range->flag & NEAR_MAX) ? HA_READ_KEY_OR_NEXT : HA_READ_AFTER_KEY)); result = file->index_prev(record); +#endif } if (result) { @@ -2769,7 +2780,7 @@ static void print_key(KEY_PART *key_part,const char *key,uint used_length) { char buff[1024]; - String tmp(buff,sizeof(buff)); + String tmp(buff,sizeof(buff),default_charset_info); for (uint length=0; length < used_length ; diff --git a/sql/opt_range.h b/sql/opt_range.h index af977eb3093..e96c3792f24 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; diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc index 4b6a196051e..1477d46e756 100644 --- a/sql/opt_sum.cc +++ b/sql/opt_sum.cc @@ -364,7 +364,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/procedure.h b/sql/procedure.h index 349908a8d84..c3280b951d3 100644 --- a/sql/procedure.h +++ b/sql/procedure.h @@ -62,7 +62,7 @@ public: { value=atof(str); } double val() { return value; } longlong val_int() { return (longlong) value; } - String *val_str(String *s) { s->set(value,decimals); return s; } + String *val_str(String *s) { s->set(value,decimals,thd_charset()); return s; } unsigned int size_of() { return sizeof(*this);} }; @@ -80,7 +80,7 @@ public: { value=strtoll(str,NULL,10); } double val() { return (double) value; } longlong val_int() { return value; } - String *val_str(String *s) { s->set(value); return s; } + String *val_str(String *s) { s->set(value, thd_charset()); return s; } unsigned int size_of() { return sizeof(*this);} }; @@ -92,9 +92,9 @@ public: { this->max_length=length; } enum Item_result result_type () const { return STRING_RESULT; } enum_field_types field_type() const { return FIELD_TYPE_STRING; } - void set(double nr) { str_value.set(nr); } - void set(longlong nr) { str_value.set(nr); } - void set(const char *str, uint length) { str_value.copy(str,length); } + void set(double nr) { str_value.set(nr, 2, thd_charset()); } + void set(longlong nr) { str_value.set(nr, thd_charset()); } + void set(const char *str, uint length) { str_value.copy(str,length, thd_charset()); } double val() { return atof(str_value.ptr()); } longlong val_int() { return strtoll(str_value.ptr(),NULL,10); } String *val_str(String*) diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc index 4ebb2f5b476..785a253b1ac 100644 --- a/sql/repl_failsafe.cc +++ b/sql/repl_failsafe.cc @@ -184,7 +184,7 @@ err: my_message(ER_UNKNOWN_ERROR, "Wrong parameters to function register_slave", MYF(0)); err2: - send_error(&thd->net); + send_error(thd); return 1; } @@ -203,7 +203,7 @@ extern "C" 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, (hash_free_key) slave_info_free, 0); pthread_mutex_init(&LOCK_slave_list, MY_MUTEX_INIT_FAST); } @@ -441,7 +441,7 @@ int show_new_master(THD* thd) net_store_data(packet, (longlong)lex_mi->pos); if (my_net_write(&thd->net, packet->ptr(), packet->length())) DBUG_RETURN(-1); - send_eof(&thd->net); + send_eof(thd); DBUG_RETURN(0); } } @@ -456,7 +456,7 @@ int update_slave_list(MYSQL* mysql) int port_ind; DBUG_ENTER("update_slave_list"); - if (mc_mysql_query(mysql,"SHOW SLAVE HOSTS",0) || + if (mc_mysql_query(mysql,"SHOW SLAVE HOSTS",16) || !(res = mc_mysql_store_result(mysql))) { error = "Query error"; @@ -620,7 +620,7 @@ int show_slave_hosts(THD* thd) } } pthread_mutex_unlock(&LOCK_slave_list); - send_eof(net); + send_eof(thd); DBUG_RETURN(0); } @@ -706,7 +706,7 @@ int load_master_data(THD* thd) (error=terminate_slave_threads(active_mi,restart_thread_mask, 1 /*skip lock*/))) { - send_error(&thd->net,error); + send_error(thd,error); unlock_slave_threads(active_mi); UNLOCK_ACTIVE_MI; return 1; @@ -714,7 +714,7 @@ int load_master_data(THD* thd) if (connect_to_master(thd, &mysql, active_mi)) { - net_printf(&thd->net, error= ER_CONNECT_TO_MASTER, + net_printf(thd, error= ER_CONNECT_TO_MASTER, mc_mysql_error(&mysql)); goto err; } @@ -724,10 +724,10 @@ int load_master_data(THD* thd) MYSQL_RES *db_res, **table_res, **table_res_end, **cur_table_res; uint num_dbs; - if (mc_mysql_query(&mysql, "show databases", 0) || + if (mc_mysql_query(&mysql, "SHOW DATABASES", 14) || !(db_res = mc_mysql_store_result(&mysql))) { - net_printf(&thd->net, error = ER_QUERY_ON_MASTER, + net_printf(thd, error = ER_QUERY_ON_MASTER, mc_mysql_error(&mysql)); goto err; } @@ -741,7 +741,7 @@ int load_master_data(THD* thd) if (!(table_res = (MYSQL_RES**)thd->alloc(num_dbs * sizeof(MYSQL_RES*)))) { - net_printf(&thd->net, error = ER_OUTOFMEMORY); + net_printf(thd, error = ER_OUTOFMEMORY); goto err; } @@ -751,11 +751,11 @@ int load_master_data(THD* thd) we wait to issue FLUSH TABLES WITH READ LOCK for as long as we can to minimize the lock time. */ - if (mc_mysql_query(&mysql, "FLUSH TABLES WITH READ LOCK", 0) || - mc_mysql_query(&mysql, "SHOW MASTER STATUS",0) || + if (mc_mysql_query(&mysql, "FLUSH TABLES WITH READ LOCK", 27) || + mc_mysql_query(&mysql, "SHOW MASTER STATUS",18) || !(master_status_res = mc_mysql_store_result(&mysql))) { - net_printf(&thd->net, error = ER_QUERY_ON_MASTER, + net_printf(thd, error = ER_QUERY_ON_MASTER, mc_mysql_error(&mysql)); goto err; } @@ -795,16 +795,16 @@ int load_master_data(THD* thd) if (mysql_rm_db(thd, db, 1,1) || mysql_create_db(thd, db, 0, 1)) { - send_error(&thd->net, 0, 0); + send_error(thd, 0, 0); cleanup_mysql_results(db_res, cur_table_res - 1, table_res); goto err; } if (mc_mysql_select_db(&mysql, db) || - mc_mysql_query(&mysql, "show tables", 0) || + mc_mysql_query(&mysql, "SHOW TABLES", 11) || !(*cur_table_res = mc_mysql_store_result(&mysql))) { - net_printf(&thd->net, error = ER_QUERY_ON_MASTER, + net_printf(thd, error = ER_QUERY_ON_MASTER, mc_mysql_error(&mysql)); cleanup_mysql_results(db_res, cur_table_res - 1, table_res); goto err; @@ -845,9 +845,9 @@ int load_master_data(THD* thd) mc_mysql_free_result(master_status_res); } - if (mc_mysql_query(&mysql, "UNLOCK TABLES", 0)) + if (mc_mysql_query(&mysql, "UNLOCK TABLES", 13)) { - net_printf(&thd->net, error = ER_QUERY_ON_MASTER, + net_printf(thd, error = ER_QUERY_ON_MASTER, mc_mysql_error(&mysql)); goto err; } @@ -857,7 +857,7 @@ int load_master_data(THD* thd) 0 /* not only reset, but also reinit */, &errmsg)) { - send_error(&thd->net, 0, "Failed purging old relay logs"); + send_error(thd, 0, "Failed purging old relay logs"); unlock_slave_threads(active_mi); UNLOCK_ACTIVE_MI; return 1; @@ -885,7 +885,7 @@ err: mc_mysql_close(&mysql); // safe to call since we always do mc_mysql_init() if (!error) - send_ok(&thd->net); + send_ok(thd); return error; } diff --git a/sql/set_var.cc b/sql/set_var.cc index 0675f7b4286..599c4af06cc 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -24,8 +24,9 @@ - Use one of the 'sys_var... classes from set_var.h or write a specific one for the variable type. - Define it in the 'variable definition list' in this file. - - If the variable should be changeable, it should be added to the - 'list of all variables' list in this file. + - If the variable should be changeable or one should be able to access it + with @@variable_name, it should be added to the 'list of all variables' + list in this file. - If the variable should be changed from the command line, add a definition of it in the my_option structure list in mysqld.dcc - If the variable should show up in 'show variables' add it to the @@ -82,6 +83,8 @@ static void fix_net_retry_count(THD *thd, enum_var_type type); static void fix_max_join_size(THD *thd, enum_var_type type); static void fix_query_cache_size(THD *thd, enum_var_type type); static void fix_key_buffer_size(THD *thd, enum_var_type type); +static byte *get_error_count(THD *thd); +static byte *get_warning_count(THD *thd); /* Variable definition list @@ -147,16 +150,20 @@ sys_var_long_ptr sys_max_connect_errors("max_connect_errors", &max_connect_errors); sys_var_long_ptr sys_max_delayed_threads("max_delayed_threads", &max_insert_delayed_threads); +sys_var_thd_ulong sys_max_error_count("max_error_count", + &SV::max_error_count); sys_var_thd_ulong sys_max_heap_table_size("max_heap_table_size", &SV::max_heap_table_size); -sys_var_thd_ulong sys_max_join_size("max_join_size", +sys_var_thd_ulonglong sys_max_join_size("max_join_size", &SV::max_join_size, fix_max_join_size); #ifndef TO_BE_DELETED /* Alias for max_join_size */ -sys_var_thd_ulong sys_sql_max_join_size("sql_max_join_size", +sys_var_thd_ulonglong sys_sql_max_join_size("sql_max_join_size", &SV::max_join_size, fix_max_join_size); #endif +sys_var_thd_ulong sys_max_prep_stmt_count("max_prepared_statements", + &SV::max_prep_stmt_count); sys_var_thd_ulong sys_max_sort_length("max_sort_length", &SV::max_sort_length); sys_var_long_ptr sys_max_user_connections("max_user_connections", @@ -218,8 +225,6 @@ sys_var_thd_ulong sys_tmp_table_size("tmp_table_size", &SV::tmp_table_size); sys_var_thd_ulong sys_net_wait_timeout("wait_timeout", &SV::net_wait_timeout); - - /* Variables that are bits in THD */ @@ -275,12 +280,21 @@ static sys_var_thd_bit sys_unique_checks("unique_checks", /* Local state variables */ -static sys_var_thd_ulong sys_select_limit("sql_select_limit", +static sys_var_thd_ulonglong sys_select_limit("sql_select_limit", &SV::select_limit); static sys_var_timestamp sys_timestamp("timestamp"); static sys_var_last_insert_id sys_last_insert_id("last_insert_id"); static sys_var_last_insert_id sys_identity("identity"); static sys_var_insert_id sys_insert_id("insert_id"); +static sys_var_readonly sys_error_count("error_count", + OPT_SESSION, + SHOW_LONG, + get_error_count); +static sys_var_readonly sys_warning_count("warning_count", + OPT_SESSION, + SHOW_LONG, + get_warning_count); + /* alias for last_insert_id() to be compatible with Sybase */ static sys_var_slave_skip_counter sys_slave_skip_counter("sql_slave_skip_counter"); static sys_var_rand_seed1 sys_rand_seed1("rand_seed1"); @@ -311,6 +325,7 @@ sys_var *sys_variables[]= &sys_delayed_insert_limit, &sys_delayed_insert_timeout, &sys_delayed_queue_size, + &sys_error_count, &sys_flush, &sys_flush_time, &sys_foreign_key_checks, @@ -333,8 +348,10 @@ sys_var *sys_variables[]= &sys_max_connect_errors, &sys_max_connections, &sys_max_delayed_threads, + &sys_max_error_count, &sys_max_heap_table_size, &sys_max_join_size, + &sys_max_prep_stmt_count, &sys_max_sort_length, &sys_max_tmp_tables, &sys_max_user_connections, @@ -376,7 +393,8 @@ sys_var *sys_variables[]= &sys_timestamp, &sys_tmp_table_size, &sys_tx_isolation, - &sys_unique_checks + &sys_unique_checks, + &sys_warning_count }; @@ -466,9 +484,11 @@ struct show_var_st init_vars[]= { {sys_max_binlog_size.name, (char*) &sys_max_binlog_size, SHOW_SYS}, {sys_max_connections.name, (char*) &sys_max_connections, SHOW_SYS}, {sys_max_connect_errors.name, (char*) &sys_max_connect_errors, SHOW_SYS}, + {sys_max_error_count.name, (char*) &sys_max_error_count, SHOW_SYS}, {sys_max_delayed_threads.name,(char*) &sys_max_delayed_threads, SHOW_SYS}, {sys_max_heap_table_size.name,(char*) &sys_max_heap_table_size, SHOW_SYS}, {sys_max_join_size.name, (char*) &sys_max_join_size, SHOW_SYS}, + {sys_max_prep_stmt_count.name,(char*) &sys_max_prep_stmt_count, SHOW_SYS}, {sys_max_sort_length.name, (char*) &sys_max_sort_length, SHOW_SYS}, {sys_max_user_connections.name,(char*) &sys_max_user_connections, SHOW_SYS}, {sys_max_tmp_tables.name, (char*) &sys_max_tmp_tables, SHOW_SYS}, @@ -500,6 +520,10 @@ struct show_var_st init_vars[]= { {sys_query_cache_size.name, (char*) &sys_query_cache_size, SHOW_SYS}, {sys_query_cache_type.name, (char*) &sys_query_cache_type, SHOW_SYS}, #endif /* HAVE_QUERY_CACHE */ +#ifdef HAVE_SMEM + {"shared_memory", (char*) &opt_enable_shared_memory, SHOW_MY_BOOL}, + {"shared_memory_base_name", (char*) &shared_memory_base_name, SHOW_CHAR_PTR}, +#endif {sys_server_id.name, (char*) &sys_server_id, SHOW_SYS}, {sys_slave_net_timeout.name,(char*) &sys_slave_net_timeout, SHOW_SYS}, {"skip_external_locking", (char*) &my_disable_locking, SHOW_MY_BOOL}, @@ -523,7 +547,7 @@ struct show_var_st init_vars[]= { {"timezone", time_zone, SHOW_CHAR}, #endif {sys_tmp_table_size.name, (char*) &sys_tmp_table_size, SHOW_SYS}, - {"tmpdir", (char*) &mysql_tmpdir, SHOW_CHAR_PTR}, + {"tmpdir", (char*) &opt_mysql_tmpdir, SHOW_CHAR_PTR}, {"version", server_version, SHOW_CHAR}, {sys_net_wait_timeout.name, (char*) &sys_net_wait_timeout, SHOW_SYS}, {NullS, NullS, SHOW_LONG} @@ -576,7 +600,7 @@ static void fix_max_join_size(THD *thd, enum_var_type type) { if (type != OPT_GLOBAL) { - if (thd->variables.max_join_size == (ulong) HA_POS_ERROR) + if (thd->variables.max_join_size == (ulonglong) HA_POS_ERROR) thd->options|= OPTION_BIG_SELECTS; else thd->options&= ~OPTION_BIG_SELECTS; @@ -751,7 +775,7 @@ bool sys_var_thd_ulonglong::update(THD *thd, set_var *var) void sys_var_thd_ulonglong::set_default(THD *thd, enum_var_type type) { if (type == OPT_GLOBAL) - global_system_variables.*offset= (ulong) option_limits->def_value; + global_system_variables.*offset= (ulonglong) option_limits->def_value; else thd->variables.*offset= global_system_variables.*offset; } @@ -795,7 +819,7 @@ byte *sys_var_thd_bool::value_ptr(THD *thd, enum_var_type type) bool sys_var::check_enum(THD *thd, set_var *var, TYPELIB *enum_names) { char buff[80], *value; - String str(buff,sizeof(buff)), *res; + String str(buff, sizeof(buff), system_charset_info), *res; if (var->value->result_type() == STRING_RESULT) { @@ -833,6 +857,10 @@ err: We have to use netprintf() instead of my_error() here as this is called on the parsing stage. + + TODO: + With prepared statements/stored procedures this has to be fixed + to create an item that gets the current value at fix_fields() stage. */ Item *sys_var::item(THD *thd, enum_var_type var_type) @@ -841,7 +869,7 @@ Item *sys_var::item(THD *thd, enum_var_type var_type) { if (var_type != OPT_DEFAULT) { - net_printf(&thd->net, + net_printf(thd, var_type == OPT_GLOBAL ? ER_LOCAL_VARIABLE : ER_GLOBAL_VARIABLE, name); return 0; @@ -859,10 +887,10 @@ Item *sys_var::item(THD *thd, enum_var_type var_type) case SHOW_CHAR: { char *str= (char*) value_ptr(thd, var_type); - return new Item_string(str,strlen(str)); + return new Item_string(str, strlen(str), system_charset_info); } default: - net_printf(&thd->net, ER_VAR_CANT_BE_READ, name); + net_printf(thd, ER_VAR_CANT_BE_READ, name); } return 0; } @@ -920,7 +948,7 @@ bool sys_var_thd_conv_charset::check(THD *thd, set_var *var) { CONVERT *tmp; char buff[80]; - String str(buff,sizeof(buff)), *res; + String str(buff,sizeof(buff), system_charset_info), *res; if (!var->value) // Default value { @@ -1115,6 +1143,21 @@ static bool set_log_update(THD *thd, set_var *var) return 0; } +static byte *get_warning_count(THD *thd) +{ + thd->sys_var_tmp.long_value= + (thd->warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_NOTE] + + thd->warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_WARN]); + return (byte*) &thd->sys_var_tmp.long_value; +} + +static byte *get_error_count(THD *thd) +{ + thd->sys_var_tmp.long_value= + thd->warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_ERROR]; + return (byte*) &thd->sys_var_tmp.long_value; +} + /**************************************************************************** Main handling of variables: @@ -1176,7 +1219,8 @@ void set_var_init() { extern struct my_option my_long_options[]; // From mysqld - hash_init(&system_variable_hash,array_elements(sys_variables),0,0, + hash_init(&system_variable_hash, system_charset_info, + array_elements(sys_variables),0,0, (hash_get_key) get_sys_var_length,0, HASH_CASE_INSENSITIVE); sys_var **var, **end; for (var= sys_variables, end= sys_variables+array_elements(sys_variables) ; @@ -1228,7 +1272,7 @@ sys_var *find_sys_var(const char *str, uint length) length ? length : strlen(str)); if (!var) - net_printf(¤t_thd->net, ER_UNKNOWN_SYSTEM_VARIABLE, (char*) str); + net_printf(current_thd, ER_UNKNOWN_SYSTEM_VARIABLE, (char*) str); return var; } @@ -1300,7 +1344,7 @@ int set_var::check(THD *thd) return 0; } - if (value->fix_fields(thd,0)) + if (value->fix_fields(thd, 0, &value)) return -1; if (var->check_update_type(value->result_type())) { @@ -1329,7 +1373,7 @@ int set_var::update(THD *thd) int set_var_user::check(THD *thd) { - return user_var_item->fix_fields(thd,0) ? -1 : 0; + return user_var_item->fix_fields(thd,0, (Item**) 0) ? -1 : 0; } diff --git a/sql/set_var.h b/sql/set_var.h index a171c4f5e76..de1e27e0da8 100644 --- a/sql/set_var.h +++ b/sql/set_var.h @@ -39,6 +39,7 @@ typedef bool (*sys_check_func)(THD *, set_var *); typedef bool (*sys_update_func)(THD *, set_var *); typedef void (*sys_after_update_func)(THD *,enum_var_type); typedef void (*sys_set_default_func)(THD *, enum_var_type); +typedef byte *(*sys_value_ptr_func)(THD *thd); class sys_var { @@ -202,6 +203,10 @@ public: sys_var_thd_ulonglong(const char *name_arg, ulonglong SV::*offset_arg) :sys_var_thd(name_arg), offset(offset_arg) {} + sys_var_thd_ulonglong(const char *name_arg, ulonglong SV::*offset_arg, + sys_after_update_func func) + :sys_var_thd(name_arg,func), offset(offset_arg) + {} bool update(THD *thd, set_var *var); void set_default(THD *thd, enum_var_type type); SHOW_TYPE type() { return SHOW_LONGLONG; } @@ -367,6 +372,31 @@ public: }; +/* Variable that you can only read from */ + +class sys_var_readonly: public sys_var +{ +public: + enum_var_type var_type; + SHOW_TYPE show_type; + sys_value_ptr_func value_ptr_func; + sys_var_readonly(const char *name_arg, enum_var_type type, + SHOW_TYPE show_type_arg, + sys_value_ptr_func value_ptr_func_arg) + :sys_var(name_arg), var_type(type), + show_type(show_type_arg), value_ptr_func(value_ptr_func_arg) + {} + bool update(THD *thd, set_var *var) { return 1; } + bool check_default(enum_var_type type) { return 1; } + bool check_type(enum_var_type type) { return type != var_type; } + bool check_update_type(Item_result type) { return 1; } + byte *value_ptr(THD *thd, enum_var_type type) + { + return (*value_ptr_func)(thd); + } + SHOW_TYPE type() { return show_type; } +}; + /**************************************************************************** Classes for parsing of the SET command ****************************************************************************/ @@ -405,7 +435,8 @@ public: if (value_arg && value_arg->type() == Item::FIELD_ITEM) { Item_field *item= (Item_field*) value_arg; - if (!(value=new Item_string(item->field_name, strlen(item->field_name)))) + if (!(value=new Item_string(item->field_name, strlen(item->field_name), + system_charset_info))) value=value_arg; /* Give error message later */ } else diff --git a/sql/share/charsets/Index b/sql/share/charsets/Index index 5cf30682cc0..b2d9fe3e2a1 100644 --- a/sql/share/charsets/Index +++ b/sql/share/charsets/Index @@ -20,19 +20,51 @@ sjis 13 cp1251 14 danish 15 hebrew 16 -# The win1251 character set is deprecated. Please use cp1251 instead. -win1251 17 tis620 18 euc_kr 19 estonia 20 hungarian 21 koi8_ukr 22 +# win1251ukr is depreciated. Use cp1251cias, cp1251csas or cp1251bin instead. win1251ukr 23 gb2312 24 greek 25 win1250 26 croat 27 gbk 28 +# cp1257 is depreciated. +# Use cp1257ltlvciai, cp1257ltlvcsas, cp1257bin, cp1257ltlvcias instead cp1257 29 latin5 30 latin1_de 31 +armscii8 32 +utf8 33 +win1250ch 34 + +ucs2 35 +cp866 36 +keybcs2 37 + +macce 38 +macroman 39 + +pclatin2 40 +latvian 41 +latvian1 42 +maccebin 43 +macceciai 44 +maccecias 45 +maccecsas 46 +latin1bin 47 +latin1cias 48 +latin1csas 49 +cp1251bin 50 +cp1251cias 51 +cp1251csas 52 +macromanbin 53 +macromancias 54 +macromanciai 55 +macromancsas 56 +cp1256 57 + +binary 63 diff --git a/sql/share/charsets/armscii8.conf b/sql/share/charsets/armscii8.conf new file mode 100644 index 00000000000..54d2d0fec47 --- /dev/null +++ b/sql/share/charsets/armscii8.conf @@ -0,0 +1,93 @@ +# 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 + + +# Unicode mapping (256 elements) +0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F +0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F +0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F +0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F +0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F +0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F +0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F +0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F +0080 0081 0082 0083 0084 0085 0086 0087 0088 0089 008A 008B 008C 008D 008E 008F +0090 0091 0092 0093 0094 0095 0096 0097 0098 0099 009A 009B 009C 009D 009E 009F +00A0 2741 00A7 0589 0029 0028 00BB 00AB 2014 002E 055D 002C 002D 055F 2026 055C +055B 055E 0531 0561 0532 0562 0533 0563 0534 0564 0535 0565 0536 0566 0537 0567 +0538 0568 0539 0569 053A 056A 053B 056B 053C 056C 053D 056D 053E 056E 053F 056F +0540 0570 0541 0571 0542 0572 0543 0573 0544 0574 0545 0575 0546 0576 0547 0577 +0548 0578 0549 0579 054A 057A 054B 057B 054C 057C 054D 057D 054E 057E 054F 057F +0550 0580 0551 0581 0552 0582 0553 0583 0554 0584 0555 0585 0556 0586 2019 0027 diff --git a/sql/share/charsets/cp1251.conf b/sql/share/charsets/cp1251.conf index 6af97c891b8..ee72c6e7b27 100644 --- a/sql/share/charsets/cp1251.conf +++ b/sql/share/charsets/cp1251.conf @@ -72,3 +72,22 @@ 6C 6D 6E 6F 70 71 72 73 74 75 76 77 78 79 7A 7B 5B 5C 5D 5E 5F 60 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 + +# Unicode mapping (must be 256 elements) + 0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F + 0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F + 0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F + 0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F + 0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F + 0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F + 0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F + 0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F + 0402 0403 201A 0453 201E 2026 2020 2021 0000 2030 0409 2039 040A 040C 040B 040F + 0452 2018 2019 201C 201D 2022 2013 2014 0000 2122 0459 203A 045A 045C 045B 045F + 00A0 040E 045E 0408 00A4 0490 00A6 00A7 0401 00A9 0404 00AB 00AC 00AD 00AE 0407 + 00B0 00B1 0406 0456 0491 00B5 00B6 00B7 0451 2116 0454 00BB 0458 0405 0455 0457 + 0410 0411 0412 0413 0414 0415 0416 0417 0418 0419 041A 041B 041C 041D 041E 041F + 0420 0421 0422 0423 0424 0425 0426 0427 0428 0429 042A 042B 042C 042D 042E 042F + 0430 0431 0432 0433 0434 0435 0436 0437 0438 0439 043A 043B 043C 043D 043E 043F + 0440 0441 0442 0443 0444 0445 0446 0447 0448 0449 044A 044B 044C 044D 044E 044F + diff --git a/sql/share/charsets/cp1251bin.conf b/sql/share/charsets/cp1251bin.conf new file mode 100644 index 00000000000..4c17fee5934 --- /dev/null +++ b/sql/share/charsets/cp1251bin.conf @@ -0,0 +1,95 @@ +# +# cp1251 +# Binary sort order +# +# ctype array (must be 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 00 + 01 01 00 02 00 00 00 00 00 00 01 00 01 01 01 01 + 02 00 00 00 00 00 00 00 00 00 02 00 02 02 02 02 + 00 01 02 01 00 01 00 00 01 00 01 00 00 00 00 01 + 00 00 01 02 02 00 00 00 02 00 02 00 02 01 02 02 + 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 + 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 + 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 + 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 + +# to_lower array (must be 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 54 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 54 75 76 77 78 79 7A 7B 7C 7D 7E 7F + 90 83 82 83 84 85 86 87 88 89 9A 8B 9C 9D 9E 9F + 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F + A0 A2 A2 BC A4 B4 A6 A7 B8 A9 BA AB AC AD AE BF + B0 B1 B3 B3 B4 B5 B6 B7 B8 B9 BA BB BC BE BE BF + 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 + 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 + +# to_upper array (must be 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 74 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 74 55 56 57 58 59 5A 7B 7C 7D 7E 7F + 80 81 82 81 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F + 80 91 92 93 94 95 96 97 98 99 8A 9B 8C 9D 8E 8F + A0 A1 A1 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF + B0 B1 B2 B2 A5 B5 B6 B7 A8 B9 AA BB A3 BD BD AF + 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 + 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 + +# sort_order array (must be 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 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 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 + +# Unicode mapping (must be 256 elements) + 0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F + 0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F + 0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F + 0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F + 0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F + 0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F + 0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F + 0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F + 0402 0403 201A 0453 201E 2026 2020 2021 0000 2030 0409 2039 040A 040C 040B 040F + 0452 2018 2019 201C 201D 2022 2013 2014 0000 2122 0459 203A 045A 045C 045B 045F + 00A0 040E 045E 0408 00A4 0490 00A6 00A7 0401 00A9 0404 00AB 00AC 00AD 00AE 0407 + 00B0 00B1 0406 0456 0491 00B5 00B6 00B7 0451 2116 0454 00BB 0458 0405 0455 0457 + 0410 0411 0412 0413 0414 0415 0416 0417 0418 0419 041A 041B 041C 041D 041E 041F + 0420 0421 0422 0423 0424 0425 0426 0427 0428 0429 042A 042B 042C 042D 042E 042F + 0430 0431 0432 0433 0434 0435 0436 0437 0438 0439 043A 043B 043C 043D 043E 043F + 0440 0441 0442 0443 0444 0445 0446 0447 0448 0449 044A 044B 044C 044D 044E 044F + diff --git a/sql/share/charsets/cp1251cias.conf b/sql/share/charsets/cp1251cias.conf new file mode 100644 index 00000000000..612be640b11 --- /dev/null +++ b/sql/share/charsets/cp1251cias.conf @@ -0,0 +1,99 @@ +# +# cp1251 +# Case insensitive, accent sensitive +# Sort order is correct for Belarusian, Bulgarian, Macedonian, +# Russian, Serbian, Mongolian languages. Almost good for Ukrainian, +# except that "CYRILLIC LETTER SOFT SIGN" is not in the end of alphabet, +# but between YERU and E. +# +# ctype array (must be 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 00 + 01 01 00 02 00 00 00 00 00 00 01 00 01 01 01 01 + 02 00 00 00 00 00 00 00 00 00 02 00 02 02 02 02 + 00 01 02 01 00 01 00 00 01 00 01 00 00 00 00 01 + 00 00 01 02 02 00 00 00 02 00 02 00 02 01 02 02 + 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 + 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 + 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 + 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 + +# to_lower array (must be 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 54 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 54 75 76 77 78 79 7A 7B 7C 7D 7E 7F + 90 83 82 83 84 85 86 87 88 89 9A 8B 9C 9D 9E 9F + 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F + A0 A2 A2 BC A4 B4 A6 A7 B8 A9 BA AB AC AD AE BF + B0 B1 B3 B3 B4 B5 B6 B7 B8 B9 BA BB BC BE BE BF + 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 + 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 + +# to_upper array (must be 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 74 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 74 55 56 57 58 59 5A 7B 7C 7D 7E 7F + 80 81 82 81 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F + 80 91 92 93 94 95 96 97 98 99 8A 9B 8C 9D 8E 8F + A0 A1 A1 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF + B0 B1 B2 B2 A5 B5 B6 B7 A8 B9 AA BB A3 BD BD AF + 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 + 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 + +# sort_order array (must be 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 43 45 47 49 4B 4D 4F 51 53 55 57 59 5B 5D + 5F 61 63 65 67 69 6B 6D 6F 71 73 D3 D4 D5 D6 D7 + D8 41 43 45 47 49 4B 4D 4F 51 53 55 57 59 5B 5D + 5F 61 63 65 67 69 6B 6D 6F 71 73 D9 DA DB DC DD + 81 83 DE 83 DF E0 E1 E2 E3 E4 A1 E5 A7 9D B3 C1 + 81 E6 E7 E8 E9 EA EB EC ED EE A1 EF A7 9D B3 C1 + F0 B7 B7 99 F1 7D F2 F3 87 F4 89 F5 F6 F7 F8 95 + F9 FA 93 93 7D FB FC FD 87 FE 89 FF 99 8F 8F 95 + 75 77 79 7B 7F 85 8B 8D 91 97 9B 9F A3 A5 A9 AB + AD AF B1 B5 B9 BB BD BF C3 C5 C7 C9 CB CD CF D1 + 75 77 79 7B 7F 85 8B 8D 91 97 9B 9F A3 A5 A9 AB + AD AF B1 B5 B9 BB BD BF C3 C5 C7 C9 CB CD CF D1 + +# Unicode mapping (must be 256 elements) + 0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F + 0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F + 0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F + 0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F + 0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F + 0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F + 0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F + 0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F + 0402 0403 201A 0453 201E 2026 2020 2021 0000 2030 0409 2039 040A 040C 040B 040F + 0452 2018 2019 201C 201D 2022 2013 2014 0000 2122 0459 203A 045A 045C 045B 045F + 00A0 040E 045E 0408 00A4 0490 00A6 00A7 0401 00A9 0404 00AB 00AC 00AD 00AE 0407 + 00B0 00B1 0406 0456 0491 00B5 00B6 00B7 0451 2116 0454 00BB 0458 0405 0455 0457 + 0410 0411 0412 0413 0414 0415 0416 0417 0418 0419 041A 041B 041C 041D 041E 041F + 0420 0421 0422 0423 0424 0425 0426 0427 0428 0429 042A 042B 042C 042D 042E 042F + 0430 0431 0432 0433 0434 0435 0436 0437 0438 0439 043A 043B 043C 043D 043E 043F + 0440 0441 0442 0443 0444 0445 0446 0447 0448 0449 044A 044B 044C 044D 044E 044F + diff --git a/sql/share/charsets/cp1251csas.conf b/sql/share/charsets/cp1251csas.conf new file mode 100644 index 00000000000..b6b2f853ea9 --- /dev/null +++ b/sql/share/charsets/cp1251csas.conf @@ -0,0 +1,99 @@ +# +# cp1251 +# Case sensitive, accent sensitive +# Sort order is correct for Belarusian, Bulgarian, Macedonian, +# Russian, Serbian, Mongolian languages. Almost good for Ukrainian, +# except that "CYRILLIC LETTER SOFT SIGN" is not in the end of alphabet, +# but between YERU and E. +# +# ctype array (must be 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 00 + 01 01 00 02 00 00 00 00 00 00 01 00 01 01 01 01 + 02 00 00 00 00 00 00 00 00 00 02 00 02 02 02 02 + 00 01 02 01 00 01 00 00 01 00 01 00 00 00 00 01 + 00 00 01 02 02 00 00 00 02 00 02 00 02 01 02 02 + 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 + 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 + 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 + 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 + +# to_lower array (must be 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 54 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 54 75 76 77 78 79 7A 7B 7C 7D 7E 7F + 90 83 82 83 84 85 86 87 88 89 9A 8B 9C 9D 9E 9F + 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F + A0 A2 A2 BC A4 B4 A6 A7 B8 A9 BA AB AC AD AE BF + B0 B1 B3 B3 B4 B5 B6 B7 B8 B9 BA BB BC BE BE BF + 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 + 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 + +# to_upper array (must be 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 74 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 74 55 56 57 58 59 5A 7B 7C 7D 7E 7F + 80 81 82 81 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F + 80 91 92 93 94 95 96 97 98 99 8A 9B 8C 9D 8E 8F + A0 A1 A1 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF + B0 B1 B2 B2 A5 B5 B6 B7 A8 B9 AA BB A3 BD BD AF + 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 + 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 + +# sort_order array (must be 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 43 45 47 49 4B 4D 4F 51 53 55 57 59 5B 5D + 5F 61 63 65 67 69 6B 6D 6F 71 73 D3 D4 D5 D6 D7 + D8 42 44 46 48 4A 4C 4E 50 52 54 56 58 5A 5C 5E + 60 62 64 66 68 6A 6C 6E 70 72 74 D9 DA DB DC DD + 81 83 DE 84 DF E0 E1 E2 E3 E4 A1 E5 A7 9D B3 C1 + 82 E6 E7 E8 E9 EA EB EC ED EE A2 EF A8 9E B4 C2 + F0 B7 B8 99 F1 7D F2 F3 87 F4 89 F5 F6 F7 F8 95 + F9 FA 93 94 7E FB FC FD 88 FE 8A FF 9A 8F 90 96 + 75 77 79 7B 7F 85 8B 8D 91 97 9B 9F A3 A5 A9 AB + AD AF B1 B5 B9 BB BD BF C3 C5 C7 C9 CB CD CF D1 + 76 78 7A 7C 80 86 8C 8E 92 98 9C A0 A4 A6 AA AC + AE B0 B2 B6 BA BC BE C0 C4 C6 C8 CA CC CE D0 D2 + +# Unicode mapping (must be 256 elements) + 0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F + 0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F + 0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F + 0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F + 0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F + 0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F + 0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F + 0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F + 0402 0403 201A 0453 201E 2026 2020 2021 0000 2030 0409 2039 040A 040C 040B 040F + 0452 2018 2019 201C 201D 2022 2013 2014 0000 2122 0459 203A 045A 045C 045B 045F + 00A0 040E 045E 0408 00A4 0490 00A6 00A7 0401 00A9 0404 00AB 00AC 00AD 00AE 0407 + 00B0 00B1 0406 0456 0491 00B5 00B6 00B7 0451 2116 0454 00BB 0458 0405 0455 0457 + 0410 0411 0412 0413 0414 0415 0416 0417 0418 0419 041A 041B 041C 041D 041E 041F + 0420 0421 0422 0423 0424 0425 0426 0427 0428 0429 042A 042B 042C 042D 042E 042F + 0430 0431 0432 0433 0434 0435 0436 0437 0438 0439 043A 043B 043C 043D 043E 043F + 0440 0441 0442 0443 0444 0445 0446 0447 0448 0449 044A 044B 044C 044D 044E 044F + diff --git a/sql/share/charsets/cp1256.conf b/sql/share/charsets/cp1256.conf new file mode 100644 index 00000000000..6072551813c --- /dev/null +++ b/sql/share/charsets/cp1256.conf @@ -0,0 +1,94 @@ +# +# Arabic, Persian, Pakistani, Urdu +# +# ctype array (must be 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 00 00 + 00 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 03 00 02 00 00 00 00 00 00 00 00 01 03 03 00 + 03 10 10 10 10 00 00 00 00 00 00 00 02 00 00 00 + 00 10 00 00 00 00 00 00 00 00 00 10 10 10 00 00 + 10 10 00 00 00 00 00 00 00 00 10 10 00 00 00 10 + 00 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 + 03 03 03 03 03 03 03 00 03 03 03 03 03 03 03 03 + 02 03 02 03 03 03 03 02 02 02 02 02 03 03 02 02 + 03 03 03 03 02 03 03 00 03 02 03 02 02 00 00 00 + +# to_lower array (must be 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 54 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 54 75 76 77 78 79 7A 7B 7C 7D 7E 7F + 80 81 82 83 84 85 86 87 88 89 8A 8B 9C 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 + +# to_upper array (must be 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 74 55 56 57 58 59 5A 5B 5C 5F 5E 5F + 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F + 50 51 52 53 74 55 56 57 58 59 5A 7B 7C 7F 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 8C 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 + +# sort_order array (must be 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 45 47 4A 4C 52 55 57 59 5D 5F 61 63 65 67 + 6C 6E 70 72 74 76 7B 7D 7F 81 83 B9 BA BB BC BD + BE 41 45 47 4A 4C 52 55 57 59 5D 5F 61 63 65 67 + 6C 6E 70 72 74 76 7B 7D 7F 81 83 BF C0 C1 C2 C3 + C4 8E C5 54 C6 C7 C8 C9 CA CB CC CD 6A 92 99 CE + A5 CF D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 6A DA DB DC + DD B6 DE DF E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB + EC ED EE EF F0 F1 F2 F3 F4 F5 B7 F6 F7 F8 F9 B8 + FA 85 86 87 88 89 8A 8B 8C 8D 9F 90 91 93 94 95 + 96 97 98 9A 9B 9C 9D FB 9E 9F A0 A1 AD A2 A3 A4 + 43 A6 44 A7 A8 A9 AA 49 4E 4F 50 51 AB AC 5B 5C + AE AF B0 B1 69 B2 B3 FC B4 78 B5 79 7A FD FE FF + +# Unicode mapping (must be 256 elements) + 0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F + 0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F + 0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F + 0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F + 0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F + 0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F + 0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F + 0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F + 20AC 067E 201A 0192 201E 2026 2020 2021 02C6 2030 0000 2039 0152 0686 0698 0000 + 06AF 2018 2019 201C 201D 2022 2013 2014 0000 2122 0000 203A 0153 200C 200D 0000 + 00A0 060C 00A2 00A3 00A4 00A5 00A6 00A7 00A8 00A9 0000 00AB 00AC 00AD 00AE 00AF + 00B0 00B1 00B2 00B3 00B4 00B5 00B6 00B7 00B8 00B9 061B 00BB 00BC 00BD 00BE 061F + 0000 0621 0622 0623 0624 0625 0626 0627 0628 0629 062A 062B 062C 062D 062E 062F + 0630 0631 0632 0633 0634 0635 0636 00D7 0637 0638 0639 063A 0640 0641 0642 0643 + 00E0 0644 00E2 0645 0646 0647 0648 00E7 00E8 00E9 00EA 00EB 0649 064A 00EE 00EF + 064B 064C 064D 064E 00F4 064F 0650 00F7 0651 00F9 0652 00FB 00FC 200E 200F 0000 + diff --git a/sql/share/charsets/cp1257.conf b/sql/share/charsets/cp1257.conf index 610ed5a646f..8338f99c83b 100644 --- a/sql/share/charsets/cp1257.conf +++ b/sql/share/charsets/cp1257.conf @@ -72,3 +72,21 @@ 5A FF FF FF FF FF FF FF 5E FF FF 5D FF FF FF FF FF 4F FF FF FF FF 48 FF 45 FF FF 49 FF FF FF FF 5A FF FF FF FF FF FF FF 5E FF FF 5D FF FF FF FF + +# Unicode mapping (256 elements) +0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F +0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F +0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F +0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F +0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F +0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F +0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F +0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F +20AC 0000 201A 0000 201E 2026 2020 2021 0000 2030 0000 2039 0000 00A8 02C7 00B8 +0000 2018 2019 201C 201D 2022 2013 2014 0000 2122 0000 203A 0000 00AF 02DB 0000 +00A0 0000 00A2 00A3 00A4 0000 00A6 00A7 00D8 00A9 0156 00AB 00AC 00AD 00AE 00C6 +00B0 00B1 00B2 00B3 00B4 00B5 00B6 00B7 00F8 00B9 0157 00BB 00BC 00BD 00BE 00E6 +0104 012E 0100 0106 00C4 00C5 0118 0112 010C 00C9 0179 0116 0122 0136 012A 013B +0160 0143 0145 00D3 014C 00D5 00D6 00D7 0172 0141 015A 016A 00DC 017B 017D 00DF +0105 012F 0101 0107 00E4 00E5 0119 0113 010D 00E9 017A 0117 0123 0137 012B 013C +0161 0144 0146 00F3 014D 00F5 00F6 00F7 0173 0142 015B 016B 00FC 017C 017E 02D9 diff --git a/sql/share/charsets/cp1257bin.conf b/sql/share/charsets/cp1257bin.conf new file mode 100644 index 00000000000..032f8a7e05d --- /dev/null +++ b/sql/share/charsets/cp1257bin.conf @@ -0,0 +1,96 @@ +# +# cp1257 character set +# +# Binary sorting order +# +# ctype array (must be 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 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 00 + 00 00 00 00 00 00 00 00 01 00 01 00 00 00 00 01 + 00 00 00 00 00 00 00 00 02 00 02 00 00 00 00 02 + 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 + 01 01 01 01 01 01 01 00 01 01 01 01 01 01 01 02 + 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 + 02 02 02 02 02 02 02 00 02 02 02 02 02 02 02 00 + +# to_lower array (must be 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 BA AB AC AD AE BF + B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF + E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF + F0 F1 F2 F3 F4 F5 F6 D7 F8 F9 FA FB FC FD FE 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 + +# to_upper array (must be 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 BA AB AC AD AE AF + B0 B1 B2 B3 B4 B5 B6 B7 A8 B9 BA BB BC BD BE AF + 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 + C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF + D0 D1 D2 D3 D4 D5 D6 F7 D8 D9 DA DB DC DD DE FF + +# sort_order array (must be 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 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 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 + +# Unicode mapping (must be 256 elements) + 0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F + 0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F + 0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F + 0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F + 0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F + 0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F + 0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F + 0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F + 20AC 0000 201A 0000 201E 2026 2020 2021 0000 2030 0000 2039 0000 00A8 02C7 00B8 + 0000 2018 2019 201C 201D 2022 2013 2014 0000 2122 0000 203A 0000 00AF 02DB 0000 + 00A0 0000 00A2 00A3 00A4 0000 00A6 00A7 00D8 00A9 0156 00AB 00AC 00AD 00AE 00C6 + 00B0 00B1 00B2 00B3 00B4 00B5 00B6 00B7 00F8 00B9 0157 00BB 00BC 00BD 00BE 00E6 + 0104 012E 0100 0106 00C4 00C5 0118 0112 010C 00C9 0179 0116 0122 0136 012A 013B + 0160 0143 0145 00D3 014C 00D5 00D6 00D7 0172 0141 015A 016A 00DC 017B 017D 00DF + 0105 012F 0101 0107 00E4 00E5 0119 0113 010D 00E9 017A 0117 0123 0137 012B 013C + 0161 0144 0146 00F3 014D 00F5 00F6 00F7 0173 0142 015B 016B 00FC 017C 017E 02D9 + diff --git a/sql/share/charsets/cp1257ltlvciai.conf b/sql/share/charsets/cp1257ltlvciai.conf new file mode 100644 index 00000000000..246ae4d1fe8 --- /dev/null +++ b/sql/share/charsets/cp1257ltlvciai.conf @@ -0,0 +1,97 @@ +# +# cp1257 character set +# +# Case-insensitive, accent insensitive sorting order +# For Latvian and Lithuanian languages +# +# ctype array (must be 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 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 00 + 00 00 00 00 00 00 00 00 01 00 01 00 00 00 00 01 + 00 00 00 00 00 00 00 00 02 00 02 00 00 00 00 02 + 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 + 01 01 01 01 01 01 01 00 01 01 01 01 01 01 01 02 + 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 + 02 02 02 02 02 02 02 00 02 02 02 02 02 02 02 00 + +# to_lower array (must be 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 BA AB AC AD AE BF + B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF + E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF + F0 F1 F2 F3 F4 F5 F6 D7 F8 F9 FA FB FC FD FE 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 + +# to_upper array (must be 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 BA AB AC AD AE AF + B0 B1 B2 B3 B4 B5 B6 B7 A8 B9 BA BB BC BD BE AF + 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 + C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF + D0 D1 D2 D3 D4 D5 D6 F7 D8 D9 DA DB DC DD DE FF + +# sort_order array (must be 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 4D 4F 55 57 61 63 67 69 6F 71 75 7B 7D 83 + 8F 91 93 97 9E A0 A8 AA AC AE B0 B8 B9 BA BB BC + BD 41 4D 4F 55 57 61 63 67 69 6F 71 75 7B 7D 83 + 8F 91 93 97 9E A0 A8 AA AC AE B0 BE BF C0 C1 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 83 ED 93 EE EF F0 F1 41 + F2 F3 F4 F5 F6 F7 F8 F9 83 FA 93 FB FC FD FE 41 + 41 69 41 4F 41 41 57 57 4F 57 B0 57 63 71 69 75 + 97 7D 7D 83 83 83 83 C2 A0 75 97 A0 A0 B0 B0 97 + 41 69 41 4F 41 41 57 57 4F 57 B0 57 63 71 69 75 + 97 7D 7D 83 83 83 83 C3 A0 75 97 A0 A0 B0 B0 FF + +# Unicode mapping (must be 256 elements) + 0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F + 0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F + 0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F + 0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F + 0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F + 0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F + 0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F + 0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F + 20AC 0000 201A 0000 201E 2026 2020 2021 0000 2030 0000 2039 0000 00A8 02C7 00B8 + 0000 2018 2019 201C 201D 2022 2013 2014 0000 2122 0000 203A 0000 00AF 02DB 0000 + 00A0 0000 00A2 00A3 00A4 0000 00A6 00A7 00D8 00A9 0156 00AB 00AC 00AD 00AE 00C6 + 00B0 00B1 00B2 00B3 00B4 00B5 00B6 00B7 00F8 00B9 0157 00BB 00BC 00BD 00BE 00E6 + 0104 012E 0100 0106 00C4 00C5 0118 0112 010C 00C9 0179 0116 0122 0136 012A 013B + 0160 0143 0145 00D3 014C 00D5 00D6 00D7 0172 0141 015A 016A 00DC 017B 017D 00DF + 0105 012F 0101 0107 00E4 00E5 0119 0113 010D 00E9 017A 0117 0123 0137 012B 013C + 0161 0144 0146 00F3 014D 00F5 00F6 00F7 0173 0142 015B 016B 00FC 017C 017E 02D9 + diff --git a/sql/share/charsets/cp1257ltlvcias.conf b/sql/share/charsets/cp1257ltlvcias.conf new file mode 100644 index 00000000000..6e49f5a245d --- /dev/null +++ b/sql/share/charsets/cp1257ltlvcias.conf @@ -0,0 +1,97 @@ +# +# cp1257 character set +# +# Case-insensitive, accent sensitive sorting order +# For Latvian and Lithuanian languages +# +# ctype array (must be 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 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 00 + 00 00 00 00 00 00 00 00 01 00 01 00 00 00 00 01 + 00 00 00 00 00 00 00 00 02 00 02 00 00 00 00 02 + 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 + 01 01 01 01 01 01 01 00 01 01 01 01 01 01 01 02 + 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 + 02 02 02 02 02 02 02 00 02 02 02 02 02 02 02 00 + +# to_lower array (must be 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 BA AB AC AD AE BF + B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF + E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF + F0 F1 F2 F3 F4 F5 F6 D7 F8 F9 FA FB FC FD FE 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 + +# to_upper array (must be 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 BA AB AC AD AE AF + B0 B1 B2 B3 B4 B5 B6 B7 A8 B9 BA BB BC BD BE AF + 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 + C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF + D0 D1 D2 D3 D4 D5 D6 F7 D8 D9 DA DB DC DD DE FF + +# sort_order array (must be 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 4D 4F 55 57 61 63 67 69 6F 71 75 7B 7D 83 + 8F 91 93 97 9E A0 A8 AA AC AE B0 B8 B9 BA BB BC + BD 41 4D 4F 55 57 61 63 67 69 6F 71 75 7B 7D 83 + 8F 91 93 97 9E A0 A8 AA AC AE B0 BE BF C0 C1 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 85 ED 95 EE EF F0 F1 4B + F2 F3 F4 F5 F6 F7 F8 F9 85 FA 95 FB FC FD FE 4B + 43 6B 45 51 47 49 59 5B 53 5D B2 5F 65 73 6D 77 + 99 7F 81 87 89 8B 8D C2 A2 79 9B A4 A6 B4 B6 9D + 43 6B 45 51 47 49 59 5B 53 5D B2 5F 65 73 6D 77 + 99 7F 81 87 89 8B 8D C3 A2 79 9B A4 A6 B4 B6 FF + +# Unicode mapping (must be 256 elements) + 0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F + 0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F + 0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F + 0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F + 0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F + 0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F + 0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F + 0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F + 20AC 0000 201A 0000 201E 2026 2020 2021 0000 2030 0000 2039 0000 00A8 02C7 00B8 + 0000 2018 2019 201C 201D 2022 2013 2014 0000 2122 0000 203A 0000 00AF 02DB 0000 + 00A0 0000 00A2 00A3 00A4 0000 00A6 00A7 00D8 00A9 0156 00AB 00AC 00AD 00AE 00C6 + 00B0 00B1 00B2 00B3 00B4 00B5 00B6 00B7 00F8 00B9 0157 00BB 00BC 00BD 00BE 00E6 + 0104 012E 0100 0106 00C4 00C5 0118 0112 010C 00C9 0179 0116 0122 0136 012A 013B + 0160 0143 0145 00D3 014C 00D5 00D6 00D7 0172 0141 015A 016A 00DC 017B 017D 00DF + 0105 012F 0101 0107 00E4 00E5 0119 0113 010D 00E9 017A 0117 0123 0137 012B 013C + 0161 0144 0146 00F3 014D 00F5 00F6 00F7 0173 0142 015B 016B 00FC 017C 017E 02D9 + diff --git a/sql/share/charsets/cp1257ltlvcsas.conf b/sql/share/charsets/cp1257ltlvcsas.conf new file mode 100644 index 00000000000..32cd1390bd5 --- /dev/null +++ b/sql/share/charsets/cp1257ltlvcsas.conf @@ -0,0 +1,97 @@ +# +# cp1257 character set +# +# Case-sensitive, accent sensitive sorting order +# For Latvian and Lithuanian languages +# +# ctype array (must be 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 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 00 + 00 00 00 00 00 00 00 00 01 00 01 00 00 00 00 01 + 00 00 00 00 00 00 00 00 02 00 02 00 00 00 00 02 + 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 + 01 01 01 01 01 01 01 00 01 01 01 01 01 01 01 02 + 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 + 02 02 02 02 02 02 02 00 02 02 02 02 02 02 02 00 + +# to_lower array (must be 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 BA AB AC AD AE BF + B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF + E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF + F0 F1 F2 F3 F4 F5 F6 D7 F8 F9 FA FB FC FD FE 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 + +# to_upper array (must be 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 BA AB AC AD AE AF + B0 B1 B2 B3 B4 B5 B6 B7 A8 B9 BA BB BC BD BE AF + 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 + C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF + D0 D1 D2 D3 D4 D5 D6 F7 D8 D9 DA DB DC DD DE FF + +# sort_order array (must be 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 4D 4F 55 57 61 63 67 69 6F 71 75 7B 7D 83 + 8F 91 93 97 9E A0 A8 AA AC AE B0 B8 B9 BA BB BC + BD 42 4E 50 56 58 62 64 68 6A 70 72 76 7C 7E 84 + 90 92 94 98 9F A1 A9 AB AD AF B1 BE BF C0 C1 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 85 ED 95 EE EF F0 F1 4B + F2 F3 F4 F5 F6 F7 F8 F9 86 FA 96 FB FC FD FE 4C + 43 6B 45 51 47 49 59 5B 53 5D B2 5F 65 73 6D 77 + 99 7F 81 87 89 8B 8D C2 A2 79 9B A4 A6 B4 B6 9D + 44 6C 46 52 48 4A 5A 5C 54 5E B3 60 66 74 6E 78 + 9A 80 82 88 8A 8C 8E C3 A3 7A 9C A5 A7 B5 B7 FF + +# Unicode mapping (must be 256 elements) + 0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F + 0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F + 0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F + 0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F + 0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F + 0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F + 0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F + 0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F + 20AC 0000 201A 0000 201E 2026 2020 2021 0000 2030 0000 2039 0000 00A8 02C7 00B8 + 0000 2018 2019 201C 201D 2022 2013 2014 0000 2122 0000 203A 0000 00AF 02DB 0000 + 00A0 0000 00A2 00A3 00A4 0000 00A6 00A7 00D8 00A9 0156 00AB 00AC 00AD 00AE 00C6 + 00B0 00B1 00B2 00B3 00B4 00B5 00B6 00B7 00F8 00B9 0157 00BB 00BC 00BD 00BE 00E6 + 0104 012E 0100 0106 00C4 00C5 0118 0112 010C 00C9 0179 0116 0122 0136 012A 013B + 0160 0143 0145 00D3 014C 00D5 00D6 00D7 0172 0141 015A 016A 00DC 017B 017D 00DF + 0105 012F 0101 0107 00E4 00E5 0119 0113 010D 00E9 017A 0117 0123 0137 012B 013C + 0161 0144 0146 00F3 014D 00F5 00F6 00F7 0173 0142 015B 016B 00FC 017C 017E 02D9 + diff --git a/sql/share/charsets/cp866.conf b/sql/share/charsets/cp866.conf new file mode 100644 index 00000000000..0e4dcb3b9bc --- /dev/null +++ b/sql/share/charsets/cp866.conf @@ -0,0 +1,96 @@ +# +# cp866_DOSCyrillicRussian +# Case insensitive, accent sensitive. +# +# +# ctype array (must be 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 00 + 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 + 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 + 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 + 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 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 + 01 02 01 02 01 02 01 02 00 00 00 00 00 00 00 48 + +# to_lower array (must be 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 + A0 A1 A2 A3 A4 A5 86 87 88 89 AA AB AC AD AE AF + E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF + A0 A1 A2 A3 A4 A5 86 87 88 89 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 + F1 F1 F3 F3 F5 F5 F7 F7 F8 F9 FA FB FC FD FE FF + +# to_upper array (must be 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 + 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F + 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 + 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F + F0 F0 F2 F2 F4 F4 F6 F6 F8 F9 FA FB FC FD FE FF + +# sort_order array (must be 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 43 45 47 49 4B 4D 4F 51 53 55 57 59 5B 5D + 5F 61 63 65 67 69 6B 6D 6F 71 73 BD BE BF C0 C1 + C2 41 43 45 47 49 4B 4D 4F 51 54 55 57 59 5B 5D + 5F 61 63 65 67 69 6B 6D 6F 71 73 C3 C4 C5 C6 C7 + 75 77 79 7B 7D 7F 85 87 89 8D 8F 91 93 95 97 99 + 9B 9D 9F A1 A5 A7 A9 AB AD AF B1 B3 B5 B7 B9 BB + 75 77 79 7B 7D 7F 85 87 89 8D 8F 91 93 95 97 99 + C8 C9 CA 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 + 9B 9D 9F A1 A5 A7 A9 AB AD AF B1 B3 B5 B7 B9 BB + 81 81 83 83 8B 8B A3 A3 CB CC CD CE CF D0 D1 D2 + +# Unicode mapping (must be 256 elements) + 0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F + 0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F + 0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F + 0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F + 0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F + 0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F + 0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F + 0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F + 0410 0411 0412 0413 0414 0415 0416 0417 0418 0419 041A 041B 041C 041D 041E 041F + 0420 0421 0422 0423 0424 0425 0426 0427 0428 0429 042A 042B 042C 042D 042E 042F + 0430 0431 0432 0433 0434 0435 0436 0437 0438 0439 043A 043B 043C 043D 043E 043F + 2591 2592 2593 2502 2524 2561 2562 2556 2555 2563 2551 2557 255D 255C 255B 2510 + 2514 2534 252C 251C 2500 253C 255E 255F 255A 2554 2569 2566 2560 2550 256C 2567 + 2568 2564 2565 2559 2558 2552 2553 256B 256A 2518 250C 2588 2584 258C 2590 2580 + 0440 0441 0442 0443 0444 0445 0446 0447 0448 0449 044A 044B 044C 044D 044E 044F + 0401 0451 0404 0454 0407 0457 040E 045E 00B0 2219 00B7 221A 207F 00B2 25A0 00A0 + diff --git a/sql/share/charsets/croat.conf b/sql/share/charsets/croat.conf index fbbe3328547..bc8c1a376eb 100644 --- a/sql/share/charsets/croat.conf +++ b/sql/share/charsets/croat.conf @@ -72,3 +72,21 @@ 47 4E 4F 4F 4F 4F 5D D7 D8 55 55 55 59 59 DE DF 41 41 41 41 5C 5B 45 43 44 45 45 45 49 49 49 49 47 4E 4F 4F 4F 4F 5D F7 D8 55 55 55 59 59 DE FF + +# Unicode mapping (256 elements) +0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F +0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F +0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F +0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F +0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F +0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F +0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F +0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F +0080 0081 0082 0083 0084 0085 0086 0087 0088 0089 008A 008B 008C 008D 008E 008F +0090 0091 0092 0093 0094 0095 0096 0097 0098 0099 009A 009B 009C 009D 009E 009F +00A0 0104 02D8 0141 00A4 013D 015A 00A7 00A8 0160 015E 0164 0179 00AD 017D 017B +00B0 0105 02DB 0142 00B4 013E 015B 02C7 00B8 0161 015F 0165 017A 02DD 017E 017C +0154 00C1 00C2 0102 00C4 0139 0106 00C7 010C 00C9 0118 00CB 011A 00CD 00CE 010E +0110 0143 0147 00D3 00D4 0150 00D6 00D7 0158 016E 00DA 0170 00DC 00DD 0162 00DF +0155 00E1 00E2 0103 00E4 013A 0107 00E7 010D 00E9 0119 00EB 011B 00ED 00EE 010F +0111 0144 0148 00F3 00F4 0151 00F6 00F7 0159 016F 00FA 0171 00FC 00FD 0163 02D9 diff --git a/sql/share/charsets/danish.conf b/sql/share/charsets/danish.conf index f99590ed6f3..1543a64d7c3 100644 --- a/sql/share/charsets/danish.conf +++ b/sql/share/charsets/danish.conf @@ -72,3 +72,21 @@ 44 4E 4F 4F 4F 4F 5C D7 5C 55 55 55 59 59 DE DF 41 41 41 41 5B 5D 5B 43 45 45 45 45 49 49 49 49 44 4E 4F 4F 4F 4F 5C F7 5C 55 55 55 59 59 DE FF + +# Unicode mapping (256 elements) +0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F +0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F +0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F +0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F +0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F +0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F +0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F +0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F +0080 0081 0082 0083 0084 0085 0086 0087 0088 0089 008A 008B 008C 008D 008E 008F +0090 0091 0092 0093 0094 0095 0096 0097 0098 0099 009A 009B 009C 009D 009E 009F +00A0 00A1 00A2 00A3 00A4 00A5 00A6 00A7 00A8 00A9 00AA 00AB 00AC 00AD 00AE 00AF +00B0 00B1 00B2 00B3 00B4 00B5 00B6 00B7 00B8 00B9 00BA 00BB 00BC 00BD 00BE 00BF +00C0 00C1 00C2 00C3 00C4 00C5 00C6 00C7 00C8 00C9 00CA 00CB 00CC 00CD 00CE 00CF +00D0 00D1 00D2 00D3 00D4 00D5 00D6 00D7 00D8 00D9 00DA 00DB 00DC 00DD 00DE 00DF +00E0 00E1 00E2 00E3 00E4 00E5 00E6 00E7 00E8 00E9 00EA 00EB 00EC 00ED 00EE 00EF +00F0 00F1 00F2 00F3 00F4 00F5 00F6 00F7 00F8 00F9 00FA 00FB 00FC 00FD 00FE 00FF diff --git a/sql/share/charsets/dec8.conf b/sql/share/charsets/dec8.conf index a4849aaa04c..d1ffe45032d 100644 --- a/sql/share/charsets/dec8.conf +++ b/sql/share/charsets/dec8.conf @@ -72,3 +72,21 @@ 44 4E 4F 4F 4F 4F 5D D7 D8 55 55 55 59 59 DE DF 41 41 41 41 5C 5B 5C 43 45 45 45 45 49 49 49 49 44 4E 4F 4F 4F 4F 5D F7 D8 55 55 55 59 59 DE FF + +# Unicode mapping (256 elements) +0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F +0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F +0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F +0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F +0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F +0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F +0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F +0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F +0080 0081 0082 0083 0084 0085 0086 0087 0088 0089 008A 008B 008C 008D 008E 008F +0090 0091 0092 0093 0094 0095 0096 0097 0098 0099 009A 009B 009C 009D 009E 009F +00A0 00A1 00A2 00A3 0000 00A5 0000 00A7 00A4 00A9 00AA 00AB 0000 0000 0000 0000 +00B0 00B1 00B2 00B3 0000 00B5 00B6 00B7 0000 00B9 00BA 00BB 00BC 00BD 0000 00BF +00C0 00C1 00C2 00C3 00C4 00C5 00C6 00C7 00C8 00C9 00CA 00CB 00CC 00CD 00CE 00CF +0000 00D1 00D2 00D3 00D4 00D5 00D6 0152 00D8 00D9 00DA 00DB 00DC 0178 0000 00DF +00E0 00E1 00E2 00E3 00E4 00E5 00E6 00E7 00E8 00E9 00EA 00EB 00EC 00ED 00EE 00EF +0000 00F1 00F2 00F3 00F4 00F5 00F6 0153 00F8 00F9 00FA 00FB 00FC 00FF 0000 0000 diff --git a/sql/share/charsets/dos.conf b/sql/share/charsets/dos.conf index dda86d0f3e8..205202711b8 100644 --- a/sql/share/charsets/dos.conf +++ b/sql/share/charsets/dos.conf @@ -1,4 +1,4 @@ -# Configuration file for the dos character set +# Configuration file for the dos (aka cp437 DOSLatinUS) character set # ctype array (must have 257 elements) 00 @@ -72,3 +72,22 @@ 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 + +# Unicode mapping (256 elements) + +0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000a 000b 000c 000d 000e 000f +0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001a 001b 001c 001d 001e 001f +0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002a 002b 002c 002d 002e 002f +0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003a 003b 003c 003d 003e 003f +0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004a 004b 004c 004d 004e 004f +0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005a 005b 005c 005d 005e 005f +0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006a 006b 006c 006d 006e 006f +0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007a 007b 007c 007d 007e 007f +00c7 00fc 00e9 00e2 00e4 00e0 00e5 00e7 00ea 00eb 00e8 00ef 00ee 00ec 00c4 00c5 +00c9 00e6 00c6 00f4 00f6 00f2 00fb 00f9 00ff 00d6 00dc 00a2 00a3 00a5 20a7 0192 +00e1 00ed 00f3 00fa 00f1 00d1 00aa 00ba 00bf 2310 00ac 00bd 00bc 00a1 00ab 00bb +2591 2592 2593 2502 2524 2561 2562 2556 2555 2563 2551 2557 255d 255c 255b 2510 +2514 2534 252c 251c 2500 253c 255e 255f 255a 2554 2569 2566 2560 2550 256c 2567 +2568 2564 2565 2559 2558 2552 2553 256b 256a 2518 250c 2588 2584 258c 2590 2580 +03b1 00df 0393 03c0 03a3 03c3 00b5 03c4 03a6 0398 03a9 03b4 221e 03c6 03b5 2229 +2261 00b1 2265 2264 2320 2321 00f7 2248 00b0 2219 00b7 221a 207f 00b2 25a0 00a0 diff --git a/sql/share/charsets/estonia.conf b/sql/share/charsets/estonia.conf index 76bbc021b0c..0226fd1fe82 100644 --- a/sql/share/charsets/estonia.conf +++ b/sql/share/charsets/estonia.conf @@ -72,3 +72,21 @@ DB C2 C4 C8 CA F2 F6 64 EC BC D8 EA F8 E1 E3 DA 8D B1 89 95 F5 8B A3 A1 97 9D E0 9F A9 B7 AF BB DC C3 C5 C9 CB F3 F7 65 ED BD D9 EB F9 E2 E4 53 + +# Unicode mapping (256 elements) +0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F +0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F +0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F +0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F +0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F +0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F +0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F +0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F +0080 0081 0082 0083 0084 0085 0086 0087 0088 0089 008A 008B 008C 008D 008E 008F +0090 0091 0092 0093 0094 0095 0096 0097 0098 0099 009A 009B 009C 009D 009E 009F +00A0 201D 00A2 00A3 00A4 201E 00A6 00A7 00D8 00A9 0156 00AB 00AC 00AD 00AE 00C6 +00B0 00B1 00B2 00B3 201C 00B5 00B6 00B7 00F8 00B9 0157 00BB 00BC 00BD 00BE 00E6 +0104 012E 0100 0106 00C4 00C5 0118 0112 010C 00C9 0179 0116 0122 0136 012A 013B +0160 0143 0145 00D3 014C 00D5 00D6 00D7 0172 0141 015A 016A 00DC 017B 017D 00DF +0105 012F 0101 0107 00E4 00E5 0119 0113 010D 00E9 017A 0117 0123 0137 012B 013C +0161 0144 0146 00F3 014D 00F5 00F6 00F7 0173 0142 015B 016B 00FC 017C 017E 2019 diff --git a/sql/share/charsets/german1.conf b/sql/share/charsets/german1.conf index 3090c921ebe..64f27da3499 100644 --- a/sql/share/charsets/german1.conf +++ b/sql/share/charsets/german1.conf @@ -72,3 +72,21 @@ D0 4E 4F 4F 4F 4F 4F D7 4F 55 55 55 55 59 DE 53 41 41 41 41 41 41 41 43 45 45 45 45 49 49 49 49 D0 4E 4F 4F 4F 4F 4F F7 4F 55 55 55 55 59 DE FF + +# Unicode mapping (256 elements) +0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F +0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F +0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F +0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F +0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F +0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F +0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F +0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F +0080 0081 0082 0083 0084 0085 0086 0087 0088 0089 008A 008B 008C 008D 008E 008F +0090 0091 0092 0093 0094 0095 0096 0097 0098 0099 009A 009B 009C 009D 009E 009F +00A0 00A1 00A2 00A3 00A4 00A5 00A6 00A7 00A8 00A9 00AA 00AB 00AC 00AD 00AE 00AF +00B0 00B1 00B2 00B3 00B4 00B5 00B6 00B7 00B8 00B9 00BA 00BB 00BC 00BD 00BE 00BF +00C0 00C1 00C2 00C3 00C4 00C5 00C6 00C7 00C8 00C9 00CA 00CB 00CC 00CD 00CE 00CF +00D0 00D1 00D2 00D3 00D4 00D5 00D6 00D7 00D8 00D9 00DA 00DB 00DC 00DD 00DE 00DF +00E0 00E1 00E2 00E3 00E4 00E5 00E6 00E7 00E8 00E9 00EA 00EB 00EC 00ED 00EE 00EF +00F0 00F1 00F2 00F3 00F4 00F5 00F6 00F7 00F8 00F9 00FA 00FB 00FC 00FD 00FE 00FF diff --git a/sql/share/charsets/greek.conf b/sql/share/charsets/greek.conf index 73d67d6ee71..5eb38e2efbe 100644 --- a/sql/share/charsets/greek.conf +++ b/sql/share/charsets/greek.conf @@ -72,3 +72,22 @@ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 C9 D5 C1 C5 C7 C9 D5 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF D0 D1 D3 D3 D4 D5 D6 D7 D8 D9 C9 D5 CF D5 D9 FF + +# Unicode mapping (256 elements) +0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F +0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F +0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F +0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F +0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F +0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F +0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F +0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F +0080 0081 0082 0083 0084 0085 0086 0087 0088 0089 008A 008B 008C 008D 008E 008F +0090 0091 0092 0093 0094 0095 0096 0097 0098 0099 009A 009B 009C 009D 009E 009F +00A0 02BD 02BC 00A3 0000 0000 00A6 00A7 00A8 00A9 0000 00AB 00AC 00AD 0000 2015 +00B0 00B1 00B2 00B3 0384 0385 0386 00B7 0388 0389 038A 00BB 038C 00BD 038E 038F +0390 0391 0392 0393 0394 0395 0396 0397 0398 0399 039A 039B 039C 039D 039E 039F +03A0 03A1 0000 03A3 03A4 03A5 03A6 03A7 03A8 03A9 03AA 03AB 03AC 03AD 03AE 03AF +03B0 03B1 03B2 03B3 03B4 03B5 03B6 03B7 03B8 03B9 03BA 03BB 03BC 03BD 03BE 03BF +03C0 03C1 03C2 03C3 03C4 03C5 03C6 03C7 03C8 03C9 03CA 03CB 03CC 03CD 03CE 0000 +
\ No newline at end of file diff --git a/sql/share/charsets/hebrew.conf b/sql/share/charsets/hebrew.conf index 6a5f88eb228..84581f6f1bb 100644 --- a/sql/share/charsets/hebrew.conf +++ b/sql/share/charsets/hebrew.conf @@ -72,3 +72,22 @@ D0 D1 D2 D3 D4 D5 D6 F7 D8 D9 DA DB DC DD DE FF 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 + +# Unicode mapping (256 elements) +0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F +0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F +0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F +0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F +0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F +0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F +0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F +0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F +0080 0081 0082 0083 0084 0085 0086 0087 0088 0089 008A 008B 008C 008D 008E 008F +0090 0091 0092 0093 0094 0095 0096 0097 0098 0099 009A 009B 009C 009D 009E 009F +00A0 0000 00A2 00A3 00A4 00A5 00A6 00A7 00A8 00A9 00D7 00AB 00AC 00AD 00AE 203E +00B0 00B1 00B2 00B3 00B4 00B5 00B6 00B7 00B8 00B9 00F7 00BB 00BC 00BD 00BE 0000 +0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 2017 +05D0 05D1 05D2 05D3 05D4 05D5 05D6 05D7 05D8 05D9 05DA 05DB 05DC 05DD 05DE 05DF +05E0 05E1 05E2 05E3 05E4 05E5 05E6 05E7 05E8 05E9 05EA 0000 0000 0000 0000 0000 +
\ No newline at end of file diff --git a/sql/share/charsets/hp8.conf b/sql/share/charsets/hp8.conf index e9fadacbf76..07036d6f186 100644 --- a/sql/share/charsets/hp8.conf +++ b/sql/share/charsets/hp8.conf @@ -72,3 +72,22 @@ 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 + +# Unicode mapping (256 elements) +0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F +0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F +0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F +0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F +0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F +0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F +0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F +0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F +0080 0081 0082 0083 0084 0085 0086 0087 0088 0089 008A 008B 008C 008D 008E 008F +0090 0091 0092 0093 0094 0095 0096 0097 0098 0099 009A 009B 009C 009D 009E 009F +00A0 00C0 00C2 00C8 00CA 00CB 00CE 00CF 00B4 02CB 02C6 00A8 02DC 00D9 00DB 20A4 +00AF 00DD 00FD 00B0 00C7 00E7 00D1 00F1 00A1 00BF 00A4 00A3 00A5 00A7 0192 00A2 +00E2 00EA 00F4 00FB 00E1 00E9 00F3 00FA 00E0 00E8 00F2 00F9 00E4 00EB 00F6 00FC +00C5 00EE 00D8 00C6 00E5 00ED 00F8 00E6 00C4 00EC 00D6 00DC 00C9 00EF 00DF 00D4 +00C1 00C3 00E3 00D0 00F0 00CD 00CC 00D3 00D2 00D5 00F5 0160 0161 00DA 0178 00FF +00DE 00FE 00B7 00B5 00B6 00BE 2014 00BC 00BD 00AA 00BA 00AB 25A0 00BB 00B1 0000 + diff --git a/sql/share/charsets/hungarian.conf b/sql/share/charsets/hungarian.conf index db58d62575f..dffaff9348d 100644 --- a/sql/share/charsets/hungarian.conf +++ b/sql/share/charsets/hungarian.conf @@ -72,3 +72,21 @@ FF 62 63 64 66 67 67 FF 6D 77 75 78 78 7E 74 FF 64 41 44 45 46 5F 49 4B 4A 4E 51 78 50 56 58 4D FF 62 63 64 66 67 67 FF 6D 77 75 78 78 7E 74 FF + +# Unicode mapping (256 elements) +0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F +0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F +0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F +0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F +0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F +0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F +0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F +0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F +0080 0081 0082 0083 0084 0085 0086 0087 0088 0089 008A 008B 008C 008D 008E 008F +0090 0091 0092 0093 0094 0095 0096 0097 0098 0099 009A 009B 009C 009D 009E 009F +00A0 0104 02D8 0141 00A4 013D 015A 00A7 00A8 0160 015E 0164 0179 00AD 017D 017B +00B0 0105 02DB 0142 00B4 013E 015B 02C7 00B8 0161 015F 0165 017A 02DD 017E 017C +0154 00C1 00C2 0102 00C4 0139 0106 00C7 010C 00C9 0118 00CB 011A 00CD 00CE 010E +0110 0143 0147 00D3 00D4 0150 00D6 00D7 0158 016E 00DA 0170 00DC 00DD 0162 00DF +0155 00E1 00E2 0103 00E4 013A 0107 00E7 010D 00E9 0119 00EB 011B 00ED 00EE 010F +0111 0144 0148 00F3 00F4 0151 00F6 00F7 0159 016F 00FA 0171 00FC 00FD 0163 02D9 diff --git a/sql/share/charsets/keybcs2.conf b/sql/share/charsets/keybcs2.conf new file mode 100644 index 00000000000..f272960b683 --- /dev/null +++ b/sql/share/charsets/keybcs2.conf @@ -0,0 +1,91 @@ +# ctype array (must be 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 00 + 01 02 82 02 02 01 01 02 82 81 01 01 02 02 01 01 + 81 02 01 02 02 01 02 01 02 01 01 01 01 01 01 02 + 02 02 02 02 02 01 01 01 02 02 02 01 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 00 00 00 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + 02 02 01 02 01 02 00 02 01 01 01 02 00 02 02 00 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 48 + +# to_lower array (must be 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 + 87 81 82 83 84 83 86 87 88 88 8D A1 8C 8D 84 A0 + 82 91 91 93 94 A2 96 A3 98 94 81 9B 8C 98 A9 9F + A0 A1 A2 A3 A4 A4 96 93 9B A9 AA AA 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 ED E9 EA EB EC ED EE EF + F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF + +# to_upper array (must be 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 68 59 5A 7B 7C 7D 7E 7F + 87 9A 90 85 8E 85 86 80 89 89 8A 8B 9C 8A 8E 8F + 90 92 92 A7 99 95 A6 97 9D 99 9A A8 9C 9D 9E 9F + 8F 8B 95 97 A5 A5 A6 A7 A8 9E AB 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 E8 EE EF + F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF + +# sort_order array (must be 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 44 45 47 49 50 51 52 53 54 55 56 57 58 5A + 5E 5F 60 63 66 68 6C 6D 6E 6F 72 90 91 92 93 94 + 95 41 44 45 47 49 50 51 52 53 54 55 56 57 58 5A + 5E 5F 60 63 66 68 6C 6D 6E 6F 72 96 97 98 99 9A + 45 68 49 47 41 47 66 45 49 49 56 53 56 56 41 41 + 49 72 72 5A 5A 5A 68 68 6F 5A 68 63 56 6F 60 66 + 41 53 5A 68 58 58 68 5A 63 60 60 60 A0 A1 A2 A3 + A4 A5 A6 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 + 80 65 83 87 88 89 DD 8A 85 8B 84 81 DE 85 82 DF + F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF + +# Unicode mappping (must be 256 elements) + 0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F + 0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F + 0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F + 0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F + 0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F + 0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F + 0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F + 0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F + 010C 00FC 00E9 010F 00E4 010E 0164 010D 011B 011A 0139 00CD 013E 013A 00C4 00C1 + 00C9 017E 017D 00F4 00F6 00D3 016F 00DA 00FD 00D6 00DC 0160 013D 00DD 0158 0165 + 00E1 00ED 00F3 00FA 0148 0147 016E 00D4 0161 0159 0155 0154 00BC 00A1 00AB 00BB + 2591 2592 2593 2502 2524 2561 2562 2556 2555 2563 2551 2557 255D 255C 255B 2510 + 2514 2534 252C 251C 2500 253C 255E 255F 255A 2554 2569 2566 2560 2550 256C 2567 + 2568 2564 2565 2559 2558 2552 2553 256B 256A 2518 250C 2588 2584 258C 2590 2580 + 03B1 00DF 0393 03C0 03A3 03C3 00B5 03C4 03A6 0398 03A9 03B4 221E 03C6 03B5 2229 + 2261 00B1 2265 2264 2320 2321 00F7 2248 00B0 2219 00B7 221A 207F 00B2 25A0 00A0 + diff --git a/sql/share/charsets/koi8_ru.conf b/sql/share/charsets/koi8_ru.conf index 4cfee67a236..b1d9755173f 100644 --- a/sql/share/charsets/koi8_ru.conf +++ b/sql/share/charsets/koi8_ru.conf @@ -72,3 +72,22 @@ EF FF F0 F1 F2 F3 E6 E1 FC FB E7 F8 FD F9 F7 FA FE DF E0 F6 E3 E4 F4 E2 F5 E8 E9 EA EB EC ED EE EF FF F0 F1 F2 F3 E6 E1 FC FB E7 F8 FD F9 F7 FA + +# Unicode mapping table (256 elements) + +0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000a 000b 000c 000d 000e 000f +0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001a 001b 001c 001d 001e 001f +0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002a 002b 002c 002d 002e 002f +0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003a 003b 003c 003d 003e 003f +0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004a 004b 004c 004d 004e 004f +0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005a 005b 005c 005d 005e 005f +0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006a 006b 006c 006d 006e 006f +0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007a 007b 007c 007d 007e 007f +2500 2502 250c 2510 2514 2518 251c 2524 252c 2534 253c 2580 2584 2588 258c 2590 +2591 2592 2593 2320 25a0 2219 221a 2248 2264 2265 00a0 2321 00b0 00b2 00b7 00f7 +2550 2551 2552 0451 2553 2554 2555 2556 2557 2558 2559 255a 255b 255c 255d 255e +255f 2560 2561 0401 2562 2563 2564 2565 2566 2567 2568 2569 256a 256b 256c 00a9 +044e 0430 0431 0446 0434 0435 0444 0433 0445 0438 0439 043a 043b 043c 043d 043e +043f 044f 0440 0441 0442 0443 0436 0432 044c 044b 0437 0448 044d 0449 0447 044a +042e 0410 0411 0426 0414 0415 0424 0413 0425 0418 0419 041a 041b 041c 041d 041e +041f 042f 0420 0421 0422 0423 0416 0412 042c 042b 0417 0428 042d 0429 0427 042a diff --git a/sql/share/charsets/koi8_ukr.conf b/sql/share/charsets/koi8_ukr.conf index 3e2c8e27325..5a552900544 100644 --- a/sql/share/charsets/koi8_ukr.conf +++ b/sql/share/charsets/koi8_ukr.conf @@ -72,3 +72,21 @@ 94 A4 95 96 97 98 89 82 A1 A0 8A 9D A2 9E 9C 9F A3 80 81 9B 85 86 99 83 9A 8B 8E 8F 90 91 92 93 94 A4 95 96 97 98 89 82 A1 A0 8A 9D A2 9E 9C 9F + +# Unicode mapping (256 elements) +0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F +0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F +0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F +0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F +0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F +0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F +0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F +0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F +2500 2502 250C 2510 2514 2518 251C 2524 252C 2534 253C 2580 2584 2588 258C 2590 +2591 2592 2593 2320 25A0 2022 221A 2248 2264 2265 00A0 2321 00B0 00B2 00B7 00F7 +2550 2551 2552 0451 0454 2554 0456 0457 2557 2558 2559 255A 255B 0491 255D 255E +255F 2560 2561 0401 0404 2563 0406 0407 2566 2567 2568 2569 256A 0490 256C 00A9 +044E 0430 0431 0446 0434 0435 0444 0433 0445 0438 0439 043A 043B 043C 043D 043E +043F 044F 0440 0441 0442 0443 0436 0432 044C 044B 0437 0448 044D 0449 0447 044A +042E 0410 0411 0426 0414 0415 0424 0413 0425 0418 0419 041A 041B 041C 041D 041E +041F 042F 0420 0421 0422 0423 0416 0412 042C 042B 0417 0428 042D 0429 0427 042A diff --git a/sql/share/charsets/latin1.conf b/sql/share/charsets/latin1.conf index cf974aefa14..7cb5cfb3cfd 100644 --- a/sql/share/charsets/latin1.conf +++ b/sql/share/charsets/latin1.conf @@ -72,3 +72,21 @@ 44 4E 4F 4F 4F 4F 5D D7 D8 55 55 55 59 59 DE DF 41 41 41 41 5C 5B 5C 43 45 45 45 45 49 49 49 49 44 4E 4F 4F 4F 4F 5D F7 D8 55 55 55 59 59 DE FF + +# Unicode mapping (256 elements) +0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F +0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F +0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F +0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F +0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F +0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F +0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F +0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F +0080 0081 0082 0083 0084 0085 0086 0087 0088 0089 008A 008B 008C 008D 008E 008F +0090 0091 0092 0093 0094 0095 0096 0097 0098 0099 009A 009B 009C 009D 009E 009F +00A0 00A1 00A2 00A3 00A4 00A5 00A6 00A7 00A8 00A9 00AA 00AB 00AC 00AD 00AE 00AF +00B0 00B1 00B2 00B3 00B4 00B5 00B6 00B7 00B8 00B9 00BA 00BB 00BC 00BD 00BE 00BF +00C0 00C1 00C2 00C3 00C4 00C5 00C6 00C7 00C8 00C9 00CA 00CB 00CC 00CD 00CE 00CF +00D0 00D1 00D2 00D3 00D4 00D5 00D6 00D7 00D8 00D9 00DA 00DB 00DC 00DD 00DE 00DF +00E0 00E1 00E2 00E3 00E4 00E5 00E6 00E7 00E8 00E9 00EA 00EB 00EC 00ED 00EE 00EF +00F0 00F1 00F2 00F3 00F4 00F5 00F6 00F7 00F8 00F9 00FA 00FB 00FC 00FD 00FE 00FF diff --git a/sql/share/charsets/latin1bin.conf b/sql/share/charsets/latin1bin.conf new file mode 100644 index 00000000000..37e6350bcb2 --- /dev/null +++ b/sql/share/charsets/latin1bin.conf @@ -0,0 +1,96 @@ +# +# Latin1, accent sensitive, case sensitive +# +# Binary sorting order +# +# ctype array (must be 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 + 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 + 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 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 + 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 + 01 01 01 01 01 01 01 00 01 01 01 01 01 01 01 02 + 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 + 02 02 02 02 02 02 02 00 02 02 02 02 02 02 02 02 + +# to_lower array (must be 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 A8 A9 AA AB AC AD AE AF + B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF + E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF + F0 F1 F2 F3 F4 F5 F6 D7 F8 F9 FA FB FC FD FE 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 + +# to_upper array (must be 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 + C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF + D0 D1 D2 D3 D4 D5 D6 F7 D8 D9 DA DB DC DD DE FF + +# sort_order array (must be 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 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 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 + +# Unicode mapping (must be 256 elements) + 0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F + 0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F + 0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F + 0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F + 0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F + 0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F + 0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F + 0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F + 0080 0081 0082 0083 0084 0085 0086 0087 0088 0089 008A 008B 008C 008D 008E 008F + 0090 0091 0092 0093 0094 0095 0096 0097 0098 0099 009A 009B 009C 009D 009E 009F + 00A0 00A1 00A2 00A3 00A4 00A5 00A6 00A7 00A8 00A9 00AA 00AB 00AC 00AD 00AE 00AF + 00B0 00B1 00B2 00B3 00B4 00B5 00B6 00B7 00B8 00B9 00BA 00BB 00BC 00BD 00BE 00BF + 00C0 00C1 00C2 00C3 00C4 00C5 00C6 00C7 00C8 00C9 00CA 00CB 00CC 00CD 00CE 00CF + 00D0 00D1 00D2 00D3 00D4 00D5 00D6 00D7 00D8 00D9 00DA 00DB 00DC 00DD 00DE 00DF + 00E0 00E1 00E2 00E3 00E4 00E5 00E6 00E7 00E8 00E9 00EA 00EB 00EC 00ED 00EE 00EF + 00F0 00F1 00F2 00F3 00F4 00F5 00F6 00F7 00F8 00F9 00FA 00FB 00FC 00FD 00FE 00FF + diff --git a/sql/share/charsets/latin1cias.conf b/sql/share/charsets/latin1cias.conf new file mode 100644 index 00000000000..3b0e104aafd --- /dev/null +++ b/sql/share/charsets/latin1cias.conf @@ -0,0 +1,97 @@ +# +# Latin1, accent sensitive, case insensitive +# +# Sorting for Dutch, English, French, German (Duden), +# Italian, Latin, Pogtuguese, Spanish +# +# ctype array (must be 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 + 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 + 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 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 + 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 + 01 01 01 01 01 01 01 00 01 01 01 01 01 01 01 02 + 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 + 02 02 02 02 02 02 02 00 02 02 02 02 02 02 02 02 + +# to_lower array (must be 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 A8 A9 AA AB AC AD AE AF + B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF + E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF + F0 F1 F2 F3 F4 F5 F6 D7 F8 F9 FA FB FC FD FE 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 + +# to_upper array (must be 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 + C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF + D0 D1 D2 D3 D4 D5 D6 F7 D8 D9 DA DB DC DD DE FF + +# sort_order array (must be 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 51 53 57 5B 65 67 69 6B 75 77 79 7B 7D 81 + 8F 91 93 95 98 9A A4 A6 A8 AA AF B3 B4 B5 B6 B7 + B8 41 51 53 57 5B 65 67 69 6B 75 77 79 7B 7D 81 + 8F 91 93 95 98 9A A4 A6 A8 AA AF B9 BA BB BC 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 + 43 45 47 49 4B 4D 4F 55 5D 5F 61 63 6D 6F 71 73 + 59 7F 83 85 87 89 8B BD 8D 9C 9E A0 A2 AC B1 97 + 43 45 47 49 4B 4D 4F 55 5D 5F 61 63 6D 6F 71 73 + 59 7F 83 85 87 89 8B BE 8D 9C 9E A0 A2 AC B1 AE + +# Unicode mapping (must be 256 elements) + 0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F + 0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F + 0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F + 0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F + 0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F + 0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F + 0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F + 0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F + 0080 0081 0082 0083 0084 0085 0086 0087 0088 0089 008A 008B 008C 008D 008E 008F + 0090 0091 0092 0093 0094 0095 0096 0097 0098 0099 009A 009B 009C 009D 009E 009F + 00A0 00A1 00A2 00A3 00A4 00A5 00A6 00A7 00A8 00A9 00AA 00AB 00AC 00AD 00AE 00AF + 00B0 00B1 00B2 00B3 00B4 00B5 00B6 00B7 00B8 00B9 00BA 00BB 00BC 00BD 00BE 00BF + 00C0 00C1 00C2 00C3 00C4 00C5 00C6 00C7 00C8 00C9 00CA 00CB 00CC 00CD 00CE 00CF + 00D0 00D1 00D2 00D3 00D4 00D5 00D6 00D7 00D8 00D9 00DA 00DB 00DC 00DD 00DE 00DF + 00E0 00E1 00E2 00E3 00E4 00E5 00E6 00E7 00E8 00E9 00EA 00EB 00EC 00ED 00EE 00EF + 00F0 00F1 00F2 00F3 00F4 00F5 00F6 00F7 00F8 00F9 00FA 00FB 00FC 00FD 00FE 00FF + diff --git a/sql/share/charsets/latin1csas.conf b/sql/share/charsets/latin1csas.conf new file mode 100644 index 00000000000..cb3a1285de8 --- /dev/null +++ b/sql/share/charsets/latin1csas.conf @@ -0,0 +1,97 @@ +# +# Latin1, accent sensitive, case sensitive +# +# Sorting for Dutch, English, French, German (Duden), +# Italian, Latin, Pogtuguese, Spanish +# +# ctype array (must be 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 + 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 + 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 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 + 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 + 01 01 01 01 01 01 01 00 01 01 01 01 01 01 01 02 + 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 + 02 02 02 02 02 02 02 00 02 02 02 02 02 02 02 02 + +# to_lower array (must be 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 A8 A9 AA AB AC AD AE AF + B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF + E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF + F0 F1 F2 F3 F4 F5 F6 D7 F8 F9 FA FB FC FD FE 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 + +# to_upper array (must be 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 + C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF + D0 D1 D2 D3 D4 D5 D6 F7 D8 D9 DA DB DC DD DE FF + +# sort_order array (must be 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 51 53 57 5B 65 67 69 6B 75 77 79 7B 7D 81 + 8F 91 93 95 98 9A A4 A6 A8 AA AF B3 B4 B5 B6 B7 + B8 42 52 54 58 5C 66 68 6A 6C 76 78 7A 7C 7E 82 + 90 92 94 96 99 9B A5 A7 A9 AB B0 B9 BA BB BC 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 + 43 45 47 49 4B 4D 4F 55 5D 5F 61 63 6D 6F 71 73 + 59 7F 83 85 87 89 8B BD 8D 9C 9E A0 A2 AC B1 97 + 44 46 48 4A 4C 4E 50 56 5E 60 62 64 6E 70 72 74 + 5A 80 84 86 88 8A 8C BE 8E 9D 9F A1 A3 AD B2 AE + +# Unicode mapping (must be 256 elements) + 0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F + 0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F + 0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F + 0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F + 0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F + 0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F + 0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F + 0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F + 0080 0081 0082 0083 0084 0085 0086 0087 0088 0089 008A 008B 008C 008D 008E 008F + 0090 0091 0092 0093 0094 0095 0096 0097 0098 0099 009A 009B 009C 009D 009E 009F + 00A0 00A1 00A2 00A3 00A4 00A5 00A6 00A7 00A8 00A9 00AA 00AB 00AC 00AD 00AE 00AF + 00B0 00B1 00B2 00B3 00B4 00B5 00B6 00B7 00B8 00B9 00BA 00BB 00BC 00BD 00BE 00BF + 00C0 00C1 00C2 00C3 00C4 00C5 00C6 00C7 00C8 00C9 00CA 00CB 00CC 00CD 00CE 00CF + 00D0 00D1 00D2 00D3 00D4 00D5 00D6 00D7 00D8 00D9 00DA 00DB 00DC 00DD 00DE 00DF + 00E0 00E1 00E2 00E3 00E4 00E5 00E6 00E7 00E8 00E9 00EA 00EB 00EC 00ED 00EE 00EF + 00F0 00F1 00F2 00F3 00F4 00F5 00F6 00F7 00F8 00F9 00FA 00FB 00FC 00FD 00FE 00FF + diff --git a/sql/share/charsets/latin2.conf b/sql/share/charsets/latin2.conf index cc18c22c0a2..cc21af9faa1 100644 --- a/sql/share/charsets/latin2.conf +++ b/sql/share/charsets/latin2.conf @@ -72,3 +72,21 @@ FF 55 54 57 56 56 56 FF 5A 5F 5F 5F 5F 63 5E FF 5A 43 43 43 43 51 46 45 47 49 4A 49 49 4E 4E 48 FF 55 54 57 56 56 56 FF 5A 5F 5F 5F 5F 63 5E FF + +# Unicode mapping (256 elements) +0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F +0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F +0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F +0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F +0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F +0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F +0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F +0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F +0080 0081 0082 0083 0084 0085 0086 0087 0088 0089 008A 008B 008C 008D 008E 008F +0090 0091 0092 0093 0094 0095 0096 0097 0098 0099 009A 009B 009C 009D 009E 009F +00A0 0104 02D8 0141 00A4 013D 015A 00A7 00A8 0160 015E 0164 0179 00AD 017D 017B +00B0 0105 02DB 0142 00B4 013E 015B 02C7 00B8 0161 015F 0165 017A 02DD 017E 017C +0154 00C1 00C2 0102 00C4 0139 0106 00C7 010C 00C9 0118 00CB 011A 00CD 00CE 010E +0110 0143 0147 00D3 00D4 0150 00D6 00D7 0158 016E 00DA 0170 00DC 00DD 0162 00DF +0155 00E1 00E2 0103 00E4 013A 0107 00E7 010D 00E9 0119 00EB 011B 00ED 00EE 010F +0111 0144 0148 00F3 00F4 0151 00F6 00F7 0159 016F 00FA 0171 00FC 00FD 0163 02D9 diff --git a/sql/share/charsets/latin5.conf b/sql/share/charsets/latin5.conf index 92fbd2299bb..d603d019ce6 100644 --- a/sql/share/charsets/latin5.conf +++ b/sql/share/charsets/latin5.conf @@ -76,3 +76,21 @@ 49 DB DC DD DE DF 53 E0 E1 E2 E3 E4 5B 4C 58 E5 CC CD CE CF D0 D1 D2 44 D3 D4 D5 D6 D7 D8 D9 DA 49 DB DC DD DE DF 53 FA E1 E2 E3 E4 5B 4B 58 FF + +# Unicode mapping (256 elements) +0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F +0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F +0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F +0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F +0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F +0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F +0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F +0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F +0080 0081 0082 0083 0084 0085 0086 0087 0088 0089 008A 008B 008C 008D 008E 008F +0090 0091 0092 0093 0094 0095 0096 0097 0098 0099 009A 009B 009C 009D 009E 009F +00A0 00A1 00A2 00A3 00A4 00A5 00A6 00A7 00A8 00A9 00AA 00AB 00AC 00AD 00AE 00AF +00B0 00B1 00B2 00B3 00B4 00B5 00B6 00B7 00B8 00B9 00BA 00BB 00BC 00BD 00BE 00BF +00C0 00C1 00C2 00C3 00C4 00C5 00C6 00C7 00C8 00C9 00CA 00CB 00CC 00CD 00CE 00CF +011E 00D1 00D2 00D3 00D4 00D5 00D6 00D7 00D8 00D9 00DA 00DB 00DC 0130 015E 00DF +00E0 00E1 00E2 00E3 00E4 00E5 00E6 00E7 00E8 00E9 00EA 00EB 00EC 00ED 00EE 00EF +011F 00F1 00F2 00F3 00F4 00F5 00F6 00F7 00F8 00F9 00FA 00FB 00FC 0131 015F 00FF diff --git a/sql/share/charsets/latvian.conf b/sql/share/charsets/latvian.conf new file mode 100644 index 00000000000..c3dee95d55c --- /dev/null +++ b/sql/share/charsets/latvian.conf @@ -0,0 +1,95 @@ +# Configuration file for the latvian character set. +# Created for case-sensitive record search +# Created accord with windows-1257 (iso-8859-4) codepage +# Created by Andis Grasis & Rihards Grasis e-mail:andis@cata.lv + +# The 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 + 01 20 10 20 10 10 00 00 20 10 20 10 20 10 10 10 + 20 10 10 10 10 10 10 10 20 00 20 10 20 10 10 20 + 48 20 10 10 10 20 10 10 10 10 01 10 10 10 10 01 + 10 10 10 10 10 10 10 10 10 10 02 10 10 10 10 02 + 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 + 01 01 01 01 01 01 01 10 01 01 01 01 01 01 01 02 + 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 + 02 02 02 02 02 02 02 10 02 02 02 02 02 02 02 10 + +# The 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 BA AB AC AD AE BF + B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF + E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF + F0 F1 F2 F3 F4 F5 F6 D7 F8 F9 FA FB FC FD FE 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 + +# The 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 B3 B4 B5 B6 B7 A8 B9 AA BB BC BD BE AF + 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 + C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF + D0 D1 D2 D3 D4 D5 D6 F7 D8 D9 DA DB DC DD DE FF + +# The 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 + 30 32 33 34 35 36 37 2B 38 39 3A 5C 3B 2C 3C 3D + 76 7A 7C 7E 80 81 82 83 84 85 3E 3F 5D 5E 5F 40 + 41 86 92 94 9A 9C A6 A8 AC AE B4 B6 BA C0 C2 C8 + D4 D6 D8 DC E3 E6 EE F0 F2 F4 F6 42 43 44 45 46 + 47 87 93 95 9B 9D A7 A9 AD AF B5 B7 BB C1 C3 C9 + D5 D7 D9 DD E4 E7 EF F1 F3 F5 F7 48 49 4A 4B 20 + 75 21 56 22 59 73 70 71 23 74 24 5A 25 4D 51 50 + 26 54 55 57 58 72 2E 2F 27 E5 28 5B 29 4E 53 2A + 31 FE 65 66 67 FF 4C 68 D3 69 DA 61 6A 2D 6B 90 + 6C 60 7D 7F 4F 6D 6E 6F D2 7B DB 62 77 78 79 91 + 8E B2 8A 96 88 8C A4 A2 98 9E F8 A0 AA B8 B0 BE + E1 C4 C6 CA CE D0 CC 63 EC BC DE EA E8 FA FC E0 + 8F B3 8B 97 89 8D A5 A3 99 9F F9 A1 AB B9 B1 BF + E2 C5 C7 CB CF D1 CD 64 ED BD DF EB E9 FB FD 52 + +# Unicode mapping (256 elements) +0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F +0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F +0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F +0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F +0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F +0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F +0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F +0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F +0080 0081 0082 0083 0084 0085 0086 0087 0088 0089 008A 008B 008C 008D 008E 008F +0090 0091 0092 0093 0094 0095 0096 0097 0098 0099 009A 009B 009C 009D 009E 009F +00A0 201D 00A2 00A3 00A4 201E 00A6 00A7 00D8 00A9 0156 00AB 00AC 00AD 00AE 00C6 +00B0 00B1 00B2 00B3 201C 00B5 00B6 00B7 00F8 00B9 0157 00BB 00BC 00BD 00BE 00E6 +0104 012E 0100 0106 00C4 00C5 0118 0112 010C 00C9 0179 0116 0122 0136 012A 013B +0160 0143 0145 00D3 014C 00D5 00D6 00D7 0172 0141 015A 016A 00DC 017B 017D 00DF +0105 012F 0101 0107 00E4 00E5 0119 0113 010D 00E9 017A 0117 0123 0137 012B 013C +0161 0144 0146 00F3 014D 00F5 00F6 00F7 0173 0142 015B 016B 00FC 017C 017E 2019 diff --git a/sql/share/charsets/latvian1.conf b/sql/share/charsets/latvian1.conf new file mode 100644 index 00000000000..3094525052d --- /dev/null +++ b/sql/share/charsets/latvian1.conf @@ -0,0 +1,94 @@ +# Configuration file for the latvian character set. +# Created for case-insensitive record search +# Created by Andis & Rihards + +# The 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 01 01 01 01 01 01 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 02 02 02 02 02 02 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 10 00 10 10 00 00 00 00 00 10 00 10 10 10 + 00 10 10 10 10 10 10 10 00 00 00 10 00 10 10 00 + 48 00 10 10 10 00 10 10 10 10 01 10 10 10 10 10 + 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 + 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 + 01 01 01 01 01 01 01 10 01 01 01 01 01 01 01 02 + 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 + 02 02 02 02 02 02 02 10 02 02 02 02 02 02 02 10 + +# The 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 BA AB AC AD AE BF + B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF + E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF + F0 F1 F2 F3 F4 F5 F6 D7 F8 F9 FA FB FC FD FE 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 + +# The 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 B3 B4 B5 B6 B7 A8 B9 AA BB BC BD BE AF + 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 + C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF + D0 D1 D2 D3 D4 D5 D6 F7 D8 D9 DA DB DC DD DE FF + +# The 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 + 30 32 33 34 35 36 37 2B 38 39 3A 5C 3B 2C 3C 3D + 76 7A 7C 7E 80 81 82 83 84 85 3E 3F 5D 5E 5F 40 + 41 86 92 94 9A 9C A6 A8 AC AE B4 B6 BA C0 C2 C8 + D4 D6 D8 DC E3 E6 EE F0 F2 F4 F6 42 43 44 45 46 + 47 86 92 94 9A 9C A6 A8 AC AE B4 B6 BA C0 C2 C8 + D4 D6 D8 DC E2 E6 EE F0 F2 F4 F6 48 49 4A 4B 20 + 75 21 56 22 59 73 70 71 23 74 24 5A 25 4D 51 50 + 26 54 55 57 58 72 2E 2F 27 E5 28 5B 29 4E 53 2A + 31 FE 65 66 67 FF 4C 68 2D 69 DA 61 6A 2D 6B 90 + 6C 60 7D 7F 4F 6D 6E 6F D3 7B DB 62 77 78 79 90 + 8E B2 8A 96 88 8C A4 A2 98 9E F8 A0 AA B8 B0 BE + E1 C4 C6 CA CE D0 CC 63 EC BC DE EA E8 FA FC E0 + 8E B2 8A 96 88 8C A4 A2 98 9E F8 A0 AA B8 B0 BE + E1 C4 C6 CA CE D0 CC 64 EC BC DE EA E8 FA FC 52 + +# Unicode mapping (256 elements) +0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F +0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F +0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F +0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F +0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F +0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F +0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F +0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F +0080 0081 0082 0083 0084 0085 0086 0087 0088 0089 008A 008B 008C 008D 008E 008F +0090 0091 0092 0093 0094 0095 0096 0097 0098 0099 009A 009B 009C 009D 009E 009F +00A0 201D 00A2 00A3 00A4 201E 00A6 00A7 00D8 00A9 0156 00AB 00AC 00AD 00AE 00C6 +00B0 00B1 00B2 00B3 201C 00B5 00B6 00B7 00F8 00B9 0157 00BB 00BC 00BD 00BE 00E6 +0104 012E 0100 0106 00C4 00C5 0118 0112 010C 00C9 0179 0116 0122 0136 012A 013B +0160 0143 0145 00D3 014C 00D5 00D6 00D7 0172 0141 015A 016A 00DC 017B 017D 00DF +0105 012F 0101 0107 00E4 00E5 0119 0113 010D 00E9 017A 0117 0123 0137 012B 013C +0161 0144 0146 00F3 014D 00F5 00F6 00F7 0173 0142 015B 016B 00FC 017C 017E 2019 diff --git a/sql/share/charsets/macce.conf b/sql/share/charsets/macce.conf new file mode 100644 index 00000000000..f3ac08df087 --- /dev/null +++ b/sql/share/charsets/macce.conf @@ -0,0 +1,91 @@ +# ctype array (must be 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 00 + 01 01 02 01 01 01 01 02 02 01 02 02 01 02 02 01 + 02 01 02 02 01 02 01 02 02 02 02 02 02 01 02 02 + 00 00 01 00 00 00 00 02 00 00 00 02 00 00 02 01 + 02 01 00 00 02 01 00 00 02 01 02 01 02 01 02 01 + 02 01 00 00 02 01 00 00 00 00 00 02 01 01 02 01 + 00 00 00 00 00 00 00 00 02 01 02 01 00 00 02 01 + 02 01 00 00 02 01 02 01 01 02 01 01 02 01 01 01 + 02 01 01 02 01 02 01 02 01 02 02 01 01 02 01 00 + +# to_lower array (must be 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 54 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 54 75 76 77 78 79 7A 7B 7C 7D 7E 7F + 8A 82 82 8E 88 9A 9F 87 88 8B 8A 8B 8D 8D 8E 90 + 90 93 92 93 95 95 98 97 98 99 9A 9B 9C 9E 9E 9F + A0 A1 AB A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE B0 + B0 B4 B2 B3 B4 FA B6 B7 B8 BA BA BC BC BE BE C0 + C0 C4 C2 C3 C4 CB C6 C7 C8 C9 CA CB CE 9B CE D8 + D0 D1 D2 D3 D4 D5 D6 D7 D8 DA DA DE DC DD DE E0 + E0 E4 E2 E3 E4 E6 E6 87 E9 E9 92 EC EC F0 97 99 + F0 F3 9C F3 F5 F5 F7 F7 F9 F9 FA FD B8 FD AE FF + +# to_upper array (must be 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 74 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 74 55 56 57 58 59 5A 7B 7C 7D 7E 7F + 80 81 81 83 84 85 86 E7 84 89 80 89 8C 8C 83 8F + 8F 91 EA 91 94 94 96 EE 96 EF 85 CD F2 9D 9D 86 + A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA A2 AC AD FE AF + AF B1 B2 B3 B1 B5 B6 B7 FC B9 B9 BB BB BD BD BF + BF C1 C2 C3 C1 C5 C6 C7 C8 C9 CA C5 CC CD CC CF + D0 D1 D2 D3 D4 D5 D6 D7 CF D9 D9 DB DC DD DB DF + DF E1 E2 E3 E1 E5 E5 E7 E8 E8 EA EB EB ED EE EF + ED F1 F2 F1 F4 F4 F6 F6 F8 F8 B5 FB FC FB FE FF + +# sort_order array (must be 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 46 47 4A 4C 52 53 55 56 5A 5B 5D 62 62 67 + 6F 70 71 75 79 81 88 89 8A 8B 8D 90 91 92 93 94 + 95 41 46 47 4A 4C 52 53 55 56 5A 5B 5D 62 62 67 + 6F 70 71 75 79 81 88 89 8A 8B 8D 96 97 98 99 9A + 41 41 41 4C 41 67 81 41 41 47 41 47 47 47 4C 8D + 8D 4A 56 4A 4C 4C 4C 67 4C 67 67 67 81 4C 4C 81 + A0 A1 4C A3 A4 A5 A6 75 A8 A9 AA 4C AC AD 53 56 + 56 56 B2 B3 56 5B B6 B7 5D 5D 5D 5D 5D 5D 5D 62 + 62 62 C2 C3 62 62 C6 C7 C8 C9 CA 62 67 67 67 67 + D0 D1 D2 D3 D4 D5 D6 D7 67 71 71 71 DC DD 71 71 + 71 75 E2 E3 75 75 75 41 79 79 56 8D 8D 81 67 67 + 81 81 81 81 81 81 81 81 8B 8B 5B 8D 5D 8D 53 FF + +# Unicode mappping (must be 256 elements) + 0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F + 0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F + 0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F + 0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F + 0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F + 0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F + 0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F + 0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F + 00C4 0100 0101 00C9 0104 00D6 00DC 00E1 0105 010C 00E4 010D 0106 0107 00E9 0179 + 017A 010E 00ED 010F 0112 0113 0116 00F3 0117 00F4 00F6 00F5 00FA 011A 011B 00FC + 2020 00B0 0118 00A3 00A7 2022 00B6 00DF 00AE 00A9 2122 0119 00A8 2260 0123 012E + 012F 012A 2264 2265 012B 0136 2202 2211 0142 013B 013C 013D 013E 0139 013A 0145 + 0146 0143 00AC 221A 0144 0147 2206 00AB 00BB 2026 00A0 0148 0150 00D5 0151 014C + 2013 2014 201C 201D 2018 2019 00F7 25CA 014D 0154 0155 0158 2039 203A 0159 0156 + 0157 0160 201A 201E 0161 015A 015B 00C1 0164 0165 00CD 017D 017E 016A 00D3 00D4 + 016B 016E 00DA 016F 0170 0171 0172 0173 00DD 00FD 0137 017B 0141 017C 0122 02C7 + diff --git a/sql/share/charsets/maccebin.conf b/sql/share/charsets/maccebin.conf new file mode 100644 index 00000000000..f859e64354c --- /dev/null +++ b/sql/share/charsets/maccebin.conf @@ -0,0 +1,96 @@ +# Mac OS Central European, binary sort order +# +# Czech (cs), Hungarian (hu), Polish (pl), Romanian (ro), Croatian (hr), +# Slovak (sk), Slovenian (sl), Sorbian. +# +# ctype array (must be 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 00 + 01 01 02 01 01 01 01 02 02 01 02 02 01 02 02 01 + 02 01 02 02 01 02 01 02 02 02 02 02 02 01 02 02 + 00 00 01 00 00 00 00 02 00 00 00 02 00 00 02 01 + 02 01 00 00 02 01 00 00 02 01 02 01 02 01 02 01 + 02 01 00 00 02 01 00 00 00 00 00 02 01 01 02 01 + 00 00 00 00 00 00 00 00 02 01 02 01 00 00 02 01 + 02 01 00 00 02 01 02 01 01 02 01 01 02 01 01 01 + 02 01 01 02 01 02 01 02 01 02 02 01 01 02 01 00 + +# to_lower array (must be 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 54 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 54 75 76 77 78 79 7A 7B 7C 7D 7E 7F + 8A 82 82 8E 88 9A 9F 87 88 8B 8A 8B 8D 8D 8E 90 + 90 93 92 93 95 95 98 97 98 99 9A 9B 9C 9E 9E 9F + A0 A1 AB A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE B0 + B0 B4 B2 B3 B4 FA B6 B7 B8 BA BA BC BC BE BE C0 + C0 C4 C2 C3 C4 CB C6 C7 C8 C9 CA CB CE 9B CE D8 + D0 D1 D2 D3 D4 D5 D6 D7 D8 DA DA DE DC DD DE E0 + E0 E4 E2 E3 E4 E6 E6 87 E9 E9 92 EC EC F0 97 99 + F0 F3 9C F3 F5 F5 F7 F7 F9 F9 FA FD B8 FD AE FF + +# to_upper array (must be 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 74 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 74 55 56 57 58 59 5A 7B 7C 7D 7E 7F + 80 81 81 83 84 85 86 E7 84 89 80 89 8C 8C 83 8F + 8F 91 EA 91 94 94 96 EE 96 EF 85 CD F2 9D 9D 86 + A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA A2 AC AD FE AF + AF B1 B2 B3 B1 B5 B6 B7 FC B9 B9 BB BB BD BD BF + BF C1 C2 C3 C1 C5 C6 C7 C8 C9 CA C5 CC CD CC CF + D0 D1 D2 D3 D4 D5 D6 D7 CF D9 D9 DB DC DD DB DF + DF E1 E2 E3 E1 E5 E5 E7 E8 E8 EA EB EB ED EE EF + ED F1 F2 F1 F4 F4 F6 F6 F8 F8 B5 FB FC FB FE FF + +# sort_order array (must be 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 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 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 + +# Unicode mapping (must be 256 elements) + 0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F + 0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F + 0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F + 0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F + 0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F + 0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F + 0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F + 0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F + 00C4 0100 0101 00C9 0104 00D6 00DC 00E1 0105 010C 00E4 010D 0106 0107 00E9 0179 + 017A 010E 00ED 010F 0112 0113 0116 00F3 0117 00F4 00F6 00F5 00FA 011A 011B 00FC + 2020 00B0 0118 00A3 00A7 2022 00B6 00DF 00AE 00A9 2122 0119 00A8 2260 0123 012E + 012F 012A 2264 2265 012B 0136 2202 2211 0142 013B 013C 013D 013E 0139 013A 0145 + 0146 0143 00AC 221A 0144 0147 2206 00AB 00BB 2026 00A0 0148 0150 00D5 0151 014C + 2013 2014 201C 201D 2018 2019 00F7 25CA 014D 0154 0155 0158 2039 203A 0159 0156 + 0157 0160 201A 201E 0161 015A 015B 00C1 0164 0165 00CD 017D 017E 016A 00D3 00D4 + 016B 016E 00DA 016F 0170 0171 0172 0173 00DD 00FD 0137 017B 0141 017C 0122 02C7 + diff --git a/sql/share/charsets/macceciai.conf b/sql/share/charsets/macceciai.conf new file mode 100644 index 00000000000..d7cdaddc425 --- /dev/null +++ b/sql/share/charsets/macceciai.conf @@ -0,0 +1,96 @@ +# Mac OS Central European, case insensitive, accent sensitive +# +# Czech (cs), Hungarian (hu), Polish (pl), Romanian (ro), Croatian (hr), +# Slovak (sk), Slovenian (sl), Sorbian. +# +# ctype array (must be 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 00 + 01 01 02 01 01 01 01 02 02 01 02 02 01 02 02 01 + 02 01 02 02 01 02 01 02 02 02 02 02 02 01 02 02 + 00 00 01 00 00 00 00 02 00 00 00 02 00 00 02 01 + 02 01 00 00 02 01 00 00 02 01 02 01 02 01 02 01 + 02 01 00 00 02 01 00 00 00 00 00 02 01 01 02 01 + 00 00 00 00 00 00 00 00 02 01 02 01 00 00 02 01 + 02 01 00 00 02 01 02 01 01 02 01 01 02 01 01 01 + 02 01 01 02 01 02 01 02 01 02 02 01 01 02 01 00 + +# to_lower array (must be 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 54 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 54 75 76 77 78 79 7A 7B 7C 7D 7E 7F + 8A 82 82 8E 88 9A 9F 87 88 8B 8A 8B 8D 8D 8E 90 + 90 93 92 93 95 95 98 97 98 99 9A 9B 9C 9E 9E 9F + A0 A1 AB A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE B0 + B0 B4 B2 B3 B4 FA B6 B7 B8 BA BA BC BC BE BE C0 + C0 C4 C2 C3 C4 CB C6 C7 C8 C9 CA CB CE 9B CE D8 + D0 D1 D2 D3 D4 D5 D6 D7 D8 DA DA DE DC DD DE E0 + E0 E4 E2 E3 E4 E6 E6 87 E9 E9 92 EC EC F0 97 99 + F0 F3 9C F3 F5 F5 F7 F7 F9 F9 FA FD B8 FD AE FF + +# to_upper array (must be 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 74 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 74 55 56 57 58 59 5A 7B 7C 7D 7E 7F + 80 81 81 83 84 85 86 E7 84 89 80 89 8C 8C 83 8F + 8F 91 EA 91 94 94 96 EE 96 EF 85 CD F2 9D 9D 86 + A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA A2 AC AD FE AF + AF B1 B2 B3 B1 B5 B6 B7 FC B9 B9 BB BB BD BD BF + BF C1 C2 C3 C1 C5 C6 C7 C8 C9 CA C5 CC CD CC CF + D0 D1 D2 D3 D4 D5 D6 D7 CF D9 D9 DB DC DD DB DF + DF E1 E2 E3 E1 E5 E5 E7 E8 E8 EA EB EB ED EE EF + ED F1 F2 F1 F4 F4 F6 F6 F8 F8 B5 FB FC FB FE FF + +# sort_order array (must be 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 4B 4D 53 57 63 65 69 6B 73 75 79 83 85 8D + 9B 9D 9F A7 AE B2 C0 C2 C4 C6 CA D2 D3 D4 D5 D6 + D7 41 4B 4D 53 57 63 65 69 6B 73 75 79 83 85 8D + 9B 9D 9F A7 AE B2 C0 C2 C4 C6 CA D8 D9 DA DB DC + 41 41 41 57 41 8D B2 41 41 4D 41 4D 4D 4D 57 CA + CA 53 6B 53 57 57 57 8D 57 8D 8D 8D B2 57 57 B2 + DD DE 57 DF E0 E1 E2 A7 E3 E4 E5 57 E6 E7 65 6B + 6B 6B E8 E9 6B 75 EA EB 79 79 79 79 79 79 79 85 + 85 85 EC ED 85 85 EE EF F0 F1 F2 85 8D 8D 8D 8D + F3 F4 F5 F6 F7 F8 F9 FA 8D 9F 9F 9F FB FC 9F 9F + 9F A7 FD FE A7 A7 A7 41 BE BE 6B CA CA B2 8D 8D + B2 B2 B2 B2 B2 B2 B2 B2 C6 C6 75 CA 79 CA 65 FF + +# Unicode mapping (must be 256 elements) + 0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F + 0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F + 0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F + 0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F + 0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F + 0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F + 0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F + 0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F + 00C4 0100 0101 00C9 0104 00D6 00DC 00E1 0105 010C 00E4 010D 0106 0107 00E9 0179 + 017A 010E 00ED 010F 0112 0113 0116 00F3 0117 00F4 00F6 00F5 00FA 011A 011B 00FC + 2020 00B0 0118 00A3 00A7 2022 00B6 00DF 00AE 00A9 2122 0119 00A8 2260 0123 012E + 012F 012A 2264 2265 012B 0136 2202 2211 0142 013B 013C 013D 013E 0139 013A 0145 + 0146 0143 00AC 221A 0144 0147 2206 00AB 00BB 2026 00A0 0148 0150 00D5 0151 014C + 2013 2014 201C 201D 2018 2019 00F7 25CA 014D 0154 0155 0158 2039 203A 0159 0156 + 0157 0160 201A 201E 0161 015A 015B 00C1 0164 0165 00CD 017D 017E 016A 00D3 00D4 + 016B 016E 00DA 016F 0170 0171 0172 0173 00DD 00FD 0137 017B 0141 017C 0122 02C7 + diff --git a/sql/share/charsets/maccecias.conf b/sql/share/charsets/maccecias.conf new file mode 100644 index 00000000000..8cefd4cf9ec --- /dev/null +++ b/sql/share/charsets/maccecias.conf @@ -0,0 +1,96 @@ +# Mac OS Central European, case insensitive, accent sensitive +# +# Czech (cs), Hungarian (hu), Polish (pl), Romanian (ro), Croatian (hr), +# Slovak (sk), Slovenian (sl), Sorbian. +# +# ctype array (must be 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 00 + 01 01 02 01 01 01 01 02 02 01 02 02 01 02 02 01 + 02 01 02 02 01 02 01 02 02 02 02 02 02 01 02 02 + 00 00 01 00 00 00 00 02 00 00 00 02 00 00 02 01 + 02 01 00 00 02 01 00 00 02 01 02 01 02 01 02 01 + 02 01 00 00 02 01 00 00 00 00 00 02 01 01 02 01 + 00 00 00 00 00 00 00 00 02 01 02 01 00 00 02 01 + 02 01 00 00 02 01 02 01 01 02 01 01 02 01 01 01 + 02 01 01 02 01 02 01 02 01 02 02 01 01 02 01 00 + +# to_lower array (must be 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 54 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 54 75 76 77 78 79 7A 7B 7C 7D 7E 7F + 8A 82 82 8E 88 9A 9F 87 88 8B 8A 8B 8D 8D 8E 90 + 90 93 92 93 95 95 98 97 98 99 9A 9B 9C 9E 9E 9F + A0 A1 AB A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE B0 + B0 B4 B2 B3 B4 FA B6 B7 B8 BA BA BC BC BE BE C0 + C0 C4 C2 C3 C4 CB C6 C7 C8 C9 CA CB CE 9B CE D8 + D0 D1 D2 D3 D4 D5 D6 D7 D8 DA DA DE DC DD DE E0 + E0 E4 E2 E3 E4 E6 E6 87 E9 E9 92 EC EC F0 97 99 + F0 F3 9C F3 F5 F5 F7 F7 F9 F9 FA FD B8 FD AE FF + +# to_upper array (must be 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 74 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 74 55 56 57 58 59 5A 7B 7C 7D 7E 7F + 80 81 81 83 84 85 86 E7 84 89 80 89 8C 8C 83 8F + 8F 91 EA 91 94 94 96 EE 96 EF 85 CD F2 9D 9D 86 + A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA A2 AC AD FE AF + AF B1 B2 B3 B1 B5 B6 B7 FC B9 B9 BB BB BD BD BF + BF C1 C2 C3 C1 C5 C6 C7 C8 C9 CA C5 CC CD CC CF + D0 D1 D2 D3 D4 D5 D6 D7 CF D9 D9 DB DC DD DB DF + DF E1 E2 E3 E1 E5 E5 E7 E8 E8 EA EB EB ED EE EF + ED F1 F2 F1 F4 F4 F6 F6 F8 F8 B5 FB FC FB FE FF + +# sort_order array (must be 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 4B 4D 53 57 63 65 69 6B 73 75 79 83 85 8D + 9B 9D 9F A7 AE B2 C0 C2 C4 C6 CA D2 D3 D4 D5 D6 + D7 41 4B 4D 53 57 63 65 69 6B 73 75 79 83 85 8D + 9B 9D 9F A7 AE B2 C0 C2 C4 C6 CA D8 D9 DA DB DC + 45 47 47 59 49 91 B6 43 49 4F 45 4F 51 51 59 CE + CE 55 71 55 5B 5B 5D 8F 5D 99 91 97 B8 5F 5F B6 + DD DE 61 DF E0 E1 E2 AD E3 E4 E5 61 E6 E7 67 6F + 6F 6D E8 E9 6D 77 EA EB 7B 81 82 7F 7F 7D 7D 8B + 8B 87 EC ED 87 89 EE EF F0 F1 F2 89 93 97 93 95 + F3 F4 F5 F6 F7 F8 F9 FA 95 A1 A1 A3 FB FC A3 A5 + A5 A9 FD FE A9 AB AB 43 B0 B0 71 CC CC BC 8F 99 + BC B4 B8 B4 BA BA BE BE C8 C8 77 D0 7B D0 67 FF + +# Unicode mapping (must be 256 elements) + 0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F + 0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F + 0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F + 0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F + 0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F + 0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F + 0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F + 0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F + 00C4 0100 0101 00C9 0104 00D6 00DC 00E1 0105 010C 00E4 010D 0106 0107 00E9 0179 + 017A 010E 00ED 010F 0112 0113 0116 00F3 0117 00F4 00F6 00F5 00FA 011A 011B 00FC + 2020 00B0 0118 00A3 00A7 2022 00B6 00DF 00AE 00A9 2122 0119 00A8 2260 0123 012E + 012F 012A 2264 2265 012B 0136 2202 2211 0142 013B 013C 013D 013E 0139 013A 0145 + 0146 0143 00AC 221A 0144 0147 2206 00AB 00BB 2026 00A0 0148 0150 00D5 0151 014C + 2013 2014 201C 201D 2018 2019 00F7 25CA 014D 0154 0155 0158 2039 203A 0159 0156 + 0157 0160 201A 201E 0161 015A 015B 00C1 0164 0165 00CD 017D 017E 016A 00D3 00D4 + 016B 016E 00DA 016F 0170 0171 0172 0173 00DD 00FD 0137 017B 0141 017C 0122 02C7 + diff --git a/sql/share/charsets/maccecsas.conf b/sql/share/charsets/maccecsas.conf new file mode 100644 index 00000000000..8cc1de422f2 --- /dev/null +++ b/sql/share/charsets/maccecsas.conf @@ -0,0 +1,96 @@ +# Mac OS Central European, case sensitive, accent sensitive +# +# Czech (cs), Hungarian (hu), Polish (pl), Romanian (ro), Croatian (hr), +# Slovak (sk), Slovenian (sl), Sorbian. +# +# ctype array (must be 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 00 + 01 01 02 01 01 01 01 02 02 01 02 02 01 02 02 01 + 02 01 02 02 01 02 01 02 02 02 02 02 02 01 02 02 + 00 00 01 00 00 00 00 02 00 00 00 02 00 00 02 01 + 02 01 00 00 02 01 00 00 02 01 02 01 02 01 02 01 + 02 01 00 00 02 01 00 00 00 00 00 02 01 01 02 01 + 00 00 00 00 00 00 00 00 02 01 02 01 00 00 02 01 + 02 01 00 00 02 01 02 01 01 02 01 01 02 01 01 01 + 02 01 01 02 01 02 01 02 01 02 02 01 01 02 01 00 + +# to_lower array (must be 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 54 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 54 75 76 77 78 79 7A 7B 7C 7D 7E 7F + 8A 82 82 8E 88 9A 9F 87 88 8B 8A 8B 8D 8D 8E 90 + 90 93 92 93 95 95 98 97 98 99 9A 9B 9C 9E 9E 9F + A0 A1 AB A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE B0 + B0 B4 B2 B3 B4 FA B6 B7 B8 BA BA BC BC BE BE C0 + C0 C4 C2 C3 C4 CB C6 C7 C8 C9 CA CB CE 9B CE D8 + D0 D1 D2 D3 D4 D5 D6 D7 D8 DA DA DE DC DD DE E0 + E0 E4 E2 E3 E4 E6 E6 87 E9 E9 92 EC EC F0 97 99 + F0 F3 9C F3 F5 F5 F7 F7 F9 F9 FA FD B8 FD AE FF + +# to_upper array (must be 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 74 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 74 55 56 57 58 59 5A 7B 7C 7D 7E 7F + 80 81 81 83 84 85 86 E7 84 89 80 89 8C 8C 83 8F + 8F 91 EA 91 94 94 96 EE 96 EF 85 CD F2 9D 9D 86 + A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA A2 AC AD FE AF + AF B1 B2 B3 B1 B5 B6 B7 FC B9 B9 BB BB BD BD BF + BF C1 C2 C3 C1 C5 C6 C7 C8 C9 CA C5 CC CD CC CF + D0 D1 D2 D3 D4 D5 D6 D7 CF D9 D9 DB DC DD DB DF + DF E1 E2 E3 E1 E5 E5 E7 E8 E8 EA EB EB ED EE EF + ED F1 F2 F1 F4 F4 F6 F6 F8 F8 B5 FB FC FB FE FF + +# sort_order array (must be 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 4B 4D 53 57 63 65 69 6B 73 75 79 83 85 8D + 9B 9D 9F A7 AE B2 C0 C2 C4 C6 CA D2 D3 D4 D5 D6 + D7 42 4C 4E 54 58 64 66 6A 6C 74 76 7A 84 86 8E + 9C 9E A0 A8 AF B3 C1 C3 C5 C7 CB D8 D9 DA DB DC + 45 47 48 59 49 91 B6 44 4A 4F 46 50 51 52 5A CE + CF 55 72 56 5B 5C 5D 90 5E 9A 92 98 B8 5F 60 B7 + DD DE 61 DF E0 E1 E2 AD E3 E4 E5 62 E6 E7 68 6F + 70 6D E8 E9 6E 77 EA EB 7C 81 82 7F 80 7D 7E 8B + 8C 87 EC ED 88 89 EE EF F0 F1 F2 8A 93 97 94 95 + F3 F4 F5 F6 F7 F8 F9 FA 96 A1 A2 A3 FB FC A4 A5 + A6 A9 FD FE AA AB AC 43 B0 B1 71 CC CD BC 8F 99 + BD B4 B9 B5 BA BB BE BF C8 C9 78 D0 7B D1 67 FF + +# Unicode mapping (must be 256 elements) + 0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F + 0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F + 0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F + 0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F + 0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F + 0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F + 0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F + 0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F + 00C4 0100 0101 00C9 0104 00D6 00DC 00E1 0105 010C 00E4 010D 0106 0107 00E9 0179 + 017A 010E 00ED 010F 0112 0113 0116 00F3 0117 00F4 00F6 00F5 00FA 011A 011B 00FC + 2020 00B0 0118 00A3 00A7 2022 00B6 00DF 00AE 00A9 2122 0119 00A8 2260 0123 012E + 012F 012A 2264 2265 012B 0136 2202 2211 0142 013B 013C 013D 013E 0139 013A 0145 + 0146 0143 00AC 221A 0144 0147 2206 00AB 00BB 2026 00A0 0148 0150 00D5 0151 014C + 2013 2014 201C 201D 2018 2019 00F7 25CA 014D 0154 0155 0158 2039 203A 0159 0156 + 0157 0160 201A 201E 0161 015A 015B 00C1 0164 0165 00CD 017D 017E 016A 00D3 00D4 + 016B 016E 00DA 016F 0170 0171 0172 0173 00DD 00FD 0137 017B 0141 017C 0122 02C7 + diff --git a/sql/share/charsets/macroman.conf b/sql/share/charsets/macroman.conf new file mode 100644 index 00000000000..11cbee40e94 --- /dev/null +++ b/sql/share/charsets/macroman.conf @@ -0,0 +1,91 @@ +# ctype array (must be 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 10 + 20 01 01 01 01 01 01 02 02 02 02 02 02 02 02 02 + 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 + 00 00 00 00 00 00 00 02 00 00 00 00 00 00 01 01 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 02 + 00 00 00 00 02 00 00 00 00 00 00 20 01 01 00 00 + 00 00 00 00 00 00 00 00 02 01 00 00 00 00 00 00 + 00 00 00 00 00 20 01 01 01 01 01 01 01 01 01 01 + 00 01 01 01 01 02 00 00 00 00 00 00 00 00 00 00 + +# to_lower array (must be 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 + 8A 8C 8D 8E 96 9A 9F 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 BE BF + 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 88 8B 9B CE CF + D0 D1 D2 D3 D4 D5 D6 D7 D8 D8 DA DB DC DD DE DF + E0 E1 E2 E3 E4 89 90 87 91 8F 92 94 95 93 97 99 + F0 98 9C 9E 9D F5 F6 F7 F8 F9 FA FB FC FD FE FF + +# to_upper array (must be 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 E7 CB E5 80 CC 81 82 83 E9 + E6 E8 EA ED EB EC 84 EE F1 EF 85 CD F2 F4 F3 86 + 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 AE AF + C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF + D0 D1 D2 D3 D4 D5 D6 D7 D9 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 + +# sort_order array (must be 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 49 50 52 53 57 59 60 61 67 68 69 70 71 72 + 79 80 81 82 84 85 90 91 92 93 95 A0 A1 A2 A3 A4 + A5 41 49 50 52 53 57 59 60 61 67 68 69 70 71 72 + 79 80 81 82 84 85 90 91 92 93 95 A6 A7 A8 A9 AA + 41 41 50 53 71 72 85 41 41 41 41 41 41 50 53 53 + 53 53 61 61 61 61 71 72 72 72 72 72 85 85 85 85 + AB AC AD AE AF B0 B1 82 B2 B3 B4 B5 B6 B7 48 72 + B8 B9 BA BB BC BD BE BF C0 C1 C2 C3 C4 C5 48 72 + C6 C7 C8 C9 57 CA CB CC CD CE CF 41 41 72 D0 D1 + D2 D3 D4 D5 D6 D7 D8 D9 93 93 DA DB DC DD DE DF + E0 E1 E2 E3 E4 41 53 41 53 53 61 61 61 61 72 72 + F0 72 85 85 85 61 F6 F7 F8 F9 FA FB FC FD FE FF + +# Unicode mappping (must be 256 elements) + 0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F + 0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F + 0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F + 0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F + 0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F + 0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F + 0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F + 0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F + 00C4 00C5 00C7 00C9 00D1 00D6 00DC 00E1 00E0 00E2 00E4 00E3 00E5 00E7 00E9 00E8 + 00EA 00EB 00ED 00EC 00EE 00EF 00F1 00F3 00F2 00F4 00F6 00F5 00FA 00F9 00FB 00FC + 2020 00B0 00A2 00A3 00A7 2022 00B6 00DF 00AE 00A9 2122 00B4 00A8 2260 00C6 00D8 + 221E 00B1 2264 2265 00A5 00B5 2202 2211 220F 03C0 222B 00AA 00BA 03A9 00E6 00F8 + 00BF 00A1 00AC 221A 0192 2248 2206 00AB 00BB 2026 00A0 00C0 00C3 00D5 0152 0153 + 2013 2014 201C 201D 2018 2019 00F7 25CA 00FF 0178 2044 20AC 2039 203A FB01 FB02 + 2021 00B7 201A 201E 2030 00C2 00CA 00C1 00CB 00C8 00CD 00CE 00CF 00CC 00D3 00D4 + F8FF 00D2 00DA 00DB 00D9 0131 02C6 02DC 00AF 02D8 02D9 02DA 00B8 02DD 02DB 02C7 + diff --git a/sql/share/charsets/macromanbin.conf b/sql/share/charsets/macromanbin.conf new file mode 100644 index 00000000000..d0845c07f2b --- /dev/null +++ b/sql/share/charsets/macromanbin.conf @@ -0,0 +1,96 @@ +# +# Mac OS Roman, accent insensitive, case insensitive +# +# Binary sort order +# +# ctype array (must be 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 10 + 20 01 01 01 01 01 01 02 02 02 02 02 02 02 02 02 + 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 + 00 00 00 00 00 00 00 02 00 00 00 00 00 00 01 01 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 02 + 00 00 00 00 02 00 00 00 00 00 00 20 01 01 01 02 + 00 00 00 00 00 00 00 00 02 01 00 00 00 00 00 00 + 00 00 00 00 00 20 01 01 01 01 01 01 01 01 01 01 + 00 01 01 01 01 02 00 00 00 00 00 00 00 00 00 00 + +# to_lower array (must be 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 + 8A 8C 8D 8E 96 9A 9F 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 BE BF + 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 88 8B 9B CE CF + D0 D1 D2 D3 D4 D5 D6 D7 D8 D8 DA DB DC DD DE DF + E0 E1 E2 E3 E4 89 90 87 91 8F 92 94 95 93 97 99 + F0 98 9C 9E 9D F5 F6 F7 F8 F9 FA FB FC FD FE FF + +# to_upper array (must be 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 E7 CB E5 80 CC 81 82 83 E9 + E6 E8 EA ED EB EC 84 EE F1 EF 85 CD F2 F4 F3 86 + 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 AE AF + C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF + D0 D1 D2 D3 D4 D5 D6 D7 D9 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 + +# sort_order array (must be 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 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 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 + +# Unicode mapping (must be 256 elements) + 0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F + 0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F + 0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F + 0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F + 0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F + 0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F + 0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F + 0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F + 00C4 00C5 00C7 00C9 00D1 00D6 00DC 00E1 00E0 00E2 00E4 00E3 00E5 00E7 00E9 00E8 + 00EA 00EB 00ED 00EC 00EE 00EF 00F1 00F3 00F2 00F4 00F6 00F5 00FA 00F9 00FB 00FC + 2020 00B0 00A2 00A3 00A7 2022 00B6 00DF 00AE 00A9 2122 00B4 00A8 2260 00C6 00D8 + 221E 00B1 2264 2265 00A5 00B5 2202 2211 220F 03C0 222B 00AA 00BA 03A9 00E6 00F8 + 00BF 00A1 00AC 221A 0192 2248 2206 00AB 00BB 2026 00A0 00C0 00C3 00D5 0152 0153 + 2013 2014 201C 201D 2018 2019 00F7 25CA 00FF 0178 2044 20AC 2039 203A FB01 FB02 + 2021 00B7 201A 201E 2030 00C2 00CA 00C1 00CB 00C8 00CD 00CE 00CF 00CC 00D3 00D4 + F8FF 00D2 00DA 00DB 00D9 0131 02C6 02DC 00AF 02D8 02D9 02DA 00B8 02DD 02DB 02C7 + diff --git a/sql/share/charsets/macromanciai.conf b/sql/share/charsets/macromanciai.conf new file mode 100644 index 00000000000..457e6b4f8d9 --- /dev/null +++ b/sql/share/charsets/macromanciai.conf @@ -0,0 +1,97 @@ +# +# Mac OS Roman, accent insensitive, case insensitive +# +# Sort order: Dutch, English, French, German (Duden), +# Italian, Latin, Pogtuguese, Spanish +# +# ctype array (must be 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 10 + 20 01 01 01 01 01 01 02 02 02 02 02 02 02 02 02 + 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 + 00 00 00 00 00 00 00 02 00 00 00 00 00 00 01 01 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 02 + 00 00 00 00 02 00 00 00 00 00 00 20 01 01 01 02 + 00 00 00 00 00 00 00 00 02 01 00 00 00 00 00 00 + 00 00 00 00 00 20 01 01 01 01 01 01 01 01 01 01 + 00 01 01 01 01 02 00 00 00 00 00 00 00 00 00 00 + +# to_lower array (must be 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 + 8A 8C 8D 8E 96 9A 9F 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 BE BF + 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 88 8B 9B CE CF + D0 D1 D2 D3 D4 D5 D6 D7 D8 D8 DA DB DC DD DE DF + E0 E1 E2 E3 E4 89 90 87 91 8F 92 94 95 93 97 99 + F0 98 9C 9E 9D F5 F6 F7 F8 F9 FA FB FC FD FE FF + +# to_upper array (must be 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 E7 CB E5 80 CC 81 82 83 E9 + E6 E8 EA ED EB EC 84 EE F1 EF 85 CD F2 F4 F3 86 + 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 AE AF + C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF + D0 D1 D2 D3 D4 D5 D6 D7 D9 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 + +# sort_order array (must be 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 51 53 57 59 63 66 68 6A 75 77 79 7B 7D 81 + 91 93 95 97 9A 9C A6 A8 AA AC B0 B2 B3 B4 B5 B6 + B7 41 51 53 57 59 63 66 68 6A 75 77 79 7B 7D 81 + 91 93 95 97 9A 9C A6 A8 AA AC B0 B8 B9 BA BB BC + 41 41 53 59 7D 81 9C 41 41 41 41 41 41 53 59 59 + 59 59 6A 6A 6A 6A 7D 81 81 81 81 81 9C 9C 9C 9C + BD BE BF C0 C1 C2 C3 97 C4 C5 C6 C7 C8 C9 41 81 + CA CB CC CD CE CF D0 D1 D2 D3 D4 D5 D6 D7 41 81 + D8 D9 DA DB 63 DC DD DE DF E0 E1 41 41 81 81 81 + E2 E3 E4 E5 E6 E7 E8 E9 AC AC EA EB EC ED EE EF + F0 F1 F2 F3 F4 41 59 41 59 59 6A 6A 6A 6A 81 81 + F0 81 9C 9C 9C 6A F6 F7 F8 F9 FA FB FC FD FE FF + +# Unicode mapping (must be 256 elements) + 0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F + 0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F + 0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F + 0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F + 0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F + 0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F + 0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F + 0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F + 00C4 00C5 00C7 00C9 00D1 00D6 00DC 00E1 00E0 00E2 00E4 00E3 00E5 00E7 00E9 00E8 + 00EA 00EB 00ED 00EC 00EE 00EF 00F1 00F3 00F2 00F4 00F6 00F5 00FA 00F9 00FB 00FC + 2020 00B0 00A2 00A3 00A7 2022 00B6 00DF 00AE 00A9 2122 00B4 00A8 2260 00C6 00D8 + 221E 00B1 2264 2265 00A5 00B5 2202 2211 220F 03C0 222B 00AA 00BA 03A9 00E6 00F8 + 00BF 00A1 00AC 221A 0192 2248 2206 00AB 00BB 2026 00A0 00C0 00C3 00D5 0152 0153 + 2013 2014 201C 201D 2018 2019 00F7 25CA 00FF 0178 2044 20AC 2039 203A FB01 FB02 + 2021 00B7 201A 201E 2030 00C2 00CA 00C1 00CB 00C8 00CD 00CE 00CF 00CC 00D3 00D4 + F8FF 00D2 00DA 00DB 00D9 0131 02C6 02DC 00AF 02D8 02D9 02DA 00B8 02DD 02DB 02C7 + diff --git a/sql/share/charsets/macromancias.conf b/sql/share/charsets/macromancias.conf new file mode 100644 index 00000000000..a00d7d412e6 --- /dev/null +++ b/sql/share/charsets/macromancias.conf @@ -0,0 +1,97 @@ +# +# Mac OS Roman, accent sensitive, case insensitive +# +# Sort order: Dutch, English, French, German (Duden), +# Italian, Latin, Pogtuguese, Spanish +# +# ctype array (must be 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 10 + 20 01 01 01 01 01 01 02 02 02 02 02 02 02 02 02 + 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 + 00 00 00 00 00 00 00 02 00 00 00 00 00 00 01 01 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 02 + 00 00 00 00 02 00 00 00 00 00 00 20 01 01 01 02 + 00 00 00 00 00 00 00 00 02 01 00 00 00 00 00 00 + 00 00 00 00 00 20 01 01 01 01 01 01 01 01 01 01 + 00 01 01 01 01 02 00 00 00 00 00 00 00 00 00 00 + +# to_lower array (must be 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 + 8A 8C 8D 8E 96 9A 9F 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 BE BF + 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 88 8B 9B CE CF + D0 D1 D2 D3 D4 D5 D6 D7 D8 D8 DA DB DC DD DE DF + E0 E1 E2 E3 E4 89 90 87 91 8F 92 94 95 93 97 99 + F0 98 9C 9E 9D F5 F6 F7 F8 F9 FA FB FC FD FE FF + +# to_upper array (must be 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 E7 CB E5 80 CC 81 82 83 E9 + E6 E8 EA ED EB EC 84 EE F1 EF 85 CD F2 F4 F3 86 + 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 AE AF + C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF + D0 D1 D2 D3 D4 D5 D6 D7 D9 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 + +# sort_order array (must be 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 51 53 57 59 63 66 68 6A 75 77 79 7B 7D 81 + 91 93 95 97 9A 9C A6 A8 AA AC B0 B2 B3 B4 B5 B6 + B7 41 51 53 57 59 63 66 68 6A 75 77 79 7B 7D 81 + 91 93 95 97 9A 9C A6 A8 AA AC B0 B8 B9 BA BB BC + 4B 4D 55 5D 7F 8B A4 45 43 47 4B 49 4D 55 5D 5B + 5F 61 6E 6C 70 72 7F 85 83 87 8B 89 A0 9E A2 A4 + BD BE BF C0 C1 C2 C3 99 C4 C5 C6 C7 C8 C9 4F 8D + CA CB CC CD CE CF D0 D1 D2 D3 D4 D5 D6 D7 4F 8D + D8 D9 DA DB 65 DC DD DE DF E0 E1 43 49 89 8F 8F + E2 E3 E4 E5 E6 E7 E8 E9 AE AE EA EB EC ED EE EF + F0 F1 F2 F3 F4 47 5F 45 61 5B 6E 70 70 6C 85 87 + F0 83 A0 A2 9E 72 F6 F7 F8 F9 FA FB FC FD FE FF + +# Unicode mapping (must be 256 elements) + 0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F + 0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F + 0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F + 0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F + 0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F + 0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F + 0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F + 0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F + 00C4 00C5 00C7 00C9 00D1 00D6 00DC 00E1 00E0 00E2 00E4 00E3 00E5 00E7 00E9 00E8 + 00EA 00EB 00ED 00EC 00EE 00EF 00F1 00F3 00F2 00F4 00F6 00F5 00FA 00F9 00FB 00FC + 2020 00B0 00A2 00A3 00A7 2022 00B6 00DF 00AE 00A9 2122 00B4 00A8 2260 00C6 00D8 + 221E 00B1 2264 2265 00A5 00B5 2202 2211 220F 03C0 222B 00AA 00BA 03A9 00E6 00F8 + 00BF 00A1 00AC 221A 0192 2248 2206 00AB 00BB 2026 00A0 00C0 00C3 00D5 0152 0153 + 2013 2014 201C 201D 2018 2019 00F7 25CA 00FF 0178 2044 20AC 2039 203A FB01 FB02 + 2021 00B7 201A 201E 2030 00C2 00CA 00C1 00CB 00C8 00CD 00CE 00CF 00CC 00D3 00D4 + F8FF 00D2 00DA 00DB 00D9 0131 02C6 02DC 00AF 02D8 02D9 02DA 00B8 02DD 02DB 02C7 + diff --git a/sql/share/charsets/macromancsas.conf b/sql/share/charsets/macromancsas.conf new file mode 100644 index 00000000000..1f67148680d --- /dev/null +++ b/sql/share/charsets/macromancsas.conf @@ -0,0 +1,97 @@ +# +# Mac OS Roman, accent sensitive, case sensitive +# +# Sort order: Dutch, English, French, German (Duden), +# Italian, Latin, Pogtuguese, Spanish +# +# ctype array (must be 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 10 + 20 01 01 01 01 01 01 02 02 02 02 02 02 02 02 02 + 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 02 + 00 00 00 00 00 00 00 02 00 00 00 00 00 00 01 01 + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 02 + 00 00 00 00 02 00 00 00 00 00 00 20 01 01 01 02 + 00 00 00 00 00 00 00 00 02 01 00 00 00 00 00 00 + 00 00 00 00 00 20 01 01 01 01 01 01 01 01 01 01 + 00 01 01 01 01 02 00 00 00 00 00 00 00 00 00 00 + +# to_lower array (must be 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 + 8A 8C 8D 8E 96 9A 9F 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 BE BF + 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 88 8B 9B CE CF + D0 D1 D2 D3 D4 D5 D6 D7 D8 D8 DA DB DC DD DE DF + E0 E1 E2 E3 E4 89 90 87 91 8F 92 94 95 93 97 99 + F0 98 9C 9E 9D F5 F6 F7 F8 F9 FA FB FC FD FE FF + +# to_upper array (must be 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 E7 CB E5 80 CC 81 82 83 E9 + E6 E8 EA ED EB EC 84 EE F1 EF 85 CD F2 F4 F3 86 + 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 AE AF + C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF + D0 D1 D2 D3 D4 D5 D6 D7 D9 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 + +# sort_order array (must be 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 51 53 57 59 63 66 68 6A 75 77 79 7B 7D 81 + 91 93 95 97 9A 9C A6 A8 AA AC B0 B2 B3 B4 B5 B6 + B7 42 52 54 58 5A 64 67 69 6B 76 78 7A 7C 7E 82 + 92 94 96 98 9B 9D A7 A9 AB AD B1 B8 B9 BA BB BC + 4B 4D 55 5D 7F 8B A4 46 44 48 4C 4A 4E 56 5E 5C + 60 62 6F 6D 71 73 80 86 84 88 8C 8A A1 9F A3 A5 + BD BE BF C0 C1 C2 C3 99 C4 C5 C6 C7 C8 C9 4F 8D + CA CB CC CD CE CF D0 D1 D2 D3 D4 D5 D6 D7 50 8E + D8 D9 DA DB 65 DC DD DE DF E0 E1 43 49 89 8F 90 + E2 E3 E4 E5 E6 E7 E8 E9 AF AE EA EB EC ED EE EF + F0 F1 F2 F3 F4 47 5F 45 61 5B 6E 70 72 6C 85 87 + F0 83 A0 A2 9E 74 F6 F7 F8 F9 FA FB FC FD FE FF + +# Unicode mapping (must be 256 elements) + 0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F + 0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F + 0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F + 0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F + 0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F + 0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F + 0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F + 0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F + 00C4 00C5 00C7 00C9 00D1 00D6 00DC 00E1 00E0 00E2 00E4 00E3 00E5 00E7 00E9 00E8 + 00EA 00EB 00ED 00EC 00EE 00EF 00F1 00F3 00F2 00F4 00F6 00F5 00FA 00F9 00FB 00FC + 2020 00B0 00A2 00A3 00A7 2022 00B6 00DF 00AE 00A9 2122 00B4 00A8 2260 00C6 00D8 + 221E 00B1 2264 2265 00A5 00B5 2202 2211 220F 03C0 222B 00AA 00BA 03A9 00E6 00F8 + 00BF 00A1 00AC 221A 0192 2248 2206 00AB 00BB 2026 00A0 00C0 00C3 00D5 0152 0153 + 2013 2014 201C 201D 2018 2019 00F7 25CA 00FF 0178 2044 20AC 2039 203A FB01 FB02 + 2021 00B7 201A 201E 2030 00C2 00CA 00C1 00CB 00C8 00CD 00CE 00CF 00CC 00D3 00D4 + F8FF 00D2 00DA 00DB 00D9 0131 02C6 02DC 00AF 02D8 02D9 02DA 00B8 02DD 02DB 02C7 + diff --git a/sql/share/charsets/pclatin2.conf b/sql/share/charsets/pclatin2.conf new file mode 100644 index 00000000000..dea8d085595 --- /dev/null +++ b/sql/share/charsets/pclatin2.conf @@ -0,0 +1,91 @@ +# ctype array (must be 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 00 + 01 02 02 02 02 02 02 02 02 02 01 02 02 01 01 01 + 01 01 02 02 02 01 02 01 02 01 01 01 02 01 00 02 + 02 02 02 02 01 02 01 02 01 02 00 02 01 01 00 00 + 00 00 00 00 00 01 01 01 02 00 00 00 00 01 02 00 + 00 00 00 00 00 00 01 02 00 00 00 00 00 00 00 00 + 02 01 01 01 02 01 01 01 02 00 00 00 00 01 01 00 + 01 02 01 01 02 02 01 02 01 01 02 01 02 01 02 00 + 00 00 00 00 00 00 00 00 00 00 00 02 01 02 00 48 + +# to_lower array (must be 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 + 87 81 82 83 84 85 86 87 88 89 8B 8B 8C AB 84 86 + 82 92 92 93 94 96 96 98 98 94 81 9C 9C 88 9E 9F + A0 A1 A2 A3 A5 A5 A7 A7 A9 A9 AA AB 9F B8 AE AF + B0 B1 B2 B3 B4 A0 83 D8 B8 B9 BA BB BC BE BE BF + C0 C1 C2 C3 C4 C5 C7 C7 C8 C9 CA CB CC CD CE CF + D0 D0 D4 89 D4 E5 A1 8C D8 D9 DA DB DC EE 85 DF + A2 E1 93 E4 E4 E5 E7 E7 EA A3 E8 FB EC EC EE EF + F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF + +# to_upper array (must be 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 9A 90 B6 8E DE 8F 80 9D D3 8A 8A D7 8D 8E 8F + 90 91 91 E2 99 95 95 97 97 99 9A 9B 9B 9D 9E AC + B5 D6 E0 E9 A4 A4 A6 A6 A8 A8 AA 8D AC AD AE AF + B0 B1 B2 B3 B4 B5 B6 B7 AD B9 BA BB BC BE BD BF + C0 C1 C2 C3 C4 C5 C6 C6 C8 C9 CA CB CC CD CE CF + D1 D1 D2 D3 D2 D5 D6 D7 B7 D9 DA DB DC DD DE DF + E0 E1 E2 E3 E3 D5 E6 E6 E8 E9 E8 EB ED ED DD EF + F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA EB FC FC FE FF + +# sort_order array (must be 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 47 48 4C 4F 54 55 56 57 5A 5B 5C 5E 5F 62 + 67 68 69 6C 71 74 75 76 77 78 7B 90 91 92 93 94 + 95 41 47 48 4C 4F 54 55 56 57 5A 5B 5C 5E 5F 62 + 67 68 69 6C 71 74 75 76 77 78 7B 96 97 98 99 9A + 48 74 4F 41 41 74 48 48 5C 4F 62 62 57 7B 41 48 + 4F 5C 5C 62 62 5C 5C 6C 6C 62 74 71 71 5C 9E 48 + 41 57 62 74 41 41 7B 7B 4F 4F AA 7B 48 6C AE AF + B0 B1 B2 B3 B4 41 41 4F 6C B5 BA BB BC 7B 7B BF + C0 C1 C2 C3 C4 C5 41 41 C8 C9 CA CB CC CD CE CF + 4C 4C 4C 4F 4C 60 57 57 4F D9 DA DB DC 71 74 DF + 62 70 62 60 60 60 6C 6C 69 74 69 74 78 78 71 EF + F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA 74 69 69 FE FF + +# Unicode mappping (must be 256 elements) + 0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F + 0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F + 0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F + 0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F + 0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F + 0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F + 0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F + 0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F + 00C7 00FC 00E9 00E2 00E4 016F 0107 00E7 0142 00EB 0150 0151 00EE 0179 00C4 0106 + 00C9 0139 013A 00F4 00F6 013D 013E 015A 015B 00D6 00DC 0164 0165 0141 00D7 010D + 00E1 00ED 00F3 00FA 0104 0105 017D 017E 0118 0119 00AC 017A 010C 015F 00AB 00BB + 2591 2592 2593 2502 2524 00C1 00C2 011A 015E 2563 2551 2557 255D 017B 017C 2510 + 2514 2534 252C 251C 2500 253C 0102 0103 255A 2554 2569 2566 2560 2550 256C 00A4 + 0111 0110 010E 00CB 010F 0147 00CD 00CE 011B 2518 250C 2588 2584 0162 016E 2580 + 00D3 00DF 00D4 0143 0144 0148 0160 0161 0154 00DA 0155 0170 00FD 00DD 0163 00B4 + 00AD 02DD 02DB 02C7 02D8 00A7 00F7 00B8 00B0 00A8 02D9 0171 0158 0159 25A0 00A0 + diff --git a/sql/share/charsets/swe7.conf b/sql/share/charsets/swe7.conf index d2de48b4d1c..49938800f39 100644 --- a/sql/share/charsets/swe7.conf +++ b/sql/share/charsets/swe7.conf @@ -72,3 +72,21 @@ 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 + +# Unicode mapping (256 elements) +0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F +0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F +0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F +0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F +00C9 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F +0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 00C4 00D6 00C5 00DC 005F +00E9 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F +0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 00E4 00F6 00E5 00FC 0000 +0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 diff --git a/sql/share/charsets/usa7.conf b/sql/share/charsets/usa7.conf index b9e7a44c894..380fc9b5d8b 100644 --- a/sql/share/charsets/usa7.conf +++ b/sql/share/charsets/usa7.conf @@ -72,3 +72,21 @@ 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 + +# Unicode mapping (256 elements) +0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F +0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F +0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F +0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F +0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F +0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F +0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F +0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 0000 +0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 +0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 diff --git a/sql/share/charsets/win1250.conf b/sql/share/charsets/win1250.conf index 31d253d7381..0a5b5074bde 100644 --- a/sql/share/charsets/win1250.conf +++ b/sql/share/charsets/win1250.conf @@ -72,3 +72,21 @@ 47 53 53 55 55 55 55 D7 58 5C 5C 5C 5C 60 5B 59 58 41 41 41 41 50 45 43 44 49 49 49 49 4D 4D 46 47 53 53 55 55 55 55 F7 58 5C 5C 5C 5C 60 5B FF + +# Unicode mapping table (256 elements) +0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F +0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F +0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F +0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F +0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F +0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F +0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F +0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F +20AC 0000 201A 0000 201E 2026 2020 2021 0000 2030 0160 2039 015A 0164 017D 0179 +0000 2018 2019 201C 201D 2022 2013 2014 0000 2122 0161 203A 015B 0165 017E 017A +00A0 02C7 02D8 0141 00A4 0104 00A6 00A7 00A8 00A9 015E 00AB 00AC 00AD 00AE 017B +00B0 00B1 02DB 0142 00B4 00B5 00B6 00B7 00B8 0105 015F 00BB 013D 02DD 013E 017C +0154 00C1 00C2 0102 00C4 0139 0106 00C7 010C 00C9 0118 00CB 011A 00CD 00CE 010E +0110 0143 0147 00D3 00D4 0150 00D6 00D7 0158 016E 00DA 0170 00DC 00DD 0162 00DF +0155 00E1 00E2 0103 00E4 013A 0107 00E7 010D 00E9 0119 00EB 011B 00ED 00EE 010F +0111 0144 0148 00F3 00F4 0151 00F6 00F7 0159 016F 00FA 0171 00FC 00FD 0163 02D9 diff --git a/sql/share/charsets/win1251.conf b/sql/share/charsets/win1251.conf index a5ccc3190ad..2164cb36b9e 100644 --- a/sql/share/charsets/win1251.conf +++ b/sql/share/charsets/win1251.conf @@ -80,3 +80,21 @@ D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF E0 C0 C1 C2 C3 C4 C5 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 + +# Unicode mapping (256 elements) +0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F +0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F +0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F +0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F +0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F +0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F +0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F +0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F +0402 0403 201A 0453 201E 2026 2020 2021 0000 2030 0409 2039 040A 040C 040B 040F +0452 2018 2019 201C 201D 2022 2013 2014 0000 2122 0459 203A 045A 045C 045B 045F +00A0 040E 045E 0408 00A4 0490 00A6 00A7 0401 00A9 0404 00AB 00AC 00AD 00AE 0407 +00B0 00B1 0406 0456 0491 00B5 00B6 00B7 0451 2116 0454 00BB 0458 0405 0455 0457 +0410 0411 0412 0413 0414 0415 0416 0417 0418 0419 041A 041B 041C 041D 041E 041F +0420 0421 0422 0423 0424 0425 0426 0427 0428 0429 042A 042B 042C 042D 042E 042F +0430 0431 0432 0433 0434 0435 0436 0437 0438 0439 043A 043B 043C 043D 043E 043F +0440 0441 0442 0443 0444 0445 0446 0447 0448 0449 044A 044B 044C 044D 044E 044F diff --git a/sql/share/charsets/win1251ukr.conf b/sql/share/charsets/win1251ukr.conf index e693958910e..da08e4c7d6f 100644 --- a/sql/share/charsets/win1251ukr.conf +++ b/sql/share/charsets/win1251ukr.conf @@ -75,3 +75,21 @@ 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 80 81 82 83 85 86 89 8A 8B 8E 8F 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F A0 A1 A2 A3 A4 + +# Unicode mapping (256 elements) +0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F +0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F +0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F +0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F +0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F +0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F +0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F +0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F +0402 0403 201A 0453 201E 2026 2020 2021 0000 2030 0409 2039 040A 040C 040B 040F +0452 2018 2019 201C 201D 2022 2013 2014 0000 2122 0459 203A 045A 045C 045B 045F +00A0 040E 045E 0408 00A4 0490 00A6 00A7 0401 00A9 0404 00AB 00AC 00AD 00AE 0407 +00B0 00B1 0406 0456 0491 00B5 00B6 00B7 0451 2116 0454 00BB 0458 0405 0455 0457 +0410 0411 0412 0413 0414 0415 0416 0417 0418 0419 041A 041B 041C 041D 041E 041F +0420 0421 0422 0423 0424 0425 0426 0427 0428 0429 042A 042B 042C 042D 042E 042F +0430 0431 0432 0433 0434 0435 0436 0437 0438 0439 043A 043B 043C 043D 043E 043F +0440 0441 0442 0443 0444 0445 0446 0447 0448 0449 044A 044B 044C 044D 044E 044F diff --git a/sql/share/czech/errmsg.txt b/sql/share/czech/errmsg.txt index b69484cb38b..1b1f90abfb3 100644 --- a/sql/share/czech/errmsg.txt +++ b/sql/share/czech/errmsg.txt @@ -206,7 +206,7 @@ "Nezn-Bámá systémová promìnná '%-.64s'", "Tabulka '%-.64s' je ozna-Bèena jako poru¹ená a mìla by být opravena", "Tabulka '%-.64s' je ozna-Bèena jako poru¹ená a poslední (automatická?) oprava se nezdaøila", -"Warning: Some non-transactional changed tables couldn't be rolled back", +"Some non-transactional changed tables couldn't be rolled back", "Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage. Increase this mysqld variable and try again', "This operation cannot be performed with a running slave, run SLAVE STOP first", "This operation requires a running slave, configure slave and do SLAVE START", @@ -247,3 +247,11 @@ "Wrong usage/placement of '%s'", "This version of MySQL doesn't yet support '%s'", "Got fatal error %d: '%-.128s' from master when reading data from binary log", +"Wrong foreign key definition for '%-.64s': %s", +"Key reference and table reference doesn't match", +"Subselect returns more than 1 field", +"Subselect returns more than 1 record", +"Unknown prepared statement handler (%ld) given to %s", +"Help database is corrupt or does not exist", +"Cyclic reference on subqueries", +"Converting column '%s' from %s to %s" diff --git a/sql/share/danish/errmsg.txt b/sql/share/danish/errmsg.txt index ccbc53a0d29..65eb190b48b 100644 --- a/sql/share/danish/errmsg.txt +++ b/sql/share/danish/errmsg.txt @@ -241,3 +241,11 @@ "Wrong usage/placement of '%s'", "This version of MySQL doesn't yet support '%s'", "Got fatal error %d: '%-.128s' from master when reading data from binary log", +"Wrong foreign key definition for '%-.64s': %s", +"Key reference and table reference doesn't match", +"Subselect returns more than 1 field", +"Subselect returns more than 1 record", +"Unknown prepared statement handler (%ld) given to %s", +"Help database is corrupt or does not exist", +"Cyclic reference on subqueries", +"Converting column '%s' from %s to %s" diff --git a/sql/share/dutch/errmsg.txt b/sql/share/dutch/errmsg.txt index 7fce0c7b4f9..965221dd83f 100644 --- a/sql/share/dutch/errmsg.txt +++ b/sql/share/dutch/errmsg.txt @@ -249,3 +249,11 @@ "Foutieve toepassing/plaatsing van '%s'", "Deze versie van MySQL ondersteunt nog geen '%s'", "Kreeg fatale fout %d: '%-.128s' van master tijdens lezen van data uit binaire log", +"Wrong foreign key definition for '%-.64s': %s", +"Key reference and table reference doesn't match", +"Subselect returns more than 1 field", +"Subselect returns more than 1 record", +"Unknown prepared statement handler (%ld) given to %s", +"Help database is corrupt or does not exist", +"Cyclic reference on subqueries", +"Converting column '%s' from %s to %s" diff --git a/sql/share/english/errmsg.txt b/sql/share/english/errmsg.txt index 105cf90ca7d..7472fe14365 100644 --- a/sql/share/english/errmsg.txt +++ b/sql/share/english/errmsg.txt @@ -197,7 +197,7 @@ "Unknown system variable '%-.64s'", "Table '%-.64s' is marked as crashed and should be repaired", "Table '%-.64s' is marked as crashed and last (automatic?) repair failed", -"Warning: Some non-transactional changed tables couldn't be rolled back", +"Some non-transactional changed tables couldn't be rolled back", "Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage. Increase this mysqld variable and try again', "This operation cannot be performed with a running slave, run SLAVE STOP first", "This operation requires a running slave, configure slave and do SLAVE START", @@ -238,3 +238,11 @@ "Wrong usage/placement of '%s'", "This version of MySQL doesn't yet support '%s'", "Got fatal error %d: '%-.128s' from master when reading data from binary log", +"Wrong foreign key definition for '%-.64s': %s", +"Key reference and table reference doesn't match", +"Subselect returns more than 1 field", +"Subselect returns more than 1 record", +"Unknown prepared statement handler (%ld) given to %s", +"Help database is corrupt or does not exist", +"Cyclic reference on subqueries", +"Converting column '%s' from %s to %s" diff --git a/sql/share/estonian/errmsg.txt b/sql/share/estonian/errmsg.txt index d0a30b2f434..3f2745a8809 100644 --- a/sql/share/estonian/errmsg.txt +++ b/sql/share/estonian/errmsg.txt @@ -243,3 +243,11 @@ "Wrong usage/placement of '%s'", "This version of MySQL doesn't yet support '%s'", "Got fatal error %d: '%-.128s' from master when reading data from binary log", +"Wrong foreign key definition for '%-.64s': %s", +"Key reference and table reference doesn't match", +"Subselect returns more than 1 field", +"Subselect returns more than 1 record", +"Unknown prepared statement handler (%ld) given to %s", +"Help database is corrupt or does not exist", +"Cyclic reference on subqueries", +"Converting column '%s' from %s to %s" diff --git a/sql/share/french/errmsg.txt b/sql/share/french/errmsg.txt index ab1761ca042..f1df0c0c2f2 100644 --- a/sql/share/french/errmsg.txt +++ b/sql/share/french/errmsg.txt @@ -238,3 +238,11 @@ "Wrong usage/placement of '%s'", "This version of MySQL doesn't yet support '%s'", "Got fatal error %d: '%-.128s' from master when reading data from binary log", +"Wrong foreign key definition for '%-.64s': %s", +"Key reference and table reference doesn't match", +"Subselect returns more than 1 field", +"Subselect returns more than 1 record", +"Unknown prepared statement handler (%ld) given to %s", +"Help database is corrupt or does not exist", +"Cyclic reference on subqueries", +"Converting column '%s' from %s to %s" diff --git a/sql/share/german/errmsg.txt b/sql/share/german/errmsg.txt index a99aea38563..bd51de5a257 100644 --- a/sql/share/german/errmsg.txt +++ b/sql/share/german/errmsg.txt @@ -241,3 +241,11 @@ "Wrong usage/placement of '%s'", "This version of MySQL doesn't yet support '%s'", "Got fatal error %d: '%-.128s' from master when reading data from binary log", +"Wrong foreign key definition for '%-.64s': %s", +"Key reference and table reference doesn't match", +"Subselect return more than 1 field", +"Subselect return more than 1 record", +"Unknown prepared statement handler (%ld) given to %s", +"Help database is corrupt or does not exist", +"Cyclic reference on subqueries", +"Converting column '%s' from %s to %s" diff --git a/sql/share/greek/errmsg.txt b/sql/share/greek/errmsg.txt index 554176e340b..915b4e9f64b 100644 --- a/sql/share/greek/errmsg.txt +++ b/sql/share/greek/errmsg.txt @@ -197,7 +197,7 @@ "Unknown system variable '%-.64s'", "Table '%-.64s' is marked as crashed and should be repaired", "Table '%-.64s' is marked as crashed and last (automatic?) repair failed", -"Warning: Some non-transactional changed tables couldn't be rolled back", +"Some non-transactional changed tables couldn't be rolled back", "Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage. Increase this mysqld variable and try again', "This operation cannot be performed with a running slave, run SLAVE STOP first", "This operation requires a running slave, configure slave and do SLAVE START", @@ -238,3 +238,11 @@ "Wrong usage/placement of '%s'", "This version of MySQL doesn't yet support '%s'", "Got fatal error %d: '%-.128s' from master when reading data from binary log", +"Wrong foreign key definition for '%-.64s': %s", +"Key reference and table reference doesn't match", +"Subselect returns more than 1 field", +"Subselect returns more than 1 record", +"Unknown prepared statement handler (%ld) given to %s", +"Help database is corrupt or does not exist", +"Cyclic reference on subqueries", +"Converting column '%s' from %s to %s" diff --git a/sql/share/hungarian/errmsg.txt b/sql/share/hungarian/errmsg.txt index 32333ce4439..aa8567dac87 100644 --- a/sql/share/hungarian/errmsg.txt +++ b/sql/share/hungarian/errmsg.txt @@ -199,7 +199,7 @@ "Unknown system variable '%-.64s'", "Table '%-.64s' is marked as crashed and should be repaired", "Table '%-.64s' is marked as crashed and last (automatic?) repair failed", -"Warning: Some non-transactional changed tables couldn't be rolled back", +"Some non-transactional changed tables couldn't be rolled back", "Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage. Increase this mysqld variable and try again', "This operation cannot be performed with a running slave, run SLAVE STOP first", "This operation requires a running slave, configure slave and do SLAVE START", @@ -240,3 +240,11 @@ "Wrong usage/placement of '%s'", "This version of MySQL doesn't yet support '%s'", "Got fatal error %d: '%-.128s' from master when reading data from binary log", +"Wrong foreign key definition for '%-.64s': %s", +"Key reference and table reference doesn't match", +"Subselect returns more than 1 field", +"Subselect returns more than 1 record", +"Unknown prepared statement handler (%ld) given to %s", +"Help database is corrupt or does not exist", +"Cyclic reference on subqueries", +"Converting column '%s' from %s to %s" diff --git a/sql/share/italian/errmsg.txt b/sql/share/italian/errmsg.txt index 4dd7b02de4e..20430757590 100644 --- a/sql/share/italian/errmsg.txt +++ b/sql/share/italian/errmsg.txt @@ -238,3 +238,11 @@ "Wrong usage/placement of '%s'", "This version of MySQL doesn't yet support '%s'", "Got fatal error %d: '%-.128s' from master when reading data from binary log", +"Wrong foreign key definition for '%-.64s': %s", +"Key reference and table reference doesn't match", +"Subselect returns more than 1 field", +"Subselect returns more than 1 record", +"Unknown prepared statement handler (%ld) given to %s", +"Help database is corrupt or does not exist", +"Cyclic reference on subqueries", +"Converting column '%s' from %s to %s" diff --git a/sql/share/japanese/errmsg.txt b/sql/share/japanese/errmsg.txt index 663676e0cf3..2f3c61c1fe1 100644 --- a/sql/share/japanese/errmsg.txt +++ b/sql/share/japanese/errmsg.txt @@ -199,7 +199,7 @@ "Unknown system variable '%-.64s'", "Table '%-.64s' is marked as crashed and should be repaired", "Table '%-.64s' is marked as crashed and last (automatic?) repair failed", -"Warning: Some non-transactional changed tables couldn't be rolled back", +"Some non-transactional changed tables couldn't be rolled back", "Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage. Increase this mysqld variable and try again', "This operation cannot be performed with a running slave, run SLAVE STOP first", "This operation requires a running slave, configure slave and do SLAVE START", @@ -240,3 +240,11 @@ "Wrong usage/placement of '%s'", "This version of MySQL doesn't yet support '%s'", "Got fatal error %d: '%-.128s' from master when reading data from binary log", +"Wrong foreign key definition for '%-.64s': %s", +"Key reference and table reference doesn't match", +"Subselect returns more than 1 field", +"Subselect returns more than 1 record", +"Unknown prepared statement handler (%ld) given to %s", +"Help database is corrupt or does not exist", +"Cyclic reference on subqueries", +"Converting column '%s' from %s to %s" diff --git a/sql/share/korean/errmsg.txt b/sql/share/korean/errmsg.txt index da1ee97f6b6..277e53895c3 100644 --- a/sql/share/korean/errmsg.txt +++ b/sql/share/korean/errmsg.txt @@ -197,7 +197,7 @@ "Unknown system variable '%-.64s'", "Table '%-.64s' is marked as crashed and should be repaired", "Table '%-.64s' is marked as crashed and last (automatic?) repair failed", -"Warning: Some non-transactional changed tables couldn't be rolled back", +"Some non-transactional changed tables couldn't be rolled back", "Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage. Increase this mysqld variable and try again', "This operation cannot be performed with a running slave, run SLAVE STOP first", "This operation requires a running slave, configure slave and do SLAVE START", @@ -238,3 +238,11 @@ "Wrong usage/placement of '%s'", "This version of MySQL doesn't yet support '%s'", "Got fatal error %d: '%-.128s' from master when reading data from binary log", +"Wrong foreign key definition for '%-.64s': %s", +"Key reference and table reference doesn't match", +"Subselect returns more than 1 field", +"Subselect returns more than 1 record", +"Unknown prepared statement handler (%ld) given to %s", +"Help database is corrupt or does not exist", +"Cyclic reference on subqueries", +"Converting column '%s' from %s to %s" diff --git a/sql/share/norwegian-ny/errmsg.txt b/sql/share/norwegian-ny/errmsg.txt index bc334ace9f1..4c3a12d6557 100644 --- a/sql/share/norwegian-ny/errmsg.txt +++ b/sql/share/norwegian-ny/errmsg.txt @@ -199,7 +199,7 @@ "Unknown system variable '%-.64s'", "Table '%-.64s' is marked as crashed and should be repaired", "Table '%-.64s' is marked as crashed and last (automatic?) repair failed", -"Warning: Some non-transactional changed tables couldn't be rolled back", +"Some non-transactional changed tables couldn't be rolled back", "Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage. Increase this mysqld variable and try again', "This operation cannot be performed with a running slave, run SLAVE STOP first", "This operation requires a running slave, configure slave and do SLAVE START", @@ -240,3 +240,11 @@ "Wrong usage/placement of '%s'", "This version of MySQL doesn't yet support '%s'", "Got fatal error %d: '%-.128s' from master when reading data from binary log", +"Wrong foreign key definition for '%-.64s': %s", +"Key reference and table reference doesn't match", +"Subselect returns more than 1 field", +"Subselect returns more than 1 record", +"Unknown prepared statement handler (%ld) given to %s", +"Help database is corrupt or does not exist", +"Cyclic reference on subqueries", +"Converting column '%s' from %s to %s" diff --git a/sql/share/norwegian/errmsg.txt b/sql/share/norwegian/errmsg.txt index e7f54549462..46bf84c409e 100644 --- a/sql/share/norwegian/errmsg.txt +++ b/sql/share/norwegian/errmsg.txt @@ -199,7 +199,7 @@ "Unknown system variable '%-.64s'", "Table '%-.64s' is marked as crashed and should be repaired", "Table '%-.64s' is marked as crashed and last (automatic?) repair failed", -"Warning: Some non-transactional changed tables couldn't be rolled back", +"Some non-transactional changed tables couldn't be rolled back", "Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage. Increase this mysqld variable and try again', "This operation cannot be performed with a running slave, run SLAVE STOP first", "This operation requires a running slave, configure slave and do SLAVE START", @@ -240,3 +240,11 @@ "Wrong usage/placement of '%s'", "This version of MySQL doesn't yet support '%s'", "Got fatal error %d: '%-.128s' from master when reading data from binary log", +"Wrong foreign key definition for '%-.64s': %s", +"Key reference and table reference doesn't match", +"Subselect returns more than 1 field", +"Subselect returns more than 1 record", +"Unknown prepared statement handler (%ld) given to %s", +"Help database is corrupt or does not exist", +"Cyclic reference on subqueries", +"Converting column '%s' from %s to %s" diff --git a/sql/share/polish/errmsg.txt b/sql/share/polish/errmsg.txt index 0e92bf2f9b8..e4d9832725d 100644 --- a/sql/share/polish/errmsg.txt +++ b/sql/share/polish/errmsg.txt @@ -201,7 +201,7 @@ "Unknown system variable '%-.64s'", "Table '%-.64s' is marked as crashed and should be repaired", "Table '%-.64s' is marked as crashed and last (automatic?) repair failed", -"Warning: Some non-transactional changed tables couldn't be rolled back", +"Some non-transactional changed tables couldn't be rolled back", "Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage. Increase this mysqld variable and try again', "This operation cannot be performed with a running slave, run SLAVE STOP first", "This operation requires a running slave, configure slave and do SLAVE START", @@ -242,3 +242,11 @@ "Wrong usage/placement of '%s'", "This version of MySQL doesn't yet support '%s'", "Got fatal error %d: '%-.128s' from master when reading data from binary log", +"Wrong foreign key definition for '%-.64s': %s", +"Key reference and table reference doesn't match", +"Subselect returns more than 1 field", +"Subselect returns more than 1 record", +"Unknown prepared statement handler (%ld) given to %s", +"Help database is corrupt or does not exist", +"Cyclic reference on subqueries", +"Converting column '%s' from %s to %s" diff --git a/sql/share/portuguese/errmsg.txt b/sql/share/portuguese/errmsg.txt index 6f4f86f9024..1c5adc96560 100644 --- a/sql/share/portuguese/errmsg.txt +++ b/sql/share/portuguese/errmsg.txt @@ -238,3 +238,11 @@ "Wrong usage/placement of '%s'", "This version of MySQL doesn't yet support '%s'", "Got fatal error %d: '%-.128s' from master when reading data from binary log", +"Wrong foreign key definition for '%-.64s': %s", +"Key reference and table reference doesn't match", +"Subselect returns more than 1 field", +"Subselect returns more than 1 record", +"Unknown prepared statement handler (%ld) given to %s", +"Help database is corrupt or does not exist", +"Cyclic reference on subqueries", +"Converting column '%s' from %s to %s" diff --git a/sql/share/romanian/errmsg.txt b/sql/share/romanian/errmsg.txt index b888a2bc8cd..313af2e5f14 100644 --- a/sql/share/romanian/errmsg.txt +++ b/sql/share/romanian/errmsg.txt @@ -201,7 +201,7 @@ "Unknown system variable '%-.64s'", "Table '%-.64s' is marked as crashed and should be repaired", "Table '%-.64s' is marked as crashed and last (automatic?) repair failed", -"Warning: Some non-transactional changed tables couldn't be rolled back", +"Some non-transactional changed tables couldn't be rolled back", "Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage. Increase this mysqld variable and try again', "This operation cannot be performed with a running slave, run SLAVE STOP first", "This operation requires a running slave, configure slave and do SLAVE START", @@ -242,3 +242,11 @@ "Wrong usage/placement of '%s'", "This version of MySQL doesn't yet support '%s'", "Got fatal error %d: '%-.128s' from master when reading data from binary log", +"Wrong foreign key definition for '%-.64s': %s", +"Key reference and table reference doesn't match", +"Subselect returns more than 1 field", +"Subselect returns more than 1 record", +"Unknown prepared statement handler (%ld) given to %s", +"Help database is corrupt or does not exist", +"Cyclic reference on subqueries", +"Converting column '%s' from %s to %s" diff --git a/sql/share/russian/errmsg.txt b/sql/share/russian/errmsg.txt index 0329f760e38..3b636aacae7 100644 --- a/sql/share/russian/errmsg.txt +++ b/sql/share/russian/errmsg.txt @@ -241,3 +241,11 @@ "Wrong usage/placement of '%s'", "This version of MySQL doesn't yet support '%s'", "Got fatal error %d: '%-.128s' from master when reading data from binary log", +"Wrong foreign key definition for '%-.64s': %s", +"Key reference and table reference doesn't match", +"ðÏÄÚÁÐÒÏÓ ×ÏÚ×ÒÁÝÁÅÔ ÂÏÌÅÅ ÏÄÎÏÇÏ ÐÏÌÑ", +"ðÏÄÚÁÐÒÏÓ ×ÏÚ×ÒÁÝÁÅÔ ÂÏÌÅÅ ÏÄÎÏÊ ÚÁÐÉÓÉ", +"Unknown prepared statement handler (%ld) given to %s", +"Help database is corrupt or does not exist", +"ãÉËÌÉÞÅÓËÁÑ ÓÓÙÌËÁ ÎÁ ÐÏÄÚÁÐÒÏÓ", +"Converting column '%s' from %s to %s" diff --git a/sql/share/serbian/errmsg.txt b/sql/share/serbian/errmsg.txt new file mode 100644 index 00000000000..0ee69010aca --- /dev/null +++ b/sql/share/serbian/errmsg.txt @@ -0,0 +1,244 @@ +/* Copyright Abandoned 1997 TCX DataKonsult AB & Monty Program KB & Detron HB + This file is public domain and comes with NO WARRANTY of any kind */ + +/* Serbian Translation, version 1.0: + Copyright 2002 Vladimir Kraljevic, vladimir_kraljevic@yahoo.com + This file is public domain and comes with NO WARRANTY of any kind. + Charset: cp1250 +*/ + +"hashchk", +"isamchk", +"NE", +"DA", +"Ne mogu da kreiram file '%-.64s' (errno: %d)", +"Ne mogu da kreiram tabelu '%-.64s' (errno: %d)", +"Ne mogu da kreiram bazu '%-.64s'. (errno: %d)", +"Ne mogu da kreiram bazu '%-.64s'. Baza veæ postoji.", +"Ne mogu da izbrišem bazu '%-.64s'. Baza ne postoji.", +"Ne mogu da izbrišem bazu (ne mogu da izbrišem '%-.64s', errno: %d)", +"Ne mogu da izbrišem bazu (ne mogu da izbrišem direktorijum '%-.64s', errno: %d)", +"Greška pri brisanju '%-.64s' (errno: %d)", +"Ne mogu da proèitam slog iz sistemske tabele", +"Ne mogu da dobijem stanje file-a '%-.64s' (errno: %d)", +"Ne mogu da dobijem trenutni direktorijum (errno: %d)", +"Ne mogu da zakljuèam file (errno: %d)", +"Ne mogu da otvorim file: '%-.64s'. (errno: %d)", +"Ne mogu da pronaðem file: '%-.64s' (errno: %d)", +"Ne mogu da proèitam direktorijum '%-.64s' (errno: %d)", +"Ne mogu da promenim direktorijum na '%-.64s' (errno: %d)", +"Slog je promenjen od zadnjeg èitanja tabele '%-.64s'", +"Disk je pun (%s). Èekam nekoga da doðe i oslobodi nešto mesta....", +"Ne mogu da pišem pošto postoji duplirani kljuè u tabeli '%-.64s'", +"Greška pri zatvaranju '%-.64s' (errno: %d)", +"Greška pri èitanju file-a '%-.64s' (errno: %d)", +"Greška pri promeni imena '%-.64s' na '%-.64s' (errno: %d)", +"Greška pri upisu '%-.64s' (errno: %d)", +"'%-.64s' je zakljuèan za upis", +"Sortiranje je prekinuto", +"View '%-.64s' ne postoji za '%-.64s'", +"Handler tabela je vratio grešku %d", +"Handler tabela za '%-.64s' nema ovu opciju", +"Ne mogu da pronaðem slog u '%-.64s'", +"Pogrešna informacija u file-u: '%-.64s'", +"Pogrešan key file za tabelu: '%-.64s'. Probajte da ga ispravite", +"Zastareo key file za tabelu '%-.64s'; Ispravite ga", +"Tabelu '%-.64s' je dozvoljeno samo èitati", +"Nema memorije. Restartujte MySQL server i probajte ponovo (potrebno je %d byte-ova)", +"Nema memorije za sortiranje. Poveæajte velièinu sort buffer-a MySQL server-u", +"Neoèekivani kraj pri èitanju file-a '%-.64s' (errno: %d)", +"Previše konekcija", +"Nema memorije; Proverite da li MySQL server ili neki drugi proces koristi svu slobodnu memoriju. (UNIX: Ako ne, probajte da upotrebite 'ulimit' komandu da biste dozvolili daemon-u da koristi više memorije ili probajte da dodate više swap memorije)", +"Ne mogu da dobijem ime host-a za vašu IP adresu", +"Loš poèetak komunikacije (handshake)", +"Pristup je zabranjen korisniku '%-.32s@%-.64s' za bazu '%-.64s'", +"Pristup je zabranjen korisniku '%-.32s@%-.64s' (koristi lozinku: '%s')", +"Ni jedna baza nije selektovana", +"Nepoznata komanda", +"Kolona '%-.64s' ne može biti NULL", +"Nepoznata baza '%-.64s'", +"Tabela '%-.64s' veæ postoji", +"Nepoznata tabela '%-.64s'", +"Kolona '%-.64s' u %-.64s nije jedinstvena u kontekstu", +"Gašenje servera je u toku", +"Nepoznata kolona '%-.64s' u '%-.64s'", +"Entitet '%-.64s' nije naveden u komandi 'GROUP BY'", +"Ne mogu da grupišem po '%-.64s'", +"Izraz ima 'SUM' agregatnu funkciju i kolone u isto vreme", +"Broj kolona ne odgovara broju vrednosti", +"Ime '%-.100s' je predugaèko", +"Duplirano ime kolone '%-.64s'", +"Duplirano ime kljuèa '%-.64s'", +"Dupliran unos '%-.64s' za kljuè '%d'", +"Pogrešan naziv kolone za kolonu '%-.64s'", +"'%s' u iskazu '%-.80s' na liniji %d", +"Upit je bio prazan", +"Tabela ili alias nisu bili jedinstveni: '%-.64s'", +"Loša default vrednost za '%-.64s'", +"Definisani višestruki primarni kljuèevi", +"Navedeno je previše kljuèeva. Maksimum %d kljuèeva je dozvoljeno", +"Navedeno je previše delova kljuèa. Maksimum %d delova je dozvoljeno", +"Navedeni kljuè je predug. Maksimalna dužina kljuèa je %d", +"Kljuèna kolona '%-.64s' ne postoji u tabeli", +"BLOB kolona '%-.64s' ne može biti upotrebljena za navoðenje kljuèa sa tipom tabele koji se trenutno koristi", +"Previše podataka za kolonu '%-.64s' (maksimum je %d). Upotrebite BLOB polje", +"Pogrešna definicija tabele; U tabeli može postojati samo jedna 'AUTO' kolona i ona mora biti istovremeno definisana kao kolona kljuèa", +"%s: Spreman za konekcije\n", +"%s: Normalno gašenje\n", +"%s: Dobio signal %d. Prekidam!\n", +"%s: Gašenje završeno\n", +"%s: Usiljeno gašenje thread-a %ld koji pripada korisniku: '%-.32s'\n", +"Ne mogu da kreiram IP socket", +"Tabela '%-.64s' nema isti indeks kao onaj upotrebljen pri komandi 'CREATE INDEX'. Napravite tabelu ponovo", +"Argument separatora polja nije ono što se oèekivalo. Proverite uputstvo MySQL server-a", +"Ne možete koristiti fiksnu velièinu sloga kada imate BLOB polja. Molim koristite 'fields terminated by' opciju.", +"File '%-.64s' mora biti u direktorijumu gde su file-ovi baze i mora imati odgovarajuæa prava pristupa", +"File '%-.80s' veæ postoji", +"Slogova: %ld Izbrisano: %ld Preskoèeno: %ld Upozorenja: %ld", +"Slogova: %ld Duplikata: %ld", +"Pogrešan pod-kljuè dela kljuèa. Upotrebljeni deo kljuèa nije string, upotrebljena dužina je veæa od dela kljuèa ili handler tabela ne podržava jedinstvene pod-kljuèeve", +"Ne možete da izbrišete sve kolone pomoæu komande 'ALTER TABLE'. Upotrebite komandu 'DROP TABLE' ako želite to da uradite", +"Ne mogu da izvršim komandu drop 'DROP' na '%-.64s'. Proverite da li ta kolona (odnosno kljuè) postoji", +"Slogova: %ld Duplikata: %ld Upozorenja: %ld", +"Komanda 'INSERT TABLE' na '%-.64s' nije dozvoljena u listi 'FROM' tabela", +"Nepoznat thread identifikator: %lu", +"Vi niste vlasnik thread-a %lu", +"Nema upotrebljenih tabela", +"Previše string-ova za kolonu '%-.64s' i komandu 'SET'", +"Ne mogu da generišem jedinstveno ime log-file-a: '%-.64s.(1-999)'\n", +"Tabela '%-.64s' je zakljuèana READ lock-om; iz nje se može samo èitati ali u nju se ne može pisati", +"Tabela '%-.64s' nije bila zakljuèana komandom 'LOCK TABLES'", +"BLOB kolona '%-.64s' ne može imati default vrednost", +"Pogrešno ime baze '%-.100s'", +"Pogrešno ime tabele '%-.100s'", +"Komanda 'SELECT' æe ispitati previše slogova i potrošiti previše vremena. Proverite vaš 'WHERE' filter i upotrebite 'SET OPTION SQL_BIG_SELECTS=1' ako želite baš ovakvu komandu", +"Nepoznata greška", +"Nepoznata procedura '%-.64s'", +"Pogrešan broj parametara za proceduru '%-.64s'", +"Pogrešni parametri prosleðeni proceduri '%-.64s'", +"Nepoznata tabela '%-.64s' u '%-.32s'", +"Kolona '%-.64s' je navedena dva puta", +"Pogrešna upotreba 'GROUP' funkcije", +"Tabela '%-.64s' koristi ekstenziju koje ne postoji u ovoj verziji MySQL-a", +"Tabela mora imati najmanje jednu kolonu", +"Tabela '%-.64s' je popunjena do kraja", +"Nepoznati karakter-set: '%-.64s'", +"Previše tabela. MySQL može upotrebiti maksimum %d tabela pri 'JOIN' operaciji", +"Previše kolona", +"Prevelik slog. Maksimalna velièina sloga, ne raèunajuæi BLOB polja, je %d. Trebali bi da promenite tip nekih polja u BLOB", +"Prepisivanje thread stack-a: Upotrebljeno: %ld od %ld stack memorije. Upotrebite 'mysqld -O thread_stack=#' da navedete veæi stack ako je potrebno", +"Unakrsna zavisnost pronaðena u komandi 'OUTER JOIN'. Istražite vaše 'ON' uslove", +"Kolona '%-.64s' je upotrebljena kao 'UNIQUE' ili 'INDEX' ali nije definisana kao 'NOT NULL'", +"Ne mogu da uèitam funkciju '%-.64s'", +"Ne mogu da inicijalizujem funkciju '%-.64s'; %-.80s", +"Ne postoje dozvoljene putanje do share-ovane biblioteke", +"Funkcija '%-.64s' veæ postoji", +"Ne mogu da otvorim share-ovanu biblioteku '%-.64s' (errno: %d %-.64s)", +"Ne mogu da pronadjem funkciju '%-.64s' u biblioteci", +"Funkcija '%-.64s' nije definisana", +"Host '%-.64s' je blokiran zbog previše grešaka u konekciji. Možete ga odblokirati pomoæu komande 'mysqladmin flush-hosts'", +"Host-u '%-.64s' nije dozvoljeno da se konektuje na ovaj MySQL server", +"Vi koristite MySQL kao anonimni korisnik a anonimnim korisnicima nije dozvoljeno da menjaju lozinke", +"Morate imati privilegije da možete da update-ujete odreðene tabele ako želite da menjate lozinke za druge korisnike", +"Ne mogu da pronaðem odgovarajuæi slog u 'user' tabeli", +"Odgovarajuæih slogova: %ld Promenjeno: %ld Upozorenja: %ld", +"Ne mogu da kreiram novi thread (errno %d). Ako imate još slobodne memorije, trebali biste da pogledate u priruèniku da li je ovo specifièna greška vašeg operativnog sistema", +"Broj kolona ne odgovara broju vrednosti u slogu %ld", +"Ne mogu da ponovo otvorim tabelu '%-.64s'", +"Pogrešna upotreba vrednosti NULL", +"Funkcija regexp je vratila grešku '%-.64s'", +"Upotreba agregatnih funkcija (MIN(),MAX(),COUNT()...) bez 'GROUP' kolona je pogrešna ako ne postoji 'GROUP BY' iskaz", +"Ne postoji odobrenje za pristup korisniku '%-.32s' na host-u '%-.64s'", +"%-.16s komanda zabranjena za korisnika '%-.32s@%-.64s' za tabelu '%-.64s'", +"%-.16s komanda zabranjena za korisnika '%-.32s@%-.64s' za kolonu '%-.64s' iz tabele '%-.64s'", +"Pogrešna 'GRANT' odnosno 'REVOKE' komanda. Molim Vas pogledajte u priruèniku koje vrednosti mogu biti upotrebljene.", +"Argument 'host' ili 'korisnik' prosleðen komandi 'GRANT' je predugaèak", +"Tabela '%-.64s.%-.64s' ne postoji", +"Ne postoji odobrenje za pristup korisniku '%-.32s' na host-u '%-.64s' tabeli '%-.64s'", +"Upotrebljena komanda nije dozvoljena sa ovom verzijom MySQL servera", +"Imate grešku u vašoj SQL sintaksi", +"Prolongirani 'INSERT' thread nije mogao da dobije traženo zakljuèavanje tabele '%-.64s'", +"Previše prolongiranih thread-ova je u upotrebi", +"Prekinuta konekcija broj %ld ka bazi: '%-.64s' korisnik je bio: '%-.32s' (%-.64s)", +"Primio sam mrežni paket veæi od definisane vrednosti 'max_allowed_packet'", +"Greška pri èitanju podataka sa pipe-a", +"Greška pri izvršavanju funkcije fcntl()", +"Primio sam mrežne pakete van reda", +"Ne mogu da dekompresujem mrežne pakete", +"Greška pri primanju mrežnih paketa", +"Vremenski limit za èitanje mrežnih paketa je istekao", +"Greška pri slanju mrežnih paketa", +"Vremenski limit za slanje mrežnih paketa je istekao", +"Rezultujuèi string je duži nego što to dozvoljava parametar servera 'max_allowed_packet'", +"Iskorišteni tip tabele ne podržava kolone tipa 'BLOB' odnosno 'TEXT'", +"Iskorišteni tip tabele ne podržava kolone tipa 'AUTO_INCREMENT'", +"Komanda 'INSERT DELAYED' ne može biti iskorištena u tabeli '%-.64s', zbog toga što je zakljuèana komandom 'LOCK TABLES'", +"Pogrešno ime kolone '%-.100s'", +"Handler tabele ne može da indeksira kolonu '%-.64s'", +"Tabele iskorištene u 'MERGE' tabeli nisu definisane na isti naèin", +"Zbog provere jedinstvenosti ne mogu da upišem podatke u tabelu '%-.64s'", +"BLOB kolona '%-.64s' je upotrebljena u specifikaciji kljuèa bez navoðenja dužine kljuèa", +"Svi delovi primarnog kljuèa moraju biti razlièiti od NULL; Ako Vam ipak treba NULL vrednost u kljuèu, upotrebite 'UNIQUE'", +"Rezultat je saèinjen od više slogova", +"Ovaj tip tabele zahteva da imate definisan primarni kljuè", +"Ova verzija MySQL servera nije kompajlirana sa podrškom za RAID ureðaje", +"Vi koristite safe update mod servera, a probali ste da promenite podatke bez 'WHERE' komande koja koristi kolonu kljuèa", +"Kljuè '%-.64s' ne postoji u tabeli '%-.64s'", +"Ne mogu da otvorim tabelu", +"Handler za ovu tabelu ne dozvoljava 'check' odnosno 'repair' komande", +"Nije Vam dozvoljeno da izvršite ovu komandu u transakciji", +"Greška %d za vreme izvršavanja komande 'COMMIT'", +"Greška %d za vreme izvršavanja komande 'ROLLBACK'", +"Greška %d za vreme izvršavanja komande 'FLUSH_LOGS'", +"Greška %d za vreme izvršavanja komande 'CHECKPOINT'", +"Prekinuta konekcija broj %ld ka bazi: '%-.64s' korisnik je bio: '%-.32s' a host: `%-.64s' (%-.64s)", +"Handler tabele ne podržava binarni dump tabele", +"Binarni log file zatvoren, ne mogu da izvršim komandu 'RESET MASTER'", +"Izgradnja indeksa dump-ovane tabele '%-.64s' nije uspela", +"Greška iz glavnog servera '%-.64s' u klasteru", +"Greška u primanju mrežnih paketa sa glavnog servera u klasteru", +"Greška u slanju mrežnih paketa na glavni server u klasteru", +"Ne mogu da pronaðem 'FULLTEXT' indeks koli odgovara listi kolona", +"Ne mogu da izvršim datu komandu zbog toga što su tabele zakljuèane ili je transakcija u toku", +"Nepoznata sistemska promenljiva '%-.64'", +"Tabela '%-.64s' je markirana kao ošteæena i trebala bi biti popravljena", +"Tabela '%-.64s' je markirana kao ošteæena, a zadnja (automatska?) popravka je bila neuspela", +"Upozorenje: Neke izmenjene tabele ne podržavaju komandu 'ROLLBACK'", +"Transakcija sa više stavki zahtevala je više od 'max_binlog_cache_size' bajtova skladišnog prostora. Uveæajte ovu promenljivu servera i pokušajte ponovo', +"Ova operacija ne može biti izvršena dok je aktivan podreðeni server. Zadajte prvo komandu 'SLAVE STOP' da zaustavite podreðeni server.", +"Ova operacija zahteva da je aktivan podreðeni server. Konfigurišite prvo podreðeni server i onda izvršite komandu 'SLAVE START'", +"Server nije konfigurisan kao podreðeni server, ispravite konfiguracioni file ili na njemu izvršite komandu 'CHANGE MASTER TO'", +"Nisam mogao da inicijalizujem informacionu strukturu glavnog servera, proverite da li imam privilegije potrebne za pristup file-u 'master.info'", +"Nisam mogao da startujem thread za podreðeni server, proverite sistemske resurse", +"Korisnik %-.64s veæ ima više aktivnih konekcija nego što je to odreðeno 'max_user_connections' promenljivom", +"Možete upotrebiti samo konstantan iskaz sa komandom 'SET'", +"Vremenski limit za zakljuèavanje tabele je istekao; Probajte da ponovo startujete transakciju", +"Broj totalnih zakljuèavanja tabele premašuje velièinu tabele zakljuèavanja", +"Zakljuèavanja izmena ne mogu biti realizovana sve dok traje 'READ UNCOMMITTED' transakcija", +"Komanda 'DROP DATABASE' nije dozvoljena dok thread globalno zakljuèava èitanje podataka", +"Komanda 'CREATE DATABASE' nije dozvoljena dok thread globalno zakljuèava èitanje podataka", +"Pogrešni argumenti prosleðeni na %s", +"Korisniku %-.32s@%-.64s nije dozvoljeno da kreira nove korisnike", +"Pogrešna definicija tabele; Sve 'MERGE' tabele moraju biti u istoj bazi podataka", +"Unakrsno zakljuèavanje pronaðeno kada sam pokušao da dobijem pravo na zakljuèavanje; Probajte da restartujete transakciju", +"Upotrebljeni tip tabele ne podržava 'FULLTEXT' indekse", +"Ne mogu da dodam proveru spoljnog kljuèa", +"Ne mogu da dodam slog: provera spoljnog kljuèa je neuspela", +"Ne mogu da izbrišem roditeljski slog: provera spoljnog kljuèa je neuspela", +"Greška pri povezivanju sa glavnim serverom u klasteru: %-.128s", +"Greška pri izvršavanju upita na glavnom serveru u klasteru: %-.128s", +"Greška pri izvršavanju komande %s: %-.128s", +"Pogrešna upotreba %s i %s", +"Upotrebljene 'SELECT' komande adresiraju razlièit broj kolona", +"Ne mogu da izvršim upit zbog toga što imate zakljuèavanja èitanja podataka u konfliktu", +"Mešanje tabela koje podržavaju transakcije i onih koje ne podržavaju transakcije je iskljuèeno", +"Opcija '%s' je upotrebljena dva puta u istom iskazu", +"User '%-.64s' has exceeded the '%s' resource (current value: %ld)", +"Wrong foreign key definition for '%-.64s': %s", +"Key reference and table reference doesn't match", +"Subselect returns more than 1 field", +"Subselect returns more than 1 record", +"Unknown prepared statement handler (%ld) given to %s", +"Help database is corrupt or does not exist", +"Cyclic reference on subqueries", +"Converting column '%s' from %s to %s" diff --git a/sql/share/slovak/errmsg.txt b/sql/share/slovak/errmsg.txt index 1dd696affb0..9f610a84bd9 100644 --- a/sql/share/slovak/errmsg.txt +++ b/sql/share/slovak/errmsg.txt @@ -205,7 +205,7 @@ "Unknown system variable '%-.64s'", "Table '%-.64s' is marked as crashed and should be repaired", "Table '%-.64s' is marked as crashed and last (automatic?) repair failed", -"Warning: Some non-transactional changed tables couldn't be rolled back", +"Some non-transactional changed tables couldn't be rolled back", "Multi-statement transaction required more than 'max_binlog_cache_size' bytes of storage. Increase this mysqld variable and try again', "This operation cannot be performed with a running slave, run SLAVE STOP first", "This operation requires a running slave, configure slave and do SLAVE START", @@ -246,3 +246,11 @@ "Wrong usage/placement of '%s'", "This version of MySQL doesn't yet support '%s'", "Got fatal error %d: '%-.128s' from master when reading data from binary log", +"Wrong foreign key definition for '%-.64s': %s", +"Key reference and table reference doesn't match", +"Subselect returns more than 1 field", +"Subselect returns more than 1 record", +"Unknown prepared statement handler (%ld) given to %s", +"Help database is corrupt or does not exist", +"Cyclic reference on subqueries", +"Converting column '%s' from %s to %s" diff --git a/sql/share/spanish/errmsg.txt b/sql/share/spanish/errmsg.txt index c91726a6557..ab4e3e93a25 100644 --- a/sql/share/spanish/errmsg.txt +++ b/sql/share/spanish/errmsg.txt @@ -239,3 +239,11 @@ "Wrong usage/placement of '%s'", "This version of MySQL doesn't yet support '%s'", "Got fatal error %d: '%-.128s' from master when reading data from binary log", +"Wrong foreign key definition for '%-.64s': %s", +"Key reference and table reference doesn't match", +"Subselect returns more than 1 field", +"Subselect returns more than 1 record", +"Unknown prepared statement handler (%ld) given to %s", +"Help database is corrupt or does not exist", +"Cyclic reference on subqueries", +"Converting column '%s' from %s to %s" diff --git a/sql/share/swedish/errmsg.txt b/sql/share/swedish/errmsg.txt index 5b7ed499038..3d91522bf0f 100644 --- a/sql/share/swedish/errmsg.txt +++ b/sql/share/swedish/errmsg.txt @@ -197,7 +197,7 @@ "Okänd system variabel '%-.64s'", "Tabell '%-.64s' är crashad och bör repareras med REPAIR TABLE", "Tabell '%-.64s' är crashad och senast (automatiska?) reparation misslyckades", -"Warning: Några icke transaktionella tabeller kunde inte återställas vid ROLLBACK", +"Några icke transaktionella tabeller kunde inte återställas vid ROLLBACK", "Transaktionen krävde mera än 'max_binlog_cache_size' minne. Utöka denna mysqld variabel och försök på nytt", "Denna operation kan inte göras under replikering; Gör SLAVE STOP först", "Denna operation kan endast göras under replikering; Konfigurera slaven och gör SLAVE START", @@ -229,12 +229,20 @@ "Option '%s' användes två gånger", "Användare '%-.64s' har överskridit '%s' (nuvarande värde: %ld)", "Du har inte privlegiet '%-.128s' som behövs för denna operation", -"Variable '%-.64s' is a LOCAL variable and can't be used with SET GLOBAL", -"Variable '%-.64s' is a GLOBAL variable and should be set with SET GLOBAL", -"Variable '%-.64s' doesn't have a default value", -"Variable '%-.64s' can't be set to the value of '%-.64s'", -"Wrong argument type to variable '%-.64s'", -"Variable '%-.64s' can only be set, not read", -"Wrong usage/placement of '%s'", -"This version of MySQL doesn't yet support '%s'", -"Got fatal error %d: '%-.128s' from master when reading data from binary log", +"Variable '%-.64s' är en LOCAL variabel och kan inte ändrad med SET GLOBAL", +"Variable '%-.64s' är en GLOBAL variabel och bör sättas med SET GLOBAL", +"Variable '%-.64s' har inte ett DEFAULT värde", +"Variable '%-.64s' kan inte be satt till '%-.64s'", +"Fel typ av argument till variabel '%-.64s'", +"Variabeln '%-.64s' kan endast sättas, inte läsas", +"Fel använding/placering av '%s'", +"Denna version av MySQL kan inte utföra '%s'", +"Fick fatalt fel %d: '%-.128s' från master vid läsning av binär loggen", +"Felaktig FOREIGN KEY definition för '%-.64s': %s", +"Nyckel referensen och table referensen stämmer inte överens", +"Subselect returnerade mer än 1 fält", +"Subselect returnerade mer än 1 rad", +"Okänd PREPARED STATEMENT id (%ld) var given till %s", +"Hjälp databasen finns inte eller är skadad", +"Syklisk referens i subselect", +"Konvertar kolumn '%s' från %s till %s" diff --git a/sql/share/ukrainian/errmsg.txt b/sql/share/ukrainian/errmsg.txt index 6eeefa11ff2..d16a8e678d1 100644 --- a/sql/share/ukrainian/errmsg.txt +++ b/sql/share/ukrainian/errmsg.txt @@ -243,3 +243,11 @@ "Wrong usage/placement of '%s'", "This version of MySQL doesn't yet support '%s'", "Got fatal error %d: '%-.128s' from master when reading data from binary log", +"Wrong foreign key definition for '%-.64s': %s", +"Key reference and table reference doesn't match", +"ðiÄÚÁÐÉÔ ÐÏ×ÅÒÔÁ¤ ÂiÌØÛ ÎiÖ 1 ÓÔÏ×ÂÅÃØ", +"ðiÄÚÁÐÉÔ ÐÏ×ÅÒÔÁ¤ ÂiÌØÛ ÎiÖ 1 ÚÁÐÉÓ", +"Unknown prepared statement handler (%ld) given to %s", +"Help database is corrupt or does not exist", +"ãÉËÌiÞÎÅ ÐÏÓÉÌÁÎÎÑ ÎÁ ÐiÄÚÁÐÉÔ", +"Converting column '%s' from %s to %s" diff --git a/sql/slave.cc b/sql/slave.cc index eb53e488856..f8acc592afa 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -56,7 +56,6 @@ static int events_till_disconnect = -1; typedef enum { SLAVE_THD_IO, SLAVE_THD_SQL} SLAVE_THD_TYPE; -void skip_load_data_infile(NET* net); static int process_io_rotate(MASTER_INFO* mi, Rotate_log_event* rev); static int process_io_create_file(MASTER_INFO* mi, Create_file_log_event* cev); static bool wait_for_relay_log_space(RELAY_LOG_INFO* rli); @@ -78,10 +77,14 @@ static int check_master_version(MYSQL* mysql, MASTER_INFO* mi); char* rewrite_db(char* db); -/* - Get a bit mask for which threads are running so that we later can - restart these threads -*/ +/***************************************************************************** + + init_thread_mask() + + Get a bit mask for which threads are running so that we can later restart + these threads. + +*****************************************************************************/ void init_thread_mask(int* mask,MASTER_INFO* mi,bool inverse) { @@ -96,7 +99,11 @@ void init_thread_mask(int* mask,MASTER_INFO* mi,bool inverse) *mask = tmp_mask; } +/***************************************************************************** + + lock_slave_threads() +*****************************************************************************/ void lock_slave_threads(MASTER_INFO* mi) { //TODO: see if we can do this without dual mutex @@ -104,6 +111,11 @@ void lock_slave_threads(MASTER_INFO* mi) pthread_mutex_lock(&mi->rli.run_lock); } +/***************************************************************************** + + unlock_slave_threads() + +*****************************************************************************/ void unlock_slave_threads(MASTER_INFO* mi) { //TODO: see if we can do this without dual mutex @@ -111,7 +123,11 @@ void unlock_slave_threads(MASTER_INFO* mi) pthread_mutex_unlock(&mi->run_lock); } +/***************************************************************************** + init_slave() + +*****************************************************************************/ int init_slave() { DBUG_ENTER("init_slave"); @@ -154,12 +170,21 @@ int init_slave() DBUG_RETURN(0); } +/***************************************************************************** + + free_table_ent() +*****************************************************************************/ static void free_table_ent(TABLE_RULE_ENT* e) { my_free((gptr) e, MYF(0)); } +/***************************************************************************** + + get_table_key() + +*****************************************************************************/ static byte* get_table_key(TABLE_RULE_ENT* e, uint* len, my_bool not_used __attribute__((unused))) { @@ -167,8 +192,10 @@ static byte* get_table_key(TABLE_RULE_ENT* e, uint* len, return (byte*)e->db; } +/***************************************************************************** + + init_relay_log_pos() -/* Open the given relay log SYNOPSIS @@ -195,8 +222,8 @@ static byte* get_table_key(TABLE_RULE_ENT* e, uint* len, RETURN VALUES 0 ok 1 error. errmsg is set to point to the error message -*/ +*****************************************************************************/ int init_relay_log_pos(RELAY_LOG_INFO* rli,const char* log, ulonglong pos, bool need_data_lock, const char** errmsg) @@ -277,9 +304,13 @@ err: DBUG_RETURN ((*errmsg) ? 1 : 0); } +/***************************************************************************** -/* called from get_options() in mysqld.cc on start-up */ + init_slave_skip_errors() + called from get_options() in mysqld.cc on start-up + +*****************************************************************************/ void init_slave_skip_errors(const char* arg) { const char *p; @@ -289,9 +320,9 @@ void init_slave_skip_errors(const 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; @@ -303,17 +334,18 @@ void init_slave_skip_errors(const 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++; } } +/***************************************************************************** -/* - We assume we have a run lock on rli and that both slave thread - are not running -*/ + purge_relay_logs() + + Assumes to have a run lock on rli and that no slave thread are running. +*****************************************************************************/ int purge_relay_logs(RELAY_LOG_INFO* rli, THD *thd, bool just_reset, const char** errmsg) { @@ -358,6 +390,11 @@ err: } +/***************************************************************************** + + terminate_slave_threads() + +*****************************************************************************/ int terminate_slave_threads(MASTER_INFO* mi,int thread_mask,bool skip_lock) { if (!mi->inited) @@ -398,7 +435,11 @@ int terminate_slave_threads(MASTER_INFO* mi,int thread_mask,bool skip_lock) DBUG_RETURN(0); } +/***************************************************************************** + terminate_slave_thread() + +*****************************************************************************/ int terminate_slave_thread(THD* thd, pthread_mutex_t* term_lock, pthread_mutex_t *cond_lock, pthread_cond_t* term_cond, @@ -443,6 +484,11 @@ int terminate_slave_thread(THD* thd, pthread_mutex_t* term_lock, } +/***************************************************************************** + + start_slave_thread() + +*****************************************************************************/ int start_slave_thread(pthread_handler h_func, pthread_mutex_t *start_lock, pthread_mutex_t *cond_lock, pthread_cond_t *start_cond, @@ -505,13 +551,15 @@ int start_slave_thread(pthread_handler h_func, pthread_mutex_t *start_lock, DBUG_RETURN(0); } +/***************************************************************************** + + start_slave_threads() -/* SLAVE_FORCE_ALL is not implemented here on purpose since it does not make - sense to do that for starting a slave - we always care if it actually + sense to do that for starting a slave--we always care if it actually started the threads that were not previously running -*/ +*****************************************************************************/ int start_slave_threads(bool need_slave_mutex, bool wait_for_start, MASTER_INFO* mi, const char* master_info_fname, const char* slave_info_fname, int thread_mask) @@ -551,15 +599,24 @@ int start_slave_threads(bool need_slave_mutex, bool wait_for_start, DBUG_RETURN(error); } +/***************************************************************************** + init_table_rule_hash() + +*****************************************************************************/ 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, (hash_free_key) free_table_ent, 0); *h_inited = 1; } +/***************************************************************************** + + init_table_rule_array() + +*****************************************************************************/ void init_table_rule_array(DYNAMIC_ARRAY* a, bool* a_inited) { my_init_dynamic_array(a, sizeof(TABLE_RULE_ENT*), TABLE_RULE_ARR_SIZE, @@ -567,6 +624,11 @@ void init_table_rule_array(DYNAMIC_ARRAY* a, bool* a_inited) *a_inited = 1; } +/***************************************************************************** + + find_wild() + +*****************************************************************************/ static TABLE_RULE_ENT* find_wild(DYNAMIC_ARRAY *a, const char* key, int len) { uint i; @@ -576,14 +638,21 @@ 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, - (const char*)(e->db + e->key_len),'\\')) + if (!my_wildcmp(system_charset_info, key, key_end, + (const char*)e->db, + (const char*)(e->db + e->key_len), + '\\',wild_one,wild_many)) return e; } return 0; } +/***************************************************************************** + + tables_ok() + +*****************************************************************************/ int tables_ok(THD* thd, TABLE_LIST* tables) { for (; tables; tables = tables->next) @@ -620,7 +689,11 @@ int tables_ok(THD* thd, TABLE_LIST* tables) return !do_table_inited && !wild_do_table_inited; } +/***************************************************************************** + add_table_rule() + +*****************************************************************************/ int add_table_rule(HASH* h, const char* table_spec) { const char* dot = strchr(table_spec, '.'); @@ -638,6 +711,11 @@ int add_table_rule(HASH* h, const char* table_spec) return 0; } +/***************************************************************************** + + add_wild_table_rule() + +*****************************************************************************/ int add_wild_table_rule(DYNAMIC_ARRAY* a, const char* table_spec) { const char* dot = strchr(table_spec, '.'); @@ -654,6 +732,11 @@ int add_wild_table_rule(DYNAMIC_ARRAY* a, const char* table_spec) return 0; } +/***************************************************************************** + + free_string_array() + +*****************************************************************************/ static void free_string_array(DYNAMIC_ARRAY *a) { uint i; @@ -666,8 +749,12 @@ static void free_string_array(DYNAMIC_ARRAY *a) delete_dynamic(a); } -#ifdef NOT_USED_YET +/***************************************************************************** + end_slave_on_walk() + +*****************************************************************************/ +#ifdef NOT_USED_YET static int end_slave_on_walk(MASTER_INFO* mi, gptr /*unused*/) { end_master_info(mi); @@ -675,6 +762,11 @@ static int end_slave_on_walk(MASTER_INFO* mi, gptr /*unused*/) } #endif +/***************************************************************************** + + end_slave() + +*****************************************************************************/ void end_slave() { /* @@ -694,7 +786,11 @@ void end_slave() free_string_array(&replicate_wild_ignore_table); } +/***************************************************************************** + + io_slave_killed() +*****************************************************************************/ static bool io_slave_killed(THD* thd, MASTER_INFO* mi) { DBUG_ASSERT(mi->io_thd == thd); @@ -702,7 +798,11 @@ static bool io_slave_killed(THD* thd, MASTER_INFO* mi) return mi->abort_slave || abort_loop || thd->killed; } +/***************************************************************************** + sql_slave_killed() + +*****************************************************************************/ static bool sql_slave_killed(THD* thd, RELAY_LOG_INFO* rli) { DBUG_ASSERT(rli->sql_thd == thd); @@ -710,7 +810,11 @@ static bool sql_slave_killed(THD* thd, RELAY_LOG_INFO* rli) return rli->abort_slave || abort_loop || thd->killed; } +/***************************************************************************** + + slave_print_error() +*****************************************************************************/ void slave_print_error(RELAY_LOG_INFO* rli, int err_code, const char* msg, ...) { va_list args; @@ -722,16 +826,36 @@ void slave_print_error(RELAY_LOG_INFO* rli, int err_code, const char* msg, ...) rli->last_slave_errno = err_code; } +/***************************************************************************** + + skip_load_data_infile() + + This is used to tell a 3.23 master to break send_file() + +*****************************************************************************/ +void skip_load_data_infile(NET *net) +{ + (void)net_request_file(net, "/dev/null"); + (void)my_net_read(net); // discard response + (void)net_write_command(net, 0, "", 0, "", 0); // Send ok +} + +/***************************************************************************** + + net_request_file() -void skip_load_data_infile(NET* net) +*****************************************************************************/ +bool net_request_file(NET* net, const char* fname) { - (void)my_net_write(net, "\xfb/dev/null", 10); - (void)net_flush(net); - (void)my_net_read(net); // discard response - send_ok(net); // the master expects it + DBUG_ENTER("net_request_file"); + DBUG_RETURN(net_write_command(net, 251, fname, strlen(fname), "", 0)); } +/***************************************************************************** + rewrite_db() + +*****************************************************************************/ char* rewrite_db(char* db) { if (replicate_rewrite_db.is_empty() || !db) @@ -747,7 +871,11 @@ char* rewrite_db(char* db) return db; } +/***************************************************************************** + + db_ok() +*****************************************************************************/ int db_ok(const char* db, I_List<i_string> &do_list, I_List<i_string> &ignore_list ) { @@ -787,7 +915,11 @@ int db_ok(const char* db, I_List<i_string> &do_list, } } +/***************************************************************************** + init_strvar_from_file() + +*****************************************************************************/ static int init_strvar_from_file(char *var, int max_size, IO_CACHE *f, const char *default_val) { @@ -816,7 +948,11 @@ static int init_strvar_from_file(char *var, int max_size, IO_CACHE *f, return 1; } +/***************************************************************************** + + init_intvar_from_file() +*****************************************************************************/ static int init_intvar_from_file(int* var, IO_CACHE* f, int default_val) { char buf[32]; @@ -834,7 +970,11 @@ static int init_intvar_from_file(int* var, IO_CACHE* f, int default_val) return 1; } +/***************************************************************************** + + check_master_version() +*****************************************************************************/ static int check_master_version(MYSQL* mysql, MASTER_INFO* mi) { const char* errmsg= 0; @@ -860,7 +1000,11 @@ static int check_master_version(MYSQL* mysql, MASTER_INFO* mi) return 0; } +/***************************************************************************** + create_table_from_dump() + +*****************************************************************************/ static int create_table_from_dump(THD* thd, NET* net, const char* db, const char* table_name) { @@ -874,13 +1018,13 @@ static int create_table_from_dump(THD* thd, NET* net, const char* db, if (packet_len == packet_error) { - send_error(&thd->net, ER_MASTER_NET_READ); + send_error(thd, ER_MASTER_NET_READ); return 1; } if (net->read_pos[0] == 255) // error from master { net->read_pos[packet_len] = 0; - net_printf(&thd->net, ER_MASTER, net->read_pos + 3); + net_printf(thd, ER_MASTER, net->read_pos + 3); return 1; } thd->command = COM_TABLE_DUMP; @@ -888,7 +1032,7 @@ static int create_table_from_dump(THD* thd, NET* net, const char* db, if (!thd->query) { sql_print_error("create_table_from_dump: out of memory"); - net_printf(&thd->net, ER_GET_ERRNO, "Out of memory"); + net_printf(thd, ER_GET_ERRNO, "Out of memory"); return 1; } memcpy(thd->query, net->read_pos, packet_len); @@ -918,7 +1062,7 @@ static int create_table_from_dump(THD* thd, NET* net, const char* db, thd->proc_info = "Opening master dump table"; if (!open_ltable(thd, &tables, TL_WRITE)) { - send_error(&thd->net,0,0); // Send error from open_ltable + send_error(thd,0,0); // Send error from open_ltable sql_print_error("create_table_from_dump: could not open created table"); goto err; } @@ -927,7 +1071,7 @@ static int create_table_from_dump(THD* thd, NET* net, const char* db, thd->proc_info = "Reading master dump table data"; if (file->net_read_dump(net)) { - net_printf(&thd->net, ER_MASTER_NET_READ); + net_printf(thd, ER_MASTER_NET_READ); sql_print_error("create_table_from_dump::failed in\ handler::net_read_dump()"); goto err; @@ -946,7 +1090,7 @@ static int create_table_from_dump(THD* thd, NET* net, const char* db, error=file->repair(thd,&check_opt) != 0; thd->net.vio = save_vio; if (error) - net_printf(&thd->net, ER_INDEX_REBUILD,tables.table->real_name); + net_printf(thd, ER_INDEX_REBUILD,tables.table->real_name); err: close_thread_tables(thd); @@ -954,6 +1098,11 @@ err: return error; } +/***************************************************************************** + + fetch_master_table() + +*****************************************************************************/ int fetch_master_table(THD *thd, const char *db_name, const char *table_name, MASTER_INFO *mi, MYSQL *mysql) { @@ -968,12 +1117,12 @@ int fetch_master_table(THD *thd, const char *db_name, const char *table_name, { if (!(mysql = mc_mysql_init(NULL))) { - send_error(&thd->net); // EOM + send_error(thd); // EOM DBUG_RETURN(1); } if (connect_to_master(thd, mysql, mi)) { - net_printf(&thd->net, ER_CONNECT_TO_MASTER, mc_mysql_error(mysql)); + net_printf(thd, ER_CONNECT_TO_MASTER, mc_mysql_error(mysql)); mc_mysql_close(mysql); DBUG_RETURN(1); } @@ -997,11 +1146,14 @@ int fetch_master_table(THD *thd, const char *db_name, const char *table_name, if (!called_connected) mc_mysql_close(mysql); if (errmsg && thd->net.vio) - send_error(&thd->net, error, errmsg); + send_error(thd, error, errmsg); DBUG_RETURN(test(error)); // Return 1 on error } +/***************************************************************************** + end_master_info() +*****************************************************************************/ void end_master_info(MASTER_INFO* mi) { DBUG_ENTER("end_master_info"); @@ -1020,7 +1172,11 @@ void end_master_info(MASTER_INFO* mi) DBUG_VOID_RETURN; } +/***************************************************************************** + + init_relay_log_info() +*****************************************************************************/ int init_relay_log_info(RELAY_LOG_INFO* rli, const char* info_fname) { char fname[FN_REFLEN+128]; @@ -1154,7 +1310,11 @@ err: DBUG_RETURN(1); } +/***************************************************************************** + add_relay_log() + +*****************************************************************************/ static inline int add_relay_log(RELAY_LOG_INFO* rli,LOG_INFO* linfo) { MY_STAT s; @@ -1173,7 +1333,11 @@ static inline int add_relay_log(RELAY_LOG_INFO* rli,LOG_INFO* linfo) DBUG_RETURN(0); } +/***************************************************************************** + + wait_for_relay_log_space() +*****************************************************************************/ static bool wait_for_relay_log_space(RELAY_LOG_INFO* rli) { bool slave_killed=0; @@ -1182,9 +1346,11 @@ static bool wait_for_relay_log_space(RELAY_LOG_INFO* rli) THD* thd = mi->io_thd; DBUG_ENTER("wait_for_relay_log_space"); + pthread_mutex_lock(&rli->log_space_lock); save_proc_info = thd->proc_info; thd->proc_info = "Waiting for relay log space to free"; + while (rli->log_space_limit < rli->log_space_total && !(slave_killed=io_slave_killed(thd,mi))) { @@ -1195,7 +1361,11 @@ static bool wait_for_relay_log_space(RELAY_LOG_INFO* rli) DBUG_RETURN(slave_killed); } +/***************************************************************************** + count_relay_log_space() + +*****************************************************************************/ static int count_relay_log_space(RELAY_LOG_INFO* rli) { LOG_INFO linfo; @@ -1214,7 +1384,11 @@ static int count_relay_log_space(RELAY_LOG_INFO* rli) DBUG_RETURN(0); } +/***************************************************************************** + + init_master_info() +*****************************************************************************/ int init_master_info(MASTER_INFO* mi, const char* master_info_fname, const char* slave_info_fname, bool abort_if_no_master_info_file) @@ -1332,7 +1506,11 @@ err: DBUG_RETURN(1); } +/***************************************************************************** + register_slave_on_master() + +*****************************************************************************/ int register_slave_on_master(MYSQL* mysql) { String packet; @@ -1374,6 +1552,11 @@ int register_slave_on_master(MYSQL* mysql) return 0; } +/***************************************************************************** + + show_master_info() + +*****************************************************************************/ int show_master_info(THD* thd, MASTER_INFO* mi) { // TODO: fix this for multi-master @@ -1437,11 +1620,15 @@ int show_master_info(THD* thd, MASTER_INFO* mi) if (my_net_write(&thd->net, (char*)thd->packet.ptr(), packet->length())) DBUG_RETURN(-1); } - send_eof(&thd->net); + send_eof(thd); DBUG_RETURN(0); } +/***************************************************************************** + + flush_master_info() +*****************************************************************************/ bool flush_master_info(MASTER_INFO* mi) { IO_CACHE* file = &mi->file; @@ -1459,7 +1646,11 @@ bool flush_master_info(MASTER_INFO* mi) DBUG_RETURN(0); } +/***************************************************************************** + + st_relay_log_info::wait_for_pos() +*****************************************************************************/ int st_relay_log_info::wait_for_pos(THD* thd, String* log_name, ulonglong log_pos) { @@ -1480,7 +1671,7 @@ int st_relay_log_info::wait_for_pos(THD* thd, String* log_name, mi->slave_running) { bool pos_reached; - int cmp_result= 0; + int different_file= 0; DBUG_ASSERT(*master_log_name || master_log_pos == 0); if (*master_log_name) { @@ -1492,11 +1683,11 @@ int st_relay_log_info::wait_for_pos(THD* thd, String* log_name, mysqlbin.1000 */ char *basename= master_log_name + dirname_length(master_log_name); - cmp_result = strncmp(basename, log_name->ptr(), + different_file = strncmp(basename, log_name->ptr(), log_name->length()); } - pos_reached = ((!cmp_result && master_log_pos >= log_pos) || - cmp_result > 0); + pos_reached = ((!different_file && master_log_pos >= log_pos) || + different_file > 0); if (pos_reached || thd->killed) break; @@ -1517,7 +1708,11 @@ int st_relay_log_info::wait_for_pos(THD* thd, String* log_name, -1 : event_count); } +/***************************************************************************** + init_slave_thread() + +*****************************************************************************/ static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type) { DBUG_ENTER("init_slave_thread"); @@ -1560,7 +1755,11 @@ static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type) DBUG_RETURN(0); } +/***************************************************************************** + + safe_sleep() +*****************************************************************************/ static int safe_sleep(THD* thd, int sec, CHECK_KILLED_FUNC thread_killed, void* thread_killed_arg) { @@ -1589,7 +1788,11 @@ static int safe_sleep(THD* thd, int sec, CHECK_KILLED_FUNC thread_killed, return 0; } +/***************************************************************************** + request_dump() + +*****************************************************************************/ static int request_dump(MYSQL* mysql, MASTER_INFO* mi, bool *suppress_warnings) { @@ -1624,7 +1827,11 @@ static int request_dump(MYSQL* mysql, MASTER_INFO* mi, DBUG_RETURN(0); } +/***************************************************************************** + + request_table_dump() +*****************************************************************************/ static int request_table_dump(MYSQL* mysql, const char* db, const char* table) { char buf[1024]; @@ -1654,8 +1861,11 @@ command"); } -/* - read one event from the master +/***************************************************************************** + + read_event() + + Read one event from the master SYNOPSIS read_event() @@ -1670,8 +1880,7 @@ command"); 'packet_error' Error number Length of packet -*/ - +*****************************************************************************/ static ulong read_event(MYSQL* mysql, MASTER_INFO *mi, bool* suppress_warnings) { ulong len; @@ -1720,7 +1929,11 @@ server_errno=%d)", return len - 1; } +/***************************************************************************** + check_expected_error() + +*****************************************************************************/ int check_expected_error(THD* thd, RELAY_LOG_INFO* rli, int expected_error) { switch (expected_error) { @@ -1742,7 +1955,11 @@ point. If you are sure that your master is ok, run this query manually on the\ } } +/***************************************************************************** + + exec_relay_log_event() +*****************************************************************************/ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli) { DBUG_ASSERT(rli->sql_thd==thd); @@ -1807,8 +2024,10 @@ This may also be a network problem, or just a bug in the master or slave code.\ } } +/***************************************************************************** + Slave I/O Thread entry point +*****************************************************************************/ -/* slave I/O thread */ extern "C" pthread_handler_decl(handle_slave_io,arg) { THD *thd; // needs to be first for thread_stack @@ -2077,8 +2296,9 @@ err: DBUG_RETURN(0); // Can't return anything here } - -/* slave SQL logic thread */ +/***************************************************************************** + Slave SQL Thread entry point +*****************************************************************************/ extern "C" pthread_handler_decl(handle_slave_sql,arg) { @@ -2215,13 +2435,18 @@ the slave SQL thread with \"SLAVE START\". We stopped at log \ DBUG_RETURN(0); // Can't return anything here } +/***************************************************************************** + + process_io_create_file() + +*****************************************************************************/ static int process_io_create_file(MASTER_INFO* mi, Create_file_log_event* cev) { int error = 1; ulong num_bytes; bool cev_not_written; - THD* thd; - NET* net = &mi->mysql->net; + THD *thd = mi->io_thd; + NET *net = &mi->mysql->net; DBUG_ENTER("process_io_create_file"); if (unlikely(!cev->is_valid())) @@ -2235,7 +2460,6 @@ static int process_io_create_file(MASTER_INFO* mi, Create_file_log_event* cev) DBUG_RETURN(0); } DBUG_ASSERT(cev->inited_from_old); - thd = mi->io_thd; thd->file_id = cev->file_id = mi->file_id++; thd->server_id = cev->server_id; cev_not_written = 1; @@ -2264,7 +2488,7 @@ static int process_io_create_file(MASTER_INFO* mi, Create_file_log_event* cev) } if (unlikely(!num_bytes)) /* eof */ { - send_ok(net); /* 3.23 master wants it */ + net_write_command(net, 0, "", 0, "", 0);/* 3.23 master wants it */ Execute_load_log_event xev(thd,0); xev.log_pos = mi->master_log_pos; if (unlikely(mi->rli.relay_log.append(&xev))) @@ -2310,7 +2534,10 @@ err: DBUG_RETURN(error); } -/* +/***************************************************************************** + + process_io_rotate() + Start using a new binary log on the master SYNOPSIS @@ -2328,8 +2555,8 @@ err: RETURN VALUES 0 ok 1 Log event is illegal -*/ +*****************************************************************************/ static int process_io_rotate(MASTER_INFO *mi, Rotate_log_event *rev) { int return_val= 1; @@ -2360,12 +2587,15 @@ static int process_io_rotate(MASTER_INFO *mi, Rotate_log_event *rev) DBUG_RETURN(0); } -/* +/***************************************************************************** + + queue_old_event() + TODO: Test this code before release - it has to be tested on a separate setup with 3.23 master -*/ +*****************************************************************************/ static int queue_old_event(MASTER_INFO *mi, const char *buf, ulong event_len) { @@ -2453,11 +2683,14 @@ static int queue_old_event(MASTER_INFO *mi, const char *buf, DBUG_RETURN(0); } -/* +/***************************************************************************** + + queue_event() + TODO: verify the issue with stop events, see if we need them at all in the relay log -*/ +*****************************************************************************/ int queue_event(MASTER_INFO* mi,const char* buf, ulong event_len) { int error= 0; @@ -2510,7 +2743,11 @@ int queue_event(MASTER_INFO* mi,const char* buf, ulong event_len) DBUG_RETURN(error); } +/***************************************************************************** + end_relay_log_info() + +*****************************************************************************/ void end_relay_log_info(RELAY_LOG_INFO* rli) { DBUG_ENTER("end_relay_log_info"); @@ -2535,18 +2772,26 @@ void end_relay_log_info(RELAY_LOG_INFO* rli) DBUG_VOID_RETURN; } -/* try to connect until successful or slave killed */ +/***************************************************************************** + + safe_connect() + + Try to connect until successful or slave killed + +*****************************************************************************/ static int safe_connect(THD* thd, MYSQL* mysql, MASTER_INFO* mi) { return connect_to_master(thd, mysql, mi, 0, 0); } +/***************************************************************************** + + connect_to_master() -/* Try to connect until successful or slave killed or we have retried master_retry_count times -*/ +*****************************************************************************/ static int connect_to_master(THD* thd, MYSQL* mysql, MASTER_INFO* mi, bool reconnect, bool suppress_warnings) { @@ -2625,20 +2870,24 @@ replication resumed in log '%s' at position %s", mi->user, DBUG_RETURN(slave_was_killed); } +/***************************************************************************** + + safe_reconnect() -/* Try to connect until successful or slave killed or we have retried master_retry_count times -*/ +*****************************************************************************/ static int safe_reconnect(THD* thd, MYSQL* mysql, MASTER_INFO* mi, bool suppress_warnings) { return connect_to_master(thd, mysql, mi, 1, suppress_warnings); } +/***************************************************************************** + + flush_relay_log_info() -/* Store the file and position where the execute-slave thread are in the relay log. @@ -2665,8 +2914,8 @@ static int safe_reconnect(THD* thd, MYSQL* mysql, MASTER_INFO* mi, RETURN VALUES 0 ok 1 write error -*/ +*****************************************************************************/ bool flush_relay_log_info(RELAY_LOG_INFO* rli) { bool error=0; @@ -2695,12 +2944,13 @@ bool flush_relay_log_info(RELAY_LOG_INFO* rli) return error; } +/***************************************************************************** -/* - This function is called when we notice that the current "hot" log - got rotated under our feet. -*/ + reopen_relay_log() + + Called when we notice that the current "hot" log got rotated under our feet. +*****************************************************************************/ static IO_CACHE *reopen_relay_log(RELAY_LOG_INFO *rli, const char **errmsg) { DBUG_ASSERT(rli->cur_log != &rli->cache_buf); @@ -2715,7 +2965,11 @@ static IO_CACHE *reopen_relay_log(RELAY_LOG_INFO *rli, const char **errmsg) DBUG_RETURN(cur_log); } +/***************************************************************************** + + next_event() +*****************************************************************************/ Log_event* next_event(RELAY_LOG_INFO* rli) { Log_event* ev; diff --git a/sql/slave.h b/sql/slave.h index 721fd8534a0..2c750e415bc 100644 --- a/sql/slave.h +++ b/sql/slave.h @@ -7,22 +7,28 @@ #define MAX_SLAVE_ERRMSG 1024 #define MAX_SLAVE_ERROR 2000 -/* - The replication is accomplished by starting two threads - I/O - thread, and SQL thread. I/O thread is associated with its - MASTER_INFO struct, so MASTER_INFO can be viewed as I/O thread - descriptor. SQL thread is associated with RELAY_LOG_INFO struct. - - I/O thread reads maintains a connection to the master, and reads log - events from the master as they arrive, queueing them by writing them - out into the temporary slave binary log (relay log). The SQL thread, - in turn, reads the slave binary log executing each event. - - Relay log is needed to be able to handle situations when there is a large - backlog of unprocessed events from the master (eg. one particular update - takes a day to finish), and to be able to restart the slave server without - having to re-read the master updates. - */ +/***************************************************************************** + + MySQL Replication + + Replication is implemented via two types of threads: + + I/O Thread - One of these threads is started for each master server. + They maintain a connection to their master server, read log + events from the master as they arrive, and queues them into + a single, shared relay log file. A MASTER_INFO struct + represents each of these threads. + + SQL Thread - One of these threads is started and reads from the relay log + file, executing each event. A RELAY_LOG_INFO struct + represents this thread. + + Buffering in the relay log file makes it unnecessary to reread events from + a master server across a slave restart. It also decouples the slave from + the master where long-running updates and event logging are concerned--ie + it can continue to log new events while a slow query executes on the slave. + +*****************************************************************************/ extern ulong slave_net_timeout, master_retry_count; extern MY_BITMAP slave_error_mask; @@ -48,11 +54,16 @@ struct st_master_info; --active_mi_in_use; \ pthread_mutex_unlock(&LOCK_active_mi); } -/* - st_relay_log_info contains information on the current relay log and - relay log offset, and master log name and log sequence corresponding to the - last update. Additionally, misc information specific to the SQL thread is - included. +/***************************************************************************** + + Replication SQL Thread + + st_relay_log_info contains: + - the current relay log + - the current relay log offset + - master log name + - master log sequence corresponding to the last update + - misc information specific to the SQL thread st_relay_log_info is initialized from the slave.info file if such exists. Otherwise, data members are intialized with defaults. The initialization is @@ -66,7 +77,8 @@ struct st_master_info; master_log_pos To clean up, call end_relay_log_info() - */ + +*****************************************************************************/ typedef struct st_relay_log_info { @@ -128,13 +140,18 @@ typedef struct st_relay_log_info uint32 cur_log_old_open_count; /* - Current offset in the relay log. - pending - in some cases we do not increment offset immediately after - processing an event, because the following event needs to be processed - atomically together with this one ( so far, there is only one type of - such event - Intvar_event that sets auto_increment value). However, once - both events have been processed, we need to increment by the cumulative - offset. pending stored the extra offset to be added to the position. + relay_log_pos - Current offset in the relay log. + pending - In some cases we do not increment offset immediately + after processing an event, because the following event + needs to be processed atomically together with this one + such as: + + Intvar_event - sets auto_increment value + Rand_event - sets the random seed + + However, once both events have been processed, we need to + increment by the cumulative offset. 'pending' stores the + extra offset to be added to the position. */ ulonglong relay_log_pos, pending; ulonglong log_space_limit,log_space_total; @@ -230,10 +247,15 @@ typedef struct st_relay_log_info Log_event* next_event(RELAY_LOG_INFO* rli); -/* - st_master_info contains information about how to connect to a master, - current master log name, and current log offset, as well as misc - control variables +/***************************************************************************** + + Replication IO Thread + + st_master_info contains: + - information about how to connect to a master + - current master log name + - current master log offset + - misc control variables st_master_info is initialized once from the master.info file if such exists. Otherwise, data members corresponding to master.info fields @@ -255,9 +277,9 @@ Log_event* next_event(RELAY_LOG_INFO* rli); flush_master_info() is required. To clean up, call end_master_info() -*/ - +*****************************************************************************/ + typedef struct st_master_info { char master_log_name[FN_REFLEN]; diff --git a/sql/spatial.cc b/sql/spatial.cc new file mode 100644 index 00000000000..b21d30e4b53 --- /dev/null +++ b/sql/spatial.cc @@ -0,0 +1,1442 @@ +#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(data, 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(data, 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; + LINT_INIT(res_area); + LINT_INIT(res_cx); + LINT_INIT(res_cy); + + if (no_data(data, 4)) + return 1; + n_linear_rings = uint4korr(data); + data += 4; + + 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(data + WKB_HEADER_SIZE, 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(data, 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(data, 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; + + LINT_INIT(res_area); + LINT_INIT(res_cx); + LINT_INIT(res_cy); + + const char *data = m_data; + if (no_data(data, 4)) + return 1; + n_polygons = uint4korr(data); + data += 4; + + 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..3f09e86e823 --- /dev/null +++ b/sql/spatial.h @@ -0,0 +1,497 @@ +/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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 */ + +#ifndef _spatial_h +#define _spatial_h + +const uint POINT_DATA_SIZE = 8+8; +const uint 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(const char *px, const char *py) + { + double x, y; + float8get(x, px); + float8get(y, py); + /* Not using "else" for proper one point MBR calculation */ + if (x<xmin) + { + xmin=x; + } + if (x>xmax) + { + xmax=x; + } + if (y<ymin) + { + ymin=y; + } + if (y>ymax) + { + ymax=y; + } + } + + 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; +}; + +#define SIZEOF_STORED_DOUBLE 8 + +/***************************** 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_STORED_DOUBLE * 2)) return 1; + float8get(*x, data); + float8get(*y, data + SIZEOF_STORED_DOUBLE); + return 0; + } + + int get_x(double *x) const + { + if (no_data(m_data, SIZEOF_STORED_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_STORED_DOUBLE * 2)) return 1; + float8get(*y, data + SIZEOF_STORED_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 673bc441b6b..8ccd7dbde68 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -422,7 +422,7 @@ static ulong get_access(TABLE *form, uint fieldnr) { ulong access_bits=0,bit; char buff[2]; - String res(buff,sizeof(buff)); + String res(buff,sizeof(buff),default_charset_info); Field **pos; for (pos=form->field+fieldnr, bit=1; @@ -431,7 +431,7 @@ static ulong get_access(TABLE *form, uint fieldnr) 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; @@ -649,7 +649,7 @@ static void acl_update_user(const char *user, const char *host, { if (!acl_user->host.hostname && !host[0] || acl_user->host.hostname && - !my_strcasecmp(host,acl_user->host.hostname)) + !my_strcasecmp(system_charset_info, host, acl_user->host.hostname)) { acl_user->access=privileges; if (mqh->bits & 1) @@ -738,7 +738,8 @@ static void acl_update_db(const char *user, const char *host, const char *db, !strcmp(user,acl_db->user)) { if (!acl_db->host.hostname && !host[0] || - acl_db->host.hostname && !my_strcasecmp(host,acl_db->host.hostname)) + acl_db->host.hostname && + !my_strcasecmp(system_charset_info, host, acl_db->host.hostname)) { if (!acl_db->db && !db[0] || acl_db->db && !strcmp(db,acl_db->db)) @@ -802,7 +803,7 @@ ulong 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); @@ -866,7 +867,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"); @@ -877,7 +878,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) @@ -895,12 +897,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); } @@ -919,7 +921,7 @@ static void init_check_host(void) DBUG_ENTER("init_check_host"); VOID(my_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) { @@ -935,7 +937,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 @@ -1008,19 +1011,19 @@ bool check_change_password(THD *thd, const char *host, const char *user) { if (!initialized) { - send_error(&thd->net, ER_PASSWORD_NOT_ALLOWED); /* purecov: inspected */ + send_error(thd, ER_PASSWORD_NOT_ALLOWED); /* purecov: inspected */ return(1); /* purecov: inspected */ } 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)) return(1); } if (!thd->slave_thread && !thd->user[0]) { - send_error(&thd->net, ER_PASSWORD_ANONYMOUS_USER); + send_error(thd, ER_PASSWORD_ANONYMOUS_USER); return(1); } return(0); @@ -1062,7 +1065,7 @@ bool change_password(THD *thd, const char *host, const char *user, ACL_USER *acl_user; if (!(acl_user= find_acl_user(host,user))) { - send_error(&thd->net, ER_PASSWORD_NO_MATCH); + send_error(thd, ER_PASSWORD_NO_MATCH); VOID(pthread_mutex_unlock(&acl_cache->lock)); DBUG_RETURN(1); } @@ -1072,7 +1075,7 @@ bool change_password(THD *thd, const char *host, const char *user, new_password)) { VOID(pthread_mutex_unlock(&acl_cache->lock)); /* purecov: deadcode */ - send_error(&thd->net,0); /* purecov: deadcode */ + send_error(thd,0); /* purecov: deadcode */ DBUG_RETURN(1); /* purecov: deadcode */ } get_salt_from_password(acl_user->salt,new_password); @@ -1173,7 +1176,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))); } @@ -1196,8 +1200,8 @@ static bool update_user_table(THD *thd, const char *host, const char *user, tables.db=(char*) "mysql"; if (!(table=open_ltable(thd,&tables,TL_WRITE))) DBUG_RETURN(1); /* purecov: deadcode */ - table->field[0]->store(host,(uint) strlen(host)); - table->field[1]->store(user,(uint) strlen(user)); + table->field[0]->store(host,(uint) strlen(host), system_charset_info); + table->field[1]->store(user,(uint) strlen(user), system_charset_info); if (table->file->index_read_idx(table->record[0],0, (byte*) table->field[0]->ptr,0, @@ -1207,7 +1211,7 @@ static bool update_user_table(THD *thd, const char *host, const char *user, DBUG_RETURN(1); /* purecov: deadcode */ } store_record(table,1); - table->field[2]->store(new_password,(uint) strlen(new_password)); + table->field[2]->store(new_password,(uint) strlen(new_password), system_charset_info); if ((error=table->file->update_row(table->record[1],table->record[0]))) { table->file->print_error(error,MYF(0)); /* purecov: deadcode */ @@ -1273,8 +1277,8 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo, password=combo.password.str; } - table->field[0]->store(combo.host.str,combo.host.length); - table->field[1]->store(combo.user.str,combo.user.length); + table->field[0]->store(combo.host.str,combo.host.length, system_charset_info); + table->field[1]->store(combo.user.str,combo.user.length, system_charset_info); table->file->index_init(0); if (table->file->index_read(table->record[0], (byte*) table->field[0]->ptr,0, @@ -1294,17 +1298,17 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo, goto end; } old_row_exists = 0; - restore_record(table,2); // cp empty row from record[2] - table->field[0]->store(combo.host.str,combo.host.length); - table->field[1]->store(combo.user.str,combo.user.length); - table->field[2]->store(password,(uint) strlen(password)); + restore_record(table,2); // cp empty row from record[2] + table->field[0]->store(combo.host.str,combo.host.length, system_charset_info); + table->field[1]->store(combo.user.str,combo.user.length, system_charset_info); + table->field[2]->store(password,(uint) strlen(password), system_charset_info); } else { old_row_exists = 1; store_record(table,1); // Save copy for update if (combo.password.str) // If password given - table->field[2]->store(password,(uint) strlen(password)); + table->field[2]->store(password,(uint) strlen(password), system_charset_info); } /* Update table columns with new privileges */ @@ -1317,7 +1321,7 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo, tmp_field++, priv <<= 1) { if (priv & rights) // set requested privileges - (*tmp_field)->store(&what,1); + (*tmp_field)->store(&what, 1, system_charset_info); } rights=get_access(table,3); DBUG_PRINT("info",("table->fields: %d",table->fields)); @@ -1326,31 +1330,31 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo, /* We write down SSL related ACL stuff */ switch (thd->lex.ssl_type) { case SSL_TYPE_ANY: - table->field[24]->store("ANY",3); - table->field[25]->store("",0); - table->field[26]->store("",0); - table->field[27]->store("",0); + table->field[24]->store("ANY",3, system_charset_info); + table->field[25]->store("", 0, system_charset_info); + table->field[26]->store("", 0, system_charset_info); + table->field[27]->store("", 0, system_charset_info); break; case SSL_TYPE_X509: - table->field[24]->store("X509",4); - table->field[25]->store("",0); - table->field[26]->store("",0); - table->field[27]->store("",0); + table->field[24]->store("X509",4, system_charset_info); + table->field[25]->store("", 0, system_charset_info); + table->field[26]->store("", 0, system_charset_info); + table->field[27]->store("", 0, system_charset_info); break; case SSL_TYPE_SPECIFIED: - table->field[24]->store("SPECIFIED",9); - table->field[25]->store("",0); - table->field[26]->store("",0); - table->field[27]->store("",0); + table->field[24]->store("SPECIFIED",9, system_charset_info); + table->field[25]->store("", 0, system_charset_info); + table->field[26]->store("", 0, system_charset_info); + table->field[27]->store("", 0, system_charset_info); if (thd->lex.ssl_cipher) table->field[25]->store(thd->lex.ssl_cipher, - strlen(thd->lex.ssl_cipher)); + strlen(thd->lex.ssl_cipher), system_charset_info); if (thd->lex.x509_issuer) table->field[26]->store(thd->lex.x509_issuer, - strlen(thd->lex.x509_issuer)); + strlen(thd->lex.x509_issuer), system_charset_info); if (thd->lex.x509_subject) table->field[27]->store(thd->lex.x509_subject, - strlen(thd->lex.x509_subject)); + strlen(thd->lex.x509_subject), system_charset_info); break; case SSL_TYPE_NOT_SPECIFIED: break; @@ -1447,9 +1451,9 @@ static int replace_db_table(TABLE *table, const char *db, DBUG_RETURN(-1); } - table->field[0]->store(combo.host.str,combo.host.length); - table->field[1]->store(db,(uint) strlen(db)); - table->field[2]->store(combo.user.str,combo.user.length); + table->field[0]->store(combo.host.str,combo.host.length, system_charset_info); + table->field[1]->store(db,(uint) strlen(db), system_charset_info); + table->field[2]->store(combo.user.str,combo.user.length, system_charset_info); table->file->index_init(0); if (table->file->index_read(table->record[0],(byte*) table->field[0]->ptr,0, HA_READ_KEY_EXACT)) @@ -1462,9 +1466,9 @@ static int replace_db_table(TABLE *table, const char *db, } old_row_exists = 0; restore_record(table,2); // cp empty row from record[2] - table->field[0]->store(combo.host.str,combo.host.length); - table->field[1]->store(db,(uint) strlen(db)); - table->field[2]->store(combo.user.str,combo.user.length); + table->field[0]->store(combo.host.str,combo.host.length, system_charset_info); + table->field[1]->store(db,(uint) strlen(db), system_charset_info); + table->field[2]->store(combo.user.str,combo.user.length, system_charset_info); } else { @@ -1476,7 +1480,7 @@ static int replace_db_table(TABLE *table, const char *db, for (i= 3, priv= 1; i < table->fields; i++, priv <<= 1) { if (priv & store_rights) // do it if priv is chosen - table->field [i]->store(&what,1); // set requested privileges + table->field [i]->store(&what,1, system_charset_info);// set requested privileges } rights=get_access(table,3); rights=fix_rights_for_db(rights); @@ -1557,13 +1561,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); } @@ -1585,8 +1590,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); @@ -1597,21 +1602,22 @@ 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) { int key_len; - col_privs->field[0]->store(host,(uint) strlen(host)); - col_privs->field[1]->store(db,(uint) strlen(db)); - col_privs->field[2]->store(user,(uint) strlen(user)); - col_privs->field[3]->store(tname,(uint) strlen(tname)); + col_privs->field[0]->store(host,(uint) strlen(host), system_charset_info); + col_privs->field[1]->store(db,(uint) strlen(db), system_charset_info); + col_privs->field[2]->store(user,(uint) strlen(user), system_charset_info); + col_privs->field[3]->store(tname,(uint) strlen(tname), system_charset_info); key_len=(col_privs->field[0]->pack_length()+ col_privs->field[1]->pack_length()+ col_privs->field[2]->pack_length()+ col_privs->field[3]->pack_length()); key_copy(key,col_privs,0,key_len); - col_privs->field[4]->store("",0); + col_privs->field[4]->store("",0, system_charset_info); col_privs->file->index_init(0); if (col_privs->file->index_read(col_privs->record[0], (byte*) col_privs->field[0]->ptr, @@ -1667,7 +1673,6 @@ static GRANT_TABLE *table_hash_search(const char *host,const char* ip, char helping [NAME_LEN*2+USERNAME_LENGTH+3]; uint len; GRANT_TABLE *grant_table,*found=0; - safe_mutex_assert_owner(&LOCK_grant); len = (uint) (strmov(strmov(strmov(helping,user)+1,db)+1,tname)-helping)+ 1; for (grant_table=(GRANT_TABLE*) hash_search(&hash_tables,(byte*) helping, @@ -1677,14 +1682,17 @@ static GRANT_TABLE *table_hash_search(const char *host,const char* ip, { if (exact) { - if ((host && !my_strcasecmp(host,grant_table->host)) || + if ((host && + !my_strcasecmp(system_charset_info, host, grant_table->host)) || (ip && !strcmp(ip,grant_table->host))) return grant_table; } 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 } } @@ -1711,10 +1719,10 @@ static int replace_column_table(GRANT_TABLE *g_t, byte key[MAX_KEY_LENGTH]; DBUG_ENTER("replace_column_table"); - table->field[0]->store(combo.host.str,combo.host.length); - table->field[1]->store(db,(uint) strlen(db)); - table->field[2]->store(combo.user.str,combo.user.length); - table->field[3]->store(table_name,(uint) strlen(table_name)); + table->field[0]->store(combo.host.str,combo.host.length, system_charset_info); + table->field[1]->store(db,(uint) strlen(db), system_charset_info); + table->field[2]->store(combo.user.str,combo.user.length, system_charset_info); + table->field[3]->store(table_name,(uint) strlen(table_name), system_charset_info); key_length=(table->field[0]->pack_length()+ table->field[1]->pack_length()+ table->field[2]->pack_length()+ table->field[3]->pack_length()); key_copy(key,table,0,key_length); @@ -1731,7 +1739,7 @@ static int replace_column_table(GRANT_TABLE *g_t, ulong privileges = xx->rights; bool old_row_exists=0; key_restore(table,key,0,key_length); - table->field[4]->store(xx->column.ptr(),xx->column.length()); + table->field[4]->store(xx->column.ptr(),xx->column.length(),system_charset_info); if (table->file->index_read(table->record[0],(byte*) table->field[0]->ptr, 0, HA_READ_KEY_EXACT)) @@ -1745,9 +1753,9 @@ static int replace_column_table(GRANT_TABLE *g_t, continue; /* purecov: inspected */ } old_row_exists = 0; - restore_record(table,2); // Get empty record + restore_record(table,2); // Get empty record key_restore(table,key,0,key_length); - table->field[4]->store(xx->column.ptr(),xx->column.length()); + table->field[4]->store(xx->column.ptr(),xx->column.length(), system_charset_info); } else { @@ -1819,7 +1827,7 @@ static int replace_column_table(GRANT_TABLE *g_t, { GRANT_COLUMN *grant_column = NULL; char colum_name_buf[HOSTNAME_LENGTH+1]; - String column_name(colum_name_buf,sizeof(colum_name_buf)); + String column_name(colum_name_buf,sizeof(colum_name_buf),system_charset_info); privileges&= ~rights; table->field[6]->store((longlong) @@ -1875,7 +1883,6 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table, int error=0; ulong store_table_rights, store_col_rights; DBUG_ENTER("replace_table_table"); - safe_mutex_assert_owner(&LOCK_grant); strxmov(grantor, thd->user, "@", thd->host_or_ip, NullS); @@ -1890,10 +1897,10 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table, } restore_record(table,2); // Get empty record - table->field[0]->store(combo.host.str,combo.host.length); - table->field[1]->store(db,(uint) strlen(db)); - table->field[2]->store(combo.user.str,combo.user.length); - table->field[3]->store(table_name,(uint) strlen(table_name)); + table->field[0]->store(combo.host.str,combo.host.length, system_charset_info); + table->field[1]->store(db,(uint) strlen(db), system_charset_info); + table->field[2]->store(combo.user.str,combo.user.length, system_charset_info); + table->field[3]->store(table_name,(uint) strlen(table_name), system_charset_info); store_record(table,1); // store at pos 1 if (table->file->index_read_idx(table->record[0],0, @@ -1938,7 +1945,7 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table, } } - table->field[4]->store(grantor,(uint) strlen(grantor)); + table->field[4]->store(grantor,(uint) strlen(grantor), system_charset_info); table->field[6]->store((longlong) store_table_rights); table->field[7]->store((longlong) store_col_rights); rights=fix_rights_for_table(store_table_rights); @@ -1993,7 +2000,7 @@ int mysql_table_grant (THD *thd, TABLE_LIST *table_list, if (!initialized) { - send_error(&(thd->net), ER_UNKNOWN_COM_ERROR); /* purecov: inspected */ + send_error(thd, ER_UNKNOWN_COM_ERROR); /* purecov: inspected */ return 1; /* purecov: inspected */ } if (rights & ~TABLE_ACLS) @@ -2059,7 +2066,7 @@ int mysql_table_grant (THD *thd, TABLE_LIST *table_list, if (!revoke_grant) create_new_users= test_if_create_new_users(thd); int result=0; - pthread_mutex_lock(&LOCK_grant); + rw_wrlock(&LOCK_grant); MEM_ROOT *old_root=my_pthread_getspecific_ptr(MEM_ROOT*,THR_MALLOC); my_pthread_setspecific_ptr(THR_MALLOC,&memex); @@ -2172,9 +2179,9 @@ int mysql_table_grant (THD *thd, TABLE_LIST *table_list, } grant_option=TRUE; my_pthread_setspecific_ptr(THR_MALLOC,old_root); - pthread_mutex_unlock(&LOCK_grant); + rw_unlock(&LOCK_grant); if (!result) - send_ok(&thd->net); + send_ok(thd); /* Tables are automatically closed */ DBUG_RETURN(result); } @@ -2192,14 +2199,14 @@ int mysql_grant (THD *thd, const char *db, List <LEX_USER> &list, if (!initialized) { - send_error(&(thd->net), ER_UNKNOWN_COM_ERROR); /* purecov: tested */ - return 1; /* purecov: tested */ + send_error(thd, ER_UNKNOWN_COM_ERROR); /* purecov: tested */ + return 1; /* purecov: tested */ } 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; } @@ -2222,7 +2229,7 @@ int mysql_grant (THD *thd, const char *db, List <LEX_USER> &list, create_new_users= test_if_create_new_users(thd); // go through users in user_list - pthread_mutex_lock(&LOCK_grant); + rw_wrlock(&LOCK_grant); VOID(pthread_mutex_lock(&acl_cache->lock)); grant_version++; @@ -2255,11 +2262,11 @@ int mysql_grant (THD *thd, const char *db, List <LEX_USER> &list, } } VOID(pthread_mutex_unlock(&acl_cache->lock)); - pthread_mutex_unlock(&LOCK_grant); + rw_unlock(&LOCK_grant); close_thread_tables(thd); if (!result) - send_ok(&thd->net); + send_ok(thd); DBUG_RETURN(result); } @@ -2288,7 +2295,8 @@ my_bool grant_init(THD *org_thd) 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); @@ -2372,7 +2380,7 @@ void grant_reload(THD *thd) // Locked tables are checked by acl_init and doesn't have to be checked here - pthread_mutex_lock(&LOCK_grant); + rw_wrlock(&LOCK_grant); grant_version++; old_hash_tables=hash_tables; old_grant_option = grant_option; @@ -2390,7 +2398,7 @@ void grant_reload(THD *thd) hash_free(&old_hash_tables); free_root(&old_mem,MYF(0)); } - pthread_mutex_unlock(&LOCK_grant); + rw_unlock(&LOCK_grant); DBUG_VOID_RETURN; } @@ -2410,7 +2418,7 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables, if (!want_access) return 0; // ok - pthread_mutex_lock(&LOCK_grant); + rw_rdlock(&LOCK_grant); for (table=tables; table ;table=table->next) { if (!(~table->grant.privilege & want_access)) @@ -2444,11 +2452,11 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables, goto err; // impossible } } - pthread_mutex_unlock(&LOCK_grant); + rw_unlock(&LOCK_grant); return 0; err: - pthread_mutex_unlock(&LOCK_grant); + rw_unlock(&LOCK_grant); if (!no_errors) // Not a silent skip of table { const char *command=""; @@ -2470,7 +2478,7 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables, command = "index"; else if (want_access & GRANT_ACL) command = "grant"; - net_printf(&thd->net,ER_TABLEACCESS_DENIED_ERROR, + net_printf(thd,ER_TABLEACCESS_DENIED_ERROR, command, thd->priv_user, thd->host_or_ip, @@ -2490,7 +2498,7 @@ bool check_grant_column (THD *thd,TABLE *table, const char *name, if (!want_access) return 0; // Already checked - pthread_mutex_lock(&LOCK_grant); + rw_rdlock(&LOCK_grant); // reload table if someone has modified any grants @@ -2508,20 +2516,20 @@ bool check_grant_column (THD *thd,TABLE *table, const char *name, grant_column=column_hash_search(grant_table, name, length); if (grant_column && !(~grant_column->rights & want_access)) { - pthread_mutex_unlock(&LOCK_grant); + rw_unlock(&LOCK_grant); return 0; } #ifdef NOT_USED if (show_tables && (grant_column || table->grant.privilege & COL_ACLS)) { - pthread_mutex_unlock(&LOCK_grant); /* purecov: deadcode */ + rw_unlock(&LOCK_grant); /* purecov: deadcode */ return 0; /* purecov: deadcode */ } #endif /* We must use my_printf_error() here! */ err: - pthread_mutex_unlock(&LOCK_grant); + rw_unlock(&LOCK_grant); if (!show_tables) { char command[128]; @@ -2549,7 +2557,7 @@ bool check_grant_all_columns(THD *thd, ulong want_access, TABLE *table) if (!want_access) return 0; // Already checked - pthread_mutex_lock(&LOCK_grant); + rw_rdlock(&LOCK_grant); // reload table if someone has modified any grants @@ -2572,12 +2580,12 @@ bool check_grant_all_columns(THD *thd, ulong want_access, TABLE *table) if (!grant_column || (~grant_column->rights & want_access)) goto err; } - pthread_mutex_unlock(&LOCK_grant); + rw_unlock(&LOCK_grant); return 0; /* We must use my_printf_error() here! */ err: - pthread_mutex_unlock(&LOCK_grant); + rw_unlock(&LOCK_grant); const char *command=""; if (want_access & SELECT_ACL) @@ -2609,21 +2617,23 @@ bool check_grant_db(THD *thd,const char *db) bool error=1; len = (uint) (strmov(strmov(helping,thd->priv_user)+1,db)-helping)+ 1; - pthread_mutex_lock(&LOCK_grant); + rw_rdlock(&LOCK_grant); for (uint idx=0 ; idx < hash_tables.records ; idx++) { 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; } } - pthread_mutex_unlock(&LOCK_grant); + rw_unlock(&LOCK_grant); return error; } @@ -2633,12 +2643,12 @@ bool check_grant_db(THD *thd,const char *db) ulong get_table_grant(THD *thd, TABLE_LIST *table) { - uint privilege; + ulong privilege; char *user = thd->priv_user; const char *db = table->db ? table->db : thd->db; GRANT_TABLE *grant_table; - pthread_mutex_lock(&LOCK_grant); + rw_rdlock(&LOCK_grant); grant_table = table_hash_search(thd->host,thd->ip,db,user, table->real_name,0); table->grant.grant_table=grant_table; // Remember for column test @@ -2646,7 +2656,7 @@ ulong get_table_grant(THD *thd, TABLE_LIST *table) if (grant_table) table->grant.privilege|= grant_table->privs; privilege= table->grant.privilege; - pthread_mutex_unlock(&LOCK_grant); + rw_unlock(&LOCK_grant); return privilege; } @@ -2657,7 +2667,7 @@ ulong get_column_grant(THD *thd, TABLE_LIST *table, Field *field) GRANT_COLUMN *grant_column; ulong priv; - pthread_mutex_lock(&LOCK_grant); + rw_rdlock(&LOCK_grant); // reload table if someone has modified any grants if (table->grant.version != grant_version) { @@ -2679,7 +2689,7 @@ ulong get_column_grant(THD *thd, TABLE_LIST *table, Field *field) else priv=table->grant.privilege | grant_column->rights; } - pthread_mutex_unlock(&LOCK_grant); + rw_unlock(&LOCK_grant); return priv; } @@ -2714,7 +2724,7 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) LINT_INIT(acl_user); if (!initialized) { - send_error(&(thd->net), ER_UNKNOWN_COM_ERROR); + send_error(thd, ER_UNKNOWN_COM_ERROR); DBUG_RETURN(-1); } if (!lex_user->host.str) @@ -2738,7 +2748,7 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) if (!(host=acl_user->host.hostname)) host="%"; if (!strcmp(lex_user->user.str,user) && - !my_strcasecmp(lex_user->host.str,host)) + !my_strcasecmp(system_charset_info, lex_user->host.str, host)) break; } if (counter == acl_users.elements) @@ -2748,7 +2758,7 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) DBUG_RETURN(-1); } - Item_string *field=new Item_string("",0); + Item_string *field=new Item_string("",0,system_charset_info); List<Item> field_list; field->name=buff; field->max_length=1024; @@ -2758,7 +2768,7 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) if (send_fields(thd,field_list,1)) DBUG_RETURN(-1); - pthread_mutex_lock(&LOCK_grant); + rw_wrlock(&LOCK_grant); VOID(pthread_mutex_lock(&acl_cache->lock)); /* Add first global access grants */ @@ -2766,7 +2776,7 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) acl_user->ssl_type != SSL_TYPE_NONE) { want_access=acl_user->access; - String global(buff,sizeof(buff)); + String global(buff,sizeof(buff),system_charset_info); global.length(0); global.append("GRANT ",6); @@ -2885,12 +2895,12 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) host=""; if (!strcmp(lex_user->user.str,user) && - !my_strcasecmp(lex_user->host.str,host)) + !my_strcasecmp(system_charset_info, lex_user->host.str, host)) { want_access=acl_db->access; if (want_access) { - String db(buff,sizeof(buff)); + String db(buff,sizeof(buff),system_charset_info); db.length(0); db.append("GRANT ",6); @@ -2944,12 +2954,12 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) host=""; if (!strcmp(lex_user->user.str,user) && - !my_strcasecmp(lex_user->host.str,host)) + !my_strcasecmp(system_charset_info, lex_user->host.str, host)) { want_access=grant_table->privs; if ((want_access | grant_table->cols) != 0) { - String global(buff,sizeof(buff)); + String global(buff,sizeof(buff),system_charset_info); global.length(0); global.append("GRANT ",6); @@ -3013,18 +3023,17 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) if (my_net_write(&thd->net,(char*) thd->packet.ptr(), thd->packet.length())) { - error=-1; + error= -1; break; } } } } - end: VOID(pthread_mutex_unlock(&acl_cache->lock)); - pthread_mutex_unlock(&LOCK_grant); + rw_unlock(&LOCK_grant); - send_eof(&thd->net); + send_eof(thd); DBUG_RETURN(error); } diff --git a/sql/sql_analyse.cc b/sql/sql_analyse.cc index 96bbd731882..f98eb0e0b26 100644 --- a/sql/sql_analyse.cc +++ b/sql/sql_analyse.cc @@ -89,21 +89,21 @@ proc_analyse_init(THD *thd, ORDER *param, select_result *result, if ((*param->item)->type() != Item::INT_ITEM || (*param->item)->val() < 0) { - net_printf(&thd->net, ER_WRONG_PARAMETERS_TO_PROCEDURE, proc_name); + net_printf(thd, ER_WRONG_PARAMETERS_TO_PROCEDURE, proc_name); DBUG_RETURN(0); } pc->max_tree_elements = (uint) (*param->item)->val_int(); param = param->next; if (param->next) // no third parameter possible { - net_printf(&thd->net, ER_WRONG_PARAMCOUNT_TO_PROCEDURE, proc_name); + net_printf(thd, ER_WRONG_PARAMCOUNT_TO_PROCEDURE, proc_name); DBUG_RETURN(0); } // second parameter if ((*param->item)->type() != Item::INT_ITEM || (*param->item)->val() < 0) { - net_printf(&thd->net, ER_WRONG_PARAMETERS_TO_PROCEDURE, proc_name); + net_printf(thd, ER_WRONG_PARAMETERS_TO_PROCEDURE, proc_name); DBUG_RETURN(0); } pc->max_treemem = (uint) (*param->item)->val_int(); @@ -111,7 +111,7 @@ proc_analyse_init(THD *thd, ORDER *param, select_result *result, else if ((*param->item)->type() != Item::INT_ITEM || (*param->item)->val() < 0) { - net_printf(&thd->net, ER_WRONG_PARAMETERS_TO_PROCEDURE, proc_name); + net_printf(thd, ER_WRONG_PARAMETERS_TO_PROCEDURE, proc_name); DBUG_RETURN(0); } // if only one parameter was given, it will be the value of max_tree_elements @@ -168,7 +168,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; @@ -181,10 +181,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++; } @@ -210,7 +210,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 @@ -225,7 +225,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) { @@ -275,7 +275,7 @@ void free_string(String *s) void field_str::add() { char buff[MAX_FIELD_WIDTH], *ptr; - String s(buff, sizeof(buff)), *res; + String s(buff, sizeof(buff),default_charset_info), *res; ulong length; if (!(res = item->val_str(&s))) @@ -314,10 +314,10 @@ void field_str::add() { if (res != &s) s.copy(*res); - if (!tree_search(&tree, (void*) &s)) // If not in tree + if (!tree_search(&tree, (void*) &s, tree.custom_arg)) // If not in tree { s.copy(); // slow, when SAFE_MALLOC is in use - if (!tree_insert(&tree, (void*) &s, 0)) + if (!tree_insert(&tree, (void*) &s, 0, tree.custom_arg)) { room_in_tree = 0; // Remove tree, out of RAM ? delete_tree(&tree); @@ -349,7 +349,7 @@ void field_str::add() if (length > max_length) max_length = length; - if (item->binary) + if (item->binary()) { if (stringcmp(res, &min_arg) < 0) min_arg.copy(*res); @@ -387,8 +387,7 @@ void field_real::add() if ((decs = decimals()) == NOT_FIXED_DEC) { - sprintf(buff, "%g", num); - length = (uint) strlen(buff); + length= my_sprintf(buff, (buff, "%g", num)); if (rint(num) != num) max_notzero_dec_len = 1; } @@ -397,11 +396,11 @@ void field_real::add() #ifdef HAVE_SNPRINTF buff[sizeof(buff)-1]=0; // Safety snprintf(buff, sizeof(buff)-1, "%-.*f", (int) decs, num); + length = (uint) strlen(buff); #else - sprintf(buff, "%-.*f", (int) decs, num); + length= my_sprintf(buff, (buff, "%-.*f", (int) decs, num)); #endif - length = (uint) strlen(buff); // We never need to check further than this end = buff + length - 1 - decs + max_notzero_dec_len; @@ -416,7 +415,7 @@ void field_real::add() if (room_in_tree) { - if (!(element = tree_insert(&tree, (void*) &num, 0))) + if (!(element = tree_insert(&tree, (void*) &num, 0, tree.custom_arg))) { room_in_tree = 0; // Remove tree, out of RAM ? delete_tree(&tree); @@ -469,7 +468,7 @@ void field_longlong::add() if (room_in_tree) { - if (!(element = tree_insert(&tree, (void*) &num, 0))) + if (!(element = tree_insert(&tree, (void*) &num, 0, tree.custom_arg))) { room_in_tree = 0; // Remove tree, out of RAM ? delete_tree(&tree); @@ -523,7 +522,7 @@ void field_ulonglong::add() if (room_in_tree) { - if (!(element = tree_insert(&tree, (void*) &num, 0))) + if (!(element = tree_insert(&tree, (void*) &num, 0, tree.custom_arg))) { room_in_tree = 0; // Remove tree, out of RAM ? delete_tree(&tree); @@ -578,8 +577,9 @@ bool analyse::end_of_records() { field_info **f = f_info; char buff[MAX_FIELD_WIDTH]; - String *res, s_min(buff, sizeof(buff)), s_max(buff, sizeof(buff)), - ans(buff, sizeof(buff)); + String *res, s_min(buff, sizeof(buff),default_charset_info), + s_max(buff, sizeof(buff),default_charset_info), + ans(buff, sizeof(buff),default_charset_info); for (; f != f_end; f++) { @@ -625,14 +625,14 @@ bool analyse::end_of_records() ((*f)->tree.elements_in_tree * 3 - 1 + 6)))) { char tmp[331]; //331, because one double prec. num. can be this long - String tmp_str(tmp, sizeof(tmp)); + String tmp_str(tmp, sizeof(tmp),default_charset_info); TREE_INFO tree_info; tree_info.str = &tmp_str; tree_info.found = 0; tree_info.item = (*f)->item; - tmp_str.set("ENUM(", 5); + tmp_str.set("ENUM(", 5,default_charset_info); tree_walk(&(*f)->tree, (*f)->collect_enum(), (char*) &tree_info, left_root_right); tmp_str.append(')'); @@ -738,7 +738,7 @@ void field_str::get_opt_type(String *answer, ha_rows total_rows) { if (must_be_blob) { - if (item->binary) + if (item->binary()) answer->append("TINYBLOB", 8); else answer->append("TINYTEXT", 8); @@ -756,21 +756,21 @@ void field_str::get_opt_type(String *answer, ha_rows total_rows) } else if (max_length < (1L << 16)) { - if (item->binary) + if (item->binary()) answer->append("BLOB", 4); else answer->append("TEXT", 4); } else if (max_length < (1L << 24)) { - if (item->binary) + if (item->binary()) answer->append("MEDIUMBLOB", 10); else answer->append("MEDIUMTEXT", 10); } else { - if (item->binary) + if (item->binary()) answer->append("LONGBLOB", 8); else answer->append("LONGTEXT", 8); @@ -896,14 +896,14 @@ int collect_real(double *element, element_count count __attribute__((unused)), TREE_INFO *info) { char buff[MAX_FIELD_WIDTH]; - String s(buff, sizeof(buff)); + String s(buff, sizeof(buff),current_thd->thd_charset); if (info->found) info->str->append(','); else info->found = 1; info->str->append('\''); - s.set(*element, info->item->decimals); + s.set(*element, info->item->decimals, current_thd->thd_charset); info->str->append(s); info->str->append('\''); return 0; @@ -915,14 +915,14 @@ int collect_longlong(longlong *element, TREE_INFO *info) { char buff[MAX_FIELD_WIDTH]; - String s(buff, sizeof(buff)); + String s(buff, sizeof(buff),default_charset_info); if (info->found) info->str->append(','); else info->found = 1; info->str->append('\''); - s.set(*element); + s.set(*element,default_charset_info); info->str->append(s); info->str->append('\''); return 0; @@ -934,14 +934,14 @@ int collect_ulonglong(ulonglong *element, TREE_INFO *info) { char buff[MAX_FIELD_WIDTH]; - String s(buff, sizeof(buff)); + String s(buff, sizeof(buff),default_charset_info); if (info->found) info->str->append(','); else info->found = 1; info->str->append('\''); - s.set(*element); + s.set(*element,default_charset_info); info->str->append(s); info->str->append('\''); return 0; diff --git a/sql/sql_analyse.h b/sql/sql_analyse.h index 1c60d0c150f..ada46374a15 100644 --- a/sql/sql_analyse.h +++ b/sql/sql_analyse.h @@ -110,11 +110,12 @@ class field_str :public field_info EV_NUM_INFO ev_num_info; public: - field_str(Item* a, analyse* b) :field_info(a,b), min_arg(""), - max_arg(""), sum(0), + field_str(Item* a, analyse* b) :field_info(a,b), + min_arg("",default_charset_info), + max_arg("",default_charset_info), sum(0), must_be_blob(0), was_zero_fill(0), was_maybe_zerofill(0), can_be_still_num(1) - { init_tree(&tree, 0, 0, sizeof(String), a->binary ? + { init_tree(&tree, 0, 0, sizeof(String), a->binary() ? (qsort_cmp2) stringcmp2 : (qsort_cmp2) sortcmp2, 0, (tree_element_free) free_string, NULL); }; @@ -127,10 +128,10 @@ public: String *avg(String *s, ha_rows rows) { if (!(rows - nulls)) - s->set((double) 0.0, 1); + s->set((double) 0.0, 1,my_thd_charset); else s->set((ulonglong2double(sum) / ulonglong2double(rows - nulls)), - DEC_IN_AVG); + DEC_IN_AVG,my_thd_charset); return s; } friend int collect_string(String *element, element_count count, @@ -159,26 +160,34 @@ public: void add(); void get_opt_type(String*, ha_rows); - String *get_min_arg(String *s) { s->set(min_arg, item->decimals); return s; } - String *get_max_arg(String *s) { s->set(max_arg, item->decimals); return s; } + String *get_min_arg(String *s) + { + s->set(min_arg, item->decimals,my_thd_charset); + return s; + } + String *get_max_arg(String *s) + { + s->set(max_arg, item->decimals,my_thd_charset); + return s; + } String *avg(String *s, ha_rows rows) { if (!(rows - nulls)) - s->set((double) 0.0, 1); + s->set((double) 0.0, 1,my_thd_charset); else - s->set(((double)sum / (double) (rows - nulls)), item->decimals); + s->set(((double)sum / (double) (rows - nulls)), item->decimals,my_thd_charset); return s; } String *std(String *s, ha_rows rows) { double tmp = ulonglong2double(rows); if (!(tmp - nulls)) - s->set((double) 0.0, 1); + s->set((double) 0.0, 1,my_thd_charset); else { double tmp2 = ((sum_sqr - sum * sum / (tmp - nulls)) / (tmp - nulls)); - s->set(((double) tmp2 <= 0.0 ? 0.0 : sqrt(tmp2)), item->decimals); + s->set(((double) tmp2 <= 0.0 ? 0.0 : sqrt(tmp2)), item->decimals,my_thd_charset); } return s; } @@ -205,26 +214,26 @@ public: void add(); void get_opt_type(String*, ha_rows); - String *get_min_arg(String *s) { s->set(min_arg); return s; } - String *get_max_arg(String *s) { s->set(max_arg); return s; } + String *get_min_arg(String *s) { s->set(min_arg,my_thd_charset); return s; } + String *get_max_arg(String *s) { s->set(max_arg,my_thd_charset); return s; } String *avg(String *s, ha_rows rows) { if (!(rows - nulls)) - s->set((double) 0.0, 1); + s->set((double) 0.0, 1,my_thd_charset); else - s->set(((double) sum / (double) (rows - nulls)), DEC_IN_AVG); + s->set(((double) sum / (double) (rows - nulls)), DEC_IN_AVG,my_thd_charset); return s; } String *std(String *s, ha_rows rows) { double tmp = ulonglong2double(rows); if (!(tmp - nulls)) - s->set((double) 0.0, 1); + s->set((double) 0.0, 1,my_thd_charset); else { double tmp2 = ((sum_sqr - sum * sum / (tmp - nulls)) / (tmp - nulls)); - s->set(((double) tmp2 <= 0.0 ? 0.0 : sqrt(tmp2)), DEC_IN_AVG); + s->set(((double) tmp2 <= 0.0 ? 0.0 : sqrt(tmp2)), DEC_IN_AVG,my_thd_charset); } return s; } @@ -249,28 +258,28 @@ public: (qsort_cmp2) compare_ulonglong2, 0, NULL, NULL); } void add(); void get_opt_type(String*, ha_rows); - String *get_min_arg(String *s) { s->set(min_arg); return s; } - String *get_max_arg(String *s) { s->set(max_arg); return s; } + String *get_min_arg(String *s) { s->set(min_arg,my_thd_charset); return s; } + String *get_max_arg(String *s) { s->set(max_arg,my_thd_charset); return s; } String *avg(String *s, ha_rows rows) { if (!(rows - nulls)) - s->set((double) 0.0, 1); + s->set((double) 0.0, 1,my_thd_charset); else s->set((ulonglong2double(sum) / ulonglong2double(rows - nulls)), - DEC_IN_AVG); + DEC_IN_AVG,my_thd_charset); return s; } String *std(String *s, ha_rows rows) { double tmp = ulonglong2double(rows); if (!(tmp - nulls)) - s->set((double) 0.0, 1); + s->set((double) 0.0, 1,my_thd_charset); else { double tmp2 = ((ulonglong2double(sum_sqr) - ulonglong2double(sum * sum) / (tmp - nulls)) / (tmp - nulls)); - s->set(((double) tmp2 <= 0.0 ? 0.0 : sqrt(tmp2)), DEC_IN_AVG); + s->set(((double) tmp2 <= 0.0 ? 0.0 : sqrt(tmp2)), DEC_IN_AVG,my_thd_charset); } return s; } diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 032882080ff..59310fb00de 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -49,7 +49,8 @@ extern "C" byte *table_cache_key(const byte *record,uint *length, void table_cache_init(void) { - VOID(hash_init(&open_cache,table_cache_size+16,0,0,table_cache_key, + VOID(hash_init(&open_cache,system_charset_info, + table_cache_size+16,0,0,table_cache_key, (hash_free_key) free_cache_entry,0)); mysql_rm_tmp_tables(); } @@ -195,34 +196,36 @@ OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *wild) } -/****************************************************************************** -** Send name and type of result to client. -** Sum fields has table name empty and field_name. -** flag is a bit mask with the following functions: -** 1 send number of rows -** 2 send default values -** 4 Don't convert field names -******************************************************************************/ +/* + Send name and type of result to client converted to a given char set + + SYNOPSIS + send_convert_fields() + THD Thread data object + list List of items to send to client + convert object used to convertation to another character set + flag Bit mask with the following functions: + 2 send default values + 4 Don't convert field names + + DESCRIPTION + Sum fields has table name empty and field_name. + + RETURN VALUES + 0 ok + 1 Error (Note that in this case the error is not sent to the client) +*/ bool -send_fields(THD *thd,List<Item> &list,uint flag) +send_convert_fields(THD *thd,List<Item> &list,CONVERT *convert,uint flag) { List_iterator_fast<Item> it(list); Item *item; char buff[80]; - CONVERT *convert= (flag & 4) ? (CONVERT*) 0 : thd->variables.convert_set; - DBUG_ENTER("send_fields"); - - String tmp((char*) buff,sizeof(buff)),*res,*packet= &thd->packet; + String tmp((char*) buff,sizeof(buff),default_charset_info); + String *res,*packet= &thd->packet; + DBUG_ENTER("send_convert_fields"); - if (thd->fatal_error) // We have got an error - goto err; - - if (flag & 1) - { // Packet with number of elements - char *pos=net_store_length(buff,(uint) list.elements); - (void) my_net_write(&thd->net, buff,(uint) (pos-buff)); - } while ((item=it++)) { char *pos; @@ -230,19 +233,30 @@ send_fields(THD *thd,List<Item> &list,uint flag) item->make_field(&field); packet->length(0); - if (convert) + if (thd->client_capabilities & CLIENT_PROTOCOL_41) { - if (convert->store(packet,field.table_name, + if (convert->store(packet,field.db_name, + (uint) strlen(field.db_name)) || + convert->store(packet,field.table_name, (uint) strlen(field.table_name)) || + convert->store(packet,field.org_table_name, + (uint) strlen(field.org_table_name)) || convert->store(packet,field.col_name, (uint) strlen(field.col_name)) || + convert->store(packet,field.org_col_name, + (uint) strlen(field.org_col_name)) || packet->realloc(packet->length()+10)) goto err; + } + else + { + if (convert->store(packet,field.table_name, + (uint) strlen(field.table_name)) || + convert->store(packet,field.col_name, + (uint) strlen(field.col_name)) || + packet->realloc(packet->length()+10)) + goto err; } - else if (net_store_data(packet,field.table_name) || - net_store_data(packet,field.col_name) || - packet->realloc(packet->length()+10)) - goto err; /* purecov: inspected */ pos= (char*) packet->ptr()+packet->length(); if (!(thd->client_capabilities & CLIENT_LONG_FLAG)) @@ -266,16 +280,162 @@ send_fields(THD *thd,List<Item> &list,uint flag) if (net_store_null(packet)) goto err; } - else if (net_store_data(packet,res->ptr(),res->length())) + else if (convert->store(packet,res->ptr(),res->length())) goto err; } if (my_net_write(&thd->net, (char*) packet->ptr(),packet->length())) break; /* purecov: inspected */ } - send_eof(&thd->net,1); DBUG_RETURN(0); - err: - send_error(&thd->net,ER_OUT_OF_RESOURCES); /* purecov: inspected */ + +err: + DBUG_RETURN(1); +} + + +/* + Send name and type of result to client. + + SYNOPSIS + send_non_convert_fields() + THD Thread data object + list List of items to send to client + flag Bit mask with the following functions: + 2 send default values + 4 Don't convert field names + + DESCRIPTION + Sum fields has table name empty and field_name. + + RETURN VALUES + 0 ok + 1 Error +*/ + +bool +send_non_convert_fields(THD *thd,List<Item> &list,uint flag) +{ + List_iterator_fast<Item> it(list); + Item *item; + char buff[80]; + + String tmp((char*) buff,sizeof(buff),default_charset_info); + String *res,*packet= &thd->packet; + + while ((item=it++)) + { + char *pos; + Send_field field; + item->make_field(&field); + packet->length(0); + + if (thd->client_capabilities & CLIENT_PROTOCOL_41) + { + if (net_store_data(packet,field.db_name) || + net_store_data(packet,field.table_name) || + net_store_data(packet,field.org_table_name) || + net_store_data(packet,field.col_name) || + net_store_data(packet,field.org_col_name) || + packet->realloc(packet->length()+10)) + return 1; + } + else + { + if (net_store_data(packet,field.table_name) || + net_store_data(packet,field.col_name) || + packet->realloc(packet->length()+10)) + return 1; + } + + pos= (char*) packet->ptr()+packet->length(); + + if (!(thd->client_capabilities & CLIENT_LONG_FLAG)) + { + packet->length(packet->length()+9); + pos[0]=3; int3store(pos+1,field.length); + pos[4]=1; pos[5]=field.type; + pos[6]=2; pos[7]=(char) field.flags; pos[8]= (char) field.decimals; + } + else + { + packet->length(packet->length()+10); + pos[0]=3; int3store(pos+1,field.length); + pos[4]=1; pos[5]=field.type; + pos[6]=3; int2store(pos+7,field.flags); pos[9]= (char) field.decimals; + } + if (flag & 2) + { // Send default value + if (!(res=item->val_str(&tmp))) + { + if (net_store_null(packet)) + return 1; + } + else if (net_store_data(packet,res->ptr(),res->length())) + return 1; + } + if (my_net_write(&thd->net, (char*) packet->ptr(),packet->length())) + break; + } + return 0; +} + + +/* + Send name and type of result to client. + + SYNOPSIS + send_fields() + THD Thread data object + list List of items to send to client + convert object used to convertation to another character set + flag Bit mask with the following functions: + 1 send number of rows + 2 send default values + 4 Don't convert field names + + DESCRIPTION + Sum fields has table name empty and field_name. + Uses send_fields_convert() and send_fields() depending on + if we have an active character set convert or not. + + RETURN VALUES + 0 ok + 1 Error (Note that in this case the error is not sent to the client) +*/ + +bool +send_fields(THD *thd, List<Item> &list, uint flag) +{ + char buff[9]; // Big enough for store_length + CONVERT *convert= (flag & 4) ? (CONVERT*) 0 : thd->variables.convert_set; + DBUG_ENTER("send_fields"); + + if (thd->fatal_error) // We have got an error + goto err; + + if (flag & 1) + { // Packet with number of elements + char *pos=net_store_length(buff, (uint) list.elements); + (void) my_net_write(&thd->net, buff,(uint) (pos-buff)); + } + + /* + Avoid check conditions on convert() for each field + by having two different functions + */ + if (convert) + { + if (send_convert_fields(thd, list, convert, flag)) + goto err; + } + else if (send_non_convert_fields(thd, list, flag)) + goto err; + + send_eof(thd); + DBUG_RETURN(0); + +err: + send_error(thd,ER_OUT_OF_RESOURCES); /* purecov: inspected */ DBUG_RETURN(1); /* purecov: inspected */ } @@ -808,7 +968,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); @@ -1300,9 +1460,8 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db, } } pthread_mutex_unlock(&LOCK_open); - thd->net.last_error[0]=0; // Clear error message - thd->net.last_errno=0; - error=0; + thd->clear_error(); // Clear error message + error= 0; if (openfrm(path,alias, (uint) (HA_OPEN_KEYFILE | HA_OPEN_RNDFILE | HA_GET_INDEX | HA_TRY_READ_ONLY), @@ -1312,8 +1471,7 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db, (entry->file->is_crashed() && entry->file->check_and_repair(thd))) { /* Give right error message */ - thd->net.last_error[0]=0; - thd->net.last_errno=0; + thd->clear_error(); my_error(ER_NOT_KEYFILE, MYF(0), name, my_errno); sql_print_error("Error: Couldn't repair table: %s.%s",db,name); if (entry->file) @@ -1322,8 +1480,7 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db, } else { - thd->net.last_error[0]=0; // Clear error message - thd->net.last_errno=0; + thd->clear_error(); // Clear error message } pthread_mutex_lock(&LOCK_open); unlock_table_name(thd,&table_list); @@ -1649,14 +1806,17 @@ Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length, } else { - Field **ptr=table->field; + Field **ptr; + if (!(ptr=table->field)) + return (Field *)0; 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; @@ -1679,9 +1839,30 @@ Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length, return field; } +// Special Field pointer for find_field_in_tables returning +const Field *not_found_field= (Field*) 0x1; +/* + Find field in table list. + + SYNOPSIS + find_field_in_tables() + thd - pointer to current thread structure + item - field item that should be found + tables - tables for scaning + report_error - if FALSE then do not report error if item not found and + return not_found_field; + + RETURN VALUES + 0 - field is not found or field is not unique, error message is + reported + not_found_field - function was called with report_error == FALSE and + field if not found, no error message reported + found field +*/ Field * -find_field_in_tables(THD *thd,Item_field *item,TABLE_LIST *tables) +find_field_in_tables(THD *thd, Item_field *item, TABLE_LIST *tables, + bool report_error) { Field *found=0; const char *db=item->db_name; @@ -1718,7 +1899,7 @@ find_field_in_tables(THD *thd,Item_field *item,TABLE_LIST *tables) } if (found) return found; - if (!found_table) + if (!found_table && report_error) { char buff[NAME_LEN*2+1]; if (db) @@ -1726,12 +1907,18 @@ find_field_in_tables(THD *thd,Item_field *item,TABLE_LIST *tables) strxnmov(buff,sizeof(buff)-1,db,".",table_name,NullS); table_name=buff; } - my_printf_error(ER_UNKNOWN_TABLE,ER(ER_UNKNOWN_TABLE),MYF(0),table_name, - thd->where); + if (report_error) + my_printf_error(ER_UNKNOWN_TABLE, ER(ER_UNKNOWN_TABLE), MYF(0), + table_name, thd->where); + else + return (Field*) not_found_field; } else - my_printf_error(ER_BAD_FIELD_ERROR,ER(ER_BAD_FIELD_ERROR),MYF(0), - item->full_name(),thd->where); + if (report_error) + my_printf_error(ER_BAD_FIELD_ERROR,ER(ER_BAD_FIELD_ERROR),MYF(0), + item->full_name(),thd->where); + else + return (Field*) not_found_field; return (Field*) 0; } bool allow_rowid= tables && !tables->next; // Only one table @@ -1757,13 +1944,42 @@ find_field_in_tables(THD *thd,Item_field *item,TABLE_LIST *tables) } if (found) return found; - my_printf_error(ER_BAD_FIELD_ERROR,ER(ER_BAD_FIELD_ERROR), - MYF(0),item->full_name(),thd->where); + if (report_error) + my_printf_error(ER_BAD_FIELD_ERROR, ER(ER_BAD_FIELD_ERROR), + MYF(0), item->full_name(), thd->where); + else + return (Field*) not_found_field; return (Field*) 0; } +// Special Item pointer for find_item_in_list returning +const Item **not_found_item= (const Item**) 0x1; + +/* + Find Item in list of items (find_field_in_tables analog) + + SYNOPSIS + find_item_in_list() + find - item to find + items - list of items + report_error + REPORT_ALL_ERRORS - report errors, return 0 if error + REPORT_EXCEPT_NOT_FOUND - do not report 'not found' error and return not_ found_item, report other errors, return 0 + IGNORE_ERRORS - do not report errors, return 0 if error + + RETURN VALUES + 0 - item is not found or item is not unique, error message is + reported + not_found_item - function was called with report_error == + REPORT_EXCEPT_NOT_FOUND and item if not found, no error + message reported + found field + +*/ + Item ** -find_item_in_list(Item *find,List<Item> &items) +find_item_in_list(Item *find, List<Item> &items, + find_item_error_report_type report_error) { List_iterator<Item> li(items); Item **found=0,*item; @@ -1779,7 +1995,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) { @@ -1787,7 +2004,7 @@ find_item_in_list(Item *find,List<Item> &items) { if ((*found)->eq(item,0)) continue; // Same field twice (Access?) - if (current_thd->where) + if (report_error != IGNORE_ERRORS) my_printf_error(ER_NON_UNIQ_ERROR,ER(ER_NON_UNIQ_ERROR),MYF(0), find->full_name(), current_thd->where); return (Item**) 0; @@ -1802,17 +2019,25 @@ 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; } } - if (!found && current_thd->where) - my_printf_error(ER_BAD_FIELD_ERROR,ER(ER_BAD_FIELD_ERROR),MYF(0), - find->full_name(),current_thd->where); - return found; + if (found) + return found; + else if (report_error != REPORT_EXCEPT_NOT_FOUND) + { + if (report_error == REPORT_ALL_ERRORS) + my_printf_error(ER_BAD_FIELD_ERROR, ER(ER_BAD_FIELD_ERROR), MYF(0), + find->full_name(), current_thd->where); + return (Item **) 0; + } + else + return (Item **) not_found_item; } /**************************************************************************** @@ -1852,7 +2077,7 @@ int setup_fields(THD *thd, TABLE_LIST *tables, List<Item> &fields, } else { - if (item->fix_fields(thd,tables)) + if (item->fix_fields(thd, tables, it.ref())) DBUG_RETURN(-1); /* purecov: inspected */ if (item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM && sum_func_list) @@ -2005,7 +2230,7 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds) if (*conds) { thd->where="where clause"; - if ((*conds)->fix_fields(thd,tables)) + if ((*conds)->fix_fields(thd, tables, conds)) DBUG_RETURN(1); } @@ -2016,7 +2241,7 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds) { /* Make a join an a expression */ thd->where="on clause"; - if (table->on_expr->fix_fields(thd,tables)) + if (table->on_expr->fix_fields(thd, tables, &table->on_expr)) DBUG_RETURN(1); thd->cond_count++; @@ -2044,7 +2269,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]), @@ -2093,7 +2319,7 @@ fill_record(List<Item> &fields,List<Item> &values) while ((field=(Item_field*) f++)) { value=v++; - if (value->save_in_field(field->field)) + if (value->save_in_field(field->field) > 0) DBUG_RETURN(1); } DBUG_RETURN(0); @@ -2111,7 +2337,7 @@ fill_record(Field **ptr,List<Item> &values) while ((field = *ptr++)) { value=v++; - if (value->save_in_field(field)) + if (value->save_in_field(field) == 1) DBUG_RETURN(1); } DBUG_RETURN(0); @@ -2120,39 +2346,41 @@ fill_record(Field **ptr,List<Item> &values) static void mysql_rm_tmp_tables(void) { - uint idx; - char filePath[FN_REFLEN]; + uint i, idx; + char filePath[FN_REFLEN], *tmpdir; MY_DIR *dirp; FILEINFO *file; DBUG_ENTER("mysql_rm_tmp_tables"); + for (i=0; i<=mysql_tmpdir_list.max; i++) + { + tmpdir=mysql_tmpdir_list.list[i]; /* See if the directory exists */ - if (!(dirp = my_dir(mysql_tmpdir,MYF(MY_WME | MY_DONT_SORT)))) - DBUG_VOID_RETURN; /* purecov: inspected */ + if (!(dirp = my_dir(tmpdir,MYF(MY_WME | MY_DONT_SORT)))) + continue; - /* - ** Remove all SQLxxx tables from directory - */ + /* Remove all SQLxxx tables from directory */ for (idx=2 ; idx < (uint) dirp->number_off_files ; idx++) { file=dirp->dir_entry+idx; if (!bcmp(file->name,tmp_file_prefix,tmp_file_prefix_length)) { - sprintf(filePath,"%s%s",mysql_tmpdir,file->name); /* purecov: inspected */ - VOID(my_delete(filePath,MYF(MY_WME))); /* purecov: inspected */ + sprintf(filePath,"%s%s",tmpdir,file->name); + VOID(my_delete(filePath,MYF(MY_WME))); } } my_dirend(dirp); + } DBUG_VOID_RETURN; } /* -** CREATE INDEX and DROP INDEX are implemented by calling ALTER TABLE with -** the proper arguments. This isn't very fast but it should work for most -** cases. -** One should normally create all indexes with CREATE TABLE or ALTER TABLE. + CREATE INDEX and DROP INDEX are implemented by calling ALTER TABLE with + the proper arguments. This isn't very fast but it should work for most + cases. + One should normally create all indexes with CREATE TABLE or ALTER TABLE. */ int mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys) @@ -2164,6 +2392,8 @@ int mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys) DBUG_ENTER("mysql_create_index"); bzero((char*) &create_info,sizeof(create_info)); create_info.db_type=DB_TYPE_DEFAULT; + /* TODO: Fix to use database character set */ + create_info.table_charset=default_charset_info; DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->real_name, &create_info, table_list, fields, keys, drop, alter, (ORDER*)0, FALSE, @@ -2180,6 +2410,7 @@ int mysql_drop_index(THD *thd, TABLE_LIST *table_list, List<Alter_drop> &drop) DBUG_ENTER("mysql_drop_index"); bzero((char*) &create_info,sizeof(create_info)); create_info.db_type=DB_TYPE_DEFAULT; + create_info.table_charset=default_charset_info; DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->real_name, &create_info, table_list, fields, keys, drop, alter, (ORDER*)0, FALSE, @@ -2279,10 +2510,10 @@ bool remove_table_from_cache(THD *thd, const char *db, const char *table_name, DBUG_RETURN(result); } -int setup_ftfuncs(THD *thd) +int setup_ftfuncs(SELECT_LEX *select_lex) { - List_iterator<Item_func_match> li(thd->lex.select->ftfunc_list), - lj(thd->lex.select->ftfunc_list); + List_iterator<Item_func_match> li(*(select_lex->ftfunc_list)), + lj(*(select_lex->ftfunc_list)); Item_func_match *ftf, *ftf2; while ((ftf=li++)) @@ -2301,11 +2532,11 @@ int setup_ftfuncs(THD *thd) } -int init_ftfuncs(THD *thd, bool no_order) +int init_ftfuncs(THD *thd, SELECT_LEX *select_lex, bool no_order) { - if (thd->lex.select->ftfunc_list.elements) + if (select_lex->ftfunc_list->elements) { - List_iterator<Item_func_match> li(thd->lex.select->ftfunc_list); + List_iterator<Item_func_match> li(*(select_lex->ftfunc_list)); Item_func_match *ifm; DBUG_PRINT("info",("Performing FULLTEXT search")); thd->proc_info="FULLTEXT initialization"; diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc index 64c62345182..ef584f4364e 100644 --- a/sql/sql_cache.cc +++ b/sql/sql_cache.cc @@ -278,6 +278,21 @@ TODO list: - Move MRG_MYISAM table type processing to handlers, something like: tables_used->table->file->register_used_filenames(callback, first_argument); + - Make derived tables cachable. + - QC improvement suggested by Monty: + - Add a counter in open_table() for how many MERGE (ISAM or MyISAM) + tables are cached in the table cache. + (This will be trivial when we have the new table cache in place I + have been working on) + - After this we can add the following test around the for loop in + is_cacheable:: + + if (thd->temp_tables || global_merge_table_count) + + - Another option would be to set thd->safe_to_cache_query to 0 + in 'get_lock_data' if any of the tables was a tmp table or a + MRG_ISAM table. + (This could be done with almost no speed penalty) */ #include "mysql_priv.h" @@ -895,8 +910,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; @@ -1383,16 +1399,16 @@ 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)); #ifndef FN_NO_CASE_SENCE - 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)); #else // windows, OS/2 or other case insensitive file names work around - 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, - (lower_case_table_names?0:HASH_CASE_INSENSITIVE))); + (lower_case_table_names?0:HASH_CASE_INSENSITIVE))); #endif queries_in_cache = 0; @@ -2439,14 +2455,14 @@ TABLE_COUNTER_TYPE Query_cache::is_cacheable(THD *thd, uint32 query_len, if (lex->sql_command == SQLCOM_SELECT && (thd->variables.query_cache_type == 1 || - (thd->variables.query_cache_type == 2 && (lex->select->options & + (thd->variables.query_cache_type == 2 && (lex->select_lex.options & OPTION_TO_QUERY_CACHE))) && thd->safe_to_cache_query) { my_bool has_transactions = 0; DBUG_PRINT("qcache", ("options %lx %lx, type %u", OPTION_TO_QUERY_CACHE, - lex->select->options, + lex->select_lex.options, (int) thd->variables.query_cache_type)); for (; tables_used; tables_used= tables_used->next) @@ -2493,7 +2509,7 @@ TABLE_COUNTER_TYPE Query_cache::is_cacheable(THD *thd, uint32 query_len, ("not interesting query: %d or not cacheable, options %lx %lx, type %u", (int) lex->sql_command, OPTION_TO_QUERY_CACHE, - lex->select->options, + lex->select_lex.options, (int) thd->variables.query_cache_type)); DBUG_RETURN(0); } diff --git a/sql/sql_class.cc b/sql/sql_class.cc index a5f14a507f7..e3ee0fb9f72 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -79,14 +79,15 @@ extern "C" void free_user_var(user_var_entry *entry) ** Thread specific functions ****************************************************************************/ -THD::THD():user_time(0),fatal_error(0),last_insert_id_used(0), - insert_id_used(0),rand_used(0),in_lock_tables(0), - global_read_lock(0),bootstrap(0) +THD::THD():user_time(0), fatal_error(0), + last_insert_id_used(0), + insert_id_used(0), rand_used(0), in_lock_tables(0), + global_read_lock(0), bootstrap(0) { host=user=priv_user=db=query=ip=0; host_or_ip="unknown ip"; locked=killed=count_cuted_fields=some_tables_deleted=no_errors=password= - query_start_used=safe_to_cache_query=0; + query_start_used=safe_to_cache_query=prepare_command=0; db_length=query_length=col_access=0; query_error=0; next_insert_id=last_insert_id=0; @@ -96,13 +97,16 @@ THD::THD():user_time(0),fatal_error(0),last_insert_id_used(0), tmp_table=0; lock=locked_tables=0; used_tables=0; - cuted_fields=sent_row_count=0L; + cuted_fields= sent_row_count= current_stmt_id= 0L; start_time=(time_t) 0; current_linfo = 0; slave_thread = 0; slave_proxy_id = 0; file_id = 0; cond_count=0; + warn_id= 0; + db_charset=default_charset_info; + thd_charset=default_charset_info; mysys_var=0; #ifndef DBUG_OFF dbug_sentry=THD_SENTRY_MAGIC; @@ -135,10 +139,22 @@ THD::THD():user_time(0),fatal_error(0),last_insert_id_used(0), /* Initialize sub structures */ bzero((char*) &mem_root,sizeof(mem_root)); bzero((char*) &transaction.mem_root,sizeof(transaction.mem_root)); + bzero((char*) &con_root,sizeof(con_root)); + bzero((char*) &warn_root,sizeof(warn_root)); + init_alloc_root(&warn_root, 1024, 0); + bzero((char*) warn_count, sizeof(warn_count)); + warn_list.empty(); user_connect=(USER_CONN *)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, (hash_free_key) free_user_var,0); + + /* Prepared statements */ + last_prepared_stmt= 0; + init_tree(&prepared_statements, 0, 0, sizeof(PREP_STMT), + (qsort_cmp2) compare_prep_stmt, 1, + (tree_element_free) free_prep_stmt, 0); + #ifdef USING_TRANSACTIONS bzero((char*) &transaction,sizeof(transaction)); if (opt_using_transactions) @@ -270,7 +286,10 @@ THD::~THD() safeFree(db); safeFree(ip); free_root(&mem_root,MYF(0)); + free_root(&con_root,MYF(0)); + free_root(&warn_root,MYF(0)); free_root(&transaction.mem_root,MYF(0)); + delete_tree(&prepared_statements); mysys_var=0; // Safety (shouldn't be needed) pthread_mutex_destroy(&LOCK_delete); #ifndef DBUG_OFF @@ -320,8 +339,7 @@ void THD::awake(bool prepare_to_die) bool THD::store_globals() { if (my_pthread_setspecific_ptr(THR_THD, this) || - my_pthread_setspecific_ptr(THR_MALLOC, &mem_root) || - my_pthread_setspecific_ptr(THR_NET, &net)) + my_pthread_setspecific_ptr(THR_MALLOC, &mem_root)) return 1; mysys_var=my_thread_var; dbug_thread_id=my_thread_id(); @@ -417,6 +435,28 @@ CHANGED_TABLE_LIST* THD::changed_table_dup(const char *key, long key_length) return new_table; } +int THD::send_explain_fields(select_result *result) +{ + List<Item> field_list; + Item *item; + field_list.push_back(new Item_int("id",0,3)); + field_list.push_back(new Item_empty_string("select_type",19)); + field_list.push_back(new Item_empty_string("table",NAME_LEN)); + field_list.push_back(new Item_empty_string("type",10)); + field_list.push_back(item=new Item_empty_string("possible_keys", + NAME_LEN*MAX_KEY)); + item->maybe_null=1; + field_list.push_back(item=new Item_empty_string("key",NAME_LEN)); + item->maybe_null=1; + field_list.push_back(item=new Item_int("key_len",0,3)); + item->maybe_null=1; + field_list.push_back(item=new Item_empty_string("ref", + NAME_LEN*MAX_REF_PARTS)); + item->maybe_null=1; + field_list.push_back(new Item_real("rows",0.0,0,10)); + field_list.push_back(new Item_empty_string("Extra",255)); + return (result->send_fields(field_list,1)); +} #ifdef SIGNAL_WITH_VIO_CLOSE void THD::close_active_vio() @@ -430,6 +470,15 @@ void THD::close_active_vio() } #endif +void THD::add_possible_loop (Item *item) +{ + if (!possible_loops) + { + possible_loops= new List<Item>; + } + possible_loops->push_back(item); +} + /***************************************************************************** ** Functions to provide a interface to select results *****************************************************************************/ @@ -439,8 +488,10 @@ select_result::select_result() thd=current_thd; } -static String default_line_term("\n"),default_escaped("\\"), - default_field_term("\t"); +static String + default_line_term("\n",default_charset_info), + default_escaped("\\",default_charset_info), + default_field_term("\t",default_charset_info); sql_exchange::sql_exchange(char *name,bool flag) :file_name(name), opt_enclosed(0), dumpfile(flag), skip_lines(0) @@ -465,9 +516,9 @@ bool select_send::send_data(List<Item> &items) String *packet= &thd->packet; DBUG_ENTER("send_data"); - if (thd->offset_limit) + if (unit->offset_limit_cnt) { // using limit offset,count - thd->offset_limit--; + unit->offset_limit_cnt--; DBUG_RETURN(0); } packet->length(0); // Reset packet @@ -477,13 +528,19 @@ bool select_send::send_data(List<Item> &items) if (item->send(thd, packet)) { packet->free(); // Free used - my_error(ER_OUT_OF_RESOURCES,MYF(0)); + my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0)); DBUG_RETURN(1); } } thd->sent_row_count++; - bool error=my_net_write(&thd->net,(char*) packet->ptr(),packet->length()); - DBUG_RETURN(error); + if (!thd->net.report_error) + { + DBUG_RETURN(my_net_write(&thd->net, + (char*) packet->ptr(), + packet->length())); + } + else + DBUG_RETURN(1); } bool select_send::send_eof() @@ -493,8 +550,13 @@ bool select_send::send_eof() { mysql_unlock_tables(thd, thd->lock); thd->lock=0; } - ::send_eof(&thd->net); - return 0; + if (!thd->net.report_error) + { + ::send_eof(thd); + return 0; + } + else + return 1; } @@ -515,11 +577,12 @@ select_export::~select_export() } int -select_export::prepare(List<Item> &list) +select_export::prepare(List<Item> &list, SELECT_LEX_UNIT *u) { char path[FN_REFLEN]; uint option=4; bool blob_flag=0; + unit= u; #ifdef DONT_ALLOW_FULL_LOAD_DATA_PATHS option|=1; // Force use of db directory #endif @@ -529,7 +592,7 @@ select_export::prepare(List<Item> &list) option); if (!access(path,F_OK)) { - my_error(ER_FILE_EXISTS_ERROR,MYF(0),exchange->file_name); + my_error(ER_FILE_EXISTS_ERROR, MYF(0), exchange->file_name); return 1; } /* Create the file world readable */ @@ -583,12 +646,12 @@ bool select_export::send_data(List<Item> &items) DBUG_ENTER("send_data"); char buff[MAX_FIELD_WIDTH],null_buff[2],space[MAX_FIELD_WIDTH]; bool space_inited=0; - String tmp(buff,sizeof(buff)),*res; + String tmp(buff,sizeof(buff),default_charset_info),*res; tmp.length(0); - if (thd->offset_limit) + if (unit->offset_limit_cnt) { // using limit offset,count - thd->offset_limit--; + unit->offset_limit_cnt--; DBUG_RETURN(0); } row_count++; @@ -715,9 +778,9 @@ err: } -void select_export::send_error(uint errcode,const char *err) +void select_export::send_error(uint errcode, const char *err) { - ::send_error(&thd->net,errcode,err); + my_message(errcode, err, MYF(0));; (void) end_io_cache(&cache); (void) my_close(file,MYF(0)); file= -1; @@ -729,10 +792,8 @@ bool select_export::send_eof() int error=test(end_io_cache(&cache)); if (my_close(file,MYF(MY_WME))) error=1; - if (error) - ::send_error(&thd->net); - else - ::send_ok(&thd->net,row_count); + if (!error) + ::send_ok(thd,row_count); file= -1; return error; } @@ -754,9 +815,11 @@ select_dump::~select_dump() } int -select_dump::prepare(List<Item> &list __attribute__((unused))) +select_dump::prepare(List<Item> &list __attribute__((unused)), + SELECT_LEX_UNIT *u) { uint option=4; + unit= u; #ifdef DONT_ALLOW_FULL_LOAD_DATA_PATHS option|=1; // Force use of db directory #endif @@ -790,19 +853,19 @@ bool select_dump::send_data(List<Item> &items) { List_iterator_fast<Item> li(items); char buff[MAX_FIELD_WIDTH]; - String tmp(buff,sizeof(buff)),*res; + String tmp(buff,sizeof(buff),default_charset_info),*res; tmp.length(0); Item *item; DBUG_ENTER("send_data"); - if (thd->offset_limit) + if (unit->offset_limit_cnt) { // using limit offset,count - thd->offset_limit--; + unit->offset_limit_cnt--; DBUG_RETURN(0); } if (row_count++ > 1) { - my_error(ER_TOO_MANY_ROWS,MYF(0)); + my_error(ER_TOO_MANY_ROWS, MYF(0)); goto err; } while ((item=li++)) @@ -827,23 +890,139 @@ err: void select_dump::send_error(uint errcode,const char *err) { - ::send_error(&thd->net,errcode,err); + my_message(errcode, err, MYF(0)); (void) end_io_cache(&cache); (void) my_close(file,MYF(0)); (void) my_delete(path,MYF(0)); // Delete file on error file= -1; } - bool select_dump::send_eof() { int error=test(end_io_cache(&cache)); if (my_close(file,MYF(MY_WME))) error=1; - if (error) - ::send_error(&thd->net); - else - ::send_ok(&thd->net,row_count); + if (!error) + ::send_ok(thd,row_count); file= -1; return error; } + +select_subselect::select_subselect(Item_subselect *item) +{ + this->item=item; +} + +bool select_singleval_subselect::send_data(List<Item> &items) +{ + DBUG_ENTER("select_singleval_subselect::send_data"); + Item_singleval_subselect *it= (Item_singleval_subselect *)item; + if (it->assigned()) + { + my_message(ER_SUBSELECT_NO_1_ROW, ER(ER_SUBSELECT_NO_1_ROW), MYF(0)); + DBUG_RETURN(1); + } + if (unit->offset_limit_cnt) + { // Using limit offset,count + unit->offset_limit_cnt--; + DBUG_RETURN(0); + } + List_iterator_fast<Item> li(items); + Item *val_item= li++; // Only one (single value subselect) + /* + Following val() call have to be first, because function AVG() & STD() + calculate value on it & determinate "is it NULL?". + */ + it->real_value= val_item->val_result(); + if ((it->null_value= val_item->is_null_result())) + { + it->assign_null(); + } + else + { + it->max_length= val_item->max_length; + it->decimals= val_item->decimals; + it->set_charset(val_item->charset()); + it->int_value= val_item->val_int_result(); + String *s= val_item->str_result(&it->string_value); + if (s != &it->string_value) + { + it->string_value.set(*s, 0, s->length()); + } + // TODO: remove when correct charset handling appeared for Item + it->str_value.set(*s, 0, s->length()); // store charset + + it->res_type= val_item->result_type(); + } + it->assigned(1); + DBUG_RETURN(0); +} + +bool select_exists_subselect::send_data(List<Item> &items) +{ + DBUG_ENTER("select_exists_subselect::send_data"); + Item_exists_subselect *it= (Item_exists_subselect *)item; + if (unit->offset_limit_cnt) + { // Using limit offset,count + unit->offset_limit_cnt--; + DBUG_RETURN(0); + } + it->value= 1; + it->assigned(1); + DBUG_RETURN(0); +} + + +/*************************************************************************** +** Dump of select to variables +***************************************************************************/ +int select_dumpvar::prepare(List<Item> &list, SELECT_LEX_UNIT *u) +{ + List_iterator_fast<Item> li(list); + List_iterator_fast<LEX_STRING> gl(var_list); + Item *item; + LEX_STRING *ls; + if (var_list.elements != list.elements) + { + my_error(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT, MYF(0)); + return 1; + } + while ((item=li++)) + { + ls= gl++; + Item_func_set_user_var *xx = new Item_func_set_user_var(*ls,item); + xx->fix_fields(current_thd,(TABLE_LIST*) current_thd->lex.select_lex.table_list.first,&item); + xx->fix_length_and_dec(); + vars.push_back(xx); + } + return 0; +} +bool select_dumpvar::send_data(List<Item> &items) +{ + List_iterator_fast<Item_func_set_user_var> li(vars); + Item_func_set_user_var *xx; + DBUG_ENTER("send_data"); + + if (row_count++) + { + my_error(ER_TOO_MANY_ROWS, MYF(0)); + DBUG_RETURN(1); + } + while ((xx=li++)) + xx->update(); + DBUG_RETURN(0); +} + +bool select_dumpvar::send_eof() +{ + if (row_count) + { + ::send_ok(thd,row_count); + return 0; + } + else + { + my_error(ER_EMPTY_QUERY,MYF(0)); + return 1; + } +} diff --git a/sql/sql_class.h b/sql/sql_class.h index dba2ad130bf..acdf2471ba8 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -73,14 +73,14 @@ class MYSQL_LOG { // current file sequence number for load data infile binary logging uint file_id; uint open_count; // For replication + volatile enum_log_type log_type; + enum cache_type io_cache_type; + bool write_error,inited; /* For binlog - if log name can never change we should not try to rotate it or write any rotation events. The user should use FLUSH MASTER instead of FLUSH LOGS for purging. */ - volatile enum_log_type log_type; - enum cache_type io_cache_type; - bool write_error,inited; bool no_rotate; bool need_start_event; bool no_auto_events; // for relay binlog @@ -220,19 +220,40 @@ public: class Key :public Sql_alloc { public: - enum Keytype { PRIMARY, UNIQUE, MULTIPLE, FULLTEXT }; + enum Keytype { PRIMARY, UNIQUE, MULTIPLE, FULLTEXT, SPATIAL, FOREIGN_KEY}; enum Keytype type; enum ha_key_alg algorithm; List<key_part_spec> columns; - const char *Name; + 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, const char *name_arg, enum ha_key_alg alg_par, + List<key_part_spec> &cols) + :type(type_par), algorithm(alg_par), columns(cols), name(name_arg) {} ~Key() {} - const char *name() { return Name; } }; +class Table_ident; + +class foreign_key: public Key { +public: + enum fk_match_opt { FK_MATCH_UNDEF, FK_MATCH_FULL, + FK_MATCH_PARTIAL, FK_MATCH_SIMPLE}; + enum fk_option { FK_OPTION_UNDEF, FK_OPTION_RESTRICT, FK_OPTION_CASCADE, + FK_OPTION_SET_NULL, FK_OPTION_NO_ACTION, FK_OPTION_DEFAULT}; + + Table_ident *ref_table; + List<key_part_spec> ref_columns; + uint delete_opt, update_opt, match_opt; + foreign_key(const char *name_arg, List<key_part_spec> &cols, + Table_ident *table, List<key_part_spec> &ref_cols, + uint delete_opt_arg, uint update_opt_arg, uint match_opt_arg) + :Key(FOREIGN_KEY, name_arg, HA_KEY_ALG_UNDEF, cols), + ref_table(table), ref_columns(cols), + delete_opt(delete_opt_arg), update_opt(update_opt_arg), + match_opt(match_opt_arg) + {} +}; typedef struct st_mysql_lock { @@ -252,8 +273,8 @@ public: #include "sql_lex.h" /* Must be here */ -// needed to be able to have an I_List of char* strings.in mysqld.cc where we cannot use String -// because it is Sql_alloc'ed +/* Needed to be able to have an I_List of char* strings in mysqld.cc. */ + class i_string: public ilink { public: @@ -262,7 +283,7 @@ public: i_string(char* s) : ptr(s) {} }; -//needed for linked list of two strings for replicate-rewrite-db +/* needed for linked list of two strings for replicate-rewrite-db */ class i_string_pair: public ilink { public: @@ -273,7 +294,43 @@ public: }; +class MYSQL_ERROR: public Sql_alloc +{ +public: + enum enum_warning_level + { WARN_LEVEL_NOTE, WARN_LEVEL_WARN, WARN_LEVEL_ERROR, WARN_LEVEL_END}; + + uint code; + enum_warning_level level; + char *msg; + + MYSQL_ERROR(uint code_arg, enum_warning_level level_arg, + const char *msg_arg) + :code(code_arg), level(level_arg) + { + msg=sql_strdup(msg_arg); + } +}; + + +/* This is a struct as it's allocated in tree_insert */ + +typedef struct st_prep_stmt +{ + THD *thd; + Item_param *param; + Item *free_list; + MEM_ROOT mem_root; + ulong stmt_id; + uint param_count; + uint last_errno; + char last_error[MYSQL_ERRMSG_SIZE]; + bool error_in_prepare, long_data_used; +} PREP_STMT; + + class delayed_insert; +class select_result; #define THD_SENTRY_MAGIC 0xfeedd1ff #define THD_SENTRY_GONE 0xdeadbeef @@ -284,29 +341,31 @@ struct system_variables { ulonglong myisam_max_extra_sort_file_size; ulonglong myisam_max_sort_file_size; + ulonglong select_limit; + ulonglong max_join_size; ulong bulk_insert_buff_size; ulong join_buff_size; ulong long_query_time; ulong max_allowed_packet; + ulong max_error_count; ulong max_heap_table_size; + ulong max_prep_stmt_count; ulong max_sort_length; - ulong max_join_size; ulong max_tmp_tables; ulong myisam_sort_buff_size; ulong net_buffer_length; ulong net_interactive_timeout; ulong net_read_timeout; + ulong net_retry_count; ulong net_wait_timeout; ulong net_write_timeout; - ulong net_retry_count; ulong query_cache_type; ulong read_buff_size; ulong read_rnd_buff_size; - ulong select_limit; ulong sortbuff_size; + ulong table_type; ulong tmp_table_size; ulong tx_isolation; - ulong table_type; my_bool log_warnings; my_bool low_priority_updates; @@ -325,7 +384,10 @@ public: NET net; // client connection descriptor LEX lex; // parse tree descriptor MEM_ROOT mem_root; // 1 command-life memory pool + MEM_ROOT con_root; // connection-life memory + MEM_ROOT warn_root; // For warnings and errors HASH user_vars; // hash for user variables + TREE prepared_statements; String packet; // dynamic buffer for network I/O struct sockaddr_in remote; // client socket address struct rand_struct rand; // used for authentication @@ -343,8 +405,7 @@ public: host - host of the client user - user of the client, set to NULL until the user has been read from the connection - priv_user - not sure why we have it, but it is set to "boot" when we run - with --bootstrap + priv_user - The user privilege we are using. May be '' for anonymous user. db - currently selected database ip - client IP */ @@ -362,7 +423,6 @@ public: ulong master_access; /* Global privileges from mysql.user */ ulong db_access; /* Privileges for current db */ - /* open_tables - list of regular tables in use by this thread temporary_tables - list of temp tables in use by this thread @@ -371,8 +431,10 @@ public: */ TABLE *open_tables,*temporary_tables, *handler_tables; // TODO: document the variables below - MYSQL_LOCK *lock,*locked_tables; - ULL *ull; + MYSQL_LOCK *lock; /* Current locks */ + MYSQL_LOCK *locked_tables; /* Tables locked with LOCK */ + ULL *ull; + PREP_STMT *last_prepared_stmt; #ifndef DBUG_OFF uint dbug_sentry; // watch out for memory corruption #endif @@ -418,7 +480,14 @@ public: sent_row_count, examined_row_count; table_map used_tables; USER_CONN *user_connect; - ulong query_id,version, options,thread_id, col_access; + CHARSET_INFO *db_charset; + CHARSET_INFO *thd_charset; + List<Item> *possible_loops; // Items that may cause loops in subselects + List <MYSQL_ERROR> warn_list; + uint warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_END]; + uint total_warn_count, old_total_warn_count; + ulong query_id, warn_id, version, options, thread_id, col_access; + ulong current_stmt_id; ulong rand_saved_seed1, rand_saved_seed2; long dbug_thread_id; pthread_t real_id; @@ -426,6 +495,8 @@ public: uint server_status,open_options; uint32 query_length; uint32 db_length; + uint select_number; //number of select (used for EXPLAIN) + uint check_loops_counter; //last id used to check loops /* variables.transaction_isolation is reset to this after each commit */ enum_tx_isolation session_tx_isolation; char scramble[9]; @@ -438,6 +509,9 @@ public: bool query_error, bootstrap, cleanup_done; bool safe_to_cache_query; bool volatile killed; + bool prepare_command; + Item_param *params; // Pointer to array of params + /* If we do a purge of binary logs, log index info of the threads that are currently reading it needs to be adjusted. To do that @@ -451,7 +525,6 @@ public: ulong slave_proxy_id; NET* slave_net; // network connection from slave -> m. my_off_t log_pos; - /* Used by the sys_var class to store temporary values */ union { @@ -555,6 +628,14 @@ public: void add_changed_table(TABLE *table); void add_changed_table(const char *key, long key_length); CHANGED_TABLE_LIST * changed_table_dup(const char *key, long key_length); + int send_explain_fields(select_result *result); + inline void clear_error() + { + net.last_error[0]= 0; + net.last_errno= 0; + net.report_error= 0; + } + void add_possible_loop(Item *); }; /* @@ -576,26 +657,31 @@ public: #include "log_event.h" /* -** This is used to get result from a select + This is used to get result from a select */ class JOIN; -void send_error(NET *net,uint sql_errno=0, const char *err=0); +void send_error(THD *thd, uint sql_errno=0, const char *err=0); class select_result :public Sql_alloc { protected: THD *thd; + SELECT_LEX_UNIT *unit; public: select_result(); virtual ~select_result() {}; - virtual int prepare(List<Item> &list) { return 0; } + virtual int prepare(List<Item> &list, SELECT_LEX_UNIT *u) + { + unit= u; + return 0; + } virtual bool send_fields(List<Item> &list,uint flag)=0; virtual bool send_data(List<Item> &items)=0; virtual void initialize_tables (JOIN *join=0) {} virtual void send_error(uint errcode,const char *err) { - ::send_error(&thd->net,errcode,err); + my_message(errcode, err, MYF(0)); } virtual bool send_eof()=0; virtual void abort() {} @@ -622,7 +708,7 @@ class select_export :public select_result { public: select_export(sql_exchange *ex) :exchange(ex),file(-1),row_count(0L) {} ~select_export(); - int prepare(List<Item> &list); + int prepare(List<Item> &list, SELECT_LEX_UNIT *u); bool send_fields(List<Item> &list, uint flag) { return 0; } bool send_data(List<Item> &items); @@ -641,7 +727,7 @@ public: select_dump(sql_exchange *ex) :exchange(ex),file(-1),row_count(0L) { path[0]=0; } ~select_dump(); - int prepare(List<Item> &list); + int prepare(List<Item> &list, SELECT_LEX_UNIT *u); bool send_fields(List<Item> &list, uint flag) { return 0; } bool send_data(List<Item> &items); @@ -664,7 +750,7 @@ class select_insert :public select_result { info.handle_duplicates=duplic; } ~select_insert(); - int prepare(List<Item> &list); + int prepare(List<Item> &list, SELECT_LEX_UNIT *u); bool send_fields(List<Item> &list, uint flag) { return 0; } bool send_data(List<Item> &items); @@ -693,7 +779,7 @@ public: create_info(create_info_par), lock(0) {} - int prepare(List<Item> &list); + int prepare(List<Item> &list, SELECT_LEX_UNIT *u); bool send_data(List<Item> &values); bool send_eof(); void abort(); @@ -708,7 +794,7 @@ class select_union :public select_result { select_union(TABLE *table_par); ~select_union(); - int prepare(List<Item> &list); + int prepare(List<Item> &list, SELECT_LEX_UNIT *u); bool send_fields(List<Item> &list, uint flag) { return 0; } bool send_data(List<Item> &items); @@ -716,6 +802,36 @@ class select_union :public select_result { bool flush(); }; +/* Base subselect interface class */ +class select_subselect :public select_result +{ +protected: + Item_subselect *item; +public: + select_subselect(Item_subselect *item); + bool send_fields(List<Item> &list, uint flag) { return 0; }; + bool send_data(List<Item> &items)=0; + bool send_eof() { return 0; }; + + friend class Ttem_subselect; +}; + +/* Single value subselect interface class */ +class select_singleval_subselect :public select_subselect +{ +public: + select_singleval_subselect(Item_subselect *item):select_subselect(item){} + bool send_data(List<Item> &items); +}; + +/* EXISTS subselect interface class */ +class select_exists_subselect :public select_subselect +{ +public: + select_exists_subselect(Item_subselect *item):select_subselect(item){} + bool send_data(List<Item> &items); +}; + /* Structs used when sorting */ typedef struct st_sort_field { @@ -742,17 +858,28 @@ class Table_ident :public Sql_alloc { public: LEX_STRING db; LEX_STRING table; - inline Table_ident(LEX_STRING db_arg,LEX_STRING table_arg,bool force) - :table(table_arg) + SELECT_LEX_UNIT *sel; + inline Table_ident(LEX_STRING db_arg, LEX_STRING table_arg, bool force) + :table(table_arg), sel((SELECT_LEX_UNIT *)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_UNIT *)0) + { + db.str=0; + } + inline Table_ident(SELECT_LEX_UNIT *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); } + { + db.str= db_name; db.length= (uint) strlen(db_name); + } }; // this is needed for user_vars hash @@ -763,6 +890,7 @@ class user_var_entry char *value; ulong length, update_query_id; Item_result type; + CHARSET_INFO *var_charset; }; /* Class for unique (removing of duplicates) */ @@ -785,7 +913,7 @@ public: { if (tree.elements_in_tree > max_elements && flush()) return 1; - return !tree_insert(&tree,ptr,0); + return !tree_insert(&tree, ptr, 0, tree.custom_arg); } bool get(TABLE *table); @@ -810,7 +938,7 @@ public: public: multi_delete(THD *thd, TABLE_LIST *dt, uint num_of_tables); ~multi_delete(); - int prepare(List<Item> &list); + int prepare(List<Item> &list, SELECT_LEX_UNIT *u); bool send_fields(List<Item> &list, uint flag) { return 0; } bool send_data(List<Item> &items); @@ -822,7 +950,6 @@ public: class multi_update : public select_result { TABLE_LIST *update_tables, *table_being_updated; -// Unique **tempfiles; COPY_INFO *infos; TABLE **tmp_tables; THD *thd; @@ -838,7 +965,7 @@ public: enum enum_duplicates handle_duplicates, uint num); ~multi_update(); - int prepare(List<Item> &list); + int prepare(List<Item> &list, SELECT_LEX_UNIT *u); bool send_fields(List<Item> &list, uint flag) { return 0; } bool send_data(List<Item> &items); @@ -848,3 +975,15 @@ public: bool send_eof(); }; +class select_dumpvar :public select_result { + ha_rows row_count; +public: + List<LEX_STRING> var_list; + List<Item_func_set_user_var> vars; + select_dumpvar(void) { var_list.empty(); vars.empty(); row_count=0;} + ~select_dumpvar() {} + int prepare(List<Item> &list, SELECT_LEX_UNIT *u); + bool send_fields(List<Item> &list, uint flag) {return 0;} + bool send_data(List<Item> &items); + bool send_eof(); +}; diff --git a/sql/sql_db.cc b/sql/sql_db.cc index cde0c6cc31f..cefad6a0805 100644 --- a/sql/sql_db.cc +++ b/sql/sql_db.cc @@ -25,20 +25,139 @@ #include <direct.h> #endif +#define MY_DB_OPT_FILE "db.opt" + +const char *del_exts[]= {".frm", ".BAK", ".TMD",".opt", NullS}; +static TYPELIB deletable_extentions= +{array_elements(del_exts)-1,"del_exts", del_exts}; + +const char *known_exts[]= +{".ISM",".ISD",".ISM",".MRG",".MYI",".MYD",".db",NullS}; +static TYPELIB known_extentions= +{array_elements(known_exts)-1,"known_exts", known_exts}; + static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db, const char *path, uint level); -/* db-name is already validated when we come here */ +/* + Create database options file: + + DESCRIPTION + Currently database default charset is only stored there. + + RETURN VALUES + 0 ok + 1 Could not create file or write to it. Error sent through my_error() +*/ + +static bool write_db_opt(const char *path, HA_CREATE_INFO *create) +{ + register File file; + char buf[256]; // Should be enough for one option + bool error=1; + + if ((file=my_create(path, CREATE_MODE,O_RDWR | O_TRUNC,MYF(MY_WME))) >= 0) + { + ulong length; + length= my_sprintf(buf,(buf, "default-character-set=%s\n", + (create && create->table_charset) ? + create->table_charset->name : "DEFAULT")); + + /* Error is written by my_write */ + if (!my_write(file,(byte*) buf, length, MYF(MY_NABP+MY_WME))) + error=0; + my_close(file,MYF(0)); + } + return error; +} + + +/* + Load database options file + + load_db_opt() + path Path for option file + create Where to store the read options + + DESCRIPTION + For now, only default-character-set is read. + + RETURN VALUES + 0 File found + 1 No database file or could not open it + +*/ + +static bool load_db_opt(const char *path, HA_CREATE_INFO *create) +{ + File file; + char buf[256]; + DBUG_ENTER("load_db_opt"); + bool error=1; + uint nbytes; + + bzero((char*) create,sizeof(*create)); + if ((file=my_open(path, O_RDONLY | O_SHARE, MYF(0))) >= 0) + { + IO_CACHE cache; + init_io_cache(&cache, file, IO_SIZE, READ_CACHE, 0, 0, MYF(0)); + + while ((int) (nbytes= my_b_gets(&cache, (char*) buf, sizeof(buf))) > 0) + { + char *pos= buf+nbytes-1; + /* Remove end space and control characters */ + while (pos > buf && !my_isgraph(system_charset_info, pos[-1])) + pos--; + *pos=0; + if ((pos= strchr(buf, '='))) + { + if (!strncmp(buf,"default-character-set", (pos-buf))) + { + if (!(create->table_charset=get_charset_by_name(pos+1, MYF(0)))) + { + sql_print_error(ER(ER_UNKNOWN_CHARACTER_SET), + pos+1); + } + } + } + } + error=0; + end_io_cache(&cache); + my_close(file,MYF(0)); + } + DBUG_RETURN(error); +} + + +/* + Create a database + + SYNOPSIS + mysql_create_db() + thd Thread handler + db Name of database to create + Function assumes that this is already validated. + create_info Database create options (like character set) + silent Used by replication when internally creating a database. + In this case the entry should not be logged. + + RETURN VALUES + 0 ok + -1 Error + +*/ -int mysql_create_db(THD *thd, char *db, uint create_options, bool silent) +int mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info, + bool silent) { char path[FN_REFLEN+16]; MY_DIR *dirp; long result=1; int error = 0; + uint create_options = create_info ? create_info->options : 0; DBUG_ENTER("mysql_create_db"); - + VOID(pthread_mutex_lock(&LOCK_mysql_create_db)); // do not create database if another thread is holding read lock @@ -73,29 +192,49 @@ int mysql_create_db(THD *thd, char *db, uint create_options, bool silent) } } + unpack_dirname(path, path); + strcat(path,MY_DB_OPT_FILE); + if (write_db_opt(path, create_info)) + { + /* + Could not create options file. + Restore things to beginning. + */ + if (rmdir(path) >= 0) + { + error= -1; + goto exit; + } + /* + We come here when we managed to create the database, but not the option + file. In this case it's best to just continue as if nothing has + happened. (This is a very unlikely senario) + */ + } + if (!silent) { - if (!thd->query) + char *query; + uint query_length; + + if (!thd->query) // Only in replication { - /* The client used the old obsolete mysql_create_db() call */ - thd->query = path; - thd->query_length = (uint) (strxmov(path,"create database `", db, "`", - NullS) - path); + query= path; + query_length= (uint) (strxmov(path,"create database `", db, "`", NullS) - + path); } + else { - mysql_update_log.write(thd,thd->query, thd->query_length); - if (mysql_bin_log.is_open()) - { - Query_log_event qinfo(thd, thd->query, thd->query_length, 0); - mysql_bin_log.write(&qinfo); - } + query= thd->query; + query_length= thd->query_length; } - if (thd->query == path) + mysql_update_log.write(thd, query, query_length); + if (mysql_bin_log.is_open()) { - thd->query = 0; // just in case - thd->query_length = 0; + Query_log_event qinfo(thd, query, query_length, 0); + mysql_bin_log.write(&qinfo); } - send_ok(&thd->net, result); + send_ok(thd, result); } exit: @@ -105,14 +244,56 @@ exit2: DBUG_RETURN(error); } -const char *del_exts[]= {".frm", ".BAK", ".TMD", NullS}; -static TYPELIB deletable_extentions= -{array_elements(del_exts)-1,"del_exts", del_exts}; -const char *known_exts[]= -{".ISM",".ISD",".ISM",".MRG",".MYI",".MYD",".db",NullS}; -static TYPELIB known_extentions= -{array_elements(known_exts)-1,"known_exts", known_exts}; +/* db-name is already validated when we come here */ + +int mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info) +{ + char path[FN_REFLEN+16]; + long result=1; + int error = 0; + uint create_options = create_info ? create_info->options : 0; + DBUG_ENTER("mysql_alter_db"); + + VOID(pthread_mutex_lock(&LOCK_mysql_create_db)); + + // do not alter database if another thread is holding read lock + if (wait_if_global_read_lock(thd,0)) + { + error= -1; + goto exit2; + } + + /* Check directory */ + (void)sprintf(path,"%s/%s/%s", mysql_data_home, db, MY_DB_OPT_FILE); + fn_format(path, path, "", "", MYF(MY_UNPACK_FILENAME)); + if ((error=write_db_opt(path, create_info))) + goto exit; + + /* + Change options if current database is being altered + TODO: Delete this code + */ + if (thd->db && !strcmp(thd->db,db)) + { + thd->db_charset= create_info ? create_info->table_charset : NULL; + } + + mysql_update_log.write(thd,thd->query, thd->query_length); + if (mysql_bin_log.is_open()) + { + Query_log_event qinfo(thd, thd->query, thd->query_length); + mysql_bin_log.write(&qinfo); + } + send_ok(thd, result); + +exit: + start_waiting_global_read_lock(thd); +exit2: + VOID(pthread_mutex_unlock(&LOCK_mysql_create_db)); + DBUG_RETURN(error); +} + /* Drop all tables in a database. @@ -151,7 +332,7 @@ int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) my_error(ER_DB_DROP_EXISTS,MYF(0),db); } else if (!silent) - send_ok(&thd->net,0); + send_ok(thd,0); goto exit; } pthread_mutex_lock(&LOCK_open); @@ -165,24 +346,27 @@ int mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent) query_cache_invalidate1(db); if (!silent) { + const char *query; + ulong query_length; if (!thd->query) { - thd->query = path; - thd->query_length = (uint) (strxmov(path,"drop database ", db, NullS)- - path); + /* The client used the old obsolete mysql_drop_db() call */ + query= path; + query_length = (uint) (strxmov(path,"drop database `", db, "`", + NullS)- path); } - mysql_update_log.write(thd, thd->query, thd->query_length); - if (mysql_bin_log.is_open()) + else { - Query_log_event qinfo(thd, thd->query, thd->query_length, 0); - mysql_bin_log.write(&qinfo); + query=thd->query; + query_length=thd->query_length; } - if (thd->query == path) + mysql_update_log.write(thd, query, query_length); + if (mysql_bin_log.is_open()) { - thd->query = 0; // just in case - thd->query_length = 0; + Query_log_event qinfo(thd, query, query_length, 0); + mysql_bin_log.write(&qinfo); } - send_ok(&thd->net,(ulong) deleted); + send_ok(thd,(ulong) deleted); } error = 0; } @@ -221,7 +405,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]; @@ -246,7 +431,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 @@ -328,28 +514,47 @@ static long mysql_rm_known_files(THD *thd, MY_DIR *dirp, const char *db, } -bool mysql_change_db(THD *thd,const char *name) +/* + Change default database. + + SYNOPSIS + mysql_change_db() + thd Thread handler + name Databasename + + DESCRIPTION + Becasue the database name may have been given directly from the + communication packet (in case of 'connect' or 'COM_INIT_DB') + we have to do end space removal in this function. + + RETURN VALUES + 0 ok + 1 error +*/ + +bool mysql_change_db(THD *thd, const char *name) { int length, db_length; char *dbname=my_strdup((char*) name,MYF(MY_WME)); char path[FN_REFLEN]; ulong db_access; + HA_CREATE_INFO create; DBUG_ENTER("mysql_change_db"); if (!dbname || !(db_length=strip_sp(dbname))) { x_free(dbname); /* purecov: inspected */ - send_error(&thd->net,ER_NO_DB_ERROR); /* purecov: inspected */ + send_error(thd,ER_NO_DB_ERROR); /* purecov: inspected */ DBUG_RETURN(1); /* purecov: inspected */ } if ((db_length > NAME_LEN) || check_db_name(dbname)) { - net_printf(&thd->net,ER_WRONG_DB_NAME, dbname); + net_printf(thd,ER_WRONG_DB_NAME, dbname); x_free(dbname); DBUG_RETURN(1); } if (lower_case_table_names) - casedn_str(dbname); + my_casedn_str(system_charset_info, dbname); DBUG_PRINT("info",("Use database: %s", dbname)); if (test_all_bits(thd->master_access,DB_ACLS)) db_access=DB_ACLS; @@ -359,7 +564,7 @@ bool mysql_change_db(THD *thd,const char *name) thd->master_access); if (!(db_access & DB_ACLS) && (!grant_option || check_grant_db(thd,dbname))) { - net_printf(&thd->net,ER_DBACCESS_DENIED_ERROR, + net_printf(thd,ER_DBACCESS_DENIED_ERROR, thd->priv_user, thd->host_or_ip, dbname); @@ -377,16 +582,103 @@ bool mysql_change_db(THD *thd,const char *name) path[length-1]=0; // remove ending '\' if (access(path,F_OK)) { - net_printf(&thd->net,ER_BAD_DB_ERROR,dbname); + net_printf(thd,ER_BAD_DB_ERROR,dbname); my_free(dbname,MYF(0)); DBUG_RETURN(1); } - send_ok(&thd->net); + send_ok(thd); x_free(thd->db); - if (lower_case_table_names) - casedn_str(dbname); - thd->db=dbname; + thd->db=dbname; // THD::~THD will free this thd->db_length=db_length; thd->db_access=db_access; + + strmov(path+unpack_dirname(path,path), MY_DB_OPT_FILE); + load_db_opt(path, &create); + thd->db_charset=create.table_charset; + thd->thd_charset=thd->db_charset ? thd->db_charset : default_charset_info; + DBUG_RETURN(0); +} + + +int mysqld_show_create_db(THD *thd, const char *dbname, HA_CREATE_INFO *create_info) +{ + int length; + char path[FN_REFLEN], *to; + uint db_access; + bool found_libchar; + HA_CREATE_INFO create; + CONVERT *convert=thd->variables.convert_set; + uint create_options = create_info ? create_info->options : 0; + + DBUG_ENTER("mysql_show_create_db"); + + if (check_db_name(dbname)) + { + net_printf(thd,ER_WRONG_DB_NAME, dbname); + DBUG_RETURN(1); + } + + if (test_all_bits(thd->master_access,DB_ACLS)) + db_access=DB_ACLS; + else + db_access= (acl_get(thd->host,thd->ip,(char*) &thd->remote.sin_addr, + thd->priv_user,dbname) | + thd->master_access); + if (!(db_access & DB_ACLS) && (!grant_option || check_grant_db(thd,dbname))) + { + net_printf(thd,ER_DBACCESS_DENIED_ERROR, + thd->priv_user, + thd->host_or_ip, + dbname); + mysql_log.write(thd,COM_INIT_DB,ER(ER_DBACCESS_DENIED_ERROR), + thd->priv_user, + thd->host_or_ip, + dbname); + DBUG_RETURN(1); + } + + (void) sprintf(path,"%s/%s",mysql_data_home, dbname); + length=unpack_dirname(path,path); // Convert if not unix + found_libchar= 0; + if (length && path[length-1] == FN_LIBCHAR) + { + found_libchar= 1; + path[length-1]=0; // remove ending '\' + } + if (access(path,F_OK)) + { + net_printf(thd,ER_BAD_DB_ERROR,dbname); + DBUG_RETURN(1); + } + if (found_libchar) + path[length-1]= FN_LIBCHAR; + strmov(path+length, MY_DB_OPT_FILE); + load_db_opt(path, &create); + + List<Item> field_list; + field_list.push_back(new Item_empty_string("Database",NAME_LEN)); + field_list.push_back(new Item_empty_string("Create Database",1024)); + + if (send_fields(thd,field_list,1)) + DBUG_RETURN(1); + + String *packet = &thd->packet; + packet->length(0); + net_store_data(packet, convert, dbname); + to= strxmov(path, "CREATE DATABASE ", NullS); + if (create_options & HA_LEX_CREATE_IF_NOT_EXISTS) + to= strxmov(to,"/*!32312 IF NOT EXISTS*/ ", NullS); + to=strxmov(to,"`",dbname,"`", NullS); + + if (create.table_charset) + to= strxmov(to," /*!40100 DEFAULT CHARACTER SET ", + create.table_charset->name,"*/",NullS); + + net_store_data(packet, convert, path, (uint) (to-path)); + + if (my_net_write(&thd->net,(char*) packet->ptr(), packet->length())) + DBUG_RETURN(1); + + send_eof(thd); DBUG_RETURN(0); } diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 5f2d7e36a04..cc60ebfb58d 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -35,27 +35,30 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order, SQL_SELECT *select=0; READ_RECORD info; bool using_limit=limit != HA_POS_ERROR; - bool transactional_table, log_delayed, safe_update; + bool using_transactions, log_delayed, safe_update, const_cond; ha_rows deleted; DBUG_ENTER("mysql_delete"); - if (((safe_update=thd->options & OPTION_SAFE_UPDATES)) && !conds) - { - send_error(&thd->net,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE); - DBUG_RETURN(1); - } - if (!(table = open_ltable(thd, table_list, table_list->lock_type))) DBUG_RETURN(-1); table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK); thd->proc_info="init"; table->map=1; - if (setup_conds(thd,table_list,&conds) || setup_ftfuncs(thd)) + if (setup_conds(thd,table_list,&conds) || + setup_ftfuncs(&thd->lex.select_lex)) DBUG_RETURN(-1); + const_cond= (!conds || conds->const_item()); + safe_update=test(thd->options & OPTION_SAFE_UPDATES); + if (safe_update && const_cond) + { + send_error(thd,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE); + DBUG_RETURN(1); + } + /* Test if the user wants to delete all rows */ - if (!using_limit && (!conds || conds->const_item()) && - !(specialflag & (SPECIAL_NO_NEW_FUNC | SPECIAL_SAFE_MODE)) && !safe_update) + if (!using_limit && const_cond && + !(specialflag & (SPECIAL_NO_NEW_FUNC | SPECIAL_SAFE_MODE))) { deleted= table->file->records; if (!(error=table->file->delete_all_rows())) @@ -76,12 +79,10 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order, select=make_select(table,0,0,conds,&error); if (error) DBUG_RETURN(-1); - if ((select && select->check_quick(test(thd->options & OPTION_SAFE_UPDATES), - limit)) || - !limit) + if ((select && select->check_quick(safe_update, limit)) || !limit) { delete select; - send_ok(&thd->net,0L); + send_ok(thd,0L); DBUG_RETURN(0); // Nothing to delete } @@ -92,7 +93,7 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order, if (safe_update && !using_limit) { delete select; - send_error(&thd->net,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE); + send_error(thd,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE); DBUG_RETURN(1); } } @@ -115,8 +116,8 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order, MYF(MY_FAE | MY_ZEROFILL)); if (setup_order(thd, &tables, fields, all_fields, order) || !(sortorder=make_unireg_sortorder(order, &length)) || - (table->found_records = filesort(table, sortorder, length, - (SQL_SELECT *) 0, 0L, HA_POS_ERROR, + (table->found_records = filesort(thd, table, sortorder, length, + (SQL_SELECT *) 0, HA_POS_ERROR, &examined_rows)) == HA_POS_ERROR) { @@ -127,7 +128,7 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order, init_read_record(&info,thd,table,select,1,1); deleted=0L; - init_ftfuncs(thd,1); + init_ftfuncs(thd, &thd->lex.select_lex, 1); thd->proc_info="updating"; while (!(error=info.read_record(&info)) && !thd->killed) { @@ -197,10 +198,10 @@ cleanup: } delete select; if (error >= 0) // Fatal error - send_error(&thd->net,thd->killed ? ER_SERVER_SHUTDOWN: 0); + send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN: 0); else { - send_ok(&thd->net,deleted); + send_ok(thd,deleted); DBUG_PRINT("info",("%d records deleted",deleted)); } DBUG_RETURN(0); @@ -229,9 +230,10 @@ multi_delete::multi_delete(THD *thd_arg, TABLE_LIST *dt, int -multi_delete::prepare(List<Item> &values) +multi_delete::prepare(List<Item> &values, SELECT_LEX_UNIT *u) { DBUG_ENTER("multi_delete::prepare"); + unit= u; do_delete = true; thd->proc_info="deleting from main table"; @@ -294,7 +296,7 @@ multi_delete::initialize_tables(JOIN *join) table->file->ref_length, MEM_STRIP_BUF_SIZE); } - init_ftfuncs(thd,1); + init_ftfuncs(thd, thd->lex.current_select->select_lex(), 1); } @@ -364,7 +366,7 @@ void multi_delete::send_error(uint errcode,const char *err) DBUG_ENTER("multi_delete::send_error"); /* First send error what ever it is ... */ - ::send_error(&thd->net,errcode,err); + ::send_error(thd,errcode,err); /* If nothing deleted return */ if (!deleted) @@ -464,6 +466,7 @@ bool multi_delete::send_eof() /* reset used flags */ thd->proc_info="end"; + /* Write the SQL statement to the binlog if we deleted rows and we succeeded, or also in an error case when there @@ -486,9 +489,9 @@ bool multi_delete::send_eof() query_cache_invalidate3(thd, delete_tables, 1); } if (local_error) - ::send_error(&thd->net); + ::send_error(thd); else - ::send_ok(&thd->net,deleted); + ::send_ok(thd, deleted); return 0; } @@ -526,8 +529,9 @@ int mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok) table->file->info(HA_STATUS_AUTO | HA_STATUS_NO_LOCK); bzero((char*) &create_info,sizeof(create_info)); create_info.auto_increment_value= table->file->auto_increment_value; - db_type table_type=table->db_type; + create_info.table_charset=default_charset_info; + db_type table_type=table->db_type; strmov(path,table->path); *table_ptr= table->next; // Unlink table from list close_temporary(table,0); @@ -538,8 +542,8 @@ int mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok) table_list->real_name, 1)))) (void) rm_temporary_table(table_type, path); /* - Sasha: if we return here we will not have binloged the truncation and - we will not send_ok() to the client. + If we return here we will not have logged the truncation to the bin log + and we will not send_ok() to the client. */ goto end; } @@ -569,6 +573,8 @@ int mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok) } bzero((char*) &create_info,sizeof(create_info)); + create_info.table_charset=default_charset_info; + *fn_ext(path)=0; // Remove the .frm extension error= ha_create_table(path,&create_info,1) ? -1 : 0; query_cache_invalidate3(thd, table_list, 0); @@ -585,7 +591,7 @@ end: thd->tmp_table); mysql_bin_log.write(&qinfo); } - send_ok(&thd->net); // This should return record count + send_ok(thd); // This should return record count } VOID(pthread_mutex_lock(&LOCK_open)); unlock_table_name(thd, table_list); diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc new file mode 100644 index 00000000000..b3d2b1602d0 --- /dev/null +++ b/sql/sql_derived.cc @@ -0,0 +1,134 @@ +/* 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_UNIT *unit, TABLE_LIST *t) +{ + /* + TODO: make derived tables with union inside (now only 1 SELECT may be + procesed) + */ + SELECT_LEX *sl= unit->first_select(); + List<Item> item_list; + TABLE *table; + int res= 0; + 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_UNIT *)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 (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, item_list, + (ORDER*) 0, 0, 1, 0, + (sl->options | thd->options | + TMP_TABLE_ALL_COLUMNS), + unit))) + { + res=-1; + goto exit; + } + + if ((derived_result=new select_union(table))) + { + derived_result->tmp_table_param=&tmp_table_param; + unit->offset_limit_cnt= sl->offset_limit; + unit->select_limit_cnt= sl->select_limit+sl->offset_limit; + if (unit->select_limit_cnt < sl->select_limit) + unit->select_limit_cnt= HA_POS_ERROR; + if (unit->select_limit_cnt == HA_POS_ERROR) + sl->options&= ~OPTION_FOUND_ROWS; + + SELECT_LEX_NODE *save_current_select= lex->current_select; + lex->current_select= sl; + 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, unit, sl, 0); + lex->current_select= save_current_select; + + 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; + table->derived_select_number= sl->select_number; + table->tmp_table=TMP_TABLE; + if (!lex->describe) + sl->exclude(); + t->db=(char *)""; + t->derived=(SELECT_LEX *)0; // just in case ... + } + } + delete derived_result; + } + if (res) + free_tmp_table(thd,table); +exit: + close_thread_tables(thd); + } + DBUG_RETURN(res); +} diff --git a/sql/sql_do.cc b/sql/sql_do.cc index 70124c2d796..2eef088da5b 100644 --- a/sql/sql_do.cc +++ b/sql/sql_do.cc @@ -29,6 +29,6 @@ int mysql_do(THD *thd, List<Item> &values) DBUG_RETURN(-1); while ((value = li++)) value->val_int(); - send_ok(&thd->net); + send_ok(thd); DBUG_RETURN(0); } diff --git a/sql/sql_error.cc b/sql/sql_error.cc new file mode 100644 index 00000000000..0740dc428f0 --- /dev/null +++ b/sql/sql_error.cc @@ -0,0 +1,165 @@ +/* Copyright (C) 1995-2002 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 +*/ + +/********************************************************************** +This file contains the implementation of error and warnings related + + - Whenever an error or warning occurred, it pushes it to a warning list + that the user can retrieve with SHOW WARNINGS or SHOW ERRORS. + + - For each statement, we return the number of warnings generated from this + command. Note that this can be different from @@warning_count as + we reset the warning list only for questions that uses a table. + This is done to allow on to do: + INSERT ...; + SELECT @@warning_count; + SHOW WARNINGS; + (If we would reset after each command, we could not retrieve the number + of warnings) + + - When client requests the information using SHOW command, then + server processes from this list and returns back in the form of + resultset. + + Supported syntaxes: + + SHOW [COUNT(*)] ERRORS [LIMIT [offset,] rows] + SHOW [COUNT(*)] WARNINGS [LIMIT [offset,] rows] + SELECT @@warning_count, @@error_count; + +***********************************************************************/ + +#include "mysql_priv.h" + +/* + Reset all warnings for the thread + + SYNOPSIS + mysql_reset_errors() + thd Thread handle + + IMPLEMENTATION + Don't reset warnings if this has already been called for this query. + This may happen if one gets a warning during the parsing stage, + in which case push_warnings() has already called this function. +*/ + +void mysql_reset_errors(THD *thd) +{ + if (thd->query_id != thd->warn_id) + { + thd->warn_id= thd->query_id; + free_root(&thd->warn_root,MYF(0)); + bzero((char*) thd->warn_count, sizeof(thd->warn_count)); + thd->warn_list.empty(); + } +} + + +/* + Push the warning/error to error list if there is still room in the list + + SYNOPSIS + push_warning() + thd Thread handle + level Severity of warning (note, warning, error ...) + code Error number + msg Clear error message +*/ + +void push_warning(THD *thd, MYSQL_ERROR::enum_warning_level level, uint code, + const char *msg) +{ + if (thd->query_id != thd->warn_id) + mysql_reset_errors(thd); + + if (thd->warn_list.elements < thd->variables.max_error_count) + { + /* + The following code is here to change the allocation to not + use the thd->mem_root, which is freed after each query + */ + MEM_ROOT *old_root=my_pthread_getspecific_ptr(MEM_ROOT*,THR_MALLOC); + my_pthread_setspecific_ptr(THR_MALLOC, &thd->warn_root); + MYSQL_ERROR *err= new MYSQL_ERROR(code, level, msg); + if (err) + thd->warn_list.push_back(err); + my_pthread_setspecific_ptr(THR_MALLOC, old_root); + } + thd->warn_count[(uint) level]++; + thd->total_warn_count++; +} + + +/* + Send all notes, errors or warnings to the client in a result set + + SYNOPSIS + mysqld_show_warnings() + thd Thread handler + levels_to_show Bitmap for which levels to show + + DESCRIPTION + Takes into account the current LIMIT + + RETURN VALUES + 0 ok + 1 Error sending data to client +*/ + +static const char *warning_level_names[]= {"Note", "Warning", "Error", "?"}; + + +my_bool mysqld_show_warnings(THD *thd, ulong levels_to_show) +{ + List<Item> field_list; + DBUG_ENTER("mysqld_show_errors"); + + field_list.push_back(new Item_empty_string("Level", 7)); + field_list.push_back(new Item_int("Code",0,4)); + field_list.push_back(new Item_empty_string("Message",MYSQL_ERRMSG_SIZE)); + + if (send_fields(thd,field_list,1)) + DBUG_RETURN(1); + + MYSQL_ERROR *err; + SELECT_LEX *sel= &thd->lex.select_lex; + ha_rows offset= sel->offset_limit, limit= sel->select_limit; + + List_iterator_fast<MYSQL_ERROR> it(thd->warn_list); + while ((err= it++)) + { + /* Skip levels that the user is not interested in */ + if (!(levels_to_show & ((ulong) 1 << err->level))) + continue; + if (offset) + { + offset--; + continue; + } + thd->packet.length(0); + net_store_data(&thd->packet,warning_level_names[err->level]); + net_store_data(&thd->packet,(uint32) err->code); + net_store_data(&thd->packet,err->msg); + if (my_net_write(&thd->net,(char*)thd->packet.ptr(),thd->packet.length())) + DBUG_RETURN(1); + if (!--limit) + break; + } + send_eof(thd); + DBUG_RETURN(0); +} diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index ea02c46c0f4..c43869d9d55 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -62,7 +62,7 @@ int mysql_ha_open(THD *thd, TABLE_LIST *tables) return -1; } - send_ok(&thd->net); + send_ok(thd); return 0; } @@ -83,12 +83,12 @@ int mysql_ha_close(THD *thd, TABLE_LIST *tables, bool dont_send_ok) return -1; } if (!dont_send_ok) - send_ok(&thd->net); + send_ok(thd); return 0; } static enum enum_ha_read_modes rkey_to_rnext[]= - { RNEXT, RNEXT, RPREV, RNEXT, RPREV, RNEXT, RPREV }; + { RNEXT, RNEXT, RPREV, RNEXT, RPREV, RNEXT, RPREV, RPREV }; int mysql_ha_read(THD *thd, TABLE_LIST *tables, @@ -106,7 +106,7 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables, } tables->table=table; - if (cond && cond->fix_fields(thd,tables)) + if (cond && cond->fix_fields(thd, tables, &cond)) return -1; if (keyname) @@ -180,12 +180,12 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables, Item *item; for (key_len=0 ; (item=it_ke++) ; key_part++) { - item->save_in_field(key_part->field); + (void) item->save_in_field(key_part->field); key_len+=key_part->store_length; } if (!(key= (byte*) sql_calloc(ALIGN_SIZE(key_len)))) { - send_error(&thd->net,ER_OUTOFMEMORY); + send_error(thd,ER_OUTOFMEMORY); goto err; } key_copy(key, table, keyno, key_len); @@ -195,7 +195,7 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables, break; } default: - send_error(&thd->net,ER_ILLEGAL_HA); + send_error(thd,ER_ILLEGAL_HA); goto err; } @@ -240,7 +240,7 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables, } ok: mysql_unlock_tables(thd,lock); - send_eof(&thd->net); + send_eof(thd); return 0; err: mysql_unlock_tables(thd,lock); @@ -271,9 +271,9 @@ 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,alias)) + !my_strcasecmp(system_charset_info,table->table_name,alias)) break; - ptr=&(table->next); + ptr= &(table->next); } return ptr; } diff --git a/sql/sql_help.cc b/sql/sql_help.cc new file mode 100644 index 00000000000..d2bea9ba44b --- /dev/null +++ b/sql/sql_help.cc @@ -0,0 +1,408 @@ +/* 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 */ + +#include "mysql_priv.h" +#include "sql_select.h" // For select_describe +#include "sql_acl.h" + +/*************************************************************************** +** Get help on string +***************************************************************************/ + +MI_INFO *open_help_file(THD *thd, const char *name) +{ + char path[FN_REFLEN]; + (void) sprintf(path,"%s/mysql_help/%s",mysql_data_home,name); + MI_INFO *res= 0; + if (!(res= mi_open(path,O_RDONLY,HA_OPEN_WAIT_IF_LOCKED))) + { + send_error(thd,ER_CORRUPT_HELP_DB); + return 0; + } + mi_extra(res,HA_EXTRA_WAIT_LOCK,0); + return res; +} + +#define size_hf_func_id 4 /* func_id int unsigned, */ +#define size_hf_name 64 /* name varchar(64), */ +#define size_hf_url 128 /* url varchar(128), */ +#define size_hf_description sizeof(char*) /* description text, */ +#define size_hf_example sizeof(char*) /* example text, */ +#define size_hf_min_args 16 /* min_args tinyint, */ +#define size_hf_max_args 16 /* max_args tinyint, */ +#define size_hf_date_created 8 /* date_created datetime, */ +#define size_hf_last_modified 8 /* last_modified timestamp, */ + +#define offset_hf_func_id 1 +#define offset_hf_name (offset_hf_func_id+size_hf_func_id) +#define offset_hf_url (offset_hf_name+size_hf_name) +#define offset_hf_description (offset_hf_url+size_hf_url) +#define offset_hf_example (offset_hf_description+size_hf_description) +#define offset_hf_min_args (offset_hf_example+size_hf_example) +#define offset_hf_max_args (offset_hf_min_args+size_hf_min_args) +#define offset_hf_date_created (offset_hf_max_args+size_hf_max_args) +#define offset_hf_last_modified (offset_hf_date_created+size_hf_date_created) + +#define HELP_LEAF_SIZE (offset_hf_last_modified+size_hf_last_modified) + +class help_leaf{ +public: + char record[HELP_LEAF_SIZE]; + + inline const char *get_name() + { + return &record[offset_hf_name]; + } + + inline const char *get_description() + { + return *((char**)&record[199/*offset_hf_description*/]); + } + + inline const char *get_example() + { + return *((char**)&record[209/*offset_hf_example*/]); + } + + void prepare_fields() + { + const char *name= get_name(); + const char *c= name + size_hf_name - 1; + while (*c==' ') c--; + int len= c-name+1; + ((char*)name)[len]= '\0'; + } +}; + +int search_functions(MI_INFO *file_leafs, const char *mask, + List<String> *names, + String **name, String **description, String **example) +{ + DBUG_ENTER("search_functions"); + int count= 0; + + if(mi_scan_init(file_leafs)) + DBUG_RETURN(-1); + + help_leaf leaf; + + while (!mi_scan(file_leafs,(byte*)&leaf)) + { + leaf.prepare_fields(); + + const char *lname= leaf.get_name(); + if (wild_case_compare(system_charset_info,lname,mask)) + continue; + count++; + + if (count>2) + { + String *s= new String(lname,system_charset_info); + if (!s->copy()) + names->push_back(s); + } + else if (count==1) + { + *description= new String(leaf.get_description(),system_charset_info); + *example= new String(leaf.get_example(),system_charset_info); + *name= new String(lname,system_charset_info); + (*description)->copy(); + (*example)->copy(); + (*name)->copy(); + } + else + { + names->push_back(*name); + delete *description; + delete *example; + *name= 0; + *description= 0; + *example= 0; + + String *s= new String(lname,system_charset_info); + if (!s->copy()) + names->push_back(s); + } + } + + DBUG_RETURN(count); +} + +#define size_hc_cat_id 2 /* cat_id smallint, */ +#define size_hc_name 64 /* name varchar(64), */ +#define size_hc_url 128 /* url varchar(128), */ +#define size_hc_date_created 8 /* date_created datetime, */ +#define size_hc_last_modified 8 /* last_modified timestamp, */ + +#define offset_hc_cat_id 0 +#define offset_hc_name (offset_hc_cat_id+size_hc_cat_id) +#define offset_hc_url (offset_hc_name+size_hc_name) +#define offset_hc_date_created (offset_hc_url+size_hc_url) +#define offset_hc_last_modified (offset_hc_date_created+size_hc_date_created) + +#define HELP_CATEGORY_SIZE (offset_hc_last_modified+size_hc_last_modified) + +class help_category{ +public: + char record[HELP_CATEGORY_SIZE]; + + inline int16 get_cat_id() + { + return sint2korr(&record[offset_hc_cat_id]); + } + + inline const char *get_name() + { + return &record[offset_hc_name]; + } + + void prepare_fields() + { + const char *name= get_name(); + const char *c= name + size_hc_name - 1; + while (*c==' ') c--; + int len= c-name+1; + ((char*)name)[len]= '\0'; + } +}; + +int search_categories(THD *thd, + const char *mask, List<String> *names, int16 *res_id) +{ + DBUG_ENTER("search_categories"); + int count= 0; + + MI_INFO *file_categories= 0; + if (!(file_categories= open_help_file(thd,"function_category_name"))) + DBUG_RETURN(-1); + + if(mi_scan_init(file_categories)) + { + mi_close(file_categories); + DBUG_RETURN(-1); + } + + help_category category; + + + while (!mi_scan(file_categories,(byte*)&category)) + { + category.prepare_fields(); + + const char *lname= category.get_name(); + if (mask && wild_case_compare(system_charset_info,lname,mask)) + continue; + count++; + + if (count==1 && res_id) + *res_id= category.get_cat_id(); + + String *s= new String(lname,system_charset_info); + if (!s->copy()) + names->push_back(s); + } + + mi_close(file_categories); + DBUG_RETURN(count); +} + +int send_variant_2_list(THD *thd, List<String> *names, my_bool is_category) +{ + DBUG_ENTER("send_names"); + + List_iterator<String> it(*names); + String *cur_name; + String *packet= &thd->packet; + while ((cur_name = it++)) + { + packet->length(0); + net_store_data(packet, cur_name->ptr()); + net_store_data(packet, is_category ? "Y" : "N"); + if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length())) + DBUG_RETURN(-1); + } + + DBUG_RETURN(0); +} + +#define size_hcn_cat_id 2 /* cat_id smallint, */ +#define size_hcn_func_id 4 /* func_id int, */ + +#define offset_hcn_cat_id 1 +#define offset_hcn_func_id (offset_hcn_cat_id+size_hcn_cat_id) + +#define HELP_CATEGORY_NAME_SIZE (offset_hcn_func_id + size_hcn_func_id) + +class help_category_leaf{ +public: + char record[HELP_CATEGORY_NAME_SIZE]; + + inline int16 get_cat_id() + { + return sint2korr(&record[offset_hcn_cat_id]); + } + + inline int get_func_id() + { + return sint3korr(&record[offset_hcn_func_id]); + } +}; + +int get_all_names_for_category(THD *thd,MI_INFO *file_leafs, + int16 cat_id, List<String> *res) +{ + DBUG_ENTER("get_all_names_for_category"); + + MI_INFO *file_names_categories= 0; + if (!(file_names_categories= open_help_file(thd,"function_category"))) + DBUG_RETURN(1); + + help_category_leaf cat_leaf; + help_leaf leaf; + int key_res= mi_rkey(file_names_categories, (byte*)&cat_leaf, 0, + (const byte*)&cat_id,2,HA_READ_KEY_EXACT); + + while (!key_res && cat_leaf.get_cat_id()==cat_id) + { + int leaf_id= cat_leaf.get_func_id(); + + if (!mi_rkey(file_leafs, (byte*)&leaf, 0, + (const byte*)&leaf_id,4,HA_READ_KEY_EXACT)) + { + leaf.prepare_fields(); + String *s= new String(leaf.get_name(),system_charset_info); + if (!s->copy()) + res->push_back(s); + } + + key_res= mi_rnext(file_names_categories, (byte*)&cat_leaf, 0); + } + + mi_close(file_names_categories); + + DBUG_RETURN(0); +} + +int send_answer_1(THD *thd, const char *s1, const char *s2, + const char *s3, const char *s4) +{ + DBUG_ENTER("send_answer_1"); + List<Item> field_list; + field_list.push_back(new Item_empty_string("name",64)); + field_list.push_back(new Item_empty_string("is_category",1)); + field_list.push_back(new Item_empty_string("description",1000)); + field_list.push_back(new Item_empty_string("example",1000)); + + if (send_fields(thd,field_list,1)) + DBUG_RETURN(1); + + String *packet= &thd->packet; + packet->length(0); + net_store_data(packet, s1); + net_store_data(packet, s2); + net_store_data(packet, s3); + net_store_data(packet, s4); + + if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length())) + DBUG_RETURN(-1); + + DBUG_RETURN(0); +} + +int send_header_2(THD *thd) +{ + DBUG_ENTER("send_header2"); + List<Item> field_list; + field_list.push_back(new Item_empty_string("name",64)); + field_list.push_back(new Item_empty_string("is_category",1)); + DBUG_RETURN(send_fields(thd,field_list,1)); +} + +int mysqld_help (THD *thd, const char *mask) +{ + DBUG_ENTER("mysqld_help"); + + MI_INFO *file_leafs= 0; + if (!(file_leafs= open_help_file(thd,"function"))) + DBUG_RETURN(1); + + List<String> function_list, categories_list; + String *name, *description, *example; + int res; + + int count= search_functions(file_leafs, mask, + &function_list,&name,&description,&example); + if (count<0) + { + res= 1; + goto end; + } + else if (count==0) + { + int16 category_id; + count= search_categories(thd, mask, &categories_list, &category_id); + if (count<0) + { + res= 1; + goto end; + } + else if (count==1) + { + if ((res= get_all_names_for_category(thd, file_leafs, + category_id,&function_list))) + goto end; + List_iterator<String> it(function_list); + String *cur_leaf, example; + while ((cur_leaf = it++)) + { + example.append(*cur_leaf); + example.append("\n",1); + } + if ((res= send_answer_1(thd, categories_list.head()->ptr(), + "Y","",example.ptr()))) + goto end; + } + else + { + if ((res= send_header_2(thd)) || + (count==0 && + (search_categories(thd, 0, &categories_list, 0)<0 && + (res= 1))) || + (res= send_variant_2_list(thd,&categories_list,true))) + goto end; + } + } + else if (count==1) + { + if ((res= send_answer_1(thd,name->ptr(),"N", + description->ptr(), example->ptr()))) + goto end; + } + else if((res= send_header_2(thd)) || + (res= send_variant_2_list(thd,&function_list,false)) || + (search_categories(thd, mask, &categories_list, 0)<0 && + (res=1)) || + (res= send_variant_2_list(thd,&categories_list,true))) + { + goto end; + } + + send_eof(thd); + +end: + mi_close(file_leafs); + DBUG_RETURN(res); +} diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 2508314c469..6cb146afb33 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -44,7 +44,7 @@ static void unlink_blobs(register TABLE *table); Resets form->time_stamp if a timestamp value is set */ -static int +int check_insert_fields(THD *thd,TABLE *table,List<Item> &fields, List<Item> &values, ulong counter) { @@ -347,7 +347,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields, if (values_list.elements == 1 && (!(thd->options & OPTION_WARNINGS) || !thd->cuted_fields)) - send_ok(&thd->net,info.copied+info.deleted,id); + send_ok(thd,info.copied+info.deleted,id); else { char buff[160]; @@ -359,7 +359,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields, else sprintf(buff,ER(ER_INSERT_INFO),info.records,info.deleted, thd->cuted_fields); - ::send_ok(&thd->net,info.copied+info.deleted,(ulonglong)id,buff); + ::send_ok(thd,info.copied+info.deleted,(ulonglong)id,buff); } DBUG_RETURN(0); @@ -681,7 +681,7 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list) delete tmp; thd->fatal_error=1; pthread_mutex_unlock(&LOCK_delayed_create); - net_printf(&thd->net,ER_CANT_CREATE_THREAD,error); + net_printf(thd,ER_CANT_CREATE_THREAD,error); DBUG_RETURN(0); } @@ -1192,7 +1192,7 @@ bool delayed_insert::handle_inserts(void) table->file->extra(HA_EXTRA_IGNORE_DUP_KEY); using_ignore=1; } - thd.net.last_errno = 0; // reset error for binlog + thd.clear_error(); // reset error for binlog if (write_record(table,&info)) { info.error_count++; // Ignore errors @@ -1286,10 +1286,11 @@ bool delayed_insert::handle_inserts(void) ***************************************************************************/ int -select_insert::prepare(List<Item> &values) +select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u) { DBUG_ENTER("select_insert::prepare"); + unit= u; save_time_stamp=table->time_stamp; if (check_insert_fields(thd,table,*fields,values,1)) DBUG_RETURN(1); @@ -1322,9 +1323,9 @@ select_insert::~select_insert() bool select_insert::send_data(List<Item> &values) { - if (thd->offset_limit) + if (unit->offset_limit_cnt) { // using limit offset,count - thd->offset_limit--; + unit->offset_limit_cnt--; return 0; } if (fields->elements) @@ -1345,7 +1346,8 @@ bool select_insert::send_data(List<Item> &values) void select_insert::send_error(uint errcode,const char *err) { - ::send_error(&thd->net,errcode,err); + //TODO error should be sent at the query processing end + ::send_error(thd,errcode,err); table->file->extra(HA_EXTRA_NO_CACHE); table->file->activate_all_index(thd); ha_rollback_stmt(thd); @@ -1371,7 +1373,8 @@ bool select_insert::send_eof() if (error) { table->file->print_error(error,MYF(0)); - ::send_error(&thd->net); + //TODO error should be sent at the query processing end + ::send_error(thd); return 1; } else @@ -1385,7 +1388,7 @@ bool select_insert::send_eof() thd->cuted_fields); if (last_insert_id) thd->insert_id(last_insert_id); // For update log - ::send_ok(&thd->net,info.copied,last_insert_id,buff); + ::send_ok(thd,info.copied,last_insert_id,buff); mysql_update_log.write(thd,thd->query,thd->query_length); if (mysql_bin_log.is_open()) { @@ -1403,10 +1406,11 @@ bool select_insert::send_eof() ***************************************************************************/ int -select_create::prepare(List<Item> &values) +select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u) { DBUG_ENTER("select_create::prepare"); + unit= u; table=create_table_from_items(thd, create_info, db, name, extra_fields, keys, &values, &lock); if (!table) @@ -1436,9 +1440,9 @@ select_create::prepare(List<Item> &values) bool select_create::send_data(List<Item> &values) { - if (thd->offset_limit) + if (unit->offset_limit_cnt) { // using limit offset,count - thd->offset_limit--; + unit->offset_limit_cnt--; return 0; } fill_record(field,values); diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 854f3924155..975c3cfcf2b 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -21,6 +21,7 @@ #include "item_create.h" #include <m_ctype.h> #include <hash.h> +#include <assert.h> LEX_STRING tmp_table_alias= {(char*) "tmp-table",8}; @@ -92,15 +93,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; @@ -142,12 +143,13 @@ LEX *lex_start(THD *thd, uchar *buf,uint length) lex->next_state=STATE_START; lex->end_of_query=(lex->ptr=buf)+length; lex->yylineno = 1; - lex->select->create_refs=lex->in_comment=0; + lex->select_lex.create_refs=lex->in_comment=0; lex->length=0; - lex->select->in_sum_expr=0; - lex->select->expr_list.empty(); - lex->select->ftfunc_list.empty(); - lex->convert_set=(lex->thd=thd)->variables.convert_set; + lex->select_lex.in_sum_expr=0; + lex->select_lex.expr_list.empty(); + lex->select_lex.ftfunc_list_alloc.empty(); + lex->select_lex.ftfunc_list= &lex->select_lex.ftfunc_list_alloc; + lex->convert_set= (lex->thd= thd)->variables.convert_set; lex->yacc_yyss=lex->yacc_yyvs=0; lex->ignore_space=test(thd->sql_mode & MODE_IGNORE_SPACE); lex->slave_thd_opt=0; @@ -158,7 +160,7 @@ LEX *lex_start(THD *thd, uchar *buf,uint length) void lex_end(LEX *lex) { - lex->select->expr_list.delete_elements(); // If error when parsing sql-varargs + lex->select_lex.expr_list.delete_elements(); // If error when parsing sql-varargs x_free(lex->yacc_yyss); x_free(lex->yacc_yyvs); } @@ -222,8 +224,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 +269,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 +475,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 +491,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; @@ -525,7 +527,19 @@ int yylex(void *arg) yylval->lex_str=get_token(lex,length); if (lex->convert_set) lex->convert_set->convert((char*) yylval->lex_str.str,lex->yytoklen); - return(IDENT); + + /* + Note: "SELECT _bla AS 'alias'" + _bla should be considered as a IDENT if charset haven't been found. + So we don't use MYF(MY_WME) with get_charset_by_name to avoid + producing an error. + */ + + if ((yylval->lex_str.str[0]=='_') && + (lex->charset=get_charset_by_name(yylval->lex_str.str+1,MYF(0)))) + return(UNDERSCORE_CHARSET); + else + return(IDENT); case STATE_IDENT_SEP: // Found ident and now '.' lex->next_state=STATE_IDENT_START;// Next is an ident (not a keyword) @@ -535,7 +549,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 +558,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 +574,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 +588,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 +605,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 +635,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 +668,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 +687,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 +703,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 +724,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 +804,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); } @@ -839,11 +855,10 @@ int yylex(void *arg) case STATE_END: lex->next_state=STATE_END; return(0); // We found end of input last time - - // Actually real shouldn't start - // with . but allow them anyhow + + /* 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 { @@ -868,7 +883,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); @@ -902,3 +917,370 @@ int yylex(void *arg) } } } + +/* + st_select_lex structures initialisations +*/ + +void st_select_lex_node::init_query() +{ + next= master= slave= link_next= 0; + prev= link_prev= 0; +} + +void st_select_lex_node::init_select() +{ + order_list.elements= 0; + order_list.first= 0; + order_list.next= (byte**) &order_list.first; + select_limit= HA_POS_ERROR; + offset_limit= 0; + create_refs= dependent= 0; +} + +void st_select_lex_unit::init_query() +{ + linkage= GLOBAL_OPTIONS_TYPE; + st_select_lex_node::init_query(); + global_parameters= this; + select_limit_cnt= HA_POS_ERROR; + offset_limit_cnt= 0; + union_option= 0; + prepared= optimized= executed= 0; + item= 0; +} + +void st_select_lex::init_query() +{ + st_select_lex_node::init_query(); + table_list.elements= 0; + table_list.first= 0; + table_list.next= (byte**) &table_list.first; + item_list.empty(); + join= 0; + olap= UNSPECIFIED_OLAP_TYPE; +} + +void st_select_lex::init_select() +{ + st_select_lex_node::init_select(); + group_list.elements= 0; + group_list.first= 0; + group_list.next= (byte**) &group_list.first; + options= 0; + where= having= 0; + when_list.empty(); + expr_list.empty(); + interval_list.empty(); + use_index.empty(); + ftfunc_list_alloc.empty(); + ftfunc_list= &ftfunc_list_alloc; + linkage= UNSPECIFIED_TYPE; + having_fix_field= 0; +} + +/* + st_select_lex structures linking +*/ + +/* include on level down */ +void st_select_lex_node::include_down(st_select_lex_node *upper) +{ + if ((next= upper->slave)) + next->prev= &next; + prev= &upper->slave; + upper->slave= this; + master= upper; +} + +/* include neighbour (on same level) */ +void st_select_lex_node::include_neighbour(st_select_lex_node *before) +{ + if ((next= before->next)) + next->prev= &next; + prev= &before->next; + before->next= this; + master= before->master; +} + +/* including in global SELECT_LEX list */ +void st_select_lex_node::include_global(st_select_lex_node **plink) +{ + if ((link_next= *plink)) + link_next->link_prev= &link_next; + link_prev= plink; + *plink= this; +} + +//excluding from global list (internal function) +void st_select_lex_node::fast_exclude() +{ + if(link_prev) + { + if ((*link_prev= link_next)) + link_next->link_prev= link_prev; + // Remove slave structure + for (; slave; slave= slave->next) + slave->fast_exclude(); + } +} + +/* + excluding select_lex structure (except first (first select can't be + deleted, because it is most upper select)) +*/ +void st_select_lex_node::exclude() +{ + //exclude from global list + fast_exclude(); + //exclude from other structures + if ((*prev= next)) + next->prev= prev; + /* + We do not need following statements, because prev pointer of first + list element point to master->slave + if (master->slave == this) + master->slave= next; + */ +} + +st_select_lex* st_select_lex_node::select_lex() +{ + DBUG_ENTER("st_select_lex_node::select_lex (never should be called)"); + DBUG_ASSERT(0); + DBUG_RETURN(0); +} + +bool st_select_lex_node::add_item_to_list(Item *item) +{ + return 1; +} + +bool st_select_lex_node::add_group_to_list(Item *item, bool asc) +{ + return 1; +} + +bool st_select_lex_node::add_order_to_list(Item *item, bool asc) +{ + return add_to_list(order_list,item,asc); +} + +bool st_select_lex_node::add_ftfunc_to_list(Item_func_match *func) +{ + return 1; +} + +/* + st_select_lex_node::mark_as_dependent mark all st_select_lex struct from + this to 'last' as dependent + + SYNOPSIS + last - pointer to last st_select_lex struct, before wich all + st_select_lex have to be marked as dependent + + NOTE + 'last' should be reachable from this st_select_lex_node + +*/ + +void st_select_lex_node::mark_as_dependent(SELECT_LEX *last) +{ + /* + Mark all selects from resolved to 1 before select where was + found table as depended (of select where was found table) + */ + for (SELECT_LEX_NODE *s= this; + s &&s != last; + s= s->outer_select()) + if( !s->dependent ) + { + // Select is dependent of outer select + s->dependent= 1; + if (s->linkage != GLOBAL_OPTIONS_TYPE) + { + //s is st_select_lex* + + s->master_unit()->dependent= 1; + //Tables will be reopened many times + for (TABLE_LIST *tbl= + s->get_table_list(); + tbl; + tbl= tbl->next) + tbl->shared= 1; + } + } +} + +bool st_select_lex_node::set_braces(bool value) { return 1; } +bool st_select_lex_node::inc_in_sum_expr() { return 1; } +uint st_select_lex_node::get_in_sum_expr() { return 0; } +TABLE_LIST* st_select_lex_node::get_table_list() { return 0; } +List<Item>* st_select_lex_node::get_item_list() { return 0; } +List<String>* st_select_lex_node::get_use_index() { return 0; } +List<String>* st_select_lex_node::get_ignore_index() { return 0; } +TABLE_LIST *st_select_lex_node::add_table_to_list(Table_ident *table, + LEX_STRING *alias, + bool updating, + thr_lock_type flags, + List<String> *use_index, + List<String> *ignore_index) +{ + return 0; +} + +/* + This is used for UNION & subselect to create a new table list of all used + tables. + The table_list->table entry in all used tables are set to point + to the entries in this list. +*/ + +// interface +bool st_select_lex_unit::create_total_list(THD *thd, st_lex *lex, + TABLE_LIST **result) +{ + *result= 0; + return create_total_list_n_last_return(thd, lex, &result); +} + +// list creator +bool st_select_lex_unit::create_total_list_n_last_return(THD *thd, st_lex *lex, + TABLE_LIST ***result) +{ + TABLE_LIST *slave_list_first=0, **slave_list_last= &slave_list_first; + TABLE_LIST **new_table_list= *result, *aux; + SELECT_LEX *sl= (SELECT_LEX*)slave; + for (; sl; sl= sl->next_select()) + { + // check usage of ORDER BY in union + if (sl->order_list.first && sl->next_select() && !sl->braces) + { + net_printf(thd,ER_WRONG_USAGE,"UNION","ORDER BY"); + return 1; + } + for (SELECT_LEX_UNIT *inner= sl->first_inner_unit(); + inner; + inner= inner->next_unit()) + if (inner->create_total_list_n_last_return(thd, lex, + &slave_list_last)) + return 1; + if ((aux= (TABLE_LIST*) sl->table_list.first)) + { + TABLE_LIST *next; + for (; aux; aux= next) + { + TABLE_LIST *cursor; + next= aux->next; + for (cursor= **result; cursor; cursor= cursor->next) + if (!strcmp(cursor->db, aux->db) && + !strcmp(cursor->real_name, aux->real_name) && + !strcmp(cursor->alias, aux->alias)) + break; + if (!cursor) + { + /* Add not used table to the total table list */ + aux->lock_type= lex->lock_option; + if (!(cursor= (TABLE_LIST *) thd->memdup((char*) aux, + sizeof(*aux)))) + { + send_error(thd,0); + return 1; + } + *new_table_list= cursor; + new_table_list= &cursor->next; + *new_table_list= 0; // end result list + } + else + aux->shared= 1; // Mark that it's used twice + aux->table_list= cursor; + } + } + } + if (slave_list_first) + { + *new_table_list= slave_list_first; + new_table_list= slave_list_last; + } + *result= new_table_list; + return 0; +} + +st_select_lex_unit* st_select_lex_unit::master_unit() +{ + return this; +} + +st_select_lex* st_select_lex_unit::outer_select() +{ + return (st_select_lex*) master; +} + +st_select_lex* st_select_lex::select_lex() +{ + return this; +} + +bool st_select_lex::add_item_to_list(Item *item) +{ + return item_list.push_back(item); +} + +bool st_select_lex::add_group_to_list(Item *item, bool asc) +{ + return add_to_list(group_list, item, asc); +} + +bool st_select_lex::add_ftfunc_to_list(Item_func_match *func) +{ + return !func || ftfunc_list->push_back(func); // end of memory? +} + +st_select_lex_unit* st_select_lex::master_unit() +{ + return (st_select_lex_unit*) master; +} + +st_select_lex* st_select_lex::outer_select() +{ + return (st_select_lex*) master->get_master(); +} + +bool st_select_lex::set_braces(bool value) +{ + braces= value; + return 0; +} + +bool st_select_lex::inc_in_sum_expr() +{ + in_sum_expr++; + return 0; +} + +uint st_select_lex::get_in_sum_expr() +{ + return in_sum_expr; +} + +TABLE_LIST* st_select_lex::get_table_list() +{ + return (TABLE_LIST*) table_list.first; +} + +List<Item>* st_select_lex::get_item_list() +{ + return &item_list; +} + +List<String>* st_select_lex::get_use_index() +{ + return use_index_ptr; +} + +List<String>* st_select_lex::get_ignore_index() +{ + return ignore_index_ptr; +} + +// There are st_select_lex::add_table_to_list in sql_parse.cc diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 54e72fafdd5..9f8e3200246 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -46,10 +46,12 @@ enum enum_sql_command { SQLCOM_SHOW_KEYS, SQLCOM_SHOW_VARIABLES, SQLCOM_SHOW_LOGS, SQLCOM_SHOW_STATUS, SQLCOM_SHOW_INNODB_STATUS, SQLCOM_SHOW_PROCESSLIST, SQLCOM_SHOW_MASTER_STAT, SQLCOM_SHOW_SLAVE_STAT, - SQLCOM_SHOW_GRANTS, SQLCOM_SHOW_CREATE, + SQLCOM_SHOW_GRANTS, SQLCOM_SHOW_CREATE, SQLCOM_SHOW_CHARSETS, + SQLCOM_SHOW_CREATE_DB, SQLCOM_LOAD,SQLCOM_SET_OPTION,SQLCOM_LOCK_TABLES,SQLCOM_UNLOCK_TABLES, - SQLCOM_GRANT, SQLCOM_CHANGE_DB, SQLCOM_CREATE_DB, SQLCOM_DROP_DB, + SQLCOM_GRANT, + SQLCOM_CHANGE_DB, SQLCOM_CREATE_DB, SQLCOM_DROP_DB, SQLCOM_ALTER_DB, SQLCOM_REPAIR, SQLCOM_REPLACE, SQLCOM_REPLACE_SELECT, SQLCOM_CREATE_FUNCTION, SQLCOM_DROP_FUNCTION, SQLCOM_REVOKE,SQLCOM_OPTIMIZE, SQLCOM_CHECK, @@ -62,8 +64,9 @@ enum enum_sql_command { SQLCOM_HA_OPEN, SQLCOM_HA_CLOSE, SQLCOM_HA_READ, SQLCOM_SHOW_SLAVE_HOSTS, SQLCOM_DELETE_MULTI, SQLCOM_MULTI_UPDATE, SQLCOM_SHOW_BINLOG_EVENTS, SQLCOM_SHOW_NEW_MASTER, SQLCOM_DO, - SQLCOM_EMPTY_QUERY, - SQLCOM_END + SQLCOM_SHOW_WARNS, SQLCOM_EMPTY_QUERY, SQLCOM_SHOW_ERRORS, + SQLCOM_SHOW_COLUMN_TYPES, SQLCOM_SHOW_TABLE_TYPES, SQLCOM_SHOW_PRIVILEGES, + SQLCOM_END, SQLCOM_HELP }; enum lex_states @@ -78,6 +81,7 @@ enum lex_states STATE_IDENT_OR_KEYWORD }; + typedef List<Item> List_item; typedef struct st_lex_master_info @@ -93,7 +97,8 @@ typedef struct st_lex_master_info enum sub_select_type { - UNSPECIFIED_TYPE, UNION_TYPE, INTERSECT_TYPE, EXCEPT_TYPE, OLAP_TYPE, NOT_A_SELECT + UNSPECIFIED_TYPE,UNION_TYPE, INTERSECT_TYPE, + EXCEPT_TYPE, GLOBAL_OPTIONS_TYPE, DERIVED_TABLE_TYPE, OLAP_TYPE }; enum olap_type @@ -101,27 +106,274 @@ enum olap_type UNSPECIFIED_OLAP_TYPE, CUBE_TYPE, ROLLUP_TYPE }; -/* The state of the lex parsing for selects */ +/* + The state of the lex parsing for selects + + All select describing structures linked with following pointers: + - list of neighbors (next/prev) (prev of first element point to slave + pointer of upper structure) + - one level units for unit (union) structure + - member of one union(unit) for ordinary select_lex + - pointer to master + - outer select_lex for unit (union) + - unit structure for ordinary select_lex + - pointer to slave + - first list element of select_lex belonged to this unit for unit + - first unit in list of units that belong to this select_lex (as + subselects or derived tables) for ordinary select_lex + - list of all select_lex (for group operation like correcting list of opened + tables) + for example for following query: -typedef struct st_select_lex -{ - enum sub_select_type linkage; - enum olap_type olap; - char *db,*db1,*table1,*db2,*table2; /* For outer join using .. */ - Item *where,*having; - ha_rows select_limit,offset_limit; + select * + from table1 + where table1.field IN (select * from table1_1_1 union + select * from table1_1_2) + union + select * + from table2 + where table2.field=(select (select f1 from table2_1_1_1_1 + where table2_1_1_1_1.f2=table2_1_1.f3) + from table2_1_1 + where table2_1_1.f1=table2.f2) + union + select * from table3; + + we will have following structure: + + + main unit + select1 select2 select3 + |^^ |^ + s||| ||master + l||| |+---------------------------------+ + a||| +---------------------------------+| + v|||master slave || + e||+-------------------------+ || + V| neighbor | V| + unit 1.1<==================>unit1.2 unit2.1 + select1.1.1 select 1.1.2 select1.2.1 select2.1.1 select2.1.2 + |^ + || + V| + unit2.1.1.1 + select2.1.1.1.1 + + + relation in main unit will be following: + + main unit + |^^^ + |||| + |||+------------------------------+ + ||+--------------+ | + slave||master | | + V| neighbor | neighbor | + select1<========>select2<========>select3 + + list of all select_lex will be following (as it will be constructed by + parser): + + select1->select2->select3->select2.1.1->select 2.1.2->select2.1.1.1.1-+ + | + +---------------------------------------------------------------------+ + | + +->select1.1.1->select1.1.2 + +*/ + +/* + Base class for st_select_lex (SELECT_LEX) & + st_select_lex_unit (SELECT_LEX_UNIT) +*/ +class st_select_lex; +class st_select_lex_unit; +class st_select_lex_node { +protected: + st_select_lex_node *next, **prev, /* neighbor list */ + *master, *slave, /* vertical links */ + *link_next, **link_prev; /* list of whole SELECT_LEX */ +public: ulong options; + enum sub_select_type linkage; + SQL_LIST order_list; /* ORDER clause */ List<List_item> expr_list; - List<List_item> when_list; - SQL_LIST order_list,table_list,group_list; - List<Item> item_list; - List<String> interval_list,use_index, *use_index_ptr, + List<List_item> when_list; /* WHEN clause (expression) */ + ha_rows select_limit, offset_limit; /* LIMIT clause parameters */ + bool create_refs; + bool dependent; /* dependent from outer select subselect */ + + static void *operator new(size_t size) + { + return (void*) sql_calloc((uint) size); + } + static void operator delete(void *ptr,size_t size) {} + virtual ~st_select_lex_node() {} + inline st_select_lex_node* get_master() { return master; } + virtual void init_query(); + virtual void init_select(); + void include_down(st_select_lex_node *upper); + void include_neighbour(st_select_lex_node *before); + void include_global(st_select_lex_node **plink); + void exclude(); + + virtual st_select_lex* select_lex(); + virtual bool add_item_to_list(Item *item); + bool add_order_to_list(Item *item, bool asc); + virtual bool add_group_to_list(Item *item, bool asc); + virtual bool add_ftfunc_to_list(Item_func_match *func); + + virtual st_select_lex_unit* master_unit()= 0; + virtual st_select_lex* outer_select()= 0; + + virtual bool set_braces(bool value); + virtual bool inc_in_sum_expr(); + virtual uint get_in_sum_expr(); + virtual TABLE_LIST* get_table_list(); + virtual List<Item>* get_item_list(); + virtual List<String>* get_use_index(); + virtual List<String>* get_ignore_index(); + virtual TABLE_LIST *add_table_to_list(Table_ident *table, + LEX_STRING *alias, + bool updating, + thr_lock_type flags= TL_UNLOCK, + List<String> *use_index= 0, + List<String> *ignore_index= 0); + + void mark_as_dependent(st_select_lex *last); +private: + void fast_exclude(); +}; +typedef class st_select_lex_node SELECT_LEX_NODE; + +/* + SELECT_LEX_UNIT - unit of selects (UNION, INTERSECT, ...) group + SELECT_LEXs +*/ +struct st_lex; +class THD; +class select_result; +class JOIN; +class select_union; +class st_select_lex_unit: public st_select_lex_node { +protected: + List<Item> item_list; + List<JOIN*> joins; /* list of *JOINs, to delete it in cleanup() */ + TABLE_LIST result_table_list; + select_union *union_result; + TABLE *table; /* temporary table using for appending UNION results */ + THD *thd; + select_result *result; + int res; + bool describe, found_rows_for_union, + prepared, // prepare phase already performed for UNION (unit) + optimized, // optimize phase already performed for UNION (unit) + executed; // already executed +public: + /* + Pointer to 'last' select or pointer to unit where stored + global parameters for union + */ + st_select_lex_node *global_parameters; + /* LIMIT clause runtime counters */ + ha_rows select_limit_cnt, offset_limit_cnt; + /* not NULL if union used in subselect, point to subselect item */ + Item_subselect *item; + uint union_option; + + void init_query(); + bool create_total_list(THD *thd, st_lex *lex, TABLE_LIST **result); + st_select_lex_unit* master_unit(); + st_select_lex* outer_select(); + st_select_lex* first_select() { return (st_select_lex*) slave; } + st_select_lex_unit* next_unit() { return (st_select_lex_unit*) next; } + + /* UNION methods */ + int prepare(THD *thd, select_result *result); + int exec(); + int cleanup(); + + friend void mysql_init_query(THD *thd); +private: + bool create_total_list_n_last_return(THD *thd, st_lex *lex, + TABLE_LIST ***result); +}; +typedef class st_select_lex_unit SELECT_LEX_UNIT; + +/* + SELECT_LEX - store information of parsed SELECT_LEX statment +*/ +class st_select_lex: public st_select_lex_node +{ +public: + char *db, *db1, *table1, *db2, *table2; /* For outer join using .. */ + Item *where, *having; /* WHERE & HAVING clauses */ + enum olap_type olap; + SQL_LIST table_list, group_list; /* FROM & GROUP BY clauses */ + List<Item> item_list; /* list of fields & expressions */ + List<String> interval_list, use_index, *use_index_ptr, ignore_index, *ignore_index_ptr; - List<Item_func_match> ftfunc_list; - uint in_sum_expr, sort_default; - bool create_refs, braces; - st_select_lex *next; -} SELECT_LEX; + /* + Usualy it is pointer to ftfunc_list_alloc, but in union used to create fake + select_lex for calling mysql_select under results of union + */ + List<Item_func_match> *ftfunc_list; + List<Item_func_match> ftfunc_list_alloc; + JOIN *join; /* after JOIN::prepare it is pointer to corresponding JOIN */ + const char *type; /* type of select for EXPLAIN */ + uint in_sum_expr; + uint select_number; /* number of select (used for EXPLAIN) */ + bool braces; /* SELECT ... UNION (SELECT ... ) <- this braces */ + /* TRUE when having fix field called in processing of this SELECT */ + bool having_fix_field; + + void init_query(); + void init_select(); + st_select_lex_unit* master_unit(); + st_select_lex_unit* first_inner_unit() + { + return (st_select_lex_unit*) slave; + } + st_select_lex* outer_select(); + st_select_lex* next_select() { return (st_select_lex*) next; } + st_select_lex* next_select_in_list() + { + return (st_select_lex*) link_next; + } + st_select_lex_node** next_select_in_list_addr() + { + return &link_next; + } + + bool set_braces(bool value); + bool inc_in_sum_expr(); + uint get_in_sum_expr(); + + st_select_lex* select_lex(); + bool add_item_to_list(Item *item); + bool add_group_to_list(Item *item, bool asc); + bool add_ftfunc_to_list(Item_func_match *func); + + TABLE_LIST* get_table_list(); + List<Item>* get_item_list(); + List<String>* get_use_index(); + List<String>* get_ignore_index(); + TABLE_LIST* add_table_to_list(Table_ident *table, + LEX_STRING *alias, + bool updating, + thr_lock_type flags= TL_UNLOCK, + List<String> *use_index= 0, + List<String> *ignore_index= 0); + inline void init_order() + { + order_list.elements= 0; + order_list.first= 0; + order_list.next= (byte**) &order_list.first; + } + + friend void mysql_init_query(THD *thd); +}; +typedef class st_select_lex SELECT_LEX; /* The state of the lex parsing. This is saved in the THD struct */ @@ -130,7 +382,10 @@ typedef struct st_lex { uint yylineno,yytoklen; /* Simulate lex */ LEX_YYSTYPE yylval; - SELECT_LEX select_lex, *select, *last_selects; + SELECT_LEX_UNIT unit; /* most upper unit */ + SELECT_LEX select_lex; /* first SELECT_LEX */ + /* current SELECT_LEX in parsing */ + SELECT_LEX_NODE *current_select; uchar *ptr,*tok_start,*tok_end,*end_of_query; char *length,*dec,*change,*name; char *backup_dir; /* For RESTORE/BACKUP */ @@ -139,8 +394,10 @@ typedef struct st_lex enum SSL_type ssl_type; /* defined in violite.h */ String *wild; sql_exchange *exchange; + select_result *result; List<key_part_spec> col_list; + List<key_part_spec> ref_list; List<Alter_drop> drop_list; List<Alter_column> alter_list; List<String> interval_list; @@ -151,10 +408,11 @@ typedef struct st_lex List<Item> *insert_list,field_list,value_list; List<List_item> many_values; List<set_var_base> var_list; + List<Item> param_list; SQL_LIST proc_list, auxilliary_table_list; TYPELIB *interval; create_field *last_field; - Item *default_value; + Item *default_value, *comment; CONVERT *convert_set; CONVERT *thd_convert_set; // Set with SET CHAR SET LEX_USER *grant_user; @@ -167,6 +425,7 @@ typedef struct st_lex USER_RESOURCES mqh; ulong thread_id,type; enum_sql_command sql_command; + thr_lock_type lock_option; enum lex_states next_state; enum enum_duplicates duplicates; enum enum_tx_isolation tx_isolation; @@ -174,11 +433,15 @@ typedef struct st_lex enum ha_rkey_function ha_rkey_mode; enum enum_enable_or_disable alter_keys_onoff; enum enum_var_type option_type; - uint grant,grant_tot_col,which_columns, union_option; - thr_lock_type lock_option; - bool drop_primary, drop_if_exists, drop_temporary, local_file, olap; - bool in_comment,ignore_space,verbose,simple_alter; + uint grant, grant_tot_col, which_columns; + uint fk_delete_opt, fk_update_opt, fk_match_option; + uint param_count; + bool drop_primary, drop_if_exists, drop_temporary, local_file; + bool in_comment, ignore_space, verbose, simple_alter; + bool derived_tables, describe, olap; uint slave_thd_opt; + CHARSET_INFO *charset; + char *help_arg; } LEX; diff --git a/sql/sql_list.h b/sql/sql_list.h index 542eef623f0..56e6528f214 100644 --- a/sql/sql_list.h +++ b/sql/sql_list.h @@ -82,6 +82,7 @@ public: first=tmp.first; last=tmp.last; } + inline base_list(bool error) { } inline bool push_back(void *info) { if (((*last)=new list_node(info, &end_of_list))) @@ -122,11 +123,15 @@ public: last= &first; return tmp->info; } + inline list_node* last_node() { return *last; } + inline list_node* first_node() { return first;} inline void *head() { return first->info; } inline void **head_ref() { return first != &end_of_list ? &first->info : 0; } inline bool is_empty() { return first == &end_of_list ; } inline list_node *last_ref() { return &end_of_list; } friend class base_list_iterator; + friend class error_list; + friend class error_list_iterator; protected: void after(void *info,list_node *node) @@ -204,6 +209,7 @@ public: { return el == &list->last_ref()->next; } + friend class error_list_iterator; }; diff --git a/sql/sql_load.cc b/sql/sql_load.cc index cfb12b8a5bf..00450a3b86c 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -296,7 +296,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, } sprintf(name,ER(ER_LOAD_INFO),info.records,info.deleted, info.records-info.copied,thd->cuted_fields); - send_ok(&thd->net,info.copied+info.deleted,0L,name); + send_ok(thd,info.copied+info.deleted,0L,name); // on the slave thd->query is never initialized if (!thd->slave_thread) mysql_update_log.write(thd,thd->query,thd->query_length); @@ -374,7 +374,7 @@ read_fixed_length(THD *thd,COPY_INFO &info,TABLE *table,List<Item> &fields, field->field_length) length=field->field_length; save_chr=pos[length]; pos[length]='\0'; // Safeguard aganst malloc - field->store((char*) pos,length); + field->store((char*) pos,length,default_charset_info); pos[length]=save_chr; if ((pos+=length) > read_info.row_end) pos= read_info.row_end; /* Fills rest with space */ @@ -443,7 +443,7 @@ read_sep_field(THD *thd,COPY_INFO &info,TABLE *table, } field->set_notnull(); read_info.row_end[0]=0; // Safe to change end marker - field->store((char*) read_info.row_start,length); + field->store((char*) read_info.row_start,length,default_charset_info); } if (read_info.error) break; diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 0cebde364f7..4816a0539f3 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -57,17 +57,15 @@ extern "C" pthread_mutex_t THR_LOCK_keycache; extern "C" int gethostname(char *name, int namelen); #endif -static int check_for_max_user_connections(USER_CONN *uc); +static int check_for_max_user_connections(THD *thd, USER_CONN *uc); static void decrease_user_connections(USER_CONN *uc); static bool check_db_used(THD *thd,TABLE_LIST *tables); static bool check_merge_table_access(THD *thd, char *db, TABLE_LIST *tables); static bool check_dup(const char *db, const char *name, TABLE_LIST *tables); -static void mysql_init_query(THD *thd); static void remove_escape(char *name); static void refresh_status(void); static bool append_file_to_dir(THD *thd, char **filename_ptr, char *table_name); -static bool create_total_list(THD *thd, LEX *lex, TABLE_LIST **result); const char *any_db="*any*"; // Special symbol for check_access @@ -75,10 +73,11 @@ const char *command_name[]={ "Sleep", "Quit", "Init DB", "Query", "Field List", "Create DB", "Drop DB", "Refresh", "Shutdown", "Statistics", "Processlist", "Connect","Kill","Debug","Ping","Time","Delayed_insert","Change user", - "Binlog Dump","Table Dump", "Connect Out", "Register Slave" + "Binlog Dump","Table Dump", "Connect Out", "Register Slave", + "Prepare", "Prepare Execute", "Long Data" }; -bool volatile abort_slave = 0; +static char empty_c_string[1]= {0}; // Used for not defined 'db' #ifdef __WIN__ static void test_signal(int sig_ptr) @@ -151,7 +150,7 @@ static int get_or_create_user_conn(THD *thd, const char *user, my_malloc(sizeof(struct user_conn) + temp_len+1, MYF(MY_WME))))) { - send_error(¤t_thd->net, 0, NullS); // Out of memory + send_error(thd, 0, NullS); // Out of memory return_val=1; goto end; } @@ -169,7 +168,7 @@ static int get_or_create_user_conn(THD *thd, const char *user, if (hash_insert(&hash_user_connections, (byte*) uc)) { my_free((char*) uc,0); - send_error(¤t_thd->net, 0, NullS); // Out of memory + send_error(thd, 0, NullS); // Out of memory return_val=1; goto end; } @@ -191,14 +190,13 @@ end: static bool check_user(THD *thd,enum_server_command command, const char *user, const char *passwd, const char *db, bool check_count) { - NET *net= &thd->net; thd->db=0; thd->db_length=0; USER_RESOURCES ur; if (!(thd->user = my_strdup(user, MYF(0)))) { - send_error(net,ER_OUT_OF_RESOURCES); + send_error(thd,ER_OUT_OF_RESOURCES); return 1; } thd->master_access=acl_getroot(thd, thd->host, thd->ip, thd->user, @@ -214,7 +212,7 @@ static bool check_user(THD *thd,enum_server_command command, const char *user, thd->master_access, thd->db ? thd->db : "*none*")); if (thd->master_access & NO_ACCESS) { - net_printf(net, ER_ACCESS_DENIED_ERROR, + net_printf(thd, ER_ACCESS_DENIED_ERROR, thd->user, thd->host_or_ip, passwd[0] ? ER(ER_YES) : ER(ER_NO)); @@ -232,7 +230,7 @@ static bool check_user(THD *thd,enum_server_command command, const char *user, VOID(pthread_mutex_unlock(&LOCK_thread_count)); if (tmp) { // Too many connections - send_error(net, ER_CON_COUNT_ERROR); + send_error(thd, ER_CON_COUNT_ERROR); return(1); } } @@ -249,7 +247,7 @@ static bool check_user(THD *thd,enum_server_command command, const char *user, get_or_create_user_conn(thd,user,thd->host_or_ip,&ur)) return -1; if (thd->user_connect && thd->user_connect->user_resources.connections && - check_for_max_user_connections(thd->user_connect)) + check_for_max_user_connections(thd, thd->user_connect)) return -1; if (db && db[0]) { @@ -259,7 +257,7 @@ static bool check_user(THD *thd,enum_server_command command, const char *user, return error; } else - send_ok(net); // Ready to handle questions + send_ok(thd); // Ready to handle questions return 0; // ok } @@ -283,13 +281,14 @@ extern "C" 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, (hash_free_key) free_user, 0); } -static int check_for_max_user_connections(USER_CONN *uc) +static int check_for_max_user_connections(THD *thd, USER_CONN *uc) { int error=0; DBUG_ENTER("check_for_max_user_connections"); @@ -297,7 +296,7 @@ static int check_for_max_user_connections(USER_CONN *uc) if (max_user_connections && (max_user_connections <= (uint) uc->connections)) { - net_printf(&(current_thd->net),ER_TOO_MANY_USER_CONNECTIONS, uc->user); + net_printf(thd,ER_TOO_MANY_USER_CONNECTIONS, uc->user); error=1; goto end; } @@ -305,11 +304,10 @@ static int check_for_max_user_connections(USER_CONN *uc) if (uc->user_resources.connections && uc->conn_per_hour++ >= uc->user_resources.connections) { - net_printf(¤t_thd->net, ER_USER_LIMIT_REACHED, uc->user, + net_printf(thd, ER_USER_LIMIT_REACHED, uc->user, "max_connections", (long) uc->user_resources.connections); error=1; - goto end; } end: DBUG_RETURN(error); @@ -400,7 +398,7 @@ static bool check_mqh(THD *thd, uint check_command) if (uc->user_resources.questions && uc->questions++ >= uc->user_resources.questions) { - net_printf(&thd->net, ER_USER_LIMIT_REACHED, uc->user, "max_questions", + net_printf(thd, ER_USER_LIMIT_REACHED, uc->user, "max_questions", (long) uc->user_resources.questions); error=1; goto end; @@ -411,7 +409,7 @@ static bool check_mqh(THD *thd, uint check_command) if (uc->user_resources.updates && uc_update_queries[check_command] && uc->updates++ >= uc->user_resources.updates) { - net_printf(&thd->net, ER_USER_LIMIT_REACHED, uc->user, "max_updates", + net_printf(thd, ER_USER_LIMIT_REACHED, uc->user, "max_updates", (long) uc->user_resources.updates); error=1; goto end; @@ -516,7 +514,7 @@ check_connections(THD *thd) { /* buff[] needs to big enough to hold the server_version variable */ char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH+32],*end; - int client_flags = CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB; + int client_flags = CLIENT_LONG_FLAG | CLIENT_CONNECT_WITH_DB | CLIENT_PROTOCOL_41; if (opt_using_transactions) client_flags|=CLIENT_TRANSACTIONS; @@ -538,7 +536,7 @@ check_connections(THD *thd) int2store(end+3,thd->server_status); bzero(end+5,13); end+=18; - if (net_write_command(net,(uchar) protocol_version, buff, + if (net_write_command(net,(uchar) protocol_version, "", 0, buff, (uint) (end-buff)) || (pkt_len= my_net_read(net)) == packet_error || pkt_len < MIN_HANDSHAKE_SIZE) @@ -669,7 +667,7 @@ pthread_handler_decl(handle_one_connection,arg) if ((error=check_connections(thd))) { // Wrong permissions if (error > 0) - net_printf(net,error,thd->host_or_ip); + net_printf(thd,error,thd->host_or_ip); #ifdef __NT__ if (vio_type(net->vio) == VIO_TYPE_NAMEDPIPE) sleep(1); /* must wait after eof() */ @@ -678,7 +676,7 @@ pthread_handler_decl(handle_one_connection,arg) goto end_thread; } - if ((ulong) thd->variables.max_join_size == (ulong) HA_POS_ERROR) + if ((ulong) thd->variables.max_join_size == (ulonglong) HA_POS_ERROR) thd->options |= OPTION_BIG_SELECTS; if (thd->client_capabilities & CLIENT_COMPRESS) net->compress=1; // Use compression @@ -698,7 +696,7 @@ pthread_handler_decl(handle_one_connection,arg) if (thd->user_connect) decrease_user_connections(thd->user_connect); free_root(&thd->mem_root,MYF(0)); - if (net->error && net->vio != 0) + if (net->error && net->vio != 0 && net->report_error) { if (!thd->killed && thd->variables.log_warnings) sql_print_error(ER(ER_NEW_ABORTING_CONNECTION), @@ -707,7 +705,7 @@ pthread_handler_decl(handle_one_connection,arg) thd->host_or_ip, (net->last_errno ? ER(net->last_errno) : ER(ER_UNKNOWN_ERROR))); - send_error(net,net->last_errno,NullS); + send_error(thd,net->last_errno,NullS); statistic_increment(aborted_threads,&LOCK_status); } @@ -754,7 +752,7 @@ extern "C" pthread_handler_decl(handle_bootstrap,arg) #endif - if ((ulong) thd->variables.max_join_size == (ulong) HA_POS_ERROR) + if ((ulong) thd->variables.max_join_size == (ulonglong) HA_POS_ERROR) thd->options |= OPTION_BIG_SELECTS; thd->proc_info=0; @@ -768,7 +766,8 @@ extern "C" 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; @@ -802,11 +801,11 @@ end: DBUG_RETURN(0); // Never reached } + /* This works because items are allocated with sql_alloc() */ -inline void free_items(THD *thd) +void free_items(Item *item) { - /* This works because items are allocated with sql_alloc() */ - for (Item *item=thd->free_list ; item ; item=item->next) + for (; item ; item=item->next) delete item; } @@ -830,7 +829,7 @@ int mysql_table_dump(THD* thd, char* db, char* tbl_name, int fd) if (!db || check_db_name(db)) { - net_printf(&thd->net,ER_WRONG_DB_NAME, db ? db : "NULL"); + net_printf(thd,ER_WRONG_DB_NAME, db ? db : "NULL"); goto err; } if (check_access(thd, SELECT_ACL, db, &table_list->grant.privilege)) @@ -874,8 +873,7 @@ bool do_command(THD *thd) old_timeout=net->read_timeout; // Wait max for 8 hours net->read_timeout=(uint) thd->variables.net_wait_timeout; - net->last_error[0]=0; // Clear error message - net->last_errno=0; + thd->clear_error(); // Clear error message net_new_transaction(net); if ((packet_length=my_net_read(net)) == packet_error) @@ -928,7 +926,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, case COM_REGISTER_SLAVE: { if (!register_slave(thd, (uchar*)packet, packet_length)) - send_ok(&thd->net); + send_ok(thd); break; } case COM_TABLE_DUMP: @@ -944,7 +942,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, memcpy(tbl_name, packet + db_len + 2, tbl_len); tbl_name[tbl_len] = 0; if (mysql_table_dump(thd, db, tbl_name, -1)) - send_error(&thd->net); // dump to NET + send_error(thd); // dump to NET break; } @@ -969,7 +967,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, if ((uint) ((uchar*) db - net->read_pos) > packet_length) { // Check if protocol is ok - send_error(net, ER_UNKNOWN_COM_ERROR); + send_error(thd, ER_UNKNOWN_COM_ERROR); break; } if (check_user(thd, COM_CHANGE_USER, user, passwd, db, 0)) @@ -991,35 +989,28 @@ bool dispatch_command(enum enum_server_command command, THD *thd, thd->password=test(passwd[0]); break; } - + case COM_EXECUTE: + { + mysql_stmt_execute(thd, packet); + break; + } + case COM_LONG_DATA: + { + mysql_stmt_get_longdata(thd, packet, packet_length); + break; + } + case COM_PREPARE: + { + mysql_stmt_prepare(thd, packet, packet_length); + break; + } case COM_QUERY: { - packet_length--; // Remove end null - /* Remove garage at start and end of query */ - while (isspace(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]))) - { - pos--; - packet_length--; - } - /* We must allocate some extra memory for query cache */ - if (!(thd->query= (char*) thd->memdup_w_gap((gptr) (packet), - packet_length, - thd->db_length+2))) - break; - thd->query[packet_length]=0; - thd->packet.shrink(thd->variables.net_buffer_length);// Reclaim some memory - if (!(specialflag & SPECIAL_NO_PRIOR)) - my_pthread_setprio(pthread_self(),QUERY_PRIOR); + if (alloc_query(thd, packet, packet_length)) + break; // fatal error is set mysql_log.write(thd,command,"%s",thd->query); DBUG_PRINT("query",("%s",thd->query)); - /* thd->query_length is set by mysql_parse() */ - mysql_parse(thd,thd->query,packet_length); + mysql_parse(thd,thd->query, thd->query_length); if (!(specialflag & SPECIAL_NO_PRIOR)) my_pthread_setprio(pthread_self(),WAIT_PRIOR); DBUG_PRINT("info",("query ready")); @@ -1027,7 +1018,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, } case COM_FIELD_LIST: // This isn't actually needed #ifdef DONT_ALLOW_SHOW_COMMANDS - send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */ + send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */ break; #else { @@ -1037,7 +1028,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, bzero((char*) &table_list,sizeof(table_list)); if (!(table_list.db=thd->db)) { - send_error(net,ER_NO_DB_ERROR); + send_error(thd,ER_NO_DB_ERROR); break; } thd->free_list=0; @@ -1055,7 +1046,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, if (grant_option && check_grant(thd,SELECT_ACL,&table_list,2)) break; mysqld_list_fields(thd,&table_list,fields); - free_items(thd); + free_items(thd->free_list); break; } #endif @@ -1073,11 +1064,11 @@ bool dispatch_command(enum enum_server_command command, THD *thd, // null test to handle EOM if (!db || !strip_sp(db) || check_db_name(db)) { - net_printf(&thd->net,ER_WRONG_DB_NAME, db ? db : "NULL"); + net_printf(thd,ER_WRONG_DB_NAME, db ? db : "NULL"); break; } if (lower_case_table_names) - casedn_str(db); + my_casedn_str(system_charset_info, db); if (check_access(thd,CREATE_ACL,db,0,1)) break; mysql_log.write(thd,command,packet); @@ -1091,14 +1082,14 @@ bool dispatch_command(enum enum_server_command command, THD *thd, // null test to handle EOM if (!db || !strip_sp(db) || check_db_name(db)) { - net_printf(&thd->net,ER_WRONG_DB_NAME, db ? db : "NULL"); + net_printf(thd,ER_WRONG_DB_NAME, db ? db : "NULL"); break; } if (lower_case_table_names) - casedn_str(db); + my_casedn_str(system_charset_info, db); if (thd->locked_tables || thd->active_transaction()) { - send_error(&thd->net,ER_LOCK_OR_ACTIVE_TRANSACTION); + send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION); break; } mysql_log.write(thd,command,db); @@ -1137,9 +1128,9 @@ bool dispatch_command(enum enum_server_command command, THD *thd, break; mysql_log.write(thd,command,NullS); if (reload_acl_and_cache(thd, options, (TABLE_LIST*) 0)) - send_error(net,0); + send_error(thd,0); else - send_eof(net); + send_eof(thd); break; } case COM_SHUTDOWN: @@ -1148,12 +1139,12 @@ bool dispatch_command(enum enum_server_command command, THD *thd, break; /* purecov: inspected */ DBUG_PRINT("quit",("Got shutdown command")); mysql_log.write(thd,command,NullS); - send_eof(net); + send_eof(thd); #ifdef __WIN__ sleep(1); // must wait after eof() #endif #ifndef OS2 - send_eof(net); // This is for 'quit request' + send_eof(thd); // This is for 'quit request' #endif close_connection(net); close_thread_tables(thd); // Free before kill @@ -1186,7 +1177,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, } case COM_PING: statistic_increment(com_other,&LOCK_status); - send_ok(net); // Tell client we are alive + send_ok(thd); // Tell client we are alive break; case COM_PROCESS_INFO: statistic_increment(com_stat[SQLCOM_SHOW_PROCESSLIST],&LOCK_status); @@ -1209,14 +1200,14 @@ bool dispatch_command(enum enum_server_command command, THD *thd, break; /* purecov: inspected */ mysql_print_status(thd); mysql_log.write(thd,command,NullS); - send_eof(net); + send_eof(thd); break; case COM_SLEEP: case COM_CONNECT: // Impossible here case COM_TIME: // Impossible from client case COM_DELAYED_INSERT: default: - send_error(net, ER_UNKNOWN_COM_ERROR); + send_error(thd, ER_UNKNOWN_COM_ERROR); break; } if (thd->lock || thd->open_tables) @@ -1226,7 +1217,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd, } if (thd->fatal_error) - send_error(net,0); // End of memory ? + send_error(thd,0); // End of memory ? time_t start_of_query=thd->start_time; thd->end_time(); // Set start time @@ -1258,21 +1249,82 @@ bool dispatch_command(enum enum_server_command command, THD *thd, DBUG_RETURN(error); } + +/* + Read query from packet and store in thd->query + Used in COM_QUERY and COM_PREPARE + + DESCRIPTION + Sets the following THD variables: + query + query_length + + RETURN VALUES + 0 ok + 1 error; In this case thd->fatal_error is set +*/ + +bool alloc_query(THD *thd, char *packet, ulong packet_length) +{ + packet_length--; // Remove end null + /* Remove garage at start and end of query */ + 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] == ';' || my_isspace(system_charset_info,pos[-1]))) + { + pos--; + packet_length--; + } + /* We must allocate some extra memory for query cache */ + if (!(thd->query= (char*) thd->memdup_w_gap((gptr) (packet), + packet_length, + thd->db_length+2))) + return 1; + thd->query[packet_length]=0; + thd->query_length= packet_length; + thd->packet.shrink(thd->variables.net_buffer_length);// Reclaim some memory + + if (!(specialflag & SPECIAL_NO_PRIOR)) + my_pthread_setprio(pthread_self(),QUERY_PRIOR); + return 0; +} + /**************************************************************************** ** mysql_execute_command ** Execute command saved in thd and current_lex->sql_command ****************************************************************************/ void -mysql_execute_command(void) +mysql_execute_command(THD *thd) { - int res=0; - THD *thd=current_thd; + int res= 0; LEX *lex= &thd->lex; - TABLE_LIST *tables=(TABLE_LIST*) lex->select_lex.table_list.first; - SELECT_LEX *select_lex = lex->select; + TABLE_LIST *tables= (TABLE_LIST*) lex->select_lex.table_list.first; + TABLE_LIST *cursor; + SELECT_LEX *select_lex= &lex->select_lex; + SELECT_LEX_UNIT *unit= &lex->unit; DBUG_ENTER("mysql_execute_command"); + /* + Reset warning count for each query that uses tables + A better approach would be to reset this for any commands + that is not a SHOW command or a select that only access local + variables, but for now this is probably good enough. + */ + if (tables || lex->select_lex.next_select_in_list()) + mysql_reset_errors(thd); + /* + Save old warning count to be able to send to client how many warnings we + got + */ + thd->old_total_warn_count= thd->total_warn_count; + + thd->net.report_error= 0; if (thd->slave_thread) { /* @@ -1296,10 +1348,28 @@ 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 + TODO: make derived tables processing 'inside' SELECT processing. + TODO: solve problem with depended derived tables in subselects */ - if ((lex->select_lex.next && create_total_list(thd,lex,&tables)) || + if (lex->derived_tables) + { + for (SELECT_LEX *sl= &lex->select_lex; sl; sl= sl->next_select_in_list()) + if (sl->linkage != DERIVED_TABLE_TYPE) + for (TABLE_LIST *cursor= sl->get_table_list(); + cursor; + cursor= cursor->next) + if (cursor->derived && (res=mysql_derived(thd, lex, + (SELECT_LEX_UNIT *) + cursor->derived, + cursor))) + { + if (res < 0 || thd->net.report_error) + send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN : 0); + DBUG_VOID_RETURN; + } + } + if ((lex->select_lex.next_select_in_list() && + lex->unit.create_total_list(thd, lex, &tables)) || (table_rules_on && tables && thd->slave_thread && !tables_ok(thd,tables))) DBUG_VOID_RETURN; @@ -1308,9 +1378,7 @@ mysql_execute_command(void) switch (lex->sql_command) { case SQLCOM_SELECT: { - select_result *result; - if (select_lex->options & SELECT_DESCRIBE) - lex->exchange=0; + select_result *result=lex->result; if (tables) { res=check_table_access(thd, @@ -1327,62 +1395,64 @@ mysql_execute_command(void) break; // Error message is given } - thd->offset_limit=select_lex->offset_limit; - thd->select_limit=select_lex->select_limit+select_lex->offset_limit; - if (thd->select_limit < select_lex->select_limit) - thd->select_limit= HA_POS_ERROR; // no limit - if (thd->select_limit == HA_POS_ERROR) + unit->offset_limit_cnt= (ha_rows) unit->global_parameters->offset_limit; + unit->select_limit_cnt= (ha_rows) (unit->global_parameters->select_limit+ + unit->global_parameters->offset_limit); + if (unit->select_limit_cnt < + (ha_rows) unit->global_parameters->select_limit) + unit->select_limit_cnt= HA_POS_ERROR; // no limit + if (unit->select_limit_cnt == HA_POS_ERROR) select_lex->options&= ~OPTION_FOUND_ROWS; - if (lex->exchange) + if (!(res=open_and_lock_tables(thd,tables))) { - if (lex->exchange->dumpfile) + if (lex->describe) { - if (!(result=new select_dump(lex->exchange))) + if (!(result= new select_send())) { - res= -1; - break; + send_error(thd, ER_OUT_OF_RESOURCES); + DBUG_VOID_RETURN; } + else + thd->send_explain_fields(result); + fix_tables_pointers(select_lex); + res= mysql_explain_union(thd, &thd->lex.unit, result); + MYSQL_LOCK *save_lock= thd->lock; + thd->lock= (MYSQL_LOCK *)0; + result->send_eof(); + thd->lock= save_lock; } else { - if (!(result=new select_export(lex->exchange))) + if (!result) { - res= -1; - break; - } - } - } - else if (!(result=new select_send())) - { - res= -1; + if ((result=new select_send())) + { + /* + Normal select: + Change lock if we are using SELECT HIGH PRIORITY, + FOR UPDATE or IN SHARE MODE + + TODO: Delete the following loop when locks is set by sql_yacc + */ + TABLE_LIST *table; + for (table = tables ; table ; table=table->next) + table->lock_type= lex->lock_option; + } + else + { + res= -1; #ifdef DELETE_ITEMS - delete select_lex->having; - delete select_lex->where; + delete select_lex->having; + delete select_lex->where; #endif - break; - } - else - { - /* - Normal select: - Change lock if we are using SELECT HIGH PRIORITY, - FOR UPDATE or IN SHARE MODE - - TODO: Delete the following loop when locks is set by sql_yacc - */ - TABLE_LIST *table; - for (table = tables ; table ; table=table->next) - table->lock_type= lex->lock_option; - } - - if (!(res=open_and_lock_tables(thd,tables))) - { - query_cache_store_query(thd, tables); - res=handle_select(thd, lex, result); + break; + } + } + query_cache_store_query(thd, tables); + res=handle_select(thd, lex, result); + } } - else - delete result; break; } case SQLCOM_DO: @@ -1390,7 +1460,11 @@ mysql_execute_command(void) break; case SQLCOM_EMPTY_QUERY: - send_ok(&thd->net); + send_ok(thd); + break; + + case SQLCOM_HELP: + res= mysqld_help(thd,lex->help_arg); break; case SQLCOM_PURGE: @@ -1400,12 +1474,25 @@ mysql_execute_command(void) res = purge_master_logs(thd, lex->to_log); break; } + case SQLCOM_SHOW_WARNS: + { + res= mysqld_show_warnings(thd, (ulong) + ((1L << (uint) MYSQL_ERROR::WARN_LEVEL_NOTE) | + (1L << (uint) MYSQL_ERROR::WARN_LEVEL_WARN))); + break; + } + case SQLCOM_SHOW_ERRORS: + { + res= mysqld_show_warnings(thd, (ulong) + (1L << (uint) MYSQL_ERROR::WARN_LEVEL_ERROR)); + break; + } case SQLCOM_SHOW_NEW_MASTER: { if (check_global_access(thd, REPL_SLAVE_ACL)) goto error; #ifndef WORKING_NEW_MASTER - net_printf(&thd->net, ER_NOT_SUPPORTED_YET, "SHOW NEW MASTER"); + net_printf(thd, ER_NOT_SUPPORTED_YET, "SHOW NEW MASTER"); res= 1; #else res = show_new_master(thd); @@ -1508,7 +1595,7 @@ mysql_execute_command(void) } if (strlen(tables->real_name) > NAME_LEN) { - net_printf(&thd->net,ER_WRONG_TABLE_NAME,tables->real_name); + net_printf(thd,ER_WRONG_TABLE_NAME,tables->real_name); break; } LOCK_ACTIVE_MI; @@ -1516,7 +1603,7 @@ mysql_execute_command(void) if (!fetch_master_table(thd, tables->db, tables->real_name, active_mi, 0)) { - send_ok(&thd->net); + send_ok(thd); } UNLOCK_ACTIVE_MI; break; @@ -1544,7 +1631,7 @@ mysql_execute_command(void) } if (strlen(tables->real_name) > NAME_LEN) { - net_printf(&thd->net, ER_WRONG_TABLE_NAME, tables->alias); + net_printf(thd, ER_WRONG_TABLE_NAME, tables->alias); res=0; break; } @@ -1568,7 +1655,7 @@ mysql_execute_command(void) if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) && check_dup(tables->db, tables->real_name, tables->next)) { - net_printf(&thd->net,ER_INSERT_TABLE_USED,tables->real_name); + net_printf(thd,ER_INSERT_TABLE_USED,tables->real_name); DBUG_VOID_RETURN; } if (tables->next) @@ -1580,10 +1667,11 @@ mysql_execute_command(void) for (table = tables->next ; table ; table=table->next) table->lock_type= lex->lock_option; } - thd->offset_limit=select_lex->offset_limit; - thd->select_limit=select_lex->select_limit+select_lex->offset_limit; - if (thd->select_limit < select_lex->select_limit) - thd->select_limit= HA_POS_ERROR; // No limit + unit->offset_limit_cnt= select_lex->offset_limit; + unit->select_limit_cnt= select_lex->select_limit+ + select_lex->offset_limit; + if (unit->select_limit_cnt < select_lex->select_limit) + unit->select_limit_cnt= HA_POS_ERROR; // No limit /* Skip first table, which is the table we are creating */ lex->select_lex.table_list.first= @@ -1605,9 +1693,9 @@ mysql_execute_command(void) res = mysql_create_table(thd,tables->db ? tables->db : thd->db, tables->real_name, &lex->create_info, lex->create_list, - lex->key_list,0, 0); // do logging + lex->key_list,0,0,0); // do logging if (!res) - send_ok(&thd->net); + send_ok(thd); } break; } @@ -1640,14 +1728,14 @@ mysql_execute_command(void) } case SQLCOM_ALTER_TABLE: #if defined(DONT_ALLOW_SHOW_COMMANDS) - send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */ + send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */ break; #else { ulong priv=0; if (lex->name && (!lex->name[0] || strlen(lex->name) > NAME_LEN)) { - net_printf(&thd->net,ER_WRONG_TABLE_NAME,lex->name); + net_printf(thd,ER_WRONG_TABLE_NAME,lex->name); res=0; break; } @@ -1730,7 +1818,7 @@ mysql_execute_command(void) } case SQLCOM_SHOW_BINLOGS: #ifdef DONT_ALLOW_SHOW_COMMANDS - send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */ + send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */ DBUG_VOID_RETURN; #else { @@ -1742,7 +1830,7 @@ mysql_execute_command(void) #endif case SQLCOM_SHOW_CREATE: #ifdef DONT_ALLOW_SHOW_COMMANDS - send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */ + send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */ DBUG_VOID_RETURN; #else { @@ -1796,6 +1884,7 @@ mysql_execute_command(void) bzero((char*) &create_info,sizeof(create_info)); create_info.db_type=DB_TYPE_DEFAULT; create_info.row_type=ROW_TYPE_DEFAULT; + create_info.table_charset=default_charset_info; res= mysql_alter_table(thd, NullS, NullS, &create_info, tables, lex->create_list, lex->key_list, lex->drop_list, lex->alter_list, @@ -1813,7 +1902,7 @@ mysql_execute_command(void) goto error; if (select_lex->item_list.elements != lex->value_list.elements) { - send_error(&thd->net,ER_WRONG_VALUE_COUNT); + send_error(thd,ER_WRONG_VALUE_COUNT); DBUG_VOID_RETURN; } if (select_lex->table_list.elements == 1) @@ -1834,27 +1923,28 @@ mysql_execute_command(void) const char *msg=0; lex->sql_command=SQLCOM_MULTI_UPDATE; - for (auxi=(TABLE_LIST*) tables, table_count=0 ; auxi ; auxi=auxi->next) + for (auxi= (TABLE_LIST*) tables, table_count=0 ; auxi ; auxi=auxi->next) table_count++; + if (select_lex->order_list.elements) msg="ORDER BY"; else if (select_lex->select_limit && select_lex->select_limit != HA_POS_ERROR) msg="LIMIT"; - if (msg) { - net_printf(&thd->net, ER_WRONG_USAGE, "UPDATE", msg); + net_printf(thd, ER_WRONG_USAGE, "UPDATE", msg); res= 1; break; } + tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege); if ((res=open_and_lock_tables(thd,tables))) break; - thd->select_limit=HA_POS_ERROR; + unit->select_limit_cnt= HA_POS_ERROR; if (!setup_fields(thd,tables,select_lex->item_list,1,0,0) && - !setup_fields(thd,tables,lex->value_list,0,0,0) && - ! thd->fatal_error && + !setup_fields(thd,tables,lex->value_list,0,0,0) && + !thd->fatal_error && (result=new multi_update(thd,tables,select_lex->item_list, lex->duplicates, table_count))) { @@ -1867,13 +1957,13 @@ mysql_execute_command(void) while ((item=value_list++)) total_list.push_back(item); - res=mysql_select(thd,tables,total_list, - select_lex->where, - (ORDER *)NULL,(ORDER *)NULL,(Item *)NULL, - (ORDER *)NULL, - select_lex->options | thd->options | - SELECT_NO_JOIN_CACHE, - result); + res= mysql_select(thd, tables, total_list, + select_lex->where, + (ORDER *)NULL, (ORDER *)NULL, (Item *)NULL, + (ORDER *)NULL, + select_lex->options | thd->options | + SELECT_NO_JOIN_CACHE, + result, unit, select_lex, 0); delete result; } else @@ -1923,14 +2013,14 @@ mysql_execute_command(void) } select_result *result; - thd->offset_limit=select_lex->offset_limit; - thd->select_limit=select_lex->select_limit+select_lex->offset_limit; - if (thd->select_limit < select_lex->select_limit) - thd->select_limit= HA_POS_ERROR; // No limit + unit->offset_limit_cnt= select_lex->offset_limit; + unit->select_limit_cnt= select_lex->select_limit+select_lex->offset_limit; + if (unit->select_limit_cnt < select_lex->select_limit) + unit->select_limit_cnt= HA_POS_ERROR; // No limit if (check_dup(tables->db, tables->real_name, tables->next)) { - net_printf(&thd->net,ER_INSERT_TABLE_USED,tables->real_name); + net_printf(thd,ER_INSERT_TABLE_USED,tables->real_name); DBUG_VOID_RETURN; } { @@ -1962,7 +2052,7 @@ mysql_execute_command(void) */ if (thd->locked_tables || thd->active_transaction()) { - send_error(&thd->net,ER_LOCK_OR_ACTIVE_TRANSACTION,NullS); + send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION,NullS); goto error; } res=mysql_truncate(thd,tables); @@ -1994,7 +2084,7 @@ mysql_execute_command(void) goto error; if ((thd->options & OPTION_SAFE_UPDATES) && !select_lex->where) { - send_error(&thd->net,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE); + send_error(thd,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE); goto error; } for (auxi=(TABLE_LIST*) aux_tables ; auxi ; auxi=auxi->next) @@ -2010,34 +2100,33 @@ mysql_execute_command(void) } if (!walk) { - net_printf(&thd->net,ER_NONUNIQ_TABLE,auxi->real_name); + net_printf(thd,ER_NONUNIQ_TABLE,auxi->real_name); goto error; } walk->lock_type= auxi->lock_type; - auxi->table= (TABLE *) walk; // Remember corresponding table + auxi->table_list= walk; // Remember corresponding table } if (add_item_to_list(new Item_null())) { res= -1; break; } - tables->grant.want_privilege=(SELECT_ACL & ~tables->grant.privilege); thd->proc_info="init"; if ((res=open_and_lock_tables(thd,tables))) break; /* Fix tables-to-be-deleted-from list to point at opened tables */ for (auxi=(TABLE_LIST*) aux_tables ; auxi ; auxi=auxi->next) - auxi->table= ((TABLE_LIST*) auxi->table)->table; + auxi->table= auxi->table_list->table; if (!thd->fatal_error && (result= new multi_delete(thd,aux_tables, table_count))) { - res=mysql_select(thd,tables,select_lex->item_list, - select_lex->where, - (ORDER *)NULL,(ORDER *)NULL,(Item *)NULL, - (ORDER *)NULL, - select_lex->options | thd->options | - SELECT_NO_JOIN_CACHE, - result); + res= mysql_select(thd,tables,select_lex->item_list, + select_lex->where, + (ORDER *)NULL,(ORDER *)NULL,(Item *)NULL, + (ORDER *)NULL, + select_lex->options | thd->options | + SELECT_NO_JOIN_CACHE, + result, unit, select_lex, 0); delete result; } else @@ -2069,7 +2158,7 @@ mysql_execute_command(void) break; case SQLCOM_SHOW_DATABASES: #if defined(DONT_ALLOW_SHOW_COMMANDS) - send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */ + send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */ DBUG_VOID_RETURN; #else if ((specialflag & SPECIAL_SKIP_SHOW_DB) && @@ -2084,6 +2173,15 @@ mysql_execute_command(void) mysqld_list_processes(thd,thd->master_access & PROCESS_ACL ? NullS : thd->priv_user,lex->verbose); break; + case SQLCOM_SHOW_TABLE_TYPES: + res= mysqld_show_table_types(thd); + break; + case SQLCOM_SHOW_PRIVILEGES: + res= mysqld_show_privileges(thd); + break; + case SQLCOM_SHOW_COLUMN_TYPES: + res= mysqld_show_column_types(thd); + break; case SQLCOM_SHOW_STATUS: res= mysqld_show(thd,(lex->wild ? lex->wild->ptr() : NullS),status_vars, OPT_GLOBAL); @@ -2093,27 +2191,34 @@ mysql_execute_command(void) init_vars, lex->option_type); break; case SQLCOM_SHOW_LOGS: - { - res= mysqld_show_logs(thd); - break; - } +#ifdef DONT_ALLOW_SHOW_COMMANDS + send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */ + DBUG_VOID_RETURN; +#else + { + if (grant_option && check_access(thd, FILE_ACL, any_db)) + goto error; + res= mysqld_show_logs(thd); + break; + } +#endif case SQLCOM_SHOW_TABLES: /* FALL THROUGH */ #ifdef DONT_ALLOW_SHOW_COMMANDS - send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */ + send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */ DBUG_VOID_RETURN; #else { char *db=select_lex->db ? select_lex->db : thd->db; if (!db) { - send_error(&thd->net,ER_NO_DB_ERROR); /* purecov: inspected */ + send_error(thd,ER_NO_DB_ERROR); /* purecov: inspected */ goto error; /* purecov: inspected */ } remove_escape(db); // Fix escaped '_' if (check_db_name(db)) { - net_printf(&thd->net,ER_WRONG_DB_NAME, db); + net_printf(thd,ER_WRONG_DB_NAME, db); goto error; } if (check_access(thd,SELECT_ACL,db,&thd->col_access)) @@ -2131,16 +2236,19 @@ mysql_execute_command(void) case SQLCOM_SHOW_OPEN_TABLES: res= mysqld_show_open_tables(thd,(lex->wild ? lex->wild->ptr() : NullS)); break; + case SQLCOM_SHOW_CHARSETS: + res= mysqld_show_charsets(thd,(lex->wild ? lex->wild->ptr() : NullS)); + break; case SQLCOM_SHOW_FIELDS: #ifdef DONT_ALLOW_SHOW_COMMANDS - send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */ + send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */ DBUG_VOID_RETURN; #else { char *db=tables->db; if (!*db) { - send_error(&thd->net,ER_NO_DB_ERROR); /* purecov: inspected */ + send_error(thd,ER_NO_DB_ERROR); /* purecov: inspected */ goto error; /* purecov: inspected */ } remove_escape(db); // Fix escaped '_' @@ -2158,14 +2266,14 @@ mysql_execute_command(void) #endif case SQLCOM_SHOW_KEYS: #ifdef DONT_ALLOW_SHOW_COMMANDS - send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */ + send_error(thd,ER_NOT_ALLOWED_COMMAND); /* purecov: inspected */ DBUG_VOID_RETURN; #else { char *db=tables->db; if (!db) { - send_error(&thd->net,ER_NO_DB_ERROR); /* purecov: inspected */ + send_error(thd,ER_NO_DB_ERROR); /* purecov: inspected */ goto error; /* purecov: inspected */ } remove_escape(db); // Fix escaped '_' @@ -2199,7 +2307,7 @@ mysql_execute_command(void) if (!(thd->client_capabilities & CLIENT_LOCAL_FILES) || ! opt_local_infile) { - send_error(&thd->net,ER_NOT_ALLOWED_COMMAND); + send_error(thd,ER_NOT_ALLOWED_COMMAND); goto error; } if (check_access(thd,privilege,tables->db,&tables->grant.privilege) || @@ -2212,7 +2320,7 @@ mysql_execute_command(void) } case SQLCOM_SET_OPTION: if (!(res=sql_set_variables(thd, &lex->var_list))) - send_ok(&thd->net); + send_ok(thd); break; case SQLCOM_UNLOCK_TABLES: unlock_locked_tables(thd); @@ -2223,7 +2331,7 @@ mysql_execute_command(void) } if (thd->global_read_lock) unlock_global_read_lock(thd); - send_ok(&thd->net); + send_ok(thd); break; case SQLCOM_LOCK_TABLES: unlock_locked_tables(thd); @@ -2237,7 +2345,7 @@ mysql_execute_command(void) { thd->locked_tables=thd->lock; thd->lock=0; - send_ok(&thd->net); + send_ok(thd); } else thd->options&= ~(ulong) (OPTION_TABLE_LOCK); @@ -2247,41 +2355,75 @@ mysql_execute_command(void) { if (!strip_sp(lex->name) || check_db_name(lex->name)) { - net_printf(&thd->net,ER_WRONG_DB_NAME, lex->name); + net_printf(thd,ER_WRONG_DB_NAME, lex->name); break; } if (lower_case_table_names) - casedn_str(lex->name); + my_casedn_str(system_charset_info, lex->name); if (check_access(thd,CREATE_ACL,lex->name,0,1)) break; - res=mysql_create_db(thd,lex->name,lex->create_info.options,0); + res=mysql_create_db(thd,lex->name,&lex->create_info,0); break; } case SQLCOM_DROP_DB: { if (!strip_sp(lex->name) || check_db_name(lex->name)) { - net_printf(&thd->net,ER_WRONG_DB_NAME, lex->name); + net_printf(thd,ER_WRONG_DB_NAME, lex->name); break; } if (lower_case_table_names) - casedn_str(lex->name); + my_casedn_str(system_charset_info, lex->name); if (check_access(thd,DROP_ACL,lex->name,0,1)) break; if (thd->locked_tables || thd->active_transaction()) { - send_error(&thd->net,ER_LOCK_OR_ACTIVE_TRANSACTION); + send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION); goto error; } res=mysql_rm_db(thd,lex->name,lex->drop_if_exists,0); break; } + case SQLCOM_ALTER_DB: + { + if (!strip_sp(lex->name) || check_db_name(lex->name)) + { + net_printf(thd,ER_WRONG_DB_NAME, lex->name); + break; + } + if (check_access(thd,ALTER_ACL,lex->name,0,1)) + break; + if (thd->locked_tables || thd->active_transaction()) + { + send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION); + goto error; + } + res=mysql_alter_db(thd,lex->name,&lex->create_info); + break; + } + case SQLCOM_SHOW_CREATE_DB: + { + if (!strip_sp(lex->name) || check_db_name(lex->name)) + { + net_printf(thd,ER_WRONG_DB_NAME, lex->name); + break; + } + if (check_access(thd,DROP_ACL,lex->name,0,1)) + break; + if (thd->locked_tables || thd->active_transaction()) + { + send_error(thd,ER_LOCK_OR_ACTIVE_TRANSACTION); + goto error; + } + res=mysqld_show_create_db(thd,lex->name,&lex->create_info); + break; + } case SQLCOM_CREATE_FUNCTION: if (check_access(thd,INSERT_ACL,"mysql",0,1)) break; #ifdef HAVE_DLOPEN if (!(res = mysql_create_function(thd,&lex->udf))) - send_ok(&thd->net); + send_ok(thd); #else res= -1; #endif @@ -2291,7 +2433,7 @@ mysql_execute_command(void) break; #ifdef HAVE_DLOPEN if (!(res = mysql_drop_function(thd,lex->udf.name))) - send_ok(&thd->net); + send_ok(thd); #else res= -1; #endif @@ -2319,7 +2461,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; @@ -2350,7 +2493,7 @@ mysql_execute_command(void) { if (lex->columns.elements) { - send_error(&thd->net,ER_ILLEGAL_GRANT_FOR_TABLE); + send_error(thd,ER_ILLEGAL_GRANT_FOR_TABLE); res=1; } else @@ -2380,9 +2523,9 @@ mysql_execute_command(void) if (check_global_access(thd,RELOAD_ACL) || check_db_used(thd, tables)) goto error; if (reload_acl_and_cache(thd, lex->type, tables)) - send_error(&thd->net,0); + send_error(thd,0); else - send_ok(&thd->net); + send_ok(thd); break; case SQLCOM_KILL: kill_one_thread(thd,lex->thread_id); @@ -2432,7 +2575,7 @@ mysql_execute_command(void) thd->options= ((thd->options & (ulong) ~(OPTION_STATUS_NO_TRANS_UPDATE)) | OPTION_BEGIN); thd->server_status|= SERVER_STATUS_IN_TRANS; - send_ok(&thd->net); + send_ok(thd); } break; case SQLCOM_COMMIT: @@ -2446,7 +2589,7 @@ mysql_execute_command(void) thd->server_status&= ~SERVER_STATUS_IN_TRANS; if (!ha_commit(thd)) { - send_ok(&thd->net); + send_ok(thd); } else res= -1; @@ -2457,21 +2600,21 @@ mysql_execute_command(void) if (!ha_rollback(thd)) { if (thd->options & OPTION_STATUS_NO_TRANS_UPDATE) - send_warning(&thd->net,ER_WARNING_NOT_COMPLETE_ROLLBACK,0); + send_warning(thd,ER_WARNING_NOT_COMPLETE_ROLLBACK,0); else - send_ok(&thd->net); + send_ok(thd); } else res= -1; thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE); break; default: /* Impossible */ - send_ok(&thd->net); + send_ok(thd); break; } thd->proc_info="query end"; // QQ if (res < 0) - send_error(&thd->net,thd->killed ? ER_SERVER_SHUTDOWN : 0); + send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN : 0); error: DBUG_VOID_RETURN; @@ -2504,7 +2647,7 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv, if ((!db || !db[0]) && !thd->db && !dont_check_global_grants) { if (!no_errors) - send_error(&thd->net,ER_NO_DB_ERROR); /* purecov: tested */ + send_error(thd,ER_NO_DB_ERROR); /* purecov: tested */ DBUG_RETURN(TRUE); /* purecov: tested */ } @@ -2517,7 +2660,7 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv, ! db && dont_check_global_grants) { // We can never grant this if (!no_errors) - net_printf(&thd->net,ER_ACCESS_DENIED_ERROR, + net_printf(thd,ER_ACCESS_DENIED_ERROR, thd->priv_user, thd->host_or_ip, thd->password ? ER(ER_YES) : ER(ER_NO));/* purecov: tested */ @@ -2542,7 +2685,7 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv, !(want_access & ~TABLE_ACLS))) DBUG_RETURN(FALSE); /* Ok */ if (!no_errors) - net_printf(&thd->net,ER_DBACCESS_DENIED_ERROR, + net_printf(thd,ER_DBACCESS_DENIED_ERROR, thd->priv_user, thd->host_or_ip, db ? db : thd->db ? thd->db : "unknown"); /* purecov: tested */ @@ -2558,7 +2701,7 @@ bool check_global_access(THD *thd, ulong want_access) if ((thd->master_access & want_access) == want_access) return 0; get_privilege_desc(command, sizeof(command), want_access); - net_printf(&thd->net,ER_SPECIFIC_ACCESS_DENIED_ERROR, + net_printf(thd,ER_SPECIFIC_ACCESS_DENIED_ERROR, command); return 1; } @@ -2578,6 +2721,8 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables, TABLE_LIST *org_tables=tables; for (; tables ; tables=tables->next) { + if (tables->derived || (tables->table && (int)tables->table->tmp_table)) + continue; if ((thd->master_access & want_access) == (want_access & ~EXTRA_ACL) && thd->db) tables->grant.privilege= want_access; @@ -2613,7 +2758,7 @@ static bool check_db_used(THD *thd,TABLE_LIST *tables) { if (!(tables->db=thd->db)) { - send_error(&thd->net,ER_NO_DB_ERROR); /* purecov: tested */ + send_error(thd,ER_NO_DB_ERROR); /* purecov: tested */ return TRUE; /* purecov: tested */ } } @@ -2636,7 +2781,7 @@ static bool check_merge_table_access(THD *thd, char *db, tmp->db=db; else if (strcmp(tmp->db,db)) { - send_error(&thd->net,ER_UNION_TABLES_IN_DIFFERENT_DIR); + send_error(thd,ER_UNION_TABLES_IN_DIFFERENT_DIR); return 1; } } @@ -2707,82 +2852,120 @@ bool my_yyoverflow(short **yyss, YYSTYPE **yyvs, int *yystacksize) Initialize global thd variables needed for query ****************************************************************************/ -static void +void mysql_init_query(THD *thd) { DBUG_ENTER("mysql_init_query"); - thd->lex.select_lex.item_list.empty(); - 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_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; - thd->lex.olap=0; - thd->lex.select->olap= UNSPECIFIED_OLAP_TYPE; - thd->fatal_error=0; // Safety - thd->last_insert_id_used=thd->query_start_used=thd->insert_id_used=0; - thd->rand_used=0; - thd->sent_row_count=thd->examined_row_count=0; - thd->safe_to_cache_query=1; + LEX *lex=&thd->lex; + lex->unit.init_query(); + lex->unit.init_select(); + lex->select_lex.init_query(); + lex->value_list.empty(); + lex->param_list.empty(); + lex->unit.global_parameters= lex->unit.slave= lex->current_select= + &lex->select_lex; + lex->select_lex.master= &lex->unit; + lex->select_lex.prev= &lex->unit.slave; + lex->olap=lex->describe=0; + lex->derived_tables= false; + thd->check_loops_counter= thd->select_number= + lex->select_lex.select_number= 1; + thd->free_list= 0; + thd->total_warn_count=0; // Warnings for this query + thd->last_insert_id_used= thd->query_start_used= thd->insert_id_used=0; + thd->sent_row_count= thd->examined_row_count= 0; + thd->fatal_error= thd->rand_used= 0; + thd->safe_to_cache_query= 1; + thd->possible_loops= 0; DBUG_VOID_RETURN; } void mysql_init_select(LEX *lex) { - SELECT_LEX *select_lex = lex->select; - select_lex->where=select_lex->having=0; - select_lex->select_limit= lex->thd->variables.select_limit; - select_lex->offset_limit=0; - select_lex->options=0; - select_lex->linkage=UNSPECIFIED_TYPE; - select_lex->olap= UNSPECIFIED_OLAP_TYPE; - lex->exchange = 0; - lex->proc_list.first=0; - select_lex->order_list.elements=select_lex->group_list.elements=0; - select_lex->order_list.first=0; - 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 *select_lex= lex->current_select->select_lex(); + DBUG_ASSERT(select_lex->linkage != GLOBAL_OPTIONS_TYPE); + select_lex->init_select(); + select_lex->master_unit()->select_limit= select_lex->select_limit= + lex->thd->variables.select_limit; + lex->exchange= 0; + lex->result= 0; + lex->proc_list.first= 0; } bool -mysql_new_select(LEX *lex) +mysql_new_select(LEX *lex, bool move_down) { - SELECT_LEX *select_lex = (SELECT_LEX *) lex->thd->calloc(sizeof(SELECT_LEX)); + SELECT_LEX *select_lex = new SELECT_LEX(); + select_lex->select_number= ++lex->thd->select_number; if (!select_lex) return 1; - lex->select->next=select_lex; - lex->select=select_lex; - select_lex->table_list.next= (byte**) &select_lex->table_list.first; - select_lex->item_list.empty(); - select_lex->when_list.empty(); - select_lex->expr_list.empty(); - select_lex->interval_list.empty(); - select_lex->use_index.empty(); - select_lex->ftfunc_list.empty(); + select_lex->init_query(); + select_lex->init_select(); + if (move_down) + { + /* first select_lex of subselect or derived table */ + SELECT_LEX_UNIT *unit= new SELECT_LEX_UNIT(); + if (!unit) + return 1; + unit->init_query(); + unit->init_select(); + unit->include_down(lex->current_select); + select_lex->include_down(unit); + } + else + select_lex->include_neighbour(lex->current_select); + + select_lex->master_unit()->global_parameters= select_lex; + DBUG_ASSERT(lex->current_select->linkage != GLOBAL_OPTIONS_TYPE); + select_lex->include_global(lex->current_select->select_lex()-> + next_select_in_list_addr()); + lex->current_select= select_lex; return 0; } +/* + Create a select to return the same output as 'SELECT @@var_name'. + + SYNOPSIS + create_select_for_variable() + var_name Variable name + + DESCRIPTION + Used for SHOW COUNT(*) [ WARNINGS | ERROR] + + This will crash with a core dump if the variable doesn't exists +*/ + +void create_select_for_variable(const char *var_name) +{ + LEX *lex; + LEX_STRING tmp; + DBUG_ENTER("create_select_for_variable"); + lex= current_lex; + mysql_init_select(lex); + lex->sql_command= SQLCOM_SELECT; + tmp.str= (char*) var_name; + tmp.length=strlen(var_name); + add_item_to_list(get_system_var(OPT_SESSION, tmp)); + DBUG_VOID_RETURN; +} + void mysql_init_multi_delete(LEX *lex) { - lex->sql_command = SQLCOM_DELETE_MULTI; + lex->sql_command= SQLCOM_DELETE_MULTI; mysql_init_select(lex); - lex->select->select_limit=lex->thd->select_limit=HA_POS_ERROR; - lex->auxilliary_table_list=lex->select_lex.table_list; - lex->select->table_list.elements=0; - lex->select->table_list.first=0; - lex->select->table_list.next= (byte**) &(lex->select->table_list.first); + lex->select_lex.select_limit= lex->unit.select_limit_cnt= + HA_POS_ERROR; + lex->auxilliary_table_list= lex->select_lex.table_list; + lex->select_lex.init_query(); } void -mysql_parse(THD *thd,char *inBuf,uint length) +mysql_parse(THD *thd, char *inBuf, uint length) { DBUG_ENTER("mysql_parse"); @@ -2794,13 +2977,13 @@ mysql_parse(THD *thd,char *inBuf,uint length) if (!yyparse() && ! thd->fatal_error) { if (mqh_used && thd->user_connect && - check_mqh(thd, thd->lex.sql_command)) + check_mqh(thd, lex->sql_command)) { thd->net.error = 0; } else { - mysql_execute_command(); + mysql_execute_command(thd); query_cache_end_of_result(&thd->net); } } @@ -2811,7 +2994,7 @@ mysql_parse(THD *thd,char *inBuf,uint length) query_cache_abort(&thd->net); } thd->proc_info="freeing items"; - free_items(thd); /* Free strings used by items */ + free_items(thd->free_list); /* Free strings used by items */ lex_end(lex); } DBUG_VOID_RETURN; @@ -2835,31 +3018,33 @@ link_in_list(SQL_LIST *list,byte *element,byte **next) bool add_field_to_list(char *field_name, enum_field_types type, char *length, char *decimals, - uint type_modifier, Item *default_value,char *change, - TYPELIB *interval) + uint type_modifier, + Item *default_value, Item *comment, + char *change, TYPELIB *interval, CHARSET_INFO *cs) { register create_field *new_field; THD *thd=current_thd; LEX *lex= &thd->lex; uint allowed_type_modifier=0; + char warn_buff[MYSQL_ERRMSG_SIZE]; DBUG_ENTER("add_field_to_list"); if (strlen(field_name) > NAME_LEN) { - net_printf(&thd->net, ER_TOO_LONG_IDENT, field_name); /* purecov: inspected */ + net_printf(thd, ER_TOO_LONG_IDENT, field_name); /* purecov: inspected */ DBUG_RETURN(1); /* purecov: inspected */ } if (type_modifier & PRI_KEY_FLAG) { lex->col_list.push_back(new key_part_spec(field_name,0)); - lex->key_list.push_back(new Key(Key::PRIMARY,NullS, + lex->key_list.push_back(new Key(Key::PRIMARY, NullS, HA_KEY_ALG_UNDEF, lex->col_list)); lex->col_list.empty(); } if (type_modifier & (UNIQUE_FLAG | UNIQUE_KEY_FLAG)) { lex->col_list.push_back(new key_part_spec(field_name,0)); - lex->key_list.push_back(new Key(Key::UNIQUE,NullS, + lex->key_list.push_back(new Key(Key::UNIQUE, NullS, HA_KEY_ALG_UNDEF, lex->col_list)); lex->col_list.empty(); } @@ -2869,7 +3054,7 @@ bool add_field_to_list(char *field_name, enum_field_types type, if ((type_modifier & (NOT_NULL_FLAG | AUTO_INCREMENT_FLAG)) == NOT_NULL_FLAG) { - net_printf(&thd->net,ER_INVALID_DEFAULT,field_name); + net_printf(thd,ER_INVALID_DEFAULT,field_name); DBUG_RETURN(1); } default_value=0; @@ -2889,6 +3074,19 @@ bool add_field_to_list(char *field_name, enum_field_types type, new_field->change=change; new_field->interval=0; new_field->pack_length=0; + new_field->charset=cs; + + if (!comment) + { + new_field->comment.str=0; + new_field->comment.length=0; + } + else + { + /* In this case comment is always of type Item_string */ + new_field->comment.str= (char*) comment->str_value.ptr(); + new_field->comment.length=comment->str_value.length(); + } if (length) if (!(new_field->length= (uint) atoi(length))) length=0; /* purecov: inspected */ @@ -2920,8 +3118,6 @@ bool add_field_to_list(char *field_name, enum_field_types type, if (!length) new_field->length=20; allowed_type_modifier= AUTO_INCREMENT_FLAG; break; - case FIELD_TYPE_STRING: - case FIELD_TYPE_VAR_STRING: case FIELD_TYPE_NULL: case FIELD_TYPE_GEOMETRY: break; @@ -2932,17 +3128,42 @@ bool add_field_to_list(char *field_name, enum_field_types type, if (new_field->decimals) new_field->length++; break; + case FIELD_TYPE_STRING: + case FIELD_TYPE_VAR_STRING: + if (new_field->length < MAX_FIELD_WIDTH || default_value) + break; + /* Convert long CHAR() and VARCHAR columns to TEXT or BLOB */ + new_field->sql_type= FIELD_TYPE_BLOB; + sprintf(warn_buff, ER(ER_AUTO_CONVERT), field_name, "CHAR", + (cs == my_charset_bin) ? "BLOB" : "TEXT"); + push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_AUTO_CONVERT, + warn_buff); + /* fall through */ case FIELD_TYPE_BLOB: case FIELD_TYPE_TINY_BLOB: case FIELD_TYPE_LONG_BLOB: case FIELD_TYPE_MEDIUM_BLOB: + if (new_field->length) + { + /* The user has given a length to the blob column */ + if (new_field->length < 256) + type= FIELD_TYPE_TINY_BLOB; + if (new_field->length < 65536) + type= FIELD_TYPE_BLOB; + else if (new_field->length < 256L*256L*256L) + type= FIELD_TYPE_MEDIUM_BLOB; + else + type= FIELD_TYPE_LONG_BLOB; + new_field->length= 0; + } + new_field->sql_type= type; if (default_value) // Allow empty as default value { String str,*res; res=default_value->val_str(&str); if (res->length()) { - net_printf(&thd->net,ER_BLOB_CANT_HAVE_DEFAULT,field_name); /* purecov: inspected */ + net_printf(thd,ER_BLOB_CANT_HAVE_DEFAULT,field_name); /* purecov: inspected */ DBUG_RETURN(1); /* purecov: inspected */ } new_field->def=0; @@ -2962,7 +3183,7 @@ bool add_field_to_list(char *field_name, enum_field_types type, uint tmp_length=new_field->length; if (tmp_length > PRECISION_FOR_DOUBLE) { - net_printf(&thd->net,ER_WRONG_FIELD_SPEC,field_name); + net_printf(thd,ER_WRONG_FIELD_SPEC,field_name); DBUG_RETURN(1); } else if (tmp_length > PRECISION_FOR_FLOAT) @@ -3016,7 +3237,7 @@ bool add_field_to_list(char *field_name, enum_field_types type, { if (interval->count > sizeof(longlong)*8) { - net_printf(&thd->net,ER_TOO_BIG_SET,field_name); /* purecov: inspected */ + net_printf(thd,ER_TOO_BIG_SET,field_name); /* purecov: inspected */ DBUG_RETURN(1); /* purecov: inspected */ } new_field->pack_length=(interval->count+7)/8; @@ -3038,7 +3259,7 @@ bool add_field_to_list(char *field_name, enum_field_types type, (void) find_set(interval,res->ptr(),res->length()); if (thd->cuted_fields) { - net_printf(&thd->net,ER_INVALID_DEFAULT,field_name); + net_printf(thd,ER_INVALID_DEFAULT,field_name); DBUG_RETURN(1); } } @@ -3061,7 +3282,7 @@ bool add_field_to_list(char *field_name, enum_field_types type, res=default_value->val_str(&str); if (!find_enum(interval,res->ptr(),res->length())) { - net_printf(&thd->net,ER_INVALID_DEFAULT,field_name); + net_printf(thd,ER_INVALID_DEFAULT,field_name); DBUG_RETURN(1); } } @@ -3073,14 +3294,14 @@ bool add_field_to_list(char *field_name, enum_field_types type, (!new_field->length && !(new_field->flags & BLOB_FLAG) && type != FIELD_TYPE_STRING && type != FIELD_TYPE_VAR_STRING)) { - net_printf(&thd->net,ER_TOO_BIG_FIELDLENGTH,field_name, + net_printf(thd,ER_TOO_BIG_FIELDLENGTH,field_name, MAX_FIELD_WIDTH-1); /* purecov: inspected */ DBUG_RETURN(1); /* purecov: inspected */ } type_modifier&= AUTO_INCREMENT_FLAG; if ((~allowed_type_modifier) & type_modifier) { - net_printf(&thd->net,ER_WRONG_FIELD_SPEC,field_name); + net_printf(thd,ER_WRONG_FIELD_SPEC,field_name); DBUG_RETURN(1); } if (!new_field->pack_length) @@ -3133,8 +3354,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++; @@ -3172,12 +3393,12 @@ bool add_to_list(SQL_LIST &list,Item *item,bool asc) } -TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias, - bool updating, - thr_lock_type flags, - List<String> *use_index, - List<String> *ignore_index - ) +TABLE_LIST *st_select_lex::add_table_to_list(Table_ident *table, + LEX_STRING *alias, + bool updating, + thr_lock_type flags, + List<String> *use_index, + List<String> *ignore_index) { register TABLE_LIST *ptr; THD *thd=current_thd; @@ -3188,10 +3409,10 @@ 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); + net_printf(thd,ER_WRONG_TABLE_NAME,table->table.str); DBUG_RETURN(0); } @@ -3213,20 +3434,22 @@ TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias, } else { - ptr->db= (char*) ""; + /* The following can't be "" as we may do 'casedn_str()' on it */ + ptr->db= empty_c_string; ptr->db_length= 0; } ptr->alias= 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_UNIT *) table->sel; if (use_index) ptr->use_index=(List<String> *) thd->memdup((gptr) use_index, sizeof(*use_index)); @@ -3237,21 +3460,22 @@ TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias, /* check that used name is unique */ if (flags != TL_IGNORE) { - for (TABLE_LIST *tables=(TABLE_LIST*) thd->lex.select->table_list.first ; + for (TABLE_LIST *tables=(TABLE_LIST*) table_list.first ; tables ; tables=tables->next) { if (!strcmp(alias_str,tables->alias) && !strcmp(ptr->db, tables->db)) { - net_printf(&thd->net,ER_NONUNIQ_TABLE,alias_str); /* purecov: tested */ + net_printf(thd,ER_NONUNIQ_TABLE,alias_str); /* purecov: tested */ DBUG_RETURN(0); /* purecov: tested */ } } } - link_in_list(&thd->lex.select->table_list,(byte*) ptr,(byte**) &ptr->next); + link_in_list(&table_list, (byte*) ptr, (byte**) &ptr->next); DBUG_RETURN(ptr); } + /* Set lock for all tables in current select level @@ -3284,68 +3508,6 @@ void set_lock_for_tables(thr_lock_type lock_type) } -/* -** This is used for UNION to create a new table list of all used tables -** The table_list->table entry in all used tables are set to point -** to the entries in this list. -*/ - -static bool create_total_list(THD *thd, LEX *lex, TABLE_LIST **result) -{ - /* Handle the case when we are not using union */ - if (!lex->select_lex.next) - { - *result= (TABLE_LIST*) lex->select_lex.table_list.first; - return 0; - } - - SELECT_LEX *sl; - TABLE_LIST **new_table_list= result, *aux; - - *new_table_list=0; // end result list - for (sl= &lex->select_lex; sl; sl=sl->next) - { - if (sl->order_list.first && sl->next && !sl->braces) - { - net_printf(&thd->net,ER_WRONG_USAGE,"UNION","ORDER BY"); - return 1; - } - if ((aux= (TABLE_LIST*) sl->table_list.first)) - { - TABLE_LIST *next; - for (; aux; aux=next) - { - TABLE_LIST *cursor; - aux->do_redirect=true; - next= aux->next; - for (cursor= *result; cursor; cursor=cursor->next) - if (!strcmp(cursor->db,aux->db) && - !strcmp(cursor->real_name,aux->real_name) && - !strcmp(cursor->alias, aux->alias)) - break; - if (!cursor) - { - /* Add not used table to the total table list */ - if (!(cursor = (TABLE_LIST *) thd->memdup((char*) aux, - sizeof(*aux)))) - { - send_error(&thd->net,0); - return 1; - } - *new_table_list= cursor; - new_table_list= &cursor->next; - *new_table_list=0; // end result list - } - else - aux->shared=1; // Mark that it's used twice - aux->table=(TABLE *) cursor; - } - } - } - return 0; -} - - void add_join_on(TABLE_LIST *b,Item *expr) { if (expr) @@ -3488,9 +3650,9 @@ void kill_one_thread(THD *thd, ulong id) } if (!error) - send_ok(&thd->net); + send_ok(thd); else - net_printf(&thd->net,error,id); + net_printf(thd,error,id); } /* Clear most status variables */ @@ -3548,12 +3710,12 @@ static bool append_file_to_dir(THD *thd, char **filename_ptr, char *table_name) bool check_simple_select() { THD *thd= current_thd; - if (thd->lex.select != &thd->lex.select_lex) + if (thd->lex.current_select != &thd->lex.select_lex) { char command[80]; strmake(command, thd->lex.yylval->symbol.str, min(thd->lex.yylval->symbol.length, sizeof(command)-1)); - net_printf(&thd->net, ER_CANT_USE_OPTION_HERE, command); + net_printf(thd, ER_CANT_USE_OPTION_HERE, command); return 1; } return 0; diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc new file mode 100644 index 00000000000..08377a10501 --- /dev/null +++ b/sql/sql_prepare.cc @@ -0,0 +1,835 @@ +/* Copyright (C) 1995-2002 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 +*/ + +/********************************************************************** +This file contains the implementation of prepare and executes. + +Prepare: + + - Server gets the query from client with command 'COM_PREPARE' + - Parse the query and recognize any parameter markers '?' and + store its information list lex->param_list + - Without executing the query, return back to client the total + number of parameters along with result-set metadata information + (if any) + +Prepare-execute: + + - Server gets the command 'COM_EXECUTE' to execute the + previously prepared query. + - If there is are any parameters, then replace the markers with the + data supplied by client with the following format: + [types_specified(0/1)][type][length][data] .. [type][length].. + - Execute the query without re-parsing and send back the results + to client + +Long data handling: + - Server gets the long data in pieces with command type 'COM_LONG_DATA'. + - The packet recieved will have the format as: + [COM_LONG_DATA:1][parameter_number:2][type:2][data] + - Checks if the type is specified by client, and if yes reads the type, + and stores the data in that format. + - It's up to the client to check for read data ended. The server doesn't + care. + +***********************************************************************/ + +#include "mysql_priv.h" +#include "sql_acl.h" +#include <assert.h> // for DEBUG_ASSERT() +#include <m_ctype.h> // for isspace() + +extern int yyparse(void); +static ulong get_param_length(uchar **packet); +static uint get_buffer_type(uchar **packet); +static bool param_is_null(uchar **packet); +static bool setup_param_fields(THD *thd,List<Item> ¶ms); +static uchar* setup_param_field(Item_param *item_param, uchar *pos, + uint buffer_type); +static void setup_longdata_field(Item_param *item_param, uchar *pos); +static bool setup_longdata(THD *thd,List<Item> ¶ms); +static bool send_prepare_results(PREP_STMT *stmt); +static bool parse_prepare_query(PREP_STMT *stmt, char *packet, uint length); +static bool mysql_send_insert_fields(PREP_STMT *stmt, TABLE_LIST *table_list, + List<Item> &fields, + List<List_item> &values_list, + thr_lock_type lock_type); +static bool mysql_test_insert_fields(PREP_STMT *stmt, TABLE_LIST *table_list, + List<Item> &fields, + List<List_item> &values_list, + thr_lock_type lock_type); +static bool mysql_test_upd_fields(PREP_STMT *stmt, TABLE_LIST *table_list, + List<Item> &fields, List<Item> &values, + COND *conds,thr_lock_type lock_type); +static bool mysql_test_select_fields(PREP_STMT *stmt, TABLE_LIST *tables, + List<Item> &fields, List<Item> &values, + COND *conds, ORDER *order, ORDER *group, + Item *having,thr_lock_type lock_type); + + +/* + Find prepared statement in thd + + SYNOPSIS + find_prepared_statement() + thd Thread handler + stmt_id Statement id server specified to the client on prepare + + RETURN VALUES + 0 error. In this case the error is sent with my_error() + ptr Pointer to statement +*/ + +static PREP_STMT *find_prepared_statement(THD *thd, ulong stmt_id, + const char *when) +{ + PREP_STMT *stmt; + DBUG_ENTER("find_prepared_statement"); + DBUG_PRINT("enter",("stmt_id: %d", stmt_id)); + + if (thd->last_prepared_stmt && thd->last_prepared_stmt->stmt_id == stmt_id) + DBUG_RETURN(thd->last_prepared_stmt); + if ((stmt= (PREP_STMT*) tree_search(&thd->prepared_statements, &stmt_id, + (void*) 0))) + DBUG_RETURN (thd->last_prepared_stmt= stmt); + my_error(ER_UNKNOWN_STMT_HANDLER, MYF(0), stmt_id, when); + DBUG_RETURN(0); +} + +/* + Compare two prepared statements; Used to find a prepared statement +*/ + +int compare_prep_stmt(PREP_STMT *a, PREP_STMT *b, void *not_used) +{ + return (a->stmt_id < b->stmt_id) ? -1 : (a->stmt_id == b->stmt_id) ? 0 : 1; +} + + +/* + Free prepared statement. + + SYNOPSIS + standard tree_element_free function. + + DESCRIPTION + We don't have to free the stmt itself as this was stored in the tree + and will be freed when the node is deleted +*/ + +void free_prep_stmt(PREP_STMT *stmt, TREE_FREE mode, void *not_used) +{ + free_root(&stmt->mem_root, MYF(0)); + free_items(stmt->free_list); +} + +/* + Send prepared stmt info to client after prepare +*/ + +bool send_prep_stmt(PREP_STMT *stmt, uint columns) +{ + char buff[8]; + int4store(buff, stmt->stmt_id); + int2store(buff+4, columns); + int2store(buff+6, stmt->param_count); + return my_net_write(&stmt->thd->net, buff, sizeof(buff)); +} + +/* + Send information about all item parameters + + TODO: Not yet ready +*/ + +bool send_item_params(PREP_STMT *stmt) +{ + char buff[1]; + buff[0]=0; + return my_net_write(&stmt->thd->net, buff, sizeof(buff)); +} + + + +/* + Read the buffer type, this happens only first time +*/ + +static uint get_buffer_type(uchar **packet) +{ + reg1 uchar *pos= *packet; + (*packet)+= 2; + return (uint) uint2korr(pos); +} + + +/* + Check for NULL param data + + RETURN VALUES + 0 Value was not NULL + 1 Value was NULL +*/ + +static bool param_is_null(uchar **packet) +{ + reg1 uchar *pos= *packet; + if (*pos == 251) + { + (*packet)++; + return 1; + } + return 0; +} + +/* + Read the length of the parameter data and retun back to + caller by positing the pointer to param data +*/ + +static ulong get_param_length(uchar **packet) +{ + reg1 uchar *pos= *packet; + if (*pos < 251) + { + (*packet)++; + return (ulong) *pos; + } + if (*pos == 252) + { + (*packet)+=3; + return (ulong) uint2korr(pos+1); + } + if (*pos == 253) + { + (*packet)+=4; + return (ulong) uint3korr(pos+1); + } + (*packet)+=9; // Must be 254 when here + return (ulong) uint4korr(pos+1); +} + +/* + Read and return the data for parameters supplied by client +*/ + +static uchar* setup_param_field(Item_param *item_param, + uchar *pos, uint buffer_type) +{ + if (param_is_null(&pos)) + { + item_param->set_null(); + return(pos); + } + switch (buffer_type) { + case FIELD_TYPE_TINY: + item_param->set_int((longlong)(*pos)); + pos += 1; + break; + case FIELD_TYPE_SHORT: + item_param->set_int((longlong)sint2korr(pos)); + pos += 2; + break; + case FIELD_TYPE_INT24: + item_param->set_int((longlong)sint4korr(pos)); + pos += 3; + break; + case FIELD_TYPE_LONG: + item_param->set_int((longlong)sint4korr(pos)); + pos += 4; + break; + case FIELD_TYPE_LONGLONG: + item_param->set_int((longlong)sint8korr(pos)); + pos += 8; + break; + case FIELD_TYPE_FLOAT: + float data; + float4get(data,pos); + item_param->set_double((double) data); + pos += 4; + break; + case FIELD_TYPE_DOUBLE: + double j; + float8get(j,pos) + item_param->set_double(j); + pos += 8; + break; + default: + { + ulong len=get_param_length(&pos); + item_param->set_value((const char*)pos,len,current_thd->thd_charset); + pos+=len; + } + } + return(pos); +} + +/* + Update the parameter markers by reading the data + from client .. +*/ + +static bool setup_param_fields(THD *thd, PREP_STMT *stmt) +{ + DBUG_ENTER("setup_param_fields"); +#ifdef READY_TO_BE_USED + Item_param *item_param; + ulong param_count=0; + uchar *pos=(uchar*) thd->net.read_pos+1;// skip command type + + + if (*pos++) // No types supplied, read only param data + { + while ((item_param=(Item_param *)it++) && + (param_count++ < stmt->param_count)) + { + if (item_param->long_data_supplied) + continue; + + if (!(pos=setup_param_field(item_param,pos,item_param->buffer_type))) + DBUG_RETURN(1); + } + } + else // Types supplied, read and store it along with param data + { + while ((item_param=(Item_param *)it++) && + (param_count++ < thd->param_count)) + { + if (item_param->long_data_supplied) + continue; + + if (!(pos=setup_param_field(item_param,pos, + item_param->buffer_type= + (enum_field_types) get_buffer_type(&pos)))) + DBUG_RETURN(1); + } + } +#endif + DBUG_RETURN(0); +} + + +/* + Validates insert fields +*/ + +static int check_prepare_fields(THD *thd,TABLE *table, List<Item> &fields, + List<Item> &values, ulong counter) +{ + if (fields.elements == 0 && values.elements != 0) + { + if (values.elements != table->fields) + { + my_printf_error(ER_WRONG_VALUE_COUNT_ON_ROW, + ER(ER_WRONG_VALUE_COUNT_ON_ROW), + MYF(0),counter); + return -1; + } + } + else + { + if (fields.elements != values.elements) + { + my_printf_error(ER_WRONG_VALUE_COUNT_ON_ROW, + ER(ER_WRONG_VALUE_COUNT_ON_ROW), + MYF(0),counter); + return -1; + } + TABLE_LIST table_list; + bzero((char*) &table_list,sizeof(table_list)); + table_list.db= table->table_cache_key; + table_list.real_name= table_list.alias= table->table_name; + table_list.table= table; + table_list.grant= table->grant; + + thd->dupp_field=0; + if (setup_tables(&table_list) || + setup_fields(thd,&table_list,fields,1,0,0)) + return -1; + if (thd->dupp_field) + { + my_error(ER_FIELD_SPECIFIED_TWICE,MYF(0), thd->dupp_field->field_name); + return -1; + } + } + return 0; +} + + +/* + Validate the following information for INSERT statement: + - field existance + - fields count +*/ + +static bool mysql_test_insert_fields(PREP_STMT *stmt, + TABLE_LIST *table_list, + List<Item> &fields, + List<List_item> &values_list, + thr_lock_type lock_type) +{ + THD *thd= stmt->thd; + TABLE *table; + List_iterator_fast<List_item> its(values_list); + List_item *values; + DBUG_ENTER("mysql_test_insert_fields"); + + if (!(table = open_ltable(thd,table_list,lock_type))) + DBUG_RETURN(1); + + if ((values= its++)) + { + uint value_count; + ulong counter= 0; + + if (check_insert_fields(thd,table,fields,*values,1)) + DBUG_RETURN(1); + + value_count= values->elements; + its.rewind(); + + while ((values= its++)) + { + counter++; + if (values->elements != value_count) + { + my_printf_error(ER_WRONG_VALUE_COUNT_ON_ROW, + ER(ER_WRONG_VALUE_COUNT_ON_ROW), + MYF(0), counter); + DBUG_RETURN(1); + } + } + } + if (send_prep_stmt(stmt, 0) || send_item_params(stmt)) + DBUG_RETURN(1); + DBUG_RETURN(0); +} + + +/* + Validate the following information + UPDATE - set and where clause DELETE - where clause + + And send update-set clause column list fields info + back to client. For DELETE, just validate where clause + and return no fields information back to client. +*/ + +static bool mysql_test_upd_fields(PREP_STMT *stmt, TABLE_LIST *table_list, + List<Item> &fields, List<Item> &values, + COND *conds, thr_lock_type lock_type) +{ + THD *thd= stmt->thd; + TABLE *table; + DBUG_ENTER("mysql_test_upd_fields"); + + if (!(table = open_ltable(thd,table_list,lock_type))) + DBUG_RETURN(1); + + if (setup_tables(table_list) || setup_fields(thd,table_list,fields,1,0,0) || + setup_conds(thd,table_list,&conds)) + DBUG_RETURN(1); + + /* + Currently return only column list info only, and we are not + sending any info on where clause. + */ + if (send_prep_stmt(stmt, 0) || send_item_params(stmt)) + DBUG_RETURN(1); + DBUG_RETURN(0); +} + +/* + Validate the following information: + + SELECT - column list + - where clause + - order clause + - having clause + - group by clause + - if no column spec i.e. '*', then setup all fields + + And send column list fields info back to client. +*/ + +static bool mysql_test_select_fields(PREP_STMT *stmt, TABLE_LIST *tables, + List<Item> &fields, List<Item> &values, + COND *conds, ORDER *order, ORDER *group, + Item *having, thr_lock_type lock_type) +{ + TABLE *table; + bool hidden_group_fields; + THD *thd= stmt->thd; + List<Item> all_fields(fields); + DBUG_ENTER("mysql_test_select_fields"); + + if (!(table = open_ltable(thd,tables,lock_type))) + DBUG_RETURN(1); + + thd->used_tables=0; // Updated by setup_fields + if (setup_tables(tables) || + setup_fields(thd,tables,fields,1,&all_fields,1) || + setup_conds(thd,tables,&conds) || + setup_order(thd,tables,fields,all_fields,order) || + setup_group(thd,tables,fields,all_fields,group,&hidden_group_fields)) + DBUG_RETURN(1); + + if (having) + { + thd->where="having clause"; + thd->allow_sum_func=1; + if (having->fix_fields(thd, tables, &having) || thd->fatal_error) + DBUG_RETURN(1); + if (having->with_sum_func) + having->split_sum_func(all_fields); + } + if (setup_ftfuncs(&thd->lex.select_lex)) + DBUG_RETURN(1); + + /* + Currently return only column list info only, and we are not + sending any info on where clause. + */ + if (send_prep_stmt(stmt, fields.elements) || + send_fields(thd,fields,0) || send_item_params(stmt)) + DBUG_RETURN(1); + DBUG_RETURN(0); +} + + +/* + Check the access privileges +*/ + +static bool check_prepare_access(THD *thd, TABLE_LIST *tables, + uint type) +{ + if (check_access(thd,type,tables->db,&tables->grant.privilege)) + return 1; + if (grant_option && check_grant(thd,type,tables)) + return 1; + return 0; +} + +/* + Send the prepare query results back to client +*/ + +static bool send_prepare_results(PREP_STMT *stmt) +{ + THD *thd= stmt->thd; + LEX *lex= &thd->lex; + enum enum_sql_command sql_command = thd->lex.sql_command; + DBUG_ENTER("send_prepare_results"); + DBUG_PRINT("enter",("command: %d, param_count: %ld", + sql_command, lex->param_count)); + + /* Setup prepared stmt */ + stmt->param_count= lex->param_count; + stmt->free_list= thd->free_list; // Save items used in stmt + thd->free_list= 0; + + SELECT_LEX *select_lex = &lex->select_lex; + TABLE_LIST *tables=(TABLE_LIST*) select_lex->table_list.first; + + switch (sql_command) { + + case SQLCOM_INSERT: + if (mysql_test_insert_fields(stmt, tables, lex->field_list, + lex->many_values, lex->lock_option)) + goto abort; + break; + + case SQLCOM_UPDATE: + if (mysql_test_upd_fields(stmt, tables, select_lex->item_list, + lex->value_list, select_lex->where, + lex->lock_option)) + goto abort; + break; + + case SQLCOM_DELETE: + if (mysql_test_upd_fields(stmt, tables, select_lex->item_list, + lex->value_list, select_lex->where, + lex->lock_option)) + goto abort; + break; + + case SQLCOM_SELECT: + if (mysql_test_select_fields(stmt, tables, select_lex->item_list, + lex->value_list, select_lex->where, + (ORDER*) select_lex->order_list.first, + (ORDER*) select_lex->group_list.first, + select_lex->having, lex->lock_option)) + goto abort; + break; + + default: + { + /* + Rest fall through to default category, no parsing + for non-DML statements + */ + } + } + DBUG_RETURN(0); + +abort: + send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN : 0); + DBUG_RETURN(1); +} + +/* + Parse the prepare query +*/ + +static bool parse_prepare_query(PREP_STMT *stmt, + char *packet, uint length) +{ + bool error= 1; + THD *thd= stmt->thd; + DBUG_ENTER("parse_prepare_query"); + + mysql_log.write(thd,COM_PREPARE,"%s",packet); + mysql_init_query(thd); + thd->prepare_command=true; + thd->safe_to_cache_query= 0; + + LEX *lex=lex_start(thd, (uchar*) packet, length); + if (!yyparse() && !thd->fatal_error) + error= send_prepare_results(stmt); + lex_end(lex); + DBUG_RETURN(error); +} + + +/* + Parse the query and send the total number of parameters + and resultset metadata information back to client (if any), + without executing the query i.e. with out any log/disk + writes. This will allow the queries to be re-executed + without re-parsing during execute. + + If parameter markers are found in the query, then store + the information using Item_param along with maintaining a + list in lex->param_list, so that a fast and direct + retrieveal can be made without going through all field + items. +*/ + +bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length) +{ + MEM_ROOT thd_root = thd->mem_root; + PREP_STMT stmt; + DBUG_ENTER("mysql_stmt_prepare"); + + bzero((char*) &stmt, sizeof(stmt)); + stmt.thd= thd; + stmt.stmt_id= ++thd->current_stmt_id; + init_sql_alloc(&stmt.mem_root, 8192, 8192); + + thd->mem_root= stmt.mem_root; + if (alloc_query(thd, packet, packet_length)) + goto err; + if (parse_prepare_query(&stmt, thd->query, thd->query_length)) + goto err; + + if (!(specialflag & SPECIAL_NO_PRIOR)) + my_pthread_setprio(pthread_self(),WAIT_PRIOR); + + stmt.mem_root= thd->mem_root; + thd->mem_root= thd_root; // restore main mem_root + DBUG_RETURN(0); + +err: + stmt.mem_root= thd->mem_root; + free_prep_stmt(&stmt, free_free, (void*) 0); + thd->mem_root = thd_root; // restore main mem_root + DBUG_RETURN(1); +} + + +/* + Executes previously prepared query + + If there is any parameters(thd->param_count), then replace + markers with the data supplied from client, and then + execute the query +*/ + +void mysql_stmt_execute(THD *thd, char *packet) +{ + ulong stmt_id= uint4korr(packet); + PREP_STMT *stmt; + DBUG_ENTER("mysql_stmt_execute"); + + if (!(stmt=find_prepared_statement(thd, stmt_id, "execute"))) + { + send_error(thd); + DBUG_VOID_RETURN; + } + + /* Check if we got an error when sending long data */ + if (stmt->error_in_prepare) + { + send_error(thd); + DBUG_VOID_RETURN; + } + + if (stmt->param_count && setup_param_fields(thd, stmt)) + DBUG_VOID_RETURN; + + MEM_ROOT thd_root= thd->mem_root; + thd->mem_root = thd->con_root; + if (!(specialflag & SPECIAL_NO_PRIOR)) + my_pthread_setprio(pthread_self(),QUERY_PRIOR); + + /* + TODO: + Also, have checks on basic executions such as mysql_insert(), + mysql_delete(), mysql_update() and mysql_select() to not to + have re-check on setup_* and other things .. + */ + mysql_execute_command(thd); + + if (!(specialflag & SPECIAL_NO_PRIOR)) + my_pthread_setprio(pthread_self(), WAIT_PRIOR); + + thd->mem_root= thd_root; + DBUG_VOID_RETURN; +} + + +/* + Reset a prepared statement + + SYNOPSIS + mysql_stmt_reset() + thd Thread handle + packet Packet with stmt handle + + DESCRIPTION + This function is useful when one gets an error after calling + mysql_stmt_getlongdata() and one wants to reset the handle + so that one can call execute again. +*/ + +void mysql_stmt_reset(THD *thd, char *packet) +{ + ulong stmt_id= uint4korr(packet); + PREP_STMT *stmt; + DBUG_ENTER("mysql_stmt_reset"); + + if (!(stmt=find_prepared_statement(thd, stmt_id, "close"))) + { + send_error(thd); + DBUG_VOID_RETURN; + } + + stmt->error_in_prepare=0; + Item_param *item= stmt->param, *end= item + stmt->param_count; + + /* Free long data if used */ + if (stmt->long_data_used) + { + stmt->long_data_used= 0; + for (; item < end ; item++) + item->reset(); + } + DBUG_VOID_RETURN; +} + + +/* + Delete a prepared statement from memory +*/ + +void mysql_stmt_close(THD *thd, char *packet) +{ + ulong stmt_id= uint4korr(packet); + PREP_STMT *stmt; + DBUG_ENTER("mysql_stmt_close"); + + if (!(stmt=find_prepared_statement(thd, stmt_id, "close"))) + { + send_error(thd); + DBUG_VOID_RETURN; + } + /* Will call free_prep_stmt() */ + tree_delete(&thd->prepared_statements, (void*) stmt, NULL); + thd->last_prepared_stmt=0; + DBUG_VOID_RETURN; +} + + +/* + Long data in pieces from client + + SYNOPSIS + mysql_stmt_get_longdata() + thd Thread handle + pos String to append + packet_length Length of string + + DESCRIPTION + Get a part of a long data. + To make the protocol efficient, we are not sending any return packages + here. + If something goes wrong, then we will send the error on 'execute' + + We assume that the client takes care of checking that all parts are sent + to the server. (No checking that we get a 'end of column' in the server) +*/ + +void mysql_stmt_get_longdata(THD *thd, char *pos, ulong packet_length) +{ + PREP_STMT *stmt; + DBUG_ENTER("mysql_stmt_get_longdata"); + + /* The following should never happen */ + if (packet_length < 9) + { + my_error(ER_WRONG_ARGUMENTS, MYF(0), "get_longdata"); + DBUG_VOID_RETURN; + } + + pos++; // skip command type at first position + ulong stmt_id= uint4korr(pos); + uint param_number= uint2korr(pos+4); + uint param_type= uint2korr(pos+6); + pos+=8; // Point to data + + if (!(stmt=find_prepared_statement(thd, stmt_id, "get_longdata"))) + { + /* + There is a chance that the client will never see this as + it doesn't expect an answer from this call... + */ + send_error(thd); + DBUG_VOID_RETURN; + } + + if (param_number >= stmt->param_count) + { + stmt->error_in_prepare=1; + stmt->last_errno=ER_WRONG_ARGUMENTS; + sprintf(stmt->last_error, ER(ER_WRONG_ARGUMENTS), "get_longdata"); + DBUG_VOID_RETURN; + } + stmt->param[param_number].set_longdata(pos, packet_length-9, current_thd->thd_charset); + stmt->long_data_used= 1; + DBUG_VOID_RETURN; +} diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc index 3eddd2646d5..5b0ec2ec843 100644 --- a/sql/sql_rename.cc +++ b/sql/sql_rename.cc @@ -97,7 +97,7 @@ end: Query_log_event qinfo(thd, thd->query, thd->query_length, 0); mysql_bin_log.write(&qinfo); } - send_ok(&thd->net); + send_ok(thd); } for (TABLE_LIST *table=table_list ; table != lock_table ; table=table->next) diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index ee16b84f87e..23951cec29f 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -283,11 +283,11 @@ binlog purge"; break; if (errmsg) { - send_error(&thd->net, 0, errmsg); + send_error(thd, 0, errmsg); return 1; } else - send_ok(&thd->net); + send_ok(thd); return 0; } @@ -372,7 +372,7 @@ impossible position"; We need to start a packet with something other than 255 to distiquish it from error */ - packet->set("\0", 1); + packet->set("\0", 1, system_charset_info); // if we are at the start of the log if (pos == BIN_LOG_HEADER_SIZE) @@ -383,7 +383,7 @@ impossible position"; my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG; goto err; } - packet->set("\0", 1); + packet->set("\0", 1, system_charset_info); } while (!net->error && net->vio != 0 && !thd->killed) @@ -418,7 +418,7 @@ impossible position"; goto err; } } - packet->set("\0", 1); + packet->set("\0", 1, system_charset_info); } /* TODO: now that we are logging the offset, check to make sure @@ -538,7 +538,7 @@ Increase max_allowed_packet on master"; goto err; } } - packet->set("\0", 1); + packet->set("\0", 1, system_charset_info); /* No need to net_flush because we will get to flush later when we hit EOF pretty quick @@ -593,7 +593,7 @@ Increase max_allowed_packet on master"; end_io_cache(&log); (void)my_close(file, MYF(MY_WME)); - send_eof(&thd->net); + send_eof(thd); thd->proc_info = "waiting to finalize termination"; pthread_mutex_lock(&LOCK_thread_count); thd->current_linfo = 0; @@ -615,15 +615,15 @@ Increase max_allowed_packet on master"; pthread_mutex_unlock(&LOCK_thread_count); if (file >= 0) (void) my_close(file, MYF(MY_WME)); - send_error(&thd->net, my_errno, errmsg); + send_error(thd, my_errno, errmsg); DBUG_VOID_RETURN; } int start_slave(THD* thd , MASTER_INFO* mi, bool net_report) { int slave_errno = 0; - if (!thd) thd = current_thd; - NET* net = &thd->net; + if (!thd) + thd = current_thd; int thread_mask; DBUG_ENTER("start_slave"); @@ -654,20 +654,21 @@ int start_slave(THD* thd , MASTER_INFO* mi, bool net_report) if (slave_errno) { if (net_report) - send_error(net, slave_errno); + send_error(thd, slave_errno); DBUG_RETURN(1); } else if (net_report) - send_ok(net); + send_ok(thd); DBUG_RETURN(0); } + int stop_slave(THD* thd, MASTER_INFO* mi, bool net_report ) { int slave_errno = 0; - if (!thd) thd = current_thd; - NET* net = &thd->net; + if (!thd) + thd = current_thd; if (check_access(thd, SUPER_ACL, any_db)) return 1; @@ -686,11 +687,11 @@ int stop_slave(THD* thd, MASTER_INFO* mi, bool net_report ) if (slave_errno) { if (net_report) - send_error(net, slave_errno); + send_error(thd, slave_errno); return 1; } else if (net_report) - send_ok(net); + send_ok(thd); return 0; } @@ -779,7 +780,7 @@ int change_master(THD* thd, MASTER_INFO* mi) restart_thread_mask, 1 /*skip lock*/))) { - send_error(&thd->net,error); + send_error(thd,error); unlock_slave_threads(mi); DBUG_RETURN(1); } @@ -788,7 +789,7 @@ int change_master(THD* thd, MASTER_INFO* mi) // TODO: see if needs re-write if (init_master_info(mi, master_info_file, relay_log_info_file, 0)) { - send_error(&thd->net, 0, "Could not initialize master info"); + send_error(thd, 0, "Could not initialize master info"); unlock_slave_threads(mi); DBUG_RETURN(1); } @@ -850,7 +851,7 @@ int change_master(THD* thd, MASTER_INFO* mi) 0 /* not only reset, but also reinit */, &errmsg)) { - net_printf(&thd->net, 0, "Failed purging old relay logs: %s",errmsg); + net_printf(thd, 0, "Failed purging old relay logs: %s",errmsg); DBUG_RETURN(1); } } @@ -864,7 +865,7 @@ int change_master(THD* thd, MASTER_INFO* mi) 0 /*no data lock*/, &msg)) { - net_printf(&thd->net,0,"Failed initializing relay log position: %s",msg); + net_printf(thd,0,"Failed initializing relay log position: %s",msg); unlock_slave_threads(mi); DBUG_RETURN(1); } @@ -890,9 +891,9 @@ int change_master(THD* thd, MASTER_INFO* mi) unlock_slave_threads(mi); thd->proc_info = 0; if (error) - send_error(&thd->net,error); + send_error(thd,error); else - send_ok(&thd->net); + send_ok(thd); DBUG_RETURN(0); } @@ -948,8 +949,8 @@ int show_binlog_events(THD* thd) LOG_INFO linfo; Log_event* ev; - limit_start = thd->lex.select->offset_limit; - limit_end = thd->lex.select->select_limit + limit_start; + limit_start = thd->lex.current_select->offset_limit; + limit_end = thd->lex.current_select->select_limit + limit_start; name= search_file_name; if (log_file_name) @@ -1021,7 +1022,7 @@ err: DBUG_RETURN(-1); } - send_eof(&thd->net); + send_eof(thd); DBUG_RETURN(0); } @@ -1052,7 +1053,7 @@ int show_binlog_info(THD* thd) if (my_net_write(&thd->net, (char*)thd->packet.ptr(), packet->length())) DBUG_RETURN(-1); } - send_eof(&thd->net); + send_eof(thd); DBUG_RETURN(0); } @@ -1105,11 +1106,11 @@ int show_binlogs(THD* thd) goto err; } mysql_bin_log.unlock_index(); - send_eof(net); + send_eof(thd); return 0; err_with_msg: - send_error(net, 0, errmsg); + send_error(thd, ER_UNKNOWN_ERROR, errmsg); err: mysql_bin_log.unlock_index(); return 1; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index a7e378420f2..20b000392df 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -38,7 +38,8 @@ static bool make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds, DYNAMIC_ARRAY *keyuse); static bool update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse, JOIN_TAB *join_tab, - uint tables,COND *conds,table_map table_map); + uint tables, COND *conds, + table_map table_map, SELECT_LEX *select_lex); static int sort_keyuse(KEYUSE *a,KEYUSE *b); static void set_position(JOIN *join,uint index,JOIN_TAB *table,KEYUSE *key); static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse, @@ -65,7 +66,8 @@ static ORDER *remove_const(JOIN *join,ORDER *first_order,COND *cond, static int return_zero_rows(JOIN *join, select_result *res,TABLE_LIST *tables, List<Item> &fields, bool send_row, uint select_options, const char *info, - Item *having, Procedure *proc); + Item *having, Procedure *proc, + SELECT_LEX_UNIT *unit); static COND *optimize_cond(COND *conds,Item::cond_result *cond_value); static COND *remove_eq_conds(COND *cond,Item::cond_result *cond_value); static bool const_expression_in_where(COND *conds,Item *item, Item **comp_item); @@ -111,7 +113,9 @@ static Item* part_of_refkey(TABLE *form,Field *field); static uint find_shortest_key(TABLE *table, key_map usable_keys); static bool test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order, ha_rows select_limit, bool no_changes); -static int create_sort_index(JOIN_TAB *tab,ORDER *order,ha_rows filesort_limit, +static int create_sort_index(THD *thd, JOIN_TAB *tab,ORDER *order, + ha_rows filesort_limit, ha_rows select_limit); +static int create_sort_index(THD *thd, JOIN_TAB *tab,ORDER *order, ha_rows select_limit); static int remove_duplicates(JOIN *join,TABLE *entry,List<Item> &fields, Item *having); @@ -126,8 +130,6 @@ static bool store_record_in_cache(JOIN_CACHE *cache); static void reset_cache(JOIN_CACHE *cache); static void read_cached_record(JOIN_TAB *tab); static bool cmp_buffer_with_ref(JOIN_TAB *tab); -static int setup_group(THD *thd,TABLE_LIST *tables,List<Item> &fields, - List<Item> &all_fields, ORDER *order, bool *hidden); static bool setup_new_fields(THD *thd,TABLE_LIST *tables,List<Item> &fields, List<Item> &all_fields,ORDER *new_order); static ORDER *create_distinct_group(ORDER *order, List<Item> &fields); @@ -146,7 +148,7 @@ static void init_sum_functions(Item_sum **func); static bool update_sum_func(Item_sum **func); static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, bool distinct, const char *message=NullS); -static void describe_info(JOIN *join, const char *info); + /* This handles SELECT with and without UNION @@ -156,26 +158,8 @@ int handle_select(THD *thd, LEX *lex, select_result *result) { int res; register SELECT_LEX *select_lex = &lex->select_lex; - -#ifdef DISABLED_UNTIL_REWRITTEN_IN_4_1 - if (lex->olap) - { - SELECT_LEX *sl, *sl_next; - int error; - for (sl= &select_lex; sl; sl=sl_next) - { - sl_next=sl->next; // Save if sl->next changes - if (sl->olap != UNSPECIFIED_OLAP_TYPE) - { - if ((error=handle_olaps(lex,sl))) - return error; - lex->last_selects->next=sl_next; - } - } - lex->select = select_lex; - } -#endif /* DISABLED_UNTIL_REWRITTEN_IN_4_1 */ - if (select_lex->next) + fix_tables_pointers(select_lex); + if (select_lex->next_select()) res=mysql_union(thd,lex,result); else res=mysql_select(thd,(TABLE_LIST*) select_lex->table_list.first, @@ -186,66 +170,88 @@ int handle_select(THD *thd, LEX *lex, select_result *result) select_lex->having, (ORDER*) lex->proc_list.first, select_lex->options | thd->options, - result); + result, &(lex->unit), &(lex->select_lex), 0); if (res && result) result->abort(); + if (res || thd->net.report_error) + { + send_error(thd, 0, NullS); + res= 1; + } delete result; return res; } +void fix_tables_pointers(SELECT_LEX *select_lex) +{ + if (select_lex->next_select_in_list()) + { + /* Fix tables 'to-be-unioned-from' list to point at opened tables */ + for (SELECT_LEX *sl= select_lex; + sl; + sl= sl->next_select_in_list()) + { + for (TABLE_LIST *cursor= (TABLE_LIST *)sl->table_list.first; + cursor; + cursor=cursor->next) + cursor->table= cursor->table_list->table; + } + } +} /***************************************************************************** Check fields, find best join, do the select and output fields. mysql_select assumes that all tables are already opened *****************************************************************************/ +/* + Prepare of whole select (including subselect in future). + return -1 on error + 0 on success +*/ int -mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds, - ORDER *order, ORDER *group,Item *having,ORDER *proc_param, - ulong select_options,select_result *result) -{ - TABLE *tmp_table; - int error, tmp_error; - bool need_tmp,hidden_group_fields; - bool simple_order,simple_group,no_order, skip_sort_order; - ha_rows select_limit; - Item::cond_result cond_value; - SQL_SELECT *select; - DYNAMIC_ARRAY keyuse; - JOIN join; - Procedure *procedure; - List<Item> all_fields(fields); - bool select_distinct; - SELECT_LEX *cur_sel = thd->lex.select; - DBUG_ENTER("mysql_select"); - +JOIN::prepare(TABLE_LIST *tables_init, + COND *conds_init, ORDER *order_init, ORDER *group_init, + Item *having_init, + ORDER *proc_param_init, SELECT_LEX *select, + SELECT_LEX_UNIT *unit, bool fake_select_lex) +{ + DBUG_ENTER("JOIN::prepare"); + + conds= conds_init; + order= order_init; + group_list= group_init; + having= having_init; + proc_param= proc_param_init; + tables_list= tables_init; + select_lex= select; + if (!fake_select_lex) + select_lex->join= this; + union_part= (unit->first_select()->next_select() != 0); + /* Check that all tables, fields, conds and order are ok */ - select_distinct=test(select_options & SELECT_DISTINCT); - tmp_table=0; - select=0; - no_order=skip_sort_order=0; - bzero((char*) &keyuse,sizeof(keyuse)); - thd->proc_info="init"; - thd->used_tables=0; // Updated by setup_fields - - if (setup_tables(tables) || - setup_fields(thd,tables,fields,1,&all_fields,1) || - setup_conds(thd,tables,&conds) || - setup_order(thd,tables,fields,all_fields,order) || - setup_group(thd,tables,fields,all_fields,group,&hidden_group_fields)) + if (setup_tables(tables_list) || + setup_fields(thd,tables_list,fields_list,1,&all_fields,1) || + setup_conds(thd,tables_list,&conds) || + setup_order(thd,tables_list,fields_list,all_fields,order) || + setup_group(thd,tables_list,fields_list,all_fields,group_list, + &hidden_group_fields)) DBUG_RETURN(-1); /* purecov: inspected */ if (having) { thd->where="having clause"; thd->allow_sum_func=1; - if (having->fix_fields(thd,tables) || thd->fatal_error) + select_lex->having_fix_field= 1; + bool having_fix_rc= having->fix_fields(thd, tables_list, &having); + select_lex->having_fix_field= 0; + if (having_fix_rc || thd->net.report_error) DBUG_RETURN(-1); /* purecov: inspected */ if (having->with_sum_func) having->split_sum_func(all_fields); } - if (setup_ftfuncs(thd)) /* should be after having->fix_fields */ + if (setup_ftfuncs(select_lex)) /* should be after having->fix_fields */ DBUG_RETURN(-1); /* Check if one one uses a not constant column with group functions @@ -253,13 +259,11 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds, TODO: Add check of calculation of GROUP functions and fields: SELECT COUNT(*)+table.col1 from table1; */ - join.table=0; - join.tables=0; { - if (!group) + if (!group_list) { uint flag=0; - List_iterator_fast<Item> it(fields); + List_iterator_fast<Item> it(fields_list); Item *item; while ((item= it++)) { @@ -275,22 +279,23 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds, } } TABLE_LIST *table; - for (table=tables ; table ; table=table->next) - join.tables++; + for (table=tables_list ; table ; table=table->next) + tables++; } - procedure=setup_procedure(thd,proc_param,result,fields,&error); + procedure=setup_procedure(thd,proc_param,result,fields_list,&error); if (error) DBUG_RETURN(-1); /* purecov: inspected */ if (procedure) { - if (setup_new_fields(thd,tables,fields,all_fields,procedure->param_fields)) + if (setup_new_fields(thd, tables_list, fields_list, all_fields, + procedure->param_fields)) { /* purecov: inspected */ delete procedure; /* purecov: inspected */ DBUG_RETURN(-1); /* purecov: inspected */ } if (procedure->group) { - if (!test_if_subpart(procedure->group,group)) + if (!test_if_subpart(procedure->group,group_list)) { /* purecov: inspected */ my_message(0,"Can't handle procedures with differents groups yet", MYF(0)); /* purecov: inspected */ @@ -299,7 +304,7 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds, } } #ifdef NOT_NEEDED - else if (!group && procedure->flags & PROC_GROUP) + else if (!group_list && procedure->flags & PROC_GROUP) { my_message(0,"Select must have a group with this procedure",MYF(0)); delete procedure; @@ -315,150 +320,139 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds, } /* Init join struct */ - join.thd=thd; - join.lock=thd->lock; - join.join_tab=0; - join.tmp_table_param.copy_field=0; - join.sum_funcs=0; - join.send_records=join.found_records=join.examined_rows=0; - join.tmp_table_param.end_write_records= HA_POS_ERROR; - join.first_record=join.sort_and_group=0; - join.select_options=select_options; - join.result=result; - count_field_types(&join.tmp_table_param,all_fields,0); - join.const_tables=0; - join.having=0; - join.do_send_rows = 1; - join.group= group != 0; - join.row_limit= ((select_distinct || order || group) ? HA_POS_ERROR : - thd->select_limit); + count_field_types(&tmp_table_param, all_fields, 0); + this->group= group_list != 0; + row_limit= ((select_distinct || order || group_list) ? HA_POS_ERROR : + unit->select_limit_cnt); + do_send_rows = (unit->select_limit_cnt) ? 1 : 0; + this->unit= unit; #ifdef RESTRICTED_GROUP - if (join.sum_func_count && !group && (join.func_count || join.field_count)) + if (sum_func_count && !group_list && (func_count || field_count)) { my_message(ER_WRONG_SUM_SELECT,ER(ER_WRONG_SUM_SELECT),MYF(0)); delete procedure; DBUG_RETURN(-1); } #endif - if (!procedure && result->prepare(fields)) + if (!procedure && result->prepare(fields_list, unit)) { /* purecov: inspected */ DBUG_RETURN(-1); /* purecov: inspected */ } + DBUG_RETURN(0); // All OK +} + +/* + global select optimisation. + return 0 - success + 1 - go out + -1 - go out with cleaning + error code saved in field 'error' +*/ +int +JOIN::optimize() +{ + DBUG_ENTER("JOIN::optimize"); #ifdef HAVE_REF_TO_FIELDS // Not done yet /* Add HAVING to WHERE if possible */ - if (having && !group && ! join.sum_func_count) + if (having && !group_list && ! sum_func_count) { if (!conds) { - conds=having; - having=0; + conds= having; + having= 0; } else if ((conds=new Item_cond_and(conds,having))) { - conds->fix_fields(thd,tables); - conds->change_ref_to_fields(thd,tables); + conds->fix_fields(thd, tables_list, &conds); + conds->change_ref_to_fields(thd, tables_list); conds->top_level_item(); - having=0; + having= 0; } } #endif - conds=optimize_cond(conds,&cond_value); - if (thd->fatal_error) // Out of memory + conds= optimize_cond(conds,&cond_value); + if (thd->fatal_error) { + // quick abort delete procedure; - DBUG_RETURN(0); - } - if (cond_value == Item::COND_FALSE || !thd->select_limit) + error= 0; + DBUG_RETURN(1); + } else if (thd->net.report_error) + // normal error processing & cleanup + DBUG_RETURN(-1); + + if (cond_value == Item::COND_FALSE || (!unit->select_limit_cnt && !(select_options & OPTION_FOUND_ROWS))) { /* Impossible cond */ - error=return_zero_rows(&join, result, tables, fields, - join.tmp_table_param.sum_func_count != 0 && !group, - select_options,"Impossible WHERE",having, - procedure); - delete procedure; - DBUG_RETURN(error); + zero_result_cause= "Impossible WHERE"; + DBUG_RETURN(0); } /* Optimize count(*), min() and max() */ - if (tables && join.tmp_table_param.sum_func_count && ! group) + if (tables_list && tmp_table_param.sum_func_count && ! group_list) { int res; - if ((res=opt_sum_query(tables, all_fields, conds))) + if ((res=opt_sum_query(tables_list, all_fields, conds))) { if (res < 0) { - error=return_zero_rows(&join, result, tables, fields, !group, - select_options,"No matching min/max row", - having,procedure); - delete procedure; - DBUG_RETURN(error); - } - if (select_options & SELECT_DESCRIBE) - { - describe_info(&join, "Select tables optimized away"); - delete procedure; - DBUG_RETURN(error); + zero_result_cause= "No matching min/max row"; + DBUG_RETURN(0); } - tables=0; // All tables resolved + zero_result_cause= "Select tables optimized away"; + tables_list= 0; // All tables resolved } } - if (!tables) - { // Only test of functions - error=0; - if (select_options & SELECT_DESCRIBE) - describe_info(&join, "No tables used"); - else - { - result->send_fields(fields,1); - if (!having || having->val_int()) - { - if (join.do_send_rows && result->send_data(fields)) - { - result->send_error(0,NullS); /* purecov: inspected */ - error=1; - } - else - error=(int) result->send_eof(); - } - else - error=(int) result->send_eof(); - } - delete procedure; - DBUG_RETURN(error); + + if (!tables_list) + { + test_function_query= 1; + DBUG_RETURN(0); } - error = -1; - join.sort_by_table=get_sort_by_table(order,group,tables); + error= -1; + sort_by_table= get_sort_by_table(order, group_list, tables_list); /* Calculate how to do the join */ - thd->proc_info="statistics"; - if (make_join_statistics(&join,tables,conds,&keyuse) || thd->fatal_error) - goto err; - thd->proc_info="preparing"; - result->initialize_tables(&join); - if (join.const_table_map != join.found_const_table_map && + thd->proc_info= "statistics"; + if (make_join_statistics(this, tables_list, conds, &keyuse) || + thd->fatal_error) + DBUG_RETURN(-1); + + if (select_lex->dependent) + { + /* + Just remove all const-table optimization in case of depended query + TODO: optimize + */ + const_table_map= 0; + const_tables= 0; + found_const_table_map= 0; + } + thd->proc_info= "preparing"; + result->initialize_tables(this); + if (const_table_map != found_const_table_map && !(select_options & SELECT_DESCRIBE)) { - error=return_zero_rows(&join,result,tables,fields, - join.tmp_table_param.sum_func_count != 0 && - !group,0,"",having,procedure); - goto err; + zero_result_cause= ""; + select_options= 0; //TODO why option in return_zero_rows was droped + DBUG_RETURN(0); } if (!(thd->options & OPTION_BIG_SELECTS) && - join.best_read > (double) thd->variables.max_join_size && + best_read > (double) thd->variables.max_join_size && !(select_options & SELECT_DESCRIBE)) { /* purecov: inspected */ - result->send_error(ER_TOO_BIG_SELECT,ER(ER_TOO_BIG_SELECT)); /* purecov: inspected */ + my_message(ER_TOO_BIG_SELECT, ER(ER_TOO_BIG_SELECT), MYF(0)); error= 1; /* purecov: inspected */ - goto err; /* purecov: inspected */ + DBUG_RETURN(-1); } - if (join.const_tables && !thd->locked_tables && + if (const_tables && !thd->locked_tables && !(select_options & SELECT_NO_UNLOCK)) { TABLE **table, **end; - for (table=join.table, end=table + join.const_tables ; + for (table=this->table, end=table + const_tables ; table != end; table++) { @@ -470,80 +464,79 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds, } (*table)->file->index_end(); } - mysql_unlock_some_tables(thd, join.table,join.const_tables); + mysql_unlock_some_tables(thd, this->table, const_tables); } - if (!conds && join.outer_join) + if (!conds && outer_join) { /* Handle the case where we have an OUTER JOIN without a WHERE */ conds=new Item_int((longlong) 1,1); // Always true } - select=make_select(*join.table, join.const_table_map, - join.const_table_map,conds,&error); + select=make_select(*table, const_table_map, + const_table_map, conds, &error); if (error) { /* purecov: inspected */ error= -1; /* purecov: inspected */ - goto err; /* purecov: inspected */ + DBUG_RETURN(-1); } - if (make_join_select(&join,select,conds)) + if (make_join_select(this, select, conds)) { - error=return_zero_rows(&join, result, tables, fields, - join.tmp_table_param.sum_func_count != 0 && !group, - select_options, - "Impossible WHERE noticed after reading const tables", - having,procedure); - goto err; + zero_result_cause= + "Impossible WHERE noticed after reading const tables"; + DBUG_RETURN(0); } error= -1; /* if goto err */ /* Optimize distinct away if possible */ - order=remove_const(&join,order,conds,&simple_order); - if (group || join.tmp_table_param.sum_func_count) + order= remove_const(this, order, conds, &simple_order); + if (group_list || tmp_table_param.sum_func_count) { if (! hidden_group_fields) select_distinct=0; } - else if (select_distinct && join.tables - join.const_tables == 1 && - (thd->select_limit == HA_POS_ERROR || - (join.select_options & OPTION_FOUND_ROWS) || + else if (select_distinct && tables - const_tables == 1 && + (unit->select_limit_cnt == HA_POS_ERROR || + (select_options & OPTION_FOUND_ROWS) || order && !(skip_sort_order= - test_if_skip_sort_order(&join.join_tab[join.const_tables], - order, thd->select_limit,1)))) + test_if_skip_sort_order(&join_tab[const_tables], + order, + unit->select_limit_cnt, + 1)))) { - if ((group=create_distinct_group(order,fields))) + if ((group_list= create_distinct_group(order, fields_list))) { - select_distinct=0; + select_distinct= 0; no_order= !order; - join.group=1; // For end_write_group + group= 1; // For end_write_group } else if (thd->fatal_error) // End of memory - goto err; + DBUG_RETURN(-1); } - group=remove_const(&join,group,conds,&simple_group); - if (!group && join.group) + group_list= remove_const(this, group_list, conds, &simple_group); + if (!group_list && group) { order=0; // The output has only one row simple_order=1; } - calc_group_buffer(&join,group); - join.send_group_parts=join.tmp_table_param.group_parts; /* Save org parts */ + calc_group_buffer(this, group_list); + send_group_parts= tmp_table_param.group_parts; /* Save org parts */ if (procedure && procedure->group) { - group=procedure->group=remove_const(&join,procedure->group,conds, - &simple_group); - calc_group_buffer(&join,group); + group_list= procedure->group= remove_const(this, procedure->group, conds, + &simple_group); + calc_group_buffer(this, group_list); } - if (test_if_subpart(group,order) || - (!group && join.tmp_table_param.sum_func_count)) + if (test_if_subpart(group_list, order) || + (!group_list && tmp_table_param.sum_func_count)) order=0; // Can't use sort on head table if using row cache - if (join.full_join) + if (full_join) { - if (group) + if (group_list) simple_group=0; if (order) simple_order=0; @@ -558,17 +551,18 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds, - We are using different ORDER BY and GROUP BY orders - The user wants us to buffer the result. */ - need_tmp= (join.const_tables != join.tables && + need_tmp= (const_tables != tables && ((select_distinct || !simple_order || !simple_group) || - (group && order) || + (group_list && order) || test(select_options & OPTION_BUFFER_RESULT))); // No cache for MATCH - make_join_readinfo(&join, + make_join_readinfo(this, (select_options & (SELECT_DESCRIBE | SELECT_NO_JOIN_CACHE)) | - (cur_sel->ftfunc_list.elements ? SELECT_NO_JOIN_CACHE : - 0)); + (select_lex->ftfunc_list->elements ? + SELECT_NO_JOIN_CACHE : 0)); + /* Need to tell Innobase that to play it safe, it should fetch all columns of the tables: this is because MySQL may build row @@ -578,63 +572,157 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds, */ #ifdef HAVE_INNOBASE_DB - if (need_tmp || select_distinct || group || order) + if (need_tmp || select_distinct || group_list || order) { - for (uint i_h = join.const_tables; i_h < join.tables; i_h++) + for (uint i_h = const_tables; i_h < tables; i_h++) { - TABLE* table_h = join.join_tab[i_h].table; + TABLE* table_h = join_tab[i_h].table; if (table_h->db_type == DB_TYPE_INNODB) table_h->file->extra(HA_EXTRA_DONT_USE_CURSOR_TO_UPDATE); } } #endif - DBUG_EXECUTE("info",TEST_join(&join);); + DBUG_EXECUTE("info",TEST_join(this);); /* Because filesort always does a full table scan or a quick range scan we must add the removed reference to the select for the table. We only need to do this when we have a simple_order or simple_group as in other cases the join is done before the sort. */ - if ((order || group) && join.join_tab[join.const_tables].type != JT_ALL && - join.join_tab[join.const_tables].type != JT_FT && - (order && simple_order || group && simple_group)) + if ((order || group_list) && join_tab[const_tables].type != JT_ALL && + join_tab[const_tables].type != JT_FT && + (order && simple_order || group_list && simple_group)) { - if (add_ref_to_table_cond(thd,&join.join_tab[join.const_tables])) - goto err; + if (add_ref_to_table_cond(thd,&join_tab[const_tables])) + DBUG_RETURN(-1); } if (!(select_options & SELECT_BIG_RESULT) && - ((group && join.const_tables != join.tables && + ((group_list && const_tables != tables && (!simple_group || - !test_if_skip_sort_order(&join.join_tab[join.const_tables], group, - thd->select_limit,0))) || + !test_if_skip_sort_order(&join_tab[const_tables], group_list, + unit->select_limit_cnt, + 0))) || select_distinct) && - join.tmp_table_param.quick_group && !procedure) + tmp_table_param.quick_group && !procedure) { need_tmp=1; simple_order=simple_group=0; // Force tmp table without sort } + DBUG_RETURN(0); +} + +/* + Global optimization (with subselect) must be here (TODO) +*/ + +int +JOIN::global_optimize() +{ + return 0; +} + +int +JOIN::reinit() +{ + DBUG_ENTER("JOIN::reinit"); + //TODO move to unit reinit + unit->offset_limit_cnt =select_lex->offset_limit; + unit->select_limit_cnt =select_lex->select_limit+select_lex->offset_limit; + if (unit->select_limit_cnt < select_lex->select_limit) + unit->select_limit_cnt= HA_POS_ERROR; // no limit + if (unit->select_limit_cnt == HA_POS_ERROR) + select_lex->options&= ~OPTION_FOUND_ROWS; + + if (setup_tables(tables_list)) + DBUG_RETURN(1); + + // Reset of sum functions + first_record= 0; + if (sum_funcs) + { + Item_sum *func, **func_ptr= sum_funcs; + while ((func= *(func_ptr++))) + func->null_value= 1; + } + + DBUG_RETURN(0); +} + +/* + Exec select +*/ +void +JOIN::exec() +{ + int tmp_error; + + DBUG_ENTER("JOIN::exec"); + + if (test_function_query) + { // Only test of functions + error=0; + if (select_options & SELECT_DESCRIBE) + select_describe(this, false, false, false, + (zero_result_cause?zero_result_cause:"No tables used")); + else + { + result->send_fields(fields_list,1); + if (!having || having->val_int()) + { + if (do_send_rows && result->send_data(fields_list)) + error= 1; + else + { + error= (int) result->send_eof(); + send_records=1; + } + } + else + error=(int) result->send_eof(); + } + delete procedure; + DBUG_VOID_RETURN; + } + + if (zero_result_cause) + { + error=0; + + (void) return_zero_rows(this, result, tables_list, fields_list, + tmp_table_param.sum_func_count != 0 && + !group_list, + select_options, + zero_result_cause, + having,procedure, + unit); + DBUG_VOID_RETURN; + } + + Item *having_list = having; + having = 0; if (select_options & SELECT_DESCRIBE) { if (!order && !no_order) - order=group; + order=group_list; if (order && - (join.const_tables == join.tables || + (const_tables == tables || (simple_order && - test_if_skip_sort_order(&join.join_tab[join.const_tables], order, - (join.select_options & OPTION_FOUND_ROWS) ? - HA_POS_ERROR : thd->select_limit,0)))) + test_if_skip_sort_order(&join_tab[const_tables], order, + (select_options & OPTION_FOUND_ROWS) ? + HA_POS_ERROR : unit->select_limit_cnt, + 0)))) order=0; - select_describe(&join,need_tmp, + select_describe(this, need_tmp, order != 0 && !skip_sort_order, select_distinct); error=0; - goto err; + DBUG_VOID_RETURN; } /* Perform FULLTEXT search before all regular searches */ - init_ftfuncs(thd,test(order)); + init_ftfuncs(thd, select_lex, test(order)); /* Create a tmp table if distinct or if the sort is too complicated */ if (need_tmp) @@ -642,46 +730,47 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds, DBUG_PRINT("info",("Creating tmp table")); thd->proc_info="Creating tmp table"; - join.tmp_table_param.hidden_field_count= (all_fields.elements - - fields.elements); - if (!(tmp_table = - create_tmp_table(thd,&join.tmp_table_param,all_fields, + tmp_table_param.hidden_field_count= (all_fields.elements - + fields_list.elements); + if (!(exec_tmp_table = + create_tmp_table(thd, &tmp_table_param, all_fields, ((!simple_group && !procedure && !(test_flags & TEST_NO_KEY_GROUP)) ? - group : (ORDER*) 0), - group ? 0 : select_distinct, - group && simple_group, + group_list : (ORDER*) 0), + group_list ? 0 : select_distinct, + group_list && simple_group, (order == 0 || skip_sort_order) && - !(join.select_options & OPTION_FOUND_ROWS), - join.select_options))) - goto err; /* purecov: inspected */ + !(select_options & OPTION_FOUND_ROWS), + select_options, unit))) + DBUG_VOID_RETURN; - if (having && (join.sort_and_group || (tmp_table->distinct && !group))) - join.having=having; + if (having_list && + (sort_and_group || (exec_tmp_table->distinct && !group_list))) + having=having_list; /* if group or order on first table, sort first */ - if (group && simple_group) + if (group_list && simple_group) { DBUG_PRINT("info",("Sorting for group")); thd->proc_info="Sorting for group"; - if (create_sort_index(&join.join_tab[join.const_tables],group, + if (create_sort_index(thd, &join_tab[const_tables], group_list, HA_POS_ERROR, HA_POS_ERROR) || - make_sum_func_list(&join,all_fields) || - alloc_group_fields(&join,group)) - goto err; - group=0; + make_sum_func_list(this, all_fields) || + alloc_group_fields(this, group_list)) + DBUG_VOID_RETURN; + group_list=0; } else { - if (make_sum_func_list(&join,all_fields)) - goto err; - if (!group && ! tmp_table->distinct && order && simple_order) + if (make_sum_func_list(this, all_fields)) + DBUG_VOID_RETURN; + if (!group_list && ! exec_tmp_table->distinct && order && simple_order) { DBUG_PRINT("info",("Sorting for order")); thd->proc_info="Sorting for order"; - if (create_sort_index(&join.join_tab[join.const_tables],order, - HA_POS_ERROR, HA_POS_ERROR)) - goto err; /* purecov: inspected */ + if (create_sort_index(thd, &join_tab[const_tables], order, + HA_POS_ERROR, HA_POS_ERROR)) + DBUG_VOID_RETURN; order=0; } } @@ -692,58 +781,58 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds, In this case we can stop scanning t2 when we have found one t1.a */ - if (tmp_table->distinct) + if (exec_tmp_table->distinct) { table_map used_tables= thd->used_tables; - JOIN_TAB *join_tab=join.join_tab+join.tables-1; + JOIN_TAB *join_tab= this->join_tab+tables-1; do { if (used_tables & join_tab->table->map) break; join_tab->not_used_in_distinct=1; - } while (join_tab-- != join.join_tab); + } while (join_tab-- != this->join_tab); /* Optimize "select distinct b from t1 order by key_part_1 limit #" */ if (order && skip_sort_order) { - (void) test_if_skip_sort_order(&join.join_tab[join.const_tables], - order, thd->select_limit,0); + (void) test_if_skip_sort_order(&this->join_tab[const_tables], + order, unit->select_limit_cnt, 0); order=0; } } /* Copy data to the temporary table */ - thd->proc_info="Copying to tmp table"; - if ((tmp_error=do_select(&join,(List<Item> *) 0,tmp_table,0))) + thd->proc_info= "Copying to tmp table"; + if ((tmp_error= do_select(this, (List<Item> *) 0, exec_tmp_table, 0))) { - error=tmp_error; - goto err; /* purecov: inspected */ + error= tmp_error; + DBUG_VOID_RETURN; } - if (join.having) - join.having=having=0; // Allready done + if (having) + having= having_list= 0; // Allready done /* Change sum_fields reference to calculated fields in tmp_table */ - if (join.sort_and_group || tmp_table->group) + if (sort_and_group || exec_tmp_table->group) { if (change_to_use_tmp_fields(all_fields)) - goto err; - join.tmp_table_param.field_count+=join.tmp_table_param.sum_func_count+ - join.tmp_table_param.func_count; - join.tmp_table_param.sum_func_count=join.tmp_table_param.func_count=0; + DBUG_VOID_RETURN; + tmp_table_param.field_count+= tmp_table_param.sum_func_count+ + tmp_table_param.func_count; + tmp_table_param.sum_func_count= tmp_table_param.func_count= 0; } else { if (change_refs_to_tmp_fields(thd,all_fields)) - goto err; - join.tmp_table_param.field_count+=join.tmp_table_param.func_count; - join.tmp_table_param.func_count=0; + DBUG_VOID_RETURN; + tmp_table_param.field_count+= tmp_table_param.func_count; + tmp_table_param.func_count= 0; } if (procedure) procedure->update_refs(); - if (tmp_table->group) + if (exec_tmp_table->group) { // Already grouped if (!order && !no_order) - order=group; /* order by group */ - group=0; + order= group_list; /* order by group */ + group_list= 0; } /* @@ -754,176 +843,302 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds, like SEC_TO_TIME(SUM(...)). */ - if (group && (!test_if_subpart(group,order) || select_distinct) || + if (group_list && (!test_if_subpart(group_list,order) || + select_distinct) || (select_distinct && - join.tmp_table_param.using_indirect_summary_function)) + tmp_table_param.using_indirect_summary_function)) { /* Must copy to another table */ TABLE *tmp_table2; DBUG_PRINT("info",("Creating group table")); /* Free first data from old join */ - join_free(&join); - if (make_simple_join(&join,tmp_table)) - goto err; - calc_group_buffer(&join,group); - count_field_types(&join.tmp_table_param,all_fields, - select_distinct && !group); - join.tmp_table_param.hidden_field_count=(all_fields.elements- - fields.elements); + join_free(this); + if (make_simple_join(this, exec_tmp_table)) + DBUG_VOID_RETURN; + calc_group_buffer(this, group_list); + count_field_types(&tmp_table_param, all_fields, + select_distinct && !group_list); + tmp_table_param.hidden_field_count= (all_fields.elements- + fields_list.elements); /* group data to new table */ - if (!(tmp_table2 = create_tmp_table(thd,&join.tmp_table_param,all_fields, + if (!(tmp_table2 = create_tmp_table(thd, &tmp_table_param, all_fields, (ORDER*) 0, - select_distinct && !group, + select_distinct && !group_list, 1, 0, - join.select_options))) - goto err; /* purecov: inspected */ - if (group) + select_options, unit))) + DBUG_VOID_RETURN; + if (group_list) { thd->proc_info="Creating sort index"; - if (create_sort_index(join.join_tab,group,HA_POS_ERROR, HA_POS_ERROR) || - alloc_group_fields(&join,group)) + if (create_sort_index(thd, join_tab, group_list, HA_POS_ERROR, + HA_POS_ERROR) || + alloc_group_fields(this, group_list)) { free_tmp_table(thd,tmp_table2); /* purecov: inspected */ - goto err; /* purecov: inspected */ + DBUG_VOID_RETURN; } - group=0; + group_list= 0; } thd->proc_info="Copying to group table"; tmp_error= -1; - if (make_sum_func_list(&join,all_fields) || - (tmp_error=do_select(&join,(List<Item> *) 0,tmp_table2,0))) + if (make_sum_func_list(this, all_fields) || + (tmp_error=do_select(this, (List<Item> *) 0,tmp_table2,0))) { error=tmp_error; free_tmp_table(thd,tmp_table2); - goto err; /* purecov: inspected */ + DBUG_VOID_RETURN; } - end_read_record(&join.join_tab->read_record); - free_tmp_table(thd,tmp_table); - join.const_tables=join.tables; // Mark free for join_free() - tmp_table=tmp_table2; - join.join_tab[0].table=0; // Table is freed + end_read_record(&join_tab->read_record); + free_tmp_table(thd,exec_tmp_table); + const_tables= tables; // Mark free for join_free() + exec_tmp_table= tmp_table2; + join_tab[0].table= 0; // Table is freed if (change_to_use_tmp_fields(all_fields)) // No sum funcs anymore - goto err; - join.tmp_table_param.field_count+=join.tmp_table_param.sum_func_count; - join.tmp_table_param.sum_func_count=0; + DBUG_VOID_RETURN; + tmp_table_param.field_count+= tmp_table_param.sum_func_count; + tmp_table_param.sum_func_count= 0; } - if (tmp_table->distinct) + if (exec_tmp_table->distinct) select_distinct=0; /* Each row is unique */ - join_free(&join); /* Free quick selects */ - if (select_distinct && ! group) + join_free(this); /* Free quick selects */ + if (select_distinct && ! group_list) { thd->proc_info="Removing duplicates"; - if (having) - having->update_used_tables(); - if (remove_duplicates(&join,tmp_table,fields, having)) - goto err; /* purecov: inspected */ - having=0; + if (having_list) + having_list->update_used_tables(); + if (remove_duplicates(this, exec_tmp_table, fields_list, having_list)) + DBUG_VOID_RETURN; + having_list=0; select_distinct=0; } - tmp_table->reginfo.lock_type=TL_UNLOCK; - if (make_simple_join(&join,tmp_table)) - goto err; - calc_group_buffer(&join,group); - count_field_types(&join.tmp_table_param,all_fields,0); + exec_tmp_table->reginfo.lock_type=TL_UNLOCK; + if (make_simple_join(this, exec_tmp_table)) + DBUG_VOID_RETURN; + calc_group_buffer(this, group_list); + count_field_types(&tmp_table_param, all_fields, 0); } if (procedure) { - if (procedure->change_columns(fields) || - result->prepare(fields)) - goto err; - count_field_types(&join.tmp_table_param,all_fields,0); + if (procedure->change_columns(fields_list) || + result->prepare(fields_list, unit)) + DBUG_VOID_RETURN; + count_field_types(&tmp_table_param, all_fields, 0); } - if (join.group || join.tmp_table_param.sum_func_count || + if (group || tmp_table_param.sum_func_count || (procedure && (procedure->flags & PROC_GROUP))) { - alloc_group_fields(&join,group); - setup_copy_fields(thd, &join.tmp_table_param,all_fields); - if (make_sum_func_list(&join,all_fields) || thd->fatal_error) - goto err; /* purecov: inspected */ + alloc_group_fields(this, group_list); + setup_copy_fields(thd, &tmp_table_param,all_fields); + if (make_sum_func_list(this, all_fields) || thd->fatal_error) + DBUG_VOID_RETURN; } - if (group || order) + if (group_list || order) { DBUG_PRINT("info",("Sorting for send_fields")); thd->proc_info="Sorting result"; /* If we have already done the group, add HAVING to sorted table */ - if (having && ! group && ! join.sort_and_group) + if (having_list && ! group_list && ! sort_and_group) { - having->update_used_tables(); // Some tables may have been const - JOIN_TAB *table=&join.join_tab[join.const_tables]; - table_map used_tables= join.const_table_map | table->table->map; + having_list->update_used_tables(); // Some tables may have been const + JOIN_TAB *table= &join_tab[const_tables]; + table_map used_tables= const_table_map | table->table->map; - Item* sort_table_cond=make_cond_for_table(having,used_tables,used_tables); + Item* sort_table_cond= make_cond_for_table(having_list, used_tables, + used_tables); if (sort_table_cond) { if (!table->select) if (!(table->select=new SQL_SELECT)) - goto err; + DBUG_VOID_RETURN; if (!table->select->cond) table->select->cond=sort_table_cond; else // This should never happen if (!(table->select->cond=new Item_cond_and(table->select->cond, sort_table_cond))) - goto err; + DBUG_VOID_RETURN; table->select_cond=table->select->cond; table->select_cond->top_level_item(); DBUG_EXECUTE("where",print_where(table->select->cond, "select and having");); - having=make_cond_for_table(having,~ (table_map) 0,~used_tables); + having_list= make_cond_for_table(having_list, ~ (table_map) 0, + ~used_tables); DBUG_EXECUTE("where",print_where(conds,"having after sort");); } } - select_limit= thd->select_limit; - if (having || group || (join.select_options & OPTION_FOUND_ROWS)) - select_limit= HA_POS_ERROR; - else { - /* - We can abort sorting after thd->select_limit rows if we there is no - WHERE clause for any tables after the sorted one. - */ - JOIN_TAB *table= &join.join_tab[join.const_tables+1]; - JOIN_TAB *end_table= &join.join_tab[join.tables]; - for (; table < end_table ; table++) + ha_rows select_limit= unit->select_limit_cnt; + if (having || group || (select_options & OPTION_FOUND_ROWS)) + select_limit= HA_POS_ERROR; + else { - if (table->select_cond) + /* + We can abort sorting after thd->select_limit rows if we there is no + WHERE clause for any tables after the sorted one. + */ + JOIN_TAB *table= &join_tab[const_tables+1]; + JOIN_TAB *end_table= &join_tab[tables]; + for (; table < end_table ; table++) { - /* We have to sort all rows */ - select_limit= HA_POS_ERROR; - break; + if (table->select_cond) + { + /* We have to sort all rows */ + select_limit= HA_POS_ERROR; + break; + } } } + if (create_sort_index(thd, &join_tab[const_tables], + group_list ? group_list : order, + select_limit, unit->select_limit_cnt)) + DBUG_VOID_RETURN; } - if (create_sort_index(&join.join_tab[join.const_tables], - group ? group : order, - select_limit, - thd->select_limit)) - goto err; /* purecov: inspected */ } - join.having=having; // Actually a parameter + having=having_list; // Actually a parameter thd->proc_info="Sending data"; - error=do_select(&join,&fields,NULL,procedure); + error= thd->net.report_error || + do_select(this, &fields_list, NULL, procedure); + DBUG_VOID_RETURN; +} -err: - thd->limit_found_rows = join.send_records; - thd->examined_row_count = join.examined_rows; - thd->proc_info="end"; - join.lock=0; // It's faster to unlock later - join_free(&join); - thd->proc_info="end2"; // QQ - if (tmp_table) - free_tmp_table(thd,tmp_table); - thd->proc_info="end3"; // QQ +/* + Clean up join. Return error that hold JOIN. +*/ + +int +JOIN::cleanup(THD *thd) +{ + DBUG_ENTER("JOIN::cleanup"); + + lock=0; // It's faster to unlock later + join_free(this); + if (exec_tmp_table) + free_tmp_table(thd, exec_tmp_table); delete select; delete_dynamic(&keyuse); delete procedure; - thd->proc_info="end4"; // QQ + for (SELECT_LEX_UNIT *unit= select_lex->first_inner_unit(); + unit != 0; + unit= unit->next_unit()) + { + for (SELECT_LEX *sl= unit->first_select(); + sl != 0; + sl= sl->next_select()) + { + if (sl->join) + { + int err= sl->join->cleanup(thd); + if (err) + error= err; + sl->join= 0; + } + } + } DBUG_RETURN(error); } +bool JOIN::check_loop(uint id) +{ + DBUG_ENTER("JOIN::check_loop"); + Item *item; + List_iterator<Item> it(all_fields); + DBUG_PRINT("info", ("all_fields:")); + while ((item= it++)) + if (item->check_loop(id)) + DBUG_RETURN(1); + DBUG_PRINT("info", ("where:")); + if (select_lex->where && select_lex->where->check_loop(id)) + DBUG_RETURN(1); + DBUG_PRINT("info", ("having:")); + if (select_lex->having && select_lex->having->check_loop(id)) + DBUG_RETURN(1); + DBUG_RETURN(0); +} + +int +mysql_select(THD *thd, TABLE_LIST *tables, List<Item> &fields, COND *conds, + ORDER *order, ORDER *group,Item *having, ORDER *proc_param, + ulong select_options, select_result *result, + SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex, + bool fake_select_lex) +{ + DBUG_ENTER("mysql_select"); + + bool free_join= 1; + JOIN *join; + if (!fake_select_lex && select_lex->join != 0) + { + //here is EXPLAIN of subselect or derived table + join= select_lex->join; + join->result= result; + if (!join->procedure && result->prepare(join->fields_list, unit)) + { + DBUG_RETURN(-1); + } + join->select_options= select_options; + free_join= 0; + } + else + { + join= new JOIN(thd, fields, select_options, result); + thd->proc_info="init"; + thd->used_tables=0; // Updated by setup_fields + + if (join->prepare(tables, conds, order, group, having, proc_param, + select_lex, unit, fake_select_lex)) + { + DBUG_RETURN(-1); + } + if (thd->possible_loops) + { + Item *item; + while(thd->possible_loops->elements) + { + item= thd->possible_loops->pop(); + if (item->check_loop(thd->check_loops_counter++)) + { + delete thd->possible_loops; + thd->possible_loops= 0; + my_message(ER_CYCLIC_REFERENCE, ER(ER_CYCLIC_REFERENCE), MYF(0)); + return 1; + } + } + delete thd->possible_loops; + thd->possible_loops= 0; + } + } + + switch (join->optimize()) + { + case 1: + DBUG_RETURN(join->error); + case -1: + goto err; + } + + if (thd->net.report_error || (free_join && join->global_optimize())) + goto err; + + join->exec(); + +err: + if (free_join) + { + thd->limit_found_rows = join->send_records; + thd->examined_row_count = join->examined_rows; + thd->proc_info="end"; + int error= (fake_select_lex?join->error:join->cleanup(thd)) || + thd->net.report_error; + delete join; + DBUG_RETURN(error); + } + else + DBUG_RETURN(join->error); +} + /***************************************************************************** Create JOIN_TABS, make a guess about the table types, Approximate how many records will be used in each table @@ -1064,8 +1279,8 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds, } if (conds || outer_join) - if (update_ref_and_keys(join->thd,keyuse_array,stat,join->tables, - conds,~outer_join)) + if (update_ref_and_keys(join->thd, keyuse_array, stat, join->tables, + conds, ~outer_join, join->select_lex)) DBUG_RETURN(1); /* Read tables with 0 or 1 rows (system tables) */ @@ -1625,7 +1840,8 @@ sort_keyuse(KEYUSE *a,KEYUSE *b) static bool update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab, - uint tables, COND *cond, table_map normal_tables) + uint tables, COND *cond, table_map normal_tables, + SELECT_LEX *select_lex) { uint and_level,i,found_eq_constant; @@ -1653,7 +1869,7 @@ update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab, add_key_part(keyuse,field); } - if (thd->lex.select->ftfunc_list.elements) + if (select_lex->ftfunc_list->elements) { add_ft_keys(keyuse,join_tab,cond,normal_tables); } @@ -1753,7 +1969,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count, { ha_rows rec; double tmp; - THD *thd= current_thd; + THD *thd= join->thd; if (!rest_tables) { @@ -2041,7 +2257,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count, join->positions[idx].table= s; if (!best_key && idx == join->const_tables && s->table == join->sort_by_table && - join->thd->select_limit >= records) + join->unit->select_limit_cnt >= records) join->sort_by_table= (TABLE*) 1; // Must use temporary table /* @@ -2375,7 +2591,7 @@ store_val_in_field(Field *field,Item *item) THD *thd=current_thd; ha_rows cuted_fields=thd->cuted_fields; thd->count_cuted_fields=1; - item->save_in_field(field); + (void) item->save_in_field(field); thd->count_cuted_fields=0; return cuted_fields != thd->cuted_fields; } @@ -2402,8 +2618,8 @@ make_simple_join(JOIN *join,TABLE *tmp_table) join->sum_funcs=0; join->send_records=(ha_rows) 0; join->group=0; - join->do_send_rows = 1; - join->row_limit=join->thd->select_limit; + join->row_limit=join->unit->select_limit_cnt; + join->do_send_rows = (join->row_limit) ? 1 : 0; join_tab->cache.buff=0; /* No cacheing */ join_tab->table=tmp_table; @@ -2520,7 +2736,8 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) if ((tab->keys & ~ tab->const_keys && i > 0) || (tab->const_keys && i == join->const_tables && - join->thd->select_limit < join->best_positions[i].records_read && + join->unit->select_limit_cnt < + join->best_positions[i].records_read && !(join->select_options & OPTION_FOUND_ROWS))) { /* Join with outer join condition */ @@ -2531,7 +2748,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) (join->select_options & OPTION_FOUND_ROWS ? HA_POS_ERROR : - join->thd->select_limit)) < 0) + join->unit->select_limit_cnt)) < 0) DBUG_RETURN(1); // Impossible range sel->cond=orig_cond; } @@ -2573,7 +2790,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) static void -make_join_readinfo(JOIN *join,uint options) +make_join_readinfo(JOIN *join, uint options) { uint i; SELECT_LEX *select_lex = &(join->thd->lex.select_lex); @@ -2735,25 +2952,43 @@ join_free(JOIN *join) */ if (join->tables > join->const_tables) // Test for not-const tables free_io_cache(join->table[join->const_tables]); - for (tab=join->join_tab,end=tab+join->tables ; tab != end ; tab++) + if (join->select_lex->dependent) + for (tab=join->join_tab,end=tab+join->tables ; tab != end ; tab++) + { + if (tab->table) + { + if (tab->table->key_read) + { + tab->table->key_read= 0; + tab->table->file->extra(HA_EXTRA_NO_KEYREAD); + } + /* Don't free index if we are using read_record */ + if (!tab->read_record.table) + tab->table->file->index_end(); + } + } + else { - delete tab->select; - delete tab->quick; - x_free(tab->cache.buff); - if (tab->table) + for (tab=join->join_tab,end=tab+join->tables ; tab != end ; tab++) { - if (tab->table->key_read) + delete tab->select; + delete tab->quick; + x_free(tab->cache.buff); + if (tab->table) { - tab->table->key_read=0; - tab->table->file->extra(HA_EXTRA_NO_KEYREAD); + if (tab->table->key_read) + { + tab->table->key_read= 0; + tab->table->file->extra(HA_EXTRA_NO_KEYREAD); + } + /* Don't free index if we are using read_record */ + if (!tab->read_record.table) + tab->table->file->index_end(); } - /* Don't free index if we are using read_record */ - if (!tab->read_record.table) - tab->table->file->index_end(); + end_read_record(&tab->read_record); } - end_read_record(&tab->read_record); + join->table= 0; } - join->table=0; } /* We are not using tables anymore @@ -2972,18 +3207,20 @@ remove_const(JOIN *join,ORDER *first_order, COND *cond, bool *simple_order) static int return_zero_rows(JOIN *join, select_result *result,TABLE_LIST *tables, List<Item> &fields, bool send_row, uint select_options, - const char *info, Item *having, Procedure *procedure) + const char *info, Item *having, Procedure *procedure, + SELECT_LEX_UNIT *unit) { DBUG_ENTER("return_zero_rows"); if (select_options & SELECT_DESCRIBE) - { - describe_info(join, info); + { + select_describe(join, false, false, false, info); DBUG_RETURN(0); } + if (procedure) { - if (result->prepare(fields)) // This hasn't been done yet + if (result->prepare(fields, unit)) // This hasn't been done yet DBUG_RETURN(-1); } if (send_row) @@ -3302,7 +3539,7 @@ remove_eq_conds(COND *cond,Item::cond_result *cond_value) 21)))) { cond=new_cond; - cond->fix_fields(thd,0); + cond->fix_fields(thd, 0, &cond); } thd->insert_id(0); // Clear for next request } @@ -3316,7 +3553,7 @@ remove_eq_conds(COND *cond,Item::cond_result *cond_value) if ((new_cond= new Item_func_eq(args[0],new Item_int("0", 0, 2)))) { cond=new_cond; - cond->fix_fields(thd,0); + cond->fix_fields(thd, 0, &cond); } } } @@ -3420,14 +3657,14 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, case Item_sum::AVG_FUNC: /* Place for sum & count */ if (group) return new Field_string(sizeof(double)+sizeof(longlong), - maybe_null, item->name,table,1); + maybe_null, item->name,table,my_charset_bin); else return new Field_double(item_sum->max_length,maybe_null, item->name, table, item_sum->decimals); case Item_sum::STD_FUNC: /* Place for sum & count */ if (group) return new Field_string(sizeof(double)*2+sizeof(longlong), - maybe_null, item->name,table,1); + maybe_null, item->name,table,my_charset_bin); else return new Field_double(item_sum->max_length, maybe_null, item->name,table,item_sum->decimals); @@ -3444,9 +3681,9 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, case STRING_RESULT: if (item_sum->max_length > 255) return new Field_blob(item_sum->max_length,maybe_null, - item->name,table,item->binary); + item->name,table,item->charset()); return new Field_string(item_sum->max_length,maybe_null, - item->name,table,item->binary); + item->name,table,item->charset()); } } thd->fatal_error=1; @@ -3474,6 +3711,7 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, case Item::COND_ITEM: case Item::FIELD_AVG_ITEM: case Item::FIELD_STD_ITEM: + case Item::SUBSELECT_ITEM: /* The following can only happen with 'CREATE TABLE ... SELECT' */ case Item::INT_ITEM: case Item::REAL_ITEM: @@ -3497,10 +3735,10 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, case STRING_RESULT: if (item->max_length > 255) new_field= new Field_blob(item->max_length,maybe_null, - item->name,table,item->binary); + item->name,table,item->str_value.charset()); else new_field= new Field_string(item->max_length,maybe_null, - item->name,table,item->binary); + item->name,table,item->str_value.charset()); break; } if (copy_func) @@ -3518,7 +3756,8 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, TABLE * create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, ORDER *group, bool distinct, bool save_sum_fields, - bool allow_distinct_limit, ulong select_options) + bool allow_distinct_limit, ulong select_options, + SELECT_LEX_UNIT *unit) { TABLE *table; uint i,field_count,reclength,null_count,null_pack_length, @@ -3616,6 +3855,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, table->blob_ptr_size=mi_portable_sizeof_char_ptr; table->map=1; table->tmp_table= TMP_TABLE; + table->derived_select_number= 0; table->db_low_byte_first=1; // True for HEAP and MyISAM table->temp_pool_slot = temp_pool_slot; table->copy_blobs= 1; @@ -3906,8 +4146,8 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, test(null_pack_length)); if (allow_distinct_limit) { - set_if_smaller(table->max_rows,thd->select_limit); - param->end_write_records=thd->select_limit; + set_if_smaller(table->max_rows, unit->select_limit_cnt); + param->end_write_records= unit->select_limit_cnt; } else param->end_write_records= HA_POS_ERROR; @@ -3936,7 +4176,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, (uchar*) 0, (uint) 0, Field::NONE, - NullS, table, (bool) 1); + NullS, table, my_charset_bin); key_part_info->key_type=FIELDFLAG_BINARY; key_part_info->type= HA_KEYTYPE_BINARY; key_part_info++; @@ -4009,7 +4249,7 @@ static bool create_myisam_tmp_table(TABLE *table,TMP_TABLE_PARAM *param, if (table->keys) { // Get keys for ni_create bool using_unique_constraint=0; - MI_KEYSEG *seg= (MI_KEYSEG*) sql_calloc(sizeof(*seg) * + HA_KEYSEG *seg= (HA_KEYSEG*) sql_calloc(sizeof(*seg) * keyinfo->key_parts); if (!seg) goto err; @@ -4046,7 +4286,7 @@ static bool create_myisam_tmp_table(TABLE *table,TMP_TABLE_PARAM *param, { Field *field=keyinfo->key_part[i].field; seg->flag= 0; - seg->language= MY_CHARSET_CURRENT; + seg->language= field->charset()->number; seg->length= keyinfo->key_part[i].length; seg->start= keyinfo->key_part[i].offset; if (field->flags & BLOB_FLAG) @@ -4085,6 +4325,7 @@ static bool create_myisam_tmp_table(TABLE *table,TMP_TABLE_PARAM *param, } MI_CREATE_INFO create_info; bzero((char*) &create_info,sizeof(create_info)); + if ((options & (OPTION_BIG_TABLES | SELECT_SMALL_RESULT)) == OPTION_BIG_TABLES) create_info.data_file_length= ~(ulonglong) 0; @@ -4244,7 +4485,7 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure) VOID(table->file->extra(HA_EXTRA_WRITE_CACHE)); empty_record(table); } - join->tmp_table=table; /* Save for easy recursion */ + join->tmp_table= table; /* Save for easy recursion */ join->fields= fields; /* Set up select_end */ @@ -4294,20 +4535,14 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure) } else { - error=sub_select(join,join_tab,0); + error= sub_select(join,join_tab,0); if (error >= 0) - error=sub_select(join,join_tab,1); + error= sub_select(join,join_tab,1); if (error == -3) - error=0; /* select_limit used */ + error= 0; /* select_limit used */ } - /* Return 1 if error is sent; -1 if error should be sent */ - if (error < 0) - { - join->result->send_error(0,NullS); /* purecov: inspected */ - error=1; // Error sent - } - else + if (error >= 0) { error=0; if (!table) // If sending data to client @@ -4334,7 +4569,7 @@ do_select(JOIN *join,List<Item> *fields,TABLE *table,Procedure *procedure) if (error == -1) table->file->print_error(my_errno,MYF(0)); } - DBUG_RETURN(error); + DBUG_RETURN(error || join->thd->net.report_error); } @@ -4960,7 +5195,7 @@ end_send(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), error=join->result->send_data(*join->fields); if (error) DBUG_RETURN(-1); /* purecov: inspected */ - if (++join->send_records >= join->thd->select_limit && + if (++join->send_records >= join->unit->select_limit_cnt && join->do_send_rows) { if (join->select_options & OPTION_FOUND_ROWS) @@ -4989,8 +5224,8 @@ end_send(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), } else { - join->do_send_rows=0; - join->thd->select_limit = HA_POS_ERROR; + join->do_send_rows= 0; + join->unit->select_limit= HA_POS_ERROR; DBUG_RETURN(0); } } @@ -5053,14 +5288,13 @@ end_send_group(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), join->send_records++; DBUG_RETURN(0); } - if (!error && - ++join->send_records >= join->thd->select_limit && + if (!error && ++join->send_records >= join->unit->select_limit_cnt && join->do_send_rows) { if (!(join->select_options & OPTION_FOUND_ROWS)) DBUG_RETURN(-3); // Abort nicely join->do_send_rows=0; - join->thd->select_limit = HA_POS_ERROR; + join->unit->select_limit_cnt = HA_POS_ERROR; } } } @@ -5141,7 +5375,7 @@ end_write(JOIN *join, JOIN_TAB *join_tab __attribute__((unused)), if (!(join->select_options & OPTION_FOUND_ROWS)) DBUG_RETURN(-3); join->do_send_rows=0; - join->thd->select_limit = HA_POS_ERROR; + join->unit->select_limit_cnt = HA_POS_ERROR; DBUG_RETURN(0); } } @@ -5687,8 +5921,8 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, *****************************************************************************/ static int -create_sort_index(JOIN_TAB *tab, ORDER *order, ha_rows filesort_limit, - ha_rows select_limit) +create_sort_index(THD *thd, JOIN_TAB *tab, ORDER *order, + ha_rows filesort_limit, ha_rows select_limit) { SORT_FIELD *sortorder; uint length; @@ -5732,8 +5966,8 @@ create_sort_index(JOIN_TAB *tab, ORDER *order, ha_rows filesort_limit, } if (table->tmp_table) table->file->info(HA_STATUS_VARIABLE); // Get record count - table->found_records=filesort(table,sortorder,length, - select, 0L, filesort_limit, &examined_rows); + table->found_records=filesort(thd, table,sortorder, length, + select, filesort_limit, &examined_rows); tab->records=table->found_records; // For SQL_CALC_ROWS delete select; // filesort did select tab->select=0; @@ -5832,7 +6066,7 @@ remove_duplicates(JOIN *join, TABLE *entry,List<Item> &fields, Item *having) int error; ulong reclength,offset; uint field_count; - THD *thd= current_thd; + THD *thd= join->thd; DBUG_ENTER("remove_duplicates"); entry->reginfo.lock_type=TL_WRITE; @@ -5849,7 +6083,7 @@ remove_duplicates(JOIN *join, TABLE *entry,List<Item> &fields, Item *having) if (!field_count) { // only const items - join->thd->select_limit=1; // Only send first row + join->unit->select_limit_cnt= 1; // Only send first row DBUG_RETURN(0); } Field **first_field=entry->field+entry->fields - field_count; @@ -5986,8 +6220,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); @@ -6380,10 +6616,7 @@ find_order_in_list(THD *thd,TABLE_LIST *tables,ORDER *order,List<Item> &fields, order->in_field_list=1; return 0; } - const char *save_where=thd->where; - thd->where=0; // No error if not found - Item **item=find_item_in_list(*order->item,fields); - thd->where=save_where; + Item **item= find_item_in_list(*order->item, fields, IGNORE_ERRORS); if (item) { order->item=item; // use it @@ -6391,7 +6624,7 @@ find_order_in_list(THD *thd,TABLE_LIST *tables,ORDER *order,List<Item> &fields, return 0; } order->in_field_list=0; - if ((*order->item)->fix_fields(thd,tables) || thd->fatal_error) + if ((*order->item)->fix_fields(thd, tables, order->item) || thd->fatal_error) return 1; // Wrong field all_fields.push_front(*order->item); // Add new field to field list order->item=(Item**) all_fields.head_ref(); @@ -6417,7 +6650,7 @@ int setup_order(THD *thd,TABLE_LIST *tables,List<Item> &fields, } -static int +int setup_group(THD *thd,TABLE_LIST *tables,List<Item> &fields, List<Item> &all_fields, ORDER *order, bool *hidden_group_fields) { @@ -6481,17 +6714,15 @@ setup_new_fields(THD *thd,TABLE_LIST *tables,List<Item> &fields, DBUG_ENTER("setup_new_fields"); thd->set_query_id=1; // Not really needed, but... - thd->where=0; // Don't give error - for (; new_field ; new_field=new_field->next) + for (; new_field ; new_field= new_field->next) { - if ((item=find_item_in_list(*new_field->item,fields))) + if ((item= find_item_in_list(*new_field->item, fields, IGNORE_ERRORS))) new_field->item=item; /* Change to shared Item */ else { thd->where="procedure list"; - if ((*new_field->item)->fix_fields(thd,tables)) + if ((*new_field->item)->fix_fields(thd, tables, new_field->item)) DBUG_RETURN(1); /* purecov: inspected */ - thd->where=0; all_fields.push_front(*new_field->item); new_field->item=all_fields.head_ref(); } @@ -6882,7 +7113,7 @@ change_to_use_tmp_fields(List<Item> &items) if (_db_on_ && !item_field->name) { char buff[256]; - String str(buff,sizeof(buff)); + String str(buff,sizeof(buff),default_charset_info); str.length(0); item->print(&str); item_field->name=sql_strmake(str.ptr(),str.length()); @@ -7054,7 +7285,7 @@ static bool add_ref_to_table_cond(THD *thd, JOIN_TAB *join_tab) Here we pass 0 as the first argument to fix_fields that don't need to do any stack checking (This is already done in the initial fix_fields). */ - cond->fix_fields((THD *) 0,(TABLE_LIST *) 0); + cond->fix_fields((THD *) 0,(TABLE_LIST *) 0, (Item**)&cond); if (join_tab->select) { error=(int) cond->add(join_tab->select->cond); @@ -7074,44 +7305,30 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, bool distinct,const char *message) { List<Item> field_list; - Item *item; List<Item> item_list; THD *thd=join->thd; - MYSQL_LOCK *save_lock; SELECT_LEX *select_lex = &(join->thd->lex.select_lex); select_result *result=join->result; Item *item_null= new Item_null(); DBUG_ENTER("select_describe"); - + DBUG_PRINT("info", ("Select 0x%lx, type %s, message %s", + (ulong)join->select_lex, join->select_lex->type, + message)); /* Don't log this into the slow query log */ select_lex->options&= ~(QUERY_NO_INDEX_USED | QUERY_NO_GOOD_INDEX_USED); - thd->offset_limit=0; - if (thd->lex.select == select_lex) - { - field_list.push_back(new Item_empty_string("table",NAME_LEN)); - field_list.push_back(new Item_empty_string("type",10)); - field_list.push_back(item=new Item_empty_string("possible_keys", - NAME_LEN*MAX_KEY)); - item->maybe_null=1; - field_list.push_back(item=new Item_empty_string("key",NAME_LEN)); - item->maybe_null=1; - field_list.push_back(item=new Item_int("key_len",0,3)); - item->maybe_null=1; - field_list.push_back(item=new Item_empty_string("ref", - NAME_LEN*MAX_REF_PARTS)); - item->maybe_null=1; - field_list.push_back(new Item_real("rows",0.0,0,10)); - field_list.push_back(new Item_empty_string("Extra",255)); - if (result->send_fields(field_list,1)) - return; - } + join->unit->offset_limit_cnt= 0; if (message) { + item_list.push_back(new Item_int((int32) join->select_lex->select_number)); + item_list.push_back(new Item_string(join->select_lex->type, + strlen(join->select_lex->type), + default_charset_info)); Item *empty= new Item_empty_string("",0); for (uint i=0 ; i < 7; i++) item_list.push_back(empty); - item_list.push_back(new Item_string(message,strlen(message))); + item_list.push_back(new Item_string(message,strlen(message), + default_charset_info)); if (result->send_data(item_list)) result->send_error(0,NullS); } @@ -7124,18 +7341,32 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, TABLE *table=tab->table; char buff[512],*buff_ptr=buff; char buff1[512], buff2[512], buff3[512]; - String tmp1(buff1,sizeof(buff1)); - String tmp2(buff2,sizeof(buff2)); + String tmp1(buff1,sizeof(buff1),default_charset_info); + String tmp2(buff2,sizeof(buff2),default_charset_info); tmp1.length(0); tmp2.length(0); - item_list.empty(); + item_list.empty(); + item_list.push_back(new Item_int((int32) + join->select_lex->select_number)); + item_list.push_back(new Item_string(join->select_lex->type, + strlen(join->select_lex->type), + default_charset_info)); if (tab->type == JT_ALL && tab->select && tab->select->quick) tab->type= JT_RANGE; - item_list.push_back(new Item_string(table->table_name, - strlen(table->table_name))); - item_list.push_back(new Item_string(join_type_str[tab->type], - strlen(join_type_str[tab->type]))); + if (table->tmp_table == TMP_TABLE && table->derived_select_number != 0) + { + // Derived table name generation + char buff[512]; + int len= my_snprintf(buff, 512, "<derived%u>", + table->derived_select_number); + item_list.push_back(new Item_string(buff, len, default_charset_info)); + } + else + item_list.push_back(new Item_string(table->table_name, + strlen(table->table_name), + default_charset_info)); + item_list.push_back(new Item_string(join_type_str[tab->type],strlen(join_type_str[tab->type]),default_charset_info)); key_map bits; uint j; for (j=0,bits=tab->keys ; bits ; j++,bits>>=1) @@ -7148,14 +7379,16 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, } } if (tmp1.length()) - item_list.push_back(new Item_string(tmp1.ptr(),tmp1.length())); + item_list.push_back(new Item_string(tmp1.ptr(),tmp1.length(), + default_charset_info)); else - item_list.push_back(item_null); + item_list.push_back(item_null); if (tab->ref.key_parts) { KEY *key_info=table->key_info+ tab->ref.key; item_list.push_back(new Item_string(key_info->name, - strlen(key_info->name))); + strlen(key_info->name), + system_charset_info)); item_list.push_back(new Item_int((int32) tab->ref.key_length)); for (store_key **ref=tab->ref.key_copy ; *ref ; ref++) { @@ -7163,13 +7396,15 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, tmp2.append(','); tmp2.append((*ref)->name()); } - item_list.push_back(new Item_string(tmp2.ptr(),tmp2.length())); + item_list.push_back(new Item_string(tmp2.ptr(),tmp2.length(), + default_charset_info)); } else if (tab->type == JT_NEXT) { KEY *key_info=table->key_info+ tab->index; item_list.push_back(new Item_string(key_info->name, - strlen(key_info->name))); + strlen(key_info->name), + default_charset_info)); item_list.push_back(new Item_int((int32) key_info->key_length)); item_list.push_back(item_null); } @@ -7177,8 +7412,10 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, { KEY *key_info=table->key_info+ tab->select->quick->index; item_list.push_back(new Item_string(key_info->name, - strlen(key_info->name))); - item_list.push_back(new Item_int((int32) tab->select->quick->max_used_key_length)); + strlen(key_info->name), + default_charset_info)); + item_list.push_back(new Item_int((int32) tab->select->quick-> + max_used_key_length)); item_list.push_back(item_null); } else @@ -7188,14 +7425,16 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, item_list.push_back(item_null); } sprintf(buff3,"%.0f",join->best_positions[i].records_read); - item_list.push_back(new Item_string(buff3,strlen(buff3))); + item_list.push_back(new Item_string(buff3,strlen(buff3), + default_charset_info)); my_bool key_read=table->key_read; if (tab->type == JT_NEXT && ((table->used_keys & ((key_map) 1 << tab->index)))) key_read=1; if (tab->info) - item_list.push_back(new Item_string(tab->info,strlen(tab->info))); + item_list.push_back(new Item_string(tab->info,strlen(tab->info), + default_charset_info)); else if (tab->select) { if (tab->use_quick == 2) @@ -7221,48 +7460,75 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, need_order=0; buff_ptr= strmov(buff_ptr,"; Using filesort"); } - if (distinct && test_all_bits(used_tables,thd->used_tables)) + if (distinct & test_all_bits(used_tables,thd->used_tables)) buff_ptr= strmov(buff_ptr,"; Distinct"); if (buff_ptr == buff) - buff_ptr+= 2; - item_list.push_back(new Item_string(buff+2,(uint) (buff_ptr - buff)-2)); + buff_ptr+= 2; // Skip inital "; " + item_list.push_back(new Item_string(buff+2,(uint) (buff_ptr - buff)-2, + default_charset_info)); // For next iteration used_tables|=table->map; if (result->send_data(item_list)) result->send_error(0,NullS); } } - if (!thd->lex.select->next) // Not union + for (SELECT_LEX_UNIT *unit= join->select_lex->first_inner_unit(); + unit; + unit= unit->next_unit()) { - save_lock=thd->lock; - thd->lock=(MYSQL_LOCK *)0; - result->send_eof(); - thd->lock=save_lock; + if (mysql_explain_union(thd, unit, result)) + DBUG_VOID_RETURN; } DBUG_VOID_RETURN; } - -static void describe_info(JOIN *join, const char *info) +int mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result) { - THD *thd= join->thd; + DBUG_ENTER("mysql_explain_union"); + int res= 0; + SELECT_LEX *first= unit->first_select(); + for (SELECT_LEX *sl= first; + sl; + sl= sl->next_select()) + { + res= mysql_explain_select(thd, sl, + (((&thd->lex.select_lex)==sl)? + ((sl->next_select_in_list())?"PRIMARY": + "SIMPLE"): + ((sl == first)? + ((sl->linkage == DERIVED_TABLE_TYPE) ? + "DERIVED": + ((sl->dependent)?"DEPENDENT SUBSELECT": + "SUBSELECT")): + ((sl->dependent)?"DEPENDENT UNION": + "UNION"))), + result); + if (res) + break; - if (thd->lex.select_lex.next) /* If in UNION */ - { - select_describe(join,FALSE,FALSE,FALSE,info); - return; } - List<Item> field_list; - String *packet= &thd->packet; + if (res > 0 || thd->net.report_error) + res= -1; // mysql_explain_select do not report error + DBUG_RETURN(res); +} - /* Don't log this into the slow query log */ - thd->lex.select_lex.options&= ~(QUERY_NO_INDEX_USED | - QUERY_NO_GOOD_INDEX_USED); - field_list.push_back(new Item_empty_string("Comment",80)); - if (send_fields(thd,field_list,1)) - return; /* purecov: inspected */ - packet->length(0); - net_store_data(packet,info); - if (!my_net_write(&thd->net,(char*) packet->ptr(),packet->length())) - send_eof(&thd->net); +int mysql_explain_select(THD *thd, SELECT_LEX *select_lex, char const *type, + select_result *result) +{ + DBUG_ENTER("mysql_explain_select"); + DBUG_PRINT("info", ("Select 0x%lx, type %s", (ulong)select_lex, type)) + select_lex->type= type; + thd->lex.current_select= select_lex; + SELECT_LEX_UNIT *unit= select_lex->master_unit(); + int res= mysql_select(thd,(TABLE_LIST*) select_lex->table_list.first, + select_lex->item_list, + select_lex->where, + (ORDER*) select_lex->order_list.first, + (ORDER*) select_lex->group_list.first, + select_lex->having, + (ORDER*) thd->lex.proc_list.first, + select_lex->options | thd->options | SELECT_DESCRIBE, + result, unit, select_lex, 0); + DBUG_RETURN(res); } + diff --git a/sql/sql_select.h b/sql/sql_select.h index befa1efde53..3b89c1ce0d3 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -149,8 +149,8 @@ class TMP_TABLE_PARAM { } }; - -class JOIN { +class JOIN :public Sql_alloc +{ public: JOIN_TAB *join_tab,**best_ref,**map2table; TABLE **table,**all_tables,*sort_by_table; @@ -173,6 +173,79 @@ class JOIN { select_result *result; TMP_TABLE_PARAM tmp_table_param; MYSQL_LOCK *lock; + // unit structure (with global parameters) for this select + SELECT_LEX_UNIT *unit; + // select that processed + SELECT_LEX *select_lex; + + bool select_distinct, //Is select distinct? + no_order, simple_order, simple_group, + skip_sort_order, need_tmp, + hidden_group_fields, + buffer_result; + DYNAMIC_ARRAY keyuse; + Item::cond_result cond_value; + List<Item> all_fields; + List<Item> & fields_list; // hold field list passed to mysql_select + int error; + + ORDER *order, *group_list, *proc_param; //hold parameters of mysql_select + COND *conds; // ---"--- + TABLE_LIST *tables_list; //hold 'tables' parameter of mysql_selec + SQL_SELECT *select; //created in optimisation phase + TABLE *exec_tmp_table; //used in 'exec' to hold temporary + + my_bool test_function_query; // need to return select items 1 row + const char *zero_result_cause; // not 0 if exec must return zero result + + my_bool union_part; // this subselect is part of union + + JOIN(THD *thd, List<Item> &fields, + ulong select_options, select_result *result): + join_tab(0), + table(0), + tables(0), const_tables(0), + sort_and_group(0), first_record(0), + do_send_rows(1), + send_records(0), found_records(0), examined_rows(0), + thd(thd), + sum_funcs(0), + procedure(0), + having(0), + select_options(select_options), + result(result), + lock(thd->lock), + select_lex(0), //for safety + select_distinct(test(select_options & SELECT_DISTINCT)), + no_order(0), simple_order(0), simple_group(0), skip_sort_order(0), + need_tmp(0), + hidden_group_fields (0), /*safety*/ + buffer_result(test(select_options & OPTION_BUFFER_RESULT) && + !test(select_options & OPTION_FOUND_ROWS)), + all_fields(fields), + fields_list(fields), + error(0), + select(0), + exec_tmp_table(0), + test_function_query(0), + zero_result_cause(0) + { + fields_list = fields; + bzero((char*) &keyuse,sizeof(keyuse)); + tmp_table_param.copy_field=0; + tmp_table_param.end_write_records= HA_POS_ERROR; + } + + int prepare(TABLE_LIST *tables, + COND *conds, ORDER *order, ORDER *group, Item *having, + ORDER *proc_param, SELECT_LEX *select, SELECT_LEX_UNIT *unit, + bool fake_select_lex); + int optimize(); + int global_optimize(); + int reinit(); + void exec(); + int cleanup(THD *thd); + bool check_loop(uint id); }; @@ -187,7 +260,8 @@ void TEST_join(JOIN *join); bool store_val_in_field(Field *field,Item *val); TABLE *create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, ORDER *group, bool distinct, bool save_sum_fields, - bool allow_distinct_limit, ulong select_options); + bool allow_distinct_limit, ulong select_options, + SELECT_LEX_UNIT *unit); void free_tmp_table(THD *thd, TABLE *entry); void count_field_types(TMP_TABLE_PARAM *param, List<Item> &fields, bool reset_with_sum_func); @@ -217,7 +291,7 @@ class store_key :public Sql_alloc if (field_arg->type() == FIELD_TYPE_BLOB) to_field=new Field_varstring(ptr, length, (uchar*) null, 1, Field::NONE, field_arg->field_name, - field_arg->table, field_arg->binary()); + field_arg->table, field_arg->charset()); else { to_field=field_arg->new_field(&thd->mem_root,field_arg->table); @@ -269,7 +343,7 @@ public: {} bool copy() { - item->save_in_field(to_field); + (void) item->save_in_field(to_field); return err != 0; } const char *name() const { return "func"; } @@ -293,7 +367,7 @@ public: if (!inited) { inited=1; - item->save_in_field(to_field); + (void)item->save_in_field(to_field); } return err != 0; } diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 8dfe5e9e948..ebf5b210d6c 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -1,4 +1,4 @@ -/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB +/* 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 @@ -57,7 +57,7 @@ extern struct st_VioSSLAcceptorFd * ssl_acceptor_fd; int mysqld_show_dbs(THD *thd,const char *wild) { - Item_string *field=new Item_string("",0); + Item_string *field=new Item_string("",0,default_charset_info); List<Item> field_list; char *end; List<char> files; @@ -76,6 +76,8 @@ mysqld_show_dbs(THD *thd,const char *wild) if (mysql_find_files(thd,&files,NullS,mysql_data_home,wild,1)) DBUG_RETURN(1); List_iterator_fast<char> it(files); + + String *packet= &thd->packet; while ((file_name=it++)) { if (thd->master_access & (DB_ACLS | SHOW_DB_ACL) || @@ -83,19 +85,20 @@ mysqld_show_dbs(THD *thd,const char *wild) thd->priv_user, file_name) || (grant_option && !check_grant_db(thd, file_name))) { - thd->packet.length(0); - net_store_data(&thd->packet, thd->variables.convert_set, file_name); - if (my_net_write(&thd->net, (char*) thd->packet.ptr(), - thd->packet.length())) + packet->length(0); + net_store_data(packet, thd->variables.convert_set, file_name); + if (my_net_write(&thd->net, (char*) packet->ptr(), + packet->length())) DBUG_RETURN(-1); } } - send_eof(&thd->net); + send_eof(thd); DBUG_RETURN(0); } + /*************************************************************************** -** List all open tables in a database + List all open tables in a database ***************************************************************************/ int mysqld_show_open_tables(THD *thd,const char *wild) @@ -116,19 +119,20 @@ int mysqld_show_open_tables(THD *thd,const char *wild) if (!(open_list=list_open_tables(thd,wild)) && thd->fatal_error) DBUG_RETURN(-1); + String *packet= &thd->packet; for (; open_list ; open_list=open_list->next) { - thd->packet.length(0); - net_store_data(&thd->packet,convert, open_list->db); - net_store_data(&thd->packet,convert, open_list->table); - net_store_data(&thd->packet,open_list->in_use); - net_store_data(&thd->packet,open_list->locked); - if (my_net_write(&thd->net,(char*) thd->packet.ptr(),thd->packet.length())) + packet->length(0); + net_store_data(packet,convert, open_list->db); + net_store_data(packet,convert, open_list->table); + net_store_data(packet,open_list->in_use); + net_store_data(packet,open_list->locked); + if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length())) { DBUG_RETURN(-1); } } - send_eof(&thd->net); + send_eof(thd); DBUG_RETURN(0); } @@ -140,7 +144,7 @@ int mysqld_show_open_tables(THD *thd,const char *wild) int mysqld_show_tables(THD *thd,const char *db,const char *wild) { - Item_string *field=new Item_string("",0); + Item_string *field=new Item_string("",0,default_charset_info); List<Item> field_list; char path[FN_LEN],*end; List<char> files; @@ -160,14 +164,228 @@ int mysqld_show_tables(THD *thd,const char *db,const char *wild) if (mysql_find_files(thd,&files,db,path,wild,0)) DBUG_RETURN(-1); List_iterator_fast<char> it(files); + String *packet= &thd->packet; while ((file_name=it++)) { - thd->packet.length(0); - net_store_data(&thd->packet, thd->variables.convert_set, file_name); - if (my_net_write(&thd->net,(char*) thd->packet.ptr(),thd->packet.length())) + packet->length(0); + net_store_data(packet, thd->variables.convert_set, file_name); + if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length())) DBUG_RETURN(-1); } - send_eof(&thd->net); + send_eof(thd); + DBUG_RETURN(0); +} + +/*************************************************************************** +** List all table types supported +***************************************************************************/ + +struct show_table_type_st { + const char *type; + SHOW_COMP_OPTION *value; + const char *comment; +}; + + +SHOW_COMP_OPTION have_yes= SHOW_OPTION_YES; + +static struct show_table_type_st sys_table_types[]= +{ + {"MyISAM", &have_yes, + "Default type from 3.23 with great performance"}, + {"HEAP" , &have_yes, + "Hash based, stored in memory, useful for temporary tables"}, + {"MERGE", &have_yes, + "Collection of identical MyISAM tables"}, + {"ISAM", &have_isam, + "Obsolete table type; Is replaced by MyISAM"}, + {"InnoDB", &have_innodb, + "Supports transactions, row-level locking and foreign keys"}, + {"BDB", &have_berkeley_db, + "Supports transactions and page-level locking"}, + {NullS, NULL, NullS} +}; + + +int mysqld_show_table_types(THD *thd) +{ + List<Item> field_list; + DBUG_ENTER("mysqld_show_table_types"); + + field_list.push_back(new Item_empty_string("Type",10)); + field_list.push_back(new Item_empty_string("Support",10)); + field_list.push_back(new Item_empty_string("Comment",80)); + + if (send_fields(thd,field_list,1)) + DBUG_RETURN(1); + + const char *default_type_name= ha_table_typelib.type_names[thd->variables.table_type]; + + show_table_type_st *types; + String *packet= &thd->packet; + for (types= sys_table_types; types->type; types++) + { + packet->length(0); + net_store_data(packet, types->type); + const char *option_name= show_comp_option_name[(int) *types->value]; + + if (*types->value == SHOW_OPTION_YES && + !my_strcasecmp(system_charset_info, default_type_name, types->type)) + option_name= "DEFAULT"; + net_store_data(packet, option_name); + net_store_data(packet, types->comment); + if (my_net_write(&thd->net, (char*) packet->ptr(), packet->length())) + DBUG_RETURN(-1); + } + send_eof(thd); + DBUG_RETURN(0); +} + + +/*************************************************************************** + List all privileges supported +***************************************************************************/ + +struct show_privileges_st { + const char *privilege; + const char *context; + const char *comment; +}; + + +/* + TODO: Update with new privileges +*/ +static struct show_privileges_st sys_privileges[]= +{ + {"Select", "Tables", "To retrieve rows from table"}, + {"Insert", "Tables", "To insert data into tables"}, + {"Update", "Tables", "To update existing rows "}, + {"Delete", "Tables", "To delete existing rows"}, + {"Index", "Tables", "To create or drop indexes"}, + {"Alter", "Tables", "To alter the table"}, + {"Create", "Databases,Tables,Indexes", "To create new databases and tables"}, + {"Drop", "Databases,Tables", "To drop databases and tables"}, + {"Grant", "Databases,Tables", "To give to other users those privileges you possess"}, + {"References", "Databases,Tables", "To have references on tables"}, + {"Reload", "Server Admin", "To reload or refresh tables, logs and privileges"}, + {"Shutdown","Server Admin", "To shutdown the server"}, + {"Process", "Server Admin", "To view the plain text of currently executing queries"}, + {"File", "File access on server", "To read and write files on the server"}, + {NullS, NullS, NullS} +}; + + +int mysqld_show_privileges(THD *thd) +{ + List<Item> field_list; + DBUG_ENTER("mysqld_show_privileges"); + + field_list.push_back(new Item_empty_string("Privilege",10)); + field_list.push_back(new Item_empty_string("Context",15)); + field_list.push_back(new Item_empty_string("Comment",NAME_LEN)); + + if (send_fields(thd,field_list,1)) + DBUG_RETURN(1); + + show_privileges_st *privilege= sys_privileges; + String *packet= &thd->packet; + for (privilege= sys_privileges; privilege->privilege ; privilege++) + { + packet->length(0); + net_store_data(packet,privilege->privilege); + net_store_data(packet,privilege->context); + net_store_data(packet,privilege->comment); + if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length())) + DBUG_RETURN(-1); + } + send_eof(thd); + DBUG_RETURN(0); +} + + +/*************************************************************************** + List all column types +***************************************************************************/ + +struct show_column_type_st +{ + const char *type; + uint size; + const char *min_value; + const char *max_value; + uint precision; + uint scale; + const char *nullable; + const char *auto_increment; + const char *unsigned_attr; + const char *zerofill; + const char *searchable; + const char *case_sensitivity; + const char *default_value; + const char *comment; +}; + +/* TODO: Add remaning types */ + +static struct show_column_type_st sys_column_types[]= +{ + {"tinyint", + 1, "-128", "127", 0, 0, "YES", "YES", + "NO", "YES", "YES", "NO", "NULL,0", + "A very small integer"}, + {"tinyint unsigned", + 1, "0" , "255", 0, 0, "YES", "YES", + "YES", "YES", "YES", "NO", "NULL,0", + "A very small integer"}, +}; + +int mysqld_show_column_types(THD *thd) +{ + List<Item> field_list; + DBUG_ENTER("mysqld_show_column_types"); + + field_list.push_back(new Item_empty_string("Type",30)); + field_list.push_back(new Item_int("Size",(longlong) 1,21)); + field_list.push_back(new Item_empty_string("Min_Value",20)); + field_list.push_back(new Item_empty_string("Max_Value",20)); + field_list.push_back(new Item_int("Prec", 0,4)); + field_list.push_back(new Item_int("Scale", 0,4)); + field_list.push_back(new Item_empty_string("Nullable",4)); + field_list.push_back(new Item_empty_string("Auto_Increment",4)); + field_list.push_back(new Item_empty_string("Unsigned",4)); + field_list.push_back(new Item_empty_string("Zerofill",4)); + field_list.push_back(new Item_empty_string("Searchable",4)); + field_list.push_back(new Item_empty_string("Case_Sensitive",4)); + field_list.push_back(new Item_empty_string("Default",NAME_LEN)); + field_list.push_back(new Item_empty_string("Comment",NAME_LEN)); + + if (send_fields(thd,field_list,1)) + DBUG_RETURN(1); + + /* TODO: Change the loop to not use 'i' */ + String *packet= &thd->packet; + for (uint i=0; i < sizeof(sys_column_types)/sizeof(sys_column_types[0]); i++) + { + packet->length(0); + net_store_data(packet,sys_column_types[i].type); + net_store_data(packet,(longlong)sys_column_types[i].size); + net_store_data(packet,sys_column_types[i].min_value); + net_store_data(packet,sys_column_types[i].max_value); + net_store_data(packet,(uint32)sys_column_types[i].precision); + net_store_data(packet,(uint32)sys_column_types[i].scale); + net_store_data(packet,sys_column_types[i].nullable); + net_store_data(packet,sys_column_types[i].auto_increment); + net_store_data(packet,sys_column_types[i].unsigned_attr); + net_store_data(packet,sys_column_types[i].zerofill); + net_store_data(packet,sys_column_types[i].searchable); + net_store_data(packet,sys_column_types[i].case_sensitivity); + net_store_data(packet,sys_column_types[i].default_value); + net_store_data(packet,sys_column_types[i].comment); + if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length())) + DBUG_RETURN(-1); + } + send_eof(thd); DBUG_RETURN(0); } @@ -211,7 +429,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; @@ -219,7 +437,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)) @@ -246,8 +464,9 @@ mysql_find_files(THD *thd,List<char> *files, const char *db,const char *path, DBUG_RETURN(0); } + /*************************************************************************** -** Extended version of mysqld_show_tables + Extended version of mysqld_show_tables ***************************************************************************/ int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild) @@ -264,7 +483,6 @@ int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild) (void) sprintf(path,"%s/%s",mysql_data_home,db); (void) unpack_dirname(path,path); - field_list.push_back(item=new Item_empty_string("Name",NAME_LEN)); item->maybe_null=1; field_list.push_back(item=new Item_empty_string("Type",10)); @@ -291,6 +509,8 @@ int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild) item->maybe_null=1; field_list.push_back(item=new Item_datetime("Check_time")); item->maybe_null=1; + field_list.push_back(item=new Item_empty_string("Charset",32)); + item->maybe_null=1; field_list.push_back(item=new Item_empty_string("Create_options",255)); item->maybe_null=1; field_list.push_back(item=new Item_empty_string("Comment",80)); @@ -366,6 +586,8 @@ int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild) localtime_r(&file->check_time,&tm_tmp); net_store_data(packet, &tm_tmp); } + net_store_data(packet, convert, table->table_charset ? + table->table_charset->name : "default"); { char option_buff[350],*ptr; ptr=option_buff; @@ -417,12 +639,11 @@ int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild) packet->length())) DBUG_RETURN(-1); } - send_eof(&thd->net); + send_eof(thd); DBUG_RETURN(0); } - /*************************************************************************** ** List all columns in a table_list->real_name ***************************************************************************/ @@ -442,7 +663,7 @@ mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild, if (!(table = open_ltable(thd, table_list, TL_UNLOCK))) { - send_error(&thd->net); + send_error(thd); DBUG_RETURN(1); } file=table->file; @@ -458,8 +679,10 @@ mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild, item->maybe_null=1; field_list.push_back(new Item_empty_string("Extra",20)); if (verbose) + { field_list.push_back(new Item_empty_string("Privileges",80)); - + field_list.push_back(new Item_empty_string("Comment",255)); + } // Send first number of fields and records { char *pos; @@ -476,7 +699,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 || @@ -486,7 +710,7 @@ mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild, { byte *pos; uint flags=field->flags; - String type(tmp,sizeof(tmp)); + String type(tmp,sizeof(tmp),default_charset_info); uint col_access; bool null_default_value=0; @@ -509,7 +733,7 @@ mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild, null_default_value=1; if (!null_default_value && !field->is_null()) { // Not null by default - type.set(tmp,sizeof(tmp)); + type.set(tmp,sizeof(tmp),default_charset_info); field->val_str(&type,&type); net_store_data(packet,convert,type.ptr(),type.length()); } @@ -525,7 +749,7 @@ mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild, if (verbose) { - /* Add grant options */ + /* Add grant options & comments */ col_access= get_column_grant(thd,table_list,field) & COL_ACLS; end=tmp; for (uint bitnr=0; col_access ; col_access>>=1,bitnr++) @@ -537,16 +761,18 @@ mysqld_show_fields(THD *thd, TABLE_LIST *table_list,const char *wild, } } net_store_data(packet,convert, tmp+1,end == tmp ? 0 : (uint) (end-tmp-1)); + net_store_data(packet, field->comment.str,field->comment.length); } if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length())) DBUG_RETURN(1); } } } - send_eof(&thd->net); + send_eof(thd); DBUG_RETURN(0); } + int mysqld_show_create(THD *thd, TABLE_LIST *table_list) { @@ -559,7 +785,7 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) /* Only one table for now */ if (!(table = open_ltable(thd, table_list, TL_UNLOCK))) { - send_error(&thd->net); + send_error(thd); DBUG_RETURN(1); } @@ -584,6 +810,10 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) if (store_create_info(thd, table, packet)) DBUG_RETURN(-1); ulong create_len = packet->length() - store_len_offset - 4; + /* + Just in case somebody manages to create a table + with *that* much stuff in the definition + */ if (create_len > 0x00ffffff) // better readable in HEX ... { /* @@ -606,7 +836,7 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list) if (my_net_write(&thd->net, (char*)packet->ptr(), packet->length())) DBUG_RETURN(1); } - send_eof(&thd->net); + send_eof(thd); DBUG_RETURN(0); } @@ -629,7 +859,7 @@ mysqld_show_logs(THD *thd) DBUG_RETURN(-1); #endif - send_eof(&thd->net); + send_eof(thd); DBUG_RETURN(0); } @@ -646,7 +876,7 @@ mysqld_show_keys(THD *thd, TABLE_LIST *table_list) if (!(table = open_ltable(thd, table_list, TL_UNLOCK))) { - send_error(&thd->net); + send_error(thd); DBUG_RETURN(1); } @@ -730,14 +960,14 @@ mysqld_show_keys(THD *thd, TABLE_LIST *table_list) DBUG_RETURN(1); /* purecov: inspected */ } } - send_eof(&thd->net); + send_eof(thd); DBUG_RETURN(0); } /**************************************************************************** -** Return only fields for API mysql_list_fields -** Use "show table wildcard" in mysql instead of this + Return only fields for API mysql_list_fields + Use "show table wildcard" in mysql instead of this ****************************************************************************/ void @@ -749,7 +979,7 @@ mysqld_list_fields(THD *thd, TABLE_LIST *table_list, const char *wild) if (!(table = open_ltable(thd, table_list, TL_UNLOCK))) { - send_error(&thd->net); + send_error(thd); DBUG_VOID_RETURN; } List<Item> field_list; @@ -757,7 +987,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 @@ -767,6 +998,7 @@ mysqld_list_fields(THD *thd, TABLE_LIST *table_list, const char *wild) DBUG_VOID_RETURN; } + int mysqld_dump_create_info(THD *thd, TABLE *table, int fd) { @@ -774,7 +1006,7 @@ mysqld_dump_create_info(THD *thd, TABLE *table, int fd) DBUG_ENTER("mysqld_dump_create_info"); DBUG_PRINT("enter",("table: %s",table->real_name)); - String* packet = &thd->packet; + String *packet = &thd->packet; packet->length(0); if (store_create_info(thd,table,packet)) DBUG_RETURN(-1); @@ -796,6 +1028,7 @@ mysqld_dump_create_info(THD *thd, TABLE *table, int fd) DBUG_RETURN(0); } + static void append_identifier(THD *thd, String *packet, const char *name) { @@ -811,6 +1044,7 @@ append_identifier(THD *thd, String *packet, const char *name) } } + static int store_create_info(THD *thd, TABLE *table, String *packet) { @@ -821,7 +1055,7 @@ store_create_info(THD *thd, TABLE *table, String *packet) List<Item> field_list; char tmp[MAX_FIELD_WIDTH]; - String type(tmp, sizeof(tmp)); + String type(tmp, sizeof(tmp),default_charset_info); if (table->tmp_table) packet->append("CREATE TEMPORARY TABLE ", 23); else @@ -841,7 +1075,7 @@ store_create_info(THD *thd, TABLE *table, String *packet) packet->append(' '); // check for surprises from the previous call to Field::sql_type() if (type.ptr() != tmp) - type.set(tmp, sizeof(tmp)); + type.set(tmp, sizeof(tmp),default_charset_info); field->sql_type(type); packet->append(type.ptr(),type.length()); @@ -857,12 +1091,12 @@ store_create_info(THD *thd, TABLE *table, String *packet) packet->append(" default ", 9); if (!field->is_null()) { // Not null by default - type.set(tmp,sizeof(tmp)); + type.set(tmp,sizeof(tmp),default_charset_info); field->val_str(&type,&type); - packet->append('\''); if (type.length()) - append_unescaped(packet, type.c_ptr()); - packet->append('\''); + append_unescaped(packet, type.ptr(), type.length()); + else + packet->append("''",2); } else if (field->maybe_null()) packet->append("NULL", 4); // Null as default @@ -871,7 +1105,13 @@ store_create_info(THD *thd, TABLE *table, String *packet) } if (field->unireg_check == Field::NEXT_NUMBER) - packet->append(" auto_increment", 15 ); + packet->append(" auto_increment", 15 ); + + if (field->comment.length) + { + packet->append(" COMMENT ",9); + append_unescaped(packet, field->comment.str, field->comment.length); + } } KEY *key_info=table->key_info; @@ -893,11 +1133,22 @@ 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); + if (table->db_type == DB_TYPE_HEAP && + key_info->algorithm == HA_KEY_ALG_BTREE) + packet->append(" USING BTREE", 12); + + // +BAR: send USING only in non-default case: non-spatial rtree + if((key_info->algorithm == 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++) @@ -941,6 +1192,12 @@ store_create_info(THD *thd, TABLE *table, String *packet) char buff[128]; char* p; + if (table->table_charset) + { + packet->append(" CHARSET="); + packet->append(table->table_charset->name); + } + if (table->min_rows) { packet->append(" MIN_ROWS="); @@ -977,9 +1234,8 @@ store_create_info(THD *thd, TABLE *table, String *packet) table->file->append_create_info(packet); if (table->comment && table->comment[0]) { - packet->append(" COMMENT='", 10); - append_unescaped(packet, table->comment); - packet->append('\''); + packet->append(" COMMENT=", 9); + append_unescaped(packet, table->comment, strlen(table->comment)); } if (file->raid_type) { @@ -993,8 +1249,8 @@ store_create_info(THD *thd, TABLE *table, String *packet) /**************************************************************************** -** Return info about all processes -** returns for each thread: thread id, user, host, db, command, info + Return info about all processes + returns for each thread: thread id, user, host, db, command, info ****************************************************************************/ class thread_info :public ilink { @@ -1135,25 +1391,66 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose) if (my_net_write(&thd->net,(char*) packet->ptr(),packet->length())) break; /* purecov: inspected */ } - send_eof(&thd->net); + send_eof(thd); DBUG_VOID_RETURN; } /***************************************************************************** -** Status functions + Status functions *****************************************************************************/ +int mysqld_show_charsets(THD *thd, const char *wild) +{ + char buff[8192]; + String packet2(buff,sizeof(buff),default_charset_info); + List<Item> field_list; + CONVERT *convert=thd->variables.convert_set; + CHARSET_INFO **cs; + DBUG_ENTER("mysqld_show_charsets"); + + field_list.push_back(new Item_empty_string("Name",30)); + field_list.push_back(new Item_int("Id",0,7)); + field_list.push_back(new Item_int("strx_maxlen",0,7)); + field_list.push_back(new Item_int("mb_maxlen",0,7)); + + if (send_fields(thd,field_list,1)) + DBUG_RETURN(1); + + for (cs=all_charsets ; cs < all_charsets+255 ; cs++ ) + { + if (!cs[0]) + continue; + if (!(wild && wild[0] && + wild_case_compare(system_charset_info,cs[0]->name,wild))) + { + packet2.length(0); + net_store_data(&packet2,convert,cs[0]->name); + net_store_data(&packet2,(uint32) cs[0]->number); + net_store_data(&packet2,(uint32) cs[0]->strxfrm_multiply); + net_store_data(&packet2,(uint32) (cs[0]->mbmaxlen)); + + if (my_net_write(&thd->net, (char*) packet2.ptr(),packet2.length())) + goto err; + } + } + send_eof(thd); + DBUG_RETURN(0); +err: + DBUG_RETURN(1); +} + + int mysqld_show(THD *thd, const char *wild, show_var_st *variables, enum enum_var_type value_type) { char buff[8192]; - String packet2(buff,sizeof(buff)); + String packet2(buff,sizeof(buff), system_charset_info); List<Item> field_list; CONVERT *convert=thd->variables.convert_set; - DBUG_ENTER("mysqld_show"); + field_list.push_back(new Item_empty_string("Variable_name",30)); field_list.push_back(new Item_empty_string("Value",256)); if (send_fields(thd,field_list,1)) @@ -1163,7 +1460,8 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables, pthread_mutex_lock(&LOCK_status); for (; variables->name; variables++) { - if (!(wild && wild[0] && wild_case_compare(variables->name,wild))) + if (!(wild && wild[0] && wild_case_compare(system_charset_info, + variables->name,wild))) { packet2.length(0); net_store_data(&packet2,convert,variables->name); @@ -1196,9 +1494,7 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables, case SHOW_HAVE: { SHOW_COMP_OPTION tmp= *(SHOW_COMP_OPTION*) value; - net_store_data(&packet2, (tmp == SHOW_OPTION_NO ? "NO" : - tmp == SHOW_OPTION_YES ? "YES" : - "DISABLED")); + net_store_data(&packet2, show_comp_option_name[(int) tmp]); break; } case SHOW_CHAR: @@ -1398,7 +1694,7 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables, } pthread_mutex_unlock(&LOCK_status); /* pthread_mutex_unlock(&THR_LOCK_keycache); */ - send_eof(&thd->net); + send_eof(thd); DBUG_RETURN(0); err: diff --git a/sql/sql_string.cc b/sql/sql_string.cc index 2dcda2d40c2..5083fb13105 100644 --- a/sql/sql_string.cc +++ b/sql/sql_string.cc @@ -91,36 +91,58 @@ bool String::realloc(uint32 alloc_length) return FALSE; } -bool String::set(longlong num) +bool String::set(longlong num, CHARSET_INFO *cs) { - if (alloc(21)) + uint l=20*cs->mbmaxlen+1; + + if (alloc(l)) return TRUE; - str_length=(uint32) (longlong10_to_str(num,Ptr,-10)-Ptr); + if (cs->snprintf == my_snprintf_8bit) + { + str_length=(uint32) (longlong10_to_str(num,Ptr,-10)-Ptr); + } + else + { + str_length=cs->snprintf(cs,Ptr,l,"%d",num); + } + str_charset=cs; return FALSE; } -bool String::set(ulonglong num) +bool String::set(ulonglong num, CHARSET_INFO *cs) { - if (alloc(21)) + uint l=20*cs->mbmaxlen+1; + + if (alloc(l)) return TRUE; - str_length=(uint32) (longlong10_to_str(num,Ptr,10)-Ptr); + if (cs->snprintf == my_snprintf_8bit) + { + str_length=(uint32) (longlong10_to_str(num,Ptr,10)-Ptr); + } + else + { + str_length=cs->snprintf(cs,Ptr,l,"%d",num); + } + str_charset=cs; return FALSE; } -bool String::set(double num,uint decimals) +bool String::set(double num,uint decimals, CHARSET_INFO *cs) { char buff[331]; + + str_charset=cs; if (decimals >= NOT_FIXED_DEC) { sprintf(buff,"%.14g",num); // Enough for a DATETIME - return copy(buff, (uint32) strlen(buff)); + return copy(buff, (uint32) strlen(buff), my_charset_latin1, cs); } #ifdef HAVE_FCONVERT int decpt,sign; char *pos,*to; VOID(fconvert(num,(int) decimals,&decpt,&sign,buff+1)); - if (!isdigit(buff[1])) + if (!my_isdigit(my_charset_latin1, buff[1])) { // Nan or Inf pos=buff+1; if (sign) @@ -128,7 +150,7 @@ bool String::set(double num,uint decimals) buff[0]='-'; pos=buff; } - return copy(pos,(uint32) strlen(pos)); + return copy(pos,(uint32) strlen(pos), my_charset_latin1, cs); } if (alloc((uint32) ((uint32) decpt+3+decimals))) return TRUE; @@ -178,7 +200,7 @@ end: #else sprintf(buff,"%.*f",(int) decimals,num); #endif - return copy(buff,(uint32) strlen(buff)); + return copy(buff,(uint32) strlen(buff), my_charset_latin1, cs); #endif } @@ -200,16 +222,67 @@ bool String::copy(const String &str) str_length=str.str_length; bmove(Ptr,str.Ptr,str_length); // May be overlapping Ptr[str_length]=0; + str_charset=str.str_charset; return FALSE; } -bool String::copy(const char *str,uint32 arg_length) +bool String::copy(const char *str,uint32 arg_length, CHARSET_INFO *cs) { if (alloc(arg_length)) return TRUE; if ((str_length=arg_length)) memcpy(Ptr,str,arg_length); Ptr[arg_length]=0; + str_charset=cs; + return FALSE; +} + +/* Copy with charset convertion */ +bool String::copy(const char *str,uint32 arg_length, CHARSET_INFO *from, CHARSET_INFO *to) +{ + uint32 new_length=to->mbmaxlen*arg_length; + int cnvres; + my_wc_t wc; + const uchar *s=(const uchar *)str; + const uchar *se=s+arg_length; + uchar *d, *de; + + if (alloc(new_length)) + return TRUE; + + d=(uchar *)Ptr; + de=d+new_length; + + for (str_length=new_length ; s < se && d < de ; ) + { + if ((cnvres=from->mb_wc(from,&wc,s,se)) > 0 ) + { + s+=cnvres; + } + else if (cnvres==MY_CS_ILSEQ) + { + s++; + wc='?'; + } + else + break; + +outp: + if((cnvres=to->wc_mb(to,wc,d,de)) >0 ) + { + d+=cnvres; + } + else if (cnvres==MY_CS_ILUNI && wc!='?') + { + wc='?'; + goto outp; + } + else + break; + } + Ptr[new_length]=0; + length((uint32) (d-(uchar *)Ptr)); + str_charset=to; return FALSE; } @@ -231,7 +304,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--; } @@ -293,10 +366,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; } @@ -313,11 +386,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; } @@ -377,12 +450,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; } } @@ -456,6 +531,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, (char*) 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) { @@ -464,15 +577,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_strnxfrm(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 @@ -480,11 +593,23 @@ int sortcmp(const String *x,const String *y) #endif /* USE_STRCOLL */ x_len-=len; // For easy end space test y_len-=len; - while (len--) + if (x->str_charset->sort_order) { - 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]]); + while (len--) + { + 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]]); + } + } + else + { + while (len--) + { + if (*s++ != *t++) + return ((int) s[-1] - (int) t[-1]); + } } #ifndef CMP_ENDSPACE /* Don't compare end space in strings */ @@ -493,14 +618,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; @@ -542,263 +667,9 @@ String *copy_if_not_alloced(String *to,String *from,uint32 from_length) return from; // Actually an error if ((to->str_length=min(from->str_length,from_length))) memcpy(to->Ptr,from->Ptr,to->str_length); + to->str_charset=from->str_charset; return to; } -/* 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) -#else -#define INC_PTR(A,B) A++ -#endif -/* -** Compare string against string with wildcard -** 0 if matched -** -1 if not matched with wildcard -** 1 if matched with wildcard -*/ - -#ifdef LIKE_CMP_TOUPPER -#define likeconv(A) (uchar) toupper(A) -#else -#define likeconv(A) (uchar) my_sort_order[(uchar) (A)] -#endif - -int wild_case_compare(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); -#endif - while (wildstr != wildend) - { - while (*wildstr != wild_many && *wildstr != wild_one) - { - if (*wildstr == escape && wildstr+1 != wildend) - wildstr++; -#ifdef USE_MB - int l; - if (use_mb_flag && - (l = my_ismbchar(default_charset_info, wildstr, wildend))) - { - if (str+l > str_end || memcmp(str, wildstr, l) != 0) - return 1; - str += l; - wildstr += l; - } - else -#endif - if (str == str_end || likeconv(*wildstr++) != likeconv(*str++)) - return(1); // No match - if (wildstr == wildend) - return (str != str_end); // Match if both are at end - result=1; // Found an anchor char - } - if (*wildstr == wild_one) - { - do - { - if (str == str_end) // Skip one char if possible - return (result); - INC_PTR(str,str_end); - } while (++wildstr < wildend && *wildstr == wild_one); - if (wildstr == wildend) - break; - } - if (*wildstr == wild_many) - { // Found wild_many - wildstr++; - /* Remove any '%' and '_' from the wild search string */ - for (; wildstr != wildend ; wildstr++) - { - if (*wildstr == wild_many) - continue; - if (*wildstr == wild_one) - { - if (str == str_end) - return (-1); - INC_PTR(str,str_end); - continue; - } - break; // Not a wild character - } - if (wildstr == wildend) - return(0); // Ok if wild_many is last - if (str == str_end) - return -1; - - uchar cmp; - if ((cmp= *wildstr) == escape && wildstr+1 != wildend) - cmp= *++wildstr; -#ifdef USE_MB - const char* mb = wildstr; - int mblen; - LINT_INIT(mblen); - if (use_mb_flag) - mblen = my_ismbchar(default_charset_info, wildstr, wildend); -#endif - INC_PTR(wildstr,wildend); // This is compared trough cmp - cmp=likeconv(cmp); - do - { -#ifdef USE_MB - if (use_mb_flag) - { - for (;;) - { - if (str >= str_end) - return -1; - if (mblen) - { - if (str+mblen <= str_end && memcmp(str, mb, mblen) == 0) - { - str += mblen; - break; - } - } - else if (!my_ismbchar(default_charset_info, str, str_end) && - likeconv(*str) == cmp) - { - str++; - break; - } - INC_PTR(str, str_end); - } - } - else - { -#endif /* USE_MB */ - while (str != str_end && likeconv(*str) != cmp) - str++; - if (str++ == str_end) return (-1); -#ifdef USE_MB - } -#endif - { - int tmp=wild_case_compare(str,str_end,wildstr,wildend,escape); - if (tmp <= 0) - return (tmp); - } - } while (str != str_end && wildstr[0] != wild_many); - return(-1); - } - } - return (str != str_end ? 1 : 0); -} - - -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(), - wild.ptr(), wild.ptr()+wild.length(),escape)); -} - -/* -** The following is used when using LIKE on binary strings -*/ - -int wild_compare(const char *str,const char *str_end, - const char *wildstr,const char *wildend,char escape) -{ - DBUG_ENTER("wild_compare"); - DBUG_PRINT("enter",("str='%s', str_end='%s', wildstr='%s', wildend='%s', escape='%c'" - ,str,str_end,wildstr,wildend,escape)); - int result= -1; // Not found, using wildcards - while (wildstr != wildend) - { - while (*wildstr != wild_many && *wildstr != wild_one) - { - if (*wildstr == escape && wildstr+1 != wildend) - wildstr++; - if (str == str_end || *wildstr++ != *str++) - { - DBUG_RETURN(1); - } - if (wildstr == wildend) - { - DBUG_RETURN(str != str_end); // Match if both are at end - } - result=1; // Found an anchor char - } - if (*wildstr == wild_one) - { - do - { - if (str == str_end) // Skip one char if possible - DBUG_RETURN(result); - str++; - } while (*++wildstr == wild_one && wildstr != wildend); - if (wildstr == wildend) - break; - } - if (*wildstr == wild_many) - { // Found wild_many - wildstr++; - /* Remove any '%' and '_' from the wild search string */ - for (; wildstr != wildend ; wildstr++) - { - if (*wildstr == wild_many) - continue; - if (*wildstr == wild_one) - { - if (str == str_end) - { - DBUG_RETURN(-1); - } - str++; - continue; - } - break; // Not a wild character - } - if (wildstr == wildend) - { - DBUG_RETURN(0); // Ok if wild_many is last - } - if (str == str_end) - { - DBUG_RETURN(-1); - } - char cmp; - if ((cmp= *wildstr) == escape && wildstr+1 != wildend) - cmp= *++wildstr; - wildstr++; // This is compared trough cmp - do - { - while (str != str_end && *str != cmp) - str++; - if (str++ == str_end) - { - DBUG_RETURN(-1); - } - { - int tmp=wild_compare(str,str_end,wildstr,wildend,escape); - if (tmp <= 0) - { - DBUG_RETURN(tmp); - } - } - } while (str != str_end && wildstr[0] != wild_many); - DBUG_RETURN(-1); - } - } - DBUG_RETURN(str != str_end ? 1 : 0); -} - - -int wild_compare(String &match,String &wild, char escape) -{ - DBUG_ENTER("wild_compare"); - DBUG_PRINT("enter",("match='%s', wild='%s', escape='%c'" - ,match.ptr(),wild.ptr(),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..42f9e446981 100644 --- a/sql/sql_string.h +++ b/sql/sql_string.h @@ -28,34 +28,52 @@ class String; int sortcmp(const String *a,const String *b); int stringcmp(const String *a,const String *b); String *copy_if_not_alloced(String *a,String *b,uint32 arg_length); -int wild_case_compare(String &match,String &wild,char escape); -int wild_compare(String &match,String &wild,char escape); 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); } - String(const char *str) - { Ptr=(char*) str; str_length=(uint) strlen(str); Alloced_length=0; alloced=0;} - String(const char *str,uint32 len) - { Ptr=(char*) str; str_length=len; Alloced_length=0; alloced=0;} - String(char *str,uint32 len) - { Ptr=(char*) str; Alloced_length=str_length=len; alloced=0;} + { + alloced=0; Alloced_length=0; (void) real_alloc(length_arg); + str_charset=default_charset_info; + } + String(const char *str, CHARSET_INFO *cs) + { + Ptr=(char*) str; str_length=(uint) strlen(str); Alloced_length=0; alloced=0; + str_charset=cs; + } + String(const char *str,uint32 len, CHARSET_INFO *cs) + { + Ptr=(char*) str; str_length=len; Alloced_length=0; alloced=0; + str_charset=cs; + } + String(char *str,uint32 len, CHARSET_INFO *cs) + { + Ptr=(char*) str; Alloced_length=str_length=len; alloced=0; + str_charset=cs; + } 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]; } @@ -83,28 +101,31 @@ public: Alloced_length=str.Alloced_length-offset; else Alloced_length=0; + str_charset=str.str_charset; } - inline void set(char *str,uint32 arg_length) + inline void set(char *str,uint32 arg_length, CHARSET_INFO *cs) { free(); Ptr=(char*) str; str_length=Alloced_length=arg_length ; alloced=0; + str_charset=cs; } - inline void set(const char *str,uint32 arg_length) + inline void set(const char *str,uint32 arg_length, CHARSET_INFO *cs) { free(); Ptr=(char*) str; str_length=arg_length; Alloced_length=0 ; alloced=0; + str_charset=cs; } - inline void set_quick(char *str,uint32 arg_length) + inline void set_quick(char *str,uint32 arg_length, CHARSET_INFO *cs) { if (!alloced) { Ptr=(char*) str; str_length=Alloced_length=arg_length; } + str_charset=cs; } - bool set(longlong num); - /* bool set(long num); */ - bool set(ulonglong num); - bool set(double num,uint decimals=2); + bool set(longlong num, CHARSET_INFO *cs); + bool set(ulonglong num, CHARSET_INFO *cs); + bool set(double num,uint decimals, CHARSET_INFO *cs); inline void free() { if (alloced) @@ -155,7 +176,8 @@ public: bool copy(); // Alloc string if not alloced bool copy(const String &s); // Allocate new string - bool copy(const char *s,uint32 arg_length); // Allocate new string + bool copy(const char *s,uint32 arg_length, CHARSET_INFO *cs); // Allocate new string + bool copy(const char*s,uint32 arg_length, CHARSET_INFO *csfrom, CHARSET_INFO *csto); bool append(const String &s); bool append(const char *s,uint32 arg_length=0); bool append(IO_CACHE* file, uint32 arg_length); @@ -179,13 +201,57 @@ 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); - friend int wild_case_compare(String &match,String &wild,char escape); - friend int wild_compare(String &match,String &wild,char escape); uint32 numchars(); int charpos(int i,uint32 offset=0); + + int reserve(uint32 space_needed) + { + return realloc(str_length + space_needed); + } + int reserve(uint32 space_needed, uint32 grow_by); + + /* + The following 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 aa0946113c9..00077bda39f 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -74,7 +74,7 @@ int mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists) } error=mysql_rm_table_part2(thd,tables,if_exists,0); - err: + err: pthread_mutex_unlock(&LOCK_open); VOID(pthread_cond_broadcast(&COND_refresh)); // Signal to refresh @@ -85,7 +85,7 @@ int mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists) if (error) DBUG_RETURN(-1); - send_ok(&thd->net); + send_ok(thd); DBUG_RETURN(0); } @@ -185,7 +185,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, { if (wrong_tables.length()) wrong_tables.append(','); - wrong_tables.append(String(table->real_name)); + wrong_tables.append(String(table->real_name,default_charset_info)); } } if (some_tables_deleted || tmp_table_deleted) @@ -239,7 +239,6 @@ int quick_rm_table(enum db_type base,const char *db, PRIMARY keys are prioritized. */ - static int sort_keys(KEY *a, KEY *b) { if (a->flags & HA_NOSAME) @@ -304,7 +303,8 @@ static int sort_keys(KEY *a, KEY *b) int mysql_create_table(THD *thd,const char *db, const char *table_name, HA_CREATE_INFO *create_info, List<create_field> &fields, - List<Key> &keys,bool tmp_table,bool no_log) + List<Key> &keys,bool tmp_table,bool no_log, + uint select_field_count) { char path[FN_REFLEN]; const char *key_name; @@ -312,14 +312,15 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, int error= -1; uint db_options,field,null_fields,blob_columns; ulong pos; - KEY *key_info,*key_info_buffer; + KEY *key_info,*key_info_buffer; KEY_PART_INFO *key_part_info; int auto_increment=0; handler *file; + int field_no,dup_no; DBUG_ENTER("mysql_create_table"); /* - ** Check for duplicate fields and check type of table to create + Check for duplicate fields and check type of table to create */ if (!fields.elements) @@ -328,6 +329,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, DBUG_RETURN(-1); } List_iterator<create_field> it(fields),it2(fields); + int select_field_pos=fields.elements - select_field_count; null_fields=blob_columns=0; db_options=create_info->table_options; if (create_info->row_type == ROW_TYPE_DYNAMIC) @@ -341,10 +343,9 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, DBUG_RETURN(-1); } - /* Don't pack keys in old tables if the user has requested this */ - - while ((sql_field=it++)) + for (field_no=0; (sql_field=it++) ; field_no++) { + /* Don't pack keys in old tables if the user has requested this */ if ((sql_field->flags & BLOB_FLAG) || sql_field->sql_type == FIELD_TYPE_VAR_STRING && create_info->row_type != ROW_TYPE_FIXED) @@ -353,12 +354,36 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, } if (!(sql_field->flags & NOT_NULL_FLAG)) null_fields++; - while ((dup_field=it2++) != sql_field) + + /* Check if we have used the same field name before */ + for (dup_no=0; (dup_field=it2++) != sql_field; dup_no++) { - 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); + /* + If this was a CREATE ... SELECT statement, accept a field + redefinition if we are changing a field in the SELECT part + */ + if (field_no < select_field_pos || dup_no >= select_field_pos) + { + my_error(ER_DUP_FIELDNAME,MYF(0),sql_field->field_name); + DBUG_RETURN(-1); + } + else + { + /* Field redefined */ + sql_field->length= dup_field->length; + sql_field->decimals= dup_field->decimals; + sql_field->flags= dup_field->flags; + sql_field->pack_length= dup_field->pack_length; + sql_field->unireg_check= dup_field->unireg_check; + sql_field->sql_type= dup_field->sql_type; + it2.remove(); // Remove first (create) definition + select_field_pos--; + break; + } } } it2.rewind(); @@ -371,6 +396,12 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, it.rewind(); while ((sql_field=it++)) { + if(!sql_field->charset) + sql_field->charset = create_info->table_charset ? + create_info->table_charset : + thd->db_charset? thd->db_charset : + default_charset_info; + switch (sql_field->sql_type) { case FIELD_TYPE_BLOB: case FIELD_TYPE_MEDIUM_BLOB: @@ -379,7 +410,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, sql_field->pack_flag=FIELDFLAG_BLOB | pack_length_to_packflag(sql_field->pack_length - portable_sizeof_char_ptr); - if (sql_field->flags & BINARY_FLAG) + if (sql_field->charset->state & MY_CS_BINSORT) sql_field->pack_flag|=FIELDFLAG_BINARY; sql_field->length=8; // Unireg field length sql_field->unireg_check=Field::BLOB_FIELD; @@ -388,17 +419,21 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, case FIELD_TYPE_VAR_STRING: case FIELD_TYPE_STRING: sql_field->pack_flag=0; - if (sql_field->flags & BINARY_FLAG) + if (sql_field->charset->state & MY_CS_BINSORT) sql_field->pack_flag|=FIELDFLAG_BINARY; break; case FIELD_TYPE_ENUM: sql_field->pack_flag=pack_length_to_packflag(sql_field->pack_length) | FIELDFLAG_INTERVAL; + if (sql_field->charset->state & MY_CS_BINSORT) + sql_field->pack_flag|=FIELDFLAG_BINARY; sql_field->unireg_check=Field::INTERVAL_FIELD; break; case FIELD_TYPE_SET: sql_field->pack_flag=pack_length_to_packflag(sql_field->pack_length) | FIELDFLAG_BITFIELD; + if (sql_field->charset->state & MY_CS_BINSORT) + sql_field->pack_flag|=FIELDFLAG_BINARY; sql_field->unireg_check=Field::BIT_FIELD; break; case FIELD_TYPE_DATE: // Rest of string types @@ -449,35 +484,50 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, /* Create keys */ List_iterator<Key> key_iterator(keys); - uint key_parts=0,key_count=keys.elements; + uint key_parts=0, key_count=0, fk_key_count=0; List<Key> keys_in_order; // Add new keys here bool primary_key=0,unique_key=0; Key *key; uint tmp, key_number; - tmp=min(file->max_keys(), MAX_KEY); - if (key_count > tmp) - { - my_error(ER_TOO_MANY_KEYS,MYF(0),tmp); - DBUG_RETURN(-1); - } /* Calculate number of key segements */ while ((key=key_iterator++)) { + if (key->type == Key::FOREIGN_KEY) + { + fk_key_count++; + foreign_key *fk_key= (foreign_key*) key; + if (fk_key->ref_columns.elements && + fk_key->ref_columns.elements != fk_key->columns.elements) + { + my_error(ER_WRONG_FK_DEF, MYF(0), fk_key->name ? fk_key->name : + "foreign key without name", + ER(ER_KEY_REF_DO_NOT_MATCH_TABLE_REF)); + DBUG_RETURN(-1); + } + continue; + } + key_count++; tmp=max(file->max_key_parts(),MAX_REF_PARTS); if (key->columns.elements > tmp) { my_error(ER_TOO_MANY_KEY_PARTS,MYF(0),tmp); DBUG_RETURN(-1); } - if (key->name() && strlen(key->name()) > NAME_LEN) + if (key->name && strlen(key->name) > NAME_LEN) { - my_error(ER_TOO_LONG_IDENT, MYF(0), key->name()); + my_error(ER_TOO_LONG_IDENT, MYF(0), key->name); DBUG_RETURN(-1); } key_parts+=key->columns.elements; } + tmp=min(file->max_keys(), MAX_KEY); + if (key_count > tmp) + { + my_error(ER_TOO_MANY_KEYS,MYF(0),tmp); + DBUG_RETURN(-1); + } key_info_buffer=key_info=(KEY*) sql_calloc(sizeof(KEY)*key_count); key_part_info=(KEY_PART_INFO*) sql_calloc(sizeof(KEY_PART_INFO)*key_parts); @@ -486,13 +536,28 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, key_iterator.rewind(); key_number=0; - for (; (key=key_iterator++) ; key_info++, key_number++) + for (; (key=key_iterator++) ; key_number++) { 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; + case Key::FOREIGN_KEY: + key_number--; // Skip this key + continue; + default: + key_info->flags = HA_NOSAME; + } + key_info->key_parts=(uint8) key->columns.elements; key_info->key_part=key_part_info; key_info->usable_key_parts= key_number; @@ -507,14 +572,42 @@ 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->algorithm == 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) { @@ -535,6 +628,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, @@ -626,7 +727,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, key_name=primary_key_name; primary_key=1; } - else if (!(key_name = key->name())) + else if (!(key_name = key->name)) key_name=make_unique_key_name(sql_field->field_name, key_info_buffer,key_info); if (check_if_keyname_exists(key_name,key_info_buffer,key_info)) @@ -646,6 +747,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, my_error(ER_TOO_LONG_KEY,MYF(0),max_key_length); DBUG_RETURN(-1); } + key_info++; } if (!unique_key && !primary_key && (file->table_flags() & HA_REQUIRE_PRIMARY_KEY)) @@ -696,7 +798,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name, thd->proc_info="creating table"; create_info->table_options=db_options; - if (rea_create_table(path, create_info, fields, key_count, + if (rea_create_table(thd, path, create_info, fields, key_count, key_info_buffer)) { /* my_error(ER_CANT_CREATE_TABLE,MYF(0),table_name,my_errno); */ @@ -738,7 +840,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; } @@ -774,6 +876,7 @@ TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, TABLE tmp_table; // Used during 'create_field()' TABLE *table; tmp_table.table_name=0; + uint select_field_count= items->elements; DBUG_ENTER("create_table_from_items"); /* Add selected items to field list */ @@ -811,7 +914,7 @@ TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, /* create and lock table */ /* QQ: This should be done atomic ! */ if (mysql_create_table(thd,db,name,create_info,*extra_fields, - *keys,0,1)) // no logging + *keys,0,1,select_field_count)) // no logging DBUG_RETURN(0); if (!(table=open_table(thd,db,name,name,(bool*) 0))) { @@ -1225,7 +1328,7 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables, goto err; } - send_eof(&thd->net); + send_eof(thd); DBUG_RETURN(0); err: close_thread_tables(thd); // Shouldn't be needed @@ -1344,9 +1447,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 @@ -1430,7 +1533,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, Query_log_event qinfo(thd, thd->query, thd->query_length, 0); mysql_bin_log.write(&qinfo); } - send_ok(&thd->net); + send_ok(thd); } DBUG_RETURN(error); } @@ -1444,7 +1547,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, List<Key> key_list; // Add new keys here /* - ** First collect all fields from table which isn't in drop_list + First collect all fields from table which isn't in drop_list */ create_field *def; @@ -1457,7 +1560,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 && @@ -1478,7 +1581,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) @@ -1502,7 +1606,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) @@ -1536,7 +1640,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) @@ -1559,8 +1663,8 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, } /* - ** Collect all keys which isn't in drop list. Add only those - ** for which some fields exists. + Collect all keys which isn't in drop list. Add only those + for which some fields exists. */ List_iterator<Key> key_it(keys); @@ -1582,7 +1686,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) @@ -1604,11 +1708,13 @@ 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)) - break; + else if (!my_strcasecmp(system_charset_info, + key_part_name, cfield->field_name)) + break; } if (!cfield) continue; // Field is removed @@ -1625,18 +1731,24 @@ 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_name,key_parts)); + (key_info->flags & HA_FULLTEXT ? + Key::FULLTEXT : Key::MULTIPLE)), + key_name, + key_info->algorithm, + key_parts)); } - key_it.rewind(); { Key *key; while ((key=key_it++)) // Add new keys - key_list.push_back(key); + { + if (key->type != Key::FOREIGN_KEY) + key_list.push_back(key); + } } if (drop_list.elements) @@ -1664,6 +1776,8 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, create_info->max_rows=table->max_rows; if (!(used_fields & HA_CREATE_USED_AVG_ROW_LENGTH)) create_info->avg_row_length=table->avg_row_length; + if (!(used_fields & HA_CREATE_USED_CHARSET)) + create_info->table_charset=table->table_charset; table->file->update_create_info(create_info); if ((create_info->table_options & @@ -1731,7 +1845,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, if ((error=mysql_create_table(thd, new_db, tmp_name, create_info, - create_list,key_list,1,1))) // no logging + create_list,key_list,1,1,0))) // no logging DBUG_RETURN(error); if (table->tmp_table) @@ -1808,9 +1922,9 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, goto err; } /* - ** Data is copied. Now we rename the old table to a temp name, - ** rename the new one to the old name, remove all entries from the old table - ** from the cash, free all locks, close the old table and remove it. + Data is copied. Now we rename the old table to a temp name, + rename the new one to the old name, remove all entries from the old table + from the cash, free all locks, close the old table and remove it. */ thd->proc_info="rename result table"; @@ -1955,7 +2069,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, end_temporary: sprintf(tmp_name,ER(ER_INSERT_INFO),(ulong) (copied+deleted), (ulong) deleted, thd->cuted_fields); - send_ok(&thd->net,copied+deleted,0L,tmp_name); + send_ok(thd,copied+deleted,0L,tmp_name); thd->some_tables_deleted=0; DBUG_RETURN(0); @@ -2018,8 +2132,8 @@ copy_data_between_tables(TABLE *from,TABLE *to, if (setup_order(thd, &tables, fields, all_fields, order) || !(sortorder=make_unireg_sortorder(order, &length)) || - (from->found_records = filesort(from, sortorder, length, - (SQL_SELECT *) 0, 0L, HA_POS_ERROR, + (from->found_records = filesort(thd, from, sortorder, length, + (SQL_SELECT *) 0, HA_POS_ERROR, &examined_rows)) == HA_POS_ERROR) goto err; diff --git a/sql/sql_test.cc b/sql/sql_test.cc index b226bc1300a..3fbeaa753db 100644 --- a/sql/sql_test.cc +++ b/sql/sql_test.cc @@ -26,6 +26,24 @@ /* Intern key cache variables */ extern "C" pthread_mutex_t THR_LOCK_keycache; +static const char *lock_descriptions[] = +{ + "No lock", + "Low priority read lock", + "Shared Read lock", + "High priority read lock", + "Read lock without concurrent inserts", + "Write lock that allows other writers", + "Write lock, but allow reading", + "Concurrent insert lock", + "Lock Used by delayed insert", + "Low priority write lock", + "High priority write lock", + "Highest priority write lock" +}; +extern HASH open_cache; + + #ifndef DBUG_OFF void @@ -34,7 +52,7 @@ print_where(COND *cond,const char *info) if (cond) { char buff[256]; - String str(buff,(uint32) sizeof(buff)); + String str(buff,(uint32) sizeof(buff), default_charset_info); str.length(0); cond->print(&str); str.append('\0'); @@ -45,10 +63,8 @@ print_where(COND *cond,const char *info) DBUG_UNLOCK_FILE; } } - /* This is for debugging purposes */ -extern HASH open_cache; extern TABLE *unused_tables; void print_cached_tables(void) @@ -57,16 +73,16 @@ void print_cached_tables(void) TABLE *start_link,*lnk; VOID(pthread_mutex_lock(&LOCK_open)); - puts("DB Table Version Thread L.thread Open"); + puts("DB Table Version Thread L.thread Open Lock"); for (idx=unused=0 ; idx < open_cache.records ; idx++) { TABLE *entry=(TABLE*) hash_element(&open_cache,idx); - printf("%-14.14s %-32s%6ld%8ld%10ld%6d\n", + printf("%-14.14s %-32s%6ld%8ld%10ld%6d %s\n", entry->table_cache_key,entry->real_name,entry->version, entry->in_use ? entry->in_use->thread_id : 0L, entry->in_use ? entry->in_use->dbug_thread_id : 0L, - entry->db_stat ? 1 : 0); + entry->db_stat ? 1 : 0, entry->in_use ? lock_descriptions[(int)entry->reginfo.lock_type] : "Not in use"); if (!entry->in_use) unused++; } @@ -97,10 +113,11 @@ void print_cached_tables(void) } -void TEST_filesort(SORT_FIELD *sortorder,uint s_length, ha_rows special) +void TEST_filesort(SORT_FIELD *sortorder,uint s_length) { char buff[256],buff2[256]; - String str(buff,sizeof(buff)),out(buff2,sizeof(buff2)); + String str(buff,sizeof(buff),default_charset_info); + String out(buff2,sizeof(buff2),default_charset_info); const char *sep; DBUG_ENTER("TEST_filesort"); @@ -130,8 +147,6 @@ void TEST_filesort(SORT_FIELD *sortorder,uint s_length, ha_rows special) out.append('\0'); // Purify doesn't like c_ptr() DBUG_LOCK_FILE; VOID(fputs("\nInfo about FILESORT\n",DBUG_FILE)); - if (special) - fprintf(DBUG_FILE,"Records to sort: %ld\n",special); fprintf(DBUG_FILE,"Sortorder: %s\n",out.ptr()); DBUG_UNLOCK_FILE; DBUG_VOID_RETURN; @@ -187,6 +202,99 @@ TEST_join(JOIN *join) #endif +typedef struct st_debug_lock +{ + ulong thread_id; + char table_name[FN_REFLEN]; + bool waiting; + const char *lock_text; + enum thr_lock_type type; +} TABLE_LOCK_INFO; + +static int dl_compare(TABLE_LOCK_INFO *a,TABLE_LOCK_INFO *b) +{ + if (a->thread_id > b->thread_id) + return 1; + if (a->thread_id < b->thread_id) + return -1; + if (a->waiting == b->waiting) + return 0; + else if (a->waiting) + return -1; + return 1; +} + +static void push_locks_into_array(DYNAMIC_ARRAY *ar, THR_LOCK_DATA *data, bool wait, const char *text) +{ + if (data) + { + TABLE *table=(TABLE *)data->debug_print_param; + if (table && table->tmp_table == NO_TMP_TABLE) + { + TABLE_LOCK_INFO table_lock_info; + table_lock_info.thread_id=table->in_use->thread_id; + memcpy(table_lock_info.table_name, table->table_cache_key, table->key_length); + table_lock_info.table_name[strlen(table_lock_info.table_name)]='.'; + table_lock_info.waiting=wait; + table_lock_info.lock_text=text; + table_lock_info.type=table->reginfo.lock_type; // obtainable also from THR_LOCK_DATA + VOID(push_dynamic(ar,(gptr) &table_lock_info)); + } + } +} +/* + Regarding MERGE tables: + +For now, the best option is to use the common TABLE *pointer for all +cases; The drawback is that for MERGE tables we will see many locks +for the merge tables even if some of them are for individual tables. + +The way to solve this is to add to 'THR_LOCK' structure a pointer to +the filename and use this when printing the data. +(We can for now ignore this and just print the same name for all merge +table parts; Please add the above as a comment to the display_lock +function so that we can easily add this if we ever need this. + +*/ + +static void display_table_locks (void) +{ + LIST *list; + DYNAMIC_ARRAY saved_table_locks; + + VOID(my_init_dynamic_array(&saved_table_locks,sizeof(TABLE_LOCK_INFO),open_cache.records + 20,50)); + VOID(pthread_mutex_lock(&THR_LOCK_lock)); + for (list=thr_lock_thread_list ; list ; list=rest(list)) + { + THR_LOCK *lock=(THR_LOCK*) list->data; + + VOID(pthread_mutex_lock(&lock->mutex)); + push_locks_into_array(&saved_table_locks, lock->write.data, false, "Locked - write"); + push_locks_into_array(&saved_table_locks, lock->write_wait.data, true, "Waiting - write"); + push_locks_into_array(&saved_table_locks, lock->read.data, false, "Locked - read"); + push_locks_into_array(&saved_table_locks, lock->read_wait.data, true, "Waiting - read"); + VOID(pthread_mutex_unlock(&lock->mutex)); + } + VOID(pthread_mutex_unlock(&THR_LOCK_lock)); + if (!saved_table_locks.elements) goto end; + + qsort((gptr) dynamic_element(&saved_table_locks,0,TABLE_LOCK_INFO *),saved_table_locks.elements,sizeof(TABLE_LOCK_INFO),(qsort_cmp) dl_compare); + freeze_size(&saved_table_locks); + + puts("\nThread database.table_name Locked/Waiting Lock_type\n"); + + for (uint i=0 ; i < saved_table_locks.elements ; i++) + { + TABLE_LOCK_INFO *dl_ptr=dynamic_element(&saved_table_locks,i,TABLE_LOCK_INFO*); + printf("%-8ld%-28.28s%-22s%s\n", + dl_ptr->thread_id,dl_ptr->table_name,dl_ptr->lock_text,lock_descriptions[(int)dl_ptr->type]); + } + puts("\n\n"); +end: + delete_dynamic(&saved_table_locks); +} + + void mysql_print_status(THD *thd) { char current_dir[FN_REFLEN]; @@ -252,6 +360,7 @@ Next alarm time: %lu\n", alarm_info.max_used_alarms, alarm_info.next_alarm_time); #endif + display_table_locks(); fflush(stdout); if (thd) thd->proc_info="malloc"; diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc index 420ec67f0c5..35e33caf572 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); @@ -352,7 +353,7 @@ int mysql_create_function(THD *thd,udf_func *udf) if (!initialized) { - send_error(&thd->net, ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES)); + send_error(thd, ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES)); DBUG_RETURN(1); } @@ -363,19 +364,19 @@ int mysql_create_function(THD *thd,udf_func *udf) */ if (strchr(udf->dl, '/')) { - send_error(&thd->net, ER_UDF_NO_PATHS,ER(ER_UDF_NO_PATHS)); + send_error(thd, ER_UDF_NO_PATHS,ER(ER_UDF_NO_PATHS)); DBUG_RETURN(1); } if (udf->name_length > NAME_LEN) { - net_printf(&thd->net, ER_TOO_LONG_IDENT,udf->name); + net_printf(thd, ER_TOO_LONG_IDENT,udf->name); DBUG_RETURN(1); } pthread_mutex_lock(&THR_LOCK_udf); if ((hash_search(&udf_hash,(byte*) udf->name, udf->name_length))) { - net_printf(&thd->net, ER_UDF_EXISTS, udf->name); + net_printf(thd, ER_UDF_EXISTS, udf->name); goto err; } if (!(dl = find_udf_dl(udf->dl))) @@ -384,7 +385,7 @@ int mysql_create_function(THD *thd,udf_func *udf) { DBUG_PRINT("error",("dlopen of %s failed, error: %d (%s)", udf->dl,errno,dlerror())); - net_printf(&thd->net, ER_CANT_OPEN_LIBRARY, udf->dl, errno, dlerror()); + net_printf(thd, ER_CANT_OPEN_LIBRARY, udf->dl, errno, dlerror()); goto err; } new_dl=1; @@ -394,14 +395,14 @@ int mysql_create_function(THD *thd,udf_func *udf) if (udf->func == NULL) { - net_printf(&thd->net, ER_CANT_FIND_DL_ENTRY, udf->name); + net_printf(thd, ER_CANT_FIND_DL_ENTRY, udf->name); goto err; } udf->name=strdup_root(&mem,udf->name); udf->dl=strdup_root(&mem,udf->dl); if (!(u_d=add_udf(udf->name,udf->returns,udf->dl,udf->type))) { - send_error(&thd->net,0); // End of memory + send_error(thd,0); // End of memory goto err; } u_d->dlhandle = dl; @@ -421,9 +422,9 @@ int mysql_create_function(THD *thd,udf_func *udf) goto err; restore_record(table,2); // Get default values for fields - table->field[0]->store(u_d->name, u_d->name_length); + table->field[0]->store(u_d->name, u_d->name_length, default_charset_info); table->field[1]->store((longlong) u_d->returns); - table->field[2]->store(u_d->dl,(uint) strlen(u_d->dl)); + table->field[2]->store(u_d->dl,(uint) strlen(u_d->dl), default_charset_info); if (table->fields >= 4) // If not old func format table->field[3]->store((longlong) u_d->type); error = table->file->write_row(table->record[0]); @@ -431,7 +432,7 @@ int mysql_create_function(THD *thd,udf_func *udf) close_thread_tables(thd); if (error) { - net_printf(&thd->net, ER_ERROR_ON_WRITE, "func@mysql",error); + net_printf(thd, ER_ERROR_ON_WRITE, "func@mysql",error); del_udf(u_d); goto err; } @@ -454,14 +455,14 @@ int mysql_drop_function(THD *thd,const char *udf_name) DBUG_ENTER("mysql_drop_function"); if (!initialized) { - send_error(&thd->net, ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES)); + send_error(thd, ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES)); DBUG_RETURN(1); } pthread_mutex_lock(&THR_LOCK_udf); if (!(udf=(udf_func*) hash_search(&udf_hash,(byte*) udf_name, (uint) strlen(udf_name)))) { - net_printf(&thd->net, ER_FUNCTION_NOT_DEFINED, udf_name); + net_printf(thd, ER_FUNCTION_NOT_DEFINED, udf_name); goto err; } del_udf(udf); diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 9d20a4bd7c9..0e6de306c0d 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -24,108 +24,137 @@ #include "mysql_priv.h" #include "sql_select.h" - -int mysql_union(THD *thd, LEX *lex,select_result *result) +int mysql_union(THD *thd, LEX *lex, select_result *result) { - SELECT_LEX *sl, *last_sl, *lex_sl; - ORDER *order; - List<Item> item_list; - TABLE *table; - int describe=(lex->select_lex.options & SELECT_DESCRIBE) ? 1 : 0; - int res; - bool found_rows_for_union=false; - TABLE_LIST result_table_list; - TABLE_LIST *first_table=(TABLE_LIST *)lex->select_lex.table_list.first; - TMP_TABLE_PARAM tmp_table_param; - select_union *union_result; DBUG_ENTER("mysql_union"); + SELECT_LEX_UNIT *unit= &lex->unit; + int res= 0; + if (!(res= unit->prepare(thd, result))) + res= unit->exec(); + res|= unit->cleanup(); + DBUG_RETURN(res); +} + + +/*************************************************************************** +** store records in temporary table for UNION +***************************************************************************/ + +select_union::select_union(TABLE *table_par) + :table(table_par) +{ + bzero((char*) &info,sizeof(info)); + /* + We can always use DUP_IGNORE because the temporary table will only + contain a unique key if we are using not using UNION ALL + */ + info.handle_duplicates= DUP_IGNORE; +} - /* Fix tables 'to-be-unioned-from' list to point at opened tables */ - last_sl= &lex->select_lex; - for (sl= last_sl; - sl && sl->linkage != NOT_A_SELECT; - last_sl=sl, sl=sl->next) +select_union::~select_union() +{ +} + + +int select_union::prepare(List<Item> &list, SELECT_LEX_UNIT *u) +{ + unit= u; + if (save_time_stamp && list.elements != table->fields) { - for (TABLE_LIST *cursor= (TABLE_LIST *)sl->table_list.first; - cursor; - cursor=cursor->next) - { - if (cursor->do_redirect) // False if CUBE/ROLLUP - { - cursor->table= ((TABLE_LIST*) cursor->table)->table; - cursor->do_redirect=false; - } - } + my_message(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT, + ER(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT),MYF(0)); + return -1; } + return 0; +} - /* last_sel now points at the last select where the ORDER BY is stored */ - if (sl) - { - /* - The found SL is an extra SELECT_LEX argument that contains - the ORDER BY and LIMIT parameter for the whole UNION - */ - lex_sl= sl; - order= (ORDER *) lex_sl->order_list.first; - found_rows_for_union = (lex->select_lex.options & OPTION_FOUND_ROWS && - !describe && sl->select_limit); - if (found_rows_for_union) - lex->select_lex.options ^= OPTION_FOUND_ROWS; - // This is done to eliminate unnecessary slowing down of the first query - if (!order || !describe) - last_sl->next=0; // Remove this extra element +bool select_union::send_data(List<Item> &values) +{ + if (unit->offset_limit_cnt) + { // using limit offset,count + unit->offset_limit_cnt--; + return 0; } - else if (!last_sl->braces) + fill_record(table->field,values); + if ((write_record(table,&info))) { - lex_sl= last_sl; // ORDER BY is here - order= (ORDER *) lex_sl->order_list.first; + if (thd->net.last_errno == ER_RECORD_FILE_FULL) + { + thd->clear_error(); // do not report user about table overflow + if (create_myisam_from_heap(table, tmp_table_param, info.last_errno, 0)) + return 1; + } + else + return 1; } - else + return 0; +} + +bool select_union::send_eof() +{ + return 0; +} + +bool select_union::flush() +{ + int error; + if ((error=table->file->extra(HA_EXTRA_NO_CACHE))) { - lex_sl=0; - order=0; + table->file->print_error(error,MYF(0)); + ::send_error(thd); + return 1; } - - if (describe) + return 0; +} + +typedef JOIN * JOIN_P; +int st_select_lex_unit::prepare(THD *thd, select_result *result) +{ + DBUG_ENTER("st_select_lex_unit::prepare"); + + if (prepared) + DBUG_RETURN(0); + prepared= 1; + union_result=0; + res= 0; + found_rows_for_union= false; + TMP_TABLE_PARAM tmp_table_param; + this->thd= thd; + this->result= result; + SELECT_LEX_NODE *lex_select_save= thd->lex.current_select; + SELECT_LEX *sl; + + /* Global option */ + if (((void*)(global_parameters)) == ((void*)this)) { - Item *item; - item_list.push_back(new Item_empty_string("table",NAME_LEN)); - item_list.push_back(new Item_empty_string("type",10)); - item_list.push_back(item=new Item_empty_string("possible_keys", - NAME_LEN*MAX_KEY)); - item->maybe_null=1; - item_list.push_back(item=new Item_empty_string("key",NAME_LEN)); - item->maybe_null=1; - item_list.push_back(item=new Item_int("key_len",0,3)); - item->maybe_null=1; - item_list.push_back(item=new Item_empty_string("ref", - NAME_LEN*MAX_REF_PARTS)); - item->maybe_null=1; - item_list.push_back(new Item_real("rows",0.0,0,10)); - item_list.push_back(new Item_empty_string("Extra",255)); + found_rows_for_union= first_select()->options & OPTION_FOUND_ROWS && + global_parameters->select_limit; + if (found_rows_for_union) + first_select()->options ^= OPTION_FOUND_ROWS; } - else + item_list.empty(); { Item *item; - List_iterator<Item> it(lex->select_lex.item_list); - TABLE_LIST *first_table= (TABLE_LIST*) lex->select_lex.table_list.first; + List_iterator<Item> it(first_select()->item_list); + TABLE_LIST *first_table= (TABLE_LIST*) first_select()->table_list.first; /* Create a list of items that will be in the result set */ while ((item= it++)) if (item_list.push_back(item)) - DBUG_RETURN(-1); + goto err; if (setup_fields(thd,first_table,item_list,0,0,1)) - DBUG_RETURN(-1); + goto err; } 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, item_list, - (ORDER*) 0, !describe & !lex->union_option, - 1, 0, - (lex->select_lex.options | thd->options | - TMP_TABLE_ALL_COLUMNS)))) - DBUG_RETURN(-1); + if (!(table= create_tmp_table(thd, &tmp_table_param, item_list, + (ORDER*) 0, !union_option, + 1, 0, + (first_select()->options | thd->options | + TMP_TABLE_ALL_COLUMNS), + this))) + goto err; table->file->extra(HA_EXTRA_WRITE_CACHE); table->file->extra(HA_EXTRA_IGNORE_DUP_KEY); bzero((char*) &result_table_list,sizeof(result_table_list)); @@ -134,43 +163,97 @@ int mysql_union(THD *thd, LEX *lex,select_result *result) result_table_list.table=table; if (!(union_result=new select_union(table))) - { - res= -1; - goto exit; - } - union_result->save_time_stamp=!describe; + goto err; + + union_result->save_time_stamp=1; union_result->tmp_table_param=&tmp_table_param; - for (sl= &lex->select_lex; sl; sl=sl->next) + + // prepare selects + joins.empty(); + for (sl= first_select(); sl; sl= sl->next_select()) { - lex->select=sl; - 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; // no limit - if (thd->select_limit == HA_POS_ERROR) + JOIN *join= new JOIN(thd, sl->item_list, + sl->options | thd->options | SELECT_NO_UNLOCK, + union_result); + joins.push_back(new JOIN_P(join)); + thd->lex.current_select= sl; + offset_limit_cnt= sl->offset_limit; + select_limit_cnt= sl->select_limit+sl->offset_limit; + if (select_limit_cnt < sl->select_limit) + select_limit_cnt= HA_POS_ERROR; // no limit + if (select_limit_cnt == HA_POS_ERROR) sl->options&= ~OPTION_FOUND_ROWS; - res=mysql_select(thd, (describe && sl->linkage==NOT_A_SELECT) ? first_table : (TABLE_LIST*) sl->table_list.first, - sl->item_list, - sl->where, - (sl->braces) ? (ORDER *)sl->order_list.first : (ORDER *) 0, - (ORDER*) sl->group_list.first, - sl->having, - (ORDER*) NULL, - sl->options | thd->options | SELECT_NO_UNLOCK | ((describe) ? SELECT_DESCRIBE : 0), - union_result); - if (res) - goto exit; + res= join->prepare((TABLE_LIST*) sl->table_list.first, + sl->where, + (sl->braces) ? + (ORDER *)sl->order_list.first : (ORDER *) 0, + (ORDER*) sl->group_list.first, + sl->having, + (ORDER*) NULL, + sl, this, 0); + if (res | thd->fatal_error) + goto err; } + thd->lex.current_select= lex_select_save; + DBUG_RETURN(res | thd->fatal_error); +err: + thd->lex.current_select= lex_select_save; + DBUG_RETURN(-1); +} + +int st_select_lex_unit::exec() +{ + DBUG_ENTER("st_select_lex_unit::exec"); + SELECT_LEX_NODE *lex_select_save= thd->lex.current_select; + + if (executed && !dependent) + DBUG_RETURN(0); + executed= 1; + + if (dependent || !item || !item->assigned()) + { + if (optimized && item && item->assigned()) + item->assigned(0); // We will reinit & rexecute unit + for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select()) + { + thd->lex.current_select= sl; + offset_limit_cnt= sl->offset_limit; + select_limit_cnt= sl->select_limit+sl->offset_limit; + if (select_limit_cnt < sl->select_limit) + select_limit_cnt= HA_POS_ERROR; // no limit + if (select_limit_cnt == HA_POS_ERROR) + sl->options&= ~OPTION_FOUND_ROWS; + + if (!optimized) + res= sl->join->optimize(); + else + res= sl->join->reinit(); + + if (!res) + { + sl->join->exec(); + res= sl->join->error; + } + if (res) + { + thd->lex.current_select= lex_select_save; + DBUG_RETURN(res); + } + } + optimized= 1; + } + if (union_result->flush()) { - res= 1; // Error is already sent - goto exit; + thd->lex.current_select= lex_select_save; + DBUG_RETURN(1); } - delete union_result; /* Send result to 'result' */ - lex->select = &lex->select_lex; + + // to correct ORDER BY reference resolving + thd->lex.current_select = first_select(); res =-1; { /* Create a list of fields in the temporary table */ @@ -180,7 +263,9 @@ int mysql_union(THD *thd, LEX *lex,select_result *result) List<Item_func_match> ftfunc_list; ftfunc_list.empty(); #else - thd->lex.select_lex.ftfunc_list.empty(); + List<Item_func_match> empty_list; + empty_list.empty(); + thd->lex.select_lex.ftfunc_list= &empty_list; #endif for (field=table->field ; *field ; field++) @@ -190,98 +275,44 @@ int mysql_union(THD *thd, LEX *lex,select_result *result) } if (!thd->fatal_error) // Check if EOM { - if (lex_sl) - { - thd->offset_limit=lex_sl->offset_limit; - thd->select_limit=lex_sl->select_limit+lex_sl->offset_limit; - if (thd->select_limit < lex_sl->select_limit) - thd->select_limit= HA_POS_ERROR; // no limit - if (thd->select_limit == HA_POS_ERROR) - thd->options&= ~OPTION_FOUND_ROWS; - } - else - { - thd->offset_limit= 0; - thd->select_limit= thd->variables.select_limit; - } - if (describe) - thd->select_limit= HA_POS_ERROR; // no limit - res=mysql_select(thd,&result_table_list, - item_list, NULL, (describe) ? 0 : order, - (ORDER*) NULL, NULL, (ORDER*) NULL, - thd->options, result); + offset_limit_cnt= global_parameters->offset_limit; + select_limit_cnt= global_parameters->select_limit+ + global_parameters->offset_limit; + if (select_limit_cnt < global_parameters->select_limit) + select_limit_cnt= HA_POS_ERROR; // no limit + if (select_limit_cnt == HA_POS_ERROR) + thd->options&= ~OPTION_FOUND_ROWS; + res= mysql_select(thd,&result_table_list, + item_list, NULL, + (ORDER*)global_parameters->order_list.first, + (ORDER*) NULL, NULL, (ORDER*) NULL, + thd->options, result, this, first_select(), 1); if (found_rows_for_union && !res) thd->limit_found_rows = (ulonglong)table->file->records; } } - -exit: - free_tmp_table(thd,table); + thd->lex.select_lex.ftfunc_list= &thd->lex.select_lex.ftfunc_list_alloc; + thd->lex.current_select= lex_select_save; DBUG_RETURN(res); } - -/*************************************************************************** -** store records in temporary table for UNION -***************************************************************************/ - -select_union::select_union(TABLE *table_par) - :table(table_par) -{ - bzero((char*) &info,sizeof(info)); - /* - We can always use DUP_IGNORE because the temporary table will only - contain a unique key if we are using not using UNION ALL - */ - info.handle_duplicates=DUP_IGNORE; -} - -select_union::~select_union() -{ -} - - -int select_union::prepare(List<Item> &list) +int st_select_lex_unit::cleanup() { - if (save_time_stamp && list.elements != table->fields) + DBUG_ENTER("st_select_lex_unit::cleanup"); + if (union_result) { - my_message(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT, - ER(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT),MYF(0)); - return -1; + delete union_result; + free_tmp_table(thd,table); + table= 0; // Safety } - return 0; -} - -bool select_union::send_data(List<Item> &values) -{ - if (thd->offset_limit) - { // using limit offset,count - thd->offset_limit--; - return 0; - } - - fill_record(table->field,values); - if ((write_record(table,&info))) + List_iterator<JOIN*> j(joins); + JOIN** join; + while ((join= j++)) { - if (create_myisam_from_heap(table, tmp_table_param, info.last_errno, 0)) - return 1; - } - return 0; -} - -bool select_union::send_eof() -{ - return 0; -} - -bool select_union::flush() -{ - int error; - if ((error=table->file->extra(HA_EXTRA_NO_CACHE))) - { - table->file->print_error(error,MYF(0)); - ::send_error(&thd->net); - return 1; + (*join)->cleanup(thd); + delete *join; + delete join; } - return 0; + joins.empty(); + DBUG_RETURN(0); } diff --git a/sql/sql_update.cc b/sql/sql_update.cc index b5263322301..73343ab1a50 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -77,7 +77,7 @@ int mysql_update(THD *thd, want_privilege=table->grant.want_privilege; table->grant.want_privilege=(SELECT_ACL & ~table->grant.privilege); if (setup_tables(table_list) || setup_conds(thd,table_list,&conds) - || setup_ftfuncs(thd)) + || setup_ftfuncs(&thd->lex.select_lex)) DBUG_RETURN(-1); /* purecov: inspected */ old_used_keys=table->used_keys; // Keys used in WHERE @@ -124,7 +124,7 @@ int mysql_update(THD *thd, { DBUG_RETURN(-1); // Error in where } - send_ok(&thd->net); // No matching records + send_ok(thd); // No matching records DBUG_RETURN(0); } /* If running in safe sql mode, don't allow updates without keys */ @@ -135,11 +135,11 @@ int mysql_update(THD *thd, { delete select; table->time_stamp=save_time_stamp; - send_error(&thd->net,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE); + send_error(thd,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE); DBUG_RETURN(1); } } - init_ftfuncs(thd,1); + init_ftfuncs(thd, &thd->lex.select_lex, 1); /* Check if we are modifying a key that we are used to search with */ if (select && select->quick) used_key_is_modified= (!select->quick->unique_key_range() && @@ -187,8 +187,8 @@ int mysql_update(THD *thd, MYF(MY_FAE | MY_ZEROFILL)); if (setup_order(thd, &tables, fields, all_fields, order) || !(sortorder=make_unireg_sortorder(order, &length)) || - (table->found_records = filesort(table, sortorder, length, - (SQL_SELECT *) 0, 0L, + (table->found_records = filesort(thd, table, sortorder, length, + (SQL_SELECT *) 0, HA_POS_ERROR, &examined_rows)) == HA_POS_ERROR) { @@ -337,13 +337,13 @@ int mysql_update(THD *thd, delete select; if (error >= 0) - send_error(&thd->net,thd->killed ? ER_SERVER_SHUTDOWN : 0); /* purecov: inspected */ + send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN : 0); /* purecov: inspected */ else { char buff[80]; sprintf(buff,ER(ER_UPDATE_INFO), (long) found, (long) updated, (long) thd->cuted_fields); - send_ok(&thd->net, + send_ok(thd, (thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated, thd->insert_id_used ? thd->insert_id() : 0L,buff); DBUG_PRINT("info",("%d records updated",updated)); @@ -390,9 +390,10 @@ multi_update::multi_update(THD *thd_arg, TABLE_LIST *ut, List<Item> &fs, } int -multi_update::prepare(List<Item> &values) +multi_update::prepare(List<Item> &values, SELECT_LEX_UNIT *u) { DBUG_ENTER("multi_update::prepare"); + unit= u; do_update = true; thd->count_cuted_fields=1; thd->cuted_fields=0L; @@ -448,7 +449,7 @@ multi_update::prepare(List<Item> &values) } if (!table_ref) { - net_printf(&thd->net, ER_NOT_SUPPORTED_YET, "JOIN SYNTAX WITH MULTI-TABLE UPDATES"); + net_printf(thd, ER_NOT_SUPPORTED_YET, "JOIN SYNTAX WITH MULTI-TABLE UPDATES"); DBUG_RETURN(1); } else @@ -456,7 +457,7 @@ multi_update::prepare(List<Item> &values) } if (!num_updated--) { - net_printf(&thd->net, ER_NOT_SUPPORTED_YET, "SET CLAUSE MUST CONTAIN TABLE.FIELD REFERENCE"); + net_printf(thd, ER_NOT_SUPPORTED_YET, "SET CLAUSE MUST CONTAIN TABLE.FIELD REFERENCE"); DBUG_RETURN(1); } @@ -490,9 +491,11 @@ multi_update::prepare(List<Item> &values) } if (counter) { - Field_string offset(table_ref->table->file->ref_length,false,"offset",table_ref->table,true); + Field_string offset(table_ref->table->file->ref_length, false, + "offset", table_ref->table, my_charset_bin); temp_fields->push_front(new Item_field(((Field *)&offset))); - // Here I make tmp tables + + // Make a temporary table int cnt=counter-1; TMP_TABLE_PARAM tmp_table_param; bzero((char*) &tmp_table_param,sizeof(tmp_table_param)); @@ -500,7 +503,8 @@ multi_update::prepare(List<Item> &values) if (!(tmp_tables[cnt]=create_tmp_table(thd, &tmp_table_param, *temp_fields, (ORDER*) 0, 1, 0, 0, - TMP_TABLE_ALL_COLUMNS))) + TMP_TABLE_ALL_COLUMNS, + unit))) { error = 1; // A proper error message is due here DBUG_RETURN(1); @@ -514,7 +518,7 @@ multi_update::prepare(List<Item> &values) counter++; } } - init_ftfuncs(thd,1); + init_ftfuncs(thd, thd->lex.current_select->select_lex(), 1); error = 0; // Timestamps do not need to be restored, so far ... DBUG_RETURN(0); } @@ -648,7 +652,8 @@ bool multi_update::send_data(List<Item> &values) { // Here we insert into each temporary table values_by_table.push_front(new Item_string((char*) table->file->ref, - table->file->ref_length)); + table->file->ref_length, + system_charset_info)); fill_record(tmp_tables[secure_counter]->field,values_by_table); error= write_record(tmp_tables[secure_counter], &(infos[secure_counter])); @@ -665,8 +670,10 @@ bool multi_update::send_data(List<Item> &values) void multi_update::send_error(uint errcode,const char *err) { + + //TODO error should be sent at the query processing end /* First send error what ever it is ... */ - ::send_error(&thd->net,errcode,err); + ::send_error(thd,errcode,err); /* reset used flags */ // update_tables->table->no_keyread=0; @@ -788,6 +795,7 @@ bool multi_update::send_eof() if (local_error == -1) local_error= 0; thd->proc_info= "end"; + // TODO: Error should be sent at the query processing end if (local_error) send_error(local_error, "An error occured in multi-table update"); @@ -826,7 +834,7 @@ bool multi_update::send_eof() { query_cache_invalidate3(thd, update_tables, 1); } - ::send_ok(&thd->net, + ::send_ok(thd, (thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated, thd->insert_id_used ? thd->insert_id() : 0L,buff); } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index f6a0c483bb9..a994a2539f7 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -21,11 +21,12 @@ #define YYINITDEPTH 100 #define YYMAXDEPTH 3200 /* Because of 64K stack */ #define Lex current_lex -#define Select Lex->select +#define Select Lex->current_select #include "mysql_priv.h" #include "slave.h" #include "sql_acl.h" #include "lex_symbol.h" +#include "item_create.h" #include <myisam.h> #include <myisammrg.h> @@ -60,12 +61,14 @@ inline Item *or_or_concat(Item* A, Item* B) LEX_USER *lex_user; sys_var *variable; 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; enum enum_tx_isolation tx_isolation; enum Item_cast cast_type; enum Item_udftype udf_type; + CHARSET_INFO *charset; thr_lock_type lock_type; interval_type interval; } @@ -84,6 +87,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token NEXT_SYM %token PREV_SYM +%token DIV_SYM %token EQ %token EQUAL_SYM %token GE @@ -92,6 +96,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token LT %token NE %token IS +%token MOD_SYM %token SHIFT_LEFT %token SHIFT_RIGHT %token SET_VAR @@ -113,6 +118,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token CROSS %token CUBE_SYM %token DELETE_SYM +%token DUAL_SYM %token DO_SYM %token DROP %token EVENTS_SYM @@ -163,13 +169,17 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token BOOL_SYM %token BOOLEAN_SYM %token BOTH +%token BTREE_SYM %token BY +%token BYTE_SYM %token CACHE_SYM %token CASCADE %token CAST_SYM +%token CHARSET %token CHECKSUM_SYM %token CHECK_SYM %token COMMITTED_SYM +%token COLLATE_SYM %token COLUMNS %token COLUMN_SYM %token CONCURRENT @@ -193,6 +203,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token ESCAPE_SYM %token EXISTS %token EXTENDED_SYM +%token FALSE_SYM %token FILE_SYM %token FIRST_SYM %token FIXED_SYM @@ -207,6 +218,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 @@ -302,11 +314,15 @@ 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 SERIAL_SYM %token SERIALIZABLE_SYM %token SESSION_SYM +%token SIMPLE_SYM %token SHUTDOWN -%token SSL_SYM +%token SPATIAL_SYM +%token SSL_SYM %token STARTING %token STATUS_SYM %token STRAIGHT_JOIN @@ -319,7 +335,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token TO_SYM %token TRAILING %token TRANSACTION_SYM +%token TRUE_SYM %token TYPE_SYM +%token TYPES_SYM %token FUNC_ARG0 %token FUNC_ARG1 %token FUNC_ARG2 @@ -328,21 +346,26 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token UDF_SONAME_SYM %token UDF_SYM %token UNCOMMITTED_SYM +%token UNDERSCORE_CHARSET %token UNION_SYM %token UNIQUE_SYM %token USAGE %token USE_FRM %token USE_SYM %token USING +%token VALUE_SYM %token VALUES %token VARIABLES %token WHERE %token WITH %token WRITE_SYM %token X509_SYM -%token XOR +%token XOR %token COMPRESSED_SYM +%token ERRORS +%token WARNINGS + %token BIGINT %token BLOB_SYM %token CHAR_SYM @@ -355,6 +378,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 @@ -412,6 +436,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 @@ -422,6 +449,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 @@ -429,8 +458,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 @@ -472,6 +510,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token SUBJECT_SYM %token CIPHER_SYM +%token HELP + %left SET_VAR %left OR_OR_CONCAT OR %left AND @@ -481,13 +521,12 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %left '&' %left SHIFT_LEFT SHIFT_RIGHT %left '-' '+' -%left '*' '/' '%' +%left '*' '/' '%' DIV_SYM MOD_SYM %left NEG '~' %left XOR %left '^' %right NOT -%right BINARY - +%right BINARY COLLATE_SYM /* These don't actually affect the way the query is really evaluated, but they silence a few warnings for shift/reduce conflicts. */ %left ',' @@ -496,16 +535,16 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %type <lex_str> IDENT TEXT_STRING REAL_NUM FLOAT_NUM NUM LONG_NUM HEX_NUM LEX_HOSTNAME - ULONGLONG_NUM field_ident select_alias ident ident_or_text + ULONGLONG_NUM field_ident select_alias ident ident_or_text UNDERSCORE_CHARSET %type <lex_str_ptr> opt_table_alias %type <table> - table_ident + table_ident references %type <simple_string> - remember_name remember_end opt_len opt_ident opt_db text_or_password + remember_name remember_end opt_ident opt_db text_or_password opt_escape %type <string> @@ -515,7 +554,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); type int_type real_type order_dir opt_field_spec lock_option udf_type if_exists opt_local opt_table_options table_options table_option opt_if_not_exists opt_var_type opt_var_ident_type - opt_temporary + delete_option opt_temporary %type <ulong_num> ULONG_NUM raid_types merge_insert_types @@ -531,6 +570,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); simple_ident select_item2 expr opt_expr opt_else sum_expr in_sum_expr table_wild opt_pad no_in_expr expr_expr simple_expr no_and_expr using_list expr_or_default set_expr_or_default + param_marker singleval_subselect singleval_subselect_init + exists_subselect exists_subselect_init %type <item_list> expr_list udf_expr_list when_list ident_list ident_list_arg @@ -538,6 +579,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 @@ -545,7 +589,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); key_part %type <table_list> - join_table_list join_table + join_table_list join_table %type <udf> UDF_CHAR_FUNC UDF_FLOAT_FUNC UDF_INT_FUNC @@ -569,6 +613,11 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %type <lex_user> user grant_user +%type <charset> + charset_name + charset_name_or_default + opt_db_default_character_set + %type <variable> internal_variable_name %type <NONE> @@ -585,7 +634,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); opt_precision opt_ignore opt_column opt_restrict grant revoke set lock unlock string_list field_options field_option field_opt_list opt_binary table_lock_list table_lock varchar - references opt_on_delete opt_on_delete_list opt_on_delete_item use + ref_list opt_on_delete opt_on_delete_list opt_on_delete_item use opt_delete_options opt_delete_option opt_outer table_list table_name opt_option opt_place opt_attribute opt_attribute_list attribute column_list column_list_id @@ -596,13 +645,16 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); opt_mi_check_type opt_to mi_check_types normal_join table_to_table_list table_to_table opt_table_list opt_as handler_rkey_function handler_read_or_scan - single_multi table_wild_list table_wild_one opt_wild opt_union union_list - precision union_option opt_and + single_multi table_wild_list table_wild_one opt_wild + union opt_union union_list union_option + precision opt_on_delete_item subselect_start opt_and + subselect_end select_var_list select_var_list_init help opt_len END_OF_INPUT %type <NONE> '-' '+' '*' '/' '%' '(' ')' - ',' '!' '{' '}' '&' '|' AND OR OR_OR_CONCAT BETWEEN_SYM CASE_SYM THEN_SYM WHEN_SYM + ',' '!' '{' '}' '&' '|' AND OR OR_OR_CONCAT BETWEEN_SYM CASE_SYM + THEN_SYM WHEN_SYM DIV_SYM MOD_SYM %% @@ -613,7 +665,7 @@ query: if (!thd->bootstrap && (!(thd->lex.select_lex.options & OPTION_FOUND_COMMENT))) { - send_error(¤t_thd->net,ER_EMPTY_QUERY); + send_error(current_thd,ER_EMPTY_QUERY); YYABORT; } else @@ -659,7 +711,18 @@ verb_clause: | handler | unlock | update - | use; + | use + | help; + +/* help */ + +help: + HELP TEXT_STRING + { + LEX *lex= Lex; + lex->sql_command= SQLCOM_HELP; + lex->help_arg= $2.str; + }; /* change master */ @@ -719,7 +782,8 @@ master_def: RELAY_LOG_POS_SYM EQ ULONG_NUM { Lex->mi.relay_log_pos = $3; - }; + } + ; /* create a table */ @@ -727,11 +791,14 @@ master_def: create: CREATE opt_table_options TABLE_SYM opt_if_not_exists table_ident { + THD *thd=current_thd; LEX *lex=Lex; lex->sql_command= SQLCOM_CREATE_TABLE; - if (!add_table_to_list($5, - ($2 & HA_LEX_CREATE_TMP_TABLE ? - &tmp_table_alias : (LEX_STRING*) 0),1)) + if (!lex->select_lex.add_table_to_list($5, + ($2 & + HA_LEX_CREATE_TMP_TABLE ? + &tmp_table_alias : + (LEX_STRING*) 0),1)) YYABORT; lex->create_list.empty(); lex->key_list.empty(); @@ -740,32 +807,35 @@ create: bzero((char*) &lex->create_info,sizeof(lex->create_info)); lex->create_info.options=$2 | $4; lex->create_info.db_type= (enum db_type) lex->thd->variables.table_type; + lex->create_info.table_charset=thd->db_charset?thd->db_charset:default_charset_info; } 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 (!lex->current_select->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,$4.str, $5, lex->col_list)); lex->col_list.empty(); } - | CREATE DATABASE opt_if_not_exists ident + | CREATE DATABASE opt_if_not_exists ident opt_db_default_character_set { LEX *lex=Lex; lex->sql_command=SQLCOM_CREATE_DB; lex->name=$4.str; lex->create_info.options=$3; + lex->create_info.table_charset=$5; } | CREATE udf_func_type UDF_SYM ident { @@ -780,11 +850,13 @@ create: LEX *lex=Lex; lex->udf.returns=(Item_result) $7; lex->udf.dl=$9.str; - }; + } + ; create2: '(' field_list ')' opt_create_table_options create3 {} - | opt_create_table_options create3 {}; + | opt_create_table_options create3 {} + ; create3: /* empty */ {} @@ -794,7 +866,8 @@ create3: lex->lock_option= (using_update_log) ? TL_READ_NO_INSERT : TL_READ; mysql_init_select(lex); } - select_options select_item_list opt_select_from opt_union {}; + select_options select_item_list opt_select_from union {} + ; opt_as: /* empty */ {} @@ -819,42 +892,61 @@ opt_create_table_options: /* empty */ | create_table_options; +create_table_options_space_separated: + create_table_option + | create_table_option create_table_options_space_separated; + create_table_options: create_table_option - | create_table_option create_table_options; + | create_table_option create_table_options; + | create_table_option ',' create_table_options; + +o_eq: + /* empty */ + | EQ {}; create_table_option: - TYPE_SYM EQ table_types { Lex->create_info.db_type= $3; } - | MAX_ROWS EQ ulonglong_num { Lex->create_info.max_rows= $3; Lex->create_info.used_fields|= HA_CREATE_USED_MAX_ROWS;} - | MIN_ROWS EQ ulonglong_num { Lex->create_info.min_rows= $3; Lex->create_info.used_fields|= HA_CREATE_USED_MIN_ROWS;} - | AVG_ROW_LENGTH EQ ULONG_NUM { Lex->create_info.avg_row_length=$3; Lex->create_info.used_fields|= HA_CREATE_USED_AVG_ROW_LENGTH;} - | PASSWORD EQ TEXT_STRING { Lex->create_info.password=$3.str; } - | COMMENT_SYM EQ TEXT_STRING { Lex->create_info.comment=$3.str; } - | AUTO_INC EQ ulonglong_num { Lex->create_info.auto_increment_value=$3; Lex->create_info.used_fields|= HA_CREATE_USED_AUTO;} - | PACK_KEYS_SYM EQ ULONG_NUM { Lex->create_info.table_options|= $3 ? HA_OPTION_PACK_KEYS : HA_OPTION_NO_PACK_KEYS; Lex->create_info.used_fields|= HA_CREATE_USED_PACK_KEYS;} - | PACK_KEYS_SYM EQ DEFAULT { Lex->create_info.table_options&= ~(HA_OPTION_PACK_KEYS | HA_OPTION_NO_PACK_KEYS); Lex->create_info.used_fields|= HA_CREATE_USED_PACK_KEYS;} - | CHECKSUM_SYM EQ ULONG_NUM { Lex->create_info.table_options|= $3 ? HA_OPTION_CHECKSUM : HA_OPTION_NO_CHECKSUM; } - | DELAY_KEY_WRITE_SYM EQ ULONG_NUM { Lex->create_info.table_options|= $3 ? HA_OPTION_DELAY_KEY_WRITE : HA_OPTION_NO_DELAY_KEY_WRITE; } - | ROW_FORMAT_SYM EQ row_types { Lex->create_info.row_type= $3; } - | RAID_TYPE EQ raid_types { Lex->create_info.raid_type= $3; Lex->create_info.used_fields|= HA_CREATE_USED_RAID;} - | RAID_CHUNKS EQ ULONG_NUM { Lex->create_info.raid_chunks= $3; Lex->create_info.used_fields|= HA_CREATE_USED_RAID;} - | RAID_CHUNKSIZE EQ ULONG_NUM { Lex->create_info.raid_chunksize= $3*RAID_BLOCK_SIZE; Lex->create_info.used_fields|= HA_CREATE_USED_RAID;} - | UNION_SYM EQ '(' table_list ')' + TYPE_SYM o_eq table_types { Lex->create_info.db_type= $3; } + | MAX_ROWS o_eq ulonglong_num { Lex->create_info.max_rows= $3; Lex->create_info.used_fields|= HA_CREATE_USED_MAX_ROWS;} + | MIN_ROWS o_eq ulonglong_num { Lex->create_info.min_rows= $3; Lex->create_info.used_fields|= HA_CREATE_USED_MIN_ROWS;} + | AVG_ROW_LENGTH o_eq ULONG_NUM { Lex->create_info.avg_row_length=$3; Lex->create_info.used_fields|= HA_CREATE_USED_AVG_ROW_LENGTH;} + | PASSWORD o_eq TEXT_STRING { Lex->create_info.password=$3.str; } + | COMMENT_SYM o_eq TEXT_STRING { Lex->create_info.comment=$3.str; } + | AUTO_INC o_eq ulonglong_num { Lex->create_info.auto_increment_value=$3; Lex->create_info.used_fields|= HA_CREATE_USED_AUTO;} + | PACK_KEYS_SYM o_eq ULONG_NUM { Lex->create_info.table_options|= $3 ? HA_OPTION_PACK_KEYS : HA_OPTION_NO_PACK_KEYS; Lex->create_info.used_fields|= HA_CREATE_USED_PACK_KEYS;} + | PACK_KEYS_SYM o_eq DEFAULT { Lex->create_info.table_options&= ~(HA_OPTION_PACK_KEYS | HA_OPTION_NO_PACK_KEYS); Lex->create_info.used_fields|= HA_CREATE_USED_PACK_KEYS;} + | CHECKSUM_SYM o_eq ULONG_NUM { Lex->create_info.table_options|= $3 ? HA_OPTION_CHECKSUM : HA_OPTION_NO_CHECKSUM; } + | DELAY_KEY_WRITE_SYM o_eq ULONG_NUM { Lex->create_info.table_options|= $3 ? HA_OPTION_DELAY_KEY_WRITE : HA_OPTION_NO_DELAY_KEY_WRITE; } + | ROW_FORMAT_SYM o_eq row_types { Lex->create_info.row_type= $3; } + | RAID_TYPE o_eq raid_types { Lex->create_info.raid_type= $3; Lex->create_info.used_fields|= HA_CREATE_USED_RAID;} + | RAID_CHUNKS o_eq ULONG_NUM { Lex->create_info.raid_chunks= $3; Lex->create_info.used_fields|= HA_CREATE_USED_RAID;} + | RAID_CHUNKSIZE o_eq ULONG_NUM { Lex->create_info.raid_chunksize= $3*RAID_BLOCK_SIZE; Lex->create_info.used_fields|= HA_CREATE_USED_RAID;} + | UNION_SYM o_eq '(' table_list ')' { /* Move the union list to the merge_list */ LEX *lex=Lex; - TABLE_LIST *table_list= (TABLE_LIST*) lex->select->table_list.first; - lex->create_info.merge_list= lex->select->table_list; + TABLE_LIST *table_list= lex->select_lex.get_table_list(); + lex->create_info.merge_list= lex->select_lex.table_list; lex->create_info.merge_list.elements--; lex->create_info.merge_list.first= (byte*) (table_list->next); - lex->select->table_list.elements=1; - lex->select->table_list.next= (byte**) &(table_list->next); + lex->select_lex.table_list.elements=1; + lex->select_lex.table_list.next= (byte**) &(table_list->next); table_list->next=0; lex->create_info.used_fields|= HA_CREATE_USED_UNION; } - | INSERT_METHOD EQ merge_insert_types { Lex->create_info.merge_insert_method= $3; Lex->create_info.used_fields|= HA_CREATE_USED_INSERT_METHOD;} - | DATA_SYM DIRECTORY_SYM EQ TEXT_STRING { Lex->create_info.data_file_name= $4.str; } - | INDEX DIRECTORY_SYM EQ TEXT_STRING { Lex->create_info.index_file_name= $4.str; }; + | opt_default CHARSET o_eq charset_name_or_default + { + Lex->create_info.table_charset= $4; + Lex->create_info.used_fields|= HA_CREATE_USED_CHARSET; + } + | opt_default CHAR_SYM SET o_eq charset_name_or_default + { + Lex->create_info.table_charset= $5; + Lex->create_info.used_fields|= HA_CREATE_USED_CHARSET; + } + | INSERT_METHOD o_eq merge_insert_types { Lex->create_info.merge_insert_method= $3; Lex->create_info.used_fields|= HA_CREATE_USED_INSERT_METHOD;} + | DATA_SYM DIRECTORY_SYM o_eq TEXT_STRING { Lex->create_info.data_file_name= $4.str; } + | INDEX DIRECTORY_SYM o_eq TEXT_STRING { Lex->create_info.index_file_name= $4.str; }; table_types: ISAM_SYM { $$= DB_TYPE_ISAM; } @@ -904,15 +996,22 @@ 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,$2, $3, lex->col_list)); lex->col_list.empty(); /* Alloced by sql_alloc */ } | opt_constraint FOREIGN KEY_SYM opt_ident '(' key_list ')' references { - Lex->col_list.empty(); /* Alloced by sql_alloc */ + LEX *lex=Lex; + lex->key_list.push_back(new foreign_key($4, lex->col_list, + $8, + lex->ref_list, + lex->fk_delete_opt, + lex->fk_update_opt, + lex->fk_match_option)); + lex->col_list.empty(); /* Alloced by sql_alloc */ } | opt_constraint CHECK_SYM '(' expr ')' { @@ -928,7 +1027,8 @@ field_spec: { LEX *lex=Lex; lex->length=lex->dec=0; lex->type=0; lex->interval=0; - lex->default_value=0; + lex->default_value=lex->comment=0; + lex->charset=NULL; } type opt_attribute { @@ -936,69 +1036,81 @@ field_spec: if (add_field_to_list($1.str, (enum enum_field_types) $3, lex->length,lex->dec,lex->type, - lex->default_value,lex->change, - lex->interval)) + lex->default_value, lex->comment, + lex->change,lex->interval,lex->charset)) YYABORT; }; type: - int_type opt_len field_options { Lex->length=$2; $$=$1; } + int_type opt_len field_options { $$=$1; } | real_type opt_precision field_options { $$=$1; } | FLOAT_SYM float_options field_options { $$=FIELD_TYPE_FLOAT; } | BIT_SYM opt_len { Lex->length=(char*) "1"; $$=FIELD_TYPE_TINY; } | BOOL_SYM { Lex->length=(char*) "1"; $$=FIELD_TYPE_TINY; } - | char '(' NUM ')' opt_binary { Lex->length=$3.str; + | char '(' NUM ')' opt_binary { Lex->length=$3.str; $$=FIELD_TYPE_STRING; } | char opt_binary { Lex->length=(char*) "1"; $$=FIELD_TYPE_STRING; } | BINARY '(' NUM ')' { Lex->length=$3.str; - Lex->type|=BINARY_FLAG; + Lex->charset=my_charset_bin; $$=FIELD_TYPE_STRING; } | varchar '(' NUM ')' opt_binary { Lex->length=$3.str; $$=FIELD_TYPE_VAR_STRING; } | VARBINARY '(' NUM ')' { Lex->length=$3.str; - Lex->type|=BINARY_FLAG; + Lex->charset=my_charset_bin; $$=FIELD_TYPE_VAR_STRING; } - | YEAR_SYM opt_len field_options { $$=FIELD_TYPE_YEAR; Lex->length=$2; } + | YEAR_SYM opt_len field_options { $$=FIELD_TYPE_YEAR; } | DATE_SYM { $$=FIELD_TYPE_DATE; } | TIME_SYM { $$=FIELD_TYPE_TIME; } - | TIMESTAMP { $$=FIELD_TYPE_TIMESTAMP; } + | TIMESTAMP + { + if (current_thd->sql_mode & MODE_SAPDB) + $$=FIELD_TYPE_DATETIME; + else + $$=FIELD_TYPE_TIMESTAMP; + } | TIMESTAMP '(' NUM ')' { Lex->length=$3.str; $$=FIELD_TYPE_TIMESTAMP; } | DATETIME { $$=FIELD_TYPE_DATETIME; } - | TINYBLOB { Lex->type|=BINARY_FLAG; + | TINYBLOB { Lex->charset=my_charset_bin; $$=FIELD_TYPE_TINY_BLOB; } - | BLOB_SYM { Lex->type|=BINARY_FLAG; + | BLOB_SYM opt_len { Lex->charset=my_charset_bin; $$=FIELD_TYPE_BLOB; } - | MEDIUMBLOB { Lex->type|=BINARY_FLAG; + | GEOMETRY_SYM { Lex->charset=my_charset_bin; + $$=FIELD_TYPE_GEOMETRY; } + | MEDIUMBLOB { Lex->charset=my_charset_bin; $$=FIELD_TYPE_MEDIUM_BLOB; } - | LONGBLOB { Lex->type|=BINARY_FLAG; + | LONGBLOB { Lex->charset=my_charset_bin; $$=FIELD_TYPE_LONG_BLOB; } - | LONG_SYM VARBINARY { Lex->type|=BINARY_FLAG; + | LONG_SYM VARBINARY { Lex->charset=my_charset_bin; $$=FIELD_TYPE_MEDIUM_BLOB; } - | LONG_SYM varchar { $$=FIELD_TYPE_MEDIUM_BLOB; } - | TINYTEXT { $$=FIELD_TYPE_TINY_BLOB; } - | TEXT_SYM { $$=FIELD_TYPE_BLOB; } - | MEDIUMTEXT { $$=FIELD_TYPE_MEDIUM_BLOB; } - | LONGTEXT { $$=FIELD_TYPE_LONG_BLOB; } + | LONG_SYM varchar opt_binary { $$=FIELD_TYPE_MEDIUM_BLOB; } + | TINYTEXT opt_binary { $$=FIELD_TYPE_TINY_BLOB; } + | TEXT_SYM opt_len opt_binary { $$=FIELD_TYPE_BLOB; } + | MEDIUMTEXT opt_binary { $$=FIELD_TYPE_MEDIUM_BLOB; } + | LONGTEXT opt_binary { $$=FIELD_TYPE_LONG_BLOB; } | DECIMAL_SYM float_options field_options { $$=FIELD_TYPE_DECIMAL;} | NUMERIC_SYM float_options field_options { $$=FIELD_TYPE_DECIMAL;} - | ENUM {Lex->interval_list.empty();} '(' string_list ')' + | FIXED_SYM float_options field_options + { $$=FIELD_TYPE_DECIMAL;} + | ENUM {Lex->interval_list.empty();} '(' string_list ')' opt_binary { LEX *lex=Lex; lex->interval=typelib(lex->interval_list); $$=FIELD_TYPE_ENUM; } - | SET { Lex->interval_list.empty();} '(' string_list ')' + | SET { Lex->interval_list.empty();} '(' string_list ')' opt_binary { LEX *lex=Lex; lex->interval=typelib(lex->interval_list); $$=FIELD_TYPE_SET; - }; + } + | LONG_SYM opt_binary { $$=FIELD_TYPE_MEDIUM_BLOB; } + ; char: CHAR_SYM {} @@ -1051,8 +1163,8 @@ field_option: | ZEROFILL { Lex->type|= UNSIGNED_FLAG | ZEROFILL_FLAG; }; opt_len: - /* empty */ { $$=(char*) 0; } /* use default length */ - | '(' NUM ')' { $$=$2.str; }; + /* empty */ { Lex->length=(char*) 0; } /* use default length */ + | '(' NUM ')' { Lex->length= $2.str; }; opt_precision: /* empty */ {} @@ -1071,21 +1183,70 @@ attribute: | NOT NULL_SYM { Lex->type|= NOT_NULL_FLAG; } | DEFAULT literal { Lex->default_value=$2; } | AUTO_INC { Lex->type|= AUTO_INCREMENT_FLAG | NOT_NULL_FLAG; } + | SERIAL_SYM DEFAULT VALUE_SYM + { Lex->type|= AUTO_INCREMENT_FLAG | NOT_NULL_FLAG; } | PRIMARY_SYM KEY_SYM { Lex->type|= PRI_KEY_FLAG | NOT_NULL_FLAG; } | UNIQUE_SYM { Lex->type|= UNIQUE_FLAG; } | UNIQUE_SYM KEY_SYM { Lex->type|= UNIQUE_KEY_FLAG; } - | COMMENT_SYM text_literal {}; + | COMMENT_SYM text_literal { Lex->comment= $2; }; -opt_binary: +charset_name: + BINARY + { + if (!($$=get_charset_by_name("binary",MYF(0)))) + { + net_printf(current_thd,ER_UNKNOWN_CHARACTER_SET,"binary"); + YYABORT; + } + } + | ident + { + if (!($$=get_charset_by_name($1.str,MYF(0)))) + { + net_printf(current_thd,ER_UNKNOWN_CHARACTER_SET,$1.str); + YYABORT; + } + }; + +charset_name_or_default: + charset_name { $$=$1; } + | DEFAULT { $$=NULL; } ; + +opt_default: /* empty */ {} - | BINARY { Lex->type|=BINARY_FLAG; }; + | DEFAULT {}; + +opt_db_default_character_set: + /* empty */ { $$=default_charset_info; } + | opt_default CHAR_SYM SET charset_name_or_default { $$=$4; } + | opt_default CHARSET charset_name_or_default { $$=$3; }; + +opt_binary: + /* empty */ { Lex->charset=NULL; } + | BYTE_SYM { Lex->charset=my_charset_bin; } + | BINARY { Lex->charset=my_charset_bin; } + | CHAR_SYM SET charset_name { Lex->charset=$3; } ; references: - REFERENCES table_ident opt_on_delete {} - | REFERENCES table_ident '(' key_list ')' opt_on_delete - { - Lex->col_list.empty(); /* Alloced by sql_alloc */ - }; + REFERENCES table_ident + { + LEX *lex=Lex; + lex->fk_delete_opt= lex->fk_update_opt= lex->fk_match_option= 0; + lex->ref_list.empty(); + } + opt_ref_list + { + $$=$2; + }; + +opt_ref_list: + /* empty */ opt_on_delete {} + | '(' ref_list ')' opt_on_delete {}; + +ref_list: + ref_list ',' ident { Lex->ref_list.push_back(new key_part_spec($3.str)); } + | ident { Lex->ref_list.push_back(new key_part_spec($1.str)); }; + opt_on_delete: /* empty */ {} @@ -1095,25 +1256,27 @@ opt_on_delete_list: opt_on_delete_list opt_on_delete_item {} | opt_on_delete_item {}; - opt_on_delete_item: - ON DELETE_SYM delete_option {} - | ON UPDATE_SYM delete_option {} - | MATCH FULL {} - | MATCH PARTIAL {}; + ON DELETE_SYM delete_option { Lex->fk_delete_opt= $3; } + | ON UPDATE_SYM delete_option { Lex->fk_update_opt= $3; } + | MATCH FULL { Lex->fk_match_option= foreign_key::FK_MATCH_FULL; } + | MATCH PARTIAL { Lex->fk_match_option= foreign_key::FK_MATCH_PARTIAL; } + | MATCH SIMPLE_SYM { Lex->fk_match_option= foreign_key::FK_MATCH_SIMPLE; }; delete_option: - RESTRICT {} - | CASCADE {} - | SET NULL_SYM {} - | NO_SYM ACTION {} - | SET DEFAULT {}; + RESTRICT { $$= (int) foreign_key::FK_OPTION_RESTRICT; } + | CASCADE { $$= (int) foreign_key::FK_OPTION_CASCADE; } + | SET NULL_SYM { $$= (int) foreign_key::FK_OPTION_SET_NULL; } + | NO_SYM ACTION { $$= (int) foreign_key::FK_OPTION_NO_ACTION; } + | SET DEFAULT { $$= (int) foreign_key::FK_OPTION_DEFAULT; }; key_type: opt_constraint PRIMARY_SYM KEY_SYM { $$= Key::PRIMARY; } | 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; }; @@ -1129,7 +1292,16 @@ keys_or_index: 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_UNDEF; } + | 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); } @@ -1154,10 +1326,11 @@ string_list: alter: ALTER opt_ignore TABLE_SYM table_ident { - LEX *lex=Lex; + THD *thd=current_thd; + LEX *lex=&thd->lex; lex->sql_command = SQLCOM_ALTER_TABLE; lex->name=0; - if (!add_table_to_list($4, NULL,1)) + if (!lex->select_lex.add_table_to_list($4, NULL,1)) YYABORT; lex->drop_primary=0; lex->create_list.empty(); @@ -1165,18 +1338,26 @@ alter: lex->col_list.empty(); lex->drop_list.empty(); lex->alter_list.empty(); - lex->select->order_list.elements=0; - lex->select->order_list.first=0; - lex->select->order_list.next= (byte**) &lex->select->order_list.first; - lex->select->db=lex->name=0; + lex->select_lex.init_order(); + lex->select_lex.db=lex->name=0; bzero((char*) &lex->create_info,sizeof(lex->create_info)); lex->create_info.db_type= DB_TYPE_DEFAULT; + lex->create_info.table_charset=thd->db_charset?thd->db_charset:default_charset_info; lex->create_info.row_type= ROW_TYPE_NOT_USED; lex->alter_keys_onoff=LEAVE_AS_IS; lex->simple_alter=1; } alter_list; - + + | ALTER DATABASE ident opt_db_default_character_set + { + LEX *lex=Lex; + lex->sql_command=SQLCOM_ALTER_DB; + lex->name=$3.str; + lex->create_info.table_charset=$4; + }; + + alter_list: | alter_list_item | alter_list ',' alter_list_item; @@ -1193,24 +1374,24 @@ alter_list_item: lex->change= $3.str; lex->simple_alter=0; } field_spec opt_place - | MODIFY_SYM opt_column field_ident - { - LEX *lex=Lex; - lex->length=lex->dec=0; lex->type=0; lex->interval=0; - lex->default_value=0; + | MODIFY_SYM opt_column field_ident + { + LEX *lex=Lex; + lex->length=lex->dec=0; lex->type=0; lex->interval=0; + lex->default_value=lex->comment=0; lex->simple_alter=0; - } - type opt_attribute - { - LEX *lex=Lex; - if (add_field_to_list($3.str, - (enum enum_field_types) $5, - lex->length,lex->dec,lex->type, - lex->default_value, $3.str, - lex->interval)) - YYABORT; - } - opt_place + } + type opt_attribute + { + LEX *lex=Lex; + if (add_field_to_list($3.str, + (enum enum_field_types) $5, + lex->length,lex->dec,lex->type, + lex->default_value, lex->comment, + $3.str, lex->interval, lex->charset)) + YYABORT; + } + opt_place | DROP opt_column field_ident opt_restrict { LEX *lex=Lex; @@ -1247,10 +1428,10 @@ alter_list_item: | RENAME opt_to table_ident { LEX *lex=Lex; - lex->select->db=$3->db.str; + lex->select_lex.db=$3->db.str; lex->name= $3->table.str; } - | create_table_options { Lex->simple_alter=0; } + | create_table_options_space_separated { Lex->simple_alter=0; } | order_clause { Lex->simple_alter=0; }; opt_column: @@ -1278,36 +1459,23 @@ opt_to: | AS {}; /* - * The first two deprecate the last two--delete the last two for 4.1 release - */ + The first two deprecate the last two--delete the last two for 4.1 release +*/ + slave: START_SYM SLAVE slave_thread_opts - { - LEX *lex=Lex; - lex->sql_command = SQLCOM_SLAVE_START; - lex->type = 0; - } - | - STOP_SYM SLAVE slave_thread_opts - { - LEX *lex=Lex; - lex->sql_command = SQLCOM_SLAVE_STOP; - lex->type = 0; - } - | - SLAVE START_SYM slave_thread_opts - { - LEX *lex=Lex; - lex->sql_command = SQLCOM_SLAVE_START; - lex->type = 0; - } - | - SLAVE STOP_SYM slave_thread_opts - { - LEX *lex=Lex; - lex->sql_command = SQLCOM_SLAVE_STOP; - lex->type = 0; - }; + { + LEX *lex=Lex; + lex->sql_command = SQLCOM_SLAVE_START; + lex->type = 0; + } + | STOP_SYM SLAVE slave_thread_opts + { + LEX *lex=Lex; + lex->sql_command = SQLCOM_SLAVE_STOP; + lex->type = 0; + } + ; slave_thread_opts: slave_thread_opt @@ -1416,9 +1584,11 @@ table_to_table_list: table_to_table: table_ident TO_SYM table_ident - { if (!add_table_to_list($1,NULL,1,TL_IGNORE) || - !add_table_to_list($3,NULL,1,TL_IGNORE)) - YYABORT; + { + SELECT_LEX_NODE *sl= Lex->current_select; + if (!sl->add_table_to_list($1,NULL,1,TL_IGNORE) || + !sl->add_table_to_list($3,NULL,1,TL_IGNORE)) + YYABORT; }; /* @@ -1430,10 +1600,30 @@ select: select_init { Lex->sql_command=SQLCOM_SELECT; }; select_init: - SELECT_SYM select_part2 { Select->braces=false; } opt_union + SELECT_SYM select_part2 + { + LEX *lex= Lex; + if (lex->current_select->set_braces(false)) + { + send_error(lex->thd, ER_SYNTAX_ERROR); + YYABORT; + } + } + union | - '(' SELECT_SYM select_part2 ')' { Select->braces=true;} union_opt; - + '(' SELECT_SYM select_part2 ')' + { + LEX *lex= Lex; + SELECT_LEX_NODE * sel= lex->current_select; + if (sel->set_braces(true)) + { + send_error(lex->thd, ER_SYNTAX_ERROR); + YYABORT; + } + /* select in braces, can't contain global parameters */ + sel->master_unit()->global_parameters= + sel->master_unit(); + } union_opt; select_part2: { @@ -1446,6 +1636,8 @@ select_part2: select_into: limit_clause {} | select_from + | FROM DUAL_SYM + | opt_into | opt_into select_from | select_from opt_into; @@ -1552,8 +1744,8 @@ optional_braces: | '(' ')' {}; /* all possible expressions */ -expr: expr_expr {$$ = $1; } - | simple_expr {$$ = $1; }; +expr: expr_expr { $$= $1; } + | simple_expr { $$= $1; }; /* expressions that begin with 'expr' */ expr_expr: @@ -1588,6 +1780,8 @@ expr_expr: | expr '-' expr { $$= new Item_func_minus($1,$3); } | expr '*' expr { $$= new Item_func_mul($1,$3); } | expr '/' expr { $$= new Item_func_div($1,$3); } + | expr DIV_SYM expr { $$= new Item_func_int_div($1,$3); } + | expr MOD_SYM expr { $$= new Item_func_mod($1,$3); } | expr '|' expr { $$= new Item_func_bit_or($1,$3); } | expr '^' expr { $$= new Item_func_bit_xor($1,$3); } | expr '&' expr { $$= new Item_func_bit_and($1,$3); } @@ -1595,7 +1789,9 @@ expr_expr: | expr '+' INTERVAL_SYM expr interval { $$= new Item_date_add_interval($1,$4,$5,0); } | expr '-' INTERVAL_SYM expr interval - { $$= new Item_date_add_interval($1,$4,$5,1); }; + { $$= new Item_date_add_interval($1,$4,$5,1); } + | expr COLLATE_SYM charset_name + { $$= new Item_func_set_collation($1,$3); }; /* expressions that begin with 'expr' that do NOT follow IN_SYM */ no_in_expr: @@ -1626,10 +1822,12 @@ no_in_expr: | no_in_expr '-' expr { $$= new Item_func_minus($1,$3); } | no_in_expr '*' expr { $$= new Item_func_mul($1,$3); } | no_in_expr '/' expr { $$= new Item_func_div($1,$3); } + | no_in_expr DIV_SYM expr { $$= new Item_func_int_div($1,$3); } | no_in_expr '|' expr { $$= new Item_func_bit_or($1,$3); } | no_in_expr '^' expr { $$= new Item_func_bit_xor($1,$3); } | no_in_expr '&' expr { $$= new Item_func_bit_and($1,$3); } | no_in_expr '%' expr { $$= new Item_func_mod($1,$3); } + | no_in_expr MOD_SYM expr { $$= new Item_func_mod($1,$3); } | no_in_expr '+' INTERVAL_SYM expr interval { $$= new Item_date_add_interval($1,$4,$5,0); } | no_in_expr '-' INTERVAL_SYM expr interval @@ -1668,10 +1866,12 @@ no_and_expr: | no_and_expr '-' expr { $$= new Item_func_minus($1,$3); } | no_and_expr '*' expr { $$= new Item_func_mul($1,$3); } | no_and_expr '/' expr { $$= new Item_func_div($1,$3); } + | no_and_expr DIV_SYM expr { $$= new Item_func_int_div($1,$3); } | no_and_expr '|' expr { $$= new Item_func_bit_or($1,$3); } | no_and_expr '^' expr { $$= new Item_func_bit_xor($1,$3); } | no_and_expr '&' expr { $$= new Item_func_bit_and($1,$3); } | no_and_expr '%' expr { $$= new Item_func_mod($1,$3); } + | no_and_expr MOD_SYM expr { $$= new Item_func_mod($1,$3); } | no_and_expr '+' INTERVAL_SYM expr interval { $$= new Item_date_add_interval($1,$4,$5,0); } | no_and_expr '-' INTERVAL_SYM expr interval @@ -1681,6 +1881,7 @@ no_and_expr: simple_expr: simple_ident | literal + | param_marker | '@' ident_or_text SET_VAR expr { $$= new Item_func_set_user_var($2,$4); @@ -1702,18 +1903,24 @@ simple_expr: | NOT expr %prec NEG { $$= new Item_func_not($2); } | '!' expr %prec NEG { $$= new Item_func_not($2); } | '(' expr ')' { $$= $2; } + | EXISTS exists_subselect { $$= $2; } + | singleval_subselect { $$= $1; } | '{' ident expr '}' { $$= $3; } | MATCH ident_list_arg AGAINST '(' expr ')' - { Select->ftfunc_list.push_back((Item_func_match *) + { Select->add_ftfunc_to_list((Item_func_match *) ($$=new Item_func_match_nl(*$2,$5))); } | MATCH ident_list_arg AGAINST '(' expr IN_SYM BOOLEAN_SYM MODE_SYM ')' - { Select->ftfunc_list.push_back((Item_func_match *) + { Select->add_ftfunc_to_list((Item_func_match *) ($$=new Item_func_match_bool(*$2,$5))); } - | BINARY expr %prec NEG { $$= new Item_func_binary($2); } + | BINARY expr %prec NEG { $$= new Item_func_set_collation($2,my_charset_bin); } | CAST_SYM '(' expr AS cast_type ')' { $$= create_func_cast($3, $5); } | 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 charset_name ')' + { $$= new Item_func_conv_charset($3,$5); } + | CONVERT_SYM '(' expr ',' expr ',' expr ')' + { $$= new Item_func_conv_charset3($3,$7,$5); } | FUNC_ARG0 '(' ')' { $$= ((Item*(*)(void))($1.symbol->create_func))();} | FUNC_ARG1 '(' expr ')' @@ -1728,6 +1935,8 @@ simple_expr: { $$= new Item_func_atan($3,$5); } | CHAR_SYM '(' expr_list ')' { $$= new Item_func_char(*$3); } + | CHARSET '(' expr ')' + { $$= new Item_func_charset($3); } | COALESCE '(' expr_list ')' { $$= new Item_func_coalesce(* $3); } | CONCAT '(' expr_list ')' @@ -1780,6 +1989,8 @@ simple_expr: { $$= new Item_func_export_set($3, $5, $7, $9); } | EXPORT_SET '(' expr ',' expr ',' expr ',' expr ',' expr ')' { $$= new Item_func_export_set($3, $5, $7, $9, $11); } + | FALSE_SYM + { $$= new Item_int((char*) "FALSE",0,1); } | FORMAT_SYM '(' expr ',' NUM ')' { $$= new Item_func_format($3,atoi($5.str)); } | FROM_UNIXTIME '(' expr ')' @@ -1790,6 +2001,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 ')' @@ -1803,9 +2022,8 @@ simple_expr: { $$= new Item_func_interval($3,* $5); } | LAST_INSERT_ID '(' ')' { - $$= new Item_int((char*) "last_insert_id()", - current_thd->insert_id(),21); - current_thd->safe_to_cache_query=0; + $$= get_system_var(OPT_SESSION, "last_insert_id", 14, + "last_insert_id()"); } | LAST_INSERT_ID '(' expr ')' { @@ -1814,22 +2032,56 @@ 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); } | LOG_SYM '(' expr ')' - { $$= new Item_func_log($3); } + { $$= new Item_func_log($3); } | LOG_SYM '(' expr ',' expr ')' - { $$= new Item_func_log($3, $5); } + { $$= new Item_func_log($3, $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); } + | MOD_SYM '(' expr ',' expr ')' + { $$ = new Item_func_mod( $3, $5); } | 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 ')' @@ -1838,6 +2090,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 ')' @@ -1864,7 +2127,7 @@ simple_expr: | SUBSTRING_INDEX '(' expr ',' expr ',' expr ')' { $$= new Item_func_substr_index($3,$5,$7); } | TRIM '(' expr ')' - { $$= new Item_func_trim($3,new Item_string(" ",1)); } + { $$= new Item_func_trim($3,new Item_string(" ",1,default_charset_info)); } | TRIM '(' LEADING opt_pad FROM expr ')' { $$= new Item_func_ltrim($6,$4); } | TRIM '(' TRAILING opt_pad FROM expr ')' @@ -1875,6 +2138,8 @@ simple_expr: { $$= new Item_func_trim($5,$3); } | TRUNCATE_SYM '(' expr ',' expr ')' { $$= new Item_func_round($3,$5,1); } + | TRUE_SYM + { $$= new Item_int((char*) "TRUE",1,1); } | UDA_CHAR_SUM '(' udf_expr_list ')' { if ($3 != NULL) @@ -1977,10 +2242,17 @@ sum_expr: { $$=new Item_sum_sum($3); }; in_sum_expr: - { Select->in_sum_expr++; } + { + LEX *lex= Lex; + if (lex->current_select->inc_in_sum_expr()) + { + send_error(lex->thd, ER_SYNTAX_ERROR); + YYABORT; + } + } expr { - Select->in_sum_expr--; + Select->select_lex()->in_sum_expr--; $$=$2; }; @@ -2032,19 +2304,19 @@ when_list: when_list2: expr THEN_SYM expr { - SELECT_LEX *sel=Select; + SELECT_LEX_NODE *sel=Select; sel->when_list.head()->push_back($1); sel->when_list.head()->push_back($3); } | when_list2 WHEN_SYM expr THEN_SYM expr { - SELECT_LEX *sel=Select; + SELECT_LEX_NODE *sel=Select; sel->when_list.head()->push_back($3); sel->when_list.head()->push_back($5); }; opt_pad: - /* empty */ { $$=new Item_string(" ",1); } + /* empty */ { $$=new Item_string(" ",1,default_charset_info); } | expr { $$=$1; }; join_table_list: @@ -2057,7 +2329,7 @@ join_table_list: { add_join_on($4,$6); $$=$4; } | join_table_list INNER_SYM JOIN_SYM join_table_list { - SELECT_LEX *sel=Select; + SELECT_LEX *sel= Select->select_lex(); sel->db1=$1->db; sel->table1=$1->alias; sel->db2=$4->db; sel->table2=$4->alias; } @@ -2067,7 +2339,7 @@ join_table_list: { add_join_on($5,$7); $5->outer_join|=JOIN_TYPE_LEFT; $$=$5; } | join_table_list LEFT opt_outer JOIN_SYM join_table_list { - SELECT_LEX *sel=Select; + SELECT_LEX *sel= Select->select_lex(); sel->db1=$1->db; sel->table1=$1->alias; sel->db2=$5->db; sel->table2=$5->alias; } @@ -2079,7 +2351,7 @@ join_table_list: { add_join_on($1,$7); $1->outer_join|=JOIN_TYPE_RIGHT; $$=$1; } | join_table_list RIGHT opt_outer JOIN_SYM join_table_list { - SELECT_LEX *sel=Select; + SELECT_LEX *sel= Select->select_lex(); sel->db1=$1->db; sel->table1=$1->alias; sel->db2=$5->db; sel->table2=$5->alias; } @@ -2097,18 +2369,44 @@ normal_join: join_table: { - SELECT_LEX *sel=Select; + SELECT_LEX *sel= Select->select_lex(); sel->use_index_ptr=sel->ignore_index_ptr=0; } table_ident opt_table_alias opt_key_definition { - SELECT_LEX *sel=Select; - if (!($$=add_table_to_list($2,$3,0,TL_UNLOCK, sel->use_index_ptr, - sel->ignore_index_ptr))) + SELECT_LEX_NODE *sel=Select; + if (!($$= sel->add_table_to_list($2, $3, 0, TL_UNLOCK, + sel->get_use_index(), + sel->get_ignore_index()))) YYABORT; } | '{' ident join_table LEFT OUTER JOIN_SYM join_table ON expr '}' - { add_join_on($7,$9); $7->outer_join|=JOIN_TYPE_LEFT; $$=$7; }; + { add_join_on($7,$9); $7->outer_join|=JOIN_TYPE_LEFT; $$=$7; } + | '(' SELECT_SYM select_part3 ')' opt_table_alias + { + LEX *lex=Lex; + SELECT_LEX_UNIT *unit= lex->current_select->master_unit(); + lex->current_select= unit->outer_select(); + if (!($$= lex->current_select-> + add_table_to_list(new Table_ident(unit), $5, 0, TL_UNLOCK))) + YYABORT; + }; + +select_part3: + { + LEX *lex= Lex; + lex->derived_tables= true; + if (lex->current_select->linkage == GLOBAL_OPTIONS_TYPE || + mysql_new_select(lex, 1)) + YYABORT; + mysql_init_select(lex); + lex->current_select->linkage= DERIVED_TABLE_TYPE; + } + select_options select_item_list select_intoto; + +select_intoto: + limit_clause {} + | select_from; opt_outer: /* empty */ {} @@ -2118,39 +2416,49 @@ opt_key_definition: /* empty */ {} | USE_SYM key_usage_list { - SELECT_LEX *sel=Select; + SELECT_LEX *sel= Select->select_lex(); sel->use_index= *$2; sel->use_index_ptr= &sel->use_index; } | IGNORE_SYM key_usage_list { - SELECT_LEX *sel=Select; + SELECT_LEX *sel= Select->select_lex(); sel->ignore_index= *$2; sel->ignore_index_ptr= &sel->ignore_index; }; key_usage_list: - key_or_index { Select->interval_list.empty(); } '(' key_usage_list2 ')' - { $$= &Select->interval_list; }; + key_or_index { Select->select_lex()->interval_list.empty(); } + '(' key_usage_list2 ')' + { $$= &Select->select_lex()->interval_list; }; key_usage_list2: key_usage_list2 ',' ident - { Select->interval_list.push_back(new String((const char*) $3.str,$3.length)); } + { Select->select_lex()-> + interval_list.push_back(new String((const char*) $3.str, $3.length, + default_charset_info)); } | ident - { Select->interval_list.push_back(new String((const char*) $1.str,$1.length)); } + { Select->select_lex()-> + interval_list.push_back(new String((const char*) $1.str, $1.length, + default_charset_info)); } | PRIMARY_SYM - { Select->interval_list.push_back(new String("PRIMARY",7)); }; + { Select->select_lex()-> + interval_list.push_back(new String("PRIMARY", 7, + default_charset_info)); }; using_list: ident { - SELECT_LEX *sel=Select; - if (!($$= new Item_func_eq(new Item_field(sel->db1,sel->table1, $1.str), new Item_field(sel->db2,sel->table2,$1.str)))) + SELECT_LEX *sel= Select->select_lex(); + if (!($$= new Item_func_eq(new Item_field(sel->db1, sel->table1, + $1.str), + new Item_field(sel->db2, sel->table2, + $1.str)))) YYABORT; } | using_list ',' ident { - SELECT_LEX *sel=Select; + SELECT_LEX *sel= Select->select_lex(); if (!($$= new Item_cond_and(new Item_func_eq(new Item_field(sel->db1,sel->table1,$3.str), new Item_field(sel->db2,sel->table2,$3.str)), $1))) YYABORT; }; @@ -2182,25 +2490,24 @@ opt_table_alias: where_clause: - /* empty */ { Select->where= 0; } + /* empty */ { Select->select_lex()->where= 0; } | WHERE expr { - Select->where= $2; + Select->select_lex()->where= $2; if ($2) $2->top_level_item(); } - ; + ; having_clause: /* empty */ - | HAVING { Select->create_refs=1; } expr - { - SELECT_LEX *sel=Select; - sel->having= $3; - sel->create_refs=0; - if ($3) - $3->top_level_item(); - } + | HAVING { Select->select_lex()->create_refs= 1; } expr + { + SELECT_LEX *sel= Select->select_lex(); + sel->having= $3; sel->create_refs=0; + if ($3) + $3->top_level_item(); + } ; opt_escape: @@ -2228,16 +2535,28 @@ olap_opt: { LEX *lex=Lex; lex->olap = true; - lex->select->olap= CUBE_TYPE; - net_printf(&lex->thd->net, ER_NOT_SUPPORTED_YET, "CUBE"); + if (lex->current_select->linkage == GLOBAL_OPTIONS_TYPE) + { + net_printf(lex->thd, ER_WRONG_USAGE, "WITH CUBE", + "global union parameters"); + YYABORT; + } + lex->current_select->select_lex()->olap= CUBE_TYPE; + net_printf(lex->thd, ER_NOT_SUPPORTED_YET, "CUBE"); YYABORT; /* To be deleted in 4.1 */ } | WITH ROLLUP_SYM { - LEX *lex=Lex; - lex->olap = true; - lex->select->olap= ROLLUP_TYPE; - net_printf(&lex->thd->net, ER_NOT_SUPPORTED_YET, "ROLLUP"); + LEX *lex= Lex; + lex->olap= true; + if (lex->current_select->linkage == GLOBAL_OPTIONS_TYPE) + { + net_printf(lex->thd, ER_WRONG_USAGE, "WITH ROLLUP", + "global union parameters"); + YYABORT; + } + lex->current_select->select_lex()->olap= ROLLUP_TYPE; + net_printf(lex->thd, ER_NOT_SUPPORTED_YET, "ROLLUP"); YYABORT; /* To be deleted in 4.1 */ } ; @@ -2254,14 +2573,15 @@ order_clause: ORDER_SYM BY { LEX *lex=Lex; - if (lex->select->olap != UNSPECIFIED_OLAP_TYPE) + if (lex->current_select->linkage != GLOBAL_OPTIONS_TYPE && + lex->current_select->select_lex()->olap != + UNSPECIFIED_OLAP_TYPE) { - net_printf(&lex->thd->net, ER_WRONG_USAGE, + net_printf(lex->thd, ER_WRONG_USAGE, "CUBE/ROLLUP", "ORDER BY"); YYABORT; } - lex->select->sort_default=1; } order_list; order_list: @@ -2280,43 +2600,46 @@ limit_clause: /* empty */ {} | LIMIT { - LEX *lex=Lex; - if (lex->select->olap != UNSPECIFIED_OLAP_TYPE) + LEX *lex= Lex; + if (lex->current_select->linkage != GLOBAL_OPTIONS_TYPE && + lex->current_select->select_lex()->olap != + UNSPECIFIED_OLAP_TYPE) { - net_printf(&lex->thd->net, ER_WRONG_USAGE, "CUBE/ROLLUP", + net_printf(lex->thd, ER_WRONG_USAGE, "CUBE/ROLLUP", "LIMIT"); YYABORT; } } limit_options - ; + ; limit_options: ULONG_NUM { - SELECT_LEX *sel= Select; + SELECT_LEX_NODE *sel= Select; sel->select_limit= $1; sel->offset_limit= 0L; } | ULONG_NUM ',' ULONG_NUM { - SELECT_LEX *sel= Select; + SELECT_LEX_NODE *sel= Select; sel->select_limit= $3; sel->offset_limit= $1; } | ULONG_NUM OFFSET_SYM ULONG_NUM { - SELECT_LEX *sel= Select; + SELECT_LEX_NODE *sel= Select; sel->select_limit= $1; sel->offset_limit= $3; } ; + delete_limit_clause: /* empty */ { LEX *lex=Lex; - lex->select->select_limit= HA_POS_ERROR; + lex->current_select->select_limit= HA_POS_ERROR; } | LIMIT ulonglong_num { Select->select_limit= (ha_rows) $2; }; @@ -2364,20 +2687,61 @@ procedure_item: YYABORT; if (!$2->name) $2->set_name($1,(uint) ((char*) Lex->tok_end - $1)); - }; + } + ; + + +select_var_list_init: + { + LEX *lex=Lex; + if (!lex->describe && (!(lex->result= new select_dumpvar()))) + YYABORT; + } + select_var_list + ; + +select_var_list: + select_var_list ',' select_var_ident + | select_var_ident {} + ; + +select_var_ident: '@' ident_or_text + { + LEX *lex=Lex; + if (lex->result && ((select_dumpvar *)lex->result)->var_list.push_back((LEX_STRING*) sql_memdup(&$2,sizeof(LEX_STRING)))) + YYABORT; + } + ; opt_into: - INTO OUTFILE TEXT_STRING + INTO OUTFILE TEXT_STRING { - if (!(Lex->exchange= new sql_exchange($3.str,0))) - YYABORT; + LEX *lex=Lex; + if (!lex->describe) + { + if (!(lex->exchange= new sql_exchange($3.str,0))) + YYABORT; + if (!(lex->result= new select_export(lex->exchange))) + YYABORT; + } } opt_field_term opt_line_term | INTO DUMPFILE TEXT_STRING { - if (!(Lex->exchange= new sql_exchange($3.str,1))) - YYABORT; - }; + LEX *lex=Lex; + if (!lex->describe) + { + if (!(lex->exchange= new sql_exchange($3.str,1))) + YYABORT; + if (!(lex->result= new select_dump(lex->exchange))) + YYABORT; + } + } + | INTO select_var_list_init + { + current_thd->safe_to_cache_query=0; + } + ; /* DO statement @@ -2410,7 +2774,7 @@ drop: lex->drop_list.empty(); lex->drop_list.push_back(new Alter_drop(Alter_drop::KEY, $3.str)); - if (!add_table_to_list($5,NULL, 1)) + if (!lex->current_select->add_table_to_list($5,NULL, 1)) YYABORT; } | DROP DATABASE if_exists ident @@ -2434,7 +2798,7 @@ table_list: table_name: table_ident - { if (!add_table_to_list($1,NULL,1)) YYABORT; }; + { if (!Select->add_table_to_list($1, NULL, 1)) YYABORT; }; if_exists: /* empty */ { $$=0; } @@ -2596,11 +2960,9 @@ expr_or_default: update: UPDATE_SYM { - LEX *lex=Lex; - lex->sql_command = SQLCOM_UPDATE; - lex->select->order_list.elements=0; - lex->select->order_list.first=0; - lex->select->order_list.next= (byte**) &lex->select->order_list.first; + LEX *lex= Lex; + lex->sql_command= SQLCOM_UPDATE; + lex->select_lex.init_order(); } opt_low_priority opt_ignore join_table_list SET update_list where_clause opt_order_clause delete_limit_clause @@ -2630,12 +2992,11 @@ opt_low_priority: delete: DELETE_SYM { - LEX *lex=Lex; - lex->sql_command= SQLCOM_DELETE; lex->select->options=0; + LEX *lex= Lex; + lex->sql_command= SQLCOM_DELETE; + lex->select_lex.options= 0; lex->lock_option= lex->thd->update_lock_default; - lex->select->order_list.elements=0; - lex->select->order_list.first=0; - lex->select->order_list.next= (byte**) &lex->select->order_list.first; + lex->select_lex.init_order(); } opt_delete_options single_multi {} ; @@ -2660,18 +3021,18 @@ table_wild_list: | table_wild_list ',' table_wild_one {}; table_wild_one: - ident opt_wild - { - if (!add_table_to_list(new Table_ident($1), NULL, 1, - Lex->lock_option)) - YYABORT; - } - | ident '.' ident opt_wild - { - if (!add_table_to_list(new Table_ident($1,$3,0), NULL, 1, - Lex->lock_option)) + ident opt_wild + { + if (!Select->add_table_to_list(new Table_ident($1), NULL, 1, + Lex->lock_option)) + YYABORT; + } + | ident '.' ident opt_wild + { + if (!Select->add_table_to_list(new Table_ident($1, $3, 0), NULL, 1, + Lex->lock_option)) YYABORT; - } + } ; opt_wild: @@ -2690,12 +3051,10 @@ opt_delete_option: truncate: TRUNCATE_SYM opt_table_sym table_name { - LEX* lex = Lex; + LEX* lex= Lex; lex->sql_command= SQLCOM_TRUNCATE; - lex->select->options=0; - lex->select->order_list.elements=0; - lex->select->order_list.first=0; - lex->select->order_list.next= (byte**) &lex->select->order_list.first; + lex->select_lex.options= 0; + lex->select_lex.init_order(); } ; @@ -2705,37 +3064,44 @@ opt_table_sym: /* Show things */ -show: SHOW { Lex->wild=0;} show_param; +show: SHOW + { + LEX *lex=Lex; + lex->wild=0; + bzero((char*) &lex->create_info,sizeof(lex->create_info)); + } + show_param; show_param: DATABASES wild { Lex->sql_command= SQLCOM_SHOW_DATABASES; } | TABLES opt_db wild { - LEX *lex=Lex; + LEX *lex= Lex; lex->sql_command= SQLCOM_SHOW_TABLES; - lex->select->db= $2; lex->select->options=0; + lex->select_lex.db= $2; + lex->select_lex.options= 0; } | TABLE_SYM STATUS_SYM opt_db wild { - LEX *lex=Lex; + LEX *lex= Lex; lex->sql_command= SQLCOM_SHOW_TABLES; - lex->select->options|= SELECT_DESCRIBE; - lex->select->db= $3; + lex->select_lex.options|= SELECT_DESCRIBE; + lex->select_lex.db= $3; } | OPEN_SYM TABLES opt_db wild { - LEX *lex=Lex; + LEX *lex= Lex; lex->sql_command= SQLCOM_SHOW_OPEN_TABLES; - lex->select->db= $3; - lex->select->options=0; + lex->select_lex.db= $3; + lex->select_lex.options= 0; } | opt_full COLUMNS from_or_in table_ident opt_db wild { Lex->sql_command= SQLCOM_SHOW_FIELDS; if ($5) $4->change_db($5); - if (!add_table_to_list($4,NULL,0)) + if (!Select->add_table_to_list($4, NULL, 0)) YYABORT; } | NEW_SYM MASTER_SYM FOR_SYM SLAVE WITH MASTER_LOG_FILE_SYM EQ @@ -2748,7 +3114,7 @@ show_param: Lex->mi.pos = $12; Lex->mi.server_id = $16; } - | MASTER_SYM LOGS_SYM + | BINARY LOGS_SYM { Lex->sql_command = SQLCOM_SHOW_BINLOGS; } @@ -2758,19 +3124,42 @@ show_param: } | BINLOG_SYM EVENTS_SYM binlog_in binlog_from { - LEX *lex=Lex; - lex->sql_command = SQLCOM_SHOW_BINLOG_EVENTS; - lex->select->select_limit= lex->thd->variables.select_limit; - lex->select->offset_limit= 0L; + LEX *lex= Lex; + lex->sql_command= SQLCOM_SHOW_BINLOG_EVENTS; + lex->select_lex.select_limit= lex->thd->variables.select_limit; + lex->select_lex.offset_limit= 0L; } limit_clause | keys_or_index FROM table_ident opt_db { Lex->sql_command= SQLCOM_SHOW_KEYS; if ($4) $3->change_db($4); - if (!add_table_to_list($3,NULL,0)) + if (!Select->add_table_to_list($3, NULL, 0)) YYABORT; } + | COLUMN_SYM TYPES_SYM + { + LEX *lex=Lex; + lex->sql_command= SQLCOM_SHOW_COLUMN_TYPES; + } + | TABLE_SYM TYPES_SYM + { + LEX *lex=Lex; + lex->sql_command= SQLCOM_SHOW_TABLE_TYPES; + } + | PRIVILEGES + { + LEX *lex=Lex; + lex->sql_command= SQLCOM_SHOW_PRIVILEGES; + } + | COUNT_SYM '(' '*' ')' WARNINGS + { (void) create_select_for_variable("warning_count"); } + | COUNT_SYM '(' '*' ')' ERRORS + { (void) create_select_for_variable("error_count"); } + | WARNINGS {Select->offset_limit=0L;} limit_clause + { Lex->sql_command = SQLCOM_SHOW_WARNS;} + | ERRORS {Select->offset_limit=0L;} limit_clause + { Lex->sql_command = SQLCOM_SHOW_ERRORS;} | STATUS_SYM wild { Lex->sql_command= SQLCOM_SHOW_STATUS; } | INNOBASE_SYM STATUS_SYM @@ -2778,11 +3167,13 @@ show_param: | opt_full PROCESSLIST_SYM { Lex->sql_command= SQLCOM_SHOW_PROCESSLIST;} | opt_var_type VARIABLES wild - { + { THD *thd= current_thd; thd->lex.sql_command= SQLCOM_SHOW_VARIABLES; thd->lex.option_type= (enum_var_type) $1; } + | CHAR_SYM SET wild + { Lex->sql_command= SQLCOM_SHOW_CHARSETS; } | LOGS_SYM { Lex->sql_command= SQLCOM_SHOW_LOGS; } | GRANTS FOR_SYM user @@ -2792,10 +3183,16 @@ show_param: lex->grant_user=$3; lex->grant_user->password.str=NullS; } + | CREATE DATABASE opt_if_not_exists ident + { + Lex->sql_command=SQLCOM_SHOW_CREATE_DB; + Lex->create_info.options=$3; + Lex->name=$4.str; + } | CREATE TABLE_SYM table_ident { Lex->sql_command = SQLCOM_SHOW_CREATE; - if(!add_table_to_list($3, NULL,0)) + if(!Select->add_table_to_list($3, NULL,0)) YYABORT; } | MASTER_SYM STATUS_SYM @@ -2840,12 +3237,16 @@ describe: lex->wild=0; lex->verbose=0; lex->sql_command=SQLCOM_SHOW_FIELDS; - if (!add_table_to_list($2, NULL,0)) + if (!Select->add_table_to_list($2, NULL,0)) YYABORT; } opt_describe_column | describe_command select - { Lex->select_lex.options|= SELECT_DESCRIBE; }; + { + LEX *lex=Lex; + lex->select_lex.options|= SELECT_DESCRIBE; + lex->describe=1; + }; describe_command: @@ -2856,7 +3257,7 @@ opt_describe_column: /* empty */ {} | text_string { Lex->wild= $1; } | ident - { Lex->wild= new String((const char*) $1.str,$1.length); }; + { Lex->wild= new String((const char*) $1.str,$1.length,default_charset_info); }; /* flush things */ @@ -2923,9 +3324,9 @@ kill: KILL_SYM expr { LEX *lex=Lex; - if ($2->fix_fields(lex->thd,0)) + if ($2->fix_fields(lex->thd, 0, &$2)) { - send_error(&lex->thd->net, ER_SET_CONSTANTS_ONLY); + send_error(lex->thd, ER_SET_CONSTANTS_ONLY); YYABORT; } lex->sql_command=SQLCOM_KILL; @@ -2937,7 +3338,8 @@ kill: use: USE_SYM ident { LEX *lex=Lex; - lex->sql_command=SQLCOM_CHANGE_DB; lex->select->db= $2.str; + lex->sql_command=SQLCOM_CHANGE_DB; + lex->select_lex.db= $2.str; }; /* import, export of files */ @@ -2955,14 +3357,14 @@ load: LOAD DATA_SYM load_data_lock opt_local INFILE TEXT_STRING opt_duplicate INTO TABLE_SYM table_ident opt_field_term opt_line_term opt_ignore_lines opt_field_spec { - if (!add_table_to_list($11,NULL,1)) + if (!Select->add_table_to_list($11, NULL, 1)) YYABORT; } | LOAD TABLE_SYM table_ident FROM MASTER_SYM { Lex->sql_command = SQLCOM_LOAD_MASTER_TABLE; - if (!add_table_to_list($3,NULL,1)) + if (!Select->add_table_to_list($3, NULL, 1)) YYABORT; } @@ -3026,18 +3428,33 @@ opt_ignore_lines: /* Common definitions */ text_literal: - TEXT_STRING { $$ = new Item_string($1.str,$1.length); } + TEXT_STRING { $$ = new Item_string($1.str,$1.length,current_thd->thd_charset); } + | UNDERSCORE_CHARSET TEXT_STRING { $$ = new Item_string($2.str,$2.length,Lex->charset); } | text_literal TEXT_STRING { ((Item_string*) $1)->append($2.str,$2.length); }; text_string: - TEXT_STRING { $$= new String($1.str,$1.length); } + TEXT_STRING { $$= new String($1.str,$1.length,current_thd->thd_charset); } | HEX_NUM { Item *tmp = new Item_varbinary($1.str,$1.length); $$= tmp ? tmp->val_str((String*) 0) : (String*) 0; }; - +param_marker: + '?' + { + LEX *lex=Lex; + if (current_thd->prepare_command) + { + lex->param_list.push_back($$=new Item_param()); + lex->param_count++; + } + else + { + yyerror("You have an error in your SQL syntax"); + YYABORT; + } + }; literal: text_literal { $$ = $1; } | NUM { $$ = new Item_int($1.str, (longlong) atol($1.str),$1.length); } @@ -3072,23 +3489,23 @@ order_ident: simple_ident: ident { - SELECT_LEX *sel=Select; - $$ = !sel->create_refs || sel->in_sum_expr > 0 ? (Item*) new Item_field(NullS,NullS,$1.str) : (Item*) new Item_ref(NullS,NullS,$1.str); + SELECT_LEX_NODE *sel=Select; + $$ = !sel->create_refs || sel->get_in_sum_expr() > 0 ? (Item*) new Item_field(NullS,NullS,$1.str) : (Item*) new Item_ref(NullS,NullS,$1.str); } | ident '.' ident { - SELECT_LEX *sel=Select; - $$ = !sel->create_refs || sel->in_sum_expr > 0 ? (Item*) new Item_field(NullS,$1.str,$3.str) : (Item*) new Item_ref(NullS,$1.str,$3.str); + SELECT_LEX_NODE *sel=Select; + $$ = !sel->create_refs || sel->get_in_sum_expr() > 0 ? (Item*) new Item_field(NullS,$1.str,$3.str) : (Item*) new Item_ref(NullS,$1.str,$3.str); } | '.' ident '.' ident { - SELECT_LEX *sel=Select; - $$ = !sel->create_refs || sel->in_sum_expr > 0 ? (Item*) new Item_field(NullS,$2.str,$4.str) : (Item*) new Item_ref(NullS,$2.str,$4.str); + SELECT_LEX_NODE *sel=Select; + $$ = !sel->create_refs || sel->get_in_sum_expr() > 0 ? (Item*) new Item_field(NullS,$2.str,$4.str) : (Item*) new Item_ref(NullS,$2.str,$4.str); } | ident '.' ident '.' ident { - SELECT_LEX *sel=Select; - $$ = !sel->create_refs || sel->in_sum_expr > 0 ? (Item*) new Item_field((current_thd->client_capabilities & CLIENT_NO_SCHEMA ? NullS :$1.str),$3.str,$5.str) : (Item*) new Item_ref((current_thd->client_capabilities & CLIENT_NO_SCHEMA ? NullS :$1.str),$3.str,$5.str); + SELECT_LEX_NODE *sel=Select; + $$ = !sel->create_refs || sel->get_in_sum_expr() > 0 ? (Item*) new Item_field((current_thd->client_capabilities & CLIENT_NO_SCHEMA ? NullS :$1.str),$3.str,$5.str) : (Item*) new Item_ref((current_thd->client_capabilities & CLIENT_NO_SCHEMA ? NullS :$1.str),$3.str,$5.str); }; @@ -3151,8 +3568,10 @@ keyword: | BIT_SYM {} | BOOL_SYM {} | BOOLEAN_SYM {} + | BYTE_SYM {} | CACHE_SYM {} | CHANGED {} + | CHARSET {} | CHECKSUM_SYM {} | CHECK_SYM {} | CIPHER_SYM {} @@ -3173,6 +3592,7 @@ keyword: | DIRECTORY_SYM {} | DO_SYM {} | DUMPFILE {} + | DUAL_SYM {} | DYNAMIC_SYM {} | END {} | ENUM {} @@ -3181,14 +3601,14 @@ keyword: | EXECUTE_SYM {} | EXTENDED_SYM {} | FAST_SYM {} - | DISABLE_SYM {} - | ENABLE_SYM {} + | DISABLE_SYM {} + | ENABLE_SYM {} | FULL {} | FILE_SYM {} | FIRST_SYM {} | FIXED_SYM {} | FLUSH_SYM {} - | GRANTS {} + | GRANTS {} | GLOBAL_SYM {} | HEAP_SYM {} | HANDLER_SYM {} @@ -3201,7 +3621,7 @@ keyword: | ISSUER_SYM {} | INNOBASE_SYM {} | INSERT_METHOD {} - | IO_THREAD {} + | IO_THREAD {} | LAST_SYM {} | LEVEL_SYM {} | LOCAL_SYM {} @@ -3216,9 +3636,9 @@ keyword: | MASTER_USER_SYM {} | MASTER_PASSWORD_SYM {} | MASTER_CONNECT_RETRY_SYM {} - | MAX_CONNECTIONS_PER_HOUR {} - | MAX_QUERIES_PER_HOUR {} - | MAX_UPDATES_PER_HOUR {} + | MAX_CONNECTIONS_PER_HOUR {} + | MAX_QUERIES_PER_HOUR {} + | MAX_UPDATES_PER_HOUR {} | MEDIUM_SYM {} | MERGE_SYM {} | MINUTE_SYM {} @@ -3236,19 +3656,20 @@ keyword: | OFFSET_SYM {} | OPEN_SYM {} | PACK_KEYS_SYM {} + | PARTIAL {} | PASSWORD {} | PREV_SYM {} | PROCESS {} | PROCESSLIST_SYM {} | QUERY_SYM {} | QUICK {} - | RAID_0_SYM {} + | RAID_0_SYM {} | RAID_CHUNKS {} | RAID_CHUNKSIZE {} - | RAID_STRIPED_SYM {} + | RAID_STRIPED_SYM {} | RAID_TYPE {} - | RELAY_LOG_FILE_SYM {} - | RELAY_LOG_POS_SYM {} + | RELAY_LOG_FILE_SYM {} + | RELAY_LOG_POS_SYM {} | RELOAD {} | REPAIR {} | REPEATABLE_SYM {} @@ -3262,16 +3683,18 @@ keyword: | ROW_FORMAT_SYM {} | ROW_SYM {} | SECOND_SYM {} + | SERIAL_SYM {} | SERIALIZABLE_SYM {} | SESSION_SYM {} | SIGNED_SYM {} + | SIMPLE_SYM {} | SHARE_SYM {} | SHUTDOWN {} - | SLAVE {} + | SLAVE {} | SQL_CACHE_SYM {} | SQL_BUFFER_RESULT {} | SQL_NO_CACHE_SYM {} - | SQL_THREAD {} + | SQL_THREAD {} | START_SYM {} | STATUS_SYM {} | STOP_SYM {} @@ -3289,8 +3712,10 @@ keyword: | UNCOMMITTED_SYM {} | USE_FRM {} | VARIABLES {} + | VALUE_SYM {} | WORK_SYM {} - | YEAR_SYM {}; + | YEAR_SYM {} + ; /* Option functions */ @@ -3321,16 +3746,16 @@ option_type: opt_var_type: /* empty */ { $$=OPT_SESSION; } + | GLOBAL_SYM { $$=OPT_GLOBAL; } | LOCAL_SYM { $$=OPT_SESSION; } | SESSION_SYM { $$=OPT_SESSION; } - | GLOBAL_SYM { $$=OPT_GLOBAL; } ; opt_var_ident_type: /* empty */ { $$=OPT_DEFAULT; } + | GLOBAL_SYM '.' { $$=OPT_GLOBAL; } | LOCAL_SYM '.' { $$=OPT_SESSION; } | SESSION_SYM '.' { $$=OPT_SESSION; } - | GLOBAL_SYM '.' { $$=OPT_GLOBAL; } ; option_value: @@ -3386,7 +3811,7 @@ internal_variable_name: YYABORT; $$=tmp; } - ; + ; isolation_types: READ_SYM UNCOMMITTED_SYM { $$= ISO_READ_UNCOMMITTED; } @@ -3394,7 +3819,7 @@ isolation_types: | REPEATABLE_SYM READ_SYM { $$= ISO_REPEATABLE_READ; } | SERIALIZABLE_SYM { $$= ISO_SERIALIZABLE; } ; - + text_or_password: TEXT_STRING { $$=$1.str;} | PASSWORD '(' TEXT_STRING ')' @@ -3407,14 +3832,15 @@ text_or_password: make_scrambled_password(buff,$3.str); $$=buff; } - }; + } + ; set_expr_or_default: expr { $$=$1; } | DEFAULT { $$=0; } - | ON { $$=new Item_string("ON",2); } - | ALL { $$=new Item_string("ALL",3); } + | ON { $$=new Item_string("ON", 2, system_charset_info); } + | ALL { $$=new Item_string("ALL", 3, system_charset_info); } ; @@ -3437,16 +3863,22 @@ table_lock_list: table_lock: table_ident opt_table_alias lock_option - { if (!add_table_to_list($1,$2,0,(thr_lock_type) $3)) YYABORT; }; + { + if (!Select->add_table_to_list($1, $2, 0, (thr_lock_type) $3)) + YYABORT; + } + ; lock_option: READ_SYM { $$=TL_READ_NO_INSERT; } | WRITE_SYM { $$=current_thd->update_lock_default; } | LOW_PRIORITY WRITE_SYM { $$=TL_WRITE_LOW_PRIORITY; } - | READ_SYM LOCAL_SYM { $$= TL_READ; }; + | READ_SYM LOCAL_SYM { $$= TL_READ; } + ; unlock: - UNLOCK_SYM table_or_tables { Lex->sql_command=SQLCOM_UNLOCK_TABLES; }; + UNLOCK_SYM table_or_tables { Lex->sql_command=SQLCOM_UNLOCK_TABLES; } + ; /* @@ -3456,14 +3888,16 @@ unlock: handler: HANDLER_SYM table_ident OPEN_SYM opt_table_alias { - Lex->sql_command = SQLCOM_HA_OPEN; - if (!add_table_to_list($2,$4,0)) + LEX *lex= Lex; + lex->sql_command = SQLCOM_HA_OPEN; + if (!lex->current_select->add_table_to_list($2, $4, 0)) YYABORT; } | HANDLER_SYM table_ident CLOSE_SYM { - Lex->sql_command = SQLCOM_HA_CLOSE; - if (!add_table_to_list($2,0,0)) + LEX *lex= Lex; + lex->sql_command = SQLCOM_HA_CLOSE; + if (!lex->current_select->add_table_to_list($2, 0, 0)) YYABORT; } | HANDLER_SYM table_ident READ_SYM @@ -3471,20 +3905,23 @@ handler: LEX *lex=Lex; lex->sql_command = SQLCOM_HA_READ; lex->ha_rkey_mode= HA_READ_KEY_EXACT; /* Avoid purify warnings */ - lex->select->select_limit= 1; - lex->select->offset_limit= 0L; - if (!add_table_to_list($2,0,0)) + lex->current_select->select_limit= 1; + lex->current_select->offset_limit= 0L; + if (!lex->current_select->add_table_to_list($2, 0, 0)) YYABORT; } - handler_read_or_scan where_clause limit_clause { }; + handler_read_or_scan where_clause limit_clause { } + ; handler_read_or_scan: handler_scan_function { Lex->backup_dir= 0; } - | ident handler_rkey_function { Lex->backup_dir= $1.str; }; + | ident handler_rkey_function { Lex->backup_dir= $1.str; } + ; handler_scan_function: FIRST_SYM { Lex->ha_read_mode = RFIRST; } - | NEXT_SYM { Lex->ha_read_mode = RNEXT; }; + | NEXT_SYM { Lex->ha_read_mode = RNEXT; } + ; handler_rkey_function: FIRST_SYM { Lex->ha_read_mode = RFIRST; } @@ -3498,14 +3935,16 @@ handler_rkey_function: lex->ha_rkey_mode=$1; if (!(lex->insert_list = new List_item)) YYABORT; - } '(' values ')' { }; + } '(' values ')' { } + ; handler_rkey_mode: EQ { $$=HA_READ_KEY_EXACT; } | GE { $$=HA_READ_KEY_OR_NEXT; } | LE { $$=HA_READ_KEY_OR_PREV; } | GT_SYM { $$=HA_READ_AFTER_KEY; } - | LT { $$=HA_READ_BEFORE_KEY; }; + | LT { $$=HA_READ_BEFORE_KEY; } + ; /* GRANT / REVOKE */ @@ -3517,7 +3956,7 @@ revoke: lex->users_list.empty(); lex->columns.empty(); lex->grant= lex->grant_tot_col=0; - lex->select->db=0; + lex->select_lex.db=0; lex->ssl_type= SSL_TYPE_NOT_SPECIFIED; lex->ssl_cipher= lex->x509_subject= lex->x509_issuer= 0; bzero((char*) &lex->mqh, sizeof(lex->mqh)); @@ -3532,7 +3971,7 @@ grant: lex->columns.empty(); lex->sql_command = SQLCOM_GRANT; lex->grant= lex->grant_tot_col= 0; - lex->select->db= 0; + lex->select_lex.db= 0; lex->ssl_type= SSL_TYPE_NOT_SPECIFIED; lex->ssl_cipher= lex->x509_subject= lex->x509_issuer= 0; bzero(&(lex->mqh),sizeof(lex->mqh)); @@ -3543,7 +3982,8 @@ grant: grant_privileges: grant_privilege_list {} | ALL PRIVILEGES { Lex->grant = GLOBAL_ACLS;} - | ALL { Lex->grant = GLOBAL_ACLS;}; + | ALL { Lex->grant = GLOBAL_ACLS;} + ; grant_privilege_list: grant_privilege @@ -3591,7 +4031,7 @@ require_list_element: LEX *lex=Lex; if (lex->x509_subject) { - net_printf(&lex->thd->net,ER_DUP_ARGUMENT, "SUBJECT"); + net_printf(lex->thd,ER_DUP_ARGUMENT, "SUBJECT"); YYABORT; } lex->x509_subject=$2.str; @@ -3601,7 +4041,7 @@ require_list_element: LEX *lex=Lex; if (lex->x509_issuer) { - net_printf(&lex->thd->net,ER_DUP_ARGUMENT, "ISSUER"); + net_printf(lex->thd,ER_DUP_ARGUMENT, "ISSUER"); YYABORT; } lex->x509_issuer=$2.str; @@ -3611,7 +4051,7 @@ require_list_element: LEX *lex=Lex; if (lex->ssl_cipher) { - net_printf(&lex->thd->net,ER_DUP_ARGUMENT, "CIPHER"); + net_printf(lex->thd,ER_DUP_ARGUMENT, "CIPHER"); YYABORT; } lex->ssl_cipher=$2.str; @@ -3621,48 +4061,49 @@ require_list_element: opt_table: '*' { - LEX *lex=Lex; - lex->select->db=lex->thd->db; + LEX *lex= Lex; + lex->current_select->select_lex()->db= lex->thd->db; if (lex->grant == GLOBAL_ACLS) lex->grant = DB_ACLS & ~GRANT_ACL; else if (lex->columns.elements) { - send_error(&lex->thd->net,ER_ILLEGAL_GRANT_FOR_TABLE); + send_error(lex->thd,ER_ILLEGAL_GRANT_FOR_TABLE); YYABORT; } } | ident '.' '*' { - LEX *lex=Lex; - lex->select->db = $1.str; + LEX *lex= Lex; + lex->current_select->select_lex()->db = $1.str; if (lex->grant == GLOBAL_ACLS) lex->grant = DB_ACLS & ~GRANT_ACL; else if (lex->columns.elements) { - send_error(&lex->thd->net,ER_ILLEGAL_GRANT_FOR_TABLE); + send_error(lex->thd,ER_ILLEGAL_GRANT_FOR_TABLE); YYABORT; } } | '*' '.' '*' { - LEX *lex=Lex; - lex->select->db = NULL; + LEX *lex= Lex; + lex->current_select->select_lex()->db = NULL; if (lex->grant == GLOBAL_ACLS) lex->grant= GLOBAL_ACLS & ~GRANT_ACL; else if (lex->columns.elements) { - send_error(&lex->thd->net,ER_ILLEGAL_GRANT_FOR_TABLE); + send_error(lex->thd,ER_ILLEGAL_GRANT_FOR_TABLE); YYABORT; } } | table_ident { LEX *lex=Lex; - if (!add_table_to_list($1,NULL,0)) + if (!lex->current_select->add_table_to_list($1,NULL,0)) YYABORT; if (lex->grant == GLOBAL_ACLS) lex->grant = TABLE_ACLS & ~GRANT_ACL; - }; + } + ; user_list: @@ -3693,7 +4134,8 @@ grant_user: | user IDENTIFIED_SYM BY PASSWORD TEXT_STRING { $$=$1; $1->password=$5 ; } | user - { $$=$1; $1->password.str=NullS; }; + { $$=$1; $1->password.str=NullS; } + ; opt_column_list: @@ -3711,13 +4153,14 @@ column_list: column_list_id: ident { - String *new_str = new String((const char*) $1.str,$1.length); + String *new_str = new String((const char*) $1.str,$1.length,default_charset_info); List_iterator <LEX_COLUMN> iter(Lex->columns); class LEX_COLUMN *point; 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; @@ -3725,7 +4168,8 @@ column_list_id: point->rights |= lex->which_columns; else lex->columns.push_back(new LEX_COLUMN (*new_str,lex->which_columns)); - }; + } + ; require_clause: /* empty */ @@ -3745,7 +4189,7 @@ require_clause: /* empty */ { Lex->ssl_type=SSL_TYPE_NONE; } - ; + ; grant_options: /* empty */ {} @@ -3753,7 +4197,8 @@ grant_options: grant_option_list: grant_option_list grant_option {} - | grant_option {}; + | grant_option {} + ; grant_option: GRANT OPTION { Lex->grant |= GRANT_ACL;} @@ -3771,14 +4216,16 @@ grant_option: { Lex->mqh.connections=$2; Lex->mqh.bits |= 4; - }; + } + ; begin: BEGIN_SYM { Lex->sql_command = SQLCOM_BEGIN;} opt_work; opt_work: /* empty */ {} - | WORK_SYM {;}; + | WORK_SYM {;} + ; commit: COMMIT_SYM { Lex->sql_command = SQLCOM_COMMIT;}; @@ -3788,7 +4235,7 @@ rollback: /* -** UNIONS : glue selects together + UNIONS : glue selects together */ @@ -3797,24 +4244,24 @@ opt_union: | union_list; union_list: - UNION_SYM union_option + UNION_SYM union_option { LEX *lex=Lex; if (lex->exchange) { /* Only the last SELECT can have INTO...... */ - net_printf(&lex->thd->net, ER_WRONG_USAGE,"UNION","INTO"); + net_printf(lex->thd, ER_WRONG_USAGE, "UNION", "INTO"); YYABORT; - } - if (lex->select->linkage == NOT_A_SELECT) + } + if (lex->current_select->linkage == GLOBAL_OPTIONS_TYPE) { - send_error(&lex->thd->net, ER_SYNTAX_ERROR); + send_error(lex->thd, ER_SYNTAX_ERROR); YYABORT; } - if (mysql_new_select(lex)) + if (mysql_new_select(lex, 0)) YYABORT; - lex->select->linkage=UNION_TYPE; - } + lex->current_select->linkage=UNION_TYPE; + } select_init ; @@ -3829,22 +4276,66 @@ optional_order_or_limit: when neither ORDER BY nor LIMIT are used */ {} | { - LEX *lex=Lex; - if (!lex->select->braces) + LEX *lex=Lex; + if (!lex->current_select->linkage == GLOBAL_OPTIONS_TYPE) { - send_error(&lex->thd->net, ER_SYNTAX_ERROR); + send_error(lex->thd, ER_SYNTAX_ERROR); YYABORT; } - if (mysql_new_select(lex)) - YYABORT; - mysql_init_select(lex); - lex->select->linkage=NOT_A_SELECT; - lex->select->select_limit=lex->thd->variables.select_limit; + SELECT_LEX *sel= lex->current_select->select_lex(); + sel->master_unit()->global_parameters= + sel->master_unit(); + lex->current_select= sel->master_unit(); + lex->current_select->select_limit= + lex->thd->variables.select_limit; } - opt_order_clause limit_clause + opt_order_clause limit_clause ; union_option: /* empty */ {} - | ALL { Lex->union_option=1; } - ; + | ALL {Select->master_unit()->union_option= 1;}; + +singleval_subselect: + subselect_start singleval_subselect_init + subselect_end + { + $$= $2; + }; + +singleval_subselect_init: + select_init + { + $$= new Item_singleval_subselect(current_thd, + Lex->current_select->master_unit()-> + first_select()); + }; + +exists_subselect: + subselect_start exists_subselect_init + subselect_end + { + $$= $2; + }; + +exists_subselect_init: + select_init + { + $$= new Item_exists_subselect(current_thd, + Lex->current_select->master_unit()-> + first_select()); + }; + +subselect_start: + '(' + { + if (mysql_new_select(Lex, 1)) + YYABORT; + }; + +subselect_end: + ')' + { + LEX *lex=Lex; + lex->current_select = lex->current_select->outer_select(); + }; diff --git a/sql/structs.h b/sql/structs.h index bd058a08e46..7873de4db63 100644 --- a/sql/structs.h +++ b/sql/structs.h @@ -148,14 +148,19 @@ enum SHOW_TYPE }; enum SHOW_COMP_OPTION { SHOW_OPTION_YES, SHOW_OPTION_NO, SHOW_OPTION_DISABLED}; + +extern const char *show_comp_option_name[]; + typedef int *(*update_var)(THD *, struct show_var_st *); + typedef struct show_var_st { const char *name; char *value; SHOW_TYPE type; } SHOW_VAR; + typedef struct lex_string { char *str; uint length; diff --git a/sql/table.cc b/sql/table.cc index 62163819599..84a072c886d 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -49,7 +49,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, interval_count,interval_parts,read_length,db_create_options; uint key_info_length, com_length; ulong pos; - char index_file[FN_REFLEN], *names, *keynames; + char index_file[FN_REFLEN], *names, *keynames, *comment_pos; uchar head[288],*disk_buff,new_field_pack_flag; my_string record; const char **int_array; @@ -117,6 +117,8 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, outparam->raid_type= head[41]; outparam->raid_chunks= head[42]; outparam->raid_chunksize= uint4korr(head+43); + if (!(outparam->table_charset=get_charset((uint) head[38],MYF(0)))) + outparam->table_charset=NULL; // QQ display error message? null_field_first=1; } outparam->db_record_offset=1; @@ -279,7 +281,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, outparam->comment=strdup_root(&outparam->mem_root, (char*) head+47); - DBUG_PRINT("info",("i_count: %d i_parts: %d index: %d n_length: %d int_length: %d", interval_count,interval_parts, outparam->keys,n_length,int_length)); + DBUG_PRINT("info",("i_count: %d i_parts: %d index: %d n_length: %d int_length: %d com_length: %d", interval_count,interval_parts, outparam->keys,n_length,int_length, com_length)); if (!(field_ptr = (Field **) alloc_root(&outparam->mem_root, @@ -310,6 +312,8 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, outparam->intervals=0; // For better debugging memcpy((char*) names, strpos+(outparam->fields*field_pack_length), (uint) (n_length+int_length)); + comment_pos=names+(n_length+int_length); + memcpy(comment_pos, disk_buff+read_length-com_length, com_length); fix_type_pointers(&int_array,&outparam->fieldnames,1,&names); fix_type_pointers(&int_array,outparam->intervals,interval_count, @@ -337,6 +341,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); @@ -346,35 +351,55 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, uint pack_flag= uint2korr(strpos+6); uint interval_nr= (uint) strpos[10]; enum_field_types field_type; + CHARSET_INFO *charset=NULL; + LEX_STRING comment; if (new_frm_ver == 2) { /* new frm file in 4.1 */ + uint comment_length=uint2korr(strpos+13); field_type=(enum_field_types) (uint) strpos[11]; + if (!(charset=get_charset((uint) strpos[12], MYF(0)))) + charset=outparam->table_charset?outparam->table_charset:default_charset_info; + if (!comment_length) + { + comment.str= (char*) ""; + comment.length=0; + } + else + { + comment.str= (char*) comment_pos; + comment.length= comment_length; + comment_pos+= comment_length; + } } else { /* old frm file */ field_type= (enum_field_types) f_packtype(pack_flag); + charset=outparam->table_charset?outparam->table_charset:default_charset_info; + bzero((char*) &comment, sizeof(comment)); } - *field_ptr=reg_field= make_field(record+uint2korr(strpos+4), (uint32) strpos[3], // field_length null_pos,null_bit, pack_flag, field_type, + charset, (Field::utype) MTYP_TYPENR((uint) strpos[8]), (interval_nr ? outparam->intervals+interval_nr-1 : (TYPELIB*) 0), outparam->fieldnames.type_names[i], outparam); - if (!*field_ptr) // Field in 4.1 + if (!reg_field) // Not supported field type { error= 4; goto err_not_open; /* purecov: inspected */ } + reg_field->comment=comment; + reg_field->set_charset(charset); if (!(reg_field->flags & NOT_NULL_FLAG)) { if ((null_bit<<=1) == 256) @@ -472,13 +497,13 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag, keyinfo->key_length ? UNIQUE_KEY_FLAG : MULTIPLE_KEY_FLAG); if (i == 0) field->key_start|= ((key_map) 1 << key); - if ((index_flags & HA_KEY_READ_ONLY) && - field->key_length() == key_part->length && + if (field->key_length() == key_part->length && field->type() != FIELD_TYPE_BLOB) { - if (field->key_type() != HA_KEYTYPE_TEXT || - (!(ha_option & HA_KEY_READ_WRONG_STR) && - !(keyinfo->flags & HA_FULLTEXT))) + if ((index_flags & HA_KEY_READ_ONLY) && + (field->key_type() != HA_KEYTYPE_TEXT || + (!(ha_option & HA_KEY_READ_WRONG_STR) && + !(keyinfo->flags & HA_FULLTEXT)))) field->part_of_key|= ((key_map) 1 << key); if ((field->key_type() != HA_KEYTYPE_TEXT || !(keyinfo->flags & HA_FULLTEXT)) && @@ -968,9 +993,14 @@ ulong next_io_size(register ulong pos) } /* next_io_size */ -void append_unescaped(String *res,const char *pos) + /* Store in String an SQL quoted string */ + +void append_unescaped(String *res,const char *pos, uint length) { - for (; *pos ; pos++) + const char *end= pos+length; + res->append('\''); + + for (; pos != end ; pos++) { switch (*pos) { case 0: /* Must be escaped for 'mysql' */ @@ -998,6 +1028,7 @@ void append_unescaped(String *res,const char *pos) break; } } + res->append('\''); } /* Create a .frm file */ @@ -1021,7 +1052,7 @@ File create_frm(register my_string name, uint reclength, uchar *fileinfo, if ((file=my_create(name,CREATE_MODE,O_RDWR | O_TRUNC,MYF(MY_WME))) >= 0) { bzero((char*) fileinfo,64); - fileinfo[0]=(uchar) 254; fileinfo[1]= 1; fileinfo[2]= FRM_VER+1; // Header + fileinfo[0]=(uchar) 254; fileinfo[1]= 1; fileinfo[2]= FRM_VER+2; // Header fileinfo[3]= (uchar) ha_checktype(create_info->db_type); fileinfo[4]=1; int2store(fileinfo+6,IO_SIZE); /* Next block starts here */ @@ -1037,6 +1068,7 @@ File create_frm(register my_string name, uint reclength, uchar *fileinfo, int2store(fileinfo+30,create_info->table_options); fileinfo[32]=0; // No filename anymore int4store(fileinfo+34,create_info->avg_row_length); + fileinfo[38]= create_info->table_charset?create_info->table_charset->number:0; fileinfo[40]= (uchar) create_info->row_type; fileinfo[41]= (uchar) create_info->raid_type; fileinfo[42]= (uchar) create_info->raid_chunks; @@ -1067,6 +1099,7 @@ void update_create_info_from_table(HA_CREATE_INFO *create_info, TABLE *table) create_info->raid_type=table->raid_type; create_info->raid_chunks=table->raid_chunks; create_info->raid_chunksize=table->raid_chunksize; + create_info->table_charset=table->table_charset; DBUG_VOID_RETURN; } @@ -1089,7 +1122,7 @@ char *get_field(MEM_ROOT *mem, TABLE *table, uint fieldnr) { Field *field=table->field[fieldnr]; char buff[MAX_FIELD_WIDTH]; - String str(buff,sizeof(buff)); + String str(buff,sizeof(buff),default_charset_info); field->val_str(&str,&str); uint length=str.length(); if (!length) @@ -1106,9 +1139,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; @@ -1121,7 +1155,7 @@ bool check_db_name(const char *name) return 1; name++; } - return (uint) (name - start) > NAME_LEN; + return (uint) (name - start) > NAME_LEN || name == start; } @@ -1139,9 +1173,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; @@ -1161,9 +1195,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; @@ -1195,7 +1230,7 @@ db_type get_table_type(const char *name) error=my_read(file,(byte*) head,4,MYF(MY_NABP)); my_close(file,MYF(0)); if (error || head[0] != (uchar) 254 || head[1] != 1 || - (head[2] != FRM_VER && head[2] != FRM_VER+1)) + (head[2] < FRM_VER && head[2] > FRM_VER+2)) DBUG_RETURN(DB_TYPE_UNKNOWN); DBUG_RETURN(ha_checktype((enum db_type) (uint) *(head+3))); } diff --git a/sql/table.h b/sql/table.h index f998a0fd4e6..18079e183ce 100644 --- a/sql/table.h +++ b/sql/table.h @@ -106,6 +106,7 @@ struct st_table { *rowid_field; Field_timestamp *timestamp_field; my_string comment; /* Comment about table */ + CHARSET_INFO *table_charset; /* Default charset of string fields */ REGINFO reginfo; /* field connections */ MEM_ROOT mem_root; GRANT_INFO grant; @@ -128,6 +129,9 @@ struct st_table { uint temp_pool_slot; + /* number of select if it is derived table */ + uint derived_select_number; + THD *in_use; /* Which thread uses this */ struct st_table *next,*prev; }; @@ -143,9 +147,18 @@ typedef struct st_table_list Item *on_expr; /* Used with outer join */ struct st_table_list *natural_join; /* natural join on this table*/ /* ... join ... USE INDEX ... IGNORE INDEX */ - List<String> *use_index,*ignore_index; - TABLE *table; - GRANT_INFO grant; + List<String> *use_index, *ignore_index; + /* + Usually hold reference on opened table, but may hold reference + to node of complete list of tables used in UNION & subselect. + */ + union + { + TABLE *table; /* opened table */ + st_table_list *table_list; /* pointer to node of list of all tables */ + }; + void *derived; /* SELECT_LEX_UNIT of derived table */ + GRANT_INFO grant; thr_lock_type lock_type; uint outer_join; /* Which join type */ uint32 db_length, real_name_length; @@ -155,7 +168,6 @@ typedef struct st_table_list bool do_redirect; /* To get the struct in UNION's */ } TABLE_LIST; - typedef struct st_changed_table_list { struct st_changed_table_list *next; @@ -163,7 +175,6 @@ typedef struct st_changed_table_list uint32 key_length; } CHANGED_TABLE_LIST; - typedef struct st_open_table_list { struct st_open_table_list *next; diff --git a/sql/time.cc b/sql/time.cc index 4fe79966404..0811b896bfc 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])); @@ -417,13 +418,28 @@ ulong convert_month_to_period(ulong month) } -/***************************************************************************** -** convert a timestamp string to a TIME value. -** At least the following formats are recogniced (based on number of digits) -** YYMMDD, YYYYMMDD, YYMMDDHHMMSS, YYYYMMDDHHMMSS -** YY-MM-DD, YYYY-MM-DD, YY-MM-DD HH.MM.SS -** Returns the type of string -*****************************************************************************/ +/* + Convert a timestamp string to a TIME value. + + SYNOPSIS + str_to_TIME() + str String to parse + length Length of string + l_time Date is stored here + fuzzy_date 1 if we should allow dates where one part is zero + + DESCRIPTION + At least the following formats are recogniced (based on number of digits) + YYMMDD, YYYYMMDD, YYMMDDHHMMSS, YYYYMMDDHHMMSS + YY-MM-DD, YYYY-MM-DD, YY-MM-DD HH.MM.SS + YYYYMMDDTHHMMSS where T is a the character T (ISO8601) + Also dates where all parts are zero are allowed + + RETURN VALUES + TIMESTAMP_NONE String wasn't a timestamp + TIMESTAMP_DATE DATE string (YY MM and DD parts ok) + TIMESTAMP_FULL Full timestamp +*/ timestamp_type str_to_TIME(const char *str, uint length, TIME *l_time,bool fuzzy_date) @@ -435,23 +451,25 @@ 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); /* - ** calculate first number of digits. - ** If length= 8 or >= 14 then year is of format YYYY. - (YYYY-MM-DD, YYYYMMDD, YYYYYMMDDHHMMSS) + calculate first number of digits. + 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; not_zero_date= 0; - 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++; @@ -462,10 +480,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++; } @@ -473,12 +493,14 @@ 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; not_zero_date|= tmp_value; @@ -500,7 +522,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)) { not_zero_date= 1; // Give warning break; @@ -515,7 +537,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; @@ -576,7 +598,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 == '-') { @@ -595,7 +618,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 == ' ') @@ -606,14 +629,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; @@ -635,10 +660,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 ':' } @@ -658,11 +684,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; } @@ -687,7 +715,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; diff --git a/sql/uniques.cc b/sql/uniques.cc index 60905567ba0..ed256a4b791 100644 --- a/sql/uniques.cc +++ b/sql/uniques.cc @@ -53,7 +53,8 @@ Unique::Unique(qsort_cmp2 comp_func, void * comp_func_fixed_arg, :max_in_memory_size(max_in_memory_size_arg),elements(0) { my_b_clear(&file); - init_tree(&tree, max_in_memory_size / 16, 0, size, comp_func, 0, NULL, comp_func_fixed_arg); + init_tree(&tree, max_in_memory_size / 16, 0, size, comp_func, 0, NULL, + comp_func_fixed_arg); /* If the following fail's the next add will also fail */ my_init_dynamic_array(&file_ptrs, sizeof(BUFFPEK), 16, 16); max_elements= max_in_memory_size / ALIGN_SIZE(sizeof(TREE_ELEMENT)+size); diff --git a/sql/unireg.cc b/sql/unireg.cc index cc8440da1e4..81310c4a863 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -28,7 +28,7 @@ #include "mysql_priv.h" #include <m_ctype.h> -#define FCOMP 11 /* Byte per packat f{lt */ +#define FCOMP 15 /* Bytes for a packed field */ static uchar * pack_screens(List<create_field> &create_fields, uint *info_length, uint *screens, bool small_file); @@ -46,7 +46,7 @@ static bool make_empty_rec(int file, enum db_type table_type, uint reclength,uint null_fields); -int rea_create_table(my_string file_name, +int rea_create_table(THD *thd, my_string file_name, HA_CREATE_INFO *create_info, List<create_field> &create_fields, uint keys, KEY *key_info) @@ -67,13 +67,12 @@ int rea_create_table(my_string file_name, if (pack_header(forminfo, create_info->db_type,create_fields,info_length, screens, create_info->table_options, db_file)) { - NET *net=my_pthread_getspecific_ptr(NET*,THR_NET); my_free((gptr) screen_buff,MYF(0)); - if (net->last_errno != ER_TOO_MANY_FIELDS) + if (thd->net.last_errno != ER_TOO_MANY_FIELDS) DBUG_RETURN(1); // Try again without UNIREG screens (to get more columns) - net->last_error[0]=0; + thd->net.last_error[0]=0; if (!(screen_buff=pack_screens(create_fields,&info_length,&screens,1))) DBUG_RETURN(1); if (pack_header(forminfo, create_info->db_type, create_fields,info_length, @@ -246,7 +245,7 @@ static uchar * pack_screens(List<create_field> &create_fields, static uint pack_keys(uchar *keybuff,uint key_count,KEY *keyinfo) { uint key_parts,length; - uchar *pos, *keyname_pos, *key_alg_pos; + uchar *pos, *keyname_pos; KEY *key,*end; KEY_PART_INFO *key_part,*key_part_end; DBUG_ENTER("pack_keys"); @@ -255,10 +254,12 @@ static uint pack_keys(uchar *keybuff,uint key_count,KEY *keyinfo) key_parts=0; for (key=keyinfo,end=keyinfo+key_count ; key != end ; key++) { - pos[0]=(uchar) (key->flags ^ HA_NOSAME); - int2store(pos+1,key->key_length); - pos[3]=key->key_parts; - pos+=4; + int2store(pos, (key->flags ^ HA_NOSAME)); + int2store(pos+2,key->key_length); + pos[4]= (uchar) key->key_parts; + pos[5]= (uchar) key->algorithm; + pos[6]=pos[7]=0; // For the future + pos+=8; key_parts+=key->key_parts; DBUG_PRINT("loop",("flags: %d key_parts: %d at %lx", key->flags,key->key_parts, @@ -290,18 +291,11 @@ static uint pack_keys(uchar *keybuff,uint key_count,KEY *keyinfo) } *(pos++)=0; - /* For MySQL 4.0; Store key algoritms last */ - key_alg_pos= pos; - for (key=keyinfo ; key != end ; key++) - { - *(pos++)= (uchar) key->algorithm; - } - keybuff[0]=(uchar) key_count; keybuff[1]=(uchar) key_parts; length=(uint) (keyname_pos-keybuff); int2store(keybuff+2,length); - length=(uint) (key_alg_pos-keyname_pos); + length=(uint) (pos-keyname_pos); int2store(keybuff+4,length); DBUG_RETURN((uint) (pos-keybuff)); } /* pack_keys */ @@ -314,9 +308,9 @@ static bool pack_header(uchar *forminfo, enum db_type table_type, uint info_length, uint screens,uint table_options, handler *file) { - uint length,int_count,int_length,no_empty, int_parts, - time_stamp_pos,null_fields; - ulong reclength,totlength,n_length; + uint length,int_count,int_length,no_empty, int_parts; + uint time_stamp_pos,null_fields; + ulong reclength, totlength, n_length, com_length; DBUG_ENTER("pack_header"); if (create_fields.elements > MAX_FIELDS) @@ -326,7 +320,8 @@ static bool pack_header(uchar *forminfo, enum db_type table_type, } totlength=reclength=0L; - no_empty=int_count=int_parts=int_length=time_stamp_pos=null_fields=0; + no_empty=int_count=int_parts=int_length=time_stamp_pos=null_fields= + com_length=0; n_length=2L; /* Check fields */ @@ -336,6 +331,7 @@ static bool pack_header(uchar *forminfo, enum db_type table_type, while ((field=it++)) { totlength+= field->length; + com_length+= field->comment.length; if (MTYP_TYPENR(field->unireg_check) == Field::NOEMPTY || field->unireg_check & MTYP_NOEMPTY_BIT) { @@ -378,14 +374,15 @@ static bool pack_header(uchar *forminfo, enum db_type table_type, /* Hack to avoid bugs with small static rows in MySQL */ reclength=max(file->min_record_length(table_options),reclength); if (info_length+(ulong) create_fields.elements*FCOMP+288+ - n_length+int_length > 65535L || int_count > 255) + n_length+int_length+com_length > 65535L || int_count > 255) { my_error(ER_TOO_MANY_FIELDS,MYF(0)); DBUG_RETURN(1); } bzero((char*)forminfo,288); - length=info_length+create_fields.elements*FCOMP+288+n_length+int_length; + length=(info_length+create_fields.elements*FCOMP+288+n_length+int_length+ + com_length); int2store(forminfo,length); forminfo[256] = (uint8) screens; int2store(forminfo+258,create_fields.elements); @@ -401,6 +398,7 @@ static bool pack_header(uchar *forminfo, enum db_type table_type, int2store(forminfo+278,80); /* Columns needed */ int2store(forminfo+280,22); /* Rows needed */ int2store(forminfo+282,null_fields); + int2store(forminfo+284,com_length); DBUG_RETURN(0); } /* pack_header */ @@ -438,7 +436,7 @@ static uint get_interval_id(uint *int_count,List<create_field> &create_fields, static bool pack_fields(File file,List<create_field> &create_fields) { reg2 uint i; - uint int_count; + uint int_count, comment_length=0; uchar buff[MAX_FIELD_WIDTH]; create_field *field; DBUG_ENTER("pack_fields"); @@ -459,6 +457,10 @@ static bool pack_fields(File file,List<create_field> &create_fields) int2store(buff+6,field->pack_flag); int2store(buff+8,field->unireg_check); buff[10]= (uchar) field->interval_id; + buff[11]= (uchar) field->sql_type; + buff[12]= (uchar) field->charset->number; + int2store(buff+13, field->comment.length); + comment_length+= field->comment.length; set_if_bigger(int_count,field->interval_id); if (my_write(file,(byte*) buff,FCOMP,MYF_RW)) DBUG_RETURN(1); @@ -484,7 +486,7 @@ static bool pack_fields(File file,List<create_field> &create_fields) /* Write intervals */ if (int_count) { - String tmp((char*) buff,sizeof(buff)); + String tmp((char*) buff,sizeof(buff), default_charset_info); tmp.length(0); it.rewind(); int_count=0; @@ -505,6 +507,18 @@ static bool pack_fields(File file,List<create_field> &create_fields) if (my_write(file,(byte*) tmp.ptr(),tmp.length(),MYF_RW)) DBUG_RETURN(1); } + if (comment_length) + { + it.rewind(); + int_count=0; + while ((field=it++)) + { + if (field->comment.length) + if (my_write(file, (byte*) field->comment.str, field->comment.length, + MYF_RW)) + DBUG_RETURN(1); + } + } DBUG_RETURN(0); } @@ -558,10 +572,12 @@ static bool make_empty_rec(File file,enum db_type table_type, 1 << (null_count & 7), field->pack_flag, field->sql_type, + field->charset, field->unireg_check, field->interval, field->field_name, &table); + if (!(field->flags & NOT_NULL_FLAG)) null_count++; @@ -574,7 +590,7 @@ static bool make_empty_rec(File file,enum db_type table_type, if (field->def && (regfield->real_type() != FIELD_TYPE_YEAR || field->def->val_int() != 0)) - field->def->save_in_field(regfield); + (void) field->def->save_in_field(regfield); else if (regfield->real_type() == FIELD_TYPE_ENUM && (field->flags & NOT_NULL_FLAG)) { @@ -582,9 +598,9 @@ static bool make_empty_rec(File file,enum db_type table_type, regfield->store((longlong) 1); } else if (type == Field::YES) // Old unireg type - regfield->store(ER(ER_YES),(uint) strlen(ER(ER_YES))); + regfield->store(ER(ER_YES),(uint) strlen(ER(ER_YES)),default_charset_info); else if (type == Field::NO) // Old unireg type - regfield->store(ER(ER_NO), (uint) strlen(ER(ER_NO))); + regfield->store(ER(ER_NO), (uint) strlen(ER(ER_NO)),default_charset_info); else regfield->reset(); delete regfield; diff --git a/sql/unireg.h b/sql/unireg.h index eec89fcee0f..724ff3f6197 100644 --- a/sql/unireg.h +++ b/sql/unireg.h @@ -63,6 +63,8 @@ #define MAX_SORT_MEMORY (2048*1024-MALLOC_OVERHEAD) #define MIN_SORT_MEMORY (32*1024-MALLOC_OVERHEAD) +#define DEFAULT_ERROR_COUNT 64 +#define DEFAULT_PREP_STMT_COUNT 64 #define EXTRA_RECORDS 10 /* Extra records in sort */ #define SCROLL_EXTRA 5 /* Extra scroll-rows. */ #define FIELD_NAME_USED ((uint) 32768) /* Bit set if fieldname used */ |