diff options
Diffstat (limited to 'sql')
-rw-r--r-- | sql/item.cc | 33 | ||||
-rw-r--r-- | sql/item_cmpfunc.cc | 1 | ||||
-rw-r--r-- | sql/item_subselect.cc | 37 | ||||
-rw-r--r-- | sql/item_subselect.h | 7 | ||||
-rw-r--r-- | sql/item_sum.cc | 30 | ||||
-rw-r--r-- | sql/log_event.h | 8 | ||||
-rw-r--r-- | sql/mysqld.cc | 2 | ||||
-rw-r--r-- | sql/protocol.cc | 18 | ||||
-rw-r--r-- | sql/protocol.h | 1 | ||||
-rw-r--r-- | sql/set_var.cc | 14 | ||||
-rw-r--r-- | sql/slave.cc | 23 | ||||
-rw-r--r-- | sql/sql_class.h | 6 | ||||
-rw-r--r-- | sql/sql_repl.cc | 6 |
13 files changed, 138 insertions, 48 deletions
diff --git a/sql/item.cc b/sql/item.cc index 94f0a24fcc3..45d7856b2c1 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -1761,10 +1761,37 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) Item** res= find_item_in_list(this, thd->lex->current_select->item_list, &counter, REPORT_EXCEPT_NOT_FOUND, ¬_used); - if (res != (Item **)not_found_item && (*res)->type() == Item::FIELD_ITEM) + if (res != (Item **)not_found_item) { - set_field((*((Item_field**)res))->field); - return 0; + if ((*res)->type() == Item::FIELD_ITEM) + { + /* + It's an Item_field referencing another Item_field in the select + list. + use the field from the Item_field in the select list and leave + the Item_field instance in place. + */ + set_field((*((Item_field**)res))->field); + return 0; + } + else + { + /* + It's not an Item_field in the select list so we must make a new + Item_ref to point to the Item in the select list and replace the + Item_field created by the parser with the new Item_ref. + */ + Item_ref *rf= new Item_ref(db_name,table_name,field_name); + if (!rf) + return 1; + thd->change_item_tree(ref, rf); + /* + Because Item_ref never substitutes itself with other items + in Item_ref::fix_fields(), we can safely use the original + pointer to it even after fix_fields() + */ + return rf->fix_fields(thd, tables, ref) || rf->check_cols(1); + } } } diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 6b6996160a1..859b4e0ecc1 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -1998,7 +1998,6 @@ void Item_func_in::fix_length_and_dec() if (cmp_type == STRING_RESULT) in_item->cmp_charset= cmp_collation.collation; } - maybe_null= args[0]->maybe_null; max_length= 1; } diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index f3be0663af8..cd1f8f83821 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -391,6 +391,15 @@ enum Item_result Item_singlerow_subselect::result_type() const return engine->type(); } +/* + Don't rely on the result type to calculate field type. + Ask the engine instead. +*/ +enum_field_types Item_singlerow_subselect::field_type() const +{ + return engine->field_type(); +} + void Item_singlerow_subselect::fix_length_and_dec() { if ((max_columns= engine->cols()) == 1) @@ -610,6 +619,7 @@ double Item_in_subselect::val() */ DBUG_ASSERT(0); DBUG_ASSERT(fixed == 1); + null_value= 0; if (exec()) { reset(); @@ -625,6 +635,7 @@ double Item_in_subselect::val() longlong Item_in_subselect::val_int() { DBUG_ASSERT(fixed == 1); + null_value= 0; if (exec()) { reset(); @@ -645,6 +656,7 @@ String *Item_in_subselect::val_str(String *str) */ DBUG_ASSERT(0); DBUG_ASSERT(fixed == 1); + null_value= 0; if (exec()) { reset(); @@ -1354,31 +1366,35 @@ int subselect_uniquesubquery_engine::prepare() return 1; } -static Item_result set_row(List<Item> &item_list, Item *item, - Item_cache **row, bool *maybe_null) +/* + makes storage for the output values for the subquery and calcuates + their data and column types and their nullability. +*/ +void subselect_engine::set_row(List<Item> &item_list, Item_cache **row) { - Item_result res_type= STRING_RESULT; Item *sel_item; List_iterator_fast<Item> li(item_list); + res_type= STRING_RESULT; + res_field_type= FIELD_TYPE_VAR_STRING; for (uint i= 0; (sel_item= li++); i++) { item->max_length= sel_item->max_length; res_type= sel_item->result_type(); + res_field_type= sel_item->field_type(); item->decimals= sel_item->decimals; - *maybe_null= sel_item->maybe_null; + maybe_null= sel_item->maybe_null; if (!(row[i]= Item_cache::get_cache(res_type))) - return STRING_RESULT; // we should return something + return; row[i]->setup(sel_item); } if (item_list.elements > 1) res_type= ROW_RESULT; - return res_type; } void subselect_single_select_engine::fix_length_and_dec(Item_cache **row) { DBUG_ASSERT(row || select_lex->item_list.elements==1); - res_type= set_row(select_lex->item_list, item, row, &maybe_null); + set_row(select_lex->item_list, row); item->collation.set(row[0]->collation); if (cols() != 1) maybe_null= 0; @@ -1390,13 +1406,14 @@ void subselect_union_engine::fix_length_and_dec(Item_cache **row) if (unit->first_select()->item_list.elements == 1) { - res_type= set_row(unit->types, item, row, &maybe_null); + set_row(unit->types, row); item->collation.set(row[0]->collation); } else { - bool fake= 0; - res_type= set_row(unit->types, item, row, &fake); + bool maybe_null_saved= maybe_null; + set_row(unit->types, row); + maybe_null= maybe_null_saved; } } diff --git a/sql/item_subselect.h b/sql/item_subselect.h index 93171ad64a1..7b064bfe92c 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -142,6 +142,7 @@ public: longlong val_int (); String *val_str (String *); enum Item_result result_type() const; + enum_field_types field_type() const; void fix_length_and_dec(); uint cols(); @@ -273,6 +274,7 @@ protected: THD *thd; /* pointer to current THD */ Item_subselect *item; /* item, that use this engine */ enum Item_result res_type; /* type of results */ + enum_field_types res_field_type; /* column type of the results */ bool maybe_null; /* may be null (first item in select) */ public: @@ -282,6 +284,7 @@ public: result= res; item= si; res_type= STRING_RESULT; + res_field_type= FIELD_TYPE_VAR_STRING; maybe_null= 0; } virtual ~subselect_engine() {}; // to satisfy compiler @@ -296,6 +299,7 @@ public: virtual uint cols()= 0; /* return number of columnss in select */ virtual uint8 uncacheable()= 0; /* query is uncacheable */ enum Item_result type() { return res_type; } + enum_field_types field_type() { return res_field_type; } virtual void exclude()= 0; bool may_be_null() { return maybe_null; }; virtual table_map upper_select_const_tables()= 0; @@ -303,6 +307,9 @@ public: virtual void print(String *str)= 0; virtual int change_item(Item_subselect *si, select_subselect *result)= 0; virtual bool no_tables()= 0; + +protected: + void set_row(List<Item> &item_list, Item_cache **row); }; diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 5fd65fecbfc..419efd07615 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -71,9 +71,13 @@ void Item_sum::make_field(Send_field *tmp_field) if (args[0]->type() == Item::FIELD_ITEM && keep_field_type()) { ((Item_field*) args[0])->field->make_field(tmp_field); - 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; + /* For expressions only col_name should be non-empty string. */ + char *empty_string= (char*)""; + tmp_field->db_name= empty_string; + tmp_field->org_table_name= empty_string; + tmp_field->table_name= empty_string; + tmp_field->org_col_name= empty_string; + tmp_field->col_name= name; if (maybe_null) tmp_field->flags&= ~NOT_NULL_FLAG; } @@ -1673,6 +1677,7 @@ int dump_leaf_key(byte* key, uint32 count __attribute__((unused)), { char buff[MAX_FIELD_WIDTH]; String tmp((char *)&buff,sizeof(buff),default_charset_info), tmp2; + uint old_length= item->result.length(); if (item->no_appended) item->no_appended= FALSE; @@ -1711,8 +1716,22 @@ int dump_leaf_key(byte* key, uint32 count __attribute__((unused)), /* stop if length of result more than group_concat_max_len */ if (item->result.length() > item->group_concat_max_len) { + int well_formed_error; + CHARSET_INFO *cs= item->collation.collation; + const char *ptr= item->result.ptr(); + uint add_length; + /* + It's ok to use item->result.length() as the fourth argument + as this is never used to limit the length of the data. + Cut is done with the third argument. + */ + add_length= cs->cset->well_formed_len(cs, + ptr + old_length, + ptr + item->group_concat_max_len, + item->result.length(), + &well_formed_error); + item->result.length(old_length + add_length); item->count_cut_values++; - item->result.length(item->group_concat_max_len); item->warning_for_row= TRUE; return 1; } @@ -1902,8 +1921,7 @@ bool Item_func_group_concat::add() we can dump the row here in case of GROUP_CONCAT(DISTINCT...) instead of doing tree traverse later. */ - if (result.length() <= group_concat_max_len && - !warning_for_row && + if (!warning_for_row && (!tree_mode || (el->count == 1 && distinct && !arg_count_order))) dump_leaf_key(table->record[0], 1, this); diff --git a/sql/log_event.h b/sql/log_event.h index 6c4e65f7460..ec2d8993bca 100644 --- a/sql/log_event.h +++ b/sql/log_event.h @@ -148,6 +148,14 @@ struct sql_ex_info #define DELETE_FILE_HEADER_LEN 4 /* + Max number of possible extra bytes in a replication event compared to a + packet (i.e. a query) sent from client to master. +*/ +#define MAX_LOG_EVENT_HEADER (LOG_EVENT_HEADER_LEN + /* write_header */ \ + QUERY_HEADER_LEN + /* write_data */ \ + NAME_LEN + 1) + +/* Event header offsets; these point to places inside the fixed header. */ diff --git a/sql/mysqld.cc b/sql/mysqld.cc index dbb1838c3d7..3327224be46 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -5722,6 +5722,7 @@ struct show_var_st status_vars[]= { {"Open_streams", (char*) &my_stream_opened, SHOW_LONG_CONST}, {"Open_tables", (char*) 0, SHOW_OPENTABLES}, {"Opened_tables", (char*) &opened_tables, SHOW_LONG}, + {"Prepared_stmt_count", (char*) &prepared_stmt_count, SHOW_LONG_CONST}, #ifdef HAVE_QUERY_CACHE {"Qcache_free_blocks", (char*) &query_cache.free_memory_blocks, SHOW_LONG_CONST}, @@ -5892,6 +5893,7 @@ static void mysql_init_variables(void) binlog_cache_use= binlog_cache_disk_use= 0; max_used_connections= slow_launch_threads = 0; mysqld_user= mysqld_chroot= opt_init_file= opt_bin_logname = 0; + prepared_stmt_count= 0; errmesg= 0; mysqld_unix_port= opt_mysql_tmpdir= my_bind_addr_str= NullS; bzero((gptr) &mysql_tmpdir_list, sizeof(mysql_tmpdir_list)); diff --git a/sql/protocol.cc b/sql/protocol.cc index a2287740f1e..7c7dfaf7bef 100644 --- a/sql/protocol.cc +++ b/sql/protocol.cc @@ -43,7 +43,7 @@ bool Protocol_prep::net_store_data(const char *from, uint length) packet->realloc(packet_length+9+length)) return 1; char *to=(char*) net_store_length((char*) packet->ptr()+packet_length, - (ulonglong) length); + length); memcpy(to,from,length); packet->length((uint) (to+length-packet->ptr())); return 0; @@ -297,8 +297,8 @@ send_ok(THD *thd, ha_rows affected_rows, ulonglong id, const char *message) DBUG_VOID_RETURN; buff[0]=0; // No fields - pos=net_store_length(buff+1,(ulonglong) affected_rows); - pos=net_store_length(pos, (ulonglong) id); + pos=net_store_length(buff+1,affected_rows); + pos=net_store_length(pos, id); if (thd->client_capabilities & CLIENT_PROTOCOL_41) { DBUG_PRINT("info", @@ -416,7 +416,7 @@ bool send_old_password_request(THD *thd) ulonglong for bigger numbers. */ -char *net_store_length(char *pkg, uint length) +static char *net_store_length_fast(char *pkg, uint length) { uchar *packet=(uchar*) pkg; if (length < 251) @@ -439,7 +439,7 @@ char *net_store_length(char *pkg, uint length) char *net_store_data(char *to,const char *from, uint length) { - to=net_store_length(to,length); + to=net_store_length_fast(to,length); memcpy(to,from,length); return to+length; } @@ -448,7 +448,7 @@ char *net_store_data(char *to,int32 from) { char buff[20]; uint length=(uint) (int10_to_str(from,buff,10)-buff); - to=net_store_length(to,length); + to=net_store_length_fast(to,length); memcpy(to,buff,length); return to+length; } @@ -457,7 +457,7 @@ char *net_store_data(char *to,longlong from) { char buff[22]; uint length=(uint) (longlong10_to_str(from,buff,10)-buff); - to=net_store_length(to,length); + to=net_store_length_fast(to,length); memcpy(to,buff,length); return to+length; } @@ -520,7 +520,7 @@ bool Protocol::send_fields(List<Item> *list, uint flag) if (flag & 1) { // Packet with number of elements - char *pos=net_store_length(buff, (uint) list->elements); + char *pos=net_store_length(buff, list->elements); (void) my_net_write(&thd->net, buff,(uint) (pos-buff)); } @@ -648,7 +648,7 @@ bool Protocol::send_records_num(List<Item> *list, ulonglong records) { char *pos; char buff[20]; - pos=net_store_length(buff, (uint) list->elements); + pos=net_store_length(buff, list->elements); pos=net_store_length(pos, records); return my_net_write(&thd->net, buff,(uint) (pos-buff)); } diff --git a/sql/protocol.h b/sql/protocol.h index 32d6acccddf..ce3adb41df5 100644 --- a/sql/protocol.h +++ b/sql/protocol.h @@ -177,7 +177,6 @@ void send_ok(THD *thd, ha_rows affected_rows=0L, ulonglong id=0L, const char *info=0); void send_eof(THD *thd, bool no_flush=0); bool send_old_password_request(THD *thd); -char *net_store_length(char *packet,uint length); char *net_store_data(char *to,const char *from, uint length); char *net_store_data(char *to,int32 from); char *net_store_data(char *to,longlong from); diff --git a/sql/set_var.cc b/sql/set_var.cc index 4433b6bf7d8..71ca382f9d9 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -119,7 +119,6 @@ static KEY_CACHE *create_key_cache(const char *name, uint length); void fix_sql_mode_var(THD *thd, enum_var_type type); static byte *get_error_count(THD *thd); static byte *get_warning_count(THD *thd); -static byte *get_prepared_stmt_count(THD *thd); static byte *get_have_innodb(THD *thd); /* @@ -482,9 +481,6 @@ static sys_var_readonly sys_warning_count("warning_count", OPT_SESSION, SHOW_LONG, get_warning_count); -static sys_var_readonly sys_prepared_stmt_count("prepared_stmt_count", - OPT_GLOBAL, SHOW_LONG, - get_prepared_stmt_count); /* alias for last_insert_id() to be compatible with Sybase */ #ifdef HAVE_REPLICATION @@ -604,7 +600,6 @@ sys_var *sys_variables[]= &sys_new_mode, &sys_old_passwords, &sys_preload_buff_size, - &sys_prepared_stmt_count, &sys_pseudo_thread_id, &sys_query_alloc_block_size, &sys_query_cache_size, @@ -860,7 +855,6 @@ struct show_var_st init_vars[]= { {"pid_file", (char*) pidfile_name, SHOW_CHAR}, {"port", (char*) &mysqld_port, SHOW_INT}, {sys_preload_buff_size.name, (char*) &sys_preload_buff_size, SHOW_SYS}, - {sys_prepared_stmt_count.name, (char*) &sys_prepared_stmt_count, SHOW_SYS}, {"protocol_version", (char*) &protocol_version, SHOW_INT}, {sys_query_alloc_block_size.name, (char*) &sys_query_alloc_block_size, SHOW_SYS}, @@ -2715,14 +2709,6 @@ static byte *get_have_innodb(THD *thd) } -static byte *get_prepared_stmt_count(THD *thd) -{ - pthread_mutex_lock(&LOCK_prepared_stmt_count); - thd->sys_var_tmp.ulong_value= prepared_stmt_count; - pthread_mutex_unlock(&LOCK_prepared_stmt_count); - return (byte*) &thd->sys_var_tmp.ulong_value; -} - /**************************************************************************** Main handling of variables: - Initialisation diff --git a/sql/slave.cc b/sql/slave.cc index e3bc2d75829..6785e92b9f9 100644 --- a/sql/slave.cc +++ b/sql/slave.cc @@ -2618,6 +2618,13 @@ static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type) SYSTEM_THREAD_SLAVE_SQL : SYSTEM_THREAD_SLAVE_IO; thd->host_or_ip= ""; my_net_init(&thd->net, 0); +/* + Adding MAX_LOG_EVENT_HEADER_LEN to the max_allowed_packet on all + slave threads, since a replication event can become this much larger + than the corresponding packet (query) sent from client to master. +*/ + thd->variables.max_allowed_packet= global_system_variables.max_allowed_packet + + MAX_LOG_EVENT_HEADER; /* note, incr over the global not session var */ thd->net.read_timeout = slave_net_timeout; thd->master_access= ~(ulong)0; thd->priv_user = 0; @@ -3143,16 +3150,24 @@ slave_begin: sql_print_error("Slave I/O thread: error in mysql_init()"); goto err; } - + thd->proc_info = "Connecting to master"; // we can get killed during safe_connect if (!safe_connect(thd, mysql, mi)) + { sql_print_information("Slave I/O thread: connected to master '%s@%s:%d',\ replication started in log '%s' at position %s", mi->user, - mi->host, mi->port, - IO_RPL_LOG_NAME, - llstr(mi->master_log_pos,llbuff)); + mi->host, mi->port, + IO_RPL_LOG_NAME, + llstr(mi->master_log_pos,llbuff)); + /* + Adding MAX_LOG_EVENT_HEADER_LEN to the max_packet_size on the I/O + thread, since a replication event can become this much larger than + the corresponding packet (query) sent from client to master. + */ + mysql->net.max_packet_size= thd->net.max_packet_size+= MAX_LOG_EVENT_HEADER; + } else { sql_print_error("Slave I/O thread killed while connecting to master"); diff --git a/sql/sql_class.h b/sql/sql_class.h index 7cf0b474ed7..16abfe2b6b6 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -686,6 +686,12 @@ public: char *extra_data; ulong extra_length; String query_rest; + /* + In embedded server it points to the statement that is processed + in the current query. We store some results directly in statement + fields then. + */ + struct st_mysql_stmt *current_stmt; #endif NET net; // client connection descriptor MEM_ROOT warn_root; // For warnings and errors diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc index 2a7ab55b8c4..a20f2a6506c 100644 --- a/sql/sql_repl.cc +++ b/sql/sql_repl.cc @@ -420,6 +420,12 @@ impossible position"; goto err; } packet->set("\0", 1, &my_charset_bin); + /* + Adding MAX_LOG_EVENT_HEADER_LEN, since a binlog event can become + this larger than the corresponding packet (query) sent + from client to master. + */ + thd->variables.max_allowed_packet+= MAX_LOG_EVENT_HEADER; while (!net->error && net->vio != 0 && !thd->killed) { |