summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorMikael Ronström <mikael@dator9>2011-05-12 14:29:32 +0200
committerMikael Ronström <mikael@dator9>2011-05-12 14:29:32 +0200
commit43c55e9a01fed3babab6e53eac2aed388f3ed2dc (patch)
treeb38b221786a2d3d9fc1ff6572ad859f7aeacde27 /sql
parent385551271556a8a4f1c9b669a91cb08adf33a89f (diff)
parent30265fd178745430101cfe6e15e02fa3dbc28797 (diff)
downloadmariadb-git-43c55e9a01fed3babab6e53eac2aed388f3ed2dc.tar.gz
merge
Diffstat (limited to 'sql')
-rw-r--r--sql/event_db_repository.cc22
-rw-r--r--sql/field.cc6
-rw-r--r--sql/handler.h14
-rw-r--r--sql/item.cc93
-rw-r--r--sql/item_cmpfunc.cc4
-rw-r--r--sql/item_func.cc2
-rw-r--r--sql/item_row.cc2
-rw-r--r--sql/item_strfunc.cc2
-rw-r--r--sql/item_timefunc.cc13
-rw-r--r--sql/my_decimal.cc11
-rw-r--r--sql/my_decimal.h3
-rw-r--r--sql/rpl_handler.h3
-rw-r--r--sql/slave.cc6
-rw-r--r--sql/sql_acl.cc178
-rw-r--r--sql/sql_base.cc15
-rw-r--r--sql/sql_class.h18
-rw-r--r--sql/sql_load.cc5
-rw-r--r--sql/sql_parse.cc6
-rw-r--r--sql/sql_partition.cc2
-rw-r--r--sql/sql_yacc.yy20
20 files changed, 342 insertions, 83 deletions
diff --git a/sql/event_db_repository.cc b/sql/event_db_repository.cc
index 3a25324db52..75d1c8ef8e8 100644
--- a/sql/event_db_repository.cc
+++ b/sql/event_db_repository.cc
@@ -534,6 +534,13 @@ Event_db_repository::fill_schema_events(THD *thd, TABLE_LIST *i_s_table,
if (open_system_tables_for_read(thd, &event_table, &open_tables_backup))
DBUG_RETURN(TRUE);
+ if (table_intact.check(event_table.table, &event_table_def))
+ {
+ close_system_tables(thd, &open_tables_backup);
+ my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
+ DBUG_RETURN(TRUE);
+ }
+
/*
1. SELECT I_S => use table scan. I_S.EVENTS does not guarantee order
thus we won't order it. OTOH, SHOW EVENTS will be
@@ -591,6 +598,14 @@ Event_db_repository::open_event_table(THD *thd, enum thr_lock_type lock_type,
*table= tables.table;
tables.table->use_all_columns();
+
+ if (table_intact.check(*table, &event_table_def))
+ {
+ close_thread_tables(thd);
+ my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
+ DBUG_RETURN(TRUE);
+ }
+
DBUG_RETURN(FALSE);
}
@@ -1035,6 +1050,13 @@ Event_db_repository::load_named_event(THD *thd, LEX_STRING dbname,
*/
if (!(ret= open_system_tables_for_read(thd, &event_table, &open_tables_backup)))
{
+ if (table_intact.check(event_table.table, &event_table_def))
+ {
+ close_system_tables(thd, &open_tables_backup);
+ my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
+ DBUG_RETURN(TRUE);
+ }
+
if ((ret= find_named_event(dbname, name, event_table.table)))
my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), name.str);
else if ((ret= etn->load_from_row(thd, event_table.table)))
diff --git a/sql/field.cc b/sql/field.cc
index 7ffc399718c..d273f26306d 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -2608,7 +2608,7 @@ bool Field_new_decimal::store_value(const my_decimal *decimal_value)
DBUG_ENTER("Field_new_decimal::store_value");
#ifndef DBUG_OFF
{
- char dbug_buff[DECIMAL_MAX_STR_LENGTH+1];
+ char dbug_buff[DECIMAL_MAX_STR_LENGTH+2];
DBUG_PRINT("enter", ("value: %s", dbug_decimal_as_string(dbug_buff, decimal_value)));
}
#endif
@@ -2623,7 +2623,7 @@ bool Field_new_decimal::store_value(const my_decimal *decimal_value)
}
#ifndef DBUG_OFF
{
- char dbug_buff[DECIMAL_MAX_STR_LENGTH+1];
+ char dbug_buff[DECIMAL_MAX_STR_LENGTH+2];
DBUG_PRINT("info", ("saving with precision %d scale: %d value %s",
(int)precision, (int)dec,
dbug_decimal_as_string(dbug_buff, decimal_value)));
@@ -2692,7 +2692,7 @@ int Field_new_decimal::store(const char *from, uint length,
}
#ifndef DBUG_OFF
- char dbug_buff[DECIMAL_MAX_STR_LENGTH+1];
+ char dbug_buff[DECIMAL_MAX_STR_LENGTH+2];
DBUG_PRINT("enter", ("value: %s",
dbug_decimal_as_string(dbug_buff, &decimal_value)));
#endif
diff --git a/sql/handler.h b/sql/handler.h
index 1250388f459..fbc52170297 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -3,18 +3,20 @@
/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
- 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; version 2 of the License.
+ 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; version 2 of
+ the License.
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
+ 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 */
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ 02110-1301 USA */
/* Definitions for parameters to do with handler-routines */
@@ -60,7 +62,7 @@
a table with rnd_next()
- We will see all rows (including deleted ones)
- Row positions are 'table->s->db_record_offset' apart
- If this flag is not set, filesort will do a postion() call for each matched
+ If this flag is not set, filesort will do a position() call for each matched
row to be able to find the row later.
*/
#define HA_REC_NOT_IN_SEQ (1 << 3)
diff --git a/sql/item.cc b/sql/item.cc
index af3917c09c1..2c0da80b43b 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -581,7 +581,7 @@ void Item::rename(char *new_name)
Item* Item::transform(Item_transformer transformer, uchar *arg)
{
- DBUG_ASSERT(!current_thd->is_stmt_prepare());
+ DBUG_ASSERT(!current_thd->stmt_arena->is_stmt_prepare());
return (this->*transformer)(arg);
}
@@ -1781,14 +1781,17 @@ bool agg_item_set_converter(DTCollation &coll, const char *fname,
}
THD *thd= current_thd;
- Query_arena *arena, backup;
bool res= FALSE;
uint i;
+
/*
In case we're in statement prepare, create conversion item
in its memory: it will be reused on each execute.
*/
- arena= thd->activate_stmt_arena_if_needed(&backup);
+ Query_arena backup;
+ Query_arena *arena= thd->stmt_arena->is_stmt_prepare() ?
+ thd->activate_stmt_arena_if_needed(&backup) :
+ NULL;
for (i= 0, arg= args; i < nargs; i++, arg+= item_sep)
{
@@ -1845,7 +1848,7 @@ bool agg_item_set_converter(DTCollation &coll, const char *fname,
been created in prepare. In this case register the change for
rollback.
*/
- if (thd->is_stmt_prepare())
+ if (thd->stmt_arena->is_stmt_prepare())
*arg= conv;
else
thd->change_item_tree(arg, conv);
@@ -2008,6 +2011,61 @@ Item_field::Item_field(THD *thd, Item_field *item)
collation.set(DERIVATION_IMPLICIT);
}
+
+/**
+ Calculate the max column length not taking into account the
+ limitations over integer types.
+
+ When storing data into fields the server currently just ignores the
+ limits specified on integer types, e.g. 1234 can safely be stored in
+ an int(2) and will not cause an error.
+ Thus when creating temporary tables and doing transformations
+ we must adjust the maximum field length to reflect this fact.
+ We take the un-restricted maximum length and adjust it similarly to
+ how the declared length is adjusted wrt unsignedness etc.
+ TODO: this all needs to go when we disable storing 1234 in int(2).
+
+ @param field_par Original field the use to calculate the lengths
+ @param max_length Item's calculated explicit max length
+ @return The adjusted max length
+*/
+
+inline static uint32
+adjust_max_effective_column_length(Field *field_par, uint32 max_length)
+{
+ uint32 new_max_length= field_par->max_display_length();
+ uint32 sign_length= (field_par->flags & UNSIGNED_FLAG) ? 0 : 1;
+
+ switch (field_par->type())
+ {
+ case MYSQL_TYPE_INT24:
+ /*
+ Compensate for MAX_MEDIUMINT_WIDTH being 1 too long (8)
+ compared to the actual number of digits that can fit into
+ the column.
+ */
+ new_max_length+= 1;
+ /* fall through */
+ case MYSQL_TYPE_LONG:
+ case MYSQL_TYPE_TINY:
+ case MYSQL_TYPE_SHORT:
+
+ /* Take out the sign and add a conditional sign */
+ new_max_length= new_max_length - 1 + sign_length;
+ break;
+
+ /* BINGINT is always 20 no matter the sign */
+ case MYSQL_TYPE_LONGLONG:
+ /* make gcc happy */
+ default:
+ break;
+ }
+
+ /* Adjust only if the actual precision based one is bigger than specified */
+ return new_max_length > max_length ? new_max_length : max_length;
+}
+
+
void Item_field::set_field(Field *field_par)
{
field=result_field=field_par; // for easy coding with fields
@@ -2021,6 +2079,9 @@ void Item_field::set_field(Field *field_par)
collation.set(field_par->charset(), field_par->derivation(),
field_par->repertoire());
fix_char_length(field_par->char_length());
+
+ max_length= adjust_max_effective_column_length(field_par, max_length);
+
fixed= 1;
if (field->table->s->tmp_table == SYSTEM_TMP_TABLE)
any_privileges= 0;
@@ -6965,7 +7026,7 @@ int Item_default_value::save_in_field(Field *field_arg, bool no_conversions)
Item *Item_default_value::transform(Item_transformer transformer, uchar *args)
{
- DBUG_ASSERT(!current_thd->is_stmt_prepare());
+ DBUG_ASSERT(!current_thd->stmt_arena->is_stmt_prepare());
/*
If the value of arg is NULL, then this object represents a constant,
@@ -7131,8 +7192,26 @@ bool Item_trigger_field::set_value(THD *thd, sp_rcontext * /*ctx*/, Item **it)
{
Item *item= sp_prepare_func_item(thd, it);
- return (!item || (!fixed && fix_fields(thd, 0)) ||
- (item->save_in_field(field, 0) < 0));
+ if (!item)
+ return true;
+
+ if (!fixed)
+ {
+ if (fix_fields(thd, NULL))
+ return true;
+ }
+
+ // NOTE: field->table->copy_blobs should be false here, but let's
+ // remember the value at runtime to avoid subtle bugs.
+ bool copy_blobs_saved= field->table->copy_blobs;
+
+ field->table->copy_blobs= true;
+
+ int err_code= item->save_in_field(field, 0);
+
+ field->table->copy_blobs= copy_blobs_saved;
+
+ return err_code < 0;
}
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index cf5da5313d9..e0057d1550b 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -4345,7 +4345,7 @@ bool Item_cond::walk(Item_processor processor, bool walk_subquery, uchar *arg)
Item *Item_cond::transform(Item_transformer transformer, uchar *arg)
{
- DBUG_ASSERT(!current_thd->is_stmt_prepare());
+ DBUG_ASSERT(!current_thd->stmt_arena->is_stmt_prepare());
List_iterator<Item> li(list);
Item *item;
@@ -5718,7 +5718,7 @@ bool Item_equal::walk(Item_processor processor, bool walk_subquery, uchar *arg)
Item *Item_equal::transform(Item_transformer transformer, uchar *arg)
{
- DBUG_ASSERT(!current_thd->is_stmt_prepare());
+ DBUG_ASSERT(!current_thd->stmt_arena->is_stmt_prepare());
List_iterator<Item_field> it(fields);
Item *item;
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 9035d644962..a7e9ed43cb4 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -295,7 +295,7 @@ void Item_func::traverse_cond(Cond_traverser traverser,
Item *Item_func::transform(Item_transformer transformer, uchar *argument)
{
- DBUG_ASSERT(!current_thd->is_stmt_prepare());
+ DBUG_ASSERT(!current_thd->stmt_arena->is_stmt_prepare());
if (arg_count)
{
diff --git a/sql/item_row.cc b/sql/item_row.cc
index 94515640625..0f5d6f27823 100644
--- a/sql/item_row.cc
+++ b/sql/item_row.cc
@@ -170,7 +170,7 @@ bool Item_row::walk(Item_processor processor, bool walk_subquery, uchar *arg)
Item *Item_row::transform(Item_transformer transformer, uchar *arg)
{
- DBUG_ASSERT(!current_thd->is_stmt_prepare());
+ DBUG_ASSERT(!current_thd->stmt_arena->is_stmt_prepare());
for (uint i= 0; i < arg_count; i++)
{
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index e5c47c110f4..e1a4fcc8def 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -2536,7 +2536,7 @@ String *Item_func_make_set::val_str(String *str)
Item *Item_func_make_set::transform(Item_transformer transformer, uchar *arg)
{
- DBUG_ASSERT(!current_thd->is_stmt_prepare());
+ DBUG_ASSERT(!current_thd->stmt_arena->is_stmt_prepare());
Item *new_item= item->transform(transformer, arg);
if (!new_item)
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index 68e75a262dc..0952a5448e4 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -2524,6 +2524,19 @@ String *Item_char_typecast::val_str(String *str)
String *res;
uint32 length;
+ if (cast_length >= 0 &&
+ ((unsigned) cast_length) > current_thd->variables.max_allowed_packet)
+ {
+ push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_WARN_ALLOWED_PACKET_OVERFLOWED,
+ ER(ER_WARN_ALLOWED_PACKET_OVERFLOWED),
+ cast_cs == &my_charset_bin ?
+ "cast_as_binary" : func_name(),
+ current_thd->variables.max_allowed_packet);
+ null_value= 1;
+ return 0;
+ }
+
if (!charset_conversion)
{
if (!(res= args[0]->val_str(str)))
diff --git a/sql/my_decimal.cc b/sql/my_decimal.cc
index a5b60739b26..3b5fa81eab9 100644
--- a/sql/my_decimal.cc
+++ b/sql/my_decimal.cc
@@ -99,10 +99,11 @@ int my_decimal2string(uint mask, const my_decimal *d,
UNSIGNED. Hence the buffer for a ZEROFILLed value is the length
the user requested, plus one for a possible decimal point, plus
one if the user only wanted decimal places, but we force a leading
- zero on them. Because the type is implicitly UNSIGNED, we do not
- need to reserve a character for the sign. For all other cases,
- fixed_prec will be 0, and my_decimal_string_length() will be called
- instead to calculate the required size of the buffer.
+ zero on them, plus one for the '\0' terminator. Because the type
+ is implicitly UNSIGNED, we do not need to reserve a character for
+ the sign. For all other cases, fixed_prec will be 0, and
+ my_decimal_string_length() will be called instead to calculate the
+ required size of the buffer.
*/
int length= (fixed_prec
? (fixed_prec + ((fixed_prec == fixed_dec) ? 1 : 0) + 1)
@@ -332,7 +333,7 @@ print_decimal_buff(const my_decimal *dec, const uchar* ptr, int length)
const char *dbug_decimal_as_string(char *buff, const my_decimal *val)
{
- int length= DECIMAL_MAX_STR_LENGTH;
+ int length= DECIMAL_MAX_STR_LENGTH + 1; /* minimum size for buff */
if (!val)
return "NULL";
(void)decimal2string((decimal_t*) val, buff, &length, 0,0,0);
diff --git a/sql/my_decimal.h b/sql/my_decimal.h
index f3fd39f5721..6ac9d25b87d 100644
--- a/sql/my_decimal.h
+++ b/sql/my_decimal.h
@@ -62,7 +62,7 @@ typedef struct st_mysql_time MYSQL_TIME;
/**
maximum length of string representation (number of maximum decimal
- digits + 1 position for sign + 1 position for decimal point)
+ digits + 1 position for sign + 1 position for decimal point, no terminator)
*/
#define DECIMAL_MAX_STR_LENGTH (DECIMAL_MAX_POSSIBLE_PRECISION + 2)
@@ -243,6 +243,7 @@ inline uint32 my_decimal_precision_to_length(uint precision, uint8 scale,
inline
int my_decimal_string_length(const my_decimal *d)
{
+ /* length of string representation including terminating '\0' */
return decimal_string_size(d);
}
diff --git a/sql/rpl_handler.h b/sql/rpl_handler.h
index bf207e53e2d..9a181250efc 100644
--- a/sql/rpl_handler.h
+++ b/sql/rpl_handler.h
@@ -73,7 +73,10 @@ public:
while (info && info->observer != observer)
info= iter++;
if (info)
+ {
iter.remove();
+ delete info;
+ }
else
ret= TRUE;
unlock();
diff --git a/sql/slave.cc b/sql/slave.cc
index c676c89b369..223ea21851a 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -113,7 +113,7 @@ static const char *reconnect_messages[SLAVE_RECON_ACT_MAX][SLAVE_RECON_MSG_MAX]=
registration on master",
"Reconnecting after a failed registration on master",
"failed registering on master, reconnecting to try again, \
-log '%s' at postion %s",
+log '%s' at position %s",
"COM_REGISTER_SLAVE",
"Slave I/O thread killed during or after reconnect"
},
@@ -121,7 +121,7 @@ log '%s' at postion %s",
"Waiting to reconnect after a failed binlog dump request",
"Slave I/O thread killed while retrying master dump",
"Reconnecting after a failed binlog dump request",
- "failed dump request, reconnecting to try again, log '%s' at postion %s",
+ "failed dump request, reconnecting to try again, log '%s' at position %s",
"COM_BINLOG_DUMP",
"Slave I/O thread killed during or after reconnect"
},
@@ -130,7 +130,7 @@ log '%s' at postion %s",
"Slave I/O thread killed while waiting to reconnect after a failed read",
"Reconnecting after a failed master event read",
"Slave I/O thread: Failed reading log event, reconnecting to retry, \
-log '%s' at postion %s",
+log '%s' at position %s",
"",
"Slave I/O thread killed during or after a reconnect done to recover from \
failed read"
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index a269d5a1eef..18758130767 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -8399,6 +8399,94 @@ static bool parse_com_change_user_packet(MPVIO_EXT *mpvio, uint packet_length)
DBUG_RETURN (0);
}
+#ifndef EMBEDDED_LIBRARY
+/**
+ Get a null character terminated string from a user-supplied buffer.
+
+ @param buffer[in, out] Pointer to the buffer to be scanned.
+ @param max_bytes_available[in, out] Limit the bytes to scan.
+ @param string_length[out] The number of characters scanned not including
+ the null character.
+
+ @remark The string_length does not include the terminating null character.
+ However, after the call, the buffer is increased by string_length+1
+ bytes, beyond the null character if there still available bytes to
+ scan.
+
+ @return pointer to beginning of the string scanned.
+ @retval NULL The buffer content is malformed
+*/
+
+static
+char *get_null_terminated_string(char **buffer,
+ size_t *max_bytes_available,
+ size_t *string_length)
+{
+ char *str= (char *)memchr(*buffer, '\0', *max_bytes_available);
+
+ if (str == NULL)
+ return NULL;
+
+ *string_length= (size_t)(str - *buffer);
+ *max_bytes_available-= *string_length + 1;
+ str= *buffer;
+ *buffer += *string_length + 1;
+
+ return str;
+}
+
+/**
+ Get a length encoded string from a user-supplied buffer.
+
+ @param buffer[in, out] The buffer to scan; updates position after scan.
+ @param max_bytes_available[in, out] Limit the number of bytes to scan
+ @param string_length[out] Number of characters scanned
+
+ @remark In case the length is zero, then the total size of the string is
+ considered to be 1 byte; the size byte.
+
+ @return pointer to first byte after the header in buffer.
+ @retval NULL The buffer content is malformed
+*/
+
+static
+char *get_length_encoded_string(char **buffer,
+ size_t *max_bytes_available,
+ size_t *string_length)
+{
+ if (*max_bytes_available == 0)
+ return NULL;
+
+ /* Do double cast to prevent overflow from signed / unsigned conversion */
+ size_t str_len= (size_t)(unsigned char)**buffer;
+
+ /*
+ If the length encoded string has the length 0
+ the total size of the string is only one byte long (the size byte)
+ */
+ if (str_len == 0)
+ {
+ ++*buffer;
+ *string_length= 0;
+ /*
+ Return a pointer to the 0 character so the return value will be
+ an empty string.
+ */
+ return *buffer-1;
+ }
+
+ if (str_len >= *max_bytes_available)
+ return NULL;
+
+ char *str= *buffer+1;
+ *string_length= str_len;
+ *max_bytes_available-= *string_length + 1;
+ *buffer+= *string_length + 1;
+ return str;
+}
+#endif
+
+
/* the packet format is described in send_client_reply_packet() */
static ulong parse_client_handshake_packet(MPVIO_EXT *mpvio,
uchar **buff, ulong pkt_len)
@@ -8463,50 +8551,76 @@ static ulong parse_client_handshake_packet(MPVIO_EXT *mpvio,
}
#endif
- if (end >= (char*) net->read_pos + pkt_len + 2)
+ if (end > (char *)net->read_pos + pkt_len)
return packet_error;
if ((mpvio->client_capabilities & CLIENT_TRANSACTIONS) &&
opt_using_transactions)
net->return_status= mpvio->server_status;
+
+ /*
+ In order to safely scan a head for '\0' string terminators
+ we must keep track of how many bytes remain in the allocated
+ buffer or we might read past the end of the buffer.
+ */
+ size_t bytes_remaining_in_packet= pkt_len - (end - (char *)net->read_pos);
- char *user= end;
- char *passwd= strend(user) + 1;
- uint user_len= passwd - user - 1, db_len;
- char *db= passwd;
- char db_buff[NAME_LEN + 1]; // buffer to store db in utf8
- char user_buff[USERNAME_LENGTH + 1]; // buffer to store user in utf8
- uint dummy_errors;
+ size_t user_len;
+ char *user= get_null_terminated_string(&end, &bytes_remaining_in_packet,
+ &user_len);
+ if (user == NULL)
+ return packet_error;
/*
- Old clients send null-terminated string as password; new clients send
+ Old clients send a null-terminated string as password; new clients send
the size (1 byte) + string (not null-terminated). Hence in case of empty
password both send '\0'.
-
- This strlen() can't be easily deleted without changing protocol.
-
- Cast *passwd to an unsigned char, so that it doesn't extend the sign for
- *passwd > 127 and become 2**32-127+ after casting to uint.
*/
- uint passwd_len= mpvio->client_capabilities & CLIENT_SECURE_CONNECTION ?
- (uchar) (*passwd++) : strlen(passwd);
-
- if (mpvio->client_capabilities & CLIENT_CONNECT_WITH_DB)
+ size_t passwd_len= 0;
+ char *passwd= NULL;
+
+ if (mpvio->client_capabilities & CLIENT_SECURE_CONNECTION)
{
- db= db + passwd_len + 1;
- /* strlen() can't be easily deleted without changing protocol */
- db_len= strlen(db);
+ /*
+ 4.1+ password. First byte is password length.
+ */
+ passwd= get_length_encoded_string(&end, &bytes_remaining_in_packet,
+ &passwd_len);
}
else
{
- db= 0;
- db_len= 0;
+ /*
+ Old passwords are zero terminated strings.
+ */
+ passwd= get_null_terminated_string(&end, &bytes_remaining_in_packet,
+ &passwd_len);
}
- if (passwd + passwd_len + db_len > (char *) net->read_pos + pkt_len)
+ if (passwd == NULL)
return packet_error;
- char *client_plugin= passwd + passwd_len + (db ? db_len + 1 : 0);
+ size_t db_len= 0;
+ char *db= NULL;
+
+ if (mpvio->client_capabilities & CLIENT_CONNECT_WITH_DB)
+ {
+ db= get_null_terminated_string(&end, &bytes_remaining_in_packet,
+ &db_len);
+ if (db == NULL)
+ return packet_error;
+ }
+
+ size_t client_plugin_len= 0;
+ char *client_plugin= get_null_terminated_string(&end,
+ &bytes_remaining_in_packet,
+ &client_plugin_len);
+ if (client_plugin == NULL)
+ client_plugin= &empty_c_string[0];
+
+ char db_buff[NAME_LEN + 1]; // buffer to store db in utf8
+ char user_buff[USERNAME_LENGTH + 1]; // buffer to store user in utf8
+ uint dummy_errors;
+
/* Since 4.1 all database names are stored in utf8 */
if (db)
@@ -8552,18 +8666,18 @@ static ulong parse_client_handshake_packet(MPVIO_EXT *mpvio,
if (find_mpvio_user(mpvio))
return packet_error;
- if (mpvio->client_capabilities & CLIENT_PLUGIN_AUTH)
- {
- if ((client_plugin + strlen(client_plugin)) >
- (char *) net->read_pos + pkt_len)
- return packet_error;
- }
- else
+ if (!(mpvio->client_capabilities & CLIENT_PLUGIN_AUTH))
{
+ /*
+ An old client is connecting
+ */
if (mpvio->client_capabilities & CLIENT_SECURE_CONNECTION)
client_plugin= native_password_plugin_name.str;
else
{
+ /*
+ A really old client is connecting
+ */
client_plugin= old_password_plugin_name.str;
/*
For a passwordless accounts we use native_password_plugin.
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 628e3b49719..f9d85b1e024 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -7602,9 +7602,10 @@ static bool setup_natural_join_row_types(THD *thd,
List<TABLE_LIST> *from_clause,
Name_resolution_context *context)
{
+ DBUG_ENTER("setup_natural_join_row_types");
thd->where= "from clause";
if (from_clause->elements == 0)
- return FALSE; /* We come here in the case of UNIONs. */
+ DBUG_RETURN(false); /* We come here in the case of UNIONs. */
List_iterator_fast<TABLE_LIST> table_ref_it(*from_clause);
TABLE_LIST *table_ref; /* Current table reference. */
@@ -7612,10 +7613,6 @@ static bool setup_natural_join_row_types(THD *thd,
TABLE_LIST *left_neighbor;
/* Table reference to the right of the current. */
TABLE_LIST *right_neighbor= NULL;
- bool save_first_natural_join_processing=
- context->select_lex->first_natural_join_processing;
-
- context->select_lex->first_natural_join_processing= FALSE;
/* Note that tables in the list are in reversed order */
for (left_neighbor= table_ref_it++; left_neighbor ; )
@@ -7627,12 +7624,11 @@ static bool setup_natural_join_row_types(THD *thd,
1) for stored procedures,
2) for multitable update after lock failure and table reopening.
*/
- if (save_first_natural_join_processing)
+ if (context->select_lex->first_natural_join_processing)
{
- context->select_lex->first_natural_join_processing= FALSE;
if (store_top_level_join_columns(thd, table_ref,
left_neighbor, right_neighbor))
- return TRUE;
+ DBUG_RETURN(true);
if (left_neighbor)
{
TABLE_LIST *first_leaf_on_the_right;
@@ -7652,8 +7648,9 @@ static bool setup_natural_join_row_types(THD *thd,
DBUG_ASSERT(right_neighbor);
context->first_name_resolution_table=
right_neighbor->first_leaf_for_name_resolution();
+ context->select_lex->first_natural_join_processing= false;
- return FALSE;
+ DBUG_RETURN (false);
}
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 060f2ef77f5..71b1a7d4c1c 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -655,15 +655,10 @@ public:
virtual ~Query_arena() {};
inline bool is_stmt_prepare() const { return state == STMT_INITIALIZED; }
- inline bool is_first_sp_execute() const
- { return state == STMT_INITIALIZED_FOR_SP; }
inline bool is_stmt_prepare_or_first_sp_execute() const
{ return (int)state < (int)STMT_PREPARED; }
inline bool is_stmt_prepare_or_first_stmt_execute() const
{ return (int)state <= (int)STMT_PREPARED; }
- inline bool is_first_stmt_execute() const { return state == STMT_PREPARED; }
- inline bool is_stmt_execute() const
- { return state == STMT_PREPARED || state == STMT_EXECUTED; }
inline bool is_conventional() const
{ return state == STMT_CONVENTIONAL_EXECUTION; }
@@ -1434,6 +1429,19 @@ extern "C" void my_message_sql(uint error, const char *str, myf MyFlags);
class THD :public Statement,
public Open_tables_state
{
+private:
+ inline bool is_stmt_prepare() const
+ { DBUG_ASSERT(0); return Statement::is_stmt_prepare(); }
+
+ inline bool is_stmt_prepare_or_first_sp_execute() const
+ { DBUG_ASSERT(0); return Statement::is_stmt_prepare_or_first_sp_execute(); }
+
+ inline bool is_stmt_prepare_or_first_stmt_execute() const
+ { DBUG_ASSERT(0); return Statement::is_stmt_prepare_or_first_stmt_execute(); }
+
+ inline bool is_conventional() const
+ { DBUG_ASSERT(0); return Statement::is_conventional(); }
+
public:
MDL_context mdl_context;
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index ae708178097..35c26f9bb89 100644
--- a/sql/sql_load.cc
+++ b/sql/sql_load.cc
@@ -1,4 +1,4 @@
-/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2000, 2011 Oracle and/or its affiliates. All rights reserved.
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
@@ -743,8 +743,7 @@ static bool write_execute_load_query_log_event(THD *thd, sql_exchange* ex,
pfields.append("`");
pfields.append(item->name);
pfields.append("`");
- pfields.append("=");
- val->print(&pfields, QT_ORDINARY);
+ pfields.append(val->name);
}
}
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index d9d99de2911..24f7fdb8e61 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -4434,7 +4434,11 @@ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables)
return 1; /* purecov: inspected */
thd->send_explain_fields(result);
res= mysql_explain_union(thd, &thd->lex->unit, result);
- if (lex->describe & DESCRIBE_EXTENDED)
+ /*
+ The code which prints the extended description is not robust
+ against malformed queries, so skip it if we have an error.
+ */
+ if (!res && (lex->describe & DESCRIBE_EXTENDED))
{
char buff[1024];
String str(buff,(uint32) sizeof(buff), system_charset_info);
diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc
index 5c2c0bb95d6..776ce01cc54 100644
--- a/sql/sql_partition.cc
+++ b/sql/sql_partition.cc
@@ -3979,7 +3979,7 @@ void get_partition_set(const TABLE *table, uchar *buf, const uint index,
part_spec->start_part= 0;
part_spec->end_part= num_parts - 1;
if ((index < MAX_KEY) &&
- key_spec->flag == (uint)HA_READ_KEY_EXACT &&
+ key_spec && key_spec->flag == (uint)HA_READ_KEY_EXACT &&
part_info->some_fields_in_PF.is_set(index))
{
key_info= table->key_info+index;
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 13a1b8029f2..5ab1a648d09 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -1,4 +1,4 @@
-/* Copyright (c) 2000, 2010 Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2000, 2011 Oracle and/or its affiliates. All rights reserved.
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
@@ -11574,7 +11574,23 @@ field_or_var:
opt_load_data_set_spec:
/* empty */ {}
- | SET insert_update_list {}
+ | SET load_data_set_list {}
+ ;
+
+load_data_set_list:
+ load_data_set_list ',' load_data_set_elem
+ | load_data_set_elem
+ ;
+
+load_data_set_elem:
+ simple_ident_nospvar equal remember_name expr_or_default remember_end
+ {
+ LEX *lex= Lex;
+ if (lex->update_list.push_back($1) ||
+ lex->value_list.push_back($4))
+ MYSQL_YYABORT;
+ $4->set_name($3, (uint) ($5 - $3), YYTHD->charset());
+ }
;
/* Common definitions */