summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorSergei Golubchik <sergii@pisem.net>2012-05-21 15:30:25 +0200
committerSergei Golubchik <sergii@pisem.net>2012-05-21 15:30:25 +0200
commit431e042b5d76ed5fd219c39db798c9e7478731c8 (patch)
treea5556e1a39e43ca6a9549ef949541efcd9725f40 /sql
parent3f4ef5928e72faf2b7fd0c98c8705ac649d2faf9 (diff)
parent83d455be90a06e8fc1293a611061bd9529ed8536 (diff)
downloadmariadb-git-431e042b5d76ed5fd219c39db798c9e7478731c8.tar.gz
c
Diffstat (limited to 'sql')
-rw-r--r--sql/field.cc14
-rw-r--r--sql/field.h8
-rw-r--r--sql/field_conv.cc9
-rw-r--r--sql/handler.cc12
-rw-r--r--sql/handler.h1
-rw-r--r--sql/item.cc16
-rw-r--r--sql/item_subselect.cc1
-rw-r--r--sql/log_event.cc52
-rw-r--r--sql/log_event_old.cc12
-rw-r--r--sql/mysqld.cc21
-rw-r--r--sql/rpl_rli.cc20
-rw-r--r--sql/share/errmsg-utf8.txt9
-rw-r--r--sql/spatial.cc3
-rw-r--r--sql/sql_base.cc26
-rw-r--r--sql/sql_class.cc43
-rw-r--r--sql/sql_class.h1
-rw-r--r--sql/sql_lex.cc3
-rw-r--r--sql/sql_lex.h6
-rw-r--r--sql/sql_select.cc26
-rw-r--r--sql/sql_table.cc33
20 files changed, 246 insertions, 70 deletions
diff --git a/sql/field.cc b/sql/field.cc
index d913e395b1a..6e1851d89d1 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -7860,7 +7860,19 @@ String *Field_set::val_str(String *val_buffer,
ulonglong tmp=(ulonglong) Field_enum::val_int();
uint bitnr=0;
- val_buffer->set("", 0, field_charset);
+ if (tmp == 0)
+ {
+ /*
+ Some callers expect *val_buffer to contain the result,
+ so we assign to it, rather than doing 'return &empty_set_string.
+ */
+ *val_buffer= empty_set_string;
+ return val_buffer;
+ }
+
+ val_buffer->set_charset(field_charset);
+ val_buffer->length(0);
+
while (tmp && bitnr < (uint) typelib->count)
{
if (tmp & 1)
diff --git a/sql/field.h b/sql/field.h
index 0b32aab0337..c86c0975117 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -2016,7 +2016,8 @@ public:
:Field_enum(ptr_arg, len_arg, null_ptr_arg, null_bit_arg,
unireg_check_arg, field_name_arg,
packlength_arg,
- typelib_arg,charset_arg)
+ typelib_arg,charset_arg),
+ empty_set_string("", 0, charset_arg)
{
flags=(flags & ~ENUM_FLAG) | SET_FLAG;
}
@@ -2027,8 +2028,11 @@ public:
virtual bool zero_pack() const { return 1; }
String *val_str(String*,String *);
void sql_type(String &str) const;
+ uint size_of() const { return sizeof(*this); }
enum_field_types real_type() const { return MYSQL_TYPE_SET; }
bool has_charset(void) const { return TRUE; }
+private:
+ const String empty_set_string;
};
@@ -2240,6 +2244,8 @@ public:
{
return (flags & (BINCMP_FLAG | BINARY_FLAG)) != 0;
}
+private:
+ const String empty_set_string;
};
diff --git a/sql/field_conv.cc b/sql/field_conv.cc
index 37aee93fe82..20da18a129c 100644
--- a/sql/field_conv.cc
+++ b/sql/field_conv.cc
@@ -361,10 +361,11 @@ static void do_save_blob(Copy_field *copy)
static void do_field_string(Copy_field *copy)
{
char buff[MAX_FIELD_WIDTH];
- copy->tmp.set_quick(buff,sizeof(buff),copy->tmp.charset());
- copy->from_field->val_str(&copy->tmp);
- copy->to_field->store(copy->tmp.c_ptr_quick(),copy->tmp.length(),
- copy->tmp.charset());
+ String res(buff, sizeof(buff), copy->from_field->charset());
+ res.length(0U);
+
+ copy->from_field->val_str(&res);
+ copy->to_field->store(res.c_ptr_quick(), res.length(), res.charset());
}
diff --git a/sql/handler.cc b/sql/handler.cc
index 546491c2f32..2c9cc388006 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -1,4 +1,4 @@
-/* Copyright (c) 2000, 2011, Oracle and/or its affiliates.
+/* Copyright (c) 2000, 2012, Oracle and/or its affiliates.
Copyright (c) 2009-2011 Monty Program Ab
This program is free software; you can redistribute it and/or modify
@@ -11,8 +11,8 @@
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 */
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
/** @file handler.cc
@@ -362,7 +362,8 @@ int ha_init_errors(void)
SETMSG(HA_ERR_AUTOINC_ERANGE, ER_DEFAULT(ER_WARN_DATA_OUT_OF_RANGE));
SETMSG(HA_ERR_TOO_MANY_CONCURRENT_TRXS, ER_DEFAULT(ER_TOO_MANY_CONCURRENT_TRXS));
SETMSG(HA_ERR_INDEX_COL_TOO_LONG, ER_DEFAULT(ER_INDEX_COLUMN_TOO_LONG));
- SETMSG(HA_ERR_INDEX_CORRUPT, ER_DEFAULT(ER_INDEX_CORRUPT));
+ SETMSG(HA_ERR_INDEX_CORRUPT, ER_DEFAULT(ER_INDEX_CORRUPT));
+ SETMSG(HA_ERR_TABLE_IN_FK_CHECK, ER_DEFAULT(ER_TABLE_IN_FK_CHECK));
SETMSG(HA_ERR_DISK_FULL, ER_DEFAULT(ER_DISK_FULL));
/* Register the error messages for use with my_error(). */
@@ -3042,6 +3043,9 @@ void handler::print_error(int error, myf errflag)
case HA_ERR_UNDO_REC_TOO_BIG:
textno= ER_UNDO_RECORD_TOO_BIG;
break;
+ case HA_ERR_TABLE_IN_FK_CHECK:
+ textno= ER_TABLE_IN_FK_CHECK;
+ break;
default:
{
/* The error was "unknown" to this function.
diff --git a/sql/handler.h b/sql/handler.h
index 142139dbabc..ee1731af563 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -1042,6 +1042,7 @@ struct handlerton
const char *wild, bool dir, List<LEX_STRING> *files);
int (*table_exists_in_engine)(handlerton *hton, THD* thd, const char *db,
const char *name);
+
uint32 license; /* Flag for Engine License */
/*
Optional clauses in the CREATE/ALTER TABLE
diff --git a/sql/item.cc b/sql/item.cc
index 9400af0f79f..3af415fe5c2 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -8191,20 +8191,12 @@ bool Item_insert_value::fix_fields(THD *thd, Item **items)
}
if (arg->type() == REF_ITEM)
+ arg= static_cast<Item_ref *>(arg)->ref[0];
+ if (arg->type() != FIELD_ITEM)
{
- Item_ref *ref= (Item_ref *)arg;
- if (ref->ref[0]->type() != FIELD_ITEM)
- {
- my_error(ER_BAD_FIELD_ERROR, MYF(0), "", "VALUES() function");
- return TRUE;
- }
- arg= ref->ref[0];
+ my_error(ER_BAD_FIELD_ERROR, MYF(0), "", "VALUES() function");
+ return TRUE;
}
- /*
- According to our SQL grammar, VALUES() function can reference
- only to a column.
- */
- DBUG_ASSERT(arg->type() == FIELD_ITEM);
Item_field *field_arg= (Item_field *)arg;
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 276f35fe301..d7687c70134 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -265,6 +265,7 @@ bool Item_subselect::fix_fields(THD *thd_param, Item **ref)
(*ref)= substitution;
substitution->name= name;
+ substitution->name_length= name_length;
if (have_to_be_excluded)
engine->exclude();
substitution= 0;
diff --git a/sql/log_event.cc b/sql/log_event.cc
index f8fdbae6214..10d976e6b59 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -6061,6 +6061,11 @@ int Xid_log_event::do_apply_event(Relay_log_info const *rli)
res= trans_commit(thd); /* Automatically rolls back on error. */
thd->mdl_context.release_transactional_locks();
+ /*
+ Increment the global status commit count variable
+ */
+ status_var_increment(thd->status_var.com_stat[SQLCOM_COMMIT]);
+
return res;
}
@@ -8144,9 +8149,24 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli)
{
DBUG_PRINT("debug", ("Checking compability of tables to lock - tables_to_lock: %p",
rli->tables_to_lock));
+
+ /**
+ When using RBR and MyISAM MERGE tables the base tables that make
+ up the MERGE table can be appended to the list of tables to lock.
+
+ Thus, we just check compatibility for those that tables that have
+ a correspondent table map event (ie, those that are actually going
+ to be accessed while applying the event). That's why the loop stops
+ at rli->tables_to_lock_count .
+
+ NOTE: The base tables are added here are removed when
+ close_thread_tables is called.
+ */
RPL_TABLE_LIST *ptr= rli->tables_to_lock;
- for ( ; ptr ; ptr= static_cast<RPL_TABLE_LIST*>(ptr->next_global))
+ for (uint i= 0 ; ptr && (i < rli->tables_to_lock_count);
+ ptr= static_cast<RPL_TABLE_LIST*>(ptr->next_global), i++)
{
+ DBUG_ASSERT(ptr->m_tabledef_valid);
TABLE *conv_table;
if (!ptr->m_tabledef.compatible_with(thd, const_cast<Relay_log_info*>(rli),
ptr->table, &conv_table))
@@ -8184,10 +8204,10 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli)
Rows_log_event, we can invalidate the query cache for the
associated table.
*/
- for (TABLE_LIST *ptr= rli->tables_to_lock ; ptr ; ptr= ptr->next_global)
- {
+ TABLE_LIST *ptr= rli->tables_to_lock;
+ for (uint i=0 ; ptr && (i < rli->tables_to_lock_count); ptr= ptr->next_global, i++)
const_cast<Relay_log_info*>(rli)->m_table_map.set_table(ptr->table_id, ptr->table);
- }
+
#ifdef HAVE_QUERY_CACHE
query_cache.invalidate_locked_for_write(thd, rli->tables_to_lock);
#endif
@@ -9214,9 +9234,9 @@ check_table_map(Relay_log_info const *rli, RPL_TABLE_LIST *table_list)
res= FILTERED_OUT;
else
{
- for(RPL_TABLE_LIST *ptr= static_cast<RPL_TABLE_LIST*>(rli->tables_to_lock);
- ptr;
- ptr= static_cast<RPL_TABLE_LIST*>(ptr->next_local))
+ RPL_TABLE_LIST *ptr= static_cast<RPL_TABLE_LIST*>(rli->tables_to_lock);
+ for(uint i=0 ; ptr && (i< rli->tables_to_lock_count);
+ ptr= static_cast<RPL_TABLE_LIST*>(ptr->next_local), i++)
{
if (ptr->table_id == table_list->table_id)
{
@@ -9480,6 +9500,12 @@ Write_rows_log_event::do_before_row_operations(const Slave_reporting_capability
{
int error= 0;
+ /*
+ Increment the global status insert count variable
+ */
+ if (get_flags(STMT_END_F))
+ status_var_increment(thd->status_var.com_stat[SQLCOM_INSERT]);
+
/**
todo: to introduce a property for the event (handler?) which forces
applying the event in the replace (idempotent) fashion.
@@ -10483,6 +10509,12 @@ Delete_rows_log_event::Delete_rows_log_event(const char *buf, uint event_len,
int
Delete_rows_log_event::do_before_row_operations(const Slave_reporting_capability *const)
{
+ /*
+ Increment the global status delete count variable
+ */
+ if (get_flags(STMT_END_F))
+ status_var_increment(thd->status_var.com_stat[SQLCOM_DELETE]);
+
if ((m_table->file->ha_table_flags() & HA_PRIMARY_KEY_REQUIRED_FOR_POSITION) &&
m_table->s->primary_key < MAX_KEY)
{
@@ -10607,6 +10639,12 @@ Update_rows_log_event::Update_rows_log_event(const char *buf, uint event_len,
int
Update_rows_log_event::do_before_row_operations(const Slave_reporting_capability *const)
{
+ /*
+ Increment the global status update count variable
+ */
+ if (get_flags(STMT_END_F))
+ status_var_increment(thd->status_var.com_stat[SQLCOM_UPDATE]);
+
int err;
if ((err= find_key()))
return err;
diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc
index 104a77c65a7..040b35d28f1 100644
--- a/sql/log_event_old.cc
+++ b/sql/log_event_old.cc
@@ -126,8 +126,10 @@ Old_rows_log_event::do_apply_event(Old_rows_log_event *ev, const Relay_log_info
{
RPL_TABLE_LIST *ptr= rli->tables_to_lock;
- for ( ; ptr ; ptr= static_cast<RPL_TABLE_LIST*>(ptr->next_global))
+ for (uint i= 0 ; ptr&& (i< rli->tables_to_lock_count);
+ ptr= static_cast<RPL_TABLE_LIST*>(ptr->next_global), i++)
{
+ DBUG_ASSERT(ptr->m_tabledef_valid);
TABLE *conv_table;
if (!ptr->m_tabledef.compatible_with(thd, const_cast<Relay_log_info*>(rli),
ptr->table, &conv_table))
@@ -158,10 +160,9 @@ Old_rows_log_event::do_apply_event(Old_rows_log_event *ev, const Relay_log_info
Old_rows_log_event, we can invalidate the query cache for the
associated table.
*/
- for (TABLE_LIST *ptr= rli->tables_to_lock ; ptr ; ptr= ptr->next_global)
- {
+ TABLE_LIST *ptr= rli->tables_to_lock;
+ for (uint i=0; ptr && (i < rli->tables_to_lock_count); ptr= ptr->next_global, i++)
const_cast<Relay_log_info*>(rli)->m_table_map.set_table(ptr->table_id, ptr->table);
- }
#ifdef HAVE_QUERY_CACHE
query_cache.invalidate_locked_for_write(thd, rli->tables_to_lock);
#endif
@@ -1548,7 +1549,8 @@ int Old_rows_log_event::do_apply_event(Relay_log_info const *rli)
{
RPL_TABLE_LIST *ptr= rli->tables_to_lock;
- for ( ; ptr ; ptr= static_cast<RPL_TABLE_LIST*>(ptr->next_global))
+ for (uint i= 0 ; ptr&& (i< rli->tables_to_lock_count);
+ ptr= static_cast<RPL_TABLE_LIST*>(ptr->next_global), i++)
{
TABLE *conv_table;
if (ptr->m_tabledef.compatible_with(thd, const_cast<Relay_log_info*>(rli),
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 776a5a99dae..9decf82dc13 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -1345,13 +1345,13 @@ static void close_connections(void)
{
if (base_ip_sock != INVALID_SOCKET)
{
- (void) shutdown(base_ip_sock, SHUT_RDWR);
+ (void) mysql_socket_shutdown(base_ip_sock, SHUT_RDWR);
(void) closesocket(base_ip_sock);
base_ip_sock= INVALID_SOCKET;
}
if (extra_ip_sock != INVALID_SOCKET)
{
- (void) shutdown(extra_ip_sock, SHUT_RDWR);
+ (void) mysql_socket_shutdown(extra_ip_sock, SHUT_RDWR);
(void) closesocket(extra_ip_sock);
extra_ip_sock= INVALID_SOCKET;
}
@@ -1383,7 +1383,7 @@ static void close_connections(void)
#ifdef HAVE_SYS_UN_H
if (unix_sock != INVALID_SOCKET)
{
- (void) shutdown(unix_sock, SHUT_RDWR);
+ (void) mysql_socket_shutdown(unix_sock, SHUT_RDWR);
(void) closesocket(unix_sock);
(void) unlink(mysqld_unix_port);
unix_sock= INVALID_SOCKET;
@@ -1498,7 +1498,7 @@ static void close_socket(my_socket sock, const char *info)
if (sock != INVALID_SOCKET)
{
DBUG_PRINT("info", ("calling shutdown on %s socket", info));
- (void) shutdown(sock, SHUT_RDWR);
+ (void) mysql_socket_shutdown(sock, SHUT_RDWR);
#if defined(__NETWARE__)
/*
The following code is disabled for normal systems as it causes MySQL
@@ -2233,7 +2233,10 @@ static void network_init(void)
{
report_port= mysqld_port;
}
- DBUG_ASSERT(report_port != 0);
+#ifndef DBUG_OFF
+ if (!opt_disable_networking)
+ DBUG_ASSERT(report_port != 0);
+#endif
if (!opt_disable_networking && !opt_bootstrap)
{
if (mysqld_port)
@@ -5614,7 +5617,7 @@ void handle_connections_sockets()
if (req.sink)
((void (*)(int))req.sink)(req.fd);
- (void) shutdown(new_sock, SHUT_RDWR);
+ (void) mysql_socket_shutdown(new_sock, SHUT_RDWR);
(void) closesocket(new_sock);
continue;
}
@@ -5630,7 +5633,7 @@ void handle_connections_sockets()
(SOCKET_SIZE_TYPE *)&dummyLen) < 0 )
{
sql_perror("Error on new connection socket");
- (void) shutdown(new_sock, SHUT_RDWR);
+ (void) mysql_socket_shutdown(new_sock, SHUT_RDWR);
(void) closesocket(new_sock);
continue;
}
@@ -5642,7 +5645,7 @@ void handle_connections_sockets()
if (!(thd= new THD))
{
- (void) shutdown(new_sock, SHUT_RDWR);
+ (void) mysql_socket_shutdown(new_sock, SHUT_RDWR);
(void) closesocket(new_sock);
continue;
}
@@ -5661,7 +5664,7 @@ void handle_connections_sockets()
vio_delete(vio_tmp);
else
{
- (void) shutdown(new_sock, SHUT_RDWR);
+ (void) mysql_socket_shutdown(new_sock, SHUT_RDWR);
(void) closesocket(new_sock);
}
delete thd;
diff --git a/sql/rpl_rli.cc b/sql/rpl_rli.cc
index e1efbc7ee4c..940fc201bae 100644
--- a/sql/rpl_rli.cc
+++ b/sql/rpl_rli.cc
@@ -1268,6 +1268,23 @@ void Relay_log_info::cleanup_context(THD *thd, bool error)
void Relay_log_info::clear_tables_to_lock()
{
+ DBUG_ENTER("Relay_log_info::clear_tables_to_lock()");
+#ifndef DBUG_OFF
+ /**
+ When replicating in RBR and MyISAM Merge tables are involved
+ open_and_lock_tables (called in do_apply_event) appends the
+ base tables to the list of tables_to_lock. Then these are
+ removed from the list in close_thread_tables (which is called
+ before we reach this point).
+
+ This assertion just confirms that we get no surprises at this
+ point.
+ */
+ uint i=0;
+ for (TABLE_LIST *ptr= tables_to_lock ; ptr ; ptr= ptr->next_global, i++) ;
+ DBUG_ASSERT(i == tables_to_lock_count);
+#endif
+
while (tables_to_lock)
{
uchar* to_free= reinterpret_cast<uchar*>(tables_to_lock);
@@ -1292,10 +1309,12 @@ void Relay_log_info::clear_tables_to_lock()
my_free(to_free);
}
DBUG_ASSERT(tables_to_lock == NULL && tables_to_lock_count == 0);
+ DBUG_VOID_RETURN;
}
void Relay_log_info::slave_close_thread_tables(THD *thd)
{
+ DBUG_ENTER("Relay_log_info::slave_close_thread_tables(THD *thd)");
thd->stmt_da->can_overwrite_status= TRUE;
thd->is_error() ? trans_rollback_stmt(thd) : trans_commit_stmt(thd);
thd->stmt_da->can_overwrite_status= FALSE;
@@ -1317,5 +1336,6 @@ void Relay_log_info::slave_close_thread_tables(THD *thd)
thd->mdl_context.release_statement_locks();
clear_tables_to_lock();
+ DBUG_VOID_RETURN;
}
#endif
diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt
index 8510eb1f1ac..140220dfa9c 100644
--- a/sql/share/errmsg-utf8.txt
+++ b/sql/share/errmsg-utf8.txt
@@ -6492,6 +6492,15 @@ ER_BINLOG_UNSAFE_WRITE_AUTOINC_SELECT
ER_BINLOG_UNSAFE_CREATE_SELECT_AUTOINC
eng "CREATE TABLE... SELECT... on a table with an auto-increment column is unsafe because the order in which rows are retrieved by the SELECT determines which (if any) rows are inserted. This order cannot be predicted and may differ on master and the slave."
+ER_BINLOG_UNSAFE_INSERT_TWO_KEYS
+ eng "INSERT... ON DUPLICATE KEY UPDATE on a table with more than one UNIQUE KEY is unsafe"
+
+ER_TABLE_IN_FK_CHECK
+ eng "Table is being used in foreign key check."
+
+ER_UNUSED_1
+ eng "You should never see it"
+
#
# End of 5.5 error messages.
#
diff --git a/sql/spatial.cc b/sql/spatial.cc
index 4dfc20716fc..1616f93241d 100644
--- a/sql/spatial.cc
+++ b/sql/spatial.cc
@@ -716,7 +716,8 @@ int Gis_line_string::is_closed(int *closed) const
return 0;
}
data+= 4;
- if (no_data(data, POINT_DATA_SIZE * n_points))
+ if (n_points == 0 ||
+ no_data(data, POINT_DATA_SIZE * n_points))
return 1;
/* Get first point */
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index c5d11aa71f6..51b84f309c7 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -5746,6 +5746,32 @@ bool lock_tables(THD *thd, TABLE_LIST *tables, uint count,
has_write_table_with_auto_increment_and_select(tables))
thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_WRITE_AUTOINC_SELECT);
+ /*
+ INSERT...ON DUPLICATE KEY UPDATE on a table with more than one unique keys
+ can be unsafe.
+ */
+ uint unique_keys= 0;
+ for (TABLE_LIST *query_table= tables; query_table && unique_keys <= 1;
+ query_table= query_table->next_global)
+ if(query_table->table)
+ {
+ uint keys= query_table->table->s->keys, i= 0;
+ unique_keys= 0;
+ for (KEY* keyinfo= query_table->table->s->key_info;
+ i < keys && unique_keys <= 1; i++, keyinfo++)
+ {
+ if (keyinfo->flags & HA_NOSAME)
+ unique_keys++;
+ }
+ if (!query_table->placeholder() &&
+ query_table->lock_type >= TL_WRITE_ALLOW_WRITE &&
+ unique_keys > 1 && thd->lex->sql_command == SQLCOM_INSERT &&
+ /* Duplicate key update is not supported by INSERT DELAYED */
+ thd->command != COM_DELAYED_INSERT &&
+ thd->lex->duplicates == DUP_UPDATE)
+ thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_INSERT_TWO_KEYS);
+ }
+
/* We have to emulate LOCK TABLES if we are statement needs prelocking. */
if (thd->lex->requires_prelocking())
{
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 169c68c1918..a9375a4f05e 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -3015,13 +3015,42 @@ int select_exists_subselect::send_data(List<Item> &items)
int select_dumpvar::prepare(List<Item> &list, SELECT_LEX_UNIT *u)
{
unit= u;
+ List_iterator_fast<my_var> var_li(var_list);
+ List_iterator_fast<Item> it(list);
+ Item *item;
+ my_var *mv;
+ Item_func_set_user_var **suv;
if (var_list.elements != list.elements)
{
my_message(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT,
ER(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT), MYF(0));
return 1;
- }
+ }
+
+ /*
+ Iterate over the destination variables and mark them as being
+ updated in this query.
+ We need to do this at JOIN::prepare time to ensure proper
+ const detection of Item_func_get_user_var that is determined
+ by the presence of Item_func_set_user_vars
+ */
+
+ suv= set_var_items= (Item_func_set_user_var **)
+ sql_alloc(sizeof(Item_func_set_user_var *) * list.elements);
+
+ while ((mv= var_li++) && (item= it++))
+ {
+ if (!mv->local)
+ {
+ *suv= new Item_func_set_user_var(mv->s, item);
+ (*suv)->fix_fields(thd, 0);
+ }
+ else
+ *suv= NULL;
+ suv++;
+ }
+
return 0;
}
@@ -3341,6 +3370,7 @@ int select_dumpvar::send_data(List<Item> &items)
List_iterator<Item> it(items);
Item *item;
my_var *mv;
+ Item_func_set_user_var **suv;
DBUG_ENTER("select_dumpvar::send_data");
if (unit->offset_limit_cnt)
@@ -3353,20 +3383,19 @@ int select_dumpvar::send_data(List<Item> &items)
my_message(ER_TOO_MANY_ROWS, ER(ER_TOO_MANY_ROWS), MYF(0));
DBUG_RETURN(1);
}
- while ((mv= var_li++) && (item= it++))
+ for (suv= set_var_items; ((mv= var_li++) && (item= it++)); suv++)
{
if (mv->local)
{
+ DBUG_ASSERT(!*suv);
if (thd->spcont->set_variable(thd, mv->offset, &item))
DBUG_RETURN(1);
}
else
{
- Item_func_set_user_var *suv= new Item_func_set_user_var(mv->s, item);
- if (suv->fix_fields(thd, 0))
- DBUG_RETURN (1);
- suv->save_item_result(item);
- if (suv->update())
+ DBUG_ASSERT(*suv);
+ (*suv)->save_item_result(item);
+ if ((*suv)->update())
DBUG_RETURN (1);
}
}
diff --git a/sql/sql_class.h b/sql/sql_class.h
index c6c46975076..c88d8211986 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -3998,6 +3998,7 @@ public:
class select_dumpvar :public select_result_interceptor {
ha_rows row_count;
+ Item_func_set_user_var **set_var_items;
public:
List<my_var> var_list;
select_dumpvar() { var_list.empty(); row_count= 0;}
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 6fd6e53424f..ba189d89ccb 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -67,7 +67,8 @@ Query_tables_list::binlog_stmt_unsafe_errcode[BINLOG_STMT_UNSAFE_COUNT] =
ER_BINLOG_UNSAFE_CREATE_IGNORE_SELECT,
ER_BINLOG_UNSAFE_CREATE_REPLACE_SELECT,
ER_BINLOG_UNSAFE_CREATE_SELECT_AUTOINC,
- ER_BINLOG_UNSAFE_UPDATE_IGNORE
+ ER_BINLOG_UNSAFE_UPDATE_IGNORE,
+ ER_BINLOG_UNSAFE_INSERT_TWO_KEYS
};
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index f1ee6cf22ec..7da0cc48298 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -1427,6 +1427,12 @@ public:
*/
BINLOG_STMT_UNSAFE_UPDATE_IGNORE,
+ /**
+ INSERT... ON DUPLICATE KEY UPDATE on a table with more than one
+ UNIQUE KEYS is unsafe.
+ */
+ BINLOG_STMT_UNSAFE_INSERT_TWO_KEYS,
+
/* The last element of this enumeration type. */
BINLOG_STMT_UNSAFE_COUNT
};
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 2f8e3a8d97b..515a21505d9 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -5567,7 +5567,6 @@ best_access_path(JOIN *join,
tmp= best_time; // Do nothing
}
- DBUG_ASSERT(tmp > 0 || record_count == 0);
tmp += s->startup_cost;
loose_scan_opt.check_ref_access_part2(key, start_key, records, tmp);
} /* not ft_key */
@@ -7772,16 +7771,19 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j,
}
keyuse++;
} while (keyuse->table == table && keyuse->key == key);
+
+ if (!keyparts && allow_full_scan)
+ {
+ /* It's a LooseIndexScan strategy scanning whole index */
+ j->type= JT_ALL;
+ j->index= key;
+ DBUG_RETURN(FALSE);
+ }
+
+ DBUG_ASSERT(length > 0);
+ DBUG_ASSERT(keyparts != 0);
} /* not ftkey */
- if (!keyparts && allow_full_scan)
- {
- /* It's a LooseIndexScan strategy scanning whole index */
- j->type= JT_ALL;
- j->index= key;
- DBUG_RETURN(FALSE);
- }
-
/* set up fieldref */
j->ref.key_parts= keyparts;
j->ref.key_length= length;
@@ -18283,6 +18285,9 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
bool changed_key= false;
DBUG_ENTER("test_if_skip_sort_order");
+ /* Check that we are always called with first non-const table */
+ DBUG_ASSERT(tab == tab->join->join_tab + tab->join->const_tables);
+
/*
Keys disabled by ALTER TABLE ... DISABLE KEYS should have already
been taken into account.
@@ -18370,7 +18375,8 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
keyuse++;
if (create_ref_for_key(tab->join, tab, keyuse, FALSE,
- tab->join->const_table_map))
+ (tab->join->const_table_map |
+ OUTER_REF_TABLE_BIT)))
goto use_filesort;
pick_table_access_method(tab);
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 6e9d1709c8a..13411bea8a3 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -69,7 +69,7 @@ static int copy_data_between_tables(THD *thd, TABLE *,TABLE *,
enum enum_enable_or_disable, bool);
static bool prepare_blob_field(THD *thd, Create_field *sql_field);
-static bool check_engine(THD *, const char *, HA_CREATE_INFO *);
+static bool check_engine(THD *, const char *, const char *, HA_CREATE_INFO *);
static int mysql_prepare_create_table(THD *, HA_CREATE_INFO *, Alter_info *,
bool, uint *, handler *, KEY **, uint *,
int);
@@ -4049,7 +4049,7 @@ bool mysql_create_table_no_lock(THD *thd,
MYF(0));
DBUG_RETURN(TRUE);
}
- if (check_engine(thd, table_name, create_info))
+ if (check_engine(thd, db, table_name, create_info))
DBUG_RETURN(TRUE);
set_table_default_charset(thd, create_info, (char*) db);
@@ -6100,7 +6100,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
create_info->db_type= old_db_type;
}
- if (check_engine(thd, new_name, create_info))
+ if (check_engine(thd, new_db, new_name, create_info))
goto err;
new_db_type= create_info->db_type;
@@ -7571,16 +7571,32 @@ err:
DBUG_RETURN(TRUE);
}
-static bool check_engine(THD *thd, const char *table_name,
- HA_CREATE_INFO *create_info)
+/**
+ @brief Check if the table can be created in the specified storage engine.
+
+ Checks if the storage engine is enabled and supports the given table
+ type (e.g. normal, temporary, system). May do engine substitution
+ if the requested engine is disabled.
+
+ @param thd Thread descriptor.
+ @param db_name Database name.
+ @param table_name Name of table to be created.
+ @param create_info Create info from parser, including engine.
+
+ @retval true Engine not available/supported, error has been reported.
+ @retval false Engine available/supported.
+*/
+static bool check_engine(THD *thd, const char *db_name,
+ const char *table_name, HA_CREATE_INFO *create_info)
{
+ DBUG_ENTER("check_engine");
handlerton **new_engine= &create_info->db_type;
handlerton *req_engine= *new_engine;
bool no_substitution=
test(thd->variables.sql_mode & MODE_NO_ENGINE_SUBSTITUTION);
if (!(*new_engine= ha_checktype(thd, ha_legacy_type(req_engine),
no_substitution, 1)))
- return TRUE;
+ DBUG_RETURN(true);
if (req_engine && req_engine != *new_engine)
{
@@ -7598,9 +7614,10 @@ static bool check_engine(THD *thd, const char *table_name,
my_error(ER_ILLEGAL_HA_CREATE_OPTION, MYF(0),
hton_name(*new_engine)->str, "TEMPORARY");
*new_engine= 0;
- return TRUE;
+ DBUG_RETURN(true);
}
*new_engine= myisam_hton;
}
- return FALSE;
+
+ DBUG_RETURN(false);
}