summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/item.cc33
-rw-r--r--sql/item_cmpfunc.cc1
-rw-r--r--sql/item_subselect.cc37
-rw-r--r--sql/item_subselect.h7
-rw-r--r--sql/item_sum.cc30
-rw-r--r--sql/log_event.h8
-rw-r--r--sql/mysqld.cc2
-rw-r--r--sql/protocol.cc18
-rw-r--r--sql/protocol.h1
-rw-r--r--sql/set_var.cc14
-rw-r--r--sql/slave.cc23
-rw-r--r--sql/sql_class.h6
-rw-r--r--sql/sql_repl.cc6
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,
&not_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)
{