diff options
-rw-r--r-- | include/mysql/plugin_audit.h | 46 | ||||
-rw-r--r-- | include/mysql/plugin_audit.h.pp | 21 | ||||
-rw-r--r-- | mysql-test/suite/plugins/r/audit_null.result | 73 | ||||
-rw-r--r-- | mysql-test/suite/plugins/t/audit_null.test | 29 | ||||
-rw-r--r-- | plugin/audit_null/audit_null.c | 89 | ||||
-rw-r--r-- | sql/handler.cc | 13 | ||||
-rw-r--r-- | sql/handler.h | 1 | ||||
-rw-r--r-- | sql/sql_audit.cc | 32 | ||||
-rw-r--r-- | sql/sql_audit.h | 91 | ||||
-rw-r--r-- | sql/sql_table.cc | 10 |
10 files changed, 372 insertions, 33 deletions
diff --git a/include/mysql/plugin_audit.h b/include/mysql/plugin_audit.h index eee32a9e523..86b6dea5668 100644 --- a/include/mysql/plugin_audit.h +++ b/include/mysql/plugin_audit.h @@ -25,7 +25,7 @@ #define MYSQL_AUDIT_CLASS_MASK_SIZE 1 -#define MYSQL_AUDIT_INTERFACE_VERSION 0x0300 +#define MYSQL_AUDIT_INTERFACE_VERSION 0x0301 /************************************************************************* @@ -97,6 +97,50 @@ struct mysql_event_connection unsigned int database_length; }; +/* + AUDIT CLASS : TABLE + + LOCK occurs when a connection "locks" (this does not necessarily mean a table + lock and also happens for row-locking engines) the table at the beginning of + a statement. This event is generated at the beginning of every statement for + every affected table, unless there's a LOCK TABLES statement in effect (in + which case it is generated once for LOCK TABLES and then is suppressed until + the tables are unlocked). + + CREATE/DROP/RENAME occur when a table is created, dropped, or renamed. +*/ + +#define MYSQL_AUDIT_TABLE_CLASS 15 +#define MYSQL_AUDIT_TABLE_CLASSMASK (1 << MYSQL_AUDIT_TABLE_CLASS) +#define MYSQL_AUDIT_TABLE_LOCK 0 +#define MYSQL_AUDIT_TABLE_CREATE 1 +#define MYSQL_AUDIT_TABLE_DROP 2 +#define MYSQL_AUDIT_TABLE_RENAME 3 +#define MYSQL_AUDIT_TABLE_ALTER 4 + +struct mysql_event_table +{ + unsigned int event_subclass; + unsigned long thread_id; + const char *user; + const char *priv_user; + const char *priv_host; + const char *external_user; + const char *proxy_user; + const char *host; + const char *ip; + const char *database; + unsigned int database_length; + const char *table; + unsigned int table_length; + /* for MYSQL_AUDIT_TABLE_LOCK, true if read-only, false if read/write */ + int read_only; + /* for MYSQL_AUDIT_TABLE_RENAME */ + const char *new_database; + unsigned int new_database_length; + const char *new_table; + unsigned int new_table_length; +}; /************************************************************************* Here we define the descriptor structure, that is referred from diff --git a/include/mysql/plugin_audit.h.pp b/include/mysql/plugin_audit.h.pp index f19d5fe797c..cb8435a1ec7 100644 --- a/include/mysql/plugin_audit.h.pp +++ b/include/mysql/plugin_audit.h.pp @@ -279,6 +279,27 @@ struct mysql_event_connection const char *database; unsigned int database_length; }; +struct mysql_event_table +{ + unsigned int event_subclass; + unsigned long thread_id; + const char *user; + const char *priv_user; + const char *priv_host; + const char *external_user; + const char *proxy_user; + const char *host; + const char *ip; + const char *database; + unsigned int database_length; + const char *table; + unsigned int table_length; + int read_only; + const char *new_database; + unsigned int new_database_length; + const char *new_table; + unsigned int new_table_length; +}; struct st_mysql_audit { int interface_version; diff --git a/mysql-test/suite/plugins/r/audit_null.result b/mysql-test/suite/plugins/r/audit_null.result index 4cf648510e6..76aef454b94 100644 --- a/mysql-test/suite/plugins/r/audit_null.result +++ b/mysql-test/suite/plugins/r/audit_null.result @@ -1,5 +1,6 @@ set @old_global_general_log=@@global.general_log; set global general_log=OFF; +grant select on *.* to testuser@localhost; install plugin audit_null soname 'adt_null'; select 1; 1 @@ -18,12 +19,82 @@ concat("test1", x) test1-12 show status like 'audit_null%'; Variable_name Value -Audit_null_called 19 +Audit_null_called 21 Audit_null_general_error 1 Audit_null_general_log 7 Audit_null_general_result 5 +create table t1 (a int); +insert t1 values (1), (2); +select * from t1; +a +1 +2 +rename table t1 to t2; +alter table t2 add column b int; +create definer=testuser@localhost view v1 as select t2.a+1, t2_copy.a+2 from t2, t2 as t2_copy; +select * from v1; +t2.a+1 t2_copy.a+2 +2 3 +3 3 +2 4 +3 4 +drop view v1; +create temporary table t2 (a date); +insert t2 values ('2020-10-09'); +select * from t2; +a +2020-10-09 +drop table t2; +explain select distinct * from t2; +id select_type table type possible_keys key key_len ref rows Extra +1 SIMPLE t2 ALL NULL NULL NULL NULL 2 Using temporary +select distinct * from t2; +a b +1 NULL +2 NULL +drop table t2; uninstall plugin audit_null; Warnings: Warning 1620 Plugin is busy and will be uninstalled on shutdown drop procedure au1; +drop user testuser@localhost; set global general_log=@old_global_general_log; +root[root] @ localhost [] >> select 1 +root[root] @ localhost [] >> select foobar +root[root] @ localhost [] >> show status like 'audit_null%' +root[root] @ localhost [] >> create procedure au1(x char(16)) select concat("test1", x) +root[root] @ localhost [] mysql.proc : write +root[root] @ localhost [] >> call au1("-12") +root[root] @ localhost [] mysql.proc : read +root[root] @ localhost [] >> select concat("test1", NAME_CONST('x',_latin1'-12' COLLATE 'latin1_swedish_ci')) +root[root] @ localhost [] >> show status like 'audit_null%' +root[root] @ localhost [] >> create table t1 (a int) +root[root] @ localhost [] test.t1 : create +root[root] @ localhost [] >> insert t1 values (1), (2) +root[root] @ localhost [] test.t1 : write +root[root] @ localhost [] >> select * from t1 +root[root] @ localhost [] test.t1 : read +root[root] @ localhost [] >> rename table t1 to t2 +root[root] @ localhost [] test.t1 : rename to test.t2 +root[root] @ localhost [] >> alter table t2 add column b int +root[root] @ localhost [] test.t2 : alter +root[root] @ localhost [] test.t2 : read +root[root] @ localhost [] >> create definer=testuser@localhost view v1 as select t2.a+1, t2_copy.a+2 from t2, t2 as t2_copy +root[root] @ localhost [] test.t2 : read +root[root] @ localhost [] test.t2 : read +root[root] @ localhost [] >> select * from v1 +root[root] @ localhost [] test.t2 : read +root[root] @ localhost [] test.t2 : read +root[root] @ localhost [] >> drop view v1 +root[root] @ localhost [] >> create temporary table t2 (a date) +root[root] @ localhost [] >> insert t2 values ('2020-10-09') +root[root] @ localhost [] >> select * from t2 +root[root] @ localhost [] >> drop table t2 +root[root] @ localhost [] >> explain select distinct * from t2 +root[root] @ localhost [] test.t2 : read +root[root] @ localhost [] >> select distinct * from t2 +root[root] @ localhost [] test.t2 : read +root[root] @ localhost [] >> drop table t2 +root[root] @ localhost [] test.t2 : drop +root[root] @ localhost [] >> uninstall plugin audit_null +root[root] @ localhost [] mysql.plugin : write diff --git a/mysql-test/suite/plugins/t/audit_null.test b/mysql-test/suite/plugins/t/audit_null.test index 428fd0c276e..47491668529 100644 --- a/mysql-test/suite/plugins/t/audit_null.test +++ b/mysql-test/suite/plugins/t/audit_null.test @@ -8,6 +8,8 @@ if (!$ADT_NULL_SO) { set @old_global_general_log=@@global.general_log; set global general_log=OFF; +grant select on *.* to testuser@localhost; + --disable_ps_protocol install plugin audit_null soname 'adt_null'; @@ -22,9 +24,36 @@ call au1("-12"); show status like 'audit_null%'; +create table t1 (a int); +insert t1 values (1), (2); +select * from t1; +rename table t1 to t2; +alter table t2 add column b int; + +create definer=testuser@localhost view v1 as select t2.a+1, t2_copy.a+2 from t2, t2 as t2_copy; +select * from v1; +drop view v1; + +# temp table generates no audit events +create temporary table t2 (a date); +insert t2 values ('2020-10-09'); +select * from t2; +drop table t2; + +# internal temp table generates no audit events +explain select distinct * from t2; +select distinct * from t2; + +drop table t2; + uninstall plugin audit_null; --enable_ps_protocol drop procedure au1; +drop user testuser@localhost; set global general_log=@old_global_general_log; +let $MYSQLD_DATADIR= `SELECT @@datadir`; +--replace_regex /#sql-[0-9a-f_]*/#sql-temporary/ /#sql2-[-0-9a-f_]*/#sql2-temporary/ +cat_file $MYSQLD_DATADIR/audit_null_tables.log; + diff --git a/plugin/audit_null/audit_null.c b/plugin/audit_null/audit_null.c index be0c70fbd35..916c7187a57 100644 --- a/plugin/audit_null/audit_null.c +++ b/plugin/audit_null/audit_null.c @@ -22,11 +22,12 @@ #define __attribute__(A) #endif -static volatile int number_of_calls; /* for SHOW STATUS, see below */ -static volatile int number_of_calls_general_log; -static volatile int number_of_calls_general_error; -static volatile int number_of_calls_general_result; +static volatile int ncalls; /* for SHOW STATUS, see below */ +static volatile int ncalls_general_log; +static volatile int ncalls_general_error; +static volatile int ncalls_general_result; +FILE *f; /* Initialize the plugin at server start or plugin installation. @@ -44,11 +45,16 @@ static volatile int number_of_calls_general_result; static int audit_null_plugin_init(void *arg __attribute__((unused))) { - number_of_calls= 0; - number_of_calls_general_log= 0; - number_of_calls_general_error= 0; - number_of_calls_general_result= 0; - return(0); + ncalls= 0; + ncalls_general_log= 0; + ncalls_general_error= 0; + ncalls_general_result= 0; + + f = fopen("audit_null_tables.log", "w"); + if (!f) + return 1; + + return 0; } @@ -67,7 +73,8 @@ static int audit_null_plugin_init(void *arg __attribute__((unused))) static int audit_null_plugin_deinit(void *arg __attribute__((unused))) { - return(0); + fclose(f); + return 0; } @@ -86,7 +93,7 @@ static void audit_null_notify(MYSQL_THD thd __attribute__((unused)), const void *event) { /* prone to races, oh well */ - number_of_calls++; + ncalls++; if (event_class == MYSQL_AUDIT_GENERAL_CLASS) { const struct mysql_event_general *event_general= @@ -94,18 +101,56 @@ static void audit_null_notify(MYSQL_THD thd __attribute__((unused)), switch (event_general->event_subclass) { case MYSQL_AUDIT_GENERAL_LOG: - number_of_calls_general_log++; + ncalls_general_log++; + fprintf(f, "%s\t>> %s\n", event_general->general_user, + event_general->general_query); break; case MYSQL_AUDIT_GENERAL_ERROR: - number_of_calls_general_error++; + ncalls_general_error++; break; case MYSQL_AUDIT_GENERAL_RESULT: - number_of_calls_general_result++; + ncalls_general_result++; break; default: break; } } + else + if (event_class == MYSQL_AUDIT_TABLE_CLASS) + { + const struct mysql_event_table *event_table= + (const struct mysql_event_table *) event; + const char *ip= event_table->ip ? event_table->ip : ""; + const char *op= 0; + char buf[1024]; + + switch (event_table->event_subclass) + { + case MYSQL_AUDIT_TABLE_LOCK: + op= event_table->read_only ? "read" : "write"; + break; + case MYSQL_AUDIT_TABLE_CREATE: + op= "create"; + break; + case MYSQL_AUDIT_TABLE_DROP: + op= "drop"; + break; + case MYSQL_AUDIT_TABLE_ALTER: + op= "alter"; + break; + case MYSQL_AUDIT_TABLE_RENAME: + snprintf(buf, sizeof(buf), "rename to %s.%s", + event_table->new_database, event_table->new_table); + buf[sizeof(buf)-1]= 0; + op= buf; + break; + } + + fprintf(f, "%s[%s] @ %s [%s]\t%s.%s : %s\n", + event_table->priv_user, event_table->user, + event_table->host, ip, + event_table->database, event_table->table, op); + } } @@ -115,10 +160,8 @@ static void audit_null_notify(MYSQL_THD thd __attribute__((unused)), static struct st_mysql_audit audit_null_descriptor= { - MYSQL_AUDIT_INTERFACE_VERSION, /* interface version */ - NULL, /* release_thd function */ - audit_null_notify, /* notify function */ - { (unsigned long) MYSQL_AUDIT_GENERAL_CLASSMASK } /* class mask */ + MYSQL_AUDIT_INTERFACE_VERSION, NULL, audit_null_notify, + { MYSQL_AUDIT_GENERAL_CLASSMASK | MYSQL_AUDIT_TABLE_CLASSMASK } }; /* @@ -127,12 +170,10 @@ static struct st_mysql_audit audit_null_descriptor= static struct st_mysql_show_var simple_status[]= { - { "Audit_null_called", (char *) &number_of_calls, SHOW_INT }, - { "Audit_null_general_log", (char *) &number_of_calls_general_log, SHOW_INT }, - { "Audit_null_general_error", (char *) &number_of_calls_general_error, - SHOW_INT }, - { "Audit_null_general_result", (char *) &number_of_calls_general_result, - SHOW_INT }, + { "Audit_null_called", (char *) &ncalls, SHOW_INT }, + { "Audit_null_general_log", (char *) &ncalls_general_log, SHOW_INT }, + { "Audit_null_general_error", (char *) &ncalls_general_error, SHOW_INT }, + { "Audit_null_general_result", (char *) &ncalls_general_result, SHOW_INT }, { 0, 0, 0} }; diff --git a/sql/handler.cc b/sql/handler.cc index a4505b807c2..355226b0e25 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -43,6 +43,7 @@ #include "myisam.h" #include "probes_mysql.h" #include "debug_sync.h" // DEBUG_SYNC +#include "sql_audit.h" #ifdef WITH_PARTITION_STORAGE_ENGINE #include "ha_partition.h" @@ -3689,7 +3690,6 @@ int handler::ha_delete_table(const char *name) { mark_trx_read_write(); - return delete_table(name); } @@ -3722,8 +3722,11 @@ int handler::ha_create(const char *name, TABLE *form, HA_CREATE_INFO *info) { mark_trx_read_write(); - - return create(name, form, info); + int error= create(name, form, info); + if (!error && + !(info->options & (HA_LEX_CREATE_TMP_TABLE | HA_CREATE_TMP_ALTER))) + mysql_audit_create_table(form); + return error; } @@ -5099,7 +5102,11 @@ int handler::ha_external_lock(THD *thd, int lock_type) int error= external_lock(thd, lock_type); if (error == 0) + { cached_table_flags= table_flags(); + if (table_share->tmp_table == NO_TMP_TABLE) + mysql_audit_external_lock(thd, table_share, lock_type); + } if (MYSQL_HANDLER_RDLOCK_DONE_ENABLED() || MYSQL_HANDLER_WRLOCK_DONE_ENABLED() || diff --git a/sql/handler.h b/sql/handler.h index 4a91d989e52..af9574d82f8 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -318,6 +318,7 @@ #define HA_LEX_CREATE_TMP_TABLE 1 #define HA_LEX_CREATE_IF_NOT_EXISTS 2 #define HA_LEX_CREATE_TABLE_LIKE 4 +#define HA_CREATE_TMP_ALTER 8 #define HA_MAX_REC_LENGTH 65535 /* Table caching type */ diff --git a/sql/sql_audit.cc b/sql/sql_audit.cc index 523f07592bc..8e17f49df28 100644 --- a/sql/sql_audit.cc +++ b/sql/sql_audit.cc @@ -31,8 +31,7 @@ unsigned long mysql_global_audit_mask[MYSQL_AUDIT_CLASS_MASK_SIZE]; static mysql_mutex_t LOCK_audit_mask; -static void event_class_dispatch(THD *thd, unsigned int event_class, - const void *event); +static void event_class_dispatch(THD *, unsigned int, const void *); static inline @@ -111,9 +110,36 @@ static void connection_class_handler(THD *thd, uint event_subclass, va_list ap) } +static void table_class_handler(THD *thd, uint event_subclass, va_list ap) +{ + mysql_event_table event; + event.event_subclass= event_subclass; + event.read_only= va_arg(ap, int); + event.thread_id= va_arg(ap, unsigned long); + event.user= va_arg(ap, const char *); + event.priv_user= va_arg(ap, const char *); + event.priv_host= va_arg(ap, const char *); + event.external_user= va_arg(ap, const char *); + event.proxy_user= va_arg(ap, const char *); + event.host= va_arg(ap, const char *); + event.ip= va_arg(ap, const char *); + event.database= va_arg(ap, const char *); + event.database_length= va_arg(ap, unsigned int); + event.table= va_arg(ap, const char *); + event.table_length= va_arg(ap, unsigned int); + event.new_database= va_arg(ap, const char *); + event.new_database_length= va_arg(ap, unsigned int); + event.new_table= va_arg(ap, const char *); + event.new_table_length= va_arg(ap, unsigned int); + event_class_dispatch(thd, MYSQL_AUDIT_TABLE_CLASS, &event); +} + + static audit_handler_t audit_handlers[] = { - general_class_handler, connection_class_handler + general_class_handler, connection_class_handler, + 0,0,0,0,0,0,0,0,0,0,0,0,0, /* placeholders */ + table_class_handler }; static const uint audit_handlers_count= diff --git a/sql/sql_audit.h b/sql/sql_audit.h index 46afe4b7596..75b338a16c8 100644 --- a/sql/sql_audit.h +++ b/sql/sql_audit.h @@ -43,17 +43,23 @@ static inline bool mysql_audit_general_enabled() return mysql_global_audit_mask[0] & MYSQL_AUDIT_GENERAL_CLASSMASK; } +static inline bool mysql_audit_table_enabled() +{ + return mysql_global_audit_mask[0] & MYSQL_AUDIT_TABLE_CLASSMASK; +} + #else static inline void mysql_audit_notify(THD *thd, uint event_class, uint event_subtype, ...) { } #define mysql_audit_general_enabled() 0 +#define mysql_audit_table_enabled() 0 #endif extern void mysql_audit_release(THD *thd); #define MAX_USER_HOST_SIZE 512 static inline uint make_user_name(THD *thd, char *buf) { - Security_context *sctx= thd->security_ctx; + const Security_context *sctx= thd->security_ctx; return strxnmov(buf, MAX_USER_HOST_SIZE, sctx->priv_user[0] ? sctx->priv_user : "", "[", sctx->user ? sctx->user : "", "] @ ", @@ -174,4 +180,87 @@ void mysql_audit_general(THD *thd, uint event_subtype, (thd)->security_ctx->ip ? strlen((thd)->security_ctx->ip) : 0,\ (thd)->db, (thd)->db ? strlen((thd)->db) : 0) +static inline +void mysql_audit_external_lock(THD *thd, TABLE_SHARE *share, int lock) +{ + if (lock != F_UNLCK && mysql_audit_table_enabled()) + { + const Security_context *sctx= thd->security_ctx; + mysql_audit_notify(thd, MYSQL_AUDIT_TABLE_CLASS, MYSQL_AUDIT_TABLE_LOCK, + (int)(lock == F_RDLCK), (ulong)thd->thread_id, + sctx->user, sctx->priv_user, sctx->priv_host, + sctx->external_user, sctx->proxy_user, sctx->host, + sctx->ip, share->db.str, (uint)share->db.length, + share->table_name.str, (uint)share->table_name.length, + 0,0,0,0); + } +} + +static inline +void mysql_audit_create_table(TABLE *table) +{ + if (mysql_audit_table_enabled()) + { + THD *thd= table->in_use; + const TABLE_SHARE *share= table->s; + const Security_context *sctx= thd->security_ctx; + mysql_audit_notify(thd, MYSQL_AUDIT_TABLE_CLASS, MYSQL_AUDIT_TABLE_CREATE, + 0, (ulong)thd->thread_id, + sctx->user, sctx->priv_user, sctx->priv_host, + sctx->external_user, sctx->proxy_user, sctx->host, + sctx->ip, share->db.str, (uint)share->db.length, + share->table_name.str, (uint)share->table_name.length, + 0,0,0,0); + } +} + +static inline +void mysql_audit_drop_table(THD *thd, TABLE_LIST *table) +{ + if (mysql_audit_table_enabled()) + { + const Security_context *sctx= thd->security_ctx; + mysql_audit_notify(thd, MYSQL_AUDIT_TABLE_CLASS, MYSQL_AUDIT_TABLE_DROP, + 0, (ulong)thd->thread_id, + sctx->user, sctx->priv_user, sctx->priv_host, + sctx->external_user, sctx->proxy_user, sctx->host, + sctx->ip, table->db, (uint)table->db_length, + table->table_name, (uint)table->table_name_length, + 0,0,0,0); + } +} + +static inline +void mysql_audit_rename_table(THD *thd, const char *old_db, const char *old_tb, + const char *new_db, const char *new_tb) +{ + if (mysql_audit_table_enabled()) + { + const Security_context *sctx= thd->security_ctx; + mysql_audit_notify(thd, MYSQL_AUDIT_TABLE_CLASS, MYSQL_AUDIT_TABLE_RENAME, + 0, (ulong)thd->thread_id, + sctx->user, sctx->priv_user, sctx->priv_host, + sctx->external_user, sctx->proxy_user, sctx->host, + sctx->ip, + old_db, (uint)strlen(old_db), old_tb, (uint)strlen(old_tb), + new_db, (uint)strlen(new_db), new_tb, (uint)strlen(new_tb)); + } +} + +static inline +void mysql_audit_alter_table(THD *thd, TABLE_LIST *table) +{ + if (mysql_audit_table_enabled()) + { + const Security_context *sctx= thd->security_ctx; + mysql_audit_notify(thd, MYSQL_AUDIT_TABLE_CLASS, MYSQL_AUDIT_TABLE_ALTER, + 0, (ulong)thd->thread_id, + sctx->user, sctx->priv_user, sctx->priv_host, + sctx->external_user, sctx->proxy_user, sctx->host, + sctx->ip, table->db, (uint)table->db_length, + table->table_name, (uint)table->table_name_length, + 0,0,0,0); + } +} + #endif /* SQL_AUDIT_INCLUDED */ diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 0effe2a7351..85c557acbfa 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -54,6 +54,7 @@ #include "sql_show.h" #include "transaction.h" #include "datadict.h" // dd_frm_type() +#include "sql_audit.h" #ifdef __WIN__ #include <io.h> @@ -2344,6 +2345,10 @@ int mysql_rm_table_no_locks(THD *thd, TABLE_LIST *tables, bool if_exists, wrong_tables.append(','); wrong_tables.append(String(table->table_name,system_charset_info)); } + else + { + mysql_audit_drop_table(thd, table); + } DBUG_PRINT("table", ("table: 0x%lx s: 0x%lx", (long) table->table, table->table ? (long) table->table->s : (long) -1)); @@ -4728,6 +4733,8 @@ mysql_rename_table(handlerton *base, const char *old_db, my_error(ER_NOT_SUPPORTED_YET, MYF(0), "ALTER TABLE"); else if (error) my_error(ER_ERROR_ON_RENAME, MYF(0), from, to, error); + else if (!(flags & FN_IS_TMP)) + mysql_audit_rename_table(thd, old_db, old_name, new_db, new_name); DBUG_RETURN(error != 0); } @@ -6054,6 +6061,8 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, mysql_ha_rm_tables(thd, table_list); + mysql_audit_alter_table(thd, table_list); + /* DISCARD/IMPORT TABLESPACE is always alone in an ALTER TABLE */ if (alter_info->tablespace_op != NO_TABLESPACE_OP) /* Conditionally writes to binlog. */ @@ -6716,6 +6725,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name, HA_OPTION_PACK_RECORD)); } tmp_disable_binlog(thd); + create_info->options|=HA_CREATE_TMP_ALTER; error= mysql_create_table_no_lock(thd, new_db, tmp_name, create_info, alter_info, |