developers
Threads by month
- ----- 2025 -----
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- 1 participants
- 6854 discussions

[Maria-developers] bzr commit into MariaDB 5.1, with Maria 1.5:maria branch (monty:2834)
by Michael Widenius 29 Mar '10
by Michael Widenius 29 Mar '10
29 Mar '10
#At lp:maria based on revid:sergii@pisem.net-20100324221239-7bj3zf8yv6bgclx1
2834 Michael Widenius 2010-03-28
Fixed compiler warnings and sporadic failures in test cases
modified:
mysql-test/extra/rpl_tests/rpl_tmp_table_and_DDL.test
mysql-test/include/default_mysqld.cnf
mysql-test/lib/My/SafeProcess/safe_process.cc
mysql-test/lib/v1/mysql-test-run.pl
mysql-test/suite/rpl/r/rpl_do_grant.result
mysql-test/suite/rpl/t/rpl_do_grant.test
mysql-test/suite/rpl/t/rpl_name_const.test
mysql-test/suite/rpl/t/rpl_row_basic_11bugs.test
mysql-test/t/bug47671-master.opt
mysql-test/t/ctype_latin1_de-master.opt
mysql-test/t/ctype_ucs2_def-master.opt
sql-common/client.c
sql/item.cc
sql/item.h
sql/item_cmpfunc.cc
sql/item_create.cc
sql/item_create.h
sql/item_sum.cc
sql/item_sum.h
sql/set_var.cc
sql/sql_yacc.yy
storage/example/ha_example.h
storage/maria/ma_search.c
storage/maria/maria_def.h
storage/myisam/ft_stopwords.c
storage/xtradb/fil/fil0fil.c
storage/xtradb/include/page0page.h
storage/xtradb/include/page0page.ic
support-files/compiler_warnings.supp
per-file messages:
mysql-test/extra/rpl_tests/rpl_tmp_table_and_DDL.test
Added missing sync_slave_with_master; Fixes random failures
mysql-test/include/default_mysqld.cnf
default-character-set -> character-set-server (removes warning in error files for usage of deprecated options)
mysql-test/lib/My/SafeProcess/safe_process.cc
Fixed compiler warning
mysql-test/lib/v1/mysql-test-run.pl
default-character-set -> character-set-server (removes warning in error files for usage of deprecated options)
mysql-test/suite/rpl/r/rpl_do_grant.result
Updated test results
mysql-test/suite/rpl/t/rpl_do_grant.test
Added missing sync_slave_with_master; Fixes random failures
Had to explictely do stop slave before DROP USER to avoid failure on slave as the user is already dropped on slave.
mysql-test/suite/rpl/t/rpl_name_const.test
Added missing sync_slave_with_master; Fixes random failures
mysql-test/suite/rpl/t/rpl_row_basic_11bugs.test
Added missing sync_slave_with_master; Fixes random failures
mysql-test/t/bug47671-master.opt
default-character-set -> character-set-server (removes warning in error files for usage of deprecated options)
mysql-test/t/ctype_latin1_de-master.opt
default-character-set -> character-set-server (removes warning in error files for usage of deprecated options)
mysql-test/t/ctype_ucs2_def-master.opt
default-character-set -> character-set-server (removes warning in error files for usage of deprecated options)
sql-common/client.c
Fixed compiler warning
sql/item.cc
Renamed function to remove compiler warnings (with gcc)
sql/item.h
Renamed function to remove compiler warnings (with gcc)
sql/item_cmpfunc.cc
Renamed function to remove compiler warnings (with gcc)
sql/item_create.cc
Renamed function to remove compiler warnings (with gcc)
sql/item_create.h
Renamed function to remove compiler warnings (with gcc)
sql/item_sum.cc
Renamed function to remove compiler warnings (with gcc)
sql/item_sum.h
Renamed function to remove compiler warnings (with gcc)
sql/set_var.cc
Don't use bit_do_set() / bot_is_set() / bit_do_clear() as this generates compiler warnings
(They are also of no use as we know the value can hold the bits)
sql/sql_yacc.yy
Renamed function to remove compiler warnings (with gcc)
storage/example/ha_example.h
Fixed old read_time() prototype
storage/maria/ma_search.c
Added extra variables to remove compiler warnings
storage/maria/maria_def.h
Added extra variables to remove compiler warnings
storage/myisam/ft_stopwords.c
Added cast to get rid of compiler warning
storage/xtradb/fil/fil0fil.c
Added cast to get rid of compiler warning
storage/xtradb/include/page0page.h
Added const to get rid of compiler warning
storage/xtradb/include/page0page.ic
Added const to get rid of compiler warning
support-files/compiler_warnings.supp
Added suppression of strict-aliasing
=== modified file 'mysql-test/extra/rpl_tests/rpl_tmp_table_and_DDL.test'
--- a/mysql-test/extra/rpl_tests/rpl_tmp_table_and_DDL.test 2010-01-22 09:38:21 +0000
+++ b/mysql-test/extra/rpl_tests/rpl_tmp_table_and_DDL.test 2010-03-28 18:10:00 +0000
@@ -157,3 +157,4 @@ INSERT INTO t1 VALUES (1);
DROP TEMPORARY TABLE t1;
+--sync_slave_with_master
=== modified file 'mysql-test/include/default_mysqld.cnf'
--- a/mysql-test/include/default_mysqld.cnf 2008-04-08 14:51:26 +0000
+++ b/mysql-test/include/default_mysqld.cnf 2010-03-28 18:10:00 +0000
@@ -2,7 +2,7 @@
[mysqld]
open-files-limit= 1024
local-infile
-default-character-set= latin1
+character-set-server= latin1
# Increase default connect_timeout to avoid intermittent
# disconnects when test servers are put under load see BUG#28359
=== modified file 'mysql-test/lib/My/SafeProcess/safe_process.cc'
--- a/mysql-test/lib/My/SafeProcess/safe_process.cc 2009-07-08 12:31:22 +0000
+++ b/mysql-test/lib/My/SafeProcess/safe_process.cc 2010-03-28 18:10:00 +0000
@@ -159,7 +159,7 @@ int main(int argc, char* const argv[] )
signal(SIGCHLD, handle_signal);
signal(SIGABRT, handle_abort);
- sprintf(safe_process_name, "safe_process[%d]", own_pid);
+ sprintf(safe_process_name, "safe_process[%d]", (int) own_pid);
message("Started");
=== modified file 'mysql-test/lib/v1/mysql-test-run.pl'
--- a/mysql-test/lib/v1/mysql-test-run.pl 2010-03-04 08:03:07 +0000
+++ b/mysql-test/lib/v1/mysql-test-run.pl 2010-03-28 18:10:00 +0000
@@ -3965,7 +3965,7 @@ sub mysqld_arguments ($$$$) {
}
}
- mtr_add_arg($args, "%s--default-character-set=latin1", $prefix);
+ mtr_add_arg($args, "%s--character-set-server-set=latin1", $prefix);
mtr_add_arg($args, "%s--language=%s", $prefix, $path_language);
mtr_add_arg($args, "%s--tmpdir=$opt_tmpdir", $prefix);
=== modified file 'mysql-test/suite/rpl/r/rpl_do_grant.result'
--- a/mysql-test/suite/rpl/r/rpl_do_grant.result 2009-12-06 23:12:11 +0000
+++ b/mysql-test/suite/rpl/r/rpl_do_grant.result 2010-03-28 18:10:00 +0000
@@ -165,10 +165,9 @@ USE bug42217_db;
DROP FUNCTION upgrade_del_func;
DROP FUNCTION upgrade_alter_func;
DROP DATABASE bug42217_db;
-DROP USER 'create_rout_db'@'localhost';
-call mtr.add_suppression("Slave: Operation DROP USER failed for 'create_rout_db'@'localhost' Error_code: 1396");
-USE mtr;
call mtr.add_suppression("Slave: Operation DROP USER failed for 'create_rout_db'@'localhost' Error_code: 1396");
+stop slave;
+DROP USER 'create_rout_db'@'localhost';
######## BUG#49119 #######
### i) test case from the 'how to repeat section'
stop slave;
=== modified file 'mysql-test/suite/rpl/t/rpl_do_grant.test'
--- a/mysql-test/suite/rpl/t/rpl_do_grant.test 2010-03-04 08:03:07 +0000
+++ b/mysql-test/suite/rpl/t/rpl_do_grant.test 2010-03-28 18:10:00 +0000
@@ -209,12 +209,18 @@ USE bug42217_db;
DROP FUNCTION upgrade_del_func;
DROP FUNCTION upgrade_alter_func;
DROP DATABASE bug42217_db;
-DROP USER 'create_rout_db'@'localhost';
call mtr.add_suppression("Slave: Operation DROP USER failed for 'create_rout_db'@'localhost' Error_code: 1396");
+
+sync_slave_with_master;
+
+# Drop the user that was already dropped on the slave
connection slave;
-USE mtr;
-call mtr.add_suppression("Slave: Operation DROP USER failed for 'create_rout_db'@'localhost' Error_code: 1396");
+--disable_warnings
+stop slave;
+connection master;
+DROP USER 'create_rout_db'@'localhost';
+--enable_warnings
# BUG#49119: Master crashes when executing 'REVOKE ... ON
# {PROCEDURE|FUNCTION} FROM ...'
=== modified file 'mysql-test/suite/rpl/t/rpl_name_const.test'
--- a/mysql-test/suite/rpl/t/rpl_name_const.test 2009-04-08 23:42:51 +0000
+++ b/mysql-test/suite/rpl/t/rpl_name_const.test 2010-03-28 18:10:00 +0000
@@ -45,3 +45,4 @@ select * from t1 order by id;
connection master;
drop table t1;
drop procedure test_procedure;
+--sync_slave_with_master
=== modified file 'mysql-test/suite/rpl/t/rpl_row_basic_11bugs.test'
--- a/mysql-test/suite/rpl/t/rpl_row_basic_11bugs.test 2007-12-12 10:14:59 +0000
+++ b/mysql-test/suite/rpl/t/rpl_row_basic_11bugs.test 2010-03-28 18:10:00 +0000
@@ -53,6 +53,7 @@ UPDATE t1 SET a=99 WHERE a = 0;
SHOW BINLOG EVENTS;
DROP TABLE t1;
+--sync_slave_with_master
# BUG#17620: Replicate (Row Based) Fails when Query Cache enabled on
# slave
=== modified file 'mysql-test/t/bug47671-master.opt'
--- a/mysql-test/t/bug47671-master.opt 2009-11-25 06:55:49 +0000
+++ b/mysql-test/t/bug47671-master.opt 2010-03-28 18:10:00 +0000
@@ -1 +1 @@
---default-character-set=utf8 --skip-character-set-client-handshake
+--character-set-server=utf8 --skip-character-set-client-handshake
=== modified file 'mysql-test/t/ctype_latin1_de-master.opt'
--- a/mysql-test/t/ctype_latin1_de-master.opt 2003-05-21 23:57:27 +0000
+++ b/mysql-test/t/ctype_latin1_de-master.opt 2010-03-28 18:10:00 +0000
@@ -1 +1 @@
---default-character-set=latin1 --default-collation=latin1_german2_ci
+--character-set-server=latin1 --default-collation=latin1_german2_ci
=== modified file 'mysql-test/t/ctype_ucs2_def-master.opt'
--- a/mysql-test/t/ctype_ucs2_def-master.opt 2007-02-19 11:04:38 +0000
+++ b/mysql-test/t/ctype_ucs2_def-master.opt 2010-03-28 18:10:00 +0000
@@ -1 +1 @@
---default-collation=ucs2_unicode_ci --default-character-set=ucs2,latin1
+--default-collation=ucs2_unicode_ci --character-set-server=ucs2,latin1
=== modified file 'sql-common/client.c'
--- a/sql-common/client.c 2010-01-29 18:42:22 +0000
+++ b/sql-common/client.c 2010-03-28 18:10:00 +0000
@@ -1863,7 +1863,6 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,cons
uint port, const char *unix_socket,ulong client_flag)
{
char buff[NAME_LEN+USERNAME_LENGTH+100];
- char error_string[1024];
char *end,*host_info= NULL;
my_socket sock;
in_addr_t ip_addr;
@@ -2304,6 +2303,7 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,cons
/* Do the SSL layering. */
struct st_mysql_options *options= &mysql->options;
struct st_VioSSLFd *ssl_fd;
+ char error_string[1024];
/*
Send client_flag, max_packet_size - unencrypted otherwise
=== modified file 'sql/item.cc'
--- a/sql/item.cc 2010-03-04 08:03:07 +0000
+++ b/sql/item.cc 2010-03-28 18:10:00 +0000
@@ -7010,7 +7010,7 @@ bool Item_cache_int::cache_value()
}
-void Item_cache_int::store(Item *item, longlong val_arg)
+void Item_cache_int::store_longlong(Item *item, longlong val_arg)
{
/* An explicit values is given, save it. */
value_cached= TRUE;
=== modified file 'sql/item.h'
--- a/sql/item.h 2010-03-04 08:03:07 +0000
+++ b/sql/item.h 2010-03-28 18:10:00 +0000
@@ -3045,7 +3045,7 @@ public:
Item_cache_int(enum_field_types field_type_arg):
Item_cache(field_type_arg), value(0) {}
- void store(Item *item, longlong val_arg);
+ void store_longlong(Item *item, longlong val_arg);
double val_real();
longlong val_int();
String* val_str(String *str);
=== modified file 'sql/item_cmpfunc.cc'
--- a/sql/item_cmpfunc.cc 2010-03-04 08:03:07 +0000
+++ b/sql/item_cmpfunc.cc 2010-03-28 18:10:00 +0000
@@ -879,7 +879,7 @@ get_time_value(THD *thd, Item ***item_ar
Item_cache_int *cache= new Item_cache_int();
/* Mark the cache as non-const to prevent re-caching. */
cache->set_used_tables(1);
- cache->store(item, value);
+ cache->store_longlong(item, value);
*cache_arg= cache;
*item_arg= cache_arg;
}
@@ -917,13 +917,13 @@ int Arg_comparator::set_cmp_func(Item_re
cache->set_used_tables(1);
if (!(*a)->is_datetime())
{
- cache->store((*a), const_value);
+ cache->store_longlong((*a), const_value);
a_cache= cache;
a= (Item **)&a_cache;
}
else
{
- cache->store((*b), const_value);
+ cache->store_longlong((*b), const_value);
b_cache= cache;
b= (Item **)&b_cache;
}
@@ -1145,7 +1145,7 @@ get_datetime_value(THD *thd, Item ***ite
Item_cache_int *cache= new Item_cache_int(MYSQL_TYPE_DATETIME);
/* Mark the cache as non-const to prevent re-caching. */
cache->set_used_tables(1);
- cache->store(item, value);
+ cache->store_longlong(item, value);
*cache_arg= cache;
*item_arg= cache_arg;
}
=== modified file 'sql/item_create.cc'
--- a/sql/item_create.cc 2010-03-04 08:03:07 +0000
+++ b/sql/item_create.cc 2010-03-28 18:10:00 +0000
@@ -101,7 +101,7 @@ public:
@param arg1 The first argument of the function
@return An item representing the function call
*/
- virtual Item *create(THD *thd, Item *arg1) = 0;
+ virtual Item *create_1_arg(THD *thd, Item *arg1) = 0;
protected:
/** Constructor. */
@@ -127,7 +127,7 @@ public:
@param arg2 The second argument of the function
@return An item representing the function call
*/
- virtual Item *create(THD *thd, Item *arg1, Item *arg2) = 0;
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2) = 0;
protected:
/** Constructor. */
@@ -154,7 +154,7 @@ public:
@param arg3 The third argument of the function
@return An item representing the function call
*/
- virtual Item *create(THD *thd, Item *arg1, Item *arg2, Item *arg3) = 0;
+ virtual Item *create_3_arg(THD *thd, Item *arg1, Item *arg2, Item *arg3) = 0;
protected:
/** Constructor. */
@@ -171,8 +171,8 @@ protected:
class Create_sp_func : public Create_qfunc
{
public:
- virtual Item *create(THD *thd, LEX_STRING db, LEX_STRING name,
- bool use_explicit_name, List<Item> *item_list);
+ virtual Item *create_with_db(THD *thd, LEX_STRING db, LEX_STRING name,
+ bool use_explicit_name, List<Item> *item_list);
static Create_sp_func s_singleton;
@@ -217,7 +217,7 @@ protected:
class Create_func_abs : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_abs s_singleton;
@@ -230,7 +230,7 @@ protected:
class Create_func_acos : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_acos s_singleton;
@@ -243,7 +243,7 @@ protected:
class Create_func_addtime : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_addtime s_singleton;
@@ -256,7 +256,7 @@ protected:
class Create_func_aes_encrypt : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_aes_encrypt s_singleton;
@@ -269,7 +269,7 @@ protected:
class Create_func_aes_decrypt : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_aes_decrypt s_singleton;
@@ -283,7 +283,7 @@ protected:
class Create_func_area : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_area s_singleton;
@@ -298,7 +298,7 @@ protected:
class Create_func_as_wkb : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_as_wkb s_singleton;
@@ -313,7 +313,7 @@ protected:
class Create_func_as_wkt : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_as_wkt s_singleton;
@@ -327,7 +327,7 @@ protected:
class Create_func_asin : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_asin s_singleton;
@@ -353,7 +353,7 @@ protected:
class Create_func_benchmark : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_benchmark s_singleton;
@@ -366,7 +366,7 @@ protected:
class Create_func_bin : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_bin s_singleton;
@@ -379,7 +379,7 @@ protected:
class Create_func_bit_count : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_bit_count s_singleton;
@@ -392,7 +392,7 @@ protected:
class Create_func_bit_length : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_bit_length s_singleton;
@@ -405,7 +405,7 @@ protected:
class Create_func_ceiling : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_ceiling s_singleton;
@@ -419,7 +419,7 @@ protected:
class Create_func_centroid : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_centroid s_singleton;
@@ -433,7 +433,7 @@ protected:
class Create_func_char_length : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_char_length s_singleton;
@@ -446,7 +446,7 @@ protected:
class Create_func_coercibility : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_coercibility s_singleton;
@@ -459,7 +459,7 @@ protected:
class Create_func_compress : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_compress s_singleton;
@@ -512,7 +512,7 @@ protected:
class Create_func_contains : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_contains s_singleton;
@@ -526,7 +526,7 @@ protected:
class Create_func_conv : public Create_func_arg3
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2, Item *arg3);
+ virtual Item *create_3_arg(THD *thd, Item *arg1, Item *arg2, Item *arg3);
static Create_func_conv s_singleton;
@@ -539,7 +539,7 @@ protected:
class Create_func_convert_tz : public Create_func_arg3
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2, Item *arg3);
+ virtual Item *create_3_arg(THD *thd, Item *arg1, Item *arg2, Item *arg3);
static Create_func_convert_tz s_singleton;
@@ -552,7 +552,7 @@ protected:
class Create_func_cos : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_cos s_singleton;
@@ -565,7 +565,7 @@ protected:
class Create_func_cot : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_cot s_singleton;
@@ -578,7 +578,7 @@ protected:
class Create_func_crc32 : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_crc32 s_singleton;
@@ -592,7 +592,7 @@ protected:
class Create_func_crosses : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_crosses s_singleton;
@@ -606,7 +606,7 @@ protected:
class Create_func_date_format : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_date_format s_singleton;
@@ -619,7 +619,7 @@ protected:
class Create_func_datediff : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_datediff s_singleton;
@@ -632,7 +632,7 @@ protected:
class Create_func_dayname : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_dayname s_singleton;
@@ -645,7 +645,7 @@ protected:
class Create_func_dayofmonth : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_dayofmonth s_singleton;
@@ -658,7 +658,7 @@ protected:
class Create_func_dayofweek : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_dayofweek s_singleton;
@@ -671,7 +671,7 @@ protected:
class Create_func_dayofyear : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_dayofyear s_singleton;
@@ -684,7 +684,7 @@ protected:
class Create_func_decode : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_decode s_singleton;
@@ -697,7 +697,7 @@ protected:
class Create_func_degrees : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_degrees s_singleton;
@@ -737,7 +737,7 @@ protected:
class Create_func_dimension : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_dimension s_singleton;
@@ -752,7 +752,7 @@ protected:
class Create_func_disjoint : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_disjoint s_singleton;
@@ -779,7 +779,7 @@ protected:
class Create_func_encode : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_encode s_singleton;
@@ -806,7 +806,7 @@ protected:
class Create_func_endpoint : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_endpoint s_singleton;
@@ -821,7 +821,7 @@ protected:
class Create_func_envelope : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_envelope s_singleton;
@@ -836,7 +836,7 @@ protected:
class Create_func_equals : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_equals s_singleton;
@@ -850,7 +850,7 @@ protected:
class Create_func_exp : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_exp s_singleton;
@@ -877,7 +877,7 @@ protected:
class Create_func_exteriorring : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_exteriorring s_singleton;
@@ -904,7 +904,7 @@ protected:
class Create_func_find_in_set : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_find_in_set s_singleton;
@@ -917,7 +917,7 @@ protected:
class Create_func_floor : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_floor s_singleton;
@@ -930,7 +930,7 @@ protected:
class Create_func_format : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_format s_singleton;
@@ -956,7 +956,7 @@ protected:
class Create_func_from_days : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_from_days s_singleton;
@@ -1013,7 +1013,7 @@ protected:
class Create_func_geometry_type : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_geometry_type s_singleton;
@@ -1028,7 +1028,7 @@ protected:
class Create_func_geometryn : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_geometryn s_singleton;
@@ -1042,7 +1042,7 @@ protected:
class Create_func_get_lock : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_get_lock s_singleton;
@@ -1056,7 +1056,7 @@ protected:
class Create_func_glength : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_glength s_singleton;
@@ -1083,7 +1083,7 @@ protected:
class Create_func_hex : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_hex s_singleton;
@@ -1096,7 +1096,7 @@ protected:
class Create_func_ifnull : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_ifnull s_singleton;
@@ -1109,7 +1109,7 @@ protected:
class Create_func_inet_ntoa : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_inet_ntoa s_singleton;
@@ -1122,7 +1122,7 @@ protected:
class Create_func_inet_aton : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_inet_aton s_singleton;
@@ -1135,7 +1135,7 @@ protected:
class Create_func_instr : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_instr s_singleton;
@@ -1149,7 +1149,7 @@ protected:
class Create_func_interiorringn : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_interiorringn s_singleton;
@@ -1164,7 +1164,7 @@ protected:
class Create_func_intersects : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_intersects s_singleton;
@@ -1178,7 +1178,7 @@ protected:
class Create_func_is_free_lock : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_is_free_lock s_singleton;
@@ -1191,7 +1191,7 @@ protected:
class Create_func_is_used_lock : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_is_used_lock s_singleton;
@@ -1205,7 +1205,7 @@ protected:
class Create_func_isclosed : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_isclosed s_singleton;
@@ -1220,7 +1220,7 @@ protected:
class Create_func_isempty : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_isempty s_singleton;
@@ -1234,7 +1234,7 @@ protected:
class Create_func_isnull : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_isnull s_singleton;
@@ -1248,7 +1248,7 @@ protected:
class Create_func_issimple : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_issimple s_singleton;
@@ -1262,7 +1262,7 @@ protected:
class Create_func_last_day : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_last_day s_singleton;
@@ -1288,7 +1288,7 @@ protected:
class Create_func_lcase : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_lcase s_singleton;
@@ -1314,7 +1314,7 @@ protected:
class Create_func_length : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_length s_singleton;
@@ -1327,7 +1327,7 @@ protected:
class Create_func_ln : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_ln s_singleton;
@@ -1340,7 +1340,7 @@ protected:
class Create_func_load_file : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_load_file s_singleton;
@@ -1379,7 +1379,7 @@ protected:
class Create_func_log10 : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_log10 s_singleton;
@@ -1392,7 +1392,7 @@ protected:
class Create_func_log2 : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_log2 s_singleton;
@@ -1405,7 +1405,7 @@ protected:
class Create_func_lpad : public Create_func_arg3
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2, Item *arg3);
+ virtual Item *create_3_arg(THD *thd, Item *arg1, Item *arg2, Item *arg3);
static Create_func_lpad s_singleton;
@@ -1418,7 +1418,7 @@ protected:
class Create_func_ltrim : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_ltrim s_singleton;
@@ -1431,7 +1431,7 @@ protected:
class Create_func_makedate : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_makedate s_singleton;
@@ -1444,7 +1444,7 @@ protected:
class Create_func_maketime : public Create_func_arg3
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2, Item *arg3);
+ virtual Item *create_3_arg(THD *thd, Item *arg1, Item *arg2, Item *arg3);
static Create_func_maketime s_singleton;
@@ -1483,7 +1483,7 @@ protected:
class Create_func_md5 : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_md5 s_singleton;
@@ -1496,7 +1496,7 @@ protected:
class Create_func_monthname : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_monthname s_singleton;
@@ -1509,7 +1509,7 @@ protected:
class Create_func_name_const : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_name_const s_singleton;
@@ -1522,7 +1522,7 @@ protected:
class Create_func_nullif : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_nullif s_singleton;
@@ -1536,7 +1536,7 @@ protected:
class Create_func_numgeometries : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_numgeometries s_singleton;
@@ -1551,7 +1551,7 @@ protected:
class Create_func_numinteriorring : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_numinteriorring s_singleton;
@@ -1566,7 +1566,7 @@ protected:
class Create_func_numpoints : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_numpoints s_singleton;
@@ -1580,7 +1580,7 @@ protected:
class Create_func_oct : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_oct s_singleton;
@@ -1593,7 +1593,7 @@ protected:
class Create_func_ord : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_ord s_singleton;
@@ -1607,7 +1607,7 @@ protected:
class Create_func_overlaps : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_overlaps s_singleton;
@@ -1621,7 +1621,7 @@ protected:
class Create_func_period_add : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_period_add s_singleton;
@@ -1634,7 +1634,7 @@ protected:
class Create_func_period_diff : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_period_diff s_singleton;
@@ -1661,7 +1661,7 @@ protected:
class Create_func_pointn : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_pointn s_singleton;
@@ -1675,7 +1675,7 @@ protected:
class Create_func_pow : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_pow s_singleton;
@@ -1688,7 +1688,7 @@ protected:
class Create_func_quote : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_quote s_singleton;
@@ -1701,7 +1701,7 @@ protected:
class Create_func_radians : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_radians s_singleton;
@@ -1727,7 +1727,7 @@ protected:
class Create_func_release_lock : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_release_lock s_singleton;
@@ -1740,7 +1740,7 @@ protected:
class Create_func_reverse : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_reverse s_singleton;
@@ -1779,7 +1779,7 @@ protected:
class Create_func_rpad : public Create_func_arg3
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2, Item *arg3);
+ virtual Item *create_3_arg(THD *thd, Item *arg1, Item *arg2, Item *arg3);
static Create_func_rpad s_singleton;
@@ -1792,7 +1792,7 @@ protected:
class Create_func_rtrim : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_rtrim s_singleton;
@@ -1805,7 +1805,7 @@ protected:
class Create_func_sec_to_time : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_sec_to_time s_singleton;
@@ -1818,7 +1818,7 @@ protected:
class Create_func_sha : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_sha s_singleton;
@@ -1831,7 +1831,7 @@ protected:
class Create_func_sign : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_sign s_singleton;
@@ -1844,7 +1844,7 @@ protected:
class Create_func_sin : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_sin s_singleton;
@@ -1857,7 +1857,7 @@ protected:
class Create_func_sleep : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_sleep s_singleton;
@@ -1870,7 +1870,7 @@ protected:
class Create_func_soundex : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_soundex s_singleton;
@@ -1883,7 +1883,7 @@ protected:
class Create_func_space : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_space s_singleton;
@@ -1896,7 +1896,7 @@ protected:
class Create_func_sqrt : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_sqrt s_singleton;
@@ -1910,7 +1910,7 @@ protected:
class Create_func_srid : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_srid s_singleton;
@@ -1925,7 +1925,7 @@ protected:
class Create_func_startpoint : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_startpoint s_singleton;
@@ -1939,7 +1939,7 @@ protected:
class Create_func_str_to_date : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_str_to_date s_singleton;
@@ -1952,7 +1952,7 @@ protected:
class Create_func_strcmp : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_strcmp s_singleton;
@@ -1965,7 +1965,7 @@ protected:
class Create_func_substr_index : public Create_func_arg3
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2, Item *arg3);
+ virtual Item *create_3_arg(THD *thd, Item *arg1, Item *arg2, Item *arg3);
static Create_func_substr_index s_singleton;
@@ -1978,7 +1978,7 @@ protected:
class Create_func_subtime : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_subtime s_singleton;
@@ -1991,7 +1991,7 @@ protected:
class Create_func_tan : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_tan s_singleton;
@@ -2004,7 +2004,7 @@ protected:
class Create_func_time_format : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_time_format s_singleton;
@@ -2017,7 +2017,7 @@ protected:
class Create_func_time_to_sec : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_time_to_sec s_singleton;
@@ -2030,7 +2030,7 @@ protected:
class Create_func_timediff : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_timediff s_singleton;
@@ -2043,7 +2043,7 @@ protected:
class Create_func_to_days : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_to_days s_singleton;
@@ -2057,7 +2057,7 @@ protected:
class Create_func_touches : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_touches s_singleton;
@@ -2071,7 +2071,7 @@ protected:
class Create_func_ucase : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_ucase s_singleton;
@@ -2084,7 +2084,7 @@ protected:
class Create_func_uncompress : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_uncompress s_singleton;
@@ -2097,7 +2097,7 @@ protected:
class Create_func_uncompressed_length : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_uncompressed_length s_singleton;
@@ -2110,7 +2110,7 @@ protected:
class Create_func_unhex : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_unhex s_singleton;
@@ -2175,7 +2175,7 @@ protected:
class Create_func_weekday : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_weekday s_singleton;
@@ -2188,7 +2188,7 @@ protected:
class Create_func_weekofyear : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_weekofyear s_singleton;
@@ -2202,7 +2202,7 @@ protected:
class Create_func_within : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_within s_singleton;
@@ -2217,7 +2217,7 @@ protected:
class Create_func_x : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_x s_singleton;
@@ -2231,7 +2231,7 @@ protected:
class Create_func_xml_extractvalue : public Create_func_arg2
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2);
+ virtual Item *create_2_arg(THD *thd, Item *arg1, Item *arg2);
static Create_func_xml_extractvalue s_singleton;
@@ -2244,7 +2244,7 @@ protected:
class Create_func_xml_update : public Create_func_arg3
{
public:
- virtual Item *create(THD *thd, Item *arg1, Item *arg2, Item *arg3);
+ virtual Item *create_3_arg(THD *thd, Item *arg1, Item *arg2, Item *arg3);
static Create_func_xml_update s_singleton;
@@ -2258,7 +2258,7 @@ protected:
class Create_func_y : public Create_func_arg1
{
public:
- virtual Item *create(THD *thd, Item *arg1);
+ virtual Item *create_1_arg(THD *thd, Item *arg1);
static Create_func_y s_singleton;
@@ -2353,7 +2353,7 @@ Create_qfunc::create(THD *thd, LEX_STRIN
if (thd->lex->copy_db_to(&db.str, &db.length))
return NULL;
- return create(thd, db, name, false, item_list);
+ return create_with_db(thd, db, name, false, item_list);
}
@@ -2470,8 +2470,8 @@ Create_udf_func::create(THD *thd, udf_fu
Create_sp_func Create_sp_func::s_singleton;
Item*
-Create_sp_func::create(THD *thd, LEX_STRING db, LEX_STRING name,
- bool use_explicit_name, List<Item> *item_list)
+Create_sp_func::create_with_db(THD *thd, LEX_STRING db, LEX_STRING name,
+ bool use_explicit_name, List<Item> *item_list)
{
int arg_count= 0;
Item *func= NULL;
@@ -2564,7 +2564,7 @@ Create_func_arg1::create(THD *thd, LEX_S
return NULL;
}
- return create(thd, param_1);
+ return create_1_arg(thd, param_1);
}
@@ -2592,7 +2592,7 @@ Create_func_arg2::create(THD *thd, LEX_S
return NULL;
}
- return create(thd, param_1, param_2);
+ return create_2_arg(thd, param_1, param_2);
}
@@ -2622,14 +2622,14 @@ Create_func_arg3::create(THD *thd, LEX_S
return NULL;
}
- return create(thd, param_1, param_2, param_3);
+ return create_3_arg(thd, param_1, param_2, param_3);
}
Create_func_abs Create_func_abs::s_singleton;
Item*
-Create_func_abs::create(THD *thd, Item *arg1)
+Create_func_abs::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_abs(arg1);
}
@@ -2638,7 +2638,7 @@ Create_func_abs::create(THD *thd, Item *
Create_func_acos Create_func_acos::s_singleton;
Item*
-Create_func_acos::create(THD *thd, Item *arg1)
+Create_func_acos::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_acos(arg1);
}
@@ -2647,7 +2647,7 @@ Create_func_acos::create(THD *thd, Item
Create_func_addtime Create_func_addtime::s_singleton;
Item*
-Create_func_addtime::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_addtime::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_add_time(arg1, arg2, 0, 0);
}
@@ -2656,7 +2656,7 @@ Create_func_addtime::create(THD *thd, It
Create_func_aes_encrypt Create_func_aes_encrypt::s_singleton;
Item*
-Create_func_aes_encrypt::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_aes_encrypt::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_aes_encrypt(arg1, arg2);
}
@@ -2665,7 +2665,7 @@ Create_func_aes_encrypt::create(THD *thd
Create_func_aes_decrypt Create_func_aes_decrypt::s_singleton;
Item*
-Create_func_aes_decrypt::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_aes_decrypt::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_aes_decrypt(arg1, arg2);
}
@@ -2675,7 +2675,7 @@ Create_func_aes_decrypt::create(THD *thd
Create_func_area Create_func_area::s_singleton;
Item*
-Create_func_area::create(THD *thd, Item *arg1)
+Create_func_area::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_area(arg1);
}
@@ -2686,7 +2686,7 @@ Create_func_area::create(THD *thd, Item
Create_func_as_wkb Create_func_as_wkb::s_singleton;
Item*
-Create_func_as_wkb::create(THD *thd, Item *arg1)
+Create_func_as_wkb::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_as_wkb(arg1);
}
@@ -2697,7 +2697,7 @@ Create_func_as_wkb::create(THD *thd, Ite
Create_func_as_wkt Create_func_as_wkt::s_singleton;
Item*
-Create_func_as_wkt::create(THD *thd, Item *arg1)
+Create_func_as_wkt::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_as_wkt(arg1);
}
@@ -2707,7 +2707,7 @@ Create_func_as_wkt::create(THD *thd, Ite
Create_func_asin Create_func_asin::s_singleton;
Item*
-Create_func_asin::create(THD *thd, Item *arg1)
+Create_func_asin::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_asin(arg1);
}
@@ -2753,7 +2753,7 @@ Create_func_atan::create_native(THD *thd
Create_func_benchmark Create_func_benchmark::s_singleton;
Item*
-Create_func_benchmark::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_benchmark::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
return new (thd->mem_root) Item_func_benchmark(arg1, arg2);
@@ -2763,7 +2763,7 @@ Create_func_benchmark::create(THD *thd,
Create_func_bin Create_func_bin::s_singleton;
Item*
-Create_func_bin::create(THD *thd, Item *arg1)
+Create_func_bin::create_1_arg(THD *thd, Item *arg1)
{
Item *i10= new (thd->mem_root) Item_int((int32) 10,2);
Item *i2= new (thd->mem_root) Item_int((int32) 2,1);
@@ -2774,7 +2774,7 @@ Create_func_bin::create(THD *thd, Item *
Create_func_bit_count Create_func_bit_count::s_singleton;
Item*
-Create_func_bit_count::create(THD *thd, Item *arg1)
+Create_func_bit_count::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_bit_count(arg1);
}
@@ -2783,7 +2783,7 @@ Create_func_bit_count::create(THD *thd,
Create_func_bit_length Create_func_bit_length::s_singleton;
Item*
-Create_func_bit_length::create(THD *thd, Item *arg1)
+Create_func_bit_length::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_bit_length(arg1);
}
@@ -2792,7 +2792,7 @@ Create_func_bit_length::create(THD *thd,
Create_func_ceiling Create_func_ceiling::s_singleton;
Item*
-Create_func_ceiling::create(THD *thd, Item *arg1)
+Create_func_ceiling::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_ceiling(arg1);
}
@@ -2802,7 +2802,7 @@ Create_func_ceiling::create(THD *thd, It
Create_func_centroid Create_func_centroid::s_singleton;
Item*
-Create_func_centroid::create(THD *thd, Item *arg1)
+Create_func_centroid::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_centroid(arg1);
}
@@ -2812,7 +2812,7 @@ Create_func_centroid::create(THD *thd, I
Create_func_char_length Create_func_char_length::s_singleton;
Item*
-Create_func_char_length::create(THD *thd, Item *arg1)
+Create_func_char_length::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_char_length(arg1);
}
@@ -2821,7 +2821,7 @@ Create_func_char_length::create(THD *thd
Create_func_coercibility Create_func_coercibility::s_singleton;
Item*
-Create_func_coercibility::create(THD *thd, Item *arg1)
+Create_func_coercibility::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_coercibility(arg1);
}
@@ -2873,7 +2873,7 @@ Create_func_concat_ws::create_native(THD
Create_func_compress Create_func_compress::s_singleton;
Item*
-Create_func_compress::create(THD *thd, Item *arg1)
+Create_func_compress::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_compress(arg1);
}
@@ -2893,7 +2893,7 @@ Create_func_connection_id::create(THD *t
Create_func_contains Create_func_contains::s_singleton;
Item*
-Create_func_contains::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_contains::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_spatial_rel(arg1, arg2,
Item_func::SP_CONTAINS_FUNC);
@@ -2904,7 +2904,7 @@ Create_func_contains::create(THD *thd, I
Create_func_conv Create_func_conv::s_singleton;
Item*
-Create_func_conv::create(THD *thd, Item *arg1, Item *arg2, Item *arg3)
+Create_func_conv::create_3_arg(THD *thd, Item *arg1, Item *arg2, Item *arg3)
{
return new (thd->mem_root) Item_func_conv(arg1, arg2, arg3);
}
@@ -2913,7 +2913,7 @@ Create_func_conv::create(THD *thd, Item
Create_func_convert_tz Create_func_convert_tz::s_singleton;
Item*
-Create_func_convert_tz::create(THD *thd, Item *arg1, Item *arg2, Item *arg3)
+Create_func_convert_tz::create_3_arg(THD *thd, Item *arg1, Item *arg2, Item *arg3)
{
return new (thd->mem_root) Item_func_convert_tz(arg1, arg2, arg3);
}
@@ -2922,7 +2922,7 @@ Create_func_convert_tz::create(THD *thd,
Create_func_cos Create_func_cos::s_singleton;
Item*
-Create_func_cos::create(THD *thd, Item *arg1)
+Create_func_cos::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_cos(arg1);
}
@@ -2931,7 +2931,7 @@ Create_func_cos::create(THD *thd, Item *
Create_func_cot Create_func_cot::s_singleton;
Item*
-Create_func_cot::create(THD *thd, Item *arg1)
+Create_func_cot::create_1_arg(THD *thd, Item *arg1)
{
Item *i1= new (thd->mem_root) Item_int((char*) "1", 1, 1);
Item *i2= new (thd->mem_root) Item_func_tan(arg1);
@@ -2942,7 +2942,7 @@ Create_func_cot::create(THD *thd, Item *
Create_func_crc32 Create_func_crc32::s_singleton;
Item*
-Create_func_crc32::create(THD *thd, Item *arg1)
+Create_func_crc32::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_crc32(arg1);
}
@@ -2952,7 +2952,7 @@ Create_func_crc32::create(THD *thd, Item
Create_func_crosses Create_func_crosses::s_singleton;
Item*
-Create_func_crosses::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_crosses::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_spatial_rel(arg1, arg2,
Item_func::SP_CROSSES_FUNC);
@@ -2963,7 +2963,7 @@ Create_func_crosses::create(THD *thd, It
Create_func_date_format Create_func_date_format::s_singleton;
Item*
-Create_func_date_format::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_date_format::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_date_format(arg1, arg2, 0);
}
@@ -2972,7 +2972,7 @@ Create_func_date_format::create(THD *thd
Create_func_datediff Create_func_datediff::s_singleton;
Item*
-Create_func_datediff::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_datediff::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
Item *i1= new (thd->mem_root) Item_func_to_days(arg1);
Item *i2= new (thd->mem_root) Item_func_to_days(arg2);
@@ -2984,7 +2984,7 @@ Create_func_datediff::create(THD *thd, I
Create_func_dayname Create_func_dayname::s_singleton;
Item*
-Create_func_dayname::create(THD *thd, Item *arg1)
+Create_func_dayname::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_dayname(arg1);
}
@@ -2993,7 +2993,7 @@ Create_func_dayname::create(THD *thd, It
Create_func_dayofmonth Create_func_dayofmonth::s_singleton;
Item*
-Create_func_dayofmonth::create(THD *thd, Item *arg1)
+Create_func_dayofmonth::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_dayofmonth(arg1);
}
@@ -3002,7 +3002,7 @@ Create_func_dayofmonth::create(THD *thd,
Create_func_dayofweek Create_func_dayofweek::s_singleton;
Item*
-Create_func_dayofweek::create(THD *thd, Item *arg1)
+Create_func_dayofweek::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_weekday(arg1, 1);
}
@@ -3011,7 +3011,7 @@ Create_func_dayofweek::create(THD *thd,
Create_func_dayofyear Create_func_dayofyear::s_singleton;
Item*
-Create_func_dayofyear::create(THD *thd, Item *arg1)
+Create_func_dayofyear::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_dayofyear(arg1);
}
@@ -3020,7 +3020,7 @@ Create_func_dayofyear::create(THD *thd,
Create_func_decode Create_func_decode::s_singleton;
Item*
-Create_func_decode::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_decode::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_decode(arg1, arg2);
}
@@ -3029,7 +3029,7 @@ Create_func_decode::create(THD *thd, Ite
Create_func_degrees Create_func_degrees::s_singleton;
Item*
-Create_func_degrees::create(THD *thd, Item *arg1)
+Create_func_degrees::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_units((char*) "degrees", arg1,
180/M_PI, 0.0);
@@ -3114,7 +3114,7 @@ Create_func_des_encrypt::create_native(T
Create_func_dimension Create_func_dimension::s_singleton;
Item*
-Create_func_dimension::create(THD *thd, Item *arg1)
+Create_func_dimension::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_dimension(arg1);
}
@@ -3125,7 +3125,7 @@ Create_func_dimension::create(THD *thd,
Create_func_disjoint Create_func_disjoint::s_singleton;
Item*
-Create_func_disjoint::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_disjoint::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_spatial_rel(arg1, arg2,
Item_func::SP_DISJOINT_FUNC);
@@ -3157,7 +3157,7 @@ Create_func_elt::create_native(THD *thd,
Create_func_encode Create_func_encode::s_singleton;
Item*
-Create_func_encode::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_encode::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_encode(arg1, arg2);
}
@@ -3205,7 +3205,7 @@ Create_func_encrypt::create_native(THD *
Create_func_endpoint Create_func_endpoint::s_singleton;
Item*
-Create_func_endpoint::create(THD *thd, Item *arg1)
+Create_func_endpoint::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_spatial_decomp(arg1,
Item_func::SP_ENDPOINT);
@@ -3217,7 +3217,7 @@ Create_func_endpoint::create(THD *thd, I
Create_func_envelope Create_func_envelope::s_singleton;
Item*
-Create_func_envelope::create(THD *thd, Item *arg1)
+Create_func_envelope::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_envelope(arg1);
}
@@ -3228,7 +3228,7 @@ Create_func_envelope::create(THD *thd, I
Create_func_equals Create_func_equals::s_singleton;
Item*
-Create_func_equals::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_equals::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_spatial_rel(arg1, arg2,
Item_func::SP_EQUALS_FUNC);
@@ -3239,7 +3239,7 @@ Create_func_equals::create(THD *thd, Ite
Create_func_exp Create_func_exp::s_singleton;
Item*
-Create_func_exp::create(THD *thd, Item *arg1)
+Create_func_exp::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_exp(arg1);
}
@@ -3302,7 +3302,7 @@ Create_func_export_set::create_native(TH
Create_func_exteriorring Create_func_exteriorring::s_singleton;
Item*
-Create_func_exteriorring::create(THD *thd, Item *arg1)
+Create_func_exteriorring::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_spatial_decomp(arg1,
Item_func::SP_EXTERIORRING);
@@ -3334,7 +3334,7 @@ Create_func_field::create_native(THD *th
Create_func_find_in_set Create_func_find_in_set::s_singleton;
Item*
-Create_func_find_in_set::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_find_in_set::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_find_in_set(arg1, arg2);
}
@@ -3343,7 +3343,7 @@ Create_func_find_in_set::create(THD *thd
Create_func_floor Create_func_floor::s_singleton;
Item*
-Create_func_floor::create(THD *thd, Item *arg1)
+Create_func_floor::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_floor(arg1);
}
@@ -3352,7 +3352,7 @@ Create_func_floor::create(THD *thd, Item
Create_func_format Create_func_format::s_singleton;
Item*
-Create_func_format::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_format::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_format(arg1, arg2);
}
@@ -3372,7 +3372,7 @@ Create_func_found_rows::create(THD *thd)
Create_func_from_days Create_func_from_days::s_singleton;
Item*
-Create_func_from_days::create(THD *thd, Item *arg1)
+Create_func_from_days::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_from_days(arg1);
}
@@ -3500,7 +3500,7 @@ Create_func_geometry_from_wkb::create_na
Create_func_geometry_type Create_func_geometry_type::s_singleton;
Item*
-Create_func_geometry_type::create(THD *thd, Item *arg1)
+Create_func_geometry_type::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_geometry_type(arg1);
}
@@ -3511,7 +3511,7 @@ Create_func_geometry_type::create(THD *t
Create_func_geometryn Create_func_geometryn::s_singleton;
Item*
-Create_func_geometryn::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_geometryn::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_spatial_decomp_n(arg1, arg2,
Item_func::SP_GEOMETRYN);
@@ -3522,7 +3522,7 @@ Create_func_geometryn::create(THD *thd,
Create_func_get_lock Create_func_get_lock::s_singleton;
Item*
-Create_func_get_lock::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_get_lock::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
thd->lex->set_stmt_unsafe();
thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
@@ -3534,7 +3534,7 @@ Create_func_get_lock::create(THD *thd, I
Create_func_glength Create_func_glength::s_singleton;
Item*
-Create_func_glength::create(THD *thd, Item *arg1)
+Create_func_glength::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_glength(arg1);
}
@@ -3565,7 +3565,7 @@ Create_func_greatest::create_native(THD
Create_func_hex Create_func_hex::s_singleton;
Item*
-Create_func_hex::create(THD *thd, Item *arg1)
+Create_func_hex::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_hex(arg1);
}
@@ -3574,7 +3574,7 @@ Create_func_hex::create(THD *thd, Item *
Create_func_ifnull Create_func_ifnull::s_singleton;
Item*
-Create_func_ifnull::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_ifnull::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_ifnull(arg1, arg2);
}
@@ -3583,7 +3583,7 @@ Create_func_ifnull::create(THD *thd, Ite
Create_func_inet_ntoa Create_func_inet_ntoa::s_singleton;
Item*
-Create_func_inet_ntoa::create(THD *thd, Item *arg1)
+Create_func_inet_ntoa::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_inet_ntoa(arg1);
}
@@ -3592,7 +3592,7 @@ Create_func_inet_ntoa::create(THD *thd,
Create_func_inet_aton Create_func_inet_aton::s_singleton;
Item*
-Create_func_inet_aton::create(THD *thd, Item *arg1)
+Create_func_inet_aton::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_inet_aton(arg1);
}
@@ -3601,7 +3601,7 @@ Create_func_inet_aton::create(THD *thd,
Create_func_instr Create_func_instr::s_singleton;
Item*
-Create_func_instr::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_instr::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_locate(arg1, arg2);
}
@@ -3611,7 +3611,7 @@ Create_func_instr::create(THD *thd, Item
Create_func_interiorringn Create_func_interiorringn::s_singleton;
Item*
-Create_func_interiorringn::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_interiorringn::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_spatial_decomp_n(arg1, arg2,
Item_func::SP_INTERIORRINGN);
@@ -3623,7 +3623,7 @@ Create_func_interiorringn::create(THD *t
Create_func_intersects Create_func_intersects::s_singleton;
Item*
-Create_func_intersects::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_intersects::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_spatial_rel(arg1, arg2,
Item_func::SP_INTERSECTS_FUNC);
@@ -3634,7 +3634,7 @@ Create_func_intersects::create(THD *thd,
Create_func_is_free_lock Create_func_is_free_lock::s_singleton;
Item*
-Create_func_is_free_lock::create(THD *thd, Item *arg1)
+Create_func_is_free_lock::create_1_arg(THD *thd, Item *arg1)
{
thd->lex->set_stmt_unsafe();
thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
@@ -3645,7 +3645,7 @@ Create_func_is_free_lock::create(THD *th
Create_func_is_used_lock Create_func_is_used_lock::s_singleton;
Item*
-Create_func_is_used_lock::create(THD *thd, Item *arg1)
+Create_func_is_used_lock::create_1_arg(THD *thd, Item *arg1)
{
thd->lex->set_stmt_unsafe();
thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
@@ -3657,7 +3657,7 @@ Create_func_is_used_lock::create(THD *th
Create_func_isclosed Create_func_isclosed::s_singleton;
Item*
-Create_func_isclosed::create(THD *thd, Item *arg1)
+Create_func_isclosed::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_isclosed(arg1);
}
@@ -3668,7 +3668,7 @@ Create_func_isclosed::create(THD *thd, I
Create_func_isempty Create_func_isempty::s_singleton;
Item*
-Create_func_isempty::create(THD *thd, Item *arg1)
+Create_func_isempty::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_isempty(arg1);
}
@@ -3678,7 +3678,7 @@ Create_func_isempty::create(THD *thd, It
Create_func_isnull Create_func_isnull::s_singleton;
Item*
-Create_func_isnull::create(THD *thd, Item *arg1)
+Create_func_isnull::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_isnull(arg1);
}
@@ -3688,7 +3688,7 @@ Create_func_isnull::create(THD *thd, Ite
Create_func_issimple Create_func_issimple::s_singleton;
Item*
-Create_func_issimple::create(THD *thd, Item *arg1)
+Create_func_issimple::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_issimple(arg1);
}
@@ -3698,7 +3698,7 @@ Create_func_issimple::create(THD *thd, I
Create_func_last_day Create_func_last_day::s_singleton;
Item*
-Create_func_last_day::create(THD *thd, Item *arg1)
+Create_func_last_day::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_last_day(arg1);
}
@@ -3744,7 +3744,7 @@ Create_func_last_insert_id::create_nativ
Create_func_lcase Create_func_lcase::s_singleton;
Item*
-Create_func_lcase::create(THD *thd, Item *arg1)
+Create_func_lcase::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_lcase(arg1);
}
@@ -3774,7 +3774,7 @@ Create_func_least::create_native(THD *th
Create_func_length Create_func_length::s_singleton;
Item*
-Create_func_length::create(THD *thd, Item *arg1)
+Create_func_length::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_length(arg1);
}
@@ -3783,7 +3783,7 @@ Create_func_length::create(THD *thd, Ite
Create_func_ln Create_func_ln::s_singleton;
Item*
-Create_func_ln::create(THD *thd, Item *arg1)
+Create_func_ln::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_ln(arg1);
}
@@ -3792,7 +3792,7 @@ Create_func_ln::create(THD *thd, Item *a
Create_func_load_file Create_func_load_file::s_singleton;
Item*
-Create_func_load_file::create(THD *thd, Item *arg1)
+Create_func_load_file::create_1_arg(THD *thd, Item *arg1)
{
thd->lex->set_stmt_unsafe();
thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
@@ -3881,7 +3881,7 @@ Create_func_log::create_native(THD *thd,
Create_func_log10 Create_func_log10::s_singleton;
Item*
-Create_func_log10::create(THD *thd, Item *arg1)
+Create_func_log10::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_log10(arg1);
}
@@ -3890,7 +3890,7 @@ Create_func_log10::create(THD *thd, Item
Create_func_log2 Create_func_log2::s_singleton;
Item*
-Create_func_log2::create(THD *thd, Item *arg1)
+Create_func_log2::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_log2(arg1);
}
@@ -3899,7 +3899,7 @@ Create_func_log2::create(THD *thd, Item
Create_func_lpad Create_func_lpad::s_singleton;
Item*
-Create_func_lpad::create(THD *thd, Item *arg1, Item *arg2, Item *arg3)
+Create_func_lpad::create_3_arg(THD *thd, Item *arg1, Item *arg2, Item *arg3)
{
return new (thd->mem_root) Item_func_lpad(arg1, arg2, arg3);
}
@@ -3908,7 +3908,7 @@ Create_func_lpad::create(THD *thd, Item
Create_func_ltrim Create_func_ltrim::s_singleton;
Item*
-Create_func_ltrim::create(THD *thd, Item *arg1)
+Create_func_ltrim::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_ltrim(arg1);
}
@@ -3917,7 +3917,7 @@ Create_func_ltrim::create(THD *thd, Item
Create_func_makedate Create_func_makedate::s_singleton;
Item*
-Create_func_makedate::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_makedate::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_makedate(arg1, arg2);
}
@@ -3926,7 +3926,7 @@ Create_func_makedate::create(THD *thd, I
Create_func_maketime Create_func_maketime::s_singleton;
Item*
-Create_func_maketime::create(THD *thd, Item *arg1, Item *arg2, Item *arg3)
+Create_func_maketime::create_3_arg(THD *thd, Item *arg1, Item *arg2, Item *arg3)
{
return new (thd->mem_root) Item_func_maketime(arg1, arg2, arg3);
}
@@ -4001,7 +4001,7 @@ Create_func_master_pos_wait::create_nati
Create_func_md5 Create_func_md5::s_singleton;
Item*
-Create_func_md5::create(THD *thd, Item *arg1)
+Create_func_md5::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_md5(arg1);
}
@@ -4010,7 +4010,7 @@ Create_func_md5::create(THD *thd, Item *
Create_func_monthname Create_func_monthname::s_singleton;
Item*
-Create_func_monthname::create(THD *thd, Item *arg1)
+Create_func_monthname::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_monthname(arg1);
}
@@ -4019,7 +4019,7 @@ Create_func_monthname::create(THD *thd,
Create_func_name_const Create_func_name_const::s_singleton;
Item*
-Create_func_name_const::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_name_const::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_name_const(arg1, arg2);
}
@@ -4028,7 +4028,7 @@ Create_func_name_const::create(THD *thd,
Create_func_nullif Create_func_nullif::s_singleton;
Item*
-Create_func_nullif::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_nullif::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_nullif(arg1, arg2);
}
@@ -4038,7 +4038,7 @@ Create_func_nullif::create(THD *thd, Ite
Create_func_numgeometries Create_func_numgeometries::s_singleton;
Item*
-Create_func_numgeometries::create(THD *thd, Item *arg1)
+Create_func_numgeometries::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_numgeometries(arg1);
}
@@ -4049,7 +4049,7 @@ Create_func_numgeometries::create(THD *t
Create_func_numinteriorring Create_func_numinteriorring::s_singleton;
Item*
-Create_func_numinteriorring::create(THD *thd, Item *arg1)
+Create_func_numinteriorring::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_numinteriorring(arg1);
}
@@ -4060,7 +4060,7 @@ Create_func_numinteriorring::create(THD
Create_func_numpoints Create_func_numpoints::s_singleton;
Item*
-Create_func_numpoints::create(THD *thd, Item *arg1)
+Create_func_numpoints::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_numpoints(arg1);
}
@@ -4070,7 +4070,7 @@ Create_func_numpoints::create(THD *thd,
Create_func_oct Create_func_oct::s_singleton;
Item*
-Create_func_oct::create(THD *thd, Item *arg1)
+Create_func_oct::create_1_arg(THD *thd, Item *arg1)
{
Item *i10= new (thd->mem_root) Item_int((int32) 10,2);
Item *i8= new (thd->mem_root) Item_int((int32) 8,1);
@@ -4081,7 +4081,7 @@ Create_func_oct::create(THD *thd, Item *
Create_func_ord Create_func_ord::s_singleton;
Item*
-Create_func_ord::create(THD *thd, Item *arg1)
+Create_func_ord::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_ord(arg1);
}
@@ -4091,7 +4091,7 @@ Create_func_ord::create(THD *thd, Item *
Create_func_overlaps Create_func_overlaps::s_singleton;
Item*
-Create_func_overlaps::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_overlaps::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_spatial_rel(arg1, arg2,
Item_func::SP_OVERLAPS_FUNC);
@@ -4102,7 +4102,7 @@ Create_func_overlaps::create(THD *thd, I
Create_func_period_add Create_func_period_add::s_singleton;
Item*
-Create_func_period_add::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_period_add::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_period_add(arg1, arg2);
}
@@ -4111,7 +4111,7 @@ Create_func_period_add::create(THD *thd,
Create_func_period_diff Create_func_period_diff::s_singleton;
Item*
-Create_func_period_diff::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_period_diff::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_period_diff(arg1, arg2);
}
@@ -4130,7 +4130,7 @@ Create_func_pi::create(THD *thd)
Create_func_pointn Create_func_pointn::s_singleton;
Item*
-Create_func_pointn::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_pointn::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_spatial_decomp_n(arg1, arg2,
Item_func::SP_POINTN);
@@ -4141,7 +4141,7 @@ Create_func_pointn::create(THD *thd, Ite
Create_func_pow Create_func_pow::s_singleton;
Item*
-Create_func_pow::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_pow::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_pow(arg1, arg2);
}
@@ -4150,7 +4150,7 @@ Create_func_pow::create(THD *thd, Item *
Create_func_quote Create_func_quote::s_singleton;
Item*
-Create_func_quote::create(THD *thd, Item *arg1)
+Create_func_quote::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_quote(arg1);
}
@@ -4159,7 +4159,7 @@ Create_func_quote::create(THD *thd, Item
Create_func_radians Create_func_radians::s_singleton;
Item*
-Create_func_radians::create(THD *thd, Item *arg1)
+Create_func_radians::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_units((char*) "radians", arg1,
M_PI/180, 0.0);
@@ -4216,7 +4216,7 @@ Create_func_rand::create_native(THD *thd
Create_func_release_lock Create_func_release_lock::s_singleton;
Item*
-Create_func_release_lock::create(THD *thd, Item *arg1)
+Create_func_release_lock::create_1_arg(THD *thd, Item *arg1)
{
thd->lex->set_stmt_unsafe();
thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
@@ -4227,7 +4227,7 @@ Create_func_release_lock::create(THD *th
Create_func_reverse Create_func_reverse::s_singleton;
Item*
-Create_func_reverse::create(THD *thd, Item *arg1)
+Create_func_reverse::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_reverse(arg1);
}
@@ -4285,7 +4285,7 @@ Create_func_row_count::create(THD *thd)
Create_func_rpad Create_func_rpad::s_singleton;
Item*
-Create_func_rpad::create(THD *thd, Item *arg1, Item *arg2, Item *arg3)
+Create_func_rpad::create_3_arg(THD *thd, Item *arg1, Item *arg2, Item *arg3)
{
return new (thd->mem_root) Item_func_rpad(arg1, arg2, arg3);
}
@@ -4294,7 +4294,7 @@ Create_func_rpad::create(THD *thd, Item
Create_func_rtrim Create_func_rtrim::s_singleton;
Item*
-Create_func_rtrim::create(THD *thd, Item *arg1)
+Create_func_rtrim::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_rtrim(arg1);
}
@@ -4303,7 +4303,7 @@ Create_func_rtrim::create(THD *thd, Item
Create_func_sec_to_time Create_func_sec_to_time::s_singleton;
Item*
-Create_func_sec_to_time::create(THD *thd, Item *arg1)
+Create_func_sec_to_time::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_sec_to_time(arg1);
}
@@ -4312,7 +4312,7 @@ Create_func_sec_to_time::create(THD *thd
Create_func_sha Create_func_sha::s_singleton;
Item*
-Create_func_sha::create(THD *thd, Item *arg1)
+Create_func_sha::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_sha(arg1);
}
@@ -4321,7 +4321,7 @@ Create_func_sha::create(THD *thd, Item *
Create_func_sign Create_func_sign::s_singleton;
Item*
-Create_func_sign::create(THD *thd, Item *arg1)
+Create_func_sign::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_sign(arg1);
}
@@ -4330,7 +4330,7 @@ Create_func_sign::create(THD *thd, Item
Create_func_sin Create_func_sin::s_singleton;
Item*
-Create_func_sin::create(THD *thd, Item *arg1)
+Create_func_sin::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_sin(arg1);
}
@@ -4339,7 +4339,7 @@ Create_func_sin::create(THD *thd, Item *
Create_func_sleep Create_func_sleep::s_singleton;
Item*
-Create_func_sleep::create(THD *thd, Item *arg1)
+Create_func_sleep::create_1_arg(THD *thd, Item *arg1)
{
thd->lex->set_stmt_unsafe();
thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
@@ -4350,7 +4350,7 @@ Create_func_sleep::create(THD *thd, Item
Create_func_soundex Create_func_soundex::s_singleton;
Item*
-Create_func_soundex::create(THD *thd, Item *arg1)
+Create_func_soundex::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_soundex(arg1);
}
@@ -4359,7 +4359,7 @@ Create_func_soundex::create(THD *thd, It
Create_func_space Create_func_space::s_singleton;
Item*
-Create_func_space::create(THD *thd, Item *arg1)
+Create_func_space::create_1_arg(THD *thd, Item *arg1)
{
/**
TODO: Fix Bug#23637
@@ -4387,7 +4387,7 @@ Create_func_space::create(THD *thd, Item
Create_func_sqrt Create_func_sqrt::s_singleton;
Item*
-Create_func_sqrt::create(THD *thd, Item *arg1)
+Create_func_sqrt::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_sqrt(arg1);
}
@@ -4397,7 +4397,7 @@ Create_func_sqrt::create(THD *thd, Item
Create_func_srid Create_func_srid::s_singleton;
Item*
-Create_func_srid::create(THD *thd, Item *arg1)
+Create_func_srid::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_srid(arg1);
}
@@ -4408,7 +4408,7 @@ Create_func_srid::create(THD *thd, Item
Create_func_startpoint Create_func_startpoint::s_singleton;
Item*
-Create_func_startpoint::create(THD *thd, Item *arg1)
+Create_func_startpoint::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_spatial_decomp(arg1,
Item_func::SP_STARTPOINT);
@@ -4419,7 +4419,7 @@ Create_func_startpoint::create(THD *thd,
Create_func_str_to_date Create_func_str_to_date::s_singleton;
Item*
-Create_func_str_to_date::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_str_to_date::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_str_to_date(arg1, arg2);
}
@@ -4428,7 +4428,7 @@ Create_func_str_to_date::create(THD *thd
Create_func_strcmp Create_func_strcmp::s_singleton;
Item*
-Create_func_strcmp::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_strcmp::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_strcmp(arg1, arg2);
}
@@ -4437,7 +4437,7 @@ Create_func_strcmp::create(THD *thd, Ite
Create_func_substr_index Create_func_substr_index::s_singleton;
Item*
-Create_func_substr_index::create(THD *thd, Item *arg1, Item *arg2, Item *arg3)
+Create_func_substr_index::create_3_arg(THD *thd, Item *arg1, Item *arg2, Item *arg3)
{
return new (thd->mem_root) Item_func_substr_index(arg1, arg2, arg3);
}
@@ -4446,7 +4446,7 @@ Create_func_substr_index::create(THD *th
Create_func_subtime Create_func_subtime::s_singleton;
Item*
-Create_func_subtime::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_subtime::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_add_time(arg1, arg2, 0, 1);
}
@@ -4455,7 +4455,7 @@ Create_func_subtime::create(THD *thd, It
Create_func_tan Create_func_tan::s_singleton;
Item*
-Create_func_tan::create(THD *thd, Item *arg1)
+Create_func_tan::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_tan(arg1);
}
@@ -4464,7 +4464,7 @@ Create_func_tan::create(THD *thd, Item *
Create_func_time_format Create_func_time_format::s_singleton;
Item*
-Create_func_time_format::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_time_format::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_date_format(arg1, arg2, 1);
}
@@ -4473,7 +4473,7 @@ Create_func_time_format::create(THD *thd
Create_func_time_to_sec Create_func_time_to_sec::s_singleton;
Item*
-Create_func_time_to_sec::create(THD *thd, Item *arg1)
+Create_func_time_to_sec::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_time_to_sec(arg1);
}
@@ -4482,7 +4482,7 @@ Create_func_time_to_sec::create(THD *thd
Create_func_timediff Create_func_timediff::s_singleton;
Item*
-Create_func_timediff::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_timediff::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_timediff(arg1, arg2);
}
@@ -4491,7 +4491,7 @@ Create_func_timediff::create(THD *thd, I
Create_func_to_days Create_func_to_days::s_singleton;
Item*
-Create_func_to_days::create(THD *thd, Item *arg1)
+Create_func_to_days::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_to_days(arg1);
}
@@ -4501,7 +4501,7 @@ Create_func_to_days::create(THD *thd, It
Create_func_touches Create_func_touches::s_singleton;
Item*
-Create_func_touches::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_touches::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_spatial_rel(arg1, arg2,
Item_func::SP_TOUCHES_FUNC);
@@ -4512,7 +4512,7 @@ Create_func_touches::create(THD *thd, It
Create_func_ucase Create_func_ucase::s_singleton;
Item*
-Create_func_ucase::create(THD *thd, Item *arg1)
+Create_func_ucase::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_ucase(arg1);
}
@@ -4521,7 +4521,7 @@ Create_func_ucase::create(THD *thd, Item
Create_func_uncompress Create_func_uncompress::s_singleton;
Item*
-Create_func_uncompress::create(THD *thd, Item *arg1)
+Create_func_uncompress::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_uncompress(arg1);
}
@@ -4530,7 +4530,7 @@ Create_func_uncompress::create(THD *thd,
Create_func_uncompressed_length Create_func_uncompressed_length::s_singleton;
Item*
-Create_func_uncompressed_length::create(THD *thd, Item *arg1)
+Create_func_uncompressed_length::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_uncompressed_length(arg1);
}
@@ -4539,7 +4539,7 @@ Create_func_uncompressed_length::create(
Create_func_unhex Create_func_unhex::s_singleton;
Item*
-Create_func_unhex::create(THD *thd, Item *arg1)
+Create_func_unhex::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_unhex(arg1);
}
@@ -4620,7 +4620,7 @@ Create_func_version::create(THD *thd)
Create_func_weekday Create_func_weekday::s_singleton;
Item*
-Create_func_weekday::create(THD *thd, Item *arg1)
+Create_func_weekday::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_weekday(arg1, 0);
}
@@ -4629,7 +4629,7 @@ Create_func_weekday::create(THD *thd, It
Create_func_weekofyear Create_func_weekofyear::s_singleton;
Item*
-Create_func_weekofyear::create(THD *thd, Item *arg1)
+Create_func_weekofyear::create_1_arg(THD *thd, Item *arg1)
{
Item *i1= new (thd->mem_root) Item_int((char*) "0", 3, 1);
return new (thd->mem_root) Item_func_week(arg1, i1);
@@ -4640,7 +4640,7 @@ Create_func_weekofyear::create(THD *thd,
Create_func_within Create_func_within::s_singleton;
Item*
-Create_func_within::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_within::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_spatial_rel(arg1, arg2,
Item_func::SP_WITHIN_FUNC);
@@ -4652,7 +4652,7 @@ Create_func_within::create(THD *thd, Ite
Create_func_x Create_func_x::s_singleton;
Item*
-Create_func_x::create(THD *thd, Item *arg1)
+Create_func_x::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_x(arg1);
}
@@ -4662,7 +4662,7 @@ Create_func_x::create(THD *thd, Item *ar
Create_func_xml_extractvalue Create_func_xml_extractvalue::s_singleton;
Item*
-Create_func_xml_extractvalue::create(THD *thd, Item *arg1, Item *arg2)
+Create_func_xml_extractvalue::create_2_arg(THD *thd, Item *arg1, Item *arg2)
{
return new (thd->mem_root) Item_func_xml_extractvalue(arg1, arg2);
}
@@ -4671,7 +4671,7 @@ Create_func_xml_extractvalue::create(THD
Create_func_xml_update Create_func_xml_update::s_singleton;
Item*
-Create_func_xml_update::create(THD *thd, Item *arg1, Item *arg2, Item *arg3)
+Create_func_xml_update::create_3_arg(THD *thd, Item *arg1, Item *arg2, Item *arg3)
{
return new (thd->mem_root) Item_func_xml_update(arg1, arg2, arg3);
}
@@ -4681,7 +4681,7 @@ Create_func_xml_update::create(THD *thd,
Create_func_y Create_func_y::s_singleton;
Item*
-Create_func_y::create(THD *thd, Item *arg1)
+Create_func_y::create_1_arg(THD *thd, Item *arg1)
{
return new (thd->mem_root) Item_func_y(arg1);
}
=== modified file 'sql/item_create.h'
--- a/sql/item_create.h 2007-08-15 13:43:08 +0000
+++ b/sql/item_create.h 2010-03-28 18:10:00 +0000
@@ -91,8 +91,9 @@ public:
@param item_list The list of arguments to the function, can be NULL
@return An item representing the parsed function call
*/
- virtual Item* create(THD *thd, LEX_STRING db, LEX_STRING name,
- bool use_explicit_name, List<Item> *item_list) = 0;
+ virtual Item *create_with_db(THD *thd, LEX_STRING db, LEX_STRING name,
+ bool use_explicit_name,
+ List<Item> *item_list) = 0;
protected:
/** Constructor. */
=== modified file 'sql/item_sum.cc'
--- a/sql/item_sum.cc 2010-01-15 15:27:55 +0000
+++ b/sql/item_sum.cc 2010-03-28 18:10:00 +0000
@@ -642,7 +642,7 @@ Item_sum_hybrid::fix_fields(THD *thd, It
default:
DBUG_ASSERT(0);
};
- setup(args[0], NULL);
+ setup_item(args[0], NULL);
/* MIN/MAX can return NULL for empty set indepedent of the used column */
maybe_null= 1;
unsigned_flag=item->unsigned_flag;
@@ -676,7 +676,7 @@ Item_sum_hybrid::fix_fields(THD *thd, It
of the original MIN/MAX object and it is saved in this object's cache.
*/
-void Item_sum_hybrid::setup(Item *item, Item *value_arg)
+void Item_sum_hybrid::setup_item(Item *item, Item *value_arg)
{
value= Item_cache::get_cache(item);
value->setup(item);
@@ -1646,7 +1646,7 @@ void Item_sum_hybrid::no_rows_in_result(
Item *Item_sum_min::copy_or_same(THD* thd)
{
Item_sum_min *item= new (thd->mem_root) Item_sum_min(thd, this);
- item->setup(args[0], value);
+ item->setup_item(args[0], value);
return item;
}
@@ -1669,7 +1669,7 @@ bool Item_sum_min::add()
Item *Item_sum_max::copy_or_same(THD* thd)
{
Item_sum_max *item= new (thd->mem_root) Item_sum_max(thd, this);
- item->setup(args[0], value);
+ item->setup_item(args[0], value);
return item;
}
=== modified file 'sql/item_sum.h'
--- a/sql/item_sum.h 2010-01-15 15:27:55 +0000
+++ b/sql/item_sum.h 2010-03-28 18:10:00 +0000
@@ -858,7 +858,7 @@ protected:
was_values(item->was_values)
{ }
bool fix_fields(THD *, Item **);
- void setup(Item *item, Item *value_arg);
+ void setup_item(Item *item, Item *value_arg);
void clear();
double val_real();
longlong val_int();
=== modified file 'sql/set_var.cc'
--- a/sql/set_var.cc 2010-03-09 19:23:30 +0000
+++ b/sql/set_var.cc 2010-03-28 18:10:00 +0000
@@ -1263,16 +1263,16 @@ uchar *sys_var_set::value_ptr(THD *thd,
void sys_var_set_slave_mode::set_default(THD *thd, enum_var_type type)
{
- slave_exec_mode_options= 0;
- bit_do_set(slave_exec_mode_options, SLAVE_EXEC_MODE_STRICT);
+ slave_exec_mode_options= (ULL(1) << SLAVE_EXEC_MODE_STRICT);
}
bool sys_var_set_slave_mode::check(THD *thd, set_var *var)
{
bool rc= sys_var_set::check(thd, var);
if (!rc &&
- bit_is_set(var->save_result.ulong_value, SLAVE_EXEC_MODE_STRICT) == 1 &&
- bit_is_set(var->save_result.ulong_value, SLAVE_EXEC_MODE_IDEMPOTENT) == 1)
+ test_all_bits(var->save_result.ulong_value,
+ ((ULL(1) << SLAVE_EXEC_MODE_STRICT) |
+ (ULL(1) << SLAVE_EXEC_MODE_IDEMPOTENT))))
{
rc= true;
my_error(ER_SLAVE_AMBIGOUS_EXEC_MODE, MYF(0), "");
@@ -1294,15 +1294,16 @@ void fix_slave_exec_mode(enum_var_type t
DBUG_ENTER("fix_slave_exec_mode");
compile_time_assert(sizeof(slave_exec_mode_options) * CHAR_BIT
> SLAVE_EXEC_MODE_LAST_BIT - 1);
- if (bit_is_set(slave_exec_mode_options, SLAVE_EXEC_MODE_STRICT) == 1 &&
- bit_is_set(slave_exec_mode_options, SLAVE_EXEC_MODE_IDEMPOTENT) == 1)
+ if (test_all_bits(slave_exec_mode_options,
+ ((ULL(1) << SLAVE_EXEC_MODE_STRICT) |
+ (ULL(1) << SLAVE_EXEC_MODE_IDEMPOTENT))))
{
sql_print_error("Ambiguous slave modes combination."
" STRICT will be used");
- bit_do_clear(slave_exec_mode_options, SLAVE_EXEC_MODE_IDEMPOTENT);
+ slave_exec_mode_options&= ~(ULL(1) << SLAVE_EXEC_MODE_IDEMPOTENT);
}
- if (bit_is_set(slave_exec_mode_options, SLAVE_EXEC_MODE_IDEMPOTENT) == 0)
- bit_do_set(slave_exec_mode_options, SLAVE_EXEC_MODE_STRICT);
+ if (!(slave_exec_mode_options & (ULL(1) << SLAVE_EXEC_MODE_IDEMPOTENT)))
+ slave_exec_mode_options|= (ULL(1)<< SLAVE_EXEC_MODE_STRICT);
DBUG_VOID_RETURN;
}
=== modified file 'sql/sql_yacc.yy'
--- a/sql/sql_yacc.yy 2010-03-04 08:03:07 +0000
+++ b/sql/sql_yacc.yy 2010-03-28 18:10:00 +0000
@@ -8082,7 +8082,7 @@ function_call_generic:
builder= find_qualified_function_builder(thd);
DBUG_ASSERT(builder);
- item= builder->create(thd, $1, $3, true, $5);
+ item= builder->create_with_db(thd, $1, $3, true, $5);
if (! ($$= item))
{
=== modified file 'storage/example/ha_example.h'
--- a/storage/example/ha_example.h 2007-08-13 13:11:25 +0000
+++ b/storage/example/ha_example.h 2010-03-28 18:10:00 +0000
@@ -155,7 +155,8 @@ public:
/** @brief
This method will never be called if you do not implement indexes.
*/
- virtual double read_time(ha_rows rows) { return (double) rows / 20.0+1; }
+ virtual double read_time(uint index, uint ranges, ha_rows rows)
+ { return (double) rows / 20.0+1; }
/*
Everything below are methods that we implement in ha_example.cc.
=== modified file 'storage/maria/ma_search.c'
--- a/storage/maria/ma_search.c 2010-03-09 19:22:24 +0000
+++ b/storage/maria/ma_search.c 2010-03-28 18:10:00 +0000
@@ -76,8 +76,8 @@ int _ma_search(register MARIA_HA *info,
bmove512(info->keyread_buff, page_buff, info->s->block_size);
/* Save position for a possible read next / previous */
- info->int_keypos= info->keyread_buff + (ulonglong) info->int_keypos;
- info->int_maxpos= info->keyread_buff + (ulonglong) info->int_maxpos;
+ info->int_keypos= info->keyread_buff + info->keypos_offset;
+ info->int_maxpos= info->keyread_buff + info->maxpos_offset;
info->int_keytree_version= key->keyinfo->version;
info->last_search_keypage= info->last_keypage;
info->page_changed= 0;
@@ -214,8 +214,8 @@ static int _ma_search_no_save(register M
info->cur_row.trid= _ma_trid_from_key(&info->last_key);
/* Store offset to key */
- info->int_keypos= (uchar*) (keypos - page.buff);
- info->int_maxpos= (uchar*) (maxpos - page.buff);
+ info->keypos_offset= (uint) (keypos - page.buff);
+ info->maxpos_offset= (uint) (maxpos - page.buff);
info->int_nod_flag= nod_flag;
info->last_keypage= pos;
*res_page_link= page_link;
=== modified file 'storage/maria/maria_def.h'
--- a/storage/maria/maria_def.h 2010-03-09 19:22:24 +0000
+++ b/storage/maria/maria_def.h 2010-03-28 18:10:00 +0000
@@ -506,8 +506,10 @@ struct st_maria_handler
uchar *first_mbr_key; /* Searhed spatial key */
uchar *rec_buff; /* Temp buffer for recordpack */
uchar *blob_buff; /* Temp buffer for blobs */
- uchar *int_keypos, /* Save position for next/previous */
- *int_maxpos; /* -""- */
+ uchar *int_keypos; /* Save position for next/previous */
+ uchar *int_maxpos; /* -""- */
+ uint keypos_offset; /* Tmp storage for offset int_keypos */
+ uint maxpos_offset; /* Tmp storage for offset int_maxpos */
uchar *update_field_data; /* Used by update in rows-in-block */
uint int_nod_flag; /* -""- */
uint32 int_keytree_version; /* -""- */
=== modified file 'storage/myisam/ft_stopwords.c'
--- a/storage/myisam/ft_stopwords.c 2010-03-10 10:32:14 +0000
+++ b/storage/myisam/ft_stopwords.c 2010-03-28 18:10:00 +0000
@@ -44,9 +44,10 @@ static void FT_STOPWORD_free(FT_STOPWORD
static int ft_add_stopword(const char *w)
{
FT_STOPWORD sw;
- return !w ||
- (((sw.len= (uint) strlen(sw.pos=(const uchar *)w)) >= ft_min_word_len) &&
- (tree_insert(stopwords3, &sw, 0, stopwords3->custom_arg)==NULL));
+ return (!w ||
+ (((sw.len= (uint) strlen((char*) (sw.pos=(const uchar *)w))) >=
+ ft_min_word_len) &&
+ (tree_insert(stopwords3, &sw, 0, stopwords3->custom_arg)==NULL)));
}
int ft_init_stopwords()
=== modified file 'storage/xtradb/fil/fil0fil.c'
--- a/storage/xtradb/fil/fil0fil.c 2010-01-15 15:58:25 +0000
+++ b/storage/xtradb/fil/fil0fil.c 2010-03-28 18:10:00 +0000
@@ -3168,7 +3168,7 @@ skip_info:
mach_write_to_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, id);
for (i = 0; (ulint) i < n_index; i++) {
- if (offset / UNIV_PAGE_SIZE == root_page[i]) {
+ if ((ulint) (offset / UNIV_PAGE_SIZE) == root_page[i]) {
/* this is index root page */
mach_write_to_4(page + FIL_PAGE_DATA + PAGE_BTR_SEG_LEAF
+ FSEG_HDR_SPACE, id);
=== modified file 'storage/xtradb/include/page0page.h'
--- a/storage/xtradb/include/page0page.h 2010-01-06 12:00:14 +0000
+++ b/storage/xtradb/include/page0page.h 2010-03-28 18:10:00 +0000
@@ -517,7 +517,7 @@ UNIV_INLINE
rec_t*
page_rec_get_next(
/*==============*/
- rec_t* rec); /*!< in: pointer to record */
+ const rec_t* rec); /*!< in: pointer to record */
/************************************************************//**
Gets the pointer to the next record on the page.
@return pointer to next record */
=== modified file 'storage/xtradb/include/page0page.ic'
--- a/storage/xtradb/include/page0page.ic 2010-01-06 12:00:14 +0000
+++ b/storage/xtradb/include/page0page.ic 2010-03-28 18:10:00 +0000
@@ -731,7 +731,7 @@ UNIV_INLINE
rec_t*
page_rec_get_next(
/*==============*/
- rec_t* rec) /*!< in: pointer to record */
+ const rec_t* rec) /*!< in: pointer to record */
{
return((rec_t*) page_rec_get_next_low(rec, page_rec_is_comp(rec)));
}
=== modified file 'support-files/compiler_warnings.supp'
--- a/support-files/compiler_warnings.supp 2010-03-10 10:32:14 +0000
+++ b/support-files/compiler_warnings.supp 2010-03-28 18:10:00 +0000
@@ -66,6 +66,11 @@ db_vrfy.c : .*comparison is always false
/usr/share/aclocal/audiofile.m4 : .*
#
+# Ignore strict-aliasing warnings (for now)
+#
+.*: break strict-aliasing rules
+
+#
# Ignore all conversion warnings on windows 64
# (Is safe as we are not yet supporting strings >= 2G)
#
2
2
Hi!
Review of ~maria-captains/maria/5.2-pluggable-auth
(3 day of work!)
> === modified file 'client/mysql.cc'
<cut>
> + /**
> + An example of mysql_authentication_dialog_ask callback.
> +
> + The C function with the name "mysql_authentication_dialog_ask", if exists,
> + will be used by the "dialog" client authentication plugin when user
> + input is needed. This function should be of mysql_authentication_dialog_ask_t
> + type. If the function does not exists, a built-in implementation will be
> + used.
> +
> + @param mysql mysql
> + @param type type of the input
> + 1 - normal string input
> + 2 - password string
> + @param prompt prompt
> + @param buf a buffer to store the use input
> + @param buf_len the length of the buffer
> +
> + @retval a pointer to the user input string.
> + It may be equal to 'buf' or to 'mysql->password'.
> + In all other cases it is assumed to be an allocated
> + string, and the "dialog" plugin will free() it.
> + */
> + extern "C" char *mysql_authentication_dialog_ask(MYSQL *mysql, int type,
I would prefer to have type as my_bool as there is only two options
for it and rename it to 'ask_for_password'. This would make the code
more self_explanatory.
> + const char *prompt,
> + char *buf, int buf_len)
> + {
> + int ch;
> + char *s=buf, *end=buf+buf_len-1;
> +
> + fputs("[mysql] ", stdout);
[mysql] -> [mariadb]
> + fputs(prompt, stdout);
> + fputs(" ", stdout);
> +
> + if (type == 2) /* password */
> + {
> + s= get_tty_password("");
> + strncpy(buf, s, buf_len);
Better to use strnmov() like we use in all other part of the code.
> + my_free(s, MYF(0));
> + }
> + else
> + {
> + for (ch= fgetc(stdin); s < end && ch != '\n' && ch != EOF; ch= fgetc(stdin))
> + *s++= ch;
hm, we should really support backspace too....
Why not simply use fgets() that gives you basic editing?
fgets(buf, buf_len-1, stdin);
if (buf[0] && (s= strend(buf))[-1] == '\n')
*s= 0;
> + *s=0;
> + }
> +
> + return buf;
> + }
> === modified file 'include/my_global.h'
> *** include/my_global.h 2009-12-03 11:19:05 +0000
> --- include/my_global.h 2010-02-19 08:18:09 +0000
> *************** int __void__;
> *** 578,583 ****
> --- 578,591 ----
> #define IF_VALGRIND(A,B) (B)
> #endif
>
> + #ifdef _WIN32
In the rest of my_global.h we use __WIN__
Wouldn't it be better to use the same constant everywhere?
> + #define SO_EXT ".dll"
> + #elif defined(__APPLE__)
> + #define SO_EXT ".dylib"
> + #else
> + #define SO_EXT ".so"
> + #endif
> === modified file 'include/mysql.h'
> *** include/mysql.h 2010-02-01 06:14:12 +0000
> --- include/mysql.h 2010-02-19 08:18:09 +0000
> *************** enum mysql_option
> *** 167,175 ****
> MYSQL_OPT_USE_REMOTE_CONNECTION, MYSQL_OPT_USE_EMBEDDED_CONNECTION,
> MYSQL_OPT_GUESS_CONNECTION, MYSQL_SET_CLIENT_IP, MYSQL_SECURE_AUTH,
> MYSQL_REPORT_DATA_TRUNCATION, MYSQL_OPT_RECONNECT,
> ! MYSQL_OPT_SSL_VERIFY_SERVER_CERT
> };
>
> struct st_mysql_options {
> unsigned int connect_timeout, read_timeout, write_timeout;
> unsigned int port, protocol;
> --- 167,181 ----
> MYSQL_OPT_USE_REMOTE_CONNECTION, MYSQL_OPT_USE_EMBEDDED_CONNECTION,
> MYSQL_OPT_GUESS_CONNECTION, MYSQL_SET_CLIENT_IP, MYSQL_SECURE_AUTH,
> MYSQL_REPORT_DATA_TRUNCATION, MYSQL_OPT_RECONNECT,
> ! MYSQL_OPT_SSL_VERIFY_SERVER_CERT, MYSQL_PLUGIN_DIR, MYSQL_DEFAULT_AUTH
> };
>
> + /**
> + @todo remove the "extension", move st_mysql_options completely
> + out of mysql.h
The reason to have it in mysql.h is to be able to put it into the
MYSQL structure to avoid mallocs (for most cases) if you have MYSQL on
the stack or as a static variable. Don't see how we can easily remove
it, if we want to keep this property.
> --- include/mysql/plugin_auth.h 2010-02-19 08:18:09 +0000
> ***************
> *** 0 ****
> --- 1,83 ----
> + #ifndef MYSQL_PLUGIN_AUTH_INCLUDED
> + /* Copyright (C) 2010 Monty Program Ab
Add your/original author name here too
> === added file 'include/mysql/plugin_auth_common.h'
> *** include/mysql/plugin_auth_common.h 1970-01-01 00:00:00 +0000
> --- include/mysql/plugin_auth_common.h 2010-02-19 08:18:09 +0000
> ***************
> *** 0 ****
> --- 1,105 ----
> + #ifndef MYSQL_PLUGIN_AUTH_COMMON_INCLUDED
> + /* Copyright (C) 2010 Monty Program Ab
Add your/original author name here too
> + /** the max allowed length for a user name */
> + #define MYSQL_USERNAME_LENGTH 48
Shouldn't this be the define USERNAME_LENGTH ?
Otherwise there will be a crash if someone redefines USERNAME_CHAR_LENGTH
<cut>
> + typedef struct st_plugin_vio_info
> + {
> + enum { MYSQL_VIO_INVALID, MYSQL_VIO_TCP, MYSQL_VIO_SOCKET,
> + MYSQL_VIO_PIPE, MYSQL_VIO_MEMORY } protocol;
> + int socket; /**< it's set, if the protocol is SOCKET or TCP */
> + #ifdef _WIN32
_WIN32 -> __WIN__ ?
> + HANDLE handle; /**< it's set, if the protocol is PIPE or MEMORY */
> + #endif
> + } MYSQL_PLUGIN_VIO_INFO;
> +
> === modified file 'libmysqld/lib_sql.cc'
> *** libmysqld/lib_sql.cc 2009-12-03 11:19:05 +0000
> --- libmysqld/lib_sql.cc 2010-03-02 20:32:24 +0000
> *************** static MYSQL_RES * emb_store_result(MYSQ
> *** 413,423 ****
> return mysql_store_result(mysql);
> }
>
> ! int emb_read_change_user_result(MYSQL *mysql,
> ! char *buff __attribute__((unused)),
> ! const char *passwd __attribute__((unused)))
> {
> ! return mysql_errno(mysql);
> }
>
> MYSQL_METHODS embedded_methods=
> --- 412,421 ----
> return mysql_store_result(mysql);
> }
>
> ! int emb_read_change_user_result(MYSQL *mysql)
> {
> ! mysql->net.read_pos= (uchar*)""; // fake an OK packet
> ! return mysql_errno(mysql) ? packet_error : 1;
> }
Add a comment that '1' is packet length.
> *************** void init_embedded_mysql(MYSQL *mysql, i
> *** 584,589 ****
> --- 582,588 ----
> THD *thd = (THD *)mysql->thd;
> thd->mysql= mysql;
> mysql->server_version= server_version;
> + mysql->client_flag= client_flag;
> init_alloc_root(&mysql->field_alloc, 8192, 0);
> }
Was this a bug in the old code ?
(Just curious)
> === modified file 'mysql-test/suite/rpl/r/rpl_stm_000001.result'
> *** mysql-test/suite/rpl/r/rpl_stm_000001.result 2009-11-18 14:50:31 +0000
> --- mysql-test/suite/rpl/r/rpl_stm_000001.result 2010-02-19 08:18:09 +0000
> *************** Warnings:
> *** 66,71 ****
> --- 66,72 ----
> Warning 1364 Field 'ssl_cipher' doesn't have a default value
> Warning 1364 Field 'x509_issuer' doesn't have a default value
> Warning 1364 Field 'x509_subject' doesn't have a default value
> + Warning 1364 Field 'auth_string' doesn't have a default value
Should auth_string have a default value (to not cause a problem for
anyone using --strict mode and is inserting things into the auth
tables?)
Note likely problem, but possible...
IRC: conclusion
- As auth_string is a blob and we don't know the length, it's best to
leave it as it is.
<cut>
> *** plugin/auth/auth_socket.c 1970-01-01 00:00:00 +0000
> --- plugin/auth/auth_socket.c 2010-02-19 08:18:09 +0000
> ***************
> *** 0 ****
> --- 1,93 ----
> + /* Copyright (C) 2010 Monty Program Ab
> +
Add your/author's name here
<cut>
> === added file 'plugin/auth/dialog.c'
> *** plugin/auth/dialog.c 1970-01-01 00:00:00 +0000
> --- plugin/auth/dialog.c 2010-02-23 12:02:00 +0000
> ***************
> *** 0 ****
> --- 1,293 ----
> + /* Copyright (C) 2010 Monty Program Ab
Add your/author's name here
<cut>
> + static int two_questions(MYSQL_PLUGIN_VIO *vio, MYSQL_SERVER_AUTH_INFO *info)
> + {
> + unsigned char *pkt;
> + int pkt_len;
> +
> + /* send a password question */
> + if (vio->write_packet(vio, PASSWORD_QUESTION "Password, please:", 18))
> + return CR_ERROR;
It's a bit ugly to use concat for sending parameters...
Nicer would be
if (vio->write_packet(vio, PASSWORD_QUESTION, "Password, please:", 18))
Where the command would be stored in a slot of the MYSQL_PLUGIN_VIO on the
server side.
We can look at fixing this if there would be a deamnd for it.
<cut>
> + static int perform_dialog(MYSQL_PLUGIN_VIO *vio, MYSQL *mysql)
> + {
> + unsigned char *pkt, cmd= 0;
> + int pkt_len, res;
> + char reply_buf[1024], *reply;
> +
> + do
> + {
> + /* read the prompt */
> + pkt_len= vio->read_packet(vio, &pkt);
> + if (pkt_len < 0)
> + return CR_ERROR;
> +
> + if (pkt == 0)
> + {
> + /*
> + in mysql_change_user() the client sends the first packet, so
> + the first vio->read_packet() does nothing (pkt == 0).
> +
> + We send the "password", assuming the client knows what its doing.
> + (in other words, the dialog plugin should be only set as a default
> + authentication plugin on the client if the first question
> + asks for a password - which will be sent in cleat text, by the way)
cleat -> clear
> *** sql-common/client.c 2010-02-01 06:14:12 +0000
> --- sql-common/client.c 2010-03-02 20:32:24 +0000
> *************** my_bool net_flush(NET *net);
> *** 107,112 ****
> --- 107,113 ----
>
> #include "client_settings.h"
> #include <sql_common.h>
> + #include <mysql/client_plugin.h>
>
> uint mysql_port=0;
> char *mysql_unix_port= 0;
> *************** void net_clear_error(NET *net)
> *** 332,338 ****
> @param ... variable number of arguments
> */
>
> ! static void set_mysql_extended_error(MYSQL *mysql, int errcode,
> const char *sqlstate,
> const char *format, ...)
> {
> --- 333,339 ----
> @param ... variable number of arguments
> */
>
> ! void set_mysql_extended_error(MYSQL *mysql, int errcode,
> const char *sqlstate,
> const char *format, ...)
> {
> *************** static const char *default_options[]=
> *** 1002,1010 ****
> "replication-probe", "enable-reads-from-master", "repl-parse-query",
> "ssl-cipher", "max-allowed-packet", "protocol", "shared-memory-base-name",
> "multi-results", "multi-statements", "multi-queries", "secure-auth",
> ! "report-data-truncation",
> NullS
> };
>
> static TYPELIB option_types={array_elements(default_options)-1,
> "options",default_options, NULL};
> --- 1003,1022 ----
> "replication-probe", "enable-reads-from-master", "repl-parse-query",
> "ssl-cipher", "max-allowed-packet", "protocol", "shared-memory-base-name",
> "multi-results", "multi-statements", "multi-queries", "secure-auth",
> ! "report-data-truncation", "plugin-dir", "default-auth",
> NullS
> };
> + enum option_id {
> + OPT_port=1, OPT_socket, OPT_compress, OPT_password, OPT_pipe, OPT_timeout, OPT_user,
> + OPT_init_command, OPT_host, OPT_database, OPT_debug, OPT_return_found_rows,
> + OPT_ssl_key, OPT_ssl_cert, OPT_ssl_ca, OPT_ssl_capath,
> + OPT_character_sets_dir, OPT_default_character_set, OPT_interactive_timeout,
> + OPT_connect_timeout, OPT_local_infile, OPT_disable_local_infile,
> + OPT_replication_probe, OPT_enable_reads_from_master, OPT_repl_parse_query,
> + OPT_ssl_cipher, OPT_max_allowed_packet, OPT_protocol, OPT_shared_memory_base_name,
> + OPT_multi_results, OPT_multi_statements, OPT_multi_queries, OPT_secure_auth,
> + OPT_report_data_truncation, OPT_plugin_dir, OPT_default_auth,
> + };
If you add OPT_DUPLICATE= -1 and OPT_ERROR= 1 to the above, you can
cast (find_type(*option+2,&option_types,2)) to the enum and get more
readable code...
> *** 1035,1040 ****
> --- 1047,1060 ----
> return 0;
> }
>
> + #define extension_free(OPTS, X) \
> + if ((OPTS)->extension) \
> + my_free((OPTS)->extension->X, MYF(MY_ALLOW_ZERO_PTR)); \
> + else \
> + (OPTS)->extension= (struct st_mysql_options_extention *) \
> + my_malloc(sizeof(struct st_mysql_options_extention), \
> + MYF(MY_WME | MY_ZEROFILL));
Free is a bad name as we actually create some structures here.
How about using 'extension_reset()' instead ?
> + case OPT_plugin_dir:
> + extension_free(options, plugin_dir);
> + options->extension->plugin_dir= my_strdup(opt_arg, MYF(MY_WME));
> + break;
> + case OPT_default_auth:
> + extension_free(options, default_auth);
> + options->extension->default_auth= my_strdup(opt_arg, MYF(MY_WME));
> + break;
Even better, would be to do:
extension_set_string(options, default_auth, opt_arg);
Which would make the usage compleately clear.
<cut>
> *************** int mysql_init_character_set(MYSQL *mysq
> *** 1856,1861 ****
> --- 1889,2479 ----
> }
> C_MODE_END
>
> + /*********** client side authentication support **************************/
> +
> + typedef struct st_mysql_client_plugin_AUTHENTICATION auth_plugin_t;
> +
> + /* this is a "superset" of MYSQL_PLUGIN_VIO, in C++ I use inheritance */
> + typedef struct {
> + int (*read_packet)(struct st_plugin_vio *vio, uchar **buf);
> + int (*write_packet)(struct st_plugin_vio *vio, const uchar *pkt, int pkt_len);
> + void (*info)(struct st_plugin_vio *vio, struct st_plugin_vio_info *info);
> + /* -= end of MYSQL_PLUGIN_VIO =- */
> + MYSQL *mysql;
> + auth_plugin_t *plugin; /**< what plugin we're under */
> + const char *db;
> + struct {
> + uchar *pkt; /**< pointer into NET::buff */
> + uint pkt_len;
> + } cached_server_reply;
> + int packets_read, packets_written; /**< counters for send/received packets */
> + int mysql_change_user; /**< if it's mysql_change_user() */
> + int last_read_packet_len; /**< the length of the last *read* packet */
> + } MCPVIO_EXT;
How about changing counters to uint and mysql_change_user to my_bool ?
> + #define native_password_plugin_name "mysql_native_password"
> + #define old_password_plugin_name "mysql_old_password"
Please add defines to start of file (easier to find them)
> + /**
> + sends a client authentication packet (second packet in the 3-way handshake)
> +
> + Packet format (when the server is 4.0 or earlier):
> +
> + Bytes Content
> + ----- ----
> + 2 client capabilities
> + 3 max packet size
> + n user name, \0-terminated
> + 9 scramble_323, \0-terminated
> +
> + Packet format (when the server is 4.1 or newer):
> +
> + Bytes Content
> + ----- ----
> + 4 client capabilities
> + 4 max packet size
> + 1 charset number
> + 23 reserved (always 0)
> + n user name, \0-terminated
> + n plugin auth data (e.g. scramble), length (1 byte) coded
> + n database name, \0-terminated
> + (if CLIENT_CONNECT_WITH_DB is set in the capabilities)
> + n client auth plugin name - \0-terminated string,
> + (if CLIENT_PLUGIN_AUTH is set in the capabilities)
> +
> + @retval 0 ok
> + @retval 1 error
> + */
> + static int send_client_reply_packet(MCPVIO_EXT *mpvio,
> + const uchar *data, int data_len)
> + {
> + MYSQL *mysql= mpvio->mysql;
> + NET *net= &mysql->net;
> + char *buff, *end;
> +
> + /* see end= buff+32 below, fixed size of the packet is 32 bytes */
> + buff= my_alloca(33 + USERNAME_LENGTH + data_len + NAME_LEN + NAME_LEN);
> +
> + mysql->client_flag|= mysql->options.client_flag;
> + mysql->client_flag|= CLIENT_CAPABILITIES;
The code would be easier to read (and a bit faster/shorter) if you have
client_flag as a static variable and set mysql->client_flag from this
when all options are set.
> +
> + if (mysql->client_flag & CLIENT_MULTI_STATEMENTS)
> + mysql->client_flag|= CLIENT_MULTI_RESULTS;
> +
> + #if defined(HAVE_OPENSSL) && !defined(EMBEDDED_LIBRARY)
> + if (mysql->options.ssl_key || mysql->options.ssl_cert ||
> + mysql->options.ssl_ca || mysql->options.ssl_capath ||
> + mysql->options.ssl_cipher)
> + mysql->options.use_ssl= 1;
> + if (mysql->options.use_ssl)
> + mysql->client_flag|= CLIENT_SSL;
> + #endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY*/
Note that we from a client embedded with libmysqld, may also want to
connect to a remote MySQL server. At some point we need to test and
fix this. (This is why some part of the old embedded code didn't have
defined(EMBEDDED_LIBRARY) in all possible places.
<cut>
> + #ifdef HAVE_OPENSSL
How come you don't have !defined(EMBEDDED_LIBRARY) here ?
> + }
> + #endif /* HAVE_OPENSSL && !EMBEDDED_LIBRARY */
Comment is wrong or ifdef...
<cut>
> + if (data_len)
Add a comment that data_len is always password length here.
> + {
> + if (mysql->server_capabilities & CLIENT_SECURE_CONNECTION)
> + {
> + *end++= data_len;
> + memcpy(end, data, data_len);
> + end+= data_len;
> + }
<cut>
> + static int client_mpvio_write_packet(struct st_plugin_vio*, const uchar*, int);
Please put static declarations first in the file.
> + /**
> + vio->read_packet() callback method for client authentication plugins
> +
> + This function is called by a client authentication plugin, when it wants
> + to read data from the server.
> + */
Empty line here (makes things easier to read)
> + static int client_mpvio_read_packet(struct st_plugin_vio *mpv, uchar **buf)
> + {
> + MCPVIO_EXT *mpvio= (MCPVIO_EXT*)mpv;
> + MYSQL *mysql= mpvio->mysql;
> + ulong pkt_len;
> +
> + if (mpvio->packets_read == 0 && !mpvio->cached_server_reply.pkt)
> + {
> + /*
> + the server handshake packet came from the wrong plugin,
> + or it's mysql_change_user(). Either way, there is no data
> + for a plugin to read. send a dummy packet to the server
> + to initiate a dialog.
> + */
> + if (client_mpvio_write_packet(mpv, 0, 0))
> + return (int)packet_error;
> + }
> +
> + /* there are cached data left, feed it to a plugin */
> + if (mpvio->cached_server_reply.pkt)
> + {
> + *buf= mpvio->cached_server_reply.pkt;
> + mpvio->cached_server_reply.pkt= 0;
> + mpvio->packets_read++;
> + return mpvio->cached_server_reply.pkt_len;
> + }
Move this test first as this allows you to simplify the current first if.
> +
> + /* otherwise read the data */
> + pkt_len= (*mysql->methods->read_change_user_result)(mysql);
> + mpvio->last_read_packet_len= pkt_len;
> + *buf= mysql->net.read_pos;
> +
> + /* was it a request to change plugins ? */
> + if (**buf == 254)
> + return (int)packet_error; /* if yes, this plugin shan't continue */
shan't -> can't
> + /*
> + the server sends \1\255 or \1\254 instead of just \255 or \254 -
> + for us to not confuse it with an error or "change plugin" packets.
> + We remove this escaping \1 here.
> + */
Please add a comment 'see server_mpvio_write_packet()'
> + if (pkt_len && **buf == 1)
> + {
> + (*buf)++;
> + pkt_len--;
> + }
> + mpvio->packets_read++;
> + return pkt_len;
> + }
Wouldn't be be better to always send a 1 prefix in all cases or at
least for all not native authorization handlers?
(It would make the protocol easier to understand and also remove some
'if' code) here and in server_mpvio_write_packet()'
However, I agree that it may give a problem for the current native auth
handlers.
If there is no easy solution, we may have to live with this for now...
> + /**
> + vio->write_packet() callback method for client authentication plugins
> +
> + This function is called by a client authentication plugin, when it wants
> + to send data to the server.
> +
> + It transparently wraps the data into a change user or authentication
> + handshake packet, if neccessary.
> + */
> + static int client_mpvio_write_packet(struct st_plugin_vio *mpv,
> + const uchar *pkt, int pkt_len)
> + {
> + int res;
> + MCPVIO_EXT *mpvio= (MCPVIO_EXT*)mpv;
> +
> + if (mpvio->packets_written == 0)
> + {
> + if (mpvio->mysql_change_user)
> + res= send_change_user_packet(mpvio, pkt, pkt_len);
> + else
> + res= send_client_reply_packet(mpvio, pkt, pkt_len);
It would be nice to not have this if.
As a trick, it's possible to remove all of the above if's.
This would be to set write_packet directly to
send_change_user_packet & send_client_reply_packet
And then end both of these with
mpvio->write_packet=client_mpvio_write_packet;
mpvio->packets_written++;
In this case the packets_written may not even be neccessary to have.
> +
> + /**
> + fills MYSQL_PLUGIN_VIO_INFO structure with the information about the
> + connection
> + */
> + void mpvio_info(Vio *vio, MYSQL_PLUGIN_VIO_INFO *info)
> + {
> + bzero(info, sizeof(*info));
> + switch (vio->type) {
> + case VIO_TYPE_TCPIP:
> + info->protocol= MYSQL_VIO_TCP;
> + info->socket= vio->sd;
> + return;
> + case VIO_TYPE_SOCKET:
> + info->protocol= MYSQL_VIO_SOCKET;
> + info->socket= vio->sd;
> + return;
> + case VIO_TYPE_SSL:
> + {
> + struct sockaddr addr;
> + socklen_t addrlen= sizeof(addr);
> + if (getsockname(vio->sd, &addr, &addrlen))
> + return;
> + info->protocol= addr.sa_family == AF_UNIX ?
> + MYSQL_VIO_SOCKET : MYSQL_VIO_TCP;
> + info->socket= vio->sd;
> + return;
> + }
> + #ifdef _WIN32
> + case VIO_TYPE_NAMEDPIPE:
> + info->protocol= MYSQL_VIO_PIPE;
> + info->handle= vio->hPipe;
> + return;
> + case VIO_TYPE_SHARED_MEMORY:
> + info->protocol= MYSQL_VIO_MEMORY;
> + info->handle= vio->handle_client_file_map; /* or what ? */
> + return;
> + #endif
> + default: DBUG_ASSERT(0);
> + }
> + }
As this is not used by MariaDBL by default, add a comment that for now
this is only used by the socket_peercred plugin.
> + int run_plugin_auth(MYSQL *mysql, char *data, uint data_len,
> + char *data_plugin, const char *db)
> + {
> + const char *auth_plugin_name;
> + auth_plugin_t *auth_plugin;
> + MCPVIO_EXT mpvio;
> + ulong pkt_length;
> + int res;
> +
> + /* determine the default/initial plugin to use */
> + if (mysql->options.extension && mysql->options.extension->default_auth &&
> + mysql->server_capabilities & CLIENT_PLUGIN_AUTH)
> + auth_plugin_name= mysql->options.extension->default_auth;
> + else
> + auth_plugin_name= mysql->server_capabilities & CLIENT_PROTOCOL_41 ?
> + native_password_plugin_name : old_password_plugin_name;
> +
Better to set auth_plugin directly above.
(Yes, mysql_client_find_plugin() is fast, but setting things directly
is even faster and in this case not more code.
> + if (!(auth_plugin= (auth_plugin_t*) mysql_client_find_plugin(mysql,
> + auth_plugin_name, MYSQL_CLIENT_AUTHENTICATION_PLUGIN)))
> + return 1; /* oops, not found */
> +
> + mysql->net.last_errno= 0; /* just in case */
> +
> + if (data_plugin && strcmp(data_plugin, auth_plugin_name))
but of course, here you need to use something like auth_plugin->name instead.
<cut>
> + res= auth_plugin->authenticate_user((struct st_plugin_vio *)&mpvio, mysql);
> +
> + compile_time_assert(CR_OK == -1);
> + compile_time_assert(CR_ERROR == 0);
> + if (res > CR_OK && mysql->net.read_pos[0] != 254)
> + {
> + /*
> + the plugin returned an error. write it down in mysql,
> + unless the error code is CR_ERROR and mysql->net.last_errno
> + is already set (the plugin has done it)
> + */
> + if (res > CR_ERROR)
> + set_mysql_error(mysql, res, unknown_sqlstate);
> + else
> + if (!mysql->net.last_errno)
> + set_mysql_error(mysql, CR_UNKNOWN_ERROR, unknown_sqlstate);
> + return 1;
> + }
> +
> + /* read the OK packet (or use the cached value in mysql->net.read_pos */
> + if (res == CR_OK)
> + pkt_length= (*mysql->methods->read_change_user_result)(mysql);
> + else /* res == CR_OK_HANDSHAKE_COMPLETE */
> + pkt_length= mpvio.last_read_packet_len;
Note that here res may be CR_ERROR as mysql->net.read_pos[] can
contain 254 as part of some old 'garbage' data, so the comment is
wrong. I assume that in this case last_read_packet_len is packet_error.
> +
> + if (pkt_length == packet_error)
> + {
> + if (mysql->net.last_errno == CR_SERVER_LOST)
> + set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate,
> + ER(CR_SERVER_LOST_EXTENDED),
> + "reading authorization packet",
> + errno);
> + return 1;
> + }
> +
> + if (mysql->net.read_pos[0] == 254)
> + {
> + /* The server asked to use a different authentication plugin */
> + if (pkt_length == 1)
> + { /* old "use short scramble" packet */
Please move comment to it's own line. (Hard to read for me)
> + auth_plugin_name= old_password_plugin_name;
> + mpvio.cached_server_reply.pkt= (uchar*)mysql->scramble;
> + mpvio.cached_server_reply.pkt_len= SCRAMBLE_LENGTH + 1;
> + }
> + else
> + { /* new "use different plugin" packet */
Same here
> + uint len;
> + auth_plugin_name= (char*)mysql->net.read_pos + 1;
> + len= strlen(auth_plugin_name);
Here you may want to add a comment that this is safe becasue
my_net_read() guarantees that the packet ends with \0
> MYSQL * STDCALL
> CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
> *************** CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,cons
> *** 1863,1870 ****
> uint port, const char *unix_socket,ulong client_flag)
> {
> char buff[NAME_LEN+USERNAME_LENGTH+100];
> ! char error_string[1024];
> ! char *end,*host_info= NULL;
> my_socket sock;
> in_addr_t ip_addr;
> struct sockaddr_in sock_addr;
> --- 2481,2489 ----
> uint port, const char *unix_socket,ulong client_flag)
> {
> char buff[NAME_LEN+USERNAME_LENGTH+100];
> ! int scramble_data_len, pkt_scramble_len;
> ! char *end,*host_info, *server_version_end, *pkt_end, *scramble_data;
> ! char *scramble_plugin;
> my_socket sock;
> in_addr_t ip_addr;
> struct sockaddr_in sock_addr;
Will we not get a warning on some platform if we remove host_info= NULL ?
(I think this was the reason we added it)
> --- 2812,2840 ----
> PROTOCOL_VERSION);
> goto error;
> }
> ! server_version_end= end= strend((char*) net->read_pos+1);
> mysql->thread_id=uint4korr(end+1);
> end+=5;
> /*
> ! Scramble is split into two parts because old clients do not understand
> long scrambles; here goes the first part.
> */
> ! scramble_data= end;
> ! scramble_data_len= SCRAMBLE_LENGTH_323 + 1;
> ! scramble_plugin= old_password_plugin_name;
> ! end+= scramble_data_len;
>
> ! if (pkt_end >= end + 1)
> mysql->server_capabilities=uint2korr(end);
> ! if (pkt_end >= end + 18)
> {
> /* New protocol with 16 bytes to describe server characteristics */
> mysql->server_language=end[2];
> mysql->server_status=uint2korr(end+3);
> + mysql->server_capabilities|= uint2korr(end+5) << 16;
> + pkt_scramble_len= end[7];
> }
> end+= 18;
Don't we need to check that end + pkt_scramble_len <= pkt_end ?
<cut>
> *** 3185,3190 ****
> --- 3650,3663 ----
> else
> mysql->options.client_flag&= ~CLIENT_SSL_VERIFY_SERVER_CERT;
> break;
> + case MYSQL_PLUGIN_DIR:
> + extension_free(&mysql->options, plugin_dir);
> + mysql->options.extension->plugin_dir= my_strdup(arg, MYF(MY_WME));
> + break;
> + case MYSQL_DEFAULT_AUTH:
> + extension_free(&mysql->options, default_auth);
> + mysql->options.extension->default_auth= my_strdup(arg, MYF(MY_WME));
> + break;
-> extension_set_string()
> --- sql-common/client_plugin.c 2010-02-19 08:18:09 +0000
> ***************
> *** 0 ****
> --- 1,427 ----
> + /* Copyright (C) 2010 Monty Program Ab
-> Add author
<cut>
> + static void load_env_plugins(MYSQL *mysql)
> + {
> + char *plugs, *free_env, *s= getenv("LIBMYSQL_PLUGINS");
> +
> + /* no plugins to load */
> + if(!s)
> + return;
> +
> + free_env= plugs= my_strdup(s, MYF(MY_WME));
> + s= NULL;
Remove setting 's' to NULL.
> +
> + do {
> + if ((s= strchr(plugs, ';')))
> + *s= '\0';
> + mysql_load_plugin(mysql, plugs, -1, 0);
> + if(s)
Remove if (not needed)
> + plugs= ++s;
Change to s+1
> + } while (s);
> +
> + my_free(free_env, MYF(0));
> + }
add space after 'if'
> +
> + /********** extern functions to be used by libmysql *********************/
> +
> + /**
> + Initializes the client plugin layer.
> +
> + This function must be called before any other client plugin function.
> +
> + @retval 0 successful
> + @retval != 0 error occured
> + */
> + int mysql_client_plugin_init()
> + {
> + MYSQL mysql;
> + struct st_mysql_client_plugin **builtin;
> +
> + if (initialized)
> + return 0;
> + bzero(&mysql, sizeof(mysql)); /* dummy mysql for set_mysql_extended_error */
> +
> + pthread_mutex_init(&LOCK_load_client_plugin, MY_MUTEX_INIT_SLOW);
> + init_alloc_root(&mem_root, 128, 128);
> +
> + bzero(&plugin_list, sizeof(plugin_list));
> +
> + initialized= 1;
> +
> + pthread_mutex_lock(&LOCK_load_client_plugin);
> +
> + for (builtin= mysql_client_builtins; *builtin; builtin++)
> + add_plugin(&mysql, *builtin, 0, 0, 0);
> +
> + pthread_mutex_unlock(&LOCK_load_client_plugin);
> +
> + load_env_plugins(&mysql);
You don't need mutex_lock() here, as no other thread can access data
until this is setup. You can make this safe by setting initialized to
1 at end of function.
> +
> + return 0;
> + }
> +
> + /**
> + Deinitializes the client plugin layer.
> +
> + Unloades all client plugins and frees any associated resources.
> + */
> + void mysql_client_plugin_deinit()
> + {
> + int i;
> + struct st_client_plugin_int *p;
> +
> + if (!initialized)
> + return;
Shouldn't this be a DBUG_ASSERT() to detect wrong usage?
> --- sql/mysqld.cc 2010-02-19 08:18:09 +0000
> *************** static int init_common_variables(const c
> *** 3490,3495 ****
> --- 3492,3498 ----
> if (init_errmessage()) /* Read error messages from file */
> return 1;
> init_client_errs();
> + mysql_library_init(un,us,ed); /* for replication */
Please add comment. As this can never work, why have it here?
> === modified file 'sql/sql_acl.cc'
> *** sql/sql_acl.cc 2010-02-01 06:14:12 +0000
<cut>
> + struct acl_host_and_ip
> + {
> + char *hostname;
> + long ip,ip_mask; // Used with masked ip:s
> + };
Just a note; For future, we should change all strings to use
LEX_STRING (to avoid calling strlen() and faster compare as we can
skip strings with different lengths).
> + class ACL_ACCESS {
> + public:
> + ulong sort;
> + ulong access;
> + };
> +
> + /* ACL_HOST is used if no host is specified */
> +
> + class ACL_HOST :public ACL_ACCESS
> + {
> + public:
> + acl_host_and_ip host;
> + char *db;
> + };
db is something I wanted to put as LEX_STRING a long time...
(Noting you can do about it just now...)
> +
> + class ACL_USER :public ACL_ACCESS
> + {
> + public:
> + acl_host_and_ip host;
> + uint hostname_length;
> + USER_RESOURCES user_resource;
> + char *user;
> + uint8 salt[SCRAMBLE_LENGTH+1]; // scrambled password in binary form
> + uint8 salt_len; // 0 - no password, 4 - 3.20, 8 - 4.0, 20 - 4.1.1
> + enum SSL_type ssl_type;
> + const char *ssl_cipher, *x509_issuer, *x509_subject;
> + LEX_STRING plugin;
> + LEX_STRING auth_string;
> +
> + ACL_USER *copy(MEM_ROOT *root)
> + {
> + ACL_USER *dst= (ACL_USER *)alloc_root(root, sizeof(ACL_USER));
> + if (!dst)
> + return 0;
> + *dst= *this;
> + dst->user= safe_strdup_root(root, user);
> + dst->ssl_cipher= safe_strdup_root(root, ssl_cipher);
> + dst->x509_issuer= safe_strdup_root(root, x509_issuer);
> + dst->x509_subject= safe_strdup_root(root, x509_subject);
> + if (plugin.str == native_password_plugin_name.str ||
> + plugin.str == old_password_plugin_name.str)
> + dst->plugin= plugin;
> + else
> + dst->plugin.str= strmake_root(root, plugin.str, plugin.length);
In theory, it would be better if we didn't have to test for names but
instead have a flag in the plugin if it's dynamic or not.
> + dst->auth_string.str = safe_strdup_root(root, auth_string.str);
> + dst->host.hostname= safe_strdup_root(root, host.hostname);
> + return dst;
> + }
> + };
> *************** static my_bool acl_load(THD *thd, TABLE_
> *** 433,459 ****
> continue;
> }
>
> ! const char *password= get_field(thd->mem_root, table->field[2]);
> uint password_len= password ? strlen(password) : 0;
> set_user_salt(&user, password, password_len);
> ! if (user.salt_len == 0 && password_len != 0)
> ! {
> switch (password_len) {
> case 45: /* 4.1: to be removed */
> ! sql_print_warning("Found 4.1 style password for user '%s@%s'. "
> "Ignoring user. "
> "You should change password for this user.",
> user.user ? user.user : "",
> user.host.hostname ? user.host.hostname : "");
> ! break;
> default:
> sql_print_warning("Found invalid password for user: '%s@%s'; "
> "Ignoring user", user.user ? user.user : "",
> user.host.hostname ? user.host.hostname : "");
> ! break;
> ! }
> }
> ! else // password is correct
> {
> uint next_field;
> user.access= get_access(table,3,&next_field) & GLOBAL_ACLS;
> --- 545,578 ----
> continue;
> }
>
> ! char *password= get_field(thd->mem_root, table->field[2]);
> uint password_len= password ? strlen(password) : 0;
We should change 'get_field' to also return the length of the string.
I can do that as a separate patch if you don't want to do it.
<cut>
> --- 649,681 ----
> ptr= get_field(thd->mem_root, table->field[next_field++]);
> user.user_resource.user_conn= ptr ? atoi(ptr) : 0;
> }
> !
> ! if (table->s->fields >= 41)
> ! {
> ! /* We may have plugin & auth_String fields */
> ! char *tmpstr= get_field(&mem, table->field[next_field++]);
> ! if (tmpstr)
> ! {
> ! if (user.auth_string.length)
> ! {
> ! sql_print_warning("'user' entry '%s@%s' has both a password "
> ! "and an authentication plugin specified. The "
> ! "password will be ignored.",
> ! user.user ? user.user : "",
> ! user.host.hostname ? user.host.hostname : "");
> ! }
> ! user.plugin.str= tmpstr;
> ! user.plugin.length= strlen(tmpstr);
Another strlen() to be removed if we fix get_field()...
> ! user.auth_string.str= get_field(&mem, table->field[next_field++]);
> ! if (!user.auth_string.str)
> ! user.auth_string.str= const_cast<char*>("");
> ! user.auth_string.length= strlen(user.auth_string.str);
and another one...
> ! }
> ! }
> }
> else
> {
> user.ssl_type=SSL_TYPE_NONE;
> #ifndef TO_BE_REMOVED
> if (table->s->fields <= 13)
> { // Without grant
> *************** static int acl_compare(ACL_ACCESS *a,ACL
> *** 836,1081 ****
>
>
> /*
> ! Seek ACL entry for a user, check password, SSL cypher, and if
> ! everything is OK, update THD user data and USER_RESOURCES struct.
> !
> ! IMPLEMENTATION
> ! This function does not check if the user has any sensible privileges:
> ! only user's existence and validity is checked.
> ! Note, that entire operation is protected by acl_cache_lock.
>
> SYNOPSIS
> acl_getroot()
> - thd thread handle. If all checks are OK,
> - thd->security_ctx->priv_user/master_access are updated.
> - thd->security_ctx->host/ip/user are used for checks.
> - mqh user resources; on success mqh is reset, else
> - unchanged
> - passwd scrambled & crypted password, received from client
> - (to check): thd->scramble or thd->scramble_323 is
> - used to decrypt passwd, so they must contain
> - original random string,
> - passwd_len length of passwd, must be one of 0, 8,
> - SCRAMBLE_LENGTH_323, SCRAMBLE_LENGTH
> - 'thd' and 'mqh' are updated on success; other params are IN.
> -
> - RETURN VALUE
> - 0 success: thd->priv_user, thd->priv_host, thd->master_access, mqh are
> - updated
> - 1 user not found or authentication failure
> - 2 user found, has long (4.1.1) salt, but passwd is in old (3.23) format.
> - -1 user found, has short (3.23) salt, but passwd is in new (4.1.1) format.
> - */
> -
> - int acl_getroot(THD *thd, USER_RESOURCES *mqh,
> - const char *passwd, uint passwd_len)
> - {
> - ulong user_access= NO_ACCESS;
> - int res= 1;
> - ACL_USER *acl_user= 0;
> - Security_context *sctx= thd->security_ctx;
> - DBUG_ENTER("acl_getroot");
> -
> - if (!initialized)
> - {
> - /*
> - here if mysqld's been started with --skip-grant-tables option.
> - */
> - sctx->skip_grants();
> - bzero((char*) mqh, sizeof(*mqh));
> - DBUG_RETURN(0);
> - }
> -
> - VOID(pthread_mutex_lock(&acl_cache->lock));
> -
> - /*
> - Find acl entry in user database. Note, that find_acl_user is not the same,
> - because it doesn't take into account the case when user is not empty,
> - but acl_user->user is empty
> - */
> -
> - for (uint i=0 ; i < acl_users.elements ; i++)
> - {
> - ACL_USER *acl_user_tmp= dynamic_element(&acl_users,i,ACL_USER*);
> - if (!acl_user_tmp->user || !strcmp(sctx->user, acl_user_tmp->user))
> - {
> - if (compare_hostname(&acl_user_tmp->host, sctx->host, sctx->ip))
> - {
> - /* check password: it should be empty or valid */
> - if (passwd_len == acl_user_tmp->salt_len)
> - {
> - if (acl_user_tmp->salt_len == 0 ||
> - (acl_user_tmp->salt_len == SCRAMBLE_LENGTH ?
> - check_scramble(passwd, thd->scramble, acl_user_tmp->salt) :
> - check_scramble_323(passwd, thd->scramble,
> - (ulong *) acl_user_tmp->salt)) == 0)
> - {
> - acl_user= acl_user_tmp;
> - res= 0;
> - }
> - }
> - else if (passwd_len == SCRAMBLE_LENGTH &&
> - acl_user_tmp->salt_len == SCRAMBLE_LENGTH_323)
> - res= -1;
> - else if (passwd_len == SCRAMBLE_LENGTH_323 &&
> - acl_user_tmp->salt_len == SCRAMBLE_LENGTH)
> - res= 2;
> - /* linear search complete: */
> - break;
> - }
> - }
> - }
> - /*
> - This was moved to separate tree because of heavy HAVE_OPENSSL case.
> - If acl_user is not null, res is 0.
> - */
> -
> - if (acl_user)
> - {
> - /* OK. User found and password checked continue validation */
> - #ifdef HAVE_OPENSSL
> - Vio *vio=thd->net.vio;
> - SSL *ssl= (SSL*) vio->ssl_arg;
> - X509 *cert;
> - #endif
> -
> - /*
> - At this point we know that user is allowed to connect
> - from given host by given username/password pair. Now
> - we check if SSL is required, if user is using SSL and
> - if X509 certificate attributes are OK
> - */
> - switch (acl_user->ssl_type) {
> - case SSL_TYPE_NOT_SPECIFIED: // Impossible
> - case SSL_TYPE_NONE: // SSL is not required
> - user_access= acl_user->access;
> - break;
> - #ifdef HAVE_OPENSSL
> - case SSL_TYPE_ANY: // Any kind of SSL is ok
> - if (vio_type(vio) == VIO_TYPE_SSL)
> - user_access= acl_user->access;
> - break;
> - case SSL_TYPE_X509: /* Client should have any valid certificate. */
> - /*
> - Connections with non-valid certificates are dropped already
> - in sslaccept() anyway, so we do not check validity here.
> -
> - We need to check for absence of SSL because without SSL
> - we should reject connection.
> - */
> - if (vio_type(vio) == VIO_TYPE_SSL &&
> - SSL_get_verify_result(ssl) == X509_V_OK &&
> - (cert= SSL_get_peer_certificate(ssl)))
> - {
> - user_access= acl_user->access;
> - X509_free(cert);
> - }
> - break;
> - case SSL_TYPE_SPECIFIED: /* Client should have specified attrib */
> - /*
> - We do not check for absence of SSL because without SSL it does
> - not pass all checks here anyway.
> - If cipher name is specified, we compare it to actual cipher in
> - use.
> - */
> - if (vio_type(vio) != VIO_TYPE_SSL ||
> - SSL_get_verify_result(ssl) != X509_V_OK)
> - break;
> - if (acl_user->ssl_cipher)
> - {
> - DBUG_PRINT("info",("comparing ciphers: '%s' and '%s'",
> - acl_user->ssl_cipher,SSL_get_cipher(ssl)));
> - if (!strcmp(acl_user->ssl_cipher,SSL_get_cipher(ssl)))
> - user_access= acl_user->access;
> - else
> - {
> - if (global_system_variables.log_warnings)
> - sql_print_information("X509 ciphers mismatch: should be '%s' but is '%s'",
> - acl_user->ssl_cipher,
> - SSL_get_cipher(ssl));
> - break;
> - }
> - }
> - /* Prepare certificate (if exists) */
> - DBUG_PRINT("info",("checkpoint 1"));
> - if (!(cert= SSL_get_peer_certificate(ssl)))
> - {
> - user_access=NO_ACCESS;
> - break;
> - }
> - DBUG_PRINT("info",("checkpoint 2"));
> - /* If X509 issuer is specified, we check it... */
> - if (acl_user->x509_issuer)
> - {
> - DBUG_PRINT("info",("checkpoint 3"));
> - char *ptr = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
> - DBUG_PRINT("info",("comparing issuers: '%s' and '%s'",
> - acl_user->x509_issuer, ptr));
> - if (strcmp(acl_user->x509_issuer, ptr))
> - {
> - if (global_system_variables.log_warnings)
> - sql_print_information("X509 issuer mismatch: should be '%s' "
> - "but is '%s'", acl_user->x509_issuer, ptr);
> - free(ptr);
> - X509_free(cert);
> - user_access=NO_ACCESS;
> - break;
> - }
> - user_access= acl_user->access;
> - free(ptr);
> - }
> - DBUG_PRINT("info",("checkpoint 4"));
> - /* X509 subject is specified, we check it .. */
> - if (acl_user->x509_subject)
> - {
> - char *ptr= X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
> - DBUG_PRINT("info",("comparing subjects: '%s' and '%s'",
> - acl_user->x509_subject, ptr));
> - if (strcmp(acl_user->x509_subject,ptr))
> - {
> - if (global_system_variables.log_warnings)
> - sql_print_information("X509 subject mismatch: should be '%s' but is '%s'",
> - acl_user->x509_subject, ptr);
> - free(ptr);
> - X509_free(cert);
> - user_access=NO_ACCESS;
> - break;
> - }
> - user_access= acl_user->access;
> - free(ptr);
> - }
> - /* Deallocate the X509 certificate. */
> - X509_free(cert);
> - 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 */
> - }
> - sctx->master_access= user_access;
> - sctx->priv_user= acl_user->user ? sctx->user : (char *) "";
> - *mqh= acl_user->user_resource;
> -
> - if (acl_user->host.hostname)
> - strmake(sctx->priv_host, acl_user->host.hostname, MAX_HOSTNAME);
> - else
> - *sctx->priv_host= 0;
> - }
> - VOID(pthread_mutex_unlock(&acl_cache->lock));
> - DBUG_RETURN(res);
> - }
> -
> -
> - /*
> - This is like acl_getroot() above, but it doesn't check password,
> - and we don't care about the user resources.
> -
> - SYNOPSIS
> - acl_getroot_no_password()
> sctx Context which should be initialized
> user user name
> host host name
> --- 977,986 ----
<cut>
> --- 6238,6256 ----
> }
> else
> {
> ! push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, ER_PASSWD_LENGTH,
> ! ER(ER_PASSWD_LENGTH), SCRAMBLED_PASSWORD_CHAR_LENGTH);
> return TRUE;
> }
> combo->password.str= passwd_buff;
> }
> !
> ! if (au->plugin.str != native_password_plugin_name.str &&
> ! au->plugin.str != old_password_plugin_name.str)
Also here it would be nice with just:
if (!au->plugin.native_plugin)
...
> + /****************************************************************************
> + AUTHENTICATION CODE
> + including initial connect handshake, invoking appropriate plugins,
> + client-server plugin negotiation, COM_CHANGE_USER, and native
> + MySQL authentication plugins.
> + ****************************************************************************/
> +
> + /* few defines to have less ifdef's in the code below */
> + #ifdef EMBEDDED_LIBRARY
> + #ifdef NO_EMBEDDED_ACCESS_CHECKS
> + #define initialized 0
> + #define decrease_user_connections(X) /* nothing */
> + #define check_for_max_user_connections(X,Y) 0
> + #endif
> + #undef HAVE_OPENSSL
> + #endif
Move the undef after the first #ifdef; Makes the code easier to read
and one doesn't have to worry what each #endif stands for.
> + #ifndef HAVE_OPENSSL
> + #define ssl_acceptor_fd 0
> + #define sslaccept(A,B,C,D) 1
> + #endif
> +
> + /**
> + The internal version of what plugins know as MYSQL_PLUGIN_VIO,
> + basically the context of the authentication session
> + */
> + struct MPVIO_EXT : public MYSQL_PLUGIN_VIO
> + {
> + MYSQL_SERVER_AUTH_INFO auth_info;
> + THD *thd;
> + ACL_USER *acl_user; ///< a copy, independent from acl_users array
> + plugin_ref plugin; ///< what plugin we're under
> + LEX_STRING db; ///< db name from the handshake packet
> + /** when restarting a plugin this caches the last client reply */
> + struct {
> + char *plugin, *pkt; ///< pointers into NET::buff
> + uint pkt_len;
> + } cached_client_reply;
> + /** this caches the first plugin packet for restart request on the client */
> + struct {
> + char *pkt;
> + uint pkt_len;
> + } cached_server_packet;
> + int packets_read, packets_written; ///< counters for send/received packets
> + uint connect_errors; ///< if there were connect errors for this host
> + /** when plugin returns a failure this tells us what really happened */
> + enum { SUCCESS, FAILURE, RESTART } status;
> + };
Change comments from ///< to //
(No reason for new style here)
Also change /** to /*
> +
> + /**
> + a helper function to report an access denied error in all the proper places
> + */
> + static void login_failed_error(THD *thd, bool passwd_used)
> + {
> + my_error(ER_ACCESS_DENIED_ERROR, MYF(0),
> + thd->main_security_ctx.user,
> + thd->main_security_ctx.host_or_ip,
> + passwd_used ? ER(ER_YES) : ER(ER_NO));
> + general_log_print(thd, COM_CONNECT, ER(ER_ACCESS_DENIED_ERROR),
> + thd->main_security_ctx.user,
> + thd->main_security_ctx.host_or_ip,
> + passwd_used ? ER(ER_YES) : ER(ER_NO));
> + status_var_increment(thd->status_var.access_denied_errors);
> + /*
> + Log access denied messages to the error log when log-warnings = 2
> + so that the overhead of the general query log is not required to track
> + failed connections.
> + */
> + if (global_system_variables.log_warnings > 1)
> + {
> + sql_print_warning(ER(ER_ACCESS_DENIED_ERROR),
> + thd->main_security_ctx.user,
> + thd->main_security_ctx.host_or_ip,
> + passwd_used ? ER(ER_YES) : ER(ER_NO));
> + }
> + }
Both general_log_print() and sql_print_warning() prints error to log
file. Shouldn't we remove the first general_log_print() from above?
(I couldn't find the sql_print_warning() in the old code).
> +
> + /**
> + sends a server handshake initialization packet, the very first packet
> + after the connection was established
> +
> + Packet format:
> +
> + Bytes Content
> + ----- ----
> + 1 protocol version (always 10)
> + n server version string, \0-terminated
> + 4 thread id
> + 8 first 8 bytes of the plugin provided data (scramble)
> + 1 \0 byte, terminating the first part of a scramble
> + 2 server capabilities (two lower bytes)
> + 1 server character set
> + 2 server status
> + 2 server capabilities (two upper bytes)
> + 1 length of the scramble
> + 10 reserved, always 0
> + n rest of the plugin provided data (at least 12 bytes)
> + 1 \0 byte, terminating the second part of a scramble
> +
> + @retval 0 ok
> + @retval 1 error
> + */
Shouldn't this function be in sql_connect.c ?
> + static bool send_server_handshake_packet(MPVIO_EXT *mpvio,
> + const char *data, uint data_len)
> + {
> + DBUG_ASSERT(mpvio->status == MPVIO_EXT::FAILURE);
Add also an assert if data_len > 255.
> +
> + THD *thd= mpvio->thd;
> + char *buff= (char *)my_alloca(1 + SERVER_VERSION_LENGTH + data_len + 64);
> + char scramble_buf[SCRAMBLE_LENGTH];
> + char *end= buff;
> +
> + *end++= protocol_version;
> +
> + thd->client_capabilities= CLIENT_BASIC_FLAGS;
> +
> + if (data_len)
> + {
> + mpvio->cached_server_packet.pkt= (char*)thd->memdup(data, data_len);
> + mpvio->cached_server_packet.pkt_len= data_len;
> + }
> +
> + if (data_len < SCRAMBLE_LENGTH)
> + {
> + if (data_len)
> + { /*
> + the first packet *must* have at least 20 bytes of a scramble.
> + if a plugin provided less, we pad it to 20 with zeros
> + */
> + memcpy(scramble_buf, data, data_len);
> + bzero(scramble_buf+data_len, SCRAMBLE_LENGTH-data_len);
> + data= scramble_buf;
> + }
> + else
> + {
> + /*
> + if the default plugin does not provide the data for the scramble at
> + all, we generate a scramble internally anyway, just in case the
> + user account (that will be known only later) uses a
> + native_password_plugin (which needs a scramble). If we don't send a
> + scramble now - wasting 20 bytes in the packet -
> + native_password_plugin will have to send it in a separate packet,
> + adding one more round trip.
> + */
> + create_random_string(thd->scramble, SCRAMBLE_LENGTH, &thd->rand);
> + data= thd->scramble;
> + }
You could move the above to an else of the first if (data_len) and
move the first part inside the first if.
This saves one-two if's during execution and makes code shorter.
> + data_len= SCRAMBLE_LENGTH;
> + }
> +
> + if (opt_using_transactions)
> + thd->client_capabilities|= CLIENT_TRANSACTIONS;
> +
> + thd->client_capabilities|= CAN_CLIENT_COMPRESS;
> +
> + if (ssl_acceptor_fd)
> + {
> + thd->client_capabilities |= CLIENT_SSL;
> + thd->client_capabilities |= CLIENT_SSL_VERIFY_SERVER_CERT;
> + }
> +
> + end= strnmov(end, server_version, SERVER_VERSION_LENGTH) + 1;
> + int4store((uchar*) end, mpvio->thd->thread_id);
> + end+= 4;
> +
> + /*
> + Old clients does not understand long scrambles, but can ignore packet
> + tail: that's why first part of the scramble is placed here, and second
> + part at the end of packet.
> + */
> + end= (char*)memcpy(end, data, SCRAMBLE_LENGTH_323);
> + end+= SCRAMBLE_LENGTH_323;
> + *end++= 0;
> +
> + int2store(end, thd->client_capabilities);
> + /* write server characteristics: up to 16 bytes allowed */
> + end[2]=(char) default_charset_info->number;
> + int2store(end+3, mpvio->thd->server_status);
> + int2store(end+5, thd->client_capabilities >> 16);
> + end[7]= data_len;
> + bzero(end+8, 10);
> + end+= 18;
> + /* write scramble tail */
> + end= (char*)memcpy(end, data + SCRAMBLE_LENGTH_323,
> + data_len - SCRAMBLE_LENGTH_323);
Note that in old code, we had an end zero after scramble, that you
don't have here. I checked the client code and at least in the .c
client it's safe to nto have the end \0. You should probable check
with other native drivers that it's safe with them too.
(Especially the php driver).
> + end+= data_len - SCRAMBLE_LENGTH_323;
> + end= strmake(end, plugin_name(mpvio->plugin)->str,
> + plugin_name(mpvio->plugin)->length);
> +
> + int res= my_net_write(&mpvio->thd->net, (uchar*) buff, (size_t) (end-buff)) ||
> + net_flush(&mpvio->thd->net);
Please move declaration of 'res' to function start.
> + my_afree(buff);
> + return res;
> + }
> +
> + static uchar switch_plugin_request_buf[]= { 254 };
Move to file start.
> +
> + /**
> + sends a "change plugin" packet, requesting a client to restart authentication
> + using a different authentication plugin
> +
> + Packet format:
> +
> + Bytes Content
> + ----- ----
> + 1 byte with the value 254
> + n client plugin to use, \0-terminated
> + n plugin provided data
> +
> + In a special case of switching from native_password_plugin to
> + old_password_plugin, the packet contains only one - the first - byte,
> + plugin name is omitted, plugin data aren't needed as the scramble was
> + already sent. This one-byte packet is identical to the "use the short
> + scramble" packet in the protocol before plugins were introduced.
> +
> + @retval 0 ok
> + @retval 1 error
> + */
Maybe this also should be in sql_connect.cc ?
> + static bool send_plugin_request_packet(MPVIO_EXT *mpvio,
> + const uchar *data, uint data_len)
> + {
> + DBUG_ASSERT(mpvio->packets_written == 1);
> + DBUG_ASSERT(mpvio->packets_read == 1);
> + NET *net= &mpvio->thd->net;
> +
> + mpvio->status= MPVIO_EXT::FAILURE; // the status is no longer RESTART
> +
> + const char *client_auth_plugin=
> + ((st_mysql_auth *)(plugin_decl(mpvio->plugin)->info))->client_auth_plugin;
> +
> + DBUG_ASSERT(client_auth_plugin);
Wouldn't it be better to make this a LEX_STRING *?
(You can then avoid the strlen() later on)
> +
> + /*
> + we send an old "short 4.0 scramble request", if we need to request a
> + client to use 4.0 auth plugin (short scramble) and the scramble was
> + already sent to the client
> + */
> + bool switch_from_long_to_short_scramble=
Please move all variable declaration to start or in this case, just
change this to one if without a variable
> + my_strcasecmp(system_charset_info, native_password_plugin_name.str,
> + mpvio->cached_client_reply.plugin) == 0 &&
> + client_auth_plugin == old_password_plugin_name.str;
> +
> + if (switch_from_long_to_short_scramble)
> + return my_net_write(net, switch_plugin_request_buf, 1) ||
> + net_flush(net);
Please add to the above comment how
mpvio->cached_client_reply.plugin and client_auth_plugin comes are set?
>From IRC:
client_auth_plugin is set from the data in the users table.
mpvio->cached_client_reply.plugin contains what client tried to use.
> +
> + /*
> + We never request a client to switch from a short to long scramble.
> + Plugin-aware clients can do that, but traditionally it meant to
> + ask an old 4.0 client to use the new 4.1 authentication protocol.
> + */
> + bool switch_from_short_to_long_scramble=
> + my_strcasecmp(system_charset_info, old_password_plugin_name.str,
> + mpvio->cached_client_reply.plugin) == 0 &&
> + client_auth_plugin == native_password_plugin_name.str;
> +
> + if (switch_from_short_to_long_scramble)
Remove variable.
> + {
> + my_error(ER_NOT_SUPPORTED_AUTH_MODE, MYF(0));
> + general_log_print(mpvio->thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE));
> + return 1;
> + }
> +
> + return net_write_command(net, switch_plugin_request_buf[0],
> + (uchar*)client_auth_plugin,
> + strlen(client_auth_plugin)+1,
> + (uchar*)data, data_len);
> + }
> +
> + #ifndef NO_EMBEDDED_ACCESS_CHECKS
> + /**
> + Finds acl entry in user database for authentication purposes.
> +
> + Finds a user and copies it into mpvio. Reports an authentication
> + failure if a user is not found.
> +
> + @note find_acl_user is not the same, because it doesn't take into
> + account the case when user is not empty, but acl_user->user is empty
> +
> + @retval 0 found
> + @retval 1 not found
> + */
Please add blank line for each /*^Jstatic expression.
> + static bool find_mpvio_user(MPVIO_EXT *mpvio, Security_context *sctx)
> + {
> + pthread_mutex_lock(&acl_cache->lock);
> + for (uint i=0 ; i < acl_users.elements ; i++)
> + {
> + ACL_USER *acl_user_tmp= dynamic_element(&acl_users,i,ACL_USER*);
> + if (!acl_user_tmp->user || (!strcmp(sctx->user, acl_user_tmp->user) &&
> + compare_hostname(&acl_user_tmp->host, sctx->host, sctx->ip)))
Fix indentation (move (!strcmp to next line))
Isn't the test wrong ?
Shouldn't it be:
if (((!acl_user_tmp->user ||
(acl_user_tmp->user && strcmp(user, acl_user_tmp->user) == 0))) &&
compare_hostname(&acl_user_tmp->host, sctx->host, sctx->ip)
As now compare_hostname() is not called if user is NULL
> +
> + {
> + mpvio->acl_user= acl_user_tmp->copy(mpvio->thd->mem_root);
> + break;
> + }
> + }
> + pthread_mutex_unlock(&acl_cache->lock);
> +
> + if (!mpvio->acl_user)
> + {
> + login_failed_error(mpvio->thd, 0);
> + return 1;
> + }
Add an assert at function start that this is zero.
> +
> + /* user account requires non-default plugin and the client is too old */
> + if (my_strcasecmp(system_charset_info, mpvio->acl_user->plugin.str,
> + native_password_plugin_name.str) &&
> + my_strcasecmp(system_charset_info, mpvio->acl_user->plugin.str,
> + old_password_plugin_name.str) &&
Haveing a 'native' plugin field, would make this test:
if (!mpvio->acl_user->plugin.native_plugin)
I think we really should do this as it makes code shorter and we don't
have to do a lot of name comparisons everywhere.
<cut>
> + mpvio->auth_info.user_name= sctx->user;
> + mpvio->auth_info.auth_string= mpvio->acl_user->auth_string.str;
> + strmake(mpvio->auth_info.authenticated_as, mpvio->acl_user->user ?
> + mpvio->acl_user->user : "", USERNAME_LENGTH);
I plan to fix that acl_user->user is never a null pointer. This will
remove a lot of if's in the code.
> +
> + return 0;
> + }
> + #endif
> +
> + /* the packet format is described in send_change_user_packet() */
> + static bool parse_com_change_user_packet(MPVIO_EXT *mpvio, uint packet_length)
> + {
> + THD *thd= mpvio->thd;
> + NET *net= &thd->net;
> + Security_context *sctx= thd->security_ctx;
> +
> + char *user= (char*) net->read_pos;
> + char *end= user + packet_length;
> + /* Safe because there is always a trailing \0 at the end of the packet */
> + char *passwd= strend(user)+1;
> + uint user_len= passwd - user - 1;
> + char *db= passwd;
> + char db_buff[NAME_LEN + 1]; // buffer to store db in utf8
> + char user_buff[USERNAME_LENGTH + 1]; // buffer to store user in utf8
> + uint dummy_errors;
> +
> + if (passwd >= end)
> + {
> + my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
> + return 1;
> + }
> +
> + /*
> + Old clients send null-terminated string as password; new clients send
> + the size (1 byte) + string (not null-terminated). Hence in case of empty
> + password both send '\0'.
> +
> + This strlen() can't be easily deleted without changing protocol.
> +
> + Cast *passwd to an unsigned char, so that it doesn't extend the sign for
> + *passwd > 127 and become 2**32-127+ after casting to uint.
> + */
> + uint passwd_len= (thd->client_capabilities & CLIENT_SECURE_CONNECTION ?
> + (uchar)(*passwd++) : strlen(passwd));
Move declaration first
> +
> + db+= passwd_len + 1;
Better to do:
db= passwd + passwd_len + 1;
And remove initialization from start.
> + /*
> + Database name is always NUL-terminated, so in case of empty database
> + the packet must contain at least the trailing '\0'.
> + */
> + if (db >= end)
> + {
> + my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
> + return 1;
> + }
> +
> + uint db_len= strlen(db);
> +
> + char *ptr= db + db_len + 1;
Move declarations first.
> +
> + /* Convert database and user names to utf8 */
> + db_buff[db_len= copy_and_convert(db_buff, sizeof(db_buff)-1,
> + system_charset_info, db, db_len,
> + thd->charset(), &dummy_errors)]= 0;
We don't need to set end \0 here as we use make__lex_string() on
db_buff.
> + db= db_buff;
> +
> + user_buff[user_len= copy_and_convert(user_buff, sizeof(user_buff)-1,
> + system_charset_info, user, user_len,
> + thd->charset(), &dummy_errors)]= '\0';
We shouldn't set end \0 here either.
Better to use my_strndup() below.
(It's also faster than my_strdup())
> + user= user_buff;
> +
> + if (ptr+1 < end)
> + {
> + uint cs_number= uint2korr(ptr);
> + thd_init_client_charset(thd, cs_number);
> + thd->update_charset();
Add ptr+= 2 here (Makes rest of code simpler).
> + }
We should first set the character set and then do copy_and_convert()
(The old code on sql_connect() did it that way)
> +
> + if (!(sctx->user= my_strdup(user, MYF(MY_WME))))
> + return 1;
my_strdup -> my_strndup()
> +
> + /* Clear variables that are allocated */
> + thd->user_connect= 0;
> + strmake(sctx->priv_user, sctx->user, USERNAME_LENGTH);
> +
> + if (thd->make_lex_string(&mpvio->db, db, db_len, 0) == 0)
> + return 1; /* The error is set by make_lex_string(). */
> +
> + /*
> + Clear thd->db as it points to something, that will be freed when
> + connection is closed. We don't want to accidentally free a wrong
> + pointer if connect failed.
> + */
> + thd->reset_db(NULL, 0);
> +
> + if (!initialized)
> + {
> + // if mysqld's been started with --skip-grant-tables option
> + mpvio->status= MPVIO_EXT::SUCCESS;
> + return 0;
> + }
> +
> + #ifndef NO_EMBEDDED_ACCESS_CHECKS
> + if (find_mpvio_user(mpvio, sctx))
> + return 1;
> +
> + char *client_plugin;
> + if (thd->client_capabilities & CLIENT_PLUGIN_AUTH)
> + {
> + client_plugin= ptr + 2;
Use client_plugin= ptr;
> + if (client_plugin >= end)
> + {
> + my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
> + return 1;
> + }
> + }
> + else
Add brace here
> + if (thd->client_capabilities & CLIENT_SECURE_CONNECTION)
> + client_plugin= native_password_plugin_name.str;
> + else
> + {
> + client_plugin= old_password_plugin_name.str;
> + /*
> + For a passwordless accounts we use native_password_plugin.
> + But when an old 4.0 client connects to it, we change it to
> + old_password_plugin, otherwise MySQL will think that server
> + and client plugins don't match.
> + */
> + if (mpvio->acl_user->auth_string.length == 0)
> + mpvio->acl_user->plugin= old_password_plugin_name;
> + }
> +
> + /* remember the data part of the packet, to present it to plugin in read_packet() */
> + mpvio->cached_client_reply.pkt= passwd;
> + mpvio->cached_client_reply.pkt_len= passwd_len;
> + mpvio->cached_client_reply.plugin= client_plugin;
Consider adding here
mpvio->cached_client_reply.native_plugin= 0 | 1;
(I know it requires a two strcasecmp() when the client packet contains
a plugin, but as this is not the normal case, it's ok.
> + mpvio->status= MPVIO_EXT::RESTART;
> + #endif
> +
> + return 0;
> + }
> +
> + /* the packet format is described in send_client_reply_packet() */
> + static ulong parse_client_handshake_packet(MPVIO_EXT *mpvio,
> + uchar **buff, ulong pkt_len)
> + {
> + #ifndef EMBEDDED_LIBRARY
> + THD *thd= mpvio->thd;
> + NET *net= &thd->net;
> + char *end;
> +
> + DBUG_ASSERT(mpvio->status == MPVIO_EXT::FAILURE);
> +
> + if (pkt_len < MIN_HANDSHAKE_SIZE)
> + return packet_error;
> +
> + if (mpvio->connect_errors)
> + reset_host_errors(&net->vio->remote.sin_addr);
> +
> + ulong client_capabilities= uint2korr(net->read_pos);
Move declaration to function start
> + if (client_capabilities & CLIENT_PROTOCOL_41)
> + {
> + 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]));
> + thd_init_client_charset(thd, (uint) net->read_pos[8]);
> + thd->update_charset();
> + end= (char*) net->read_pos+32;
> + }
> + else
> + {
> + thd->max_client_packet_length= uint3korr(net->read_pos+2);
> + end= (char*) net->read_pos+5;
> + }
> +
> + /* Disable those bits which are not supported by the client. */
Should be 'server' not 'client' as client_capabilities are initially
set by server.
> + thd->client_capabilities&= client_capabilities;
> +
> + if (thd->client_capabilities & CLIENT_IGNORE_SPACE)
> + thd->variables.sql_mode|= MODE_IGNORE_SPACE;
> +
> + DBUG_PRINT("info", ("client capabilities: %lu", thd->client_capabilities));
> + if (thd->client_capabilities & CLIENT_SSL)
> + {
> + char error_string[1024] __attribute__((unused));
> +
> + /* Do the SSL layering. */
> + if (!ssl_acceptor_fd)
> + return packet_error;
> +
> + DBUG_PRINT("info", ("IO layer change in progress..."));
> + if (sslaccept(ssl_acceptor_fd, net->vio, net->read_timeout, error_string))
> + {
> + DBUG_PRINT("error", ("Failed to accept new SSL connection"));
> + return packet_error;
> + }
> +
> + DBUG_PRINT("info", ("Reading user information over SSL layer"));
> + pkt_len= my_net_read(net);
> + if (pkt_len == packet_error || pkt_len < NORMAL_HANDSHAKE_SIZE)
> + {
> + DBUG_PRINT("error", ("Failed to read user information (pkt_len= %lu)",
> + pkt_len));
> + return packet_error;
> + }
> + }
> +
> + if (end >= (char*) net->read_pos+ pkt_len +2)
> + return packet_error;
> +
> + if (thd->client_capabilities & CLIENT_INTERACTIVE)
> + thd->variables.net_wait_timeout= thd->variables.net_interactive_timeout;
> + if ((thd->client_capabilities & CLIENT_TRANSACTIONS) &&
> + opt_using_transactions)
> + net->return_status= &thd->server_status;
> +
> + char *user= end;
> + char *passwd= strend(user)+1;
> + uint user_len= passwd - user - 1;
> + char *db= passwd;
> + char db_buff[NAME_LEN + 1]; // buffer to store db in utf8
> + char user_buff[USERNAME_LENGTH + 1]; // buffer to store user in utf8
> + uint dummy_errors;
Please move variable declaration to function start.
> +
> + /*
> + Old clients send null-terminated string as password; new clients send
> + the size (1 byte) + string (not null-terminated). Hence in case of empty
> + password both send '\0'.
> +
> + This strlen() can't be easily deleted without changing protocol.
> +
> + Cast *passwd to an unsigned char, so that it doesn't extend the sign for
> + *passwd > 127 and become 2**32-127+ after casting to uint.
> + */
> + uint passwd_len= thd->client_capabilities & CLIENT_SECURE_CONNECTION ?
> + (uchar)(*passwd++) : strlen(passwd);
> + db= thd->client_capabilities & CLIENT_CONNECT_WITH_DB ?
> + db + passwd_len + 1 : 0;
> + /* strlen() can't be easily deleted without changing protocol */
> + uint db_len= db ? strlen(db) : 0;
Please clean up the above test to:
(Yes, I know it's old code, but better to fix it now as we are working
on it)
db_len= 0;
db= 0;
if (thd->client_capabilities & CLIENT_CONNECT_WITH_DB)
{
db= passwd + passwd_len + 1;
/* strlen() can't be easily deleted without changing protocol */
db_len= strlen(db);
}
> +
> + if (passwd + passwd_len + db_len > (char *)net->read_pos + pkt_len)
> + return packet_error;
> +
> + char *client_plugin= passwd + passwd_len + (db ? db_len + 1 : 0);
client_plugin= passwd + passwd_len + db_len + test(db_len);
> +
> + /* Since 4.1 all database names are stored in utf8 */
> + if (db)
> + {
> + db_buff[db_len= copy_and_convert(db_buff, sizeof(db_buff)-1,
> + system_charset_info,
> + db, db_len,
> + thd->charset(), &dummy_errors)]= 0;
No reason to set \0
> + db= db_buff;
> + }
> +
> + user_buff[user_len= copy_and_convert(user_buff, sizeof(user_buff)-1,
> + system_charset_info, user, user_len,
> + thd->charset(), &dummy_errors)]= '\0';
No reason to set \0
> + user= user_buff;
> +
> + /* If username starts and ends in "'", chop them off */
> + if (user_len > 1 && user[0] == '\'' && user[user_len - 1] == '\'')
> + {
> + user[user_len-1]= 0;
Remove setting of \0
> + user++;
> + user_len-= 2;
> + }
> +
> + Security_context *sctx= thd->security_ctx;
> +
> + if (thd->make_lex_string(&mpvio->db, db, db_len, 0) == 0)
> + return packet_error; /* The error is set by make_lex_string(). */
> + if (sctx->user)
> + x_free(sctx->user);
> + if (!(sctx->user= my_strdup(user, MYF(MY_WME))))
strdup-> strndup
> + return packet_error; /* The error is set by my_strdup(). */
> +
> + /*
> + Clear thd->db as it points to something, that will be freed when
> + connection is closed. We don't want to accidentally free a wrong
> + pointer if connect failed.
> + */
> + thd->reset_db(NULL, 0);
> +
> + if (!initialized)
> + {
> + // if mysqld's been started with --skip-grant-tables option
> + mpvio->status= MPVIO_EXT::SUCCESS;
> + return packet_error;
> + }
> +
> + if (find_mpvio_user(mpvio, sctx))
> + return packet_error;
> +
> + if (thd->client_capabilities & CLIENT_PLUGIN_AUTH)
> + {
> + if ((client_plugin + strlen(client_plugin)) >
> + (char *)net->read_pos + pkt_len)
> + return packet_error;
> + }
> + else
Add brace
> + if (thd->client_capabilities & CLIENT_SECURE_CONNECTION)
> + client_plugin= native_password_plugin_name.str;
> + else
> + {
> + client_plugin= old_password_plugin_name.str;
> + /*
> + For a passwordless accounts we use native_password_plugin.
> + But when an old 4.0 client connects to it, we change it to
> + old_password_plugin, otherwise MySQL will think that server
> + and client plugins don't match.
> + */
> + if (mpvio->acl_user->auth_string.length == 0)
> + mpvio->acl_user->plugin= old_password_plugin_name;
> + }
> +
<cut>
> + /*
> + ok, we don't need to restart the authentication on the server.
> + but if the client used the wrong plugin, we need to restart
> + the authentication on the client. Do it here, the server plugin
> + doesn't need to know.
> + */
> + const char *client_auth_plugin=
> + ((st_mysql_auth *)(plugin_decl(mpvio->plugin)->info))->client_auth_plugin;
Would be better as a LEX_STRING *, so ether comments.
> +
> + if (client_auth_plugin &&
> + my_strcasecmp(system_charset_info, client_plugin, client_auth_plugin))
> + {
> + mpvio->cached_client_reply.plugin= client_plugin;
> + if (send_plugin_request_packet(mpvio,
> + (uchar*)mpvio->cached_server_packet.pkt,
> + mpvio->cached_server_packet.pkt_len))
> + return packet_error;
> +
> + passwd_len= my_net_read(&mpvio->thd->net);
> + passwd = (char*)mpvio->thd->net.read_pos;
> + }
> +
> + *buff= (uchar*)passwd;
> + return passwd_len;
> + #else
> + return 0;
> + #endif
> + }
> +
Add empty line
> + /**
> + vio->write_packet() callback method for server authentication plugins
> +
> + This function is called by a server authentication plugin, when it wants
> + to send data to the client.
> +
> + It transparently wraps the data into a handshake packet,
> + and handles plugin negotiation with the client. If necessary,
> + it escapes the plugin data, if it starts with a mysql protocol packet byte.
> + */
> + static int server_mpvio_write_packet(MYSQL_PLUGIN_VIO *param,
> + const uchar *packet, int packet_len)
> + {
> + MPVIO_EXT *mpvio= (MPVIO_EXT*)param;
> + int res;
Add empty line
> + /* reset cached_client_reply */
> + mpvio->cached_client_reply.pkt= 0;
<cut>
> + static int server_mpvio_read_packet(MYSQL_PLUGIN_VIO *param, uchar **buf)
> + {
> + MPVIO_EXT *mpvio= (MPVIO_EXT*)param;
> + ulong pkt_len;
> +
> + if (mpvio->packets_written == 0)
> + {
> + /*
> + plugin wants to read the data without sending anything first.
> + send an empty packet, to start a handshake
> + */
Change 'empty packet' to 'server_handshake_packet'.
Here, the code would be much clearer if we would just use:
mpvio->cached_client_reply.pkt= 0;
mpvio->packets_written++;
if (send_server_handshake_packet(mpvio, 0,0))
> + if (server_mpvio_write_packet(mpvio, 0, 0))
> + pkt_len= packet_error;
> + else
> + pkt_len= my_net_read(&mpvio->thd->net);
> + }
> + else
Move if to after else
> + if (mpvio->cached_client_reply.pkt)
> + {
> + DBUG_ASSERT(mpvio->status == MPVIO_EXT::RESTART);
> + DBUG_ASSERT(mpvio->packets_read > 0);
> + /*
> + if the have the data cached from the last server_mpvio_read_packet
> + (which can be the case if it's a restarted authentication)
> + and a client has used the correct plugin, then we can return the
> + cached data straight away and avoid one round trip.
> + */
> + const char *client_auth_plugin=
> + ((st_mysql_auth *)(plugin_decl(mpvio->plugin)->info))->client_auth_plugin;
> + if (client_auth_plugin == 0 ||
> + my_strcasecmp(system_charset_info, mpvio->cached_client_reply.plugin,
> + client_auth_plugin) == 0)
> + {
> + mpvio->status= MPVIO_EXT::FAILURE;
> + *buf= (uchar*)mpvio->cached_client_reply.pkt;
> + mpvio->cached_client_reply.pkt= 0;
> + mpvio->packets_read++;
> + return (int)mpvio->cached_client_reply.pkt_len;
> + }
> + /*
> + But if the client has used the wrong plugin, the cached data are
> + useless. Furthermore, we have to send a "change plugin" request
> + to the client.
> + */
Here also, it would be clearer if we did:
mpvio->cached_client_reply.pkt= 0;
mpvio->packets_written++;
if (send_plugin_request_packet(mpvio, 0, 0))
(Of course, we can do the packets_written in
send_plugin_request_packet and send_server_handshake_packet() to
remove the above increments.
<cut>
> + /**
> + fills MYSQL_PLUGIN_VIO_INFO structure with the information about the
> + connection
> + */
> + static void server_mpvio_info(MYSQL_PLUGIN_VIO *vio,
> + MYSQL_PLUGIN_VIO_INFO *info)
> + {
> + MPVIO_EXT *mpvio= (MPVIO_EXT*)vio;
> + mpvio_info(mpvio->thd->net.vio, info);
> + }
> +
> + static int acl_check_ssl(THD *thd, ACL_USER *acl_user)
int -> bool
Add function comment (at least regarding return values)
<cut>
> + /**
> + Perform the handshake, authorize the client and update thd sctx variables.
> +
> + @param thd thread handle
> + @param connect_errors number of previous failed connect attemps
> + from this host
> + @param com_change_user_pkt_len size of the COM_CHANGE_USER packet
> + (without the first, command, byte) or 0
> + if it's not a COM_CHANGE_USER (that is, if
> + it's a new connection)
> +
> + @retval 0 success, thd is updated.
> + @retval 1 error
> + */
> + int acl_authenticate(THD *thd, uint connect_errors, uint com_change_user_pkt_len)
int -> bool
> + {
> + DBUG_ENTER("acl_authenticate");
Add DBUG_ENTER() after variable declarations.
> + int res, old_status;
> + plugin_ref plugin;
> + MPVIO_EXT mpvio;
> + st_mysql_auth *auth;
> + LEX_STRING *auth_plugin_name= default_auth_plugin_name;
> + bool unlock_plugin;
> + enum enum_server_command command= com_change_user_pkt_len ? COM_CHANGE_USER
> + : COM_CONNECT;
> +
> + compile_time_assert(MYSQL_USERNAME_LENGTH == USERNAME_LENGTH);
> +
> + bzero(&mpvio, sizeof(mpvio));
> + mpvio.read_packet= server_mpvio_read_packet;
> + mpvio.write_packet= server_mpvio_write_packet;
> + mpvio.info= server_mpvio_info;
> + mpvio.thd= thd;
> + mpvio.connect_errors= connect_errors;
> + mpvio.status= MPVIO_EXT::FAILURE;
> +
> + if (com_change_user_pkt_len == 0)
> + thd->scramble[SCRAMBLE_LENGTH]= 1; // it means - there is no scramble yet
Wouldn't it be better to use a separate flag or state for this?
Using part of scramble, even if it's safe, looks strange and hard to
remember. Having a state in MPVIO_EXT of what has taken place could
be a good addition. This could be better than just incrementing
packets_written / packets_read (in the case we ever want to do more
round trips than 2)
> + else
> + {
> + mpvio.packets_written++; // pretend that a server handshake packet was sent
> + mpvio.packets_read++; // take COM_CHANGE_USER packet into account
> +
> + if (parse_com_change_user_packet(&mpvio, com_change_user_pkt_len))
> + DBUG_RETURN(1);
> +
> + DBUG_ASSERT(mpvio.status == MPVIO_EXT::RESTART ||
> + mpvio.status == MPVIO_EXT::SUCCESS);
> + /*
> + we skip the first step of the authentication -
> + the one that starts a default plugin, sends the handshake packet with the
> + scramble and reads the packet with the user name.
> + in COM_CHANGE_USER the client already has the scramble and we already
> + know the user name
> + */
> + goto skip_first;
Noe that 'res' and 'old_status' variables are not set here,
which may be a problem as they could be tested below.
> + }
> +
The 'goto's here are not nice.
A way to fix it is to move the code between 'retry' and 'skip_first'
to a function and use:
if (!mpvio.plugin= get_plugin(auth_plugin_name))
DBUG_RETURN(1);
In the above if and instead of 'goto retry'.
With this, you can remove both 'retry' and 'skip_first'
and replace this with a for (;;) loop.
> + retry:
> + unlock_plugin= false;
> + if (auth_plugin_name->str == native_password_plugin_name.str)
> + plugin= native_password_plugin;
> + else
> + #ifndef EMBEDDED_LIBRARY
> + if (auth_plugin_name->str == old_password_plugin_name.str)
> + plugin= old_password_plugin;
> + else
> + if ((plugin= my_plugin_lock_by_name(thd, auth_plugin_name,
> + MYSQL_AUTHENTICATION_PLUGIN)))
> + unlock_plugin= true;
> + else
> + #endif
> + {
> + /* Server cannot load required plugin. */
> + my_error(ER_PLUGIN_IS_NOT_LOADED, MYF(0), auth_plugin_name->str);
> + DBUG_RETURN(1);
> + }
> +
> + mpvio.plugin= plugin;
> + auth= (st_mysql_auth*)plugin_decl(plugin)->info;
> +
> + old_status= mpvio.status;
> + res= auth->authenticate_user(&mpvio, &mpvio.auth_info);
> +
> + if (unlock_plugin)
> + plugin_unlock(thd, plugin);
> +
> + skip_first:
<cut>
> +
> + if (res > CR_OK && mpvio.status != MPVIO_EXT::SUCCESS)
How about res != CR_OK ? (More clear)
> + {
> + DBUG_ASSERT(mpvio.status == MPVIO_EXT::FAILURE);
> +
> + if (!thd->is_error())
> + login_failed_error(thd, thd->password);
> + DBUG_RETURN(1);
> + }
<cut>
> + if (command == COM_CONNECT &&
> + !(thd->main_security_ctx.master_access & SUPER_ACL))
> + {
> + pthread_mutex_lock(&LOCK_connection_count);
> + bool count_ok= (*thd->scheduler->connection_count <=
> + *thd->scheduler->max_connections);
Indentation...
> + VOID(pthread_mutex_unlock(&LOCK_connection_count));
> + if (!count_ok)
> + { // too many connections
> + my_error(ER_CON_COUNT_ERROR, MYF(0));
> + DBUG_RETURN(1);
> + }
> + }
> +
> + /*
> + This is the default access rights for the current database. It's
> + set to 0 here because we don't have an active database yet (and we
> + may not have an active database to set.
> + */
> + sctx->db_access=0;
> +
> + /* Change a database if necessary */
> + if (mpvio.db.length)
> + {
> + if (mysql_change_db(thd, &mpvio.db, FALSE))
> + {
> + /* mysql_change_db() has pushed the error message. */
> + if (thd->user_connect)
> + {
> + decrease_user_connections(thd->user_connect);
> + status_var_increment(thd->status_var.access_denied_errors);
> + thd->user_connect= 0;
Move this just after the test (easier to read)
> + }
> + DBUG_RETURN(1);
> + }
> + }
> + static int old_password_authenticate(MYSQL_PLUGIN_VIO *vio,
> + MYSQL_SERVER_AUTH_INFO *info)
> + {
> + uchar *pkt;
> + int pkt_len;
> + MPVIO_EXT *mpvio=(MPVIO_EXT*)vio;
> + THD *thd=mpvio->thd;
> +
> + if (thd->scramble[SCRAMBLE_LENGTH])
> + {
> + /* no scramble was sent to the client yet, do it now */
> + create_random_string(thd->scramble,
> + pkt_len= SCRAMBLE_LENGTH, &thd->rand);
> + pkt= (uchar*)thd->scramble;
> + if (mpvio->write_packet(mpvio, pkt, pkt_len))
> + return CR_ERROR;
> + }
> +
> + /* ok, the client has got the scramble. read the reply and authenticate */
> + if ((pkt_len= mpvio->read_packet(mpvio, &pkt)) < 0)
> + return CR_ERROR;
> +
> + #ifdef NO_EMBEDDED_ACCESS_CHECKS
> + return CR_OK;
> + #endif
> +
> + /*
> + legacy: if switch_from_long_to_short_scramble,
> + the password is sent \0-terminated, the pkt_len is always 9 bytes.
> + We need to figure out the correct scramble length here.
> + */
> + if (pkt_len == SCRAMBLE_LENGTH_323+1)
> + pkt_len= strnlen((char*)pkt, pkt_len);
> + if (pkt_len == 0) /* no password */
> + return info->auth_string[0] ? CR_ERROR : CR_OK;
If we want to do things like in the old code, we should here check the
packet length.
if (pkt_len != SCRAMBLE_LENGTH_323)
{
inc_host_errors(&mpvio->thd->net.vio->remote.sin_addr);
my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
return CR_ERROR;
}
> + If the server is running in secure auth mode, short scrambles are
> + forbidden. Extra juggling to report the same error as the old code.
> + */
> + if (opt_secure_auth)
> + {
> + if (thd->client_capabilities & CLIENT_PROTOCOL_41)
> + {
> + my_error(ER_SERVER_IS_IN_SECURE_AUTH_MODE, MYF(0),
> + thd->security_ctx->user,
> + thd->security_ctx->host_or_ip);
> + general_log_print(thd, COM_CONNECT, ER(ER_SERVER_IS_IN_SECURE_AUTH_MODE),
> + thd->security_ctx->user,
> + thd->security_ctx->host_or_ip);
> + }
I think the above error should be tested for and given when we ask for
old scramble. This error is to be given when we get an new format
scramble at start when database has old.
Now we are likely to have a problem that if client sends new password
and server has old, we will request for old one, even if
opt_secure_auth is set, which is not how things worked before.
> + else
> + {
> + my_error(ER_NOT_SUPPORTED_AUTH_MODE, MYF(0));
> + general_log_print(thd, COM_CONNECT, ER(ER_NOT_SUPPORTED_AUTH_MODE));
> + }
> + return CR_ERROR;
> + }
The old code (sql_connect.cc:check_user()) tested first for:
if (opt_secure_auth_local && passwd_len == SCRAMBLE_LENGTH_323)
And the other error condition next.
Here things are reversed so we may get other errors than from MySQL.
> +
> + info->password_used = 1;
> +
> + if (pkt_len == SCRAMBLE_LENGTH_323)
> + return check_scramble_323(pkt, thd->scramble,
> + (ulong *)mpvio->acl_user->salt) ? CR_ERROR : CR_OK;
> +
> + inc_host_errors(&mpvio->thd->net.vio->remote.sin_addr);
> + my_error(ER_HANDSHAKE_ERROR, MYF(0), thd->main_security_ctx.host_or_ip);
> + return CR_ERROR;
If we do the early check, we should of course remove the above if and
the error reporting
> + }
<cut>
> *** sql/sql_insert.cc 2010-02-01 06:14:12 +0000
> --- sql/sql_insert.cc 2010-02-19 08:18:09 +0000
> *************** public:
> *** 1769,1776 ****
> table(0),tables_in_use(0),stacked_inserts(0), status(0), dead(0),
> group_count(0)
> {
> ! thd.security_ctx->user=thd.security_ctx->priv_user=(char*) delayed_user;
> thd.security_ctx->host=(char*) my_localhost;
> thd.current_tablenr=0;
> thd.version=refresh_version;
> thd.command=COM_DELAYED_INSERT;
> --- 1769,1778 ----
> table(0),tables_in_use(0),stacked_inserts(0), status(0), dead(0),
> group_count(0)
> {
> ! thd.security_ctx->user=(char*) delayed_user;
> thd.security_ctx->host=(char*) my_localhost;
> + strmake(thd.security_ctx->priv_user, thd.security_ctx->user,
> + USERNAME_LENGTH);
A little better would be to use delayed_user above, but not that important.
> === modified file 'sql/sql_parse.cc'
> *** sql/sql_parse.cc 2010-02-01 06:14:12 +0000
> case COM_CHANGE_USER:
> {
> status_var_increment(thd->status_var.com_other);
>
> thd->change_user();
> thd->clear_error(); // if errors from rollback
>
> ! /* acl_authenticate() takes the data from net->read_pos */
> ! net->read_pos= (uchar*)packet;
>
> ! uint save_db_length= thd->db_length;
> ! char *save_db= thd->db;
> ! USER_CONN *save_user_connect= thd->user_connect;
> Security_context save_security_ctx= *thd->security_ctx;
> ! CHARSET_INFO *save_character_set_client=
> ! thd->variables.character_set_client;
> ! CHARSET_INFO *save_collation_connection=
> ! thd->variables.collation_connection;
> ! CHARSET_INFO *save_character_set_results=
> ! thd->variables.character_set_results;
Please move declarations to start of case (should make the above one liners)
>
> ! if (acl_authenticate(thd, 0, packet_length))
> {
> x_free(thd->security_ctx->user);
> *thd->security_ctx= save_security_ctx;
> thd->user_connect= save_user_connect;
> thd->db= save_db;
> thd->db_length= save_db_length;
Better to use:
thd->reset_db(save_db, save_db_length);
> + thd->variables.character_set_client= save_character_set_client;
> + thd->variables.collation_connection= save_collation_connection;
> + thd->variables.character_set_results= save_character_set_results;
> + thd->update_charset();
> }
> else
> {
> *** 4348,4355 ****
> if (sp_grant_privileges(thd, lex->sphead->m_db.str, name,
> lex->sql_command == SQLCOM_CREATE_PROCEDURE))
> push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
> ! ER_PROC_AUTO_GRANT_FAIL,
> ! ER(ER_PROC_AUTO_GRANT_FAIL));
> }
>
> /*
> --- 4280,4287 ----
> if (sp_grant_privileges(thd, lex->sphead->m_db.str, name,
> lex->sql_command == SQLCOM_CREATE_PROCEDURE))
> push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
> ! ER_PROC_AUTO_GRANT_FAIL, ER(ER_PROC_AUTO_GRANT_FAIL));
> ! thd->clear_error();
Don't understand why this is needed now, but I assume this isn't
critical to understand (except maybe it would be nice to ensure that
this is correct if sp_grant_privileges did get a out-of-memory error)
<cut>
Other things.
You need to add creation of auth_string to:
scripts/mysql_fix_privilege_tables.sql
In old_password_auth_client(), if we get an error from write_packet,
it would be good to do:
set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate,
ER(CR_SERVER_LOST_EXTENDED),
"sending password information",
errno);
See if you can combine common code from parse_com_change_user_packet()
and parse_client_handshake_packet().
It would also be nice to avoid comparison of strings and even string
pointers and instead compare objects (like pointer to plugin) and
values in plugin object (like if it's native or not).
Other than the above suggestions, it looked good and definitely
something we need!
Regards,
Monty
3
5

[Maria-developers] Updated (by Knielsen): Store in binlog text of statements that caused RBR events (47)
by worklog-noreplyï¼ askmonty.org 29 Mar '10
by worklog-noreplyï¼ askmonty.org 29 Mar '10
29 Mar '10
-----------------------------------------------------------------------
WORKLOG TASK
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
TASK...........: Store in binlog text of statements that caused RBR events
CREATION DATE..: Sat, 15 Aug 2009, 23:48
SUPERVISOR.....: Monty
IMPLEMENTOR....:
COPIES TO......: Knielsen, Serg
CATEGORY.......: Server-Sprint
TASK ID........: 47 (http://askmonty.org/worklog/?tid=47)
VERSION........: Server-9.x
STATUS.........: Code-Review
PRIORITY.......: 60
WORKED HOURS...: 40
ESTIMATE.......: 15 (hours remain)
ORIG. ESTIMATE.: 35
PROGRESS NOTES:
-=-=(Knielsen - Mon, 29 Mar 2010, 10:59)=-=-
Status updated.
--- /tmp/wklog.47.old.27790 2010-03-29 10:59:53.000000000 +0000
+++ /tmp/wklog.47.new.27790 2010-03-29 10:59:53.000000000 +0000
@@ -1 +1 @@
-In-Progress
+Code-Review
-=-=(Alexi - Thu, 18 Feb 2010, 19:29)=-=-
Worked 20 hours (alexi)
Worked 20 hours and estimate 15 hours remain (original estimate unchanged).
-=-=(Serg - Fri, 05 Feb 2010, 14:04)=-=-
Observers changed: Knielsen,Serg
-=-=(Guest - Fri, 05 Feb 2010, 13:40)=-=-
Category updated.
--- /tmp/wklog.47.old.9197 2010-02-05 13:40:36.000000000 +0200
+++ /tmp/wklog.47.new.9197 2010-02-05 13:40:36.000000000 +0200
@@ -1 +1 @@
-Server-RawIdeaBin
+Server-Sprint
-=-=(Guest - Fri, 05 Feb 2010, 13:40)=-=-
Status updated.
--- /tmp/wklog.47.old.9197 2010-02-05 13:40:36.000000000 +0200
+++ /tmp/wklog.47.new.9197 2010-02-05 13:40:36.000000000 +0200
@@ -1 +1 @@
-Un-Assigned
+In-Progress
-=-=(Alexi - Thu, 04 Feb 2010, 09:54)=-=-
Low Level Design modified.
--- /tmp/wklog.47.old.16174 2010-02-04 09:54:13.000000000 +0200
+++ /tmp/wklog.47.new.16174 2010-02-04 09:54:13.000000000 +0200
@@ -171,35 +171,20 @@
5. How slave IO thread requests Annotate_rows events
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-When requesting an event, the slave should inform the master whether
-it should send Annotate_rows events or not. To that end we add a new
-BINLOG_SEND_ANNOTATE_ROWS_EVENT flag used when requesting an event:
+If the replicate-annotate-rows-events option is not set on a slave, there
+is no need for master to send Annotate_rows events to this slave. The slave
+(or mysqlbinlog in remote case), before requesting binlog dump via the
+COM_BINLOG_DUMP command, informs the master whether it should send these
+events by executing the newly added COM_BINLOG_DUMP_OPTIONS_EXT server
+command:
+
+ case COM_BINLOG_DUMP_OPTIONS_EXT:
+ thd->binlog_dump_flags_ext= packet[0];
+ my_ok(thd);
+ break;
- #define BINLOG_DUMP_NON_BLOCK 1
- #define BINLOG_SEND_ANNOTATE_ROWS_EVENT 2
-
- pthread_handler_t handle_slave_io(void *arg)
- { ...
- request_dump(mysql, ...);
- ...
- }
-
- int request_dump(MYSQL* mysql, ...)
- { ...
- if (opt_log_slave_updates &&
- mi->io_thd->variables.binlog_annotate_rows_events)
- binlog_flags|= BINLOG_SEND_ANNOTATE_ROWS_EVENT;
- ...
- int2store(buf + 4, binlog_flags);
- ...
- simple_command(mysql, COM_BINLOG_DUMP, buf, ...);
- ...
- }
-
-NOTE. mysqlbinlog, when remotely requesting BINLOG_DUMP by calling the
-simple_command() function, should also use this flag if it wants (in case
-of the --print-annotate-rows-events option set) to recieve Annotate_rows
-events.
+Note. We add this new command and don't use COM_BINLOG_DUMP to avoid possible
+conflicts with MySQL/Sun.
6. How master executes the request
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -338,10 +323,4 @@
to internals(a)lists.mysql.com about this and suggesting to reserve the
event number.
-Also we should notice the introduction of the BINLOG_SEND_ANNOTATE_ROWS_EVENT
-flag taking into account that MySQL/Sun may also introduce a flag with the
-same value to be used in the request_dump-mysql_binlog_send interface.
-But this is mainly the question of merging: if a conflict concerning this
-flag occur, we may simply change the BINLOG_SEND_ANNOTATE_ROWS_EVENT value
-(this does not require additional changes in the code).
-=-=(Alexi - Sun, 20 Dec 2009, 16:00)=-=-
Low Level Design modified.
--- /tmp/wklog.47.old.19667 2009-12-20 14:00:56.000000000 +0000
+++ /tmp/wklog.47.new.19667 2009-12-20 14:00:56.000000000 +0000
@@ -196,6 +196,11 @@
...
}
+NOTE. mysqlbinlog, when remotely requesting BINLOG_DUMP by calling the
+simple_command() function, should also use this flag if it wants (in case
+of the --print-annotate-rows-events option set) to recieve Annotate_rows
+events.
+
6. How master executes the request
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -212,8 +217,7 @@
Log_event::read_log_event(&log, packet, ...);
...
if ((*packet)[EVENT_TYPE_OFFSET + 1] != ANNOTATE_ROWS_EVENT ||
- flags & BINLOG_SEND_ANNOTATE_ROWS_EVENT ||
- thd->server_id == 0 /* slave == mysqlbinlog */ )
+ flags & BINLOG_SEND_ANNOTATE_ROWS_EVENT)
{
my_net_write(net, packet->ptr(), packet->length());
}
-=-=(Alexi - Sun, 20 Dec 2009, 13:14)=-=-
Low Level Design modified.
--- /tmp/wklog.47.old.11350 2009-12-20 13:14:04.000000000 +0200
+++ /tmp/wklog.47.new.11350 2009-12-20 13:14:04.000000000 +0200
@@ -282,23 +282,18 @@
Annotate_rows_log_event* m_annotate_event;
};
-When the saved Annotate_rows object may be deleted? When all corresponding
-Rows events will be processed, i.e. before processing the first non-Rows
-event (note that Annotate_rows object resides in the binary log *after*
-the (possible) 'BEGIN' Query event which accompanies the rows events; note
-also that this deletion is adjusted with the case when some or all
-corresponding Rows events are filtered out by replicate filter rules):
+The saved Annotate_rows object should be deleted when all corresponding
+Rows events will be processed:
int exec_relay_log_event(THD* thd, Relay_log_info* rli)
{ ...
Log_event *ev= next_event(rli);
...
- if (rli->get_annotate_event() && !IS_RBR_EVENT_TYPE(ev->get_type_code()))
- rli->free_annotate_event();
-
apply_event_and_update_pos(ev, ...);
- if (ev->get_type_code() == ANNOTATE_ROWS_EVENT)
+ if (rli->get_annotate_event() && is_last_rows_event(ev))
+ rli->free_annotate_event();
+ else if (ev->get_type_code() == ANNOTATE_ROWS_EVENT)
rli->set_annotate_event((Annotate_rows_log_event*) ev);
else if (ev->get_type_code() != FORMAT_DESCRIPTION_EVENT)
delete ev;
@@ -307,10 +302,21 @@
where
- #define IS_RBR_EVENT_TYPE(type) ( (type) == TABLE_MAP_EVENT || \
- (type) == WRITE_ROWS_EVENT || \
+ bool is_last_rows_event(Log_event* ev)
+ {
+ Log_event_type type= ev->get_type_code();
+ if (IS_ROWS_EVENT_TYPE(type))
+ {
+ Rows_log_event* rows= (Rows_log_event*)ev;
+ return rows->get_flags(Rows_log_event::STMT_END_F);
+ }
+
+ return 0;
+ }
+
+ #define IS_ROWS_EVENT_TYPE(type) ((type) == WRITE_ROWS_EVENT || \
(type) == UPDATE_ROWS_EVENT || \
- (type) == DELETE_ROWS_EVENT )
+ (type) == DELETE_ROWS_EVENT)
8. General remarks
~~~~~~~~~~~~~~~~~~
-=-=(Alexi - Sun, 20 Dec 2009, 09:29)=-=-
Low Level Design modified.
--- /tmp/wklog.47.old.32726 2009-12-20 07:29:56.000000000 +0000
+++ /tmp/wklog.47.new.32726 2009-12-20 07:29:56.000000000 +0000
@@ -56,7 +56,7 @@
0000006A | 00 | 0 - RESERVED [27]
..... ...
00000081 | 00 | 0 - RESERVED [50]
- 00000082 | 00 | 0 - ANNOTATE_RBR_EVENT [51]
+ 00000082 | 00 | 0 - ANNOTATE_ROWS_EVENT [51]
************************
2. Outline of Annotate_rows event behavior
-=-=(Alexi - Sat, 19 Dec 2009, 16:10)=-=-
Low Level Design modified.
--- /tmp/wklog.47.old.16051 2009-12-19 16:10:48.000000000 +0200
+++ /tmp/wklog.47.new.16051 2009-12-19 16:10:48.000000000 +0200
@@ -253,7 +253,7 @@
thd query to that of the described by the event, i.e. to the query which
caused the subsequent Rows events (see "How Master writes Annotate_rows
events to the binary log" to follow what happens further when the subsequent
-Rows events is applied):
+Rows events are applied):
int Annotate_rows_log_event::do_apply_event(...)
{
------------------------------------------------------------
-=-=(View All Progress Notes, 25 total)=-=-
http://askmonty.org/worklog/index.pl?tid=47&nolimit=1
DESCRIPTION:
Store in binlog (and show in mysqlbinlog output) texts of statements that
caused RBR events
This is needed for (list from Monty):
- Easier to understand why updates happened
- Would make it easier to find out where in application things went
wrong (as you can search for exact strings)
- Allow one to filter things based on comments in the statement.
The cost of this can be that the binlog will be approximately 2x in size
(especially insert of big blob's would be a bit painful), so this should
be an optional feature.
HIGH-LEVEL SPECIFICATION:
Content
~~~~~~~
1. Annotate_rows_log_event
2. Server option: --binlog-annotate-rows-events
3. Server option: --replicate-annotate-rows-events
4. mysqlbinlog option: --print-annotate-rows-events
5. mysqlbinlog output
1. Annotate_rows_log_event [ ANNOTATE_ROWS_EVENT ]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Describes the query which caused the corresponding rows events. Has empty
post-header and contains the query text in its data part. Example:
************************
ANNOTATE_ROWS_EVENT
************************
00000220 | B6 A0 2C 4B | time_when = 1261215926
00000224 | 33 | event_type = 51
00000225 | 64 00 00 00 | server_id = 100
00000229 | 36 00 00 00 | event_len = 54
0000022D | 56 02 00 00 | log_pos = 00000256
00000231 | 00 00 | flags = <none>
------------------------
00000233 | 49 4E 53 45 | query = "INSERT INTO t1 VALUES (1), (2), (3)"
00000237 | 52 54 20 49 |
0000023B | 4E 54 4F 20 |
0000023F | 74 31 20 56 |
00000243 | 41 4C 55 45 |
00000247 | 53 20 28 31 |
0000024B | 29 2C 20 28 |
0000024F | 32 29 2C 20 |
00000253 | 28 33 29 |
************************
In binary log, Annotate_rows event follows the (possible) 'BEGIN' Query event
and precedes the first of Table map events which accompany the corresponding
rows events. (See example in the "mysqlbinlog output" section below.)
2. Server option: --binlog-annotate-rows-events
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Tells the master to write Annotate_rows events to the binary log.
* Variable Name: binlog_annotate_rows_events
* Scope: Global & Session
* Access Type: Dynamic
* Data Type: bool
* Default Value: OFF
NOTE. Session values allows to annotate only some selected statements:
...
SET SESSION binlog_annotate_rows_events=ON;
... statements to be annotated ...
SET SESSION binlog_annotate_rows_events=OFF;
... statements not to be annotated ...
3. Server option: --replicate-annotate-rows-events
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Tells the slave to reproduce Annotate_rows events recieved from the master
in its own binary log (sensible only in pair with log-slave-updates option).
* Variable Name: replicate_annotate_rows_events
* Scope: Global
* Access Type: Read only
* Data Type: bool
* Default Value: OFF
NOTE. Why do we additionally need this 'replicate' option? Why not to make
the slave to reproduce this events when its binlog-annotate-rows-events
global value is ON? Well, because, for example, we may want to configure
the slave which should reproduce Annotate_rows events but has global
binlog-annotate-rows-events = OFF meaning this to be the default value for
the client threads (see also "How slave treats replicate-annotate-rows-events
option" in LLD part).
4. mysqlbinlog option: --print-annotate-rows-events
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
With this option, mysqlbinlog prints the content of Annotate_rows events (if
the binary log does contain them). Without this option (i.e. by default),
mysqlbinlog skips Annotate_rows events.
5. mysqlbinlog output
~~~~~~~~~~~~~~~~~~~~~
With --print-annotate-rows-events, mysqlbinlog outputs Annotate_rows events
in a form like this:
...
# at 1646
#091219 12:45:26 server id 100 end_log_pos 1714 Query thread_id=1
exec_time=0 error_code=0
SET TIMESTAMP=1261215926/*!*/;
BEGIN
/*!*/;
# at 1714
# at 1812
# at 1853
# at 1894
# at 1938
#091219 12:45:26 server id 100 end_log_pos 1812 Query: `DELETE t1, t2 FROM
t1 INNER JOIN t2 INNER JOIN t3 WHERE t1.a=t2.a AND t2.a=t3.a`
#091219 12:45:26 server id 100 end_log_pos 1853 Table_map: `test`.`t1`
mapped to number 16
#091219 12:45:26 server id 100 end_log_pos 1894 Table_map: `test`.`t2`
mapped to number 17
#091219 12:45:26 server id 100 end_log_pos 1938 Delete_rows: table id 16
#091219 12:45:26 server id 100 end_log_pos 1982 Delete_rows: table id 17
flags: STMT_END_F
...
LOW-LEVEL DESIGN:
Content
~~~~~~~
1. Annotate_rows event number
2. Outline of Annotate_rows event behavior
3. How Master writes Annotate_rows events to the binary log
4. How slave treats replicate-annotate-rows-events option
5. How slave IO thread requests Annotate_rows events
6. How master executes the request
7. How slave SQL thread processes Annotate_rows events
8. General remarks
1. Annotate_rows event number
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To avoid possible event numbers conflict with MySQL/Sun, we leave a gap
between the last MySQL event number and the Annotate_rows event number:
enum Log_event_type
{ ...
INCIDENT_EVENT= 26,
// New MySQL event numbers are to be added here
MYSQL_EVENTS_END,
MARIA_EVENTS_BEGIN= 51,
// New Maria event numbers start from here
ANNOTATE_ROWS_EVENT= 51,
ENUM_END_EVENT
};
together with the corresponding extension of 'post_header_len' array in the
Format description event. (This extension does not affect the compatibility
of the binary log). Here is how Format description event looks like with
this extension:
************************
FORMAT_DESCRIPTION_EVENT
************************
00000004 | A1 A0 2C 4B | time_when = 1261215905
00000008 | 0F | event_type = 15
00000009 | 64 00 00 00 | server_id = 100
0000000D | 7F 00 00 00 | event_len = 127
00000011 | 83 00 00 00 | log_pos = 00000083
00000015 | 01 00 | flags = LOG_EVENT_BINLOG_IN_USE_F
------------------------
00000017 | 04 00 | binlog_ver = 4
00000019 | 35 2E 32 2E | server_ver = 5.2.0-MariaDB-alpha-debug-log
..... ...
0000004B | A1 A0 2C 4B | time_created = 1261215905
0000004F | 13 | common_header_len = 19
------------------------
post_header_len
------------------------
00000050 | 38 | 56 - START_EVENT_V3 [1]
..... ...
00000069 | 02 | 2 - INCIDENT_EVENT [26]
0000006A | 00 | 0 - RESERVED [27]
..... ...
00000081 | 00 | 0 - RESERVED [50]
00000082 | 00 | 0 - ANNOTATE_ROWS_EVENT [51]
************************
2. Outline of Annotate_rows event behavior
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Each Annotate_rows_log_event object has two private members describing the
corresponding query:
char *m_query_txt;
uint m_query_len;
When the object is created for writing to a binary log, this query is taken
from 'thd' (for short, below we omit the 'Annotate_rows_log_event::' prefix
as well as other implementation details):
Annotate_rows_log_event(THD *thd)
{
m_query_txt = thd->query();
m_query_len = thd->query_length();
}
When the object is read from a binary log, the query is taken from the buffer
containing the binary log representation of the event (this buffer is allocated
in Log_event object from which all Log events are derived):
Annotate_rows_log_event(char *buf, uint event_len,
Format_description_log_event *desc)
{
m_query_len = event_len - desc->common_header_len;
m_query_txt = buf + desc->common_header_len;
}
The events are written to the binary log by the Log_event::write() member
which calls virtual write_data_header() and write_data_body() members
("data header" and "post header" are synonym in replication terminology).
In our case, data header is empty and data body is just the query:
bool write_data_body(IO_CACHE *file)
{
return my_b_safe_write(file, (uchar*) m_query_txt, m_query_len);
}
Printing the event is just printing the query:
void Annotate_rows_log_event::print(FILE *file, PRINT_EVENT_INFO *pinfo)
{
my_b_printf(&pinfo->head_cache, "\tQuery: `%s`\n", m_query_txt);
}
3. How Master writes Annotate_rows events to the binary log
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The event is written to the binary log just before the group of Table_map
events which precede corresponding Rows events (one query may generate
several Table map events in the binary log, but the corresponding
Annotate_rows event must be written only once before the first Table map
event; hence the boolean variable 'with_annotate' below):
int write_locked_table_maps(THD *thd)
{ ...
bool with_annotate= thd->variables.binlog_annotate_rows_events;
...
for (uint i= 0; i < ... <number of tables> ...; ++i)
{ ...
thd->binlog_write_table_map(table, ..., with_annotate);
with_annotate= 0; // write Annotate_event not more than once
...
}
...
}
int THD::binlog_write_table_map(TABLE *table, ..., bool with_annotate)
{ ...
Table_map_log_event the_event(...);
...
if (with_annotate)
{
Annotate_rows_log_event anno(this);
mysql_bin_log.write(&anno);
}
mysql_bin_log.write(&the_event);
...
}
4. How slave treats replicate-annotate-rows-events option
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The replicate-annotate-rows-events option is treated just as the session
value of the binlog_annotate_rows_events variable for the slave IO and
SQL threads. This setting is done during initialization of these threads:
pthread_handler_t handle_slave_io(void *arg)
{
THD *thd= new THD;
...
init_slave_thread(thd, SLAVE_THD_IO);
...
}
pthread_handler_t handle_slave_sql(void *arg)
{
THD *thd= new THD;
...
init_slave_thread(thd, SLAVE_THD_SQL);
...
}
int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type)
{ ...
thd->variables.binlog_annotate_rows_events=
opt_replicate_annotate_rows_events;
...
}
5. How slave IO thread requests Annotate_rows events
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If the replicate-annotate-rows-events option is not set on a slave, there
is no need for master to send Annotate_rows events to this slave. The slave
(or mysqlbinlog in remote case), before requesting binlog dump via the
COM_BINLOG_DUMP command, informs the master whether it should send these
events by executing the newly added COM_BINLOG_DUMP_OPTIONS_EXT server
command:
case COM_BINLOG_DUMP_OPTIONS_EXT:
thd->binlog_dump_flags_ext= packet[0];
my_ok(thd);
break;
Note. We add this new command and don't use COM_BINLOG_DUMP to avoid possible
conflicts with MySQL/Sun.
6. How master executes the request
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
case COM_BINLOG_DUMP:
{ ...
flags= uint2korr(packet + 4);
...
mysql_binlog_send(thd, ..., flags);
...
}
void mysql_binlog_send(THD* thd, ..., ushort flags)
{ ...
Log_event::read_log_event(&log, packet, ...);
...
if ((*packet)[EVENT_TYPE_OFFSET + 1] != ANNOTATE_ROWS_EVENT ||
flags & BINLOG_SEND_ANNOTATE_ROWS_EVENT)
{
my_net_write(net, packet->ptr(), packet->length());
}
...
}
7. How slave SQL thread processes Annotate_rows events
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The slave processes each recieved event by "applying" it, i.e. by
calling the Log_event::apply_event() function which in turn calls
the virtual do_apply_event() member specific for each type of the
event.
int exec_relay_log_event(THD* thd, Relay_log_info* rli)
{ ...
Log_event *ev = next_event(rli);
...
apply_event_and_update_pos(ev, ...);
if (ev->get_type_code() != FORMAT_DESCRIPTION_EVENT)
delete ev;
...
}
int apply_event_and_update_pos(Log_event *ev, ...)
{ ...
ev->apply_event(...);
...
}
int Log_event::apply_event(...)
{
return do_apply_event(...);
}
What does it mean to "apply" an Annotate_rows event? It means to set current
thd query to that of the described by the event, i.e. to the query which
caused the subsequent Rows events (see "How Master writes Annotate_rows
events to the binary log" to follow what happens further when the subsequent
Rows events are applied):
int Annotate_rows_log_event::do_apply_event(...)
{
thd->set_query(m_query_txt, m_query_len);
}
NOTE. I am not sure, but possibly current values of thd->query and
thd->query_length should be saved before calling set_query() and to be
restored on the Annotate_rows_log_event object deletion.
Is it really needed ?
After calling this do_apply_event() function we may not delete the
Annotate_rows_log_event object immediatedly (see exec_relay_log_event()
above) because thd->query now points to the string inside this object.
We may keep the pointer to this object in the Relay_log_info:
class Relay_log_info
{
public:
...
void set_annotate_event(Annotate_rows_log_event*);
Annotate_rows_log_event* get_annotate_event();
void free_annotate_event();
...
private:
Annotate_rows_log_event* m_annotate_event;
};
The saved Annotate_rows object should be deleted when all corresponding
Rows events will be processed:
int exec_relay_log_event(THD* thd, Relay_log_info* rli)
{ ...
Log_event *ev= next_event(rli);
...
apply_event_and_update_pos(ev, ...);
if (rli->get_annotate_event() && is_last_rows_event(ev))
rli->free_annotate_event();
else if (ev->get_type_code() == ANNOTATE_ROWS_EVENT)
rli->set_annotate_event((Annotate_rows_log_event*) ev);
else if (ev->get_type_code() != FORMAT_DESCRIPTION_EVENT)
delete ev;
...
}
where
bool is_last_rows_event(Log_event* ev)
{
Log_event_type type= ev->get_type_code();
if (IS_ROWS_EVENT_TYPE(type))
{
Rows_log_event* rows= (Rows_log_event*)ev;
return rows->get_flags(Rows_log_event::STMT_END_F);
}
return 0;
}
#define IS_ROWS_EVENT_TYPE(type) ((type) == WRITE_ROWS_EVENT || \
(type) == UPDATE_ROWS_EVENT || \
(type) == DELETE_ROWS_EVENT)
8. General remarks
~~~~~~~~~~~~~~~~~~
Kristian noticed that introducing new log event type should be coordinated
somehow with MySQL/Sun:
Kristian: The numeric code for this event must be assigned carefully.
It should be coordinated with MySQL/Sun, otherwise we can get into a
situation where MySQL uses the same numeric code for one event that
MariaDB uses for ANNOTATE_ROWS_EVENT, which would make merging the two
impossible.
Alex: I reserved about 20 numbers not to have possible conflicts
with MySQL.
Kristian: Still, I think it would be appropriate to send a polite email
to internals(a)lists.mysql.com about this and suggesting to reserve the
event number.
ESTIMATED WORK TIME
ESTIMATED COMPLETION DATE
-----------------------------------------------------------------------
WorkLog (v3.5.9)
1
0

[Maria-developers] Updated (by Knielsen): Store in binlog text of statements that caused RBR events (47)
by worklog-noreplyï¼ askmonty.org 29 Mar '10
by worklog-noreplyï¼ askmonty.org 29 Mar '10
29 Mar '10
-----------------------------------------------------------------------
WORKLOG TASK
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
TASK...........: Store in binlog text of statements that caused RBR events
CREATION DATE..: Sat, 15 Aug 2009, 23:48
SUPERVISOR.....: Monty
IMPLEMENTOR....:
COPIES TO......: Knielsen, Serg
CATEGORY.......: Server-Sprint
TASK ID........: 47 (http://askmonty.org/worklog/?tid=47)
VERSION........: Server-9.x
STATUS.........: Code-Review
PRIORITY.......: 60
WORKED HOURS...: 40
ESTIMATE.......: 15 (hours remain)
ORIG. ESTIMATE.: 35
PROGRESS NOTES:
-=-=(Knielsen - Mon, 29 Mar 2010, 10:59)=-=-
Status updated.
--- /tmp/wklog.47.old.27790 2010-03-29 10:59:53.000000000 +0000
+++ /tmp/wklog.47.new.27790 2010-03-29 10:59:53.000000000 +0000
@@ -1 +1 @@
-In-Progress
+Code-Review
-=-=(Alexi - Thu, 18 Feb 2010, 19:29)=-=-
Worked 20 hours (alexi)
Worked 20 hours and estimate 15 hours remain (original estimate unchanged).
-=-=(Serg - Fri, 05 Feb 2010, 14:04)=-=-
Observers changed: Knielsen,Serg
-=-=(Guest - Fri, 05 Feb 2010, 13:40)=-=-
Category updated.
--- /tmp/wklog.47.old.9197 2010-02-05 13:40:36.000000000 +0200
+++ /tmp/wklog.47.new.9197 2010-02-05 13:40:36.000000000 +0200
@@ -1 +1 @@
-Server-RawIdeaBin
+Server-Sprint
-=-=(Guest - Fri, 05 Feb 2010, 13:40)=-=-
Status updated.
--- /tmp/wklog.47.old.9197 2010-02-05 13:40:36.000000000 +0200
+++ /tmp/wklog.47.new.9197 2010-02-05 13:40:36.000000000 +0200
@@ -1 +1 @@
-Un-Assigned
+In-Progress
-=-=(Alexi - Thu, 04 Feb 2010, 09:54)=-=-
Low Level Design modified.
--- /tmp/wklog.47.old.16174 2010-02-04 09:54:13.000000000 +0200
+++ /tmp/wklog.47.new.16174 2010-02-04 09:54:13.000000000 +0200
@@ -171,35 +171,20 @@
5. How slave IO thread requests Annotate_rows events
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-When requesting an event, the slave should inform the master whether
-it should send Annotate_rows events or not. To that end we add a new
-BINLOG_SEND_ANNOTATE_ROWS_EVENT flag used when requesting an event:
+If the replicate-annotate-rows-events option is not set on a slave, there
+is no need for master to send Annotate_rows events to this slave. The slave
+(or mysqlbinlog in remote case), before requesting binlog dump via the
+COM_BINLOG_DUMP command, informs the master whether it should send these
+events by executing the newly added COM_BINLOG_DUMP_OPTIONS_EXT server
+command:
+
+ case COM_BINLOG_DUMP_OPTIONS_EXT:
+ thd->binlog_dump_flags_ext= packet[0];
+ my_ok(thd);
+ break;
- #define BINLOG_DUMP_NON_BLOCK 1
- #define BINLOG_SEND_ANNOTATE_ROWS_EVENT 2
-
- pthread_handler_t handle_slave_io(void *arg)
- { ...
- request_dump(mysql, ...);
- ...
- }
-
- int request_dump(MYSQL* mysql, ...)
- { ...
- if (opt_log_slave_updates &&
- mi->io_thd->variables.binlog_annotate_rows_events)
- binlog_flags|= BINLOG_SEND_ANNOTATE_ROWS_EVENT;
- ...
- int2store(buf + 4, binlog_flags);
- ...
- simple_command(mysql, COM_BINLOG_DUMP, buf, ...);
- ...
- }
-
-NOTE. mysqlbinlog, when remotely requesting BINLOG_DUMP by calling the
-simple_command() function, should also use this flag if it wants (in case
-of the --print-annotate-rows-events option set) to recieve Annotate_rows
-events.
+Note. We add this new command and don't use COM_BINLOG_DUMP to avoid possible
+conflicts with MySQL/Sun.
6. How master executes the request
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -338,10 +323,4 @@
to internals(a)lists.mysql.com about this and suggesting to reserve the
event number.
-Also we should notice the introduction of the BINLOG_SEND_ANNOTATE_ROWS_EVENT
-flag taking into account that MySQL/Sun may also introduce a flag with the
-same value to be used in the request_dump-mysql_binlog_send interface.
-But this is mainly the question of merging: if a conflict concerning this
-flag occur, we may simply change the BINLOG_SEND_ANNOTATE_ROWS_EVENT value
-(this does not require additional changes in the code).
-=-=(Alexi - Sun, 20 Dec 2009, 16:00)=-=-
Low Level Design modified.
--- /tmp/wklog.47.old.19667 2009-12-20 14:00:56.000000000 +0000
+++ /tmp/wklog.47.new.19667 2009-12-20 14:00:56.000000000 +0000
@@ -196,6 +196,11 @@
...
}
+NOTE. mysqlbinlog, when remotely requesting BINLOG_DUMP by calling the
+simple_command() function, should also use this flag if it wants (in case
+of the --print-annotate-rows-events option set) to recieve Annotate_rows
+events.
+
6. How master executes the request
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -212,8 +217,7 @@
Log_event::read_log_event(&log, packet, ...);
...
if ((*packet)[EVENT_TYPE_OFFSET + 1] != ANNOTATE_ROWS_EVENT ||
- flags & BINLOG_SEND_ANNOTATE_ROWS_EVENT ||
- thd->server_id == 0 /* slave == mysqlbinlog */ )
+ flags & BINLOG_SEND_ANNOTATE_ROWS_EVENT)
{
my_net_write(net, packet->ptr(), packet->length());
}
-=-=(Alexi - Sun, 20 Dec 2009, 13:14)=-=-
Low Level Design modified.
--- /tmp/wklog.47.old.11350 2009-12-20 13:14:04.000000000 +0200
+++ /tmp/wklog.47.new.11350 2009-12-20 13:14:04.000000000 +0200
@@ -282,23 +282,18 @@
Annotate_rows_log_event* m_annotate_event;
};
-When the saved Annotate_rows object may be deleted? When all corresponding
-Rows events will be processed, i.e. before processing the first non-Rows
-event (note that Annotate_rows object resides in the binary log *after*
-the (possible) 'BEGIN' Query event which accompanies the rows events; note
-also that this deletion is adjusted with the case when some or all
-corresponding Rows events are filtered out by replicate filter rules):
+The saved Annotate_rows object should be deleted when all corresponding
+Rows events will be processed:
int exec_relay_log_event(THD* thd, Relay_log_info* rli)
{ ...
Log_event *ev= next_event(rli);
...
- if (rli->get_annotate_event() && !IS_RBR_EVENT_TYPE(ev->get_type_code()))
- rli->free_annotate_event();
-
apply_event_and_update_pos(ev, ...);
- if (ev->get_type_code() == ANNOTATE_ROWS_EVENT)
+ if (rli->get_annotate_event() && is_last_rows_event(ev))
+ rli->free_annotate_event();
+ else if (ev->get_type_code() == ANNOTATE_ROWS_EVENT)
rli->set_annotate_event((Annotate_rows_log_event*) ev);
else if (ev->get_type_code() != FORMAT_DESCRIPTION_EVENT)
delete ev;
@@ -307,10 +302,21 @@
where
- #define IS_RBR_EVENT_TYPE(type) ( (type) == TABLE_MAP_EVENT || \
- (type) == WRITE_ROWS_EVENT || \
+ bool is_last_rows_event(Log_event* ev)
+ {
+ Log_event_type type= ev->get_type_code();
+ if (IS_ROWS_EVENT_TYPE(type))
+ {
+ Rows_log_event* rows= (Rows_log_event*)ev;
+ return rows->get_flags(Rows_log_event::STMT_END_F);
+ }
+
+ return 0;
+ }
+
+ #define IS_ROWS_EVENT_TYPE(type) ((type) == WRITE_ROWS_EVENT || \
(type) == UPDATE_ROWS_EVENT || \
- (type) == DELETE_ROWS_EVENT )
+ (type) == DELETE_ROWS_EVENT)
8. General remarks
~~~~~~~~~~~~~~~~~~
-=-=(Alexi - Sun, 20 Dec 2009, 09:29)=-=-
Low Level Design modified.
--- /tmp/wklog.47.old.32726 2009-12-20 07:29:56.000000000 +0000
+++ /tmp/wklog.47.new.32726 2009-12-20 07:29:56.000000000 +0000
@@ -56,7 +56,7 @@
0000006A | 00 | 0 - RESERVED [27]
..... ...
00000081 | 00 | 0 - RESERVED [50]
- 00000082 | 00 | 0 - ANNOTATE_RBR_EVENT [51]
+ 00000082 | 00 | 0 - ANNOTATE_ROWS_EVENT [51]
************************
2. Outline of Annotate_rows event behavior
-=-=(Alexi - Sat, 19 Dec 2009, 16:10)=-=-
Low Level Design modified.
--- /tmp/wklog.47.old.16051 2009-12-19 16:10:48.000000000 +0200
+++ /tmp/wklog.47.new.16051 2009-12-19 16:10:48.000000000 +0200
@@ -253,7 +253,7 @@
thd query to that of the described by the event, i.e. to the query which
caused the subsequent Rows events (see "How Master writes Annotate_rows
events to the binary log" to follow what happens further when the subsequent
-Rows events is applied):
+Rows events are applied):
int Annotate_rows_log_event::do_apply_event(...)
{
------------------------------------------------------------
-=-=(View All Progress Notes, 25 total)=-=-
http://askmonty.org/worklog/index.pl?tid=47&nolimit=1
DESCRIPTION:
Store in binlog (and show in mysqlbinlog output) texts of statements that
caused RBR events
This is needed for (list from Monty):
- Easier to understand why updates happened
- Would make it easier to find out where in application things went
wrong (as you can search for exact strings)
- Allow one to filter things based on comments in the statement.
The cost of this can be that the binlog will be approximately 2x in size
(especially insert of big blob's would be a bit painful), so this should
be an optional feature.
HIGH-LEVEL SPECIFICATION:
Content
~~~~~~~
1. Annotate_rows_log_event
2. Server option: --binlog-annotate-rows-events
3. Server option: --replicate-annotate-rows-events
4. mysqlbinlog option: --print-annotate-rows-events
5. mysqlbinlog output
1. Annotate_rows_log_event [ ANNOTATE_ROWS_EVENT ]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Describes the query which caused the corresponding rows events. Has empty
post-header and contains the query text in its data part. Example:
************************
ANNOTATE_ROWS_EVENT
************************
00000220 | B6 A0 2C 4B | time_when = 1261215926
00000224 | 33 | event_type = 51
00000225 | 64 00 00 00 | server_id = 100
00000229 | 36 00 00 00 | event_len = 54
0000022D | 56 02 00 00 | log_pos = 00000256
00000231 | 00 00 | flags = <none>
------------------------
00000233 | 49 4E 53 45 | query = "INSERT INTO t1 VALUES (1), (2), (3)"
00000237 | 52 54 20 49 |
0000023B | 4E 54 4F 20 |
0000023F | 74 31 20 56 |
00000243 | 41 4C 55 45 |
00000247 | 53 20 28 31 |
0000024B | 29 2C 20 28 |
0000024F | 32 29 2C 20 |
00000253 | 28 33 29 |
************************
In binary log, Annotate_rows event follows the (possible) 'BEGIN' Query event
and precedes the first of Table map events which accompany the corresponding
rows events. (See example in the "mysqlbinlog output" section below.)
2. Server option: --binlog-annotate-rows-events
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Tells the master to write Annotate_rows events to the binary log.
* Variable Name: binlog_annotate_rows_events
* Scope: Global & Session
* Access Type: Dynamic
* Data Type: bool
* Default Value: OFF
NOTE. Session values allows to annotate only some selected statements:
...
SET SESSION binlog_annotate_rows_events=ON;
... statements to be annotated ...
SET SESSION binlog_annotate_rows_events=OFF;
... statements not to be annotated ...
3. Server option: --replicate-annotate-rows-events
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Tells the slave to reproduce Annotate_rows events recieved from the master
in its own binary log (sensible only in pair with log-slave-updates option).
* Variable Name: replicate_annotate_rows_events
* Scope: Global
* Access Type: Read only
* Data Type: bool
* Default Value: OFF
NOTE. Why do we additionally need this 'replicate' option? Why not to make
the slave to reproduce this events when its binlog-annotate-rows-events
global value is ON? Well, because, for example, we may want to configure
the slave which should reproduce Annotate_rows events but has global
binlog-annotate-rows-events = OFF meaning this to be the default value for
the client threads (see also "How slave treats replicate-annotate-rows-events
option" in LLD part).
4. mysqlbinlog option: --print-annotate-rows-events
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
With this option, mysqlbinlog prints the content of Annotate_rows events (if
the binary log does contain them). Without this option (i.e. by default),
mysqlbinlog skips Annotate_rows events.
5. mysqlbinlog output
~~~~~~~~~~~~~~~~~~~~~
With --print-annotate-rows-events, mysqlbinlog outputs Annotate_rows events
in a form like this:
...
# at 1646
#091219 12:45:26 server id 100 end_log_pos 1714 Query thread_id=1
exec_time=0 error_code=0
SET TIMESTAMP=1261215926/*!*/;
BEGIN
/*!*/;
# at 1714
# at 1812
# at 1853
# at 1894
# at 1938
#091219 12:45:26 server id 100 end_log_pos 1812 Query: `DELETE t1, t2 FROM
t1 INNER JOIN t2 INNER JOIN t3 WHERE t1.a=t2.a AND t2.a=t3.a`
#091219 12:45:26 server id 100 end_log_pos 1853 Table_map: `test`.`t1`
mapped to number 16
#091219 12:45:26 server id 100 end_log_pos 1894 Table_map: `test`.`t2`
mapped to number 17
#091219 12:45:26 server id 100 end_log_pos 1938 Delete_rows: table id 16
#091219 12:45:26 server id 100 end_log_pos 1982 Delete_rows: table id 17
flags: STMT_END_F
...
LOW-LEVEL DESIGN:
Content
~~~~~~~
1. Annotate_rows event number
2. Outline of Annotate_rows event behavior
3. How Master writes Annotate_rows events to the binary log
4. How slave treats replicate-annotate-rows-events option
5. How slave IO thread requests Annotate_rows events
6. How master executes the request
7. How slave SQL thread processes Annotate_rows events
8. General remarks
1. Annotate_rows event number
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To avoid possible event numbers conflict with MySQL/Sun, we leave a gap
between the last MySQL event number and the Annotate_rows event number:
enum Log_event_type
{ ...
INCIDENT_EVENT= 26,
// New MySQL event numbers are to be added here
MYSQL_EVENTS_END,
MARIA_EVENTS_BEGIN= 51,
// New Maria event numbers start from here
ANNOTATE_ROWS_EVENT= 51,
ENUM_END_EVENT
};
together with the corresponding extension of 'post_header_len' array in the
Format description event. (This extension does not affect the compatibility
of the binary log). Here is how Format description event looks like with
this extension:
************************
FORMAT_DESCRIPTION_EVENT
************************
00000004 | A1 A0 2C 4B | time_when = 1261215905
00000008 | 0F | event_type = 15
00000009 | 64 00 00 00 | server_id = 100
0000000D | 7F 00 00 00 | event_len = 127
00000011 | 83 00 00 00 | log_pos = 00000083
00000015 | 01 00 | flags = LOG_EVENT_BINLOG_IN_USE_F
------------------------
00000017 | 04 00 | binlog_ver = 4
00000019 | 35 2E 32 2E | server_ver = 5.2.0-MariaDB-alpha-debug-log
..... ...
0000004B | A1 A0 2C 4B | time_created = 1261215905
0000004F | 13 | common_header_len = 19
------------------------
post_header_len
------------------------
00000050 | 38 | 56 - START_EVENT_V3 [1]
..... ...
00000069 | 02 | 2 - INCIDENT_EVENT [26]
0000006A | 00 | 0 - RESERVED [27]
..... ...
00000081 | 00 | 0 - RESERVED [50]
00000082 | 00 | 0 - ANNOTATE_ROWS_EVENT [51]
************************
2. Outline of Annotate_rows event behavior
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Each Annotate_rows_log_event object has two private members describing the
corresponding query:
char *m_query_txt;
uint m_query_len;
When the object is created for writing to a binary log, this query is taken
from 'thd' (for short, below we omit the 'Annotate_rows_log_event::' prefix
as well as other implementation details):
Annotate_rows_log_event(THD *thd)
{
m_query_txt = thd->query();
m_query_len = thd->query_length();
}
When the object is read from a binary log, the query is taken from the buffer
containing the binary log representation of the event (this buffer is allocated
in Log_event object from which all Log events are derived):
Annotate_rows_log_event(char *buf, uint event_len,
Format_description_log_event *desc)
{
m_query_len = event_len - desc->common_header_len;
m_query_txt = buf + desc->common_header_len;
}
The events are written to the binary log by the Log_event::write() member
which calls virtual write_data_header() and write_data_body() members
("data header" and "post header" are synonym in replication terminology).
In our case, data header is empty and data body is just the query:
bool write_data_body(IO_CACHE *file)
{
return my_b_safe_write(file, (uchar*) m_query_txt, m_query_len);
}
Printing the event is just printing the query:
void Annotate_rows_log_event::print(FILE *file, PRINT_EVENT_INFO *pinfo)
{
my_b_printf(&pinfo->head_cache, "\tQuery: `%s`\n", m_query_txt);
}
3. How Master writes Annotate_rows events to the binary log
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The event is written to the binary log just before the group of Table_map
events which precede corresponding Rows events (one query may generate
several Table map events in the binary log, but the corresponding
Annotate_rows event must be written only once before the first Table map
event; hence the boolean variable 'with_annotate' below):
int write_locked_table_maps(THD *thd)
{ ...
bool with_annotate= thd->variables.binlog_annotate_rows_events;
...
for (uint i= 0; i < ... <number of tables> ...; ++i)
{ ...
thd->binlog_write_table_map(table, ..., with_annotate);
with_annotate= 0; // write Annotate_event not more than once
...
}
...
}
int THD::binlog_write_table_map(TABLE *table, ..., bool with_annotate)
{ ...
Table_map_log_event the_event(...);
...
if (with_annotate)
{
Annotate_rows_log_event anno(this);
mysql_bin_log.write(&anno);
}
mysql_bin_log.write(&the_event);
...
}
4. How slave treats replicate-annotate-rows-events option
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The replicate-annotate-rows-events option is treated just as the session
value of the binlog_annotate_rows_events variable for the slave IO and
SQL threads. This setting is done during initialization of these threads:
pthread_handler_t handle_slave_io(void *arg)
{
THD *thd= new THD;
...
init_slave_thread(thd, SLAVE_THD_IO);
...
}
pthread_handler_t handle_slave_sql(void *arg)
{
THD *thd= new THD;
...
init_slave_thread(thd, SLAVE_THD_SQL);
...
}
int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type)
{ ...
thd->variables.binlog_annotate_rows_events=
opt_replicate_annotate_rows_events;
...
}
5. How slave IO thread requests Annotate_rows events
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If the replicate-annotate-rows-events option is not set on a slave, there
is no need for master to send Annotate_rows events to this slave. The slave
(or mysqlbinlog in remote case), before requesting binlog dump via the
COM_BINLOG_DUMP command, informs the master whether it should send these
events by executing the newly added COM_BINLOG_DUMP_OPTIONS_EXT server
command:
case COM_BINLOG_DUMP_OPTIONS_EXT:
thd->binlog_dump_flags_ext= packet[0];
my_ok(thd);
break;
Note. We add this new command and don't use COM_BINLOG_DUMP to avoid possible
conflicts with MySQL/Sun.
6. How master executes the request
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
case COM_BINLOG_DUMP:
{ ...
flags= uint2korr(packet + 4);
...
mysql_binlog_send(thd, ..., flags);
...
}
void mysql_binlog_send(THD* thd, ..., ushort flags)
{ ...
Log_event::read_log_event(&log, packet, ...);
...
if ((*packet)[EVENT_TYPE_OFFSET + 1] != ANNOTATE_ROWS_EVENT ||
flags & BINLOG_SEND_ANNOTATE_ROWS_EVENT)
{
my_net_write(net, packet->ptr(), packet->length());
}
...
}
7. How slave SQL thread processes Annotate_rows events
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The slave processes each recieved event by "applying" it, i.e. by
calling the Log_event::apply_event() function which in turn calls
the virtual do_apply_event() member specific for each type of the
event.
int exec_relay_log_event(THD* thd, Relay_log_info* rli)
{ ...
Log_event *ev = next_event(rli);
...
apply_event_and_update_pos(ev, ...);
if (ev->get_type_code() != FORMAT_DESCRIPTION_EVENT)
delete ev;
...
}
int apply_event_and_update_pos(Log_event *ev, ...)
{ ...
ev->apply_event(...);
...
}
int Log_event::apply_event(...)
{
return do_apply_event(...);
}
What does it mean to "apply" an Annotate_rows event? It means to set current
thd query to that of the described by the event, i.e. to the query which
caused the subsequent Rows events (see "How Master writes Annotate_rows
events to the binary log" to follow what happens further when the subsequent
Rows events are applied):
int Annotate_rows_log_event::do_apply_event(...)
{
thd->set_query(m_query_txt, m_query_len);
}
NOTE. I am not sure, but possibly current values of thd->query and
thd->query_length should be saved before calling set_query() and to be
restored on the Annotate_rows_log_event object deletion.
Is it really needed ?
After calling this do_apply_event() function we may not delete the
Annotate_rows_log_event object immediatedly (see exec_relay_log_event()
above) because thd->query now points to the string inside this object.
We may keep the pointer to this object in the Relay_log_info:
class Relay_log_info
{
public:
...
void set_annotate_event(Annotate_rows_log_event*);
Annotate_rows_log_event* get_annotate_event();
void free_annotate_event();
...
private:
Annotate_rows_log_event* m_annotate_event;
};
The saved Annotate_rows object should be deleted when all corresponding
Rows events will be processed:
int exec_relay_log_event(THD* thd, Relay_log_info* rli)
{ ...
Log_event *ev= next_event(rli);
...
apply_event_and_update_pos(ev, ...);
if (rli->get_annotate_event() && is_last_rows_event(ev))
rli->free_annotate_event();
else if (ev->get_type_code() == ANNOTATE_ROWS_EVENT)
rli->set_annotate_event((Annotate_rows_log_event*) ev);
else if (ev->get_type_code() != FORMAT_DESCRIPTION_EVENT)
delete ev;
...
}
where
bool is_last_rows_event(Log_event* ev)
{
Log_event_type type= ev->get_type_code();
if (IS_ROWS_EVENT_TYPE(type))
{
Rows_log_event* rows= (Rows_log_event*)ev;
return rows->get_flags(Rows_log_event::STMT_END_F);
}
return 0;
}
#define IS_ROWS_EVENT_TYPE(type) ((type) == WRITE_ROWS_EVENT || \
(type) == UPDATE_ROWS_EVENT || \
(type) == DELETE_ROWS_EVENT)
8. General remarks
~~~~~~~~~~~~~~~~~~
Kristian noticed that introducing new log event type should be coordinated
somehow with MySQL/Sun:
Kristian: The numeric code for this event must be assigned carefully.
It should be coordinated with MySQL/Sun, otherwise we can get into a
situation where MySQL uses the same numeric code for one event that
MariaDB uses for ANNOTATE_ROWS_EVENT, which would make merging the two
impossible.
Alex: I reserved about 20 numbers not to have possible conflicts
with MySQL.
Kristian: Still, I think it would be appropriate to send a polite email
to internals(a)lists.mysql.com about this and suggesting to reserve the
event number.
ESTIMATED WORK TIME
ESTIMATED COMPLETION DATE
-----------------------------------------------------------------------
WorkLog (v3.5.9)
1
0

[Maria-developers] Updated (by Knielsen): Store in binlog text of statements that caused RBR events (47)
by worklog-noreplyï¼ askmonty.org 29 Mar '10
by worklog-noreplyï¼ askmonty.org 29 Mar '10
29 Mar '10
-----------------------------------------------------------------------
WORKLOG TASK
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
TASK...........: Store in binlog text of statements that caused RBR events
CREATION DATE..: Sat, 15 Aug 2009, 23:48
SUPERVISOR.....: Monty
IMPLEMENTOR....:
COPIES TO......: Knielsen, Serg
CATEGORY.......: Server-Sprint
TASK ID........: 47 (http://askmonty.org/worklog/?tid=47)
VERSION........: Server-9.x
STATUS.........: Code-Review
PRIORITY.......: 60
WORKED HOURS...: 40
ESTIMATE.......: 15 (hours remain)
ORIG. ESTIMATE.: 35
PROGRESS NOTES:
-=-=(Knielsen - Mon, 29 Mar 2010, 10:59)=-=-
Status updated.
--- /tmp/wklog.47.old.27790 2010-03-29 10:59:53.000000000 +0000
+++ /tmp/wklog.47.new.27790 2010-03-29 10:59:53.000000000 +0000
@@ -1 +1 @@
-In-Progress
+Code-Review
-=-=(Alexi - Thu, 18 Feb 2010, 19:29)=-=-
Worked 20 hours (alexi)
Worked 20 hours and estimate 15 hours remain (original estimate unchanged).
-=-=(Serg - Fri, 05 Feb 2010, 14:04)=-=-
Observers changed: Knielsen,Serg
-=-=(Guest - Fri, 05 Feb 2010, 13:40)=-=-
Category updated.
--- /tmp/wklog.47.old.9197 2010-02-05 13:40:36.000000000 +0200
+++ /tmp/wklog.47.new.9197 2010-02-05 13:40:36.000000000 +0200
@@ -1 +1 @@
-Server-RawIdeaBin
+Server-Sprint
-=-=(Guest - Fri, 05 Feb 2010, 13:40)=-=-
Status updated.
--- /tmp/wklog.47.old.9197 2010-02-05 13:40:36.000000000 +0200
+++ /tmp/wklog.47.new.9197 2010-02-05 13:40:36.000000000 +0200
@@ -1 +1 @@
-Un-Assigned
+In-Progress
-=-=(Alexi - Thu, 04 Feb 2010, 09:54)=-=-
Low Level Design modified.
--- /tmp/wklog.47.old.16174 2010-02-04 09:54:13.000000000 +0200
+++ /tmp/wklog.47.new.16174 2010-02-04 09:54:13.000000000 +0200
@@ -171,35 +171,20 @@
5. How slave IO thread requests Annotate_rows events
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-When requesting an event, the slave should inform the master whether
-it should send Annotate_rows events or not. To that end we add a new
-BINLOG_SEND_ANNOTATE_ROWS_EVENT flag used when requesting an event:
+If the replicate-annotate-rows-events option is not set on a slave, there
+is no need for master to send Annotate_rows events to this slave. The slave
+(or mysqlbinlog in remote case), before requesting binlog dump via the
+COM_BINLOG_DUMP command, informs the master whether it should send these
+events by executing the newly added COM_BINLOG_DUMP_OPTIONS_EXT server
+command:
+
+ case COM_BINLOG_DUMP_OPTIONS_EXT:
+ thd->binlog_dump_flags_ext= packet[0];
+ my_ok(thd);
+ break;
- #define BINLOG_DUMP_NON_BLOCK 1
- #define BINLOG_SEND_ANNOTATE_ROWS_EVENT 2
-
- pthread_handler_t handle_slave_io(void *arg)
- { ...
- request_dump(mysql, ...);
- ...
- }
-
- int request_dump(MYSQL* mysql, ...)
- { ...
- if (opt_log_slave_updates &&
- mi->io_thd->variables.binlog_annotate_rows_events)
- binlog_flags|= BINLOG_SEND_ANNOTATE_ROWS_EVENT;
- ...
- int2store(buf + 4, binlog_flags);
- ...
- simple_command(mysql, COM_BINLOG_DUMP, buf, ...);
- ...
- }
-
-NOTE. mysqlbinlog, when remotely requesting BINLOG_DUMP by calling the
-simple_command() function, should also use this flag if it wants (in case
-of the --print-annotate-rows-events option set) to recieve Annotate_rows
-events.
+Note. We add this new command and don't use COM_BINLOG_DUMP to avoid possible
+conflicts with MySQL/Sun.
6. How master executes the request
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -338,10 +323,4 @@
to internals(a)lists.mysql.com about this and suggesting to reserve the
event number.
-Also we should notice the introduction of the BINLOG_SEND_ANNOTATE_ROWS_EVENT
-flag taking into account that MySQL/Sun may also introduce a flag with the
-same value to be used in the request_dump-mysql_binlog_send interface.
-But this is mainly the question of merging: if a conflict concerning this
-flag occur, we may simply change the BINLOG_SEND_ANNOTATE_ROWS_EVENT value
-(this does not require additional changes in the code).
-=-=(Alexi - Sun, 20 Dec 2009, 16:00)=-=-
Low Level Design modified.
--- /tmp/wklog.47.old.19667 2009-12-20 14:00:56.000000000 +0000
+++ /tmp/wklog.47.new.19667 2009-12-20 14:00:56.000000000 +0000
@@ -196,6 +196,11 @@
...
}
+NOTE. mysqlbinlog, when remotely requesting BINLOG_DUMP by calling the
+simple_command() function, should also use this flag if it wants (in case
+of the --print-annotate-rows-events option set) to recieve Annotate_rows
+events.
+
6. How master executes the request
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -212,8 +217,7 @@
Log_event::read_log_event(&log, packet, ...);
...
if ((*packet)[EVENT_TYPE_OFFSET + 1] != ANNOTATE_ROWS_EVENT ||
- flags & BINLOG_SEND_ANNOTATE_ROWS_EVENT ||
- thd->server_id == 0 /* slave == mysqlbinlog */ )
+ flags & BINLOG_SEND_ANNOTATE_ROWS_EVENT)
{
my_net_write(net, packet->ptr(), packet->length());
}
-=-=(Alexi - Sun, 20 Dec 2009, 13:14)=-=-
Low Level Design modified.
--- /tmp/wklog.47.old.11350 2009-12-20 13:14:04.000000000 +0200
+++ /tmp/wklog.47.new.11350 2009-12-20 13:14:04.000000000 +0200
@@ -282,23 +282,18 @@
Annotate_rows_log_event* m_annotate_event;
};
-When the saved Annotate_rows object may be deleted? When all corresponding
-Rows events will be processed, i.e. before processing the first non-Rows
-event (note that Annotate_rows object resides in the binary log *after*
-the (possible) 'BEGIN' Query event which accompanies the rows events; note
-also that this deletion is adjusted with the case when some or all
-corresponding Rows events are filtered out by replicate filter rules):
+The saved Annotate_rows object should be deleted when all corresponding
+Rows events will be processed:
int exec_relay_log_event(THD* thd, Relay_log_info* rli)
{ ...
Log_event *ev= next_event(rli);
...
- if (rli->get_annotate_event() && !IS_RBR_EVENT_TYPE(ev->get_type_code()))
- rli->free_annotate_event();
-
apply_event_and_update_pos(ev, ...);
- if (ev->get_type_code() == ANNOTATE_ROWS_EVENT)
+ if (rli->get_annotate_event() && is_last_rows_event(ev))
+ rli->free_annotate_event();
+ else if (ev->get_type_code() == ANNOTATE_ROWS_EVENT)
rli->set_annotate_event((Annotate_rows_log_event*) ev);
else if (ev->get_type_code() != FORMAT_DESCRIPTION_EVENT)
delete ev;
@@ -307,10 +302,21 @@
where
- #define IS_RBR_EVENT_TYPE(type) ( (type) == TABLE_MAP_EVENT || \
- (type) == WRITE_ROWS_EVENT || \
+ bool is_last_rows_event(Log_event* ev)
+ {
+ Log_event_type type= ev->get_type_code();
+ if (IS_ROWS_EVENT_TYPE(type))
+ {
+ Rows_log_event* rows= (Rows_log_event*)ev;
+ return rows->get_flags(Rows_log_event::STMT_END_F);
+ }
+
+ return 0;
+ }
+
+ #define IS_ROWS_EVENT_TYPE(type) ((type) == WRITE_ROWS_EVENT || \
(type) == UPDATE_ROWS_EVENT || \
- (type) == DELETE_ROWS_EVENT )
+ (type) == DELETE_ROWS_EVENT)
8. General remarks
~~~~~~~~~~~~~~~~~~
-=-=(Alexi - Sun, 20 Dec 2009, 09:29)=-=-
Low Level Design modified.
--- /tmp/wklog.47.old.32726 2009-12-20 07:29:56.000000000 +0000
+++ /tmp/wklog.47.new.32726 2009-12-20 07:29:56.000000000 +0000
@@ -56,7 +56,7 @@
0000006A | 00 | 0 - RESERVED [27]
..... ...
00000081 | 00 | 0 - RESERVED [50]
- 00000082 | 00 | 0 - ANNOTATE_RBR_EVENT [51]
+ 00000082 | 00 | 0 - ANNOTATE_ROWS_EVENT [51]
************************
2. Outline of Annotate_rows event behavior
-=-=(Alexi - Sat, 19 Dec 2009, 16:10)=-=-
Low Level Design modified.
--- /tmp/wklog.47.old.16051 2009-12-19 16:10:48.000000000 +0200
+++ /tmp/wklog.47.new.16051 2009-12-19 16:10:48.000000000 +0200
@@ -253,7 +253,7 @@
thd query to that of the described by the event, i.e. to the query which
caused the subsequent Rows events (see "How Master writes Annotate_rows
events to the binary log" to follow what happens further when the subsequent
-Rows events is applied):
+Rows events are applied):
int Annotate_rows_log_event::do_apply_event(...)
{
------------------------------------------------------------
-=-=(View All Progress Notes, 25 total)=-=-
http://askmonty.org/worklog/index.pl?tid=47&nolimit=1
DESCRIPTION:
Store in binlog (and show in mysqlbinlog output) texts of statements that
caused RBR events
This is needed for (list from Monty):
- Easier to understand why updates happened
- Would make it easier to find out where in application things went
wrong (as you can search for exact strings)
- Allow one to filter things based on comments in the statement.
The cost of this can be that the binlog will be approximately 2x in size
(especially insert of big blob's would be a bit painful), so this should
be an optional feature.
HIGH-LEVEL SPECIFICATION:
Content
~~~~~~~
1. Annotate_rows_log_event
2. Server option: --binlog-annotate-rows-events
3. Server option: --replicate-annotate-rows-events
4. mysqlbinlog option: --print-annotate-rows-events
5. mysqlbinlog output
1. Annotate_rows_log_event [ ANNOTATE_ROWS_EVENT ]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Describes the query which caused the corresponding rows events. Has empty
post-header and contains the query text in its data part. Example:
************************
ANNOTATE_ROWS_EVENT
************************
00000220 | B6 A0 2C 4B | time_when = 1261215926
00000224 | 33 | event_type = 51
00000225 | 64 00 00 00 | server_id = 100
00000229 | 36 00 00 00 | event_len = 54
0000022D | 56 02 00 00 | log_pos = 00000256
00000231 | 00 00 | flags = <none>
------------------------
00000233 | 49 4E 53 45 | query = "INSERT INTO t1 VALUES (1), (2), (3)"
00000237 | 52 54 20 49 |
0000023B | 4E 54 4F 20 |
0000023F | 74 31 20 56 |
00000243 | 41 4C 55 45 |
00000247 | 53 20 28 31 |
0000024B | 29 2C 20 28 |
0000024F | 32 29 2C 20 |
00000253 | 28 33 29 |
************************
In binary log, Annotate_rows event follows the (possible) 'BEGIN' Query event
and precedes the first of Table map events which accompany the corresponding
rows events. (See example in the "mysqlbinlog output" section below.)
2. Server option: --binlog-annotate-rows-events
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Tells the master to write Annotate_rows events to the binary log.
* Variable Name: binlog_annotate_rows_events
* Scope: Global & Session
* Access Type: Dynamic
* Data Type: bool
* Default Value: OFF
NOTE. Session values allows to annotate only some selected statements:
...
SET SESSION binlog_annotate_rows_events=ON;
... statements to be annotated ...
SET SESSION binlog_annotate_rows_events=OFF;
... statements not to be annotated ...
3. Server option: --replicate-annotate-rows-events
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Tells the slave to reproduce Annotate_rows events recieved from the master
in its own binary log (sensible only in pair with log-slave-updates option).
* Variable Name: replicate_annotate_rows_events
* Scope: Global
* Access Type: Read only
* Data Type: bool
* Default Value: OFF
NOTE. Why do we additionally need this 'replicate' option? Why not to make
the slave to reproduce this events when its binlog-annotate-rows-events
global value is ON? Well, because, for example, we may want to configure
the slave which should reproduce Annotate_rows events but has global
binlog-annotate-rows-events = OFF meaning this to be the default value for
the client threads (see also "How slave treats replicate-annotate-rows-events
option" in LLD part).
4. mysqlbinlog option: --print-annotate-rows-events
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
With this option, mysqlbinlog prints the content of Annotate_rows events (if
the binary log does contain them). Without this option (i.e. by default),
mysqlbinlog skips Annotate_rows events.
5. mysqlbinlog output
~~~~~~~~~~~~~~~~~~~~~
With --print-annotate-rows-events, mysqlbinlog outputs Annotate_rows events
in a form like this:
...
# at 1646
#091219 12:45:26 server id 100 end_log_pos 1714 Query thread_id=1
exec_time=0 error_code=0
SET TIMESTAMP=1261215926/*!*/;
BEGIN
/*!*/;
# at 1714
# at 1812
# at 1853
# at 1894
# at 1938
#091219 12:45:26 server id 100 end_log_pos 1812 Query: `DELETE t1, t2 FROM
t1 INNER JOIN t2 INNER JOIN t3 WHERE t1.a=t2.a AND t2.a=t3.a`
#091219 12:45:26 server id 100 end_log_pos 1853 Table_map: `test`.`t1`
mapped to number 16
#091219 12:45:26 server id 100 end_log_pos 1894 Table_map: `test`.`t2`
mapped to number 17
#091219 12:45:26 server id 100 end_log_pos 1938 Delete_rows: table id 16
#091219 12:45:26 server id 100 end_log_pos 1982 Delete_rows: table id 17
flags: STMT_END_F
...
LOW-LEVEL DESIGN:
Content
~~~~~~~
1. Annotate_rows event number
2. Outline of Annotate_rows event behavior
3. How Master writes Annotate_rows events to the binary log
4. How slave treats replicate-annotate-rows-events option
5. How slave IO thread requests Annotate_rows events
6. How master executes the request
7. How slave SQL thread processes Annotate_rows events
8. General remarks
1. Annotate_rows event number
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To avoid possible event numbers conflict with MySQL/Sun, we leave a gap
between the last MySQL event number and the Annotate_rows event number:
enum Log_event_type
{ ...
INCIDENT_EVENT= 26,
// New MySQL event numbers are to be added here
MYSQL_EVENTS_END,
MARIA_EVENTS_BEGIN= 51,
// New Maria event numbers start from here
ANNOTATE_ROWS_EVENT= 51,
ENUM_END_EVENT
};
together with the corresponding extension of 'post_header_len' array in the
Format description event. (This extension does not affect the compatibility
of the binary log). Here is how Format description event looks like with
this extension:
************************
FORMAT_DESCRIPTION_EVENT
************************
00000004 | A1 A0 2C 4B | time_when = 1261215905
00000008 | 0F | event_type = 15
00000009 | 64 00 00 00 | server_id = 100
0000000D | 7F 00 00 00 | event_len = 127
00000011 | 83 00 00 00 | log_pos = 00000083
00000015 | 01 00 | flags = LOG_EVENT_BINLOG_IN_USE_F
------------------------
00000017 | 04 00 | binlog_ver = 4
00000019 | 35 2E 32 2E | server_ver = 5.2.0-MariaDB-alpha-debug-log
..... ...
0000004B | A1 A0 2C 4B | time_created = 1261215905
0000004F | 13 | common_header_len = 19
------------------------
post_header_len
------------------------
00000050 | 38 | 56 - START_EVENT_V3 [1]
..... ...
00000069 | 02 | 2 - INCIDENT_EVENT [26]
0000006A | 00 | 0 - RESERVED [27]
..... ...
00000081 | 00 | 0 - RESERVED [50]
00000082 | 00 | 0 - ANNOTATE_ROWS_EVENT [51]
************************
2. Outline of Annotate_rows event behavior
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Each Annotate_rows_log_event object has two private members describing the
corresponding query:
char *m_query_txt;
uint m_query_len;
When the object is created for writing to a binary log, this query is taken
from 'thd' (for short, below we omit the 'Annotate_rows_log_event::' prefix
as well as other implementation details):
Annotate_rows_log_event(THD *thd)
{
m_query_txt = thd->query();
m_query_len = thd->query_length();
}
When the object is read from a binary log, the query is taken from the buffer
containing the binary log representation of the event (this buffer is allocated
in Log_event object from which all Log events are derived):
Annotate_rows_log_event(char *buf, uint event_len,
Format_description_log_event *desc)
{
m_query_len = event_len - desc->common_header_len;
m_query_txt = buf + desc->common_header_len;
}
The events are written to the binary log by the Log_event::write() member
which calls virtual write_data_header() and write_data_body() members
("data header" and "post header" are synonym in replication terminology).
In our case, data header is empty and data body is just the query:
bool write_data_body(IO_CACHE *file)
{
return my_b_safe_write(file, (uchar*) m_query_txt, m_query_len);
}
Printing the event is just printing the query:
void Annotate_rows_log_event::print(FILE *file, PRINT_EVENT_INFO *pinfo)
{
my_b_printf(&pinfo->head_cache, "\tQuery: `%s`\n", m_query_txt);
}
3. How Master writes Annotate_rows events to the binary log
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The event is written to the binary log just before the group of Table_map
events which precede corresponding Rows events (one query may generate
several Table map events in the binary log, but the corresponding
Annotate_rows event must be written only once before the first Table map
event; hence the boolean variable 'with_annotate' below):
int write_locked_table_maps(THD *thd)
{ ...
bool with_annotate= thd->variables.binlog_annotate_rows_events;
...
for (uint i= 0; i < ... <number of tables> ...; ++i)
{ ...
thd->binlog_write_table_map(table, ..., with_annotate);
with_annotate= 0; // write Annotate_event not more than once
...
}
...
}
int THD::binlog_write_table_map(TABLE *table, ..., bool with_annotate)
{ ...
Table_map_log_event the_event(...);
...
if (with_annotate)
{
Annotate_rows_log_event anno(this);
mysql_bin_log.write(&anno);
}
mysql_bin_log.write(&the_event);
...
}
4. How slave treats replicate-annotate-rows-events option
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The replicate-annotate-rows-events option is treated just as the session
value of the binlog_annotate_rows_events variable for the slave IO and
SQL threads. This setting is done during initialization of these threads:
pthread_handler_t handle_slave_io(void *arg)
{
THD *thd= new THD;
...
init_slave_thread(thd, SLAVE_THD_IO);
...
}
pthread_handler_t handle_slave_sql(void *arg)
{
THD *thd= new THD;
...
init_slave_thread(thd, SLAVE_THD_SQL);
...
}
int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type)
{ ...
thd->variables.binlog_annotate_rows_events=
opt_replicate_annotate_rows_events;
...
}
5. How slave IO thread requests Annotate_rows events
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If the replicate-annotate-rows-events option is not set on a slave, there
is no need for master to send Annotate_rows events to this slave. The slave
(or mysqlbinlog in remote case), before requesting binlog dump via the
COM_BINLOG_DUMP command, informs the master whether it should send these
events by executing the newly added COM_BINLOG_DUMP_OPTIONS_EXT server
command:
case COM_BINLOG_DUMP_OPTIONS_EXT:
thd->binlog_dump_flags_ext= packet[0];
my_ok(thd);
break;
Note. We add this new command and don't use COM_BINLOG_DUMP to avoid possible
conflicts with MySQL/Sun.
6. How master executes the request
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
case COM_BINLOG_DUMP:
{ ...
flags= uint2korr(packet + 4);
...
mysql_binlog_send(thd, ..., flags);
...
}
void mysql_binlog_send(THD* thd, ..., ushort flags)
{ ...
Log_event::read_log_event(&log, packet, ...);
...
if ((*packet)[EVENT_TYPE_OFFSET + 1] != ANNOTATE_ROWS_EVENT ||
flags & BINLOG_SEND_ANNOTATE_ROWS_EVENT)
{
my_net_write(net, packet->ptr(), packet->length());
}
...
}
7. How slave SQL thread processes Annotate_rows events
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The slave processes each recieved event by "applying" it, i.e. by
calling the Log_event::apply_event() function which in turn calls
the virtual do_apply_event() member specific for each type of the
event.
int exec_relay_log_event(THD* thd, Relay_log_info* rli)
{ ...
Log_event *ev = next_event(rli);
...
apply_event_and_update_pos(ev, ...);
if (ev->get_type_code() != FORMAT_DESCRIPTION_EVENT)
delete ev;
...
}
int apply_event_and_update_pos(Log_event *ev, ...)
{ ...
ev->apply_event(...);
...
}
int Log_event::apply_event(...)
{
return do_apply_event(...);
}
What does it mean to "apply" an Annotate_rows event? It means to set current
thd query to that of the described by the event, i.e. to the query which
caused the subsequent Rows events (see "How Master writes Annotate_rows
events to the binary log" to follow what happens further when the subsequent
Rows events are applied):
int Annotate_rows_log_event::do_apply_event(...)
{
thd->set_query(m_query_txt, m_query_len);
}
NOTE. I am not sure, but possibly current values of thd->query and
thd->query_length should be saved before calling set_query() and to be
restored on the Annotate_rows_log_event object deletion.
Is it really needed ?
After calling this do_apply_event() function we may not delete the
Annotate_rows_log_event object immediatedly (see exec_relay_log_event()
above) because thd->query now points to the string inside this object.
We may keep the pointer to this object in the Relay_log_info:
class Relay_log_info
{
public:
...
void set_annotate_event(Annotate_rows_log_event*);
Annotate_rows_log_event* get_annotate_event();
void free_annotate_event();
...
private:
Annotate_rows_log_event* m_annotate_event;
};
The saved Annotate_rows object should be deleted when all corresponding
Rows events will be processed:
int exec_relay_log_event(THD* thd, Relay_log_info* rli)
{ ...
Log_event *ev= next_event(rli);
...
apply_event_and_update_pos(ev, ...);
if (rli->get_annotate_event() && is_last_rows_event(ev))
rli->free_annotate_event();
else if (ev->get_type_code() == ANNOTATE_ROWS_EVENT)
rli->set_annotate_event((Annotate_rows_log_event*) ev);
else if (ev->get_type_code() != FORMAT_DESCRIPTION_EVENT)
delete ev;
...
}
where
bool is_last_rows_event(Log_event* ev)
{
Log_event_type type= ev->get_type_code();
if (IS_ROWS_EVENT_TYPE(type))
{
Rows_log_event* rows= (Rows_log_event*)ev;
return rows->get_flags(Rows_log_event::STMT_END_F);
}
return 0;
}
#define IS_ROWS_EVENT_TYPE(type) ((type) == WRITE_ROWS_EVENT || \
(type) == UPDATE_ROWS_EVENT || \
(type) == DELETE_ROWS_EVENT)
8. General remarks
~~~~~~~~~~~~~~~~~~
Kristian noticed that introducing new log event type should be coordinated
somehow with MySQL/Sun:
Kristian: The numeric code for this event must be assigned carefully.
It should be coordinated with MySQL/Sun, otherwise we can get into a
situation where MySQL uses the same numeric code for one event that
MariaDB uses for ANNOTATE_ROWS_EVENT, which would make merging the two
impossible.
Alex: I reserved about 20 numbers not to have possible conflicts
with MySQL.
Kristian: Still, I think it would be appropriate to send a polite email
to internals(a)lists.mysql.com about this and suggesting to reserve the
event number.
ESTIMATED WORK TIME
ESTIMATED COMPLETION DATE
-----------------------------------------------------------------------
WorkLog (v3.5.9)
1
0

[Maria-developers] Updated (by Knielsen): Store in binlog text of statements that caused RBR events (47)
by worklog-noreplyï¼ askmonty.org 29 Mar '10
by worklog-noreplyï¼ askmonty.org 29 Mar '10
29 Mar '10
-----------------------------------------------------------------------
WORKLOG TASK
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
TASK...........: Store in binlog text of statements that caused RBR events
CREATION DATE..: Sat, 15 Aug 2009, 23:48
SUPERVISOR.....: Monty
IMPLEMENTOR....:
COPIES TO......: Knielsen, Serg
CATEGORY.......: Server-Sprint
TASK ID........: 47 (http://askmonty.org/worklog/?tid=47)
VERSION........: Server-9.x
STATUS.........: Code-Review
PRIORITY.......: 60
WORKED HOURS...: 40
ESTIMATE.......: 15 (hours remain)
ORIG. ESTIMATE.: 35
PROGRESS NOTES:
-=-=(Knielsen - Mon, 29 Mar 2010, 10:59)=-=-
Status updated.
--- /tmp/wklog.47.old.27790 2010-03-29 10:59:53.000000000 +0000
+++ /tmp/wklog.47.new.27790 2010-03-29 10:59:53.000000000 +0000
@@ -1 +1 @@
-In-Progress
+Code-Review
-=-=(Alexi - Thu, 18 Feb 2010, 19:29)=-=-
Worked 20 hours (alexi)
Worked 20 hours and estimate 15 hours remain (original estimate unchanged).
-=-=(Serg - Fri, 05 Feb 2010, 14:04)=-=-
Observers changed: Knielsen,Serg
-=-=(Guest - Fri, 05 Feb 2010, 13:40)=-=-
Category updated.
--- /tmp/wklog.47.old.9197 2010-02-05 13:40:36.000000000 +0200
+++ /tmp/wklog.47.new.9197 2010-02-05 13:40:36.000000000 +0200
@@ -1 +1 @@
-Server-RawIdeaBin
+Server-Sprint
-=-=(Guest - Fri, 05 Feb 2010, 13:40)=-=-
Status updated.
--- /tmp/wklog.47.old.9197 2010-02-05 13:40:36.000000000 +0200
+++ /tmp/wklog.47.new.9197 2010-02-05 13:40:36.000000000 +0200
@@ -1 +1 @@
-Un-Assigned
+In-Progress
-=-=(Alexi - Thu, 04 Feb 2010, 09:54)=-=-
Low Level Design modified.
--- /tmp/wklog.47.old.16174 2010-02-04 09:54:13.000000000 +0200
+++ /tmp/wklog.47.new.16174 2010-02-04 09:54:13.000000000 +0200
@@ -171,35 +171,20 @@
5. How slave IO thread requests Annotate_rows events
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-When requesting an event, the slave should inform the master whether
-it should send Annotate_rows events or not. To that end we add a new
-BINLOG_SEND_ANNOTATE_ROWS_EVENT flag used when requesting an event:
+If the replicate-annotate-rows-events option is not set on a slave, there
+is no need for master to send Annotate_rows events to this slave. The slave
+(or mysqlbinlog in remote case), before requesting binlog dump via the
+COM_BINLOG_DUMP command, informs the master whether it should send these
+events by executing the newly added COM_BINLOG_DUMP_OPTIONS_EXT server
+command:
+
+ case COM_BINLOG_DUMP_OPTIONS_EXT:
+ thd->binlog_dump_flags_ext= packet[0];
+ my_ok(thd);
+ break;
- #define BINLOG_DUMP_NON_BLOCK 1
- #define BINLOG_SEND_ANNOTATE_ROWS_EVENT 2
-
- pthread_handler_t handle_slave_io(void *arg)
- { ...
- request_dump(mysql, ...);
- ...
- }
-
- int request_dump(MYSQL* mysql, ...)
- { ...
- if (opt_log_slave_updates &&
- mi->io_thd->variables.binlog_annotate_rows_events)
- binlog_flags|= BINLOG_SEND_ANNOTATE_ROWS_EVENT;
- ...
- int2store(buf + 4, binlog_flags);
- ...
- simple_command(mysql, COM_BINLOG_DUMP, buf, ...);
- ...
- }
-
-NOTE. mysqlbinlog, when remotely requesting BINLOG_DUMP by calling the
-simple_command() function, should also use this flag if it wants (in case
-of the --print-annotate-rows-events option set) to recieve Annotate_rows
-events.
+Note. We add this new command and don't use COM_BINLOG_DUMP to avoid possible
+conflicts with MySQL/Sun.
6. How master executes the request
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -338,10 +323,4 @@
to internals(a)lists.mysql.com about this and suggesting to reserve the
event number.
-Also we should notice the introduction of the BINLOG_SEND_ANNOTATE_ROWS_EVENT
-flag taking into account that MySQL/Sun may also introduce a flag with the
-same value to be used in the request_dump-mysql_binlog_send interface.
-But this is mainly the question of merging: if a conflict concerning this
-flag occur, we may simply change the BINLOG_SEND_ANNOTATE_ROWS_EVENT value
-(this does not require additional changes in the code).
-=-=(Alexi - Sun, 20 Dec 2009, 16:00)=-=-
Low Level Design modified.
--- /tmp/wklog.47.old.19667 2009-12-20 14:00:56.000000000 +0000
+++ /tmp/wklog.47.new.19667 2009-12-20 14:00:56.000000000 +0000
@@ -196,6 +196,11 @@
...
}
+NOTE. mysqlbinlog, when remotely requesting BINLOG_DUMP by calling the
+simple_command() function, should also use this flag if it wants (in case
+of the --print-annotate-rows-events option set) to recieve Annotate_rows
+events.
+
6. How master executes the request
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -212,8 +217,7 @@
Log_event::read_log_event(&log, packet, ...);
...
if ((*packet)[EVENT_TYPE_OFFSET + 1] != ANNOTATE_ROWS_EVENT ||
- flags & BINLOG_SEND_ANNOTATE_ROWS_EVENT ||
- thd->server_id == 0 /* slave == mysqlbinlog */ )
+ flags & BINLOG_SEND_ANNOTATE_ROWS_EVENT)
{
my_net_write(net, packet->ptr(), packet->length());
}
-=-=(Alexi - Sun, 20 Dec 2009, 13:14)=-=-
Low Level Design modified.
--- /tmp/wklog.47.old.11350 2009-12-20 13:14:04.000000000 +0200
+++ /tmp/wklog.47.new.11350 2009-12-20 13:14:04.000000000 +0200
@@ -282,23 +282,18 @@
Annotate_rows_log_event* m_annotate_event;
};
-When the saved Annotate_rows object may be deleted? When all corresponding
-Rows events will be processed, i.e. before processing the first non-Rows
-event (note that Annotate_rows object resides in the binary log *after*
-the (possible) 'BEGIN' Query event which accompanies the rows events; note
-also that this deletion is adjusted with the case when some or all
-corresponding Rows events are filtered out by replicate filter rules):
+The saved Annotate_rows object should be deleted when all corresponding
+Rows events will be processed:
int exec_relay_log_event(THD* thd, Relay_log_info* rli)
{ ...
Log_event *ev= next_event(rli);
...
- if (rli->get_annotate_event() && !IS_RBR_EVENT_TYPE(ev->get_type_code()))
- rli->free_annotate_event();
-
apply_event_and_update_pos(ev, ...);
- if (ev->get_type_code() == ANNOTATE_ROWS_EVENT)
+ if (rli->get_annotate_event() && is_last_rows_event(ev))
+ rli->free_annotate_event();
+ else if (ev->get_type_code() == ANNOTATE_ROWS_EVENT)
rli->set_annotate_event((Annotate_rows_log_event*) ev);
else if (ev->get_type_code() != FORMAT_DESCRIPTION_EVENT)
delete ev;
@@ -307,10 +302,21 @@
where
- #define IS_RBR_EVENT_TYPE(type) ( (type) == TABLE_MAP_EVENT || \
- (type) == WRITE_ROWS_EVENT || \
+ bool is_last_rows_event(Log_event* ev)
+ {
+ Log_event_type type= ev->get_type_code();
+ if (IS_ROWS_EVENT_TYPE(type))
+ {
+ Rows_log_event* rows= (Rows_log_event*)ev;
+ return rows->get_flags(Rows_log_event::STMT_END_F);
+ }
+
+ return 0;
+ }
+
+ #define IS_ROWS_EVENT_TYPE(type) ((type) == WRITE_ROWS_EVENT || \
(type) == UPDATE_ROWS_EVENT || \
- (type) == DELETE_ROWS_EVENT )
+ (type) == DELETE_ROWS_EVENT)
8. General remarks
~~~~~~~~~~~~~~~~~~
-=-=(Alexi - Sun, 20 Dec 2009, 09:29)=-=-
Low Level Design modified.
--- /tmp/wklog.47.old.32726 2009-12-20 07:29:56.000000000 +0000
+++ /tmp/wklog.47.new.32726 2009-12-20 07:29:56.000000000 +0000
@@ -56,7 +56,7 @@
0000006A | 00 | 0 - RESERVED [27]
..... ...
00000081 | 00 | 0 - RESERVED [50]
- 00000082 | 00 | 0 - ANNOTATE_RBR_EVENT [51]
+ 00000082 | 00 | 0 - ANNOTATE_ROWS_EVENT [51]
************************
2. Outline of Annotate_rows event behavior
-=-=(Alexi - Sat, 19 Dec 2009, 16:10)=-=-
Low Level Design modified.
--- /tmp/wklog.47.old.16051 2009-12-19 16:10:48.000000000 +0200
+++ /tmp/wklog.47.new.16051 2009-12-19 16:10:48.000000000 +0200
@@ -253,7 +253,7 @@
thd query to that of the described by the event, i.e. to the query which
caused the subsequent Rows events (see "How Master writes Annotate_rows
events to the binary log" to follow what happens further when the subsequent
-Rows events is applied):
+Rows events are applied):
int Annotate_rows_log_event::do_apply_event(...)
{
------------------------------------------------------------
-=-=(View All Progress Notes, 25 total)=-=-
http://askmonty.org/worklog/index.pl?tid=47&nolimit=1
DESCRIPTION:
Store in binlog (and show in mysqlbinlog output) texts of statements that
caused RBR events
This is needed for (list from Monty):
- Easier to understand why updates happened
- Would make it easier to find out where in application things went
wrong (as you can search for exact strings)
- Allow one to filter things based on comments in the statement.
The cost of this can be that the binlog will be approximately 2x in size
(especially insert of big blob's would be a bit painful), so this should
be an optional feature.
HIGH-LEVEL SPECIFICATION:
Content
~~~~~~~
1. Annotate_rows_log_event
2. Server option: --binlog-annotate-rows-events
3. Server option: --replicate-annotate-rows-events
4. mysqlbinlog option: --print-annotate-rows-events
5. mysqlbinlog output
1. Annotate_rows_log_event [ ANNOTATE_ROWS_EVENT ]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Describes the query which caused the corresponding rows events. Has empty
post-header and contains the query text in its data part. Example:
************************
ANNOTATE_ROWS_EVENT
************************
00000220 | B6 A0 2C 4B | time_when = 1261215926
00000224 | 33 | event_type = 51
00000225 | 64 00 00 00 | server_id = 100
00000229 | 36 00 00 00 | event_len = 54
0000022D | 56 02 00 00 | log_pos = 00000256
00000231 | 00 00 | flags = <none>
------------------------
00000233 | 49 4E 53 45 | query = "INSERT INTO t1 VALUES (1), (2), (3)"
00000237 | 52 54 20 49 |
0000023B | 4E 54 4F 20 |
0000023F | 74 31 20 56 |
00000243 | 41 4C 55 45 |
00000247 | 53 20 28 31 |
0000024B | 29 2C 20 28 |
0000024F | 32 29 2C 20 |
00000253 | 28 33 29 |
************************
In binary log, Annotate_rows event follows the (possible) 'BEGIN' Query event
and precedes the first of Table map events which accompany the corresponding
rows events. (See example in the "mysqlbinlog output" section below.)
2. Server option: --binlog-annotate-rows-events
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Tells the master to write Annotate_rows events to the binary log.
* Variable Name: binlog_annotate_rows_events
* Scope: Global & Session
* Access Type: Dynamic
* Data Type: bool
* Default Value: OFF
NOTE. Session values allows to annotate only some selected statements:
...
SET SESSION binlog_annotate_rows_events=ON;
... statements to be annotated ...
SET SESSION binlog_annotate_rows_events=OFF;
... statements not to be annotated ...
3. Server option: --replicate-annotate-rows-events
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Tells the slave to reproduce Annotate_rows events recieved from the master
in its own binary log (sensible only in pair with log-slave-updates option).
* Variable Name: replicate_annotate_rows_events
* Scope: Global
* Access Type: Read only
* Data Type: bool
* Default Value: OFF
NOTE. Why do we additionally need this 'replicate' option? Why not to make
the slave to reproduce this events when its binlog-annotate-rows-events
global value is ON? Well, because, for example, we may want to configure
the slave which should reproduce Annotate_rows events but has global
binlog-annotate-rows-events = OFF meaning this to be the default value for
the client threads (see also "How slave treats replicate-annotate-rows-events
option" in LLD part).
4. mysqlbinlog option: --print-annotate-rows-events
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
With this option, mysqlbinlog prints the content of Annotate_rows events (if
the binary log does contain them). Without this option (i.e. by default),
mysqlbinlog skips Annotate_rows events.
5. mysqlbinlog output
~~~~~~~~~~~~~~~~~~~~~
With --print-annotate-rows-events, mysqlbinlog outputs Annotate_rows events
in a form like this:
...
# at 1646
#091219 12:45:26 server id 100 end_log_pos 1714 Query thread_id=1
exec_time=0 error_code=0
SET TIMESTAMP=1261215926/*!*/;
BEGIN
/*!*/;
# at 1714
# at 1812
# at 1853
# at 1894
# at 1938
#091219 12:45:26 server id 100 end_log_pos 1812 Query: `DELETE t1, t2 FROM
t1 INNER JOIN t2 INNER JOIN t3 WHERE t1.a=t2.a AND t2.a=t3.a`
#091219 12:45:26 server id 100 end_log_pos 1853 Table_map: `test`.`t1`
mapped to number 16
#091219 12:45:26 server id 100 end_log_pos 1894 Table_map: `test`.`t2`
mapped to number 17
#091219 12:45:26 server id 100 end_log_pos 1938 Delete_rows: table id 16
#091219 12:45:26 server id 100 end_log_pos 1982 Delete_rows: table id 17
flags: STMT_END_F
...
LOW-LEVEL DESIGN:
Content
~~~~~~~
1. Annotate_rows event number
2. Outline of Annotate_rows event behavior
3. How Master writes Annotate_rows events to the binary log
4. How slave treats replicate-annotate-rows-events option
5. How slave IO thread requests Annotate_rows events
6. How master executes the request
7. How slave SQL thread processes Annotate_rows events
8. General remarks
1. Annotate_rows event number
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To avoid possible event numbers conflict with MySQL/Sun, we leave a gap
between the last MySQL event number and the Annotate_rows event number:
enum Log_event_type
{ ...
INCIDENT_EVENT= 26,
// New MySQL event numbers are to be added here
MYSQL_EVENTS_END,
MARIA_EVENTS_BEGIN= 51,
// New Maria event numbers start from here
ANNOTATE_ROWS_EVENT= 51,
ENUM_END_EVENT
};
together with the corresponding extension of 'post_header_len' array in the
Format description event. (This extension does not affect the compatibility
of the binary log). Here is how Format description event looks like with
this extension:
************************
FORMAT_DESCRIPTION_EVENT
************************
00000004 | A1 A0 2C 4B | time_when = 1261215905
00000008 | 0F | event_type = 15
00000009 | 64 00 00 00 | server_id = 100
0000000D | 7F 00 00 00 | event_len = 127
00000011 | 83 00 00 00 | log_pos = 00000083
00000015 | 01 00 | flags = LOG_EVENT_BINLOG_IN_USE_F
------------------------
00000017 | 04 00 | binlog_ver = 4
00000019 | 35 2E 32 2E | server_ver = 5.2.0-MariaDB-alpha-debug-log
..... ...
0000004B | A1 A0 2C 4B | time_created = 1261215905
0000004F | 13 | common_header_len = 19
------------------------
post_header_len
------------------------
00000050 | 38 | 56 - START_EVENT_V3 [1]
..... ...
00000069 | 02 | 2 - INCIDENT_EVENT [26]
0000006A | 00 | 0 - RESERVED [27]
..... ...
00000081 | 00 | 0 - RESERVED [50]
00000082 | 00 | 0 - ANNOTATE_ROWS_EVENT [51]
************************
2. Outline of Annotate_rows event behavior
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Each Annotate_rows_log_event object has two private members describing the
corresponding query:
char *m_query_txt;
uint m_query_len;
When the object is created for writing to a binary log, this query is taken
from 'thd' (for short, below we omit the 'Annotate_rows_log_event::' prefix
as well as other implementation details):
Annotate_rows_log_event(THD *thd)
{
m_query_txt = thd->query();
m_query_len = thd->query_length();
}
When the object is read from a binary log, the query is taken from the buffer
containing the binary log representation of the event (this buffer is allocated
in Log_event object from which all Log events are derived):
Annotate_rows_log_event(char *buf, uint event_len,
Format_description_log_event *desc)
{
m_query_len = event_len - desc->common_header_len;
m_query_txt = buf + desc->common_header_len;
}
The events are written to the binary log by the Log_event::write() member
which calls virtual write_data_header() and write_data_body() members
("data header" and "post header" are synonym in replication terminology).
In our case, data header is empty and data body is just the query:
bool write_data_body(IO_CACHE *file)
{
return my_b_safe_write(file, (uchar*) m_query_txt, m_query_len);
}
Printing the event is just printing the query:
void Annotate_rows_log_event::print(FILE *file, PRINT_EVENT_INFO *pinfo)
{
my_b_printf(&pinfo->head_cache, "\tQuery: `%s`\n", m_query_txt);
}
3. How Master writes Annotate_rows events to the binary log
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The event is written to the binary log just before the group of Table_map
events which precede corresponding Rows events (one query may generate
several Table map events in the binary log, but the corresponding
Annotate_rows event must be written only once before the first Table map
event; hence the boolean variable 'with_annotate' below):
int write_locked_table_maps(THD *thd)
{ ...
bool with_annotate= thd->variables.binlog_annotate_rows_events;
...
for (uint i= 0; i < ... <number of tables> ...; ++i)
{ ...
thd->binlog_write_table_map(table, ..., with_annotate);
with_annotate= 0; // write Annotate_event not more than once
...
}
...
}
int THD::binlog_write_table_map(TABLE *table, ..., bool with_annotate)
{ ...
Table_map_log_event the_event(...);
...
if (with_annotate)
{
Annotate_rows_log_event anno(this);
mysql_bin_log.write(&anno);
}
mysql_bin_log.write(&the_event);
...
}
4. How slave treats replicate-annotate-rows-events option
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The replicate-annotate-rows-events option is treated just as the session
value of the binlog_annotate_rows_events variable for the slave IO and
SQL threads. This setting is done during initialization of these threads:
pthread_handler_t handle_slave_io(void *arg)
{
THD *thd= new THD;
...
init_slave_thread(thd, SLAVE_THD_IO);
...
}
pthread_handler_t handle_slave_sql(void *arg)
{
THD *thd= new THD;
...
init_slave_thread(thd, SLAVE_THD_SQL);
...
}
int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type)
{ ...
thd->variables.binlog_annotate_rows_events=
opt_replicate_annotate_rows_events;
...
}
5. How slave IO thread requests Annotate_rows events
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If the replicate-annotate-rows-events option is not set on a slave, there
is no need for master to send Annotate_rows events to this slave. The slave
(or mysqlbinlog in remote case), before requesting binlog dump via the
COM_BINLOG_DUMP command, informs the master whether it should send these
events by executing the newly added COM_BINLOG_DUMP_OPTIONS_EXT server
command:
case COM_BINLOG_DUMP_OPTIONS_EXT:
thd->binlog_dump_flags_ext= packet[0];
my_ok(thd);
break;
Note. We add this new command and don't use COM_BINLOG_DUMP to avoid possible
conflicts with MySQL/Sun.
6. How master executes the request
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
case COM_BINLOG_DUMP:
{ ...
flags= uint2korr(packet + 4);
...
mysql_binlog_send(thd, ..., flags);
...
}
void mysql_binlog_send(THD* thd, ..., ushort flags)
{ ...
Log_event::read_log_event(&log, packet, ...);
...
if ((*packet)[EVENT_TYPE_OFFSET + 1] != ANNOTATE_ROWS_EVENT ||
flags & BINLOG_SEND_ANNOTATE_ROWS_EVENT)
{
my_net_write(net, packet->ptr(), packet->length());
}
...
}
7. How slave SQL thread processes Annotate_rows events
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The slave processes each recieved event by "applying" it, i.e. by
calling the Log_event::apply_event() function which in turn calls
the virtual do_apply_event() member specific for each type of the
event.
int exec_relay_log_event(THD* thd, Relay_log_info* rli)
{ ...
Log_event *ev = next_event(rli);
...
apply_event_and_update_pos(ev, ...);
if (ev->get_type_code() != FORMAT_DESCRIPTION_EVENT)
delete ev;
...
}
int apply_event_and_update_pos(Log_event *ev, ...)
{ ...
ev->apply_event(...);
...
}
int Log_event::apply_event(...)
{
return do_apply_event(...);
}
What does it mean to "apply" an Annotate_rows event? It means to set current
thd query to that of the described by the event, i.e. to the query which
caused the subsequent Rows events (see "How Master writes Annotate_rows
events to the binary log" to follow what happens further when the subsequent
Rows events are applied):
int Annotate_rows_log_event::do_apply_event(...)
{
thd->set_query(m_query_txt, m_query_len);
}
NOTE. I am not sure, but possibly current values of thd->query and
thd->query_length should be saved before calling set_query() and to be
restored on the Annotate_rows_log_event object deletion.
Is it really needed ?
After calling this do_apply_event() function we may not delete the
Annotate_rows_log_event object immediatedly (see exec_relay_log_event()
above) because thd->query now points to the string inside this object.
We may keep the pointer to this object in the Relay_log_info:
class Relay_log_info
{
public:
...
void set_annotate_event(Annotate_rows_log_event*);
Annotate_rows_log_event* get_annotate_event();
void free_annotate_event();
...
private:
Annotate_rows_log_event* m_annotate_event;
};
The saved Annotate_rows object should be deleted when all corresponding
Rows events will be processed:
int exec_relay_log_event(THD* thd, Relay_log_info* rli)
{ ...
Log_event *ev= next_event(rli);
...
apply_event_and_update_pos(ev, ...);
if (rli->get_annotate_event() && is_last_rows_event(ev))
rli->free_annotate_event();
else if (ev->get_type_code() == ANNOTATE_ROWS_EVENT)
rli->set_annotate_event((Annotate_rows_log_event*) ev);
else if (ev->get_type_code() != FORMAT_DESCRIPTION_EVENT)
delete ev;
...
}
where
bool is_last_rows_event(Log_event* ev)
{
Log_event_type type= ev->get_type_code();
if (IS_ROWS_EVENT_TYPE(type))
{
Rows_log_event* rows= (Rows_log_event*)ev;
return rows->get_flags(Rows_log_event::STMT_END_F);
}
return 0;
}
#define IS_ROWS_EVENT_TYPE(type) ((type) == WRITE_ROWS_EVENT || \
(type) == UPDATE_ROWS_EVENT || \
(type) == DELETE_ROWS_EVENT)
8. General remarks
~~~~~~~~~~~~~~~~~~
Kristian noticed that introducing new log event type should be coordinated
somehow with MySQL/Sun:
Kristian: The numeric code for this event must be assigned carefully.
It should be coordinated with MySQL/Sun, otherwise we can get into a
situation where MySQL uses the same numeric code for one event that
MariaDB uses for ANNOTATE_ROWS_EVENT, which would make merging the two
impossible.
Alex: I reserved about 20 numbers not to have possible conflicts
with MySQL.
Kristian: Still, I think it would be appropriate to send a polite email
to internals(a)lists.mysql.com about this and suggesting to reserve the
event number.
ESTIMATED WORK TIME
ESTIMATED COMPLETION DATE
-----------------------------------------------------------------------
WorkLog (v3.5.9)
1
0

[Maria-developers] Rev 29: Increased warmup time. in file:///Users/hakan/work/monty_program/mariadb-tools/
by Hakan Kuecuekyilmaz 29 Mar '10
by Hakan Kuecuekyilmaz 29 Mar '10
29 Mar '10
At file:///Users/hakan/work/monty_program/mariadb-tools/
------------------------------------------------------------
revno: 29
revision-id: hakan(a)askmonty.org-20100329105306-6hthpbelo9xop3kw
parent: hakan(a)askmonty.org-20100325014205-kwsruwixwlymz1ti
committer: Hakan Kuecuekyilmaz <hakan(a)askmonty.org>
branch nick: mariadb-tools
timestamp: Mon 2010-03-29 12:53:06 +0200
message:
Increased warmup time.
=== modified file 'sysbench/run-sysbench-myisam.sh'
--- a/sysbench/run-sysbench-myisam.sh 2010-03-25 01:42:05 +0000
+++ b/sysbench/run-sysbench-myisam.sh 2010-03-29 10:53:06 +0000
@@ -92,10 +92,10 @@
TABLE_SIZE=20000000
# The run time we use for sysbench.
-RUN_TIME=900
+RUN_TIME=1800
# Warm up time we use for sysbench.
-WARM_UP_TIME=180
+WARM_UP_TIME=300
# How many times we run each test.
LOOP_COUNT=3
@@ -314,7 +314,7 @@
echo "[$(date "+%Y-%m-%d %H:%M:%S")] Running $SYSBENCH_TEST with $THREADS threads and $LOOP_COUNT iterations for $PRODUCT" | tee ${THIS_RESULT_DIR}/results.txt
echo '' >> ${THIS_RESULT_DIR}/results.txt
- SYSBENCH_OPTIONS_WARM_UP="${SYSBENCH_OPTIONS} --num-threads=1 --max-time=$WARM_UP_TIME"
+ SYSBENCH_OPTIONS_WARM_UP="${SYSBENCH_OPTIONS} --num-threads=3 --max-time=$WARM_UP_TIME"
SYSBENCH_OPTIONS_RUN="${SYSBENCH_OPTIONS} --num-threads=$THREADS --max-time=$RUN_TIME"
k=0
@@ -345,7 +345,7 @@
grep "write requests:" ${THIS_RESULT_DIR}/result${k}.txt | awk '{ print $4 }' | sed -e 's/(//' >> ${THIS_RESULT_DIR}/results.txt
- echo 'SELECT * FROM INFORMATION_SCHEMA.KEY_CACHES' | $MYSQL -uroot > ${THIS_RESULT_DIR}/key_cache_stats{k}.txt
+ echo 'SELECT * FROM INFORMATION_SCHEMA.KEY_CACHES' | $MYSQL -uroot > ${THIS_RESULT_DIR}/key_cache_stats${k}.txt
k=$(($k + 1))
done
1
0

[Maria-developers] Updated (by Psergey): Make EXPLAIN show where subquery predicates are in the WHERE clause (111)
by worklog-noreplyï¼ askmonty.org 29 Mar '10
by worklog-noreplyï¼ askmonty.org 29 Mar '10
29 Mar '10
-----------------------------------------------------------------------
WORKLOG TASK
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
TASK...........: Make EXPLAIN show where subquery predicates are in the WHERE clause
CREATION DATE..: Mon, 29 Mar 2010, 07:07
SUPERVISOR.....: Psergey
IMPLEMENTOR....:
COPIES TO......:
CATEGORY.......: Server-RawIdeaBin
TASK ID........: 111 (http://askmonty.org/worklog/?tid=111)
VERSION........: Server-5.3
STATUS.........: Un-Assigned
PRIORITY.......: 60
WORKED HOURS...: 0
ESTIMATE.......: 0 (hours remain)
ORIG. ESTIMATE.: 0
PROGRESS NOTES:
-=-=(Psergey - Mon, 29 Mar 2010, 08:23)=-=-
High-Level Specification modified.
--- /tmp/wklog.111.old.18396 2010-03-29 08:23:06.000000000 +0000
+++ /tmp/wklog.111.new.18396 2010-03-29 08:23:06.000000000 +0000
@@ -1 +1,9 @@
+* Implement Item::walk()-compatible method that calls a callback
+ function for each found subquery predicate. Enumeration should enter
+ condition/function parameters but do not descend into subquery
+ expressions.
+
+* Let select_describe() call the above method with a callback that appends
+ "subquery#n" for every encountered subquery.
+
-=-=(Psergey - Mon, 29 Mar 2010, 08:16)=-=-
High Level Description modified.
--- /tmp/wklog.111.old.18136 2010-03-29 08:16:36.000000000 +0000
+++ /tmp/wklog.111.new.18136 2010-03-29 08:16:36.000000000 +0000
@@ -30,8 +30,15 @@
to expressions being too long for current EXPLAIN output format.
A simplified solution would be to show "Subquery#n" in Extra column if the
-clause in "Using Where" has a subquery.
+clause in "Using Where" has a subquery. That is, if table's condition has
+subquery expressions, Extra column will look like this:
+ Using where; Subquery#n1; Subquery#n2,...
+
+When table's condition has only subquery expression, we could omit printing
+"Using where" (note that this case is quite rare now. the subquery must be
+correlated, non-semi-join subquery predicate that is an AND-part of the WHERE.
+such cases are in minority)
[1] http://forge.mysql.com/wiki/Image:NewSubqueryOptimizationsIn6_0_UC2008.pdf
-=-=(Guest - Mon, 29 Mar 2010, 07:09)=-=-
Supervisor updated.
--- /tmp/wklog.111.old.13259 2010-03-29 07:09:55.000000000 +0000
+++ /tmp/wklog.111.new.13259 2010-03-29 07:09:55.000000000 +0000
@@ -1 +1 @@
-Bothorsen
+Psergey
-=-=(Guest - Mon, 29 Mar 2010, 07:09)=-=-
Category updated.
--- /tmp/wklog.111.old.13259 2010-03-29 07:09:55.000000000 +0000
+++ /tmp/wklog.111.new.13259 2010-03-29 07:09:55.000000000 +0000
@@ -1 +1 @@
-Client-BackLog
+Server-RawIdeaBin
-=-=(Guest - Mon, 29 Mar 2010, 07:09)=-=-
Version updated.
--- /tmp/wklog.111.old.13259 2010-03-29 07:09:55.000000000 +0000
+++ /tmp/wklog.111.new.13259 2010-03-29 07:09:55.000000000 +0000
@@ -1 +1 @@
-Benchmarks-3.0
+9.x
-=-=(Guest - Mon, 29 Mar 2010, 07:09)=-=-
Version updated.
--- /tmp/wklog.111.old.13259 2010-03-29 07:09:55.000000000 +0000
+++ /tmp/wklog.111.new.13259 2010-03-29 07:09:55.000000000 +0000
@@ -1 +1 @@
-9.x
+Server-5.3
DESCRIPTION:
Current EXPLAIN does not show where the subquery predicate is attached to.
For example, see [1], slide#5 "Straightforward subquery evaluation (contd)", or
look here:
MariaDB [test]> explain select * from ot1, ot2 where ot1.a=ot2.a and (ot2.a in
(select it1.b from it1) or ot1.b<3);
+----+-------------+-------+------+---------------+------+---------+------+------+--------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows
| Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+--------------------------------+
| 1 | PRIMARY | ot1 | ALL | NULL | NULL | NULL | NULL | 10
| Using where |
| 1 | PRIMARY | ot2 | ALL | NULL | NULL | NULL | NULL | 10
| Using where; Using join buffer |
| 2 | SUBQUERY | it1 | ALL | NULL | NULL | NULL | NULL | 20
| |
+----+-------------+-------+------+---------------+------+---------+------+------+--------------------------------+
3 rows in set (0.01 sec)
Here there are two "Using where", and it is not clear where the predicate is
attached to. If one has sufficient knowledge, they could know that
- "ot2.a in (select )" will be substituted for "ot1.a" (provided datatypes
allow equality propagation)
- For correlated subqueries, equality propagation will not affect outside
references (so, if the subquery in the above example was correlated, it would
have been attached to table ot2, not ot1).
As one can see, the rules are quite complicated. The full solution would be to
show expressions behind "Using Where", but that has additional complications due
to expressions being too long for current EXPLAIN output format.
A simplified solution would be to show "Subquery#n" in Extra column if the
clause in "Using Where" has a subquery. That is, if table's condition has
subquery expressions, Extra column will look like this:
Using where; Subquery#n1; Subquery#n2,...
When table's condition has only subquery expression, we could omit printing
"Using where" (note that this case is quite rare now. the subquery must be
correlated, non-semi-join subquery predicate that is an AND-part of the WHERE.
such cases are in minority)
[1] http://forge.mysql.com/wiki/Image:NewSubqueryOptimizationsIn6_0_UC2008.pdf
HIGH-LEVEL SPECIFICATION:
* Implement Item::walk()-compatible method that calls a callback
function for each found subquery predicate. Enumeration should enter
condition/function parameters but do not descend into subquery
expressions.
* Let select_describe() call the above method with a callback that appends
"subquery#n" for every encountered subquery.
ESTIMATED WORK TIME
ESTIMATED COMPLETION DATE
-----------------------------------------------------------------------
WorkLog (v3.5.9)
1
0

[Maria-developers] Updated (by Psergey): Make EXPLAIN show where subquery predicates are in the WHERE clause (111)
by worklog-noreplyï¼ askmonty.org 29 Mar '10
by worklog-noreplyï¼ askmonty.org 29 Mar '10
29 Mar '10
-----------------------------------------------------------------------
WORKLOG TASK
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
TASK...........: Make EXPLAIN show where subquery predicates are in the WHERE clause
CREATION DATE..: Mon, 29 Mar 2010, 07:07
SUPERVISOR.....: Psergey
IMPLEMENTOR....:
COPIES TO......:
CATEGORY.......: Server-RawIdeaBin
TASK ID........: 111 (http://askmonty.org/worklog/?tid=111)
VERSION........: Server-5.3
STATUS.........: Un-Assigned
PRIORITY.......: 60
WORKED HOURS...: 0
ESTIMATE.......: 0 (hours remain)
ORIG. ESTIMATE.: 0
PROGRESS NOTES:
-=-=(Psergey - Mon, 29 Mar 2010, 08:16)=-=-
High Level Description modified.
--- /tmp/wklog.111.old.18136 2010-03-29 08:16:36.000000000 +0000
+++ /tmp/wklog.111.new.18136 2010-03-29 08:16:36.000000000 +0000
@@ -30,8 +30,15 @@
to expressions being too long for current EXPLAIN output format.
A simplified solution would be to show "Subquery#n" in Extra column if the
-clause in "Using Where" has a subquery.
+clause in "Using Where" has a subquery. That is, if table's condition has
+subquery expressions, Extra column will look like this:
+ Using where; Subquery#n1; Subquery#n2,...
+
+When table's condition has only subquery expression, we could omit printing
+"Using where" (note that this case is quite rare now. the subquery must be
+correlated, non-semi-join subquery predicate that is an AND-part of the WHERE.
+such cases are in minority)
[1] http://forge.mysql.com/wiki/Image:NewSubqueryOptimizationsIn6_0_UC2008.pdf
-=-=(Guest - Mon, 29 Mar 2010, 07:09)=-=-
Supervisor updated.
--- /tmp/wklog.111.old.13259 2010-03-29 07:09:55.000000000 +0000
+++ /tmp/wklog.111.new.13259 2010-03-29 07:09:55.000000000 +0000
@@ -1 +1 @@
-Bothorsen
+Psergey
-=-=(Guest - Mon, 29 Mar 2010, 07:09)=-=-
Category updated.
--- /tmp/wklog.111.old.13259 2010-03-29 07:09:55.000000000 +0000
+++ /tmp/wklog.111.new.13259 2010-03-29 07:09:55.000000000 +0000
@@ -1 +1 @@
-Client-BackLog
+Server-RawIdeaBin
-=-=(Guest - Mon, 29 Mar 2010, 07:09)=-=-
Version updated.
--- /tmp/wklog.111.old.13259 2010-03-29 07:09:55.000000000 +0000
+++ /tmp/wklog.111.new.13259 2010-03-29 07:09:55.000000000 +0000
@@ -1 +1 @@
-Benchmarks-3.0
+9.x
-=-=(Guest - Mon, 29 Mar 2010, 07:09)=-=-
Version updated.
--- /tmp/wklog.111.old.13259 2010-03-29 07:09:55.000000000 +0000
+++ /tmp/wklog.111.new.13259 2010-03-29 07:09:55.000000000 +0000
@@ -1 +1 @@
-9.x
+Server-5.3
DESCRIPTION:
Current EXPLAIN does not show where the subquery predicate is attached to.
For example, see [1], slide#5 "Straightforward subquery evaluation (contd)", or
look here:
MariaDB [test]> explain select * from ot1, ot2 where ot1.a=ot2.a and (ot2.a in
(select it1.b from it1) or ot1.b<3);
+----+-------------+-------+------+---------------+------+---------+------+------+--------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows
| Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+--------------------------------+
| 1 | PRIMARY | ot1 | ALL | NULL | NULL | NULL | NULL | 10
| Using where |
| 1 | PRIMARY | ot2 | ALL | NULL | NULL | NULL | NULL | 10
| Using where; Using join buffer |
| 2 | SUBQUERY | it1 | ALL | NULL | NULL | NULL | NULL | 20
| |
+----+-------------+-------+------+---------------+------+---------+------+------+--------------------------------+
3 rows in set (0.01 sec)
Here there are two "Using where", and it is not clear where the predicate is
attached to. If one has sufficient knowledge, they could know that
- "ot2.a in (select )" will be substituted for "ot1.a" (provided datatypes
allow equality propagation)
- For correlated subqueries, equality propagation will not affect outside
references (so, if the subquery in the above example was correlated, it would
have been attached to table ot2, not ot1).
As one can see, the rules are quite complicated. The full solution would be to
show expressions behind "Using Where", but that has additional complications due
to expressions being too long for current EXPLAIN output format.
A simplified solution would be to show "Subquery#n" in Extra column if the
clause in "Using Where" has a subquery. That is, if table's condition has
subquery expressions, Extra column will look like this:
Using where; Subquery#n1; Subquery#n2,...
When table's condition has only subquery expression, we could omit printing
"Using where" (note that this case is quite rare now. the subquery must be
correlated, non-semi-join subquery predicate that is an AND-part of the WHERE.
such cases are in minority)
[1] http://forge.mysql.com/wiki/Image:NewSubqueryOptimizationsIn6_0_UC2008.pdf
ESTIMATED WORK TIME
ESTIMATED COMPLETION DATE
-----------------------------------------------------------------------
WorkLog (v3.5.9)
1
0

[Maria-developers] Progress (by Knielsen): New replication APIs (107)
by worklog-noreplyï¼ askmonty.org 29 Mar '10
by worklog-noreplyï¼ askmonty.org 29 Mar '10
29 Mar '10
-----------------------------------------------------------------------
WORKLOG TASK
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
TASK...........: New replication APIs
CREATION DATE..: Mon, 15 Mar 2010, 13:55
SUPERVISOR.....: Knielsen
IMPLEMENTOR....: Knielsen
COPIES TO......: Sergei
CATEGORY.......: Server-Sprint
TASK ID........: 107 (http://askmonty.org/worklog/?tid=107)
VERSION........: Server-9.x
STATUS.........: Un-Assigned
PRIORITY.......: 60
WORKED HOURS...: 50
ESTIMATE.......: 0 (hours remain)
ORIG. ESTIMATE.: 0
PROGRESS NOTES:
-=-=(Knielsen - Mon, 29 Mar 2010, 07:33)=-=-
Research and design discussions: Galera, 2pc/XA, group commit, multi-engine transactions.
Worked 14 hours and estimate 0 hours remain (original estimate increased by 14 hours).
-=-=(Knielsen - Wed, 24 Mar 2010, 10:39)=-=-
Design discussions
Worked 11 hours and estimate 0 hours remain (original estimate increased by 11 hours).
-=-=(Knielsen - Mon, 15 Mar 2010, 14:28)=-=-
Research into the problem, and discussions on phone/mailing list
Worked 25 hours and estimate 0 hours remain (original estimate increased by 25 hours).
-=-=(Guest - Mon, 15 Mar 2010, 14:18)=-=-
High-Level Specification modified.
--- /tmp/wklog.107.old.9086 2010-03-15 14:18:18.000000000 +0000
+++ /tmp/wklog.107.new.9086 2010-03-15 14:18:18.000000000 +0000
@@ -1 +1,43 @@
+Current ideas/status after discussions on the mailing list:
+
+ - Implement a set of plugin APIs and use them to move all of the existing
+ MySQL replication into a (set of) plugins.
+
+ - Design the APIs so that they can support full MySQL replication, but also
+ so that they do not hardcode assumptions about how this replication
+ implementation is done, and so that they will be suitable for other types of
+ replication (Tungsten, Galera, parallel replication, ...).
+
+ - APIs need to include the concept of a global transaction ID. Need to
+ determine the extent to which the semantics of such ID will be defined
+ by the API, and to which extend it will be defined by the plugin
+ implementations.
+
+ - APIs should properly support reliable crash-recovery with decent
+ performance (eg. not require multiple mandatory fsync()s per commit, and
+ not make group commit impossible).
+
+ - Would be nice if the API provided facilities for implementing good
+ consistency checking support (mainly checking master tables against slave
+ tables is hard here I think, but also applying wrong binlog data and
+ individual event checksums).
+
+
+Steps to make this more concrete:
+
+ - Investigate the current MySQL replication, and list all of the places where
+ a plugin implementation will need to connect/hook into the MySQL server.
+ * handler::{write,update,delete}_row()
+ * Statement execution
+ * Transaction start/commit
+ * Table open
+ * Query safe/not/safe for statement based replication
+ * Statement-based logging details (user variables, random seed, etc.)
+ * ...
+
+ - Use this list to make an initial sketch of the set of APIs we need.
+
+ - Use the list to determine the feasibility of this project and the level of
+ detail in the API needed to support a full replication implementation as a
+ plugin.
-=-=(Serg - Mon, 15 Mar 2010, 14:13)=-=-
Observers changed: Sergei
DESCRIPTION:
This is a top-level task for the project of designing a new set of replication
APIs for MariaDB.
This task is for the initial discussion of what to do and where to focus.
The project is started in this email thread:
https://lists.launchpad.net/maria-developers/msg01998.html
HIGH-LEVEL SPECIFICATION:
Current ideas/status after discussions on the mailing list:
- Implement a set of plugin APIs and use them to move all of the existing
MySQL replication into a (set of) plugins.
- Design the APIs so that they can support full MySQL replication, but also
so that they do not hardcode assumptions about how this replication
implementation is done, and so that they will be suitable for other types of
replication (Tungsten, Galera, parallel replication, ...).
- APIs need to include the concept of a global transaction ID. Need to
determine the extent to which the semantics of such ID will be defined
by the API, and to which extend it will be defined by the plugin
implementations.
- APIs should properly support reliable crash-recovery with decent
performance (eg. not require multiple mandatory fsync()s per commit, and
not make group commit impossible).
- Would be nice if the API provided facilities for implementing good
consistency checking support (mainly checking master tables against slave
tables is hard here I think, but also applying wrong binlog data and
individual event checksums).
Steps to make this more concrete:
- Investigate the current MySQL replication, and list all of the places where
a plugin implementation will need to connect/hook into the MySQL server.
* handler::{write,update,delete}_row()
* Statement execution
* Transaction start/commit
* Table open
* Query safe/not/safe for statement based replication
* Statement-based logging details (user variables, random seed, etc.)
* ...
- Use this list to make an initial sketch of the set of APIs we need.
- Use the list to determine the feasibility of this project and the level of
detail in the API needed to support a full replication implementation as a
plugin.
ESTIMATED WORK TIME
ESTIMATED COMPLETION DATE
-----------------------------------------------------------------------
WorkLog (v3.5.9)
1
0