summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <monty@mysql.com>2004-12-06 11:38:56 +0200
committerunknown <monty@mysql.com>2004-12-06 11:38:56 +0200
commit796bd7de96a1d1ec422708b90df5328388201c10 (patch)
treea7bb331b7dac7ac2b3cda915e99bb8c1333f4fec /sql
parent289d3b2ee0f912dd4f128e1c61685d7bb170eb90 (diff)
parentf8cdf570979c550ef04c53f691118ed2b1296a7c (diff)
downloadmariadb-git-796bd7de96a1d1ec422708b90df5328388201c10.tar.gz
Merge with 4.1
BitKeeper/etc/ignore: auto-union BitKeeper/etc/logging_ok: auto-union BUILD/SETUP.sh: Auto merged Build-tools/Do-compile: Auto merged client/mysqladmin.cc: Auto merged configure.in: Auto merged innobase/include/lock0lock.h: Auto merged innobase/os/os0file.c: Auto merged libmysqld/Makefile.am: Auto merged mysql-test/mysql-test-run.sh: Auto merged mysql-test/r/ctype_ucs.result: Auto merged mysql-test/r/heap.result: Auto merged mysql-test/r/insert_select.result: Auto merged mysql-test/r/lowercase_table3.result: Auto merged mysql-test/r/rpl_start_stop_slave.result: Auto merged mysql-test/r/subselect.result: Auto merged mysql-test/t/ctype_ucs.test: Auto merged mysql-test/t/rpl_until.test: Auto merged mysql-test/t/subselect.test: Auto merged ndb/src/kernel/blocks/dblqh/DblqhMain.cpp: Auto merged sql/field.cc: Auto merged sql/field.h: Auto merged sql/ha_myisam.h: Auto merged sql/handler.cc: Auto merged sql/handler.h: Auto merged sql/item.h: Auto merged sql/item_cmpfunc.cc: Auto merged sql/item_func.cc: Auto merged sql/lock.cc: Auto merged sql/log_event.h: Auto merged sql/mysql_priv.h: Auto merged sql/mysqld.cc: Auto merged sql/set_var.cc: Auto merged sql/slave.cc: Auto merged sql/slave.h: Auto merged sql/sql_acl.cc: Auto merged sql/sql_base.cc: Auto merged sql/sql_class.h: Auto merged sql/sql_db.cc: Auto merged sql/sql_delete.cc: Auto merged sql/sql_prepare.cc: Auto merged sql/sql_rename.cc: Auto merged sql/sql_select.cc: Auto merged sql/sql_show.cc: Auto merged sql/sql_update.cc: Auto merged sql/sql_yacc.yy: Auto merged sql/log_event.cc: Merge with 4.1 Trivial cleanup
Diffstat (limited to 'sql')
-rw-r--r--sql/field.cc39
-rw-r--r--sql/field.h1
-rw-r--r--sql/handler.cc4
-rw-r--r--sql/item.h6
-rw-r--r--sql/item_cmpfunc.cc12
-rw-r--r--sql/item_func.cc2
-rw-r--r--sql/lock.cc65
-rw-r--r--sql/log.cc15
-rw-r--r--sql/log_event.cc22
-rw-r--r--sql/log_event.h20
-rw-r--r--sql/mysql_priv.h3
-rw-r--r--sql/mysqld.cc2
-rw-r--r--sql/set_var.cc9
-rw-r--r--sql/slave.cc2
-rw-r--r--sql/slave.h2
-rw-r--r--sql/sql_acl.cc4
-rw-r--r--sql/sql_base.cc4
-rw-r--r--sql/sql_class.h12
-rw-r--r--sql/sql_db.cc44
-rw-r--r--sql/sql_delete.cc6
-rw-r--r--sql/sql_insert.cc70
-rw-r--r--sql/sql_lex.cc2
-rw-r--r--sql/sql_lex.h2
-rw-r--r--sql/sql_parse.cc116
-rw-r--r--sql/sql_prepare.cc13
-rw-r--r--sql/sql_rename.cc2
-rw-r--r--sql/sql_select.cc7
-rw-r--r--sql/sql_show.cc9
-rw-r--r--sql/sql_table.cc158
-rw-r--r--sql/sql_update.cc4
-rw-r--r--sql/sql_yacc.yy20
31 files changed, 441 insertions, 236 deletions
diff --git a/sql/field.cc b/sql/field.cc
index 5e76c590aac..73caddf1d0b 100644
--- a/sql/field.cc
+++ b/sql/field.cc
@@ -5869,25 +5869,24 @@ bool Field_num::eq_def(Field *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;
- case MYSQL_TYPE_ENUM:
- case MYSQL_TYPE_SET:
- length*= charset->mbmaxlen;
- break;
- default:
- /* do nothing */
- break;
+ 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;
+ case MYSQL_TYPE_ENUM:
+ case MYSQL_TYPE_SET:
+ length*= charset->mbmaxlen;
+ break;
+ default:
+ /* do nothing */
+ break;
}
}
@@ -6112,6 +6111,8 @@ create_field::create_field(Field *old_field,Field *orig_field)
}
length=(length+charset->mbmaxlen-1)/charset->mbmaxlen; // QQ: Probably not needed
break;
+ case MYSQL_TYPE_ENUM:
+ case MYSQL_TYPE_SET:
case FIELD_TYPE_STRING:
case FIELD_TYPE_VAR_STRING:
length=(length+charset->mbmaxlen-1)/charset->mbmaxlen;
diff --git a/sql/field.h b/sql/field.h
index d1c2fa3b6fd..b4e8e61e3fb 100644
--- a/sql/field.h
+++ b/sql/field.h
@@ -1196,6 +1196,7 @@ public:
uint decimals,flags,pack_length;
Field::utype unireg_check;
TYPELIB *interval; // Which interval to use
+ List<String> interval_list;
CHARSET_INFO *charset;
Field::geometry_type geom_type;
Field *field; // For alter table
diff --git a/sql/handler.cc b/sql/handler.cc
index b474e6290f2..edb4d5b488b 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -736,7 +736,7 @@ int ha_rollback_to_savepoint(THD *thd, char *savepoint_name)
if (unlikely((thd->options & OPTION_STATUS_NO_TRANS_UPDATE) &&
my_b_tell(&thd->transaction.trans_log)))
{
- Query_log_event qinfo(thd, thd->query, thd->query_length, TRUE);
+ Query_log_event qinfo(thd, thd->query, thd->query_length, TRUE, FALSE);
if (mysql_bin_log.write(&qinfo))
error= 1;
}
@@ -774,7 +774,7 @@ int ha_savepoint(THD *thd, char *savepoint_name)
innobase_savepoint(thd,savepoint_name,
my_b_tell(&thd->transaction.trans_log));
#endif
- Query_log_event qinfo(thd, thd->query, thd->query_length, TRUE);
+ Query_log_event qinfo(thd, thd->query, thd->query_length, TRUE, FALSE);
if (mysql_bin_log.write(&qinfo))
error= 1;
}
diff --git a/sql/item.h b/sql/item.h
index 2c2978e841c..973039f9127 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -1375,7 +1375,7 @@ class Item_cache_int: public Item_cache
{
longlong value;
public:
- Item_cache_int(): Item_cache() {}
+ Item_cache_int(): Item_cache(), value(0) {}
void store(Item *item);
double val_real() { DBUG_ASSERT(fixed == 1); return (double) value; }
@@ -1393,7 +1393,7 @@ class Item_cache_real: public Item_cache
{
double value;
public:
- Item_cache_real(): Item_cache() {}
+ Item_cache_real(): Item_cache(), value(0) {}
void store(Item *item);
double val_real() { DBUG_ASSERT(fixed == 1); return value; }
@@ -1415,7 +1415,7 @@ class Item_cache_str: public Item_cache
char buffer[80];
String *value, value_buff;
public:
- Item_cache_str(): Item_cache() { }
+ Item_cache_str(): Item_cache(), value(0) { }
void store(Item *item);
double val_real();
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 389a614e3d5..7611b70c6a4 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -2430,10 +2430,10 @@ Item_func_regex::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
}
int error;
if ((error= regcomp(&preg,res->c_ptr(),
- ((cmp_collation.collation->state & MY_CS_BINSORT) ||
- (cmp_collation.collation->state & MY_CS_CSSORT)) ?
+ ((cmp_collation.collation->state &
+ (MY_CS_BINSORT | MY_CS_CSSORT)) ?
REG_EXTENDED | REG_NOSUB :
- REG_EXTENDED | REG_NOSUB | REG_ICASE,
+ REG_EXTENDED | REG_NOSUB | REG_ICASE),
cmp_collation.collation)))
{
(void) regerror(error,&preg,buff,sizeof(buff));
@@ -2482,10 +2482,10 @@ longlong Item_func_regex::val_int()
regex_compiled=0;
}
if (regcomp(&preg,res2->c_ptr(),
- ((cmp_collation.collation->state & MY_CS_BINSORT) ||
- (cmp_collation.collation->state & MY_CS_CSSORT)) ?
+ ((cmp_collation.collation->state &
+ (MY_CS_BINSORT | MY_CS_CSSORT)) ?
REG_EXTENDED | REG_NOSUB :
- REG_EXTENDED | REG_NOSUB | REG_ICASE,
+ REG_EXTENDED | REG_NOSUB | REG_ICASE),
cmp_collation.collation))
{
null_value=1;
diff --git a/sql/item_func.cc b/sql/item_func.cc
index eb3db156056..8fefb355efe 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -2098,7 +2098,7 @@ void item_user_lock_release(User_level_lock *ull)
tmp.copy(command, strlen(command), tmp.charset());
tmp.append(ull->key,ull->key_length);
tmp.append("\")", 2);
- Query_log_event qev(current_thd, tmp.ptr(), tmp.length(),1);
+ Query_log_event qev(current_thd, tmp.ptr(), tmp.length(),1, FALSE);
qev.error_code=0; // this query is always safe to run on slave
mysql_bin_log.write(&qev);
}
diff --git a/sql/lock.cc b/sql/lock.cc
index 3367c6a2900..8a3619b57dd 100644
--- a/sql/lock.cc
+++ b/sql/lock.cc
@@ -707,15 +707,70 @@ static void print_lock_error(int error)
/****************************************************************************
Handling of global read locks
+ Taking the global read lock is TWO steps (2nd step is optional; without
+ it, COMMIT of existing transactions will be allowed):
+ lock_global_read_lock() THEN make_global_read_lock_block_commit().
+
The global locks are handled through the global variables:
global_read_lock
+ count of threads which have the global read lock (i.e. have completed at
+ least the first step above)
global_read_lock_blocks_commit
- waiting_for_read_lock
+ count of threads which have the global read lock and block
+ commits (i.e. have completed the second step above)
+ waiting_for_read_lock
+ count of threads which want to take a global read lock but cannot
protect_against_global_read_lock
+ count of threads which have set protection against global read lock.
+
+ How blocking of threads by global read lock is achieved: that's
+ advisory. Any piece of code which should be blocked by global read lock must
+ be designed like this:
+ - call to wait_if_global_read_lock(). When this returns 0, no global read
+ lock is owned; if argument abort_on_refresh was 0, none can be obtained.
+ - job
+ - if abort_on_refresh was 0, call to start_waiting_global_read_lock() to
+ allow other threads to get the global read lock. I.e. removal of the
+ protection.
+ (Note: it's a bit like an implementation of rwlock).
+
+ [ I am sorry to mention some SQL syntaxes below I know I shouldn't but found
+ no better descriptive way ]
+
+ Why does FLUSH TABLES WITH READ LOCK need to block COMMIT: because it's used
+ to read a non-moving SHOW MASTER STATUS, and a COMMIT writes to the binary
+ log.
+
+ Why getting the global read lock is two steps and not one. Because FLUSH
+ TABLES WITH READ LOCK needs to insert one other step between the two:
+ flushing tables. So the order is
+ 1) lock_global_read_lock() (prevents any new table write locks, i.e. stalls
+ all new updates)
+ 2) close_cached_tables() (the FLUSH TABLES), which will wait for tables
+ currently opened and being updated to close (so it's possible that there is
+ a moment where all new updates of server are stalled *and* FLUSH TABLES WITH
+ READ LOCK is, too).
+ 3) make_global_read_lock_block_commit().
+ If we have merged 1) and 3) into 1), we would have had this deadlock:
+ imagine thread 1 and 2, in non-autocommit mode, thread 3, and an InnoDB
+ table t.
+ thd1: SELECT * FROM t FOR UPDATE;
+ thd2: UPDATE t SET a=1; # blocked by row-level locks of thd1
+ thd3: FLUSH TABLES WITH READ LOCK; # blocked in close_cached_tables() by the
+ table instance of thd2
+ thd1: COMMIT; # blocked by thd3.
+ thd1 blocks thd2 which blocks thd3 which blocks thd1: deadlock.
+
+ Note that we need to support that one thread does
+ FLUSH TABLES WITH READ LOCK; and then COMMIT;
+ (that's what innobackup does, for some good reason).
+ So in this exceptional case the COMMIT should not be blocked by the FLUSH
+ TABLES WITH READ LOCK.
+
+ TODO in MySQL 5.x: make_global_read_lock_block_commit() should be
+ killable. Normally CPU does not spend a long time in this function (COMMITs
+ are quite fast), but it would still be nice.
- Taking the global read lock is TWO steps (2nd step is optional; without
- it, COMMIT of existing transactions will be allowed):
- lock_global_read_lock() THEN make_global_read_lock_block_commit().
****************************************************************************/
volatile uint global_read_lock=0;
@@ -831,6 +886,8 @@ void start_waiting_global_read_lock(THD *thd)
{
bool tmp;
DBUG_ENTER("start_waiting_global_read_lock");
+ if (unlikely(thd->global_read_lock))
+ DBUG_VOID_RETURN;
(void) pthread_mutex_lock(&LOCK_open);
tmp= (!--protect_against_global_read_lock && waiting_for_read_lock);
(void) pthread_mutex_unlock(&LOCK_open);
diff --git a/sql/log.cc b/sql/log.cc
index 75a1743febc..c659a3ede2e 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -383,8 +383,7 @@ bool MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg,
master (it has binlog version of the master, event types of the
master), so this is suitable to parse the next relay log's event. It
has been produced by
- Format_description_log_event::Format_description_log_event(char*
- buf,).
+ Format_description_log_event::Format_description_log_event(char* buf,).
Why don't we want to write the description_event_for_queue if this
event is for format<4 (3.23 or 4.x): this is because in that case, the
description_event_for_queue describes the data received from the
@@ -1326,7 +1325,7 @@ bool MYSQL_LOG::write(Log_event* event_info)
(local_db && !db_ok(local_db, binlog_do_db, binlog_ignore_db)))
{
VOID(pthread_mutex_unlock(&LOCK_log));
- DBUG_PRINT("error",("!db_ok"));
+ DBUG_PRINT("error",("!db_ok('%s')", local_db));
DBUG_RETURN(0);
}
#endif /* HAVE_REPLICATION */
@@ -1369,7 +1368,7 @@ COLLATION_CONNECTION=%u,COLLATION_DATABASE=%u,COLLATION_SERVER=%u",
(uint) thd->variables.collation_connection->number,
(uint) thd->variables.collation_database->number,
(uint) thd->variables.collation_server->number);
- Query_log_event e(thd, buf, written, 0);
+ Query_log_event e(thd, buf, written, 0, FALSE);
if (e.write(file))
goto err;
}
@@ -1384,7 +1383,7 @@ COLLATION_CONNECTION=%u,COLLATION_DATABASE=%u,COLLATION_SERVER=%u",
char *buf_end= strxmov(buf, "SET ONE_SHOT TIME_ZONE='",
thd->variables.time_zone->get_name()->ptr(),
"'", NullS);
- Query_log_event e(thd, buf, buf_end - buf, 0);
+ Query_log_event e(thd, buf, buf_end - buf, 0, FALSE);
if (e.write(file))
goto err;
}
@@ -1430,7 +1429,7 @@ COLLATION_CONNECTION=%u,COLLATION_DATABASE=%u,COLLATION_SERVER=%u",
char buf[256], *p;
p= strmov(strmov(buf, "SET CHARACTER SET "),
thd->variables.convert_set->name);
- Query_log_event e(thd, buf, (ulong) (p - buf), 0);
+ Query_log_event e(thd, buf, (ulong) (p - buf), 0, FALSE);
if (e.write(file))
goto err;
}
@@ -1611,7 +1610,7 @@ bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache, bool commit_or_rollback)
we will add the "COMMIT mark and write the buffer to the binlog.
*/
{
- Query_log_event qinfo(thd, "BEGIN", 5, TRUE);
+ Query_log_event qinfo(thd, "BEGIN", 5, TRUE, FALSE);
/*
Imagine this is rollback due to net timeout, after all statements of
the transaction succeeded. Then we want a zero-error code in BEGIN.
@@ -1651,7 +1650,7 @@ bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache, bool commit_or_rollback)
Query_log_event qinfo(thd,
commit_or_rollback ? "COMMIT" : "ROLLBACK",
commit_or_rollback ? 6 : 8,
- TRUE);
+ TRUE, FALSE);
qinfo.error_code= 0;
if (qinfo.write(&log_file) || flush_io_cache(&log_file) ||
sync_binlog(&log_file))
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 77769f0e7e8..760436592b9 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -921,7 +921,8 @@ void Query_log_event::pack_info(Protocol *protocol)
if (!(buf= my_malloc(9 + db_len + q_len, MYF(MY_WME))))
return;
pos= buf;
- if (db && db_len)
+ if (!(flags & LOG_EVENT_SUPPRESS_USE_F)
+ && db && db_len)
{
pos= strmov(buf, "use `");
memcpy(pos, db, db_len);
@@ -1077,9 +1078,12 @@ bool Query_log_event::write(IO_CACHE* file)
#ifndef MYSQL_CLIENT
Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg,
- ulong query_length, bool using_trans)
- :Log_event(thd_arg, !thd_arg->tmp_table_used ?
- 0 : LOG_EVENT_THREAD_SPECIFIC_F, using_trans),
+ ulong query_length, bool using_trans,
+ bool suppress_use)
+ :Log_event(thd_arg,
+ ((thd_arg->tmp_table_used ? LOG_EVENT_THREAD_SPECIFIC_F : 0)
+ | (suppress_use ? LOG_EVENT_SUPPRESS_USE_F : 0)),
+ using_trans),
data_buf(0), query(query_arg), catalog(thd_arg->catalog),
db(thd_arg->db), q_len((uint32) query_length),
error_code((thd_arg->killed != THD::NOT_KILLED) ?
@@ -1259,14 +1263,14 @@ void Query_log_event::print(FILE* file, bool short_form,
(ulong) thread_id, (ulong) exec_time, error_code);
}
- if (db)
+ if (!(flags & LOG_EVENT_SUPPRESS_USE_F) && db)
{
- if ((different_db = memcmp(last_event_info->db, db, db_len + 1)))
+ if (different_db= memcmp(last_event_info->db, db, db_len + 1))
memcpy(last_event_info->db, db, db_len + 1);
+ if (db[0] && different_db)
+ fprintf(file, "use %s;\n", db);
}
-
- if (db && db[0] && different_db)
- fprintf(file, "use %s;\n", db);
+
end=int10_to_str((long) when, strmov(buff,"SET TIMESTAMP="),10);
*end++=';';
*end++='\n';
diff --git a/sql/log_event.h b/sql/log_event.h
index 7f958749a98..390a8c8070d 100644
--- a/sql/log_event.h
+++ b/sql/log_event.h
@@ -329,6 +329,19 @@ struct sql_ex_info
#define OPTIONS_WRITTEN_TO_BIN_LOG (OPTION_AUTO_IS_NULL | \
OPTION_NO_FOREIGN_KEY_CHECKS | OPTION_RELAXED_UNIQUE_CHECKS)
+/*
+ Suppress the generation of 'USE' statements before the actual
+ statement. This flag should be set for any events that does not need
+ the current database set to function correctly. Most notable cases
+ are 'CREATE DATABASE' and 'DROP DATABASE'.
+
+ This flags should only be used in exceptional circumstances, since
+ it introduce a significant change in behaviour regarding the
+ replication logic together with the flags --binlog-do-db and
+ --replicated-do-db.
+ */
+#define LOG_EVENT_SUPPRESS_USE_F 0x8
+
enum Log_event_type
{
/*
@@ -446,8 +459,9 @@ public:
/*
Some 16 flags. Only one is really used now; look above for
- LOG_EVENT_TIME_F, LOG_EVENT_FORCED_ROTATE_F, LOG_EVENT_THREAD_SPECIFIC_F
- for notes.
+ LOG_EVENT_TIME_F, LOG_EVENT_FORCED_ROTATE_F,
+ LOG_EVENT_THREAD_SPECIFIC_F, and LOG_EVENT_SUPPRESS_USE_F for
+ notes.
*/
uint16 flags;
@@ -650,7 +664,7 @@ public:
#ifndef MYSQL_CLIENT
Query_log_event(THD* thd_arg, const char* query_arg, ulong query_length,
- bool using_trans);
+ bool using_trans, bool suppress_use);
const char* get_db() { return db; }
#ifdef HAVE_REPLICATION
void pack_info(Protocol* protocol);
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 09bec0a9323..91d15dc1125 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -788,7 +788,8 @@ bool add_field_to_list(THD *thd, char *field_name, enum enum_field_types type,
uint type_modifier,
Item *default_value, Item *on_update_value,
LEX_STRING *comment,
- char *change, TYPELIB *interval,CHARSET_INFO *cs,
+ char *change, List<String> *interval_list,
+ CHARSET_INFO *cs,
uint uint_geom_type);
void store_position_for_column(const char *name);
bool add_to_list(THD *thd, SQL_LIST &list,Item *group,bool asc=0);
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 27248ebaec2..5e0cc47ecc5 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -4910,7 +4910,7 @@ log and this option does nothing anymore.",
"Data file autoextend increment in megabytes",
(gptr*) &srv_auto_extend_increment,
(gptr*) &srv_auto_extend_increment,
- 0, GET_LONG, REQUIRED_ARG, 8L, 1L, ~0L, 0, 1L, 0},
+ 0, GET_LONG, REQUIRED_ARG, 8L, 1L, 1000L, 0, 1L, 0},
{"innodb_buffer_pool_awe_mem_mb", OPT_INNODB_BUFFER_POOL_AWE_MEM_MB,
"If Windows AWE is used, the size of InnoDB buffer pool allocated from the AWE memory.",
(gptr*) &innobase_buffer_pool_awe_mem_mb, (gptr*) &innobase_buffer_pool_awe_mem_mb, 0,
diff --git a/sql/set_var.cc b/sql/set_var.cc
index 532547c2618..234ec6617c3 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -2773,24 +2773,23 @@ sys_var *find_sys_var(const char *str, uint length)
int sql_set_variables(THD *thd, List<set_var_base> *var_list)
{
- int error= 0;
+ int error;
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)))
+ if ((error= var->check(thd)))
goto err;
}
- if (!thd->net.report_error)
+ if (!(error= test(thd->net.report_error)))
{
it.rewind();
while ((var= it++))
error|= var->update(thd); // Returns 0, -1 or 1
}
- else
- error= 1;
+
err:
free_underlaid_joins(thd, &thd->lex->select_lex);
DBUG_RETURN(error);
diff --git a/sql/slave.cc b/sql/slave.cc
index e67def552bd..1e38d92ebc5 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -877,7 +877,7 @@ static TABLE_RULE_ENT* find_wild(DYNAMIC_ARRAY *a, const char* key, int len)
1 should be logged/replicated
*/
-int tables_ok(THD* thd, TABLE_LIST* tables)
+bool tables_ok(THD* thd, TABLE_LIST* tables)
{
bool some_tables_updating= 0;
DBUG_ENTER("tables_ok");
diff --git a/sql/slave.h b/sql/slave.h
index 1abe166c944..69d3dc38e78 100644
--- a/sql/slave.h
+++ b/sql/slave.h
@@ -494,7 +494,7 @@ bool show_master_info(THD* thd, MASTER_INFO* mi);
bool show_binlog_info(THD* thd);
/* See if the query uses any tables that should not be replicated */
-int tables_ok(THD* thd, TABLE_LIST* tables);
+bool tables_ok(THD* thd, TABLE_LIST* tables);
/*
Check to see if the database is ok to operate on with respect to the
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 0c6b061aa0c..b69ee068407 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -1313,7 +1313,7 @@ bool change_password(THD *thd, const char *host, const char *user,
acl_user->host.hostname ? acl_user->host.hostname : "",
new_password));
thd->clear_error();
- Query_log_event qinfo(thd, buff, query_length, 0);
+ Query_log_event qinfo(thd, buff, query_length, 0, FALSE);
mysql_bin_log.write(&qinfo);
DBUG_RETURN(0);
}
@@ -2153,7 +2153,7 @@ static int replace_column_table(GRANT_TABLE *g_t,
{
table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS);
if (table->file->index_read(table->record[0], (byte*) table->field[0]->ptr,
- table->key_info[0].key_length,
+ key_length,
HA_READ_KEY_EXACT))
goto end;
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 97e2a2cf0d0..3ead7163171 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -535,7 +535,7 @@ void close_temporary_tables(THD *thd)
{
/* The -1 is to remove last ',' */
thd->clear_error();
- Query_log_event qinfo(thd, query, (ulong)(end-query)-1, 0);
+ Query_log_event qinfo(thd, query, (ulong)(end-query)-1, 0, FALSE);
/*
Imagine the thread had created a temp table, then was doing a SELECT, and
the SELECT was killed. Then it's not clever to mark the statement above as
@@ -1587,7 +1587,7 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db,
{
end = strxmov(strmov(query, "DELETE FROM `"),
db,"`.`",name,"`", NullS);
- Query_log_event qinfo(thd, query, (ulong)(end-query), 0);
+ Query_log_event qinfo(thd, query, (ulong)(end-query), 0, FALSE);
mysql_bin_log.write(&qinfo);
my_free(query, MYF(0));
}
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 083f90fc93e..6cec2c2c787 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -1230,6 +1230,12 @@ public:
void set_status_var_init();
};
+#define tmp_disable_binlog(A) \
+ ulong save_options= (A)->options; \
+ (A)->options&= ~OPTION_BIN_LOG;
+
+#define reenable_binlog(A) (A)->options= save_options;
+
/* Flags for the THD::system_thread (bitmap) variable */
#define SYSTEM_THREAD_DELAYED_INSERT 1
#define SYSTEM_THREAD_SLAVE_IO 2
@@ -1371,6 +1377,7 @@ class select_insert :public select_result_interceptor {
~select_insert();
int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
bool send_data(List<Item> &items);
+ virtual void store_values(List<Item> &values);
void send_error(uint errcode,const char *err);
bool send_eof();
/* not implemented: select_insert is never re-used in prepared statements */
@@ -1397,7 +1404,8 @@ public:
lock(0)
{}
int prepare(List<Item> &list, SELECT_LEX_UNIT *u);
- bool send_data(List<Item> &values);
+ void store_values(List<Item> &values);
+ void send_error(uint errcode,const char *err);
bool send_eof();
void abort();
};
@@ -1447,7 +1455,7 @@ public:
if (copy_field) /* Fix for Intel compiler */
{
delete [] copy_field;
- copy_field=0;
+ save_copy_field= copy_field= 0;
}
}
};
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index ad4887146d8..3e606029bec 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -468,7 +468,29 @@ bool mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info,
}
if (mysql_bin_log.is_open())
{
- Query_log_event qinfo(thd, query, query_length, 0);
+ Query_log_event qinfo(thd, query, query_length, 0,
+ /* suppress_use */ TRUE);
+
+ /*
+ Write should use the database being created as the "current
+ database" and not the threads current database, which is the
+ default. If we do not change the "current database" to the
+ database being created, the CREATE statement will not be
+ replicated when using --binlog-do-db to select databases to be
+ replicated.
+
+ An example (--binlog-do-db=sisyfos):
+
+ CREATE DATABASE bob; # Not replicated
+ USE bob; # 'bob' is the current database
+ CREATE DATABASE sisyfos; # Not replicated since 'bob' is
+ # current database.
+ USE sisyfos; # Will give error on slave since
+ # database does not exist.
+ */
+ qinfo.db = db;
+ qinfo.db_len = strlen(db);
+
mysql_bin_log.write(&qinfo);
}
send_ok(thd, result);
@@ -517,7 +539,15 @@ bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info)
if (mysql_bin_log.is_open())
{
- Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
+ Query_log_event qinfo(thd, thd->query, thd->query_length, 0,
+ /* suppress_use */ TRUE);
+
+ // Write should use the database being created as the "current
+ // database" and not the threads current database, which is the
+ // default.
+ qinfo.db = db;
+ qinfo.db_len = strlen(db);
+
thd->clear_error();
mysql_bin_log.write(&qinfo);
}
@@ -623,7 +653,15 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
}
if (mysql_bin_log.is_open())
{
- Query_log_event qinfo(thd, query, query_length, 0);
+ Query_log_event qinfo(thd, query, query_length, 0,
+ /* suppress_use */ TRUE);
+
+ // Write should use the database being created as the "current
+ // database" and not the threads current database, which is the
+ // default.
+ qinfo.db = db;
+ qinfo.db_len = strlen(db);
+
thd->clear_error();
mysql_bin_log.write(&qinfo);
}
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index 51cf085cfb5..f4c5b0f8b59 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -249,7 +249,7 @@ cleanup:
if (error <= 0)
thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length,
- log_delayed);
+ log_delayed, FALSE);
if (mysql_bin_log.write(&qinfo) && transactional_table)
error=1;
}
@@ -670,7 +670,7 @@ bool multi_delete::send_eof()
if (error <= 0)
thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length,
- log_delayed);
+ log_delayed, FALSE);
if (mysql_bin_log.write(&qinfo) && !normal_tables)
local_error=1; // Log write failed: roll back the SQL statement
}
@@ -779,7 +779,7 @@ end:
{
thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length,
- thd->tmp_table);
+ thd->tmp_table, FALSE);
mysql_bin_log.write(&qinfo);
}
send_ok(thd); // This should return record count
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 673d7425c36..77a669e4c96 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -455,7 +455,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
if (error <= 0)
thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length,
- log_delayed);
+ log_delayed, FALSE);
if (mysql_bin_log.write(&qinfo) && transactional_table)
error=1;
}
@@ -1614,7 +1614,7 @@ bool delayed_insert::handle_inserts(void)
}
if (row->query && row->log_query && using_bin_log)
{
- Query_log_event qinfo(&thd, row->query, row->query_length,0);
+ Query_log_event qinfo(&thd, row->query, row->query_length, 0, FALSE);
mysql_bin_log.write(&qinfo);
}
if (table->blob_fields)
@@ -1795,7 +1795,6 @@ select_insert::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
restore_record(table,default_values); // Get empty record
table->next_number_field=table->found_next_number_field;
- thd->count_cuted_fields= CHECK_FIELD_WARN; // calc cuted fields
thd->cuted_fields=0;
if (info.handle_duplicates == DUP_IGNORE ||
info.handle_duplicates == DUP_REPLACE)
@@ -1834,35 +1833,44 @@ select_insert::~select_insert()
bool select_insert::send_data(List<Item> &values)
{
DBUG_ENTER("select_insert::send_data");
+ bool error=0;
if (unit->offset_limit_cnt)
{ // using limit offset,count
unit->offset_limit_cnt--;
DBUG_RETURN(0);
}
- if (fields->elements)
- fill_record(thd, *fields, values, 1);
- else
- fill_record(thd, table->field, values, 1);
+
+ thd->count_cuted_fields= CHECK_FIELD_WARN; // calc cuted fields
+ store_values(values);
+ thd->count_cuted_fields= CHECK_FIELD_IGNORE;
+ if (thd->net.report_error)
+ DBUG_RETURN(1);
switch (table_list->view_check_option(thd,
- thd->lex->duplicates == DUP_IGNORE))
- {
+ thd->lex->duplicates == DUP_IGNORE)) {
case VIEW_CHECK_SKIP:
DBUG_RETURN(0);
case VIEW_CHECK_ERROR:
DBUG_RETURN(1);
}
- if (thd->net.report_error || write_record(thd, table, &info))
- DBUG_RETURN(1);
- if (table->next_number_field) // Clear for next record
+ if (!(error= write_record(table,&info)) && table->next_number_field)
{
+ /* Clear for next record */
table->next_number_field->reset();
if (! last_insert_id && thd->insert_id_used)
last_insert_id=thd->insert_id();
}
- DBUG_RETURN(0);
+ DBUG_RETURN(error);
}
+void select_insert::store_values(List<Item> &values)
+{
+ if (fields->elements)
+ fill_record(*fields, values, 1);
+ else
+ fill_record(table->field, values, 1);
+}
+
void select_insert::send_error(uint errcode,const char *err)
{
DBUG_ENTER("select_insert::send_error");
@@ -1892,7 +1900,7 @@ void select_insert::send_error(uint errcode,const char *err)
if (mysql_bin_log.is_open())
{
Query_log_event qinfo(thd, thd->query, thd->query_length,
- table->file->has_transactions());
+ table->file->has_transactions(), FALSE);
mysql_bin_log.write(&qinfo);
}
if (!table->tmp_table)
@@ -1935,7 +1943,7 @@ bool select_insert::send_eof()
if (!error)
thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length,
- table->file->has_transactions());
+ table->file->has_transactions(), FALSE);
mysql_bin_log.write(&qinfo);
}
if ((error2=ha_autocommit_or_rollback(thd,error)) && ! error)
@@ -1988,8 +1996,6 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
table->next_number_field=table->found_next_number_field;
restore_record(table,default_values); // Get empty record
- /* Count warnings. This is reset in ~select_insert() */
- thd->count_cuted_fields= CHECK_FIELD_WARN;
thd->cuted_fields=0;
if (info.handle_duplicates == DUP_IGNORE ||
info.handle_duplicates == DUP_REPLACE)
@@ -2004,23 +2010,21 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
}
-bool select_create::send_data(List<Item> &values)
+void select_create::store_values(List<Item> &values)
{
- if (unit->offset_limit_cnt)
- { // using limit offset,count
- unit->offset_limit_cnt--;
- return 0;
- }
fill_record(thd, field, values, 1);
- if (thd->net.report_error || write_record(thd, table, &info))
- return 1;
- if (table->next_number_field) // Clear for next record
- {
- table->next_number_field->reset();
- if (! last_insert_id && thd->insert_id_used)
- last_insert_id=thd->insert_id();
- }
- return 0;
+}
+
+
+void select_create::send_error(uint errcode,const char *err)
+{
+ /*
+ Disable binlog, because we "roll back" partial inserts in ::abort
+ by removing the table, even for non-transactional tables.
+ */
+ tmp_disable_binlog(thd);
+ select_insert::send_error(errcode, err);
+ reenable_binlog(thd);
}
@@ -2068,7 +2072,7 @@ void select_create::abort()
enum db_type table_type=table->db_type;
if (!table->tmp_table)
{
- ulong version= table->version;
+ ulong version= table->version;
hash_delete(&open_cache,(byte*) table);
if (!create_info->table_existed)
quick_rm_table(table_type, create_table->db, create_table->real_name);
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index ce37318ca01..8a705a7438b 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -144,7 +144,7 @@ void lex_start(THD *thd, uchar *buf,uint length)
lex->select_lex.init_order();
lex->select_lex.group_list.empty();
lex->describe= 0;
- lex->derived_tables= FALSE;
+ lex->subqueries= lex->derived_tables= FALSE;
lex->view_prepare_mode= FALSE;
lex->lock_option= TL_READ;
lex->found_colon= 0;
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index e99e6138b6d..1c0e3e2e02e 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -687,7 +687,6 @@ typedef struct st_lex
List<Item_param> param_list;
List<LEX_STRING> view_list; // view list (list of field names in view)
SQL_LIST proc_list, auxilliary_table_list, save_list;
- TYPELIB *interval;
create_field *last_field;
char *savepoint_name; // Transaction savepoint id
udf_func udf;
@@ -721,6 +720,7 @@ typedef struct st_lex
/* special JOIN::prepare mode: changing of query is prohibited */
bool view_prepare_mode;
bool safe_to_cache_query;
+ bool subqueries;
bool variables_used;
ALTER_INFO alter_info;
/* Prepared statements SQL syntax:*/
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index e27cd20e15e..44adc28d41d 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -2830,7 +2830,7 @@ create_error:
if (mysql_bin_log.is_open())
{
thd->clear_error(); // No binlog error generated
- Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
+ Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
mysql_bin_log.write(&qinfo);
}
}
@@ -2860,7 +2860,7 @@ create_error:
if (mysql_bin_log.is_open())
{
thd->clear_error(); // No binlog error generated
- Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
+ Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
mysql_bin_log.write(&qinfo);
}
}
@@ -2883,7 +2883,7 @@ create_error:
if (mysql_bin_log.is_open())
{
thd->clear_error(); // No binlog error generated
- Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
+ Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
mysql_bin_log.write(&qinfo);
}
}
@@ -3411,7 +3411,7 @@ create_error:
{
if (mysql_bin_log.is_open())
{
- Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
+ Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
mysql_bin_log.write(&qinfo);
}
send_ok(thd);
@@ -3426,7 +3426,7 @@ create_error:
{
if (mysql_bin_log.is_open())
{
- Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
+ Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
mysql_bin_log.write(&qinfo);
}
send_ok(thd);
@@ -3441,7 +3441,7 @@ create_error:
{
if (mysql_bin_log.is_open())
{
- Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
+ Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
mysql_bin_log.write(&qinfo);
}
send_ok(thd);
@@ -3484,7 +3484,7 @@ create_error:
mysql_bin_log.is_open())
{
thd->clear_error();
- Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
+ Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
mysql_bin_log.write(&qinfo);
}
}
@@ -3504,7 +3504,7 @@ create_error:
if (mysql_bin_log.is_open())
{
thd->clear_error();
- Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
+ Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
mysql_bin_log.write(&qinfo);
}
if (mqh_used && lex->sql_command == SQLCOM_GRANT)
@@ -3544,7 +3544,7 @@ create_error:
{
if (mysql_bin_log.is_open())
{
- Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
+ Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
mysql_bin_log.write(&qinfo);
}
}
@@ -4529,6 +4529,7 @@ mysql_new_select(LEX *lex, bool move_down)
select_lex->parent_lex= lex;
if (move_down)
{
+ lex->subqueries= TRUE;
/* first select_lex of subselect or derived table */
SELECT_LEX_UNIT *unit;
if (!(unit= new(lex->thd->mem_root) SELECT_LEX_UNIT()))
@@ -4717,31 +4718,6 @@ bool mysql_test_parse_for_slave(THD *thd, char *inBuf, uint length)
-/*
- Calculate interval lengths.
- Strip trailing spaces from all strings.
- After this function call:
- - ENUM uses max_length
- - SET uses tot_length.
-*/
-void calculate_interval_lengths(THD *thd, TYPELIB *interval,
- uint32 *max_length, uint32 *tot_length)
-{
- const char **pos;
- uint *len;
- CHARSET_INFO *cs= thd->variables.character_set_client;
- *max_length= *tot_length= 0;
- for (pos= interval->type_names, len= interval->type_lengths;
- *pos ; pos++, len++)
- {
- *len= (uint) strip_sp((char*) *pos);
- uint length= cs->cset->numchars(cs, *pos, *pos + *len);
- *tot_length+= length;
- set_if_bigger(*max_length, (uint32)length);
- }
-}
-
-
/*****************************************************************************
** Store field definition for create
** Return 0 if ok
@@ -4752,7 +4728,8 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
uint type_modifier,
Item *default_value, Item *on_update_value,
LEX_STRING *comment,
- char *change, TYPELIB *interval, CHARSET_INFO *cs,
+ char *change,
+ List<String> *interval_list, CHARSET_INFO *cs,
uint uint_geom_type)
{
register create_field *new_field;
@@ -5059,62 +5036,39 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
break;
case FIELD_TYPE_SET:
{
- if (interval->count > sizeof(longlong)*8)
+ if (interval_list->elements > sizeof(longlong)*8)
{
my_error(ER_TOO_BIG_SET, MYF(0), field_name); /* purecov: inspected */
- DBUG_RETURN(1); /* purecov: inspected */
+ DBUG_RETURN(1); /* purecov: inspected */
}
- new_field->pack_length=(interval->count+7)/8;
+ new_field->pack_length= (interval_list->elements + 7) / 8;
if (new_field->pack_length > 4)
- new_field->pack_length=8;
- new_field->interval=interval;
- uint32 dummy_max_length;
- calculate_interval_lengths(thd, interval,
- &dummy_max_length, &new_field->length);
- new_field->length+= (interval->count - 1);
- set_if_smaller(new_field->length,MAX_FIELD_WIDTH-1);
- if (default_value)
- {
- char *not_used;
- uint not_used2;
- bool not_used3;
-
- thd->cuted_fields=0;
- String str,*res;
- res=default_value->val_str(&str);
- (void) find_set(interval, res->ptr(), res->length(),
- &my_charset_bin,
- &not_used, &not_used2, &not_used3);
- if (thd->cuted_fields)
- {
- my_error(ER_INVALID_DEFAULT, MYF(0), field_name);
- DBUG_RETURN(1);
- }
- }
+ new_field->pack_length=8;
+
+ List_iterator<String> it(*interval_list);
+ String *tmp;
+ while ((tmp= it++))
+ new_field->interval_list.push_back(tmp);
+ /*
+ Set fake length to 1 to pass the below conditions.
+ Real length will be set in mysql_prepare_table()
+ when we know the character set of the column
+ */
+ new_field->length= 1;
}
break;
case FIELD_TYPE_ENUM:
{
- new_field->interval=interval;
- new_field->pack_length=interval->count < 256 ? 1 : 2; // Should be safe
+ // Should be safe
+ new_field->pack_length= interval_list->elements < 256 ? 1 : 2;
- uint32 dummy_tot_length;
- calculate_interval_lengths(thd, interval,
- &new_field->length, &dummy_tot_length);
- set_if_smaller(new_field->length,MAX_FIELD_WIDTH-1);
- if (default_value)
- {
- String str,*res;
- res=default_value->val_str(&str);
- res->strip_sp();
- if (!find_type(interval, res->ptr(), res->length(), 0))
- {
- my_error(ER_INVALID_DEFAULT, MYF(0), field_name);
- DBUG_RETURN(1);
- }
- }
- break;
+ List_iterator<String> it(*interval_list);
+ String *tmp;
+ while ((tmp= it++))
+ new_field->interval_list.push_back(tmp);
+ new_field->length= 1; // See comment for FIELD_TYPE_SET above.
}
+ break;
}
if ((new_field->length > MAX_FIELD_CHARLENGTH && type != FIELD_TYPE_SET &&
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index d4851393a89..6d59d465445 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -427,8 +427,17 @@ static void set_param_date(Item_param *param, uchar **pos, ulong len)
#else/*!EMBEDDED_LIBRARY*/
void set_param_time(Item_param *param, uchar **pos, ulong len)
{
- MYSQL_TIME *to= (MYSQL_TIME*)*pos;
- param->set_time(to, MYSQL_TIMESTAMP_TIME,
+ MYSQL_TIME tm= *((MYSQL_TIME*)*pos);
+ tm.hour+= tm.day * 24;
+ tm.day= tm.year= tm.month= 0;
+ if (tm.hour > 838)
+ {
+ /* TODO: add warning 'Data truncated' here */
+ tm.hour= 838;
+ tm.minute= 59;
+ tm.second= 59;
+ }
+ param->set_time(&tm, MYSQL_TIMESTAMP_TIME,
MAX_TIME_WIDTH * MY_CHARSET_BIN_MB_MAXLEN);
}
diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc
index 9f29a975441..1640fc1a634 100644
--- a/sql/sql_rename.cc
+++ b/sql/sql_rename.cc
@@ -84,7 +84,7 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list)
if (mysql_bin_log.is_open())
{
thd->clear_error();
- Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
+ Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
mysql_bin_log.write(&qinfo);
}
send_ok(thd);
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 0a7cd0f7338..ba9933a3d15 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -1050,7 +1050,7 @@ JOIN::optimize()
}
}
- if (select_lex->master_unit()->uncacheable)
+ if (thd->lex->subqueries)
{
if (!(tmp_join= (JOIN*)thd->alloc(sizeof(JOIN))))
DBUG_RETURN(-1);
@@ -5702,7 +5702,9 @@ JOIN::join_free(bool full)
JOIN_TAB *tab,*end;
DBUG_ENTER("JOIN::join_free");
- full= full || !select_lex->uncacheable;
+ full= full || (!select_lex->uncacheable &&
+ !thd->lex->subqueries &&
+ !thd->lex->describe); // do not cleanup too early on EXPLAIN
if (table)
{
@@ -5731,6 +5733,7 @@ JOIN::join_free(bool full)
for (tab= join_tab, end= tab+tables; tab != end; tab++)
tab->cleanup();
table= 0;
+ tables= 0;
}
else
{
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index eb9ca43b56a..fd12c206e64 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -847,6 +847,15 @@ append_identifier(THD *thd, String *packet, const char *name, uint length)
{
uchar chr= (uchar) *name;
length= my_mbcharlen(system_charset_info, chr);
+ /*
+ my_mbcharlen can retur 0 on a wrong multibyte
+ sequence. It is possible when upgrading from 4.0,
+ and identifier contains some accented characters.
+ The manual says it does not work. So we'll just
+ change length to 1 not to hang in the endless loop.
+ */
+ if (!length)
+ length= 1;
if (length == 1 && chr == (uchar) quote_char)
packet->append(&quote_char, 1, system_charset_info);
packet->append(name, length, packet->charset());
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index a7c08f356a2..a1e09d74620 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -29,12 +29,6 @@
#include <io.h>
#endif
-#define tmp_disable_binlog(A) \
- ulong save_options= (A)->options; \
- (A)->options&= ~OPTION_BIN_LOG;
-
-#define reenable_binlog(A) (A)->options= save_options;
-
const char *primary_key_name="PRIMARY";
static bool check_if_keyname_exists(const char *name,KEY *start, KEY *end);
@@ -281,7 +275,8 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
if (!error)
thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length,
- tmp_table_deleted && !some_tables_deleted);
+ tmp_table_deleted && !some_tables_deleted,
+ FALSE);
mysql_bin_log.write(&qinfo);
}
}
@@ -390,6 +385,41 @@ void check_duplicates_in_interval(const char *set_or_name,
}
}
+
+/*
+ Check TYPELIB (set or enum) max and total lengths
+
+ SYNOPSIS
+ calculate_interval_lengths()
+ cs charset+collation pair of the interval
+ typelib list of values for the column
+ max_length length of the longest item
+ tot_length sum of the item lengths
+
+ DESCRIPTION
+ After this function call:
+ - ENUM uses max_length
+ - SET uses tot_length.
+
+ RETURN VALUES
+ void
+*/
+void calculate_interval_lengths(CHARSET_INFO *cs, TYPELIB *interval,
+ uint32 *max_length, uint32 *tot_length)
+{
+ const char **pos;
+ uint *len;
+ *max_length= *tot_length= 0;
+ for (pos= interval->type_names, len= interval->type_lengths;
+ *pos ; pos++, len++)
+ {
+ uint length= cs->cset->numchars(cs, *pos, *pos + *len);
+ *tot_length+= length;
+ set_if_bigger(*max_length, (uint32)length);
+ }
+}
+
+
/*
Preparation for table creation
@@ -453,6 +483,91 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
DBUG_RETURN(-1);
}
+ if ((sql_field->sql_type == FIELD_TYPE_SET ||
+ sql_field->sql_type == FIELD_TYPE_ENUM) && !sql_field->interval)
+ {
+ uint32 dummy;
+ CHARSET_INFO *cs= sql_field->charset;
+ TYPELIB *interval;
+
+ /*
+ Create typelib from interval_list, and if necessary
+ convert strings from client character set to the
+ column character set.
+ */
+
+ interval= sql_field->interval= typelib(sql_field->interval_list);
+ List_iterator<String> it(sql_field->interval_list);
+ String conv, *tmp;
+ for (uint i= 0; (tmp= it++); i++)
+ {
+ if (String::needs_conversion(tmp->length(), tmp->charset(), cs, &dummy))
+ {
+ uint cnv_errs;
+ conv.copy(tmp->ptr(), tmp->length(), tmp->charset(), cs, &cnv_errs);
+ char *buf= (char*) sql_alloc(conv.length()+1);
+ memcpy(buf, conv.ptr(), conv.length());
+ buf[conv.length()]= '\0';
+ interval->type_names[i]= buf;
+ interval->type_lengths[i]= conv.length();
+ }
+
+ // Strip trailing spaces.
+ uint lengthsp= cs->cset->lengthsp(cs, interval->type_names[i],
+ interval->type_lengths[i]);
+ interval->type_lengths[i]= lengthsp;
+ ((uchar *)interval->type_names[i])[lengthsp]= '\0';
+ }
+ sql_field->interval_list.empty(); // Don't need interval_list anymore
+
+
+ /*
+ Convert the default value from client character
+ set into the column character set if necessary.
+ */
+ if (sql_field->def)
+ {
+ sql_field->def=
+ sql_field->def->safe_charset_converter(cs);
+ }
+
+ if (sql_field->sql_type == FIELD_TYPE_SET)
+ {
+ if (sql_field->def)
+ {
+ char *not_used;
+ uint not_used2;
+ bool not_found= 0;
+ String str, *def= sql_field->def->val_str(&str);
+ def->length(cs->cset->lengthsp(cs, def->ptr(), def->length()));
+ (void) find_set(interval, def->ptr(), def->length(),
+ cs, &not_used, &not_used2, &not_found);
+ if (not_found)
+ {
+ my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name);
+ DBUG_RETURN(-1);
+ }
+ }
+ calculate_interval_lengths(cs, interval, &dummy, &sql_field->length);
+ sql_field->length+= (interval->count - 1);
+ }
+ else /* FIELD_TYPE_ENUM */
+ {
+ if (sql_field->def)
+ {
+ String str, *def= sql_field->def->val_str(&str);
+ def->length(cs->cset->lengthsp(cs, def->ptr(), def->length()));
+ if (!find_type2(interval, def->ptr(), def->length(), cs))
+ {
+ my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name);
+ DBUG_RETURN(-1);
+ }
+ }
+ calculate_interval_lengths(cs, interval, &sql_field->length, &dummy);
+ }
+ set_if_smaller(sql_field->length, MAX_FIELD_WIDTH-1);
+ }
+
sql_field->create_length_to_internal_length();
/* Don't pack keys in old tables if the user has requested this */
@@ -816,8 +931,7 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
DBUG_RETURN(-1);
}
}
- else
- if (key_info->algorithm == HA_KEY_ALG_RTREE)
+ else if (key_info->algorithm == HA_KEY_ALG_RTREE)
{
#ifdef HAVE_RTREE_KEYS
if ((key_info->key_parts & 1) == 1)
@@ -839,6 +953,8 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
CHARSET_INFO *ft_key_charset=0; // for FULLTEXT
for (uint column_nr=0 ; (column=cols++) ; column_nr++)
{
+ key_part_spec *dup_column;
+
it.rewind();
field=0;
while ((sql_field=it++) &&
@@ -851,9 +967,8 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0), column->field_name);
DBUG_RETURN(-1);
}
- for (uint dup_nr= 0; dup_nr < column_nr; dup_nr++)
+ while ((dup_column= cols2++) != column)
{
- key_part_spec *dup_column= cols2++;
if (!my_strcasecmp(system_charset_info,
column->field_name, dup_column->field_name))
{
@@ -864,12 +979,6 @@ int mysql_prepare_table(THD *thd, HA_CREATE_INFO *create_info,
}
}
cols2.rewind();
- /* for fulltext keys keyseg length is 1 for blobs (it's ignored in
- ft code anyway, and 0 (set to column width later) for char's.
- it has to be correct col width for char's, as char data are not
- prefixed with length (unlike blobs, where ft code takes data length
- from a data prefix, ignoring column->length).
- */
if (key->type == Key::FULLTEXT)
{
if ((sql_field->sql_type != FIELD_TYPE_STRING &&
@@ -1296,10 +1405,12 @@ bool mysql_create_table(THD *thd,const char *db, const char *table_name,
thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length,
test(create_info->options &
- HA_LEX_CREATE_TMP_TABLE));
+ HA_LEX_CREATE_TMP_TABLE),
+ FALSE);
mysql_bin_log.write(&qinfo);
}
error= FALSE;
+
end:
VOID(pthread_mutex_unlock(&LOCK_open));
start_waiting_global_read_lock(thd);
@@ -2274,7 +2385,8 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table,
thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length,
test(create_info->options &
- HA_LEX_CREATE_TMP_TABLE));
+ HA_LEX_CREATE_TMP_TABLE),
+ FALSE);
mysql_bin_log.write(&qinfo);
}
res= FALSE;
@@ -2384,7 +2496,7 @@ mysql_discard_or_import_tablespace(THD *thd,
goto err;
if (mysql_bin_log.is_open())
{
- Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
+ Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
mysql_bin_log.write(&qinfo);
}
err:
@@ -2773,7 +2885,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
if (mysql_bin_log.is_open())
{
thd->clear_error();
- Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
+ Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
mysql_bin_log.write(&qinfo);
}
if (do_send_ok)
@@ -3189,7 +3301,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
if (mysql_bin_log.is_open())
{
thd->clear_error();
- Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
+ Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
mysql_bin_log.write(&qinfo);
}
goto end_temporary;
@@ -3323,7 +3435,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
if (mysql_bin_log.is_open())
{
thd->clear_error();
- Query_log_event qinfo(thd, thd->query, thd->query_length, 0);
+ Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
mysql_bin_log.write(&qinfo);
}
VOID(pthread_cond_broadcast(&COND_refresh));
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 4a2790f7d78..7c55f281f38 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -482,7 +482,7 @@ int mysql_update(THD *thd,
if (error <= 0)
thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length,
- log_delayed);
+ log_delayed, FALSE);
if (mysql_bin_log.write(&qinfo) && transactional_table)
error=1; // Rollback update
}
@@ -1417,7 +1417,7 @@ bool multi_update::send_eof()
if (local_error <= 0)
thd->clear_error();
Query_log_event qinfo(thd, thd->query, thd->query_length,
- log_delayed);
+ log_delayed, FALSE);
if (mysql_bin_log.write(&qinfo) && trans_safe)
local_error= 1; // Rollback update
}
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 74a96701bdc..8ea7cdb34fa 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -2728,7 +2728,7 @@ field_spec:
field_ident
{
LEX *lex=Lex;
- lex->length=lex->dec=0; lex->type=0; lex->interval=0;
+ lex->length=lex->dec=0; lex->type=0;
lex->default_value= lex->on_update_value= 0;
lex->comment=0;
lex->charset=NULL;
@@ -2741,7 +2741,7 @@ field_spec:
lex->length,lex->dec,lex->type,
lex->default_value, lex->on_update_value,
lex->comment,
- lex->change,lex->interval,lex->charset,
+ lex->change,&lex->interval_list,lex->charset,
lex->uint_geom_type))
YYABORT;
};
@@ -2838,17 +2838,9 @@ type:
| FIXED_SYM float_options field_options
{ $$=FIELD_TYPE_DECIMAL;}
| ENUM {Lex->interval_list.empty();} '(' string_list ')' opt_binary
- {
- LEX *lex=Lex;
- lex->interval=typelib(lex->interval_list);
- $$=FIELD_TYPE_ENUM;
- }
+ { $$=FIELD_TYPE_ENUM; }
| SET { Lex->interval_list.empty();} '(' string_list ')' opt_binary
- {
- LEX *lex=Lex;
- lex->interval=typelib(lex->interval_list);
- $$=FIELD_TYPE_SET;
- }
+ { $$=FIELD_TYPE_SET; }
| LONG_SYM opt_binary { $$=FIELD_TYPE_MEDIUM_BLOB; }
| SERIAL_SYM
{
@@ -3328,7 +3320,7 @@ alter_list_item:
| MODIFY_SYM opt_column field_ident
{
LEX *lex=Lex;
- lex->length=lex->dec=0; lex->type=0; lex->interval=0;
+ lex->length=lex->dec=0; lex->type=0;
lex->default_value= lex->on_update_value= 0;
lex->comment=0;
lex->charset= NULL;
@@ -3342,7 +3334,7 @@ alter_list_item:
lex->length,lex->dec,lex->type,
lex->default_value, lex->on_update_value,
lex->comment,
- $3.str, lex->interval, lex->charset,
+ $3.str, &lex->interval_list, lex->charset,
lex->uint_geom_type))
YYABORT;
}