summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/Makefile.am4
-rw-r--r--sql/client_settings.h1
-rw-r--r--sql/field.cc54
-rw-r--r--sql/field.h6
-rw-r--r--sql/field_conv.cc5
-rw-r--r--sql/filesort.cc4
-rw-r--r--sql/gen_lex_hash.cc2
-rw-r--r--sql/ha_innodb.cc586
-rw-r--r--sql/ha_innodb.h24
-rw-r--r--sql/ha_myisam.cc28
-rw-r--r--sql/handler.cc74
-rw-r--r--sql/handler.h38
-rw-r--r--sql/item.cc125
-rw-r--r--sql/item.h100
-rw-r--r--sql/item_buff.cc2
-rw-r--r--sql/item_cmpfunc.cc139
-rw-r--r--sql/item_cmpfunc.h19
-rw-r--r--sql/item_create.cc10
-rw-r--r--sql/item_create.h2
-rw-r--r--sql/item_func.cc109
-rw-r--r--sql/item_func.h5
-rw-r--r--sql/item_strfunc.cc105
-rw-r--r--sql/item_strfunc.h26
-rw-r--r--sql/item_subselect.cc57
-rw-r--r--sql/item_subselect.h5
-rw-r--r--sql/item_sum.cc13
-rw-r--r--sql/item_timefunc.cc235
-rw-r--r--sql/item_timefunc.h113
-rw-r--r--sql/lex.h4
-rw-r--r--sql/log.cc429
-rw-r--r--sql/log_event.cc362
-rw-r--r--sql/log_event.h30
-rw-r--r--sql/mysql_priv.h29
-rw-r--r--sql/mysqld.cc220
-rw-r--r--sql/net_serv.cc21
-rw-r--r--sql/opt_range.cc12
-rw-r--r--sql/protocol.cc37
-rw-r--r--sql/protocol.h2
-rw-r--r--sql/records.cc8
-rw-r--r--sql/repl_failsafe.cc3
-rw-r--r--sql/set_var.cc157
-rw-r--r--sql/set_var.h39
-rw-r--r--sql/share/charsets/Index.xml9
-rw-r--r--sql/share/charsets/cp1251.xml8
-rw-r--r--sql/share/charsets/geostd8.xml121
-rw-r--r--sql/share/czech/errmsg.txt12
-rw-r--r--sql/share/danish/errmsg.txt12
-rw-r--r--sql/share/dutch/errmsg.txt12
-rw-r--r--sql/share/english/errmsg.txt14
-rw-r--r--sql/share/estonian/errmsg.txt12
-rw-r--r--sql/share/french/errmsg.txt12
-rw-r--r--sql/share/german/errmsg.txt12
-rw-r--r--sql/share/greek/errmsg.txt12
-rw-r--r--sql/share/hungarian/errmsg.txt12
-rw-r--r--sql/share/italian/errmsg.txt12
-rw-r--r--sql/share/japanese/errmsg.txt12
-rw-r--r--sql/share/korean/errmsg.txt12
-rw-r--r--sql/share/norwegian-ny/errmsg.txt12
-rw-r--r--sql/share/norwegian/errmsg.txt12
-rw-r--r--sql/share/polish/errmsg.txt12
-rw-r--r--sql/share/portuguese/errmsg.txt12
-rw-r--r--sql/share/romanian/errmsg.txt12
-rw-r--r--sql/share/russian/errmsg.txt12
-rw-r--r--sql/share/serbian/errmsg.txt11
-rw-r--r--sql/share/slovak/errmsg.txt12
-rw-r--r--sql/share/spanish/errmsg.txt26
-rw-r--r--sql/share/swedish/errmsg.txt14
-rw-r--r--sql/share/ukrainian/errmsg.txt12
-rw-r--r--sql/slave.cc483
-rw-r--r--sql/slave.h31
-rw-r--r--sql/sql_acl.cc460
-rw-r--r--sql/sql_acl.h6
-rw-r--r--sql/sql_analyse.cc12
-rw-r--r--sql/sql_base.cc29
-rw-r--r--sql/sql_cache.cc10
-rw-r--r--sql/sql_cache.h2
-rw-r--r--sql/sql_class.cc57
-rw-r--r--sql/sql_class.h65
-rw-r--r--sql/sql_db.cc16
-rw-r--r--sql/sql_delete.cc13
-rw-r--r--sql/sql_derived.cc20
-rw-r--r--sql/sql_handler.cc9
-rw-r--r--sql/sql_lex.cc19
-rw-r--r--sql/sql_lex.h34
-rw-r--r--sql/sql_list.cc15
-rw-r--r--sql/sql_list.h37
-rw-r--r--sql/sql_parse.cc207
-rw-r--r--sql/sql_repl.cc176
-rw-r--r--sql/sql_repl.h2
-rw-r--r--sql/sql_select.cc150
-rw-r--r--sql/sql_select.h3
-rw-r--r--sql/sql_show.cc8
-rw-r--r--sql/sql_table.cc83
-rw-r--r--sql/sql_union.cc84
-rw-r--r--sql/sql_update.cc9
-rw-r--r--sql/sql_yacc.yy320
-rw-r--r--sql/table.cc44
-rw-r--r--sql/table.h4
-rw-r--r--sql/uniques.cc6
-rw-r--r--sql/unireg.h7
100 files changed, 4055 insertions, 2041 deletions
diff --git a/sql/Makefile.am b/sql/Makefile.am
index 5781b6181d2..69b9c58dd6d 100644
--- a/sql/Makefile.am
+++ b/sql/Makefile.am
@@ -123,8 +123,8 @@ sql_yacc.o: sql_yacc.cc sql_yacc.h $(HEADERS)
$(CXXCOMPILE) $(LM_CFLAGS) -c $<
lex_hash.h: lex.h gen_lex_hash.cc sql_yacc.h
- $(MAKE) gen_lex_hash
- ./gen_lex_hash > $@
+ $(MAKE) gen_lex_hash$(EXEEXT)
+ ./gen_lex_hash$(EXEEXT) > $@
# Hack to ensure that lex_hash.h is built early
sql_lex.o: lex_hash.h
diff --git a/sql/client_settings.h b/sql/client_settings.h
index efae3f18a8b..b357e52ec9d 100644
--- a/sql/client_settings.h
+++ b/sql/client_settings.h
@@ -31,3 +31,4 @@
#define mysql_rpl_probe(mysql) 0
#undef HAVE_SMEM
#undef _CUSTOMCONFIG_
+
diff --git a/sql/field.cc b/sql/field.cc
index 2f89dd43c3f..051a4fa8057 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -3905,7 +3905,8 @@ int Field_string::store(const char *from,uint length,CHARSET_INFO *cs)
{
memcpy(ptr,from,length);
if (length < field_length)
- field_charset->cset->fill(field_charset,ptr+length,field_length-length,' ');
+ field_charset->cset->fill(field_charset,ptr+length,field_length-length,
+ ' ');
}
else
{
@@ -3914,7 +3915,8 @@ int Field_string::store(const char *from,uint length,CHARSET_INFO *cs)
{ // Check if we loosed some info
const char *end=from+length;
from+= field_length;
- from+= field_charset->cset->scan(field_charset, from, end, MY_SEQ_SPACES);
+ from+= field_charset->cset->scan(field_charset, from, end,
+ MY_SEQ_SPACES);
if (from != end)
{
set_warning(MYSQL_ERROR::WARN_LEVEL_WARN, ER_WARN_DATA_TRUNCATED);
@@ -4012,7 +4014,7 @@ void Field_string::sql_type(String &res) const
(table->db_options_in_use &
HA_OPTION_PACK_RECORD) ?
"varchar" : "char"),
- (int) field_length);
+ (int) field_length / charset()->mbmaxlen);
res.length(length);
}
@@ -4178,7 +4180,7 @@ void Field_varstring::sql_type(String &res) const
CHARSET_INFO *cs=res.charset();
ulong length= cs->cset->snprintf(cs,(char*) res.ptr(),
res.alloced_length(),"varchar(%u)",
- field_length);
+ field_length / charset()->mbmaxlen);
res.length(length);
}
@@ -5147,7 +5149,8 @@ int Field_set::store(const char *from,uint length,CHARSET_INFO *cs)
from= tmpstr.ptr();
length= tmpstr.length();
}
- ulonglong tmp= find_set(typelib, from, length, &not_used, &not_used2, &set_warning);
+ ulonglong tmp= find_set(typelib, from, length, &not_used, &not_used2,
+ &set_warning);
if (!tmp && length && length < 22)
{
/* This is for reading numbers with LOAD DATA INFILE */
@@ -5157,10 +5160,14 @@ int Field_set::store(const char *from,uint length,CHARSET_INFO *cs)
tmp > (ulonglong) (((longlong) 1 << typelib->count) - (longlong) 1))
{
tmp=0;
- current_thd->cuted_fields++;
- push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
- ER_WARN_DATA_TRUNCATED, ER(ER_WARN_DATA_TRUNCATED),
- field_name, 0);
+ THD *thd= current_thd;
+ if (thd->count_cuted_fields)
+ {
+ thd->cuted_fields++;
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_WARN_DATA_TRUNCATED, ER(ER_WARN_DATA_TRUNCATED),
+ field_name, 0);
+ }
}
}
store_type(tmp);
@@ -5267,6 +5274,26 @@ bool Field_num::eq_def(Field *field)
** Handling of field and create_field
*****************************************************************************/
+void create_field::create_length_to_internal_length(void)
+{
+ switch (sql_type)
+ {
+ case MYSQL_TYPE_TINY_BLOB:
+ case MYSQL_TYPE_MEDIUM_BLOB:
+ case MYSQL_TYPE_LONG_BLOB:
+ case MYSQL_TYPE_BLOB:
+ case MYSQL_TYPE_VAR_STRING:
+ case MYSQL_TYPE_STRING:
+ length*= charset->mbmaxlen;
+ pack_length= calc_pack_length(sql_type == FIELD_TYPE_VAR_STRING ?
+ FIELD_TYPE_STRING : sql_type, length);
+ break;
+ default:
+ /* do nothing */
+ break;
+ }
+}
+
/*
Make a field from the .frm file info
*/
@@ -5496,7 +5523,10 @@ create_field::create_field(Field *old_field,Field *orig_field)
void Field::set_warning(const uint level, const uint code)
{
THD *thd= current_thd;
- thd->cuted_fields++;
- push_warning_printf(thd, (MYSQL_ERROR::enum_warning_level) level,
- code, ER(code), field_name, thd->row_count);
+ if (thd->count_cuted_fields)
+ {
+ thd->cuted_fields++;
+ push_warning_printf(thd, (MYSQL_ERROR::enum_warning_level) level,
+ code, ER(code), field_name, thd->row_count);
+ }
}
diff --git a/sql/field.h b/sql/field.h
index 5df7d554c35..794b4a89542 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -1066,6 +1066,7 @@ public:
uint offset,pack_flag;
create_field() :after(0) {}
create_field(Field *field, Field *orig_field);
+ void create_length_to_internal_length(void);
};
@@ -1132,7 +1133,7 @@ bool test_if_int(const char *str, int length, const char *int_end,
*/
#define FIELDFLAG_DECIMAL 1
-#define FIELDFLAG_BINARY 1 // Shares same flag
+#define FIELDFLAG_BINARY 1 // Shares same flag
#define FIELDFLAG_NUMBER 2
#define FIELDFLAG_ZEROFILL 4
#define FIELDFLAG_PACK 120 // Bits used for packing
@@ -1163,7 +1164,8 @@ bool test_if_int(const char *str, int length, const char *int_end,
#define f_packtype(x) (((x) >> FIELDFLAG_PACK_SHIFT) & 15)
#define f_decimals(x) ((uint8) (((x) >> FIELDFLAG_DEC_SHIFT) & FIELDFLAG_MAX_DEC))
#define f_is_alpha(x) (!f_is_num(x))
-#define f_is_enum(x) ((x) & FIELDFLAG_INTERVAL)
+#define f_is_binary(x) ((x) & FIELDFLAG_BINARY) // 4.0- compatibility
+#define f_is_enum(x) ((x) & FIELDFLAG_INTERVAL)
#define f_is_bitfield(x) ((x) & FIELDFLAG_BITFIELD)
#define f_is_blob(x) (((x) & (FIELDFLAG_BLOB | FIELDFLAG_NUMBER)) == FIELDFLAG_BLOB)
#define f_is_geom(x) ((x) & FIELDFLAG_GEOM)
diff --git a/sql/field_conv.cc b/sql/field_conv.cc
index 144e6d7e74a..6510a03f5a6 100644
--- a/sql/field_conv.cc
+++ b/sql/field_conv.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2003 MySQL AB
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
@@ -172,7 +172,10 @@ set_field_to_null_with_conversions(Field *field, bool no_conversions)
}
field->reset();
if (field == field->table->next_number_field)
+ {
+ field->table->auto_increment_field_not_null= false;
return 0; // field is set in handler.cc
+ }
if (current_thd->count_cuted_fields)
{
field->set_warning(MYSQL_ERROR::WARN_LEVEL_WARN,ER_WARN_NULL_TO_NOTNULL);
diff --git a/sql/filesort.cc b/sql/filesort.cc
index 2130bdaeb93..13989bdae8f 100644
--- a/sql/filesort.cc
+++ b/sql/filesort.cc
@@ -519,7 +519,7 @@ static void make_sortkey(register SORTPARAM *param,
switch (sort_field->result_type) {
case STRING_RESULT:
{
- CHARSET_INFO *cs=item->charset();
+ CHARSET_INFO *cs=item->collation.collation;
if ((maybe_null=item->maybe_null))
*to++=1;
/* All item->str() to use some extra byte for end null.. */
@@ -1040,7 +1040,7 @@ sortlength(SORT_FIELD *sortorder, uint s_length, bool *multi_byte_charset)
switch ((sortorder->result_type=sortorder->item->result_type())) {
case STRING_RESULT:
sortorder->length=sortorder->item->max_length;
- if (use_strnxfrm((cs=sortorder->item->charset())))
+ if (use_strnxfrm((cs=sortorder->item->collation.collation)))
{
sortorder->length= sortorder->length*cs->strxfrm_multiply;
sortorder->need_strxnfrm= 1;
diff --git a/sql/gen_lex_hash.cc b/sql/gen_lex_hash.cc
index ae46bcc9ea5..dc4f23db3b2 100644
--- a/sql/gen_lex_hash.cc
+++ b/sql/gen_lex_hash.cc
@@ -89,7 +89,7 @@ static struct my_option my_long_options[] =
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
{"version", 'V', "Output version information and exit",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
- { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
+ {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
};
struct hash_lex_struct
diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc
index 1cf123dbec6..d870d0debfd 100644
--- a/sql/ha_innodb.cc
+++ b/sql/ha_innodb.cc
@@ -42,7 +42,9 @@ InnoDB */
pthread_mutex_t innobase_mutex;
/* Store MySQL definition of 'byte': in Linux it is char while InnoDB
-uses unsigned char */
+uses unsigned char; the header univ.i which we include next defines
+'byte' as a macro which expands to 'unsigned char' */
+
typedef byte mysql_byte;
#define INSIDE_HA_INNOBASE_CC
@@ -130,11 +132,44 @@ static void innobase_print_error(const char* db_errpfx, char* buffer);
/* General functions */
/**********************************************************************
+Save some CPU by testing the value of srv_thread_concurrency in inline
+functions. */
+inline
+void
+innodb_srv_conc_enter_innodb(
+/*=========================*/
+ trx_t* trx) /* in: transaction handle */
+{
+ if (srv_thread_concurrency >= 500) {
+
+ return;
+ }
+
+ srv_conc_enter_innodb(trx);
+}
+
+/**********************************************************************
+Save some CPU by testing the value of srv_thread_concurrency in inline
+functions. */
+inline
+void
+innodb_srv_conc_exit_innodb(
+/*========================*/
+ trx_t* trx) /* in: transaction handle */
+{
+ if (srv_thread_concurrency >= 500) {
+
+ return;
+ }
+
+ srv_conc_exit_innodb(trx);
+}
+
+/**********************************************************************
Releases possible search latch and InnoDB thread FIFO ticket. These should
be released at each SQL statement end, and also when mysqld passes the
control to the client. It does no harm to release these also in the middle
of an SQL statement. */
-static
inline
void
innobase_release_stat_resources(
@@ -183,7 +218,9 @@ innobase_active_small(void)
}
/************************************************************************
-Converts an InnoDB error code to a MySQL error code. */
+Converts an InnoDB error code to a MySQL error code and also tells to MySQL
+about a possible transaction rollback inside InnoDB caused by a lock wait
+timeout or a deadlock. */
static
int
convert_error_code_to_mysql(
@@ -206,10 +243,10 @@ convert_error_code_to_mysql(
} else if (error == (int) DB_ERROR) {
- return(HA_ERR_NO_ACTIVE_RECORD);
+ return(-1); /* unspecified error */
} else if (error == (int) DB_DEADLOCK) {
- /* Since we roll back the whole transaction, we must
+ /* Since we rolled back the whole transaction, we must
tell it also to MySQL so that MySQL knows to empty the
cached binlog for this transaction */
@@ -221,11 +258,10 @@ convert_error_code_to_mysql(
} else if (error == (int) DB_LOCK_WAIT_TIMEOUT) {
- /* Since we roll back the whole transaction, we must
+ /* Since we rolled back the whole transaction, we must
tell it also to MySQL so that MySQL knows to empty the
cached binlog for this transaction */
-
if (thd) {
ha_rollback(thd);
}
@@ -271,6 +307,9 @@ convert_error_code_to_mysql(
} else if (error == (int) DB_CORRUPTION) {
return(HA_ERR_CRASHED);
+ } else if (error == (int) DB_NO_SAVEPOINT) {
+
+ return(HA_ERR_NO_SAVEPOINT);
} else {
return(-1); // Unknown error
}
@@ -624,6 +663,8 @@ ha_innobase::init_table_handle_for_HANDLER(void)
prebuilt = (row_prebuilt_t*)innobase_prebuilt;
+ innobase_release_stat_resources(prebuilt->trx);
+
/* If the transaction is not started yet, start it */
trx_start_if_not_started_noninline(prebuilt->trx);
@@ -891,7 +932,7 @@ innobase_flush_logs(void)
DBUG_ENTER("innobase_flush_logs");
- log_write_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP, TRUE);
+ log_buffer_flush_to_disk();
DBUG_RETURN(result);
}
@@ -960,17 +1001,28 @@ innobase_commit(
DBUG_ENTER("innobase_commit");
DBUG_PRINT("trans", ("ending transaction"));
- /* The flag thd->transaction.all.innodb_active_trans is set to 1
- in ::external_lock and ::start_stmt, and it is only set to 0 in
- a commit or a rollback. If it is 0 we know there cannot be resources
- to be freed and we can return immediately. */
+ trx = check_trx_exists(thd);
- if (thd->transaction.all.innodb_active_trans == 0) {
+ /* Release a possible FIFO ticket and search latch. Since we will
+ reserve the kernel mutex, we have to release the search system latch
+ first to obey the latching order. */
- DBUG_RETURN(0);
- }
+ innobase_release_stat_resources(trx);
- trx = check_trx_exists(thd);
+ /* The flag thd->transaction.all.innodb_active_trans is set to 1 in
+ ::external_lock, ::start_stmt, and innobase_savepoint, and it is only
+ set to 0 in a commit or a rollback. If it is 0 we know there cannot be
+ resources to be freed and we could return immediately. For the time
+ being we play safe and do the cleanup though there should be nothing
+ to clean up. */
+
+ if (thd->transaction.all.innodb_active_trans == 0
+ && trx->conc_state != TRX_NOT_STARTED) {
+
+ fprintf(stderr,
+"InnoDB: Error: thd->transaction.all.innodb_active_trans == 0\n"
+"InnoDB: but trx->conc_state != TRX_NOT_STARTED\n");
+ }
if (trx_handle != (void*)&innodb_dummy_stmt_trx_handle
|| (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))) {
@@ -983,9 +1035,7 @@ innobase_commit(
/* If we had reserved the auto-inc lock for some
table in this SQL statement we release it now */
- srv_conc_enter_innodb(trx);
row_unlock_table_autoinc_for_mysql(trx);
- srv_conc_exit_innodb(trx);
}
/* Store the current undo_no of the transaction so that we
know where to roll back if we have to roll back the next
@@ -994,9 +1044,6 @@ innobase_commit(
trx_mark_sql_stat_end(trx);
}
- /* Release a possible FIFO ticket and search latch */
- innobase_release_stat_resources(trx);
-
/* Tell the InnoDB server that there might be work for utility
threads: */
@@ -1069,7 +1116,7 @@ innobase_commit_complete(
}
/*********************************************************************
-Rolls back a transaction or the latest SQL statement in an InnoDB database. */
+Rolls back a transaction or the latest SQL statement. */
int
innobase_rollback(
@@ -1089,54 +1136,138 @@ innobase_rollback(
trx = check_trx_exists(thd);
+ /* Release a possible FIFO ticket and search latch. Since we will
+ reserve the kernel mutex, we have to release the search system latch
+ first to obey the latching order. */
+
+ innobase_release_stat_resources(trx);
+
if (trx->auto_inc_lock) {
-
- /* If we had reserved the auto-inc lock for
- some table in this SQL statement, we release it now */
-
- srv_conc_enter_innodb(trx);
+ /* If we had reserved the auto-inc lock for some table (if
+ we come here to roll back the latest SQL statement) we
+ release it now before a possibly lengthy rollback */
+
row_unlock_table_autoinc_for_mysql(trx);
- srv_conc_exit_innodb(trx);
}
- srv_conc_enter_innodb(trx);
+ if (trx_handle != (void*)&innodb_dummy_stmt_trx_handle
+ || (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))) {
- if (trx_handle != (void*)&innodb_dummy_stmt_trx_handle) {
error = trx_rollback_for_mysql(trx);
- thd->transaction.all.innodb_active_trans=0;
+ thd->transaction.all.innodb_active_trans = 0;
} else {
error = trx_rollback_last_sql_stat_for_mysql(trx);
}
- srv_conc_exit_innodb(trx);
+ DBUG_RETURN(convert_error_code_to_mysql(error, NULL));
+}
+
+/*********************************************************************
+Rolls back a transaction to a savepoint. */
+
+int
+innobase_rollback_to_savepoint(
+/*===========================*/
+ /* out: 0 if success, HA_ERR_NO_SAVEPOINT if
+ no savepoint with the given name */
+ THD* thd, /* in: handle to the MySQL thread of the user
+ whose transaction should be rolled back */
+ char* savepoint_name, /* in: savepoint name */
+ my_off_t* binlog_cache_pos)/* out: position which corresponds to the
+ savepoint in the binlog cache of this
+ transaction, not defined if error */
+{
+ ib_longlong mysql_binlog_cache_pos;
+ int error = 0;
+ trx_t* trx;
+
+ DBUG_ENTER("innobase_rollback_to_savepoint");
+
+ trx = check_trx_exists(thd);
+
+ /* Release a possible FIFO ticket and search latch. Since we will
+ reserve the kernel mutex, we have to release the search system latch
+ first to obey the latching order. */
- /* Release a possible FIFO ticket and search latch */
innobase_release_stat_resources(trx);
+ error = trx_rollback_to_savepoint_for_mysql(trx, savepoint_name,
+ &mysql_binlog_cache_pos);
+
+ *binlog_cache_pos = (my_off_t)mysql_binlog_cache_pos;
+
DBUG_RETURN(convert_error_code_to_mysql(error, NULL));
}
/*********************************************************************
-Frees a possible InnoDB trx object associated with the current
-THD. */
+Sets a transaction savepoint. */
+
+int
+innobase_savepoint(
+/*===============*/
+ /* out: always 0, that is, always succeeds */
+ THD* thd, /* in: handle to the MySQL thread */
+ char* savepoint_name, /* in: savepoint name */
+ my_off_t binlog_cache_pos)/* in: offset up to which the current
+ transaction has cached log entries to its
+ binlog cache, not defined if no transaction
+ active, or we are in the autocommit state, or
+ binlogging is not switched on */
+{
+ int error = 0;
+ trx_t* trx;
+
+ DBUG_ENTER("innobase_savepoint");
+
+ if (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) {
+ /* In the autocommit state there is no sense to set a
+ savepoint: we return immediate success */
+ DBUG_RETURN(0);
+ }
+
+ trx = check_trx_exists(thd);
+
+ /* Release a possible FIFO ticket and search latch. Since we will
+ reserve the kernel mutex, we have to release the search system latch
+ first to obey the latching order. */
+
+ innobase_release_stat_resources(trx);
+
+ /* Setting a savepoint starts a transaction inside InnoDB since
+ it allocates resources for it (memory to store the savepoint name,
+ for example) */
+
+ thd->transaction.all.innodb_active_trans = 1;
+
+ error = trx_savepoint_for_mysql(trx, savepoint_name,
+ (ib_longlong)binlog_cache_pos);
+
+ DBUG_RETURN(convert_error_code_to_mysql(error, NULL));
+}
+
+/*********************************************************************
+Frees a possible InnoDB trx object associated with the current THD. */
int
innobase_close_connection(
/*======================*/
- /* out: 0 or error number */
- THD* thd) /* in: handle to the MySQL thread of the user
- whose transaction should be rolled back */
+ /* out: 0 or error number */
+ THD* thd) /* in: handle to the MySQL thread of the user
+ whose transaction should be rolled back */
{
- if (NULL != thd->transaction.all.innobase_tid) {
+ trx_t* trx;
- trx_rollback_for_mysql((trx_t*)
- (thd->transaction.all.innobase_tid));
- trx_free_for_mysql((trx_t*)
- (thd->transaction.all.innobase_tid));
- thd->transaction.all.innobase_tid = NULL;
- }
+ trx = (trx_t*)thd->transaction.all.innobase_tid;
- return(0);
+ if (NULL != trx) {
+ innobase_rollback(thd, (void*)trx);
+
+ trx_free_for_mysql(trx);
+
+ thd->transaction.all.innobase_tid = NULL;
+ }
+
+ return(0);
}
/**********************************************************************
@@ -1239,7 +1370,6 @@ ha_innobase::open(
{
dict_table_t* ib_table;
int error = 0;
- uint buff_len;
char norm_name[1000];
DBUG_ENTER("ha_innobase::open");
@@ -1264,11 +1394,11 @@ ha_innobase::open(
fields when packed actually became 1 byte longer, when we also
stored the string length as the first byte. */
- buff_len = table->reclength + table->max_key_length
+ upd_and_key_val_buff_len = table->reclength + table->max_key_length
+ MAX_REF_PARTS * 3;
if (!(mysql_byte*) my_multi_malloc(MYF(MY_WME),
- &upd_buff, buff_len,
- &key_val_buff, buff_len,
+ &upd_buff, upd_and_key_val_buff_len,
+ &key_val_buff, upd_and_key_val_buff_len,
NullS)) {
free_share(share);
DBUG_RETURN(1);
@@ -1519,8 +1649,12 @@ innobase_mysql_cmp(
case FIELD_TYPE_STRING:
case FIELD_TYPE_VAR_STRING:
- // BAR TODO: Discuss with heikki.tuuri@innodb.com
- // so that he sends CHARSET_INFO for the field to this function.
+ case FIELD_TYPE_TINY_BLOB:
+ case FIELD_TYPE_MEDIUM_BLOB:
+ case FIELD_TYPE_BLOB:
+ case FIELD_TYPE_LONG_BLOB:
+ // BAR TODO: Discuss with heikki.tuuri@innodb.com
+ // so that he sends CHARSET_INFO for the field to this function.
ret = my_strnncoll(default_charset_info,
a, a_length,
b, b_length);
@@ -1548,7 +1682,7 @@ get_innobase_type_from_mysql_type(
/* out: DATA_BINARY, DATA_VARCHAR, ... */
Field* field) /* in: MySQL field */
{
- /* The following asserts check that MySQL type code fits in
+ /* The following asserts check that the MySQL type code fits in
8 bits: this is used in ibuf and also when DATA_NOT_NULL is
ORed to the type */
@@ -1559,6 +1693,8 @@ get_innobase_type_from_mysql_type(
DBUG_ASSERT((ulint)FIELD_TYPE_DECIMAL < 256);
switch (field->type()) {
+ /* NOTE that we only allow string types in DATA_MYSQL
+ and DATA_VARMYSQL */
case FIELD_TYPE_VAR_STRING: if (field->binary()) {
return(DATA_BINARY);
@@ -1612,8 +1748,7 @@ get_innobase_type_from_mysql_type(
}
/***********************************************************************
-Stores a key value for a row to a buffer. This must currently only be used
-to store a row reference to the 'ref' buffer of this table handle! */
+Stores a key value for a row to a buffer. */
uint
ha_innobase::store_key_val_for_row(
@@ -1621,41 +1756,108 @@ ha_innobase::store_key_val_for_row(
/* out: key value length as stored in buff */
uint keynr, /* in: key number */
char* buff, /* in/out: buffer for the key value (in MySQL
- format); currently this MUST be the 'ref'
- buffer! */
+ format) */
+ uint buff_len,/* in: buffer length */
const mysql_byte* record)/* in: row in MySQL format */
{
KEY* key_info = table->key_info + keynr;
KEY_PART_INFO* key_part = key_info->key_part;
KEY_PART_INFO* end = key_part + key_info->key_parts;
char* buff_start = buff;
+ enum_field_types mysql_type;
+ Field* field;
+ ulint blob_len;
+ byte* blob_data;
+ ibool is_null;
DBUG_ENTER("store_key_val_for_row");
+ /* The format for storing a key field in MySQL is the following:
+
+ 1. If the column can be NULL, then in the first byte we put 1 if the
+ field value is NULL, 0 otherwise.
+
+ 2. If the column is of a BLOB type (it must be a column prefix field
+ in this case), then we put the length of the data in the field to the
+ next 2 bytes, in the little-endian format. If the field is SQL NULL,
+ then these 2 bytes are set to 0. Note that the length of data in the
+ field is <= column prefix length.
+
+ 3. In a column prefix field, prefix_len next bytes are reserved for
+ data. In a normal field the max field length next bytes are reserved
+ for data. For a VARCHAR(n) the max field length is n. If the stored
+ value is the SQL NULL then these data bytes are set to 0. */
+
+ /* We have to zero-fill the buffer so that MySQL is able to use a
+ simple memcmp to compare two key values to determine if they are
+ equal. MySQL does this to compare contents of two 'ref' values. */
+
+ bzero(buff, buff_len);
+
for (; key_part != end; key_part++) {
+ is_null = FALSE;
if (key_part->null_bit) {
- /* Store 0 if the key part is a NULL part */
-
if (record[key_part->null_offset]
& key_part->null_bit) {
- *buff++ = 1;
- continue;
- }
-
- *buff++ = 0;
+ *buff = 1;
+ is_null = TRUE;
+ } else {
+ *buff = 0;
+ }
+ buff++;
}
- memcpy(buff, record + key_part->offset, key_part->length);
- buff += key_part->length;
+ field = key_part->field;
+ mysql_type = field->type();
+
+ if (mysql_type == FIELD_TYPE_TINY_BLOB
+ || mysql_type == FIELD_TYPE_MEDIUM_BLOB
+ || mysql_type == FIELD_TYPE_BLOB
+ || mysql_type == FIELD_TYPE_LONG_BLOB) {
+
+ ut_a(key_part->key_part_flag & HA_PART_KEY);
+
+ if (is_null) {
+ buff += key_part->length + 2;
+
+ continue;
+ }
+
+ blob_data = row_mysql_read_blob_ref(&blob_len,
+ (byte*) (record
+ + (ulint)get_field_offset(table, field)),
+ (ulint) field->pack_length());
+
+ ut_a(get_field_offset(table, field)
+ == key_part->offset);
+ if (blob_len > key_part->length) {
+ blob_len = key_part->length;
+ }
+
+ /* MySQL reserves 2 bytes for the length and the
+ storage of the number is little-endian */
+
+ ut_a(blob_len < 256);
+ *((byte*)buff) = (byte)blob_len;
+ buff += 2;
+
+ memcpy(buff, blob_data, blob_len);
+
+ buff += key_part->length;
+ } else {
+ if (is_null) {
+ buff += key_part->length;
+
+ continue;
+ }
+ memcpy(buff, record + key_part->offset,
+ key_part->length);
+ buff += key_part->length;
+ }
}
- /*
- We have to zero-fill the 'ref' buffer so that MySQL is able to
- use a simple memcmp to compare two key values to determine if they
- are equal
- */
- bzero(buff, (ref_length- (uint) (buff - buff_start)));
+ ut_a(buff <= buff_start + buff_len);
DBUG_RETURN((uint)(buff - buff_start));
}
@@ -1693,7 +1895,11 @@ build_template(
if (prebuilt->read_just_key) {
/* MySQL has instructed us that it is enough to
- fetch the columns in the key */
+ fetch the columns in the key; looks like MySQL
+ can set this flag also when there is only a
+ prefix of the column in the key: in that case we
+ retrieve the whole column from the clustered
+ index */
fetch_all_in_key = TRUE;
} else {
@@ -1709,12 +1915,6 @@ build_template(
}
if (prebuilt->select_lock_type == LOCK_X) {
- /* In versions < 3.23.50 we always retrieved the clustered
- index record if prebuilt->select_lock_type == LOCK_S,
- but there is really not need for that, and in some cases
- performance could be seriously degraded because the MySQL
- optimizer did not know about our convention! */
-
/* We always retrieve the whole clustered index record if we
use exclusive row level locks, for example, if the read is
done in an UPDATE statement. */
@@ -1723,6 +1923,11 @@ build_template(
}
if (templ_type == ROW_MYSQL_REC_FIELDS) {
+ /* In versions < 3.23.50 we always retrieved the clustered
+ index record if prebuilt->select_lock_type == LOCK_S,
+ but there is really not need for that, and in some cases
+ performance could be seriously degraded because the MySQL
+ optimizer did not know about our convention! */
index = prebuilt->index;
} else {
index = clust_index;
@@ -1768,9 +1973,8 @@ build_template(
is fixed!!!!!!!!!!!!!!!!!
if (templ_type == ROW_MYSQL_REC_FIELDS
- && !(fetch_all_in_key &&
- ULINT_UNDEFINED != dict_index_get_nth_col_pos(
- index, i))
+ && !(fetch_all_in_key
+ && dict_index_contains_col_or_prefix(index, i))
&& thd->query_id != field->query_id
&& thd->query_id != (field->query_id ^ MAX_ULONG_BIT)
&& thd->query_id !=
@@ -1942,9 +2146,9 @@ ha_innobase::write_row(
The lock is released at each SQL statement's
end. */
- srv_conc_enter_innodb(prebuilt->trx);
+ innodb_srv_conc_enter_innodb(prebuilt->trx);
error = row_lock_table_autoinc_for_mysql(prebuilt);
- srv_conc_exit_innodb(prebuilt->trx);
+ innodb_srv_conc_exit_innodb(prebuilt->trx);
if (error != DB_SUCCESS) {
@@ -1955,14 +2159,15 @@ ha_innobase::write_row(
dict_table_autoinc_update(prebuilt->table, auto_inc);
} else {
- srv_conc_enter_innodb(prebuilt->trx);
+ innodb_srv_conc_enter_innodb(prebuilt->trx);
if (!prebuilt->trx->auto_inc_lock) {
error = row_lock_table_autoinc_for_mysql(
prebuilt);
if (error != DB_SUCCESS) {
- srv_conc_exit_innodb(prebuilt->trx);
+ innodb_srv_conc_exit_innodb(
+ prebuilt->trx);
error = convert_error_code_to_mysql(
error, user_thd);
@@ -1976,7 +2181,7 @@ ha_innobase::write_row(
auto_inc = dict_table_autoinc_get(prebuilt->table);
incremented_auto_inc_counter = TRUE;
- srv_conc_exit_innodb(prebuilt->trx);
+ innodb_srv_conc_exit_innodb(prebuilt->trx);
/* We can give the new value for MySQL to place in
the field */
@@ -1999,11 +2204,11 @@ ha_innobase::write_row(
build_template(prebuilt, NULL, table, ROW_MYSQL_WHOLE_ROW);
}
- srv_conc_enter_innodb(prebuilt->trx);
+ innodb_srv_conc_enter_innodb(prebuilt->trx);
error = row_insert_for_mysql((byte*) record, prebuilt);
- srv_conc_exit_innodb(prebuilt->trx);
+ innodb_srv_conc_exit_innodb(prebuilt->trx);
if (error != DB_SUCCESS) {
/* If the insert did not succeed we restore the value of
@@ -2074,7 +2279,6 @@ innobase_convert_and_store_changed_col(
while (len > 0 && data[len - 1] == ' ') {
len--;
}
-
} else if (col_type == DATA_INT) {
/* Store integer data in InnoDB in a big-endian
format, sign bit negated, if signed */
@@ -2112,9 +2316,11 @@ calc_row_difference(
struct st_table* table, /* in: table in MySQL data
dictionary */
mysql_byte* upd_buff, /* in: buffer to use */
+ ulint buff_len, /* in: buffer length */
row_prebuilt_t* prebuilt, /* in: InnoDB prebuilt struct */
THD* thd) /* in: user thread */
{
+ mysql_byte* original_upd_buff = upd_buff;
Field* field;
uint n_fields;
ulint o_len;
@@ -2196,12 +2402,13 @@ calc_row_difference(
(prebuilt->table->cols + i)->clust_pos;
n_changed++;
}
- ;
}
uvect->n_fields = n_changed;
uvect->info_bits = 0;
+ ut_a(buf <= (byte*)original_upd_buff + buff_len);
+
return(0);
}
@@ -2250,17 +2457,19 @@ ha_innobase::update_row(
(uses upd_buff of the handle) */
calc_row_difference(uvect, (mysql_byte*) old_row, new_row, table,
- upd_buff, prebuilt, user_thd);
+ upd_buff, (ulint)upd_and_key_val_buff_len,
+ prebuilt, user_thd);
+
/* This is not a delete */
prebuilt->upd_node->is_delete = FALSE;
assert(prebuilt->template_type == ROW_MYSQL_WHOLE_ROW);
- srv_conc_enter_innodb(prebuilt->trx);
+ innodb_srv_conc_enter_innodb(prebuilt->trx);
error = row_update_for_mysql((byte*) old_row, prebuilt);
- srv_conc_exit_innodb(prebuilt->trx);
+ innodb_srv_conc_exit_innodb(prebuilt->trx);
error = convert_error_code_to_mysql(error, user_thd);
@@ -2304,11 +2513,11 @@ ha_innobase::delete_row(
prebuilt->upd_node->is_delete = TRUE;
- srv_conc_enter_innodb(prebuilt->trx);
+ innodb_srv_conc_enter_innodb(prebuilt->trx);
error = row_update_for_mysql((byte*) record, prebuilt);
- srv_conc_exit_innodb(prebuilt->trx);
+ innodb_srv_conc_exit_innodb(prebuilt->trx);
error = convert_error_code_to_mysql(error, user_thd);
@@ -2491,10 +2700,11 @@ ha_innobase::index_read(
prebuilt->search_tuple */
row_sel_convert_mysql_key_to_innobase(prebuilt->search_tuple,
- (byte*) key_val_buff,
- index,
- (byte*) key_ptr,
- (ulint) key_len);
+ (byte*) key_val_buff,
+ (ulint)upd_and_key_val_buff_len,
+ index,
+ (byte*) key_ptr,
+ (ulint) key_len);
} else {
/* We position the cursor to the last or the first entry
in the index */
@@ -2516,11 +2726,11 @@ ha_innobase::index_read(
last_match_mode = match_mode;
- srv_conc_enter_innodb(prebuilt->trx);
+ innodb_srv_conc_enter_innodb(prebuilt->trx);
ret = row_search_for_mysql((byte*) buf, mode, prebuilt, match_mode, 0);
- srv_conc_exit_innodb(prebuilt->trx);
+ innodb_srv_conc_exit_innodb(prebuilt->trx);
if (ret == DB_SUCCESS) {
error = 0;
@@ -2670,11 +2880,11 @@ ha_innobase::general_fetch(
ut_a(prebuilt->trx ==
(trx_t*) current_thd->transaction.all.innobase_tid);
- srv_conc_enter_innodb(prebuilt->trx);
+ innodb_srv_conc_enter_innodb(prebuilt->trx);
ret = row_search_for_mysql((byte*)buf, 0, prebuilt, match_mode,
direction);
- srv_conc_exit_innodb(prebuilt->trx);
+ innodb_srv_conc_exit_innodb(prebuilt->trx);
if (ret == DB_SUCCESS) {
error = 0;
@@ -2963,7 +3173,8 @@ ha_innobase::position(
memcpy(ref, prebuilt->row_id, len);
} else {
- len = store_key_val_for_row(primary_key, (char*) ref, record);
+ len = store_key_val_for_row(primary_key, (char*)ref,
+ ref_length, record);
}
/* Since we do not store len to the buffer 'ref', we must assume
@@ -2977,7 +3188,6 @@ ha_innobase::position(
}
}
-
/*********************************************************************
Creates a table definition to an InnoDB database. */
static
@@ -2996,6 +3206,8 @@ create_table_def(
ulint col_type;
ulint nulls_allowed;
ulint unsigned_type;
+ ulint binary_type;
+ ulint nonlatin1_type;
ulint i;
DBUG_ENTER("create_table_def");
@@ -3024,9 +3236,24 @@ create_table_def(
unsigned_type = 0;
}
+ if (col_type == DATA_BLOB
+ && strcmp(default_charset_info->name, "latin1") != 0) {
+ nonlatin1_type = DATA_NONLATIN1;
+ } else {
+ nonlatin1_type = 0;
+ }
+
+ if (field->flags & BINARY_FLAG) {
+ binary_type = DATA_BINARY_TYPE;
+ nonlatin1_type = 0;
+ } else {
+ binary_type = 0;
+ }
+
dict_mem_table_add_col(table, (char*) field->field_name,
col_type, (ulint)field->type()
- | nulls_allowed | unsigned_type,
+ | nulls_allowed | unsigned_type
+ | nonlatin1_type | binary_type,
field->pack_length(), 0);
}
@@ -3049,6 +3276,7 @@ create_index(
const char* table_name, /* in: table name */
uint key_num) /* in: index number */
{
+ Field* field;
dict_index_t* index;
int error;
ulint n_fields;
@@ -3058,6 +3286,7 @@ create_index(
ulint col_type;
ulint prefix_len;
ulint i;
+ ulint j;
DBUG_ENTER("create_index");
@@ -3084,31 +3313,63 @@ create_index(
for (i = 0; i < n_fields; i++) {
key_part = key->key_part + i;
- if (key_part->length != key_part->field->pack_length()) {
+ /* (The flag HA_PART_KEY denotes in MySQL a column prefix
+ field in an index: we only store a specified number of first
+ bytes of the column to the index field.) The flag does not
+ seem to be properly set by MySQL. Let us fall back on testing
+ the length of the key part versus the column. */
+
+ field = NULL;
+ for (j = 0; j < form->fields; j++) {
+
+ field = form->field[j];
+
+ if (strlen(field->field_name)
+ == strlen(key_part->field->field_name)
+ && 0 == ut_cmp_in_lower_case(
+ (char*)field->field_name,
+ (char*)key_part->field->field_name,
+ strlen(field->field_name))) {
+ /* Found the corresponding column */
+
+ break;
+ }
+ }
+
+ ut_a(j < form->fields);
+
+ col_type = get_innobase_type_from_mysql_type(key_part->field);
+
+ if (DATA_BLOB == col_type
+ || key_part->length < field->pack_length()) {
+
prefix_len = key_part->length;
- col_type = get_innobase_type_from_mysql_type(
- key_part->field);
if (col_type == DATA_INT
|| col_type == DATA_FLOAT
|| col_type == DATA_DOUBLE
|| col_type == DATA_DECIMAL) {
fprintf(stderr,
"InnoDB: error: MySQL is trying to create a column prefix index field\n"
-"InnoDB: on an inappropriate data type %lu. Table name %s, column name %s.\n",
- col_type, table_name,
- key_part->field->field_name);
+"InnoDB: on an inappropriate data type. Table name %s, column name %s.\n",
+ table_name, key_part->field->field_name);
prefix_len = 0;
}
} else {
prefix_len = 0;
- }
+ }
+
+ if (prefix_len >= DICT_MAX_COL_PREFIX_LEN) {
+ DBUG_RETURN(-1);
+ }
/* We assume all fields should be sorted in ascending
order, hence the '0': */
+
dict_mem_index_add_field(index,
- (char*) key_part->field->field_name, 0);
+ (char*) key_part->field->field_name,
+ 0, prefix_len);
}
error = row_create_index_for_mysql(index, trx);
@@ -3172,6 +3433,13 @@ ha_innobase::create(
DBUG_ASSERT(thd != NULL);
+ if (form->fields > 1000) {
+ /* The limit probably should be REC_MAX_N_FIELDS - 3 = 1020,
+ but we play safe here */
+
+ return(HA_ERR_TO_BIG_ROW);
+ }
+
/* Get the transaction associated with the current thd, or create one
if not yet created */
@@ -3314,7 +3582,7 @@ ha_innobase::create(
the InnoDB data dictionary get out-of-sync if the user runs
with innodb_flush_log_at_trx_commit = 0 */
- log_write_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP, TRUE);
+ log_buffer_flush_to_disk();
innobase_table = dict_table_get(norm_name, NULL);
@@ -3389,7 +3657,7 @@ ha_innobase::delete_table(
the InnoDB data dictionary get out-of-sync if the user runs
with innodb_flush_log_at_trx_commit = 0 */
- log_write_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP, TRUE);
+ log_buffer_flush_to_disk();
/* Tell the InnoDB server that there might be work for
utility threads: */
@@ -3459,7 +3727,7 @@ innobase_drop_database(
the InnoDB data dictionary get out-of-sync if the user runs
with innodb_flush_log_at_trx_commit = 0 */
- log_write_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP, TRUE);
+ log_buffer_flush_to_disk();
/* Tell the InnoDB server that there might be work for
utility threads: */
@@ -3531,7 +3799,7 @@ ha_innobase::rename_table(
the InnoDB data dictionary get out-of-sync if the user runs
with innodb_flush_log_at_trx_commit = 0 */
- log_write_up_to(ut_dulint_max, LOG_WAIT_ONE_GROUP, TRUE);
+ log_buffer_flush_to_disk();
/* Tell the InnoDB server that there might be work for
utility threads: */
@@ -3574,6 +3842,8 @@ ha_innobase::records_in_range(
table->reclength
+ table->max_key_length + 100,
MYF(MY_WME));
+ ulint buff2_len = table->reclength
+ + table->max_key_length + 100;
dtuple_t* range_start;
dtuple_t* range_end;
ib_longlong n_rows;
@@ -3610,12 +3880,15 @@ ha_innobase::records_in_range(
dict_index_copy_types(range_end, index, key->key_parts);
row_sel_convert_mysql_key_to_innobase(
- range_start, (byte*) key_val_buff, index,
+ range_start, (byte*) key_val_buff,
+ (ulint)upd_and_key_val_buff_len,
+ index,
(byte*) start_key,
(ulint) start_key_len);
row_sel_convert_mysql_key_to_innobase(
- range_end, (byte*) key_val_buff2, index,
+ range_end, (byte*) key_val_buff2,
+ buff2_len, index,
(byte*) end_key,
(ulint) end_key_len);
@@ -3825,8 +4098,32 @@ ha_innobase::info(
}
for (i = 0; i < table->keys; i++) {
+ if (index == NULL) {
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+" InnoDB: Error: table %s contains less indexes inside InnoDB\n"
+"InnoDB: than are defined in the MySQL .frm file. Have you mixed up\n"
+"InnoDB: .frm files from different installations? See section\n"
+"InnoDB: 15.1 at http://www.innodb.com/ibman.html\n",
+ ib_table->name);
+ break;
+ }
+
for (j = 0; j < table->key_info[i].key_parts; j++) {
+ if (j + 1 > index->n_uniq) {
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+" InnoDB: Error: index %s of %s has %lu columns unique inside InnoDB\n"
+"InnoDB: but MySQL is asking statistics for %lu columns. Have you mixed up\n"
+"InnoDB: .frm files from different installations? See section\n"
+"InnoDB: 15.1 at http://www.innodb.com/ibman.html\n",
+ index->name,
+ ib_table->name, index->n_uniq,
+ j + 1);
+ break;
+ }
+
if (index->stat_n_diff_key_vals[j + 1] == 0) {
rec_per_key = records;
@@ -3885,6 +4182,12 @@ ha_innobase::analyze(
return(0);
}
+
+int ha_innobase::optimize(THD* thd, HA_CHECK_OPT* check_opt)
+{
+ return ha_innobase::analyze(thd,check_opt);
+}
+
/***********************************************************************
Tries to check that an InnoDB table is not corrupted. If corruption is
noticed, prints to stderr information about it. In case of corruption
@@ -4094,10 +4397,11 @@ ha_innobase::reset(void)
}
/**********************************************************************
-MySQL calls this function at the start of each SQL statement. Inside LOCK
-TABLES the ::external_lock method does not work to mark SQL statement
-borders. Note also a special case: if a temporary table is created inside
-LOCK TABLES, MySQL has not called external_lock() at all on that table. */
+MySQL calls this function at the start of each SQL statement inside LOCK
+TABLES. Inside LOCK TABLES the ::external_lock method does not work to
+mark SQL statement borders. Note also a special case: if a temporary table
+is created inside LOCK TABLES, MySQL has not called external_lock() at all
+on that table. */
int
ha_innobase::start_stmt(
@@ -4254,6 +4558,12 @@ ha_innobase::external_lock(
trx->mysql_n_tables_locked = 0;
prebuilt->used_in_HANDLER = FALSE;
+ /* Release a possible FIFO ticket and search latch. Since we
+ may reserve the kernel mutex, we have to release the search
+ system latch first to obey the latching order. */
+
+ innobase_release_stat_resources(trx);
+
if (!(thd->options
& (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) {
if (thd->transaction.all.innodb_active_trans != 0) {
@@ -4269,11 +4579,6 @@ ha_innobase::external_lock(
read_view_close_for_mysql(trx);
}
}
-
- /* Here we release the search latch and the InnoDB thread FIFO
- ticket if they were reserved. */
-
- innobase_release_stat_resources(trx);
}
DBUG_RETURN(error);
@@ -4289,7 +4594,9 @@ innodb_show_status(
THD* thd) /* in: the MySQL query thread of the caller */
{
char* buf;
+ trx_t* trx;
Protocol *protocol= thd->protocol;
+
DBUG_ENTER("innodb_show_status");
if (innodb_skip) {
@@ -4299,12 +4606,16 @@ innodb_show_status(
DBUG_RETURN(-1);
}
- /* We let the InnoDB Monitor to output at most 200 kB of text, add
- a safety margin of 10 kB for buffer overruns */
+ trx = check_trx_exists(thd);
+
+ innobase_release_stat_resources(trx);
+
+ /* We let the InnoDB Monitor to output at most 60 kB of text, add
+ a safety margin of 100 kB for buffer overruns */
- buf = (char*)ut_malloc(210 * 1024);
+ buf = (char*)ut_malloc(160 * 1024);
- srv_sprintf_innodb_monitor(buf, 200 * 1024);
+ srv_sprintf_innodb_monitor(buf, 60 * 1024);
List<Item> field_list;
@@ -4479,6 +4790,11 @@ ha_innobase::innobase_read_and_init_auto_inc(
(trx_t*) current_thd->transaction.all.innobase_tid);
ut_a(prebuilt->table);
+ /* In case MySQL calls this in the middle of a SELECT query, release
+ possible adaptive hash latch to avoid deadlocks of threads */
+
+ trx_search_latch_release_if_reserved(prebuilt->trx);
+
auto_inc = dict_table_autoinc_read(prebuilt->table);
if (auto_inc != 0) {
@@ -4488,9 +4804,7 @@ ha_innobase::innobase_read_and_init_auto_inc(
return(0);
}
- srv_conc_enter_innodb(prebuilt->trx);
error = row_lock_table_autoinc_for_mysql(prebuilt);
- srv_conc_exit_innodb(prebuilt->trx);
if (error != DB_SUCCESS) {
error = convert_error_code_to_mysql(error, user_thd);
diff --git a/sql/ha_innodb.h b/sql/ha_innodb.h
index 9ca8475e75e..13337f466bf 100644
--- a/sql/ha_innodb.h
+++ b/sql/ha_innodb.h
@@ -32,7 +32,6 @@ typedef struct st_innobase_share {
uint table_name_length,use_count;
} INNOBASE_SHARE;
-
/* The class defining a handle to an Innodb table */
class ha_innobase: public handler
{
@@ -52,6 +51,9 @@ class ha_innobase: public handler
byte* key_val_buff; /* buffer used in converting
search key values from MySQL format
to Innodb format */
+ ulong upd_and_key_val_buff_len;
+ /* the length of each of the previous
+ two buffers */
ulong int_table_flags;
uint primary_key;
uint last_dup_key;
@@ -73,7 +75,8 @@ class ha_innobase: public handler
longlong auto_inc_counter_for_this_stat;
ulong max_row_length(const byte *buf);
- uint store_key_val_for_row(uint keynr, char* buff, const byte* record);
+ uint store_key_val_for_row(uint keynr, char* buff, uint buff_len,
+ const byte* record);
int update_thd(THD* thd);
int change_active_index(uint keynr);
int general_fetch(byte* buf, uint direction, uint match_mode);
@@ -83,13 +86,15 @@ class ha_innobase: public handler
public:
ha_innobase(TABLE *table): handler(table),
int_table_flags(HA_REC_NOT_IN_SEQ |
- HA_KEYPOS_TO_RNDPOS | HA_LASTKEY_ORDER |
- HA_NULL_KEY | HA_CAN_SQL_HANDLER |
+ HA_KEYPOS_TO_RNDPOS |
+ HA_LASTKEY_ORDER |
+ HA_NULL_KEY |
+ HA_BLOB_KEY |
+ HA_CAN_SQL_HANDLER |
HA_NOT_EXACT_COUNT |
HA_NO_WRITE_DELAYED |
HA_PRIMARY_KEY_IN_READ_INDEX |
HA_DROP_BEFORE_CREATE |
- HA_NO_PREFIX_CHAR_KEYS |
HA_TABLE_SCAN_ON_INDEX),
last_dup_key((uint) -1),
start_of_scan(0)
@@ -153,6 +158,7 @@ class ha_innobase: public handler
void position(const byte *record);
void info(uint);
int analyze(THD* thd,HA_CHECK_OPT* check_opt);
+ int optimize(THD* thd,HA_CHECK_OPT* check_opt);
int extra(enum ha_extra_function operation);
int reset(void);
int external_lock(THD *thd, int lock_type);
@@ -219,6 +225,14 @@ int innobase_report_binlog_offset_and_commit(
int innobase_commit_complete(
void* trx_handle);
int innobase_rollback(THD *thd, void* trx_handle);
+int innobase_rollback_to_savepoint(
+ THD* thd,
+ char* savepoint_name,
+ my_off_t* binlog_cache_pos);
+int innobase_savepoint(
+ THD* thd,
+ char* savepoint_name,
+ my_off_t binlog_cache_pos);
int innobase_close_connection(THD *thd);
int innobase_drop_database(char *path);
int innodb_show_status(THD* thd);
diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc
index 4f1021232a4..e8e4798c2b2 100644
--- a/sql/ha_myisam.cc
+++ b/sql/ha_myisam.cc
@@ -572,7 +572,8 @@ int ha_myisam::repair(THD *thd, MI_CHECK &param, bool optimize)
strmov(fixed_name,file->filename);
// Don't lock tables if we have used LOCK TABLE
- if (!thd->locked_tables && mi_lock_database(file,F_WRLCK))
+ if (!thd->locked_tables &&
+ mi_lock_database(file, table->tmp_table ? F_EXTRA_LCK : F_WRLCK))
{
mi_check_print_error(&param,ER(ER_CANT_LOCK),my_errno);
DBUG_RETURN(HA_ADMIN_FAILED);
@@ -767,12 +768,20 @@ int ha_myisam::preload_keys(THD* thd, HA_CHECK_OPT *check_opt)
void ha_myisam::deactivate_non_unique_index(ha_rows rows)
{
MYISAM_SHARE* share = file->s;
+ bool do_warning=0;
if (share->state.key_map == ((ulonglong) 1L << share->base.keys)-1)
{
if (!(specialflag & SPECIAL_SAFE_MODE))
{
if (rows == HA_POS_ERROR)
+ {
+ uint orig_update= file->update;
+ file->update ^= HA_STATE_CHANGED;
+ uint check_update= file->update;
mi_extra(file, HA_EXTRA_NO_KEYS, 0);
+ do_warning= (file->update == check_update) && file->state->records;
+ file->update= orig_update;
+ }
else
{
/*
@@ -794,9 +803,14 @@ void ha_myisam::deactivate_non_unique_index(ha_rows rows)
}
}
enable_activate_all_index=1;
+ info(HA_STATUS_CONST); // Read new key info
}
else
enable_activate_all_index=0;
+ if (do_warning)
+ push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_ILLEGAL_HA,
+ ER(ER_ILLEGAL_HA), table->table_name);
}
@@ -822,6 +836,7 @@ bool ha_myisam::activate_all_index(THD *thd)
param.sort_buffer_length= thd->variables.myisam_sort_buff_size;
param.tmpdir=&mysql_tmpdir_list;
error=repair(thd,param,0) != HA_ADMIN_OK;
+ info(HA_STATUS_CONST);
thd->proc_info=save_proc_info;
}
else
@@ -1005,8 +1020,9 @@ void ha_myisam::info(uint flag)
ref_length=info.reflength;
table->db_options_in_use = info.options;
block_size=myisam_block_size;
- table->keys_in_use&= info.key_map;
- table->keys_for_keyread&= info.key_map;
+ table->keys_in_use= (set_bits(key_map, table->keys) &
+ (key_map) info.key_map);
+ table->keys_for_keyread= table->keys_in_use & ~table->read_only_keys;
table->db_record_offset=info.record_offset;
if (table->key_parts)
memcpy((char*) table->key_info[0].rec_per_key,
@@ -1075,9 +1091,9 @@ int ha_myisam::delete_table(const char *name)
int ha_myisam::external_lock(THD *thd, int lock_type)
{
- if (!table->tmp_table)
- return mi_lock_database(file,lock_type);
- return 0;
+ return mi_lock_database(file, !table->tmp_table ?
+ lock_type : ((lock_type == F_UNLCK) ?
+ F_UNLCK : F_EXTRA_LCK));
}
diff --git a/sql/handler.cc b/sql/handler.cc
index 150a0d5329e..b4d370491bb 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -389,7 +389,6 @@ int ha_commit_trans(THD *thd, THD_TRANS* trans)
trans->innodb_active_trans=0;
if (trans == &thd->transaction.all)
operation_done= transaction_commited= 1;
-
}
#endif
#ifdef HAVE_QUERY_CACHE
@@ -457,6 +456,70 @@ int ha_rollback_trans(THD *thd, THD_TRANS *trans)
DBUG_RETURN(error);
}
+
+/*
+Rolls the current transaction back to a savepoint.
+Return value: 0 if success, 1 if there was not a savepoint of the given
+name.
+*/
+
+int ha_rollback_to_savepoint(THD *thd, char *savepoint_name)
+{
+ my_off_t binlog_cache_pos=0;
+ bool operation_done=0;
+ int error=0;
+ DBUG_ENTER("ha_rollback_to_savepoint");
+#ifdef USING_TRANSACTIONS
+ if (opt_using_transactions)
+ {
+#ifdef HAVE_INNOBASE_DB
+ /*
+ Retrieve the trans_log binlog cache position corresponding to the
+ savepoint, and if the rollback is successful inside InnoDB reset the write
+ position in the binlog cache to what it was at the savepoint.
+ */
+ if ((error=innobase_rollback_to_savepoint(thd, savepoint_name,
+ &binlog_cache_pos)))
+ {
+ my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), error);
+ error=1;
+ }
+ else
+ reinit_io_cache(&thd->transaction.trans_log, WRITE_CACHE,
+ binlog_cache_pos, 0, 0);
+ operation_done=1;
+#endif
+ if (operation_done)
+ statistic_increment(ha_rollback_count,&LOCK_status);
+ }
+#endif /* USING_TRANSACTIONS */
+
+ DBUG_RETURN(error);
+}
+
+
+/*
+Sets a transaction savepoint.
+Return value: always 0, that is, succeeds always
+*/
+
+int ha_savepoint(THD *thd, char *savepoint_name)
+{
+ my_off_t binlog_cache_pos=0;
+ int error=0;
+ DBUG_ENTER("ha_savepoint");
+#ifdef USING_TRANSACTIONS
+ if (opt_using_transactions)
+ {
+ binlog_cache_pos=my_b_tell(&thd->transaction.trans_log);
+#ifdef HAVE_INNOBASE_DB
+ innobase_savepoint(thd,savepoint_name, binlog_cache_pos);
+#endif
+ }
+#endif /* USING_TRANSACTIONS */
+ DBUG_RETURN(error);
+}
+
bool ha_flush_logs()
{
bool result=0;
@@ -697,11 +760,15 @@ void handler::update_auto_increment()
longlong nr;
THD *thd;
DBUG_ENTER("update_auto_increment");
- if (table->next_number_field->val_int() != 0)
+ if (table->next_number_field->val_int() != 0 ||
+ table->auto_increment_field_not_null &&
+ current_thd->variables.sql_mode & MODE_NO_AUTO_VALUE_ON_ZERO)
{
+ table->auto_increment_field_not_null= false;
auto_increment_column_changed=0;
DBUG_VOID_RETURN;
}
+ table->auto_increment_field_not_null= false;
thd=current_thd;
if ((nr=thd->next_insert_id))
thd->next_insert_id=0; // Clear after use
@@ -755,6 +822,9 @@ void handler::print_error(int error, myf errflag)
int textno=ER_GET_ERRNO;
switch (error) {
+ case EACCES:
+ textno=ER_OPEN_AS_READONLY;
+ break;
case EAGAIN:
textno=ER_FILE_USED;
break;
diff --git a/sql/handler.h b/sql/handler.h
index 08a7c83d328..b1b5cfb02b0 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -192,39 +192,41 @@ class handler :public Sql_alloc
{
protected:
struct st_table *table; /* The table definition */
- uint active_index;
public:
byte *ref; /* Pointer to current row */
byte *dupp_ref; /* Pointer to dupp row */
- uint ref_length; /* Length of ref (1-8) */
- uint block_size; /* index block size */
- ha_rows records; /* Records i datafilen */
- ha_rows deleted; /* Deleted records */
ulonglong data_file_length; /* Length off data file */
ulonglong max_data_file_length; /* Length off data file */
ulonglong index_file_length;
ulonglong max_index_file_length;
ulonglong delete_length; /* Free bytes */
ulonglong auto_increment_value;
- uint raid_type,raid_chunks;
+ ha_rows records; /* Records in table */
+ ha_rows deleted; /* Deleted records */
ulong raid_chunksize;
- uint errkey; /* Last dup key */
- uint sortkey, key_used_on_scan;
+ ulong mean_rec_length; /* physical reclength */
time_t create_time; /* When table was created */
time_t check_time;
time_t update_time;
- ulong mean_rec_length; /* physical reclength */
+ uint errkey; /* Last dup key */
+ uint sortkey, key_used_on_scan;
+ uint active_index;
+ /* Length of ref (1-8 or the clustered key length) */
+ uint ref_length;
+ uint block_size; /* index block size */
+ uint raid_type,raid_chunks;
FT_INFO *ft_handler;
bool auto_increment_column_changed;
- handler(TABLE *table_arg) : table(table_arg),active_index(MAX_REF_PARTS),
- ref(0),ref_length(sizeof(my_off_t)), block_size(0),records(0),deleted(0),
- data_file_length(0), max_data_file_length(0), index_file_length(0),
- delete_length(0), auto_increment_value(0), raid_type(0),
- key_used_on_scan(MAX_KEY),
- create_time(0), check_time(0), update_time(0), mean_rec_length(0),
- ft_handler(0)
+ handler(TABLE *table_arg) :table(table_arg),
+ ref(0), data_file_length(0), max_data_file_length(0), index_file_length(0),
+ delete_length(0), auto_increment_value(0),
+ records(0), deleted(0), mean_rec_length(0),
+ create_time(0), check_time(0), update_time(0),
+ key_used_on_scan(MAX_KEY), active_index(MAX_REF_PARTS),
+ ref_length(sizeof(my_off_t)), block_size(0),
+ raid_type(0), ft_handler(0)
{}
virtual ~handler(void) {}
int ha_open(const char *name, int mode, int test_if_locked);
@@ -234,7 +236,7 @@ public:
uint get_dup_key(int error);
void change_table_ptr(TABLE *table_arg) { table=table_arg; }
virtual double scan_time()
- { return ulonglong2double(data_file_length) / IO_SIZE + 1; }
+ { return ulonglong2double(data_file_length) / IO_SIZE + 2; }
virtual double read_time(uint index, uint ranges, ha_rows rows)
{ return rows2double(ranges+rows); }
virtual bool fast_key_read() { return 0;}
@@ -395,6 +397,8 @@ int ha_commit_complete(THD *thd);
int ha_release_temporary_latches(THD *thd);
int ha_commit_trans(THD *thd, THD_TRANS *trans);
int ha_rollback_trans(THD *thd, THD_TRANS *trans);
+int ha_rollback_to_savepoint(THD *thd, char *savepoint_name);
+int ha_savepoint(THD *thd, char *savepoint_name);
int ha_autocommit_or_rollback(THD *thd, int error);
void ha_set_spin_retries(uint retries);
bool ha_flush_logs(void);
diff --git a/sql/item.cc b/sql/item.cc
index 57769d40fed..17b9e1b508f 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -43,21 +43,25 @@ Item::Item():
{
marker= 0;
maybe_null=null_value=with_sum_func=unsigned_flag=0;
- set_charset(default_charset(), DERIVATION_COERCIBLE);
+ collation.set(default_charset(), DERIVATION_COERCIBLE);
name= 0;
decimals= 0; max_length= 0;
THD *thd= current_thd;
next= thd->free_list; // Put in free list
thd->free_list= this;
- loop_id= 0;
/*
- Item constructor can be called during execution other tnen SQL_COM
+ Item constructor can be called during execution other then SQL_COM
command => we should check thd->lex.current_select on zero (thd->lex
can be uninitialised)
*/
- if (thd->lex.current_select &&
- thd->lex.current_select->parsing_place == SELECT_LEX_NODE::SELECT_LIST)
- thd->lex.current_select->select_items++;
+ if (thd->lex.current_select)
+ {
+ SELECT_LEX_NODE::enum_parsing_place place=
+ thd->lex.current_select->parsing_place;
+ if (place == SELECT_LEX_NODE::SELECT_LIST ||
+ place == SELECT_LEX_NODE::IN_HAVING)
+ thd->lex.current_select->select_n_having_items++;
+ }
}
/*
@@ -66,7 +70,6 @@ Item::Item():
tables
*/
Item::Item(THD *thd, Item &item):
- loop_id(0),
str_value(item.str_value),
name(item.name),
max_length(item.max_length),
@@ -155,7 +158,7 @@ bool Item_string::eq(const Item *item, bool binary_cmp) const
{
if (binary_cmp)
return !sortcmp(&str_value, &item->str_value, &my_charset_bin);
- return !sortcmp(&str_value, &item->str_value, charset());
+ return !sortcmp(&str_value, &item->str_value, collation.collation);
}
return 0;
}
@@ -264,7 +267,7 @@ bool DTCollation::aggregate(DTCollation &dt)
Item_field::Item_field(Field *f) :Item_ident(NullS,f->table_name,f->field_name)
{
set_field(f);
- set_charset(DERIVATION_IMPLICIT);
+ collation.set(DERIVATION_IMPLICIT);
fixed= 1; // This item is not needed in fix_fields
}
@@ -273,7 +276,7 @@ Item_field::Item_field(THD *thd, Item_field &item):
Item_ident(thd, item),
field(item.field),
result_field(item.result_field)
-{ set_charset(DERIVATION_IMPLICIT); }
+{ collation.set(DERIVATION_IMPLICIT); }
void Item_field::set_field(Field *field_par)
{
@@ -285,7 +288,7 @@ void Item_field::set_field(Field *field_par)
field_name=field_par->field_name;
db_name=field_par->table->table_cache_key;
unsigned_flag=test(field_par->flags & UNSIGNED_FLAG);
- set_charset(field_par->charset(), DERIVATION_IMPLICIT);
+ collation.set(field_par->charset(), DERIVATION_IMPLICIT);
}
const char *Item_ident::full_name() const
@@ -539,6 +542,11 @@ void Item_param::set_longdata(const char *str, ulong length)
int Item_param::save_in_field(Field *field, bool no_conversions)
{
+ THD *thd= current_thd;
+
+ if (thd->command == COM_PREPARE)
+ return -1;
+
if (null_value)
return (int) set_field_to_null(field);
@@ -715,73 +723,6 @@ bool Item::fix_fields(THD *thd,
return 0;
}
-bool Item_asterisk_remover::fix_fields(THD *thd,
- struct st_table_list *list,
- Item ** ref)
-{
- DBUG_ENTER("Item_asterisk_remover::fix_fields");
-
- bool res= 1;
- if (item)
- if (item->type() == Item::FIELD_ITEM &&
- ((Item_field*) item)->field_name[0] == '*')
- {
- Item_field *fitem= (Item_field*) item;
- if (list)
- if (!list->next || fitem->db_name || fitem->table_name)
- {
- TABLE_LIST *table= find_table_in_list(list,
- fitem->db_name,
- fitem->table_name);
- if (table)
- {
- TABLE * tb= table->table;
- if (find_table_in_list(table->next, fitem->db_name,
- fitem->table_name) != 0 ||
- tb->fields == 1)
- {
- if ((item= new Item_field(tb->field[0])))
- {
- res= 0;
- tb->field[0]->query_id= thd->query_id;
- tb->used_keys&= tb->field[0]->part_of_key;
- tb->used_fields= tb->fields;
- }
- else
- thd->fatal_error(); // can't create Item => out of memory
- }
- else
- my_error(ER_CARDINALITY_COL, MYF(0), 1);
- }
- else
- my_error(ER_BAD_TABLE_ERROR, MYF(0), fitem->table_name);
- }
- else
- my_error(ER_CARDINALITY_COL, MYF(0), 1);
- else
- my_error(ER_NO_TABLES_USED, MYF(0));
- }
- else
- res= item->fix_fields(thd, list, &item);
- else
- thd->fatal_error(); // no item given => out of memory
- DBUG_RETURN(res);
-}
-
-bool Item_ref_on_list_position::fix_fields(THD *thd,
- struct st_table_list *tables,
- Item ** reference)
-{
- if (select_lex->item_list.elements <= pos)
- {
- ref= 0;
- my_error(ER_CARDINALITY_COL, MYF(0), pos);
- return 1;
- }
- ref= select_lex->ref_pointer_array + pos;
- return Item_ref_null_helper::fix_fields(thd, tables, reference);
-}
-
double Item_ref_null_helper::val()
{
double tmp= (*ref)->val_result();
@@ -870,7 +811,7 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
sl= sl->outer_select())
{
table_list= (last= sl)->get_table_list();
- if (sl->insert_select && table_list)
+ if (sl->resolve_mode == SELECT_LEX::INSERT_MODE && table_list)
{
// it is primary INSERT st_select_lex => skip first table resolving
table_list= table_list->next;
@@ -879,7 +820,8 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
table_list, &where,
0)) != not_found_field)
break;
- if ((refer= find_item_in_list(this, sl->item_list, &counter,
+ if (sl->resolve_mode == SELECT_LEX::SELECT_MODE &&
+ (refer= find_item_in_list(this, sl->item_list, &counter,
REPORT_EXCEPT_NOT_FOUND)) !=
(Item **) not_found_item)
break;
@@ -960,7 +902,7 @@ void Item::init_make_field(Send_field *tmp_field,
tmp_field->org_col_name= empty_name;
tmp_field->table_name= empty_name;
tmp_field->col_name= name;
- tmp_field->charsetnr= charset()->number;
+ tmp_field->charsetnr= collation.collation->number;
tmp_field->flags=maybe_null ? 0 : NOT_NULL_FLAG;
tmp_field->type=field_type;
tmp_field->length=max_length;
@@ -1074,7 +1016,7 @@ int Item::save_in_field(Field *field, bool no_conversions)
field->result_type() == STRING_RESULT)
{
String *result;
- CHARSET_INFO *cs=charset();
+ CHARSET_INFO *cs= collation.collation;
char buff[MAX_FIELD_WIDTH]; // Alloc buffer for small columns
str_value.set_quick(buff,sizeof(buff),cs);
result=val_str(&str_value);
@@ -1111,7 +1053,8 @@ int Item_string::save_in_field(Field *field, bool no_conversions)
if (null_value)
return set_field_to_null(field);
field->set_notnull();
- return (field->store(result->ptr(),result->length(),charset())) ? -1 : 0;
+ return (field->store(result->ptr(),result->length(),collation.collation)) ?
+ -1 : 0;
}
@@ -1165,7 +1108,7 @@ Item_varbinary::Item_varbinary(const char *str, uint str_length)
str+=2;
}
*ptr=0; // Keep purify happy
- set_charset(&my_charset_bin, DERIVATION_COERCIBLE);
+ collation.set(&my_charset_bin, DERIVATION_COERCIBLE);
}
longlong Item_varbinary::val_int()
@@ -1186,7 +1129,7 @@ int Item_varbinary::save_in_field(Field *field, bool no_conversions)
field->set_notnull();
if (field->result_type() == STRING_RESULT)
{
- error=field->store(str_value.ptr(),str_value.length(),charset());
+ error=field->store(str_value.ptr(),str_value.length(),collation.collation);
}
else
{
@@ -1352,13 +1295,15 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
SELECT_LEX *last=0;
for ( ; sl ; sl= sl->outer_select())
{
- if ((ref= find_item_in_list(this, (last= sl)->item_list,
+ last= sl;
+ if (sl->resolve_mode == SELECT_LEX::SELECT_MODE &&
+ (ref= find_item_in_list(this, sl->item_list,
&counter,
REPORT_EXCEPT_NOT_FOUND)) !=
(Item **)not_found_item)
break;
table_list= sl->get_table_list();
- if (sl->insert_select && table_list)
+ if (sl->resolve_mode == SELECT_LEX::INSERT_MODE && table_list)
{
// it is primary INSERT st_select_lex => skip first table resolving
table_list= table_list->next;
@@ -1444,7 +1389,7 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
max_length= (*ref)->max_length;
maybe_null= (*ref)->maybe_null;
decimals= (*ref)->decimals;
- set_charset((*ref)->charset());
+ collation.set((*ref)->collation);
with_sum_func= (*ref)->with_sum_func;
fixed= 1;
@@ -1677,7 +1622,7 @@ Item_cache* Item_cache::get_cache(Item_result type)
void Item_cache_str::store(Item *item)
{
- value_buff.set(buffer, sizeof(buffer), item->charset());
+ value_buff.set(buffer, sizeof(buffer), item->collation.collation);
value= item->str_result(&value_buff);
if ((null_value= item->null_value))
value= 0;
@@ -1694,7 +1639,7 @@ void Item_cache_str::store(Item *item)
value_buff.copy(*value);
value= &value_buff;
}
- set_charset(&item->collation);
+ collation.set(item->collation);
}
double Item_cache_str::val()
{
diff --git a/sql/item.h b/sql/item.h
index da1c3dd9e51..296ad18b1f1 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -85,7 +85,6 @@ public:
typedef bool (Item::*Item_processor)(byte *arg);
class Item {
- uint loop_id; /* Used to find selfrefering loops */
Item(const Item &); /* Prevent use of these */
void operator=(Item &);
public:
@@ -147,7 +146,24 @@ public:
virtual double val_result() { return val(); }
virtual longlong val_int_result() { return val_int(); }
virtual String *str_result(String* tmp) { return val_str(tmp); }
+ /* bit map of tables used by item */
virtual table_map used_tables() const { return (table_map) 0L; }
+ /*
+ Return table map of tables that can't be NULL tables (tables that are
+ used in a context where if they would contain a NULL row generated
+ by a LEFT or RIGHT join, the item would not be true).
+ This expression is used on WHERE item to determinate if a LEFT JOIN can be
+ converted to a normal join.
+ Generally this function should return used_tables() if the function
+ would return null if any of the arguments are null
+ As this is only used in the beginning of optimization, the value don't
+ have to be updated in update_used_tables()
+ */
+ virtual table_map not_null_tables() const { return used_tables(); }
+ /*
+ Returns true if this is a simple constant item like an integer, not
+ a constant expression
+ */
virtual bool basic_const_item() const { return 0; }
virtual Item *new_item() { return 0; } /* Only for const items */
virtual cond_result eq_cmp_result() const { return COND_OK; }
@@ -172,21 +188,6 @@ public:
virtual Item *get_tmp_table_item(THD *thd) { return copy_or_same(thd); }
CHARSET_INFO *default_charset() const;
- Derivation derivation() const { return collation.derivation; }
- CHARSET_INFO *charset() const { return collation.collation; }
- void set_charset(CHARSET_INFO *cs)
- { collation.collation= cs; }
- void set_charset(Derivation dv)
- { collation.derivation= dv; }
- void set_charset(CHARSET_INFO *cs, Derivation dv)
- { collation.collation= cs; collation.derivation= dv; }
- void set_charset(Item &item)
- { collation= item.collation; }
- void set_charset(DTCollation *collation_arg)
- {
- collation.collation= collation_arg->collation;
- collation.derivation= collation_arg->derivation;
- }
virtual bool walk(Item_processor processor, byte *arg)
{
@@ -238,7 +239,7 @@ public:
Item_field(const char *db_par,const char *table_name_par,
const char *field_name_par)
:Item_ident(db_par,table_name_par,field_name_par),field(0),result_field(0)
- { set_charset(DERIVATION_IMPLICIT); }
+ { collation.set(DERIVATION_IMPLICIT); }
// Constructor need to process subselect with temporary tables (see Item)
Item_field(THD *thd, Item_field &item);
Item_field(Field *field);
@@ -441,18 +442,18 @@ public:
Item_string(const char *str,uint length,
CHARSET_INFO *cs, Derivation dv= DERIVATION_COERCIBLE)
{
- set_charset(cs, dv);
+ collation.set(cs, dv);
str_value.set(str,length,cs);
- max_length=length;
+ max_length= str_value.numchars()*cs->mbmaxlen;
set_name(str, length, cs);
decimals=NOT_FIXED_DEC;
}
Item_string(const char *name_par, const char *str, uint length,
CHARSET_INFO *cs, Derivation dv= DERIVATION_COERCIBLE)
{
- set_charset(cs, dv);
+ collation.set(cs, dv);
str_value.set(str,length,cs);
- max_length=length;
+ max_length= str_value.numchars()*cs->mbmaxlen;
set_name(name_par,0,cs);
decimals=NOT_FIXED_DEC;
}
@@ -642,58 +643,15 @@ public:
}
};
-
-/*
- Used to find item in list of select items after '*' items processing.
-
- Because item '*' can be used in item list. when we create
- Item_ref_on_list_position we do not know how item list will be changed, but
- we know number of item position (I mean queries like "select * from t").
-*/
-class Item_ref_on_list_position: public Item_ref_null_helper
-{
-protected:
- /*
- select_lex used for:
- 1) receiving expanded variant of item list (to check max possible
- number of elements);
- 2) to have access to ref_pointer_array, via wich item will refered.
- */
- st_select_lex *select_lex;
- uint pos;
-public:
- Item_ref_on_list_position(Item_in_subselect* master,
- st_select_lex *sl, uint num,
- char *table_name, char *field_name):
- Item_ref_null_helper(master, 0, table_name, field_name),
- select_lex(sl), pos(num) {}
- bool fix_fields(THD *, struct st_table_list *, Item ** ref);
-};
-
-/*
- To resolve '*' field moved to condition
- and register NULL values
-*/
-class Item_asterisk_remover :public Item_ref_null_helper
+class Item_null_helper :public Item_ref_null_helper
{
- Item *item;
+ Item *store;
public:
- Item_asterisk_remover(Item_in_subselect *master, Item *it,
- char *table, char *field):
- Item_ref_null_helper(master, &item, table, field),
- item(it)
- {}
- bool fix_fields(THD *, struct st_table_list *, Item ** ref);
- Item **storage() {return &item;}
- void print(String *str)
- {
- str->append("ref_null_helper('");
- if (item)
- item->print(str);
- else
- str->append('?');
- str->append(')');
- }
+ Item_null_helper(Item_in_subselect* master, Item *item,
+ const char *table_name_par, const char *field_name_par)
+ :Item_ref_null_helper(master, &store, table_name_par, field_name_par),
+ store(item)
+ {}
};
/*
diff --git a/sql/item_buff.cc b/sql/item_buff.cc
index c4431294dff..1559cfe958e 100644
--- a/sql/item_buff.cc
+++ b/sql/item_buff.cc
@@ -57,7 +57,7 @@ bool Item_str_buff::cmp(void)
else if (null_value)
return 0; // new and old value was null
else
- tmp= sortcmp(&value,res,item->charset()) != 0;
+ tmp= sortcmp(&value,res,item->collation.collation) != 0;
if (tmp)
value.copy(*res); // Remember for next cmp
return tmp;
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index e8d3cba3ddb..053eb9e6fef 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -109,7 +109,7 @@ longlong Item_func_not::val_int()
static bool convert_constant_item(Field *field, Item **item)
{
- if ((*item)->const_item() && (*item)->type() != Item::INT_ITEM)
+ if ((*item)->const_item())
{
if (!(*item)->save_in_field(field, 1) && !((*item)->null_value))
{
@@ -151,15 +151,17 @@ void Item_bool_func2::fix_length_and_dec()
uint strong= 0;
uint weak= 0;
- if ((args[0]->derivation() < args[1]->derivation()) &&
- !my_charset_same(args[0]->charset(), args[1]->charset()) &&
- (args[0]->charset()->state & MY_CS_UNICODE))
+ if ((args[0]->collation.derivation < args[1]->collation.derivation) &&
+ !my_charset_same(args[0]->collation.collation,
+ args[1]->collation.collation) &&
+ (args[0]->collation.collation->state & MY_CS_UNICODE))
{
weak= 1;
}
- else if ((args[1]->derivation() < args[0]->derivation()) &&
- !my_charset_same(args[0]->charset(), args[1]->charset()) &&
- (args[1]->charset()->state & MY_CS_UNICODE))
+ else if ((args[1]->collation.derivation < args[0]->collation.derivation) &&
+ !my_charset_same(args[0]->collation.collation,
+ args[1]->collation.collation) &&
+ (args[1]->collation.collation->state & MY_CS_UNICODE))
{
strong= 1;
}
@@ -172,15 +174,15 @@ void Item_bool_func2::fix_length_and_dec()
String tmp, cstr;
String *ostr= args[weak]->val_str(&tmp);
cstr.copy(ostr->ptr(), ostr->length(), ostr->charset(),
- args[strong]->charset());
+ args[strong]->collation.collation);
conv= new Item_string(cstr.ptr(),cstr.length(),cstr.charset(),
- args[weak]->derivation());
+ args[weak]->collation.derivation);
((Item_string*)conv)->str_value.copy();
}
else
{
- conv= new Item_func_conv_charset(args[weak],args[strong]->charset());
- conv->collation.set(args[weak]->derivation());
+ conv= new Item_func_conv_charset(args[weak],args[strong]->collation.collation);
+ conv->collation.set(args[weak]->collation.derivation);
}
args[weak]= conv ? conv : args[weak];
}
@@ -249,7 +251,8 @@ int Arg_comparator::set_compare_func(Item_bool_func2 *item, Item_result type)
We must set cmp_charset here as we may be called from for an automatic
generated item, like in natural join
*/
- if (cmp_collation.set((*a)->collation, (*b)->collation))
+ if (cmp_collation.set((*a)->collation, (*b)->collation) ||
+ cmp_collation.derivation == DERIVATION_NONE)
{
my_coll_agg_error((*a)->collation, (*b)->collation, owner->func_name());
return 1;
@@ -379,25 +382,10 @@ bool Item_in_optimizer::fix_left(THD *thd,
(!cache && !(cache= Item_cache::get_cache(args[0]->result_type()))))
return 1;
cache->setup(args[0]);
- return 0;
-}
-
-
-
-bool Item_in_optimizer::fix_fields(THD *thd, struct st_table_list *tables,
- Item ** ref)
-{
- if (fix_left(thd, tables, ref))
- return 1;
- if (args[0]->maybe_null)
- maybe_null=1;
-
- with_sum_func= args[0]->with_sum_func;
- used_tables_cache= args[0]->used_tables();
- const_item_cache= args[0]->const_item();
+ cache->store(args[0]);
if (cache->cols() == 1)
{
- if (args[0]->used_tables())
+ if ((used_tables_cache= args[0]->used_tables()))
cache->set_used_tables(OUTER_REF_TABLE_BIT);
else
cache->set_used_tables(0);
@@ -412,7 +400,24 @@ bool Item_in_optimizer::fix_fields(THD *thd, struct st_table_list *tables,
else
((Item_cache *)cache->el(i))->set_used_tables(0);
}
+ used_tables_cache= args[0]->used_tables();
}
+ not_null_tables_cache= args[0]->not_null_tables();
+ with_sum_func= args[0]->with_sum_func;
+ const_item_cache= args[0]->const_item();
+ return 0;
+}
+
+
+
+bool Item_in_optimizer::fix_fields(THD *thd, struct st_table_list *tables,
+ Item ** ref)
+{
+ if (fix_left(thd, tables, ref))
+ return 1;
+ if (args[0]->maybe_null)
+ maybe_null=1;
+
if (!args[1]->fixed && args[1]->fix_fields(thd, tables, args))
return 1;
Item_in_subselect * sub= (Item_in_subselect *)args[1];
@@ -425,6 +430,7 @@ bool Item_in_optimizer::fix_fields(THD *thd, struct st_table_list *tables,
maybe_null=1;
with_sum_func= with_sum_func || args[1]->with_sum_func;
used_tables_cache|= args[1]->used_tables();
+ not_null_tables_cache|= args[1]->not_null_tables();
const_item_cache&= args[1]->const_item();
return 0;
}
@@ -537,6 +543,7 @@ void Item_func_interval::fix_length_and_dec()
maybe_null= 0;
max_length= 2;
used_tables_cache|= row->used_tables();
+ not_null_tables_cache&= row->not_null_tables();
with_sum_func= with_sum_func || row->with_sum_func;
}
@@ -550,25 +557,27 @@ void Item_func_interval::fix_length_and_dec()
longlong Item_func_interval::val_int()
{
- double value=row->el(0)->val();
+ double value= row->el(0)->val();
+ uint i;
+
if (row->el(0)->null_value)
return -1; // -1 if null
if (intervals)
{ // Use binary search to find interval
uint start,end;
- start=1; end=row->cols()-2;
+ start= 1;
+ end= row->cols()-2;
while (start != end)
{
- uint mid=(start+end+1)/2;
+ uint mid= (start + end + 1) / 2;
if (intervals[mid] <= value)
- start=mid;
+ start= mid;
else
- end=mid-1;
+ end= mid - 1;
}
- return (value < intervals[start]) ? 0 : start+1;
+ return (value < intervals[start]) ? 0 : start + 1;
}
- uint i;
for (i=1 ; i < row->cols() ; i++)
{
if (row->el(i)->val() > value)
@@ -729,13 +738,13 @@ Item_func_ifnull::val_str(String *str)
if (!args[0]->null_value)
{
null_value=0;
- res->set_charset(charset());
+ res->set_charset(collation.collation);
return res;
}
res=args[1]->val_str(str);
if ((null_value=args[1]->null_value))
return 0;
- res->set_charset(charset());
+ res->set_charset(collation.collation);
return res;
}
@@ -754,12 +763,12 @@ Item_func_if::fix_length_and_dec()
if (null1)
{
cached_result_type= arg2_type;
- set_charset(args[2]->charset());
+ collation.set(args[2]->collation.collation);
}
else if (null2)
{
cached_result_type= arg1_type;
- set_charset(args[1]->charset());
+ collation.set(args[1]->collation.collation);
}
else
{
@@ -771,7 +780,7 @@ Item_func_if::fix_length_and_dec()
}
else
{
- set_charset(&my_charset_bin); // Number
+ collation.set(&my_charset_bin); // Number
}
}
}
@@ -801,7 +810,7 @@ Item_func_if::val_str(String *str)
Item *arg= args[0]->val_int() ? args[1] : args[2];
String *res=arg->val_str(str);
if (res)
- res->set_charset(charset());
+ res->set_charset(collation.collation);
null_value=arg->null_value;
return res;
}
@@ -1186,7 +1195,7 @@ void in_string::set(uint pos,Item *item)
if (!str->charset())
{
CHARSET_INFO *cs;
- if (!(cs= item->charset()))
+ if (!(cs= item->collation.collation))
cs= &my_charset_bin; // Should never happen for STR items
str->set_charset(cs);
}
@@ -1264,7 +1273,7 @@ cmp_item* cmp_item::get_comparator(Item *item)
{
switch (item->result_type()) {
case STRING_RESULT:
- return new cmp_item_sort_string(item->charset());
+ return new cmp_item_sort_string(item->collation.collation);
break;
case INT_RESULT:
return new cmp_item_int;
@@ -1456,7 +1465,6 @@ void Item_func_in::fix_length_and_dec()
}
maybe_null= args[0]->maybe_null;
max_length= 1;
- const_item_cache&=args[0]->const_item();
}
@@ -1537,13 +1545,19 @@ Item_cond::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
#ifndef EMBEDDED_LIBRARY
char buff[sizeof(char*)]; // Max local vars in function
#endif
- used_tables_cache=0;
- const_item_cache=0;
+ not_null_tables_cache= used_tables_cache= 0;
+ const_item_cache= 0;
+ /*
+ and_table_cache is the value that Item_cond_or() returns for
+ not_null_tables()
+ */
+ and_tables_cache= ~(table_map) 0;
if (thd && check_stack_overrun(thd,buff))
return 0; // Fatal error flag is set!
while ((item=li++))
{
+ table_map tmp_table_map;
while (item->type() == Item::COND_ITEM &&
((Item_cond*) item)->functype() == functype())
{ // Identical function
@@ -1559,9 +1573,12 @@ Item_cond::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
if ((!item->fixed &&
item->fix_fields(thd, tables, li.ref())) || item->check_cols(1))
return 1; /* purecov: inspected */
- used_tables_cache|=item->used_tables();
- with_sum_func= with_sum_func || item->with_sum_func;
- const_item_cache&=item->const_item();
+ used_tables_cache|= item->used_tables();
+ tmp_table_map= item->not_null_tables();
+ not_null_tables_cache|= tmp_table_map;
+ and_tables_cache&= tmp_table_map;
+ const_item_cache&= item->const_item();
+ with_sum_func= with_sum_func || item->with_sum_func;
if (item->maybe_null)
maybe_null=1;
}
@@ -1612,17 +1629,19 @@ Item_cond::used_tables() const
return used_tables_cache;
}
+
void Item_cond::update_used_tables()
{
- used_tables_cache=0;
- const_item_cache=1;
List_iterator_fast<Item> li(list);
Item *item;
+
+ used_tables_cache=0;
+ const_item_cache=1;
while ((item=li++))
{
item->update_used_tables();
- used_tables_cache|=item->used_tables();
- const_item_cache&= item->const_item();
+ used_tables_cache|= item->used_tables();
+ const_item_cache&= item->const_item();
}
}
@@ -1726,12 +1745,16 @@ Item *and_expressions(Item *a, Item *b, Item **org_item)
{
Item_cond *res;
if ((res= new Item_cond_and(a, (Item*) b)))
+ {
res->used_tables_cache= a->used_tables() | b->used_tables();
+ res->not_null_tables_cache= a->not_null_tables() | b->not_null_tables();
+ }
return res;
}
if (((Item_cond_and*) a)->add((Item*) b))
return 0;
((Item_cond_and*) a)->used_tables_cache|= b->used_tables();
+ ((Item_cond_and*) a)->not_null_tables_cache|= b->not_null_tables();
return a;
}
@@ -1845,7 +1868,7 @@ bool Item_func_like::fix_fields(THD *thd, TABLE_LIST *tlist, Item ** ref)
We could also do boyer-more for non-const items, but as we would have to
recompute the tables for each row it's not worth it.
*/
- if (args[1]->const_item() && !use_strnxfrm(charset()) &&
+ if (args[1]->const_item() && !use_strnxfrm(collation.collation) &&
!(specialflag & SPECIAL_NO_NEW_FUNC))
{
String* res2 = args[1]->val_str(&tmp_value2);
@@ -1866,7 +1889,7 @@ bool Item_func_like::fix_fields(THD *thd, TABLE_LIST *tlist, Item ** ref)
{
const char* tmp = first + 1;
for (; *tmp != wild_many && *tmp != wild_one && *tmp != escape; tmp++) ;
- canDoTurboBM = (tmp == last) && !use_mb(args[0]->charset());
+ canDoTurboBM = (tmp == last) && !use_mb(args[0]->collation.collation);
}
if (canDoTurboBM)
@@ -1902,6 +1925,8 @@ Item_func_regex::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
return 1;
used_tables_cache=args[0]->used_tables() | args[1]->used_tables();
+ not_null_tables_cache= (args[0]->not_null_tables() |
+ args[1]->not_null_tables());
const_item_cache=args[0]->const_item() && args[1]->const_item();
if (!regex_compiled && args[1]->const_item())
{
@@ -2143,7 +2168,7 @@ bool Item_func_like::turboBM_matches(const char* text, int text_len) const
int shift = pattern_len;
int j = 0;
int u = 0;
- CHARSET_INFO *cs=system_charset_info; // QQ Needs to be fixed
+ CHARSET_INFO *cs= cmp.cmp_collation.collation; // QQ Needs to be fixed
const int plm1= pattern_len - 1;
const int tlmpl= text_len - pattern_len;
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index 44e1cf99511..5c06f4fa1df 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -290,6 +290,7 @@ public:
enum Item_result result_type () const { return cached_result_type; }
void fix_length_and_dec();
const char *func_name() const { return "ifnull"; }
+ table_map not_null_tables() const { return 0; }
};
@@ -311,6 +312,7 @@ public:
}
void fix_length_and_dec();
const char *func_name() const { return "if"; }
+ table_map not_null_tables() const { return 0; }
};
@@ -327,6 +329,7 @@ public:
enum Item_result result_type () const { return cached_result_type; }
void fix_length_and_dec();
const char *func_name() const { return "nullif"; }
+ table_map not_null_tables() const { return 0; }
};
@@ -343,8 +346,10 @@ public:
void fix_length_and_dec();
enum Item_result result_type () const { return cached_result_type; }
const char *func_name() const { return "coalesce"; }
+ table_map not_null_tables() const { return 0; }
};
+
class Item_func_case :public Item_func
{
int first_expr_num, else_expr_num;
@@ -375,6 +380,7 @@ public:
longlong val_int();
String *val_str(String *);
void fix_length_and_dec();
+ table_map not_null_tables() const { return 0; }
enum Item_result result_type () const { return cached_result_type; }
const char *func_name() const { return "case"; }
void print(String *str);
@@ -667,6 +673,7 @@ public:
}
}
}
+ table_map not_null_tables() const { return 0; }
optimize_type select_optimize() const { return OPTIMIZE_NULL; }
};
@@ -699,8 +706,10 @@ public:
}
const char *func_name() const { return "isnotnull"; }
optimize_type select_optimize() const { return OPTIMIZE_NULL; }
+ table_map not_null_tables() const { return 0; }
};
+
class Item_func_like :public Item_bool_func2
{
char escape;
@@ -773,6 +782,8 @@ class Item_cond :public Item_bool_func
protected:
List<Item> list;
bool abort_on_null;
+ table_map and_tables_cache;
+
public:
/* Item_cond() is only used to create top level items */
Item_cond() : Item_bool_func(), abort_on_null(1) { const_item_cache=0; }
@@ -813,15 +824,23 @@ public:
enum Functype functype() const { return COND_OR_FUNC; }
longlong val_int();
const char *func_name() const { return "or"; }
+ table_map not_null_tables() const { return and_tables_cache; }
};
+/*
+ XOR is Item_cond, not an Item_int_func bevause we could like to
+ optimize (a XOR b) later on. It's low prio, though
+*/
+
class Item_cond_xor :public Item_cond
{
public:
Item_cond_xor() :Item_cond() {}
Item_cond_xor(Item *i1,Item *i2) :Item_cond(i1,i2) {}
enum Functype functype() const { return COND_XOR_FUNC; }
+ /* TODO: remove the next line when implementing XOR optimization */
+ enum Type type() const { return FUNC_ITEM; }
longlong val_int();
const char *func_name() const { return "xor"; }
};
diff --git a/sql/item_create.cc b/sql/item_create.cc
index e18d1cfa189..e3e3c021a1e 100644
--- a/sql/item_create.cc
+++ b/sql/item_create.cc
@@ -470,21 +470,21 @@ Item *create_load_file(Item* a)
}
-Item *create_func_cast(Item *a, Cast_target cast_type, CHARSET_INFO *cs)
+Item *create_func_cast(Item *a, Cast_target cast_type, int len, CHARSET_INFO *cs)
{
Item *res;
LINT_INIT(res);
switch (cast_type) {
case ITEM_CAST_BINARY: res= new Item_func_binary(a); break;
- case ITEM_CAST_CHAR:
- res= (cs == NULL) ? (Item*) new Item_char_typecast(a) :
- (Item*) new Item_func_conv_charset(a,cs);
- break;
case ITEM_CAST_SIGNED_INT: res= new Item_func_signed(a); break;
case ITEM_CAST_UNSIGNED_INT: res= new Item_func_unsigned(a); break;
case ITEM_CAST_DATE: res= new Item_date_typecast(a); break;
case ITEM_CAST_TIME: res= new Item_time_typecast(a); break;
case ITEM_CAST_DATETIME: res= new Item_datetime_typecast(a); break;
+ case ITEM_CAST_CHAR:
+ res= new Item_char_typecast(a, len, cs ? cs :
+ current_thd->variables.collation_connection);
+ break;
}
return res;
}
diff --git a/sql/item_create.h b/sql/item_create.h
index 1326077b096..16c4fccf709 100644
--- a/sql/item_create.h
+++ b/sql/item_create.h
@@ -28,7 +28,7 @@ Item *create_func_bit_length(Item* a);
Item *create_func_coercibility(Item* a);
Item *create_func_ceiling(Item* a);
Item *create_func_char_length(Item* a);
-Item *create_func_cast(Item *a, Cast_target cast_type, CHARSET_INFO *cs);
+Item *create_func_cast(Item *a, Cast_target cast_type, int len, CHARSET_INFO *cs);
Item *create_func_connection_id(void);
Item *create_func_conv(Item* a, Item *b, Item *c);
Item *create_func_cos(Item* a);
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 8a27bf16b37..4bda8ae78cd 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -22,7 +22,7 @@
#endif
#include "mysql_priv.h"
-#include "slave.h" // for wait_for_master_pos
+#include "slave.h" // for wait_for_master_pos
#include <m_ctype.h>
#include <hash.h>
#include <time.h>
@@ -31,7 +31,9 @@
#include <zlib.h>
#endif
-static void my_coll_agg_error(DTCollation &c1, DTCollation &c2, const char *fname)
+
+static void my_coll_agg_error(DTCollation &c1, DTCollation &c2,
+ const char *fname)
{
my_error(ER_CANT_AGGREGATE_2COLLATIONS,MYF(0),
c1.collation->name,c1.derivation_name(),
@@ -39,6 +41,7 @@ static void my_coll_agg_error(DTCollation &c1, DTCollation &c2, const char *fnam
fname);
}
+
static void my_coll_agg_error(DTCollation &c1,
DTCollation &c2,
DTCollation &c3,
@@ -51,11 +54,12 @@ static void my_coll_agg_error(DTCollation &c1,
fname);
}
-static void my_coll_agg_error(Item** args, uint ac, const char *fname)
+
+static void my_coll_agg_error(Item** args, uint count, const char *fname)
{
- if (2 == ac)
+ if (count == 2)
my_coll_agg_error(args[0]->collation, args[1]->collation, fname);
- else if (3 == ac)
+ else if (count == 3)
my_coll_agg_error(args[0]->collation,
args[1]->collation,
args[2]->collation,
@@ -64,30 +68,32 @@ static void my_coll_agg_error(Item** args, uint ac, const char *fname)
my_error(ER_CANT_AGGREGATE_NCOLLATIONS,MYF(0),fname);
}
-bool Item_func::agg_arg_collations(DTCollation &c, Item **av, uint ac)
+
+bool Item_func::agg_arg_collations(DTCollation &c, Item **av, uint count)
{
uint i;
c.set(av[0]->collation);
- for (i= 1; i < ac; i++)
+ for (i= 1; i < count; i++)
{
if (c.aggregate(av[i]->collation))
{
- my_coll_agg_error(av, ac, func_name());
+ my_coll_agg_error(av, count, func_name());
return TRUE;
}
}
return FALSE;
}
+
bool Item_func::agg_arg_collations_for_comparison(DTCollation &c,
- Item **av, uint ac)
+ Item **av, uint count)
{
- if (agg_arg_collations(c, av, ac))
+ if (agg_arg_collations(c, av, count))
return TRUE;
if (c.derivation == DERIVATION_NONE)
{
- my_coll_agg_error(av, ac, func_name());
+ my_coll_agg_error(av, count, func_name());
return TRUE;
}
return FALSE;
@@ -102,6 +108,7 @@ eval_const_cond(COND *cond)
return ((Item_func*) cond)->val_int() ? TRUE : FALSE;
}
+
void Item_func::set_arguments(List<Item> &list)
{
allowed_arg_cols= 1;
@@ -168,7 +175,7 @@ Item_func::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
Item **arg,**arg_end;
char buff[STACK_BUFF_ALLOC]; // Max argument in function
- used_tables_cache=0;
+ used_tables_cache= not_null_tables_cache= 0;
const_item_cache=1;
if (thd && check_stack_overrun(thd,buff))
@@ -187,11 +194,14 @@ Item_func::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
maybe_null=1;
with_sum_func= with_sum_func || item->with_sum_func;
- used_tables_cache|=item->used_tables();
- const_item_cache&= item->const_item();
+ used_tables_cache|= item->used_tables();
+ not_null_tables_cache|= item->not_null_tables();
+ const_item_cache&= item->const_item();
}
}
fix_length_and_dec();
+ if (thd && thd->net.last_errno) // An error inside fix_length_and_dec accured
+ return 1;
fixed= 1;
return 0;
}
@@ -247,6 +257,13 @@ table_map Item_func::used_tables() const
return used_tables_cache;
}
+
+table_map Item_func::not_null_tables() const
+{
+ return not_null_tables_cache;
+}
+
+
void Item_func::print(String *str)
{
str->append(func_name());
@@ -311,9 +328,9 @@ Field *Item_func::tmp_table_field(TABLE *t_arg)
break;
case STRING_RESULT:
if (max_length > 255)
- res= new Field_blob(max_length, maybe_null, name, t_arg, charset());
+ res= new Field_blob(max_length, maybe_null, name, t_arg, collation.collation);
else
- res= new Field_string(max_length, maybe_null, name, t_arg, charset());
+ res= new Field_string(max_length, maybe_null, name, t_arg, collation.collation);
break;
case ROW_RESULT:
default:
@@ -590,6 +607,7 @@ double Item_func_neg::val()
return -value;
}
+
longlong Item_func_neg::val_int()
{
longlong value=args[0]->val_int();
@@ -597,14 +615,32 @@ longlong Item_func_neg::val_int()
return -value;
}
+
void Item_func_neg::fix_length_and_dec()
{
decimals=args[0]->decimals;
max_length=args[0]->max_length;
- hybrid_type= args[0]->result_type() == INT_RESULT && !args[0]->unsigned_flag ?
- INT_RESULT : REAL_RESULT;
+ hybrid_type= REAL_RESULT;
+ if (args[0]->result_type() == INT_RESULT)
+ {
+ /*
+ If this is in integer context keep the context as integer
+ (This is how multiplication and other integer functions works)
+
+ We must however do a special case in the case where the argument
+ is a unsigned bigint constant as in this case the only safe
+ number to convert in integer context is 9223372036854775808.
+ (This is needed because the lex parser doesn't anymore handle
+ signed integers)
+ */
+ if (args[0]->type() != INT_ITEM ||
+ ((ulonglong) ((Item_uint*) args[0])->value <=
+ (ulonglong) LONGLONG_MIN))
+ hybrid_type= INT_RESULT;
+ }
}
+
double Item_func_abs::val()
{
double value=args[0]->val();
@@ -612,6 +648,7 @@ double Item_func_abs::val()
return fabs(value);
}
+
longlong Item_func_abs::val_int()
{
longlong value=args[0]->val_int();
@@ -619,13 +656,20 @@ longlong Item_func_abs::val_int()
return value >= 0 ? value : -value;
}
+
void Item_func_abs::fix_length_and_dec()
{
decimals=args[0]->decimals;
max_length=args[0]->max_length;
- hybrid_type= args[0]->result_type() == INT_RESULT ? INT_RESULT : REAL_RESULT;
+ hybrid_type= REAL_RESULT;
+ if (args[0]->result_type() == INT_RESULT)
+ {
+ hybrid_type= INT_RESULT;
+ unsigned_flag= 1;
+ }
}
+
/* Gateway to natural LOG function */
double Item_func_ln::val()
{
@@ -978,13 +1022,13 @@ String *Item_func_min_max::val_str(String *str)
res2= args[i]->val_str(res == str ? &tmp_value : str);
if (res2)
{
- int cmp= sortcmp(res,res2,charset());
+ int cmp= sortcmp(res,res2,collation.collation);
if ((cmp_sign < 0 ? cmp : -cmp) < 0)
res=res2;
}
}
}
- res->set_charset(charset());
+ res->set_charset(collation.collation);
return res;
}
case ROW_RESULT:
@@ -1055,6 +1099,7 @@ longlong Item_func_crc32::val_int()
return (longlong) crc32(0L, (Bytef*)res->ptr(), res->length());
}
+
longlong Item_func_uncompressed_length::val_int()
{
String *res= args[0]->val_str(&value);
@@ -1067,9 +1112,9 @@ longlong Item_func_uncompressed_length::val_int()
if (res->is_empty()) return 0;
return uint4korr(res->c_ptr()) & 0x3FFFFFFF;
}
-
#endif /* HAVE_COMPRESS */
+
longlong Item_func_length::val_int()
{
String *res=args[0]->val_str(&value);
@@ -1082,6 +1127,7 @@ longlong Item_func_length::val_int()
return (longlong) res->length();
}
+
longlong Item_func_char_length::val_int()
{
String *res=args[0]->val_str(&value);
@@ -1094,6 +1140,7 @@ longlong Item_func_char_length::val_int()
return (longlong) res->numchars();
}
+
longlong Item_func_coercibility::val_int()
{
if (args[0]->null_value)
@@ -1102,15 +1149,17 @@ longlong Item_func_coercibility::val_int()
return 0;
}
null_value= 0;
- return (longlong) args[0]->derivation();
+ return (longlong) args[0]->collation.derivation;
}
+
void Item_func_locate::fix_length_and_dec()
{
maybe_null=0; max_length=11;
agg_arg_collations_for_comparison(cmp_collation, args, 2);
}
+
longlong Item_func_locate::val_int()
{
String *a=args[0]->val_str(&value1);
@@ -1185,8 +1234,7 @@ longlong Item_func_field::val_int()
for (uint i=1 ; i < arg_count ; i++)
{
String *tmp_value=args[i]->val_str(&tmp);
- if (tmp_value && field->length() == tmp_value->length() &&
- !sortcmp(field,tmp_value,cmp_collation.collation))
+ if (tmp_value && !sortcmp(field,tmp_value,cmp_collation.collation))
return (longlong) (i);
}
}
@@ -1211,6 +1259,7 @@ longlong Item_func_field::val_int()
return 0;
}
+
void Item_func_field::fix_length_and_dec()
{
maybe_null=0; max_length=3;
@@ -1437,8 +1486,8 @@ udf_handler::fix_fields(THD *thd, TABLE_LIST *tables, Item_result_field *func,
There is no a general rule for UDF. Everything depends on
the particular user definted function.
*/
- if (item->charset()->state & MY_CS_BINSORT)
- func->set_charset(&my_charset_bin);
+ if (item->collation.collation->state & MY_CS_BINSORT)
+ func->collation.set(&my_charset_bin);
if (item->maybe_null)
func->maybe_null=1;
func->with_sum_func= func->with_sum_func || item->with_sum_func;
@@ -2081,6 +2130,7 @@ bool Item_func_set_user_var::fix_fields(THD *thd, TABLE_LIST *tables,
if (Item_func::fix_fields(thd, tables, ref) ||
!(entry= get_variable(&thd->user_vars, name, 1)))
return 1;
+ entry->type= cached_result_type;
entry->update_query_id=thd->query_id;
return 0;
}
@@ -2202,7 +2252,7 @@ Item_func_set_user_var::val_str(String *str)
update_hash((void*) 0, 0, STRING_RESULT, &my_charset_bin, DERIVATION_NONE);
else
update_hash((void*) res->ptr(), res->length(), STRING_RESULT,
- res->charset(), args[0]->derivation());
+ res->charset(), args[0]->collation.derivation);
return res;
}
@@ -2640,6 +2690,9 @@ double Item_func_match::val()
if (ft_handler == NULL)
DBUG_RETURN(-1.0);
+ if (table->null_row) /* NULL row from an outer join */
+ return 0.0;
+
if (join_key)
{
if (table->file->ft_handler)
diff --git a/sql/item_func.h b/sql/item_func.h
index e13d30068e4..7fedbcf48ee 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -35,7 +35,7 @@ protected:
uint allowed_arg_cols;
public:
uint arg_count;
- table_map used_tables_cache;
+ table_map used_tables_cache, not_null_tables_cache;
bool const_item_cache;
enum Functype { UNKNOWN_FUNC,EQ_FUNC,EQUAL_FUNC,NE_FUNC,LT_FUNC,LE_FUNC,
GE_FUNC,GT_FUNC,FT_FUNC,
@@ -107,6 +107,7 @@ public:
~Item_func() {} /* Nothing to do; Items are freed automaticly */
bool fix_fields(THD *,struct st_table_list *, Item **ref);
table_map used_tables() const;
+ table_map not_null_tables() const;
void update_used_tables();
bool eq(const Item *item, bool binary_cmp) const;
virtual optimize_type select_optimize() const { return OPTIMIZE_NONE; }
@@ -768,6 +769,7 @@ public:
return res;
}
Item_result result_type () const { return udf.result_type(); }
+ table_map not_null_tables() const { return 0; }
};
@@ -1005,6 +1007,7 @@ public:
}
enum Functype functype() const { return FT_FUNC; }
void update_used_tables() {}
+ table_map not_null_tables() const { return 0; }
bool fix_fields(THD *thd, struct st_table_list *tlist, Item **ref);
bool eq(const Item *, bool binary_cmp) const;
longlong val_int() { return val()!=0.0; }
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index 4e35e90b429..b0b9cc01bf1 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -310,7 +310,7 @@ String *Item_func_concat::val_str(String *str)
}
}
}
- res->set_charset(charset());
+ res->set_charset(collation.collation);
return res;
null:
@@ -596,7 +596,7 @@ String *Item_func_concat_ws::val_str(String *str)
use_as_buff=str;
}
}
- res->set_charset(charset());
+ res->set_charset(collation.collation);
return res;
null:
@@ -637,9 +637,10 @@ void Item_func_concat_ws::fix_length_and_dec()
max_length=MAX_BLOB_WIDTH;
maybe_null=1;
}
- used_tables_cache|=separator->used_tables();
- const_item_cache&=separator->const_item();
- with_sum_func= with_sum_func || separator->with_sum_func;
+ used_tables_cache|= separator->used_tables();
+ not_null_tables_cache&= separator->not_null_tables();
+ const_item_cache&= separator->const_item();
+ with_sum_func= with_sum_func || separator->with_sum_func;
}
void Item_func_concat_ws::update_used_tables()
@@ -697,7 +698,7 @@ String *Item_func_reverse::val_str(String *str)
void Item_func_reverse::fix_length_and_dec()
{
- set_charset(*args[0]);
+ collation.set(args[0]->collation);
max_length = args[0]->max_length;
}
@@ -933,7 +934,7 @@ void Item_str_func::left_right_max_length()
max_length=args[0]->max_length;
if (args[1]->const_item())
{
- int length=(int) args[1]->val_int()*charset()->mbmaxlen;
+ int length=(int) args[1]->val_int()*collation.collation->mbmaxlen;
if (length <= 0)
max_length=0;
else
@@ -944,7 +945,7 @@ void Item_str_func::left_right_max_length()
void Item_func_left::fix_length_and_dec()
{
- set_charset(*args[0]);
+ collation.set(args[0]->collation);
left_right_max_length();
}
@@ -971,7 +972,7 @@ String *Item_func_right::val_str(String *str)
void Item_func_right::fix_length_and_dec()
{
- set_charset(*args[0]);
+ collation.set(args[0]->collation);
left_right_max_length();
}
@@ -1006,7 +1007,7 @@ void Item_func_substr::fix_length_and_dec()
{
max_length=args[0]->max_length;
- set_charset(*args[0]);
+ collation.set(args[0]->collation);
if (args[1]->const_item())
{
int32 start=(int32) args[1]->val_int()-1;
@@ -1314,7 +1315,7 @@ void Item_func_trim::fix_length_and_dec()
if (arg_count == 1)
{
collation.set(args[0]->collation);
- remove.set_charset(charset());
+ remove.set_charset(collation.collation);
remove.set_ascii(" ",1);
}
else
@@ -1535,7 +1536,7 @@ String *Item_func_user::val_str(String *str)
void Item_func_soundex::fix_length_and_dec()
{
- set_charset(*args[0]);
+ collation.set(args[0]->collation);
max_length=args[0]->max_length;
set_if_bigger(max_length,4);
}
@@ -1567,7 +1568,7 @@ String *Item_func_soundex::val_str(String *str)
{
String *res =args[0]->val_str(str);
char last_ch,ch;
- CHARSET_INFO *cs= charset();
+ CHARSET_INFO *cs= collation.collation;
if ((null_value=args[0]->null_value))
return 0; /* purecov: inspected */
@@ -1627,6 +1628,10 @@ String *Item_func_format::val_str(String *str)
return 0; /* purecov: inspected */
dec= decimals ? decimals+1 : 0;
str->set(nr,decimals,default_charset());
+#ifdef HAVE_ISNAN
+ if (isnan(nr))
+ return str;
+#endif
str_length=str->length();
if (nr < 0)
str_length--; // Don't count sign
@@ -1639,7 +1644,7 @@ String *Item_func_format::val_str(String *str)
str= copy_if_not_alloced(&tmp_str,str,length);
str->length(length);
tmp= (char*) str->ptr()+length - dec-1;
- for (pos= (char*) str->ptr()+length ; pos != tmp; pos--)
+ for (pos= (char*) str->ptr()+length-1; pos != tmp; pos--)
pos[0]= pos[-(int) diff];
while (diff)
{
@@ -1675,40 +1680,40 @@ void Item_func_elt::fix_length_and_dec()
double Item_func_elt::val()
{
uint tmp;
+ null_value=1;
if ((tmp=(uint) args[0]->val_int()) == 0 || tmp >= arg_count)
- {
- null_value=1;
return 0.0;
- }
- null_value=0;
- return args[tmp]->val();
+ double result= args[tmp]->val();
+ null_value= args[tmp]->null_value;
+ return result;
}
+
longlong Item_func_elt::val_int()
{
uint tmp;
+ null_value=1;
if ((tmp=(uint) args[0]->val_int()) == 0 || tmp >= arg_count)
- {
- null_value=1;
return 0;
- }
- null_value=0;
- return args[tmp]->val_int();
+
+ longlong result= args[tmp]->val_int();
+ null_value= args[tmp]->null_value;
+ return result;
}
+
String *Item_func_elt::val_str(String *str)
{
uint tmp;
- String *res;
+ null_value=1;
if ((tmp=(uint) args[0]->val_int()) == 0 || tmp >= arg_count)
- {
- null_value=1;
return NULL;
- }
- null_value=0;
- res= args[tmp]->val_str(str);
- res->set_charset(charset());
- return res;
+
+ String *result= args[tmp]->val_str(str);
+ if (result)
+ result->set_charset(collation.collation);
+ null_value= args[tmp]->null_value;
+ return result;
}
@@ -1738,8 +1743,9 @@ void Item_func_make_set::fix_length_and_dec()
for (uint i=0 ; i < arg_count ; i++)
max_length+=args[i]->max_length;
- used_tables_cache|=item->used_tables();
- const_item_cache&=item->const_item();
+ used_tables_cache|= item->used_tables();
+ not_null_tables_cache&= item->not_null_tables();
+ const_item_cache&= item->const_item();
with_sum_func= with_sum_func || item->with_sum_func;
}
@@ -1813,7 +1819,7 @@ String *Item_func_char::val_str(String *str)
int32 num=(int32) args[i]->val_int();
if (!args[i]->null_value)
#ifdef USE_MB
- if (use_mb(charset()))
+ if (use_mb(collation.collation))
{
if (num&0xFF000000L) {
str->append((char)(num>>24));
@@ -1860,7 +1866,7 @@ inline String* alloc_buffer(String *res,String *str,String *tmp_value,
void Item_func_repeat::fix_length_and_dec()
{
- set_charset(*args[0]);
+ collation.set(args[0]->collation);
if (args[1]->const_item())
{
max_length=(long) (args[0]->max_length * args[1]->val_int());
@@ -1953,7 +1959,7 @@ String *Item_func_rpad::val_str(String *str)
String *res =args[0]->val_str(str);
String *rpad = args[2]->val_str(str);
- if (!res || args[1]->null_value || !rpad)
+ if (!res || args[1]->null_value || !rpad || count < 0)
goto err;
null_value=0;
if (count <= (int32) (res_length=res->length()))
@@ -2109,7 +2115,7 @@ String *Item_func_conv_charset::val_str(String *str)
void Item_func_conv_charset::fix_length_and_dec()
{
- set_charset(conv_charset, DERIVATION_IMPLICIT);
+ collation.set(conv_charset, DERIVATION_IMPLICIT);
max_length = args[0]->max_length*conv_charset->mbmaxlen;
}
@@ -2192,7 +2198,7 @@ String *Item_func_set_collation::val_str(String *str)
str=args[0]->val_str(str);
if ((null_value=args[0]->null_value))
return 0;
- str->set_charset(charset());
+ str->set_charset(collation.collation);
return str;
}
@@ -2203,18 +2209,25 @@ void Item_func_set_collation::fix_length_and_dec()
String tmp, *str= args[1]->val_str(&tmp);
colname= str->c_ptr();
if (colname == binary_keyword)
- set_collation= get_charset_by_csname(args[0]->charset()->csname,
+ set_collation= get_charset_by_csname(args[0]->collation.collation->csname,
MY_CS_BINSORT,MYF(0));
else
- set_collation= get_charset_by_name(colname,MYF(0));
+ {
+ if (!(set_collation= get_charset_by_name(colname,MYF(0))))
+ {
+ my_error(ER_UNKNOWN_COLLATION, MYF(0), colname);
+ return;
+ }
+ }
- if (!set_collation || !my_charset_same(args[0]->charset(),set_collation))
+ if (!set_collation ||
+ !my_charset_same(args[0]->collation.collation,set_collation))
{
my_error(ER_COLLATION_CHARSET_MISMATCH, MYF(0),
- colname,args[0]->charset()->csname);
+ colname,args[0]->collation.collation->csname);
return;
}
- set_charset(set_collation, DERIVATION_EXPLICIT);
+ collation.set(set_collation, DERIVATION_EXPLICIT);
max_length= args[0]->max_length;
}
@@ -2231,7 +2244,7 @@ bool Item_func_set_collation::eq(const Item *item, bool binary_cmp) const
func_name() != item_func->func_name())
return 0;
Item_func_set_collation *item_func_sc=(Item_func_set_collation*) item;
- if (charset() != item_func_sc->charset())
+ if (collation.collation != item_func_sc->collation.collation)
return 0;
for (uint i=0; i < arg_count ; i++)
if (!args[i]->eq(item_func_sc->args[i], binary_cmp))
@@ -2533,7 +2546,7 @@ String *Item_func_quote::val_str(String *str)
}
*to= '\'';
str->length(new_length);
- str->set_charset(charset());
+ str->set_charset(collation.collation);
return str;
null:
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index 4225dd43b12..f64a145b136 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -153,7 +153,7 @@ public:
Item_str_conv(Item *item) :Item_str_func(item) {}
void fix_length_and_dec()
{
- set_charset(*args[0]);
+ collation.set(args[0]->collation);
max_length = args[0]->max_length;
}
};
@@ -335,12 +335,11 @@ public:
class Item_func_database :public Item_str_func
{
public:
- Item_func_database() { set_charset(DERIVATION_IMPLICIT); }
+ Item_func_database() { collation.set(system_charset_info,DERIVATION_IMPLICIT); }
String *val_str(String *);
void fix_length_and_dec()
{
max_length= MAX_FIELD_NAME * system_charset_info->mbmaxlen;
- set_charset(system_charset_info);
}
const char *func_name() const { return "database"; }
};
@@ -348,12 +347,11 @@ public:
class Item_func_user :public Item_str_func
{
public:
- Item_func_user() { set_charset(DERIVATION_IMPLICIT); }
+ Item_func_user() { collation.set(system_charset_info, DERIVATION_IMPLICIT); }
String *val_str(String *);
void fix_length_and_dec()
{
max_length= (USERNAME_LENGTH+HOSTNAME_LENGTH+1)*system_charset_info->mbmaxlen;
- set_charset(system_charset_info);
}
const char *func_name() const { return "user"; }
};
@@ -418,7 +416,7 @@ public:
String *val_str(String *);
void fix_length_and_dec()
{
- set_charset(default_charset());
+ collation.set(default_charset());
max_length=args[0]->max_length+(args[0]->max_length-args[0]->decimals)/3;
}
const char *func_name() const { return "format"; }
@@ -432,7 +430,7 @@ public:
String *val_str(String *);
void fix_length_and_dec()
{
- set_charset(default_charset());
+ collation.set(default_charset());
maybe_null=0; max_length=arg_count;
}
const char *func_name() const { return "char"; }
@@ -482,7 +480,7 @@ public:
String *val_str(String *);
void fix_length_and_dec()
{
- set_charset(default_charset());
+ collation.set(default_charset());
decimals=0; max_length=64;
}
};
@@ -497,7 +495,7 @@ public:
String *val_str(String *);
void fix_length_and_dec()
{
- set_charset(default_charset());
+ collation.set(default_charset());
decimals=0; max_length=args[0]->max_length*2;
}
};
@@ -518,7 +516,7 @@ public:
}
void fix_length_and_dec()
{
- set_charset(&my_charset_bin);
+ collation.set(&my_charset_bin);
max_length=args[0]->max_length;
}
void print(String *str) { print_op(str); }
@@ -534,7 +532,7 @@ public:
const char *func_name() const { return "load_file"; }
void fix_length_and_dec()
{
- set_charset(&my_charset_bin, DERIVATION_COERCIBLE);
+ collation.set(&my_charset_bin, DERIVATION_COERCIBLE);
maybe_null=1;
max_length=MAX_BLOB_WIDTH;
}
@@ -571,7 +569,7 @@ public:
String *val_str(String *);
void fix_length_and_dec()
{
- set_charset(*args[0]);
+ collation.set(args[0]->collation);
max_length= args[0]->max_length * 2 + 2;
}
};
@@ -616,7 +614,7 @@ public:
void fix_length_and_dec()
{
max_length=40; // should be enough
- set_charset(default_charset());
+ collation.set(system_charset_info);
};
};
@@ -629,6 +627,6 @@ public:
void fix_length_and_dec()
{
max_length=40; // should be enough
- set_charset(default_charset());
+ collation.set(system_charset_info);
};
};
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 3d2a88d29e5..cbda995504c 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -148,7 +148,7 @@ void Item_subselect::fix_length_and_dec()
inline table_map Item_subselect::used_tables() const
{
return (table_map) (engine->dependent() ? 1L :
- (engine->uncacheable() ? OUTER_REF_TABLE_BIT : 0L));
+ (engine->uncacheable() ? RAND_TABLE_BIT : 0L));
}
Item_singlerow_subselect::Item_singlerow_subselect(THD *thd,
@@ -518,7 +518,7 @@ Item_in_subselect::single_value_transformer(JOIN *join,
*/
expr= new Item_ref((Item**)optimizer->get_cache(),
(char *)"<no matter>",
- (char *)"<left expr>");
+ (char *)in_left_expr_name);
unit->dependent= 1;
}
@@ -559,27 +559,6 @@ Item_in_subselect::single_value_transformer(JOIN *join,
if (select_lex->table_list.elements)
{
Item *having= item, *isnull= item;
- if (item->type() == Item::FIELD_ITEM &&
- ((Item_field*) item)->field_name[0] == '*')
- {
- Item_asterisk_remover *remover;
- item= remover= new Item_asterisk_remover(this, item,
- (char *)"<no matter>",
- (char *)"<result>");
- if (!abort_on_null)
- {
- having=
- new Item_is_not_null_test(this,
- new Item_ref(remover->storage(),
- (char *)"<no matter>",
- (char *)"<null test>"));
- isnull=
- new Item_is_not_null_test(this,
- new Item_ref(remover->storage(),
- (char *)"<no matter>",
- (char *)"<null test>"));
- }
- }
item= (*func)(expr, item);
if (!abort_on_null)
{
@@ -603,22 +582,12 @@ Item_in_subselect::single_value_transformer(JOIN *join,
}
else
{
- if (item->type() == Item::FIELD_ITEM &&
- ((Item_field*) item)->field_name[0] == '*')
- {
- my_error(ER_NO_TABLES_USED, MYF(0));
- DBUG_RETURN(ERROR);
- }
if (select_lex->master_unit()->first_select()->next_select())
{
- /*
- It is in union => we should perform it.
- Item_asterisk_remover used only as wrapper to receine NULL value
- */
join->having= (*func)(expr,
- new Item_asterisk_remover(this, item,
- (char *)"<no matter>",
- (char *)"<result>"));
+ new Item_null_helper(this, item,
+ (char *)"<no matter>",
+ (char *)"<result>"));
select_lex->having_fix_field= 1;
if (join->having->fix_fields(thd, join->tables_list, &join->having))
{
@@ -681,20 +650,22 @@ Item_in_subselect::row_value_transformer(JOIN *join,
uint n= left_expr->cols();
select_lex->dependent= 1;
-
+ select_lex->setup_ref_array(thd,
+ select_lex->order_list.elements +
+ select_lex->group_list.elements);
Item *item= 0;
List_iterator_fast<Item> li(select_lex->item_list);
for (uint i= 0; i < n; i++)
{
- Item *func=
- new Item_ref_on_list_position(this, select_lex, i,
- (char *) "<no matter>",
- (char *) "<list ref>");
+ Item *func= new Item_ref_null_helper(this,
+ select_lex->ref_pointer_array+i,
+ (char *) "<no matter>",
+ (char *) "<list ref>");
func=
Item_bool_func2::eq_creator(new Item_ref((*optimizer->get_cache())->
addr(i),
(char *)"<no matter>",
- (char *)"<left expr>"),
+ (char *)in_left_expr_name),
func);
item= and_items(item, func);
}
@@ -825,6 +796,7 @@ static Item_result set_row(SELECT_LEX *select_lex, Item * item,
if (!(row[i]= Item_cache::get_cache(res_type)))
return STRING_RESULT; // we should return something
row[i]->set_len_n_dec(sel_item->max_length, sel_item->decimals);
+ row[i]->collation.set(sel_item->collation);
}
}
if (select_lex->item_list.elements > 1)
@@ -836,6 +808,7 @@ 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, row, &maybe_null);
+ item->collation.set(row[0]->collation);
if (cols() != 1)
maybe_null= 0;
}
diff --git a/sql/item_subselect.h b/sql/item_subselect.h
index e2738102ebd..ddb53ab616a 100644
--- a/sql/item_subselect.h
+++ b/sql/item_subselect.h
@@ -192,7 +192,7 @@ public:
class Item_in_subselect :public Item_exists_subselect
{
protected:
- Item * left_expr;
+ Item *left_expr;
/*
expr & optimizer used in subselect rewriting to store Item for
all JOIN in UNION
@@ -204,7 +204,7 @@ protected:
public:
Item_in_subselect(THD *thd, Item * left_expr, st_select_lex *select_lex);
Item_in_subselect(Item_in_subselect *item);
- Item_in_subselect(): Item_exists_subselect(), abort_on_null(0) {}
+ Item_in_subselect(): Item_exists_subselect(), abort_on_null(0) {}
subs_type substype() { return IN_SUBS; }
void reset()
@@ -225,7 +225,6 @@ public:
void top_level_item() { abort_on_null=1; }
bool test_limit(st_select_lex_unit *unit);
- friend class Item_asterisk_remover;
friend class Item_ref_null_helper;
friend class Item_is_not_null_test;
friend class subselect_indexin_engine;
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index fde39135358..0d05d05f0af 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -193,13 +193,13 @@ Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
max_length=float_length(decimals);
}else
{
- cmp_charset= item->charset();
+ cmp_charset= item->collation.collation;
max_length=item->max_length;
}
decimals=item->decimals;
maybe_null=item->maybe_null;
unsigned_flag=item->unsigned_flag;
- set_charset(item->charset());
+ collation.set(item->collation);
result_field=0;
null_value=1;
fix_length_and_dec();
@@ -1023,7 +1023,9 @@ int simple_str_key_cmp(void* arg, byte* key1, byte* key2)
Item_sum_count_distinct* item = (Item_sum_count_distinct*)arg;
CHARSET_INFO *cs=item->key_charset;
uint len=item->key_length;
- return my_strnncoll(cs, (const uchar*) key1, len, (const uchar*) key2, len);
+ return cs->coll->strnncollsp(cs,
+ (const uchar*) key1, len,
+ (const uchar*) key2, len);
}
/*
@@ -1146,7 +1148,7 @@ bool Item_sum_count_distinct::setup(THD *thd)
if (!(table= create_tmp_table(thd, tmp_table_param, list, (ORDER*) 0, 1,
0,
select_lex->options | thd->options,
- HA_POS_ERROR)))
+ HA_POS_ERROR, (char*)"")))
return 1;
table->file->extra(HA_EXTRA_NO_ROWS); // Don't update rows
table->no_rows=1;
@@ -1835,7 +1837,8 @@ bool Item_func_group_concat::setup(THD *thd)
(types, sizes and so on).
*/
if (!(table=create_tmp_table(thd, tmp_table_param, all_fields, 0,
- 0, 0, 0,select_lex->options | thd->options)))
+ 0, 0, 0,select_lex->options | thd->options,
+ (char *) "")))
DBUG_RETURN(1);
table->file->extra(HA_EXTRA_NO_ROWS);
table->no_rows= 1;
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index c2d1504e94a..31ce2ad9cdc 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -571,21 +571,21 @@ longlong Item_func_from_days::val_int()
void Item_func_curdate::fix_length_and_dec()
{
- struct tm tm_tmp,*start;
- time_t query_start=current_thd->query_start();
+ struct tm start;
- set_charset(default_charset());
+ collation.set(default_charset());
decimals=0;
max_length=10*default_charset()->mbmaxlen;
- localtime_r(&query_start,&tm_tmp);
- start=&tm_tmp;
- value=(longlong) ((ulong) ((uint) start->tm_year+1900)*10000L+
- ((uint) start->tm_mon+1)*100+
- (uint) start->tm_mday);
+
+ store_now_in_tm(current_thd->query_start(),&start);
+
+ value=(longlong) ((ulong) ((uint) start.tm_year+1900)*10000L+
+ ((uint) start.tm_mon+1)*100+
+ (uint) start.tm_mday);
/* For getdate */
- ltime.year= start->tm_year+1900;
- ltime.month= start->tm_mon+1;
- ltime.day= start->tm_mday;
+ ltime.year= start.tm_year+1900;
+ ltime.month= start.tm_mon+1;
+ ltime.day= start.tm_mday;
ltime.hour= 0;
ltime.minute= 0;
ltime.second= 0;
@@ -594,6 +594,7 @@ void Item_func_curdate::fix_length_and_dec()
ltime.time_type=TIMESTAMP_DATE;
}
+
bool Item_func_curdate::get_date(TIME *res,
bool fuzzy_date __attribute__((unused)))
{
@@ -601,6 +602,27 @@ bool Item_func_curdate::get_date(TIME *res,
return 0;
}
+
+/*
+ Converts time in time_t to struct tm represenatation for local timezone.
+ Defines timezone (local) used for whole CURDATE function
+*/
+void Item_func_curdate_local::store_now_in_tm(time_t now, struct tm *now_tm)
+{
+ localtime_r(&now,now_tm);
+}
+
+
+/*
+ Converts time in time_t to struct tm represenatation for UTC
+ Defines timezone (UTC) used for whole UTC_DATE function
+*/
+void Item_func_curdate_utc::store_now_in_tm(time_t now, struct tm *now_tm)
+{
+ gmtime_r(&now,now_tm);
+}
+
+
String *Item_func_curtime::val_str(String *str)
{
str_value.set(buff,buff_length,default_charset());
@@ -609,23 +631,43 @@ String *Item_func_curtime::val_str(String *str)
void Item_func_curtime::fix_length_and_dec()
{
- struct tm tm_tmp,*start;
- time_t query_start=current_thd->query_start();
- CHARSET_INFO *cs=default_charset();
+ struct tm start;
+ CHARSET_INFO *cs= default_charset();
decimals=0;
max_length=8*cs->mbmaxlen;
- localtime_r(&query_start,&tm_tmp);
- start=&tm_tmp;
- set_charset(cs);
- value=(longlong) ((ulong) ((uint) start->tm_hour)*10000L+
- (ulong) (((uint) start->tm_min)*100L+
- (uint) start->tm_sec));
+ collation.set(cs);
+
+ store_now_in_tm(current_thd->query_start(),&start);
+
+ value=(longlong) ((ulong) ((uint) start.tm_hour)*10000L+
+ (ulong) (((uint) start.tm_min)*100L+
+ (uint) start.tm_sec));
buff_length=cs->cset->snprintf(cs,buff,sizeof(buff),"%02d:%02d:%02d",
- (int) start->tm_hour,
- (int) start->tm_min,
- (int) start->tm_sec);
+ (int) start.tm_hour,
+ (int) start.tm_min,
+ (int) start.tm_sec);
+}
+
+
+/*
+ Converts time in time_t to struct tm represenatation for local timezone.
+ Defines timezone (local) used for whole CURTIME function
+*/
+void Item_func_curtime_local::store_now_in_tm(time_t now, struct tm *now_tm)
+{
+ localtime_r(&now,now_tm);
+}
+
+
+/*
+ Converts time in time_t to struct tm represenatation for UTC.
+ Defines timezone (UTC) used for whole UTC_TIME function
+*/
+void Item_func_curtime_utc::store_now_in_tm(time_t now, struct tm *now_tm)
+{
+ gmtime_r(&now,now_tm);
}
@@ -638,37 +680,37 @@ String *Item_func_now::val_str(String *str)
void Item_func_now::fix_length_and_dec()
{
- struct tm tm_tmp,*start;
- time_t query_start=current_thd->query_start();
+ struct tm start;
CHARSET_INFO *cs= &my_charset_bin;
decimals=0;
max_length=19*cs->mbmaxlen;
- set_charset(cs);
- localtime_r(&query_start,&tm_tmp);
- start=&tm_tmp;
- value=((longlong) ((ulong) ((uint) start->tm_year+1900)*10000L+
- (((uint) start->tm_mon+1)*100+
- (uint) start->tm_mday))*(longlong) 1000000L+
- (longlong) ((ulong) ((uint) start->tm_hour)*10000L+
- (ulong) (((uint) start->tm_min)*100L+
- (uint) start->tm_sec)));
+ collation.set(cs);
+
+ store_now_in_tm(current_thd->query_start(),&start);
+
+ value=((longlong) ((ulong) ((uint) start.tm_year+1900)*10000L+
+ (((uint) start.tm_mon+1)*100+
+ (uint) start.tm_mday))*(longlong) 1000000L+
+ (longlong) ((ulong) ((uint) start.tm_hour)*10000L+
+ (ulong) (((uint) start.tm_min)*100L+
+ (uint) start.tm_sec)));
buff_length= (uint) cs->cset->snprintf(cs,buff, sizeof(buff),
"%04d-%02d-%02d %02d:%02d:%02d",
- ((int) (start->tm_year+1900)) % 10000,
- (int) start->tm_mon+1,
- (int) start->tm_mday,
- (int) start->tm_hour,
- (int) start->tm_min,
- (int) start->tm_sec);
+ ((int) (start.tm_year+1900)) % 10000,
+ (int) start.tm_mon+1,
+ (int) start.tm_mday,
+ (int) start.tm_hour,
+ (int) start.tm_min,
+ (int) start.tm_sec);
/* For getdate */
- ltime.year= start->tm_year+1900;
- ltime.month= start->tm_mon+1;
- ltime.day= start->tm_mday;
- ltime.hour= start->tm_hour;
- ltime.minute= start->tm_min;
- ltime.second= start->tm_sec;
+ ltime.year= start.tm_year+1900;
+ ltime.month= start.tm_mon+1;
+ ltime.day= start.tm_mday;
+ ltime.hour= start.tm_hour;
+ ltime.minute= start.tm_min;
+ ltime.second= start.tm_sec;
ltime.second_part=0;
ltime.neg=0;
ltime.time_type=TIMESTAMP_FULL;
@@ -690,6 +732,26 @@ int Item_func_now::save_in_field(Field *to, bool no_conversions)
}
+/*
+ Converts time in time_t to struct tm represenatation for local timezone.
+ Defines timezone (local) used for whole CURRENT_TIMESTAMP function
+*/
+void Item_func_now_local::store_now_in_tm(time_t now, struct tm *now_tm)
+{
+ localtime_r(&now,now_tm);
+}
+
+
+/*
+ Converts time in time_t to struct tm represenatation for UTC.
+ Defines timezone (UTC) used for whole UTC_TIMESTAMP function
+*/
+void Item_func_now_utc::store_now_in_tm(time_t now, struct tm *now_tm)
+{
+ gmtime_r(&now,now_tm);
+}
+
+
String *Item_func_sec_to_time::val_str(String *str)
{
char buff[23*2];
@@ -1130,7 +1192,7 @@ bool Item_func_from_unixtime::get_date(TIME *ltime,
void Item_date_add_interval::fix_length_and_dec()
{
enum_field_types arg0_field_type;
- set_charset(default_charset());
+ collation.set(default_charset());
maybe_null=1;
max_length=26*MY_CHARSET_BIN_MB_MAXLEN;
value.alloc(32);
@@ -1289,14 +1351,12 @@ String *Item_date_add_interval::val_str(String *str)
longlong Item_date_add_interval::val_int()
{
TIME ltime;
+ longlong date;
if (Item_date_add_interval::get_date(&ltime,0))
return (longlong) 0;
- return ((longlong) (((ulong) ltime.year)*10000L+
- (((uint) ltime.month)*100+
- (uint) ltime.day))*(longlong) 1000000L+
- (longlong) ((ulong) ((uint) ltime.hour)*10000L+
- (ulong) (((uint)ltime.minute)*100L+
- (uint) ltime.second)));
+ date = (ltime.year*100L + ltime.month)*100L + ltime.day;
+ return ltime.time_type == TIMESTAMP_DATE ? date :
+ ((date*100L + ltime.hour)*100L+ ltime.minute)*100L + ltime.second;
}
void Item_extract::fix_length_and_dec()
@@ -1388,6 +1448,22 @@ longlong Item_extract::val_int()
return 0; // Impossible
}
+bool Item_extract::eq(const Item *item, bool binary_cmp) const
+{
+ if (this == item)
+ return 1;
+ if (item->type() != FUNC_ITEM ||
+ func_name() != ((Item_func*)item)->func_name())
+ return 0;
+
+ Item_extract* ie= (Item_extract*)item;
+ if (ie->int_type != int_type)
+ return 0;
+
+ if (!args[0]->eq(ie->args[0], binary_cmp))
+ return 0;
+ return 1;
+}
void Item_typecast::print(String *str)
{
@@ -1398,6 +1474,59 @@ void Item_typecast::print(String *str)
str->append(')');
}
+String *Item_char_typecast::val_str(String *str)
+{
+ String *res, *res1;
+ uint32 length;
+
+ if (!charset_conversion && !(res= args[0]->val_str(str)))
+ {
+ null_value= 1;
+ return 0;
+ }
+ else
+ {
+ // Convert character set if differ
+ if (!(res1= args[0]->val_str(&tmp_value)) ||
+ str->copy(res1->ptr(), res1->length(),res1->charset(), cast_cs))
+ {
+ null_value= 1;
+ return 0;
+ }
+ res= str;
+ }
+
+ /*
+ Cut the tail if cast with length
+ and the result is longer than cast length, e.g.
+ CAST('string' AS CHAR(1))
+ */
+ if (cast_length >= 0 &&
+ (res->length() > (length= (uint32) res->charpos(cast_length))))
+ { // Safe even if const arg
+ if (!res->alloced_length())
+ { // Don't change const str
+ str_value= *res; // Not malloced string
+ res= &str_value;
+ }
+ res->length((uint) length);
+ }
+ null_value= 0;
+ return res;
+}
+
+void Item_char_typecast::fix_length_and_dec()
+{
+ uint32 char_length;
+ charset_conversion= !my_charset_same(args[0]->collation.collation, cast_cs) &&
+ args[0]->collation.collation != &my_charset_bin &&
+ cast_cs != &my_charset_bin;
+ collation.set(cast_cs, DERIVATION_IMPLICIT);
+ char_length= (cast_length >= 0) ? cast_length :
+ args[0]->max_length/args[0]->collation.collation->mbmaxlen;
+ max_length= char_length * cast_cs->mbmaxlen;
+}
+
String *Item_datetime_typecast::val_str(String *str)
{
TIME ltime;
diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h
index 20b95f8e22d..d84267a5066 100644
--- a/sql/item_timefunc.h
+++ b/sql/item_timefunc.h
@@ -93,7 +93,7 @@ public:
enum Item_result result_type () const { return INT_RESULT; }
void fix_length_and_dec()
{
- set_charset(default_charset());
+ collation.set(default_charset());
decimals=0;
max_length=2*default_charset()->mbmaxlen;
maybe_null=1;
@@ -110,7 +110,7 @@ public:
enum Item_result result_type () const { return STRING_RESULT; }
void fix_length_and_dec()
{
- set_charset(default_charset());
+ collation.set(default_charset());
decimals=0;
max_length=10*default_charset()->mbmaxlen;
maybe_null=1;
@@ -254,7 +254,7 @@ public:
enum Item_result result_type () const { return INT_RESULT; }
void fix_length_and_dec()
{
- set_charset(default_charset());
+ collation.set(default_charset());
decimals=0;
max_length=1*default_charset()->mbmaxlen;
maybe_null=1;
@@ -270,7 +270,7 @@ class Item_func_dayname :public Item_func_weekday
enum Item_result result_type () const { return STRING_RESULT; }
void fix_length_and_dec()
{
- set_charset(default_charset());
+ collation.set(default_charset());
decimals=0;
max_length=9*default_charset()->mbmaxlen;
maybe_null=1;
@@ -322,7 +322,7 @@ public:
const char *func_name() const { return "date"; }
void fix_length_and_dec()
{
- set_charset(default_charset());
+ collation.set(default_charset());
decimals=0;
max_length=10*default_charset()->mbmaxlen;
}
@@ -350,6 +350,8 @@ public:
};
+/* Abstract CURTIME function. Children should define what timezone is used */
+
class Item_func_curtime :public Item_func
{
longlong value;
@@ -363,29 +365,77 @@ public:
double val() { return (double) value; }
longlong val_int() { return value; }
String *val_str(String *str);
- const char *func_name() const { return "curtime"; }
void fix_length_and_dec();
Field *tmp_table_field() { return result_field; }
Field *tmp_table_field(TABLE *t_arg)
{
return (new Field_time(maybe_null, name, t_arg, default_charset()));
- }
+ }
+ /*
+ Abstract method that defines which time zone is used for conversion.
+ Converts time from time_t representation to broken down representation
+ in struct tm using gmtime_r or localtime_r functions.
+ */
+ virtual void store_now_in_tm(time_t now, struct tm *now_tm)=0;
+};
+
+
+class Item_func_curtime_local :public Item_func_curtime
+{
+public:
+ Item_func_curtime_local() :Item_func_curtime() {}
+ Item_func_curtime_local(Item *a) :Item_func_curtime(a) {}
+ const char *func_name() const { return "curtime"; }
+ void store_now_in_tm(time_t now, struct tm *now_tm);
+};
+
+
+class Item_func_curtime_utc :public Item_func_curtime
+{
+public:
+ Item_func_curtime_utc() :Item_func_curtime() {}
+ Item_func_curtime_utc(Item *a) :Item_func_curtime(a) {}
+ const char *func_name() const { return "utc_time"; }
+ void store_now_in_tm(time_t now, struct tm *now_tm);
};
+/* Abstract CURDATE function. See also Item_func_curtime. */
+
class Item_func_curdate :public Item_date
{
longlong value;
TIME ltime;
public:
Item_func_curdate() :Item_date() {}
+ void set_result_from_tm(struct tm *now);
longlong val_int() { return (value) ; }
- const char *func_name() const { return "curdate"; }
- void fix_length_and_dec(); /* Retrieves curtime */
+ void fix_length_and_dec();
bool get_date(TIME *res,bool fuzzy_date);
+ virtual void store_now_in_tm(time_t now, struct tm *now_tm)=0;
+};
+
+
+class Item_func_curdate_local :public Item_func_curdate
+{
+public:
+ Item_func_curdate_local() :Item_func_curdate() {}
+ const char *func_name() const { return "curdate"; }
+ void store_now_in_tm(time_t now, struct tm *now_tm);
};
+class Item_func_curdate_utc :public Item_func_curdate
+{
+public:
+ Item_func_curdate_utc() :Item_func_curdate() {}
+ const char *func_name() const { return "utc_date"; }
+ void store_now_in_tm(time_t now, struct tm *now_tm);
+};
+
+
+/* Abstract CURRENT_TIMESTAMP function. See also Item_func_curtime */
+
class Item_func_now :public Item_date_func
{
longlong value;
@@ -400,9 +450,29 @@ public:
longlong val_int() { return value; }
int save_in_field(Field *to, bool no_conversions);
String *val_str(String *str);
- const char *func_name() const { return "now"; }
void fix_length_and_dec();
bool get_date(TIME *res,bool fuzzy_date);
+ virtual void store_now_in_tm(time_t now, struct tm *now_tm)=0;
+};
+
+
+class Item_func_now_local :public Item_func_now
+{
+public:
+ Item_func_now_local() :Item_func_now() {}
+ Item_func_now_local(Item *a) :Item_func_now(a) {}
+ const char *func_name() const { return "now"; }
+ void store_now_in_tm(time_t now, struct tm *now_tm);
+};
+
+
+class Item_func_now_utc :public Item_func_now
+{
+public:
+ Item_func_now_utc() :Item_func_now() {}
+ Item_func_now_utc(Item *a) :Item_func_now(a) {}
+ const char *func_name() const { return "utc_timestamp"; }
+ void store_now_in_tm(time_t now, struct tm *now_tm);
};
@@ -440,7 +510,7 @@ class Item_func_from_unixtime :public Item_date_func
const char *func_name() const { return "from_unixtime"; }
void fix_length_and_dec()
{
- set_charset(default_charset());
+ collation.set(default_charset());
decimals=0;
max_length=19*default_charset()->mbmaxlen;
}
@@ -457,7 +527,7 @@ public:
String *val_str(String *);
void fix_length_and_dec()
{
- set_charset(default_charset());
+ collation.set(default_charset());
maybe_null=1;
max_length=13*default_charset()->mbmaxlen;
}
@@ -516,6 +586,7 @@ class Item_extract :public Item_int_func
longlong val_int();
const char *func_name() const { return "extract"; }
void fix_length_and_dec();
+ bool eq(const Item *item, bool binary_cmp) const;
};
@@ -529,12 +600,12 @@ public:
String *tmp=args[0]->val_str(a);
null_value=args[0]->null_value;
if (tmp)
- tmp->set_charset(charset());
+ tmp->set_charset(collation.collation);
return tmp;
}
void fix_length_and_dec()
{
- set_charset(default_charset());
+ collation.set(default_charset());
max_length=args[0]->max_length;
}
void print(String *str);
@@ -543,13 +614,15 @@ public:
class Item_char_typecast :public Item_typecast
{
+ int cast_length;
+ CHARSET_INFO *cast_cs;
+ bool charset_conversion;
+ String tmp_value;
public:
- Item_char_typecast(Item *a) :Item_typecast(a) {}
- void fix_length_and_dec()
- {
- set_charset(default_charset());
- max_length=args[0]->max_length;
- }
+ Item_char_typecast(Item *a, int length_arg, CHARSET_INFO *cs_arg)
+ :Item_typecast(a), cast_length(length_arg), cast_cs(cs_arg) {}
+ String *val_str(String *a);
+ void fix_length_and_dec();
};
diff --git a/sql/lex.h b/sql/lex.h
index c2860f4551a..24bfe796cc0 100644
--- a/sql/lex.h
+++ b/sql/lex.h
@@ -340,6 +340,7 @@ static SYMBOL symbols[] = {
{ "ROW", SYM(ROW_SYM),0,0},
{ "ROWS", SYM(ROWS_SYM),0,0},
{ "RTREE", SYM(RTREE_SYM),0,0},
+ { "SAVEPOINT", SYM(SAVEPOINT_SYM),0,0},
{ "SECOND", SYM(SECOND_SYM),0,0},
{ "SECOND_MICROSECOND", SYM(SECOND_MICROSECOND_SYM),0,0},
{ "SEPARATOR", SYM(SEPARATOR_SYM),0,0},
@@ -404,6 +405,9 @@ static SYMBOL symbols[] = {
{ "USE_FRM", SYM(USE_FRM),0,0},
{ "USER", SYM(USER),0,0},
{ "USING", SYM(USING),0,0},
+ { "UTC_DATE", SYM(UTC_DATE_SYM),0,0},
+ { "UTC_TIME", SYM(UTC_TIME_SYM),0,0},
+ { "UTC_TIMESTAMP", SYM(UTC_TIMESTAMP_SYM),0,0},
{ "UPDATE", SYM(UPDATE_SYM),0,0},
{ "USAGE", SYM(USAGE),0,0},
{ "VALUE", SYM(VALUE_SYM),0,0},
diff --git a/sql/log.cc b/sql/log.cc
index dd544dcac93..d3ba5b63e19 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2003 MySQL AB
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
@@ -85,11 +85,13 @@ static int find_uniq_filename(char *name)
MYSQL_LOG::MYSQL_LOG()
:bytes_written(0), last_time(0), query_start(0), name(0),
file_id(1), open_count(1), log_type(LOG_CLOSED), write_error(0), inited(0),
- no_rotate(0), need_start_event(1)
+ need_start_event(1)
{
/*
- We don't want to intialize LOCK_Log here as the thread system may
- not have been initailized yet. We do it instead at 'open'.
+ We don't want to initialize LOCK_Log here as such initialization depends on
+ safe_mutex (when using safe_mutex) which depends on MY_INIT(), which is
+ called only in main(). Doing initialization here would make it happen
+ before main().
*/
index_file_name[0] = 0;
bzero((char*) &log_file,sizeof(log_file));
@@ -102,12 +104,14 @@ MYSQL_LOG::~MYSQL_LOG()
cleanup();
}
+/* this is called only once */
+
void MYSQL_LOG::cleanup()
{
if (inited)
{
- close(1);
inited= 0;
+ close(LOG_CLOSE_INDEX);
(void) pthread_mutex_destroy(&LOCK_log);
(void) pthread_mutex_destroy(&LOCK_index);
(void) pthread_cond_destroy(&update_cond);
@@ -135,18 +139,26 @@ int MYSQL_LOG::generate_new_name(char *new_name, const char *log_name)
void MYSQL_LOG::init(enum_log_type log_type_arg,
enum cache_type io_cache_type_arg,
- bool no_auto_events_arg)
+ bool no_auto_events_arg,
+ ulong max_size_arg)
{
+ DBUG_ENTER("MYSQL_LOG::init");
log_type = log_type_arg;
io_cache_type = io_cache_type_arg;
no_auto_events = no_auto_events_arg;
- if (!inited)
- {
- inited= 1;
- (void) pthread_mutex_init(&LOCK_log,MY_MUTEX_INIT_SLOW);
- (void) pthread_mutex_init(&LOCK_index, MY_MUTEX_INIT_SLOW);
- (void) pthread_cond_init(&update_cond, 0);
- }
+ max_size=max_size_arg;
+ DBUG_PRINT("info",("log_type: %d max_size: %lu", log_type, max_size));
+ DBUG_VOID_RETURN;
+}
+
+
+void MYSQL_LOG::init_pthread_objects()
+{
+ DBUG_ASSERT(inited == 0);
+ inited= 1;
+ (void) pthread_mutex_init(&LOCK_log,MY_MUTEX_INIT_SLOW);
+ (void) pthread_mutex_init(&LOCK_index, MY_MUTEX_INIT_SLOW);
+ (void) pthread_cond_init(&update_cond, 0);
}
@@ -167,7 +179,8 @@ void MYSQL_LOG::init(enum_log_type log_type_arg,
bool MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg,
const char *new_name, const char *index_file_name_arg,
enum cache_type io_cache_type_arg,
- bool no_auto_events_arg)
+ bool no_auto_events_arg,
+ ulong max_size)
{
char buff[512];
File file= -1, index_file_nr= -1;
@@ -178,9 +191,7 @@ bool MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg,
last_time=query_start=0;
write_error=0;
- if (!inited && log_type_arg == LOG_BIN && *fn_ext(log_name))
- no_rotate = 1;
- init(log_type_arg,io_cache_type_arg,no_auto_events_arg);
+ init(log_type_arg,io_cache_type_arg,no_auto_events_arg,max_size);
if (!(name=my_strdup(log_name,MYF(MY_WME))))
goto err;
@@ -311,6 +322,7 @@ bool MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg,
break;
}
case LOG_CLOSED: // Impossible
+ case LOG_TO_BE_OPENED:
DBUG_ASSERT(1);
break;
}
@@ -328,7 +340,7 @@ shutdown the MySQL server and restart it.", log_name, errno);
end_io_cache(&log_file);
end_io_cache(&index_file);
safeFree(name);
- log_type=LOG_CLOSED;
+ log_type= LOG_CLOSED;
DBUG_RETURN(1);
}
@@ -561,7 +573,7 @@ bool MYSQL_LOG::reset_logs(THD* thd)
save_name=name;
name=0; // Protect against free
save_log_type=log_type;
- close(0); // Don't close the index file
+ close(LOG_CLOSE_TO_BE_OPENED);
/* First delete all old log files */
@@ -579,12 +591,12 @@ bool MYSQL_LOG::reset_logs(THD* thd)
}
/* Start logging with a new file */
- close(1); // Close index file
+ close(LOG_CLOSE_INDEX);
my_delete(index_file_name, MYF(MY_WME)); // Reset (open will update)
if (!thd->slave_thread)
need_start_event=1;
open(save_name, save_log_type, 0, index_file_name,
- io_cache_type, no_auto_events);
+ io_cache_type, no_auto_events, max_size);
my_free((gptr) save_name, MYF(0));
err:
@@ -736,7 +748,6 @@ int MYSQL_LOG::update_log_index(LOG_INFO* log_info, bool need_update_threads)
RETURN VALUES
0 ok
- LOG_INFO_PURGE_NO_ROTATE Binary file that can't be rotated
LOG_INFO_EOF to_log not found
*/
@@ -752,9 +763,6 @@ int MYSQL_LOG::purge_logs(const char *to_log,
DBUG_ENTER("purge_logs");
DBUG_PRINT("info",("to_log= %s",to_log));
- if (no_rotate)
- DBUG_RETURN(LOG_INFO_PURGE_NO_ROTATE);
-
if (need_mutex)
pthread_mutex_lock(&LOCK_index);
if ((error=find_log_pos(&log_info, to_log, 0 /*no mutex*/)))
@@ -835,9 +843,6 @@ int MYSQL_LOG::purge_logs_before_date(time_t purge_time)
DBUG_ENTER("purge_logs_before_date");
- if (no_rotate)
- DBUG_RETURN(LOG_INFO_PURGE_NO_ROTATE);
-
pthread_mutex_lock(&LOCK_index);
/*
@@ -888,14 +893,11 @@ err:
void MYSQL_LOG::make_log_name(char* buf, const char* log_ident)
{
- if (inited) // QQ When is this not true ?
- {
- uint dir_len = dirname_length(log_file_name);
- if (dir_len > FN_REFLEN)
- dir_len=FN_REFLEN-1;
- strnmov(buf, log_file_name, dir_len);
- strmake(buf+dir_len, log_ident, FN_REFLEN - dir_len);
- }
+ uint dir_len = dirname_length(log_file_name);
+ if (dir_len > FN_REFLEN)
+ dir_len=FN_REFLEN-1;
+ strnmov(buf, log_file_name, dir_len);
+ strmake(buf+dir_len, log_ident, FN_REFLEN - dir_len);
}
@@ -905,7 +907,7 @@ void MYSQL_LOG::make_log_name(char* buf, const char* log_ident)
bool MYSQL_LOG::is_active(const char *log_file_name_arg)
{
- return inited && !strcmp(log_file_name, log_file_name_arg);
+ return !strcmp(log_file_name, log_file_name_arg);
}
@@ -926,8 +928,12 @@ void MYSQL_LOG::new_file(bool need_lock)
char new_name[FN_REFLEN], *new_name_ptr, *old_name;
enum_log_type save_log_type;
+ DBUG_ENTER("MYSQL_LOG::new_file");
if (!is_open())
- return; // Should never happen
+ {
+ DBUG_PRINT("info",("log is closed"));
+ DBUG_VOID_RETURN;
+ }
if (need_lock)
{
@@ -937,52 +943,50 @@ void MYSQL_LOG::new_file(bool need_lock)
safe_mutex_assert_owner(&LOCK_log);
safe_mutex_assert_owner(&LOCK_index);
- // Reuse old name if not binlog and not update log
+ /* Reuse old name if not binlog and not update log */
new_name_ptr= name;
/*
- Only rotate open logs that are marked non-rotatable
- (binlog with constant name are non-rotatable)
+ If user hasn't specified an extension, generate a new log name
+ We have to do this here and not in open as we want to store the
+ new file name in the current binary log file.
*/
- if (!no_rotate)
+ if (generate_new_name(new_name, name))
+ goto end;
+ new_name_ptr=new_name;
+
+ if (log_type == LOG_BIN)
{
- /*
- If user hasn't specified an extension, generate a new log name
- We have to do this here and not in open as we want to store the
- new file name in the current binary log file.
- */
- if (generate_new_name(new_name, name))
- goto end;
- new_name_ptr=new_name;
-
- if (log_type == LOG_BIN)
+ if (!no_auto_events)
{
- if (!no_auto_events)
- {
- /*
- We log the whole file name for log file as the user may decide
- to change base names at some point.
- */
- THD* thd = current_thd;
- Rotate_log_event r(thd,new_name+dirname_length(new_name));
- r.set_log_pos(this);
- r.write(&log_file);
- bytes_written += r.get_event_len();
- }
/*
- Update needs to be signalled even if there is no rotate event
- log rotation should give the waiting thread a signal to
- discover EOF and move on to the next log.
+ We log the whole file name for log file as the user may decide
+ to change base names at some point.
*/
- signal_update();
+ THD* thd = current_thd;
+ Rotate_log_event r(thd,new_name+dirname_length(new_name));
+ r.set_log_pos(this);
+ r.write(&log_file);
+ bytes_written += r.get_event_len();
}
+ /*
+ Update needs to be signalled even if there is no rotate event
+ log rotation should give the waiting thread a signal to
+ discover EOF and move on to the next log.
+ */
+ signal_update();
}
old_name=name;
save_log_type=log_type;
name=0; // Don't free name
- close();
+ close(LOG_CLOSE_TO_BE_OPENED);
+
+ /*
+ Note that at this point, log_type == LOG_CLOSED (important for is_open()).
+ */
+
open(old_name, save_log_type, new_name_ptr, index_file_name, io_cache_type,
- no_auto_events);
+ no_auto_events, max_size);
my_free(old_name,MYF(0));
end:
@@ -991,6 +995,7 @@ end:
pthread_mutex_unlock(&LOCK_index);
pthread_mutex_unlock(&LOCK_log);
}
+ DBUG_VOID_RETURN;
}
@@ -998,7 +1003,8 @@ bool MYSQL_LOG::append(Log_event* ev)
{
bool error = 0;
pthread_mutex_lock(&LOCK_log);
-
+ DBUG_ENTER("MYSQL_LOG::append");
+
DBUG_ASSERT(log_file.type == SEQ_READ_APPEND);
/*
Log_event::write() is smart enough to use my_b_write() or
@@ -1010,7 +1016,8 @@ bool MYSQL_LOG::append(Log_event* ev)
goto err;
}
bytes_written += ev->get_event_len();
- if ((uint) my_b_append_tell(&log_file) > max_binlog_size)
+ DBUG_PRINT("info",("max_size: %lu",max_size));
+ if ((uint) my_b_append_tell(&log_file) > max_size)
{
pthread_mutex_lock(&LOCK_index);
new_file(0);
@@ -1020,13 +1027,14 @@ bool MYSQL_LOG::append(Log_event* ev)
err:
pthread_mutex_unlock(&LOCK_log);
signal_update(); // Safe as we don't call close
- return error;
+ DBUG_RETURN(error);
}
bool MYSQL_LOG::appendv(const char* buf, uint len,...)
{
bool error= 0;
+ DBUG_ENTER("MYSQL_LOG::appendv");
va_list(args);
va_start(args,len);
@@ -1042,8 +1050,8 @@ bool MYSQL_LOG::appendv(const char* buf, uint len,...)
}
bytes_written += len;
} while ((buf=va_arg(args,const char*)) && (len=va_arg(args,uint)));
-
- if ((uint) my_b_append_tell(&log_file) > max_binlog_size)
+ DBUG_PRINT("info",("max_size: %lu",max_size));
+ if ((uint) my_b_append_tell(&log_file) > max_size)
{
pthread_mutex_lock(&LOCK_index);
new_file(0);
@@ -1054,7 +1062,7 @@ err:
pthread_mutex_unlock(&LOCK_log);
if (!error)
signal_update();
- return error;
+ DBUG_RETURN(error);
}
@@ -1158,14 +1166,13 @@ bool MYSQL_LOG::write(Log_event* event_info)
bool should_rotate = 0;
DBUG_ENTER("MYSQL_LOG::write(event)");
- if (!inited) // Can't use mutex if not init
- {
- DBUG_PRINT("error",("not initied"));
- DBUG_RETURN(0);
- }
pthread_mutex_lock(&LOCK_log);
- /* In most cases this is only called if 'is_open()' is true */
+ /*
+ In most cases this is only called if 'is_open()' is true; in fact this is
+ mostly called if is_open() *was* true a few instructions before, but it
+ could have changed since.
+ */
if (is_open())
{
const char *local_db = event_info->get_db();
@@ -1177,6 +1184,11 @@ bool MYSQL_LOG::write(Log_event* event_info)
IO_CACHE *file = &log_file;
#endif
#ifdef HAVE_REPLICATION
+ /*
+ In the future we need to add to the following if tests like
+ "do the involved tables match (to be implemented)
+ binlog_[wild_]{do|ignore}_table?" (WL#1049)"
+ */
if ((thd && !(thd->options & OPTION_BIN_LOG) &&
(thd->master_access & SUPER_ACL)) ||
(local_db && !db_ok(local_db, binlog_do_db, binlog_ignore_db)))
@@ -1328,8 +1340,9 @@ bool MYSQL_LOG::write(Log_event* event_info)
called_handler_commit=1;
}
}
- /* we wrote to the real log, check automatic rotation */
- should_rotate= (my_b_tell(file) >= (my_off_t) max_binlog_size);
+ /* We wrote to the real log, check automatic rotation; */
+ DBUG_PRINT("info",("max_size: %lu",max_size));
+ should_rotate= (my_b_tell(file) >= (my_off_t) max_size);
}
error=0;
@@ -1467,7 +1480,8 @@ bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache)
log_file.pos_in_file)))
goto err;
signal_update();
- if (my_b_tell(&log_file) >= (my_off_t) max_binlog_size)
+ DBUG_PRINT("info",("max_size: %lu",max_size));
+ if (my_b_tell(&log_file) >= (my_off_t) max_size)
{
pthread_mutex_lock(&LOCK_index);
new_file(0); // inside mutex
@@ -1505,123 +1519,123 @@ bool MYSQL_LOG::write(THD *thd,const char *query, uint query_length,
time_t query_start_arg)
{
bool error=0;
+ time_t current_time;
+ if (!is_open())
+ return 0;
+ VOID(pthread_mutex_lock(&LOCK_log));
if (is_open())
- {
- time_t current_time;
- VOID(pthread_mutex_lock(&LOCK_log));
- if (is_open())
- { // Safety agains reopen
- int tmp_errno=0;
- char buff[80],*end;
- end=buff;
- if (!(thd->options & OPTION_UPDATE_LOG) &&
- (thd->master_access & SUPER_ACL))
- {
- VOID(pthread_mutex_unlock(&LOCK_log));
- return 0;
- }
- if ((specialflag & SPECIAL_LONG_LOG_FORMAT) || query_start_arg)
- {
- current_time=time(NULL);
- if (current_time != last_time)
- {
- last_time=current_time;
- struct tm tm_tmp;
- struct tm *start;
- localtime_r(&current_time,&tm_tmp);
- start=&tm_tmp;
- /* Note that my_b_write() assumes it knows the length for this */
- sprintf(buff,"# Time: %02d%02d%02d %2d:%02d:%02d\n",
- start->tm_year % 100,
- start->tm_mon+1,
- start->tm_mday,
- start->tm_hour,
- start->tm_min,
- start->tm_sec);
- if (my_b_write(&log_file, (byte*) buff,24))
- tmp_errno=errno;
- }
- if (my_b_printf(&log_file, "# User@Host: %s[%s] @ %s [%s]\n",
- thd->priv_user,
- thd->user,
- thd->host ? thd->host : "",
- thd->ip ? thd->ip : "") == (uint) -1)
- tmp_errno=errno;
- }
- if (query_start_arg)
- {
- /* For slow query log */
- if (my_b_printf(&log_file,
- "# Query_time: %lu Lock_time: %lu Rows_sent: %lu Rows_examined: %lu\n",
- (ulong) (current_time - query_start_arg),
- (ulong) (thd->time_after_lock - query_start_arg),
- (ulong) thd->sent_row_count,
- (ulong) thd->examined_row_count) == (uint) -1)
- tmp_errno=errno;
- }
- if (thd->db && strcmp(thd->db,db))
- { // Database changed
- if (my_b_printf(&log_file,"use %s;\n",thd->db) == (uint) -1)
- tmp_errno=errno;
- strmov(db,thd->db);
- }
- if (thd->last_insert_id_used)
- {
- end=strmov(end,",last_insert_id=");
- end=longlong10_to_str((longlong) thd->current_insert_id,end,-10);
- }
- // Save value if we do an insert.
- if (thd->insert_id_used)
- {
- if (specialflag & SPECIAL_LONG_LOG_FORMAT)
- {
- end=strmov(end,",insert_id=");
- end=longlong10_to_str((longlong) thd->last_insert_id,end,-10);
- }
- }
- if (thd->query_start_used)
+ { // Safety agains reopen
+ int tmp_errno=0;
+ char buff[80],*end;
+ end=buff;
+ if (!(thd->options & OPTION_UPDATE_LOG) &&
+ (thd->master_access & SUPER_ACL))
+ {
+ VOID(pthread_mutex_unlock(&LOCK_log));
+ return 0;
+ }
+ if ((specialflag & SPECIAL_LONG_LOG_FORMAT) || query_start_arg)
+ {
+ current_time=time(NULL);
+ if (current_time != last_time)
{
- if (query_start_arg != thd->query_start())
- {
- query_start_arg=thd->query_start();
- end=strmov(end,",timestamp=");
- end=int10_to_str((long) query_start_arg,end,10);
- }
+ last_time=current_time;
+ struct tm tm_tmp;
+ struct tm *start;
+ localtime_r(&current_time,&tm_tmp);
+ start=&tm_tmp;
+ /* Note that my_b_write() assumes it knows the length for this */
+ sprintf(buff,"# Time: %02d%02d%02d %2d:%02d:%02d\n",
+ start->tm_year % 100,
+ start->tm_mon+1,
+ start->tm_mday,
+ start->tm_hour,
+ start->tm_min,
+ start->tm_sec);
+ if (my_b_write(&log_file, (byte*) buff,24))
+ tmp_errno=errno;
}
- if (end != buff)
+ if (my_b_printf(&log_file, "# User@Host: %s[%s] @ %s [%s]\n",
+ thd->priv_user,
+ thd->user,
+ thd->host ? thd->host : "",
+ thd->ip ? thd->ip : "") == (uint) -1)
+ tmp_errno=errno;
+ }
+ if (query_start_arg)
+ {
+ /* For slow query log */
+ if (my_b_printf(&log_file,
+ "# Query_time: %lu Lock_time: %lu Rows_sent: %lu Rows_examined: %lu\n",
+ (ulong) (current_time - query_start_arg),
+ (ulong) (thd->time_after_lock - query_start_arg),
+ (ulong) thd->sent_row_count,
+ (ulong) thd->examined_row_count) == (uint) -1)
+ tmp_errno=errno;
+ }
+ if (thd->db && strcmp(thd->db,db))
+ { // Database changed
+ if (my_b_printf(&log_file,"use %s;\n",thd->db) == (uint) -1)
+ tmp_errno=errno;
+ strmov(db,thd->db);
+ }
+ if (thd->last_insert_id_used)
+ {
+ end=strmov(end,",last_insert_id=");
+ end=longlong10_to_str((longlong) thd->current_insert_id,end,-10);
+ }
+ // Save value if we do an insert.
+ if (thd->insert_id_used)
+ {
+ if (specialflag & SPECIAL_LONG_LOG_FORMAT)
{
- *end++=';';
- *end='\n';
- if (my_b_write(&log_file, (byte*) "SET ",4) ||
- my_b_write(&log_file, (byte*) buff+1,(uint) (end-buff)))
- tmp_errno=errno;
+ end=strmov(end,",insert_id=");
+ end=longlong10_to_str((longlong) thd->last_insert_id,end,-10);
}
- if (!query)
+ }
+ if (thd->query_start_used)
+ {
+ if (query_start_arg != thd->query_start())
{
- end=strxmov(buff, "# administrator command: ",
- command_name[thd->command], NullS);
- query_length=(ulong) (end-buff);
- query=buff;
+ query_start_arg=thd->query_start();
+ end=strmov(end,",timestamp=");
+ end=int10_to_str((long) query_start_arg,end,10);
}
- if (my_b_write(&log_file, (byte*) query,query_length) ||
- my_b_write(&log_file, (byte*) ";\n",2) ||
- flush_io_cache(&log_file))
- tmp_errno=errno;
- if (tmp_errno)
+ }
+ if (end != buff)
+ {
+ *end++=';';
+ *end='\n';
+ if (my_b_write(&log_file, (byte*) "SET ",4) ||
+ my_b_write(&log_file, (byte*) buff+1,(uint) (end-buff)))
+ tmp_errno=errno;
+ }
+ if (!query)
+ {
+ end=strxmov(buff, "# administrator command: ",
+ command_name[thd->command], NullS);
+ query_length=(ulong) (end-buff);
+ query=buff;
+ }
+ if (my_b_write(&log_file, (byte*) query,query_length) ||
+ my_b_write(&log_file, (byte*) ";\n",2) ||
+ flush_io_cache(&log_file))
+ tmp_errno=errno;
+ if (tmp_errno)
+ {
+ error=1;
+ if (! write_error)
{
- error=1;
- if (! write_error)
- {
- write_error=1;
- sql_print_error(ER(ER_ERROR_ON_WRITE),name,error);
- }
+ write_error=1;
+ sql_print_error(ER(ER_ERROR_ON_WRITE),name,error);
}
}
- VOID(pthread_mutex_unlock(&LOCK_log));
}
+ VOID(pthread_mutex_unlock(&LOCK_log));
return error;
}
+
/*
Wait until we get a signal that the binary log has been updated
@@ -1655,25 +1669,26 @@ void MYSQL_LOG:: wait_for_update(THD* thd)
SYNOPSIS
close()
- exiting Set to 1 if we should also close the index file
- This can be set to 0 if we are going to do call open
- at once after close, in which case we don't want to
- close the index file.
- We only write a 'stop' event to the log if exiting is set
+ exiting Bitmask for one or more of the following bits:
+ LOG_CLOSE_INDEX if we should close the index file
+ LOG_CLOSE_TO_BE_OPENED if we intend to call open
+ at once after close.
+ LOG_CLOSE_STOP_EVENT write a 'stop' event to the log
NOTES
One can do an open on the object at once after doing a close.
The internal structures are not freed until cleanup() is called
*/
-void MYSQL_LOG::close(bool exiting)
+void MYSQL_LOG::close(uint exiting)
{ // One can't set log_type here!
DBUG_ENTER("MYSQL_LOG::close");
DBUG_PRINT("enter",("exiting: %d", (int) exiting));
- if (is_open())
+ if (log_type != LOG_CLOSED && log_type != LOG_TO_BE_OPENED)
{
#ifdef HAVE_REPLICATION
- if (log_type == LOG_BIN && !no_auto_events && exiting)
+ if (log_type == LOG_BIN && !no_auto_events &&
+ (exiting & LOG_CLOSE_STOP_EVENT))
{
Stop_log_event s;
s.set_log_pos(this);
@@ -1694,7 +1709,7 @@ void MYSQL_LOG::close(bool exiting)
called a not complete close earlier and the index file is still open.
*/
- if (exiting && my_b_inited(&index_file))
+ if ((exiting & LOG_CLOSE_INDEX) && my_b_inited(&index_file))
{
end_io_cache(&index_file);
if (my_close(index_file.file, MYF(0)) < 0 && ! write_error)
@@ -1703,12 +1718,30 @@ void MYSQL_LOG::close(bool exiting)
sql_print_error(ER(ER_ERROR_ON_WRITE), index_file_name, errno);
}
}
- log_type= LOG_CLOSED;
+ log_type= (exiting & LOG_CLOSE_TO_BE_OPENED) ? LOG_TO_BE_OPENED : LOG_CLOSED;
safeFree(name);
DBUG_VOID_RETURN;
}
+void MYSQL_LOG::set_max_size(ulong max_size_arg)
+{
+ /*
+ We need to take locks, otherwise this may happen:
+ new_file() is called, calls open(old_max_size), then before open() starts,
+ set_max_size() sets max_size to max_size_arg, then open() starts and
+ uses the old_max_size argument, so max_size_arg has been overwritten and
+ it's like if the SET command was never run.
+ */
+ DBUG_ENTER("MYSQL_LOG::set_max_size");
+ pthread_mutex_lock(&LOCK_log);
+ if (is_open())
+ max_size= max_size_arg;
+ pthread_mutex_unlock(&LOCK_log);
+ DBUG_VOID_RETURN;
+}
+
+
/*
Check if a string is a valid number
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 749732384c7..8a52ad9ebca 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
+/* Copyright (C) 2000-2003 MySQL AB
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
@@ -72,7 +72,7 @@ static void pretty_print_str(FILE* file, char* str, int len)
}
fputc('\'', file);
}
-#endif // MYSQL_CLIENT
+#endif /* MYSQL_CLIENT */
/*
@@ -82,33 +82,35 @@ static void pretty_print_str(FILE* file, char* str, int len)
#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
inline int ignored_error_code(int err_code)
{
- return use_slave_mask && bitmap_is_set(&slave_error_mask, err_code);
+ return ((err_code == ER_SLAVE_IGNORED_TABLE) ||
+ (use_slave_mask && bitmap_is_set(&slave_error_mask, err_code)));
}
#endif
+
/*
pretty_print_str()
*/
#ifndef MYSQL_CLIENT
-static char* pretty_print_str(char* packet, char* str, int len)
+static char *pretty_print_str(char *packet, char *str, int len)
{
- char* end = str + len;
- char* pos= packet;
+ char *end= str + len;
+ char *pos= packet;
*pos++= '\'';
while (str < end)
{
char c;
switch ((c=*str++)) {
- case '\n': pos= strmov(pos, "\\n"); break;
- case '\r': pos= strmov(pos, "\\r"); break;
- case '\\': pos= strmov(pos, "\\\\"); break;
- case '\b': pos= strmov(pos, "\\b"); break;
- case '\t': pos= strmov(pos, "\\t"); break;
- case '\'': pos= strmov(pos, "\\'"); break;
- case 0 : pos= strmov(pos, "\\0"); break;
+ case '\n': *pos++= '\\'; *pos++= 'n'; break;
+ case '\r': *pos++= '\\'; *pos++= 'r'; break;
+ case '\\': *pos++= '\\'; *pos++= '\\'; break;
+ case '\b': *pos++= '\\'; *pos++= 'b'; break;
+ case '\t': *pos++= '\\'; *pos++= 't'; break;
+ case '\'': *pos++= '\\'; *pos++= '\''; break;
+ case 0 : *pos++= '\\'; *pos++= '0'; break;
default:
- *pos++= (char)c;
+ *pos++= c;
break;
}
}
@@ -126,7 +128,7 @@ static char* pretty_print_str(char* packet, char* str, int len)
static inline char* slave_load_file_stem(char*buf, uint file_id,
int event_server_id)
{
- fn_format(buf,"SQL_LOAD-",slave_load_tmpdir,"",0); /* 4+32); */
+ fn_format(buf,"SQL_LOAD-",slave_load_tmpdir, "", MY_UNPACK_FILENAME);
buf = strend(buf);
buf = int10_to_str(::server_id, buf, 10);
*buf++ = '-';
@@ -136,6 +138,7 @@ static inline char* slave_load_file_stem(char*buf, uint file_id,
}
#endif
+
/*
cleanup_load_tmpdir()
@@ -153,6 +156,8 @@ static void cleanup_load_tmpdir()
MY_DIR *dirp;
FILEINFO *file;
uint i;
+ char fname[FN_REFLEN];
+
if (!(dirp=my_dir(slave_load_tmpdir,MYF(MY_WME))))
return;
@@ -160,7 +165,10 @@ static void cleanup_load_tmpdir()
{
file=dirp->dir_entry+i;
if (is_prefix(file->name,"SQL_LOAD-"))
- my_delete(file->name, MYF(0));
+ {
+ fn_format(fname,file->name,slave_load_tmpdir,"",MY_UNPACK_FILENAME);
+ my_delete(fname, MYF(0));
+ }
}
my_dirend(dirp);
@@ -220,7 +228,7 @@ const char* Log_event::get_type_str()
case EXEC_LOAD_EVENT: return "Exec_load";
case RAND_EVENT: return "RAND";
case USER_VAR_EVENT: return "User var";
- default: /* impossible */ return "Unknown";
+ default: return "Unknown"; /* impossible */
}
}
@@ -390,7 +398,7 @@ void Log_event::init_show_field_list(List<Item>* field_list)
field_list->push_back(new Item_empty_string("Info", 20));
}
-#endif // !MYSQL_CLIENT
+#endif /* !MYSQL_CLIENT */
/*
Log_event::write()
@@ -485,7 +493,7 @@ end:
pthread_mutex_unlock(log_lock);
DBUG_RETURN(result);
}
-#endif // !MYSQL_CLIENT
+#endif /* !MYSQL_CLIENT */
#ifndef MYSQL_CLIENT
#define UNLOCK_MUTEX if (log_lock) pthread_mutex_unlock(log_lock);
@@ -558,8 +566,9 @@ err:
UNLOCK_MUTEX;
if (error)
{
- sql_print_error("Error in Log_event::read_log_event(): '%s', \
-data_len=%d,event_type=%d",error,data_len,head[EVENT_TYPE_OFFSET]);
+ sql_print_error("\
+Error in Log_event::read_log_event(): '%s', data_len: %d, event_type: %d",
+ error,data_len,head[EVENT_TYPE_OFFSET]);
my_free(buf, MYF(MY_ALLOW_ZERO_PTR));
/*
The SQL slave thread will check if file->error<0 to know
@@ -596,8 +605,6 @@ Log_event* Log_event::read_log_event(const char* buf, int event_len,
ev = new Query_log_event(buf, event_len, old_format);
break;
case LOAD_EVENT:
- ev = new Load_log_event(buf, event_len, old_format);
- break;
case NEW_LOAD_EVENT:
ev = new Load_log_event(buf, event_len, old_format);
break;
@@ -700,7 +707,8 @@ void Log_event::print_timestamp(FILE* file, time_t* ts)
res->tm_sec);
}
-#endif // MYSQL_CLIENT
+#endif /* MYSQL_CLIENT */
+
/*
Log_event::set_log_pos()
@@ -712,7 +720,7 @@ void Log_event::set_log_pos(MYSQL_LOG* log)
if (!log_pos)
log_pos = my_b_tell(&log->log_file);
}
-#endif // !MYSQL_CLIENT
+#endif /* !MYSQL_CLIENT */
/**************************************************************************
@@ -735,8 +743,7 @@ void Query_log_event::pack_info(Protocol *protocol)
{
pos= strmov(buf, "use `");
memcpy(pos, db, db_len);
- pos+= db_len;
- pos= strmov(pos, "`; ");
+ pos= strmov(pos+db_len, "`; ");
}
if (query && q_len)
{
@@ -801,6 +808,7 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg,
}
#endif /* MYSQL_CLIENT */
+
/*
Query_log_event::Query_log_event()
*/
@@ -885,8 +893,9 @@ void Query_log_event::print(FILE* file, bool short_form, char* last_db)
#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
int Query_log_event::exec_event(struct st_relay_log_info* rli)
{
- int expected_error,actual_error = 0;
- thd->db = rewrite_db((char*)db);
+ int expected_error,actual_error= 0;
+ init_sql_alloc(&thd->mem_root, 8192,0);
+ thd->db= (char*) rewrite_db(db);
/*
InnoDB internally stores the master log position it has executed so far,
@@ -902,17 +911,15 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli)
if (db_ok(thd->db, replicate_do_db, replicate_ignore_db))
{
thd->set_time((time_t)when);
- thd->current_tablenr = 0;
thd->query_length= q_len;
VOID(pthread_mutex_lock(&LOCK_thread_count));
thd->query = (char*)query;
thd->query_id = query_id++;
VOID(pthread_mutex_unlock(&LOCK_thread_count));
- thd->query_error= 0; // clear error
+ thd->query_error= 0; // clear error
thd->clear_error();
-
thd->variables.pseudo_thread_id= thread_id; // for temp tables
-
+
/*
Sanity check to make sure the master did not get a really bad
error on the query.
@@ -924,6 +931,10 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli)
DBUG_PRINT("query",("%s",thd->query));
mysql_parse(thd, thd->query, q_len);
+ /*
+ If we expected a non-zero error code, and we don't get the same error
+ code, and none of them should be ignored.
+ */
DBUG_PRINT("info",("expected_error: %d last_errno: %d",
expected_error, thd->net.last_errno));
if ((expected_error != (actual_error= thd->net.last_errno)) &&
@@ -931,14 +942,22 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli)
!ignored_error_code(actual_error) &&
!ignored_error_code(expected_error))
{
- const char* errmsg = "Slave: did not get the expected error\
- running query from master - expected: '%s' (%d), got '%s' (%d)";
- sql_print_error(errmsg, ER_SAFE(expected_error),
- expected_error,
- actual_error ? thd->net.last_error: "no error",
- actual_error);
- thd->query_error = 1;
+ slave_print_error(rli, 0,
+ "\
+Query '%s' caused different errors on master and slave. \
+Error on master: '%s' (%d), Error on slave: '%s' (%d). \
+Default database: '%s'",
+ query,
+ ER_SAFE(expected_error),
+ expected_error,
+ actual_error ? thd->net.last_error: "no error",
+ actual_error,
+ print_slave_db_safe(db));
+ thd->query_error= 1;
}
+ /*
+ If we get the same error code as expected, or they should be ignored.
+ */
else if (expected_error == actual_error ||
ignored_error_code(actual_error))
{
@@ -947,37 +966,39 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli)
*rli->last_slave_error = 0;
rli->last_slave_errno = 0;
}
- }
- else
- {
- // master could be inconsistent, abort and tell DBA to check/fix it
- VOID(pthread_mutex_lock(&LOCK_thread_count));
- thd->db = thd->query = 0;
- VOID(pthread_mutex_unlock(&LOCK_thread_count));
- //thd->variables.convert_set = 0;
- close_thread_tables(thd);
- free_root(&thd->mem_root,0);
- return 1;
- }
- }
- thd->db= 0; // prevent db from being freed
+ /*
+ Other cases: mostly we expected no error and get one.
+ */
+ else if (thd->query_error || thd->is_fatal_error)
+ {
+ slave_print_error(rli,actual_error,
+ "Error '%s' on query '%s'. Default database: '%s'",
+ (actual_error ? thd->net.last_error :
+ "unexpected success or fatal error"),
+ query,
+ print_slave_db_safe(db));
+ thd->query_error= 1;
+ }
+ }
+ /*
+ End of sanity check. If the test was wrong, the query got a really bad
+ error on the master, which could be inconsistent, abort and tell DBA to
+ check/fix it. check_expected_error() already printed the message to
+ stderr and rli, and set thd->query_error to 1.
+ */
+ } /* End of if (db_ok(... */
+
+end:
+
VOID(pthread_mutex_lock(&LOCK_thread_count));
+ thd->db= 0; // prevent db from being freed
thd->query= 0; // just to be sure
VOID(pthread_mutex_unlock(&LOCK_thread_count));
// assume no convert for next query unless set explictly
//thd->variables.convert_set = 0;
- close_thread_tables(thd);
-
- if (thd->query_error || thd->is_fatal_error)
- {
- slave_print_error(rli,actual_error, "error '%s' on query '%s'",
- actual_error ? thd->net.last_error :
- "unexpected success or fatal error", query);
- free_root(&thd->mem_root,0);
- return 1;
- }
+ close_thread_tables(thd);
free_root(&thd->mem_root,0);
- return Log_event::exec_event(rli);
+ return (thd->query_error ? thd->query_error : Log_event::exec_event(rli));
}
#endif
@@ -997,8 +1018,8 @@ void Start_log_event::pack_info(Protocol *protocol)
pos= strmov(buf, "Server ver: ");
pos= strmov(pos, server_version);
pos= strmov(pos, ", Binlog ver: ");
- pos=int10_to_str(binlog_version, pos, 10);
- protocol->store(buf, pos-buf, &my_charset_bin);
+ pos= int10_to_str(binlog_version, pos, 10);
+ protocol->store(buf, (uint) (pos-buf), &my_charset_bin);
}
#endif
@@ -1016,7 +1037,9 @@ void Start_log_event::print(FILE* file, bool short_form, char* last_db)
print_header(file);
fprintf(file, "\tStart: binlog v %d, server v %s created ", binlog_version,
server_version);
- print_timestamp(file, &created);
+ print_timestamp(file);
+ if (created)
+ fprintf(file," at startup");
fputc('\n', file);
fflush(file);
}
@@ -1057,13 +1080,10 @@ int Start_log_event::write_data(IO_CACHE* file)
The master started
IMPLEMENTATION
- - To handle the case where the master died without having time to write DROP
- TEMPORARY TABLE, DO RELEASE_LOCK (prepared statements' deletion is TODO),
- we clean up all temporary tables + locks that we got.
- However, we don't clean temporary tables if the master was 3.23
- (this is because a 3.23 master writes a Start_log_event at every
- binlog rotation; if we were not careful we would remove temp tables
- on the slave when FLUSH LOGS is issued on the master).
+ - To handle the case where the master died without having time to write
+ DROP TEMPORARY TABLE, DO RELEASE_LOCK (prepared statements' deletion is
+ TODO), we clean up all temporary tables that we got, if we are sure we
+ can (see below).
TODO
- Remove all active user locks.
@@ -1078,8 +1098,8 @@ int Start_log_event::write_data(IO_CACHE* file)
the table changes are committed, rollback has occured on the master; we
should rather rollback on the slave and go on. If we don't rollback, and
the next query is not BEGIN, then it will be considered as part of the
- unfinished transaction, and so will be rolled back at next BEGIN, which is
- a bug.
+ unfinished transaction, and so will be rolled back at next BEGIN, which
+ is a bug.
*/
#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
@@ -1087,23 +1107,46 @@ int Start_log_event::exec_event(struct st_relay_log_info* rli)
{
DBUG_ENTER("Start_log_event::exec_event");
- if (!rli->mi->old_format)
- {
+ switch (rli->mi->old_format) {
+ case BINLOG_FORMAT_CURRENT:
+ /*
+ This is 4.x, so a Start_log_event is only at master startup,
+ so we are sure the master has restarted and cleared his temp tables.
+ */
+
/*
If the master died before writing the COMMIT to the binlog, rollback;
otherwise it does not hurt to rollback.
*/
ha_rollback(thd);
+ close_temporary_tables(thd);
+ cleanup_load_tmpdir();
+ break;
+
/*
- If 4.0 master, all temporary tables have been deleted on the master;
- if 3.23 master, this is far from sure.
+ Now the older formats; in that case load_tmpdir is cleaned up by the I/O
+ thread.
*/
- close_temporary_tables(thd);
+ case BINLOG_FORMAT_323_LESS_57:
/*
- If we have old format, load_tmpdir is cleaned up by the I/O thread
+ Cannot distinguish a Start_log_event generated at master startup and
+ one generated by master FLUSH LOGS, so cannot be sure temp tables
+ have to be dropped. So do nothing.
*/
- cleanup_load_tmpdir();
+ break;
+ case BINLOG_FORMAT_323_GEQ_57:
+ /*
+ Can distinguish, based on the value of 'created',
+ which was generated at master startup.
+ */
+ if (created)
+ close_temporary_tables(thd);
+ break;
+ default:
+ /* this case is impossible */
+ return 1;
}
+
DBUG_RETURN(Log_event::exec_event(rli));
}
#endif /* defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */
@@ -1125,6 +1168,7 @@ void Load_log_event::pack_info(Protocol *protocol)
buf_len=
5 + db_len + 3 + // "use DB; "
18 + fname_len + 2 + // "LOAD DATA INFILE 'file''"
+ 7 + // LOCAL
9 + // " REPLACE or IGNORE "
11 + table_name_len + // "INTO TABLE table"
21 + sql_ex.field_term_len*4 + 2 + // " FIELDS TERMINATED BY 'str'"
@@ -1135,22 +1179,22 @@ void Load_log_event::pack_info(Protocol *protocol)
15 + 22 + // " IGNORE xxx LINES"
3 + (num_fields-1)*2 + field_block_len; // " (field1, field2, ...)"
- buf= my_malloc(buf_len, MYF(MY_WME));
- if (!buf)
+ if (!(buf= my_malloc(buf_len, MYF(MY_WME))))
return;
pos= buf;
if (db && db_len)
{
pos= strmov(pos, "use `");
memcpy(pos, db, db_len);
- pos+= db_len;
- pos= strmov(pos, "`; ");
+ pos= strmov(pos+db_len, "`; ");
}
- pos= strmov(pos, "LOAD DATA INFILE '");
+ pos= strmov(pos, "LOAD DATA ");
+ if (check_fname_outside_temp_buf())
+ pos= strmov(pos, "LOCAL ");
+ pos= strmov(pos, "INFILE '");
memcpy(pos, fname, fname_len);
- pos+= fname_len;
- pos= strmov(pos, "' ");
+ pos= strmov(pos+fname_len, "' ");
if (sql_ex.opt_flags & REPLACE_FLAG)
pos= strmov(pos, " REPLACE ");
@@ -1197,31 +1241,34 @@ void Load_log_event::pack_info(Protocol *protocol)
pos= pretty_print_str(pos, sql_ex.line_start, sql_ex.line_start_len);
}
- if ((int)skip_lines > 0)
+ if ((long) skip_lines > 0)
{
pos= strmov(pos, " IGNORE ");
- pos= longlong10_to_str((long) skip_lines, pos, 10);
+ pos= longlong10_to_str((longlong) skip_lines, pos, 10);
pos= strmov(pos," LINES ");
}
if (num_fields)
{
uint i;
- const char* field = fields;
+ const char *field= fields;
pos= strmov(pos, " (");
for (i = 0; i < num_fields; i++)
{
if (i)
- pos= strmov(pos, " ,");
+ {
+ *pos++= ' ';
+ *pos++= ',';
+ }
memcpy(pos, field, field_lens[i]);
- pos+= field_lens[i];
- field += field_lens[i] + 1;
+ pos+= field_lens[i];
+ field+= field_lens[i] + 1;
}
*pos++= ')';
}
protocol->store(buf, pos-buf, &my_charset_bin);
- my_free(buf, MYF(MY_ALLOW_ZERO_PTR));
+ my_free(buf, MYF(0));
}
#endif /* defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */
@@ -1527,7 +1574,8 @@ void Load_log_event::set_fields(List<Item> &field_list)
field+= field_lens[i] + 1;
}
}
-#endif // !MYSQL_CLIENT
+#endif /* !MYSQL_CLIENT */
+
#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
/*
@@ -1559,15 +1607,15 @@ void Load_log_event::set_fields(List<Item> &field_list)
int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli,
bool use_rli_only_for_errors)
{
- thd->db = rewrite_db((char*)db);
+ init_sql_alloc(&thd->mem_root, 8192,0);
+ thd->db= (char*) rewrite_db(db);
DBUG_ASSERT(thd->query == 0);
thd->query = 0; // Should not be needed
thd->query_error = 0;
-
+
if (db_ok(thd->db, replicate_do_db, replicate_ignore_db))
{
thd->set_time((time_t)when);
- thd->current_tablenr = 0;
VOID(pthread_mutex_lock(&LOCK_thread_count));
thd->query_id = query_id++;
VOID(pthread_mutex_unlock(&LOCK_thread_count));
@@ -1643,12 +1691,14 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli,
thd->query_error = 1;
if (thd->cuted_fields)
{
- /*
- log_pos is the position of the LOAD event in the master log
- */
- sql_print_error("Slave: load data infile at position %s in log \
-'%s' produced %d warning(s)", llstr(log_pos,llbuff), RPL_LOG_NAME,
- thd->cuted_fields );
+ /* log_pos is the position of the LOAD event in the master log */
+ sql_print_error("\
+Slave: load data infile on table '%s' at log position %s in log \
+'%s' produced %ld warning(s). Default database: '%s'",
+ (char*) table_name,
+ llstr(log_pos,llbuff), RPL_LOG_NAME,
+ (ulong) thd->cuted_fields,
+ print_slave_db_safe(db));
}
if (net)
net->pkt_nr= thd->net.pkt_nr;
@@ -1680,9 +1730,9 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli,
sql_errno=ER_UNKNOWN_ERROR;
err=ER(sql_errno);
}
- slave_print_error(rli,sql_errno,
- "Error '%s' running load data infile",
- err);
+ slave_print_error(rli,sql_errno,"\
+Error '%s' running lOAD DATA INFILE on table '%s'. Default database: '%s'",
+ err, (char*)table_name, print_slave_db_safe(db));
free_root(&thd->mem_root,0);
return 1;
}
@@ -1690,7 +1740,9 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli,
if (thd->is_fatal_error)
{
- sql_print_error("Fatal error running LOAD DATA INFILE");
+ slave_print_error(rli,ER_UNKNOWN_ERROR, "\
+Fatal error running LOAD DATA INFILE on table '%s'. Default database: '%s'",
+ (char*)table_name, print_slave_db_safe(db));
return 1;
}
@@ -1713,12 +1765,10 @@ void Rotate_log_event::pack_info(Protocol *protocol)
char *buf, *b_pos;
if (!(buf= my_malloc(ident_len + 45, MYF(MY_WME))))
return;
- b_pos= buf;
memcpy(buf, new_log_ident, ident_len);
- b_pos+= ident_len;
- b_pos= strmov(b_pos, ";pos=");
- b_pos=longlong10_to_str(pos, b_pos, 10);
- protocol->store(buf, b_pos-buf, &my_charset_bin);
+ b_pos= strmov(buf + ident_len, ";pos=");
+ b_pos= longlong10_to_str(pos, b_pos, 10);
+ protocol->store(buf, (uint) (b_pos-buf), &my_charset_bin);
my_free(buf, MYF(MY_ALLOW_ZERO_PTR));
}
#endif
@@ -1744,7 +1794,7 @@ void Rotate_log_event::print(FILE* file, bool short_form, char* last_db)
fputc('\n', file);
fflush(file);
}
-#endif // MYSQL_CLIENT
+#endif /* MYSQL_CLIENT */
/*
@@ -1790,7 +1840,7 @@ Rotate_log_event::Rotate_log_event(const char* buf, int event_len,
int Rotate_log_event::write_data(IO_CACHE* file)
{
char buf[ROTATE_HEADER_LEN];
- int8store(buf, pos + R_POS_OFFSET);
+ int8store(buf + R_POS_OFFSET, pos);
return (my_b_safe_write(file, (byte*)buf, ROTATE_HEADER_LEN) ||
my_b_safe_write(file, (byte*)new_log_ident, (uint) ident_len));
}
@@ -1823,7 +1873,8 @@ int Rotate_log_event::exec_event(struct st_relay_log_info* rli)
rli->group_master_log_pos = pos;
rli->event_relay_log_pos += get_event_len();
rli->group_relay_log_pos = rli->event_relay_log_pos;
- DBUG_PRINT("info", ("group_master_log_pos: %d", (ulong) rli->group_master_log_pos));
+ DBUG_PRINT("info", ("group_master_log_pos: %lu",
+ (ulong) rli->group_master_log_pos));
pthread_mutex_unlock(&rli->data_lock);
pthread_cond_broadcast(&rli->data_cond);
flush_relay_log_info(rli);
@@ -1845,9 +1896,9 @@ void Intvar_log_event::pack_info(Protocol *protocol)
{
char buf[64], *pos;
pos= strmov(buf, get_var_type_name());
- *(pos++)='=';
+ *pos++= '=';
pos= longlong10_to_str(val, pos, -10);
- protocol->store(buf, pos-buf, &my_charset_bin);
+ protocol->store(buf, (uint) (pos-buf), &my_charset_bin);
}
#endif
@@ -1994,7 +2045,7 @@ void Rand_log_event::print(FILE* file, bool short_form, char* last_db)
llstr(seed1, llbuff),llstr(seed2, llbuff2));
fflush(file);
}
-#endif // MYSQL_CLIENT
+#endif /* MYSQL_CLIENT */
#if defined(HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
@@ -2005,7 +2056,7 @@ int Rand_log_event::exec_event(struct st_relay_log_info* rli)
rli->inc_event_relay_log_pos(get_event_len());
return 0;
}
-#endif // !MYSQL_CLIENT
+#endif /* !MYSQL_CLIENT */
/**************************************************************************
@@ -2063,7 +2114,7 @@ void User_var_log_event::pack_info(Protocol* protocol)
protocol->store(buf, event_len, &my_charset_bin);
my_free(buf, MYF(MY_ALLOW_ZERO_PTR));
}
-#endif // !MYSQL_CLIENT
+#endif /* !MYSQL_CLIENT */
User_var_log_event::User_var_log_event(const char* buf, bool old_format)
@@ -2236,7 +2287,7 @@ int User_var_log_event::exec_event(struct st_relay_log_info* rli)
rli->inc_event_relay_log_pos(get_event_len());
return 0;
}
-#endif // !MYSQL_CLIENT
+#endif /* !MYSQL_CLIENT */
/**************************************************************************
@@ -2258,7 +2309,7 @@ void Unknown_log_event::print(FILE* file, bool short_form, char* last_db)
#ifndef MYSQL_CLIENT
void Slave_log_event::pack_info(Protocol *protocol)
{
- char buf[256], *pos;
+ char buf[256+HOSTNAME_LENGTH], *pos;
pos= strmov(buf, "host=");
pos= strnmov(pos, master_host, HOSTNAME_LENGTH);
pos= strmov(pos, ",port=");
@@ -2269,7 +2320,7 @@ void Slave_log_event::pack_info(Protocol *protocol)
pos= longlong10_to_str(master_pos, pos, 10);
protocol->store(buf, pos-buf, &my_charset_bin);
}
-#endif // !MYSQL_CLIENT
+#endif /* !MYSQL_CLIENT */
#ifndef MYSQL_CLIENT
@@ -2306,7 +2357,7 @@ Slave_log_event::Slave_log_event(THD* thd_arg,
pthread_mutex_unlock(&mi->data_lock);
DBUG_VOID_RETURN;
}
-#endif // !MYSQL_CLIENT
+#endif /* !MYSQL_CLIENT */
Slave_log_event::~Slave_log_event()
@@ -2323,11 +2374,11 @@ void Slave_log_event::print(FILE* file, bool short_form, char* last_db)
return;
print_header(file);
fputc('\n', file);
- fprintf(file, "Slave: master_host: '%s' master_port: %d \
-master_log: '%s' master_pos: %s\n",
+ fprintf(file, "\
+Slave: master_host: '%s' master_port: %d master_log: '%s' master_pos: %s\n",
master_host, master_port, master_log, llstr(master_pos, llbuff));
}
-#endif // MYSQL_CLIENT
+#endif /* MYSQL_CLIENT */
int Slave_log_event::get_data_size()
@@ -2383,7 +2434,7 @@ int Slave_log_event::exec_event(struct st_relay_log_info* rli)
mysql_bin_log.write(this);
return Log_event::exec_event(rli);
}
-#endif // !MYSQL_CLIENT
+#endif /* !MYSQL_CLIENT */
/**************************************************************************
@@ -2404,7 +2455,7 @@ void Stop_log_event::print(FILE* file, bool short_form, char* last_db)
fprintf(file, "\tStop\n");
fflush(file);
}
-#endif // MYSQL_CLIENT
+#endif /* MYSQL_CLIENT */
/*
@@ -2431,7 +2482,7 @@ int Stop_log_event::exec_event(struct st_relay_log_info* rli)
could give false triggers in MASTER_POS_WAIT() that we have reached
the target position when in fact we have not.
*/
- rli->inc_group_relay_log_pos(get_event_len(), 0);
+ rli->inc_group_relay_log_pos(get_event_len(), 0);
flush_relay_log_info(rli);
return 0;
}
@@ -2460,7 +2511,7 @@ Create_file_log_event(THD* thd_arg, sql_exchange* ex,
{
sql_ex.force_new_format();
}
-#endif // !MYSQL_CLIENT
+#endif /* !MYSQL_CLIENT */
/*
@@ -2563,12 +2614,13 @@ void Create_file_log_event::print(FILE* file, bool short_form,
fprintf(file, " file_id: %d block_len: %d\n", file_id, block_len);
}
+
void Create_file_log_event::print(FILE* file, bool short_form,
char* last_db)
{
print(file,short_form,last_db,0);
}
-#endif // MYSQL_CLIENT
+#endif /* MYSQL_CLIENT */
/*
@@ -2581,15 +2633,13 @@ void Create_file_log_event::pack_info(Protocol *protocol)
char buf[NAME_LEN*2 + 30 + 21*2], *pos;
pos= strmov(buf, "db=");
memcpy(pos, db, db_len);
- pos+= db_len;
- pos= strmov(pos, ";table=");
+ pos= strmov(pos + db_len, ";table=");
memcpy(pos, table_name, table_name_len);
- pos+= table_name_len;
- pos= strmov(pos, ";file_id=");
+ pos= strmov(pos + table_name_len, ";file_id=");
pos= int10_to_str((long) file_id, pos, 10);
pos= strmov(pos, ";block_len=");
pos= int10_to_str((long) block_len, pos, 10);
- protocol->store(buf, pos-buf, &my_charset_bin);
+ protocol->store(buf, (uint) (pos-buf), &my_charset_bin);
}
#endif
@@ -2720,7 +2770,7 @@ void Append_block_log_event::print(FILE* file, bool short_form,
fprintf(file, "#Append_block: file_id: %d block_len: %d\n",
file_id, block_len);
}
-#endif // MYSQL_CLIENT
+#endif /* MYSQL_CLIENT */
/*
@@ -2735,7 +2785,7 @@ void Append_block_log_event::pack_info(Protocol *protocol)
length= (uint) my_sprintf(buf,
(buf, ";file_id=%u;block_len=%u", file_id,
block_len));
- protocol->store(buf, (int32) length, &my_charset_bin);
+ protocol->store(buf, length, &my_charset_bin);
}
#endif
@@ -2829,7 +2879,7 @@ void Delete_file_log_event::print(FILE* file, bool short_form,
fputc('\n', file);
fprintf(file, "#Delete_file: file_id=%u\n", file_id);
}
-#endif // MYSQL_CLIENT
+#endif /* MYSQL_CLIENT */
/*
Delete_file_log_event::pack_info()
@@ -2982,8 +3032,24 @@ int Execute_load_log_event::exec_event(struct st_relay_log_info* rli)
*/
if (lev->exec_event(0,rli,1))
{
- slave_print_error(rli,my_errno, "Failed executing load from '%s'", fname);
- thd->options = save_options;
+ /*
+ We want to indicate the name of the file that could not be loaded
+ (SQL_LOADxxx).
+ But as we are here we are sure the error is in rli->last_slave_error and
+ rli->last_slave_errno (example of error: duplicate entry for key), so we
+ don't want to overwrite it with the filename.
+ What we want instead is add the filename to the current error message.
+ */
+ char *tmp= my_strdup(rli->last_slave_error,MYF(MY_WME));
+ if (tmp)
+ {
+ slave_print_error(rli,
+ rli->last_slave_errno, /* ok to re-use error code */
+ "%s. Failed executing load from '%s'",
+ tmp, fname);
+ my_free(tmp,MYF(0));
+ }
+ thd->options= save_options;
goto err;
}
thd->options = save_options;
@@ -3089,5 +3155,3 @@ char* sql_ex_info::init(char* buf,char* buf_end,bool use_new_format)
}
return buf;
}
-
-
diff --git a/sql/log_event.h b/sql/log_event.h
index bd5e1a82be4..a58479e2589 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -559,10 +559,15 @@ public:
/* fname doesn't point to memory inside Log_event::temp_buf */
void set_fname_outside_temp_buf(const char *afname, uint alen)
- {fname=afname;fname_len=alen;}
+ {
+ fname= afname;
+ fname_len= alen;
+ }
/* fname doesn't point to memory inside Log_event::temp_buf */
int check_fname_outside_temp_buf()
- {return fname<temp_buf || fname>temp_buf+cached_event_len;}
+ {
+ return fname < temp_buf || fname > temp_buf+ cached_event_len;
+ }
#ifndef MYSQL_CLIENT
String field_lens_buf;
@@ -619,6 +624,26 @@ extern char server_version[SERVER_VERSION_LENGTH];
class Start_log_event: public Log_event
{
public:
+ /*
+ If this event is at the start of the first binary log since server startup
+ 'created' should be the timestamp when the event (and the binary log) was
+ created.
+ In the other case (i.e. this event is at the start of a binary log created
+ by FLUSH LOGS or automatic rotation), 'created' should be 0.
+ This "trick" is used by MySQL >=4.0.14 slaves to know if they must drop the
+ stale temporary tables or not.
+ Note that when 'created'!=0, it is always equal to the event's timestamp;
+ indeed Start_log_event is written only in log.cc where the first
+ constructor below is called, in which 'created' is set to 'when'.
+ So in fact 'created' is a useless variable. When it is 0
+ we can read the actual value from timestamp ('when') and when it is
+ non-zero we can read the same value from timestamp ('when'). Conclusion:
+ - we use timestamp to print when the binlog was created.
+ - we use 'created' only to know if this is a first binlog or not.
+ In 3.23.57 we did not pay attention to this identity, so mysqlbinlog in
+ 3.23.57 does not print 'created the_date' if created was zero. This is now
+ fixed.
+ */
time_t created;
uint16 binlog_version;
char server_version[ST_SERVER_VER_LEN];
@@ -947,6 +972,7 @@ public:
#endif /* HAVE_REPLICATION */
#else
void print(FILE* file, bool short_form = 0, char* last_db = 0);
+ void print(FILE* file, bool short_form, char* last_db, bool enable_local);
#endif
Delete_file_log_event(const char* buf, int event_len);
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 28446ed746f..a5d9ce5bce3 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -77,6 +77,7 @@ extern CHARSET_INFO *national_charset_info, *table_alias_charset;
/* Password lengh for 4.1 version previous versions had 16 bytes password hash */
#define HASH_PASSWORD_LENGTH 45
#define HASH_OLD_PASSWORD_LENGTH 16
+#define MAX_PASSWORD_LENGTH 32
#define HOST_CACHE_SIZE 128
#define MAX_ACCEPT_RETRY 10 // Test accept this many times
#define MAX_FIELDS_BEFORE_HASH 32
@@ -158,6 +159,7 @@ extern CHARSET_INFO *national_charset_info, *table_alias_charset;
#define TEST_NO_EXTRA 128
#define TEST_CORE_ON_SIGNAL 256 /* Give core if signal */
#define TEST_NO_STACKTRACE 512
+#define TEST_SIGINT 1024 /* Allow sigint on threads */
/* options for select set by the yacc parser (stored in lex->options) */
#define SELECT_DISTINCT 1
@@ -221,6 +223,7 @@ extern CHARSET_INFO *national_charset_info, *table_alias_charset;
#define MODE_MYSQL323 32768
#define MODE_MYSQL40 65536
#define MODE_ANSI (MODE_MYSQL40*2)
+#define MODE_NO_AUTO_VALUE_ON_ZERO (MODE_ANSI*2)
#define RAID_BLOCK_SIZE 1024
@@ -284,6 +287,17 @@ typedef struct st_sql_list {
next= next_ptr;
*next=0;
}
+ inline void save_and_clear(struct st_sql_list *save)
+ {
+ *save= *this;
+ empty();
+ }
+ inline void push_front(struct st_sql_list *save)
+ {
+ *save->next= first; /* link current list last */
+ first= save->first;
+ elements+= save->elements;
+ }
} SQL_LIST;
@@ -410,7 +424,6 @@ int mysql_preload_keys(THD* thd, TABLE_LIST* table_list);
bool check_simple_select();
SORT_FIELD * make_unireg_sortorder(ORDER *order, uint *length);
-int setup_ref_array(THD *thd, Item ***rref_pointer_array, uint elements);
int setup_order(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
List<Item> &fields, List <Item> &all_fields, ORDER *order);
int setup_group(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
@@ -688,8 +701,8 @@ bool fn_format_relative_to_data_home(my_string to, const char *name,
bool open_log(MYSQL_LOG *log, const char *hostname,
const char *opt_name, const char *extension,
const char *index_file_name,
- enum_log_type type, bool read_append = 0,
- bool no_auto_events = 0);
+ enum_log_type type, bool read_append,
+ bool no_auto_events, ulong max_size);
/*
External variables
@@ -704,6 +717,7 @@ extern const char *command_name[];
extern const char *first_keyword, *localhost, *delayed_user, *binary_keyword;
extern const char **errmesg; /* Error messages */
extern const char *myisam_recover_options_str;
+extern const char *in_left_expr_name;
extern uchar *days_in_month;
extern char language[LIBLEN],reg_ext[FN_EXTLEN];
extern char glob_hostname[FN_REFLEN], mysql_home[FN_REFLEN];
@@ -736,7 +750,8 @@ extern ulong max_insert_delayed_threads, max_user_connections;
extern ulong long_query_count, what_to_log,flush_time;
extern ulong query_buff_size, thread_stack,thread_stack_min;
extern ulong binlog_cache_size, max_binlog_cache_size, open_files_limit;
-extern ulong max_binlog_size, rpl_recovery_rank, thread_cache_size;
+extern ulong max_binlog_size, max_relay_log_size;
+extern ulong rpl_recovery_rank, thread_cache_size;
extern ulong com_stat[(uint) SQLCOM_END], com_other, back_log;
extern ulong specialflag, current_pid;
extern ulong expire_logs_days;
@@ -915,6 +930,10 @@ Item *get_system_var(THD *thd, enum_var_type var_type, const char *var_name,
/* log.cc */
bool flush_error_log(void);
+/* sql_list.cc */
+void free_list(I_List <i_string_pair> *list);
+void free_list(I_List <i_string> *list);
+
/* Some inline functions for more speed */
inline bool add_item_to_list(THD *thd, Item *item)
@@ -964,7 +983,7 @@ inline void setup_table_map(TABLE *table, TABLE_LIST *table_list, uint tablenr)
{
table->used_fields= 0;
table->const_table= 0;
- table->outer_join= table->null_row= 0;
+ table->null_row= 0;
table->status= STATUS_NO_RECORD;
table->keys_in_use_for_query= table->keys_in_use;
table->maybe_null= test(table->outer_join= table_list->outer_join);
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index ef2fb78ef80..41bd9706fc3 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -212,7 +212,7 @@ const char *sql_mode_names[] =
"?", "ONLY_FULL_GROUP_BY", "NO_UNSIGNED_SUBTRACTION",
"POSTGRESQL", "ORACLE", "MSSQL", "DB2", "SAPDB", "NO_KEY_OPTIONS",
"NO_TABLE_OPTIONS", "NO_FIELD_OPTIONS", "MYSQL323", "MYSQL40", "ANSI",
- NullS
+ "NO_AUTO_VALUE_ON_ZERO", NullS
};
TYPELIB sql_mode_typelib= { array_elements(sql_mode_names)-1,"",
sql_mode_names };
@@ -229,6 +229,7 @@ bool opt_large_files= sizeof(my_off_t) > 4;
/*
Used with --help for detailed option
*/
+bool opt_help= 0;
bool opt_verbose= 0;
arg_cmp_func Arg_comparator::comparator_matrix[4][2] =
@@ -251,7 +252,7 @@ bool volatile ready_to_exit, shutdown_in_progress, grant_option;
my_bool opt_skip_slave_start = 0; // If set, slave is not autostarted
my_bool opt_reckless_slave = 0;
-my_bool opt_enable_named_pipe= 0;
+my_bool opt_enable_named_pipe= 0, opt_debugging= 0;
my_bool opt_local_infile, opt_external_locking, opt_slave_compressed_protocol;
my_bool opt_safe_user_create = 0, opt_no_mix_types = 0;
my_bool lower_case_table_names, opt_old_rpl_compat;
@@ -269,14 +270,15 @@ ulong back_log, connect_timeout, concurrency;
ulong server_id, thd_startup_options;
ulong table_cache_size, thread_stack, thread_stack_min, what_to_log;
ulong query_buff_size, slow_launch_time, slave_open_temp_tables;
-ulong open_files_limit, max_binlog_size;
+ulong open_files_limit, max_binlog_size, max_relay_log_size;
ulong slave_net_timeout;
ulong thread_cache_size=0, binlog_cache_size=0, max_binlog_cache_size=0;
ulong query_cache_size=0;
ulong com_stat[(uint) SQLCOM_END], com_other;
ulong bytes_sent, bytes_received, net_big_packet_count;
-ulong refresh_version=1L,flush_version=1L; /* Increments on each reload */
-ulong query_id, long_query_count, aborted_threads, aborted_connects;
+ulong refresh_version, flush_version; /* Increments on each reload */
+ulong query_id, long_query_count;
+ulong aborted_threads, killed_threads, aborted_connects;
ulong delayed_insert_timeout, delayed_insert_limit, delayed_queue_size;
ulong delayed_insert_threads, delayed_insert_writes, delayed_rows_in_use;
ulong delayed_insert_errors,flush_time, thread_created;
@@ -315,6 +317,8 @@ char *my_bind_addr_str;
const char **errmesg; /* Error messages */
const char *myisam_recover_options_str="OFF";
const char *sql_mode_str="OFF";
+/* name of reference on left espression in rewritten IN subquery */
+const char *in_left_expr_name= "<left expr>";
FILE *bootstrap_file;
@@ -846,7 +850,6 @@ extern "C" void unireg_abort(int exit_code)
sql_print_error("Aborting\n");
clean_up(exit_code || !opt_bootstrap); /* purecov: inspected */
DBUG_PRINT("quit",("done with cleanup in unireg_abort"));
- my_thread_end();
clean_up_mutexes();
my_end(opt_endinfo ? MY_CHECK_ERROR | MY_GIVE_INFO : 0);
exit(exit_code); /* purecov: inspected */
@@ -899,6 +902,11 @@ void clean_up(bool print_message)
free_max_user_conn();
#ifdef HAVE_REPLICATION
end_slave_list();
+ free_list(&replicate_do_db);
+ free_list(&replicate_ignore_db);
+ free_list(&binlog_do_db);
+ free_list(&binlog_ignore_db);
+ free_list(&replicate_rewrite_db);
#endif
#ifdef HAVE_OPENSSL
if (ssl_acceptor_fd)
@@ -1262,7 +1270,10 @@ extern "C" sig_handler end_thread_signal(int sig __attribute__((unused)))
THD *thd=current_thd;
DBUG_ENTER("end_thread_signal");
if (thd && ! thd->bootstrap)
+ {
+ statistic_increment(killed_threads, &LOCK_status);
end_thread(thd,0);
+ }
DBUG_VOID_RETURN; /* purecov: deadcode */
}
@@ -1581,7 +1592,8 @@ static void init_signals(void)
struct sigaction sa;
DBUG_ENTER("init_signals");
- sigset(THR_KILL_SIGNAL,end_thread_signal);
+ if (test_flags & TEST_SIGINT)
+ sigset(THR_KILL_SIGNAL,end_thread_signal);
sigset(THR_SERVER_ALARM,print_signal_warning); // Should never be called!
if (!(test_flags & TEST_NO_STACKTRACE) || (test_flags & TEST_CORE_ON_SIGNAL))
@@ -1640,7 +1652,8 @@ static void init_signals(void)
sigaddset(&set,SIGTSTP);
#endif
sigaddset(&set,THR_SERVER_ALARM);
- sigdelset(&set,THR_KILL_SIGNAL); // May be SIGINT
+ if (test_flags & TEST_SIGINT)
+ sigdelset(&set,THR_KILL_SIGNAL); // May be SIGINT
sigdelset(&set,THR_CLIENT_ALARM); // For alarms
sigprocmask(SIG_SETMASK,&set,NULL);
pthread_sigmask(SIG_SETMASK,&set,NULL);
@@ -1696,9 +1709,12 @@ extern "C" void *signal_hand(void *arg __attribute__((unused)))
*/
init_thr_alarm(max_connections+max_insert_delayed_threads+10);
#if SIGINT != THR_KILL_SIGNAL
- (void) sigemptyset(&set); // Setup up SIGINT for debug
- (void) sigaddset(&set,SIGINT); // For debugging
- (void) pthread_sigmask(SIG_UNBLOCK,&set,NULL);
+ if (test_flags & TEST_SIGINT)
+ {
+ (void) sigemptyset(&set); // Setup up SIGINT for debug
+ (void) sigaddset(&set,SIGINT); // For debugging
+ (void) pthread_sigmask(SIG_UNBLOCK,&set,NULL);
+ }
#endif
(void) sigemptyset(&set); // Setup up SIGINT for debug
#ifdef USE_ONE_SIGNAL_HAND
@@ -1930,7 +1946,7 @@ bool open_log(MYSQL_LOG *log, const char *hostname,
const char *opt_name, const char *extension,
const char *index_file_name,
enum_log_type type, bool read_append,
- bool no_auto_events)
+ bool no_auto_events, ulong max_size)
{
char tmp[FN_REFLEN];
if (!opt_name || !opt_name[0])
@@ -1947,16 +1963,13 @@ bool open_log(MYSQL_LOG *log, const char *hostname,
if (type == LOG_BIN)
{
char *p = fn_ext(opt_name);
- if (p)
- {
- uint length=(uint) (p-opt_name);
- strmake(tmp,opt_name,min(length,FN_REFLEN));
- opt_name=tmp;
- }
+ uint length=(uint) (p-opt_name);
+ strmake(tmp,opt_name,min(length,FN_REFLEN));
+ opt_name=tmp;
}
return log->open(opt_name, type, 0, index_file_name,
(read_append) ? SEQ_READ_APPEND : WRITE_CACHE,
- no_auto_events);
+ no_auto_events, max_size);
}
@@ -1988,6 +2001,17 @@ static int init_common_variables(const char *conf_file_name, int argc,
}
#endif
+ /*
+ Init mutexes for the global MYSQL_LOG objects.
+ As safe_mutex depends on what MY_INIT() does, we can't init the mutexes of
+ global MYSQL_LOGs in their constructors, because then they would be inited
+ before MY_INIT(). So we do it here.
+ */
+ mysql_log.init_pthread_objects();
+ mysql_update_log.init_pthread_objects();
+ mysql_slow_log.init_pthread_objects();
+ mysql_bin_log.init_pthread_objects();
+
if (gethostname(glob_hostname,sizeof(glob_hostname)-4) < 0)
strmov(glob_hostname,"mysql");
strmake(pidfile_name, glob_hostname, sizeof(pidfile_name)-5);
@@ -2150,21 +2174,21 @@ static int init_server_components()
/* Setup log files */
if (opt_log)
open_log(&mysql_log, glob_hostname, opt_logname, ".log", NullS,
- LOG_NORMAL);
+ LOG_NORMAL, 0, 0, 0);
if (opt_update_log)
{
open_log(&mysql_update_log, glob_hostname, opt_update_logname, "",
- NullS, LOG_NEW);
+ NullS, LOG_NEW, 0, 0, 0);
using_update_log=1;
}
if (opt_slow_log)
open_log(&mysql_slow_log, glob_hostname, opt_slow_logname, "-slow.log",
- NullS, LOG_NORMAL);
+ NullS, LOG_NORMAL, 0, 0, 0);
if (opt_bin_log)
{
open_log(&mysql_bin_log, glob_hostname, opt_bin_logname, "-bin",
- opt_binlog_index_name,LOG_BIN);
+ opt_binlog_index_name, LOG_BIN, 0, 0, max_binlog_size);
using_update_log=1;
#ifdef HAVE_REPLICATION
if (expire_logs_days)
@@ -2175,6 +2199,12 @@ static int init_server_components()
}
#endif
}
+ else if (opt_log_slave_updates)
+ {
+ sql_print_error("\
+Warning: you need to use --log-bin to make --log-slave-updates work. \
+Now disabling --log-slave-updates.");
+ }
if (opt_error_log)
{
@@ -2458,6 +2488,8 @@ The server will not act as a slave.");
if (!opt_noacl)
udf_init();
#endif
+ if (opt_bootstrap) /* If running with bootstrap, do not start replication. */
+ opt_skip_slave_start= 1;
/* init_slave() must be called after the thread keys are created */
init_slave();
@@ -2563,6 +2595,19 @@ int mysql_service(void *p)
return 0;
}
+
+/* Quote string if it contains space, else copy */
+
+static char *add_quoted_string(char *to, const char *from, char *to_end)
+{
+ uint length= (uint) (to_end-to);
+
+ if (!strchr(from, ' '))
+ return strnmov(to, from, length);
+ return strxnmov(to, length, "\"", from, "\"", NullS);
+}
+
+
/*
Handle basic handling of services, like installation and removal
@@ -2572,25 +2617,41 @@ int mysql_service(void *p)
servicename Internal name of service
displayname Display name of service (in taskbar ?)
file_path Path to this program
+ startup_option Startup option to mysqld
RETURN VALUES
0 option handled
1 Could not handle option
*/
-bool default_service_handling(char **argv,
- const char *servicename,
- const char *displayname,
- const char *file_path)
+static bool
+default_service_handling(char **argv,
+ const char *servicename,
+ const char *displayname,
+ const char *file_path,
+ const char *extra_opt)
{
+ char path_and_service[FN_REFLEN+FN_REFLEN+32], *pos, *end;
+ end= path_and_service + sizeof(path_and_service)-1;
+
+ /* We have to quote filename if it contains spaces */
+ pos= add_quoted_string(path_and_service, file_path, end);
+ if (*extra_opt)
+ {
+ /* Add (possible quoted) option after file_path */
+ *pos++= ' ';
+ pos= add_quoted_string(pos, extra_opt, end);
+ }
+ *pos= 0; // Ensure end null
+
if (Service.got_service_option(argv, "install"))
{
- Service.Install(1, servicename, displayname, file_path);
+ Service.Install(1, servicename, displayname, path_and_service);
return 0;
}
if (Service.got_service_option(argv, "install-manual"))
{
- Service.Install(0, servicename, displayname, file_path);
+ Service.Install(0, servicename, displayname, path_and_service);
return 0;
}
if (Service.got_service_option(argv, "remove"))
@@ -2616,12 +2677,13 @@ int main(int argc, char **argv)
{
char file_path[FN_REFLEN];
my_path(file_path, argv[0], ""); /* Find name in path */
- fn_format(file_path,argv[0],file_path,"",1+4+16); /* Force full path */
+ fn_format(file_path,argv[0],file_path,"",
+ MY_REPLACE_DIR | MY_UNPACK_FILENAME | MY_RESOLVE_SYMLINKS);
if (argc == 2)
{
- if (!default_service_handling(argv,MYSQL_SERVICENAME, MYSQL_SERVICENAME,
- file_path))
+ if (!default_service_handling(argv, MYSQL_SERVICENAME, MYSQL_SERVICENAME,
+ file_path, ""))
return 0;
if (Service.IsService(argv[1]))
{
@@ -2634,12 +2696,8 @@ int main(int argc, char **argv)
}
else if (argc == 3) /* install or remove any optional service */
{
- /* Add service name after filename */
- uint length=strlen(file_path);
- *strxnmov(file_path + length, sizeof(file_path)-length-2, " ",
- argv[2], NullS)= '\0';
-
- if (!default_service_handling(argv, argv[2], argv[2], file_path))
+ if (!default_service_handling(argv, argv[2], argv[2], file_path,
+ argv[2]))
return 0;
if (Service.IsService(argv[2]))
{
@@ -2661,10 +2719,8 @@ int main(int argc, char **argv)
Install an optional service with optional config file
mysqld --install-manual mysqldopt --defaults-file=c:\miguel\my.ini
*/
- uint length=strlen(file_path);
- *strxnmov(file_path + length, sizeof(file_path)-length-2, " ",
- argv[3], " ", argv[2], NullS)= '\0';
- if (!default_service_handling(argv, argv[2], argv[2], file_path))
+ if (!default_service_handling(argv, argv[2], argv[2], file_path,
+ argv[3]))
return 0;
}
else if (argc == 1 && Service.IsService(MYSQL_SERVICENAME))
@@ -2808,6 +2864,7 @@ static void create_new_thread(THD *thd)
thread_count--;
thd->killed=1; // Safety
(void) pthread_mutex_unlock(&LOCK_thread_count);
+ statistic_increment(aborted_connects,&LOCK_status);
net_printf(thd,ER_CANT_CREATE_THREAD,error);
(void) pthread_mutex_lock(&LOCK_thread_count);
close_connection(thd,0,0);
@@ -3423,7 +3480,6 @@ enum options
OPT_RPL_RECOVERY_RANK,OPT_INIT_RPL_ROLE,
OPT_RELAY_LOG, OPT_RELAY_LOG_INDEX, OPT_RELAY_LOG_INFO_FILE,
OPT_SLAVE_SKIP_ERRORS, OPT_DES_KEY_FILE, OPT_LOCAL_INFILE,
- OPT_RECKLESS_SLAVE,
OPT_SSL_SSL, OPT_SSL_KEY, OPT_SSL_CERT, OPT_SSL_CA,
OPT_SSL_CAPATH, OPT_SSL_CIPHER,
OPT_BACK_LOG, OPT_BINLOG_CACHE_SIZE,
@@ -3437,8 +3493,9 @@ enum options
OPT_MAX_BINLOG_CACHE_SIZE, OPT_MAX_BINLOG_SIZE,
OPT_MAX_CONNECTIONS, OPT_MAX_CONNECT_ERRORS,
OPT_MAX_DELAYED_THREADS, OPT_MAX_HEP_TABLE_SIZE,
- OPT_MAX_JOIN_SIZE, OPT_MAX_LENGTH_FOR_SORT_DATA, OPT_MAX_SORT_LENGTH,
- OPT_MAX_TMP_TABLES, OPT_MAX_USER_CONNECTIONS,
+ OPT_MAX_JOIN_SIZE, OPT_MAX_RELAY_LOG_SIZE, OPT_MAX_SORT_LENGTH,
+ OPT_MAX_SEEKS_FOR_KEY, OPT_MAX_TMP_TABLES, OPT_MAX_USER_CONNECTIONS,
+ OPT_MAX_LENGTH_FOR_SORT_DATA,
OPT_MAX_WRITE_LOCK_COUNT, OPT_BULK_INSERT_BUFFER_SIZE,
OPT_MAX_ERROR_COUNT, OPT_MAX_PREP_STMT,
OPT_MYISAM_BLOCK_SIZE, OPT_MYISAM_MAX_EXTRA_SORT_FILE_SIZE,
@@ -3451,7 +3508,7 @@ enum options
OPT_QUERY_CACHE_TYPE, OPT_RECORD_BUFFER,
OPT_RECORD_RND_BUFFER, OPT_RELAY_LOG_SPACE_LIMIT, OPT_RELAY_LOG_PURGE,
OPT_SLAVE_NET_TIMEOUT, OPT_SLAVE_COMPRESSED_PROTOCOL, OPT_SLOW_LAUNCH_TIME,
- OPT_READONLY,
+ OPT_READONLY, OPT_DEBUGGING,
OPT_SORT_BUFFER, OPT_TABLE_CACHE,
OPT_THREAD_CONCURRENCY, OPT_THREAD_CACHE_SIZE,
OPT_TMP_TABLE_SIZE, OPT_THREAD_STACK,
@@ -3606,6 +3663,10 @@ Disable with --skip-bdb (will save memory).",
REQUIRED_ARG, 1024, 4, (long) ~0, 0, 1, 0},
/* We must always support the next option to make scripts like mysqltest
easier to do */
+ {"gdb", OPT_DEBUGGING,
+ "Set up signals usable for debugging",
+ (gptr*) &opt_debugging, (gptr*) &opt_debugging,
+ 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"init-rpl-role", OPT_INIT_RPL_ROLE, "Set the replication role.", 0, 0, 0,
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
{"innodb_data_file_path", OPT_INNODB_DATA_FILE_PATH,
@@ -3637,13 +3698,14 @@ Disable with --skip-bdb (will save memory).",
0, 0, 0},
{"innodb_fast_shutdown", OPT_INNODB_FAST_SHUTDOWN,
"Speeds up server shutdown process.", (gptr*) &innobase_fast_shutdown,
- (gptr*) &innobase_fast_shutdown, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0},
+ (gptr*) &innobase_fast_shutdown, 0, GET_BOOL, OPT_ARG, 1, 0, 0, 0, 0, 0},
{"innodb_max_dirty_pages_pct", OPT_INNODB_MAX_DIRTY_PAGES_PCT,
"Percentage of dirty pages allowed in bufferpool.", (gptr*) &srv_max_buf_pool_modified_pct,
(gptr*) &srv_max_buf_pool_modified_pct, 0, GET_ULONG, REQUIRED_ARG, 90, 0, 100, 0, 0, 0},
#endif /* End HAVE_INNOBASE_DB */
- {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0,
- 0, 0, 0, 0, 0},
+ {"help", '?', "Display this help and exit.",
+ (gptr*) &opt_help, (gptr*) &opt_help, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
+ 0, 0},
{"verbose", 'v', "Used with --help option for detailed help",
(gptr*) &opt_verbose, (gptr*) &opt_verbose, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0,
0, 0},
@@ -3802,8 +3864,6 @@ Does nothing yet.",
OPT_ARG, 0, 0, 0, 0, 0, 0},
{"port", 'P', "Port number to use for connection.", (gptr*) &mysqld_port,
(gptr*) &mysqld_port, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
- {"reckless-slave", OPT_RECKLESS_SLAVE, "Used for debugging.", 0, 0, 0, GET_NO_ARG,
- NO_ARG, 0, 0, 0, 0, 0, 0},
{"replicate-do-db", OPT_REPLICATE_DO_DB,
"Tells the slave thread to restrict replication to the specified database. To specify more than one database, use the directive multiple times, once for each database. Note that this will only work if you do not use cross-database queries such as UPDATE some_db.some_table SET foo='bar' while having selected a different or no database. If you need cross database updates to work, make sure you have 3.23.28 or later, and use replicate-wild-do-table=db_name.%.",
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
@@ -3918,7 +3978,7 @@ Disable with --skip-isam.",
{"skip-stack-trace", OPT_SKIP_STACK_TRACE,
"Don't print a stack trace on failure.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0,
0, 0, 0, 0},
- {"skip-symlink", OPT_SKIP_SYMLINKS, "Don't allow symlinking of tables. Depricated option. Use --skip-symbolic-links instead.",
+ {"skip-symlink", OPT_SKIP_SYMLINKS, "Don't allow symlinking of tables. Deprecated option. Use --skip-symbolic-links instead.",
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
{"skip-thread-priority", OPT_SKIP_PRIOR,
"Don't give threads different priorities.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0,
@@ -3972,10 +4032,10 @@ replicating a LOAD DATA INFILE command.",
{"external-locking", OPT_USE_LOCKING, "Use system (external) locking. With this option enabled you can run myisamchk to test (not repair) tables while the MySQL server is running.",
(gptr*) &opt_external_locking, (gptr*) &opt_external_locking,
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
- {"use-symbolic-links", 's', "Enable symbolic link support. Depricated option; Use --symbolic-links instead.",
+ {"use-symbolic-links", 's', "Enable symbolic link support. Deprecated option; Use --symbolic-links instead.",
(gptr*) &my_use_symdir, (gptr*) &my_use_symdir, 0, GET_BOOL, NO_ARG,
IF_PURIFY(0,1), 0, 0, 0, 0, 0},
- {"--symbolic-links", 's', "Enable symbolic link support.",
+ {"symbolic-links", 's', "Enable symbolic link support.",
(gptr*) &my_use_symdir, (gptr*) &my_use_symdir, 0, GET_BOOL, NO_ARG,
IF_PURIFY(0,1), 0, 0, 0, 0, 0},
{"user", 'u', "Run mysqld daemon as user.", 0, 0, 0, GET_STR, REQUIRED_ARG,
@@ -4142,9 +4202,11 @@ replicating a LOAD DATA INFILE command.",
(gptr*) &max_binlog_cache_size, (gptr*) &max_binlog_cache_size, 0,
GET_ULONG, REQUIRED_ARG, ~0L, IO_SIZE, ~0L, 0, IO_SIZE, 0},
{"max_binlog_size", OPT_MAX_BINLOG_SIZE,
- "Binary log will be rotated automatically when the size crosses the limit.",
+ "Binary log will be rotated automatically when the size exceeds this \
+value. Will also apply to relay logs if max_relay_log_size is 0. \
+The minimum value for this variable is 4096.",
(gptr*) &max_binlog_size, (gptr*) &max_binlog_size, 0, GET_ULONG,
- REQUIRED_ARG, 1024*1024L*1024L, 1024, 1024*1024L*1024L, 0, 1, 0},
+ REQUIRED_ARG, 1024*1024L*1024L, IO_SIZE, 1024*1024L*1024L, 0, IO_SIZE, 0},
{"max_connections", OPT_MAX_CONNECTIONS,
"The number of simultaneous clients allowed.", (gptr*) &max_connections,
(gptr*) &max_connections, 0, GET_ULONG, REQUIRED_ARG, 100, 1, 16384, 0, 1,
@@ -4182,6 +4244,15 @@ replicating a LOAD DATA INFILE command.",
(gptr*) &global_system_variables.max_prep_stmt_count,
(gptr*) &max_system_variables.max_prep_stmt_count, 0, GET_ULONG,
REQUIRED_ARG, DEFAULT_PREP_STMT_COUNT, 0, ~0L, 0, 1, 0},
+ {"max_relay_log_size", OPT_MAX_RELAY_LOG_SIZE,
+ "If non-zero: relay log will be rotated automatically when the size exceeds this value; if zero (the default): when the size exceeds max_binlog_size. 0 expected, the minimum value for this variable is 4096.",
+ (gptr*) &max_relay_log_size, (gptr*) &max_relay_log_size, 0, GET_ULONG,
+ REQUIRED_ARG, 0L, 0L, 1024*1024L*1024L, 0, IO_SIZE, 0},
+ { "max_seeks_for_key", OPT_MAX_SEEKS_FOR_KEY,
+ "Limit assumed max number of seeks when looking up rows based on a key",
+ (gptr*) &global_system_variables.max_seeks_for_key,
+ (gptr*) &max_system_variables.max_seeks_for_key, 0, GET_ULONG,
+ REQUIRED_ARG, ~0L, 1, ~0L, 0, 1, 0 },
{"max_sort_length", OPT_MAX_SORT_LENGTH,
"The number of bytes to use when sorting BLOB or TEXT values (only the first max_sort_length bytes of each value are used; the rest are ignored).",
(gptr*) &global_system_variables.max_sort_length,
@@ -4425,6 +4496,7 @@ struct show_var_st status_vars[]= {
{"Com_restore_table", (char*) (com_stat+(uint) SQLCOM_RESTORE_TABLE),SHOW_LONG},
{"Com_revoke", (char*) (com_stat+(uint) SQLCOM_REVOKE),SHOW_LONG},
{"Com_rollback", (char*) (com_stat+(uint) SQLCOM_ROLLBACK),SHOW_LONG},
+ {"Com_savepoint", (char*) (com_stat+(uint) SQLCOM_SAVEPOINT),SHOW_LONG},
{"Com_select", (char*) (com_stat+(uint) SQLCOM_SELECT),SHOW_LONG},
{"Com_set_option", (char*) (com_stat+(uint) SQLCOM_SET_OPTION),SHOW_LONG},
{"Com_show_binlog_events", (char*) (com_stat+(uint) SQLCOM_SHOW_BINLOG_EVENTS),SHOW_LONG},
@@ -4576,8 +4648,8 @@ static void usage(void)
puts("\
Copyright (C) 2000 MySQL AB, by Monty and others\n\
This software comes with ABSOLUTELY NO WARRANTY. This is free software,\n\
-and you are welcome to modify and redistribute it under the GPL license\n\
-Starts the MySQL server\n");
+and you are welcome to modify and redistribute it under the GPL license\n\n\
+Starts the MySQL database server\n");
printf("Usage: %s [OPTIONS]\n", my_progname);
if (!opt_verbose)
@@ -4687,7 +4759,7 @@ static void mysql_init_variables(void)
protocol_version= PROTOCOL_VERSION;
what_to_log= ~ (1L << (uint) COM_TIME);
refresh_version= flush_version= 1L; /* Increments on each reload */
- thread_id= 1L;
+ query_id= thread_id= 1L;
strmov(server_version, MYSQL_SERVER_VERSION);
myisam_recover_options_str= sql_mode_str= "OFF";
my_bind_addr = htonl(INADDR_ANY);
@@ -4870,7 +4942,7 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
#endif
case OPT_SAFEMALLOC_MEM_LIMIT:
#if !defined(DBUG_OFF) && defined(SAFEMALLOC)
- safemalloc_mem_limit = atoi(argument);
+ sf_malloc_mem_limit = atoi(argument);
#endif
break;
#ifdef EMBEDDED_LIBRARY
@@ -4882,16 +4954,9 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
break;
#endif
#include <sslopt-case.h>
- case 'v':
- usage();
- exit(0);
case 'V':
print_version();
exit(0);
- case 'I':
- case '?':
- usage();
- exit(0);
case 'T':
test_flags= argument ? (uint) atoi(argument) : 0;
test_flags&= ~TEST_NO_THREADS;
@@ -5033,10 +5098,6 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
table_rules_on = 1;
break;
}
- case (int)OPT_RECKLESS_SLAVE:
- opt_reckless_slave = 1;
- init_slave_skip_errors("all");
- break;
#endif /* HAVE_REPLICATION */
case (int) OPT_SLOW_QUERY_LOG:
opt_slow_log=1;
@@ -5365,6 +5426,11 @@ static void get_options(int argc,char **argv)
exit(ho_error);
}
+ if (opt_help)
+ {
+ usage();
+ exit(0);
+ }
#if defined(HAVE_BROKEN_REALPATH)
my_use_symdir=0;
my_disable_symlinks=1;
@@ -5376,6 +5442,12 @@ static void get_options(int argc,char **argv)
have_symlink=SHOW_OPTION_DISABLED;
}
#endif
+ if (opt_debugging)
+ {
+ /* Allow break with SIGINT, no core or stack trace */
+ test_flags|= TEST_SIGINT | TEST_NO_STACKTRACE;
+ test_flags&= ~TEST_CORE_ON_SIGNAL;
+ }
/* Set global MyISAM variables from delay_key_write_options */
fix_delay_key_write((THD*) 0, OPT_GLOBAL);
@@ -5400,7 +5472,11 @@ static void get_options(int argc,char **argv)
files_charset_info :
&my_charset_bin);
/* QQ To be deleted when we have key cache variables in a struct */
- keybuff_size= (((KEY_CACHE *) find_named(&key_caches, "default", 7))->size);
+ {
+ NAMED_LIST *not_used;
+ keybuff_size= (((KEY_CACHE *) find_named(&key_caches, "default", 7,
+ &not_used))->size);
+ }
}
diff --git a/sql/net_serv.cc b/sql/net_serv.cc
index fd5e4f1d71a..f12705572d6 100644
--- a/sql/net_serv.cc
+++ b/sql/net_serv.cc
@@ -28,9 +28,15 @@
Read packets are reallocated dynamicly when reading big packets.
Each logical packet has the following pre-info:
3 byte length & 1 byte package-number.
+
+ This file needs to be written in C as it's used by the libmysql client as a
+ C file.
*/
-#ifndef EMBEDDED_LIBRARY
+/*
+ HFTODO this must be hidden if we don't want client capabilities in
+ embedded library
+ */
#ifdef __WIN__
#include <winsock.h>
#endif
@@ -46,6 +52,17 @@
#include <signal.h>
#include <errno.h>
+#ifdef EMBEDDED_LIBRARY
+
+#undef net_flush
+
+extern "C" {
+my_bool net_flush(NET *net);
+}
+
+#endif /*EMBEDDED_LIBRARY */
+
+
/*
The following handles the differences when this is linked between the
client and the server.
@@ -959,5 +976,3 @@ my_net_read(NET *net)
return len;
}
-#endif /* #ifndef EMBEDDED_LIBRARY */
-
diff --git a/sql/opt_range.cc b/sql/opt_range.cc
index 18c465ffde3..23fb36c0c91 100644
--- a/sql/opt_range.cc
+++ b/sql/opt_range.cc
@@ -930,7 +930,7 @@ get_mm_leaf(PARAM *param, Field *field, KEY_PART *key_part,
{
bool like_error;
char buff1[MAX_FIELD_WIDTH],*min_str,*max_str;
- String tmp(buff1,sizeof(buff1),value->charset()),*res;
+ String tmp(buff1,sizeof(buff1),value->collation.collation),*res;
uint length,offset,min_length,max_length;
if (!field->optimize_range(param->real_keynr[key_part->key]))
@@ -2390,9 +2390,17 @@ QUICK_SELECT *get_quick_select_for_ref(TABLE *table, TABLE_REF *ref)
if (!quick)
return 0;
+ if (cp_buffer_from_ref(ref))
+ {
+ if (current_thd->is_fatal_error)
+ return 0; // End of memory
+ return quick; // empty range
+ }
+
QUICK_RANGE *range= new QUICK_RANGE();
- if (!range || cp_buffer_from_ref(ref))
+ if (!range)
goto err;
+
range->min_key=range->max_key=(char*) ref->key_buff;
range->min_length=range->max_length=ref->key_length;
range->flag= ((ref->key_length == key_info->key_length &&
diff --git a/sql/protocol.cc b/sql/protocol.cc
index 1b9256c7723..e90aa7585e2 100644
--- a/sql/protocol.cc
+++ b/sql/protocol.cc
@@ -83,6 +83,7 @@ void send_error(THD *thd, uint sql_errno, const char *err)
#ifdef EMBEDDED_LIBRARY
net->last_errno= sql_errno;
strmake(net->last_error, err, sizeof(net->last_error)-1);
+ strmov(net->sqlstate, mysql_errno_to_sqlstate(sql_errno));
#else
if (net->vio == 0)
@@ -230,12 +231,12 @@ net_printf(THD *thd, uint errcode, ...)
#else
net->last_errno= errcode;
strmake(net->last_error, text_pos, length);
+ strmake(net->sqlstate, mysql_errno_to_sqlstate(errcode), SQLSTATE_LENGTH);
#endif
thd->is_fatal_error=0; // Error message is given
DBUG_VOID_RETURN;
}
-
/*
Return ok to the client.
@@ -350,40 +351,6 @@ send_eof(THD *thd, bool no_flush)
}
#endif /* EMBEDDED_LIBRARY */
-
-/****************************************************************************
- Store a field length in logical packet
- This is used to code the string length for normal protocol
-****************************************************************************/
-
-char *
-net_store_length(char *pkg, ulonglong length)
-{
- uchar *packet=(uchar*) pkg;
- if (length < LL(251))
- {
- *packet=(uchar) length;
- return (char*) packet+1;
- }
- /* 251 is reserved for NULL */
- if (length < LL(65536))
- {
- *packet++=252;
- int2store(packet,(uint) length);
- return (char*) packet+2;
- }
- if (length < LL(16777216))
- {
- *packet++=253;
- int3store(packet,(ulong) length);
- return (char*) packet+3;
- }
- *packet++=254;
- int8store(packet,length);
- return (char*) packet+8;
-}
-
-
/*
Faster net_store_length when we know length is a 32 bit integer
*/
diff --git a/sql/protocol.h b/sql/protocol.h
index ffd61b3e848..05aee12d3d9 100644
--- a/sql/protocol.h
+++ b/sql/protocol.h
@@ -61,7 +61,7 @@ public:
inline bool store(ulonglong from)
{ return store_longlong((longlong) from, 1); }
inline bool store(String *str)
- { return store(str->c_ptr(),str->length(),str->charset()); }
+ { return store((char*) str->ptr(), str->length(), str->charset()); }
virtual bool prepare_for_send(List<Item> *item_list)
{
diff --git a/sql/records.cc b/sql/records.cc
index 783ca663dfe..72a6d480356 100644
--- a/sql/records.cc
+++ b/sql/records.cc
@@ -73,7 +73,13 @@ void init_read_record(READ_RECORD *info,THD *thd, TABLE *table,
info->ref_pos=table->file->ref;
table->file->rnd_init(0);
- if (! (specialflag & SPECIAL_SAFE_MODE) &&
+ /*
+ table->sort.addon_field is checked because if we use addon fields,
+ it doesn't make sense to use cache - we don't read from the table
+ and table->sort.io_cache is read sequentially
+ */
+ if (!table->sort.addon_field &&
+ ! (specialflag & SPECIAL_SAFE_MODE) &&
thd->variables.read_rnd_buff_size &&
!table->file->fast_key_read() &&
(table->db_stat & HA_READ_ONLY ||
diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc
index 60af9a92c76..e9c3b1ed0b0 100644
--- a/sql/repl_failsafe.cc
+++ b/sql/repl_failsafe.cc
@@ -72,6 +72,7 @@ static int init_failsafe_rpl_thread(THD* thd)
if (init_thr_lock() || thd->store_globals())
{
close_connection(thd, ER_OUT_OF_RESOURCES, 1); // is this needed?
+ statistic_increment(aborted_connects,&LOCK_status);
end_thread(thd,0);
DBUG_RETURN(-1);
}
@@ -867,7 +868,7 @@ int load_master_data(THD* thd)
of LOAD DATA FROM MASTER - no reason to forbid it, really,
although it does not make much sense for the user to do it
*/
- if (row[0] && row[1])
+ if (row && row[0] && row[1])
{
strmake(active_mi->master_log_name, row[0],
sizeof(active_mi->master_log_name));
diff --git a/sql/set_var.cc b/sql/set_var.cc
index cb6c875d513..91583759c70 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -88,6 +88,8 @@ static void fix_query_cache_size(THD *thd, enum_var_type type);
static void fix_query_cache_min_res_unit(THD *thd, enum_var_type type);
static void fix_myisam_max_extra_sort_file_size(THD *thd, enum_var_type type);
static void fix_myisam_max_sort_file_size(THD *thd, enum_var_type type);
+static void fix_max_binlog_size(THD *thd, enum_var_type type);
+static void fix_max_relay_log_size(THD *thd, enum_var_type type);
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);
@@ -155,7 +157,8 @@ sys_var_thd_ulong sys_max_allowed_packet("max_allowed_packet",
sys_var_long_ptr sys_max_binlog_cache_size("max_binlog_cache_size",
&max_binlog_cache_size);
sys_var_long_ptr sys_max_binlog_size("max_binlog_size",
- &max_binlog_size);
+ &max_binlog_size,
+ fix_max_binlog_size);
sys_var_long_ptr sys_max_connections("max_connections",
&max_connections);
sys_var_long_ptr sys_max_connect_errors("max_connect_errors",
@@ -175,6 +178,8 @@ sys_var_pseudo_thread_id sys_pseudo_thread_id("pseudo_thread_id",
sys_var_thd_ha_rows sys_max_join_size("max_join_size",
&SV::max_join_size,
fix_max_join_size);
+sys_var_thd_ulong sys_max_seeks_for_key("max_seeks_for_key",
+ &SV::max_seeks_for_key);
sys_var_thd_ulong sys_max_length_for_sort_data("max_length_for_sort_data",
&SV::max_length_for_sort_data);
#ifndef TO_BE_DELETED /* Alias for max_join_size */
@@ -184,6 +189,9 @@ sys_var_thd_ha_rows sys_sql_max_join_size("sql_max_join_size",
#endif
sys_var_thd_ulong sys_max_prep_stmt_count("max_prepared_statements",
&SV::max_prep_stmt_count);
+sys_var_long_ptr sys_max_relay_log_size("max_relay_log_size",
+ &max_relay_log_size,
+ fix_max_relay_log_size);
sys_var_thd_ulong sys_max_sort_length("max_sort_length",
&SV::max_sort_length);
sys_var_long_ptr sys_max_user_connections("max_user_connections",
@@ -318,7 +326,6 @@ static sys_var_thd_bit sys_unique_checks("unique_checks",
OPTION_RELAXED_UNIQUE_CHECKS,
1);
-
/* Local state variables */
static sys_var_thd_ha_rows sys_select_limit("sql_select_limit",
@@ -409,6 +416,8 @@ sys_var *sys_variables[]=
&sys_max_join_size,
&sys_max_length_for_sort_data,
&sys_max_prep_stmt_count,
+ &sys_max_relay_log_size,
+ &sys_max_seeks_for_key,
&sys_max_sort_length,
&sys_max_tmp_tables,
&sys_max_user_connections,
@@ -573,8 +582,9 @@ struct show_var_st init_vars[]= {
{sys_max_delayed_threads.name,(char*) &sys_max_delayed_threads, SHOW_SYS},
{sys_max_heap_table_size.name,(char*) &sys_max_heap_table_size, SHOW_SYS},
{sys_max_join_size.name, (char*) &sys_max_join_size, SHOW_SYS},
- {sys_max_length_for_sort_data.name,
- (char*) &sys_max_length_for_sort_data,
+ {sys_max_relay_log_size.name, (char*) &sys_max_relay_log_size, SHOW_SYS},
+ {sys_max_seeks_for_key.name, (char*) &sys_max_seeks_for_key, SHOW_SYS},
+ {sys_max_length_for_sort_data.name, (char*) &sys_max_length_for_sort_data,
SHOW_SYS},
{sys_max_prep_stmt_count.name,(char*) &sys_max_prep_stmt_count, SHOW_SYS},
{sys_max_sort_length.name, (char*) &sys_max_sort_length, SHOW_SYS},
@@ -807,6 +817,30 @@ void fix_delay_key_write(THD *thd, enum_var_type type)
}
}
+void fix_max_binlog_size(THD *thd, enum_var_type type)
+{
+ DBUG_ENTER("fix_max_binlog_size");
+ DBUG_PRINT("info",("max_binlog_size=%lu max_relay_log_size=%lu",
+ max_binlog_size, max_relay_log_size));
+ mysql_bin_log.set_max_size(max_binlog_size);
+#ifdef HAVE_REPLICATION
+ if (!max_relay_log_size)
+ active_mi->rli.relay_log.set_max_size(max_binlog_size);
+#endif
+ DBUG_VOID_RETURN;
+}
+
+void fix_max_relay_log_size(THD *thd, enum_var_type type)
+{
+ DBUG_ENTER("fix_max_relay_log_size");
+ DBUG_PRINT("info",("max_binlog_size=%lu max_relay_log_size=%lu",
+ max_binlog_size, max_relay_log_size));
+#ifdef HAVE_REPLICATION
+ active_mi->rli.relay_log.set_max_size(max_relay_log_size ?
+ max_relay_log_size: max_binlog_size);
+#endif
+ DBUG_VOID_RETURN;
+}
bool sys_var_long_ptr::update(THD *thd, set_var *var)
{
@@ -1060,7 +1094,6 @@ err:
}
-
bool sys_var::check_set(THD *thd, set_var *var, TYPELIB *enum_names)
{
bool not_used;
@@ -1072,8 +1105,10 @@ bool sys_var::check_set(THD *thd, set_var *var, TYPELIB *enum_names)
{
if (!(res= var->value->val_str(&str)))
goto err;
- var->save_result.ulong_value= (ulong)
- find_set(enum_names, res->c_ptr(), res->length(), &error, &error_len, &not_used);
+ var->save_result.ulong_value= ((ulong)
+ find_set(enum_names, res->c_ptr(),
+ res->length(), &error, &error_len,
+ &not_used));
if (error_len)
{
strmake(buff, error, min(sizeof(buff), error_len));
@@ -1219,16 +1254,17 @@ static my_old_conv old_conv[]=
CHARSET_INFO *get_old_charset_by_name(const char *name)
{
- my_old_conv *c;
+ my_old_conv *conv;
- for (c= old_conv; c->old_name; c++)
+ for (conv= old_conv; conv->old_name; conv++)
{
- if (!my_strcasecmp(&my_charset_latin1,name,c->old_name))
- return get_charset_by_csname(c->new_name,MY_CS_PRIMARY,MYF(0));
+ if (!my_strcasecmp(&my_charset_latin1, name, conv->old_name))
+ return get_charset_by_csname(conv->new_name, MY_CS_PRIMARY, MYF(0));
}
return NULL;
}
+
bool sys_var_collation::check(THD *thd, set_var *var)
{
CHARSET_INFO *tmp;
@@ -1240,7 +1276,7 @@ bool sys_var_collation::check(THD *thd, set_var *var)
if (!(tmp=get_charset_by_name(res->c_ptr(),MYF(0))))
{
- my_error(ER_UNKNOWN_CHARACTER_SET, MYF(0), res->c_ptr());
+ my_error(ER_UNKNOWN_COLLATION, MYF(0), res->c_ptr());
return 1;
}
var->save_result.charset= tmp; // Save for update
@@ -1264,7 +1300,7 @@ bool sys_var_character_set::check(THD *thd, set_var *var)
tmp= NULL;
}
else if (!(tmp=get_charset_by_csname(res->c_ptr(),MY_CS_PRIMARY,MYF(0))) &&
- !(tmp=get_old_charset_by_name(res->c_ptr())))
+ !(tmp=get_old_charset_by_name(res->c_ptr())))
{
my_error(ER_UNKNOWN_CHARACTER_SET, MYF(0), res->c_ptr());
return 1;
@@ -1305,7 +1341,10 @@ void sys_var_character_set_connection::set_default(THD *thd,
if (type == OPT_GLOBAL)
global_system_variables.collation_connection= default_charset_info;
else
+ {
thd->variables.collation_connection= global_system_variables.collation_connection;
+ thd->update_charset();
+ }
}
@@ -1324,11 +1363,16 @@ void sys_var_character_set_client::set_default(THD *thd, enum_var_type type)
if (type == OPT_GLOBAL)
global_system_variables.character_set_client= default_charset_info;
else
- thd->variables.character_set_client= global_system_variables.character_set_client;
+ {
+ thd->variables.character_set_client= (global_system_variables.
+ character_set_client);
+ thd->update_charset();
+ }
}
-CHARSET_INFO ** sys_var_character_set_results::ci_ptr(THD *thd, enum_var_type type)
+CHARSET_INFO **
+sys_var_character_set_results::ci_ptr(THD *thd, enum_var_type type)
{
if (type == OPT_GLOBAL)
return &global_system_variables.character_set_results;
@@ -1342,11 +1386,16 @@ void sys_var_character_set_results::set_default(THD *thd, enum_var_type type)
if (type == OPT_GLOBAL)
global_system_variables.character_set_results= default_charset_info;
else
- thd->variables.character_set_results= global_system_variables.character_set_results;
+ {
+ thd->variables.character_set_results= (global_system_variables.
+ character_set_results);
+ thd->update_charset();
+ }
}
-CHARSET_INFO ** sys_var_character_set_server::ci_ptr(THD *thd, enum_var_type type)
+CHARSET_INFO **
+sys_var_character_set_server::ci_ptr(THD *thd, enum_var_type type)
{
if (type == OPT_GLOBAL)
return &global_system_variables.character_set_server;
@@ -1360,7 +1409,11 @@ void sys_var_character_set_server::set_default(THD *thd, enum_var_type type)
if (type == OPT_GLOBAL)
global_system_variables.character_set_server= default_charset_info;
else
- thd->variables.character_set_server= global_system_variables.character_set_server;
+ {
+ thd->variables.character_set_server= (global_system_variables.
+ character_set_server);
+ thd->update_charset();
+ }
}
@@ -1379,7 +1432,10 @@ void sys_var_character_set_database::set_default(THD *thd, enum_var_type type)
if (type == OPT_GLOBAL)
global_system_variables.character_set_database= default_charset_info;
else
+ {
thd->variables.character_set_database= thd->db_charset;
+ thd->update_charset();
+ }
}
@@ -1388,7 +1444,10 @@ bool sys_var_collation_connection::update(THD *thd, set_var *var)
if (var->type == OPT_GLOBAL)
global_system_variables.collation_connection= var->save_result.charset;
else
+ {
thd->variables.collation_connection= var->save_result.charset;
+ thd->update_charset();
+ }
return 0;
}
@@ -1408,38 +1467,47 @@ void sys_var_collation_connection::set_default(THD *thd, enum_var_type type)
if (type == OPT_GLOBAL)
global_system_variables.collation_connection= default_charset_info;
else
- thd->variables.collation_connection= global_system_variables.collation_connection;
+ {
+ thd->variables.collation_connection= (global_system_variables.
+ collation_connection);
+ thd->update_charset();
+ }
}
bool sys_var_key_buffer_size::update(THD *thd, set_var *var)
{
ulonglong tmp= var->value->val_int();
- if (!base_name.length)
+ NAMED_LIST *list;
+ LEX_STRING *base_name= &var->base;
+
+ if (!base_name->length)
{
- base_name.str= (char*) "default";
- base_name.length= 7;
+ /* We are using SET KEY_BUFFER_SIZE=# */
+ base_name->str= (char*) "default";
+ base_name->length= 7;
}
- KEY_CACHE *key_cache= (KEY_CACHE*) find_named(&key_caches, base_name.str,
- base_name.length);
+ KEY_CACHE *key_cache= (KEY_CACHE*) find_named(&key_caches, base_name->str,
+ base_name->length, &list);
if (!key_cache)
{
if (!tmp) // Tried to delete cache
return 0; // Ok, nothing to do
- if (!(key_cache= create_key_cache(base_name.str,
- base_name.length)))
+ if (!(key_cache= create_key_cache(base_name->str,
+ base_name->length)))
return 1;
}
- if (!tmp)
+ if (!tmp) // Zero size means delete
{
- /* Delete not default key caches */
- if (base_name.length != 7 || memcpy(base_name.str, "default", 7))
+ /* Don't delete the default key cache */
+ if (base_name->length != 7 || memcmp(base_name->str, "default", 7))
{
/*
- QQ: Here we should move tables using this key cache to default
- key cache
+ QQ: Here we should move tables that is using the found key cache
+ to the default key cache
*/
- delete key_cache;
+ delete list;
+ my_free((char*) key_cache, MYF(0));
return 0;
}
}
@@ -1452,6 +1520,7 @@ bool sys_var_key_buffer_size::update(THD *thd, set_var *var)
return 0;
}
+
static ulonglong zero=0;
byte *sys_var_key_buffer_size::value_ptr(THD *thd, enum_var_type type,
@@ -1459,6 +1528,8 @@ byte *sys_var_key_buffer_size::value_ptr(THD *thd, enum_var_type type,
{
const char *name;
uint length;
+ KEY_CACHE *key_cache;
+ NAMED_LIST *not_used;
if (!base->str)
{
@@ -1470,7 +1541,7 @@ byte *sys_var_key_buffer_size::value_ptr(THD *thd, enum_var_type type,
name= base->str;
length= base->length;
}
- KEY_CACHE *key_cache= (KEY_CACHE*) find_named(&key_caches, name, length);
+ key_cache= (KEY_CACHE*) find_named(&key_caches, name, length, &not_used);
if (!key_cache)
return (byte*) &zero;
return (byte*) &key_cache->size;
@@ -1492,6 +1563,7 @@ int set_var_collation_client::update(THD *thd)
thd->variables.character_set_client= character_set_client;
thd->variables.character_set_results= character_set_results;
thd->variables.collation_connection= collation_connection;
+ thd->update_charset();
thd->protocol_simple.init(thd);
thd->protocol_prep.init(thd);
return 0;
@@ -1825,17 +1897,18 @@ int sql_set_variables(THD *thd, List<set_var_base> *var_list)
{
int error= 0;
List_iterator_fast<set_var_base> it(*var_list);
+ DBUG_ENTER("sql_set_variables");
set_var_base *var;
while ((var=it++))
{
if ((error=var->check(thd)))
- return error;
+ DBUG_RETURN(error);
}
it.rewind();
while ((var=it++))
error|= var->update(thd); // Returns 0, -1 or 1
- return error;
+ DBUG_RETURN(error);
}
@@ -2036,14 +2109,18 @@ ulong fix_sql_mode(ulong sql_mode)
Named list handling
****************************************************************************/
-gptr find_named(I_List<NAMED_LIST> *list, const char *name, uint length)
+gptr find_named(I_List<NAMED_LIST> *list, const char *name, uint length,
+ NAMED_LIST **found)
{
I_List_iterator<NAMED_LIST> it(*list);
NAMED_LIST *element;
while ((element= it++))
{
if (element->cmp(name, length))
+ {
+ *found= element;
return element->data;
+ }
}
return 0;
}
@@ -2052,11 +2129,13 @@ gptr find_named(I_List<NAMED_LIST> *list, const char *name, uint length)
void delete_elements(I_List<NAMED_LIST> *list, void (*free_element)(gptr))
{
NAMED_LIST *element;
+ DBUG_ENTER("delete_elements");
while ((element= list->get()))
{
(*free_element)(element->data);
delete element;
}
+ DBUG_VOID_RETURN;
}
@@ -2065,7 +2144,8 @@ void delete_elements(I_List<NAMED_LIST> *list, void (*free_element)(gptr))
static KEY_CACHE *create_key_cache(const char *name, uint length)
{
KEY_CACHE *key_cache;
- DBUG_PRINT("info",("Creating key cache: %s", name));
+ DBUG_PRINT("info",("Creating key cache: %.*s length: %d", length, name,
+ length));
if ((key_cache= (KEY_CACHE*) my_malloc(sizeof(KEY_CACHE),
MYF(MY_ZEROFILL | MY_WME))))
{
@@ -2081,8 +2161,9 @@ static KEY_CACHE *create_key_cache(const char *name, uint length)
KEY_CACHE *get_or_create_key_cache(const char *name, uint length)
{
+ NAMED_LIST *not_used;
KEY_CACHE *key_cache= (KEY_CACHE*) find_named(&key_caches, name,
- length);
+ length, &not_used);
if (!key_cache)
key_cache= create_key_cache(name, length);
return key_cache;
diff --git a/sql/set_var.h b/sql/set_var.h
index 978aba3384a..f06b5ed22d3 100644
--- a/sql/set_var.h
+++ b/sql/set_var.h
@@ -47,18 +47,13 @@ public:
struct my_option *option_limits; /* Updated by by set_var_init() */
uint name_length; /* Updated by by set_var_init() */
const char *name;
- LEX_STRING base_name; /* for structs */
sys_after_update_func after_update;
sys_var(const char *name_arg) :name(name_arg),after_update(0)
- {
- base_name.length=0;
- }
+ {}
sys_var(const char *name_arg,sys_after_update_func func)
:name(name_arg),after_update(func)
- {
- base_name.length=0;
- }
+ {}
virtual ~sys_var() {}
virtual bool check(THD *thd, set_var *var) { return 0; }
bool check_enum(THD *thd, set_var *var, TYPELIB *enum_names);
@@ -595,9 +590,11 @@ public:
CHARSET_INFO *charset;
ulong ulong_value;
} save_result;
+ LEX_STRING base; /* for structs */
- set_var(enum_var_type type_arg, sys_var *var_arg, Item *value_arg)
- :var(var_arg), type(type_arg)
+ set_var(enum_var_type type_arg, sys_var *var_arg, LEX_STRING *base_name_arg,
+ Item *value_arg)
+ :var(var_arg), type(type_arg), base(*base_name_arg)
{
/*
If the set value is a field, change it to a string to allow things like
@@ -607,7 +604,7 @@ public:
{
Item_field *item= (Item_field*) value_arg;
if (!(value=new Item_string(item->field_name, strlen(item->field_name),
- item->charset())))
+ item->collation.collation)))
value=value_arg; /* Give error message later */
}
else
@@ -676,12 +673,12 @@ public:
gptr data;
NAMED_LIST(I_List<NAMED_LIST> *links, const char *name_arg,
- uint name_length_arg, gptr data_arg):
- name_length(name_length_arg), data(data_arg)
- {
- name=my_strdup(name_arg,MYF(MY_WME));
- links->push_back(this);
- }
+ uint name_length_arg, gptr data_arg)
+ :name_length(name_length_arg), data(data_arg)
+ {
+ name= my_memdup(name_arg, name_length, MYF(MY_WME));
+ links->push_back(this);
+ }
inline bool cmp(const char *name_cmp, uint length)
{
return length == name_length && !memcmp(name, name_cmp, length);
@@ -693,6 +690,13 @@ public:
};
+/* For sql_yacc */
+struct sys_var_with_base
+{
+ sys_var *var;
+ LEX_STRING base_name;
+};
+
/*
Prototypes for helper functions
*/
@@ -705,7 +709,8 @@ void fix_delay_key_write(THD *thd, enum_var_type type);
ulong fix_sql_mode(ulong sql_mode);
extern sys_var_str sys_charset_system;
CHARSET_INFO *get_old_charset_by_name(const char *old_name);
-gptr find_named(I_List<NAMED_LIST> *list, const char *name, uint length);
+gptr find_named(I_List<NAMED_LIST> *list, const char *name, uint length,
+ NAMED_LIST **found);
void delete_elements(I_List<NAMED_LIST> *list, void (*free_element)(gptr));
/* key_cache functions */
diff --git a/sql/share/charsets/Index.xml b/sql/share/charsets/Index.xml
index c5a2ae5dfb6..3661784325c 100644
--- a/sql/share/charsets/Index.xml
+++ b/sql/share/charsets/Index.xml
@@ -1,6 +1,6 @@
<?xml version='1.0' encoding="utf-8"?>
-<charsets max-id="91">
+<charsets max-id="93">
<description>
This file lists all of the available character sets.
@@ -522,6 +522,13 @@ To make maintaining easier please:
</collation>
</charset>
+<charset name="geostd8">
+ <family>South Asian</family>
+ <description>GEOSTD8 Georgian</description>
+ <collation name="geostd8_general_ci" id="92" order="Georgian" flag="primary"/>
+ <collation name="geostd8_bin" id="93" order="Binary" flag="binary"/>
+</charset>
+
<charset name="binary">
<description>Binary pseudo charset</description>
<collation name="binary" id="63" order="Binary">
diff --git a/sql/share/charsets/cp1251.xml b/sql/share/charsets/cp1251.xml
index 795022cc179..94774cca0f1 100644
--- a/sql/share/charsets/cp1251.xml
+++ b/sql/share/charsets/cp1251.xml
@@ -34,9 +34,9 @@
20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
40 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
- 70 71 72 73 54 75 76 77 78 79 7A 5B 5C 5D 5E 5F
+ 70 71 72 73 74 75 76 77 78 79 7A 5B 5C 5D 5E 5F
60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
- 70 71 72 73 54 75 76 77 78 79 7A 7B 7C 7D 7E 7F
+ 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
90 83 82 83 84 85 86 87 88 89 9A 8B 9C 9D 9E 9F
90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
A0 A2 A2 BC A4 B4 A6 A7 B8 A9 BA AB AC AD AE BF
@@ -56,9 +56,9 @@
20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
- 50 51 52 53 74 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
- 50 51 52 53 74 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ 50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F
80 81 82 81 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
80 91 92 93 94 95 96 97 98 99 8A 9B 8C 9D 8E 8F
A0 A1 A1 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
diff --git a/sql/share/charsets/geostd8.xml b/sql/share/charsets/geostd8.xml
new file mode 100644
index 00000000000..caf01af58d0
--- /dev/null
+++ b/sql/share/charsets/geostd8.xml
@@ -0,0 +1,121 @@
+<?xml version='1.0' encoding="utf-8"?>
+
+<charsets>
+
+<charset name="geostd8">
+
+<ctype>
+<map>
+ 00
+ 20 20 20 20 20 20 20 20 20 28 28 28 28 28 20 20
+ 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
+ 48 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10
+ 84 84 84 84 84 84 84 84 84 84 10 10 10 10 10 10
+ 10 81 81 81 81 81 81 01 01 01 01 01 01 01 01 01
+ 01 01 01 01 01 01 01 01 01 01 01 10 10 10 10 10
+ 10 82 82 82 82 82 82 02 02 02 02 02 02 02 02 02
+ 02 02 02 02 02 02 02 02 02 02 02 10 10 10 10 20
+ 00 00 10 00 10 10 10 10 00 10 00 10 00 00 00 00
+ 00 10 10 10 10 10 10 10 00 00 00 10 00 00 00 00
+ 48 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03
+ 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03 03
+ 03 03 03 03 03 03 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+</map>
+</ctype>
+
+
+<lower>
+<map>
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 5B 5C 5D 5E 5F
+ 60 61 62 63 64 65 66 67 68 69 6A 6B 6C 6D 6E 6F
+ 70 71 72 73 74 75 76 77 78 79 7A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+</map>
+</lower>
+
+
+<upper>
+<map>
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 60 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+</map>
+</upper>
+
+
+<unicode>
+<map>
+0000 0001 0002 0003 0004 0005 0006 0007 0008 0009 000A 000B 000C 000D 000E 000F
+0010 0011 0012 0013 0014 0015 0016 0017 0018 0019 001A 001B 001C 001D 001E 001F
+0020 0021 0022 0023 0024 0025 0026 0027 0028 0029 002A 002B 002C 002D 002E 002F
+0030 0031 0032 0033 0034 0035 0036 0037 0038 0039 003A 003B 003C 003D 003E 003F
+0040 0041 0042 0043 0044 0045 0046 0047 0048 0049 004A 004B 004C 004D 004E 004F
+0050 0051 0052 0053 0054 0055 0056 0057 0058 0059 005A 005B 005C 005D 005E 005F
+0060 0061 0062 0063 0064 0065 0066 0067 0068 0069 006A 006B 006C 006D 006E 006F
+0070 0071 0072 0073 0074 0075 0076 0077 0078 0079 007A 007B 007C 007D 007E 007F
+20AC 0000 201A 0000 201E 2026 2020 2021 0000 2030 0000 2039 0000 0000 0000 0000
+0000 2018 2019 201C 201D 2022 2013 2014 0000 0000 0000 203A 0000 0000 0000 0000
+00A0 00A1 00A2 00A3 00A4 00A5 00A6 00A7 00A8 00A9 00AA 00AB 00AC 00AD 00AE 00AF
+00B0 00B1 00B2 00B3 00B4 00B5 00B6 00B7 00B8 00B9 00BA 00BB 00BC 00BD 00BE 00BF
+10D0 10D1 10D2 10D3 10D4 10D5 10D6 10F1 10D7 10D8 10D9 10DA 10DB 10DC 10F2 10DD
+10DE 10DF 10E0 10E1 10E2 10F3 10E3 10E4 10E5 10E6 10E7 10E8 10E9 10EA 10EB 10EC
+10ED 10EE 10F4 10EF 10F0 10F5 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
+0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 2116 0000 0000
+</map>
+</unicode>
+
+
+<collation name="geostd8_general_ci">
+<map>
+ 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F
+ 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F
+ 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F
+ 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 5B 5C 5D 5E 5F
+ 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F
+ 50 51 52 53 54 55 56 57 58 59 5A 7B 7C 7D 7E 7F
+ 80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
+ 90 91 92 93 94 95 96 97 98 99 9A 9B 9C 9D 9E 9F
+ A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 AA AB AC AD AE AF
+ B0 B1 B2 B3 B4 B5 B6 B7 B8 B9 BA BB BC BD BE BF
+ C0 C1 C2 C3 C4 C5 C6 C7 C8 C9 CA CB CC CD CE CF
+ D0 D1 D2 D3 D4 D5 D6 D7 D8 D9 DA DB DC DD DE DF
+ E0 E1 E2 E3 E4 E5 E6 E7 E8 E9 EA EB EC ED EE EF
+ F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
+</map>
+</collation>
+
+<collation name="geostd8_bin" flag="binary"/>
+
+</charset>
+
+</charsets>
diff --git a/sql/share/czech/errmsg.txt b/sql/share/czech/errmsg.txt
index b47258fd07b..2ff51418d14 100644
--- a/sql/share/czech/errmsg.txt
+++ b/sql/share/czech/errmsg.txt
@@ -54,8 +54,8 @@ v/*
"M-Bálo prostoru/pamìti pro thread",
"Nemohu zjistit jm-Béno stroje pro Va¹i adresu",
"Chyba p-Bøi ustavování spojení",
-"P-Bøístup pro u¾ivatele '%-.32s@%-.64s' k databázi '%-.64s' není povolen",
-"P-Bøístup pro u¾ivatele '%-.32s@%-.64s' (s heslem %s)",
+"P-Bøístup pro u¾ivatele '%-.32s'@'%-.64s' k databázi '%-.64s' není povolen",
+"P-Bøístup pro u¾ivatele '%-.32s'@'%-.64s' (s heslem %s)",
"Nebyla vybr-Bána ¾ádná databáze",
"Nezn-Bámý pøíkaz",
"Sloupec '%-.64s' nem-Bù¾e být null",
@@ -152,8 +152,8 @@ v/*
"Regul-Bární výraz vrátil chybu '%-.64s'",
"Pokud nen-Bí ¾ádná GROUP BY klauzule, není dovoleno souèasné pou¾ití GROUP polo¾ek (MIN(),MAX(),COUNT()...) s ne GROUP polo¾kami",
"Neexistuje odpov-Bídající grant pro u¾ivatele '%-.32s' na stroji '%-.64s'",
-"%-.16s p-Bøíkaz nepøístupný pro u¾ivatele: '%-.32s@%-.64s' pro tabulku '%-.64s'",
-"%-.16s p-Bøíkaz nepøístupný pro u¾ivatele: '%-.32s@%-.64s' pro sloupec '%-.64s' v tabulce '%-.64s'",
+"%-.16s p-Bøíkaz nepøístupný pro u¾ivatele: '%-.32s'@'%-.64s' pro tabulku '%-.64s'",
+"%-.16s p-Bøíkaz nepøístupný pro u¾ivatele: '%-.32s'@'%-.64s' pro sloupec '%-.64s' v tabulce '%-.64s'",
"Neplatn-Bý pøíkaz GRANT/REVOKE. Prosím, pøeètìte si v manuálu, jaká privilegia je mo¾né pou¾ít.",
"Argument p-Bøíkazu GRANT u¾ivatel nebo stroj je pøíli¹ dlouhý",
"Tabulka '%-.64s.%s' neexistuje",
@@ -221,7 +221,7 @@ v/*
"DROP DATABASE not allowed while thread is holding global read lock",
"CREATE DATABASE not allowed while thread is holding global read lock",
"Wrong arguments to %s",
-"%-.32s@%-.64s is not allowed to create new users",
+"'%-.32s'@'%-.64s' is not allowed to create new users",
"Incorrect table definition; all MERGE tables must be in the same database",
"Deadlock found when trying to get lock; Try restarting transaction",
"The used table type doesn't support FULLTEXT indexes",
@@ -247,6 +247,7 @@ v/*
"Wrong usage/placement of '%s'",
"This version of MySQL doesn't yet support '%s'",
"Got fatal error %d: '%-.128s' from master when reading data from binary log",
+"Slave SQL thread ignored the query because of replicate-*-table rules",
"Wrong foreign key definition for '%-.64s': %s",
"Key reference and table reference doesn't match",
"Cardinality error (more/less than %d columns)",
@@ -276,4 +277,5 @@ v/*
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
+"Unknown collation: '%-.64s'",
"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
diff --git a/sql/share/danish/errmsg.txt b/sql/share/danish/errmsg.txt
index 56b36b98c30..cd47f4098e9 100644
--- a/sql/share/danish/errmsg.txt
+++ b/sql/share/danish/errmsg.txt
@@ -48,8 +48,8 @@
"Udgået for tråde/hukommelse",
"Kan ikke få værtsnavn for din adresse",
"Forkert håndtryk (handshake)",
-"Adgang nægtet bruger: '%-.32s@%-.64s' til databasen '%-.64s'",
-"Adgang nægtet bruger: '%-.32s@%-.64s' (Bruger adgangskode: %s)",
+"Adgang nægtet bruger: '%-.32s'@'%-.64s' til databasen '%-.64s'",
+"Adgang nægtet bruger: '%-.32s'@'%-.64s' (Bruger adgangskode: %s)",
"Ingen database valgt",
"Ukendt kommando",
"Kolonne '%-.64s' kan ikke være NULL",
@@ -146,8 +146,8 @@
"Fik fejl '%-.64s' fra regexp",
"Sammenblanding af GROUP kolonner (MIN(),MAX(),COUNT()...) uden GROUP kolonner er ikke tilladt, hvis der ikke er noget GROUP BY prædikat",
"Denne tilladelse findes ikke for brugeren '%-.32s' på vært '%-.64s'",
-"%-.16s-kommandoen er ikke tilladt for brugeren '%-.32s@%-.64s' for tabellen '%-.64s'",
-"%-.16s-kommandoen er ikke tilladt for brugeren '%-.32s@%-.64s' for kolonne '%-.64s' in tabellen '%-.64s'",
+"%-.16s-kommandoen er ikke tilladt for brugeren '%-.32s'@'%-.64s' for tabellen '%-.64s'",
+"%-.16s-kommandoen er ikke tilladt for brugeren '%-.32s'@'%-.64s' for kolonne '%-.64s' in tabellen '%-.64s'",
"Forkert GRANT/REVOKE kommando. Se i brugervejledningen hvilke privilegier der kan specificeres.",
"Værts- eller brugernavn for langt til GRANT",
"Tabellen '%-.64s.%-.64s' eksisterer ikke",
@@ -215,7 +215,7 @@
"DROP DATABASE er ikke tilladt mens en tråd holder på globalt read lock",
"CREATE DATABASE er ikke tilladt mens en tråd holder på globalt read lock",
"Wrong arguments to %s",
-"%-.32s@%-.64s is not allowed to create new users",
+"'%-.32s'@'%-.64s' is not allowed to create new users",
"Incorrect table definition; all MERGE tables must be in the same database",
"Deadlock found when trying to get lock; Try restarting transaction",
"The used table type doesn't support FULLTEXT indexes",
@@ -241,6 +241,7 @@
"Wrong usage/placement of '%s'",
"This version of MySQL doesn't yet support '%s'",
"Got fatal error %d: '%-.128s' from master when reading data from binary log",
+"Slave SQL thread ignored the query because of replicate-*-table rules",
"Wrong foreign key definition for '%-.64s': %s",
"Key reference and table reference doesn't match",
"Cardinality error (more/less than %d columns)",
@@ -270,4 +271,5 @@
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
+"Unknown collation: '%-.64s'",
"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
diff --git a/sql/share/dutch/errmsg.txt b/sql/share/dutch/errmsg.txt
index 80d931b4ab7..406f2dd1cdd 100644
--- a/sql/share/dutch/errmsg.txt
+++ b/sql/share/dutch/errmsg.txt
@@ -56,8 +56,8 @@
"Geen thread geheugen meer; controleer of mysqld of andere processen al het beschikbare geheugen gebruikt. Zo niet, dan moet u wellicht 'ulimit' gebruiken om mysqld toe te laten meer geheugen te benutten, of u kunt extra swap ruimte toevoegen",
"Kan de hostname niet krijgen van uw adres",
"Verkeerde handshake",
-"Toegang geweigerd voor gebruiker: '%-.32s@%-.64s' naar database '%-.64s'",
-"Toegang geweigerd voor gebruiker: '%-.32s@%-.64s' (Wachtwoord gebruikt: %s)",
+"Toegang geweigerd voor gebruiker: '%-.32s'@'%-.64s' naar database '%-.64s'",
+"Toegang geweigerd voor gebruiker: '%-.32s'@'%-.64s' (Wachtwoord gebruikt: %s)",
"Geen database geselecteerd",
"Onbekend commando",
"Kolom '%-.64s' kan niet null zijn",
@@ -154,8 +154,8 @@
"Fout '%-.64s' ontvangen van regexp",
"Het mixen van GROUP kolommen (MIN(),MAX(),COUNT()...) met no-GROUP kolommen is foutief indien er geen GROUP BY clausule is",
"Deze toegang (GRANT) is niet toegekend voor gebruiker '%-.32s' op host '%-.64s'",
-"%-.16s commando geweigerd voor gebruiker: '%-.32s@%-.64s' voor tabel '%-.64s'",
-"%-.16s commando geweigerd voor gebruiker: '%-.32s@%-.64s' voor kolom '%-.64s' in tabel '%-.64s'",
+"%-.16s commando geweigerd voor gebruiker: '%-.32s'@'%-.64s' voor tabel '%-.64s'",
+"%-.16s commando geweigerd voor gebruiker: '%-.32s'@'%-.64s' voor kolom '%-.64s' in tabel '%-.64s'",
"Foutief GRANT/REVOKE commando. Raadpleeg de handleiding welke priveleges gebruikt kunnen worden.",
"De host of gebruiker parameter voor GRANT is te lang",
"Tabel '%-.64s.%s' bestaat niet",
@@ -223,7 +223,7 @@
"DROP DATABASE niet toegestaan terwijl thread een globale 'read lock' bezit",
"CREATE DATABASE niet toegestaan terwijl thread een globale 'read lock' bezit",
"Foutieve parameters voor %s",
-"%-.32s@%-.64s mag geen nieuwe gebruikers creeren",
+"'%-.32s'@'%-.64s' mag geen nieuwe gebruikers creeren",
"Incorrecte tabel definitie; alle MERGE tabellen moeten tot dezelfde database behoren",
"Deadlock gevonden tijdens lock-aanvraag poging; Probeer herstart van de transactie",
"Het gebruikte tabel type ondersteund geen FULLTEXT indexen",
@@ -249,6 +249,7 @@
"Foutieve toepassing/plaatsing van '%s'",
"Deze versie van MySQL ondersteunt nog geen '%s'",
"Kreeg fatale fout %d: '%-.128s' van master tijdens lezen van data uit binaire log",
+"Slave SQL thread ignored the query because of replicate-*-table rules",
"Wrong foreign key definition for '%-.64s': %s",
"Key reference and table reference doesn't match",
"Cardinality error (more/less than %d columns)",
@@ -278,4 +279,5 @@
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
+"Unknown collation: '%-.64s'",
"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
diff --git a/sql/share/english/errmsg.txt b/sql/share/english/errmsg.txt
index 66052ff6c9a..5e938074f32 100644
--- a/sql/share/english/errmsg.txt
+++ b/sql/share/english/errmsg.txt
@@ -45,8 +45,8 @@
"Out of memory; Check if mysqld or some other process uses all available memory. If not you may have to use 'ulimit' to allow mysqld to use more memory or you can add more swap space",
"Can't get hostname for your address",
"Bad handshake",
-"Access denied for user: '%-.32s@%-.64s' to database '%-.64s'",
-"Access denied for user: '%-.32s@%-.64s' (Using password: %s)",
+"Access denied for user: '%-.32s'@'%-.64s' to database '%-.64s'",
+"Access denied for user: '%-.32s'@'%-.64s' (Using password: %s)",
"No Database Selected",
"Unknown command",
"Column '%-.64s' cannot be null",
@@ -119,7 +119,7 @@
"Unknown character set: '%-.64s'",
"Too many tables. MySQL can only use %d tables in a join",
"Too many columns",
-"Too big row size. The maximum row size, not counting BLOBs, is %d. You have to change some fields to TEXTs or BLOBs",
+"Too big row size. The maximum row size for the used table type, not counting BLOBs, is %ld. You have to change some fields to TEXT or BLOBs",
"Thread stack overrun: Used: %ld of a %ld stack. Use 'mysqld -O thread_stack=#' to specify a bigger stack if needed",
"Cross dependency found in OUTER JOIN. Examine your ON conditions",
"Column '%-.64s' is used with UNIQUE or INDEX but is not defined as NOT NULL",
@@ -143,8 +143,8 @@
"Got error '%-.64s' from regexp",
"Mixing of GROUP columns (MIN(),MAX(),COUNT()...) with no GROUP columns is illegal if there is no GROUP BY clause",
"There is no such grant defined for user '%-.32s' on host '%-.64s'",
-"%-.16s command denied to user: '%-.32s@%-.64s' for table '%-.64s'",
-"%-.16s command denied to user: '%-.32s@%-.64s' for column '%-.64s' in table '%-.64s'",
+"%-.16s command denied to user: '%-.32s'@'%-.64s' for table '%-.64s'",
+"%-.16s command denied to user: '%-.32s'@'%-.64s' for column '%-.64s' in table '%-.64s'",
"Illegal GRANT/REVOKE command. Please consult the manual which privileges can be used",
"The host or user argument to GRANT is too long",
"Table '%-.64s.%-.64s' doesn't exist",
@@ -212,7 +212,7 @@
"DROP DATABASE not allowed while thread is holding global read lock",
"CREATE DATABASE not allowed while thread is holding global read lock",
"Wrong arguments to %s",
-"%-.32s@%-.64s is not allowed to create new users",
+"'%-.32s'@'%-.64s' is not allowed to create new users",
"Incorrect table definition; all MERGE tables must be in the same database",
"Deadlock found when trying to get lock; Try restarting transaction",
"The used table type doesn't support FULLTEXT indexes",
@@ -238,6 +238,7 @@
"Wrong usage/placement of '%s'",
"This version of MySQL doesn't yet support '%s'",
"Got fatal error %d: '%-.128s' from master when reading data from binary log",
+"Slave SQL thread ignored the query because of replicate-*-table rules",
"Wrong foreign key definition for '%-.64s': %s",
"Key reference and table reference doesn't match",
"Cardinality error (more/less than %d columns)",
@@ -272,4 +273,5 @@
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
+"Unknown collation: '%-.64s'",
"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
diff --git a/sql/share/estonian/errmsg.txt b/sql/share/estonian/errmsg.txt
index 0d13c6fe237..c1d7762fef8 100644
--- a/sql/share/estonian/errmsg.txt
+++ b/sql/share/estonian/errmsg.txt
@@ -50,8 +50,8 @@
"Mälu sai otsa. Võimalik, et aitab swap-i lisamine või käsu 'ulimit' abil MySQL-le rohkema mälu kasutamise lubamine",
"Ei suuda lahendada IP aadressi masina nimeks",
"Väär handshake",
-"Ligipääs keelatud kasutajale '%-.32s@%-.64s' andmebaasile '%-.64s'",
-"Ligipääs keelatud kasutajale '%-.32s@%-.64s' (kasutab parooli: %s)",
+"Ligipääs keelatud kasutajale '%-.32s'@'%-.64s' andmebaasile '%-.64s'",
+"Ligipääs keelatud kasutajale '%-.32s'@'%-.64s' (kasutab parooli: %s)",
"Andmebaasi ei ole valitud",
"Tundmatu käsk",
"Tulp '%-.64s' ei saa omada nullväärtust",
@@ -148,8 +148,8 @@
"regexp tagastas vea '%-.64s'",
"GROUP tulpade (MIN(),MAX(),COUNT()...) kooskasutamine tavaliste tulpadega ilma GROUP BY klauslita ei ole lubatud",
"Sellist õigust ei ole defineeritud kasutajale '%-.32s' masinast '%-.64s'",
-"%-.16s käsk ei ole lubatud kasutajale '%-.32s@%-.64s' tabelis '%-.64s'",
-"%-.16s käsk ei ole lubatud kasutajale '%-.32s@%-.64s' tulbale '%-.64s' tabelis '%-.64s'",
+"%-.16s käsk ei ole lubatud kasutajale '%-.32s'@'%-.64s' tabelis '%-.64s'",
+"%-.16s käsk ei ole lubatud kasutajale '%-.32s'@'%-.64s' tulbale '%-.64s' tabelis '%-.64s'",
"Vigane GRANT/REVOKE käsk. Tutvu kasutajajuhendiga",
"Masina või kasutaja nimi GRANT lauses on liiga pikk",
"Tabelit '%-.64s.%-.64s' ei eksisteeri",
@@ -217,7 +217,7 @@
"DROP DATABASE ei ole lubatud kui lõim omab globaalset READ lukku",
"CREATE DATABASE ei ole lubatud kui lõim omab globaalset READ lukku",
"Vigased parameetrid %s-le",
-"Kasutajal %-.32s@%-.64s ei ole lubatud luua uusi kasutajaid",
+"Kasutajal '%-.32s'@'%-.64s' ei ole lubatud luua uusi kasutajaid",
"Vigane tabelimääratlus; kõik MERGE tabeli liikmed peavad asuma samas andmebaasis",
"Lukustamisel tekkis tupik (deadlock); alusta transaktsiooni otsast",
"Antud tabelitüüp ei toeta FULLTEXT indekseid",
@@ -243,6 +243,7 @@
"Wrong usage/placement of '%s'",
"This version of MySQL doesn't yet support '%s'",
"Got fatal error %d: '%-.128s' from master when reading data from binary log",
+"Slave SQL thread ignored the query because of replicate-*-table rules",
"Wrong foreign key definition for '%-.64s': %s",
"Key reference and table reference doesn't match",
"Cardinality error (more/less than %d columns)",
@@ -272,4 +273,5 @@
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
+"Unknown collation: '%-.64s'",
"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
diff --git a/sql/share/french/errmsg.txt b/sql/share/french/errmsg.txt
index 8616f0ed485..2e52ec04030 100644
--- a/sql/share/french/errmsg.txt
+++ b/sql/share/french/errmsg.txt
@@ -45,8 +45,8 @@
"Manque de 'threads'/mémoire",
"Ne peut obtenir de hostname pour votre adresse",
"Mauvais 'handshake'",
-"Accès refusé pour l'utilisateur: '%-.32s@%-.64s'. Base '%-.64s'",
-"Accès refusé pour l'utilisateur: '%-.32s@%-.64s' (mot de passe: %s)",
+"Accès refusé pour l'utilisateur: '%-.32s'@'@%-.64s'. Base '%-.64s'",
+"Accès refusé pour l'utilisateur: '%-.32s'@'@%-.64s' (mot de passe: %s)",
"Aucune base n'a été sélectionnée",
"Commande inconnue",
"Le champ '%-.64s' ne peut être vide (null)",
@@ -143,8 +143,8 @@
"Erreur '%-.64s' provenant de regexp",
"Mélanger les colonnes GROUP (MIN(),MAX(),COUNT()...) avec des colonnes normales est interdit s'il n'y a pas de clause GROUP BY",
"Un tel droit n'est pas défini pour l'utilisateur '%-.32s' sur l'hôte '%-.64s'",
-"La commande '%-.16s' est interdite à l'utilisateur: '%-.32s@%-.64s' sur la table '%-.64s'",
-"La commande '%-.16s' est interdite à l'utilisateur: '%-.32s@%-.64s' sur la colonne '%-.64s' de la table '%-.64s'",
+"La commande '%-.16s' est interdite à l'utilisateur: '%-.32s'@'@%-.64s' sur la table '%-.64s'",
+"La commande '%-.16s' est interdite à l'utilisateur: '%-.32s'@'@%-.64s' sur la colonne '%-.64s' de la table '%-.64s'",
"Commande GRANT/REVOKE incorrecte. Consultez le manuel.",
"L'hôte ou l'utilisateur donné en argument à GRANT est trop long",
"La table '%-.64s.%s' n'existe pas",
@@ -212,7 +212,7 @@
"DROP DATABASE n'est pas autorisée pendant qu'une tâche possède un verrou global en lecture",
"CREATE DATABASE n'est pas autorisée pendant qu'une tâche possède un verrou global en lecture",
"Mauvais arguments à %s",
-"%-.32s@%-.64s n'est pas autorisé à créer de nouveaux utilisateurs",
+"'%-.32s'@'%-.64s' n'est pas autorisé à créer de nouveaux utilisateurs",
"Définition de table incorrecte; toutes les tables MERGE doivent être dans la même base de donnée",
"Deadlock découvert en essayant d'obtenir les verrous : essayez de redémarrer la transaction",
"Le type de table utilisé ne supporte pas les index FULLTEXT",
@@ -238,6 +238,7 @@
"Wrong usage/placement of '%s'",
"This version of MySQL doesn't yet support '%s'",
"Got fatal error %d: '%-.128s' from master when reading data from binary log",
+"Slave SQL thread ignored the query because of replicate-*-table rules",
"Wrong foreign key definition for '%-.64s': %s",
"Key reference and table reference doesn't match",
"Cardinality error (more/less than %d columns)",
@@ -267,4 +268,5 @@
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
+"Unknown collation: '%-.64s'",
"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
diff --git a/sql/share/german/errmsg.txt b/sql/share/german/errmsg.txt
index 1850dd5e95f..6910894b095 100644
--- a/sql/share/german/errmsg.txt
+++ b/sql/share/german/errmsg.txt
@@ -54,8 +54,8 @@
"Zuwenig Speicher.",
"Kann Hostname für diese Adresse nicht erhalten.",
"Schlechter Handshake.",
-"Keine Zugriffsberechtigung für Benutzer: '%-.32s@%-.64s' für Datenbank '%-.64s'.",
-"Keine Zugriffsberechtigung für Benutzer: '%-.32s@%-.64s'. (Verwendetes Passwort: %-.64s)",
+"Keine Zugriffsberechtigung für Benutzer: '%-.32s'@'%-.64s' für Datenbank '%-.64s'.",
+"Keine Zugriffsberechtigung für Benutzer: '%-.32s'@'%-.64s'. (Verwendetes Passwort: %-.64s)",
"Keine Datenbank ausgewählt.",
"Unbekannter Befehl.",
"Feld '%-.64s' kann nicht NULL sein.",
@@ -152,8 +152,8 @@
"Fehler '%-.64s' von regexp",
"Das Vermischen von GROUP Spalten (MIN(),MAX(),COUNT()...) mit Nicht-GROUP Spalten ist nicht erlaubt, sofern keine GROUP BY Klausel vorhanden ist.",
"Keine solche Berechtigung für User '%-.32s' auf Host '%-.64s'",
-"%-.16s Befehl nicht erlaubt für User: '%-.32s@%-.64s' für Tabelle '%-.64s'",
-"%-.16s Befehl nicht erlaubt für User: '%-.32s@%-.64s' in Spalte '%-.64s' in Tabelle '%-.64s'",
+"%-.16s Befehl nicht erlaubt für User: '%-.32s'@'%-.64s' für Tabelle '%-.64s'",
+"%-.16s Befehl nicht erlaubt für User: '%-.32s'@'%-.64s' in Spalte '%-.64s' in Tabelle '%-.64s'",
"Unzulässiger GRANT/REVOKE Befehl. Weiteres zum Thema Berechtigungen im Manual.",
"Das Host oder User Argument für GRANT ist zu lang",
"Tabelle '%-.64s.%-.64s' existiert nicht",
@@ -221,7 +221,7 @@
"Solange ein globaler Read LOCK gesetzt ist, ist DROP DATABASE nicht zulässig.",
"Solange ein globaler Read LOCK gesetzt ist, ist CREATE DATABASE nicht zulässig.",
"Falsche Argumente für %s",
-"%-.32s@%-.64s is nicht berechtigt neue Benutzer hinzuzufügen.",
+"'%-.32s'@'%-.64s' is nicht berechtigt neue Benutzer hinzuzufügen.",
"Falsche Tabellendefinition; sämtliche MERGE-Tabellen müssen in derselben Datenbank sein.",
"Beim Versuch einen Lock anzufordern ist ein Deadlock aufgetreten. Es wird versucht die Transaktion erneut zu starten.",
"Der verwendete Tabellentyp unterstützt keinen FULLTEXT-Index.",
@@ -247,6 +247,7 @@
"Falsche Verwendung oder Platzierung von '%s'",
"Diese MySQL-Version unterstützt momentan nicht '%s'.",
"Schwerer Fehler %d: '%-.128s vom Master beim Lesen des Binary Logs.",
+"Slave SQL thread ignored the query because of replicate-*-table rules",
"Falsche Foreign-Key Definition für '%-64s': %s",
"Schlüssel- und Tabellenreferenz passen nicht zueinander.",
"Kardinalitäts-Fehler (mehr/oder weniger als %d Spalten).",
@@ -276,4 +277,5 @@
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
+"Unknown collation: '%-.64s'",
"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
diff --git a/sql/share/greek/errmsg.txt b/sql/share/greek/errmsg.txt
index d1a69677c81..f52987e56cf 100644
--- a/sql/share/greek/errmsg.txt
+++ b/sql/share/greek/errmsg.txt
@@ -45,8 +45,8 @@
"Ðñüâëçìá ìå ôç äéáèÝóéìç ìíÞìç (Out of thread space/memory)",
"Äåí Ýãéíå ãíùóôü ôï hostname ãéá ôçí address óáò",
"Ç áíáãíþñéóç (handshake) äåí Ýãéíå óùóôÜ",
-"Äåí åðéôÝñåôáé ç ðñüóâáóç óôï ÷ñÞóôç: '%-.32s@%-.64s' óôç âÜóç äåäïìÝíùí '%-.64s'",
-"Äåí åðéôÝñåôáé ç ðñüóâáóç óôï ÷ñÞóôç: '%-.32s@%-.64s' (÷ñÞóç password: %s)",
+"Äåí åðéôÝñåôáé ç ðñüóâáóç óôï ÷ñÞóôç: '%-.32s'@'%-.64s' óôç âÜóç äåäïìÝíùí '%-.64s'",
+"Äåí åðéôÝñåôáé ç ðñüóâáóç óôï ÷ñÞóôç: '%-.32s'@'%-.64s' (÷ñÞóç password: %s)",
"Äåí åðéëÝ÷èçêå âÜóç äåäïìÝíùí",
"Áãíùóôç åíôïëÞ",
"Ôï ðåäßï '%-.64s' äåí ìðïñåß íá åßíáé êåíü (null)",
@@ -143,8 +143,8 @@
"Got error '%-.64s' from regexp",
"Mixing of GROUP columns (MIN(),MAX(),COUNT()...) with no GROUP columns is illegal if there is no GROUP BY clause",
"There is no such grant defined for user '%-.32s' on host '%-.64s'",
-"%-.16s command denied to user: '%-.32s@%-.64s' for table '%-.64s'",
-"%-.16s command denied to user: '%-.32s@%-.64s' for column '%-.64s' in table '%-.64s'",
+"%-.16s command denied to user: '%-.32s'@'%-.64s' for table '%-.64s'",
+"%-.16s command denied to user: '%-.32s'@'%-.64s' for column '%-.64s' in table '%-.64s'",
"Illegal GRANT/REVOKE command. Please consult the manual which privileges can be used.",
"The host or user argument to GRANT is too long",
"Table '%-.64s.%-.64s' doesn't exist",
@@ -212,7 +212,7 @@
"DROP DATABASE not allowed while thread is holding global read lock",
"CREATE DATABASE not allowed while thread is holding global read lock",
"Wrong arguments to %s",
-"%-.32s@%-.64s is not allowed to create new users",
+"'%-.32s'@'%-.64s' is not allowed to create new users",
"Incorrect table definition; all MERGE tables must be in the same database",
"Deadlock found when trying to get lock; Try restarting transaction",
"The used table type doesn't support FULLTEXT indexes",
@@ -238,6 +238,7 @@
"Wrong usage/placement of '%s'",
"This version of MySQL doesn't yet support '%s'",
"Got fatal error %d: '%-.128s' from master when reading data from binary log",
+"Slave SQL thread ignored the query because of replicate-*-table rules",
"Wrong foreign key definition for '%-.64s': %s",
"Key reference and table reference doesn't match",
"Cardinality error (more/less than %d columns)",
@@ -267,4 +268,5 @@
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
+"Unknown collation: '%-.64s'",
"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
diff --git a/sql/share/hungarian/errmsg.txt b/sql/share/hungarian/errmsg.txt
index dd1c6c6eba7..3fbec6f9fc7 100644
--- a/sql/share/hungarian/errmsg.txt
+++ b/sql/share/hungarian/errmsg.txt
@@ -47,8 +47,8 @@
"Elfogyott a thread-memoria",
"A gepnev nem allapithato meg a cimbol",
"A kapcsolatfelvetel nem sikerult (Bad handshake)",
-"A(z) '%-.32s@%-.64s' felhasznalo szamara tiltott eleres az '%-.64s' adabazishoz.",
-"A(z) '%-.32s@%-.64s' felhasznalo szamara tiltott eleres. (Hasznalja a jelszot: %s)",
+"A(z) '%-.32s'@'%-.64s' felhasznalo szamara tiltott eleres az '%-.64s' adabazishoz.",
+"A(z) '%-.32s'@'%-.64s' felhasznalo szamara tiltott eleres. (Hasznalja a jelszot: %s)",
"Nincs kivalasztott adatbazis",
"Ervenytelen parancs",
"A(z) '%-.64s' oszlop erteke nem lehet nulla",
@@ -145,8 +145,8 @@
"'%-.64s' hiba a regularis kifejezes hasznalata soran (regexp)",
"A GROUP mezok (MIN(),MAX(),COUNT()...) kevert hasznalata nem lehetseges GROUP BY hivatkozas nelkul",
"A '%-.32s' felhasznalonak nincs ilyen joga a '%-.64s' host-on",
-"%-.16s parancs a '%-.32s@%-.64s' felhasznalo szamara nem engedelyezett a '%-.64s' tablaban",
-"%-.16s parancs a '%-.32s@%-.64s' felhasznalo szamara nem engedelyezett a '%-.64s' mezo eseten a '%-.64s' tablaban",
+"%-.16s parancs a '%-.32s'@'%-.64s' felhasznalo szamara nem engedelyezett a '%-.64s' tablaban",
+"%-.16s parancs a '%-.32s'@'%-.64s' felhasznalo szamara nem engedelyezett a '%-.64s' mezo eseten a '%-.64s' tablaban",
"Ervenytelen GRANT/REVOKE parancs. Kerem, nezze meg a kezikonyvben, milyen jogok lehetsegesek",
"A host vagy felhasznalo argumentuma tul hosszu a GRANT parancsban",
"A '%-.64s.%s' tabla nem letezik",
@@ -214,7 +214,7 @@
"DROP DATABASE not allowed while thread is holding global read lock",
"CREATE DATABASE not allowed while thread is holding global read lock",
"Wrong arguments to %s",
-"%-.32s@%-.64s is not allowed to create new users",
+"'%-.32s'@'%-.64s' is not allowed to create new users",
"Incorrect table definition; all MERGE tables must be in the same database",
"Deadlock found when trying to get lock; Try restarting transaction",
"The used table type doesn't support FULLTEXT indexes",
@@ -240,6 +240,7 @@
"Wrong usage/placement of '%s'",
"This version of MySQL doesn't yet support '%s'",
"Got fatal error %d: '%-.128s' from master when reading data from binary log",
+"Slave SQL thread ignored the query because of replicate-*-table rules",
"Wrong foreign key definition for '%-.64s': %s",
"Key reference and table reference doesn't match",
"Cardinality error (more/less than %d columns)",
@@ -269,4 +270,5 @@
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
+"Unknown collation: '%-.64s'",
"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
diff --git a/sql/share/italian/errmsg.txt b/sql/share/italian/errmsg.txt
index 69b605e2185..7ad72412035 100644
--- a/sql/share/italian/errmsg.txt
+++ b/sql/share/italian/errmsg.txt
@@ -45,8 +45,8 @@
"Fine dello spazio/memoria per i thread",
"Impossibile risalire al nome dell'host dall'indirizzo (risoluzione inversa)",
"Negoziazione impossibile",
-"Accesso non consentito per l'utente: '%-.32s@%-.64s' al database '%-.64s'",
-"Accesso non consentito per l'utente: '%-.32s@%-.64s' (Password: %s)",
+"Accesso non consentito per l'utente: '%-.32s'@'%-.64s' al database '%-.64s'",
+"Accesso non consentito per l'utente: '%-.32s'@'%-.64s' (Password: %s)",
"Nessun database selezionato",
"Comando sconosciuto",
"La colonna '%-.64s' non puo` essere nulla",
@@ -143,8 +143,8 @@
"Errore '%-.64s' da regexp",
"Il mescolare funzioni di aggregazione (MIN(),MAX(),COUNT()...) e non e` illegale se non c'e` una clausula GROUP BY",
"GRANT non definita per l'utente '%-.32s' dalla macchina '%-.64s'",
-"Comando %-.16s negato per l'utente: '%-.32s@%-.64s' sulla tabella '%-.64s'",
-"Comando %-.16s negato per l'utente: '%-.32s@%-.64s' sulla colonna '%-.64s' della tabella '%-.64s'",
+"Comando %-.16s negato per l'utente: '%-.32s'@'%-.64s' sulla tabella '%-.64s'",
+"Comando %-.16s negato per l'utente: '%-.32s'@'%-.64s' sulla colonna '%-.64s' della tabella '%-.64s'",
"Comando GRANT/REVOKE illegale. Prego consultare il manuale per sapere quali privilegi possono essere usati.",
"L'argomento host o utente per la GRANT e` troppo lungo",
"La tabella '%-.64s.%s' non esiste",
@@ -212,7 +212,7 @@
"DROP DATABASE non e' permesso mentre il thread ha un lock globale di lettura",
"CREATE DATABASE non e' permesso mentre il thread ha un lock globale di lettura",
"Argomenti errati a %s",
-"A %-.32s@%-.64s non e' permesso creare nuovi utenti",
+"A '%-.32s'@'%-.64s' non e' permesso creare nuovi utenti",
"Definizione della tabella errata; tutte le tabelle di tipo MERGE devono essere nello stesso database",
"Trovato deadlock durante il lock; Provare a far ripartire la transazione",
"La tabella usata non supporta gli indici FULLTEXT",
@@ -238,6 +238,7 @@
"Uso/posizione di '%s' sbagliato",
"Questa versione di MySQL non supporta ancora '%s'",
"Errore fatale %d: '%-.128s' dal master leggendo i dati dal log binario",
+"Slave SQL thread ignored the query because of replicate-*-table rules",
"Wrong foreign key definition for '%-.64s': %s",
"Key reference and table reference doesn't match",
"Cardinality error (more/less than %d columns)",
@@ -267,4 +268,5 @@
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
+"Unknown collation: '%-.64s'",
"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
diff --git a/sql/share/japanese/errmsg.txt b/sql/share/japanese/errmsg.txt
index 10e295894e6..9609fa8d8a4 100644
--- a/sql/share/japanese/errmsg.txt
+++ b/sql/share/japanese/errmsg.txt
@@ -47,8 +47,8 @@
"Out of memory; mysqld ¤«¤½¤Î¾¤Î¥×¥í¥»¥¹¤¬¥á¥â¥ê¡¼¤òÁ´¤Æ»È¤Ã¤Æ¤¤¤ë¤«³Îǧ¤·¤Æ¤¯¤À¤µ¤¤. ¥á¥â¥ê¡¼¤ò»È¤¤ÀڤäƤ¤¤Ê¤¤¾ì¹ç¡¢'ulimit' ¤òÀßÄꤷ¤Æ mysqld ¤Î¥á¥â¥ê¡¼»ÈÍѸ³¦Î̤ò¿¤¯¤¹¤ë¤«¡¢swap space ¤òÁý¤ä¤·¤Æ¤ß¤Æ¤¯¤À¤µ¤¤",
"¤½¤Î address ¤Î hostname ¤¬°ú¤±¤Þ¤»¤ó.",
"Bad handshake",
-"¥æ¡¼¥¶¡¼ '%-.32s@%-.64s' ¤Î '%-.64s' ¥Ç¡¼¥¿¥Ù¡¼¥¹¤Ø¤Î¥¢¥¯¥»¥¹¤òµñÈݤ·¤Þ¤¹",
-"¥æ¡¼¥¶¡¼ '%-.32s@%-.64s' ¤òµñÈݤ·¤Þ¤¹.(Using password: %s)",
+"¥æ¡¼¥¶¡¼ '%-.32s'@'%-.64s' ¤Î '%-.64s' ¥Ç¡¼¥¿¥Ù¡¼¥¹¤Ø¤Î¥¢¥¯¥»¥¹¤òµñÈݤ·¤Þ¤¹",
+"¥æ¡¼¥¶¡¼ '%-.32s'@'%-.64s' ¤òµñÈݤ·¤Þ¤¹.(Using password: %s)",
"¥Ç¡¼¥¿¥Ù¡¼¥¹¤¬ÁªÂò¤µ¤ì¤Æ¤¤¤Þ¤»¤ó.",
"¤½¤Î¥³¥Þ¥ó¥É¤Ï²¿¡©",
"Column '%-.64s' ¤Ï null ¤Ë¤Ï¤Ç¤­¤Ê¤¤¤Î¤Ç¤¹",
@@ -145,8 +145,8 @@
"Got error '%-.64s' from regexp",
"Mixing of GROUP columns (MIN(),MAX(),COUNT()...) with no GROUP columns is illegal if there is no GROUP BY clause",
"¥æ¡¼¥¶¡¼ '%-.32s' (¥Û¥¹¥È '%-.64s' ¤Î¥æ¡¼¥¶¡¼) ¤Ïµö²Ä¤µ¤ì¤Æ¤¤¤Þ¤»¤ó",
-"¥³¥Þ¥ó¥É %-.16s ¤Ï ¥æ¡¼¥¶¡¼ '%-.32s@%-.64s' ,¥Æ¡¼¥Ö¥ë '%-.64s' ¤ËÂФ·¤Æµö²Ä¤µ¤ì¤Æ¤¤¤Þ¤»¤ó",
-"¥³¥Þ¥ó¥É %-.16s ¤Ï ¥æ¡¼¥¶¡¼ '%-.32s@%-.64s'\n ¥«¥é¥à '%-.64s' ¥Æ¡¼¥Ö¥ë '%-.64s' ¤ËÂФ·¤Æµö²Ä¤µ¤ì¤Æ¤¤¤Þ¤»¤ó",
+"¥³¥Þ¥ó¥É %-.16s ¤Ï ¥æ¡¼¥¶¡¼ '%-.32s'@'%-.64s' ,¥Æ¡¼¥Ö¥ë '%-.64s' ¤ËÂФ·¤Æµö²Ä¤µ¤ì¤Æ¤¤¤Þ¤»¤ó",
+"¥³¥Þ¥ó¥É %-.16s ¤Ï ¥æ¡¼¥¶¡¼ '%-.32s'@'%-.64s'\n ¥«¥é¥à '%-.64s' ¥Æ¡¼¥Ö¥ë '%-.64s' ¤ËÂФ·¤Æµö²Ä¤µ¤ì¤Æ¤¤¤Þ¤»¤ó",
"Illegal GRANT/REVOKE command. Please consult the manual which privleges can be used.",
"The host or user argument to GRANT is too long",
"Table '%-.64s.%s' doesn't exist",
@@ -214,7 +214,7 @@
"DROP DATABASE not allowed while thread is holding global read lock",
"CREATE DATABASE not allowed while thread is holding global read lock",
"Wrong arguments to %s",
-"%-.32s@%-.64s is not allowed to create new users",
+"'%-.32s'@'%-.64s' is not allowed to create new users",
"Incorrect table definition; all MERGE tables must be in the same database",
"Deadlock found when trying to get lock; Try restarting transaction",
"The used table type doesn't support FULLTEXT indexes",
@@ -240,6 +240,7 @@
"Wrong usage/placement of '%s'",
"This version of MySQL doesn't yet support '%s'",
"Got fatal error %d: '%-.128s' from master when reading data from binary log",
+"Slave SQL thread ignored the query because of replicate-*-table rules",
"Wrong foreign key definition for '%-.64s': %s",
"Key reference and table reference doesn't match",
"Cardinality error (more/less than %d columns)",
@@ -269,4 +270,5 @@
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
+"Unknown collation: '%-.64s'",
"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
diff --git a/sql/share/korean/errmsg.txt b/sql/share/korean/errmsg.txt
index 37182e3514c..aeb62784594 100644
--- a/sql/share/korean/errmsg.txt
+++ b/sql/share/korean/errmsg.txt
@@ -45,8 +45,8 @@
"Out of memory; mysqld³ª ¶Ç´Ù¸¥ ÇÁ·Î¼¼¼­¿¡¼­ »ç¿ë°¡´ÉÇÑ ¸Þ¸ð¸®¸¦ »ç¿ëÇÑÁö äũÇϽÿÀ. ¸¸¾à ±×·¸Áö ¾Ê´Ù¸é ulimit ¸í·ÉÀ» ÀÌ¿¿ëÇÏ¿© ´õ¸¹Àº ¸Þ¸ð¸®¸¦ »ç¿ëÇÒ ¼ö ÀÖµµ·Ï Çϰųª ½º¿Ò ½ºÆÐÀ̽º¸¦ Áõ°¡½ÃŰ½Ã¿À",
"´ç½ÅÀÇ ÄÄÇ»ÅÍÀÇ È£½ºÆ®À̸§À» ¾òÀ» ¼ö ¾øÀ¾´Ï´Ù.",
"Bad handshake",
-"'%-.32s@%-.64s' »ç¿ëÀÚ´Â '%-.64s' µ¥ÀÌŸº£À̽º¿¡ Á¢±ÙÀÌ °ÅºÎ µÇ¾ú½À´Ï´Ù.",
-"'%-.32s@%-.64s' »ç¿ëÀÚ´Â Á¢±ÙÀÌ °ÅºÎ µÇ¾ú½À´Ï´Ù. (Using password: %s)",
+"'%-.32s'@'%-.64s' »ç¿ëÀÚ´Â '%-.64s' µ¥ÀÌŸº£À̽º¿¡ Á¢±ÙÀÌ °ÅºÎ µÇ¾ú½À´Ï´Ù.",
+"'%-.32s'@'%-.64s' »ç¿ëÀÚ´Â Á¢±ÙÀÌ °ÅºÎ µÇ¾ú½À´Ï´Ù. (Using password: %s)",
"¼±ÅÃµÈ µ¥ÀÌŸº£À̽º°¡ ¾ø½À´Ï´Ù.",
"¸í·É¾î°¡ ¹ºÁö ¸ð¸£°Ú¾î¿ä...",
"Ä®·³ '%-.64s'´Â ³Î(Null)ÀÌ µÇ¸é ¾ÈµË´Ï´Ù. ",
@@ -143,8 +143,8 @@
"regexp¿¡¼­ '%-.64s'°¡ ³µ½À´Ï´Ù.",
"Mixing of GROUP Ä®·³s (MIN(),MAX(),COUNT()...) with no GROUP Ä®·³s is illegal if there is no GROUP BY clause",
"»ç¿ëÀÚ '%-.32s' (È£½ºÆ® '%-.64s')¸¦ À§ÇÏ¿© Á¤ÀÇµÈ ±×·± ½ÂÀÎÀº ¾ø½À´Ï´Ù.",
-"'%-.16s' ¸í·ÉÀº ´ÙÀ½ »ç¿ëÀÚ¿¡°Ô °ÅºÎµÇ¾ú½À´Ï´Ù. : '%-.32s@%-.64s' for Å×À̺í '%-.64s'",
-"'%-.16s' ¸í·ÉÀº ´ÙÀ½ »ç¿ëÀÚ¿¡°Ô °ÅºÎµÇ¾ú½À´Ï´Ù. : '%-.32s@%-.64s' for Ä®·³ '%-.64s' in Å×À̺í '%-.64s'",
+"'%-.16s' ¸í·ÉÀº ´ÙÀ½ »ç¿ëÀÚ¿¡°Ô °ÅºÎµÇ¾ú½À´Ï´Ù. : '%-.32s'@'%-.64s' for Å×À̺í '%-.64s'",
+"'%-.16s' ¸í·ÉÀº ´ÙÀ½ »ç¿ëÀÚ¿¡°Ô °ÅºÎµÇ¾ú½À´Ï´Ù. : '%-.32s'@'%-.64s' for Ä®·³ '%-.64s' in Å×À̺í '%-.64s'",
"À߸øµÈ GRANT/REVOKE ¸í·É. ¾î¶² ±Ç¸®¿Í ½ÂÀÎÀÌ »ç¿ëµÇ¾î Áú ¼ö ÀÖ´ÂÁö ¸Þ´º¾óÀ» º¸½Ã¿À.",
"½ÂÀÎ(GRANT)À» À§ÇÏ¿© »ç¿ëÇÑ »ç¿ëÀÚ³ª È£½ºÆ®ÀÇ °ªµéÀÌ ³Ê¹« ±é´Ï´Ù.",
"Å×À̺í '%-.64s.%s' ´Â Á¸ÀçÇÏÁö ¾Ê½À´Ï´Ù.",
@@ -212,7 +212,7 @@
"DROP DATABASE not allowed while thread is holding global read lock",
"CREATE DATABASE not allowed while thread is holding global read lock",
"Wrong arguments to %s",
-"%-.32s@%-.64s is not allowed to create new users",
+"'%-.32s'@'%-.64s' is not allowed to create new users",
"Incorrect table definition; all MERGE tables must be in the same database",
"Deadlock found when trying to get lock; Try restarting transaction",
"The used table type doesn't support FULLTEXT indexes",
@@ -238,6 +238,7 @@
"Wrong usage/placement of '%s'",
"This version of MySQL doesn't yet support '%s'",
"Got fatal error %d: '%-.128s' from master when reading data from binary log",
+"Slave SQL thread ignored the query because of replicate-*-table rules",
"Wrong foreign key definition for '%-.64s': %s",
"Key reference and table reference doesn't match",
"Cardinality error (more/less than %d columns)",
@@ -267,4 +268,5 @@
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
+"Unknown collation: '%-.64s'",
"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
diff --git a/sql/share/norwegian-ny/errmsg.txt b/sql/share/norwegian-ny/errmsg.txt
index faae05934ba..a79d20cc20e 100644
--- a/sql/share/norwegian-ny/errmsg.txt
+++ b/sql/share/norwegian-ny/errmsg.txt
@@ -47,8 +47,8 @@
"Tomt for tråd plass/minne",
"Kan ikkje få tak i vertsnavn for di adresse",
"Feil handtrykk (handshake)",
-"Tilgang ikkje tillate for brukar: '%-.32s@%-.64s' til databasen '%-.64s' nekta",
-"Tilgang ikke tillate for brukar: '%-.32s@%-.64s' (Brukar passord: %s)",
+"Tilgang ikkje tillate for brukar: '%-.32s'@'%-.64s' til databasen '%-.64s' nekta",
+"Tilgang ikke tillate for brukar: '%-.32s'@'%-.64s' (Brukar passord: %s)",
"Ingen database vald",
"Ukjent kommando",
"Kolonne '%-.64s' kan ikkje vere null",
@@ -145,8 +145,8 @@
"Got error '%-.64s' from regexp",
"Mixing of GROUP columns (MIN(),MAX(),COUNT()...) with no GROUP columns is illegal if there is no GROUP BY clause",
"There is no such grant defined for user '%-.32s' on host '%-.64s'",
-"%-.16s command denied to user: '%-.32s@%-.64s' for table '%-.64s'",
-"%-.16s command denied to user: '%-.32s@%-.64s' for column '%-.64s' in table '%-.64s'",
+"%-.16s command denied to user: '%-.32s'@'%-.64s' for table '%-.64s'",
+"%-.16s command denied to user: '%-.32s'@'%-.64s' for column '%-.64s' in table '%-.64s'",
"Illegal GRANT/REVOKE command. Please consult the manual which privleges can be used.",
"The host or user argument to GRANT is too long",
"Table '%-.64s.%s' doesn't exist",
@@ -214,7 +214,7 @@
"DROP DATABASE not allowed while thread is holding global read lock",
"CREATE DATABASE not allowed while thread is holding global read lock",
"Wrong arguments to %s",
-"%-.32s@%-.64s is not allowed to create new users",
+"'%-.32s'@'%-.64s' is not allowed to create new users",
"Incorrect table definition; all MERGE tables must be in the same database",
"Deadlock found when trying to get lock; Try restarting transaction",
"The used table type doesn't support FULLTEXT indexes",
@@ -240,6 +240,7 @@
"Wrong usage/placement of '%s'",
"This version of MySQL doesn't yet support '%s'",
"Got fatal error %d: '%-.128s' from master when reading data from binary log",
+"Slave SQL thread ignored the query because of replicate-*-table rules",
"Wrong foreign key definition for '%-.64s': %s",
"Key reference and table reference doesn't match",
"Cardinality error (more/less than %d columns)",
@@ -269,4 +270,5 @@
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
+"Unknown collation: '%-.64s'",
"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
diff --git a/sql/share/norwegian/errmsg.txt b/sql/share/norwegian/errmsg.txt
index f131ab0baef..b018313ea39 100644
--- a/sql/share/norwegian/errmsg.txt
+++ b/sql/share/norwegian/errmsg.txt
@@ -47,8 +47,8 @@
"Tomt for tråd plass/minne",
"Kan ikke få tak i vertsnavn for din adresse",
"Feil håndtrykk (handshake)",
-"Tilgang nektet for bruker: '%-.32s@%-.64s' til databasen '%-.64s' nektet",
-"Tilgang nektet for bruker: '%-.32s@%-.64s' (Bruker passord: %s)",
+"Tilgang nektet for bruker: '%-.32s'@'%-.64s' til databasen '%-.64s' nektet",
+"Tilgang nektet for bruker: '%-.32s'@'%-.64s' (Bruker passord: %s)",
"Ingen database valgt",
"Ukjent kommando",
"Kolonne '%-.64s' kan ikke vere null",
@@ -145,8 +145,8 @@
"Got error '%-.64s' from regexp",
"Mixing of GROUP columns (MIN(),MAX(),COUNT()...) with no GROUP columns is illegal if there is no GROUP BY clause",
"There is no such grant defined for user '%-.32s' on host '%-.64s'",
-"%-.16s command denied to user: '%-.32s@%-.64s' for table '%-.64s'",
-"%-.16s command denied to user: '%-.32s@%-.64s' for column '%-.64s' in table '%-.64s'",
+"%-.16s command denied to user: '%-.32s'@'%-.64s' for table '%-.64s'",
+"%-.16s command denied to user: '%-.32s'@'%-.64s' for column '%-.64s' in table '%-.64s'",
"Illegal GRANT/REVOKE command. Please consult the manual which privleges can be used.",
"The host or user argument to GRANT is too long",
"Table '%-.64s.%s' doesn't exist",
@@ -214,7 +214,7 @@
"DROP DATABASE not allowed while thread is holding global read lock",
"CREATE DATABASE not allowed while thread is holding global read lock",
"Wrong arguments to %s",
-"%-.32s@%-.64s is not allowed to create new users",
+"'%-.32s'@'%-.64s' is not allowed to create new users",
"Incorrect table definition; all MERGE tables must be in the same database",
"Deadlock found when trying to get lock; Try restarting transaction",
"The used table type doesn't support FULLTEXT indexes",
@@ -240,6 +240,7 @@
"Wrong usage/placement of '%s'",
"This version of MySQL doesn't yet support '%s'",
"Got fatal error %d: '%-.128s' from master when reading data from binary log",
+"Slave SQL thread ignored the query because of replicate-*-table rules",
"Wrong foreign key definition for '%-.64s': %s",
"Key reference and table reference doesn't match",
"Cardinality error (more/less than %d columns)",
@@ -269,4 +270,5 @@
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
+"Unknown collation: '%-.64s'",
"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
diff --git a/sql/share/polish/errmsg.txt b/sql/share/polish/errmsg.txt
index a3759da317b..5fcdb6d84c2 100644
--- a/sql/share/polish/errmsg.txt
+++ b/sql/share/polish/errmsg.txt
@@ -49,8 +49,8 @@
"Zbyt ma³o miejsca/pamiêci dla w?tku",
"Nie mo¿na otrzymaæ nazwy hosta dla twojego adresu",
"Z³y uchwyt(handshake)",
-"Access denied for user: '%-.32s@%-.64s' to database '%-.64s'",
-"Access denied for user: '%-.32s@%-.64s' (Using password: %s)",
+"Access denied for user: '%-.32s'@'%-.64s' to database '%-.64s'",
+"Access denied for user: '%-.32s'@'%-.64s' (Using password: %s)",
"Nie wybrano ¿adnej bazy danych",
"Nieznana komenda",
"Kolumna '%-.64s' nie mo¿e byæ null",
@@ -147,8 +147,8 @@
"Got error '%-.64s' from regexp",
"Mixing of GROUP columns (MIN(),MAX(),COUNT()...) with no GROUP columns is illegal if there is no GROUP BY clause",
"There is no such grant defined for user '%-.32s' on host '%-.64s'",
-"%-.16s command denied to user: '%-.32s@%-.64s' for table '%-.64s'",
-"%-.16s command denied to user: '%-.32s@%-.64s' for column '%-.64s' in table '%-.64s'",
+"%-.16s command denied to user: '%-.32s'@'%-.64s' for table '%-.64s'",
+"%-.16s command denied to user: '%-.32s'@'%-.64s' for column '%-.64s' in table '%-.64s'",
"Illegal GRANT/REVOKE command. Please consult the manual which privleges can be used.",
"The host or user argument to GRANT is too long",
"Table '%-.64s.%s' doesn't exist",
@@ -216,7 +216,7 @@
"DROP DATABASE not allowed while thread is holding global read lock",
"CREATE DATABASE not allowed while thread is holding global read lock",
"Wrong arguments to %s",
-"%-.32s@%-.64s is not allowed to create new users",
+"'%-.32s'@'%-.64s' is not allowed to create new users",
"Incorrect table definition; all MERGE tables must be in the same database",
"Deadlock found when trying to get lock; Try restarting transaction",
"The used table type doesn't support FULLTEXT indexes",
@@ -242,6 +242,7 @@
"Wrong usage/placement of '%s'",
"This version of MySQL doesn't yet support '%s'",
"Got fatal error %d: '%-.128s' from master when reading data from binary log",
+"Slave SQL thread ignored the query because of replicate-*-table rules",
"Wrong foreign key definition for '%-.64s': %s",
"Key reference and table reference doesn't match",
"Cardinality error (more/less than %d columns)",
@@ -271,4 +272,5 @@
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
+"Unknown collation: '%-.64s'",
"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
diff --git a/sql/share/portuguese/errmsg.txt b/sql/share/portuguese/errmsg.txt
index b3833b3583b..ea639e1f8cd 100644
--- a/sql/share/portuguese/errmsg.txt
+++ b/sql/share/portuguese/errmsg.txt
@@ -45,8 +45,8 @@
"Sem memória. Verifique se o mysqld ou algum outro processo está usando toda memória disponível. Se não, você pode ter que usar 'ulimit' para permitir ao mysqld usar mais memória ou você pode adicionar mais área de 'swap'",
"Não pode obter nome do 'host' para seu endereço",
"Negociação de acesso falhou",
-"Acesso negado para o usuário '%-.32s@%-.64s' ao banco de dados '%-.64s'",
-"Acesso negado para o usuário '%-.32s@%-.64s' (senha usada: %s)",
+"Acesso negado para o usuário '%-.32s'@'%-.64s' ao banco de dados '%-.64s'",
+"Acesso negado para o usuário '%-.32s'@'%-.64s' (senha usada: %s)",
"Nenhum banco de dados foi selecionado",
"Comando desconhecido",
"Coluna '%-.64s' não pode ser vazia",
@@ -143,8 +143,8 @@
"Obteve erro '%-.64s' em regexp",
"Mistura de colunas agrupadas (com MIN(), MAX(), COUNT(), ...) com colunas não agrupadas é ilegal, se não existir uma cláusula de agrupamento (cláusula GROUP BY)",
"Não existe tal permissão (grant) definida para o usuário '%-.32s' no 'host' '%-.64s'",
-"Comando '%-.16s' negado para o usuário '%-.32s@%-.64s' na tabela '%-.64s'",
-"Comando '%-.16s' negado para o usuário '%-.32s@%-.64s' na coluna '%-.64s', na tabela '%-.64s'",
+"Comando '%-.16s' negado para o usuário '%-.32s'@'%-.64s' na tabela '%-.64s'",
+"Comando '%-.16s' negado para o usuário '%-.32s'@'%-.64s' na coluna '%-.64s', na tabela '%-.64s'",
"Comando GRANT/REVOKE ilegal. Por favor consulte no manual quais privilégios podem ser usados.",
"Argumento de 'host' ou de usuário para o GRANT é longo demais",
"Tabela '%-.64s.%-.64s' não existe",
@@ -212,7 +212,7 @@
"DROP DATABASE não permitido enquanto uma 'thread' está mantendo um travamento global de leitura",
"CREATE DATABASE não permitido enquanto uma 'thread' está mantendo um travamento global de leitura",
"Argumentos errados para %s",
-"Não é permitido a %-.32s@%-.64s criar novos usuários",
+"Não é permitido a '%-.32s'@'%-.64s' criar novos usuários",
"Definição incorreta da tabela. Todas as tabelas contidas na junção devem estar no mesmo banco de dados.",
"Encontrado um travamento fatal (deadlock) quando tentava obter uma trava. Tente reiniciar a transação.",
"O tipo de tabela utilizado não suporta índices de texto completo (fulltext indexes)",
@@ -238,6 +238,7 @@
"Uso/localização errada de '%s'",
"Esta versão de MySQL não suporta ainda '%s'",
"Obteve fatal error %d: '%-.128s' a partir do master quando lendo dados do binary log",
+"Slave SQL thread ignored the query because of replicate-*-table rules",
"Definição errada da chave estrangeira para '%-.64s': %s",
"Referência da chave e referência da tabela não coincidem",
"Error de cardinalidade (mais/menos que %d colunas)",
@@ -267,4 +268,5 @@
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
+"Unknown collation: '%-.64s'",
"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
diff --git a/sql/share/romanian/errmsg.txt b/sql/share/romanian/errmsg.txt
index 1ba2ac8ec49..49c64272dd8 100644
--- a/sql/share/romanian/errmsg.txt
+++ b/sql/share/romanian/errmsg.txt
@@ -49,8 +49,8 @@
"Out of memory; Verifica daca mysqld sau vreun alt proces foloseste toate memoria disponbila. Altfel, trebuie sa folosesi 'ulimit' ca sa permiti lui memoria disponbila. Altfel, trebuie sa folosesi 'ulimit' ca sa permiti lui mysqld sa foloseasca mai multa memorie ori adauga mai mult spatiu pentru swap (swap space)",
"Nu pot sa obtin hostname-ul adresei tale",
"Prost inceput de conectie (bad handshake)",
-"Acces interzis pentru utilizatorul: '%-.32s@%-.64s' la baza de date '%-.64s'",
-"Acces interzis pentru utilizatorul: '%-.32s@%-.64s' (Folosind parola: %s)",
+"Acces interzis pentru utilizatorul: '%-.32s'@'%-.64s' la baza de date '%-.64s'",
+"Acces interzis pentru utilizatorul: '%-.32s'@'%-.64s' (Folosind parola: %s)",
"Nici o baza de data nu a fost selectata inca",
"Comanda invalida",
"Coloana '%-.64s' nu poate sa fie null",
@@ -147,8 +147,8 @@
"Eroarea '%-.64s' obtinuta din expresia regulara (regexp)",
"Amestecarea de coloane GROUP (MIN(),MAX(),COUNT()...) fara coloane GROUP este ilegala daca nu exista o clauza GROUP BY",
"Nu exista un astfel de grant definit pentru utilzatorul '%-.32s' de pe host-ul '%-.64s'",
-"Comanda %-.16s interzisa utilizatorului: '%-.32s@%-.64s' pentru tabela '%-.64s'",
-"Comanda %-.16s interzisa utilizatorului: '%-.32s@%-.64s' pentru coloana '%-.64s' in tabela '%-.64s'",
+"Comanda %-.16s interzisa utilizatorului: '%-.32s'@'%-.64s' pentru tabela '%-.64s'",
+"Comanda %-.16s interzisa utilizatorului: '%-.32s'@'%-.64s' pentru coloana '%-.64s' in tabela '%-.64s'",
"Comanda GRANT/REVOKE ilegala. Consultati manualul in privinta privilegiilor ce pot fi folosite.",
"Argumentul host-ului sau utilizatorului pentru GRANT e prea lung",
"Tabela '%-.64s.%-.64s' nu exista",
@@ -216,7 +216,7 @@
"DROP DATABASE not allowed while thread is holding global read lock",
"CREATE DATABASE not allowed while thread is holding global read lock",
"Wrong arguments to %s",
-"%-.32s@%-.64s is not allowed to create new users",
+"'%-.32s'@'%-.64s' is not allowed to create new users",
"Incorrect table definition; all MERGE tables must be in the same database",
"Deadlock found when trying to get lock; Try restarting transaction",
"The used table type doesn't support FULLTEXT indexes",
@@ -242,6 +242,7 @@
"Wrong usage/placement of '%s'",
"This version of MySQL doesn't yet support '%s'",
"Got fatal error %d: '%-.128s' from master when reading data from binary log",
+"Slave SQL thread ignored the query because of replicate-*-table rules",
"Wrong foreign key definition for '%-.64s': %s",
"Key reference and table reference doesn't match",
"Cardinality error (more/less than %d columns)",
@@ -271,4 +272,5 @@
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
+"Unknown collation: '%-.64s'",
"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
diff --git a/sql/share/russian/errmsg.txt b/sql/share/russian/errmsg.txt
index 17ea1dfcf6e..b711d107c23 100644
--- a/sql/share/russian/errmsg.txt
+++ b/sql/share/russian/errmsg.txt
@@ -47,8 +47,8 @@
"îÅÄÏÓÔÁÔÏÞÎÏ ÐÁÍÑÔÉ; ÕÄÏÓÔÏ×ÅÒØÔÅÓØ, ÞÔÏ mysqld ÉÌÉ ËÁËÏÊ-ÌÉÂÏ ÄÒÕÇÏÊ ÐÒÏÃÅÓÓ ÎÅ ÚÁÎÉÍÁÅÔ ×ÓÀ ÄÏÓÔÕÐÎÕÀ ÐÁÍÑÔØ. åÓÌÉ ÎÅÔ, ÔÏ ×Ù ÍÏÖÅÔÅ ÉÓÐÏÌØÚÏ×ÁÔØ ulimit, ÞÔÏÂÙ ×ÙÄÅÌÉÔØ ÄÌÑ mysqld ÂÏÌØÛÅ ÐÁÍÑÔÉ, ÉÌÉ Õ×ÅÌÉÞÉÔØ ÏÂßÅÍ ÆÁÊÌÁ ÐÏÄËÁÞËÉ",
"îÅ×ÏÚÍÏÖÎÏ ÐÏÌÕÞÉÔØ ÉÍÑ ÈÏÓÔÁ ÄÌÑ ×ÁÛÅÇÏ ÁÄÒÅÓÁ",
"îÅËÏÒÒÅËÔÎÏÅ ÐÒÉ×ÅÔÓÔ×ÉÅ",
-"äÌÑ ÐÏÌØÚÏ×ÁÔÅÌÑ '%-.32s@%-.64s' ÄÏÓÔÕÐ Ë ÂÁÚÅ ÄÁÎÎÙÈ '%-.64s' ÚÁËÒÙÔ",
-"äÏÓÔÕÐ ÚÁËÒÙÔ ÄÌÑ ÐÏÌØÚÏ×ÁÔÅÌÑ '%-.32s@%-.64s' (ÂÙÌ ÉÓÐÏÌØÚÏ×ÁÎ ÐÁÒÏÌØ: %s)",
+"äÌÑ ÐÏÌØÚÏ×ÁÔÅÌÑ '%-.32s'@'%-.64s' ÄÏÓÔÕÐ Ë ÂÁÚÅ ÄÁÎÎÙÈ '%-.64s' ÚÁËÒÙÔ",
+"äÏÓÔÕÐ ÚÁËÒÙÔ ÄÌÑ ÐÏÌØÚÏ×ÁÔÅÌÑ '%-.32s'@'%-.64s' (ÂÙÌ ÉÓÐÏÌØÚÏ×ÁÎ ÐÁÒÏÌØ: %s)",
"âÁÚÁ ÄÁÎÎÙÈ ÎÅ ×ÙÂÒÁÎÁ",
"îÅÉÚ×ÅÓÔÎÁÑ ËÏÍÁÎÄÁ ËÏÍÍÕÎÉËÁÃÉÏÎÎÏÇÏ ÐÒÏÔÏËÏÌÁ",
"óÔÏÌÂÅà '%-.64s' ÎÅ ÍÏÖÅÔ ÐÒÉÎÉÍÁÔØ ×ÅÌÉÞÉÎÕ NULL",
@@ -145,8 +145,8 @@
"ðÏÌÕÞÅÎÁ ÏÛÉÂËÁ '%-.64s' ÏÔ ÒÅÇÕÌÑÒÎÏÇÏ ×ÙÒÁÖÅÎÉÑ",
"ïÄÎÏ×ÒÅÍÅÎÎÏÅ ÉÓÐÏÌØÚÏ×ÁÎÉÅ ÓÇÒÕÐÐÉÒÏ×ÁÎÎÙÈ (GROUP) ÓÔÏÌÂÃÏ× (MIN(),MAX(),COUNT(),...) Ó ÎÅÓÇÒÕÐÐÉÒÏ×ÁÎÎÙÍÉ ÓÔÏÌÂÃÁÍÉ Ñ×ÌÑÅÔÓÑ ÎÅËÏÒÒÅËÔÎÙÍ, ÅÓÌÉ × ×ÙÒÁÖÅÎÉÉ ÅÓÔØ GROUP BY",
"ôÁËÉÅ ÐÒÁ×Á ÎÅ ÏÐÒÅÄÅÌÅÎÙ ÄÌÑ ÐÏÌØÚÏ×ÁÔÅÌÑ '%-.32s' ÎÁ ÈÏÓÔÅ '%-.64s'",
-"ëÏÍÁÎÄÁ %-.16s ÚÁÐÒÅÝÅÎÁ ÐÏÌØÚÏ×ÁÔÅÌÀ '%-.32s@%-.64s' ÄÌÑ ÔÁÂÌÉÃÙ '%-.64s'",
-"ëÏÍÁÎÄÁ %-.16s ÚÁÐÒÅÝÅÎÁ ÐÏÌØÚÏ×ÁÔÅÌÀ '%-.32s@%-.64s' ÄÌÑ ÓÔÏÌÂÃÁ '%-.64s' × ÔÁÂÌÉÃÅ '%-.64s'",
+"ëÏÍÁÎÄÁ %-.16s ÚÁÐÒÅÝÅÎÁ ÐÏÌØÚÏ×ÁÔÅÌÀ '%-.32s'@'%-.64s' ÄÌÑ ÔÁÂÌÉÃÙ '%-.64s'",
+"ëÏÍÁÎÄÁ %-.16s ÚÁÐÒÅÝÅÎÁ ÐÏÌØÚÏ×ÁÔÅÌÀ '%-.32s'@'%-.64s' ÄÌÑ ÓÔÏÌÂÃÁ '%-.64s' × ÔÁÂÌÉÃÅ '%-.64s'",
"îÅ×ÅÒÎÁÑ ËÏÍÁÎÄÁ GRANT ÉÌÉ REVOKE. ïÂÒÁÔÉÔÅÓØ Ë ÄÏËÕÍÅÎÔÁÃÉÉ, ÞÔÏÂÙ ×ÙÑÓÎÉÔØ, ËÁËÉÅ ÐÒÉ×ÉÌÅÇÉÉ ÍÏÖÎÏ ÉÓÐÏÌØÚÏ×ÁÔØ",
"óÌÉÛËÏÍ ÄÌÉÎÎÏÅ ÉÍÑ ÐÏÌØÚÏ×ÁÔÅÌÑ/ÈÏÓÔÁ ÄÌÑ GRANT",
"ôÁÂÌÉÃÁ '%-.64s.%-.64s' ÎÅ ÓÕÝÅÓÔ×ÕÅÔ",
@@ -214,7 +214,7 @@
"îÅ ÄÏÐÕÓËÁÅÔÓÑ DROP DATABASE, ÐÏËÁ ÐÏÔÏË ÄÅÒÖÉÔ ÇÌÏÂÁÌØÎÕÀ ÂÌÏËÉÒÏ×ËÕ ÞÔÅÎÉÑ",
"îÅ ÄÏÐÕÓËÁÅÔÓÑ CREATE DATABASE, ÐÏËÁ ÐÏÔÏË ÄÅÒÖÉÔ ÇÌÏÂÁÌØÎÕÀ ÂÌÏËÉÒÏ×ËÕ ÞÔÅÎÉÑ",
"îÅ×ÅÒÎÙÅ ÐÁÒÁÍÅÔÒÙ ÄÌÑ %s",
-"%-.32s@%-.64s ÎÅ ÒÁÚÒÅÛÁÅÔÓÑ ÓÏÚÄÁ×ÁÔØ ÎÏ×ÙÈ ÐÏÌØÚÏ×ÁÔÅÌÅÊ",
+"'%-.32s'@'%-.64s' ÎÅ ÒÁÚÒÅÛÁÅÔÓÑ ÓÏÚÄÁ×ÁÔØ ÎÏ×ÙÈ ÐÏÌØÚÏ×ÁÔÅÌÅÊ",
"îÅ×ÅÒÎÏÅ ÏÐÒÅÄÅÌÅÎÉÅ ÔÁÂÌÉÃÙ; ÷ÓÅ ÔÁÂÌÉÃÙ × MERGE ÄÏÌÖÎÙ ÐÒÉÎÁÄÌÅÖÁÔØ ÏÄÎÏÊ É ÔÏÊ ÖÅ ÂÁÚÅ ÄÁÎÎÙÈ",
"÷ÏÚÎÉËÌÁ ÔÕÐÉËÏ×ÁÑ ÓÉÔÕÁÃÉÑ × ÐÒÏÃÅÓÓÅ ÐÏÌÕÞÅÎÉÑ ÂÌÏËÉÒÏ×ËÉ; ðÏÐÒÏÂÕÊÔÅ ÐÅÒÅÚÁÐÕÓÔÉÔØ ÔÒÁÎÚÁËÃÉÀ",
"éÓÐÏÌØÚÕÅÍÙÊ ÔÉÐ ÔÁÂÌÉà ÎÅ ÐÏÄÄÅÒÖÉ×ÁÅÔ ÐÏÌÎÏÔÅËÓÔÏ×ÙÈ ÉÎÄÅËÓÏ×",
@@ -240,6 +240,7 @@
"îÅ×ÅÒÎÏÅ ÉÓÐÏÌØÚÏ×ÁÎÉÅ ÉÌÉ × ÎÅ×ÅÒÎÏÍ ÍÅÓÔÅ ÕËÁÚÁÎ '%s'",
"üÔÁ ×ÅÒÓÉÑ MySQL ÐÏËÁ ÅÝÅ ÎÅ ÐÏÄÄÅÒÖÉ×ÁÅÔ '%s'",
"ðÏÌÕÞÅÎÁ ÎÅÉÓÐÒÁ×ÉÍÁÑ ÏÛÉÂËÁ %d: '%-.128s' ÏÔ ÇÏÌÏ×ÎÏÇÏ ÓÅÒ×ÅÒÁ × ÐÒÏÃÅÓÓÅ ×ÙÂÏÒËÉ ÄÁÎÎÙÈ ÉÚ Ä×ÏÉÞÎÏÇÏ ÖÕÒÎÁÌÁ",
+"Slave SQL thread ignored the query because of replicate-*-table rules",
"Wrong foreign key definition for '%-.64s': %s",
"Key reference and table reference doesn't match",
"ïÛÉÂËÁ ÍÏÝØÎÏÓÔÉ ÍÎÏÖÅÓÔ×Á (ÂÏÌØÛÅ/ÍÅÎØÛÅ %d ËÏÌÏÎÏË)",
@@ -269,4 +270,5 @@
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
+"Unknown collation: '%-.64s'",
"ðÏÌÅ ÉÌÉ ÓÓÙÌËÁ '%-.64s%s%-.64s%s%-.64s' ÉÚ SELECTÁ #%d ÂÙÌÁ ÎÁÊÄÅÎÁ × SELECTÅ #%d",
diff --git a/sql/share/serbian/errmsg.txt b/sql/share/serbian/errmsg.txt
index 8e9512f5567..0129cd0d643 100644
--- a/sql/share/serbian/errmsg.txt
+++ b/sql/share/serbian/errmsg.txt
@@ -51,8 +51,8 @@
"Nema memorije; Proverite da li MySQL server ili neki drugi proces koristi svu slobodnu memoriju. (UNIX: Ako ne, probajte da upotrebite 'ulimit' komandu da biste dozvolili daemon-u da koristi više memorije ili probajte da dodate više swap memorije)",
"Ne mogu da dobijem ime host-a za vašu IP adresu",
"Loš poèetak komunikacije (handshake)",
-"Pristup je zabranjen korisniku '%-.32s@%-.64s' za bazu '%-.64s'",
-"Pristup je zabranjen korisniku '%-.32s@%-.64s' (koristi lozinku: '%s')",
+"Pristup je zabranjen korisniku '%-.32s'@'%-.64s' za bazu '%-.64s'",
+"Pristup je zabranjen korisniku '%-.32s'@'%-.64s' (koristi lozinku: '%s')",
"Ni jedna baza nije selektovana",
"Nepoznata komanda",
"Kolona '%-.64s' ne može biti NULL",
@@ -149,8 +149,8 @@
"Funkcija regexp je vratila grešku '%-.64s'",
"Upotreba agregatnih funkcija (MIN(),MAX(),COUNT()...) bez 'GROUP' kolona je pogrešna ako ne postoji 'GROUP BY' iskaz",
"Ne postoji odobrenje za pristup korisniku '%-.32s' na host-u '%-.64s'",
-"%-.16s komanda zabranjena za korisnika '%-.32s@%-.64s' za tabelu '%-.64s'",
-"%-.16s komanda zabranjena za korisnika '%-.32s@%-.64s' za kolonu '%-.64s' iz tabele '%-.64s'",
+"%-.16s komanda zabranjena za korisnika '%-.32s'@'%-.64s' za tabelu '%-.64s'",
+"%-.16s komanda zabranjena za korisnika '%-.32s'@'%-.64s' za kolonu '%-.64s' iz tabele '%-.64s'",
"Pogrešna 'GRANT' odnosno 'REVOKE' komanda. Molim Vas pogledajte u priruèniku koje vrednosti mogu biti upotrebljene.",
"Argument 'host' ili 'korisnik' prosleðen komandi 'GRANT' je predugaèak",
"Tabela '%-.64s.%-.64s' ne postoji",
@@ -218,7 +218,7 @@
"Komanda 'DROP DATABASE' nije dozvoljena dok thread globalno zakljuèava èitanje podataka",
"Komanda 'CREATE DATABASE' nije dozvoljena dok thread globalno zakljuèava èitanje podataka",
"Pogrešni argumenti prosleðeni na %s",
-"Korisniku %-.32s@%-.64s nije dozvoljeno da kreira nove korisnike",
+"Korisniku '%-.32s'@'%-.64s' nije dozvoljeno da kreira nove korisnike",
"Pogrešna definicija tabele; sve 'MERGE' tabele moraju biti u istoj bazi podataka",
"Unakrsno zakljuèavanje pronaðeno kada sam pokušao da dobijem pravo na zakljuèavanje; Probajte da restartujete transakciju",
"Upotrebljeni tip tabele ne podržava 'FULLTEXT' indekse",
@@ -263,4 +263,5 @@
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
+"Unknown collation: '%-.64s'",
"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
diff --git a/sql/share/slovak/errmsg.txt b/sql/share/slovak/errmsg.txt
index f49ff1a2adc..ac8e7a5c7eb 100644
--- a/sql/share/slovak/errmsg.txt
+++ b/sql/share/slovak/errmsg.txt
@@ -53,8 +53,8 @@
"Málo miesta-pamäti pre vlákno",
"Nemô¾em zisti» meno hostiteµa pre va¹u adresu",
"Chyba pri nadväzovaní spojenia",
-"Zakázaný prístup pre u¾ívateµa: '%-.32s@%-.64s' k databázi '%-.64s'",
-"Zakázaný prístup pre u¾ívateµa: '%-.32s@%-.64s' (pou¾itie hesla: %s)",
+"Zakázaný prístup pre u¾ívateµa: '%-.32s'@'%-.64s' k databázi '%-.64s'",
+"Zakázaný prístup pre u¾ívateµa: '%-.32s'@'%-.64s' (pou¾itie hesla: %s)",
"Nebola vybraná databáza",
"Neznámy príkaz",
"Pole '%-.64s' nemô¾e by» null",
@@ -151,8 +151,8 @@
"Got error '%-.64s' from regexp",
"Mixing of GROUP columns (MIN(),MAX(),COUNT()...) with no GROUP columns is illegal if there is no GROUP BY clause",
"There is no such grant defined for user '%-.32s' on host '%-.64s'",
-"%-.16s command denied to user: '%-.32s@%-.64s' for table '%-.64s'",
-"%-.16s command denied to user: '%-.32s@%-.64s' for column '%-.64s' in table '%-.64s'",
+"%-.16s command denied to user: '%-.32s'@'%-.64s' for table '%-.64s'",
+"%-.16s command denied to user: '%-.32s'@'%-.64s' for column '%-.64s' in table '%-.64s'",
"Illegal GRANT/REVOKE command. Please consult the manual which privleges can be used.",
"The host or user argument to GRANT is too long",
"Table '%-.64s.%s' doesn't exist",
@@ -220,7 +220,7 @@
"DROP DATABASE not allowed while thread is holding global read lock",
"CREATE DATABASE not allowed while thread is holding global read lock",
"Wrong arguments to %s",
-"%-.32s@%-.64s is not allowed to create new users",
+"'%-.32s'@'%-.64s' is not allowed to create new users",
"Incorrect table definition; all MERGE tables must be in the same database",
"Deadlock found when trying to get lock; Try restarting transaction",
"The used table type doesn't support FULLTEXT indexes",
@@ -246,6 +246,7 @@
"Wrong usage/placement of '%s'",
"This version of MySQL doesn't yet support '%s'",
"Got fatal error %d: '%-.128s' from master when reading data from binary log",
+"Slave SQL thread ignored the query because of replicate-*-table rules",
"Wrong foreign key definition for '%-.64s': %s",
"Key reference and table reference doesn't match",
"Cardinality error (more/less than %d columns)",
@@ -275,4 +276,5 @@
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
+"Unknown collation: '%-.64s'",
"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
diff --git a/sql/share/spanish/errmsg.txt b/sql/share/spanish/errmsg.txt
index 9f3aa3dd478..86a3ab090a2 100644
--- a/sql/share/spanish/errmsg.txt
+++ b/sql/share/spanish/errmsg.txt
@@ -46,8 +46,8 @@
"Memoria/espacio de tranpaso insuficiente",
"No puedo obtener el nombre de maquina de tu direccion",
"Protocolo erroneo",
-"Acceso negado para usuario: '%-.32s@%-.64s' para la base de datos '%-.64s'",
-"Acceso negado para usuario: '%-.32s@%-.64s' (Usando clave: %s)",
+"Acceso negado para usuario: '%-.32s'@'%-.64s' para la base de datos '%-.64s'",
+"Acceso negado para usuario: '%-.32s'@'%-.64s' (Usando clave: %s)",
"Base de datos no seleccionada",
"Comando desconocido",
"La columna '%-.64s' no puede ser nula",
@@ -144,8 +144,8 @@
"Obtenido error '%-.64s' de regexp",
"Mezcla de columnas GROUP (MIN(),MAX(),COUNT()...) con no GROUP columnas es ilegal si no hat la clausula GROUP BY",
"No existe permiso definido para usuario '%-.32s' en el servidor '%-.64s'",
-"%-.16s comando negado para usuario: '%-.32s@%-.64s' para tabla '%-.64s'",
-"%-.16s comando negado para usuario: '%-.32s@%-.64s' para columna '%-.64s' en la tabla '%-.64s'",
+"%-.16s comando negado para usuario: '%-.32s'@'%-.64s' para tabla '%-.64s'",
+"%-.16s comando negado para usuario: '%-.32s'@'%-.64s' para columna '%-.64s' en la tabla '%-.64s'",
"Ilegal comando GRANT/REVOKE. Por favor consulte el manual para cuales permisos pueden ser usados.",
"El argumento para servidor o usuario para GRANT es demasiado grande",
"Tabla '%-.64s.%s' no existe",
@@ -212,14 +212,14 @@
"Bloqueos de actualización no pueden ser adqueridos durante una transición READ UNCOMMITTED",
"DROP DATABASE no permitido mientras un thread está ejerciendo un bloqueo de lectura global",
"CREATE DATABASE no permitido mientras un thread está ejerciendo un bloqueo de lectura global",
-"Wrong arguments to %s",
-"%-.32s@%-.64s is not allowed to create new users",
-"Incorrect table definition; all MERGE tables must be in the same database",
-"Deadlock found when trying to get lock; Try restarting transaction",
-"The used table type doesn't support FULLTEXT indexes",
-"Cannot add foreign key constraint",
-"Cannot add a child row: a foreign key constraint fails",
-"Cannot delete a parent row: a foreign key constraint fails",
+"Argumentos errados para %s",
+"'%-.32s`@`%-.64s` no es permitido para crear nuevos usuarios",
+"Incorrecta definición de la tabla; Todas las tablas MERGE deben estar en el mismo banco de datos",
+"Encontrado deadlock cuando tentando obtener el bloqueo; Tente recomenzar la transición",
+"El tipo de tabla usada no soporta índices FULLTEXT",
+"No puede adicionar clave extranjera constraint",
+"No puede adicionar una línea hijo: falla de clave extranjera constraint",
+"No puede deletar una línea padre: falla de clave extranjera constraint",
"Error de coneccion a master: %-128s",
"Error executando el query en master: %-128%",
"Error de %s: %-128%",
@@ -239,6 +239,7 @@
"Wrong usage/placement of '%s'",
"This version of MySQL doesn't yet support '%s'",
"Got fatal error %d: '%-.128s' from master when reading data from binary log",
+"Slave SQL thread ignored the query because of replicate-*-table rules",
"Wrong foreign key definition for '%-.64s': %s",
"Key reference and table reference doesn't match",
"Cardinality error (more/less than %d columns)",
@@ -268,4 +269,5 @@
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
+"Unknown collation: '%-.64s'",
"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
diff --git a/sql/share/swedish/errmsg.txt b/sql/share/swedish/errmsg.txt
index ab2cc1f66b0..0add28faab1 100644
--- a/sql/share/swedish/errmsg.txt
+++ b/sql/share/swedish/errmsg.txt
@@ -45,8 +45,8 @@
"Fick slut på minnet. Kontrollera om mysqld eller någon annan process använder allt tillgängligt minne. Om inte, försök använda 'ulimit' eller allokera mera swap",
"Kan inte hitta 'hostname' för din adress",
"Fel vid initiering av kommunikationen med klienten",
-"Användare '%-.32s@%-.64s' är ej berättigad att använda databasen %-.64s",
-"Användare '%-.32s@%-.64s' är ej berättigad att logga in (Använder lösen: %s)",
+"Användare '%-.32s'@'%-.64s' är ej berättigad att använda databasen %-.64s",
+"Användare '%-.32s'@'%-.64s' är ej berättigad att logga in (Använder lösen: %s)",
"Ingen databas i användning",
"Okänt commando",
"Kolumn '%-.64s' får inte vara NULL",
@@ -143,8 +143,8 @@
"Fick fel '%-.64s' från REGEXP",
"Man får ha både GROUP-kolumner (MIN(),MAX(),COUNT()...) och fält i en fråga om man inte har en GROUP BY-del",
"Det finns inget privilegium definierat för användare '%-.32s' på '%-.64s'",
-"%-.16s ej tillåtet för '%-.32s@%-.64s' för tabell '%-.64s'",
-"%-.16s ej tillåtet för '%-.32s@%-.64s' för kolumn '%-.64s' i tabell '%-.64s'",
+"%-.16s ej tillåtet för '%-.32s'@'%-.64s' för tabell '%-.64s'",
+"%-.16s ej tillåtet för '%-.32s'@'%-.64s' för kolumn '%-.64s' i tabell '%-.64s'",
"Felaktigt GRANT-privilegium använt",
"Felaktigt maskinnamn eller användarnamn använt med GRANT",
"Det finns ingen tabell som heter '%-.64s.%s'",
@@ -212,7 +212,7 @@
"DROP DATABASE är inte tillåtet när man har ett globalt läslås",
"CREATE DATABASE är inte tillåtet när man har ett globalt läslås",
"Felaktiga argument till %s",
-"%-.32s@%-.64s har inte rättighet att skapa nya användare",
+"'%-.32s'@'%-.64s' har inte rättighet att skapa nya användare",
"Felaktig tabelldefinition; alla tabeller i en MERGE-tabell måste vara i samma databas",
"Fick 'DEADLOCK' vid låsförsök av block/rad. Försök att starta om transaktionen",
"Tabelltypen har inte hantering av FULLTEXT-index",
@@ -237,7 +237,8 @@
"Variabeln '%-.64s' kan endast sättas, inte läsas",
"Fel använding/placering av '%s'",
"Denna version av MySQL kan ännu inte utföra '%s'",
-"Fick fatalt fel %d: '%-.128s' från master vid läsning av binärloggen"
+"Fick fatalt fel %d: '%-.128s' från master vid läsning av binärloggen",
+"Slav SQL tråden ignorerade frågan pga en replicate-*-table regel",
"Felaktig FOREIGN KEY-definition för '%-.64s': %s",
"Nyckelreferensen och tabellreferensen stämmer inte överens",
"Kardinalitetsfel (fler/färre än %d kolumner)",
@@ -267,4 +268,5 @@
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
+"Unknown collation: '%-.64s'",
"Field or reference '%-.64s%s%-.64s%s%-.64s' of SELECT #%d was resolved in SELECT #%d",
diff --git a/sql/share/ukrainian/errmsg.txt b/sql/share/ukrainian/errmsg.txt
index bfa1d0db9e4..99d3f9c6a52 100644
--- a/sql/share/ukrainian/errmsg.txt
+++ b/sql/share/ukrainian/errmsg.txt
@@ -50,8 +50,8 @@
"âÒÁË ÐÁÍ'ÑÔ¦; ðÅÒÅצÒÔÅ ÞÉ mysqld ÁÂÏ ÑË¦ÓØ ¦ÎÛ¦ ÐÒÏÃÅÓÉ ×ÉËÏÒÉÓÔÏ×ÕÀÔØ ÕÓÀ ÄÏÓÔÕÐÎÕ ÐÁÍ'ÑÔØ. ñË Î¦, ÔÏ ×É ÍÏÖÅÔÅ ÓËÏÒÉÓÔÁÔÉÓÑ 'ulimit', ÁÂÉ ÄÏÚ×ÏÌÉÔÉ mysqld ×ÉËÏÒÉÓÔÏ×Õ×ÁÔÉ Â¦ÌØÛÅ ÐÁÍ'ÑÔ¦ ÁÂÏ ×É ÍÏÖÅÔÅ ÄÏÄÁÔÉ Â¦ÌØÛŠͦÓÃÑ Ð¦Ä Ó×ÁÐ",
"îÅ ÍÏÖÕ ×ÉÚÎÁÞÉÔÉ ¦Í'Ñ ÈÏÓÔÕ ÄÌÑ ×ÁÛϧ ÁÄÒÅÓÉ",
"îÅצÒÎÁ ÕÓÔÁÎÏ×ËÁ Ú×'ÑÚËÕ",
-"äÏÓÔÕÐ ÚÁÂÏÒÏÎÅÎÏ ÄÌÑ ËÏÒÉÓÔÕ×ÁÞÁ: '%-.32s@%-.64s' ÄÏ ÂÁÚÉ ÄÁÎÎÉÈ '%-.64s'",
-"äÏÓÔÕÐ ÚÁÂÏÒÏÎÅÎÏ ÄÌÑ ËÏÒÉÓÔÕ×ÁÞÁ: '%-.32s@%-.64s' (÷ÉËÏÒÉÓÔÁÎÏ ÐÁÒÏÌØ: %s)",
+"äÏÓÔÕÐ ÚÁÂÏÒÏÎÅÎÏ ÄÌÑ ËÏÒÉÓÔÕ×ÁÞÁ: '%-.32s'@'%-.64s' ÄÏ ÂÁÚÉ ÄÁÎÎÉÈ '%-.64s'",
+"äÏÓÔÕÐ ÚÁÂÏÒÏÎÅÎÏ ÄÌÑ ËÏÒÉÓÔÕ×ÁÞÁ: '%-.32s'@'%-.64s' (÷ÉËÏÒÉÓÔÁÎÏ ÐÁÒÏÌØ: %s)",
"âÁÚÕ ÄÁÎÎÉÈ ÎÅ ×ÉÂÒÁÎÏ",
"îÅצÄÏÍÁ ËÏÍÁÎÄÁ",
"óÔÏ×ÂÅÃØ '%-.64s' ÎÅ ÍÏÖÅ ÂÕÔÉ ÎÕÌØÏ×ÉÍ",
@@ -148,8 +148,8 @@
"ïÔÒÉÍÁÎÏ ÐÏÍÉÌËÕ '%-.64s' ×¦Ä ÒÅÇÕÌÑÒÎÏÇÏ ×ÉÒÁÚÕ",
"úͦÛÕ×ÁÎÎÑ GROUP ÓÔÏ×ÂÃ¦× (MIN(),MAX(),COUNT()...) Ú ÎÅ GROUP ÓÔÏ×ÂÃÑÍÉ ¤ ÚÁÂÏÒÏÎÅÎÉÍ, ÑËÝÏ ÎÅ ÍÁ¤ GROUP BY",
"ðÏ×ÎÏ×ÁÖÅÎØ ÎÅ ×ÉÚÎÁÞÅÎÏ ÄÌÑ ËÏÒÉÓÔÕ×ÁÞÁ '%-.32s' Ú ÈÏÓÔÕ '%-.64s'",
-"%-.16s ËÏÍÁÎÄÁ ÚÁÂÏÒÏÎÅÎÁ ËÏÒÉÓÔÕ×ÁÞÕ: '%-.32s@%-.64s' Õ ÔÁÂÌÉæ '%-.64s'",
-"%-.16s ËÏÍÁÎÄÁ ÚÁÂÏÒÏÎÅÎÁ ËÏÒÉÓÔÕ×ÁÞÕ: '%-.32s@%-.64s' ÄÌÑ ÓÔÏ×ÂÃÑ '%-.64s' Õ ÔÁÂÌÉæ '%-.64s'",
+"%-.16s ËÏÍÁÎÄÁ ÚÁÂÏÒÏÎÅÎÁ ËÏÒÉÓÔÕ×ÁÞÕ: '%-.32s'@'%-.64s' Õ ÔÁÂÌÉæ '%-.64s'",
+"%-.16s ËÏÍÁÎÄÁ ÚÁÂÏÒÏÎÅÎÁ ËÏÒÉÓÔÕ×ÁÞÕ: '%-.32s'@'%-.64s' ÄÌÑ ÓÔÏ×ÂÃÑ '%-.64s' Õ ÔÁÂÌÉæ '%-.64s'",
"èÉÂÎÁ GRANT/REVOKE ËÏÍÁÎÄÁ. ðÒÏÞÉÔÁÊÔÅ ÄÏËÕÍÅÎÔÁæÀ ÓÔÏÓÏ×ÎÏ ÔÏÇÏ, Ñ˦ ÐÒÁ×Á ÍÏÖÎÁ ×ÉËÏÒÉÓÔÏ×Õ×ÁÔÉ.",
"áÒÇÕÍÅÎÔ host ÁÂÏ user ÄÌÑ GRANT ÚÁÄÏ×ÇÉÊ",
"ôÁÂÌÉÃÑ '%-.64s.%-.64s' ÎÅ ¦ÓÎÕ¤",
@@ -217,7 +217,7 @@
"DROP DATABASE ÎÅ ÄÏÚ×ÏÌÅÎÏ ÄÏËÉ Ç¦ÌËÁ ÐÅÒÅÂÕ×Á¤ Ð¦Ä ÚÁÇÁÌØÎÉÍ ÂÌÏËÕ×ÁÎÎÑÍ ÞÉÔÁÎÎÑ",
"CREATE DATABASE ÎÅ ÄÏÚ×ÏÌÅÎÏ ÄÏËÉ Ç¦ÌËÁ ÐÅÒÅÂÕ×Á¤ Ð¦Ä ÚÁÇÁÌØÎÉÍ ÂÌÏËÕ×ÁÎÎÑÍ ÞÉÔÁÎÎÑ",
"èÉÂÎÉÊ ÁÒÇÕÍÅÎÔ ÄÌÑ %s",
-"ëÏÒÉÓÔÕ×ÁÞÕ %-.32s@%-.64s ÎÅ ÄÏÚ×ÏÌÅÎÏ ÓÔ×ÏÒÀ×ÁÔÉ ÎÏ×ÉÈ ËÏÒÉÓÔÕ×ÁÞ¦×",
+"ëÏÒÉÓÔÕ×ÁÞÕ '%-.32s'@'%-.64s' ÎÅ ÄÏÚ×ÏÌÅÎÏ ÓÔ×ÏÒÀ×ÁÔÉ ÎÏ×ÉÈ ËÏÒÉÓÔÕ×ÁÞ¦×",
"Incorrect table definition; all MERGE tables must be in the same database",
"Deadlock found when trying to get lock; Try restarting transaction",
"÷ÉËÏÒÉÓÔÁÎÉÊ ÔÉÐ ÔÁÂÌÉæ ΊЦÄÔÒÉÍÕ¤ FULLTEXT ¦ÎÄÅËÓ¦×",
@@ -243,6 +243,7 @@
"Wrong usage/placement of '%s'",
"This version of MySQL doesn't yet support '%s'",
"Got fatal error %d: '%-.128s' from master when reading data from binary log",
+"Slave SQL thread ignored the query because of replicate-*-table rules",
"Wrong foreign key definition for '%-.64s': %s",
"Key reference and table reference doesn't match",
"Cardinality error (Â¦ÌØÛÅ/ÍÅÎØÛÅ Î¦Ö %d ÓÔÏ×Âæ×)",
@@ -272,4 +273,5 @@
"Illegal mix of collations (%s,%s), (%s,%s), (%s,%s) for operation '%s'",
"Illegal mix of collations for operation '%s'",
"Variable '%-.64s' is not a variable component (Can't be used as XXXX.variable_name)",
+"Unknown collation: '%-.64s'",
"óÔÏ×ÂÅÃØ ÁÂÏ ÐÏÓÉÌÁÎÎÑ '%-.64s%s%-.64s%s%-.64s' ¦Ú SELECTÕ #%d ÂÕÌÏ ÚÎÁÊÄÅÎÅ Õ SELECT¦ #%d",
diff --git a/sql/slave.cc b/sql/slave.cc
index c45c11f8bef..d45cf1aa8b9 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -74,7 +74,6 @@ static int request_table_dump(MYSQL* mysql, const char* db, const char* table);
static int create_table_from_dump(THD* thd, MYSQL *mysql, const char* db,
const char* table_name);
static int check_master_version(MYSQL* mysql, MASTER_INFO* mi);
-char* rewrite_db(char* db);
/*
@@ -139,6 +138,8 @@ int init_slave()
{
DBUG_ENTER("init_slave");
+ /* This is called when mysqld starts */
+
/*
TODO: re-write this to interate through the list of files
for multi-master
@@ -150,11 +151,16 @@ int init_slave()
If master_host is specified, create the master_info file if it doesn't
exists.
*/
- if (!active_mi ||
- init_master_info(active_mi,master_info_file,relay_log_info_file,
+ if (!active_mi)
+ {
+ sql_print_error("Failed to allocate memory for the master info structure");
+ goto err;
+ }
+
+ if (init_master_info(active_mi,master_info_file,relay_log_info_file,
!master_host))
{
- sql_print_error("Note: Failed to initialized master info");
+ sql_print_error("Failed to initialize the master info structure");
goto err;
}
@@ -174,7 +180,7 @@ int init_slave()
relay_log_info_file,
SLAVE_IO | SLAVE_SQL))
{
- sql_print_error("Warning: Can't create threads to handle slave");
+ sql_print_error("Failed to create slave threads");
goto err;
}
}
@@ -300,6 +306,7 @@ err:
pthread_cond_broadcast(&rli->data_cond);
if (need_data_lock)
pthread_mutex_unlock(&rli->data_lock);
+
pthread_mutex_unlock(log_lock);
DBUG_RETURN ((*errmsg) ? 1 : 0);
}
@@ -380,7 +387,10 @@ int purge_relay_logs(RELAY_LOG_INFO* rli, THD *thd, bool just_reset,
rli->group_master_log_pos= 0;
if (!rli->inited)
+ {
+ DBUG_PRINT("info", ("rli->inited == 0"));
DBUG_RETURN(0);
+ }
DBUG_ASSERT(rli->slave_running == 0);
DBUG_ASSERT(rli->mi->slave_running == 0);
@@ -872,15 +882,38 @@ static bool sql_slave_killed(THD* thd, RELAY_LOG_INFO* rli)
}
+/*
+ Writes an error message to rli->last_slave_error and rli->last_slave_errno
+ (which will be displayed by SHOW SLAVE STATUS), and prints it to stderr.
+
+ SYNOPSIS
+ slave_print_error()
+ rli
+ err_code The error code
+ msg The error message (usually related to the error code, but can
+ contain more information).
+ ... (this is printf-like format, with % symbols in msg)
+
+ RETURN VALUES
+ void
+*/
+
void slave_print_error(RELAY_LOG_INFO* rli, int err_code, const char* msg, ...)
{
va_list args;
va_start(args,msg);
my_vsnprintf(rli->last_slave_error,
sizeof(rli->last_slave_error), msg, args);
- sql_print_error("Slave: %s, error_code=%d", rli->last_slave_error,
- err_code);
rli->last_slave_errno = err_code;
+ /* If the error string ends with '.', do not add a ',' it would be ugly */
+ if (rli->last_slave_error[0] &&
+ (*(strend(rli->last_slave_error)-1) == '.'))
+ sql_print_error("Slave: %s Error_code: %d", rli->last_slave_error,
+ err_code);
+ else
+ sql_print_error("Slave: %s, Error_code: %d", rli->last_slave_error,
+ err_code);
+
}
/*
@@ -905,7 +938,7 @@ bool net_request_file(NET* net, const char* fname)
}
-char* rewrite_db(char* db)
+const char *rewrite_db(const char* db)
{
if (replicate_rewrite_db.is_empty() || !db)
return db;
@@ -920,6 +953,17 @@ char* rewrite_db(char* db)
return db;
}
+/*
+ From other comments and tests in code, it looks like
+ sometimes Query_log_event and Load_log_event can have db == 0
+ (see rewrite_db() above for example)
+ (cases where this happens are unclear; it may be when the master is 3.23).
+*/
+
+const char *print_slave_db_safe(const char* db)
+{
+ return (db ? rewrite_db(db) : "");
+}
/*
Checks whether a db matches some do_db and ignore_db rules
@@ -1027,13 +1071,19 @@ static int check_master_version(MYSQL* mysql, MASTER_INFO* mi)
{
const char* errmsg= 0;
+ /*
+ Note the following switch will bug when we have MySQL branch 30 ;)
+ */
switch (*mysql->server_version) {
case '3':
- mi->old_format = 1;
+ mi->old_format =
+ (strncmp(mysql->server_version, "3.23.57", 7) < 0) /* < .57 */ ?
+ BINLOG_FORMAT_323_LESS_57 :
+ BINLOG_FORMAT_323_GEQ_57 ;
break;
case '4':
case '5':
- mi->old_format = 0;
+ mi->old_format = BINLOG_FORMAT_CURRENT;
break;
default:
errmsg = "Master reported unrecognized MySQL version";
@@ -1087,7 +1137,6 @@ static int create_table_from_dump(THD* thd, MYSQL *mysql, const char* db,
return 1;
}
thd->query= query;
- thd->current_tablenr = 0;
thd->query_error = 0;
thd->net.no_send_ok = 1;
@@ -1246,11 +1295,55 @@ int init_relay_log_info(RELAY_LOG_INFO* rli, const char* info_fname)
strmov(strcend(tmp,'.'),"-relay-bin");
opt_relay_logname=my_strdup(tmp,MYF(MY_WME));
}
+
+ /*
+ The relay log will now be opened, as a SEQ_READ_APPEND IO_CACHE. It is
+ notable that the last kilobytes of it (8 kB for example) may live in
+ memory, not on disk (depending on what the thread using it does). While
+ this is efficient, it has a side-effect one must know:
+ The size of the relay log on disk (displayed by 'ls -l' on Unix) can be a
+ few kilobytes less than one would expect by doing SHOW SLAVE STATUS; this
+ happens when only the IO thread is started (not the SQL thread). The
+ "missing" kilobytes are in memory, are preserved during 'STOP SLAVE; START
+ SLAVE IO_THREAD', and are flushed to disk when the slave's mysqld stops. So
+ this does not cause any bug. Example of how disk size grows by leaps:
+
+ Read_Master_Log_Pos: 7811 -rw-rw---- 1 guilhem qq 4 Jun 5 16:19 gbichot2-relay-bin.002
+ ...later...
+ Read_Master_Log_Pos: 9744 -rw-rw---- 1 guilhem qq 8192 Jun 5 16:27 gbichot2-relay-bin.002
+
+ See how 4 is less than 7811 and 8192 is less than 9744.
+
+ WARNING: this is risky because the slave can stay like this for a long
+ time; then if it has a power failure, master.info says the I/O thread has
+ read until 9744 while the relay-log contains only until 8192 (the
+ in-memory part from 8192 to 9744 has been lost), so the SQL slave thread
+ will miss some events, silently breaking replication.
+ Ideally we would like to flush master.info only when we know that the relay
+ log has no in-memory tail.
+ Note that the above problem may arise only when only the IO thread is
+ started, which is unlikely.
+ */
+
+ /*
+ For the maximum log size, we choose max_relay_log_size if it is
+ non-zero, max_binlog_size otherwise. If later the user does SET
+ GLOBAL on one of these variables, fix_max_binlog_size and
+ fix_max_relay_log_size will reconsider the choice (for example
+ if the user changes max_relay_log_size to zero, we have to
+ switch to using max_binlog_size for the relay log) and update
+ rli->relay_log.max_size (and mysql_bin_log.max_size).
+ */
+
if (open_log(&rli->relay_log, glob_hostname, opt_relay_logname,
"-relay-bin", opt_relaylog_index_name,
LOG_BIN, 1 /* read_append cache */,
- 1 /* no auto events */))
+ 1 /* no auto events */,
+ max_relay_log_size ? max_relay_log_size : max_binlog_size))
+ {
+ sql_print_error("Failed in open_log() called from init_relay_log_info()");
DBUG_RETURN(1);
+ }
/* if file does not exist */
if (access(fname,F_OK))
@@ -1261,10 +1354,18 @@ int init_relay_log_info(RELAY_LOG_INFO* rli, const char* info_fname)
*/
if (info_fd >= 0)
my_close(info_fd, MYF(MY_WME));
- if ((info_fd = my_open(fname, O_CREAT|O_RDWR|O_BINARY, MYF(MY_WME))) < 0 ||
- init_io_cache(&rli->info_file, info_fd, IO_SIZE*2, READ_CACHE, 0L,0,
- MYF(MY_WME)))
+ if ((info_fd = my_open(fname, O_CREAT|O_RDWR|O_BINARY, MYF(MY_WME))) < 0)
+ {
+ sql_print_error("Failed to create a new relay log info file (\
+file '%s', errno %d)", fname, my_errno);
+ msg= current_thd->net.last_error;
+ goto err;
+ }
+ if (init_io_cache(&rli->info_file, info_fd, IO_SIZE*2, READ_CACHE, 0L,0,
+ MYF(MY_WME)))
{
+ sql_print_error("Failed to create a cache on relay log info file '%s'",
+ fname);
msg= current_thd->net.last_error;
goto err;
}
@@ -1272,7 +1373,10 @@ int init_relay_log_info(RELAY_LOG_INFO* rli, const char* info_fname)
/* Init relay log with first entry in the relay index file */
if (init_relay_log_pos(rli,NullS,BIN_LOG_HEADER_SIZE,0 /* no data lock */,
&msg))
+ {
+ sql_print_error("Failed to open the relay log 'FIRST' (relay_log_pos 4");
goto err;
+ }
rli->group_master_log_name[0]= 0;
rli->group_master_log_pos= 0;
rli->info_fd= info_fd;
@@ -1281,18 +1385,34 @@ int init_relay_log_info(RELAY_LOG_INFO* rli, const char* info_fname)
{
if (info_fd >= 0)
reinit_io_cache(&rli->info_file, READ_CACHE, 0L,0,0);
- else if ((info_fd = my_open(fname, O_RDWR|O_BINARY, MYF(MY_WME))) < 0 ||
- init_io_cache(&rli->info_file, info_fd,
- IO_SIZE*2, READ_CACHE, 0L, 0, MYF(MY_WME)))
+ else
{
- if (info_fd >= 0)
- my_close(info_fd, MYF(0));
- rli->info_fd= -1;
- rli->relay_log.close(1);
- pthread_mutex_unlock(&rli->data_lock);
- DBUG_RETURN(1);
+ int error=0;
+ if ((info_fd = my_open(fname, O_RDWR|O_BINARY, MYF(MY_WME))) < 0)
+ {
+ sql_print_error("\
+Failed to open the existing relay log info file '%s' (errno %d)",
+ fname, my_errno);
+ error= 1;
+ }
+ else if (init_io_cache(&rli->info_file, info_fd,
+ IO_SIZE*2, READ_CACHE, 0L, 0, MYF(MY_WME)))
+ {
+ sql_print_error("Failed to create a cache on relay log info file '%s'",
+ fname);
+ error= 1;
+ }
+ if (error)
+ {
+ if (info_fd >= 0)
+ my_close(info_fd, MYF(0));
+ rli->info_fd= -1;
+ rli->relay_log.close(LOG_CLOSE_INDEX | LOG_CLOSE_STOP_EVENT);
+ pthread_mutex_unlock(&rli->data_lock);
+ DBUG_RETURN(1);
+ }
}
-
+
rli->info_fd = info_fd;
int relay_log_pos, master_log_pos;
if (init_strvar_from_file(rli->group_relay_log_name,
@@ -1318,7 +1438,13 @@ int init_relay_log_info(RELAY_LOG_INFO* rli, const char* info_fname)
rli->group_relay_log_pos,
0 /* no data lock*/,
&msg))
+ {
+ char llbuf[22];
+ sql_print_error("Failed to open the relay log '%s' (relay_log_pos %s)",
+ rli->group_relay_log_name,
+ llstr(rli->group_relay_log_pos, llbuf));
goto err;
+ }
}
DBUG_ASSERT(rli->event_relay_log_pos >= BIN_LOG_HEADER_SIZE);
DBUG_ASSERT(my_b_tell(rli->cur_log) == rli->event_relay_log_pos);
@@ -1327,7 +1453,8 @@ int init_relay_log_info(RELAY_LOG_INFO* rli, const char* info_fname)
before flush_relay_log_info
*/
reinit_io_cache(&rli->info_file, WRITE_CACHE,0L,0,1);
- error= flush_relay_log_info(rli);
+ if ((error= flush_relay_log_info(rli)))
+ sql_print_error("Failed to flush relay log info file");
if (count_relay_log_space(rli))
{
msg="Error counting relay log space";
@@ -1343,7 +1470,7 @@ err:
if (info_fd >= 0)
my_close(info_fd, MYF(0));
rli->info_fd= -1;
- rli->relay_log.close(1);
+ rli->relay_log.close(LOG_CLOSE_INDEX | LOG_CLOSE_STOP_EVENT);
pthread_mutex_unlock(&rli->data_lock);
DBUG_RETURN(1);
}
@@ -1372,7 +1499,7 @@ static bool wait_for_relay_log_space(RELAY_LOG_INFO* rli)
{
bool slave_killed=0;
MASTER_INFO* mi = rli->mi;
- const char* save_proc_info;
+ const char *save_proc_info;
THD* thd = mi->io_thd;
DBUG_ENTER("wait_for_relay_log_space");
@@ -1380,12 +1507,14 @@ static bool wait_for_relay_log_space(RELAY_LOG_INFO* rli)
pthread_mutex_lock(&rli->log_space_lock);
save_proc_info = thd->proc_info;
thd->proc_info = "Waiting for relay log space to free";
-
+ save_proc_info= thd->enter_cond(&rli->log_space_cond,
+ &rli->log_space_lock,
+ "Waiting for relay log space to free");
while (rli->log_space_limit < rli->log_space_total &&
!(slave_killed=io_slave_killed(thd,mi)) &&
!rli->ignore_log_space_limit)
pthread_cond_wait(&rli->log_space_cond, &rli->log_space_lock);
- thd->proc_info = save_proc_info;
+ thd->exit_cond(save_proc_info);
pthread_mutex_unlock(&rli->log_space_lock);
DBUG_RETURN(slave_killed);
}
@@ -1406,9 +1535,36 @@ static int count_relay_log_space(RELAY_LOG_INFO* rli)
if (add_relay_log(rli,&linfo))
DBUG_RETURN(1);
} while (!rli->relay_log.find_next_log(&linfo, 1));
+ /*
+ As we have counted everything, including what may have written in a
+ preceding write, we must reset bytes_written, or we may count some space
+ twice.
+ */
+ rli->relay_log.reset_bytes_written();
DBUG_RETURN(0);
}
+void init_master_info_with_options(MASTER_INFO* mi)
+{
+ mi->master_log_name[0] = 0;
+ mi->master_log_pos = BIN_LOG_HEADER_SIZE; // skip magic number
+
+ if (master_host)
+ strmake(mi->host, master_host, sizeof(mi->host) - 1);
+ if (master_user)
+ strmake(mi->user, master_user, sizeof(mi->user) - 1);
+ if (master_password)
+ strmake(mi->password, master_password, HASH_PASSWORD_LENGTH);
+ mi->port = master_port;
+ mi->connect_retry = master_connect_retry;
+}
+
+void clear_last_slave_error(RELAY_LOG_INFO* rli)
+{
+ //Clear the errors displayed by SHOW SLAVE STATUS
+ rli->last_slave_error[0]=0;
+ rli->last_slave_errno=0;
+}
int init_master_info(MASTER_INFO* mi, const char* master_info_fname,
const char* slave_info_fname,
@@ -1431,6 +1587,8 @@ int init_master_info(MASTER_INFO* mi, const char* master_info_fname,
pthread_mutex_lock(&mi->data_lock);
fd = mi->fd;
+
+ /* does master.info exist ? */
if (access(fname,F_OK))
{
@@ -1445,32 +1603,44 @@ int init_master_info(MASTER_INFO* mi, const char* master_info_fname,
*/
if (fd >= 0)
my_close(fd, MYF(MY_WME));
- if ((fd = my_open(fname, O_CREAT|O_RDWR|O_BINARY, MYF(MY_WME))) < 0 ||
- init_io_cache(&mi->file, fd, IO_SIZE*2, READ_CACHE, 0L,0,
+ if ((fd = my_open(fname, O_CREAT|O_RDWR|O_BINARY, MYF(MY_WME))) < 0 )
+ {
+ sql_print_error("Failed to create a new master info file (\
+file '%s', errno %d)", fname, my_errno);
+ goto err;
+ }
+ if (init_io_cache(&mi->file, fd, IO_SIZE*2, READ_CACHE, 0L,0,
MYF(MY_WME)))
+ {
+ sql_print_error("Failed to create a cache on master info file (\
+file '%s')", fname);
goto err;
+ }
- mi->master_log_name[0] = 0;
- mi->master_log_pos = BIN_LOG_HEADER_SIZE; // skip magic number
mi->fd = fd;
-
- if (master_host)
- strmake(mi->host, master_host, sizeof(mi->host) - 1);
- if (master_user)
- strmake(mi->user, master_user, sizeof(mi->user) - 1);
- if (master_password)
- strmake(mi->password, master_password, HASH_PASSWORD_LENGTH);
- mi->port = master_port;
- mi->connect_retry = master_connect_retry;
+ init_master_info_with_options(mi);
+
}
else // file exists
{
if (fd >= 0)
reinit_io_cache(&mi->file, READ_CACHE, 0L,0,0);
- else if ((fd = my_open(fname, O_RDWR|O_BINARY, MYF(MY_WME))) < 0 ||
- init_io_cache(&mi->file, fd, IO_SIZE*2, READ_CACHE, 0L,
- 0, MYF(MY_WME)))
- goto err;
+ else
+ {
+ if ((fd = my_open(fname, O_RDWR|O_BINARY, MYF(MY_WME))) < 0 )
+ {
+ sql_print_error("Failed to open the existing master info file (\
+file '%s', errno %d)", fname, my_errno);
+ goto err;
+ }
+ if (init_io_cache(&mi->file, fd, IO_SIZE*2, READ_CACHE, 0L,
+ 0, MYF(MY_WME)))
+ {
+ sql_print_error("Failed to create a cache on master info file (\
+file '%s')", fname);
+ goto err;
+ }
+ }
mi->fd = fd;
int port, connect_retry, master_log_pos;
@@ -1511,7 +1681,8 @@ int init_master_info(MASTER_INFO* mi, const char* master_info_fname,
mi->inited = 1;
// now change cache READ -> WRITE - must do this before flush_master_info
reinit_io_cache(&mi->file, WRITE_CACHE,0L,0,1);
- error=test(flush_master_info(mi));
+ if ((error=test(flush_master_info(mi))))
+ sql_print_error("Failed to flush master info file");
pthread_mutex_unlock(&mi->data_lock);
DBUG_RETURN(error);
@@ -1565,6 +1736,48 @@ int register_slave_on_master(MYSQL* mysql)
}
+/*
+ Builds a String from a HASH of TABLE_RULE_ENT. Cannot be used for any other
+ hash, as it assumes that the hash entries are TABLE_RULE_ENT.
+
+ SYNOPSIS
+ table_rule_ent_hash_to_str()
+ s pointer to the String to fill
+ h pointer to the HASH to read
+
+ RETURN VALUES
+ none
+*/
+
+void table_rule_ent_hash_to_str(String* s, HASH* h)
+{
+ s->length(0);
+ for (uint i=0 ; i < h->records ; i++)
+ {
+ TABLE_RULE_ENT* e= (TABLE_RULE_ENT*) hash_element(h, i);
+ if (s->length())
+ s->append(',');
+ s->append(e->db,e->key_len);
+ }
+}
+
+/*
+ Mostly the same thing as above
+*/
+
+void table_rule_ent_dynamic_array_to_str(String* s, DYNAMIC_ARRAY* a)
+{
+ s->length(0);
+ for (uint i=0 ; i < a->elements ; i++)
+ {
+ TABLE_RULE_ENT* e;
+ get_dynamic(a, (gptr)&e, i);
+ if (s->length())
+ s->append(',');
+ s->append(e->db,e->key_len);
+ }
+}
+
int show_master_info(THD* thd, MASTER_INFO* mi)
{
// TODO: fix this for multi-master
@@ -1594,6 +1807,11 @@ int show_master_info(THD* thd, MASTER_INFO* mi)
field_list.push_back(new Item_empty_string("Slave_SQL_Running", 3));
field_list.push_back(new Item_empty_string("Replicate_do_db", 20));
field_list.push_back(new Item_empty_string("Replicate_ignore_db", 20));
+ field_list.push_back(new Item_empty_string("Replicate_do_table", 20));
+ field_list.push_back(new Item_empty_string("Replicate_ignore_table", 23));
+ field_list.push_back(new Item_empty_string("Replicate_wild_do_table", 24));
+ field_list.push_back(new Item_empty_string("Replicate_wild_ignore_table",
+ 28));
field_list.push_back(new Item_return_int("Last_errno", 4, MYSQL_TYPE_LONG));
field_list.push_back(new Item_empty_string("Last_error", 20));
field_list.push_back(new Item_return_int("Skip_counter", 10,
@@ -1607,6 +1825,7 @@ int show_master_info(THD* thd, MASTER_INFO* mi)
if (mi->host[0])
{
+ DBUG_PRINT("info",("host is set: '%s'", mi->host));
String *packet= &thd->packet;
protocol->prepare_for_resend();
@@ -1619,13 +1838,31 @@ int show_master_info(THD* thd, MASTER_INFO* mi)
protocol->store(mi->master_log_name, &my_charset_bin);
protocol->store((ulonglong) mi->master_log_pos);
protocol->store(mi->rli.group_relay_log_name +
- dirname_length(mi->rli.group_relay_log_name), &my_charset_bin);
+ dirname_length(mi->rli.group_relay_log_name),
+ &my_charset_bin);
protocol->store((ulonglong) mi->rli.group_relay_log_pos);
protocol->store(mi->rli.group_master_log_name, &my_charset_bin);
protocol->store(mi->slave_running ? "Yes":"No", &my_charset_bin);
protocol->store(mi->rli.slave_running ? "Yes":"No", &my_charset_bin);
protocol->store(&replicate_do_db);
protocol->store(&replicate_ignore_db);
+ /*
+ We can't directly use some protocol->store for
+ replicate_*_table,
+ as Protocol doesn't know the TABLE_RULE_ENT struct.
+ We first build Strings and then pass them to protocol->store.
+ */
+ char buf[256];
+ String tmp(buf, sizeof(buf), &my_charset_bin);
+ table_rule_ent_hash_to_str(&tmp, &replicate_do_table);
+ protocol->store(&tmp);
+ table_rule_ent_hash_to_str(&tmp, &replicate_ignore_table);
+ protocol->store(&tmp);
+ table_rule_ent_dynamic_array_to_str(&tmp, &replicate_wild_do_table);
+ protocol->store(&tmp);
+ table_rule_ent_dynamic_array_to_str(&tmp, &replicate_wild_ignore_table);
+ protocol->store(&tmp);
+
protocol->store((uint32) mi->rli.last_slave_errno);
protocol->store(mi->rli.last_slave_error, &my_charset_bin);
protocol->store((uint32) mi->rli.slave_skip_counter);
@@ -1669,8 +1906,8 @@ st_relay_log_info::st_relay_log_info()
group_relay_log_name[0]= event_relay_log_name[0]= group_master_log_name[0]= 0;
last_slave_error[0]=0;
- bzero(&info_file,sizeof(info_file));
- bzero(&cache_buf, sizeof(cache_buf));
+ bzero((char*) &info_file, sizeof(info_file));
+ bzero((char*) &cache_buf, sizeof(cache_buf));
pthread_mutex_init(&run_lock, MY_MUTEX_INIT_FAST);
pthread_mutex_init(&data_lock, MY_MUTEX_INIT_FAST);
pthread_mutex_init(&log_space_lock, MY_MUTEX_INIT_FAST);
@@ -1678,6 +1915,7 @@ st_relay_log_info::st_relay_log_info()
pthread_cond_init(&start_cond, NULL);
pthread_cond_init(&stop_cond, NULL);
pthread_cond_init(&log_space_cond, NULL);
+ relay_log.init_pthread_objects();
}
@@ -1736,11 +1974,17 @@ int st_relay_log_info::wait_for_pos(THD* thd, String* log_name,
pthread_mutex_lock(&data_lock);
/*
- This function will abort when it notices that
- some CHANGE MASTER or RESET MASTER has changed
- the master info. To catch this, these commands
- modify abort_pos_wait ; we just monitor abort_pos_wait
- and see if it has changed.
+ This function will abort when it notices that some CHANGE MASTER or
+ RESET MASTER has changed the master info.
+ To catch this, these commands modify abort_pos_wait ; We just monitor
+ abort_pos_wait and see if it has changed.
+ Why do we have this mechanism instead of simply monitoring slave_running
+ in the loop (we do this too), as CHANGE MASTER/RESET SLAVE require that
+ the SQL thread be stopped?
+ This is becasue if someones does:
+ STOP SLAVE;CHANGE MASTER/RESET SLAVE; START SLAVE;
+ the change may happen very quickly and we may not notice that
+ slave_running briefly switches between 1/0/1.
*/
init_abort_pos_wait= abort_pos_wait;
@@ -1761,7 +2005,7 @@ int st_relay_log_info::wait_for_pos(THD* thd, String* log_name,
error= -2; //means improper arguments
goto err;
}
- //p points to '.'
+ /* p points to '.' */
log_name_extension= strtoul(++p, &p_end, 10);
/*
p_end points to the first invalid character.
@@ -1774,10 +2018,10 @@ int st_relay_log_info::wait_for_pos(THD* thd, String* log_name,
goto err;
}
- //"compare and wait" main loop
+ /* The "compare and wait" main loop */
while (!thd->killed &&
init_abort_pos_wait == abort_pos_wait &&
- mi->slave_running)
+ slave_running)
{
bool pos_reached;
int cmp_result= 0;
@@ -1815,6 +2059,10 @@ int st_relay_log_info::wait_for_pos(THD* thd, String* log_name,
DBUG_PRINT("info",("Waiting for master update"));
const char* msg = thd->enter_cond(&data_cond, &data_lock,
"Waiting for master update");
+ /*
+ We are going to pthread_cond_(timed)wait(); if the SQL thread stops it
+ will wake us up.
+ */
if (timeout > 0)
{
/*
@@ -1832,6 +2080,7 @@ int st_relay_log_info::wait_for_pos(THD* thd, String* log_name,
}
else
pthread_cond_wait(&data_cond, &data_lock);
+ DBUG_PRINT("info",("Got signal of master update"));
thd->exit_cond(msg);
if (error == ETIMEDOUT || error == ETIME)
{
@@ -1840,6 +2089,7 @@ int st_relay_log_info::wait_for_pos(THD* thd, String* log_name,
}
error=0;
event_count++;
+ DBUG_PRINT("info",("Testing if killed or SQL thread not running"));
}
err:
@@ -1848,11 +2098,11 @@ err:
improper_arguments: %d timed_out: %d",
(int) thd->killed,
(int) (init_abort_pos_wait != abort_pos_wait),
- (int) mi->slave_running,
+ (int) slave_running,
(int) (error == -2),
(int) (error == -1)));
if (thd->killed || init_abort_pos_wait != abort_pos_wait ||
- !mi->slave_running)
+ !slave_running)
{
error= -2;
}
@@ -2074,14 +2324,13 @@ int check_expected_error(THD* thd, RELAY_LOG_INFO* rli, int expected_error)
case ER_NET_ERROR_ON_WRITE:
case ER_SERVER_SHUTDOWN:
case ER_NEW_ABORTING_CONNECTION:
- my_snprintf(rli->last_slave_error, sizeof(rli->last_slave_error),
- "Slave: query '%s' partially completed on the master \
+ slave_print_error(rli,expected_error,
+ "query '%s' partially completed on the master \
and was aborted. There is a chance that your master is inconsistent at this \
point. If you are sure that your master is ok, run this query manually on the\
slave and then restart the slave with SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1;\
- SLAVE START;", thd->query);
- rli->last_slave_errno = expected_error;
- sql_print_error("%s",rli->last_slave_error);
+ SLAVE START; .", thd->query);
+ thd->query_error= 1;
return 1;
default:
return 0;
@@ -2095,8 +2344,7 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli)
DBUG_ASSERT(rli->sql_thd==thd);
if (sql_slave_killed(thd,rli))
{
- /* do not forget to free ev ! */
- if (ev) delete ev;
+ delete ev;
return 1;
}
if (ev)
@@ -2137,6 +2385,7 @@ static int exec_relay_log_event(THD* thd, RELAY_LOG_INFO* rli)
thd->server_id = ev->server_id; // use the original server id for logging
thd->set_time(); // time the query
+ thd->lex.current_select= 0;
if (!ev->when)
ev->when = time(NULL);
ev->thd = thd;
@@ -2390,6 +2639,17 @@ reconnect done to recover from failed read");
for no reason, but this function will do a clean read, notice the clean
value and exit immediately.
*/
+#ifndef DBUG_OFF
+ {
+ char llbuf1[22], llbuf2[22];
+ DBUG_PRINT("info", ("log_space_limit=%s log_space_total=%s \
+ignore_log_space_limit=%d",
+ llstr(mi->rli.log_space_limit,llbuf1),
+ llstr(mi->rli.log_space_total,llbuf2),
+ (int) mi->rli.ignore_log_space_limit));
+ }
+#endif
+
if (mi->rli.log_space_limit && mi->rli.log_space_limit <
mi->rli.log_space_total &&
!mi->rli.ignore_log_space_limit)
@@ -2502,6 +2762,13 @@ slave_begin:
pthread_mutex_unlock(&rli->run_lock);
pthread_cond_broadcast(&rli->start_cond);
+ /*
+ Reset errors for a clean start (otherwise, if the master is idle, the SQL
+ thread may execute no Query_log_event, so the error will remain even
+ though there's no problem anymore).
+ */
+ clear_last_slave_error(rli);
+
//tell the I/O thread to take relay_log_space_limit into account from now on
pthread_mutex_lock(&rli->log_space_lock);
rli->ignore_log_space_limit= 0;
@@ -2561,8 +2828,16 @@ the slave SQL thread with \"SLAVE START\". We stopped at log \
VOID(pthread_mutex_unlock(&LOCK_thread_count));
thd->proc_info = "Waiting for slave mutex on exit";
pthread_mutex_lock(&rli->run_lock);
+ /* We need data_lock, at least to wake up any waiting master_pos_wait() */
+ pthread_mutex_lock(&rli->data_lock);
DBUG_ASSERT(rli->slave_running == 1); // tracking buffer overrun
- rli->slave_running = 0;
+ /* When master_pos_wait() wakes up it will check this and terminate */
+ rli->slave_running= 0;
+ /* Wake up master_pos_wait() */
+ pthread_mutex_unlock(&rli->data_lock);
+ DBUG_PRINT("info",("Signaling possibly waiting master_pos_wait() functions"));
+ pthread_cond_broadcast(&rli->data_cond);
+ rli->ignore_log_space_limit= 0; /* don't need any lock */
rli->save_temporary_tables = thd->temporary_tables;
/*
@@ -2947,7 +3222,7 @@ void end_relay_log_info(RELAY_LOG_INFO* rli)
rli->cur_log_fd = -1;
}
rli->inited = 0;
- rli->relay_log.close(1);
+ rli->relay_log.close(LOG_CLOSE_INDEX | LOG_CLOSE_STOP_EVENT);
DBUG_VOID_RETURN;
}
@@ -3210,8 +3485,21 @@ Log_event* next_event(RELAY_LOG_INFO* rli)
hot_log=0; // Using old binary log
}
}
- DBUG_ASSERT(my_b_tell(cur_log) >= BIN_LOG_HEADER_SIZE);
- DBUG_ASSERT(my_b_tell(cur_log) == rli->event_relay_log_pos);
+#ifndef DBUG_OFF
+ {
+ char llbuf1[22], llbuf2[22];
+ DBUG_ASSERT(my_b_tell(cur_log) >= BIN_LOG_HEADER_SIZE);
+ /*
+ The next assertion sometimes (very rarely) fails, let's try to track
+ it
+ */
+ DBUG_PRINT("info", ("\
+Before assert, my_b_tell(cur_log)=%s rli->event_relay_log_pos=%s",
+ llstr(my_b_tell(cur_log),llbuf1),
+ llstr(rli->group_relay_log_pos,llbuf2)));
+ DBUG_ASSERT(my_b_tell(cur_log) == rli->event_relay_log_pos);
+ }
+#endif
/*
Relay log is always in new format - if the master is 3.23, the
I/O thread will convert the format for us
@@ -3271,8 +3559,8 @@ Log_event* next_event(RELAY_LOG_INFO* rli)
log), and also when the SQL thread starts. We should also reset
ignore_log_space_limit to 0 when the user does RESET SLAVE, but in
fact, no need as RESET SLAVE requires that the slave
- be stopped, and when the SQL thread is later restarted
- ignore_log_space_limit will be reset to 0.
+ be stopped, and the SQL thread sets ignore_log_space_limit to 0 when
+ it stops.
*/
pthread_mutex_lock(&rli->log_space_lock);
// prevent the I/O thread from blocking next times
@@ -3403,6 +3691,53 @@ err:
DBUG_RETURN(0);
}
+/*
+ Rotate a relay log (this is used only by FLUSH LOGS; the automatic rotation
+ because of size is simpler because when we do it we already have all relevant
+ locks; here we don't, so this function is mainly taking locks).
+ Returns nothing as we cannot catch any error (MYSQL_LOG::new_file() is void).
+*/
+
+void rotate_relay_log(MASTER_INFO* mi)
+{
+ DBUG_ENTER("rotate_relay_log");
+ RELAY_LOG_INFO* rli= &mi->rli;
+
+ lock_slave_threads(mi);
+ pthread_mutex_lock(&rli->data_lock);
+ /*
+ We need to test inited because otherwise, new_file() will attempt to lock
+ LOCK_log, which may not be inited (if we're not a slave).
+ */
+ if (!rli->inited)
+ {
+ DBUG_PRINT("info", ("rli->inited == 0"));
+ goto end;
+ }
+
+ /* If the relay log is closed, new_file() will do nothing. */
+ rli->relay_log.new_file(1);
+
+ /*
+ We harvest now, because otherwise BIN_LOG_HEADER_SIZE will not immediately
+ be counted, so imagine a succession of FLUSH LOGS and assume the slave
+ threads are started:
+ relay_log_space decreases by the size of the deleted relay log, but does
+ not increase, so flush-after-flush we may become negative, which is wrong.
+ Even if this will be corrected as soon as a query is replicated on the
+ slave (because the I/O thread will then call harvest_bytes_written() which
+ will harvest all these BIN_LOG_HEADER_SIZE we forgot), it may give strange
+ output in SHOW SLAVE STATUS meanwhile. So we harvest now.
+ If the log is closed, then this will just harvest the last writes, probably
+ 0 as they probably have been harvested.
+ */
+ rli->relay_log.harvest_bytes_written(&rli->log_space_total);
+end:
+ pthread_mutex_unlock(&rli->data_lock);
+ unlock_slave_threads(mi);
+ DBUG_VOID_RETURN;
+}
+
#ifdef __GNUC__
template class I_List_iterator<i_string>;
diff --git a/sql/slave.h b/sql/slave.h
index 429456eb0bb..0cd291a50f8 100644
--- a/sql/slave.h
+++ b/sql/slave.h
@@ -47,6 +47,11 @@ extern "C" {
extern ulong slave_net_timeout;
};
+enum enum_binlog_formats {
+ BINLOG_FORMAT_CURRENT=0, /* 0 is important for easy 'if (mi->old_format)' */
+ BINLOG_FORMAT_323_LESS_57,
+ BINLOG_FORMAT_323_GEQ_57 };
+
/*
TODO: this needs to be redone, but for now it does not matter since
we do not have multi-master yet.
@@ -284,20 +289,20 @@ Log_event* next_event(RELAY_LOG_INFO* rli);
typedef struct st_master_info
{
char master_log_name[FN_REFLEN];
+ char host[HOSTNAME_LENGTH+1];
+ char user[USERNAME_LENGTH+1];
+ char password[MAX_PASSWORD_LENGTH+1];
my_off_t master_log_pos;
File fd; // we keep the file open, so we need to remember the file pointer
IO_CACHE file;
/* the variables below are needed because we can change masters on the fly */
- char host[HOSTNAME_LENGTH+1];
- char user[USERNAME_LENGTH+1];
- char password[HASH_PASSWORD_LENGTH+1];
pthread_mutex_t data_lock,run_lock;
pthread_cond_t data_cond,start_cond,stop_cond;
THD *io_thd;
MYSQL* mysql;
- uint32 file_id; /* for 3.23 load data infile */
+ uint32 file_id; /* for 3.23 load data infile */
RELAY_LOG_INFO rli;
uint port;
uint connect_retry;
@@ -305,16 +310,16 @@ typedef struct st_master_info
int events_till_abort;
#endif
bool inited;
- bool old_format; /* master binlog is in 3.23 format */
+ enum enum_binlog_formats old_format;
volatile bool abort_slave, slave_running;
volatile ulong slave_run_id;
st_master_info()
- :fd(-1), io_thd(0), inited(0), old_format(0),abort_slave(0),
- slave_running(0), slave_run_id(0)
+ :fd(-1), io_thd(0), inited(0), old_format(BINLOG_FORMAT_CURRENT),
+ abort_slave(0),slave_running(0), slave_run_id(0)
{
host[0] = 0; user[0] = 0; password[0] = 0;
- bzero(&file, sizeof(file));
+ bzero((char*) &file, sizeof(file));
pthread_mutex_init(&run_lock, MY_MUTEX_INIT_FAST);
pthread_mutex_init(&data_lock, MY_MUTEX_INIT_FAST);
pthread_cond_init(&data_cond, NULL);
@@ -398,6 +403,8 @@ int mysql_table_dump(THD* thd, const char* db,
int fetch_master_table(THD* thd, const char* db_name, const char* table_name,
MASTER_INFO* mi, MYSQL* mysql);
+void table_rule_ent_hash_to_str(String* s, HASH* h);
+void table_rule_ent_dynamic_array_to_str(String* s, DYNAMIC_ARRAY* a);
int show_master_info(THD* thd, MASTER_INFO* mi);
int show_binlog_info(THD* thd);
@@ -416,12 +423,15 @@ int add_table_rule(HASH* h, const char* table_spec);
int add_wild_table_rule(DYNAMIC_ARRAY* a, const char* table_spec);
void init_table_rule_hash(HASH* h, bool* h_inited);
void init_table_rule_array(DYNAMIC_ARRAY* a, bool* a_inited);
-char* rewrite_db(char* db);
+const char *rewrite_db(const char* db);
+const char *print_slave_db_safe(const char* db);
int check_expected_error(THD* thd, RELAY_LOG_INFO* rli, int error_code);
void skip_load_data_infile(NET* net);
-void slave_print_error(RELAY_LOG_INFO* rli,int err_code, const char* msg, ...);
+void slave_print_error(RELAY_LOG_INFO* rli, int err_code, const char* msg, ...);
void end_slave(); /* clean up */
+void init_master_info_with_options(MASTER_INFO* mi);
+void clear_last_slave_error(RELAY_LOG_INFO* rli);
int init_master_info(MASTER_INFO* mi, const char* master_info_fname,
const char* slave_info_fname,
bool abort_if_no_master_info_file);
@@ -436,6 +446,7 @@ int init_relay_log_pos(RELAY_LOG_INFO* rli,const char* log,ulonglong pos,
int purge_relay_logs(RELAY_LOG_INFO* rli, THD *thd, bool just_reset,
const char** errmsg);
+void rotate_relay_log(MASTER_INFO* mi);
extern "C" pthread_handler_decl(handle_slave_io,arg);
extern "C" pthread_handler_decl(handle_slave_sql,arg);
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 1bdca7167e8..9738c0c5d9e 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -1,4 +1,4 @@
-/* Copyright (C) 2000 MySQL AB
+/* Copyright (C) 2000-2003 MySQL AB
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
@@ -155,7 +155,7 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables)
host.db= get_field(&mem, table->field[1]);
host.access= get_access(table,2);
host.access= fix_rights_for_db(host.access);
- host.sort= get_sort(2,host.host.hostname,host.db);
+ host.sort= get_sort(2,host.host.hostname,host.db);
#ifndef TO_BE_REMOVED
if (table->fields == 8)
{ // Without grant
@@ -175,8 +175,7 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables)
if (table->field[2]->field_length == 8 &&
protocol_version == PROTOCOL_VERSION)
{
- sql_print_error(
- "Old 'user' table. (Check README or the Reference manual). Continuing --old-protocol"); /* purecov: tested */
+ sql_print_error("Old 'user' table. (Check README or the Reference manual). Continuing --old-protocol"); /* purecov: tested */
protocol_version=9; /* purecov: tested */
}
@@ -207,10 +206,11 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables)
{
user.pversion=get_password_version(user.password);
/* Only passwords of specific lengths depending on version are allowed */
- if ( (!user.pversion && length % 8) || (user.pversion && length!=45 ))
+ if ((!user.pversion && (length % 8 || length > 16)) ||
+ (user.pversion && length != 45))
{
sql_print_error(
- "Found invalid password for user: '%s@%s'; Ignoring user",
+ "Found invalid password for user: '%s'@'%s'; Ignoring user",
user.user ? user.user : "",
user.host.hostname ? user.host.hostname : ""); /* purecov: tested */
continue; /* purecov: tested */
@@ -221,7 +221,7 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables)
user.sort=get_sort(2,user.host.hostname,user.user);
user.hostname_length= (user.host.hostname ?
(uint) strlen(user.host.hostname) : 0);
- if (table->fields >= 31) /* Starting from 4.0.2 we have more fields */
+ if (table->fields >= 31) /* Starting from 4.0.2 we have more fields */
{
char *ssl_type=get_field(&mem, table->field[24]);
if (!ssl_type)
@@ -250,7 +250,7 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables)
else
{
user.ssl_type=SSL_TYPE_NONE;
- bzero(&(user.user_resource),sizeof(user.user_resource));
+ bzero((char *)&(user.user_resource),sizeof(user.user_resource));
#ifndef TO_BE_REMOVED
if (table->fields <= 13)
{ // Without grant
@@ -342,7 +342,14 @@ void acl_free(bool end)
}
}
- /* Reload acl list if possible */
+
+/*
+ Forget current privileges and read new privileges from the privilege tables
+
+ SYNOPSIS
+ acl_reload()
+ thd Thread handle
+*/
void acl_reload(THD *thd)
{
@@ -507,7 +514,7 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user,
ACL_USER *acl_user= NULL;
DBUG_ENTER("acl_getroot");
- bzero(mqh,sizeof(USER_RESOURCES));
+ bzero((char*) mqh, sizeof(USER_RESOURCES));
if (!initialized)
{
// If no data allow anything
@@ -590,7 +597,6 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user,
/* OK. User found and password checked continue validation */
-#ifdef HAVE_OPENSSL
{
Vio *vio=thd->net.vio;
/*
@@ -604,6 +610,7 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user,
case SSL_TYPE_NONE: /* SSL is not required to connect */
user_access=acl_user->access;
break;
+#ifdef HAVE_OPENSSL
case SSL_TYPE_ANY: /* Any kind of SSL is good enough */
if (vio_type(vio) == VIO_TYPE_SSL)
user_access=acl_user->access;
@@ -616,7 +623,9 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user,
We need to check for absence of SSL because without SSL
we should reject connection.
*/
- if (vio_type(vio) == VIO_TYPE_SSL && SSL_get_peer_certificate(vio->ssl_))
+ if (vio_type(vio) == VIO_TYPE_SSL &&
+ SSL_get_verify_result(vio->ssl_) == X509_V_OK &&
+ SSL_get_peer_certificate(vio->ssl_))
user_access=acl_user->access;
break;
case SSL_TYPE_SPECIFIED: /* Client should have specified attrib */
@@ -626,7 +635,8 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user,
If cipher name is specified, we compare it to actual cipher in
use.
*/
- if (vio_type(vio) != VIO_TYPE_SSL)
+ if (vio_type(vio) != VIO_TYPE_SSL ||
+ SSL_get_verify_result(vio->ssl_) != X509_V_OK)
break;
if (acl_user->ssl_cipher)
{
@@ -686,11 +696,17 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user,
free(ptr);
}
break;
+#else /* HAVE_OPENSSL */
+ default:
+ /*
+ If we don't have SSL but SSL is required for this user the
+ authentication should fail.
+ */
+ break;
+#endif /* HAVE_OPENSSL */
}
}
-#else /* HAVE_OPENSSL */
- user_access=acl_user->access;
-#endif /* HAVE_OPENSSL */
+
*mqh=acl_user->user_resource;
if (!acl_user->user)
*priv_user=(char*) ""; // Change to anonymous user /* purecov: inspected */
@@ -781,7 +797,7 @@ static void acl_insert_user(const char *user, const char *host,
ulong privileges)
{
ACL_USER acl_user;
- acl_user.user=strdup_root(&mem,user);
+ acl_user.user=*user ? strdup_root(&mem,user) : 0;
update_hostname(&acl_user.host,strdup_root(&mem,host));
acl_user.password=0;
acl_user.access=privileges;
@@ -872,12 +888,13 @@ static void acl_insert_db(const char *user, const char *host, const char *db,
}
-/*****************************************************************************
-** Get privilege for a host, user and db combination
-*****************************************************************************/
+
+/*
+ Get privilege for a host, user and db combination
+*/
ulong acl_get(const char *host, const char *ip, const char *bin_ip,
- const char *user, const char *db)
+ const char *user, const char *db, my_bool db_is_pattern)
{
ulong host_access,db_access;
uint i,key_length;
@@ -911,7 +928,7 @@ ulong acl_get(const char *host, const char *ip, const char *bin_ip,
{
if (compare_hostname(&acl_db->host,host,ip))
{
- if (!acl_db->db || !wild_compare(db,acl_db->db))
+ if (!acl_db->db || !wild_compare(db,acl_db->db,db_is_pattern))
{
db_access=acl_db->access;
if (acl_db->host.hostname)
@@ -933,7 +950,7 @@ ulong acl_get(const char *host, const char *ip, const char *bin_ip,
ACL_HOST *acl_host=dynamic_element(&acl_hosts,i,ACL_HOST*);
if (compare_hostname(&acl_host->host,host,ip))
{
- if (!acl_host->db || !wild_compare(db,acl_host->db))
+ if (!acl_host->db || !wild_compare(db,acl_host->db,db_is_pattern))
{
host_access=acl_host->access; // Fully specified. Take it
break;
@@ -997,11 +1014,14 @@ int wild_case_compare(CHARSET_INFO *cs, const char *str,const char *wildstr)
DBUG_RETURN (*str != '\0');
}
-/*****************************************************************************
-** check if there are any possible matching entries for this host
-** All host names without wild cards are stored in a hash table,
-** entries with wildcards are stored in a dynamic array
-*****************************************************************************/
+
+/*
+ Check if there are any possible matching entries for this host
+
+ NOTES
+ All host names without wild cards are stored in a hash table,
+ entries with wildcards are stored in a dynamic array
+*/
static void init_check_host(void)
{
@@ -1075,10 +1095,6 @@ bool acl_check_host(const char *host, const char *ip)
return 1; // Host is not allowed
}
-/*****************************************************************************
- Change password for the user if it's not an anonymous user
- Note: This should write the error directly to the client!
-*****************************************************************************/
/*
Check if the user is allowed to change password
@@ -1090,8 +1106,8 @@ bool acl_check_host(const char *host, const char *ip)
user user name
RETURN VALUE
- 0 OK
- 1 ERROR ; In this case the error is sent to the client.
+ 0 OK
+ 1 ERROR ; In this case the error is sent to the client.
*/
bool check_change_password(THD *thd, const char *host, const char *user)
@@ -1206,7 +1222,11 @@ find_acl_user(const char *host, const char *user)
{
ACL_USER *acl_user=dynamic_element(&acl_users,i,ACL_USER*);
DBUG_PRINT("info",("strcmp('%s','%s'), compare_hostname('%s','%s'),",
- user,acl_user->user,(host),(acl_user->host)));
+ user,
+ acl_user->user ? acl_user->user : "",
+ host,
+ acl_user->host.hostname ? acl_user->host.hostname :
+ ""));
if (!acl_user->user && !user[0] ||
acl_user->user && !strcmp(user,acl_user->user))
{
@@ -1219,15 +1239,18 @@ find_acl_user(const char *host, const char *user)
DBUG_RETURN(0);
}
-/*****************************************************************************
- Handle comparing of hostname
- A hostname may be of type:
- hostname (May include wildcards); monty.pp.sci.fi
- ip (May include wildcards); 192.168.0.0
- ip/netmask 192.168.0.0/255.255.255.0
- A net mask of 0.0.0.0 is not allowed.
-*****************************************************************************/
+/*
+ Comparing of hostnames
+
+ NOTES
+ A hostname may be of type:
+ hostname (May include wildcards); monty.pp.sci.fi
+ ip (May include wildcards); 192.168.0.0
+ ip/netmask 192.168.0.0/255.255.255.0
+
+ A net mask of 0.0.0.0 is not allowed.
+*/
static const char *calc_ip(const char *ip, long *val, char end)
{
@@ -1271,13 +1294,13 @@ static bool compare_hostname(const acl_host_and_ip *host, const char *hostname,
return (!host->hostname ||
(hostname && !wild_case_compare(&my_charset_latin1,
hostname,host->hostname)) ||
- (ip && !wild_compare(ip,host->hostname)));
+ (ip && !wild_compare(ip,host->hostname,0)));
}
-/****************************************************************************
- Code to update grants in the user and database privilege tables
-****************************************************************************/
+/*
+ Update grants in the user and database privilege tables
+*/
static bool update_user_table(THD *thd, const char *host, const char *user,
const char *new_password)
@@ -1291,6 +1314,24 @@ static bool update_user_table(THD *thd, const char *host, const char *user,
bzero((char*) &tables,sizeof(tables));
tables.alias=tables.real_name=(char*) "user";
tables.db=(char*) "mysql";
+#ifdef HAVE_REPLICATION
+ /*
+ GRANT and REVOKE are applied the slave in/exclusion rules as they are
+ some kind of updates to the mysql.% tables.
+ */
+ if (thd->slave_thread && table_rules_on)
+ {
+ /*
+ The tables must be marked "updating" so that tables_ok() takes them into
+ account in tests. It's ok to leave 'updating' set after tables_ok.
+ */
+ tables.updating= 1;
+ /* Thanks to bzero, tables.next==0 */
+ if (!tables_ok(0, &tables))
+ DBUG_RETURN(0);
+ }
+#endif
+
if (!(table=open_ltable(thd,&tables,TL_WRITE)))
DBUG_RETURN(1); /* purecov: deadcode */
table->field[0]->store(host,(uint) strlen(host), &my_charset_latin1);
@@ -1331,7 +1372,7 @@ static bool test_if_create_new_users(THD *thd)
tl.db= (char*) "mysql";
tl.real_name= (char*) "user";
db_access=acl_get(thd->host, thd->ip, (char*) &thd->remote.sin_addr,
- thd->priv_user, tl.db);
+ thd->priv_user, tl.db, 0);
if (!(db_access & INSERT_ACL))
{
if (check_grant(thd,INSERT_ACL,&tl,0,1))
@@ -1343,7 +1384,7 @@ static bool test_if_create_new_users(THD *thd)
/****************************************************************************
-** Handle GRANT commands
+ Handle GRANT commands
****************************************************************************/
static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
@@ -1366,8 +1407,8 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
&& combo.password.length != HASH_OLD_PASSWORD_LENGTH)
{
my_printf_error(ER_PASSWORD_NO_MATCH,
- "Password hash should be a %d-digit hexadecimal number",
- MYF(0),HASH_PASSWORD_LENGTH);
+ "Password hash should be a %d-digit hexadecimal number",
+ MYF(0),HASH_PASSWORD_LENGTH);
DBUG_RETURN(-1);
}
password=combo.password.str;
@@ -1540,7 +1581,7 @@ static int replace_db_table(TABLE *table, const char *db,
char what= (revoke_grant) ? 'N' : 'Y';
DBUG_ENTER("replace_db_table");
- // is there such a user in user table in memory ????
+ /* Check if there is such a user in user table in memory? */
if (!initialized || !find_acl_user(combo.host.str,combo.user.str))
{
my_error(ER_PASSWORD_NO_MATCH,MYF(0));
@@ -1552,7 +1593,7 @@ static int replace_db_table(TABLE *table, const char *db,
table->field[2]->store(combo.user.str,combo.user.length, &my_charset_latin1);
table->file->index_init(0);
if (table->file->index_read(table->record[0],(byte*) table->field[0]->ptr,0,
- HA_READ_KEY_EXACT))
+ HA_READ_KEY_EXACT))
{
if (what == 'N')
{ // no row, no revoke
@@ -1583,7 +1624,7 @@ static int replace_db_table(TABLE *table, const char *db,
if (old_row_exists)
{
- // update old existing row
+ /* update old existing row */
if (rights)
{
if ((error=table->file->update_row(table->record[1],table->record[0])))
@@ -1610,11 +1651,11 @@ static int replace_db_table(TABLE *table, const char *db,
DBUG_RETURN(0);
/* This could only happen if the grant tables got corrupted */
- table_error:
+table_error:
table->file->print_error(error,MYF(0)); /* purecov: deadcode */
table->file->index_end();
- abort:
+abort:
DBUG_RETURN(-1);
}
@@ -1730,7 +1771,7 @@ public:
if (!(mem_check = new GRANT_COLUMN(*res,
fix_rights_for_column(priv))))
{
- // Don't use this entry
+ /* Don't use this entry */
privs = cols = 0; /* purecov: deadcode */
return; /* purecov: deadcode */
}
@@ -1912,7 +1953,7 @@ static int replace_column_table(GRANT_TABLE *g_t,
key_length, HA_READ_KEY_EXACT))
goto end;
- // Scan trough all rows with the same host,db,user and table
+ /* Scan through all rows with the same host,db,user and table */
do
{
ulong privileges = (ulong) table->field[6]->val_int();
@@ -1962,7 +2003,7 @@ static int replace_column_table(GRANT_TABLE *g_t,
!key_cmp(table,key,0,key_length));
}
- end:
+end:
table->file->index_end();
DBUG_RETURN(result);
}
@@ -2031,7 +2072,7 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table,
if (revoke_grant)
{
- // column rights are already fixed in mysql_table_grant !
+ /* column rights are already fixed in mysql_table_grant */
store_table_rights=j & ~store_table_rights;
}
else
@@ -2067,7 +2108,7 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table,
if (rights | col_rights)
{
grant_table->privs= rights;
- grant_table->cols= col_rights;
+ grant_table->cols= col_rights;
}
else
{
@@ -2075,19 +2116,36 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table,
}
DBUG_RETURN(0);
- /* This should never happen */
- table_error:
+ /* This should never happen */
+table_error:
table->file->print_error(error,MYF(0)); /* purecov: deadcode */
DBUG_RETURN(-1); /* purecov: deadcode */
}
+/*
+ Store table level and column level grants in the privilege tables
+
+ SYNOPSIS
+ mysql_table_grant()
+ thd Thread handle
+ table_list List of tables to give grant
+ user_list List of users to give grant
+ columns List of columns to give grant
+ rights Table level grant
+ revoke_grant Set to 1 if this is a REVOKE command
+
+ RETURN
+ 0 ok
+ 1 error
+*/
+
int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
List <LEX_USER> &user_list,
List <LEX_COLUMN> &columns, ulong rights,
bool revoke_grant)
{
- ulong column_priv = 0;
+ ulong column_priv= 0;
List_iterator <LEX_USER> str_list (user_list);
LEX_USER *Str;
TABLE_LIST tables[3];
@@ -2097,7 +2155,7 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
if (!initialized)
{
send_error(thd, ER_UNKNOWN_COM_ERROR); /* purecov: inspected */
- return 1; /* purecov: inspected */
+ DBUG_RETURN(1); /* purecov: inspected */
}
if (rights & ~TABLE_ACLS)
{
@@ -2108,21 +2166,21 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
if (columns.elements && !revoke_grant)
{
TABLE *table;
- class LEX_COLUMN *check;
- List_iterator <LEX_COLUMN> iter(columns);
+ class LEX_COLUMN *column;
+ List_iterator <LEX_COLUMN> column_iter(columns);
if (!(table=open_ltable(thd,table_list,TL_READ)))
DBUG_RETURN(-1);
- while ((check = iter++))
+ while ((column = column_iter++))
{
- if (!find_field_in_table(thd,table,check->column.ptr(),
- check->column.length(),0,0))
+ if (!find_field_in_table(thd,table,column->column.ptr(),
+ column->column.length(),0,0))
{
my_printf_error(ER_BAD_FIELD_ERROR,ER(ER_BAD_FIELD_ERROR),MYF(0),
- check->column.c_ptr(), table_list->alias);
+ column->column.c_ptr(), table_list->alias);
DBUG_RETURN(-1);
}
- column_priv |= check->rights | (rights & COL_ACLS);
+ column_priv|= column->rights;
}
close_thread_tables(thd);
}
@@ -2158,8 +2216,16 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
GRANT and REVOKE are applied the slave in/exclusion rules as they are
some kind of updates to the mysql.% tables.
*/
- if (thd->slave_thread && table_rules_on && !tables_ok(0, tables))
- DBUG_RETURN(0);
+ if (thd->slave_thread && table_rules_on)
+ {
+ /*
+ The tables must be marked "updating" so that tables_ok() takes them into
+ account in tests.
+ */
+ tables[0].updating= tables[1].updating= tables[2].updating= 1;
+ if (!tables_ok(0, tables))
+ DBUG_RETURN(0);
+ }
#endif
if (open_and_lock_tables(thd,tables))
@@ -2227,21 +2293,21 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
/* If revoke_grant, calculate the new column privilege for tables_priv */
if (revoke_grant)
{
- class LEX_COLUMN *check;
- List_iterator <LEX_COLUMN> iter(columns);
+ class LEX_COLUMN *column;
+ List_iterator <LEX_COLUMN> column_iter(columns);
GRANT_COLUMN *grant_column;
/* Fix old grants */
- while ((check = iter++))
+ while ((column = column_iter++))
{
grant_column = column_hash_search(grant_table,
- check->column.ptr(),
- check->column.length());
+ column->column.ptr(),
+ column->column.length());
if (grant_column)
- grant_column->rights&= ~(check->rights | rights);
+ grant_column->rights&= ~(column->rights | rights);
}
/* scan trough all columns to get new column grant */
- column_priv=0;
+ column_priv= 0;
for (uint idx=0 ; idx < grant_table->hash_columns.records ; idx++)
{
grant_column= (GRANT_COLUMN*) hash_element(&grant_table->hash_columns,
@@ -2287,8 +2353,8 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
}
-int mysql_grant (THD *thd, const char *db, List <LEX_USER> &list,
- ulong rights, bool revoke_grant)
+int mysql_grant(THD *thd, const char *db, List <LEX_USER> &list,
+ ulong rights, bool revoke_grant)
{
List_iterator <LEX_USER> str_list (list);
LEX_USER *Str;
@@ -2298,8 +2364,8 @@ int mysql_grant (THD *thd, const char *db, List <LEX_USER> &list,
DBUG_ENTER("mysql_grant");
if (!initialized)
{
- send_error(thd, ER_UNKNOWN_COM_ERROR); /* purecov: tested */
- return 1; /* purecov: tested */
+ my_error(ER_UNKNOWN_COM_ERROR, MYF(0)); /* purecov: tested */
+ return -1; /* purecov: tested */
}
if (lower_case_table_names && db)
@@ -2324,8 +2390,16 @@ int mysql_grant (THD *thd, const char *db, List <LEX_USER> &list,
GRANT and REVOKE are applied the slave in/exclusion rules as they are
some kind of updates to the mysql.% tables.
*/
- if (thd->slave_thread && table_rules_on && !tables_ok(0, tables))
- DBUG_RETURN(0);
+ if (thd->slave_thread && table_rules_on)
+ {
+ /*
+ The tables must be marked "updating" so that tables_ok() takes them into
+ account in tests.
+ */
+ tables[0].updating= tables[1].updating= 1;
+ if (!tables_ok(0, tables))
+ DBUG_RETURN(0);
+ }
#endif
if (open_and_lock_tables(thd,tables))
@@ -2337,7 +2411,7 @@ int mysql_grant (THD *thd, const char *db, List <LEX_USER> &list,
if (!revoke_grant)
create_new_users= test_if_create_new_users(thd);
- // go through users in user_list
+ /* go through users in user_list */
rw_wrlock(&LOCK_grant);
VOID(pthread_mutex_lock(&acl_cache->lock));
grant_version++;
@@ -2353,16 +2427,26 @@ int mysql_grant (THD *thd, const char *db, List <LEX_USER> &list,
continue;
}
if ((replace_user_table(thd,
- tables[0].table,
+ tables[0].table,
*Str,
(!db ? rights : 0), revoke_grant,
create_new_users)))
result= -1;
- else
+ else if (db)
{
- if (db && replace_db_table(tables[1].table, db, *Str, rights & DB_ACLS,
- revoke_grant))
+ ulong db_rights= rights & DB_ACLS;
+ if (db_rights == rights)
+ {
+ if (replace_db_table(tables[1].table, db, *Str, db_rights,
+ revoke_grant))
+ result= -1;
+ }
+ else
+ {
+ my_printf_error(ER_WRONG_USAGE, ER(ER_WRONG_USAGE), MYF(0),
+ "DB GRANT","GLOBAL PRIVILEGES");
result= -1;
+ }
}
}
VOID(pthread_mutex_unlock(&acl_cache->lock));
@@ -2475,7 +2559,16 @@ end:
}
-/* Reload grant array (table and column privileges) if possible */
+/*
+ Reload grant array (table and column privileges) if possible
+
+ SYNOPSIS
+ grant_reload()
+ thd Thread handler
+
+ NOTES
+ Locked tables are checked by acl_init and doesn't have to be checked here
+*/
void grant_reload(THD *thd)
{
@@ -2484,8 +2577,6 @@ void grant_reload(THD *thd)
MEM_ROOT old_mem;
DBUG_ENTER("grant_reload");
- // Locked tables are checked by acl_init and doesn't have to be checked here
-
rw_wrlock(&LOCK_grant);
grant_version++;
old_column_priv_hash= column_priv_hash;
@@ -2562,29 +2653,29 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
rw_unlock(&LOCK_grant);
return 0;
- err:
+err:
rw_unlock(&LOCK_grant);
if (!no_errors) // Not a silent skip of table
{
const char *command="";
if (want_access & SELECT_ACL)
- command ="select";
+ command= "select";
else if (want_access & INSERT_ACL)
- command = "insert";
+ command= "insert";
else if (want_access & UPDATE_ACL)
- command = "update";
+ command= "update";
else if (want_access & DELETE_ACL)
- command = "delete";
+ command= "delete";
else if (want_access & DROP_ACL)
- command = "drop";
+ command= "drop";
else if (want_access & CREATE_ACL)
- command = "create";
+ command= "create";
else if (want_access & ALTER_ACL)
- command = "alter";
+ command= "alter";
else if (want_access & INDEX_ACL)
- command = "index";
+ command= "index";
else if (want_access & GRANT_ACL)
- command = "grant";
+ command= "grant";
net_printf(thd,ER_TABLEACCESS_DENIED_ERROR,
command,
thd->priv_user,
@@ -2607,7 +2698,7 @@ bool check_grant_column(THD *thd,TABLE *table, const char *name,
rw_rdlock(&LOCK_grant);
- // reload table if someone has modified any grants
+ /* reload table if someone has modified any grants */
if (table->grant.version != grant_version)
{
@@ -2635,7 +2726,7 @@ bool check_grant_column(THD *thd,TABLE *table, const char *name,
#endif
/* We must use my_printf_error() here! */
- err:
+err:
rw_unlock(&LOCK_grant);
if (!show_tables)
{
@@ -2671,7 +2762,7 @@ bool check_grant_all_columns(THD *thd, ulong want_access, TABLE *table)
rw_rdlock(&LOCK_grant);
- // reload table if someone has modified any grants
+ /* reload table if someone has modified any grants */
if (table->grant.version != grant_version)
{
@@ -2681,7 +2772,7 @@ bool check_grant_all_columns(THD *thd, ulong want_access, TABLE *table)
table->real_name,0); /* purecov: inspected */
table->grant.version=grant_version; /* purecov: inspected */
}
- // The following should always be true
+ /* The following should always be true */
if (!(grant_table=table->grant.grant_table))
goto err; /* purecov: inspected */
@@ -2699,11 +2790,11 @@ bool check_grant_all_columns(THD *thd, ulong want_access, TABLE *table)
err:
rw_unlock(&LOCK_grant);
err2:
- const char *command="";
+ const char *command= "";
if (want_access & SELECT_ACL)
- command ="select";
+ command= "select";
else if (want_access & INSERT_ACL)
- command = "insert";
+ command= "insert";
my_printf_error(ER_COLUMNACCESS_DENIED_ERROR,
ER(ER_COLUMNACCESS_DENIED_ERROR),
MYF(0),
@@ -2716,11 +2807,11 @@ err2:
}
-/****************************************************************************
+/*
Check if a user has the right to access a database
Access is accepted if he has a grant for any table in the database
Return 1 if access is denied
-****************************************************************************/
+*/
bool check_grant_db(THD *thd,const char *db)
{
@@ -2765,8 +2856,8 @@ ulong get_table_grant(THD *thd, TABLE_LIST *table)
#ifdef EMBEDDED_LIBRARY
grant_table= NULL;
#else
- grant_table = table_hash_search(thd->host,thd->ip,db,user,
- table->real_name,0);
+ grant_table= table_hash_search(thd->host, thd->ip, db, user,
+ table->real_name, 0);
#endif
table->grant.grant_table=grant_table; // Remember for column test
table->grant.version=grant_version;
@@ -2785,7 +2876,7 @@ ulong get_column_grant(THD *thd, TABLE_LIST *table, Field *field)
ulong priv;
rw_rdlock(&LOCK_grant);
- // reload table if someone has modified any grants
+ /* reload table if someone has modified any grants */
if (table->grant.version != grant_version)
{
table->grant.grant_table=
@@ -2810,11 +2901,20 @@ ulong get_column_grant(THD *thd, TABLE_LIST *table, Field *field)
return priv;
}
+/* Help function for mysql_show_grants */
-/*****************************************************************************
- SHOW GRANTS : send to client grant-like strings depicting user@host
- privileges
-*****************************************************************************/
+static void add_user_option(String *grant, ulong value, const char *name)
+{
+ if (value)
+ {
+ char buff[22], *p; // just as in int2str
+ grant->append(' ');
+ grant->append(name, strlen(name));
+ grant->append(' ');
+ p=int10_to_str(value, buff, 10);
+ grant->append(buff,p-buff);
+ }
+}
static const char *command_array[]=
{
@@ -2823,18 +2923,27 @@ static const char *command_array[]=
"SUPER", "CREATE TEMPORARY TABLES", "LOCK TABLES", "EXECUTE",
"REPLICATION SLAVE", "REPLICATION CLIENT",
};
+
static uint command_lengths[]=
{
6,6,6,6,6,4,6,8,7,4,5,10,5,5,14,5,23,11,7,17,18
};
+/*
+ SHOW GRANTS; Send grants for a user to the client
+
+ IMPLEMENTATION
+ Send to client grant-like strings depicting user@host privileges
+*/
+
int mysql_show_grants(THD *thd,LEX_USER *lex_user)
{
ulong want_access;
uint counter,index;
int error = 0;
- ACL_USER *acl_user; ACL_DB *acl_db;
+ ACL_USER *acl_user;
+ ACL_DB *acl_db;
char buff[1024];
Protocol *protocol= thd->protocol;
DBUG_ENTER("mysql_show_grants");
@@ -2886,11 +2995,11 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
/* Add first global access grants */
{
- want_access=acl_user->access;
String global(buff,sizeof(buff),&my_charset_latin1);
global.length(0);
global.append("GRANT ",6);
+ want_access= acl_user->access;
if (test_all_bits(want_access, (GLOBAL_ACLS & ~ GRANT_ACL)))
global.append("ALL PRIVILEGES",14);
else if (!(want_access & ~GRANT_ACL))
@@ -2934,25 +3043,25 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
global.append(" REQUIRE ",9);
if (acl_user->x509_issuer)
{
- ssl_options++;
- global.append("ISSUER \'",8);
- global.append(acl_user->x509_issuer,strlen(acl_user->x509_issuer));
+ ssl_options++;
+ global.append("ISSUER \'",8);
+ global.append(acl_user->x509_issuer,strlen(acl_user->x509_issuer));
global.append('\'');
}
if (acl_user->x509_subject)
{
- if (ssl_options++)
- global.append(' ');
- global.append("SUBJECT \'",9);
- global.append(acl_user->x509_subject,strlen(acl_user->x509_subject));
+ if (ssl_options++)
+ global.append(' ');
+ global.append("SUBJECT \'",9);
+ global.append(acl_user->x509_subject,strlen(acl_user->x509_subject));
global.append('\'');
}
if (acl_user->ssl_cipher)
{
- if (ssl_options++)
- global.append(' ');
- global.append("CIPHER '",8);
- global.append(acl_user->ssl_cipher,strlen(acl_user->ssl_cipher));
+ if (ssl_options++)
+ global.append(' ');
+ global.append("CIPHER '",8);
+ global.append(acl_user->ssl_cipher,strlen(acl_user->ssl_cipher));
global.append('\'');
}
}
@@ -2963,27 +3072,12 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
global.append(" WITH",5);
if (want_access & GRANT_ACL)
global.append(" GRANT OPTION",13);
- if (acl_user->user_resource.questions)
- {
- char buff[22], *p; // just as in int2str
- global.append(" MAX_QUERIES_PER_HOUR ",22);
- p=int10_to_str(acl_user->user_resource.questions,buff,10);
- global.append(buff,p-buff);
- }
- if (acl_user->user_resource.updates)
- {
- char buff[22], *p; // just as in int2str
- global.append(" MAX_UPDATES_PER_HOUR ",22);
- p=int10_to_str(acl_user->user_resource.updates,buff,10);
- global.append(buff,p-buff);
- }
- if (acl_user->user_resource.connections)
- {
- char buff[22], *p; // just as in int2str
- global.append(" MAX_CONNECTIONS_PER_HOUR ",26);
- p=int10_to_str(acl_user->user_resource.connections,buff,10);
- global.append(buff,p-buff);
- }
+ add_user_option(&global, acl_user->user_resource.questions,
+ "MAX_QUERIES_PER_HOUR");
+ add_user_option(&global, acl_user->user_resource.updates,
+ "MAX_UPDATES_PER_HOUR");
+ add_user_option(&global, acl_user->user_resource.connections,
+ "MAX_CONNECTIONS_PER_HOUR");
}
protocol->prepare_for_resend();
protocol->store(global.ptr(),global.length(),global.charset());
@@ -3018,7 +3112,7 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
if (test_all_bits(want_access,(DB_ACLS & ~GRANT_ACL)))
db.append("ALL PRIVILEGES",14);
else if (!(want_access & ~GRANT_ACL))
- db.append("USAGE",5);
+ db.append("USAGE",5);
else
{
int found=0, cnt;
@@ -3069,32 +3163,32 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
if (!strcmp(lex_user->user.str,user) &&
!my_strcasecmp(&my_charset_latin1, lex_user->host.str, host))
{
- want_access=grant_table->privs;
- if ((want_access | grant_table->cols) != 0)
+ ulong table_access= grant_table->privs;
+ if ((table_access | grant_table->cols) != 0)
{
String global(buff,sizeof(buff),&my_charset_latin1);
global.length(0);
global.append("GRANT ",6);
- if (test_all_bits(grant_table->privs,(TABLE_ACLS & ~GRANT_ACL)))
+ if (test_all_bits(table_access, (TABLE_ACLS & ~GRANT_ACL)))
global.append("ALL PRIVILEGES",14);
else
{
- int found=0;
- ulong j,test_access= (want_access | grant_table->cols) & ~GRANT_ACL;
+ int found= 0;
+ ulong j,test_access= (table_access | grant_table->cols) & ~GRANT_ACL;
- for (counter=0, j = SELECT_ACL;j <= TABLE_ACLS; counter++,j <<= 1)
+ for (counter= 0, j= SELECT_ACL; j <= TABLE_ACLS; counter++, j<<= 1)
{
if (test_access & j)
{
if (found)
global.append(", ",2);
- found = 1;
+ found= 1;
global.append(command_array[counter],command_lengths[counter]);
if (grant_table->cols)
{
- uint found_col=0;
+ uint found_col= 0;
for (uint col_index=0 ;
col_index < grant_table->hash_columns.records ;
col_index++)
@@ -3105,8 +3199,18 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
{
if (!found_col)
{
+ found_col= 1;
+ /*
+ If we have a duplicated table level privilege, we
+ must write the access privilege name again.
+ */
+ if (table_access & j)
+ {
+ global.append(", ", 2);
+ global.append(command_array[counter],
+ command_lengths[counter]);
+ }
global.append(" (",2);
- found_col=1;
}
else
global.append(", ",2);
@@ -3129,7 +3233,7 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
global.append("'@'",3);
global.append(lex_user->host.str,lex_user->host.length);
global.append('\'');
- if (want_access & GRANT_ACL)
+ if (table_access & GRANT_ACL)
global.append(" WITH GRANT OPTION",18);
protocol->prepare_for_resend();
protocol->store(global.ptr(),global.length(),global.charset());
@@ -3141,7 +3245,7 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
}
}
}
- end:
+end:
VOID(pthread_mutex_unlock(&acl_cache->lock));
rw_unlock(&LOCK_grant);
@@ -3215,8 +3319,17 @@ int open_grant_tables(THD *thd, TABLE_LIST *tables)
GRANT and REVOKE are applied the slave in/exclusion rules as they are
some kind of updates to the mysql.% tables.
*/
- if (thd->slave_thread && table_rules_on && !tables_ok(0, tables))
- DBUG_RETURN(1);
+ if (thd->slave_thread && table_rules_on)
+ {
+ /*
+ The tables must be marked "updating" so that tables_ok() takes them into
+ account in tests.
+ */
+ tables[0].updating=tables[1].updating=tables[2].updating=tables[3].updating=1;
+ if (!tables_ok(0, tables))
+ DBUG_RETURN(1);
+ tables[0].updating=tables[1].updating=tables[2].updating=tables[3].updating=0;
+ }
#endif
if (open_and_lock_tables(thd, tables))
@@ -3250,9 +3363,10 @@ ACL_USER *check_acl_user(LEX_USER *user_name,
return 0;
*acl_user_idx= counter;
- return acl_user;
+ return acl_user;
}
+
int mysql_drop_user(THD *thd, List <LEX_USER> &list)
{
uint counter, user_id;
@@ -3336,10 +3450,10 @@ int mysql_drop_user(THD *thd, List <LEX_USER> &list)
continue;
}
- tables[0].table->field[0]->store(user_name->host.str,(uint)
+ tables[0].table->field[0]->store(user_name->host.str,(uint)
user_name->host.length,
system_charset_info);
- tables[0].table->field[1]->store(user_name->user.str,(uint)
+ tables[0].table->field[1]->store(user_name->user.str,(uint)
user_name->user.length,
system_charset_info);
if (!tables[0].table->file->index_read_idx(tables[0].table->record[0],0,
@@ -3394,7 +3508,7 @@ int mysql_revoke_all(THD *thd, List <LEX_USER> &list)
result= -1;
continue;
}
-
+
if (replace_user_table(thd, tables[0].table,
*lex_user, ~0, 1, 0))
{
diff --git a/sql/sql_acl.h b/sql/sql_acl.h
index e6c6771253c..0dc8c058b3d 100644
--- a/sql/sql_acl.h
+++ b/sql/sql_acl.h
@@ -76,8 +76,8 @@
#define get_rights_for_db(A) (((A) & 63) | (((A) & DB_CHUNK1) >> 4) | (((A) & DB_CHUNK2) >> 6))
#define fix_rights_for_table(A) (((A) & 63) | (((A) & ~63) << 4))
#define get_rights_for_table(A) (((A) & 63) | (((A) & ~63) >> 4))
-#define fix_rights_for_column(A) (((A) & COL_ACLS) | ((A & ~COL_ACLS) << 7))
-#define get_rights_for_column(A) (((A) & COL_ACLS) | ((A & ~COL_ACLS) >> 7))
+#define fix_rights_for_column(A) (((A) & 7) | (((A) & ~7) << 8))
+#define get_rights_for_column(A) (((A) & 7) | ((A) >> 8))
/* Classes */
@@ -134,7 +134,7 @@ my_bool acl_init(THD *thd, bool dont_read_acl_tables);
void acl_reload(THD *thd);
void acl_free(bool end=0);
ulong acl_get(const char *host, const char *ip, const char *bin_ip,
- const char *user, const char *db);
+ const char *user, const char *db, my_bool db_is_pattern);
ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user,
const char *password,const char *scramble,
char **priv_user, char *priv_host,
diff --git a/sql/sql_analyse.cc b/sql/sql_analyse.cc
index ced5993e293..a6c24a25d6e 100644
--- a/sql/sql_analyse.cc
+++ b/sql/sql_analyse.cc
@@ -326,9 +326,9 @@ void field_str::add()
if (length > max_length)
max_length = length;
- if (sortcmp(res, &min_arg,item->charset()) < 0)
+ if (sortcmp(res, &min_arg,item->collation.collation) < 0)
min_arg.copy(*res);
- if (sortcmp(res, &max_arg,item->charset()) > 0)
+ if (sortcmp(res, &max_arg,item->collation.collation) > 0)
max_arg.copy(*res);
}
@@ -736,7 +736,7 @@ void field_str::get_opt_type(String *answer, ha_rows total_rows)
{
if (must_be_blob)
{
- if (item->charset() == &my_charset_bin)
+ if (item->collation.collation == &my_charset_bin)
answer->append("TINYBLOB", 8);
else
answer->append("TINYTEXT", 8);
@@ -754,21 +754,21 @@ void field_str::get_opt_type(String *answer, ha_rows total_rows)
}
else if (max_length < (1L << 16))
{
- if (item->charset() == &my_charset_bin)
+ if (item->collation.collation == &my_charset_bin)
answer->append("BLOB", 4);
else
answer->append("TEXT", 4);
}
else if (max_length < (1L << 24))
{
- if (item->charset() == &my_charset_bin)
+ if (item->collation.collation == &my_charset_bin)
answer->append("MEDIUMBLOB", 10);
else
answer->append("MEDIUMTEXT", 10);
}
else
{
- if (item->charset() == &my_charset_bin)
+ if (item->collation.collation == &my_charset_bin)
answer->append("LONGBLOB", 8);
else
answer->append("LONGTEXT", 8);
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 2fa88e9cfc8..dc6e791c4be 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -148,7 +148,7 @@ OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *wild)
if (wild)
{
strxmov(name,entry->table_cache_key,".",entry->real_name,NullS);
- if (wild_compare(name,wild))
+ if (wild_compare(name,wild,0))
continue;
}
@@ -787,6 +787,7 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name,
DBUG_RETURN(0);
}
table->query_id=thd->query_id;
+ table->clear_query_id=1;
thd->tmp_table_used= 1;
goto reset;
}
@@ -1354,6 +1355,7 @@ int open_tables(THD *thd,TABLE_LIST *start)
int result=0;
DBUG_ENTER("open_tables");
+ thd->current_tablenr= 0;
restart:
thd->proc_info="Opening tables";
for (tables=start ; tables ; tables=tables->next)
@@ -1472,6 +1474,7 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type)
DBUG_ENTER("open_ltable");
thd->proc_info="Opening table";
+ thd->current_tablenr= 0;
while (!(table=open_table(thd,table_list->db,
table_list->real_name,table_list->alias,
&refresh)) && refresh) ;
@@ -2039,8 +2042,9 @@ bool setup_tables(TABLE_LIST *tables)
table->keys_in_use_for_query &= ~map;
}
table->used_keys &= table->keys_in_use_for_query;
- if (table_list->shared)
+ if (table_list->shared || table->clear_query_id)
{
+ table->clear_query_id= 0;
/* Clear query_id that may have been set by previous select */
for (Field **ptr=table->field ; *ptr ; ptr++)
(*ptr)->query_id=0;
@@ -2139,6 +2143,7 @@ insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name,
int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
{
+ table_map not_null_tables= 0;
DBUG_ENTER("setup_conds");
thd->set_query_id=1;
@@ -2148,6 +2153,7 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
thd->where="where clause";
if ((*conds)->fix_fields(thd, tables, conds) || (*conds)->check_cols(1))
DBUG_RETURN(1);
+ not_null_tables= (*conds)->not_null_tables();
}
/* Check if we are using outer joins */
@@ -2162,9 +2168,15 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
DBUG_RETURN(1);
thd->lex.current_select->cond_count++;
- /* If it's a normal join, add the ON/USING expression to the WHERE */
- if (!table->outer_join)
+ /*
+ If it's a normal join or a LEFT JOIN which can be optimized away
+ add the ON/USING expression to the WHERE
+ */
+ if (!table->outer_join ||
+ ((table->table->map & not_null_tables) &&
+ !(specialflag & SPECIAL_NO_NEW_FUNC)))
{
+ table->outer_join= 0;
if (!(*conds=and_conds(*conds, table->on_expr)))
DBUG_RETURN(1);
table->on_expr=0;
@@ -2236,7 +2248,11 @@ fill_record(List<Item> &fields,List<Item> &values, bool ignore_errors)
while ((field=(Item_field*) f++))
{
value=v++;
- if (value->save_in_field(field->field, 0) > 0 && !ignore_errors)
+ Field *rfield= field->field;
+ TABLE *table= rfield->table;
+ if (rfield == table->next_number_field)
+ table->auto_increment_field_not_null= true;
+ if (value->save_in_field(rfield, 0) > 0 && !ignore_errors)
DBUG_RETURN(1);
}
DBUG_RETURN(0);
@@ -2254,6 +2270,9 @@ fill_record(Field **ptr,List<Item> &values, bool ignore_errors)
while ((field = *ptr++))
{
value=v++;
+ TABLE *table= field->table;
+ if (field == table->next_number_field)
+ table->auto_increment_field_not_null= true;
if (value->save_in_field(field, 0) == 1 && !ignore_errors)
DBUG_RETURN(1);
}
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc
index ac6471e794c..64e8be8e224 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -760,9 +760,9 @@ void Query_cache::store_query(THD *thd, TABLE_LIST *tables_used)
DBUG_VOID_RETURN;
uint8 tables_type= 0;
- if ((local_tables = is_cacheable(thd, thd->query_length,
- thd->query, &thd->lex, tables_used,
- &tables_type)))
+ if ((local_tables= is_cacheable(thd, thd->query_length,
+ thd->query, &thd->lex, tables_used,
+ &tables_type)))
{
NET *net= &thd->net;
byte flags= (thd->client_capabilities & CLIENT_LONG_FLAG ? 0x80 : 0);
@@ -1422,10 +1422,10 @@ ulong Query_cache::init_cache()
DUMP(this);
- VOID(hash_init(&queries,system_charset_info,def_query_hash_size, 0, 0,
+ VOID(hash_init(&queries, &my_charset_bin, def_query_hash_size, 0, 0,
query_cache_query_get_key, 0, 0));
#ifndef FN_NO_CASE_SENCE
- VOID(hash_init(&tables,system_charset_info,def_table_hash_size, 0, 0,
+ VOID(hash_init(&tables, &my_charset_bin, def_table_hash_size, 0, 0,
query_cache_table_get_key, 0, 0));
#else
// windows, OS/2 or other case insensitive file names work around
diff --git a/sql/sql_cache.h b/sql/sql_cache.h
index eea542e9d06..f6eb7c7a0fb 100644
--- a/sql/sql_cache.h
+++ b/sql/sql_cache.h
@@ -61,7 +61,7 @@
#define QUERY_CACHE_PACK_ITERATION 2
#define QUERY_CACHE_PACK_LIMIT (512*1024L)
-#define TABLE_COUNTER_TYPE uint8
+#define TABLE_COUNTER_TYPE uint
struct Query_cache_block;
struct Query_cache_block_table;
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index c233ffd422a..763408dc5c2 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -96,7 +96,6 @@ THD::THD():user_time(0), is_fatal_error(0),
query_error= tmp_table_used= 0;
next_insert_id=last_insert_id=0;
open_tables= temporary_tables= handler_tables= derived_tables= 0;
- current_tablenr=0;
handler_items=0;
tmp_table=0;
lock=locked_tables=0;
@@ -161,8 +160,6 @@ THD::THD():user_time(0), is_fatal_error(0),
else
bzero((char*) &user_var_events, sizeof(user_var_events));
-
-
/* Prepared statements */
last_prepared_stmt= 0;
init_tree(&prepared_statements, 0, 0, sizeof(PREP_STMT),
@@ -218,6 +215,7 @@ void THD::init(void)
warn_list.empty();
bzero((char*) warn_count, sizeof(warn_count));
total_warn_count= 0;
+ update_charset();
}
@@ -385,6 +383,59 @@ bool THD::store_globals()
}
+/*
+ Convert a string to another character set
+
+ SYNOPSIS
+ convert_string()
+ to Store new allocated string here
+ to_cs New character set for allocated string
+ from String to convert
+ from_length Length of string to convert
+ from_cs Original character set
+
+ NOTES
+ to will be 0-terminated to make it easy to pass to system funcs
+
+ RETURN
+ 0 ok
+ 1 End of memory.
+ In this case to->str will point to 0 and to->length will be 0.
+*/
+
+bool THD::convert_string(LEX_STRING *to, CHARSET_INFO *to_cs,
+ const char *from, uint from_length,
+ CHARSET_INFO *from_cs)
+{
+ DBUG_ENTER("convert_string");
+ size_s new_length= to_cs->mbmaxlen * from_length;
+ if (!(to->str= alloc(new_length+1)))
+ {
+ to->length= 0; // Safety fix
+ DBUG_RETURN(1); // EOM
+ }
+ to->length= copy_and_convert((char*) to->str, new_length, to_cs,
+ from, from_length, from_cs);
+ to->str[to->length]=0; // Safety
+ DBUG_RETURN(0);
+}
+
+
+/*
+ Update some cache variables when character set changes
+*/
+
+void THD::update_charset()
+{
+ charset_is_system_charset= my_charset_same(charset(),system_charset_info);
+ charset_is_collation_connection= my_charset_same(charset(),
+ variables.
+ collation_connection);
+}
+
+
+
+
/* routings to adding tables to list of changed in transaction tables */
inline static void list_include(CHANGED_TABLE_LIST** prev,
diff --git a/sql/sql_class.h b/sql/sql_class.h
index f6336cb7dd9..e10795c4d9d 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -30,22 +30,26 @@ class Slave_log_event;
enum enum_enable_or_disable { LEAVE_AS_IS, ENABLE, DISABLE };
enum enum_ha_read_modes { RFIRST, RNEXT, RPREV, RLAST, RKEY };
enum enum_duplicates { DUP_ERROR, DUP_REPLACE, DUP_IGNORE, DUP_UPDATE };
-enum enum_log_type { LOG_CLOSED, LOG_NORMAL, LOG_NEW, LOG_BIN };
+enum enum_log_type { LOG_CLOSED, LOG_TO_BE_OPENED, LOG_NORMAL, LOG_NEW, LOG_BIN};
enum enum_delay_key_write { DELAY_KEY_WRITE_NONE, DELAY_KEY_WRITE_ON,
DELAY_KEY_WRITE_ALL };
extern char internal_table_name[2];
-// log info errors
+/* log info errors */
#define LOG_INFO_EOF -1
#define LOG_INFO_IO -2
#define LOG_INFO_INVALID -3
#define LOG_INFO_SEEK -4
-#define LOG_INFO_PURGE_NO_ROTATE -5
#define LOG_INFO_MEM -6
#define LOG_INFO_FATAL -7
#define LOG_INFO_IN_USE -8
+/* bitmap to SQL_LOG::close() */
+#define LOG_CLOSE_INDEX 1
+#define LOG_CLOSE_TO_BE_OPENED 2
+#define LOG_CLOSE_STOP_EVENT 4
+
struct st_relay_log_info;
typedef struct st_log_info
@@ -70,8 +74,10 @@ typedef struct st_user_var_events
class Log_event;
-class MYSQL_LOG {
+class MYSQL_LOG
+ {
private:
+ /* LOCK_log and LOCK_index are inited by init_pthread_objects() */
pthread_mutex_t LOCK_log, LOCK_index;
pthread_cond_t update_cond;
ulonglong bytes_written;
@@ -86,15 +92,20 @@ class MYSQL_LOG {
uint open_count; // For replication
volatile enum_log_type log_type;
enum cache_type io_cache_type;
- bool write_error,inited;
- /*
- For binlog - if log name can never change we should not try to rotate it
- or write any rotation events. The user should use FLUSH MASTER instead
- of FLUSH LOGS for purging.
- */
- bool no_rotate;
+ bool write_error, inited;
bool need_start_event;
- bool no_auto_events; // for relay binlog
+ bool no_auto_events; // For relay binlog
+ /*
+ The max size before rotation (usable only if log_type == LOG_BIN: binary
+ logs and relay logs).
+ For a binlog, max_size should be max_binlog_size.
+ For a relay log, it should be max_relay_log_size if this is non-zero,
+ max_binlog_size otherwise.
+ max_size is set in init(), and dynamically changed (when one does SET
+ GLOBAL MAX_BINLOG_SIZE|MAX_RELAY_LOG_SIZE) by fix_max_binlog_size and
+ fix_max_relay_log_size).
+ */
+ ulong max_size;
friend class Log_event;
public:
@@ -116,17 +127,19 @@ public:
bytes_written=0;
DBUG_VOID_RETURN;
}
+ void set_max_size(ulong max_size_arg);
void signal_update() { pthread_cond_broadcast(&update_cond);}
void wait_for_update(THD* thd);
void set_need_start_event() { need_start_event = 1; }
void init(enum_log_type log_type_arg,
- enum cache_type io_cache_type_arg = WRITE_CACHE,
- bool no_auto_events_arg = 0);
+ enum cache_type io_cache_type_arg,
+ bool no_auto_events_arg, ulong max_size);
+ void init_pthread_objects();
void cleanup();
bool open(const char *log_name,enum_log_type log_type,
const char *new_name, const char *index_file_name_arg,
enum cache_type io_cache_type_arg,
- bool no_auto_events_arg);
+ bool no_auto_events_arg, ulong max_size);
void new_file(bool need_lock= 1);
bool write(THD *thd, enum enum_server_command command,
const char *format,...);
@@ -152,8 +165,7 @@ public:
int purge_logs_before_date(time_t purge_time);
int purge_first_log(struct st_relay_log_info* rli, bool included);
bool reset_logs(THD* thd);
- // if we are exiting, we also want to close the index file
- void close(bool exiting = 0);
+ void close(uint exiting);
// iterating through the log index file
int find_log_pos(LOG_INFO* linfo, const char* log_name,
@@ -161,7 +173,6 @@ public:
int find_next_log(LOG_INFO* linfo, bool need_mutex);
int get_current_log(LOG_INFO* linfo);
uint next_file_id();
-
inline bool is_open() { return log_type != LOG_CLOSED; }
inline char* get_index_fname() { return index_file_name;}
inline char* get_log_fname() { return log_file_name; }
@@ -376,6 +387,7 @@ struct system_variables
ulong tx_isolation;
ulong sql_mode;
ulong default_week_format;
+ ulong max_seeks_for_key;
ulong group_concat_max_len;
/*
In slave thread we need to know in behalf of which
@@ -520,7 +532,7 @@ public:
*/
ulonglong current_insert_id;
ulonglong limit_found_rows;
- ha_rows select_limit, offset_limit, cuted_fields,
+ ha_rows cuted_fields,
sent_row_count, examined_row_count;
table_map used_tables;
USER_CONN *user_connect;
@@ -559,6 +571,7 @@ public:
bool volatile killed;
bool prepare_command;
bool tmp_table_used;
+ bool charset_is_system_charset, charset_is_collation_connection;
/*
If we do a purge of binary logs, log index info of the threads
@@ -666,6 +679,9 @@ public:
memcpy(ptr,str,size);
return ptr;
}
+ bool convert_string(LEX_STRING *to, CHARSET_INFO *to_cs,
+ const char *from, uint from_length,
+ CHARSET_INFO *from_cs);
inline gptr trans_alloc(unsigned int size)
{
return alloc_root(&transaction.mem_root,size);
@@ -691,6 +707,7 @@ public:
DBUG_PRINT("error",("Fatal error set"));
}
inline CHARSET_INFO *charset() { return variables.character_set_client; }
+ void update_charset();
};
/*
@@ -1003,11 +1020,12 @@ class Unique :public Sql_alloc
TREE tree;
byte *record_pointers;
bool flush();
+ uint size;
public:
ulong elements;
Unique(qsort_cmp2 comp_func, void * comp_func_fixed_arg,
- uint size, ulong max_in_memory_size_arg);
+ uint size_arg, ulong max_in_memory_size_arg);
~Unique();
inline bool unique_add(gptr ptr)
{
@@ -1022,10 +1040,11 @@ public:
friend int unique_write_to_ptrs(gptr key, element_count count, Unique *unique);
};
-class multi_delete : public select_result
+
+class multi_delete :public select_result
{
TABLE_LIST *delete_tables, *table_being_deleted;
- Unique **tempfiles;
+ Unique **tempfiles;
THD *thd;
ha_rows deleted;
uint num_of_tables;
@@ -1045,7 +1064,7 @@ public:
};
-class multi_update : public select_result
+class multi_update :public select_result
{
TABLE_LIST *all_tables, *update_tables, *table_being_updated;
THD *thd;
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index f8cf1eee0c5..34e81402dd0 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -127,7 +127,7 @@ static bool load_db_opt(THD *thd, const char *path, HA_CREATE_INFO *create)
{
if (!(create->table_charset=get_charset_by_name(pos+1, MYF(0))))
{
- sql_print_error(ER(ER_UNKNOWN_CHARACTER_SET),pos+1);
+ sql_print_error(ER(ER_UNKNOWN_COLLATION),pos+1);
}
}
}
@@ -591,7 +591,7 @@ bool mysql_change_db(THD *thd, const char *name)
db_access=DB_ACLS;
else
db_access= (acl_get(thd->host,thd->ip,(char*) &thd->remote.sin_addr,
- thd->priv_user,dbname) |
+ thd->priv_user,dbname,0) |
thd->master_access);
if (!(db_access & DB_ACLS) && (!grant_option || check_grant_db(thd,dbname)))
{
@@ -625,8 +625,8 @@ bool mysql_change_db(THD *thd, const char *name)
strmov(path+unpack_dirname(path,path), MY_DB_OPT_FILE);
load_db_opt(thd, path, &create);
- thd->db_charset= create.table_charset ?
- create.table_charset :
+ thd->db_charset= create.table_charset ?
+ create.table_charset :
global_system_variables.character_set_database;
thd->variables.character_set_database= thd->db_charset;
DBUG_RETURN(0);
@@ -644,18 +644,18 @@ int mysqld_show_create_db(THD *thd, char *dbname,
uint create_options = create_info ? create_info->options : 0;
Protocol *protocol=thd->protocol;
DBUG_ENTER("mysql_show_create_db");
-
+
if (check_db_name(dbname))
{
net_printf(thd,ER_WRONG_DB_NAME, dbname);
DBUG_RETURN(1);
}
-
+
if (test_all_bits(thd->master_access,DB_ACLS))
db_access=DB_ACLS;
else
db_access= (acl_get(thd->host,thd->ip,(char*) &thd->remote.sin_addr,
- thd->priv_user,dbname) |
+ thd->priv_user,dbname,0) |
thd->master_access);
if (!(db_access & DB_ACLS) && (!grant_option || check_grant_db(thd,dbname)))
{
@@ -669,7 +669,7 @@ int mysqld_show_create_db(THD *thd, char *dbname,
dbname);
DBUG_RETURN(1);
}
-
+
(void) sprintf(path,"%s/%s",mysql_data_home, dbname);
length=unpack_dirname(path,path); // Convert if not unix
found_libchar= 0;
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index 876c4f9e670..48ef5b4b74c 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -126,8 +126,7 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order,
table->sort.io_cache = (IO_CACHE *) my_malloc(sizeof(IO_CACHE),
MYF(MY_FAE | MY_ZEROFILL));
- if (setup_ref_array(thd, &thd->lex.select_lex.ref_pointer_array,
- all_fields.elements)||
+ if (thd->lex.select_lex.setup_ref_array(thd, 0) ||
setup_order(thd, thd->lex.select_lex.ref_pointer_array, &tables,
fields, all_fields, order) ||
!(sortorder=make_unireg_sortorder(order, &length)) ||
@@ -164,7 +163,15 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order,
else
{
table->file->print_error(error,MYF(0));
- error=0;
+ /*
+ In < 4.0.14 we set the error number to 0 here, but that
+ was not sensible, because then MySQL would not roll back the
+ failed DELETE, and also wrote it to the binlog. For MyISAM
+ tables a DELETE probably never should fail (?), but for
+ InnoDB it can fail in a FOREIGN KEY error or an
+ out-of-tablespace error.
+ */
+ error= 1;
break;
}
}
diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc
index 92e37f95f0e..771d68e8462 100644
--- a/sql/sql_derived.cc
+++ b/sql/sql_derived.cc
@@ -122,13 +122,22 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit,
res= -1;
goto exit;
}
+
+ /*
+ This is done in order to redo all field optimisations when any of the
+ involved tables is used in the outer query
+ */
+ if (tables)
+ {
+ for (TABLE_LIST *cursor= tables; cursor; cursor= cursor->next)
+ cursor->table->clear_query_id= 1;
+ }
item_list= select_cursor->item_list;
select_cursor->with_wild= 0;
- if (setup_ref_array(thd, &select_cursor->ref_pointer_array,
- (item_list.elements + select_cursor->select_items +
- select_cursor->order_list.elements +
- select_cursor->group_list.elements)) ||
+ if (select_cursor->setup_ref_array(thd,
+ select_cursor->order_list.elements +
+ select_cursor->group_list.elements) ||
setup_fields(thd, select_cursor->ref_pointer_array, first_table,
item_list, 0, 0, 1))
{
@@ -146,7 +155,8 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit,
is_union && !unit->union_option, 1,
(select_cursor->options | thd->options |
TMP_TABLE_ALL_COLUMNS),
- HA_POS_ERROR)))
+ HA_POS_ERROR,
+ org_table_list->alias)))
{
res= -1;
goto exit;
diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc
index 79d13039784..93ab332bcd5 100644
--- a/sql/sql_handler.cc
+++ b/sql/sql_handler.cc
@@ -203,6 +203,13 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables,
Item *item;
for (key_len=0 ; (item=it_ke++) ; key_part++)
{
+ if (item->fix_fields(thd, tables, &item))
+ goto err;
+ if (item->used_tables() & ~RAND_TABLE_BIT)
+ {
+ my_error(ER_WRONG_ARGUMENTS,MYF(0),"HANDLER ... READ");
+ goto err;
+ }
(void) item->save_in_field(key_part->field, 1);
key_len+=key_part->store_length;
}
@@ -237,7 +244,7 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables,
}
if (cond && !cond->val_int())
continue;
- if (!err && num_rows >= offset_limit)
+ if (num_rows >= offset_limit)
{
String *packet = &thd->packet;
Item *item;
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 211377dcecb..d6cfd555c40 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -552,7 +552,7 @@ int yylex(void *arg, void *yythd)
/*
Note: "SELECT _bla AS 'alias'"
_bla should be considered as a IDENT if charset haven't been found.
- So we don't use MYF(MY_WME) with get_charset_by_name to avoid
+ So we don't use MYF(MY_WME) with get_charset_by_csname to avoid
producing an error.
*/
@@ -977,9 +977,11 @@ void st_select_lex::init_query()
join= 0;
where= 0;
olap= UNSPECIFIED_OLAP_TYPE;
- insert_select= having_fix_field= 0;
+ having_fix_field= 0;
+ resolve_mode= NOMATTER_MODE;
cond_count= with_wild= 0;
ref_pointer_array= 0;
+ select_n_having_items= 0;
}
void st_select_lex::init_select()
@@ -988,7 +990,6 @@ void st_select_lex::init_select()
group_list.empty();
type= db= db1= table1= db2= table2= 0;
having= 0;
- group_list.empty();
use_index_ptr= ignore_index_ptr= 0;
table_join_options= 0;
in_sum_expr= with_wild= 0;
@@ -1006,7 +1007,6 @@ void st_select_lex::init_select()
order_list.next= (byte**) &order_list.first;
select_limit= HA_POS_ERROR;
offset_limit= 0;
- select_items= 0;
with_sum_func= 0;
parsing_place= SELECT_LEX_NODE::NO_MATTER;
}
@@ -1409,6 +1409,17 @@ ulong st_select_lex::get_table_join_options()
return table_join_options;
}
+bool st_select_lex::setup_ref_array(THD *thd, uint order_group_num)
+{
+ if (ref_pointer_array)
+ return 0;
+ return (ref_pointer_array=
+ (Item **)thd->alloc(sizeof(Item*) *
+ (item_list.elements +
+ select_n_having_items +
+ order_group_num)* 5)) == 0;
+}
+
/*
There are st_select_lex::add_table_to_list &
st_select_lex::set_lock_for_tables in sql_parse.cc
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 6d47894d737..7a7071ae56b 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -61,7 +61,9 @@ enum enum_sql_command {
SQLCOM_CREATE_FUNCTION, SQLCOM_DROP_FUNCTION,
SQLCOM_REVOKE,SQLCOM_OPTIMIZE, SQLCOM_CHECK, SQLCOM_PRELOAD_KEYS,
SQLCOM_FLUSH, SQLCOM_KILL, SQLCOM_ANALYZE,
- SQLCOM_ROLLBACK, SQLCOM_COMMIT, SQLCOM_SLAVE_START, SQLCOM_SLAVE_STOP,
+ SQLCOM_ROLLBACK, SQLCOM_ROLLBACK_TO_SAVEPOINT,
+ SQLCOM_COMMIT, SQLCOM_SAVEPOINT,
+ SQLCOM_SLAVE_START, SQLCOM_SLAVE_STOP,
SQLCOM_BEGIN, SQLCOM_LOAD_MASTER_TABLE, SQLCOM_CHANGE_MASTER,
SQLCOM_RENAME_TABLE, SQLCOM_BACKUP_TABLE, SQLCOM_RESTORE_TABLE,
SQLCOM_RESET, SQLCOM_PURGE, SQLCOM_PURGE_BEFORE, SQLCOM_SHOW_BINLOGS,
@@ -217,6 +219,8 @@ public:
{
return (void*) sql_alloc((uint) size);
}
+ static void *operator new(size_t size, MEM_ROOT *mem_root)
+ { return (void*) alloc_root(mem_root, (uint) size); }
static void operator delete(void *ptr,size_t size) {}
st_select_lex_node(): linkage(UNSPECIFIED_TYPE) {}
virtual ~st_select_lex_node() {}
@@ -349,7 +353,12 @@ public:
// Arrays of pointers to top elements of all_fields list
Item **ref_pointer_array;
- uint select_items; /* number of items in select_list */
+ /*
+ number of items in select_list and HAVING clause used to get number
+ bigger then can be number of entries that will be added to all item
+ list during split_sum_func
+ */
+ uint select_n_having_items;
uint cond_count; /* number of arguments of and/or/xor in where/having */
enum_parsing_place parsing_place; /* where we are parsing expression */
bool with_sum_func; /* sum function indicator */
@@ -361,14 +370,27 @@ public:
bool braces; /* SELECT ... UNION (SELECT ... ) <- this braces */
/* TRUE when having fix field called in processing of this SELECT */
bool having_fix_field;
+
/*
- TRUE for primary st_select_lex structure of simple INSERT/REPLACE
+ SELECT for SELECT command st_select_lex. Used to privent scaning
+ item_list of non-SELECT st_select_lex (no sense find to finding
+ reference in it (all should be in tables, it is dangerouse due
+ to order of fix_fields calling for non-SELECTs commands (item list
+ can be not fix_fieldsd)). This value will be assigned for
+ primary select (sql_yac.yy) and for any subquery and
+ UNION SELECT (sql_parse.cc mysql_new_select())
+
+
+ INSERT for primary st_select_lex structure of simple INSERT/REPLACE
(used for name resolution, see Item_fiels & Item_ref fix_fields,
FALSE for INSERT/REPLACE ... SELECT, because it's
st_select_lex->table_list will be preprocessed (first table removed)
before passing to handle_select)
+
+ NOMATTER for other
*/
- bool insert_select;
+ enum {NOMATTER_MODE, SELECT_MODE, INSERT_MODE} resolve_mode;
+
void init_query();
void init_select();
@@ -431,6 +453,7 @@ public:
init_query();
init_select();
}
+ bool setup_ref_array(THD *thd, uint order_group_num);
};
typedef class st_select_lex SELECT_LEX;
@@ -472,9 +495,10 @@ typedef struct st_lex
List<List_item> many_values;
List<set_var_base> var_list;
List<Item> param_list;
- SQL_LIST proc_list, auxilliary_table_list;
+ SQL_LIST proc_list, auxilliary_table_list, save_list;
TYPELIB *interval;
create_field *last_field;
+ char *savepoint_name; // Transaction savepoint id
Item *default_value, *comment;
uint uint_geom_type;
LEX_USER *grant_user;
diff --git a/sql/sql_list.cc b/sql/sql_list.cc
index 1124605ca24..c99cfb8c918 100644
--- a/sql/sql_list.cc
+++ b/sql/sql_list.cc
@@ -22,3 +22,18 @@
#include "mysql_priv.h"
list_node end_of_list;
+
+void free_list(I_List <i_string_pair> *list)
+{
+ i_string_pair *tmp;
+ while ((tmp= list->get()))
+ delete tmp;
+}
+
+
+void free_list(I_List <i_string> *list)
+{
+ i_string *tmp;
+ while ((tmp= list->get()))
+ delete tmp;
+}
diff --git a/sql/sql_list.h b/sql/sql_list.h
index 2450b2051f2..7200046e6c5 100644
--- a/sql/sql_list.h
+++ b/sql/sql_list.h
@@ -15,12 +15,11 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-/* mysql standard open memoryallocator */
-
#ifdef __GNUC__
#pragma interface /* gcc class implementation */
#endif
+/* mysql standard class memoryallocator */
class Sql_alloc
{
@@ -48,14 +47,15 @@ public:
};
+
/*
-** basic single linked list
-** Used for item and item_buffs.
-** All list ends with a pointer to the 'end_of_list' element, which
-** data pointer is a null pointer and the next pointer points to itself.
-** This makes it very fast to traverse lists as we don't have to
-** test for a specialend condition for list that can't contain a null
-** pointer.
+ Basic single linked list
+ Used for item and item_buffs.
+ All list ends with a pointer to the 'end_of_list' element, which
+ data pointer is a null pointer and the next pointer points to itself.
+ This makes it very fast to traverse lists as we don't have to
+ test for a specialend condition for list that can't contain a null
+ pointer.
*/
class list_node :public Sql_alloc
@@ -75,9 +75,11 @@ public:
friend class base_list_iterator;
};
+
extern list_node end_of_list;
-class base_list :public Sql_alloc {
+class base_list :public Sql_alloc
+{
protected:
list_node *first,**last;
@@ -267,6 +269,7 @@ public:
inline T** ref(void) { return (T**) base_list_iterator::ref(); }
};
+
template <class T> class List_iterator_fast :public base_list_iterator
{
protected:
@@ -288,11 +291,12 @@ public:
/*
-** A simple intrusive list which automaticly removes element from list
-** on delete (for THD element)
+ A simple intrusive list which automaticly removes element from list
+ on delete (for THD element)
*/
-struct ilink {
+struct ilink
+{
struct ilink **prev,*next;
static void *operator new(size_t size)
{
@@ -317,9 +321,11 @@ struct ilink {
virtual ~ilink() { unlink(); } /*lint -e1740 */
};
+
template <class T> class I_List_iterator;
-class base_ilist {
+class base_ilist
+{
public:
struct ilink *first,last;
inline void empty() { first= &last; last.prev= &first; }
@@ -368,7 +374,8 @@ public:
template <class T>
-class I_List :private base_ilist {
+class I_List :private base_ilist
+{
public:
I_List() :base_ilist() {}
inline void empty() { base_ilist::empty(); }
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 78adebdfff3..33e96cc2776 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -216,7 +216,7 @@ static int check_user(THD *thd,enum_server_command command, const char *user,
thd->db=0;
thd->db_length=0;
USER_RESOURCES ur;
- char tmp_passwd[SCRAMBLE41_LENGTH];
+ char tmp_passwd[SCRAMBLE41_LENGTH+1];
DBUG_ENTER("check_user");
/*
@@ -304,10 +304,11 @@ static int check_user(THD *thd,enum_server_command command, const char *user,
db ? db : (char*) "");
thd->db_access=0;
/* Don't allow user to connect if he has done too many queries */
- if ((ur.questions || ur.updates || ur.connections) &&
+ if ((ur.questions || ur.updates || ur.connections || max_user_connections) &&
get_or_create_user_conn(thd,user,thd->host_or_ip,&ur))
DBUG_RETURN(1);
- if (thd->user_connect && thd->user_connect->user_resources.connections &&
+ if (thd->user_connect && ((thd->user_connect->user_resources.connections) ||
+ max_user_connections) &&
check_for_max_user_connections(thd, thd->user_connect))
DBUG_RETURN(1);
@@ -356,7 +357,7 @@ static int check_for_max_user_connections(THD *thd, USER_CONN *uc)
DBUG_ENTER("check_for_max_user_connections");
if (max_user_connections &&
- (max_user_connections <= (uint) uc->connections))
+ (max_user_connections < (uint) uc->connections))
{
net_printf(thd,ER_TOO_MANY_USER_CONNECTIONS, uc->user);
error=1;
@@ -548,6 +549,7 @@ check_connections(THD *thd)
NET *net= &thd->net;
char *end, *user, *passwd, *db;
char prepared_scramble[SCRAMBLE41_LENGTH+4]; /* Buffer for scramble&hash */
+ char db_buff[NAME_LEN+1];
ACL_USER* cached_user=NULL; /* Initialise to NULL for first stage */
DBUG_PRINT("info",("New connection received on %s",
vio_description(net->vio)));
@@ -566,7 +568,10 @@ check_connections(THD *thd)
#if !defined(HAVE_SYS_UN_H) || defined(HAVE_mit_thread)
/* Fast local hostname resolve for Win32 */
if (!strcmp(thd->ip,"127.0.0.1"))
- thd->host=(char*) localhost;
+ {
+ thd->host= (char*) localhost;
+ thd->host_or_ip= localhost;
+ }
else
#endif
{
@@ -662,8 +667,18 @@ check_connections(THD *thd)
{
thd->client_capabilities|= ((ulong) uint2korr(net->read_pos+2)) << 16;
thd->max_client_packet_length= uint4korr(net->read_pos+4);
+ DBUG_PRINT("info", ("client_character_set: %d", (uint) net->read_pos[8]));
+ /*
+ Use server character set and collation if
+ - client has not specified a character set
+ - client character set is the same as the servers
+ - client character set doesn't exists in server
+ */
if (!(thd->variables.character_set_client=
- get_charset((uint) net->read_pos[8], MYF(0))))
+ get_charset((uint) net->read_pos[8], MYF(0))) ||
+ !my_strcasecmp(&my_charset_latin1,
+ global_system_variables.character_set_client->name,
+ thd->variables.character_set_client->name))
{
thd->variables.character_set_client=
global_system_variables.character_set_client;
@@ -678,6 +693,7 @@ check_connections(THD *thd)
thd->variables.collation_connection=
thd->variables.character_set_client;
}
+ thd->update_charset();
end= (char*) net->read_pos+32;
}
else
@@ -693,6 +709,11 @@ check_connections(THD *thd)
if (thd->client_capabilities & CLIENT_SSL)
{
/* Do the SSL layering. */
+ if (!ssl_acceptor_fd)
+ {
+ inc_host_errors(&thd->remote.sin_addr);
+ return(ER_HANDSHAKE_ERROR);
+ }
DBUG_PRINT("info", ("IO layer change in progress..."));
if (sslaccept(ssl_acceptor_fd, net->vio, thd->variables.net_wait_timeout))
{
@@ -724,7 +745,15 @@ check_connections(THD *thd)
db=0;
using_password= test(passwd[0]);
if (thd->client_capabilities & CLIENT_CONNECT_WITH_DB)
- db=strend(passwd)+1;
+ {
+ db= strend(passwd)+1;
+ uint32 length= copy_and_convert(db_buff, sizeof(db_buff)-1,
+ system_charset_info,
+ db, strlen(db),
+ thd->charset());
+ db_buff[length]= 0;
+ db= db_buff;
+ }
/* We can get only old hash at this point */
if (using_password && strlen(passwd) != SCRAMBLE_LENGTH)
@@ -953,7 +982,6 @@ extern "C" pthread_handler_decl(handle_bootstrap,arg)
buff[length-1] == ';'))
length--;
buff[length]=0;
- thd->current_tablenr=0;
thd->query_length=length;
thd->query= thd->memdup_w_gap(buff, length+1, thd->db_length+1);
thd->query[length] = '\0';
@@ -1056,7 +1084,6 @@ bool do_command(THD *thd)
DBUG_ENTER("do_command");
net= &thd->net;
- thd->current_tablenr=0;
/*
indicator of uninitialized lex => normal flow of errors handling
(see my_message_sql)
@@ -1125,10 +1152,15 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
thd->lex.select_lex.options=0; // We store status here
switch (command) {
case COM_INIT_DB:
+ {
+ LEX_STRING tmp;
statistic_increment(com_stat[SQLCOM_CHANGE_DB],&LOCK_status);
- if (!mysql_change_db(thd,packet))
+ thd->convert_string(&tmp, system_charset_info,
+ packet, strlen(packet), thd->charset());
+ if (!mysql_change_db(thd, tmp.str))
mysql_log.write(thd,command,"%s",thd->db);
break;
+ }
#ifndef EMBEDDED_LIBRARY
case COM_REGISTER_SLAVE:
{
@@ -1138,21 +1170,20 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
}
#endif
case COM_TABLE_DUMP:
- {
- statistic_increment(com_other, &LOCK_status);
- slow_command = TRUE;
- uint db_len = *(uchar*)packet;
- uint tbl_len = *(uchar*)(packet + db_len + 1);
- char* db = thd->alloc(db_len + tbl_len + 2);
- memcpy(db, packet + 1, db_len);
- char* tbl_name = db + db_len;
- *tbl_name++ = 0;
- memcpy(tbl_name, packet + db_len + 2, tbl_len);
- tbl_name[tbl_len] = 0;
- if (mysql_table_dump(thd, db, tbl_name, -1))
- send_error(thd); // dump to NET
- break;
- }
+ {
+ char *db, *tbl_name;
+ uint db_len= *(uchar*) packet;
+ uint tbl_len= *(uchar*) (packet + db_len + 1);
+
+ statistic_increment(com_other, &LOCK_status);
+ slow_command= TRUE;
+ db= thd->alloc(db_len + tbl_len + 2);
+ tbl_name= strmake(db, packet + 1, db_len)+1;
+ strmake(tbl_name, packet + db_len + 2, tbl_len);
+ if (mysql_table_dump(thd, db, tbl_name, -1))
+ send_error(thd); // dump to NET
+ break;
+ }
#ifndef EMBEDDED_LIBRARY
case COM_CHANGE_USER:
{
@@ -1340,8 +1371,9 @@ restore_user:
#else
{
char *fields, *pend;
- String convname;
TABLE_LIST table_list;
+ LEX_STRING conv_name;
+
statistic_increment(com_stat[SQLCOM_SHOW_FIELDS],&LOCK_status);
bzero((char*) &table_list,sizeof(table_list));
if (!(table_list.db=thd->db))
@@ -1351,9 +1383,9 @@ restore_user:
}
thd->free_list=0;
pend= strend(packet);
- convname.copy(packet, pend-packet,
- thd->variables.character_set_client, system_charset_info);
- table_list.alias= table_list.real_name= convname.c_ptr();
+ thd->convert_string(&conv_name, system_charset_info,
+ packet, (uint) (pend-packet), thd->charset());
+ table_list.alias= table_list.real_name= conv_name.str;
packet= pend+1;
// command not cachable => no gap for data base name
if (!(thd->query=fields=thd->memdup(packet,thd->query_length+1)))
@@ -1433,7 +1465,8 @@ restore_user:
pos = uint4korr(packet);
flags = uint2korr(packet + 4);
thd->server_id=0; /* avoid suicide */
- kill_zombie_dump_threads(slave_server_id = uint4korr(packet+6));
+ if ((slave_server_id= uint4korr(packet+6))) // mysqlbinlog.server_id==0
+ kill_zombie_dump_threads(slave_server_id);
thd->server_id = slave_server_id;
mysql_binlog_send(thd, thd->strdup(packet + 10), (my_off_t) pos, flags);
unregister_slave(thd,1,1);
@@ -1492,9 +1525,10 @@ restore_user:
opened_tables,refresh_version, cached_tables(),
uptime ? (float)thd->query_id/(float)uptime : 0);
#ifdef SAFEMALLOC
- if (lCurMemory) // Using SAFEMALLOC
+ if (sf_malloc_cur_memory) // Using SAFEMALLOC
sprintf(strend(buff), " Memory in use: %ldK Max memory used: %ldK",
- (lCurMemory+1023L)/1024L,(lMaxMemory+1023L)/1024L);
+ (sf_malloc_cur_memory+1023L)/1024L,
+ (sf_malloc_max_memory+1023L)/1024L);
#endif
VOID(my_net_write(net, buff,(uint) strlen(buff)));
VOID(net_flush(net));
@@ -1659,12 +1693,16 @@ mysql_execute_command(THD *thd)
given and the table list says the query should not be replicated
*/
if (table_rules_on && tables && !tables_ok(thd,tables))
+ {
+ /* we warn the slave SQL thread */
+ my_error(ER_SLAVE_IGNORED_TABLE, MYF(0));
DBUG_VOID_RETURN;
+ }
#ifndef TO_BE_DELETED
/*
- This is a workaround to deal with the shortcoming in 3.23.44-3.23.46
- masters in RELEASE_LOCK() logging. We re-write SELECT RELEASE_LOCK()
- as DO RELEASE_LOCK()
+ This is a workaround to deal with the shortcoming in 3.23.44-3.23.46
+ masters in RELEASE_LOCK() logging. We re-write SELECT RELEASE_LOCK()
+ as DO RELEASE_LOCK()
*/
if (lex->sql_command == SQLCOM_SELECT)
{
@@ -1699,14 +1737,8 @@ mysql_execute_command(THD *thd)
}
}
}
- if ((&lex->select_lex != lex->all_selects_list &&
- lex->unit.create_total_list(thd, lex, &tables, 0))
-#ifdef HAVE_REPLICATION
- ||
- (table_rules_on && tables && thd->slave_thread &&
- !tables_ok(thd,tables))
-#endif
- )
+ if (&lex->select_lex != lex->all_selects_list &&
+ lex->unit.create_total_list(thd, lex, &tables, 0))
DBUG_VOID_RETURN;
/*
@@ -2067,10 +2099,20 @@ mysql_execute_command(THD *thd)
res= mysql_create_like_table(thd, tables, &lex->create_info,
(Table_ident *)lex->name);
else
+ {
+ List_iterator<create_field> fields(lex->create_list);
+ create_field *field;
+ while ((field= fields++))
+ {
+ if (!field->charset)
+ field->charset= lex->create_info.table_charset;
+ field->create_length_to_internal_length();
+ }
res= mysql_create_table(thd,tables->db ? tables->db : thd->db,
tables->real_name, &lex->create_info,
lex->create_list,
lex->key_list,0,0,0); // do logging
+ }
if (!res)
send_ok(thd);
}
@@ -2434,13 +2476,15 @@ mysql_execute_command(THD *thd)
if (find_real_table_in_list(tables->next, tables->db, tables->real_name))
{
- net_printf(thd,ER_UPDATE_TABLE_USED,tables->real_name);
- DBUG_VOID_RETURN;
+ /* Using same table for INSERT and SELECT */
+ select_lex->options |= OPTION_BUFFER_RESULT;
}
/* Skip first table, which is the table we are inserting in */
lex->select_lex.table_list.first=
(byte*) (((TABLE_LIST *) lex->select_lex.table_list.first)->next);
+ lex->select_lex.resolve_mode= SELECT_LEX::NOMATTER_MODE;
+
if (!(res=open_and_lock_tables(thd, tables)))
{
if ((result=new select_insert(tables->table,&lex->field_list,
@@ -2673,6 +2717,14 @@ mysql_execute_command(THD *thd)
}
if (check_access(thd,SELECT_ACL,db,&thd->col_access))
goto error; /* purecov: inspected */
+ if (!thd->col_access && check_grant_db(thd,db))
+ {
+ net_printf(thd, ER_DBACCESS_DENIED_ERROR,
+ thd->priv_user,
+ thd->priv_host,
+ db);
+ goto error;
+ }
/* grant is checked in mysqld_show_tables */
if (select_lex->options & SELECT_DESCRIBE)
res= mysqld_extend_show_tables(thd,db,
@@ -2831,7 +2883,10 @@ mysql_execute_command(THD *thd)
if (thd->slave_thread &&
(!db_ok(lex->name, replicate_do_db, replicate_ignore_db) ||
!db_ok_with_wild_table(lex->name)))
+ {
+ my_error(ER_SLAVE_IGNORED_TABLE, MYF(0));
break;
+ }
#endif
if (check_access(thd,CREATE_ACL,lex->name,0,1))
break;
@@ -2856,7 +2911,10 @@ mysql_execute_command(THD *thd)
if (thd->slave_thread &&
(!db_ok(lex->name, replicate_do_db, replicate_ignore_db) ||
!db_ok_with_wild_table(lex->name)))
+ {
+ my_error(ER_SLAVE_IGNORED_TABLE, MYF(0));
break;
+ }
#endif
if (check_access(thd,DROP_ACL,lex->name,0,1))
break;
@@ -3094,8 +3152,12 @@ mysql_execute_command(THD *thd)
res = mysql_ha_close(thd, tables);
break;
case SQLCOM_HA_READ:
- if (check_db_used(thd,tables) ||
- check_table_access(thd,SELECT_ACL, tables))
+ /*
+ There is no need to check for table permissions here, because
+ if a user has no permissions to read a table, he won't be
+ able to open it (with SQLCOM_HA_OPEN) in the first place.
+ */
+ if (check_db_used(thd,tables))
goto error;
res = mysql_ha_read(thd, tables, lex->ha_read_mode, lex->backup_dir,
lex->insert_list, lex->ha_rkey_mode, select_lex->where,
@@ -3151,6 +3213,23 @@ mysql_execute_command(THD *thd)
res= -1;
thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
break;
+ case SQLCOM_ROLLBACK_TO_SAVEPOINT:
+ if (!ha_rollback_to_savepoint(thd, lex->savepoint_name))
+ {
+ if (thd->options & OPTION_STATUS_NO_TRANS_UPDATE)
+ send_warning(thd, ER_WARNING_NOT_COMPLETE_ROLLBACK, 0);
+ else
+ send_ok(thd);
+ }
+ else
+ res= -1;
+ break;
+ case SQLCOM_SAVEPOINT:
+ if (!ha_savepoint(thd, lex->savepoint_name))
+ send_ok(thd);
+ else
+ res= -1;
+ break;
default: /* Impossible */
send_ok(thd);
break;
@@ -3254,7 +3333,7 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
if (!(thd->master_access & SELECT_ACL) &&
(db && (!thd->db || strcmp(db,thd->db))))
db_access=acl_get(thd->host, thd->ip, (char*) &thd->remote.sin_addr,
- thd->priv_user, db); /* purecov: inspected */
+ thd->priv_user, db, test(want_access & GRANT_ACL));
*save_priv=thd->master_access | db_access;
DBUG_RETURN(FALSE);
}
@@ -3274,7 +3353,7 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
if (db && (!thd->db || strcmp(db,thd->db)))
db_access=acl_get(thd->host, thd->ip, (char*) &thd->remote.sin_addr,
- thd->priv_user, db); /* purecov: inspected */
+ thd->priv_user, db, test(want_access & GRANT_ACL));
else
db_access=thd->db_access;
// Remove SHOW attribute and access rights we already have
@@ -3526,7 +3605,7 @@ mysql_init_select(LEX *lex)
bool
mysql_new_select(LEX *lex, bool move_down)
{
- SELECT_LEX *select_lex = new SELECT_LEX();
+ SELECT_LEX *select_lex = new(&lex->thd->mem_root) SELECT_LEX();
if (!select_lex)
return 1;
select_lex->select_number= ++lex->thd->select_number;
@@ -3535,7 +3614,7 @@ mysql_new_select(LEX *lex, bool move_down)
if (move_down)
{
/* first select_lex of subselect or derived table */
- SELECT_LEX_UNIT *unit= new SELECT_LEX_UNIT();
+ SELECT_LEX_UNIT *unit= new(&lex->thd->mem_root) SELECT_LEX_UNIT();
if (!unit)
return 1;
unit->init_query();
@@ -3546,6 +3625,7 @@ mysql_new_select(LEX *lex, bool move_down)
unit->link_prev= 0;
unit->return_to= lex->current_select;
select_lex->include_down(unit);
+ // TODO: assign resolve_mode for fake subquery after merging with new tree
}
else
{
@@ -3558,7 +3638,7 @@ mysql_new_select(LEX *lex, bool move_down)
as far as we included SELECT_LEX for UNION unit should have
fake SELECT_LEX for UNION processing
*/
- fake= unit->fake_select_lex= new SELECT_LEX();
+ fake= unit->fake_select_lex= new(&lex->thd->mem_root) SELECT_LEX();
fake->include_standalone(unit,
(SELECT_LEX_NODE**)&unit->fake_select_lex);
fake->select_number= INT_MAX;
@@ -3571,6 +3651,7 @@ mysql_new_select(LEX *lex, bool move_down)
select_lex->master_unit()->global_parameters= select_lex;
select_lex->include_global((st_select_lex_node**)&lex->all_selects_list);
lex->current_select= select_lex;
+ select_lex->resolve_mode= SELECT_LEX::SELECT_MODE;
return 0;
}
@@ -3613,8 +3694,7 @@ void mysql_init_multi_delete(LEX *lex)
mysql_init_select(lex);
lex->select_lex.select_limit= lex->unit.select_limit_cnt=
HA_POS_ERROR;
- lex->auxilliary_table_list= lex->select_lex.table_list;
- lex->select_lex.table_list.empty();
+ lex->select_lex.table_list.save_and_clear(&lex->auxilliary_table_list);
}
@@ -3792,7 +3872,7 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
break;
case FIELD_TYPE_STRING:
case FIELD_TYPE_VAR_STRING:
- if (new_field->length < MAX_FIELD_WIDTH || default_value)
+ if (new_field->length <= MAX_FIELD_CHARLENGTH || default_value)
break;
/* Convert long CHAR() and VARCHAR columns to TEXT or BLOB */
new_field->sql_type= FIELD_TYPE_BLOB;
@@ -3958,13 +4038,14 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
}
}
- if (new_field->length >= MAX_FIELD_WIDTH ||
+ if ((new_field->length > MAX_FIELD_CHARLENGTH && type != FIELD_TYPE_SET &&
+ type != FIELD_TYPE_ENUM) ||
(!new_field->length && !(new_field->flags & BLOB_FLAG) &&
- type != FIELD_TYPE_STRING &&
+ type != FIELD_TYPE_STRING &&
type != FIELD_TYPE_VAR_STRING && type != FIELD_TYPE_GEOMETRY))
{
net_printf(thd,ER_TOO_BIG_FIELDLENGTH,field_name,
- MAX_FIELD_WIDTH-1); /* purecov: inspected */
+ MAX_FIELD_CHARLENGTH); /* purecov: inspected */
DBUG_RETURN(1); /* purecov: inspected */
}
type_modifier&= AUTO_INCREMENT_FLAG;
@@ -4274,6 +4355,11 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
}
if (options & REFRESH_LOG)
{
+ /*
+ Flush the normal query log, the update log, the binary log,
+ the slow query log, and the relay log (if it exists).
+ */
+
/*
Writing this command to the binlog may result in infinite loops when doing
mysqlbinlog|mysql, and anyway it does not really make sense to log it
@@ -4283,6 +4369,7 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
mysql_log.new_file(1);
mysql_update_log.new_file(1);
mysql_bin_log.new_file(1);
+ mysql_slow_log.new_file(1);
#ifdef HAVE_REPLICATION
if (expire_logs_days)
{
@@ -4290,8 +4377,10 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
if (purge_time >= 0)
mysql_bin_log.purge_logs_before_date(purge_time);
}
+ LOCK_ACTIVE_MI;
+ rotate_relay_log(active_mi);
+ UNLOCK_ACTIVE_MI;
#endif
- mysql_slow_log.new_file(1);
if (ha_flush_logs())
result=1;
if (flush_error_log())
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index 121411379f8..3cdf033c477 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -51,7 +51,7 @@ int check_binlog_magic(IO_CACHE* log, const char** errmsg)
}
static int fake_rotate_event(NET* net, String* packet, char* log_file_name,
- const char**errmsg)
+ ulonglong position, const char**errmsg)
{
char header[LOG_EVENT_HEADER_LEN], buf[ROTATE_HEADER_LEN];
memset(header, 0, 4); // when does not matter
@@ -68,9 +68,7 @@ static int fake_rotate_event(NET* net, String* packet, char* log_file_name,
int4store(header + LOG_POS_OFFSET, 0);
packet->append(header, sizeof(header));
- /* We need to split the next statement because of problem with cxx */
- int4store(buf,4); // tell slave to skip magic number
- int4store(buf+4,0);
+ int8store(buf+R_POS_OFFSET,position);
packet->append(buf, ROTATE_HEADER_LEN);
packet->append(p,ident_len);
if (my_net_write(net, (char*)packet->ptr(), packet->length()))
@@ -159,10 +157,18 @@ File open_binlog(IO_CACHE *log, const char *log_file_name,
File file;
DBUG_ENTER("open_binlog");
- if ((file = my_open(log_file_name, O_RDONLY | O_BINARY, MYF(MY_WME))) < 0 ||
- init_io_cache(log, file, IO_SIZE*2, READ_CACHE, 0, 0,
+ if ((file = my_open(log_file_name, O_RDONLY | O_BINARY, MYF(MY_WME))) < 0)
+ {
+ sql_print_error("Failed to open log (\
+file '%s', errno %d)", log_file_name, my_errno);
+ *errmsg = "Could not open log file"; // This will not be sent
+ goto err;
+ }
+ if (init_io_cache(log, file, IO_SIZE*2, READ_CACHE, 0, 0,
MYF(MY_WME | MY_DONT_CHECK_FILESIZE)))
{
+ sql_print_error("Failed to create a cache on log (\
+file '%s')", log_file_name);
*errmsg = "Could not open log file"; // This will not be sent
goto err;
}
@@ -258,22 +264,20 @@ bool log_in_use(const char* log_name)
int purge_error_message(THD* thd, int res)
{
- const char* errmsg = 0;
+ const char *errmsg= 0;
- switch(res) {
+ switch (res) {
case 0: break;
- case LOG_INFO_EOF: errmsg = "Target log not found in binlog index"; break;
- case LOG_INFO_IO: errmsg = "I/O error reading log index file"; break;
- case LOG_INFO_INVALID: errmsg = "Server configuration does not permit \
-binlog purge"; break;
- case LOG_INFO_SEEK: errmsg = "Failed on fseek()"; break;
- case LOG_INFO_PURGE_NO_ROTATE: errmsg = "Cannot purge unrotatable log";
- break;
- case LOG_INFO_MEM: errmsg = "Out of memory"; break;
- case LOG_INFO_FATAL: errmsg = "Fatal error during purge"; break;
- case LOG_INFO_IN_USE: errmsg = "A purgeable log is in use, will not purge";
+ case LOG_INFO_EOF: errmsg= "Target log not found in binlog index"; break;
+ case LOG_INFO_IO: errmsg= "I/O error reading log index file"; break;
+ case LOG_INFO_INVALID:
+ errmsg= "Server configuration does not permit binlog purge"; break;
+ case LOG_INFO_SEEK: errmsg= "Failed on fseek()"; break;
+ case LOG_INFO_MEM: errmsg= "Out of memory"; break;
+ case LOG_INFO_FATAL: errmsg= "Fatal error during purge"; break;
+ case LOG_INFO_IN_USE: errmsg= "A purgeable log is in use, will not purge";
break;
- default: errmsg = "Unknown error during purge"; break;
+ default: errmsg= "Unknown error during purge"; break;
}
if (errmsg)
@@ -281,19 +285,24 @@ binlog purge"; break;
send_error(thd, 0, errmsg);
return 1;
}
- else
- send_ok(thd);
+ send_ok(thd);
return 0;
}
+
int purge_master_logs(THD* thd, const char* to_log)
{
char search_file_name[FN_REFLEN];
+ if (!mysql_bin_log.is_open())
+ {
+ send_ok(current_thd);
+ return 0;
+ }
mysql_bin_log.make_log_name(search_file_name, to_log);
- int res = mysql_bin_log.purge_logs(search_file_name, 0, 1, 1, NULL);
-
- return purge_error_message(thd, res);
+ return purge_error_message(thd,
+ mysql_bin_log.purge_logs(search_file_name, 0, 1,
+ 1, NULL));
}
@@ -385,17 +394,31 @@ impossible position";
*/
packet->set("\0", 1, &my_charset_bin);
- // if we are at the start of the log
- if (pos == BIN_LOG_HEADER_SIZE)
+ /*
+ Before 4.0.14 we called fake_rotate_event below only if
+ (pos == BIN_LOG_HEADER_SIZE), because if this is false then the slave
+ already knows the binlog's name.
+ Now we always call fake_rotate_event; if the slave already knew the log's
+ name (ex: CHANGE MASTER TO MASTER_LOG_FILE=...) this is useless but does
+ not harm much. It is nice for 3.23 (>=.58) slaves which test Rotate events
+ to see if the master is 4.0 (then they choose to stop because they can't
+ replicate 4.0); by always calling fake_rotate_event we are sure that
+ 3.23.58 and newer will detect the problem as soon as replication starts
+ (BUG#198).
+ Always calling fake_rotate_event makes sending of normal
+ (=from-binlog) Rotate events a priori unneeded, but it is not so simple:
+ the 2 Rotate events are not equivalent, the normal one is before the Stop
+ event, the fake one is after. If we don't send the normal one, then the
+ Stop event will be interpreted (by existing 4.0 slaves) as "the master
+ stopped", which is wrong. So for safety, given that we want minimum
+ modification of 4.0, we send the normal and fake Rotates.
+ */
+ if (fake_rotate_event(net, packet, log_file_name, pos, &errmsg))
{
- // tell the client log name with a fake rotate_event
- if (fake_rotate_event(net, packet, log_file_name, &errmsg))
- {
- my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG;
- goto err;
- }
- packet->set("\0", 1, &my_charset_bin);
+ my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG;
+ goto err;
}
+ packet->set("\0", 1, &my_charset_bin);
while (!net->error && net->vio != 0 && !thd->killed)
{
@@ -514,6 +537,11 @@ Increase max_allowed_packet on master";
case LOG_READ_EOF:
DBUG_PRINT("wait",("waiting for data in binary log"));
+ if (thd->server_id==0) // for mysqlbinlog (mysqlbinlog.server_id==0)
+ {
+ pthread_mutex_unlock(log_lock);
+ goto end;
+ }
if (!thd->killed)
{
/* Note that the following call unlocks lock_log */
@@ -588,10 +616,12 @@ Increase max_allowed_packet on master";
end_io_cache(&log);
(void) my_close(file, MYF(MY_WME));
- // fake Rotate_log event just in case it did not make it to the log
- // otherwise the slave make get confused about the offset
+ /*
+ Even if the previous log contained a Rotate_log_event, we still fake
+ one.
+ */
if ((file=open_binlog(&log, log_file_name, &errmsg)) < 0 ||
- fake_rotate_event(net, packet, log_file_name, &errmsg))
+ fake_rotate_event(net, packet, log_file_name, BIN_LOG_HEADER_SIZE, &errmsg))
{
my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG;
goto err;
@@ -601,6 +631,7 @@ Increase max_allowed_packet on master";
}
}
+end:
end_io_cache(&log);
(void)my_close(file, MYF(MY_WME));
@@ -611,7 +642,7 @@ Increase max_allowed_packet on master";
pthread_mutex_unlock(&LOCK_thread_count);
DBUG_VOID_RETURN;
- err:
+err:
thd->proc_info = "waiting to finalize termination";
end_io_cache(&log);
/*
@@ -774,9 +805,15 @@ int reset_slave(THD *thd, MASTER_INFO* mi)
&errmsg)))
goto err;
- // Clear master's log coordinates (only for good display of SHOW SLAVE STATUS)
- mi->master_log_name[0]= 0;
- mi->master_log_pos= BIN_LOG_HEADER_SIZE;
+ /*
+ Clear master's log coordinates and reset host/user/etc to the values
+ specified in mysqld's options (only for good display of SHOW SLAVE STATUS;
+ next init_master_info() (in start_slave() for example) would have set them
+ the same way; but here this is for the case where the user does SHOW SLAVE
+ STATUS; before doing START SLAVE;
+ */
+ init_master_info_with_options(mi);
+ clear_last_slave_error(&mi->rli);
// close master_info_file, relay_log_info_file, set mi->inited=rli->inited=0
end_master_info(mi);
// and delete these two files
@@ -801,6 +838,25 @@ err:
DBUG_RETURN(error);
}
+/*
+
+ Kill all Binlog_dump threads which previously talked to the same slave
+ ("same" means with the same server id). Indeed, if the slave stops, if the
+ Binlog_dump thread is waiting (pthread_cond_wait) for binlog update, then it
+ will keep existing until a query is written to the binlog. If the master is
+ idle, then this could last long, and if the slave reconnects, we could have 2
+ Binlog_dump threads in SHOW PROCESSLIST, until a query is written to the
+ binlog. To avoid this, when the slave reconnects and sends COM_BINLOG_DUMP,
+ the master kills any existing thread with the slave's server id (if this id is
+ not zero; it will be true for real slaves, but false for mysqlbinlog when it
+ sends COM_BINLOG_DUMP to get a remote binlog dump).
+
+ SYNOPSIS
+ kill_zombie_dump_threads()
+ slave_server_id the slave's server id
+
+*/
+
void kill_zombie_dump_threads(uint32 slave_server_id)
{
@@ -852,7 +908,7 @@ int change_master(THD* thd, MASTER_INFO* mi)
// TODO: see if needs re-write
if (init_master_info(mi, master_info_file, relay_log_info_file, 0))
{
- send_error(thd, 0, "Could not initialize master info");
+ send_error(thd, ER_MASTER_INFO);
unlock_slave_threads(mi);
DBUG_RETURN(1);
}
@@ -862,16 +918,21 @@ int change_master(THD* thd, MASTER_INFO* mi)
and we have the hold on the run locks which will keep all threads that
could possibly modify the data structures from running
*/
+
+ /*
+ If the user specified host or port without binlog or position,
+ reset binlog's name to FIRST and position to 4.
+ */
+
if ((lex_mi->host || lex_mi->port) && !lex_mi->log_file_name && !lex_mi->pos)
{
- // if we change host or port, we must reset the postion
mi->master_log_name[0] = 0;
mi->master_log_pos= BIN_LOG_HEADER_SIZE;
}
if (lex_mi->log_file_name)
strmake(mi->master_log_name, lex_mi->log_file_name,
- sizeof(mi->master_log_name));
+ sizeof(mi->master_log_name)-1);
if (lex_mi->pos)
{
mi->master_log_pos= lex_mi->pos;
@@ -879,11 +940,11 @@ int change_master(THD* thd, MASTER_INFO* mi)
DBUG_PRINT("info", ("master_log_pos: %d", (ulong) mi->master_log_pos));
if (lex_mi->host)
- strmake(mi->host, lex_mi->host, sizeof(mi->host));
+ strmake(mi->host, lex_mi->host, sizeof(mi->host)-1);
if (lex_mi->user)
- strmake(mi->user, lex_mi->user, sizeof(mi->user));
+ strmake(mi->user, lex_mi->user, sizeof(mi->user)-1);
if (lex_mi->password)
- strmake(mi->password, lex_mi->password, sizeof(mi->password));
+ strmake(mi->password, lex_mi->password, sizeof(mi->password)-1);
if (lex_mi->port)
mi->port = lex_mi->port;
if (lex_mi->connect_retry)
@@ -936,13 +997,25 @@ int change_master(THD* thd, MASTER_INFO* mi)
}
mi->rli.group_master_log_pos = mi->master_log_pos;
DBUG_PRINT("info", ("master_log_pos: %d", (ulong) mi->master_log_pos));
+ /* If changing RELAY_LOG_FILE or RELAY_LOG_POS, this will be nonsense: */
+ mi->rli.group_master_log_pos= mi->master_log_pos;
strmake(mi->rli.group_master_log_name,mi->master_log_name,
sizeof(mi->rli.group_master_log_name)-1);
if (!mi->rli.group_master_log_name[0]) // uninitialized case
mi->rli.group_master_log_pos=0;
pthread_mutex_lock(&mi->rli.data_lock);
- mi->rli.abort_pos_wait++;
+ mi->rli.abort_pos_wait++; /* for MASTER_POS_WAIT() to abort */
+ /* Clear the error, for a clean start. */
+ clear_last_slave_error(&mi->rli);
+ /*
+ If we don't write new coordinates to disk now, then old will remain in
+ relay-log.info until START SLAVE is issued; but if mysqld is shutdown
+ before START SLAVE, then old will remain in relay-log.info, and will be the
+ in-memory value at restart (thus causing errors, as the old relay log does
+ not exist anymore).
+ */
+ flush_relay_log_info(&mi->rli);
pthread_cond_broadcast(&mi->data_cond);
pthread_mutex_unlock(&mi->rli.data_lock);
@@ -1112,7 +1185,7 @@ int show_binlog_info(THD* thd)
/*
- Send a lost of all binary logs to client
+ Send a list of all binary logs to client
SYNOPSIS
show_binlogs()
@@ -1125,7 +1198,6 @@ int show_binlog_info(THD* thd)
int show_binlogs(THD* thd)
{
- const char *errmsg;
IO_CACHE *index_file;
char fname[FN_REFLEN];
NET* net = &thd->net;
@@ -1138,8 +1210,8 @@ int show_binlogs(THD* thd)
if (!mysql_bin_log.is_open())
{
//TODO: Replace with ER() error message
- errmsg= "You are not using binary logging";
- goto err_with_msg;
+ send_error(thd, 0, "You are not using binary logging");
+ return 1;
}
field_list.push_back(new Item_empty_string("Log_name", 255));
@@ -1164,8 +1236,6 @@ int show_binlogs(THD* thd)
send_eof(thd);
DBUG_RETURN(0);
-err_with_msg:
- send_error(thd, ER_UNKNOWN_ERROR, errmsg);
err:
mysql_bin_log.unlock_index();
DBUG_RETURN(1);
diff --git a/sql/sql_repl.h b/sql/sql_repl.h
index e3d600b9798..fe1b7167d4a 100644
--- a/sql/sql_repl.h
+++ b/sql/sql_repl.h
@@ -7,7 +7,7 @@ typedef struct st_slave_info
uint32 rpl_recovery_rank, master_id;
char host[HOSTNAME_LENGTH+1];
char user[USERNAME_LENGTH+1];
- char password[HASH_PASSWORD_LENGTH+1];
+ char password[MAX_PASSWORD_LENGTH+1];
uint16 port;
THD* thd;
} SLAVE_INFO;
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 3c5c53422ae..15d6b3954ff 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -294,9 +294,7 @@ JOIN::prepare(Item ***rref_pointer_array,
setup_wild(thd, tables_list,
fields_list,
&all_fields, wild_num))) ||
- setup_ref_array(thd, rref_pointer_array, (fields_list.elements +
- select_lex->select_items +
- og_num)) ||
+ select_lex->setup_ref_array(thd, og_num) ||
setup_fields(thd, (*rref_pointer_array), tables_list, fields_list, 1,
&all_fields, 1) ||
setup_without_group(thd, (*rref_pointer_array), tables_list, fields_list,
@@ -574,6 +572,8 @@ JOIN::optimize()
DBUG_RETURN(1);
}
+ /* Remove distinct if only const tables */
+ select_distinct= select_distinct && (const_tables != tables);
thd->proc_info= "preparing";
if (result->initialize_tables(this))
{
@@ -771,7 +771,8 @@ JOIN::optimize()
if (!having)
{
Item *where= 0;
- if (join_tab[0].type == JT_EQ_REF)
+ if (join_tab[0].type == JT_EQ_REF &&
+ join_tab[0].ref.items[0]->name == in_left_expr_name)
{
if (test_in_subselect(&where))
{
@@ -784,7 +785,8 @@ JOIN::optimize()
where)));
}
}
- else if (join_tab[0].type == JT_REF)
+ else if (join_tab[0].type == JT_REF &&
+ join_tab[0].ref.items[0]->name == in_left_expr_name)
{
if (test_in_subselect(&where))
{
@@ -799,6 +801,7 @@ JOIN::optimize()
}
}
} else if (join_tab[0].type == JT_REF_OR_NULL &&
+ join_tab[0].ref.items[0]->name == in_left_expr_name &&
having->type() == Item::FUNC_ITEM &&
((Item_func *) having)->functype() ==
Item_func::ISNOTNULLTEST_FUNC)
@@ -890,7 +893,8 @@ JOIN::optimize()
group_list && simple_group,
select_options,
(order == 0 || skip_sort_order) ? select_limit :
- HA_POS_ERROR)))
+ HA_POS_ERROR,
+ (char *) "")))
DBUG_RETURN(1);
/*
@@ -1223,7 +1227,8 @@ JOIN::exec()
curr_join->select_distinct &&
!curr_join->group_list,
1, curr_join->select_options,
- HA_POS_ERROR)))
+ HA_POS_ERROR,
+ (char *) "")))
DBUG_VOID_RETURN;
curr_join->exec_tmp_table2= exec_tmp_table2;
}
@@ -1837,9 +1842,11 @@ make_join_statistics(JOIN *join,TABLE_LIST *tables,COND *conds,
/*
Set a max range of how many seeks we can expect when using keys
- This was (s->read_time*5), but this was too low with small rows
+ This is can't be to high as otherwise we are likely to use
+ table scan.
*/
- s->worst_seeks= (double) s->found_records / 5;
+ s->worst_seeks= min((double) s->found_records / 10,
+ (double) s->read_time*3);
if (s->worst_seeks < 2.0) // Fix for small tables
s->worst_seeks=2.0;
@@ -2262,6 +2269,9 @@ add_key_part(DYNAMIC_ARRAY *keyuse_array,KEY_FIELD *key_field)
key_field->field->table->reginfo.not_exists_optimize=1;
}
+
+#define FT_KEYPART (MAX_REF_PARTS+10)
+
static void
add_ft_keys(DYNAMIC_ARRAY *keyuse_array,
JOIN_TAB *stat,COND *cond,table_map usable_tables)
@@ -2281,17 +2291,17 @@ add_ft_keys(DYNAMIC_ARRAY *keyuse_array,
{
Item_func *arg0=(Item_func *)(func->arguments()[0]),
*arg1=(Item_func *)(func->arguments()[1]);
- if ((functype == Item_func::GE_FUNC ||
- functype == Item_func::GT_FUNC) &&
- arg0->type() == Item::FUNC_ITEM &&
- arg0->functype() == Item_func::FT_FUNC &&
- arg1->const_item() && arg1->val()>0)
+ if (arg1->const_item() &&
+ ((functype == Item_func::GE_FUNC && arg1->val()> 0) ||
+ (functype == Item_func::GT_FUNC && arg1->val()>=0)) &&
+ arg0->type() == Item::FUNC_ITEM &&
+ arg0->functype() == Item_func::FT_FUNC)
cond_func=(Item_func_match *) arg0;
- else if ((functype == Item_func::LE_FUNC ||
- functype == Item_func::LT_FUNC) &&
+ else if (arg0->const_item() &&
+ ((functype == Item_func::LE_FUNC && arg0->val()> 0) ||
+ (functype == Item_func::LT_FUNC && arg0->val()>=0)) &&
arg1->type() == Item::FUNC_ITEM &&
- arg1->functype() == Item_func::FT_FUNC &&
- arg0->const_item() && arg0->val()>0)
+ arg1->functype() == Item_func::FT_FUNC)
cond_func=(Item_func_match *) arg1;
}
}
@@ -2302,34 +2312,20 @@ add_ft_keys(DYNAMIC_ARRAY *keyuse_array,
if (((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC)
{
Item *item;
- /*
- I'm (Sergei) too lazy to implement proper recursive descent here,
- and anyway, nobody will use such a stupid queries
- that will require it :-)
- May be later...
- */
while ((item=li++))
- {
- if (item->type() == Item::FUNC_ITEM &&
- ((Item_func *)item)->functype() == Item_func::FT_FUNC)
- {
- cond_func=(Item_func_match *)item;
- break;
- }
- }
+ add_ft_keys(keyuse_array,stat,item,usable_tables);
}
}
- if (!cond_func || cond_func->key == NO_SUCH_KEY)
+ if (!cond_func || cond_func->key == NO_SUCH_KEY ||
+ !(usable_tables & cond_func->table->map))
return;
KEYUSE keyuse;
-
keyuse.table= cond_func->table;
keyuse.val = cond_func;
keyuse.key = cond_func->key;
-#define FT_KEYPART (MAX_REF_PARTS+10)
- keyuse.keypart=FT_KEYPART;
+ keyuse.keypart= FT_KEYPART;
keyuse.used_tables=cond_func->key_item()->used_tables();
VOID(insert_dynamic(keyuse_array,(gptr) &keyuse));
}
@@ -2346,7 +2342,8 @@ sort_keyuse(KEYUSE *a,KEYUSE *b)
if (a->keypart != b->keypart)
return (int) (a->keypart - b->keypart);
// Place const values before other ones
- if ((res= test(a->used_tables) - test(b->used_tables)))
+ if ((res= test((a->used_tables & ~OUTER_REF_TABLE_BIT)) -
+ test((b->used_tables & ~OUTER_REF_TABLE_BIT))))
return res;
/* Place rows that are not 'OPTIMIZE_REF_OR_NULL' first */
return (int) ((a->optimize & KEY_OPTIMIZE_REF_OR_NULL) -
@@ -2477,6 +2474,12 @@ static void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array)
keyuse->ref_table_rows= max(tmp_table->file->records, 100);
}
}
+ /*
+ Outer reference (external field) is constant for single executing
+ of subquery
+ */
+ if (keyuse->used_tables == OUTER_REF_TABLE_BIT)
+ keyuse->ref_table_rows= 1;
}
}
@@ -2557,6 +2560,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
best=best_time=records=DBL_MAX;
KEYUSE *best_key=0;
uint best_max_key_part=0;
+ my_bool found_constrain= 0;
if (s->keyuse)
{ /* Use key if possible */
@@ -2621,6 +2625,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
}
else
{
+ found_constrain= 1;
/*
Check if we found full key
*/
@@ -2658,16 +2663,18 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
records=2.0; // Can't be as good as a unique
}
}
+ /* Limit the number of matched rows */
+ tmp= records;
+ set_if_smaller(tmp, (double) thd->variables.max_seeks_for_key);
if (table->used_keys & ((key_map) 1 << key))
{
/* we can use only index tree */
uint keys_per_block= table->file->block_size/2/
(keyinfo->key_length+table->file->ref_length)+1;
- tmp=(record_count*(records+keys_per_block-1)/
- keys_per_block);
+ tmp=record_count*(tmp+keys_per_block-1)/keys_per_block;
}
else
- tmp=record_count*min(records,s->worst_seeks);
+ tmp=record_count*min(tmp,s->worst_seeks);
}
}
else
@@ -2698,7 +2705,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
{
/*
Assume that the first key part matches 1% of the file
- and that the hole key matches 10 (dupplicates) or 1
+ and that the hole key matches 10 (duplicates) or 1
(unique) records.
Assume also that more key matches proportionally more
records
@@ -2736,6 +2743,8 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
records*= 2.0;
}
}
+ /* Limit the number of matched rows */
+ set_if_smaller(tmp, (double) thd->variables.max_seeks_for_key);
if (table->used_keys & ((key_map) 1 << key))
{
/* we can use only index tree */
@@ -2778,20 +2787,31 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
s->table->used_keys && best_key) &&
!(s->table->force_index && best_key))
{ // Check full join
+ ha_rows rnd_records= s->found_records;
if (s->on_expr)
{
- tmp=rows2double(s->found_records); // Can't use read cache
+ tmp=rows2double(rnd_records); // Can't use read cache
}
else
{
tmp=(double) s->read_time;
- /* Calculate time to read through cache */
+ /* Calculate time to read previous rows through cache */
tmp*=(1.0+floor((double) cache_record_length(join,idx)*
record_count /
(double) thd->variables.join_buff_size));
}
+
+ /*
+ If there is a restriction on the table, assume that 25% of the
+ rows can be skipped on next part.
+ This is to force tables that this table depends on before this
+ table
+ */
+ if (found_constrain)
+ rnd_records-= rnd_records/4;
+
if (best == DBL_MAX ||
- (tmp + record_count/(double) TIME_FOR_COMPARE*s->found_records <
+ (tmp + record_count/(double) TIME_FOR_COMPARE*rnd_records <
best + record_count/(double) TIME_FOR_COMPARE*records))
{
/*
@@ -2799,7 +2819,7 @@ find_best(JOIN *join,table_map rest_tables,uint idx,double record_count,
will ensure that this will be used
*/
best=tmp;
- records= rows2double(s->found_records);
+ records= rows2double(rnd_records);
best_key=0;
}
}
@@ -3308,9 +3328,6 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
join->best_positions[i].records_read &&
!(join->select_options & OPTION_FOUND_ROWS)))
{
- /* Join with outer join condition */
- COND *orig_cond=sel->cond;
- sel->cond=and_conds(sel->cond,tab->on_expr);
if (sel->test_quick_select(tab->keys,
used_tables & ~ current_map,
(join->select_options &
@@ -3318,7 +3335,6 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
HA_POS_ERROR :
join->unit->select_limit_cnt)) < 0)
DBUG_RETURN(1); // Impossible range
- sel->cond=orig_cond;
/* Fix for EXPLAIN */
if (sel->quick)
join->best_positions[i].records_read= sel->quick->records;
@@ -3336,7 +3352,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
(select->quick &&
(select->quick->records >= 100L)))) ?
2 : 1;
- sel->read_tables= used_tables;
+ sel->read_tables= used_tables & ~current_map;
}
if (i != join->const_tables && tab->use_quick != 2)
{ /* Read with cache */
@@ -4343,9 +4359,9 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
case STRING_RESULT:
if (item_sum->max_length > 255)
return new Field_blob(item_sum->max_length,maybe_null,
- item->name,table,item->charset());
+ item->name,table,item->collation.collation);
return new Field_string(item_sum->max_length,maybe_null,
- item->name,table,item->charset());
+ item->name,table,item->collation.collation);
case ROW_RESULT:
default:
// This case should never be choosen
@@ -4385,6 +4401,7 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
case Item::STRING_ITEM:
case Item::REF_ITEM:
case Item::NULL_ITEM:
+ case Item::VARBIN_ITEM:
{
bool maybe_null=item->maybe_null;
Field *new_field;
@@ -4402,10 +4419,10 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
case STRING_RESULT:
if (item->max_length > 255)
new_field= new Field_blob(item->max_length,maybe_null,
- item->name,table,item->charset());
+ item->name,table,item->collation.collation);
else
new_field= new Field_string(item->max_length,maybe_null,
- item->name,table,item->charset());
+ item->name,table,item->collation.collation);
break;
case ROW_RESULT:
default:
@@ -4436,7 +4453,8 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type,
TABLE *
create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
ORDER *group, bool distinct, bool save_sum_fields,
- ulong select_options, ha_rows rows_limit)
+ ulong select_options, ha_rows rows_limit,
+ char *table_alias)
{
TABLE *table;
uint i,field_count,reclength,null_count,null_pack_length,
@@ -4525,10 +4543,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
table->field=reg_field;
table->blob_field= (Field_blob**) blob_field;
table->real_name=table->path=tmpname;
- /*
- This must be "" as field may refer to it after tempory table is dropped
- */
- table->table_name= (char*) "";
+ table->table_name= table_alias;
table->reginfo.lock_type=TL_WRITE; /* Will be updated */
table->db_stat=HA_OPEN_KEYFILE+HA_OPEN_RNDFILE;
table->blob_ptr_size=mi_portable_sizeof_char_ptr;
@@ -6650,6 +6665,8 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit,
*/
if (!select->quick->reverse_sorted())
{
+ if (table->file->index_flags(ref_key) & HA_NOT_READ_PREFIX_LAST)
+ DBUG_RETURN(0); // Use filesort
// ORDER BY range_key DESC
QUICK_SELECT_DESC *tmp=new QUICK_SELECT_DESC(select->quick,
used_key_parts);
@@ -6791,6 +6808,8 @@ create_sort_index(THD *thd, JOIN_TAB *tab, ORDER *order,
/*
We have a ref on a const; Change this to a range that filesort
can use.
+ For impossible ranges (like when doing a lookup on NULL on a NOT NULL
+ field, quick will contain an empty record set.
*/
if (!(select->quick=get_ft_or_quick_select_for_ref(table, tab)))
goto err;
@@ -7473,19 +7492,6 @@ find_order_in_list(THD *thd, Item **ref_pointer_array,
}
/*
- Allocate array of references to address all_fileds list elements
-*/
-
-int setup_ref_array(THD* thd, Item ***rref_pointer_array, uint elements)
-{
- if (*rref_pointer_array)
- return 0;
-
- return (*rref_pointer_array=
- (Item **)thd->alloc(sizeof(Item*) * elements * 5)) == 0;
-}
-
-/*
Change order to point at item in select list. If item isn't a number
and doesn't exits in the select list, add it the the field list.
*/
diff --git a/sql/sql_select.h b/sql/sql_select.h
index 7b5aa49b9aa..208eaaea7bd 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -293,7 +293,8 @@ void TEST_join(JOIN *join);
bool store_val_in_field(Field *field,Item *val);
TABLE *create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
ORDER *group, bool distinct, bool save_sum_fields,
- ulong select_options, ha_rows rows_limit);
+ ulong select_options, ha_rows rows_limit,
+ char* alias);
void free_tmp_table(THD *thd, TABLE *entry);
void count_field_types(TMP_TABLE_PARAM *param, List<Item> &fields,
bool reset_with_sum_func);
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index e8cb59e387e..9084269f486 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -75,7 +75,7 @@ mysqld_show_dbs(THD *thd,const char *wild)
{
if (thd->master_access & (DB_ACLS | SHOW_DB_ACL) ||
acl_get(thd->host, thd->ip, (char*) &thd->remote.sin_addr,
- thd->priv_user, file_name) ||
+ thd->priv_user, file_name,0) ||
(grant_option && !check_grant_db(thd, file_name)))
{
protocol->prepare_for_resend();
@@ -415,7 +415,7 @@ mysql_find_files(THD *thd,List<char> *files, const char *db,const char *path,
#endif
{
if (file->name[0] == '.' || !MY_S_ISDIR(file->mystat.st_mode) ||
- (wild && wild_compare(file->name,wild)))
+ (wild && wild_compare(file->name,wild,0)))
continue;
}
}
@@ -433,7 +433,7 @@ mysql_find_files(THD *thd,List<char> *files, const char *db,const char *path,
if (wild_case_compare(system_charset_info,file->name,wild))
continue;
}
- else if (wild_compare(file->name,wild))
+ else if (wild_compare(file->name,wild,0))
continue;
}
}
@@ -1031,7 +1031,7 @@ store_create_info(THD *thd, TABLE *table, String *packet)
my_bool limited_mysql_mode= (thd->variables.sql_mode &
(MODE_NO_FIELD_OPTIONS | MODE_MYSQL323 |
MODE_MYSQL40)) != 0;
-
+
DBUG_ENTER("store_create_info");
DBUG_PRINT("enter",("table: %s",table->real_name));
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 2e6585583ba..37f8d0d7f4f 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -457,12 +457,14 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
else
{
/* Field redefined */
+ sql_field->sql_type= dup_field->sql_type;
+ sql_field->charset= dup_field->charset ? dup_field->charset : create_info->table_charset;
sql_field->length= dup_field->length;
+ sql_field->pack_length= dup_field->pack_length;
+ sql_field->create_length_to_internal_length();
sql_field->decimals= dup_field->decimals;
sql_field->flags= dup_field->flags;
- sql_field->pack_length= dup_field->pack_length;
sql_field->unireg_check= dup_field->unireg_check;
- sql_field->sql_type= dup_field->sql_type;
it2.remove(); // Remove first (create) definition
select_field_pos--;
break;
@@ -480,10 +482,7 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
while ((sql_field=it++))
{
if (!sql_field->charset)
- sql_field->charset = create_info->table_charset ?
- create_info->table_charset :
- thd->variables.character_set_database;
-
+ sql_field->charset = create_info->table_charset;
switch (sql_field->sql_type) {
case FIELD_TYPE_BLOB:
case FIELD_TYPE_MEDIUM_BLOB:
@@ -761,6 +760,8 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
sql_field->flags|= NOT_NULL_FLAG;
sql_field->pack_flag&= ~FIELDFLAG_MAYBE_NULL;
}
+ else
+ key_info->flags|= HA_NULL_PART_KEY;
if (!(file->table_flags() & HA_NULL_KEY))
{
my_printf_error(ER_NULL_COLUMN_IN_INDEX,ER(ER_NULL_COLUMN_IN_INDEX),
@@ -772,7 +773,6 @@ int mysql_create_table(THD *thd,const char *db, const char *table_name,
my_error(ER_SPATIAL_CANT_HAVE_NULL, MYF(0));
DBUG_RETURN(-1);
}
- key_info->flags|= HA_NULL_PART_KEY;
}
if (MTYP_TYPENR(sql_field->unireg_check) == Field::NEXT_NUMBER)
{
@@ -1088,7 +1088,8 @@ mysql_rename_table(enum db_type base,
wait_while_table_is_used()
thd Thread handler
table Table to remove from cache
-
+ function HA_EXTRA_PREPARE_FOR_DELETE if table is to be deleted
+ HA_EXTRA_FORCE_REOPEN if table is not be used
NOTES
When returning, the table will be unusable for other threads until
the table is closed.
@@ -1098,13 +1099,14 @@ mysql_rename_table(enum db_type base,
Win32 clients must also have a WRITE LOCK on the table !
*/
-static void wait_while_table_is_used(THD *thd,TABLE *table)
+static void wait_while_table_is_used(THD *thd,TABLE *table,
+ enum ha_extra_function function)
{
DBUG_PRINT("enter",("table: %s", table->real_name));
DBUG_ENTER("wait_while_table_is_used");
safe_mutex_assert_owner(&LOCK_open);
- VOID(table->file->extra(HA_EXTRA_FORCE_REOPEN)); // Close all data files
+ VOID(table->file->extra(function));
/* Mark all tables that are in use as 'old' */
mysql_lock_abort(thd, table); // end threads waiting on lock
@@ -1140,7 +1142,7 @@ static bool close_cached_table(THD *thd, TABLE *table)
{
DBUG_ENTER("close_cached_table");
- wait_while_table_is_used(thd,table);
+ wait_while_table_is_used(thd, table, HA_EXTRA_PREPARE_FOR_DELETE);
/* Close lock if this is not got with LOCK TABLES */
if (thd->lock)
{
@@ -1366,6 +1368,7 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables,
if (protocol->send_fields(&field_list, 1))
DBUG_RETURN(-1);
+ mysql_ha_closeall(thd, tables);
for (table = tables; table; table = table->next)
{
char table_name[NAME_LEN*2+2];
@@ -1852,16 +1855,25 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
break;
case ENABLE:
VOID(pthread_mutex_lock(&LOCK_open));
- wait_while_table_is_used(thd, table);
+ wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN);
VOID(pthread_mutex_unlock(&LOCK_open));
error= table->file->activate_all_index(thd);
/* COND_refresh will be signaled in close_thread_tables() */
break;
case DISABLE:
- VOID(pthread_mutex_lock(&LOCK_open));
- wait_while_table_is_used(thd, table);
- VOID(pthread_mutex_unlock(&LOCK_open));
- table->file->deactivate_non_unique_index(HA_POS_ERROR);
+ if (table->db_type == DB_TYPE_MYISAM)
+ {
+ VOID(pthread_mutex_lock(&LOCK_open));
+ wait_while_table_is_used(thd, table, HA_EXTRA_FORCE_REOPEN);
+ VOID(pthread_mutex_unlock(&LOCK_open));
+ table->file->deactivate_non_unique_index(HA_POS_ERROR);
+ }
+ else
+ push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+ ER_ILLEGAL_HA,
+ ER(ER_ILLEGAL_HA), table->table_name);
+ break;
+
/* COND_refresh will be signaled in close_thread_tables() */
break;
}
@@ -1882,18 +1894,42 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
}
/* Full alter table */
+
+ /* let new create options override the old ones */
+ if (!(used_fields & HA_CREATE_USED_MIN_ROWS))
+ create_info->min_rows=table->min_rows;
+ if (!(used_fields & HA_CREATE_USED_MAX_ROWS))
+ create_info->max_rows=table->max_rows;
+ if (!(used_fields & HA_CREATE_USED_AVG_ROW_LENGTH))
+ create_info->avg_row_length=table->avg_row_length;
+ if (!(used_fields & HA_CREATE_USED_CHARSET))
+ create_info->table_charset=table->table_charset;
+
restore_record(table,default_values); // Empty record for DEFAULT
List_iterator<Alter_drop> drop_it(drop_list);
List_iterator<create_field> def_it(fields);
List_iterator<Alter_column> alter_it(alter_list);
List<create_field> create_list; // Add new fields here
List<Key> key_list; // Add new keys here
+ create_field *def;
+
+ /*
+ For each column set charset to the table
+ default if the column charset hasn't been specified
+ explicitely. Change CREATE length into internal length
+ */
+ def_it.rewind();
+ while ((def= def_it++))
+ {
+ if (!def->charset)
+ def->charset= create_info->table_charset;
+ def->create_length_to_internal_length();
+ }
/*
First collect all fields from table which isn't in drop_list
*/
- create_field *def;
Field **f_ptr,*field;
for (f_ptr=table->field ; (field= *f_ptr) ; f_ptr++)
{
@@ -2112,16 +2148,6 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
if (!create_info->comment)
create_info->comment=table->comment;
- /* let new create options override the old ones */
- if (!(used_fields & HA_CREATE_USED_MIN_ROWS))
- create_info->min_rows=table->min_rows;
- if (!(used_fields & HA_CREATE_USED_MAX_ROWS))
- create_info->max_rows=table->max_rows;
- if (!(used_fields & HA_CREATE_USED_AVG_ROW_LENGTH))
- create_info->avg_row_length=table->avg_row_length;
- if (!(used_fields & HA_CREATE_USED_CHARSET))
- create_info->table_charset=table->table_charset;
-
table->file->update_create_info(create_info);
if ((create_info->table_options &
(HA_OPTION_PACK_KEYS | HA_OPTION_NO_PACK_KEYS)) ||
@@ -2479,8 +2505,7 @@ copy_data_between_tables(TABLE *from,TABLE *to,
tables.db = from->table_cache_key;
error=1;
- if (setup_ref_array(thd, &thd->lex.select_lex.ref_pointer_array,
- order_num)||
+ if (thd->lex.select_lex.setup_ref_array(thd, order_num) ||
setup_order(thd, thd->lex.select_lex.ref_pointer_array,
&tables, fields, all_fields, order) ||
!(sortorder=make_unireg_sortorder(order, &length)) ||
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index 0866163b3fd..ae91b0b3ace 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -83,7 +83,7 @@ bool select_union::send_data(List<Item> &values)
{
thd->clear_error(); // do not report user about table overflow
if (create_myisam_from_heap(thd, table, &tmp_table_param,
- info.last_errno, 0))
+ info.last_errno, 1))
return 1;
}
else
@@ -123,7 +123,8 @@ int st_select_lex_unit::prepare(THD *thd, select_result *sel_result,
DBUG_RETURN(0);
prepared= 1;
res= 0;
- found_rows_for_union= 0;
+ found_rows_for_union= test(first_select_in_union()->options
+ & OPTION_FOUND_ROWS);
TMP_TABLE_PARAM tmp_table_param;
result= sel_result;
t_and_f= tables_and_fields_initied;
@@ -131,13 +132,6 @@ int st_select_lex_unit::prepare(THD *thd, select_result *sel_result,
bzero((char *)&tmp_table_param,sizeof(TMP_TABLE_PARAM));
thd->lex.current_select= select_cursor= first_select_in_union();
/* Global option */
- if (((void*)(global_parameters)) == ((void*)this))
- {
- found_rows_for_union= first_select()->options & OPTION_FOUND_ROWS &&
- global_parameters->select_limit;
- if (found_rows_for_union)
- first_select()->options ^= OPTION_FOUND_ROWS;
- }
if (t_and_f)
{
// Item list and tables will be initialized by mysql_derived
@@ -154,18 +148,21 @@ int st_select_lex_unit::prepare(THD *thd, select_result *sel_result,
goto err;
List_iterator<Item> it(select_cursor->item_list);
Item *item;
- while((item=it++))
- item->maybe_null=1;
item_list= select_cursor->item_list;
select_cursor->with_wild= 0;
- if (setup_ref_array(thd, &select_cursor->ref_pointer_array,
- (item_list.elements + select_cursor->select_items +
- select_cursor->order_list.elements +
- select_cursor->group_list.elements)) ||
+ if (select_cursor->setup_ref_array(thd,
+ select_cursor->order_list.elements +
+ select_cursor->group_list.elements) ||
setup_fields(thd, select_cursor->ref_pointer_array, first_table,
item_list, 0, 0, 1))
goto err;
t_and_f= 1;
+ while((item=it++))
+ {
+ item->maybe_null=1;
+ if (item->type() == Item::FIELD_ITEM)
+ ((class Item_field *)item)->field->table->maybe_null=1;
+ }
}
tmp_table_param.field_count=item_list.elements;
@@ -173,7 +170,7 @@ int st_select_lex_unit::prepare(THD *thd, select_result *sel_result,
(ORDER*) 0, !union_option,
1, (select_cursor->options | thd->options |
TMP_TABLE_ALL_COLUMNS),
- HA_POS_ERROR)))
+ HA_POS_ERROR, (char*) "")))
goto err;
table->file->extra(HA_EXTRA_WRITE_CACHE);
table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
@@ -198,7 +195,7 @@ int st_select_lex_unit::prepare(THD *thd, select_result *sel_result,
select_limit_cnt= sl->select_limit+sl->offset_limit;
if (select_limit_cnt < sl->select_limit)
select_limit_cnt= HA_POS_ERROR; // no limit
- if (select_limit_cnt == HA_POS_ERROR)
+ if (select_limit_cnt == HA_POS_ERROR && !sl->braces)
sl->options&= ~OPTION_FOUND_ROWS;
res= join->prepare(&sl->ref_pointer_array,
@@ -240,9 +237,9 @@ err:
int st_select_lex_unit::exec()
{
- int do_print_slow= 0;
SELECT_LEX *lex_select_save= thd->lex.current_select;
SELECT_LEX *select_cursor=first_select_in_union();
+ ha_rows add_rows=0;
DBUG_ENTER("st_select_lex_unit::exec");
if (executed && !(dependent || uncacheable))
@@ -259,6 +256,7 @@ int st_select_lex_unit::exec()
}
for (SELECT_LEX *sl= select_cursor; sl; sl= sl->next_select())
{
+ ha_rows rows= 0;
thd->lex.current_select= sl;
if (optimized)
@@ -271,6 +269,11 @@ int st_select_lex_unit::exec()
select_limit_cnt= HA_POS_ERROR; // no limit
if (select_limit_cnt == HA_POS_ERROR)
sl->options&= ~OPTION_FOUND_ROWS;
+ else if (found_rows_for_union)
+ {
+ rows= sl->select_limit;
+ sl->options|= OPTION_FOUND_ROWS;
+ }
/*
As far as union share table space we should reassign table map,
@@ -311,7 +314,10 @@ int st_select_lex_unit::exec()
thd->lex.current_select= lex_select_save;
DBUG_RETURN(res);
}
- do_print_slow|= select_cursor->options;
+ if (found_rows_for_union && !sl->braces &&
+ (sl->options & OPTION_FOUND_ROWS))
+ add_rows+= (sl->join->send_records > rows) ?
+ sl->join->send_records - rows : 0;
}
}
optimized= 1;
@@ -326,16 +332,20 @@ int st_select_lex_unit::exec()
if (!thd->is_fatal_error) // Check if EOM
{
+ ulong options= thd->options;
thd->lex.current_select= fake_select_lex;
- offset_limit_cnt= (select_cursor->braces ?
- global_parameters->offset_limit : 0);
- select_limit_cnt= (select_cursor->braces ?
- global_parameters->select_limit+
- global_parameters->offset_limit : HA_POS_ERROR);
- if (select_limit_cnt < global_parameters->select_limit)
- select_limit_cnt= HA_POS_ERROR; // no limit
+ if (select_cursor->braces)
+ {
+ offset_limit_cnt= global_parameters->offset_limit;
+ select_limit_cnt= global_parameters->select_limit +
+ global_parameters->offset_limit;
+ if (select_limit_cnt < global_parameters->select_limit)
+ select_limit_cnt= HA_POS_ERROR; // no limit
+ }
if (select_limit_cnt == HA_POS_ERROR)
- thd->options&= ~OPTION_FOUND_ROWS;
+ options&= ~OPTION_FOUND_ROWS;
+ else if (found_rows_for_union && !describe)
+ options|= OPTION_FOUND_ROWS;
fake_select_lex->ftfunc_list= &empty_list;
fake_select_lex->table_list.link_in_list((byte *)&result_table_list,
(byte **)
@@ -348,6 +358,11 @@ int st_select_lex_unit::exec()
mysql_select automatic allocation)
*/
fake_select_lex->join= new JOIN(thd, item_list, thd->options, result);
+ /*
+ Fake st_select_lex should have item list for correctref_array
+ allocation.
+ */
+ fake_select_lex->item_list= item_list;
}
else
{
@@ -365,19 +380,18 @@ int st_select_lex_unit::exec()
global_parameters->order_list.elements,
(ORDER*)global_parameters->order_list.first,
(ORDER*) NULL, NULL, (ORDER*) NULL,
- thd->options, result, this, fake_select_lex, 0);
+ options | SELECT_NO_UNLOCK,
+ result, this, fake_select_lex, 0);
if (found_rows_for_union && !res)
- thd->limit_found_rows = (ulonglong)table->file->records;
+ {
+ thd->limit_found_rows= table->file->records;
+ if (!select_cursor->braces)
+ thd->limit_found_rows+= add_rows;
+ }
/*
Mark for slow query log if any of the union parts didn't use
indexes efficiently
*/
- select_cursor->options= ((select_cursor->options &
- ~(QUERY_NO_INDEX_USED |
- QUERY_NO_GOOD_INDEX_USED)) |
- do_print_slow &
- (QUERY_NO_INDEX_USED |
- QUERY_NO_GOOD_INDEX_USED));
}
}
thd->lex.current_select= lex_select_save;
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index e1c28dd0e4d..29138f10989 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -91,11 +91,11 @@ int mysql_update(THD *thd,
bzero((char*) &tables,sizeof(tables)); // For ORDER BY
tables.table= table;
+ tables.alias= table_list->alias;
if (setup_tables(update_table_list) ||
setup_conds(thd,update_table_list,&conds) ||
- setup_ref_array(thd, &thd->lex.select_lex.ref_pointer_array,
- order_num) ||
+ thd->lex.select_lex.setup_ref_array(thd, order_num) ||
setup_order(thd, thd->lex.select_lex.ref_pointer_array,
&tables, all_fields, all_fields, order) ||
setup_ftfuncs(&thd->lex.select_lex))
@@ -423,7 +423,7 @@ int mysql_multi_update(THD *thd,
DBUG_RETURN(res);
fix_tables_pointers(thd->lex.all_selects_list);
- thd->select_limit=HA_POS_ERROR;
+ select_lex->select_limit= HA_POS_ERROR;
if (setup_fields(thd, 0, table_list, *fields, 1, 0, 0))
DBUG_RETURN(-1);
@@ -640,7 +640,8 @@ multi_update::initialize_tables(JOIN *join)
temp_fields,
(ORDER*) &group, 0, 0,
TMP_TABLE_ALL_COLUMNS,
- HA_POS_ERROR)))
+ HA_POS_ERROR,
+ (char *) "")))
DBUG_RETURN(1);
tmp_tables[cnt]->file->extra(HA_EXTRA_WRITE_CACHE);
}
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index da7cde6c316..539bb90d907 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -67,9 +67,9 @@ inline Item *or_or_concat(THD *thd, Item* A, Item* B)
TABLE_LIST *table_list;
udf_func *udf;
LEX_USER *lex_user;
- sys_var *variable;
+ struct sys_var_with_base variable;
Key::Keytype key_type;
- enum ha_key_alg key_alg;
+ enum ha_key_alg key_alg;
enum db_type db_type;
enum row_type row_type;
enum ha_rkey_function ha_rkey_mode;
@@ -154,6 +154,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token RESET_SYM
%token ROLLBACK_SYM
%token ROLLUP_SYM
+%token SAVEPOINT_SYM
%token SELECT_SYM
%token SHOW
%token SLAVE
@@ -526,6 +527,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token UNIQUE_USERS
%token UNIX_TIMESTAMP
%token USER
+%token UTC_DATE_SYM
+%token UTC_TIME_SYM
+%token UTC_TIMESTAMP_SYM
%token WEEK_SYM
%token WHEN_SYM
%token WORK_SYM
@@ -547,7 +551,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token SUBJECT_SYM
%token CIPHER_SYM
-%token HELP
%token BEFORE_SYM
%left SET_VAR
%left OR_OR_CONCAT OR
@@ -617,7 +620,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
key_alg opt_btree_or_rtree
%type <string_list>
- key_usage_list
+ key_usage_list
%type <key_part>
key_part
@@ -639,7 +642,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%type <ha_rkey_mode> handler_rkey_mode
-%type <cast_type> cast_type
+%type <cast_type> cast_type cast_type_finalize
%type <udf_type> udf_func_type
@@ -666,7 +669,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
query verb_clause create change select do drop insert replace insert2
insert_values update delete truncate rename
show describe load alter optimize preload flush
- reset purge begin commit rollback slave master_def master_defs
+ reset purge begin commit rollback savepoint
+ slave master_def master_defs
repair restore backup analyze check start
field_list field_list_item field_spec kill column_def key_def
preload_list preload_keys
@@ -747,6 +751,7 @@ verb_clause:
| restore
| revoke
| rollback
+ | savepoint
| select
| set
| slave
@@ -815,10 +820,10 @@ master_def:
MASTER_LOG_POS_SYM EQ ulonglong_num
{
Lex->mi.pos = $3;
- /*
+ /*
If the user specified a value < BIN_LOG_HEADER_SIZE, adjust it
- instead of causing subsequent errors.
- We need to do it in this file, because only there we know that
+ instead of causing subsequent errors.
+ We need to do it in this file, because only there we know that
MASTER_LOG_POS has been explicitely specified. On the contrary
in change_master() (sql_repl.cc) we cannot distinguish between 0
(MASTER_LOG_POS explicitely specified as 0) and 0 (unspecified),
@@ -877,7 +882,7 @@ create:
lex->name=0;
}
create2
- {}
+ { Lex->current_select= &Lex->select_lex; }
| CREATE opt_unique_or_fulltext INDEX ident key_alg ON table_ident
{
LEX *lex=Lex;
@@ -897,7 +902,7 @@ create:
lex->key_list.push_back(new Key($2,$4.str, $5, lex->col_list));
lex->col_list.empty();
}
- | CREATE DATABASE opt_if_not_exists ident
+ | CREATE DATABASE opt_if_not_exists ident
{ Lex->create_info.table_charset=NULL; }
opt_create_database_options
{
@@ -922,7 +927,7 @@ create:
;
create2:
- '(' field_list ')' opt_create_table_options create3 {}
+ '(' create2a {}
| opt_create_table_options create3 {}
| LIKE table_ident
{
@@ -936,14 +941,31 @@ create2:
if (!(lex->name= (char *)$3))
YYABORT;
}
- ;
+ ;
+
+create2a:
+ field_list ')' opt_create_table_options create3 {}
+ | create_select ')' { Select->set_braces(1);} union_opt {}
+ ;
create3:
/* empty */ {}
- | opt_duplicate opt_as SELECT_SYM
+ | opt_duplicate opt_as create_select
+ { Select->set_braces(0);} union_clause {}
+ | opt_duplicate opt_as '(' create_select ')'
+ { Select->set_braces(1);} union_opt {}
+ ;
+
+create_select:
+ SELECT_SYM
{
LEX *lex=Lex;
lex->lock_option= (using_update_log) ? TL_READ_NO_INSERT : TL_READ;
+ if (lex->sql_command == SQLCOM_INSERT)
+ lex->sql_command= SQLCOM_INSERT_SELECT;
+ else if (lex->sql_command == SQLCOM_REPLACE)
+ lex->sql_command= SQLCOM_REPLACE_SELECT;
+ lex->current_select->table_list.save_and_clear(&lex->save_list);
mysql_init_select(lex);
lex->current_select->parsing_place= SELECT_LEX_NODE::SELECT_LIST;
}
@@ -951,8 +973,9 @@ create3:
{
Select->parsing_place= SELECT_LEX_NODE::NO_MATTER;
}
- opt_select_from union_clause {}
- ;
+ opt_select_from
+ { Lex->current_select->table_list.push_front(&Lex->save_list); }
+ ;
opt_as:
/* empty */ {}
@@ -1170,10 +1193,10 @@ type:
| char opt_binary { Lex->length=(char*) "1";
$$=FIELD_TYPE_STRING; }
| nchar '(' NUM ')' { Lex->length=$3.str;
- $$=FIELD_TYPE_STRING;
+ $$=FIELD_TYPE_STRING;
Lex->charset=national_charset_info; }
| nchar { Lex->length=(char*) "1";
- $$=FIELD_TYPE_STRING;
+ $$=FIELD_TYPE_STRING;
Lex->charset=national_charset_info; }
| BINARY '(' NUM ')' { Lex->length=$3.str;
Lex->charset=&my_charset_bin;
@@ -1352,8 +1375,8 @@ attribute:
| UNIQUE_SYM { Lex->type|= UNIQUE_FLAG; }
| UNIQUE_SYM KEY_SYM { Lex->type|= UNIQUE_KEY_FLAG; }
| COMMENT_SYM text_literal { Lex->comment= $2; }
- | COLLATE_SYM collation_name
- {
+ | COLLATE_SYM collation_name
+ {
if (Lex->charset && !my_charset_same(Lex->charset,$2))
{
net_printf(YYTHD,ER_COLLATION_CHARSET_MISMATCH,
@@ -1411,7 +1434,7 @@ collation_name:
{
if (!($$=get_charset_by_name($1.str,MYF(0))))
{
- net_printf(YYTHD,ER_UNKNOWN_CHARACTER_SET,$1.str);
+ net_printf(YYTHD,ER_UNKNOWN_COLLATION,$1.str);
YYABORT;
}
};
@@ -1818,7 +1841,7 @@ optimize:
{
LEX *lex=Lex;
lex->sql_command = SQLCOM_OPTIMIZE;
- lex->no_write_to_binlog= $2;
+ lex->no_write_to_binlog= $2;
lex->check_opt.init();
}
table_list opt_mi_check_type
@@ -1847,7 +1870,7 @@ table_to_table_list:
table_to_table:
table_ident TO_SYM table_ident
{
- LEX *lex=Lex;
+ LEX *lex=Lex;
SELECT_LEX *sl= lex->current_select;
if (!sl->add_table_to_list(lex->thd, $1,NULL,TL_OPTION_UPDATING,
TL_IGNORE) ||
@@ -1875,8 +1898,8 @@ preload_keys:
{
LEX *lex=Lex;
SELECT_LEX *sel= &lex->select_lex;
- if (!sel->add_table_to_list(lex->thd, $1, NULL, $3,
- TL_READ,
+ if (!sel->add_table_to_list(lex->thd, $1, NULL, $3,
+ TL_READ,
sel->get_use_index(),
(List<String> *)0))
YYABORT;
@@ -1885,13 +1908,13 @@ preload_keys:
preload_keys_spec:
keys_or_index { Select->interval_list.empty(); }
- preload_key_list_or_empty
+ preload_key_list_or_empty
{
LEX *lex=Lex;
SELECT_LEX *sel= &lex->select_lex;
sel->use_index= sel->interval_list;
sel->use_index_ptr= &sel->use_index;
- }
+ }
;
preload_key_list_or_empty:
@@ -1911,7 +1934,13 @@ opt_ignore_leaves:
select:
- select_init { Lex->sql_command=SQLCOM_SELECT; };
+ select_init
+ {
+ LEX *lex= Lex;
+ lex->sql_command= SQLCOM_SELECT;
+ lex->select_lex.resolve_mode= SELECT_LEX::SELECT_MODE;
+ }
+ ;
/* Need select_init2 for subselects. */
select_init:
@@ -2270,7 +2299,7 @@ interval_expr:
simple_expr:
simple_ident
| simple_expr COLLATE_SYM ident_or_text %prec NEG
- {
+ {
$$= new Item_func_set_collation($1,
new Item_string($3.str,
$3.length,
@@ -2320,17 +2349,25 @@ simple_expr:
{ Select->add_ftfunc_to_list((Item_func_match *)
($$=new Item_func_match_bool(*$2,$5))); }
| ASCII_SYM '(' expr ')' { $$= new Item_func_ascii($3); }
- | BINARY expr %prec NEG
+ | BINARY expr %prec NEG
{
$$= new Item_func_set_collation($2,new Item_string(binary_keyword,
6, &my_charset_latin1));
}
| CAST_SYM '(' expr AS cast_type ')'
- { $$= create_func_cast($3, $5, Lex->charset); }
+ {
+ $$= create_func_cast($3, $5,
+ Lex->length ? atoi(Lex->length) : -1,
+ Lex->charset);
+ }
| CASE_SYM opt_expr WHEN_SYM when_list opt_else END
{ $$= new Item_func_case(* $4, $2, $5 ); }
| CONVERT_SYM '(' expr ',' cast_type ')'
- { $$= create_func_cast($3, $5, Lex->charset); }
+ {
+ $$= create_func_cast($3, $5,
+ Lex->length ? atoi(Lex->length) : -1,
+ Lex->charset);
+ }
| CONVERT_SYM '(' expr USING charset_name ')'
{ $$= new Item_func_conv_charset($3,$5); }
| CONVERT_SYM '(' expr ',' expr ',' expr ')'
@@ -2368,12 +2405,12 @@ simple_expr:
| CONCAT_WS '(' expr ',' expr_list ')'
{ $$= new Item_func_concat_ws($3, *$5); }
| CURDATE optional_braces
- { $$= new Item_func_curdate(); Lex->safe_to_cache_query=0; }
+ { $$= new Item_func_curdate_local(); Lex->safe_to_cache_query=0; }
| CURTIME optional_braces
- { $$= new Item_func_curtime(); Lex->safe_to_cache_query=0; }
+ { $$= new Item_func_curtime_local(); Lex->safe_to_cache_query=0; }
| CURTIME '(' expr ')'
{
- $$= new Item_func_curtime($3);
+ $$= new Item_func_curtime_local($3);
Lex->safe_to_cache_query=0;
}
| DATE_ADD_INTERVAL '(' expr ',' interval_expr interval ')'
@@ -2496,14 +2533,14 @@ simple_expr:
| LINEFROMTEXT '(' expr ',' expr ')'
{ $$= new Item_func_geometry_from_text($3, $5); }
| MASTER_POS_WAIT '(' expr ',' expr ')'
- {
+ {
$$= new Item_master_pos_wait($3, $5);
- Lex->safe_to_cache_query=0;
+ Lex->safe_to_cache_query=0;
}
| MASTER_POS_WAIT '(' expr ',' expr ',' expr ')'
- {
+ {
$$= new Item_master_pos_wait($3, $5, $7);
- Lex->safe_to_cache_query=0;
+ Lex->safe_to_cache_query=0;
}
| MICROSECOND_SYM '(' expr ')'
{ $$= new Item_func_microsecond($3); }
@@ -2535,9 +2572,9 @@ simple_expr:
{ $$= new Item_func_spatial_collection(* $3,
Geometry::wkbMultiPolygon, Geometry::wkbPolygon ); }
| NOW_SYM optional_braces
- { $$= new Item_func_now(); Lex->safe_to_cache_query=0;}
+ { $$= new Item_func_now_local(); Lex->safe_to_cache_query=0;}
| NOW_SYM '(' expr ')'
- { $$= new Item_func_now($3); Lex->safe_to_cache_query=0;}
+ { $$= new Item_func_now_local($3); Lex->safe_to_cache_query=0;}
| PASSWORD '(' expr ')'
{ $$= new Item_func_password($3); }
| PASSWORD '(' expr ',' expr ')'
@@ -2665,10 +2702,16 @@ simple_expr:
{ $$= new Item_func_unix_timestamp($3); }
| USER '(' ')'
{ $$= new Item_func_user(); Lex->safe_to_cache_query=0; }
+ | UTC_DATE_SYM optional_braces
+ { $$= new Item_func_curdate_utc(); Lex->safe_to_cache_query=0;}
+ | UTC_TIME_SYM optional_braces
+ { $$= new Item_func_curtime_utc(); Lex->safe_to_cache_query=0;}
+ | UTC_TIMESTAMP_SYM optional_braces
+ { $$= new Item_func_now_utc(); Lex->safe_to_cache_query=0;}
| WEEK_SYM '(' expr ')'
- {
+ {
$$= new Item_func_week($3,new Item_int((char*) "0",
- YYTHD->variables.default_week_format,1));
+ YYTHD->variables.default_week_format,1));
}
| WEEK_SYM '(' expr ',' expr ')'
{ $$= new Item_func_week($3,$5); }
@@ -2719,9 +2762,10 @@ sum_expr:
{ $$=new Item_sum_variance($3); }
| SUM_SYM '(' in_sum_expr ')'
{ $$=new Item_sum_sum($3); }
- | GROUP_CONCAT_SYM '(' opt_distinct expr_list opt_gorder_clause opt_gconcat_separator ')'
- {
- $$=new Item_func_group_concat($3,$4,Lex->gorder_list,$6);
+ | GROUP_CONCAT_SYM '(' opt_distinct expr_list opt_gorder_clause
+ opt_gconcat_separator ')'
+ {
+ $$=new Item_func_group_concat($3,$4,Lex->gorder_list,$6);
$4->empty();
};
@@ -2732,10 +2776,10 @@ opt_distinct:
opt_gconcat_separator:
/* empty */ { $$ = new String(",",1,default_charset_info); }
|SEPARATOR_SYM text_string { $$ = $2; };
-
+
opt_gorder_clause:
- /* empty */
+ /* empty */
{
LEX *lex=Lex;
lex->gorder_list = NULL;
@@ -2746,7 +2790,7 @@ opt_gorder_clause:
lex->gorder_list= (SQL_LIST*) sql_memdup((char*) &lex->current_select->order_list,sizeof(st_sql_list));
lex->current_select->order_list.empty();
};
-
+
in_sum_expr:
opt_all
@@ -2764,16 +2808,25 @@ in_sum_expr:
$$= $3;
};
+cast_type_init:
+ { Lex->charset= NULL; Lex->length= (char*)0; }
+ ;
+
+cast_type_finalize:
+ BINARY { $$=ITEM_CAST_BINARY; }
+ | CHAR_SYM opt_len opt_binary { $$=ITEM_CAST_CHAR; }
+ | NCHAR_SYM opt_len { $$=ITEM_CAST_CHAR; Lex->charset= national_charset_info; }
+ | SIGNED_SYM { $$=ITEM_CAST_SIGNED_INT; }
+ | SIGNED_SYM INT_SYM { $$=ITEM_CAST_SIGNED_INT; }
+ | UNSIGNED { $$=ITEM_CAST_UNSIGNED_INT; }
+ | UNSIGNED INT_SYM { $$=ITEM_CAST_UNSIGNED_INT; }
+ | DATE_SYM { $$=ITEM_CAST_DATE; }
+ | TIME_SYM { $$=ITEM_CAST_TIME; }
+ | DATETIME { $$=ITEM_CAST_DATETIME; }
+ ;
+
cast_type:
- BINARY { $$=ITEM_CAST_BINARY; Lex->charset= NULL; }
- | CHAR_SYM opt_binary { $$=ITEM_CAST_CHAR; }
- | SIGNED_SYM { $$=ITEM_CAST_SIGNED_INT; Lex->charset= NULL; }
- | SIGNED_SYM INT_SYM { $$=ITEM_CAST_SIGNED_INT; Lex->charset= NULL; }
- | UNSIGNED { $$=ITEM_CAST_UNSIGNED_INT; Lex->charset= NULL; }
- | UNSIGNED INT_SYM { $$=ITEM_CAST_UNSIGNED_INT; Lex->charset= NULL; }
- | DATE_SYM { $$=ITEM_CAST_DATE; Lex->charset= NULL; }
- | TIME_SYM { $$=ITEM_CAST_TIME; Lex->charset= NULL; }
- | DATETIME { $$=ITEM_CAST_DATETIME; Lex->charset= NULL; }
+ cast_type_init cast_type_finalize { $$= $2; }
;
expr_list:
@@ -2835,7 +2888,7 @@ join_table_list:
| join_table_list normal_join join_table_list ON expr
{ add_join_on($3,$5); $$=$3; }
| join_table_list normal_join join_table_list
- USING
+ USING
{
SELECT_LEX *sel= Select;
sel->db1=$1->db; sel->table1=$1->alias;
@@ -2921,8 +2974,9 @@ select_derived:
{
LEX *lex= Lex;
lex->derived_tables= 1;
- if (((int)lex->sql_command >= (int)SQLCOM_HA_OPEN &&
- lex->sql_command <= (int)SQLCOM_HA_READ) || lex->sql_command == (int)SQLCOM_KILL)
+ if (((int)lex->sql_command >= (int)SQLCOM_HA_OPEN &&
+ lex->sql_command <= (int)SQLCOM_HA_READ) ||
+ lex->sql_command == (int)SQLCOM_KILL)
{
send_error(lex->thd, ER_SYNTAX_ERROR);
YYABORT;
@@ -3364,7 +3418,7 @@ drop:
LEX *lex=Lex;
lex->sql_command = SQLCOM_DROP_USER;
lex->users_list.empty();
- }
+ }
user_list
{}
;
@@ -3402,11 +3456,12 @@ insert:
lex->sql_command = SQLCOM_INSERT;
/* for subselects */
lex->lock_option= (using_update_log) ? TL_READ_NO_INSERT : TL_READ;
- lex->select_lex.insert_select= 1;
+ lex->select_lex.resolve_mode= SELECT_LEX::INSERT_MODE;
} insert_lock_option
opt_ignore insert2
{
Select->set_lock_for_tables($3);
+ Lex->current_select= &Lex->select_lex;
}
insert_field_spec opt_insert_update
{}
@@ -3418,11 +3473,12 @@ replace:
LEX *lex=Lex;
lex->sql_command = SQLCOM_REPLACE;
lex->duplicates= DUP_REPLACE;
- lex->select_lex.insert_select= 1;
+ lex->select_lex.resolve_mode= SELECT_LEX::INSERT_MODE;
}
replace_lock_option insert2
{
Select->set_lock_for_tables($3);
+ Lex->current_select= &Lex->select_lex;
}
insert_field_spec
{}
@@ -3454,7 +3510,9 @@ insert_table:
};
insert_field_spec:
- opt_field_spec insert_values {}
+ insert_values {}
+ | '(' ')' insert_values {}
+ | '(' fields ')' insert_values {}
| SET
{
LEX *lex=Lex;
@@ -3476,27 +3534,9 @@ fields:
insert_values:
VALUES values_list {}
| VALUE_SYM values_list {}
- | SELECT_SYM
- {
- LEX *lex=Lex;
- lex->sql_command = (lex->sql_command == SQLCOM_INSERT ?
- SQLCOM_INSERT_SELECT : SQLCOM_REPLACE_SELECT);
- lex->lock_option= (using_update_log) ? TL_READ_NO_INSERT : TL_READ;
- mysql_init_select(lex);
- /*
- it is not simple select => table list will be
- preprocessed before passing to handle_select
- */
- lex->select_lex.insert_select= 0;
- lex->current_select->parsing_place= SELECT_LEX_NODE::SELECT_LIST;
- }
- select_options select_item_list
- {
- Select->parsing_place= SELECT_LEX_NODE::NO_MATTER;
- }
- opt_select_from select_lock_type
- union_clause {}
- ;
+ | create_select { Select->set_braces(0);} union_clause {}
+ | '(' create_select ')' { Select->set_braces(1);} union_opt {}
+ ;
values_list:
values_list ',' no_braces
@@ -3901,7 +3941,7 @@ flush:
{
LEX *lex=Lex;
lex->sql_command= SQLCOM_FLUSH; lex->type=0;
- lex->no_write_to_binlog= $2;
+ lex->no_write_to_binlog= $2;
}
flush_options
{}
@@ -3970,7 +4010,7 @@ purge_option:
if ($2->check_cols(1) || $2->fix_fields(Lex->thd, 0, &$2))
{
net_printf(Lex->thd, ER_WRONG_ARGUMENTS, "PURGE LOGS BEFORE");
- YYABORT;
+ YYABORT;
}
Item *tmp= new Item_func_unix_timestamp($2);
Lex->sql_command = SQLCOM_PURGE_BEFORE;
@@ -4142,8 +4182,8 @@ literal:
{
Item *tmp= new Item_varbinary($2.str,$2.length);
String *str= tmp ? tmp->val_str((String*) 0) : (String*) 0;
- $$ = new Item_string(str ? str->ptr() : "", str ? str->length() : 0,
- Lex->charset);
+ $$ = new Item_string(str ? str->ptr() : "", str ? str->length() :
+ 0, Lex->charset);
}
| DATE_SYM text_literal { $$ = $2; }
| TIME_SYM text_literal { $$ = $2; }
@@ -4158,7 +4198,7 @@ insert_ident:
| table_wild { $$=$1; };
table_wild:
- ident '.' '*'
+ ident '.' '*'
{
$$ = new Item_field(NullS,$1.str,"*");
Lex->current_select->with_wild++;
@@ -4191,7 +4231,7 @@ simple_ident:
SELECT_LEX *sel= lex->current_select;
if (sel->no_table_names_allowed)
{
- my_printf_error(ER_TABLENAME_NOT_ALLOWED_HERE,
+ my_printf_error(ER_TABLENAME_NOT_ALLOWED_HERE,
ER(ER_TABLENAME_NOT_ALLOWED_HERE),
MYF(0), $1.str, thd->where);
}
@@ -4207,7 +4247,7 @@ simple_ident:
SELECT_LEX *sel= lex->current_select;
if (sel->no_table_names_allowed)
{
- my_printf_error(ER_TABLENAME_NOT_ALLOWED_HERE,
+ my_printf_error(ER_TABLENAME_NOT_ALLOWED_HERE,
ER(ER_TABLENAME_NOT_ALLOWED_HERE),
MYF(0), $2.str, thd->where);
}
@@ -4223,7 +4263,7 @@ simple_ident:
SELECT_LEX *sel= lex->current_select;
if (sel->no_table_names_allowed)
{
- my_printf_error(ER_TABLENAME_NOT_ALLOWED_HERE,
+ my_printf_error(ER_TABLENAME_NOT_ALLOWED_HERE,
ER(ER_TABLENAME_NOT_ALLOWED_HERE),
MYF(0), $3.str, thd->where);
}
@@ -4253,17 +4293,11 @@ IDENT_sys:
IDENT
{
THD *thd= YYTHD;
- if (my_charset_same(thd->charset(),system_charset_info))
- {
- $$=$1;
- }
+ if (thd->charset_is_system_charset)
+ $$= $1;
else
- {
- String ident;
- ident.copy($1.str,$1.length,thd->charset(),system_charset_info);
- $$.str= thd->strmake(ident.ptr(),ident.length());
- $$.length= ident.length();
- }
+ thd->convert_string(&$$, system_charset_info,
+ $1.str, $1.length, thd->charset());
}
;
@@ -4271,17 +4305,11 @@ TEXT_STRING_sys:
TEXT_STRING
{
THD *thd= YYTHD;
- if (my_charset_same(thd->charset(),system_charset_info))
- {
- $$=$1;
- }
+ if (thd->charset_is_system_charset)
+ $$= $1;
else
- {
- String ident;
- ident.copy($1.str,$1.length,thd->charset(),system_charset_info);
- $$.str= thd->strmake(ident.ptr(),ident.length());
- $$.length= ident.length();
- }
+ thd->convert_string(&$$, system_charset_info,
+ $1.str, $1.length, thd->charset());
}
;
@@ -4289,17 +4317,11 @@ TEXT_STRING_literal:
TEXT_STRING
{
THD *thd= YYTHD;
- if (my_charset_same(thd->charset(),thd->variables.collation_connection))
- {
- $$=$1;
- }
+ if (thd->charset_is_collation_connection)
+ $$= $1;
else
- {
- String ident;
- ident.copy($1.str,$1.length,thd->charset(),thd->variables.collation_connection);
- $$.str= thd->strmake(ident.ptr(),ident.length());
- $$.length= ident.length();
- }
+ thd->convert_string(&$$, thd->variables.collation_connection,
+ $1.str, $1.length, thd->charset());
}
;
@@ -4308,9 +4330,9 @@ ident:
IDENT_sys { $$=$1; }
| keyword
{
- LEX *lex= Lex;
- $$.str= lex->thd->strmake($1.str,$1.length);
- $$.length=$1.length;
+ THD *thd= YYTHD;
+ $$.str= thd->strmake($1.str, $1.length);
+ $$.length= $1.length;
}
;
@@ -4485,6 +4507,7 @@ keyword:
| ROWS_SYM {}
| ROW_FORMAT_SYM {}
| ROW_SYM {}
+ | SAVEPOINT_SYM {}
| SECOND_SYM {}
| SERIAL_SYM {}
| SERIALIZABLE_SYM {}
@@ -4576,18 +4599,24 @@ option_value:
| internal_variable_name equal set_expr_or_default
{
LEX *lex=Lex;
- lex->var_list.push_back(new set_var(lex->option_type, $1, $3));
+ lex->var_list.push_back(new set_var(lex->option_type, $1.var,
+ &$1.base_name, $3));
}
| '@' '@' opt_var_ident_type internal_variable_name equal set_expr_or_default
{
LEX *lex=Lex;
- lex->var_list.push_back(new set_var((enum_var_type) $3, $4, $6));
+ lex->var_list.push_back(new set_var((enum_var_type) $3, $4.var,
+ &$4.base_name, $6));
}
| TRANSACTION_SYM ISOLATION LEVEL_SYM isolation_types
{
LEX *lex=Lex;
+ LEX_STRING tmp;
+ tmp.str=0;
+ tmp.length=0;
lex->var_list.push_back(new set_var(lex->option_type,
find_sys_var("tx_isolation"),
+ &tmp,
new Item_int((int32) $4)));
}
| charset old_or_new_charset_name_or_default
@@ -4632,7 +4661,9 @@ internal_variable_name:
sys_var *tmp=find_sys_var($1.str, $1.length);
if (!tmp)
YYABORT;
- $$=tmp;
+ $$.var= tmp;
+ $$.base_name.str=0;
+ $$.base_name.length=0;
}
| ident '.' ident
{
@@ -4641,8 +4672,8 @@ internal_variable_name:
YYABORT;
if (!tmp->is_struct())
net_printf(YYTHD, ER_VARIABLE_IS_NOT_STRUCT, $3.str);
- tmp->base_name= $1;
- $$=tmp;
+ $$.var= tmp;
+ $$.base_name= $1;
}
| DEFAULT '.' ident
{
@@ -4651,9 +4682,9 @@ internal_variable_name:
YYABORT;
if (!tmp->is_struct())
net_printf(YYTHD, ER_VARIABLE_IS_NOT_STRUCT, $3.str);
- tmp->base_name.str= (char*) "default";
- tmp->base_name.length= 7;
- $$=tmp;
+ $$.var= tmp;
+ $$.base_name.str= (char*) "default";
+ $$.base_name.length= 7;
}
;
@@ -4834,7 +4865,7 @@ grant:
lex->select_lex.db= 0;
lex->ssl_type= SSL_TYPE_NOT_SPECIFIED;
lex->ssl_cipher= lex->x509_subject= lex->x509_issuer= 0;
- bzero(&(lex->mqh),sizeof(lex->mqh));
+ bzero((char *)&(lex->mqh),sizeof(lex->mqh));
}
grant_privileges ON opt_table TO_SYM user_list
require_clause grant_options
@@ -5095,8 +5126,21 @@ commit:
COMMIT_SYM { Lex->sql_command = SQLCOM_COMMIT;};
rollback:
- ROLLBACK_SYM { Lex->sql_command = SQLCOM_ROLLBACK;};
-
+ ROLLBACK_SYM
+ {
+ Lex->sql_command = SQLCOM_ROLLBACK;
+ }
+ | ROLLBACK_SYM TO_SYM SAVEPOINT_SYM ident
+ {
+ Lex->sql_command = SQLCOM_ROLLBACK_TO_SAVEPOINT;
+ Lex->savepoint_name = $4.str;
+ };
+savepoint:
+ SAVEPOINT_SYM ident
+ {
+ Lex->sql_command = SQLCOM_SAVEPOINT;
+ Lex->savepoint_name = $2.str;
+ };
/*
UNIONS : glue selects together
diff --git a/sql/table.cc b/sql/table.cc
index 0fc2a09f749..9d12de1f6c7 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -138,7 +138,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
outparam->raid_chunks= head[42];
outparam->raid_chunksize= uint4korr(head+43);
if (!(outparam->table_charset=get_charset((uint) head[38],MYF(0))))
- outparam->table_charset=NULL; // QQ display error message?
+ outparam->table_charset=default_charset_info; // QQ display error message?
null_field_first=1;
}
outparam->db_record_offset=1;
@@ -398,8 +398,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
if (!strpos[14])
charset= &my_charset_bin;
else if (!(charset=get_charset((uint) strpos[14], MYF(0))))
- charset= (outparam->table_charset ? outparam->table_charset:
- default_charset_info);
+ charset= outparam->table_charset;
}
if (!comment_length)
{
@@ -423,8 +422,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
/* old frm file */
field_type= (enum_field_types) f_packtype(pack_flag);
- charset=(outparam->table_charset ? outparam->table_charset :
- default_charset_info);
+ charset=f_is_binary(pack_flag) ? &my_charset_bin : outparam->table_charset;
bzero((char*) &comment, sizeof(comment));
}
*field_ptr=reg_field=
@@ -486,7 +484,10 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
/* This has to be done after the above fulltext correction */
index_flags=outparam->file->index_flags(key);
if (!(index_flags & HA_KEY_READ_ONLY))
+ {
+ outparam->read_only_keys|= ((key_map) 1 << key);
outparam->keys_for_keyread&= ~((key_map) 1 << key);
+ }
if (primary_key >= MAX_KEY && (keyinfo->flags & HA_NOSAME))
{
@@ -599,7 +600,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
}
keyinfo->usable_key_parts=usable_parts; // Filesort
}
- if (primary_key < MAX_KEY &&
+ if (primary_key < MAX_KEY &&
(outparam->keys_in_use & ((key_map) 1 << primary_key)))
{
outparam->primary_key=primary_key;
@@ -1172,23 +1173,25 @@ rename_file_ext(const char * from,const char * to,const char * ext)
res result String
RETURN VALUES
- true string is empty
- false all ok
+ 1 string is empty
+ 0 all ok
*/
bool get_field(MEM_ROOT *mem, Field *field, String *res)
{
- char buff[MAX_FIELD_WIDTH];
+ char buff[MAX_FIELD_WIDTH], *to;
String str(buff,sizeof(buff),&my_charset_bin);
+ uint length;
+
field->val_str(&str,&str);
- uint length=str.length();
- if (!length)
- return true;
- char *to= strmake_root(mem, str.ptr(), length);
- res->set(to,length,((Field_str*)field)->charset());
- return false;
+ if (!(length= str.length()))
+ return 1;
+ to= strmake_root(mem, str.ptr(), length);
+ res->set(to, length, ((Field_str*)field)->charset());
+ return 0;
}
+
/*
Allocate string field in MEM_ROOT and return it as NULL-terminated string
@@ -1204,14 +1207,15 @@ bool get_field(MEM_ROOT *mem, Field *field, String *res)
char *get_field(MEM_ROOT *mem, Field *field)
{
- char buff[MAX_FIELD_WIDTH];
+ char buff[MAX_FIELD_WIDTH], *to;
String str(buff,sizeof(buff),&my_charset_bin);
+ uint length;
+
field->val_str(&str,&str);
- uint length=str.length();
- if (!length)
+ if (!(length= str.length()))
return NullS;
- char *to= (char*) alloc_root(mem,length+1);
- memcpy(to,str.ptr(),(uint) length);
+ to= (char*) alloc_root(mem,length+1);
+ memcpy(to, str.ptr(), (uint) length);
to[length]=0;
return to;
}
diff --git a/sql/table.h b/sql/table.h
index 185b22a64f2..7b4e5745732 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -76,7 +76,7 @@ struct st_table {
uint uniques;
uint null_fields; /* number of null fields */
uint blob_fields; /* number of blob fields */
- key_map keys_in_use, keys_for_keyread;
+ key_map keys_in_use, keys_for_keyread, read_only_keys;
key_map quick_keys, used_keys, keys_in_use_for_query;
KEY *key_info; /* data of keys in database */
TYPELIB keynames; /* Pointers to keynames */
@@ -116,6 +116,8 @@ struct st_table {
my_bool crashed;
my_bool is_view;
my_bool no_keyread;
+ my_bool clear_query_id; /* To reset query_id for tables and cols */
+ my_bool auto_increment_field_not_null;
Field *next_number_field, /* Set if next_number is activated */
*found_next_number_field, /* Set on open */
*rowid_field;
diff --git a/sql/uniques.cc b/sql/uniques.cc
index c6fb0f25643..4514de834a8 100644
--- a/sql/uniques.cc
+++ b/sql/uniques.cc
@@ -49,8 +49,8 @@ int unique_write_to_ptrs(gptr key, element_count count, Unique *unique)
}
Unique::Unique(qsort_cmp2 comp_func, void * comp_func_fixed_arg,
- uint size, ulong max_in_memory_size_arg)
- :max_in_memory_size(max_in_memory_size_arg),elements(0)
+ uint size_arg, ulong max_in_memory_size_arg)
+ :max_in_memory_size(max_in_memory_size_arg), size(size_arg), elements(0)
{
my_b_clear(&file);
init_tree(&tree, max_in_memory_size / 16, 0, size, comp_func, 0, NULL,
@@ -101,7 +101,7 @@ bool Unique::get(TABLE *table)
{
/* Whole tree is in memory; Don't use disk if you don't need to */
if ((record_pointers=table->sort.record_pointers= (byte*)
- my_malloc(tree.size_of_element * tree.elements_in_tree, MYF(0))))
+ my_malloc(size * tree.elements_in_tree, MYF(0))))
{
(void) tree_walk(&tree, (tree_walk_action) unique_write_to_ptrs,
this, left_root_right);
diff --git a/sql/unireg.h b/sql/unireg.h
index 4bbfa8b0fae..4920d4b609a 100644
--- a/sql/unireg.h
+++ b/sql/unireg.h
@@ -58,7 +58,12 @@
#endif
#define MAX_HOSTNAME 61 /* len+1 in mysql.user */
-#define MAX_FIELD_WIDTH 256 /* Max column width +1 */
+#define MAX_MBWIDTH 3 /* Max multibyte sequence */
+#define MAX_FIELD_CHARLENGTH 255
+/* Max column width +1 */
+#define MAX_FIELD_WIDTH (MAX_FIELD_CHARLENGTH*MAX_MBWIDTH+1)
+
+
#define MAX_TABLES (sizeof(table_map)*8-2) /* Max tables in join */
#define OUTER_REF_TABLE_BIT (((table_map) 1) << (sizeof(table_map)*8-2))
#define RAND_TABLE_BIT (((table_map) 1) << (sizeof(table_map)*8-1))