diff options
Diffstat (limited to 'sql')
-rw-r--r-- | sql/field.cc | 32 | ||||
-rw-r--r-- | sql/field.h | 9 | ||||
-rw-r--r-- | sql/item.cc | 2 | ||||
-rw-r--r-- | sql/item_func.cc | 4 | ||||
-rw-r--r-- | sql/item_strfunc.cc | 40 | ||||
-rw-r--r-- | sql/item_strfunc.h | 14 | ||||
-rw-r--r-- | sql/protocol.cc | 9 | ||||
-rw-r--r-- | sql/set_var.cc | 1 | ||||
-rw-r--r-- | sql/sql_class.h | 2 | ||||
-rw-r--r-- | sql/sql_lex.cc | 59 | ||||
-rw-r--r-- | sql/sql_parse.cc | 31 | ||||
-rw-r--r-- | sql/sql_prepare.cc | 10 | ||||
-rw-r--r-- | sql/sql_string.cc | 1 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 2 |
14 files changed, 105 insertions, 111 deletions
diff --git a/sql/field.cc b/sql/field.cc index cce7446dcff..d26534b5ac7 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -4485,19 +4485,9 @@ void Field_blob::store_length(uint32 number) { switch (packlength) { case 1: - if (number > 255) - { - number=255; - set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED); - } ptr[0]= (uchar) number; break; case 2: - if (number > (uint16) ~0) - { - number= (uint16) ~0; - set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED); - } #ifdef WORDS_BIGENDIAN if (table->db_low_byte_first) { @@ -4508,11 +4498,6 @@ void Field_blob::store_length(uint32 number) shortstore(ptr,(unsigned short) number); break; case 3: - if (number > (uint32) (1L << 24)) - { - number= (uint32) (1L << 24)-1L; - set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED); - } int3store(ptr,number); break; case 4: @@ -4573,6 +4558,7 @@ int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs) bool was_conversion; char buff[80]; String tmpstr(buff,sizeof(buff), &my_charset_bin); + uint copy_length; uint32 not_used; /* Convert character set if nesessary */ @@ -4583,12 +4569,22 @@ int Field_blob::store(const char *from,uint length,CHARSET_INFO *cs) from= tmpstr.ptr(); length= tmpstr.length(); } - Field_blob::store_length(length); - if (was_conversion || table->copy_blobs || length <= MAX_FIELD_WIDTH) + + copy_length= max_data_length(); + if (copy_length > length) + copy_length= length; + copy_length= field_charset->cset->wellformedlen(field_charset, + from,from+copy_length, + field_length); + if (copy_length < length) + set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED); + + Field_blob::store_length(copy_length); + if (was_conversion || table->copy_blobs || copy_length <= MAX_FIELD_WIDTH) { // Must make a copy if (from != value.ptr()) // For valgrind { - value.copy(from,length,charset()); + value.copy(from,copy_length,charset()); from=value.ptr(); } } diff --git a/sql/field.h b/sql/field.h index 9a12fd48e54..b62b7a7859e 100644 --- a/sql/field.h +++ b/sql/field.h @@ -949,6 +949,15 @@ public: void sort_string(char *buff,uint length); uint32 pack_length() const { return (uint32) (packlength+table->blob_ptr_size); } + uint32 max_data_length() const + { + switch (packlength) { + case 1: return 255; + case 2: return (uint32) 0xFFFFL; + case 3: return (uint32) 0xFFFFFF; + default: return (uint32) 0xFFFFFFFF; + } + } void reset(void) { bzero(ptr, packlength+sizeof(char*)); } void reset_fields() { bzero((char*) &value,sizeof(value)); } void store_length(uint32 number); diff --git a/sql/item.cc b/sql/item.cc index 3b9f49b8c32..1b5518cbd8c 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -568,6 +568,8 @@ void Item_param::set_time(TIME *tm, timestamp_type type) ltime.second_part= tm->second_part; + ltime.neg= tm->neg; + ltime.time_type= type; item_is_time= true; diff --git a/sql/item_func.cc b/sql/item_func.cc index b1378784f92..34a61ba0353 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -1552,7 +1552,7 @@ udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func, if ((error=(uchar) init(&initid, &f_args, thd->net.last_error))) { my_printf_error(ER_CANT_INITIALIZE_UDF,ER(ER_CANT_INITIALIZE_UDF),MYF(0), - u_d->name,thd->net.last_error); + u_d->name.str, thd->net.last_error); free_udf(u_d); DBUG_RETURN(1); } @@ -1565,7 +1565,7 @@ udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func, if (error) { my_printf_error(ER_CANT_INITIALIZE_UDF,ER(ER_CANT_INITIALIZE_UDF),MYF(0), - u_d->name, ER(ER_UNKNOWN_ERROR)); + u_d->name.str, ER(ER_UNKNOWN_ERROR)); DBUG_RETURN(1); } DBUG_RETURN(0); diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index fd1222d5f1a..ed6e44262c7 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -2124,42 +2124,6 @@ void Item_func_conv_charset::print(String *str) str->append(')'); } -String *Item_func_conv_charset3::val_str(String *str) -{ - char cs1[30], cs2[30]; - String to_cs_buff(cs1, sizeof(cs1), default_charset_info); - String from_cs_buff(cs2, sizeof(cs2), default_charset_info); - String *arg= args[0]->val_str(str); - String *to_cs= args[1]->val_str(&to_cs_buff); - String *from_cs= args[2]->val_str(&from_cs_buff); - 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; - } - - if (str_value.copy(arg->ptr(), arg->length(), from_charset, to_charset)) - { - null_value= 1; - return 0; - } - null_value= 0; - return &str_value; -} - - -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); @@ -2226,7 +2190,7 @@ String *Item_func_charset::val_str(String *str) if ((null_value=(args[0]->null_value || !res->charset()))) return 0; str->copy(res->charset()->csname,strlen(res->charset()->csname), - &my_charset_latin1, default_charset()); + &my_charset_latin1, collation.collation); return str; } @@ -2237,7 +2201,7 @@ String *Item_func_collation::val_str(String *str) if ((null_value=(args[0]->null_value || !res->charset()))) return 0; str->copy(res->charset()->name,strlen(res->charset()->name), - &my_charset_latin1, default_charset()); + &my_charset_latin1, collation.collation); return str; } diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index 465300e721e..4832ddbd1b1 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -619,16 +619,6 @@ public: void print(String *str) { print_op(str); } }; -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 "convert"; } -}; - class Item_func_charset :public Item_str_func { public: @@ -637,8 +627,8 @@ public: const char *func_name() const { return "charset"; } void fix_length_and_dec() { - max_length=40; // should be enough collation.set(system_charset_info); + max_length= 64 * collation.collation->mbmaxlen; // should be enough }; }; @@ -650,8 +640,8 @@ public: const char *func_name() const { return "collation"; } void fix_length_and_dec() { - max_length=40; // should be enough collation.set(system_charset_info); + max_length= 64 * collation.collation->mbmaxlen; // should be enough }; }; diff --git a/sql/protocol.cc b/sql/protocol.cc index bef567ad346..40adc9e8961 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -313,6 +313,7 @@ send_ok(THD *thd, ha_rows affected_rows, ulonglong id, const char *message) DBUG_VOID_RETURN; } +static char eof_buff[1]= { (char) 254 }; /* Marker for end of fields */ /* Send eof (= end of result set) to the client @@ -339,12 +340,11 @@ send_ok(THD *thd, ha_rows affected_rows, ulonglong id, const char *message) void 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) { - if (!no_flush && (thd->client_capabilities & CLIENT_PROTOCOL_41)) + if (thd->client_capabilities & CLIENT_PROTOCOL_41) { uchar buff[5]; uint tmp= min(thd->total_warn_count, 65535); @@ -384,9 +384,8 @@ send_eof(THD *thd, bool no_flush) bool send_old_password_request(THD *thd) { - static char buff[1]= { (char) 254 }; NET *net= &thd->net; - return my_net_write(net, buff, 1) || net_flush(net); + return my_net_write(net, eof_buff, 1) || net_flush(net); } #endif /* EMBEDDED_LIBRARY */ @@ -585,7 +584,7 @@ bool Protocol::send_fields(List<Item> *list, uint flag) #endif } - send_eof(thd, 1); + my_net_write(&thd->net, eof_buff, 1); DBUG_RETURN(prepare_for_send(list)); err: diff --git a/sql/set_var.cc b/sql/set_var.cc index ecb85440068..073330e06be 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -695,7 +695,6 @@ struct show_var_st init_vars[]= { {"port", (char*) &mysqld_port, SHOW_INT}, {"protocol_version", (char*) &protocol_version, SHOW_INT}, {sys_preload_buff_size.name, (char*) &sys_preload_buff_size, SHOW_SYS}, - {sys_pseudo_thread_id.name, (char*) &sys_pseudo_thread_id, SHOW_SYS}, {sys_query_alloc_block_size.name, (char*) &sys_query_alloc_block_size, SHOW_SYS}, #ifdef HAVE_QUERY_CACHE diff --git a/sql/sql_class.h b/sql/sql_class.h index bf0d57e40b3..0d75575f6b7 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -591,6 +591,8 @@ public: struct st_mysql_bind *client_params; char *extra_data; ulong extra_length; + char *query_rest; + uint32 query_rest_length; #endif NET net; // client connection descriptor MEM_ROOT warn_root; // For warnings and errors diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 4bc04ddf9ac..f145a232809 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -193,6 +193,13 @@ static LEX_STRING get_token(LEX *lex,uint length) return tmp; } +/* + todo: + There are no dangerous charsets in mysql for function + get_quoted_token yet. But it should be fixed in the + future to operate multichar strings (like ucs2) +*/ + static LEX_STRING get_quoted_token(LEX *lex,uint length, char quote) { LEX_STRING tmp; @@ -667,32 +674,17 @@ int yylex(void *arg, void *yythd) case MY_LEX_USER_VARIABLE_DELIMITER: { - char delim= c; // Used char + uint double_quotes= 0; + char quote_char= c; // Used char lex->tok_start=lex->ptr; // Skip first ` + while ((c=yyGet())) + { #ifdef USE_MB - if (use_mb(cs)) - { - while ((c=yyGet()) && c != delim && c != (uchar) NAMES_SEP_CHAR) - { - if (my_mbcharlen(cs, c) > 1) - { - int l; - if ((l = my_ismbchar(cs, - (const char *)lex->ptr-1, - (const char *)lex->end_of_query)) == 0) - break; - lex->ptr += l-1; - } - } - yylval->lex_str=get_token(lex,yyLength()); - } - else + if (my_mbcharlen(cs, c) == 1) #endif - { - uint double_quotes= 0; - char quote_char= c; - while ((c=yyGet())) { + if (c == (uchar) NAMES_SEP_CHAR) + break; /* Old .frm format can't handle this char */ if (c == quote_char) { if (yyPeek() != quote_char) @@ -701,16 +693,25 @@ int yylex(void *arg, void *yythd) double_quotes++; continue; } - if (c == (uchar) NAMES_SEP_CHAR) - break; } - if (double_quotes) - yylval->lex_str=get_quoted_token(lex,yyLength() - double_quotes, - quote_char); +#ifdef USE_MB else - yylval->lex_str=get_token(lex,yyLength()); + { + int l; + if ((l = my_ismbchar(cs, + (const char *)lex->ptr-1, + (const char *)lex->end_of_query)) == 0) + break; + lex->ptr += l-1; + } +#endif } - if (c == delim) + if (double_quotes) + yylval->lex_str=get_quoted_token(lex,yyLength() - double_quotes, + quote_char); + else + yylval->lex_str=get_token(lex,yyLength()); + if (c == quote_char) yySkip(); // Skip end ` lex->next_state= MY_LEX_START; return(IDENT_QUOTED); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 42ea6039b6c..81d6b80678d 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -48,6 +48,7 @@ extern "C" int gethostname(char *name, int namelen); #endif +char *memdup_mysql(struct st_mysql *mysql, const char*data, int length); 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); @@ -1397,11 +1398,13 @@ bool dispatch_command(enum enum_server_command command, THD *thd, char *packet= thd->lex->found_colon; /* Multiple queries exits, execute them individually + in embedded server - just store them to be executed later */ +#ifndef EMBEDDED_LIBRARY if (thd->lock || thd->open_tables || thd->derived_tables) close_thread_tables(thd); - - ulong length= thd->query_length-(ulong)(thd->lex->found_colon-thd->query); +#endif + ulong length= thd->query_length-(ulong)(packet-thd->query); /* Remove garbage at start of query */ while (my_isspace(thd->charset(), *packet) && length > 0) @@ -1414,7 +1417,13 @@ bool dispatch_command(enum enum_server_command command, THD *thd, VOID(pthread_mutex_lock(&LOCK_thread_count)); thd->query_id= query_id++; VOID(pthread_mutex_unlock(&LOCK_thread_count)); +#ifndef EMBEDDED_LIBRARY mysql_parse(thd, packet, length); +#else + thd->query_rest= (char*)memdup_mysql(thd->mysql, packet, length); + thd->query_rest_length= length; + break; +#endif /*EMBEDDED_LIBRARY*/ } if (!(specialflag & SPECIAL_NO_PRIOR)) @@ -3845,7 +3854,23 @@ mysql_parse(THD *thd, char *inBuf, uint length) if (query_cache_send_result_to_client(thd, inBuf, length) <= 0) { LEX *lex=lex_start(thd, (uchar*) inBuf, length); - if (!yyparse((void *)thd) && ! thd->is_fatal_error) + if (!yyparse((void *)thd) && ! thd->is_fatal_error && + /* + If this is not a multiple query, ensure that it has been + successfully parsed until the last character. This is to prevent + against a wrong (too big) length passed to mysql_real_query(), + mysql_prepare()... which can generate garbage characters at the + end. If the query was initially multiple, found_colon will be false + only when we are in the last query; this last query had already + been end-spaces-stripped by alloc_query() in dispatch_command(); as + end spaces are the only thing we accept at the end of a query, and + they have been stripped already, here we can require that nothing + remains after parsing. + */ + (thd->lex->found_colon || + (char*)(thd->lex->ptr) == (thd->query+thd->query_length+1) || + /* yyerror() will show the garbage chars to the user */ + (yyerror("syntax error"), 0))) { #ifndef NO_EMBEDDED_ACCESS_CHECKS if (mqh_used && thd->user_connect && diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index 2cc90601052..34ccb67cda9 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -926,7 +926,15 @@ bool mysql_stmt_prepare(THD *thd, char *packet, uint packet_length) lex->safe_to_cache_query= 0; lex->param_count= 0; - if (yyparse((void *)thd) || thd->is_fatal_error || send_prepare_results(stmt)) + if (yyparse((void *)thd) || thd->is_fatal_error || + /* + Check for wrong (too big) length passed to mysql_prepare() resulting in + garbage at the end of the query. There is a similar check in mysql_parse(). + */ + (!thd->lex->found_colon && + (char*)(thd->lex->ptr) != (thd->query+thd->query_length+1) && + /* yyerror() will show the garbage chars to the user */ + (yyerror("syntax error"), 1)) || send_prepare_results(stmt)) goto yyparse_err; lex_end(lex); diff --git a/sql/sql_string.cc b/sql/sql_string.cc index cbee67c0a4a..093b85b46b7 100644 --- a/sql/sql_string.cc +++ b/sql/sql_string.cc @@ -24,6 +24,7 @@ #include <my_sys.h> #include <m_string.h> #include <m_ctype.h> +#include <assert.h> #ifdef HAVE_FCONVERT #include <floatingpoint.h> #endif diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 0dbe8981466..bdeaf5a0b86 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -2574,8 +2574,6 @@ simple_expr: } | 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); } | DEFAULT '(' simple_ident ')' { $$= new Item_default_value($3); } | VALUES '(' simple_ident ')' |